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 struct sockaddr_in6 addr6; 445 struct sockaddr_in addr; 446 boolean_t match = B_FALSE; 447 uchar_t *addr1, *addr2; 448 449 if (family == AF_INET) { 450 (void) memcpy(&addr, ifa->ifa_addr, sizeof (addr)); 451 addr1 = (uchar_t *)(&addr.sin_addr.s_addr); 452 addr2 = (uchar_t *)&(((struct sockaddr_in *) 453 &(wa->sockaddr))->sin_addr.s_addr); 454 } else { 455 (void) memcpy(&addr6, ifa->ifa_addr, sizeof (addr6)); 456 addr1 = (uchar_t *)(&addr6.sin6_addr.s6_addr); 457 addr2 = (uchar_t *)&(((struct sockaddr_in6 *) 458 &(wa->sockaddr))->sin6_addr.s6_addr); 459 } 460 461 match = prefixmatch(addr1, addr2, wa->prefixlen); 462 463 nlog(LOG_DEBUG, "check_ipaddr: match %d\n", match); 464 switch (wa->condition) { 465 case NWAM_CONDITION_IS: 466 case NWAM_CONDITION_IS_IN_RANGE: 467 wa->res = match; 468 if (match) 469 return (1); 470 return (0); 471 case NWAM_CONDITION_IS_NOT: 472 case NWAM_CONDITION_IS_NOT_IN_RANGE: 473 wa->res = !match; 474 return (0); 475 default: 476 return (0); 477 } 478 } 479 480 static boolean_t 481 test_condition_ip_address(nwam_condition_t condition, 482 const char *ip_address_string) 483 { 484 sa_family_t family; 485 char *copy, *ip_address, *prefixlen_string, *lasts; 486 struct nwamd_ipaddr_condition_walk_arg wa; 487 struct ifaddrs *ifap, *ifa; 488 489 if ((copy = strdup(ip_address_string)) == NULL) 490 return (B_FALSE); 491 492 if ((ip_address = strtok_r(copy, " \t/", &lasts)) == NULL) { 493 free(copy); 494 return (B_FALSE); 495 } 496 497 prefixlen_string = strtok_r(NULL, " \t", &lasts); 498 499 if (nwamd_str2sockaddr(AF_INET, ip_address, &wa.sockaddr) != NULL) { 500 family = AF_INET; 501 wa.prefixlen = IP_ABITS; 502 } else if (nwamd_str2sockaddr(AF_INET6, ip_address, &wa.sockaddr) 503 != NULL) { 504 family = AF_INET6; 505 wa.prefixlen = IPV6_ABITS; 506 } else { 507 nlog(LOG_ERR, "test_condition_ip_address: " 508 "nwamd_str2sockaddr failed for %s: %s", ip_address, 509 strerror(errno)); 510 free(copy); 511 return (B_FALSE); 512 } 513 514 if (prefixlen_string != NULL) 515 wa.prefixlen = atoi(prefixlen_string); 516 517 wa.condition = condition; 518 519 switch (condition) { 520 case NWAM_CONDITION_IS: 521 case NWAM_CONDITION_IS_IN_RANGE: 522 wa.res = B_FALSE; 523 break; 524 case NWAM_CONDITION_IS_NOT: 525 case NWAM_CONDITION_IS_NOT_IN_RANGE: 526 wa.res = B_TRUE; 527 break; 528 default: 529 free(copy); 530 return (B_FALSE); 531 } 532 free(copy); 533 534 if (getifaddrs(&ifa) == -1) { 535 nlog(LOG_ERR, "test_condition_ip_address: " 536 "getifaddrs failed: %s", strerror(errno)); 537 return (wa.res); 538 } 539 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { 540 if (ifap->ifa_addr->sa_family != family) 541 continue; 542 if (check_ipaddr(family, ifap, &wa) == 1) 543 break; 544 } 545 freeifaddrs(ifa); 546 547 return (wa.res); 548 } 549 550 struct nwamd_wlan_condition_walk_arg { 551 nwam_condition_t condition; 552 const char *exp_essid; 553 const char *exp_bssid; 554 uint_t num_connected; 555 boolean_t res; 556 }; 557 558 static int 559 check_wlan(const char *linkname, void *arg) 560 { 561 struct nwamd_wlan_condition_walk_arg *wa = arg; 562 datalink_id_t linkid; 563 dladm_wlan_linkattr_t attr; 564 dladm_status_t status; 565 char cur_essid[DLADM_STRSIZE]; 566 char cur_bssid[DLADM_STRSIZE]; 567 char errmsg[DLADM_STRSIZE]; 568 569 if ((status = dladm_name2info(dld_handle, linkname, &linkid, NULL, NULL, 570 NULL)) != DLADM_STATUS_OK) { 571 nlog(LOG_DEBUG, "check_wlan: dladm_name2info() for %s " 572 "failed: %s", linkname, 573 dladm_status2str(status, errmsg)); 574 return (DLADM_WALK_CONTINUE); 575 } 576 577 status = dladm_wlan_get_linkattr(dld_handle, linkid, &attr); 578 if (status != DLADM_STATUS_OK) { 579 nlog(LOG_DEBUG, "check_wlan: dladm_wlan_get_linkattr() for %s " 580 "failed: %s", linkname, 581 dladm_status2str(status, errmsg)); 582 return (DLADM_WALK_CONTINUE); 583 } 584 if (attr.la_status == DLADM_WLAN_LINK_DISCONNECTED) 585 return (DLADM_WALK_TERMINATE); 586 587 wa->num_connected++; 588 589 if (wa->exp_essid != NULL) { 590 /* Is the NIC associated with the expected access point? */ 591 (void) dladm_wlan_essid2str(&attr.la_wlan_attr.wa_essid, 592 cur_essid); 593 switch (wa->condition) { 594 case NWAM_CONDITION_IS: 595 wa->res = strcmp(cur_essid, wa->exp_essid) == 0; 596 if (wa->res) 597 return (DLADM_WALK_TERMINATE); 598 break; 599 case NWAM_CONDITION_IS_NOT: 600 wa->res = strcmp(cur_essid, wa->exp_essid) != 0; 601 if (!wa->res) 602 return (DLADM_WALK_TERMINATE); 603 break; 604 case NWAM_CONDITION_CONTAINS: 605 wa->res = strstr(cur_essid, wa->exp_essid) != NULL; 606 if (wa->res) 607 return (DLADM_WALK_TERMINATE); 608 break; 609 case NWAM_CONDITION_DOES_NOT_CONTAIN: 610 wa->res = strstr(cur_essid, wa->exp_essid) == NULL; 611 if (!wa->res) 612 return (DLADM_WALK_TERMINATE); 613 break; 614 default: 615 return (DLADM_WALK_TERMINATE); 616 } 617 return (DLADM_WALK_CONTINUE); 618 } 619 if (wa->exp_bssid != NULL) { 620 /* Is the NIC associated with the expected access point? */ 621 (void) dladm_wlan_bssid2str(&attr.la_wlan_attr.wa_bssid, 622 cur_bssid); 623 switch (wa->condition) { 624 case NWAM_CONDITION_IS: 625 wa->res = strcmp(cur_bssid, wa->exp_bssid) == 0; 626 if (wa->res) 627 return (DLADM_WALK_TERMINATE); 628 break; 629 case NWAM_CONDITION_IS_NOT: 630 wa->res = strcmp(cur_bssid, wa->exp_bssid) != 0; 631 if (!wa->res) 632 return (DLADM_WALK_TERMINATE); 633 break; 634 default: 635 return (DLADM_WALK_TERMINATE); 636 } 637 return (DLADM_WALK_CONTINUE); 638 } 639 /* 640 * Neither an ESSID or BSSID match is required - being connected to a 641 * WLAN is enough. 642 */ 643 switch (wa->condition) { 644 case NWAM_CONDITION_IS: 645 wa->res = B_TRUE; 646 return (DLADM_WALK_TERMINATE); 647 default: 648 wa->res = B_FALSE; 649 return (DLADM_WALK_TERMINATE); 650 } 651 /*NOTREACHED*/ 652 return (DLADM_WALK_CONTINUE); 653 } 654 655 static boolean_t 656 test_condition_wireless_essid(nwam_condition_t condition, 657 const char *essid) 658 { 659 struct nwamd_wlan_condition_walk_arg wa; 660 661 wa.condition = condition; 662 wa.exp_essid = essid; 663 wa.exp_bssid = NULL; 664 wa.num_connected = 0; 665 wa.res = B_FALSE; 666 667 (void) dladm_walk(check_wlan, dld_handle, &wa, DATALINK_CLASS_PHYS, 668 DL_WIFI, DLADM_OPT_ACTIVE); 669 670 return (wa.num_connected > 0 && wa.res == B_TRUE); 671 } 672 673 static boolean_t 674 test_condition_wireless_bssid(nwam_condition_t condition, 675 const char *bssid) 676 { 677 struct nwamd_wlan_condition_walk_arg wa; 678 679 wa.condition = condition; 680 wa.exp_bssid = bssid; 681 wa.exp_essid = NULL; 682 wa.num_connected = 0; 683 wa.res = B_FALSE; 684 685 (void) dladm_walk(check_wlan, dld_handle, &wa, DATALINK_CLASS_PHYS, 686 DL_WIFI, DLADM_OPT_ACTIVE); 687 688 return (wa.num_connected > 0 && wa.res == B_TRUE); 689 } 690 691 /* 692 * This function takes an activation mode and a string representation of a 693 * condition and evaluates it. 694 */ 695 boolean_t 696 nwamd_check_conditions(nwam_activation_mode_t activation_mode, 697 char **condition_strings, uint_t num_conditions) 698 { 699 boolean_t ret; 700 nwam_condition_t condition; 701 nwam_condition_object_type_t object_type; 702 char *object_name; 703 int i, j; 704 705 for (i = 0; i < num_conditions; i++) { 706 707 if (nwam_condition_string_to_condition(condition_strings[i], 708 &object_type, &condition, &object_name) != NWAM_SUCCESS) { 709 nlog(LOG_ERR, "check_conditions: invalid condition %s", 710 condition_strings[i]); 711 return (B_FALSE); 712 } 713 ret = B_FALSE; 714 715 for (j = 0; j < (sizeof (condition_map) / 716 sizeof (struct nwamd_condition_map)); j++) { 717 if (condition_map[j].object_type == object_type) 718 ret = condition_map[j].condition_func(condition, 719 object_name); 720 } 721 722 free(object_name); 723 724 if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ANY && 725 ret) { 726 return (B_TRUE); 727 } 728 if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ALL && 729 !ret) { 730 return (B_FALSE); 731 } 732 } 733 if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ANY && ret) 734 return (B_TRUE); 735 if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ALL && ret) 736 return (B_TRUE); 737 738 return (B_FALSE); 739 } 740 741 /* 742 * In rating activation conditions, we take the best-rated CONDITIONAL_ANY 743 * condition, or sum all the CONDITIONAL_ALL condition ratings. This allows 744 * us to compare between location activation conditions to pick the best. 745 */ 746 uint64_t 747 nwamd_rate_conditions(nwam_activation_mode_t activation_mode, 748 char **conditions, uint_t num_conditions) 749 { 750 nwam_condition_t condition; 751 nwam_condition_object_type_t object_type; 752 char *object_name; 753 int i; 754 uint64_t rating = 0, total_rating = 0; 755 756 for (i = 0; i < num_conditions; i++) { 757 758 object_name = NULL; 759 if (nwam_condition_string_to_condition(conditions[i], 760 &object_type, &condition, &object_name) != NWAM_SUCCESS || 761 nwam_condition_rate(object_type, condition, &rating) 762 != NWAM_SUCCESS) { 763 nlog(LOG_ERR, "nwamd_rate_conditions: could not rate " 764 "condition"); 765 free(object_name); 766 return (0); 767 } 768 free(object_name); 769 770 if (activation_mode == NWAM_ACTIVATION_MODE_CONDITIONAL_ANY) { 771 if (rating > total_rating) 772 total_rating = rating; 773 } else if (activation_mode == 774 NWAM_ACTIVATION_MODE_CONDITIONAL_ALL) { 775 total_rating += rating; 776 } 777 } 778 return (total_rating); 779 } 780 781 /* 782 * Different from nwamd_triggered_check_all_conditions() in that this 783 * function enqueues a timed check event. 784 */ 785 void 786 nwamd_set_timed_check_all_conditions(void) 787 { 788 nwamd_event_t check_event = nwamd_event_init 789 (NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS, NWAM_OBJECT_TYPE_UNKNOWN, 790 0, NULL); 791 if (check_event != NULL) { 792 /* Add another timed event to recheck conditions */ 793 nwamd_event_enqueue_timed(check_event, 794 condition_check_interval > CONDITION_CHECK_INTERVAL_MIN ? 795 condition_check_interval : CONDITION_CHECK_INTERVAL_MIN); 796 } 797 } 798 799 /* 800 * Does not enqueue another check event. 801 */ 802 void 803 nwamd_check_all_conditions(void) 804 { 805 nwamd_enm_check_conditions(); 806 nwamd_loc_check_conditions(); 807 } 808 809 void 810 nwamd_create_timed_condition_check_event(void) 811 { 812 nwamd_event_t check_event = nwamd_event_init 813 (NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS, NWAM_OBJECT_TYPE_UNKNOWN, 814 0, NULL); 815 if (check_event != NULL) 816 nwamd_event_enqueue(check_event); 817 } 818 819 void 820 nwamd_create_triggered_condition_check_event(uint32_t when) 821 { 822 nwamd_event_t check_event; 823 824 if (!nwamd_event_enqueued(NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS, 825 NWAM_OBJECT_TYPE_UNKNOWN, NULL)) { 826 check_event = nwamd_event_init 827 (NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS, 828 NWAM_OBJECT_TYPE_UNKNOWN, 0, NULL); 829 if (check_event != NULL) 830 nwamd_event_enqueue_timed(check_event, when); 831 } 832 } 833