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