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