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 * Copyright (c) 2016, Chris Fraire <cfraire@me.com>. 25 */ 26 27 #include <arpa/inet.h> 28 #include <assert.h> 29 #include <libdlaggr.h> 30 #include <libdllink.h> 31 #include <libdlstat.h> 32 #include <libnwam.h> 33 #include <libscf.h> 34 #include <netinet/in.h> 35 #include <stdlib.h> 36 #include <strings.h> 37 #include <sys/param.h> 38 #include <sys/socket.h> 39 #include <sys/time.h> 40 #include <sys/types.h> 41 #include <values.h> 42 #include <zone.h> 43 44 #include "conditions.h" 45 #include "events.h" 46 #include "objects.h" 47 #include "ncp.h" 48 #include "util.h" 49 50 /* 51 * ncu.c - handles various NCU tasks - intialization/refresh, state machine 52 * for NCUs etc. 53 */ 54 55 #define VBOX_IFACE_PREFIX "vboxnet" 56 57 static void populate_ip_ncu_properties(nwam_ncu_handle_t, nwamd_ncu_t *); 58 59 /* 60 * Find ncu of specified type for link/interface name. 61 */ 62 nwamd_object_t 63 nwamd_ncu_object_find(nwam_ncu_type_t type, const char *name) 64 { 65 nwam_error_t err; 66 char *object_name; 67 nwamd_object_t ncu_obj = NULL; 68 69 if ((err = nwam_ncu_name_to_typed_name(name, type, &object_name)) 70 != NWAM_SUCCESS) { 71 nlog(LOG_ERR, "nwamd_ncu_find: nwam_ncu_name_to_typed_name " 72 "returned %s", nwam_strerror(err)); 73 return (NULL); 74 } 75 ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, object_name); 76 77 free(object_name); 78 return (ncu_obj); 79 } 80 81 nwam_error_t 82 nwamd_set_ncu_string(nwam_ncu_handle_t ncuh, char **strval, uint_t cnt, 83 const char *prop) 84 { 85 nwam_error_t err; 86 nwam_value_t val; 87 88 if ((err = nwam_value_create_string_array(strval, cnt, &val)) 89 != NWAM_SUCCESS) 90 return (err); 91 err = nwam_ncu_set_prop_value(ncuh, prop, val); 92 nwam_value_free(val); 93 return (err); 94 } 95 96 nwam_error_t 97 nwamd_set_ncu_uint(nwam_ncu_handle_t ncuh, uint64_t *uintval, uint_t cnt, 98 const char *prop) 99 { 100 nwam_error_t err; 101 nwam_value_t val; 102 103 if ((err = nwam_value_create_uint64_array(uintval, cnt, &val)) 104 != NWAM_SUCCESS) 105 return (err); 106 err = nwam_ncu_set_prop_value(ncuh, prop, val); 107 nwam_value_free(val); 108 return (err); 109 } 110 111 nwam_error_t 112 nwamd_get_ncu_string(nwam_ncu_handle_t ncuh, nwam_value_t *val, char ***strval, 113 uint_t *cnt, const char *prop) 114 { 115 nwam_error_t err; 116 117 if ((err = nwam_ncu_get_prop_value(ncuh, prop, val)) != NWAM_SUCCESS) 118 return (err); 119 return (nwam_value_get_string_array(*val, strval, cnt)); 120 } 121 122 nwam_error_t 123 nwamd_get_ncu_uint(nwam_ncu_handle_t ncuh, nwam_value_t *val, 124 uint64_t **uintval, uint_t *cnt, const char *prop) 125 { 126 nwam_error_t err; 127 128 if ((err = nwam_ncu_get_prop_value(ncuh, prop, val)) != NWAM_SUCCESS) 129 return (err); 130 return (nwam_value_get_uint64_array(*val, uintval, cnt)); 131 } 132 133 nwam_error_t 134 nwamd_get_ncu_boolean(nwam_ncu_handle_t ncuh, nwam_value_t *val, 135 boolean_t **boolval, uint_t *cnt, const char *prop) 136 { 137 nwam_error_t err; 138 139 if ((err = nwam_ncu_get_prop_value(ncuh, prop, val)) != NWAM_SUCCESS) 140 return (err); 141 return (nwam_value_get_boolean_array(*val, boolval, cnt)); 142 } 143 144 /* 145 * Run link/interface state machine in response to a state change 146 * or enable/disable action event. 147 */ 148 static void 149 nwamd_ncu_state_machine(const char *object_name) 150 { 151 nwamd_object_t object; 152 nwamd_ncu_t *ncu; 153 link_state_t link_state; 154 nwamd_event_t event; 155 nwam_wlan_t key_wlan, connected_wlan; 156 nwamd_link_t *link; 157 char linkname[NWAM_MAX_NAME_LEN]; 158 boolean_t up; 159 160 if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, object_name)) 161 == NULL) { 162 nlog(LOG_ERR, "nwamd_ncu_state_machine: " 163 "request for nonexistent NCU %s", object_name); 164 return; 165 } 166 167 ncu = object->nwamd_object_data; 168 link = &ncu->ncu_link; 169 170 switch (object->nwamd_object_aux_state) { 171 case NWAM_AUX_STATE_INITIALIZED: 172 if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) { 173 /* 174 * For wired/wireless links, need to get link 175 * up/down events and even if these are not supported, 176 * dlpi_open()ing the link prevents the driver from 177 * being unloaded. 178 */ 179 nwamd_dlpi_add_link(object); 180 181 if (link->nwamd_link_media == DL_WIFI) { 182 /* 183 * First, if we're unexpectedly connected, 184 * disconnect. 185 */ 186 if (!link->nwamd_link_wifi_connected && 187 nwamd_wlan_connected(object)) { 188 nlog(LOG_DEBUG, 189 "nwamd_ncu_state_machine: " 190 "WiFi unexpectedly connected, " 191 "disconnecting..."); 192 (void) dladm_wlan_disconnect(dld_handle, 193 link->nwamd_link_id); 194 nwamd_set_selected_connected(ncu, 195 B_FALSE, B_FALSE); 196 } 197 /* move to scanning aux state */ 198 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 199 object_name, object->nwamd_object_state, 200 NWAM_AUX_STATE_LINK_WIFI_SCANNING); 201 } else { 202 /* 203 * If initial wired link state is unknown, we 204 * will need to assume the link is up, since 205 * we won´t get DL_NOTE_LINK_UP/DOWN events. 206 */ 207 link_state = nwamd_get_link_state 208 (ncu->ncu_name); 209 if (link_state == LINK_STATE_UP || 210 link_state == LINK_STATE_UNKNOWN) { 211 nwamd_object_set_state 212 (NWAM_OBJECT_TYPE_NCU, 213 object_name, NWAM_STATE_ONLINE, 214 NWAM_AUX_STATE_UP); 215 } else { 216 nwamd_object_set_state 217 (NWAM_OBJECT_TYPE_NCU, 218 object_name, 219 NWAM_STATE_ONLINE_TO_OFFLINE, 220 NWAM_AUX_STATE_DOWN); 221 } 222 } 223 } else { 224 /* 225 * In the current implementation, initialization has to 226 * start from scratch since the complexity of minimizing 227 * configuration change is considerable (e.g. if we 228 * refresh and had DHCP running on the physical 229 * interface, and now have changed to static assignment, 230 * we need to remove DHCP etc). To avoid all this, 231 * unplumb before re-plumbing the protocols and 232 * addresses we wish to configure. In the future, it 233 * would be good to try and minimize configuration 234 * changes. 235 */ 236 nwamd_unplumb_interface(ncu, AF_INET); 237 nwamd_unplumb_interface(ncu, AF_INET6); 238 239 /* 240 * We may be restarting the state machine. Re-read 241 * the IP NCU properties as the ipadm_addrobj_t in 242 * nwamd_if_address should not be reused. 243 */ 244 populate_ip_ncu_properties(object->nwamd_object_handle, 245 ncu); 246 247 /* 248 * Enqueue a WAITING_FOR_ADDR aux state change so that 249 * we are eligible to receive the IF_STATE events 250 * associated with static, DHCP, DHCPv6 and autoconf 251 * address assignment. The latter two can happen 252 * quite quickly after plumbing so we need to be ready. 253 */ 254 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 255 object_name, NWAM_STATE_OFFLINE_TO_ONLINE, 256 NWAM_AUX_STATE_IF_WAITING_FOR_ADDR); 257 258 if (ncu->ncu_if.nwamd_if_ipv4) 259 nwamd_plumb_interface(ncu, AF_INET); 260 261 if (ncu->ncu_if.nwamd_if_ipv6) 262 nwamd_plumb_interface(ncu, AF_INET6); 263 264 /* Configure addresses */ 265 nwamd_configure_interface_addresses(ncu); 266 } 267 break; 268 269 case NWAM_AUX_STATE_IF_DHCP_TIMED_OUT: 270 case NWAM_AUX_STATE_IF_WAITING_FOR_ADDR: 271 /* 272 * nothing to do here - RTM_NEWADDRs will trigger IF_STATE 273 * events to move us online. 274 */ 275 break; 276 277 case NWAM_AUX_STATE_LINK_WIFI_SCANNING: 278 /* launch scan thread */ 279 (void) strlcpy(linkname, ncu->ncu_name, sizeof (linkname)); 280 (void) nwamd_wlan_scan(linkname); 281 /* Create periodic scan event */ 282 nwamd_ncu_create_periodic_scan_event(object); 283 break; 284 285 case NWAM_AUX_STATE_LINK_WIFI_NEED_SELECTION: 286 /* send "need choice" event */ 287 event = nwamd_event_init_wlan 288 (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_NEED_CHOICE, B_FALSE, 289 link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr, 290 link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr_num); 291 if (event == NULL) 292 break; 293 nwamd_event_enqueue(event); 294 nwamd_set_selected_connected(ncu, B_FALSE, B_FALSE); 295 break; 296 297 case NWAM_AUX_STATE_LINK_WIFI_NEED_KEY: 298 /* 299 * Send "need key" event. Set selected to true, connected 300 * and have_key to false. Do not fill in WLAN details as 301 * multiple WLANs may match the ESSID name, and each may 302 * have a different speed and channel. 303 */ 304 bzero(&key_wlan, sizeof (key_wlan)); 305 (void) strlcpy(key_wlan.nww_essid, link->nwamd_link_wifi_essid, 306 sizeof (key_wlan.nww_essid)); 307 (void) strlcpy(key_wlan.nww_bssid, link->nwamd_link_wifi_bssid, 308 sizeof (key_wlan.nww_bssid)); 309 key_wlan.nww_security_mode = 310 link->nwamd_link_wifi_security_mode; 311 key_wlan.nww_selected = B_TRUE; 312 key_wlan.nww_connected = B_FALSE; 313 key_wlan.nww_have_key = B_FALSE; 314 event = nwamd_event_init_wlan 315 (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_NEED_KEY, B_FALSE, 316 &key_wlan, 1); 317 if (event == NULL) 318 break; 319 nwamd_event_enqueue(event); 320 break; 321 322 case NWAM_AUX_STATE_LINK_WIFI_CONNECTING: 323 (void) strlcpy(linkname, ncu->ncu_name, sizeof (linkname)); 324 nwamd_wlan_connect(linkname); 325 break; 326 327 case NWAM_AUX_STATE_UP: 328 case NWAM_AUX_STATE_DOWN: 329 up = (object->nwamd_object_aux_state == NWAM_AUX_STATE_UP); 330 if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) { 331 if (link->nwamd_link_media == DL_WIFI) { 332 /* 333 * Connected/disconnected - send WLAN 334 * connection report. 335 */ 336 link->nwamd_link_wifi_connected = up; 337 nwamd_set_selected_connected(ncu, B_TRUE, up); 338 339 (void) strlcpy(connected_wlan.nww_essid, 340 link->nwamd_link_wifi_essid, 341 sizeof (connected_wlan.nww_essid)); 342 (void) strlcpy(connected_wlan.nww_bssid, 343 link->nwamd_link_wifi_bssid, 344 sizeof (connected_wlan.nww_bssid)); 345 connected_wlan.nww_security_mode = 346 link->nwamd_link_wifi_security_mode; 347 event = nwamd_event_init_wlan 348 (ncu->ncu_name, 349 NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT, up, 350 &connected_wlan, 1); 351 if (event == NULL) 352 break; 353 nwamd_event_enqueue(event); 354 355 /* 356 * If disconnected, restart the state machine 357 * for the WiFi link (WiFi is always trying 358 * to connect). 359 * 360 * If connected, start signal strength 361 * monitoring thread. 362 */ 363 if (!up && ncu->ncu_enabled) { 364 nlog(LOG_DEBUG, 365 "nwamd_ncu_state_machine: " 366 "wifi disconnect - start over " 367 "after %dsec interval", 368 WIRELESS_RETRY_INTERVAL); 369 link->nwamd_link_wifi_connected = 370 B_FALSE; 371 /* propogate down event to IP NCU */ 372 nwamd_propogate_link_up_down_to_ip 373 (ncu->ncu_name, B_FALSE); 374 nwamd_object_set_state_timed 375 (NWAM_OBJECT_TYPE_NCU, object_name, 376 NWAM_STATE_OFFLINE_TO_ONLINE, 377 NWAM_AUX_STATE_INITIALIZED, 378 WIRELESS_RETRY_INTERVAL); 379 } else { 380 nlog(LOG_DEBUG, 381 "nwamd_ncu_state_machine: " 382 "wifi connected, start monitoring"); 383 (void) strlcpy(linkname, ncu->ncu_name, 384 sizeof (linkname)); 385 nwamd_wlan_monitor_signal(linkname); 386 } 387 } 388 } 389 390 /* If not in ONLINE/OFFLINE state yet, change state */ 391 if ((up && object->nwamd_object_state != NWAM_STATE_ONLINE) || 392 (!up && object->nwamd_object_state != NWAM_STATE_OFFLINE)) { 393 nlog(LOG_DEBUG, "nwamd_ncu_state_machine: " 394 "%s is moving %s", object_name, 395 up ? "online" : "offline"); 396 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 397 object_name, 398 up ? NWAM_STATE_ONLINE : NWAM_STATE_OFFLINE, 399 up ? NWAM_AUX_STATE_UP : NWAM_AUX_STATE_DOWN); 400 401 if (ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE) { 402 if (up) { 403 /* 404 * Moving online, add v4/v6 default 405 * routes (if any). 406 */ 407 nwamd_add_default_routes(ncu); 408 } else { 409 /* 410 * If this is an interface NCU and we 411 * got a down event, it is a consequence 412 * of NCU refresh, so reapply addresses 413 * by reinitializing. 414 */ 415 nwamd_object_set_state 416 (NWAM_OBJECT_TYPE_NCU, object_name, 417 NWAM_STATE_OFFLINE_TO_ONLINE, 418 NWAM_AUX_STATE_INITIALIZED); 419 } 420 } 421 } else { 422 nlog(LOG_DEBUG, "nwamd_ncu_state_machine: " 423 "%s is %s", object_name, 424 up ? "online" : "offline"); 425 } 426 /* 427 * NCU is UP or DOWN, trigger all condition checking, even if 428 * the NCU is already in the ONLINE state - an ENM may depend 429 * on NCU activity. 430 */ 431 nwamd_create_triggered_condition_check_event(NEXT_FEW_SECONDS); 432 break; 433 434 case NWAM_AUX_STATE_CONDITIONS_NOT_MET: 435 /* 436 * Link/interface is moving offline. Nothing to do except 437 * for WiFi, where we disconnect. Don't unplumb IP on 438 * a link since it may be a transient change. 439 */ 440 if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) { 441 if (link->nwamd_link_media == DL_WIFI) { 442 (void) dladm_wlan_disconnect(dld_handle, 443 link->nwamd_link_id); 444 link->nwamd_link_wifi_connected = B_FALSE; 445 nwamd_set_selected_connected(ncu, B_FALSE, 446 B_FALSE); 447 } 448 } else { 449 /* 450 * Unplumb here. In the future we may elaborate on 451 * the approach used and not unplumb for WiFi 452 * until we reconnect to a different WLAN (i.e. with 453 * a different ESSID). 454 */ 455 nwamd_unplumb_interface(ncu, AF_INET); 456 nwamd_unplumb_interface(ncu, AF_INET6); 457 } 458 if (object->nwamd_object_state != NWAM_STATE_OFFLINE) { 459 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 460 object_name, NWAM_STATE_OFFLINE, 461 NWAM_AUX_STATE_CONDITIONS_NOT_MET); 462 } 463 break; 464 465 case NWAM_AUX_STATE_MANUAL_DISABLE: 466 /* Manual disable, set enabled state appropriately. */ 467 ncu->ncu_enabled = B_FALSE; 468 /* FALLTHROUGH */ 469 case NWAM_AUX_STATE_UNINITIALIZED: 470 case NWAM_AUX_STATE_NOT_FOUND: 471 /* 472 * Link/interface NCU has been disabled/deactivated/removed. 473 * For WiFi links disconnect, and for IP interfaces we unplumb. 474 */ 475 if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) { 476 if (link->nwamd_link_media == DL_WIFI) { 477 (void) dladm_wlan_disconnect(dld_handle, 478 link->nwamd_link_id); 479 link->nwamd_link_wifi_connected = B_FALSE; 480 nwamd_set_selected_connected(ncu, B_FALSE, 481 B_FALSE); 482 } 483 nwamd_dlpi_delete_link(object); 484 } else { 485 /* Unplumb here. */ 486 if (ncu->ncu_if.nwamd_if_ipv4) { 487 nwamd_unplumb_interface(ncu, AF_INET); 488 } 489 if (ncu->ncu_if.nwamd_if_ipv6) { 490 nwamd_unplumb_interface(ncu, AF_INET6); 491 } 492 /* trigger location condition checking */ 493 nwamd_create_triggered_condition_check_event(0); 494 } 495 496 switch (object->nwamd_object_aux_state) { 497 case NWAM_AUX_STATE_MANUAL_DISABLE: 498 /* Change state to DISABLED if manually disabled */ 499 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 500 object_name, NWAM_STATE_DISABLED, 501 NWAM_AUX_STATE_MANUAL_DISABLE); 502 /* Note that NCU has been disabled */ 503 ncu->ncu_enabled = B_FALSE; 504 break; 505 case NWAM_AUX_STATE_NOT_FOUND: 506 /* Change state to UNINITIALIZED for device removal */ 507 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 508 object_name, NWAM_STATE_UNINITIALIZED, 509 NWAM_AUX_STATE_NOT_FOUND); 510 break; 511 default: 512 break; 513 } 514 break; 515 default: 516 nlog(LOG_ERR, "nwamd_ncu_state_machine: unexpected state"); 517 break; 518 } 519 520 nwamd_object_release(object); 521 } 522 523 static int 524 ncu_create_init_fini_event(nwam_ncu_handle_t ncuh, void *data) 525 { 526 boolean_t *init = data; 527 char *name, *typedname; 528 nwam_error_t err; 529 nwam_value_t typeval = NULL; 530 uint64_t *type; 531 uint_t numvalues; 532 nwamd_event_t ncu_event; 533 534 if (nwam_ncu_get_name(ncuh, &name) != NWAM_SUCCESS) { 535 nlog(LOG_ERR, 536 "ncu_create_init_fini_event: could not get NCU name"); 537 return (0); 538 } 539 540 nlog(LOG_DEBUG, "ncu_create_init_fini_event(%s, %p)", name, data); 541 542 if ((err = nwamd_get_ncu_uint(ncuh, &typeval, &type, &numvalues, 543 NWAM_NCU_PROP_TYPE)) != NWAM_SUCCESS) { 544 nlog(LOG_ERR, "ncu_create_init_fini_event: " 545 "could not get NCU type: %s", nwam_strerror(err)); 546 free(name); 547 nwam_value_free(typeval); 548 return (0); 549 } 550 551 /* convert name to typedname for event */ 552 if ((err = nwam_ncu_name_to_typed_name(name, *type, &typedname)) 553 != NWAM_SUCCESS) { 554 nlog(LOG_ERR, "ncu_create_init_fini_event: " 555 "NCU name translation failed: %s", nwam_strerror(err)); 556 free(name); 557 return (0); 558 } 559 free(name); 560 nwam_value_free(typeval); 561 562 ncu_event = nwamd_event_init(*init ? 563 NWAM_EVENT_TYPE_OBJECT_INIT : NWAM_EVENT_TYPE_OBJECT_FINI, 564 NWAM_OBJECT_TYPE_NCU, 0, typedname); 565 if (ncu_event != NULL) 566 nwamd_event_enqueue(ncu_event); 567 free(typedname); 568 569 return (0); 570 } 571 572 /* 573 * Initialization - walk the NCUs, creating initialization events for each 574 * NCU. nwamd_ncu_handle_init_event() will check if the associated 575 * physical link exists or not. 576 */ 577 void 578 nwamd_init_ncus(void) 579 { 580 boolean_t init = B_TRUE; 581 582 (void) pthread_mutex_lock(&active_ncp_mutex); 583 if (active_ncph != NULL) { 584 nlog(LOG_DEBUG, "nwamd_init_ncus: " 585 "(re)intializing NCUs for NCP %s", active_ncp); 586 (void) nwam_ncp_walk_ncus(active_ncph, 587 ncu_create_init_fini_event, &init, NWAM_FLAG_NCU_TYPE_ALL, 588 NULL); 589 } 590 (void) pthread_mutex_unlock(&active_ncp_mutex); 591 } 592 593 void 594 nwamd_fini_ncus(void) 595 { 596 boolean_t init = B_FALSE; 597 598 /* We may not have an active NCP on initialization, so skip fini */ 599 (void) pthread_mutex_lock(&active_ncp_mutex); 600 if (active_ncph != NULL) { 601 nlog(LOG_DEBUG, "nwamd_fini_ncus: deinitializing NCUs for %s", 602 active_ncp); 603 (void) nwam_ncp_walk_ncus(active_ncph, 604 ncu_create_init_fini_event, &init, NWAM_FLAG_NCU_TYPE_ALL, 605 NULL); 606 } 607 (void) pthread_mutex_unlock(&active_ncp_mutex); 608 } 609 610 /* 611 * Most properties of this type don't need to be cached locally. Only those 612 * interesting to the daemon are stored in an nwamd_ncu_t. 613 */ 614 static void 615 populate_common_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data) 616 { 617 nwam_value_t ncu_prop; 618 nwam_error_t err; 619 boolean_t enablevalue; 620 uint_t numvalues; 621 char **parent; 622 623 if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_ENABLED, 624 &ncu_prop)) != NWAM_SUCCESS) { 625 char *name; 626 (void) nwam_ncu_name_to_typed_name(ncu_data->ncu_name, 627 ncu_data->ncu_type, &name); 628 nlog(LOG_ERR, "nwam_ncu_get_prop_value %s ENABLED failed: %s", 629 name, nwam_strerror(err)); 630 free(name); 631 ncu_data->ncu_enabled = B_TRUE; 632 } else { 633 if ((err = nwam_value_get_boolean(ncu_prop, &enablevalue)) != 634 NWAM_SUCCESS) { 635 nlog(LOG_ERR, "nwam_value_get_boolean ENABLED failed: " 636 "%s", nwam_strerror(err)); 637 } else { 638 ncu_data->ncu_enabled = enablevalue; 639 } 640 nwam_value_free(ncu_prop); 641 } 642 643 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &parent, 644 &numvalues, NWAM_NCU_PROP_PARENT_NCP)) != NWAM_SUCCESS) { 645 nlog(LOG_ERR, "nwam_ncu_get_prop_value %s PARENT failed: %s", 646 ncu_data->ncu_name, nwam_strerror(err)); 647 } else { 648 (void) strlcpy(ncu_data->ncu_parent, parent[0], 649 sizeof (ncu_data->ncu_parent)); 650 nwam_value_free(ncu_prop); 651 } 652 } 653 654 /* 655 * Read in link properties. 656 */ 657 static void 658 populate_link_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data) 659 { 660 nwam_value_t ncu_prop; 661 nwam_error_t err; 662 char **mac_addr; 663 uint64_t *uintval; 664 uint_t numvalues; 665 666 /* activation-mode */ 667 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval, &numvalues, 668 NWAM_NCU_PROP_ACTIVATION_MODE)) != NWAM_SUCCESS) { 669 nlog(LOG_ERR, 670 "populate_link_ncu_properties: could not get %s value: %s", 671 NWAM_NCU_PROP_ACTIVATION_MODE, nwam_strerror(err)); 672 } else { 673 ncu_data->ncu_link.nwamd_link_activation_mode = uintval[0]; 674 nwam_value_free(ncu_prop); 675 } 676 677 /* priority-group and priority-mode for prioritized activation */ 678 if (ncu_data->ncu_link.nwamd_link_activation_mode == 679 NWAM_ACTIVATION_MODE_PRIORITIZED) { 680 /* ncus with prioritized activation are always enabled */ 681 ncu_data->ncu_enabled = B_TRUE; 682 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval, 683 &numvalues, NWAM_NCU_PROP_PRIORITY_MODE)) 684 != NWAM_SUCCESS) { 685 nlog(LOG_ERR, "populate_link_ncu_properties: " 686 "could not get %s value: %s", 687 NWAM_NCU_PROP_PRIORITY_MODE, nwam_strerror(err)); 688 } else { 689 ncu_data->ncu_link.nwamd_link_priority_mode = 690 uintval[0]; 691 nwam_value_free(ncu_prop); 692 } 693 694 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval, 695 &numvalues, NWAM_NCU_PROP_PRIORITY_GROUP)) 696 != NWAM_SUCCESS) { 697 nlog(LOG_ERR, "populate_link_ncu_properties: " 698 "could not get %s value: %s", 699 NWAM_NCU_PROP_PRIORITY_GROUP, nwam_strerror(err)); 700 } else { 701 ncu_data->ncu_link.nwamd_link_priority_group = 702 uintval[0]; 703 nwam_value_free(ncu_prop); 704 } 705 } 706 707 /* link-mac-addr */ 708 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &mac_addr, &numvalues, 709 NWAM_NCU_PROP_LINK_MAC_ADDR)) != NWAM_SUCCESS) { 710 nlog(LOG_DEBUG, 711 "populate_link_ncu_properties: could not get %s value: %s", 712 NWAM_NCU_PROP_LINK_MAC_ADDR, nwam_strerror(err)); 713 ncu_data->ncu_link.nwamd_link_mac_addr = NULL; 714 } else { 715 ncu_data->ncu_link.nwamd_link_mac_addr = strdup(*mac_addr); 716 ncu_data->ncu_link.nwamd_link_mac_addr_len = strlen(*mac_addr); 717 nwam_value_free(ncu_prop); 718 } 719 720 /* link-mtu */ 721 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &uintval, &numvalues, 722 NWAM_NCU_PROP_LINK_MTU)) != NWAM_SUCCESS) { 723 nlog(LOG_DEBUG, 724 "populate_link_ncu_properties: could not get %s value: %s", 725 NWAM_NCU_PROP_LINK_MTU, nwam_strerror(err)); 726 ncu_data->ncu_link.nwamd_link_mtu = 0; 727 } else { 728 ncu_data->ncu_link.nwamd_link_mtu = uintval[0]; 729 nwam_value_free(ncu_prop); 730 } 731 732 /* link-autopush */ 733 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, 734 &ncu_data->ncu_link.nwamd_link_autopush, 735 &ncu_data->ncu_link.nwamd_link_num_autopush, 736 NWAM_NCU_PROP_LINK_AUTOPUSH)) != NWAM_SUCCESS) { 737 nlog(LOG_DEBUG, 738 "populate_link_ncu_properties: could not get %s value: %s", 739 NWAM_NCU_PROP_LINK_AUTOPUSH, nwam_strerror(err)); 740 ncu_data->ncu_link.nwamd_link_num_autopush = 0; 741 } 742 } 743 744 static void 745 populate_ip_ncu_properties(nwam_ncu_handle_t ncuh, nwamd_ncu_t *ncu_data) 746 { 747 nwamd_if_t *nif = &ncu_data->ncu_if; 748 struct nwamd_if_address **nifa, *nifai, *nifait; 749 boolean_t static_addr = B_FALSE, *boolvalue, dhcp_primary = B_FALSE; 750 uint64_t *addrsrcvalue; 751 nwam_value_t ncu_prop; 752 nwam_error_t err; 753 ipadm_addrobj_t ipaddr; 754 ipadm_status_t ipstatus; 755 char **addrvalue, ipreqhost[MAXNAMELEN]; 756 uint_t numvalues; 757 uint64_t *ipversion; 758 int i; 759 760 nif->nwamd_if_ipv4 = B_FALSE; 761 nif->nwamd_if_ipv6 = B_FALSE; 762 nif->nwamd_if_dhcp_requested = B_FALSE; 763 nif->nwamd_if_stateful_requested = B_FALSE; 764 nif->nwamd_if_stateless_requested = B_FALSE; 765 nif->nwamd_if_ipv4_default_route_set = B_FALSE; 766 nif->nwamd_if_ipv6_default_route_set = B_FALSE; 767 768 /* ip-version */ 769 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &ipversion, &numvalues, 770 NWAM_NCU_PROP_IP_VERSION)) != NWAM_SUCCESS) { 771 nlog(LOG_ERR, 772 "populate_ip_ncu_properties: could not get %s value: %s", 773 NWAM_NCU_PROP_IP_VERSION, nwam_strerror(err)); 774 } else { 775 for (i = 0; i < numvalues; i++) { 776 switch (ipversion[i]) { 777 case IPV4_VERSION: 778 nif->nwamd_if_ipv4 = B_TRUE; 779 break; 780 case IPV6_VERSION: 781 nif->nwamd_if_ipv6 = B_TRUE; 782 break; 783 default: 784 nlog(LOG_ERR, "bogus ip version %lld", 785 ipversion[i]); 786 break; 787 } 788 } 789 nwam_value_free(ncu_prop); 790 } 791 792 /* ip-primary */ 793 if ((err = nwamd_get_ncu_boolean(ncuh, &ncu_prop, &boolvalue, 794 &numvalues, NWAM_NCU_PROP_IP_PRIMARY)) != NWAM_SUCCESS) { 795 /* ip-primary is optional, so do not LOG_ERR */ 796 nlog(LOG_DEBUG, "populate_ip_ncu_properties: " 797 "could not get %s value: %s", 798 NWAM_NCU_PROP_IP_PRIMARY, nwam_strerror(err)); 799 } else { 800 if (numvalues > 0) 801 dhcp_primary = boolvalue[0]; 802 nwam_value_free(ncu_prop); 803 } 804 805 /* ip-reqhost */ 806 *ipreqhost = '\0'; 807 808 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue, 809 &numvalues, NWAM_NCU_PROP_IP_REQHOST)) != NWAM_SUCCESS) { 810 /* ip-reqhost is optional, so do not LOG_ERR */ 811 nlog(LOG_DEBUG, "populate_ip_ncu_properties: " 812 "could not get %s value: %s", 813 NWAM_NCU_PROP_IP_REQHOST, nwam_strerror(err)); 814 } else { 815 if (numvalues > 0 && strlcpy(ipreqhost, addrvalue[0], 816 sizeof (ipreqhost)) >= sizeof (ipreqhost)) { 817 nlog(LOG_WARNING, "populate_ip_ncu_properties: " 818 "too long %s value: %s", 819 NWAM_NCU_PROP_IP_REQHOST, addrvalue[0]); 820 *ipreqhost = '\0'; 821 } 822 nwam_value_free(ncu_prop); 823 } 824 825 /* Free the old list. */ 826 for (nifai = nif->nwamd_if_list; nifai != NULL; nifai = nifait) { 827 nifait = nifai->next; 828 nifai->next = NULL; 829 ipadm_destroy_addrobj(nifai->ipaddr); 830 free(nifai); 831 } 832 nif->nwamd_if_list = NULL; 833 nifa = &(nif->nwamd_if_list); 834 835 if (!nif->nwamd_if_ipv4) 836 goto skip_ipv4; 837 838 /* ipv4-addrsrc */ 839 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &addrsrcvalue, 840 &numvalues, NWAM_NCU_PROP_IPV4_ADDRSRC)) != NWAM_SUCCESS) { 841 nlog(nif->nwamd_if_ipv4 ? LOG_ERR : LOG_DEBUG, 842 "populate_ip_ncu_properties: could not get %s value: %s", 843 NWAM_NCU_PROP_IPV4_ADDRSRC, nwam_strerror(err)); 844 } else { 845 for (i = 0; i < numvalues; i++) { 846 switch (addrsrcvalue[i]) { 847 case NWAM_ADDRSRC_DHCP: 848 nif->nwamd_if_dhcp_requested = B_TRUE; 849 break; 850 case NWAM_ADDRSRC_STATIC: 851 static_addr = B_TRUE; 852 break; 853 default: 854 break; 855 } 856 } 857 nwam_value_free(ncu_prop); 858 } 859 if (nif->nwamd_if_dhcp_requested) { 860 ipstatus = ipadm_create_addrobj(IPADM_ADDR_DHCP, 861 ncu_data->ncu_name, &ipaddr); 862 if (ipstatus != IPADM_SUCCESS) { 863 nlog(LOG_ERR, "populate_ip_ncu_properties: " 864 "ipadm_create_addrobj failed for v4 dhcp: %s", 865 ipadm_status2str(ipstatus)); 866 goto skip_ipv4_dhcp; 867 } 868 869 ipstatus = ipadm_set_wait_time(ipaddr, ncu_wait_time); 870 if (ipstatus != IPADM_SUCCESS) { 871 nlog(LOG_ERR, "populate_ip_ncu_properties: " 872 "ipadm_set_wait_time failed for v4 dhcp: %s", 873 ipadm_status2str(ipstatus)); 874 ipadm_destroy_addrobj(ipaddr); 875 goto skip_ipv4_dhcp; 876 } 877 ipstatus = ipadm_set_primary(ipaddr, dhcp_primary); 878 if (ipstatus != IPADM_SUCCESS) { 879 nlog(LOG_ERR, "populate_ip_ncu_properties: " 880 "ipadm_set_primary failed for v4 dhcp: %s", 881 ipadm_status2str(ipstatus)); 882 ipadm_destroy_addrobj(ipaddr); 883 goto skip_ipv4_dhcp; 884 } 885 ipstatus = ipadm_set_reqhost(ipaddr, ipreqhost); 886 if (ipstatus != IPADM_SUCCESS) { 887 nlog(LOG_ERR, "populate_ip_ncu_properties: " 888 "ipadm_set_reqhost failed for v4 dhcp: %s", 889 ipadm_status2str(ipstatus)); 890 ipadm_destroy_addrobj(ipaddr); 891 goto skip_ipv4_dhcp; 892 } 893 if ((*nifa = calloc(sizeof (**nifa), 1)) != NULL) { 894 (*nifa)->family = AF_INET; 895 (*nifa)->ipaddr_atype = IPADM_ADDR_DHCP; 896 (*nifa)->ipaddr = ipaddr; 897 nifa = &((*nifa)->next); 898 *nifa = NULL; 899 } else { 900 nlog(LOG_ERR, "populate_ip_ncu_properties: " 901 "couldn't allocate nwamd address for v4 dhcp: %s", 902 strerror(errno)); 903 ipadm_destroy_addrobj(ipaddr); 904 } 905 } 906 907 skip_ipv4_dhcp: 908 /* ipv4-addr */ 909 if (static_addr) { 910 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue, 911 &numvalues, NWAM_NCU_PROP_IPV4_ADDR)) != NWAM_SUCCESS) { 912 nlog(LOG_ERR, "populate_ip_ncu_properties: " 913 "could not get %s value: %s", 914 NWAM_NCU_PROP_IPV4_ADDR, nwam_strerror(err)); 915 } else { 916 for (i = 0; i < numvalues; i++) { 917 ipstatus = ipadm_create_addrobj( 918 IPADM_ADDR_STATIC, ncu_data->ncu_name, 919 &ipaddr); 920 if (ipstatus != IPADM_SUCCESS) { 921 nlog(LOG_ERR, 922 "populate_ip_ncu_properties: " 923 "ipadm_create_addrobj failed " 924 "for %s: %s", addrvalue[i], 925 ipadm_status2str(ipstatus)); 926 continue; 927 } 928 /* ipadm_set_addr takes <addr>[/<mask>] */ 929 ipstatus = ipadm_set_addr(ipaddr, addrvalue[i], 930 AF_INET); 931 if (ipstatus != IPADM_SUCCESS) { 932 nlog(LOG_ERR, 933 "populate_ip_ncu_properties: " 934 "ipadm_set_addr failed for %s: %s", 935 addrvalue[i], 936 ipadm_status2str(ipstatus)); 937 ipadm_destroy_addrobj(ipaddr); 938 continue; 939 } 940 941 if ((*nifa = calloc(sizeof (**nifa), 1)) 942 != NULL) { 943 (*nifa)->family = AF_INET; 944 (*nifa)->ipaddr_atype = 945 IPADM_ADDR_STATIC; 946 (*nifa)->ipaddr = ipaddr; 947 nifa = &((*nifa)->next); 948 } else { 949 nlog(LOG_ERR, 950 "populate_ip_ncu_properties: " 951 "couldn't allocate nwamd address " 952 "for %s: %s", addrvalue[i], 953 strerror(errno)); 954 ipadm_destroy_addrobj(ipaddr); 955 } 956 } 957 *nifa = NULL; 958 959 nwam_value_free(ncu_prop); 960 } 961 } 962 963 /* get default route, if any */ 964 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue, 965 &numvalues, NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE)) == NWAM_SUCCESS) { 966 /* Only one default route is allowed. */ 967 nif->nwamd_if_ipv4_default_route.sin_family = AF_INET; 968 (void) inet_pton(AF_INET, addrvalue[0], 969 &(nif->nwamd_if_ipv4_default_route.sin_addr)); 970 nif->nwamd_if_ipv4_default_route_set = B_TRUE; 971 nwam_value_free(ncu_prop); 972 } 973 974 skip_ipv4: 975 if (!nif->nwamd_if_ipv6) 976 goto skip_ipv6; 977 978 /* ipv6-addrsrc */ 979 static_addr = B_FALSE; 980 if ((err = nwamd_get_ncu_uint(ncuh, &ncu_prop, &addrsrcvalue, 981 &numvalues, NWAM_NCU_PROP_IPV6_ADDRSRC)) != NWAM_SUCCESS) { 982 nlog(nif->nwamd_if_ipv6 ? LOG_ERR : LOG_DEBUG, 983 "populate_ip_ncu_properties: could not get %s value: %s", 984 NWAM_NCU_PROP_IPV6_ADDRSRC, nwam_strerror(err)); 985 } else { 986 for (i = 0; i < numvalues; i++) { 987 switch (addrsrcvalue[i]) { 988 case NWAM_ADDRSRC_DHCP: 989 nif->nwamd_if_stateful_requested = B_TRUE; 990 break; 991 case NWAM_ADDRSRC_AUTOCONF: 992 nif->nwamd_if_stateless_requested = B_TRUE; 993 break; 994 case NWAM_ADDRSRC_STATIC: 995 static_addr = B_TRUE; 996 break; 997 default: 998 break; 999 } 1000 } 1001 nwam_value_free(ncu_prop); 1002 } 1003 /* 1004 * Both stateful and stateless share the same nwamd_if_address because 1005 * only one ipaddr for both of these addresses can be created. 1006 * ipadm_create_addr() adds both addresses from the same ipaddr. 1007 */ 1008 if (nif->nwamd_if_stateful_requested || 1009 nif->nwamd_if_stateless_requested) { 1010 ipstatus = ipadm_create_addrobj(IPADM_ADDR_IPV6_ADDRCONF, 1011 ncu_data->ncu_name, &ipaddr); 1012 if (ipstatus != IPADM_SUCCESS) { 1013 nlog(LOG_ERR, "populate_ip_ncu_properties: " 1014 "ipadm_create_addrobj failed for v6 " 1015 "stateless/stateful: %s", 1016 ipadm_status2str(ipstatus)); 1017 goto skip_ipv6_addrconf; 1018 } 1019 /* create_addrobj sets both stateless and stateful to B_TRUE */ 1020 if (!nif->nwamd_if_stateful_requested) { 1021 ipstatus = ipadm_set_stateful(ipaddr, B_FALSE); 1022 if (ipstatus != IPADM_SUCCESS) { 1023 nlog(LOG_ERR, "populate_ip_ncu_properties: " 1024 "ipadm_set_stateful failed for v6: %s", 1025 ipadm_status2str(ipstatus)); 1026 ipadm_destroy_addrobj(ipaddr); 1027 goto skip_ipv6_addrconf; 1028 } 1029 } 1030 if (!nif->nwamd_if_stateless_requested) { 1031 ipstatus = ipadm_set_stateless(ipaddr, B_FALSE); 1032 if (ipstatus != IPADM_SUCCESS) { 1033 nlog(LOG_ERR, "populate_ip_ncu_properties: " 1034 "ipadm_set_stateless failed for v6: %s", 1035 ipadm_status2str(ipstatus)); 1036 ipadm_destroy_addrobj(ipaddr); 1037 goto skip_ipv6_addrconf; 1038 } 1039 } 1040 if ((*nifa = calloc(sizeof (**nifa), 1)) != NULL) { 1041 (*nifa)->family = AF_INET6; 1042 (*nifa)->ipaddr_atype = IPADM_ADDR_IPV6_ADDRCONF; 1043 (*nifa)->ipaddr = ipaddr; 1044 nifa = &((*nifa)->next); 1045 *nifa = NULL; 1046 } else { 1047 nlog(LOG_ERR, "populate_ip_ncu_properties: " 1048 "couldn't allocate nwamd address for " 1049 "v6 stateless/stateful: %s", strerror(errno)); 1050 ipadm_destroy_addrobj(ipaddr); 1051 } 1052 } 1053 1054 skip_ipv6_addrconf: 1055 /* ipv6-addr */ 1056 if (static_addr) { 1057 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue, 1058 &numvalues, NWAM_NCU_PROP_IPV6_ADDR)) != NWAM_SUCCESS) { 1059 nlog(LOG_ERR, "populate_ip_ncu_properties: " 1060 "could not get %s value: %s", 1061 NWAM_NCU_PROP_IPV6_ADDR, nwam_strerror(err)); 1062 } else { 1063 for (i = 0; i < numvalues; i++) { 1064 ipstatus = ipadm_create_addrobj( 1065 IPADM_ADDR_STATIC, ncu_data->ncu_name, 1066 &ipaddr); 1067 if (ipstatus != IPADM_SUCCESS) { 1068 nlog(LOG_ERR, 1069 "populate_ip_ncu_properties: " 1070 "ipadm_create_addrobj failed " 1071 "for %s: %s", addrvalue[i], 1072 ipadm_status2str(ipstatus)); 1073 continue; 1074 } 1075 /* ipadm_set_addr takes <addr>[/<mask>] */ 1076 ipstatus = ipadm_set_addr(ipaddr, addrvalue[i], 1077 AF_INET6); 1078 if (ipstatus != IPADM_SUCCESS) { 1079 nlog(LOG_ERR, 1080 "populate_ip_ncu_properties: " 1081 "ipadm_set_addr failed for %s: %s", 1082 addrvalue[i], 1083 ipadm_status2str(ipstatus)); 1084 ipadm_destroy_addrobj(ipaddr); 1085 continue; 1086 } 1087 1088 if ((*nifa = calloc(sizeof (**nifa), 1)) 1089 != NULL) { 1090 (*nifa)->family = AF_INET6; 1091 (*nifa)->ipaddr_atype = 1092 IPADM_ADDR_STATIC; 1093 (*nifa)->ipaddr = ipaddr; 1094 nifa = &((*nifa)->next); 1095 } else { 1096 nlog(LOG_ERR, 1097 "populate_ip_ncu_properties: " 1098 "couldn't allocate nwamd address " 1099 "for %s: %s", addrvalue[i], 1100 strerror(errno)); 1101 ipadm_destroy_addrobj(ipaddr); 1102 } 1103 } 1104 *nifa = NULL; 1105 1106 nwam_value_free(ncu_prop); 1107 } 1108 } 1109 1110 /* get default route, if any */ 1111 if ((err = nwamd_get_ncu_string(ncuh, &ncu_prop, &addrvalue, 1112 &numvalues, NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE)) == NWAM_SUCCESS) { 1113 /* Only one default route is allowed. */ 1114 nif->nwamd_if_ipv6_default_route.sin6_family = AF_INET6; 1115 (void) inet_pton(AF_INET6, addrvalue[0], 1116 &(nif->nwamd_if_ipv6_default_route.sin6_addr)); 1117 nif->nwamd_if_ipv6_default_route_set = B_TRUE; 1118 nwam_value_free(ncu_prop); 1119 } 1120 1121 skip_ipv6: 1122 ; 1123 } 1124 1125 static nwamd_ncu_t * 1126 nwamd_ncu_init(nwam_ncu_type_t ncu_type, const char *name) 1127 { 1128 nwamd_ncu_t *rv; 1129 1130 nlog(LOG_DEBUG, "nwamd_ncu_init(%d, %s)", ncu_type, name); 1131 1132 if ((rv = calloc(1, sizeof (*rv))) == NULL) 1133 return (NULL); 1134 1135 rv->ncu_type = ncu_type; 1136 rv->ncu_name = strdup(name); 1137 rv->ncu_enabled = B_FALSE; 1138 1139 /* Initialize link/interface-specific data */ 1140 if (rv->ncu_type == NWAM_NCU_TYPE_LINK) { 1141 (void) bzero(&rv->ncu_link, sizeof (nwamd_link_t)); 1142 (void) dladm_name2info(dld_handle, name, 1143 &rv->ncu_link.nwamd_link_id, NULL, NULL, 1144 &rv->ncu_link.nwamd_link_media); 1145 (void) pthread_mutex_init( 1146 &rv->ncu_link.nwamd_link_wifi_mutex, NULL); 1147 rv->ncu_link.nwamd_link_wifi_priority = MAXINT; 1148 } else { 1149 (void) bzero(&rv->ncu_if, sizeof (nwamd_if_t)); 1150 } 1151 1152 return (rv); 1153 } 1154 1155 void 1156 nwamd_ncu_free(nwamd_ncu_t *ncu) 1157 { 1158 if (ncu != NULL) { 1159 assert(ncu->ncu_type == NWAM_NCU_TYPE_LINK || 1160 ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE); 1161 if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) { 1162 struct nwamd_link *l = &ncu->ncu_link; 1163 int i; 1164 1165 free(l->nwamd_link_wifi_key); 1166 free(l->nwamd_link_mac_addr); 1167 for (i = 0; i < l->nwamd_link_num_autopush; i++) 1168 free(l->nwamd_link_autopush[i]); 1169 } else if (ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE) { 1170 struct nwamd_if_address *nifa; 1171 1172 nifa = ncu->ncu_if.nwamd_if_list; 1173 while (nifa != NULL) { 1174 struct nwamd_if_address *n; 1175 1176 n = nifa; 1177 nifa = nifa->next; 1178 ipadm_destroy_addrobj(n->ipaddr); 1179 free(n); 1180 } 1181 } 1182 free(ncu->ncu_name); 1183 free(ncu); 1184 } 1185 } 1186 1187 static int 1188 nwamd_ncu_display(nwamd_object_t ncu_obj, void *data) 1189 { 1190 nwamd_ncu_t *ncu = (nwamd_ncu_t *)ncu_obj->nwamd_object_data; 1191 data = data; 1192 nlog(LOG_DEBUG, "NCU (%p) %s state %s, %s", 1193 (void *)ncu, ncu_obj->nwamd_object_name, 1194 nwam_state_to_string(ncu_obj->nwamd_object_state), 1195 nwam_aux_state_to_string(ncu_obj->nwamd_object_aux_state)); 1196 return (0); 1197 } 1198 1199 void 1200 nwamd_log_ncus(void) 1201 { 1202 nlog(LOG_DEBUG, "NCP %s", active_ncp); 1203 (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU, nwamd_ncu_display, 1204 NULL); 1205 } 1206 1207 int 1208 nwamd_ncu_action(const char *ncu, const char *parent, nwam_action_t action) 1209 { 1210 nwamd_event_t ncu_event = nwamd_event_init_object_action 1211 (NWAM_OBJECT_TYPE_NCU, ncu, parent, action); 1212 if (ncu_event == NULL) 1213 return (1); 1214 nwamd_event_enqueue(ncu_event); 1215 return (0); 1216 } 1217 1218 static void 1219 add_phys_ncu_to_ncp(nwam_ncp_handle_t ncph, const char *name) 1220 { 1221 dladm_status_t dlrtn; 1222 uint32_t media; 1223 boolean_t is_wireless; 1224 nwam_error_t err; 1225 nwam_ncu_handle_t ncuh; 1226 uint64_t uintval; 1227 1228 if ((dlrtn = dladm_name2info(dld_handle, name, NULL, NULL, NULL, 1229 &media)) != DLADM_STATUS_OK) { 1230 char errmsg[DLADM_STRSIZE]; 1231 nlog(LOG_ERR, "failed to get media type for %s: %s", name, 1232 dladm_status2str(dlrtn, errmsg)); 1233 return; 1234 } 1235 is_wireless = (media == DL_WIFI); 1236 1237 if ((err = nwam_ncu_create(ncph, name, NWAM_NCU_TYPE_LINK, 1238 NWAM_NCU_CLASS_PHYS, &ncuh)) != NWAM_SUCCESS) { 1239 nlog(LOG_ERR, "failed to create link ncu for %s: %s", name, 1240 nwam_strerror(err)); 1241 if (err == NWAM_ENTITY_READ_ONLY) { 1242 nwamd_event_t retry_event; 1243 1244 /* 1245 * Root filesystem may be read-only, retry in 1246 * a few seconds. 1247 */ 1248 nlog(LOG_DEBUG, "Retrying addition of phys ncu for %s", 1249 name); 1250 retry_event = nwamd_event_init_link_action(name, 1251 NWAM_ACTION_ADD); 1252 if (retry_event != NULL) { 1253 nwamd_event_enqueue_timed(retry_event, 1254 NWAMD_READONLY_RETRY_INTERVAL); 1255 } 1256 } 1257 return; 1258 } 1259 1260 uintval = NWAM_ACTIVATION_MODE_PRIORITIZED; 1261 if ((err = nwamd_set_ncu_uint(ncuh, &uintval, 1, 1262 NWAM_NCU_PROP_ACTIVATION_MODE)) != NWAM_SUCCESS) { 1263 goto finish; 1264 } 1265 1266 uintval = is_wireless ? 1 : 0; 1267 if ((err = nwamd_set_ncu_uint(ncuh, &uintval, 1, 1268 NWAM_NCU_PROP_PRIORITY_GROUP)) != NWAM_SUCCESS) { 1269 goto finish; 1270 } 1271 1272 uintval = is_wireless ? NWAM_PRIORITY_MODE_EXCLUSIVE : 1273 NWAM_PRIORITY_MODE_SHARED; 1274 if ((err = nwamd_set_ncu_uint(ncuh, &uintval, 1, 1275 NWAM_NCU_PROP_PRIORITY_MODE)) != NWAM_SUCCESS) { 1276 goto finish; 1277 } 1278 1279 err = nwam_ncu_commit(ncuh, 0); 1280 1281 finish: 1282 nwam_ncu_free(ncuh); 1283 if (err != NWAM_SUCCESS) { 1284 nlog(LOG_ERR, 1285 "failed to create automatic link ncu for %s: %s", 1286 name, nwam_strerror(err)); 1287 } 1288 } 1289 1290 static void 1291 add_ip_ncu_to_ncp(nwam_ncp_handle_t ncph, const char *name) 1292 { 1293 nwam_error_t err; 1294 nwam_ncu_handle_t ncuh; 1295 1296 if ((err = nwam_ncu_create(ncph, name, NWAM_NCU_TYPE_INTERFACE, 1297 NWAM_NCU_CLASS_IP, &ncuh)) != NWAM_SUCCESS) { 1298 nlog(LOG_ERR, "failed to create ip ncu for %s: %s", name, 1299 nwam_strerror(err)); 1300 /* 1301 * Root filesystem may be read-only, but no need to 1302 * retry here since add_phys_ncu_to_ncp() enqueues 1303 * a retry event which will lead to add_ip_ncu_to_ncp() 1304 * being called. 1305 */ 1306 return; 1307 } 1308 1309 /* IP NCU has the default values, so nothing else to do */ 1310 err = nwam_ncu_commit(ncuh, 0); 1311 1312 nwam_ncu_free(ncuh); 1313 if (err != NWAM_SUCCESS) { 1314 nlog(LOG_ERR, 1315 "failed to create ip ncu for %s: %s", name, 1316 nwam_strerror(err)); 1317 } 1318 } 1319 1320 static void 1321 remove_ncu_from_ncp(nwam_ncp_handle_t ncph, const char *name, 1322 nwam_ncu_type_t type) 1323 { 1324 nwam_error_t err; 1325 nwam_ncu_handle_t ncuh; 1326 1327 if ((err = nwam_ncu_read(ncph, name, type, 0, &ncuh)) != NWAM_SUCCESS) { 1328 nlog(LOG_ERR, "failed to read automatic ncu %s: %s", name, 1329 nwam_strerror(err)); 1330 return; 1331 } 1332 1333 err = nwam_ncu_destroy(ncuh, 0); 1334 if (err != NWAM_SUCCESS) { 1335 nlog(LOG_ERR, "failed to delete automatic ncu %s: %s", name, 1336 nwam_strerror(err)); 1337 } 1338 } 1339 1340 /* 1341 * Device represented by NCU has been added or removed for the active 1342 * User NCP. If an associated NCU of the given type is found, transition it 1343 * to the appropriate state. 1344 */ 1345 void 1346 ncu_action_change_state(nwam_action_t action, nwam_ncu_type_t type, 1347 const char *name) 1348 { 1349 nwamd_object_t ncu_obj = NULL; 1350 nwamd_ncu_t *ncu; 1351 1352 if ((ncu_obj = nwamd_ncu_object_find(type, name)) == NULL) 1353 return; 1354 1355 ncu = ncu_obj->nwamd_object_data; 1356 1357 /* 1358 * If device has been added, transition from uninitialized to offline. 1359 * If device has been removed, transition to uninitialized (via online* 1360 * if the NCU is currently enabled in order to tear down config). 1361 */ 1362 if (action == NWAM_ACTION_ADD) { 1363 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 1364 ncu_obj->nwamd_object_name, 1365 NWAM_STATE_OFFLINE, NWAM_AUX_STATE_CONDITIONS_NOT_MET); 1366 } else { 1367 if (ncu->ncu_enabled) { 1368 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 1369 ncu_obj->nwamd_object_name, 1370 NWAM_STATE_ONLINE_TO_OFFLINE, 1371 NWAM_AUX_STATE_NOT_FOUND); 1372 } else { 1373 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 1374 ncu_obj->nwamd_object_name, 1375 NWAM_STATE_UNINITIALIZED, 1376 NWAM_AUX_STATE_NOT_FOUND); 1377 } 1378 } 1379 nwamd_object_release(ncu_obj); 1380 } 1381 1382 /* 1383 * Called with hotplug sysevent or when nwam is started and walking the 1384 * physical interfaces. Add/remove both link and interface NCUs from the 1385 * Automatic NCP. Assumes that both link and interface NCUs don't exist. 1386 */ 1387 void 1388 nwamd_ncu_handle_link_action_event(nwamd_event_t event) 1389 { 1390 nwam_ncp_handle_t ncph; 1391 nwam_ncu_type_t type; 1392 nwam_action_t action = 1393 event->event_msg->nwe_data.nwe_link_action.nwe_action; 1394 nwam_error_t err; 1395 char *name; 1396 boolean_t automatic_ncp_active = B_FALSE; 1397 1398 if (action != NWAM_ACTION_ADD && action != NWAM_ACTION_REMOVE) { 1399 nlog(LOG_ERR, "nwamd_ncu_handle_link_action_event: " 1400 "invalid link action %s", nwam_action_to_string(action)); 1401 nwamd_event_do_not_send(event); 1402 return; 1403 } 1404 1405 nlog(LOG_DEBUG, "nwamd_ncu_handle_link_action_event: " 1406 "link action '%s' event on %s", nwam_action_to_string(action), 1407 event->event_object[0] == 0 ? "n/a" : event->event_object); 1408 1409 if ((err = nwam_ncu_typed_name_to_name(event->event_object, &type, 1410 &name)) != NWAM_SUCCESS) { 1411 nlog(LOG_ERR, "nwamd_ncu_handle_link_action_event: " 1412 "translation from typedname error: %s", nwam_strerror(err)); 1413 nwamd_event_do_not_send(event); 1414 return; 1415 } 1416 1417 (void) pthread_mutex_lock(&active_ncp_mutex); 1418 if (strcmp(active_ncp, NWAM_NCP_NAME_AUTOMATIC) == 0 && 1419 active_ncph != NULL) { 1420 automatic_ncp_active = B_TRUE; 1421 } 1422 (void) pthread_mutex_unlock(&active_ncp_mutex); 1423 1424 /* 1425 * We could use active_ncph for cases where the Automatic NCP is active, 1426 * but that would involve holding the active_ncp_mutex for too long. 1427 */ 1428 if ((err = nwam_ncp_read(NWAM_NCP_NAME_AUTOMATIC, 0, &ncph)) 1429 == NWAM_ENTITY_NOT_FOUND) { 1430 /* Automatic NCP doesn't exist, create it */ 1431 err = nwam_ncp_create(NWAM_NCP_NAME_AUTOMATIC, 0, &ncph); 1432 } 1433 if (err != NWAM_SUCCESS) 1434 goto fail; 1435 1436 /* add or remove NCUs from Automatic NCP */ 1437 if (action == NWAM_ACTION_ADD) { 1438 add_phys_ncu_to_ncp(ncph, name); 1439 add_ip_ncu_to_ncp(ncph, name); 1440 } else { 1441 /* 1442 * Order is important here, remove IP NCU first to prevent 1443 * propogation of down event from link to IP. No need to 1444 * create REFRESH or DESTROY events. They are generated by 1445 * nwam_ncu_commit() and nwam_ncu_destroy(). 1446 */ 1447 remove_ncu_from_ncp(ncph, name, NWAM_NCU_TYPE_INTERFACE); 1448 remove_ncu_from_ncp(ncph, name, NWAM_NCU_TYPE_LINK); 1449 } 1450 nwam_ncp_free(ncph); 1451 1452 /* 1453 * If the Automatic NCP is not active, and the associated NCUs 1454 * exist, they must be moved into the appropriate states given the 1455 * action that has occurred. 1456 */ 1457 if (!automatic_ncp_active) { 1458 ncu_action_change_state(action, NWAM_NCU_TYPE_INTERFACE, name); 1459 ncu_action_change_state(action, NWAM_NCU_TYPE_LINK, name); 1460 } 1461 1462 /* Need NCU check to evaluate state in light of added/removed NCUs */ 1463 if (!nwamd_event_enqueued(NWAM_EVENT_TYPE_NCU_CHECK, 1464 NWAM_OBJECT_TYPE_NCP, NULL)) { 1465 nwamd_create_ncu_check_event(NEXT_FEW_SECONDS); 1466 } 1467 1468 fail: 1469 free(name); 1470 if (err != NWAM_SUCCESS) { 1471 nwamd_event_t retry_event = nwamd_event_init_link_action(name, 1472 action); 1473 if (retry_event == NULL) { 1474 nlog(LOG_ERR, "nwamd_ncu_handle_link_action_event: " 1475 "could not create retry event to read/create " 1476 "%s NCP", NWAM_NCP_NAME_AUTOMATIC); 1477 return; 1478 } 1479 1480 nlog(LOG_ERR, "nwamd_ncu_handle_link_action_event: " 1481 "could not read/create %s NCP, retrying in %d seconds", 1482 NWAM_NCP_NAME_AUTOMATIC, NWAMD_READONLY_RETRY_INTERVAL); 1483 nwamd_event_enqueue_timed(retry_event, 1484 NWAMD_READONLY_RETRY_INTERVAL); 1485 } 1486 } 1487 1488 /* 1489 * Figure out if this link is part of an aggregation. This is fairly 1490 * inefficient since we generate this list for every query and search 1491 * linearly. A better way would be to generate the list of links in an 1492 * aggregation once and then check each link against it. 1493 */ 1494 struct link_aggr_search_data { 1495 datalink_id_t linkid; 1496 boolean_t under; 1497 }; 1498 1499 static int 1500 ncu_aggr_search(const char *name, void *data) 1501 { 1502 struct link_aggr_search_data *lasd = data; 1503 dladm_aggr_grp_attr_t ginfo; 1504 datalink_id_t linkid; 1505 int i; 1506 1507 if (dladm_name2info(dld_handle, name, &linkid, NULL, NULL, NULL) != 1508 DLADM_STATUS_OK) 1509 return (DLADM_WALK_CONTINUE); 1510 if (dladm_aggr_info(dld_handle, linkid, &ginfo, DLADM_OPT_ACTIVE) 1511 != DLADM_STATUS_OK || ginfo.lg_nports == 0) 1512 return (DLADM_WALK_CONTINUE); 1513 1514 for (i = 0; i < ginfo.lg_nports; i++) { 1515 if (lasd->linkid == ginfo.lg_ports[i].lp_linkid) { 1516 lasd->under = B_TRUE; 1517 return (DLADM_WALK_TERMINATE); 1518 } 1519 } 1520 free(ginfo.lg_ports); 1521 return (DLADM_WALK_CONTINUE); 1522 } 1523 1524 static boolean_t 1525 nwamd_link_belongs_to_an_aggr(const char *name) 1526 { 1527 struct link_aggr_search_data lasd; 1528 1529 if (dladm_name2info(dld_handle, name, &lasd.linkid, NULL, NULL, NULL) 1530 != DLADM_STATUS_OK) 1531 return (B_FALSE); 1532 lasd.under = B_FALSE; 1533 (void) dladm_walk(ncu_aggr_search, dld_handle, &lasd, 1534 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 1535 return (lasd.under); 1536 } 1537 1538 /* 1539 * If NCU doesn't exist for interface with given name, enqueue a ADD 1540 * LINK_ACTION event. 1541 */ 1542 static int 1543 ncu_create_link_action_event(const char *name, void *data) 1544 { 1545 nwam_ncp_handle_t ncph = data; 1546 nwam_ncu_handle_t ncuh; 1547 nwamd_event_t link_event; 1548 1549 /* Do not generate an event if this is a VirtualBox interface. */ 1550 if (strncmp(name, VBOX_IFACE_PREFIX, strlen(VBOX_IFACE_PREFIX)) == 0) 1551 return (DLADM_WALK_CONTINUE); 1552 1553 /* Do not generate an event if this link belongs to another zone. */ 1554 if (!nwamd_link_belongs_to_this_zone(name)) 1555 return (DLADM_WALK_CONTINUE); 1556 1557 /* Do not generate an event if this link belongs to an aggregation. */ 1558 if (nwamd_link_belongs_to_an_aggr(name)) { 1559 return (DLADM_WALK_CONTINUE); 1560 } 1561 1562 /* Don't create an event if the NCU already exists. */ 1563 if (ncph != NULL && nwam_ncu_read(ncph, name, NWAM_NCU_TYPE_LINK, 0, 1564 &ncuh) == NWAM_SUCCESS) { 1565 nwam_ncu_free(ncuh); 1566 return (DLADM_WALK_CONTINUE); 1567 } 1568 1569 nlog(LOG_DEBUG, "ncu_create_link_action_event: adding ncus for %s", 1570 name); 1571 1572 link_event = nwamd_event_init_link_action(name, NWAM_ACTION_ADD); 1573 if (link_event != NULL) 1574 nwamd_event_enqueue(link_event); 1575 1576 return (DLADM_WALK_CONTINUE); 1577 } 1578 1579 /* 1580 * Check if interface exists for this NCU. If not, enqueue a REMOVE 1581 * LINK_ACTION event. 1582 */ 1583 /* ARGSUSED */ 1584 static int 1585 nwamd_destroy_ncu(nwam_ncu_handle_t ncuh, void *data) 1586 { 1587 char *name; 1588 uint32_t flags; 1589 nwamd_event_t link_event; 1590 1591 if (nwam_ncu_get_name(ncuh, &name) != NWAM_SUCCESS) { 1592 nlog(LOG_ERR, "nwamd_destroy_ncu: could not get NCU name"); 1593 return (0); 1594 } 1595 1596 /* Interfaces that exist return DLADM_OPT_ACTIVE flag */ 1597 if ((dladm_name2info(dld_handle, name, NULL, &flags, NULL, NULL) 1598 == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) && 1599 !nwamd_link_belongs_to_an_aggr(name)) { 1600 free(name); 1601 return (0); 1602 } 1603 1604 nlog(LOG_DEBUG, "nwamd_destroy_ncu: destroying ncus for %s", name); 1605 1606 link_event = nwamd_event_init_link_action(name, NWAM_ACTION_REMOVE); 1607 if (link_event != NULL) 1608 nwamd_event_enqueue(link_event); 1609 free(name); 1610 return (0); 1611 } 1612 1613 /* 1614 * Called when nwamd is starting up. 1615 * 1616 * Walk all NCUs and destroy any NCU from the Automatic NCP without an 1617 * underlying interface (assumption here is that the interface was removed 1618 * when nwam was disabled). 1619 * 1620 * Walk the physical interfaces and create ADD LINK_ACTION event, which 1621 * will create appropriate interface and link NCUs in the Automatic NCP. 1622 */ 1623 void 1624 nwamd_walk_physical_configuration(void) 1625 { 1626 nwam_ncp_handle_t ncph; 1627 datalink_class_t dlclass = DATALINK_CLASS_PHYS; 1628 zoneid_t zoneid = getzoneid(); 1629 1630 (void) pthread_mutex_lock(&active_ncp_mutex); 1631 if (strcmp(active_ncp, NWAM_NCP_NAME_AUTOMATIC) == 0 && 1632 active_ncph != NULL) { 1633 ncph = active_ncph; 1634 } else { 1635 if (nwam_ncp_read(NWAM_NCP_NAME_AUTOMATIC, 0, &ncph) 1636 != NWAM_SUCCESS) { 1637 ncph = NULL; 1638 } 1639 } 1640 1641 /* destroy NCUs for interfaces that don't exist */ 1642 if (ncph != NULL) { 1643 (void) nwam_ncp_walk_ncus(ncph, nwamd_destroy_ncu, NULL, 1644 NWAM_FLAG_NCU_TYPE_LINK, NULL); 1645 } 1646 1647 /* In non-global zones NWAM can support VNICs */ 1648 if (zoneid != GLOBAL_ZONEID) 1649 dlclass |= DATALINK_CLASS_VNIC; 1650 1651 /* create NCUs for interfaces without NCUs */ 1652 (void) dladm_walk(ncu_create_link_action_event, dld_handle, ncph, 1653 dlclass, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 1654 1655 if (strcmp(active_ncp, NWAM_NCP_NAME_AUTOMATIC) != 0 || 1656 active_ncph == NULL) { 1657 nwam_ncp_free(ncph); 1658 } 1659 (void) pthread_mutex_unlock(&active_ncp_mutex); 1660 } 1661 1662 /* 1663 * Handle NCU initialization/refresh event. 1664 */ 1665 void 1666 nwamd_ncu_handle_init_event(nwamd_event_t event) 1667 { 1668 nwamd_object_t object = NULL; 1669 nwam_ncu_handle_t ncuh; 1670 nwamd_ncu_t *ncu = NULL; 1671 nwam_error_t err; 1672 nwam_ncu_type_t type; 1673 char *name; 1674 uint32_t flags; 1675 boolean_t new = B_TRUE; 1676 1677 nlog(LOG_DEBUG, "nwamd_ncu_handle_init_event(%s)", 1678 event->event_object); 1679 1680 /* Get base linkname rather than interface:linkname or link:linkname */ 1681 err = nwam_ncu_typed_name_to_name(event->event_object, 1682 &type, &name); 1683 if (err != NWAM_SUCCESS) { 1684 nlog(LOG_ERR, "nwamd_ncu_handle_init_event: " 1685 "nwam_ncu_typed_name_to_name returned %s", 1686 nwam_strerror(err)); 1687 nwamd_event_do_not_send(event); 1688 return; 1689 } 1690 1691 (void) pthread_mutex_lock(&active_ncp_mutex); 1692 if (active_ncph == NULL) { 1693 nlog(LOG_DEBUG, 1694 "nwamd_ncu_handle_init_event: active NCP handle NULL"); 1695 nwamd_event_do_not_send(event); 1696 free(name); 1697 (void) pthread_mutex_unlock(&active_ncp_mutex); 1698 return; 1699 } 1700 err = nwam_ncu_read(active_ncph, event->event_object, 1701 type, 0, &ncuh); 1702 (void) pthread_mutex_unlock(&active_ncp_mutex); 1703 if (err != NWAM_SUCCESS) { 1704 nlog(LOG_ERR, "nwamd_ncu_handle_init_event: " 1705 "could not read object '%s': %s", 1706 event->event_object, nwam_strerror(err)); 1707 free(name); 1708 nwamd_event_do_not_send(event); 1709 return; 1710 } 1711 1712 if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, 1713 event->event_object)) != NULL) 1714 new = B_FALSE; 1715 1716 /* 1717 * For new NCUs, or interface NCUs, we (re)initialize data from scratch. 1718 * For link NCUs, we want to retain object data. 1719 */ 1720 switch (type) { 1721 case NWAM_NCU_TYPE_LINK: 1722 if (new) { 1723 ncu = nwamd_ncu_init(type, name); 1724 } else { 1725 ncu = object->nwamd_object_data; 1726 nwam_ncu_free(object->nwamd_object_handle); 1727 } 1728 populate_common_ncu_properties(ncuh, ncu); 1729 populate_link_ncu_properties(ncuh, ncu); 1730 break; 1731 case NWAM_NCU_TYPE_INTERFACE: 1732 if (!new) { 1733 nwam_ncu_free(object->nwamd_object_handle); 1734 nwamd_ncu_free(object->nwamd_object_data); 1735 } 1736 ncu = nwamd_ncu_init(type, name); 1737 populate_common_ncu_properties(ncuh, ncu); 1738 populate_ip_ncu_properties(ncuh, ncu); 1739 break; 1740 default: 1741 nlog(LOG_ERR, "unknown ncu type %d", type); 1742 free(name); 1743 nwam_ncu_free(ncuh); 1744 nwamd_event_do_not_send(event); 1745 nwamd_object_release(object); 1746 return; 1747 } 1748 1749 if (new) { 1750 nlog(LOG_DEBUG, "nwamd_ncu_handle_init_event: didn't find " 1751 "ncu so create it %s", name); 1752 object = nwamd_object_init(NWAM_OBJECT_TYPE_NCU, 1753 event->event_object, ncuh, ncu); 1754 } else { 1755 nlog(LOG_DEBUG, "nwamd_ncu_handle_init_event: refreshing " 1756 "ncu %s", name); 1757 object->nwamd_object_data = ncu; 1758 object->nwamd_object_handle = ncuh; 1759 } 1760 1761 /* 1762 * If the physical link for this NCU doesn't exist in the system, 1763 * the state should be UNINITIALIZED/NOT_FOUND. Interfaces that 1764 * exist return DLADM_OPT_ACTIVE flag. 1765 */ 1766 if (dladm_name2info(dld_handle, name, NULL, &flags, NULL, NULL) 1767 != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) { 1768 nlog(LOG_DEBUG, "nwam_ncu_handle_init_event: " 1769 "interface for NCU %s doesn't exist", 1770 event->event_object); 1771 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 1772 object->nwamd_object_name, NWAM_STATE_UNINITIALIZED, 1773 NWAM_AUX_STATE_NOT_FOUND); 1774 free(name); 1775 nwamd_object_release(object); 1776 return; 1777 } 1778 1779 /* 1780 * If NCU is being initialized (rather than refreshed), the 1781 * object_state is INITIALIZED (from nwamd_object_init()). 1782 */ 1783 if (object->nwamd_object_state == NWAM_STATE_INITIALIZED) { 1784 /* 1785 * If the NCU is disabled, initial state should be DISABLED. 1786 * 1787 * Otherwise, the initial state will be 1788 * OFFLINE/CONDITIONS_NOT_MET, and the link selection 1789 * algorithm will do the rest. 1790 */ 1791 if (!ncu->ncu_enabled) { 1792 object->nwamd_object_state = NWAM_STATE_DISABLED; 1793 object->nwamd_object_aux_state = 1794 NWAM_AUX_STATE_MANUAL_DISABLE; 1795 } else { 1796 object->nwamd_object_state = NWAM_STATE_OFFLINE; 1797 object->nwamd_object_aux_state = 1798 NWAM_AUX_STATE_CONDITIONS_NOT_MET; 1799 } 1800 } else { 1801 nwamd_link_t *link = &ncu->ncu_link; 1802 1803 /* 1804 * Refresh NCU. Deal with disabled cases first, moving NCUs 1805 * that are not disabled - but have the enabled value set - to 1806 * the disabled state. Then handle cases where the NCU was 1807 * disabled but is no longer. Finally, deal with refresh of 1808 * link and interface NCUs, as these are handled differently. 1809 */ 1810 if (!ncu->ncu_enabled) { 1811 if (object->nwamd_object_state != NWAM_STATE_DISABLED) { 1812 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 1813 object->nwamd_object_name, 1814 NWAM_STATE_ONLINE_TO_OFFLINE, 1815 NWAM_AUX_STATE_MANUAL_DISABLE); 1816 } 1817 goto done; 1818 } else { 1819 if (object->nwamd_object_state == NWAM_STATE_DISABLED) { 1820 int64_t c; 1821 1822 /* 1823 * Try to activate the NCU if manual or 1824 * prioritized (when priority <= current). 1825 */ 1826 (void) pthread_mutex_lock(&active_ncp_mutex); 1827 c = current_ncu_priority_group; 1828 (void) pthread_mutex_unlock(&active_ncp_mutex); 1829 if (link->nwamd_link_activation_mode == 1830 NWAM_ACTIVATION_MODE_MANUAL || 1831 (link->nwamd_link_activation_mode == 1832 NWAM_ACTIVATION_MODE_PRIORITIZED && 1833 link->nwamd_link_priority_mode <= c)) { 1834 nwamd_object_set_state 1835 (NWAM_OBJECT_TYPE_NCU, 1836 object->nwamd_object_name, 1837 NWAM_STATE_OFFLINE_TO_ONLINE, 1838 NWAM_AUX_STATE_INITIALIZED); 1839 } else { 1840 nwamd_object_set_state 1841 (NWAM_OBJECT_TYPE_NCU, 1842 object->nwamd_object_name, 1843 NWAM_STATE_OFFLINE_TO_ONLINE, 1844 NWAM_AUX_STATE_INITIALIZED); 1845 } 1846 goto done; 1847 } 1848 } 1849 1850 switch (type) { 1851 case NWAM_NCU_TYPE_LINK: 1852 if (ncu->ncu_link.nwamd_link_media == DL_WIFI) { 1853 /* 1854 * Do rescan. If the current state and the 1855 * active priority-group do not allow wireless 1856 * network selection, then it won't happen. 1857 */ 1858 (void) nwamd_wlan_scan(ncu->ncu_name); 1859 } 1860 break; 1861 case NWAM_NCU_TYPE_INTERFACE: 1862 /* 1863 * If interface NCU is offline*, online or in 1864 * maintenance, mark it down (from there, it will be 1865 * reinitialized to reapply addresses). 1866 */ 1867 if (object->nwamd_object_state != NWAM_STATE_OFFLINE) { 1868 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 1869 object->nwamd_object_name, 1870 NWAM_STATE_ONLINE_TO_OFFLINE, 1871 NWAM_AUX_STATE_DOWN); 1872 } else { 1873 object->nwamd_object_state = NWAM_STATE_OFFLINE; 1874 object->nwamd_object_aux_state = 1875 NWAM_AUX_STATE_CONDITIONS_NOT_MET; 1876 } 1877 break; 1878 } 1879 } 1880 1881 done: 1882 if (type == NWAM_NCU_TYPE_LINK && 1883 !nwamd_event_enqueued(NWAM_EVENT_TYPE_NCU_CHECK, 1884 NWAM_OBJECT_TYPE_NCP, NULL)) { 1885 nwamd_create_ncu_check_event(NEXT_FEW_SECONDS); 1886 } 1887 free(name); 1888 nwamd_object_release(object); 1889 } 1890 1891 void 1892 nwamd_ncu_handle_fini_event(nwamd_event_t event) 1893 { 1894 nwamd_object_t object; 1895 nwamd_event_t state_event; 1896 1897 nlog(LOG_DEBUG, "nwamd_ncu_handle_fini_event(%s)", 1898 event->event_object); 1899 1900 /* 1901 * Simulate a state event so that the state machine can correctly 1902 * disable the NCU. Then free up allocated objects. 1903 */ 1904 state_event = nwamd_event_init_object_state(NWAM_OBJECT_TYPE_NCU, 1905 event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE, 1906 NWAM_AUX_STATE_UNINITIALIZED); 1907 if (state_event == NULL) { 1908 nwamd_event_do_not_send(event); 1909 return; 1910 } 1911 nwamd_ncu_handle_state_event(state_event); 1912 nwamd_event_fini(state_event); 1913 1914 if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, 1915 event->event_object)) == NULL) { 1916 nlog(LOG_INFO, "nwamd_ncu_handle_fini_event: " 1917 "ncu %s not found", event->event_object); 1918 nwamd_event_do_not_send(event); 1919 return; 1920 } 1921 nwamd_object_release_and_destroy(object); 1922 } 1923 1924 void 1925 nwamd_ncu_handle_action_event(nwamd_event_t event) 1926 { 1927 nwamd_object_t object; 1928 1929 (void) pthread_mutex_lock(&active_ncp_mutex); 1930 if (strcmp(event->event_msg->nwe_data.nwe_object_action.nwe_parent, 1931 active_ncp) != 0) { 1932 nlog(LOG_DEBUG, "nwamd_ncu_handle_action_event: action for " 1933 "inactive NCP %s, nothing to do", 1934 event->event_msg->nwe_data.nwe_object_action.nwe_parent); 1935 (void) pthread_mutex_unlock(&active_ncp_mutex); 1936 return; 1937 } 1938 (void) pthread_mutex_unlock(&active_ncp_mutex); 1939 1940 switch (event->event_msg->nwe_data.nwe_object_action.nwe_action) { 1941 case NWAM_ACTION_ENABLE: 1942 object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, 1943 event->event_object); 1944 if (object == NULL) { 1945 nlog(LOG_ERR, "nwamd_ncu_handle_action_event: " 1946 "could not find ncu %s", event->event_object); 1947 nwamd_event_do_not_send(event); 1948 return; 1949 } 1950 if (object->nwamd_object_state == NWAM_STATE_ONLINE) { 1951 nlog(LOG_DEBUG, "nwamd_ncu_handle_action_event: " 1952 "ncu %s already online, nothing to do", 1953 event->event_object); 1954 nwamd_object_release(object); 1955 return; 1956 } 1957 nwamd_object_release(object); 1958 1959 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 1960 event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE, 1961 NWAM_AUX_STATE_INITIALIZED); 1962 break; 1963 case NWAM_ACTION_DISABLE: 1964 object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, 1965 event->event_object); 1966 if (object == NULL) { 1967 nlog(LOG_ERR, "nwamd_ncu_handle_action_event: " 1968 "could not find ncu %s", event->event_object); 1969 nwamd_event_do_not_send(event); 1970 return; 1971 } 1972 if (object->nwamd_object_state == NWAM_STATE_DISABLED) { 1973 nlog(LOG_DEBUG, "nwamd_ncu_handle_action_event: " 1974 "ncu %s already disabled, nothing to do", 1975 event->event_object); 1976 nwamd_object_release(object); 1977 return; 1978 } 1979 nwamd_object_release(object); 1980 1981 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 1982 event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE, 1983 NWAM_AUX_STATE_MANUAL_DISABLE); 1984 break; 1985 case NWAM_ACTION_ADD: 1986 case NWAM_ACTION_REFRESH: 1987 nwamd_ncu_handle_init_event(event); 1988 break; 1989 case NWAM_ACTION_DESTROY: 1990 nwamd_ncu_handle_fini_event(event); 1991 break; 1992 default: 1993 nlog(LOG_INFO, "nwam_ncu_handle_action_event: " 1994 "unexpected action"); 1995 nwamd_event_do_not_send(event); 1996 break; 1997 } 1998 } 1999 2000 void 2001 nwamd_ncu_handle_state_event(nwamd_event_t event) 2002 { 2003 nwamd_object_t object; 2004 nwam_state_t old_state, new_state; 2005 nwam_aux_state_t new_aux_state; 2006 nwamd_ncu_t *ncu; 2007 boolean_t is_link, enabled, prioritized = B_FALSE; 2008 char linkname[NWAM_MAX_NAME_LEN]; 2009 nwam_event_t m = event->event_msg; 2010 2011 if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, 2012 event->event_object)) == NULL) { 2013 nlog(LOG_INFO, "nwamd_ncu_handle_state_event %lld: " 2014 "state event for nonexistent NCU %s", event->event_id, 2015 event->event_object); 2016 nwamd_event_do_not_send(event); 2017 return; 2018 } 2019 ncu = object->nwamd_object_data; 2020 old_state = object->nwamd_object_state; 2021 new_state = event->event_msg->nwe_data.nwe_object_state.nwe_state; 2022 new_aux_state = 2023 event->event_msg->nwe_data.nwe_object_state.nwe_aux_state; 2024 2025 /* 2026 * For NCU state changes, we need to supply the parent NCP name also, 2027 * regardless of whether the event is handled or not. It is best to 2028 * fill this in here as we have the object lock - when we create 2029 * object state events we sometimes do not have the object lock, but 2030 * at this point in consuming the events (and prior to the associated 2031 * event message being sent out) we do. 2032 */ 2033 (void) strlcpy(m->nwe_data.nwe_object_state.nwe_parent, ncu->ncu_parent, 2034 sizeof (m->nwe_data.nwe_object_state.nwe_parent)); 2035 2036 /* 2037 * If we receive a state change event moving this NCU to 2038 * DHCP_TIMED_OUT or UP state but this NCU is already ONLINE, then 2039 * ignore this state change event. 2040 */ 2041 if ((new_aux_state == NWAM_AUX_STATE_IF_DHCP_TIMED_OUT || 2042 new_aux_state == NWAM_AUX_STATE_UP) && 2043 object->nwamd_object_state == NWAM_STATE_ONLINE) { 2044 nlog(LOG_INFO, "nwamd_ncu_handle_state_event: " 2045 "NCU %s already online, not going to '%s' state", 2046 object->nwamd_object_name, 2047 nwam_aux_state_to_string(new_aux_state)); 2048 nwamd_event_do_not_send(event); 2049 nwamd_object_release(object); 2050 return; 2051 } 2052 2053 if (new_state == object->nwamd_object_state && 2054 new_aux_state == object->nwamd_object_aux_state) { 2055 nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: " 2056 "NCU %s already in state (%s, %s)", 2057 object->nwamd_object_name, nwam_state_to_string(new_state), 2058 nwam_aux_state_to_string(new_aux_state)); 2059 nwamd_object_release(object); 2060 return; 2061 } 2062 2063 if (old_state == NWAM_STATE_MAINTENANCE && 2064 (new_state == NWAM_STATE_ONLINE || 2065 (new_state == NWAM_STATE_OFFLINE_TO_ONLINE && 2066 new_aux_state != NWAM_AUX_STATE_INITIALIZED))) { 2067 nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: " 2068 "NCU %s cannot transition from state %s to state (%s, %s)", 2069 object->nwamd_object_name, nwam_state_to_string(old_state), 2070 nwam_state_to_string(new_state), 2071 nwam_aux_state_to_string(new_aux_state)); 2072 nwamd_event_do_not_send(event); 2073 nwamd_object_release(object); 2074 return; 2075 } 2076 2077 object->nwamd_object_state = new_state; 2078 object->nwamd_object_aux_state = new_aux_state; 2079 2080 nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: changing state for NCU " 2081 "%s to (%s, %s)", object->nwamd_object_name, 2082 nwam_state_to_string(object->nwamd_object_state), 2083 nwam_aux_state_to_string(object->nwamd_object_aux_state)); 2084 2085 is_link = (ncu->ncu_type == NWAM_NCU_TYPE_LINK); 2086 if (is_link) 2087 (void) strlcpy(linkname, ncu->ncu_name, sizeof (linkname)); 2088 prioritized = (ncu->ncu_type == NWAM_NCU_TYPE_LINK && 2089 ncu->ncu_link.nwamd_link_activation_mode == 2090 NWAM_ACTIVATION_MODE_PRIORITIZED); 2091 enabled = ncu->ncu_enabled; 2092 2093 nwamd_object_release(object); 2094 2095 /* 2096 * State machine for NCUs 2097 */ 2098 switch (new_state) { 2099 case NWAM_STATE_OFFLINE_TO_ONLINE: 2100 if (enabled) { 2101 nwamd_ncu_state_machine(event->event_object); 2102 } else { 2103 nlog(LOG_DEBUG, "nwamd_ncu_handle_state_event: " 2104 "cannot move disabled NCU %s online", 2105 event->event_object); 2106 nwamd_event_do_not_send(event); 2107 } 2108 break; 2109 2110 case NWAM_STATE_ONLINE_TO_OFFLINE: 2111 nwamd_ncu_state_machine(event->event_object); 2112 break; 2113 2114 case NWAM_STATE_ONLINE: 2115 /* 2116 * We usually don't need to do anything when we're in the 2117 * ONLINE state. However, for WiFi we can be in INIT or 2118 * SCAN aux states while being ONLINE. 2119 */ 2120 nwamd_ncu_state_machine(event->event_object); 2121 break; 2122 2123 case NWAM_STATE_OFFLINE: 2124 /* Reassess priority group now member is offline */ 2125 if (prioritized) { 2126 nwamd_create_ncu_check_event(0); 2127 } 2128 break; 2129 2130 case NWAM_STATE_DISABLED: 2131 case NWAM_STATE_UNINITIALIZED: 2132 case NWAM_STATE_MAINTENANCE: 2133 case NWAM_STATE_DEGRADED: 2134 default: 2135 /* do nothing */ 2136 break; 2137 } 2138 2139 if (is_link) { 2140 if ((new_state == NWAM_STATE_ONLINE_TO_OFFLINE && 2141 new_aux_state != NWAM_AUX_STATE_UNINITIALIZED && 2142 new_aux_state != NWAM_AUX_STATE_NOT_FOUND) || 2143 new_state == NWAM_STATE_DISABLED) { 2144 /* 2145 * Going offline, propogate down event to IP NCU. Do 2146 * not propogate event if new aux state is uninitialized 2147 * or not found as these auxiliary states signify 2148 * that an NCP switch/device removal is in progress. 2149 */ 2150 nwamd_propogate_link_up_down_to_ip(linkname, B_FALSE); 2151 } 2152 if (new_state == NWAM_STATE_ONLINE) { 2153 /* gone online, propogate up event to IP NCU */ 2154 nwamd_propogate_link_up_down_to_ip(linkname, B_TRUE); 2155 } 2156 } else { 2157 /* If IP NCU is online, reasses priority group */ 2158 if (new_state == NWAM_STATE_ONLINE) 2159 nwamd_create_ncu_check_event(0); 2160 } 2161 } 2162