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
nwamd_ncu_object_find(nwam_ncu_type_t type,const char * name)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
nwamd_set_ncu_string(nwam_ncu_handle_t ncuh,char ** strval,uint_t cnt,const char * prop)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
nwamd_set_ncu_uint(nwam_ncu_handle_t ncuh,uint64_t * uintval,uint_t cnt,const char * prop)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
nwamd_get_ncu_string(nwam_ncu_handle_t ncuh,nwam_value_t * val,char *** strval,uint_t * cnt,const char * prop)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
nwamd_get_ncu_uint(nwam_ncu_handle_t ncuh,nwam_value_t * val,uint64_t ** uintval,uint_t * cnt,const char * prop)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
nwamd_get_ncu_boolean(nwam_ncu_handle_t ncuh,nwam_value_t * val,boolean_t ** boolval,uint_t * cnt,const char * prop)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
nwamd_ncu_state_machine(const char * object_name)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
ncu_create_init_fini_event(nwam_ncu_handle_t ncuh,void * data)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
nwamd_init_ncus(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
nwamd_fini_ncus(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
populate_common_ncu_properties(nwam_ncu_handle_t ncuh,nwamd_ncu_t * ncu_data)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
populate_link_ncu_properties(nwam_ncu_handle_t ncuh,nwamd_ncu_t * ncu_data)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
populate_ip_ncu_properties(nwam_ncu_handle_t ncuh,nwamd_ncu_t * ncu_data)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 *
nwamd_ncu_init(nwam_ncu_type_t ncu_type,const char * name)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
nwamd_ncu_free(nwamd_ncu_t * ncu)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
nwamd_ncu_display(nwamd_object_t ncu_obj,void * data)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
nwamd_log_ncus(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
nwamd_ncu_action(const char * ncu,const char * parent,nwam_action_t action)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
add_phys_ncu_to_ncp(nwam_ncp_handle_t ncph,const char * name)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
add_ip_ncu_to_ncp(nwam_ncp_handle_t ncph,const char * name)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
remove_ncu_from_ncp(nwam_ncp_handle_t ncph,const char * name,nwam_ncu_type_t type)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
ncu_action_change_state(nwam_action_t action,nwam_ncu_type_t type,const char * name)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
nwamd_ncu_handle_link_action_event(nwamd_event_t event)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
ncu_aggr_search(const char * name,void * data)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
nwamd_link_belongs_to_an_aggr(const char * name)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
ncu_create_link_action_event(const char * name,void * data)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
nwamd_destroy_ncu(nwam_ncu_handle_t ncuh,void * data)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
nwamd_walk_physical_configuration(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
nwamd_ncu_handle_init_event(nwamd_event_t event)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
nwamd_ncu_handle_fini_event(nwamd_event_t event)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
nwamd_ncu_handle_action_event(nwamd_event_t event)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
nwamd_ncu_handle_state_event(nwamd_event_t event)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