xref: /onnv-gate/usr/src/cmd/cmd-inet/lib/nwamd/conditions.c (revision 12805:288ae711509e)
111767SAnurag.Maskey@Sun.COM /*
211767SAnurag.Maskey@Sun.COM  * CDDL HEADER START
311767SAnurag.Maskey@Sun.COM  *
411767SAnurag.Maskey@Sun.COM  * The contents of this file are subject to the terms of the
511767SAnurag.Maskey@Sun.COM  * Common Development and Distribution License (the "License").
611767SAnurag.Maskey@Sun.COM  * You may not use this file except in compliance with the License.
711767SAnurag.Maskey@Sun.COM  *
811767SAnurag.Maskey@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911767SAnurag.Maskey@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011767SAnurag.Maskey@Sun.COM  * See the License for the specific language governing permissions
1111767SAnurag.Maskey@Sun.COM  * and limitations under the License.
1211767SAnurag.Maskey@Sun.COM  *
1311767SAnurag.Maskey@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411767SAnurag.Maskey@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511767SAnurag.Maskey@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611767SAnurag.Maskey@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711767SAnurag.Maskey@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811767SAnurag.Maskey@Sun.COM  *
1911767SAnurag.Maskey@Sun.COM  * CDDL HEADER END
2011767SAnurag.Maskey@Sun.COM  */
2111767SAnurag.Maskey@Sun.COM 
2211767SAnurag.Maskey@Sun.COM /*
2312576SAnurag.Maskey@Oracle.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2411767SAnurag.Maskey@Sun.COM  */
2511767SAnurag.Maskey@Sun.COM 
2611767SAnurag.Maskey@Sun.COM #include <arpa/inet.h>
2711767SAnurag.Maskey@Sun.COM #include <ctype.h>
2811767SAnurag.Maskey@Sun.COM #include <errno.h>
2911767SAnurag.Maskey@Sun.COM #include <inet/ip.h>
3011767SAnurag.Maskey@Sun.COM #include <libdladm.h>
3111767SAnurag.Maskey@Sun.COM #include <libdllink.h>
3211767SAnurag.Maskey@Sun.COM #include <libdlwlan.h>
3311767SAnurag.Maskey@Sun.COM #include <netdb.h>
3411767SAnurag.Maskey@Sun.COM #include <stdio.h>
3511767SAnurag.Maskey@Sun.COM #include <stdlib.h>
3611767SAnurag.Maskey@Sun.COM #include <string.h>
3711767SAnurag.Maskey@Sun.COM 
3811767SAnurag.Maskey@Sun.COM #include <libnwam.h>
3911767SAnurag.Maskey@Sun.COM #include "conditions.h"
4011767SAnurag.Maskey@Sun.COM #include "ncu.h"
4111767SAnurag.Maskey@Sun.COM #include "objects.h"
4211767SAnurag.Maskey@Sun.COM #include "util.h"
4311767SAnurag.Maskey@Sun.COM 
4411767SAnurag.Maskey@Sun.COM /*
4511767SAnurag.Maskey@Sun.COM  * conditions.c - contains routines which check state to see if activation
4611767SAnurag.Maskey@Sun.COM  * conditions for NWAM objects are satisfied and rates activation conditions to
4711767SAnurag.Maskey@Sun.COM  * help determine which is most specific.
4811767SAnurag.Maskey@Sun.COM  *
4911767SAnurag.Maskey@Sun.COM  * If the activation-mode is CONDITIONAL_ANY or CONDITIONAL_ALL, the conditions
5011767SAnurag.Maskey@Sun.COM  * property is set to a string made up of conditional expressions. Each
5111767SAnurag.Maskey@Sun.COM  * expression is made up of a condition that can be assigned a boolean value,
5211767SAnurag.Maskey@Sun.COM  * e.g. "system-domain is sun.com" or "ncu ip:bge0 is-not active". If the
5311767SAnurag.Maskey@Sun.COM  * activation-mode is CONDITIONAL_ANY, the condition will be satisfied if any
5411767SAnurag.Maskey@Sun.COM  * one of the conditions is true; if the activation-mode is CONDITIONAL_ALL,
5511767SAnurag.Maskey@Sun.COM  * the condition is satisfied only if all of the conditions are true.
5611767SAnurag.Maskey@Sun.COM  */
5711767SAnurag.Maskey@Sun.COM 
5811767SAnurag.Maskey@Sun.COM uint64_t condition_check_interval = CONDITION_CHECK_INTERVAL_DEFAULT;
5911767SAnurag.Maskey@Sun.COM 
6011767SAnurag.Maskey@Sun.COM extern int getdomainname(char *, int);
6111767SAnurag.Maskey@Sun.COM 
6211767SAnurag.Maskey@Sun.COM /* NCP, NCU, ENM and location conditions */
6311767SAnurag.Maskey@Sun.COM static boolean_t test_condition_ncp(nwam_condition_t condition,
6411767SAnurag.Maskey@Sun.COM     const char *ncp_name);
6511767SAnurag.Maskey@Sun.COM static boolean_t test_condition_ncu(nwam_condition_t condition,
6611767SAnurag.Maskey@Sun.COM     const char *ncu_name);
6711767SAnurag.Maskey@Sun.COM static boolean_t test_condition_enm(nwam_condition_t condition,
6811767SAnurag.Maskey@Sun.COM     const char *enm_name);
6911767SAnurag.Maskey@Sun.COM static boolean_t test_condition_loc(nwam_condition_t condition,
7011767SAnurag.Maskey@Sun.COM     const char *loc_name);
7111767SAnurag.Maskey@Sun.COM 
7211767SAnurag.Maskey@Sun.COM /* IP address conditions */
7311767SAnurag.Maskey@Sun.COM static boolean_t test_condition_ip_address(nwam_condition_t condition,
7411767SAnurag.Maskey@Sun.COM     const char *ip_address);
7511767SAnurag.Maskey@Sun.COM 
7611767SAnurag.Maskey@Sun.COM /* domainname conditions */
7711767SAnurag.Maskey@Sun.COM static boolean_t test_condition_sys_domain(nwam_condition_t condition,
7811767SAnurag.Maskey@Sun.COM     const char *domainname);
7911767SAnurag.Maskey@Sun.COM static boolean_t test_condition_adv_domain(nwam_condition_t condition,
8011767SAnurag.Maskey@Sun.COM     const char *domainname);
8111767SAnurag.Maskey@Sun.COM 
8211767SAnurag.Maskey@Sun.COM /*  WLAN conditions */
8311767SAnurag.Maskey@Sun.COM static boolean_t test_condition_wireless_essid(nwam_condition_t condition,
8411767SAnurag.Maskey@Sun.COM     const char *essid);
8511767SAnurag.Maskey@Sun.COM static boolean_t test_condition_wireless_bssid(nwam_condition_t condition,
8611767SAnurag.Maskey@Sun.COM     const char *essid);
8711767SAnurag.Maskey@Sun.COM 
8811767SAnurag.Maskey@Sun.COM struct nwamd_condition_map {
8911767SAnurag.Maskey@Sun.COM 	nwam_condition_object_type_t object_type;
9011767SAnurag.Maskey@Sun.COM 	boolean_t (*condition_func)(nwam_condition_t, const char *);
9111767SAnurag.Maskey@Sun.COM } condition_map[] =
9211767SAnurag.Maskey@Sun.COM {
9311767SAnurag.Maskey@Sun.COM 	{ NWAM_CONDITION_OBJECT_TYPE_NCP, test_condition_ncp },
9411767SAnurag.Maskey@Sun.COM 	{ NWAM_CONDITION_OBJECT_TYPE_NCU, test_condition_ncu },
9511767SAnurag.Maskey@Sun.COM 	{ NWAM_CONDITION_OBJECT_TYPE_ENM, test_condition_enm },
9611767SAnurag.Maskey@Sun.COM 	{ NWAM_CONDITION_OBJECT_TYPE_LOC, test_condition_loc },
9711767SAnurag.Maskey@Sun.COM 	{ NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS, test_condition_ip_address },
9811767SAnurag.Maskey@Sun.COM 	{ NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN, test_condition_sys_domain },
9911767SAnurag.Maskey@Sun.COM 	{ NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN, test_condition_adv_domain },
10011767SAnurag.Maskey@Sun.COM 	{ NWAM_CONDITION_OBJECT_TYPE_ESSID, test_condition_wireless_essid },
10111767SAnurag.Maskey@Sun.COM 	{ NWAM_CONDITION_OBJECT_TYPE_BSSID, test_condition_wireless_bssid }
10211767SAnurag.Maskey@Sun.COM };
10311767SAnurag.Maskey@Sun.COM 
10411767SAnurag.Maskey@Sun.COM /*
10511767SAnurag.Maskey@Sun.COM  * This function takes which kind of conditions (is or is not) we are testing
10611767SAnurag.Maskey@Sun.COM  * the object against and an object and applies the conditon to the object.
10711767SAnurag.Maskey@Sun.COM  */
10811767SAnurag.Maskey@Sun.COM static boolean_t
test_condition_object_state(nwam_condition_t condition,nwam_object_type_t object_type,const char * object_name)10911767SAnurag.Maskey@Sun.COM test_condition_object_state(nwam_condition_t condition,
11011767SAnurag.Maskey@Sun.COM     nwam_object_type_t object_type, const char *object_name)
11111767SAnurag.Maskey@Sun.COM {
11211767SAnurag.Maskey@Sun.COM 	nwamd_object_t object;
11311767SAnurag.Maskey@Sun.COM 	nwam_state_t state;
11411767SAnurag.Maskey@Sun.COM 
11511767SAnurag.Maskey@Sun.COM 	object = nwamd_object_find(object_type, object_name);
11611767SAnurag.Maskey@Sun.COM 	if (object == NULL)
11711767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
11811767SAnurag.Maskey@Sun.COM 
11911767SAnurag.Maskey@Sun.COM 	state = object->nwamd_object_state;
12011767SAnurag.Maskey@Sun.COM 	nwamd_object_release(object);
12111767SAnurag.Maskey@Sun.COM 
12211767SAnurag.Maskey@Sun.COM 	switch (condition) {
12311767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS:
12411767SAnurag.Maskey@Sun.COM 		return (state == NWAM_STATE_ONLINE);
12511767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS_NOT:
12611767SAnurag.Maskey@Sun.COM 		return (state != NWAM_STATE_ONLINE);
12711767SAnurag.Maskey@Sun.COM 	default:
12811767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
12911767SAnurag.Maskey@Sun.COM 	}
13011767SAnurag.Maskey@Sun.COM }
13111767SAnurag.Maskey@Sun.COM 
13211767SAnurag.Maskey@Sun.COM static boolean_t
test_condition_ncp(nwam_condition_t condition,const char * name)13311767SAnurag.Maskey@Sun.COM test_condition_ncp(nwam_condition_t condition, const char *name)
13411767SAnurag.Maskey@Sun.COM {
13511767SAnurag.Maskey@Sun.COM 	boolean_t active;
13611767SAnurag.Maskey@Sun.COM 
13711767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_lock(&active_ncp_mutex);
13811767SAnurag.Maskey@Sun.COM 	active = (strcasecmp(active_ncp, name) == 0);
13911767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_unlock(&active_ncp_mutex);
14011767SAnurag.Maskey@Sun.COM 
14111767SAnurag.Maskey@Sun.COM 	switch (condition) {
14211767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS:
14311767SAnurag.Maskey@Sun.COM 		return (active);
14411767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS_NOT:
14511767SAnurag.Maskey@Sun.COM 		return (active != B_TRUE);
14611767SAnurag.Maskey@Sun.COM 	default:
14711767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
14811767SAnurag.Maskey@Sun.COM 	}
14911767SAnurag.Maskey@Sun.COM }
15011767SAnurag.Maskey@Sun.COM 
15111767SAnurag.Maskey@Sun.COM static boolean_t
test_condition_ncu(nwam_condition_t condition,const char * name)15211767SAnurag.Maskey@Sun.COM test_condition_ncu(nwam_condition_t condition, const char *name)
15311767SAnurag.Maskey@Sun.COM {
15411767SAnurag.Maskey@Sun.COM 	char *real_name, *ncu_name;
15511767SAnurag.Maskey@Sun.COM 	nwam_ncu_handle_t ncuh;
15611767SAnurag.Maskey@Sun.COM 	nwam_ncu_type_t ncu_type;
15711767SAnurag.Maskey@Sun.COM 	boolean_t rv;
15811767SAnurag.Maskey@Sun.COM 
15911767SAnurag.Maskey@Sun.COM 	/* names are case-insensitive, so get real name from libnwam */
16011767SAnurag.Maskey@Sun.COM 	if (nwam_ncu_read(active_ncph, name, NWAM_NCU_TYPE_INTERFACE, 0, &ncuh)
16111767SAnurag.Maskey@Sun.COM 	    == NWAM_SUCCESS) {
16211767SAnurag.Maskey@Sun.COM 		ncu_type = NWAM_NCU_TYPE_INTERFACE;
16311767SAnurag.Maskey@Sun.COM 	} else if (nwam_ncu_read(active_ncph, name, NWAM_NCU_TYPE_LINK, 0,
16411767SAnurag.Maskey@Sun.COM 	    &ncuh) == NWAM_SUCCESS) {
16511767SAnurag.Maskey@Sun.COM 		ncu_type = NWAM_NCU_TYPE_LINK;
16611767SAnurag.Maskey@Sun.COM 	} else {
16711767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
16811767SAnurag.Maskey@Sun.COM 	}
16911767SAnurag.Maskey@Sun.COM 	if (nwam_ncu_get_name(ncuh, &real_name) != NWAM_SUCCESS) {
17011767SAnurag.Maskey@Sun.COM 		nwam_ncu_free(ncuh);
17111767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
17211767SAnurag.Maskey@Sun.COM 	}
17311767SAnurag.Maskey@Sun.COM 	nwam_ncu_free(ncuh);
17411767SAnurag.Maskey@Sun.COM 
17511767SAnurag.Maskey@Sun.COM 	/*
17611767SAnurag.Maskey@Sun.COM 	 * Name may be either unqualified or qualified by NCU type
17711767SAnurag.Maskey@Sun.COM 	 * (interface:/link:).  Need to translate unqualified names
17811767SAnurag.Maskey@Sun.COM 	 * to qualified, specifying interface:name if an interface
17911767SAnurag.Maskey@Sun.COM 	 * NCU is present, otherwise link:ncu.
18011767SAnurag.Maskey@Sun.COM 	 */
18111767SAnurag.Maskey@Sun.COM 	if (nwam_ncu_name_to_typed_name(real_name, ncu_type, &ncu_name)
18211767SAnurag.Maskey@Sun.COM 	    != NWAM_SUCCESS) {
18311767SAnurag.Maskey@Sun.COM 		free(real_name);
18411767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
18511767SAnurag.Maskey@Sun.COM 	}
18611767SAnurag.Maskey@Sun.COM 	free(real_name);
18711767SAnurag.Maskey@Sun.COM 
18811767SAnurag.Maskey@Sun.COM 	rv = test_condition_object_state(condition, NWAM_OBJECT_TYPE_NCU,
18911767SAnurag.Maskey@Sun.COM 	    ncu_name);
19011767SAnurag.Maskey@Sun.COM 	free(ncu_name);
19111767SAnurag.Maskey@Sun.COM 	return (rv);
19211767SAnurag.Maskey@Sun.COM }
19311767SAnurag.Maskey@Sun.COM 
19411767SAnurag.Maskey@Sun.COM static boolean_t
test_condition_enm(nwam_condition_t condition,const char * enm_name)19511767SAnurag.Maskey@Sun.COM test_condition_enm(nwam_condition_t condition, const char *enm_name)
19611767SAnurag.Maskey@Sun.COM {
19711767SAnurag.Maskey@Sun.COM 	nwam_enm_handle_t enmh;
19811767SAnurag.Maskey@Sun.COM 	char *real_name;
19911767SAnurag.Maskey@Sun.COM 	boolean_t rv;
20011767SAnurag.Maskey@Sun.COM 
20111767SAnurag.Maskey@Sun.COM 	/* names are case-insensitive, so get real name from libnwam */
20211767SAnurag.Maskey@Sun.COM 	if (nwam_enm_read(enm_name, 0, &enmh) != NWAM_SUCCESS)
20311767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
20411767SAnurag.Maskey@Sun.COM 	if (nwam_enm_get_name(enmh, &real_name) != NWAM_SUCCESS) {
20511767SAnurag.Maskey@Sun.COM 		nwam_enm_free(enmh);
20611767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
20711767SAnurag.Maskey@Sun.COM 	}
20811767SAnurag.Maskey@Sun.COM 	nwam_enm_free(enmh);
20911767SAnurag.Maskey@Sun.COM 
21011767SAnurag.Maskey@Sun.COM 	rv = test_condition_object_state(condition, NWAM_OBJECT_TYPE_ENM,
21111767SAnurag.Maskey@Sun.COM 	    real_name);
21211767SAnurag.Maskey@Sun.COM 	free(real_name);
21311767SAnurag.Maskey@Sun.COM 	return (rv);
21411767SAnurag.Maskey@Sun.COM }
21511767SAnurag.Maskey@Sun.COM 
21611767SAnurag.Maskey@Sun.COM static boolean_t
test_condition_loc(nwam_condition_t condition,const char * loc_name)21711767SAnurag.Maskey@Sun.COM test_condition_loc(nwam_condition_t condition, const char *loc_name)
21811767SAnurag.Maskey@Sun.COM {
21911767SAnurag.Maskey@Sun.COM 	nwam_loc_handle_t loch;
22011767SAnurag.Maskey@Sun.COM 	char *real_name;
22111767SAnurag.Maskey@Sun.COM 	boolean_t rv;
22211767SAnurag.Maskey@Sun.COM 
22311767SAnurag.Maskey@Sun.COM 	/* names are case-insensitive, so get real name from libnwam */
22411767SAnurag.Maskey@Sun.COM 	if (nwam_loc_read(loc_name, 0, &loch) != NWAM_SUCCESS)
22511767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
22611767SAnurag.Maskey@Sun.COM 	if (nwam_loc_get_name(loch, &real_name) != NWAM_SUCCESS) {
22711767SAnurag.Maskey@Sun.COM 		nwam_loc_free(loch);
22811767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
22911767SAnurag.Maskey@Sun.COM 	}
23011767SAnurag.Maskey@Sun.COM 	nwam_loc_free(loch);
23111767SAnurag.Maskey@Sun.COM 
23211767SAnurag.Maskey@Sun.COM 	rv = test_condition_object_state(condition, NWAM_OBJECT_TYPE_LOC,
23311767SAnurag.Maskey@Sun.COM 	    real_name);
23411767SAnurag.Maskey@Sun.COM 	free(real_name);
23511767SAnurag.Maskey@Sun.COM 	return (rv);
23611767SAnurag.Maskey@Sun.COM }
23711767SAnurag.Maskey@Sun.COM 
23811767SAnurag.Maskey@Sun.COM static boolean_t
test_condition_domain(nwam_condition_t condition,const char * target_domain,const char * found_domain)23911767SAnurag.Maskey@Sun.COM test_condition_domain(nwam_condition_t condition, const char *target_domain,
24011767SAnurag.Maskey@Sun.COM     const char *found_domain)
24111767SAnurag.Maskey@Sun.COM {
24211767SAnurag.Maskey@Sun.COM 	int i, len_t, len_f;
24311767SAnurag.Maskey@Sun.COM 	char target[MAXHOSTNAMELEN], found[MAXHOSTNAMELEN];
24411767SAnurag.Maskey@Sun.COM 
24511767SAnurag.Maskey@Sun.COM 	len_t = target_domain == NULL ? 0 : strlen(target_domain);
24611767SAnurag.Maskey@Sun.COM 	len_f = found_domain == NULL ? 0 : strlen(found_domain);
24711767SAnurag.Maskey@Sun.COM 
24811767SAnurag.Maskey@Sun.COM 	/* convert target_domain and found_domain to lowercase for strstr() */
24911767SAnurag.Maskey@Sun.COM 	for (i = 0; i < len_t; i++)
25011767SAnurag.Maskey@Sun.COM 		target[i] = tolower(target_domain[i]);
25111767SAnurag.Maskey@Sun.COM 	target[len_t] = '\0';
25211767SAnurag.Maskey@Sun.COM 
25311767SAnurag.Maskey@Sun.COM 	for (i = 0; i < len_f; i++)
25411767SAnurag.Maskey@Sun.COM 		found[i] = tolower(found_domain[i]);
25511767SAnurag.Maskey@Sun.COM 	found[len_f] = '\0';
25611767SAnurag.Maskey@Sun.COM 
25711767SAnurag.Maskey@Sun.COM 	switch (condition) {
25811767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS:
25911767SAnurag.Maskey@Sun.COM 		return (found_domain != NULL && strcmp(found, target) == 0);
26011767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS_NOT:
26111767SAnurag.Maskey@Sun.COM 		return (found_domain == NULL || strcmp(found, target) != 0);
26211767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_CONTAINS:
26311767SAnurag.Maskey@Sun.COM 		return (found_domain != NULL && strstr(found, target) != NULL);
26411767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_DOES_NOT_CONTAIN:
26511767SAnurag.Maskey@Sun.COM 		return (found_domain == NULL || strstr(found, target) == NULL);
26611767SAnurag.Maskey@Sun.COM 	default:
26711767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
26811767SAnurag.Maskey@Sun.COM 	}
26911767SAnurag.Maskey@Sun.COM }
27011767SAnurag.Maskey@Sun.COM 
27111767SAnurag.Maskey@Sun.COM struct ncu_adv_domains {
27211767SAnurag.Maskey@Sun.COM 	struct ncu_adv_domains *next;
27311767SAnurag.Maskey@Sun.COM 	char *dns_domain;
27411767SAnurag.Maskey@Sun.COM 	char *nis_domain;
27511767SAnurag.Maskey@Sun.COM };
27611767SAnurag.Maskey@Sun.COM 
27711767SAnurag.Maskey@Sun.COM static int
get_adv_domains(nwamd_object_t obj,void * arg)27811767SAnurag.Maskey@Sun.COM get_adv_domains(nwamd_object_t obj, void *arg)
27911767SAnurag.Maskey@Sun.COM {
28011767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu = (nwamd_ncu_t *)obj->nwamd_object_data;
28111767SAnurag.Maskey@Sun.COM 	struct ncu_adv_domains **headpp = (struct ncu_adv_domains **)arg;
28211767SAnurag.Maskey@Sun.COM 	struct ncu_adv_domains *adp;
28311767SAnurag.Maskey@Sun.COM 	char *dns, *nis;
28411767SAnurag.Maskey@Sun.COM 
28511767SAnurag.Maskey@Sun.COM 	if (ncu->ncu_type != NWAM_NCU_TYPE_INTERFACE)
28611767SAnurag.Maskey@Sun.COM 		return (0);
28711767SAnurag.Maskey@Sun.COM 
28811767SAnurag.Maskey@Sun.COM 	dns = nwamd_get_dhcpinfo_data("DNSdmain", ncu->ncu_name);
28911767SAnurag.Maskey@Sun.COM 	nis = nwamd_get_dhcpinfo_data("NISdmain", ncu->ncu_name);
29011767SAnurag.Maskey@Sun.COM 
29111767SAnurag.Maskey@Sun.COM 	if (dns != NULL || nis != NULL) {
29211767SAnurag.Maskey@Sun.COM 		adp = (struct ncu_adv_domains *)malloc(sizeof (*adp));
29311767SAnurag.Maskey@Sun.COM 		if (adp == NULL)
29411767SAnurag.Maskey@Sun.COM 			return (1);
29511767SAnurag.Maskey@Sun.COM 		adp->dns_domain = dns;
29611767SAnurag.Maskey@Sun.COM 		adp->nis_domain = nis;
29711767SAnurag.Maskey@Sun.COM 		adp->next = *headpp;
29811767SAnurag.Maskey@Sun.COM 		*headpp = adp;
29911767SAnurag.Maskey@Sun.COM 	}
30011767SAnurag.Maskey@Sun.COM 
30111767SAnurag.Maskey@Sun.COM 	return (0);
30211767SAnurag.Maskey@Sun.COM }
30311767SAnurag.Maskey@Sun.COM 
30411767SAnurag.Maskey@Sun.COM static boolean_t
test_condition_sys_domain(nwam_condition_t condition,const char * domainname)30511767SAnurag.Maskey@Sun.COM test_condition_sys_domain(nwam_condition_t condition, const char *domainname)
30611767SAnurag.Maskey@Sun.COM {
30711767SAnurag.Maskey@Sun.COM 	char cur_domainname[MAXHOSTNAMELEN];
30811767SAnurag.Maskey@Sun.COM 
30911767SAnurag.Maskey@Sun.COM 	if (getdomainname(cur_domainname, MAXHOSTNAMELEN) != 0)
31011767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
31111767SAnurag.Maskey@Sun.COM 
31211767SAnurag.Maskey@Sun.COM 	return (test_condition_domain(condition, domainname, cur_domainname));
31311767SAnurag.Maskey@Sun.COM }
31411767SAnurag.Maskey@Sun.COM 
31511767SAnurag.Maskey@Sun.COM static boolean_t
test_condition_adv_domain(nwam_condition_t condition,const char * domainname)31611767SAnurag.Maskey@Sun.COM test_condition_adv_domain(nwam_condition_t condition, const char *domainname)
31711767SAnurag.Maskey@Sun.COM {
31811767SAnurag.Maskey@Sun.COM 	struct ncu_adv_domains *adv_domains = NULL;
31911767SAnurag.Maskey@Sun.COM 	struct ncu_adv_domains *adp, *prev;
32011767SAnurag.Maskey@Sun.COM 	boolean_t positive, rtn;
32111767SAnurag.Maskey@Sun.COM 
32211767SAnurag.Maskey@Sun.COM 	(void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU, get_adv_domains,
32311767SAnurag.Maskey@Sun.COM 	    &adv_domains);
32411767SAnurag.Maskey@Sun.COM 
32511767SAnurag.Maskey@Sun.COM 	positive = (condition == NWAM_CONDITION_IS ||
32611767SAnurag.Maskey@Sun.COM 	    condition == NWAM_CONDITION_CONTAINS);
32711767SAnurag.Maskey@Sun.COM 
32811767SAnurag.Maskey@Sun.COM 	/*
32911767SAnurag.Maskey@Sun.COM 	 * Walk the advertised domain list.  Our test function tests one
33011767SAnurag.Maskey@Sun.COM 	 * single domain, but we're dealing with a list: if our condition
33111767SAnurag.Maskey@Sun.COM 	 * is positive ('is' or 'contains'), the test function for each
33211767SAnurag.Maskey@Sun.COM 	 * domain results are or'd together; if our condition is negative
33311767SAnurag.Maskey@Sun.COM 	 * ('is-not' or 'does-not-contain'), the test function results must
33411767SAnurag.Maskey@Sun.COM 	 * be and'd.  Thus our short-circuit exit value depends on our
33511767SAnurag.Maskey@Sun.COM 	 * condition: if the test function returns TRUE it implies immediate
33611767SAnurag.Maskey@Sun.COM 	 * success for a positive condition; if it returns FALSE it implies
33711767SAnurag.Maskey@Sun.COM 	 * immediate failure for a negative condition.
33811767SAnurag.Maskey@Sun.COM 	 */
33911767SAnurag.Maskey@Sun.COM 	adp = adv_domains;
34011767SAnurag.Maskey@Sun.COM 	while (adp != NULL) {
34111767SAnurag.Maskey@Sun.COM 		if ((test_condition_domain(condition, domainname,
34211767SAnurag.Maskey@Sun.COM 		    adp->dns_domain) == positive) ||
34311767SAnurag.Maskey@Sun.COM 		    (test_condition_domain(condition, domainname,
34411767SAnurag.Maskey@Sun.COM 		    adp->nis_domain) == positive)) {
34511767SAnurag.Maskey@Sun.COM 			rtn = positive;
34611767SAnurag.Maskey@Sun.COM 			break;
34711767SAnurag.Maskey@Sun.COM 		}
34811767SAnurag.Maskey@Sun.COM 		adp = adp->next;
34911767SAnurag.Maskey@Sun.COM 	}
35011767SAnurag.Maskey@Sun.COM 	if (adp == NULL) {
35111767SAnurag.Maskey@Sun.COM 		/*
35211767SAnurag.Maskey@Sun.COM 		 * We did not short-circuit; we therefore failed if our
35311767SAnurag.Maskey@Sun.COM 		 * condition was positive, and succeeded if our condition
35411767SAnurag.Maskey@Sun.COM 		 * was negative.
35511767SAnurag.Maskey@Sun.COM 		 */
35611767SAnurag.Maskey@Sun.COM 		rtn = !positive;
35711767SAnurag.Maskey@Sun.COM 	}
35811767SAnurag.Maskey@Sun.COM 
35911767SAnurag.Maskey@Sun.COM 	/* now free the domain list */
36011767SAnurag.Maskey@Sun.COM 	adp = adv_domains;
36111767SAnurag.Maskey@Sun.COM 	while (adp != NULL) {
36211767SAnurag.Maskey@Sun.COM 		prev = adp;
36311767SAnurag.Maskey@Sun.COM 		adp = prev->next;
36411767SAnurag.Maskey@Sun.COM 		free(prev->dns_domain);
36511767SAnurag.Maskey@Sun.COM 		free(prev->nis_domain);
36611767SAnurag.Maskey@Sun.COM 		free(prev);
36711767SAnurag.Maskey@Sun.COM 	}
36811767SAnurag.Maskey@Sun.COM 
36911767SAnurag.Maskey@Sun.COM 	return (rtn);
37011767SAnurag.Maskey@Sun.COM }
37111767SAnurag.Maskey@Sun.COM 
37211767SAnurag.Maskey@Sun.COM /*
37311767SAnurag.Maskey@Sun.COM  * Returns true if prefixlen bits of addr1 match prefixlen bits of addr2.
37411767SAnurag.Maskey@Sun.COM  */
37511767SAnurag.Maskey@Sun.COM static boolean_t
prefixmatch(uchar_t * addr1,uchar_t * addr2,int prefixlen)37611767SAnurag.Maskey@Sun.COM prefixmatch(uchar_t *addr1, uchar_t *addr2, int prefixlen)
37711767SAnurag.Maskey@Sun.COM {
37811767SAnurag.Maskey@Sun.COM 	uchar_t mask[IPV6_ABITS/8];
37911767SAnurag.Maskey@Sun.COM 	int i, j = 0;
38011767SAnurag.Maskey@Sun.COM 
38111767SAnurag.Maskey@Sun.COM 	if (prefixlen == 0)
38211767SAnurag.Maskey@Sun.COM 		return (B_TRUE);
38311767SAnurag.Maskey@Sun.COM 
38411767SAnurag.Maskey@Sun.COM 	while (prefixlen > 0) {
38511767SAnurag.Maskey@Sun.COM 		if (prefixlen >= 8) {
38611767SAnurag.Maskey@Sun.COM 			mask[j++] = 0xFF;
38711767SAnurag.Maskey@Sun.COM 			prefixlen -= 8;
38811767SAnurag.Maskey@Sun.COM 		} else {
38911767SAnurag.Maskey@Sun.COM 			mask[j] |= 1 << (8 - prefixlen);
39011767SAnurag.Maskey@Sun.COM 			prefixlen--;
39111767SAnurag.Maskey@Sun.COM 		}
39211767SAnurag.Maskey@Sun.COM 	}
39311767SAnurag.Maskey@Sun.COM 	/* Ensure at least one byte is tested */
39411767SAnurag.Maskey@Sun.COM 	if (j == 0) j++;
39511767SAnurag.Maskey@Sun.COM 
39611767SAnurag.Maskey@Sun.COM 	for (i = 0; i < j; i++) {
39711767SAnurag.Maskey@Sun.COM 		if ((addr1[i] & mask[i]) != (addr2[i] & mask[i]))
39811767SAnurag.Maskey@Sun.COM 			return (B_FALSE);
39911767SAnurag.Maskey@Sun.COM 	}
40011767SAnurag.Maskey@Sun.COM 	return (B_TRUE);
40111767SAnurag.Maskey@Sun.COM }
40211767SAnurag.Maskey@Sun.COM 
40312576SAnurag.Maskey@Oracle.COM /*
40412576SAnurag.Maskey@Oracle.COM  * Given a string representation of an IPv4 or IPv6 address returns the
40512576SAnurag.Maskey@Oracle.COM  * sockaddr representation. Note that 'sockaddr' should point at the correct
40612576SAnurag.Maskey@Oracle.COM  * sockaddr structure for the address family (sockaddr_in for AF_INET or
40712576SAnurag.Maskey@Oracle.COM  * sockaddr_in6 for AF_INET6) or alternatively at a sockaddr_storage
40812576SAnurag.Maskey@Oracle.COM  * structure.
40912576SAnurag.Maskey@Oracle.COM  */
41012576SAnurag.Maskey@Oracle.COM static struct sockaddr_storage *
nwamd_str2sockaddr(sa_family_t af,const char * straddr,struct sockaddr_storage * addr)41112576SAnurag.Maskey@Oracle.COM nwamd_str2sockaddr(sa_family_t af, const char *straddr,
41212576SAnurag.Maskey@Oracle.COM     struct sockaddr_storage *addr)
41312576SAnurag.Maskey@Oracle.COM {
41412576SAnurag.Maskey@Oracle.COM 	struct sockaddr_in *sin;
41512576SAnurag.Maskey@Oracle.COM 	struct sockaddr_in6 *sin6;
41612576SAnurag.Maskey@Oracle.COM 	int err;
41712576SAnurag.Maskey@Oracle.COM 
41812576SAnurag.Maskey@Oracle.COM 	if (af == AF_INET) {
41912576SAnurag.Maskey@Oracle.COM 		sin = (struct sockaddr_in *)addr;
42012576SAnurag.Maskey@Oracle.COM 		sin->sin_family = AF_INET;
42112576SAnurag.Maskey@Oracle.COM 		err = inet_pton(AF_INET, straddr, &sin->sin_addr);
42212576SAnurag.Maskey@Oracle.COM 	} else if (af == AF_INET6) {
42312576SAnurag.Maskey@Oracle.COM 		sin6 = (struct sockaddr_in6 *)addr;
42412576SAnurag.Maskey@Oracle.COM 		sin6->sin6_family = AF_INET6;
42512576SAnurag.Maskey@Oracle.COM 		err = inet_pton(AF_INET6, straddr, &sin6->sin6_addr);
42612576SAnurag.Maskey@Oracle.COM 	} else {
42712576SAnurag.Maskey@Oracle.COM 		errno = EINVAL;
42812576SAnurag.Maskey@Oracle.COM 		return (NULL);
42912576SAnurag.Maskey@Oracle.COM 	}
43012576SAnurag.Maskey@Oracle.COM 	return (err == 1 ? addr : NULL);
43112576SAnurag.Maskey@Oracle.COM }
43212576SAnurag.Maskey@Oracle.COM 
43311767SAnurag.Maskey@Sun.COM struct nwamd_ipaddr_condition_walk_arg {
43411767SAnurag.Maskey@Sun.COM 	nwam_condition_t condition;
43511767SAnurag.Maskey@Sun.COM 	struct sockaddr_storage sockaddr;
43611767SAnurag.Maskey@Sun.COM 	int prefixlen;
43711767SAnurag.Maskey@Sun.COM 	boolean_t res;
43811767SAnurag.Maskey@Sun.COM };
43911767SAnurag.Maskey@Sun.COM 
44011767SAnurag.Maskey@Sun.COM static int
check_ipaddr(sa_family_t family,struct ifaddrs * ifa,void * arg)44112576SAnurag.Maskey@Oracle.COM check_ipaddr(sa_family_t family, struct ifaddrs *ifa, void *arg)
44211767SAnurag.Maskey@Sun.COM {
44311767SAnurag.Maskey@Sun.COM 	struct nwamd_ipaddr_condition_walk_arg *wa = arg;
444*12805SDarren.Reed@Oracle.COM 	struct sockaddr_in6 addr6;
445*12805SDarren.Reed@Oracle.COM 	struct sockaddr_in addr;
44611767SAnurag.Maskey@Sun.COM 	boolean_t match = B_FALSE;
44711767SAnurag.Maskey@Sun.COM 	uchar_t *addr1, *addr2;
44811767SAnurag.Maskey@Sun.COM 
44912576SAnurag.Maskey@Oracle.COM 	if (family == AF_INET) {
450*12805SDarren.Reed@Oracle.COM 		(void) memcpy(&addr, ifa->ifa_addr, sizeof (addr));
451*12805SDarren.Reed@Oracle.COM 		addr1 = (uchar_t *)(&addr.sin_addr.s_addr);
45211767SAnurag.Maskey@Sun.COM 		addr2 = (uchar_t *)&(((struct sockaddr_in *)
45311767SAnurag.Maskey@Sun.COM 		    &(wa->sockaddr))->sin_addr.s_addr);
45411767SAnurag.Maskey@Sun.COM 	} else {
455*12805SDarren.Reed@Oracle.COM 		(void) memcpy(&addr6, ifa->ifa_addr, sizeof (addr6));
456*12805SDarren.Reed@Oracle.COM 		addr1 = (uchar_t *)(&addr6.sin6_addr.s6_addr);
45711767SAnurag.Maskey@Sun.COM 		addr2 = (uchar_t *)&(((struct sockaddr_in6 *)
45811767SAnurag.Maskey@Sun.COM 		    &(wa->sockaddr))->sin6_addr.s6_addr);
45911767SAnurag.Maskey@Sun.COM 	}
46011767SAnurag.Maskey@Sun.COM 
46111767SAnurag.Maskey@Sun.COM 	match = prefixmatch(addr1, addr2, wa->prefixlen);
46211767SAnurag.Maskey@Sun.COM 
46311767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "check_ipaddr: match %d\n", match);
46411767SAnurag.Maskey@Sun.COM 	switch (wa->condition) {
46511767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS:
46611767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS_IN_RANGE:
46711767SAnurag.Maskey@Sun.COM 		wa->res = match;
46811767SAnurag.Maskey@Sun.COM 		if (match)
46911767SAnurag.Maskey@Sun.COM 			return (1);
47011767SAnurag.Maskey@Sun.COM 		return (0);
47111767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS_NOT:
47211767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS_NOT_IN_RANGE:
47311767SAnurag.Maskey@Sun.COM 		wa->res = !match;
47411767SAnurag.Maskey@Sun.COM 		return (0);
47511767SAnurag.Maskey@Sun.COM 	default:
47611767SAnurag.Maskey@Sun.COM 		return (0);
47711767SAnurag.Maskey@Sun.COM 	}
47811767SAnurag.Maskey@Sun.COM }
47911767SAnurag.Maskey@Sun.COM 
48011767SAnurag.Maskey@Sun.COM static boolean_t
test_condition_ip_address(nwam_condition_t condition,const char * ip_address_string)48111767SAnurag.Maskey@Sun.COM test_condition_ip_address(nwam_condition_t condition,
48211767SAnurag.Maskey@Sun.COM     const char *ip_address_string)
48311767SAnurag.Maskey@Sun.COM {
48412576SAnurag.Maskey@Oracle.COM 	sa_family_t family;
48511767SAnurag.Maskey@Sun.COM 	char *copy, *ip_address, *prefixlen_string, *lasts;
48611767SAnurag.Maskey@Sun.COM 	struct nwamd_ipaddr_condition_walk_arg wa;
48712576SAnurag.Maskey@Oracle.COM 	struct ifaddrs *ifap, *ifa;
48811767SAnurag.Maskey@Sun.COM 
48911767SAnurag.Maskey@Sun.COM 	if ((copy = strdup(ip_address_string)) == NULL)
49011767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
49111767SAnurag.Maskey@Sun.COM 
49211767SAnurag.Maskey@Sun.COM 	if ((ip_address = strtok_r(copy, " \t/", &lasts)) == NULL) {
49311767SAnurag.Maskey@Sun.COM 		free(copy);
49411767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
49511767SAnurag.Maskey@Sun.COM 	}
49611767SAnurag.Maskey@Sun.COM 
49711767SAnurag.Maskey@Sun.COM 	prefixlen_string = strtok_r(NULL, " \t", &lasts);
49811767SAnurag.Maskey@Sun.COM 
49912576SAnurag.Maskey@Oracle.COM 	if (nwamd_str2sockaddr(AF_INET, ip_address, &wa.sockaddr) != NULL) {
50012576SAnurag.Maskey@Oracle.COM 		family = AF_INET;
50111767SAnurag.Maskey@Sun.COM 		wa.prefixlen = IP_ABITS;
50212576SAnurag.Maskey@Oracle.COM 	} else if (nwamd_str2sockaddr(AF_INET6, ip_address, &wa.sockaddr)
50312576SAnurag.Maskey@Oracle.COM 	    != NULL) {
50412576SAnurag.Maskey@Oracle.COM 		family = AF_INET6;
50511767SAnurag.Maskey@Sun.COM 		wa.prefixlen = IPV6_ABITS;
50611767SAnurag.Maskey@Sun.COM 	} else {
50711767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "test_condition_ip_address: "
50812576SAnurag.Maskey@Oracle.COM 		    "nwamd_str2sockaddr failed for %s: %s", ip_address,
50912576SAnurag.Maskey@Oracle.COM 		    strerror(errno));
51011767SAnurag.Maskey@Sun.COM 		free(copy);
51111767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
51211767SAnurag.Maskey@Sun.COM 	}
51311767SAnurag.Maskey@Sun.COM 
51411767SAnurag.Maskey@Sun.COM 	if (prefixlen_string != NULL)
51511767SAnurag.Maskey@Sun.COM 		wa.prefixlen = atoi(prefixlen_string);
51611767SAnurag.Maskey@Sun.COM 
51711767SAnurag.Maskey@Sun.COM 	wa.condition = condition;
51811767SAnurag.Maskey@Sun.COM 
51911767SAnurag.Maskey@Sun.COM 	switch (condition) {
52011767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS:
52111767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS_IN_RANGE:
52211767SAnurag.Maskey@Sun.COM 		wa.res = B_FALSE;
52311767SAnurag.Maskey@Sun.COM 		break;
52411767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS_NOT:
52511767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS_NOT_IN_RANGE:
52611767SAnurag.Maskey@Sun.COM 		wa.res = B_TRUE;
52711767SAnurag.Maskey@Sun.COM 		break;
52811767SAnurag.Maskey@Sun.COM 	default:
52911767SAnurag.Maskey@Sun.COM 		free(copy);
53011767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
53111767SAnurag.Maskey@Sun.COM 	}
53212576SAnurag.Maskey@Oracle.COM 	free(copy);
53311767SAnurag.Maskey@Sun.COM 
53412576SAnurag.Maskey@Oracle.COM 	if (getifaddrs(&ifa) == -1) {
53512576SAnurag.Maskey@Oracle.COM 		nlog(LOG_ERR, "test_condition_ip_address: "
53612576SAnurag.Maskey@Oracle.COM 		    "getifaddrs failed: %s", strerror(errno));
53712576SAnurag.Maskey@Oracle.COM 		return (wa.res);
53812576SAnurag.Maskey@Oracle.COM 	}
53912576SAnurag.Maskey@Oracle.COM 	for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
540*12805SDarren.Reed@Oracle.COM 		if (ifap->ifa_addr->sa_family != family)
54112576SAnurag.Maskey@Oracle.COM 			continue;
54212576SAnurag.Maskey@Oracle.COM 		if (check_ipaddr(family, ifap, &wa) == 1)
54312576SAnurag.Maskey@Oracle.COM 			break;
54412576SAnurag.Maskey@Oracle.COM 	}
54512576SAnurag.Maskey@Oracle.COM 	freeifaddrs(ifa);
54611767SAnurag.Maskey@Sun.COM 
54711767SAnurag.Maskey@Sun.COM 	return (wa.res);
54811767SAnurag.Maskey@Sun.COM }
54911767SAnurag.Maskey@Sun.COM 
55011767SAnurag.Maskey@Sun.COM struct nwamd_wlan_condition_walk_arg {
55111767SAnurag.Maskey@Sun.COM 	nwam_condition_t condition;
55211767SAnurag.Maskey@Sun.COM 	const char *exp_essid;
55311767SAnurag.Maskey@Sun.COM 	const char *exp_bssid;
55411767SAnurag.Maskey@Sun.COM 	uint_t num_connected;
55511767SAnurag.Maskey@Sun.COM 	boolean_t res;
55611767SAnurag.Maskey@Sun.COM };
55711767SAnurag.Maskey@Sun.COM 
55811767SAnurag.Maskey@Sun.COM static int
check_wlan(const char * linkname,void * arg)55911767SAnurag.Maskey@Sun.COM check_wlan(const char *linkname, void *arg)
56011767SAnurag.Maskey@Sun.COM {
56111767SAnurag.Maskey@Sun.COM 	struct nwamd_wlan_condition_walk_arg *wa = arg;
56211767SAnurag.Maskey@Sun.COM 	datalink_id_t linkid;
56311767SAnurag.Maskey@Sun.COM 	dladm_wlan_linkattr_t attr;
56411767SAnurag.Maskey@Sun.COM 	dladm_status_t status;
56511767SAnurag.Maskey@Sun.COM 	char cur_essid[DLADM_STRSIZE];
56611767SAnurag.Maskey@Sun.COM 	char cur_bssid[DLADM_STRSIZE];
56711767SAnurag.Maskey@Sun.COM 	char errmsg[DLADM_STRSIZE];
56811767SAnurag.Maskey@Sun.COM 
56911767SAnurag.Maskey@Sun.COM 	if ((status = dladm_name2info(dld_handle, linkname, &linkid, NULL, NULL,
57011767SAnurag.Maskey@Sun.COM 	    NULL)) != DLADM_STATUS_OK) {
57111767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "check_wlan: dladm_name2info() for %s "
57211767SAnurag.Maskey@Sun.COM 		    "failed: %s", linkname,
57311767SAnurag.Maskey@Sun.COM 		    dladm_status2str(status, errmsg));
57411767SAnurag.Maskey@Sun.COM 		return (DLADM_WALK_CONTINUE);
57511767SAnurag.Maskey@Sun.COM 	}
57611767SAnurag.Maskey@Sun.COM 
57711767SAnurag.Maskey@Sun.COM 	status = dladm_wlan_get_linkattr(dld_handle, linkid, &attr);
57811767SAnurag.Maskey@Sun.COM 	if (status != DLADM_STATUS_OK) {
57911767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "check_wlan: dladm_wlan_get_linkattr() for %s "
58011767SAnurag.Maskey@Sun.COM 		    "failed: %s", linkname,
58111767SAnurag.Maskey@Sun.COM 		    dladm_status2str(status, errmsg));
58211767SAnurag.Maskey@Sun.COM 		return (DLADM_WALK_CONTINUE);
58311767SAnurag.Maskey@Sun.COM 	}
58411767SAnurag.Maskey@Sun.COM 	if (attr.la_status == DLADM_WLAN_LINK_DISCONNECTED)
58511767SAnurag.Maskey@Sun.COM 		return (DLADM_WALK_TERMINATE);
58611767SAnurag.Maskey@Sun.COM 
58711767SAnurag.Maskey@Sun.COM 	wa->num_connected++;
58811767SAnurag.Maskey@Sun.COM 
58911767SAnurag.Maskey@Sun.COM 	if (wa->exp_essid != NULL) {
59011767SAnurag.Maskey@Sun.COM 		/* Is the NIC associated with the expected access point? */
59111767SAnurag.Maskey@Sun.COM 		(void) dladm_wlan_essid2str(&attr.la_wlan_attr.wa_essid,
59211767SAnurag.Maskey@Sun.COM 		    cur_essid);
59311767SAnurag.Maskey@Sun.COM 		switch (wa->condition) {
59411767SAnurag.Maskey@Sun.COM 		case NWAM_CONDITION_IS:
59511767SAnurag.Maskey@Sun.COM 			wa->res = strcmp(cur_essid, wa->exp_essid) == 0;
59611767SAnurag.Maskey@Sun.COM 			if (wa->res)
59711767SAnurag.Maskey@Sun.COM 				return (DLADM_WALK_TERMINATE);
59811767SAnurag.Maskey@Sun.COM 			break;
59911767SAnurag.Maskey@Sun.COM 		case NWAM_CONDITION_IS_NOT:
60011767SAnurag.Maskey@Sun.COM 			wa->res = strcmp(cur_essid, wa->exp_essid) != 0;
60111767SAnurag.Maskey@Sun.COM 			if (!wa->res)
60211767SAnurag.Maskey@Sun.COM 				return (DLADM_WALK_TERMINATE);
60311767SAnurag.Maskey@Sun.COM 			break;
60411767SAnurag.Maskey@Sun.COM 		case NWAM_CONDITION_CONTAINS:
60511767SAnurag.Maskey@Sun.COM 			wa->res = strstr(cur_essid, wa->exp_essid) != NULL;
60611767SAnurag.Maskey@Sun.COM 			if (wa->res)
60711767SAnurag.Maskey@Sun.COM 				return (DLADM_WALK_TERMINATE);
60811767SAnurag.Maskey@Sun.COM 			break;
60911767SAnurag.Maskey@Sun.COM 		case NWAM_CONDITION_DOES_NOT_CONTAIN:
61011767SAnurag.Maskey@Sun.COM 			wa->res = strstr(cur_essid, wa->exp_essid) == NULL;
61111767SAnurag.Maskey@Sun.COM 			if (!wa->res)
61211767SAnurag.Maskey@Sun.COM 				return (DLADM_WALK_TERMINATE);
61311767SAnurag.Maskey@Sun.COM 			break;
61411767SAnurag.Maskey@Sun.COM 		default:
61511767SAnurag.Maskey@Sun.COM 			return (DLADM_WALK_TERMINATE);
61611767SAnurag.Maskey@Sun.COM 		}
61711767SAnurag.Maskey@Sun.COM 		return (DLADM_WALK_CONTINUE);
61811767SAnurag.Maskey@Sun.COM 	}
61911767SAnurag.Maskey@Sun.COM 	if (wa->exp_bssid != NULL) {
62011767SAnurag.Maskey@Sun.COM 		/* Is the NIC associated with the expected access point? */
62111767SAnurag.Maskey@Sun.COM 		(void) dladm_wlan_bssid2str(&attr.la_wlan_attr.wa_bssid,
62211767SAnurag.Maskey@Sun.COM 		    cur_bssid);
62311767SAnurag.Maskey@Sun.COM 		switch (wa->condition) {
62411767SAnurag.Maskey@Sun.COM 		case NWAM_CONDITION_IS:
62511767SAnurag.Maskey@Sun.COM 			wa->res = strcmp(cur_bssid, wa->exp_bssid) == 0;
62611767SAnurag.Maskey@Sun.COM 			if (wa->res)
62711767SAnurag.Maskey@Sun.COM 				return (DLADM_WALK_TERMINATE);
62811767SAnurag.Maskey@Sun.COM 			break;
62911767SAnurag.Maskey@Sun.COM 		case NWAM_CONDITION_IS_NOT:
63011767SAnurag.Maskey@Sun.COM 			wa->res = strcmp(cur_bssid, wa->exp_bssid) != 0;
63111767SAnurag.Maskey@Sun.COM 			if (!wa->res)
63211767SAnurag.Maskey@Sun.COM 				return (DLADM_WALK_TERMINATE);
63311767SAnurag.Maskey@Sun.COM 			break;
63411767SAnurag.Maskey@Sun.COM 		default:
63511767SAnurag.Maskey@Sun.COM 			return (DLADM_WALK_TERMINATE);
63611767SAnurag.Maskey@Sun.COM 		}
63711767SAnurag.Maskey@Sun.COM 		return (DLADM_WALK_CONTINUE);
63811767SAnurag.Maskey@Sun.COM 	}
63911767SAnurag.Maskey@Sun.COM 	/*
64011767SAnurag.Maskey@Sun.COM 	 * Neither an ESSID or BSSID match is required - being connected to a
64111767SAnurag.Maskey@Sun.COM 	 * WLAN is enough.
64211767SAnurag.Maskey@Sun.COM 	 */
64311767SAnurag.Maskey@Sun.COM 	switch (wa->condition) {
64411767SAnurag.Maskey@Sun.COM 	case NWAM_CONDITION_IS:
64511767SAnurag.Maskey@Sun.COM 		wa->res = B_TRUE;
64611767SAnurag.Maskey@Sun.COM 		return (DLADM_WALK_TERMINATE);
64711767SAnurag.Maskey@Sun.COM 	default:
64811767SAnurag.Maskey@Sun.COM 		wa->res = B_FALSE;
64911767SAnurag.Maskey@Sun.COM 		return (DLADM_WALK_TERMINATE);
65011767SAnurag.Maskey@Sun.COM 	}
65111767SAnurag.Maskey@Sun.COM 	/*NOTREACHED*/
65211767SAnurag.Maskey@Sun.COM 	return (DLADM_WALK_CONTINUE);
65311767SAnurag.Maskey@Sun.COM }
65411767SAnurag.Maskey@Sun.COM 
65511767SAnurag.Maskey@Sun.COM static boolean_t
test_condition_wireless_essid(nwam_condition_t condition,const char * essid)65611767SAnurag.Maskey@Sun.COM test_condition_wireless_essid(nwam_condition_t condition,
65711767SAnurag.Maskey@Sun.COM     const char *essid)
65811767SAnurag.Maskey@Sun.COM {
65911767SAnurag.Maskey@Sun.COM 	struct nwamd_wlan_condition_walk_arg wa;
66011767SAnurag.Maskey@Sun.COM 
66111767SAnurag.Maskey@Sun.COM 	wa.condition = condition;
66211767SAnurag.Maskey@Sun.COM 	wa.exp_essid = essid;
66311767SAnurag.Maskey@Sun.COM 	wa.exp_bssid = NULL;
66411767SAnurag.Maskey@Sun.COM 	wa.num_connected = 0;
66511767SAnurag.Maskey@Sun.COM 	wa.res = B_FALSE;
66611767SAnurag.Maskey@Sun.COM 
66711767SAnurag.Maskey@Sun.COM 	(void) dladm_walk(check_wlan, dld_handle, &wa, DATALINK_CLASS_PHYS,
66811767SAnurag.Maskey@Sun.COM 	    DL_WIFI, DLADM_OPT_ACTIVE);
66911767SAnurag.Maskey@Sun.COM 
67011767SAnurag.Maskey@Sun.COM 	return (wa.num_connected > 0 && wa.res == B_TRUE);
67111767SAnurag.Maskey@Sun.COM }
67211767SAnurag.Maskey@Sun.COM 
67311767SAnurag.Maskey@Sun.COM static boolean_t
test_condition_wireless_bssid(nwam_condition_t condition,const char * bssid)67411767SAnurag.Maskey@Sun.COM test_condition_wireless_bssid(nwam_condition_t condition,
67511767SAnurag.Maskey@Sun.COM     const char *bssid)
67611767SAnurag.Maskey@Sun.COM {
67711767SAnurag.Maskey@Sun.COM 	struct nwamd_wlan_condition_walk_arg wa;
67811767SAnurag.Maskey@Sun.COM 
67911767SAnurag.Maskey@Sun.COM 	wa.condition = condition;
68011767SAnurag.Maskey@Sun.COM 	wa.exp_bssid = bssid;
68111767SAnurag.Maskey@Sun.COM 	wa.exp_essid = NULL;
68211767SAnurag.Maskey@Sun.COM 	wa.num_connected = 0;
68311767SAnurag.Maskey@Sun.COM 	wa.res = B_FALSE;
68411767SAnurag.Maskey@Sun.COM 
68511767SAnurag.Maskey@Sun.COM 	(void) dladm_walk(check_wlan, dld_handle, &wa, DATALINK_CLASS_PHYS,
68611767SAnurag.Maskey@Sun.COM 	    DL_WIFI, DLADM_OPT_ACTIVE);
68711767SAnurag.Maskey@Sun.COM 
68811767SAnurag.Maskey@Sun.COM 	return (wa.num_connected > 0 && wa.res == B_TRUE);
68911767SAnurag.Maskey@Sun.COM }
69011767SAnurag.Maskey@Sun.COM 
69111767SAnurag.Maskey@Sun.COM /*
69211767SAnurag.Maskey@Sun.COM  * This function takes an activation mode and a string representation of a
69311767SAnurag.Maskey@Sun.COM  * condition and evaluates it.
69411767SAnurag.Maskey@Sun.COM  */
69511767SAnurag.Maskey@Sun.COM boolean_t
nwamd_check_conditions(nwam_activation_mode_t activation_mode,char ** condition_strings,uint_t num_conditions)69611767SAnurag.Maskey@Sun.COM nwamd_check_conditions(nwam_activation_mode_t activation_mode,
69711767SAnurag.Maskey@Sun.COM     char **condition_strings, uint_t num_conditions)
69811767SAnurag.Maskey@Sun.COM {
69911767SAnurag.Maskey@Sun.COM 	boolean_t ret;
70011767SAnurag.Maskey@Sun.COM 	nwam_condition_t condition;
70111767SAnurag.Maskey@Sun.COM 	nwam_condition_object_type_t object_type;
70211767SAnurag.Maskey@Sun.COM 	char *object_name;
70311767SAnurag.Maskey@Sun.COM 	int i, j;
70411767SAnurag.Maskey@Sun.COM 
70511767SAnurag.Maskey@Sun.COM 	for (i = 0; i < num_conditions; i++) {
70611767SAnurag.Maskey@Sun.COM 
70711767SAnurag.Maskey@Sun.COM 		if (nwam_condition_string_to_condition(condition_strings[i],
70811767SAnurag.Maskey@Sun.COM 		    &object_type, &condition, &object_name) != NWAM_SUCCESS) {
70911767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "check_conditions: invalid condition %s",
71011767SAnurag.Maskey@Sun.COM 			    condition_strings[i]);
71111767SAnurag.Maskey@Sun.COM 			return (B_FALSE);
71211767SAnurag.Maskey@Sun.COM 		}
71311767SAnurag.Maskey@Sun.COM 		ret = B_FALSE;
71411767SAnurag.Maskey@Sun.COM 
71511767SAnurag.Maskey@Sun.COM 		for (j = 0; j < (sizeof (condition_map) /
71611767SAnurag.Maskey@Sun.COM 		    sizeof (struct nwamd_condition_map)); j++) {
71711767SAnurag.Maskey@Sun.COM 			if (condition_map[j].object_type == object_type)
71811767SAnurag.Maskey@Sun.COM 				ret = condition_map[j].condition_func(condition,
71911767SAnurag.Maskey@Sun.COM 				    object_name);
72011767SAnurag.Maskey@Sun.COM 		}
72111767SAnurag.Maskey@Sun.COM 
72211767SAnurag.Maskey@Sun.COM 		free(object_name);
72311767SAnurag.Maskey@Sun.COM 
72411767SAnurag.Maskey@Sun.COM 		if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ANY &&
72511767SAnurag.Maskey@Sun.COM 		    ret) {
72611767SAnurag.Maskey@Sun.COM 			return (B_TRUE);
72711767SAnurag.Maskey@Sun.COM 		}
72811767SAnurag.Maskey@Sun.COM 		if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ALL &&
72911767SAnurag.Maskey@Sun.COM 		    !ret) {
73011767SAnurag.Maskey@Sun.COM 			return (B_FALSE);
73111767SAnurag.Maskey@Sun.COM 		}
73211767SAnurag.Maskey@Sun.COM 	}
73311767SAnurag.Maskey@Sun.COM 	if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ANY && ret)
73411767SAnurag.Maskey@Sun.COM 		return (B_TRUE);
73511767SAnurag.Maskey@Sun.COM 	if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ALL && ret)
73611767SAnurag.Maskey@Sun.COM 		return (B_TRUE);
73711767SAnurag.Maskey@Sun.COM 
73811767SAnurag.Maskey@Sun.COM 	return (B_FALSE);
73911767SAnurag.Maskey@Sun.COM }
74011767SAnurag.Maskey@Sun.COM 
74111767SAnurag.Maskey@Sun.COM /*
74211767SAnurag.Maskey@Sun.COM  * In rating activation conditions, we take the best-rated CONDITIONAL_ANY
74311767SAnurag.Maskey@Sun.COM  * condition, or sum all the CONDITIONAL_ALL condition ratings. This allows
74411767SAnurag.Maskey@Sun.COM  * us to compare between location activation conditions to pick the best.
74511767SAnurag.Maskey@Sun.COM  */
74611767SAnurag.Maskey@Sun.COM uint64_t
nwamd_rate_conditions(nwam_activation_mode_t activation_mode,char ** conditions,uint_t num_conditions)74711767SAnurag.Maskey@Sun.COM nwamd_rate_conditions(nwam_activation_mode_t activation_mode,
74811767SAnurag.Maskey@Sun.COM     char **conditions, uint_t num_conditions)
74911767SAnurag.Maskey@Sun.COM {
75011767SAnurag.Maskey@Sun.COM 	nwam_condition_t condition;
75111767SAnurag.Maskey@Sun.COM 	nwam_condition_object_type_t object_type;
75211767SAnurag.Maskey@Sun.COM 	char *object_name;
75311767SAnurag.Maskey@Sun.COM 	int i;
75411767SAnurag.Maskey@Sun.COM 	uint64_t rating = 0, total_rating = 0;
75511767SAnurag.Maskey@Sun.COM 
75611767SAnurag.Maskey@Sun.COM 	for (i = 0; i < num_conditions; i++) {
75711767SAnurag.Maskey@Sun.COM 
75811767SAnurag.Maskey@Sun.COM 		object_name = NULL;
75911767SAnurag.Maskey@Sun.COM 		if (nwam_condition_string_to_condition(conditions[i],
76011767SAnurag.Maskey@Sun.COM 		    &object_type, &condition, &object_name) != NWAM_SUCCESS ||
76111767SAnurag.Maskey@Sun.COM 		    nwam_condition_rate(object_type, condition, &rating)
76211767SAnurag.Maskey@Sun.COM 		    != NWAM_SUCCESS) {
76311767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "nwamd_rate_conditions: could not rate "
76411767SAnurag.Maskey@Sun.COM 			    "condition");
76511767SAnurag.Maskey@Sun.COM 			free(object_name);
76611767SAnurag.Maskey@Sun.COM 			return (0);
76711767SAnurag.Maskey@Sun.COM 		}
76811767SAnurag.Maskey@Sun.COM 		free(object_name);
76911767SAnurag.Maskey@Sun.COM 
77011767SAnurag.Maskey@Sun.COM 		if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ANY) {
77111767SAnurag.Maskey@Sun.COM 			if (rating > total_rating)
77211767SAnurag.Maskey@Sun.COM 				total_rating = rating;
77311767SAnurag.Maskey@Sun.COM 		} else if (activation_mode ==
77411767SAnurag.Maskey@Sun.COM 		    NWAM_ACTIVATION_MODE_CONDITIONAL_ALL) {
77511767SAnurag.Maskey@Sun.COM 			total_rating += rating;
77611767SAnurag.Maskey@Sun.COM 		}
77711767SAnurag.Maskey@Sun.COM 	}
77811767SAnurag.Maskey@Sun.COM 	return (total_rating);
77911767SAnurag.Maskey@Sun.COM }
78011767SAnurag.Maskey@Sun.COM 
78111767SAnurag.Maskey@Sun.COM /*
78211767SAnurag.Maskey@Sun.COM  * Different from nwamd_triggered_check_all_conditions() in that this
78311767SAnurag.Maskey@Sun.COM  * function enqueues a timed check event.
78411767SAnurag.Maskey@Sun.COM  */
78511767SAnurag.Maskey@Sun.COM void
nwamd_set_timed_check_all_conditions(void)78611767SAnurag.Maskey@Sun.COM nwamd_set_timed_check_all_conditions(void)
78711767SAnurag.Maskey@Sun.COM {
78811767SAnurag.Maskey@Sun.COM 	nwamd_event_t check_event = nwamd_event_init
78911767SAnurag.Maskey@Sun.COM 	    (NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS, NWAM_OBJECT_TYPE_UNKNOWN,
79011767SAnurag.Maskey@Sun.COM 	    0, NULL);
79111767SAnurag.Maskey@Sun.COM 	if (check_event != NULL) {
79211767SAnurag.Maskey@Sun.COM 		/* Add another timed event to recheck conditions */
79311767SAnurag.Maskey@Sun.COM 		nwamd_event_enqueue_timed(check_event,
79411767SAnurag.Maskey@Sun.COM 		    condition_check_interval > CONDITION_CHECK_INTERVAL_MIN ?
79511767SAnurag.Maskey@Sun.COM 		    condition_check_interval : CONDITION_CHECK_INTERVAL_MIN);
79611767SAnurag.Maskey@Sun.COM 	}
79711767SAnurag.Maskey@Sun.COM }
79811767SAnurag.Maskey@Sun.COM 
79911767SAnurag.Maskey@Sun.COM /*
80011767SAnurag.Maskey@Sun.COM  * Does not enqueue another check event.
80111767SAnurag.Maskey@Sun.COM  */
80211767SAnurag.Maskey@Sun.COM void
nwamd_check_all_conditions(void)80311767SAnurag.Maskey@Sun.COM nwamd_check_all_conditions(void)
80411767SAnurag.Maskey@Sun.COM {
80511767SAnurag.Maskey@Sun.COM 	nwamd_enm_check_conditions();
80611767SAnurag.Maskey@Sun.COM 	nwamd_loc_check_conditions();
80711767SAnurag.Maskey@Sun.COM }
80811767SAnurag.Maskey@Sun.COM 
80911767SAnurag.Maskey@Sun.COM void
nwamd_create_timed_condition_check_event(void)81011767SAnurag.Maskey@Sun.COM nwamd_create_timed_condition_check_event(void)
81111767SAnurag.Maskey@Sun.COM {
81211767SAnurag.Maskey@Sun.COM 	nwamd_event_t check_event = nwamd_event_init
81311767SAnurag.Maskey@Sun.COM 	    (NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS, NWAM_OBJECT_TYPE_UNKNOWN,
81411767SAnurag.Maskey@Sun.COM 	    0, NULL);
81511767SAnurag.Maskey@Sun.COM 	if (check_event != NULL)
81611767SAnurag.Maskey@Sun.COM 		nwamd_event_enqueue(check_event);
81711767SAnurag.Maskey@Sun.COM }
81811767SAnurag.Maskey@Sun.COM 
81911767SAnurag.Maskey@Sun.COM void
nwamd_create_triggered_condition_check_event(uint32_t when)82011767SAnurag.Maskey@Sun.COM nwamd_create_triggered_condition_check_event(uint32_t when)
82111767SAnurag.Maskey@Sun.COM {
82211767SAnurag.Maskey@Sun.COM 	nwamd_event_t check_event;
82311767SAnurag.Maskey@Sun.COM 
82411767SAnurag.Maskey@Sun.COM 	if (!nwamd_event_enqueued(NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS,
82511767SAnurag.Maskey@Sun.COM 	    NWAM_OBJECT_TYPE_UNKNOWN, NULL)) {
82611767SAnurag.Maskey@Sun.COM 		check_event = nwamd_event_init
82711767SAnurag.Maskey@Sun.COM 		    (NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS,
82811767SAnurag.Maskey@Sun.COM 		    NWAM_OBJECT_TYPE_UNKNOWN, 0, NULL);
82911767SAnurag.Maskey@Sun.COM 		if (check_event != NULL)
83011767SAnurag.Maskey@Sun.COM 			nwamd_event_enqueue_timed(check_event, when);
83111767SAnurag.Maskey@Sun.COM 	}
83211767SAnurag.Maskey@Sun.COM }
833