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