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