xref: /onnv-gate/usr/src/cmd/cmd-inet/lib/nwamd/conditions.c (revision 12576:ab8aacaead3f)
1  /*
2   * CDDL HEADER START
3   *
4   * The contents of this file are subject to the terms of the
5   * Common Development and Distribution License (the "License").
6   * You may not use this file except in compliance with the License.
7   *
8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9   * or http://www.opensolaris.org/os/licensing.
10   * See the License for the specific language governing permissions
11   * and limitations under the License.
12   *
13   * When distributing Covered Code, include this CDDL HEADER in each
14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15   * If applicable, add the following below this CDDL HEADER, with the
16   * fields enclosed by brackets "[]" replaced with your own identifying
17   * information: Portions Copyright [yyyy] [name of copyright owner]
18   *
19   * CDDL HEADER END
20   */
21  
22  /*
23   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24   */
25  
26  #include <arpa/inet.h>
27  #include <ctype.h>
28  #include <errno.h>
29  #include <inet/ip.h>
30  #include <libdladm.h>
31  #include <libdllink.h>
32  #include <libdlwlan.h>
33  #include <netdb.h>
34  #include <stdio.h>
35  #include <stdlib.h>
36  #include <string.h>
37  
38  #include <libnwam.h>
39  #include "conditions.h"
40  #include "ncu.h"
41  #include "objects.h"
42  #include "util.h"
43  
44  /*
45   * conditions.c - contains routines which check state to see if activation
46   * conditions for NWAM objects are satisfied and rates activation conditions to
47   * help determine which is most specific.
48   *
49   * If the activation-mode is CONDITIONAL_ANY or CONDITIONAL_ALL, the conditions
50   * property is set to a string made up of conditional expressions. Each
51   * expression is made up of a condition that can be assigned a boolean value,
52   * e.g. "system-domain is sun.com" or "ncu ip:bge0 is-not active". If the
53   * activation-mode is CONDITIONAL_ANY, the condition will be satisfied if any
54   * one of the conditions is true; if the activation-mode is CONDITIONAL_ALL,
55   * the condition is satisfied only if all of the conditions are true.
56   */
57  
58  uint64_t condition_check_interval = CONDITION_CHECK_INTERVAL_DEFAULT;
59  
60  extern int getdomainname(char *, int);
61  
62  /* NCP, NCU, ENM and location conditions */
63  static boolean_t test_condition_ncp(nwam_condition_t condition,
64      const char *ncp_name);
65  static boolean_t test_condition_ncu(nwam_condition_t condition,
66      const char *ncu_name);
67  static boolean_t test_condition_enm(nwam_condition_t condition,
68      const char *enm_name);
69  static boolean_t test_condition_loc(nwam_condition_t condition,
70      const char *loc_name);
71  
72  /* IP address conditions */
73  static boolean_t test_condition_ip_address(nwam_condition_t condition,
74      const char *ip_address);
75  
76  /* domainname conditions */
77  static boolean_t test_condition_sys_domain(nwam_condition_t condition,
78      const char *domainname);
79  static boolean_t test_condition_adv_domain(nwam_condition_t condition,
80      const char *domainname);
81  
82  /*  WLAN conditions */
83  static boolean_t test_condition_wireless_essid(nwam_condition_t condition,
84      const char *essid);
85  static boolean_t test_condition_wireless_bssid(nwam_condition_t condition,
86      const char *essid);
87  
88  struct nwamd_condition_map {
89  	nwam_condition_object_type_t object_type;
90  	boolean_t (*condition_func)(nwam_condition_t, const char *);
91  } condition_map[] =
92  {
93  	{ NWAM_CONDITION_OBJECT_TYPE_NCP, test_condition_ncp },
94  	{ NWAM_CONDITION_OBJECT_TYPE_NCU, test_condition_ncu },
95  	{ NWAM_CONDITION_OBJECT_TYPE_ENM, test_condition_enm },
96  	{ NWAM_CONDITION_OBJECT_TYPE_LOC, test_condition_loc },
97  	{ NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS, test_condition_ip_address },
98  	{ NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN, test_condition_sys_domain },
99  	{ NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN, test_condition_adv_domain },
100  	{ NWAM_CONDITION_OBJECT_TYPE_ESSID, test_condition_wireless_essid },
101  	{ NWAM_CONDITION_OBJECT_TYPE_BSSID, test_condition_wireless_bssid }
102  };
103  
104  /*
105   * This function takes which kind of conditions (is or is not) we are testing
106   * the object against and an object and applies the conditon to the object.
107   */
108  static boolean_t
109  test_condition_object_state(nwam_condition_t condition,
110      nwam_object_type_t object_type, const char *object_name)
111  {
112  	nwamd_object_t object;
113  	nwam_state_t state;
114  
115  	object = nwamd_object_find(object_type, object_name);
116  	if (object == NULL)
117  		return (B_FALSE);
118  
119  	state = object->nwamd_object_state;
120  	nwamd_object_release(object);
121  
122  	switch (condition) {
123  	case NWAM_CONDITION_IS:
124  		return (state == NWAM_STATE_ONLINE);
125  	case NWAM_CONDITION_IS_NOT:
126  		return (state != NWAM_STATE_ONLINE);
127  	default:
128  		return (B_FALSE);
129  	}
130  }
131  
132  static boolean_t
133  test_condition_ncp(nwam_condition_t condition, const char *name)
134  {
135  	boolean_t active;
136  
137  	(void) pthread_mutex_lock(&active_ncp_mutex);
138  	active = (strcasecmp(active_ncp, name) == 0);
139  	(void) pthread_mutex_unlock(&active_ncp_mutex);
140  
141  	switch (condition) {
142  	case NWAM_CONDITION_IS:
143  		return (active);
144  	case NWAM_CONDITION_IS_NOT:
145  		return (active != B_TRUE);
146  	default:
147  		return (B_FALSE);
148  	}
149  }
150  
151  static boolean_t
152  test_condition_ncu(nwam_condition_t condition, const char *name)
153  {
154  	char *real_name, *ncu_name;
155  	nwam_ncu_handle_t ncuh;
156  	nwam_ncu_type_t ncu_type;
157  	boolean_t rv;
158  
159  	/* names are case-insensitive, so get real name from libnwam */
160  	if (nwam_ncu_read(active_ncph, name, NWAM_NCU_TYPE_INTERFACE, 0, &ncuh)
161  	    == NWAM_SUCCESS) {
162  		ncu_type = NWAM_NCU_TYPE_INTERFACE;
163  	} else if (nwam_ncu_read(active_ncph, name, NWAM_NCU_TYPE_LINK, 0,
164  	    &ncuh) == NWAM_SUCCESS) {
165  		ncu_type = NWAM_NCU_TYPE_LINK;
166  	} else {
167  		return (B_FALSE);
168  	}
169  	if (nwam_ncu_get_name(ncuh, &real_name) != NWAM_SUCCESS) {
170  		nwam_ncu_free(ncuh);
171  		return (B_FALSE);
172  	}
173  	nwam_ncu_free(ncuh);
174  
175  	/*
176  	 * Name may be either unqualified or qualified by NCU type
177  	 * (interface:/link:).  Need to translate unqualified names
178  	 * to qualified, specifying interface:name if an interface
179  	 * NCU is present, otherwise link:ncu.
180  	 */
181  	if (nwam_ncu_name_to_typed_name(real_name, ncu_type, &ncu_name)
182  	    != NWAM_SUCCESS) {
183  		free(real_name);
184  		return (B_FALSE);
185  	}
186  	free(real_name);
187  
188  	rv = test_condition_object_state(condition, NWAM_OBJECT_TYPE_NCU,
189  	    ncu_name);
190  	free(ncu_name);
191  	return (rv);
192  }
193  
194  static boolean_t
195  test_condition_enm(nwam_condition_t condition, const char *enm_name)
196  {
197  	nwam_enm_handle_t enmh;
198  	char *real_name;
199  	boolean_t rv;
200  
201  	/* names are case-insensitive, so get real name from libnwam */
202  	if (nwam_enm_read(enm_name, 0, &enmh) != NWAM_SUCCESS)
203  		return (B_FALSE);
204  	if (nwam_enm_get_name(enmh, &real_name) != NWAM_SUCCESS) {
205  		nwam_enm_free(enmh);
206  		return (B_FALSE);
207  	}
208  	nwam_enm_free(enmh);
209  
210  	rv = test_condition_object_state(condition, NWAM_OBJECT_TYPE_ENM,
211  	    real_name);
212  	free(real_name);
213  	return (rv);
214  }
215  
216  static boolean_t
217  test_condition_loc(nwam_condition_t condition, const char *loc_name)
218  {
219  	nwam_loc_handle_t loch;
220  	char *real_name;
221  	boolean_t rv;
222  
223  	/* names are case-insensitive, so get real name from libnwam */
224  	if (nwam_loc_read(loc_name, 0, &loch) != NWAM_SUCCESS)
225  		return (B_FALSE);
226  	if (nwam_loc_get_name(loch, &real_name) != NWAM_SUCCESS) {
227  		nwam_loc_free(loch);
228  		return (B_FALSE);
229  	}
230  	nwam_loc_free(loch);
231  
232  	rv = test_condition_object_state(condition, NWAM_OBJECT_TYPE_LOC,
233  	    real_name);
234  	free(real_name);
235  	return (rv);
236  }
237  
238  static boolean_t
239  test_condition_domain(nwam_condition_t condition, const char *target_domain,
240      const char *found_domain)
241  {
242  	int i, len_t, len_f;
243  	char target[MAXHOSTNAMELEN], found[MAXHOSTNAMELEN];
244  
245  	len_t = target_domain == NULL ? 0 : strlen(target_domain);
246  	len_f = found_domain == NULL ? 0 : strlen(found_domain);
247  
248  	/* convert target_domain and found_domain to lowercase for strstr() */
249  	for (i = 0; i < len_t; i++)
250  		target[i] = tolower(target_domain[i]);
251  	target[len_t] = '\0';
252  
253  	for (i = 0; i < len_f; i++)
254  		found[i] = tolower(found_domain[i]);
255  	found[len_f] = '\0';
256  
257  	switch (condition) {
258  	case NWAM_CONDITION_IS:
259  		return (found_domain != NULL && strcmp(found, target) == 0);
260  	case NWAM_CONDITION_IS_NOT:
261  		return (found_domain == NULL || strcmp(found, target) != 0);
262  	case NWAM_CONDITION_CONTAINS:
263  		return (found_domain != NULL && strstr(found, target) != NULL);
264  	case NWAM_CONDITION_DOES_NOT_CONTAIN:
265  		return (found_domain == NULL || strstr(found, target) == NULL);
266  	default:
267  		return (B_FALSE);
268  	}
269  }
270  
271  struct ncu_adv_domains {
272  	struct ncu_adv_domains *next;
273  	char *dns_domain;
274  	char *nis_domain;
275  };
276  
277  static int
278  get_adv_domains(nwamd_object_t obj, void *arg)
279  {
280  	nwamd_ncu_t *ncu = (nwamd_ncu_t *)obj->nwamd_object_data;
281  	struct ncu_adv_domains **headpp = (struct ncu_adv_domains **)arg;
282  	struct ncu_adv_domains *adp;
283  	char *dns, *nis;
284  
285  	if (ncu->ncu_type != NWAM_NCU_TYPE_INTERFACE)
286  		return (0);
287  
288  	dns = nwamd_get_dhcpinfo_data("DNSdmain", ncu->ncu_name);
289  	nis = nwamd_get_dhcpinfo_data("NISdmain", ncu->ncu_name);
290  
291  	if (dns != NULL || nis != NULL) {
292  		adp = (struct ncu_adv_domains *)malloc(sizeof (*adp));
293  		if (adp == NULL)
294  			return (1);
295  		adp->dns_domain = dns;
296  		adp->nis_domain = nis;
297  		adp->next = *headpp;
298  		*headpp = adp;
299  	}
300  
301  	return (0);
302  }
303  
304  static boolean_t
305  test_condition_sys_domain(nwam_condition_t condition, const char *domainname)
306  {
307  	char cur_domainname[MAXHOSTNAMELEN];
308  
309  	if (getdomainname(cur_domainname, MAXHOSTNAMELEN) != 0)
310  		return (B_FALSE);
311  
312  	return (test_condition_domain(condition, domainname, cur_domainname));
313  }
314  
315  static boolean_t
316  test_condition_adv_domain(nwam_condition_t condition, const char *domainname)
317  {
318  	struct ncu_adv_domains *adv_domains = NULL;
319  	struct ncu_adv_domains *adp, *prev;
320  	boolean_t positive, rtn;
321  
322  	(void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU, get_adv_domains,
323  	    &adv_domains);
324  
325  	positive = (condition == NWAM_CONDITION_IS ||
326  	    condition == NWAM_CONDITION_CONTAINS);
327  
328  	/*
329  	 * Walk the advertised domain list.  Our test function tests one
330  	 * single domain, but we're dealing with a list: if our condition
331  	 * is positive ('is' or 'contains'), the test function for each
332  	 * domain results are or'd together; if our condition is negative
333  	 * ('is-not' or 'does-not-contain'), the test function results must
334  	 * be and'd.  Thus our short-circuit exit value depends on our
335  	 * condition: if the test function returns TRUE it implies immediate
336  	 * success for a positive condition; if it returns FALSE it implies
337  	 * immediate failure for a negative condition.
338  	 */
339  	adp = adv_domains;
340  	while (adp != NULL) {
341  		if ((test_condition_domain(condition, domainname,
342  		    adp->dns_domain) == positive) ||
343  		    (test_condition_domain(condition, domainname,
344  		    adp->nis_domain) == positive)) {
345  			rtn = positive;
346  			break;
347  		}
348  		adp = adp->next;
349  	}
350  	if (adp == NULL) {
351  		/*
352  		 * We did not short-circuit; we therefore failed if our
353  		 * condition was positive, and succeeded if our condition
354  		 * was negative.
355  		 */
356  		rtn = !positive;
357  	}
358  
359  	/* now free the domain list */
360  	adp = adv_domains;
361  	while (adp != NULL) {
362  		prev = adp;
363  		adp = prev->next;
364  		free(prev->dns_domain);
365  		free(prev->nis_domain);
366  		free(prev);
367  	}
368  
369  	return (rtn);
370  }
371  
372  /*
373   * Returns true if prefixlen bits of addr1 match prefixlen bits of addr2.
374   */
375  static boolean_t
376  prefixmatch(uchar_t *addr1, uchar_t *addr2, int prefixlen)
377  {
378  	uchar_t mask[IPV6_ABITS/8];
379  	int i, j = 0;
380  
381  	if (prefixlen == 0)
382  		return (B_TRUE);
383  
384  	while (prefixlen > 0) {
385  		if (prefixlen >= 8) {
386  			mask[j++] = 0xFF;
387  			prefixlen -= 8;
388  		} else {
389  			mask[j] |= 1 << (8 - prefixlen);
390  			prefixlen--;
391  		}
392  	}
393  	/* Ensure at least one byte is tested */
394  	if (j == 0) j++;
395  
396  	for (i = 0; i < j; i++) {
397  		if ((addr1[i] & mask[i]) != (addr2[i] & mask[i]))
398  			return (B_FALSE);
399  	}
400  	return (B_TRUE);
401  }
402  
403  /*
404   * Given a string representation of an IPv4 or IPv6 address returns the
405   * sockaddr representation. Note that 'sockaddr' should point at the correct
406   * sockaddr structure for the address family (sockaddr_in for AF_INET or
407   * sockaddr_in6 for AF_INET6) or alternatively at a sockaddr_storage
408   * structure.
409   */
410  static struct sockaddr_storage *
411  nwamd_str2sockaddr(sa_family_t af, const char *straddr,
412      struct sockaddr_storage *addr)
413  {
414  	struct sockaddr_in *sin;
415  	struct sockaddr_in6 *sin6;
416  	int err;
417  
418  	if (af == AF_INET) {
419  		sin = (struct sockaddr_in *)addr;
420  		sin->sin_family = AF_INET;
421  		err = inet_pton(AF_INET, straddr, &sin->sin_addr);
422  	} else if (af == AF_INET6) {
423  		sin6 = (struct sockaddr_in6 *)addr;
424  		sin6->sin6_family = AF_INET6;
425  		err = inet_pton(AF_INET6, straddr, &sin6->sin6_addr);
426  	} else {
427  		errno = EINVAL;
428  		return (NULL);
429  	}
430  	return (err == 1 ? addr : NULL);
431  }
432  
433  struct nwamd_ipaddr_condition_walk_arg {
434  	nwam_condition_t condition;
435  	struct sockaddr_storage sockaddr;
436  	int prefixlen;
437  	boolean_t res;
438  };
439  
440  static int
441  check_ipaddr(sa_family_t family, struct ifaddrs *ifa, void *arg)
442  {
443  	struct nwamd_ipaddr_condition_walk_arg *wa = arg;
444  	boolean_t match = B_FALSE;
445  	uchar_t *addr1, *addr2;
446  
447  	if (family == AF_INET) {
448  		addr1 = (uchar_t *)&(((struct sockaddr_in *)
449  		    ifa->ifa_addr)->sin_addr.s_addr);
450  		addr2 = (uchar_t *)&(((struct sockaddr_in *)
451  		    &(wa->sockaddr))->sin_addr.s_addr);
452  	} else {
453  		addr1 = (uchar_t *)&(((struct sockaddr_in6 *)
454  		    ifa->ifa_addr)->sin6_addr.s6_addr);
455  		addr2 = (uchar_t *)&(((struct sockaddr_in6 *)
456  		    &(wa->sockaddr))->sin6_addr.s6_addr);
457  	}
458  
459  	match = prefixmatch(addr1, addr2, wa->prefixlen);
460  
461  	nlog(LOG_DEBUG, "check_ipaddr: match %d\n", match);
462  	switch (wa->condition) {
463  	case NWAM_CONDITION_IS:
464  	case NWAM_CONDITION_IS_IN_RANGE:
465  		wa->res = match;
466  		if (match)
467  			return (1);
468  		return (0);
469  	case NWAM_CONDITION_IS_NOT:
470  	case NWAM_CONDITION_IS_NOT_IN_RANGE:
471  		wa->res = !match;
472  		return (0);
473  	default:
474  		return (0);
475  	}
476  }
477  
478  static boolean_t
479  test_condition_ip_address(nwam_condition_t condition,
480      const char *ip_address_string)
481  {
482  	sa_family_t family;
483  	char *copy, *ip_address, *prefixlen_string, *lasts;
484  	struct nwamd_ipaddr_condition_walk_arg wa;
485  	struct ifaddrs *ifap, *ifa;
486  
487  	if ((copy = strdup(ip_address_string)) == NULL)
488  		return (B_FALSE);
489  
490  	if ((ip_address = strtok_r(copy, " \t/", &lasts)) == NULL) {
491  		free(copy);
492  		return (B_FALSE);
493  	}
494  
495  	prefixlen_string = strtok_r(NULL, " \t", &lasts);
496  
497  	if (nwamd_str2sockaddr(AF_INET, ip_address, &wa.sockaddr) != NULL) {
498  		family = AF_INET;
499  		wa.prefixlen = IP_ABITS;
500  	} else if (nwamd_str2sockaddr(AF_INET6, ip_address, &wa.sockaddr)
501  	    != NULL) {
502  		family = AF_INET6;
503  		wa.prefixlen = IPV6_ABITS;
504  	} else {
505  		nlog(LOG_ERR, "test_condition_ip_address: "
506  		    "nwamd_str2sockaddr failed for %s: %s", ip_address,
507  		    strerror(errno));
508  		free(copy);
509  		return (B_FALSE);
510  	}
511  
512  	if (prefixlen_string != NULL)
513  		wa.prefixlen = atoi(prefixlen_string);
514  
515  	wa.condition = condition;
516  
517  	switch (condition) {
518  	case NWAM_CONDITION_IS:
519  	case NWAM_CONDITION_IS_IN_RANGE:
520  		wa.res = B_FALSE;
521  		break;
522  	case NWAM_CONDITION_IS_NOT:
523  	case NWAM_CONDITION_IS_NOT_IN_RANGE:
524  		wa.res = B_TRUE;
525  		break;
526  	default:
527  		free(copy);
528  		return (B_FALSE);
529  	}
530  	free(copy);
531  
532  	if (getifaddrs(&ifa) == -1) {
533  		nlog(LOG_ERR, "test_condition_ip_address: "
534  		    "getifaddrs failed: %s", strerror(errno));
535  		return (wa.res);
536  	}
537  	for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
538  		if (ifap->ifa_addr->ss_family != family)
539  			continue;
540  		if (check_ipaddr(family, ifap, &wa) == 1)
541  			break;
542  	}
543  	freeifaddrs(ifa);
544  
545  	return (wa.res);
546  }
547  
548  struct nwamd_wlan_condition_walk_arg {
549  	nwam_condition_t condition;
550  	const char *exp_essid;
551  	const char *exp_bssid;
552  	uint_t num_connected;
553  	boolean_t res;
554  };
555  
556  static int
557  check_wlan(const char *linkname, void *arg)
558  {
559  	struct nwamd_wlan_condition_walk_arg *wa = arg;
560  	datalink_id_t linkid;
561  	dladm_wlan_linkattr_t attr;
562  	dladm_status_t status;
563  	char cur_essid[DLADM_STRSIZE];
564  	char cur_bssid[DLADM_STRSIZE];
565  	char errmsg[DLADM_STRSIZE];
566  
567  	if ((status = dladm_name2info(dld_handle, linkname, &linkid, NULL, NULL,
568  	    NULL)) != DLADM_STATUS_OK) {
569  		nlog(LOG_DEBUG, "check_wlan: dladm_name2info() for %s "
570  		    "failed: %s", linkname,
571  		    dladm_status2str(status, errmsg));
572  		return (DLADM_WALK_CONTINUE);
573  	}
574  
575  	status = dladm_wlan_get_linkattr(dld_handle, linkid, &attr);
576  	if (status != DLADM_STATUS_OK) {
577  		nlog(LOG_DEBUG, "check_wlan: dladm_wlan_get_linkattr() for %s "
578  		    "failed: %s", linkname,
579  		    dladm_status2str(status, errmsg));
580  		return (DLADM_WALK_CONTINUE);
581  	}
582  	if (attr.la_status == DLADM_WLAN_LINK_DISCONNECTED)
583  		return (DLADM_WALK_TERMINATE);
584  
585  	wa->num_connected++;
586  
587  	if (wa->exp_essid != NULL) {
588  		/* Is the NIC associated with the expected access point? */
589  		(void) dladm_wlan_essid2str(&attr.la_wlan_attr.wa_essid,
590  		    cur_essid);
591  		switch (wa->condition) {
592  		case NWAM_CONDITION_IS:
593  			wa->res = strcmp(cur_essid, wa->exp_essid) == 0;
594  			if (wa->res)
595  				return (DLADM_WALK_TERMINATE);
596  			break;
597  		case NWAM_CONDITION_IS_NOT:
598  			wa->res = strcmp(cur_essid, wa->exp_essid) != 0;
599  			if (!wa->res)
600  				return (DLADM_WALK_TERMINATE);
601  			break;
602  		case NWAM_CONDITION_CONTAINS:
603  			wa->res = strstr(cur_essid, wa->exp_essid) != NULL;
604  			if (wa->res)
605  				return (DLADM_WALK_TERMINATE);
606  			break;
607  		case NWAM_CONDITION_DOES_NOT_CONTAIN:
608  			wa->res = strstr(cur_essid, wa->exp_essid) == NULL;
609  			if (!wa->res)
610  				return (DLADM_WALK_TERMINATE);
611  			break;
612  		default:
613  			return (DLADM_WALK_TERMINATE);
614  		}
615  		return (DLADM_WALK_CONTINUE);
616  	}
617  	if (wa->exp_bssid != NULL) {
618  		/* Is the NIC associated with the expected access point? */
619  		(void) dladm_wlan_bssid2str(&attr.la_wlan_attr.wa_bssid,
620  		    cur_bssid);
621  		switch (wa->condition) {
622  		case NWAM_CONDITION_IS:
623  			wa->res = strcmp(cur_bssid, wa->exp_bssid) == 0;
624  			if (wa->res)
625  				return (DLADM_WALK_TERMINATE);
626  			break;
627  		case NWAM_CONDITION_IS_NOT:
628  			wa->res = strcmp(cur_bssid, wa->exp_bssid) != 0;
629  			if (!wa->res)
630  				return (DLADM_WALK_TERMINATE);
631  			break;
632  		default:
633  			return (DLADM_WALK_TERMINATE);
634  		}
635  		return (DLADM_WALK_CONTINUE);
636  	}
637  	/*
638  	 * Neither an ESSID or BSSID match is required - being connected to a
639  	 * WLAN is enough.
640  	 */
641  	switch (wa->condition) {
642  	case NWAM_CONDITION_IS:
643  		wa->res = B_TRUE;
644  		return (DLADM_WALK_TERMINATE);
645  	default:
646  		wa->res = B_FALSE;
647  		return (DLADM_WALK_TERMINATE);
648  	}
649  	/*NOTREACHED*/
650  	return (DLADM_WALK_CONTINUE);
651  }
652  
653  static boolean_t
654  test_condition_wireless_essid(nwam_condition_t condition,
655      const char *essid)
656  {
657  	struct nwamd_wlan_condition_walk_arg wa;
658  
659  	wa.condition = condition;
660  	wa.exp_essid = essid;
661  	wa.exp_bssid = NULL;
662  	wa.num_connected = 0;
663  	wa.res = B_FALSE;
664  
665  	(void) dladm_walk(check_wlan, dld_handle, &wa, DATALINK_CLASS_PHYS,
666  	    DL_WIFI, DLADM_OPT_ACTIVE);
667  
668  	return (wa.num_connected > 0 && wa.res == B_TRUE);
669  }
670  
671  static boolean_t
672  test_condition_wireless_bssid(nwam_condition_t condition,
673      const char *bssid)
674  {
675  	struct nwamd_wlan_condition_walk_arg wa;
676  
677  	wa.condition = condition;
678  	wa.exp_bssid = bssid;
679  	wa.exp_essid = NULL;
680  	wa.num_connected = 0;
681  	wa.res = B_FALSE;
682  
683  	(void) dladm_walk(check_wlan, dld_handle, &wa, DATALINK_CLASS_PHYS,
684  	    DL_WIFI, DLADM_OPT_ACTIVE);
685  
686  	return (wa.num_connected > 0 && wa.res == B_TRUE);
687  }
688  
689  /*
690   * This function takes an activation mode and a string representation of a
691   * condition and evaluates it.
692   */
693  boolean_t
694  nwamd_check_conditions(nwam_activation_mode_t activation_mode,
695      char **condition_strings, uint_t num_conditions)
696  {
697  	boolean_t ret;
698  	nwam_condition_t condition;
699  	nwam_condition_object_type_t object_type;
700  	char *object_name;
701  	int i, j;
702  
703  	for (i = 0; i < num_conditions; i++) {
704  
705  		if (nwam_condition_string_to_condition(condition_strings[i],
706  		    &object_type, &condition, &object_name) != NWAM_SUCCESS) {
707  			nlog(LOG_ERR, "check_conditions: invalid condition %s",
708  			    condition_strings[i]);
709  			return (B_FALSE);
710  		}
711  		ret = B_FALSE;
712  
713  		for (j = 0; j < (sizeof (condition_map) /
714  		    sizeof (struct nwamd_condition_map)); j++) {
715  			if (condition_map[j].object_type == object_type)
716  				ret = condition_map[j].condition_func(condition,
717  				    object_name);
718  		}
719  
720  		free(object_name);
721  
722  		if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ANY &&
723  		    ret) {
724  			return (B_TRUE);
725  		}
726  		if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ALL &&
727  		    !ret) {
728  			return (B_FALSE);
729  		}
730  	}
731  	if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ANY && ret)
732  		return (B_TRUE);
733  	if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ALL && ret)
734  		return (B_TRUE);
735  
736  	return (B_FALSE);
737  }
738  
739  /*
740   * In rating activation conditions, we take the best-rated CONDITIONAL_ANY
741   * condition, or sum all the CONDITIONAL_ALL condition ratings. This allows
742   * us to compare between location activation conditions to pick the best.
743   */
744  uint64_t
745  nwamd_rate_conditions(nwam_activation_mode_t activation_mode,
746      char **conditions, uint_t num_conditions)
747  {
748  	nwam_condition_t condition;
749  	nwam_condition_object_type_t object_type;
750  	char *object_name;
751  	int i;
752  	uint64_t rating = 0, total_rating = 0;
753  
754  	for (i = 0; i < num_conditions; i++) {
755  
756  		object_name = NULL;
757  		if (nwam_condition_string_to_condition(conditions[i],
758  		    &object_type, &condition, &object_name) != NWAM_SUCCESS ||
759  		    nwam_condition_rate(object_type, condition, &rating)
760  		    != NWAM_SUCCESS) {
761  			nlog(LOG_ERR, "nwamd_rate_conditions: could not rate "
762  			    "condition");
763  			free(object_name);
764  			return (0);
765  		}
766  		free(object_name);
767  
768  		if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ANY) {
769  			if (rating > total_rating)
770  				total_rating = rating;
771  		} else if (activation_mode ==
772  		    NWAM_ACTIVATION_MODE_CONDITIONAL_ALL) {
773  			total_rating += rating;
774  		}
775  	}
776  	return (total_rating);
777  }
778  
779  /*
780   * Different from nwamd_triggered_check_all_conditions() in that this
781   * function enqueues a timed check event.
782   */
783  void
784  nwamd_set_timed_check_all_conditions(void)
785  {
786  	nwamd_event_t check_event = nwamd_event_init
787  	    (NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS, NWAM_OBJECT_TYPE_UNKNOWN,
788  	    0, NULL);
789  	if (check_event != NULL) {
790  		/* Add another timed event to recheck conditions */
791  		nwamd_event_enqueue_timed(check_event,
792  		    condition_check_interval > CONDITION_CHECK_INTERVAL_MIN ?
793  		    condition_check_interval : CONDITION_CHECK_INTERVAL_MIN);
794  	}
795  }
796  
797  /*
798   * Does not enqueue another check event.
799   */
800  void
801  nwamd_check_all_conditions(void)
802  {
803  	nwamd_enm_check_conditions();
804  	nwamd_loc_check_conditions();
805  }
806  
807  void
808  nwamd_create_timed_condition_check_event(void)
809  {
810  	nwamd_event_t check_event = nwamd_event_init
811  	    (NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS, NWAM_OBJECT_TYPE_UNKNOWN,
812  	    0, NULL);
813  	if (check_event != NULL)
814  		nwamd_event_enqueue(check_event);
815  }
816  
817  void
818  nwamd_create_triggered_condition_check_event(uint32_t when)
819  {
820  	nwamd_event_t check_event;
821  
822  	if (!nwamd_event_enqueued(NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS,
823  	    NWAM_OBJECT_TYPE_UNKNOWN, NULL)) {
824  		check_event = nwamd_event_init
825  		    (NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS,
826  		    NWAM_OBJECT_TYPE_UNKNOWN, 0, NULL);
827  		if (check_event != NULL)
828  			nwamd_event_enqueue_timed(check_event, when);
829  	}
830  }
831