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