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