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.
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.
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]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <arpa/inet.h>
28 #include <dhcpagent_ipc.h>
29 #include <dhcp_inittab.h>
30 #include <dhcp_symbol.h>
31 #include <dhcpagent_util.h>
41 #include "conditions.h"
49 * ncu_ip.c - contains routines that are IP interface-specific for NCUs.
52 #define STATELESS_RUNNING (IFF_RUNNING | IFF_UP | IFF_ADDRCONF)
53 #define DHCP_RUNNING (IFF_RUNNING | IFF_UP | IFF_DHCPRUNNING)
55 static void nwamd_dhcp(const char *, ipadm_addrobj_t
, dhcp_ipc_type_t
);
56 static void nwamd_down_interface(const char *, ipadm_addr_type_t
, const char *);
57 static boolean_t
stateless_running(const nwamd_ncu_t
*);
60 * Given a sockaddr representation of an IPv4 or IPv6 address returns the
61 * string representation. Note that 'sockaddr' should point at the correct
62 * sockaddr structure for the address family (sockaddr_in for AF_INET or
63 * sockaddr_in6 for AF_INET6) or alternatively at a sockaddr_storage
67 nwamd_sockaddr2str(const struct sockaddr
*addr
, char *str
, size_t len
)
69 struct sockaddr_in
*sin
;
70 struct sockaddr_in6
*sin6
;
76 if (addr
->sa_family
== AF_INET
) {
77 /* LINTED E_BAD_PTR_CAST_ALIGN */
78 sin
= (struct sockaddr_in
*)addr
;
79 straddr
= inet_ntop(AF_INET
, (void *)&sin
->sin_addr
, str
, len
);
80 } else if (addr
->sa_family
== AF_INET6
) {
81 /* LINTED E_BAD_PTR_CAST_ALIGN */
82 sin6
= (struct sockaddr_in6
*)addr
;
83 straddr
= inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
, str
,
89 return (straddr
!= NULL
? str
: NULL
);
93 nwamd_propogate_link_up_down_to_ip(const char *linkname
, boolean_t up
)
95 nwamd_object_t ip_ncu
= nwamd_ncu_object_find(NWAM_NCU_TYPE_INTERFACE
,
100 nlog(LOG_DEBUG
, "nwamd_propogate_link_up_down_to_ip: no IP NCU "
101 "for link %s, cannot propogate %s event", linkname
,
105 ncu
= ip_ncu
->nwamd_object_data
;
107 if (ncu
->ncu_enabled
) {
108 if (ip_ncu
->nwamd_object_aux_state
==
109 NWAM_AUX_STATE_UNINITIALIZED
) {
111 "nwamd_propogate_link_up_down_to_ip: will not "
112 "propogate link %s event as IP NCU %s is being "
113 "removed", up
? "up" : "down", linkname
);
116 "nwamd_propogate_link_up_down_to_ip: propogating "
117 "link %s event to interface %s",
118 up
? "up" : "down", linkname
);
119 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
120 ip_ncu
->nwamd_object_name
,
122 NWAM_STATE_OFFLINE_TO_ONLINE
:
123 NWAM_STATE_ONLINE_TO_OFFLINE
,
124 up
? NWAM_AUX_STATE_INITIALIZED
:
125 NWAM_AUX_STATE_CONDITIONS_NOT_MET
);
129 "nwamd_propogate_link_up_down_to_ip: not propogating "
130 "link %s event to interface %s, IP NCU is disabled",
131 up
? "up" : "down", linkname
);
133 nwamd_object_release(ip_ncu
);
137 * Returns the value associated with the given symbol for the given
138 * interface. The interface may be NULL, in which case the primary
140 * This function substitutes the need to call dhcpinfo(1), thus it is
141 * very similar to the implementation of dhcpinfo(1).
142 * When multiple values need to be returned (e.g., nameservers), they
143 * are separated by a space ' '.
146 nwamd_get_dhcpinfo_data(const char *sym_name
, char *ifname
)
148 dhcp_symbol_t
*entry
;
149 dhcp_optnum_t optnum
;
150 dhcp_ipc_request_t
*request
;
151 dhcp_ipc_reply_t
*reply
;
154 char *value
; /* return value */
156 char errmsg
[LINE_MAX
];
158 /* if interface is not given, change it to empty string */
162 /* find code and category in dhcp_inittab(4) */
163 entry
= inittab_getbyname(ITAB_CAT_SITE
| ITAB_CAT_STANDARD
|
164 ITAB_CAT_VENDOR
| ITAB_CAT_FIELD
, ITAB_CONS_INFO
, sym_name
);
167 (void) snprintf(errmsg
, LINE_MAX
, "unknown identifier: %s",
172 /* allocate request */
173 optnum
.code
= entry
->ds_code
;
174 optnum
.category
= entry
->ds_category
;
175 optnum
.size
= entry
->ds_max
* inittab_type_to_size(entry
);
176 request
= dhcp_ipc_alloc_request(DHCP_GET_TAG
, ifname
, &optnum
,
177 sizeof (dhcp_optnum_t
), DHCP_TYPE_OPTNUM
);
178 if (request
== NULL
) {
179 (void) snprintf(errmsg
, LINE_MAX
, "failed dhcp alloc request");
183 /* make the request */
184 err
= dhcp_ipc_make_request(request
, &reply
, DHCP_IPC_WAIT_DEFAULT
);
185 if (err
!= 0 || reply
->return_code
!= 0) {
186 (void) snprintf(errmsg
, LINE_MAX
, "%s",
187 dhcp_ipc_strerror(err
== 0 ? reply
->return_code
: err
));
190 /* get data from the reply */
191 opt
= dhcp_ipc_get_data(reply
, &opt_len
, NULL
);
193 (void) snprintf(errmsg
, LINE_MAX
, "invalid data");
197 /* check protocol error */
198 if (opt_len
< 2 || (opt_len
-2 != opt
->len
)) {
199 (void) snprintf(errmsg
, LINE_MAX
, "data length mismatch");
204 /* decode the data into ascii */
205 value
= inittab_decode(entry
, opt
->value
, opt_len
, B_TRUE
);
207 (void) snprintf(errmsg
, LINE_MAX
, "cannot decode reply");
216 nlog(LOG_DEBUG
, "get_dhcpinfo_data() failed: %s", errmsg
);
223 nwamd_add_default_routes(nwamd_ncu_t
*ncu
)
225 nwamd_if_t
*nif
= &ncu
->ncu_if
;
226 char str
[INET6_ADDRSTRLEN
];
228 if (nif
->nwamd_if_ipv4
&& nif
->nwamd_if_ipv4_default_route_set
) {
229 struct sockaddr_in v4dest
, v4mask
;
231 v4dest
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
232 v4dest
.sin_family
= AF_INET
;
234 v4mask
.sin_addr
.s_addr
= 0;
235 v4mask
.sin_family
= AF_INET
;
237 nlog(LOG_DEBUG
, "nwamd_add_default_routes: adding default "
238 "route %s", nwamd_sockaddr2str((struct sockaddr
*)
239 &nif
->nwamd_if_ipv4_default_route
, str
,
241 nwamd_add_route((struct sockaddr
*)&v4dest
,
242 (struct sockaddr
*)&v4mask
,
243 (struct sockaddr
*)&nif
->nwamd_if_ipv4_default_route
,
247 if (nif
->nwamd_if_ipv6
&& nif
->nwamd_if_ipv6_default_route_set
) {
248 struct sockaddr_in6 v6dest
, v6mask
;
250 (void) bzero(&v6dest
, sizeof (struct sockaddr_in6
));
251 v6dest
.sin6_family
= AF_INET6
;
253 (void) bzero(&v6mask
, sizeof (struct sockaddr_in6
));
254 v6mask
.sin6_family
= AF_INET6
;
256 nlog(LOG_DEBUG
, "nwamd_add_default_routes: adding default "
257 "route %s", nwamd_sockaddr2str((struct sockaddr
*)
258 &nif
->nwamd_if_ipv6_default_route
, str
,
260 nwamd_add_route((struct sockaddr
*)&v6dest
,
261 (struct sockaddr
*)&v6mask
,
262 (struct sockaddr
*)&nif
->nwamd_if_ipv6_default_route
,
268 * Returns the nwamd_if_address structure for the given static address,
271 static struct nwamd_if_address
*
272 find_static_address(const struct sockaddr_storage
*addr
, const nwamd_ncu_t
*ncu
)
274 struct nwamd_if_address
*nifap
, *nifa
= ncu
->ncu_if
.nwamd_if_list
;
275 struct sockaddr_storage saddr
;
276 char str
[INET6_ADDRSTRLEN
];
278 nlog(LOG_DEBUG
, "find_static_address: %s",
279 nwamd_sockaddr2str((struct sockaddr
*)addr
, str
, sizeof (str
)));
280 for (nifap
= nifa
; nifap
!= NULL
; nifap
= nifap
->next
) {
281 if (nifap
->ipaddr_atype
!= IPADM_ADDR_STATIC
||
282 ipadm_get_addr(nifap
->ipaddr
, &saddr
) != IPADM_SUCCESS
)
285 if (sockaddrcmp(addr
, &saddr
))
292 * Returns the nwamd_if_address structure representing the non-static address
293 * in the NCU. For IPv6, both stateless and stateful (DHCPv6) share the same
294 * nwamd_if_address. Will only return the nwamd_if_address if the relevant
295 * address is configured (v4 DHCP, v6 either stateless or stateless) for the
296 * NCU. Returns NULL if the structure is not found.
298 static struct nwamd_if_address
*
299 find_nonstatic_address(const nwamd_ncu_t
*ncu
, sa_family_t family
)
301 struct nwamd_if_address
*nifap
, *nifa
= ncu
->ncu_if
.nwamd_if_list
;
302 const nwamd_if_t
*u_if
= &ncu
->ncu_if
;
304 nlog(LOG_DEBUG
, "find_nonstatic_address for %s %s",
305 (family
== AF_INET
? "IPv4" : "IPv6"), ncu
->ncu_name
);
306 for (nifap
= nifa
; nifap
!= NULL
; nifap
= nifap
->next
) {
307 if (nifap
->ipaddr_atype
== IPADM_ADDR_STATIC
)
310 if (family
== AF_INET
) {
311 if (nifap
->ipaddr_atype
== IPADM_ADDR_DHCP
&&
312 u_if
->nwamd_if_dhcp_requested
)
314 } else if (family
== AF_INET6
) {
315 if (nifap
->ipaddr_atype
== IPADM_ADDR_IPV6_ADDRCONF
&&
316 (u_if
->nwamd_if_stateful_requested
||
317 u_if
->nwamd_if_stateless_requested
))
325 * Returns the nwamd_if_address structure that configured the given address,
328 static struct nwamd_if_address
*
329 find_configured_address(const struct sockaddr_storage
*addr
,
330 const nwamd_ncu_t
*ncu
)
332 struct nwamd_if_address
*nifap
, *nifa
= ncu
->ncu_if
.nwamd_if_list
;
333 char str
[INET6_ADDRSTRLEN
];
335 nlog(LOG_DEBUG
, "find_configured_address: %s",
336 nwamd_sockaddr2str((struct sockaddr
*)addr
, str
, sizeof (str
)));
337 for (nifap
= nifa
; nifap
!= NULL
; nifap
= nifap
->next
) {
338 if (sockaddrcmp(addr
, &nifap
->conf_addr
) ||
339 sockaddrcmp(addr
, &nifap
->conf_stateless_addr
))
346 * Are one or more static addresses configured?
349 nwamd_static_addresses_configured(nwamd_ncu_t
*ncu
, sa_family_t family
)
351 struct nwamd_if_address
*n
;
353 for (n
= ncu
->ncu_if
.nwamd_if_list
; n
!= NULL
; n
= n
->next
) {
354 if (n
->ipaddr_atype
!= IPADM_ADDR_STATIC
)
356 if ((family
== AF_UNSPEC
|| family
== n
->family
) &&
360 nlog(LOG_DEBUG
, "no static addresses configured for %s", ncu
->ncu_name
);
365 * Is DHCP probably managing an address on this index. We decide that it is
366 * probably managing an address if there is an interface with IFF_DHCP set
367 * that isn't in our set of static addresses. Note that IFF_DHCP gets set
368 * on static addresses when we do a dhcp inform and if that list has changed
369 * recently then the result of this function could be erronous.
372 nwamd_dhcp_managing(int protocol
, nwamd_ncu_t
*ncu
)
374 struct sockaddr_storage addr
;
376 boolean_t rv
= B_FALSE
;
377 ipadm_addr_info_t
*addrinfo
, *a
;
378 ipadm_status_t ipstatus
;
380 if ((ipstatus
= ipadm_addr_info(ipadm_handle
, ncu
->ncu_name
, &addrinfo
,
381 0, 0)) != IPADM_SUCCESS
) {
382 nlog(LOG_ERR
, "nwamd_dhcp_managing: "
383 "ipadm_addr_info failed for %s: %s",
384 ncu
->ncu_name
, ipadm_status2str(ipstatus
));
388 for (a
= addrinfo
; a
!= NULL
; a
= IA_NEXT(a
)) {
390 * WARNING: This memcpy() assumes knowledge of the
391 * implementation of getifaddrs() and that it always
392 * uses sockaddr_storage as the backing store for
393 * address information, thus making it possible to
394 * copy the entire structure rather than do it on
395 * the size of the sockaddr according to family.
396 * This assumption is made elsewhere in this file.
398 (void) memcpy(&addr
, a
->ia_ifa
.ifa_addr
, sizeof (addr
));
400 /* is this address an expected static one? */
401 if (find_static_address(&addr
, ncu
) != NULL
)
405 * For IPv4, DHCPRUNNING flag is set when dhcpagent is in
406 * the process of getting an address, but doesn't have one
407 * yet (interface has 0.0.0.0). For IPv6, DHCPRUNNING flag
408 * is set on the link-local address if trying to get a
409 * stateful address. In both cases, consider the interface
410 * as not being managed by DHCP and skip checking of flags.
412 if ((protocol
== AF_INET
&&
413 ((struct sockaddr_in
*)&addr
)->sin_addr
.s_addr
==
415 (protocol
== AF_INET6
&&
416 IN6_IS_ADDR_LINKLOCAL(
417 &((struct sockaddr_in6
*)&addr
)->sin6_addr
))) {
421 flags
= a
->ia_ifa
.ifa_flags
;
422 if (flags
& IFF_DHCPRUNNING
) {
424 * If we get here we have an address that has the
425 * DHCP flag set and isn't an expected static address.
432 ipadm_free_addr_info(addrinfo
);
437 * Return B_TRUE if IPv4 is requested in the given NCU.
440 nwamd_v4_requested(nwamd_ncu_t
*ncu
)
442 boolean_t anyv4_requested
;
445 anyv4_requested
= B_FALSE
;
447 if (u_if
->nwamd_if_dhcp_requested
) {
448 anyv4_requested
= B_TRUE
;
450 struct nwamd_if_address
*n
;
452 for (n
= u_if
->nwamd_if_list
; n
!= NULL
; n
= n
->next
) {
453 if (n
->family
== AF_INET
&&
454 n
->ipaddr_atype
== IPADM_ADDR_STATIC
)
458 anyv4_requested
= B_TRUE
;
461 return (anyv4_requested
);
465 * Returns B_TRUE if IPv6 is requested in the given NCU.
468 nwamd_v6_requested(nwamd_ncu_t
*ncu
)
470 boolean_t anyv6_requested
;
473 anyv6_requested
= B_FALSE
;
475 if (u_if
->nwamd_if_stateful_requested
||
476 u_if
->nwamd_if_stateless_requested
) {
477 anyv6_requested
= B_TRUE
;
479 struct nwamd_if_address
*n
;
481 for (n
= u_if
->nwamd_if_list
; n
!= NULL
; n
= n
->next
) {
482 if (n
->family
== AF_INET6
&&
483 n
->ipaddr_atype
== IPADM_ADDR_STATIC
)
487 anyv6_requested
= B_TRUE
;
490 return (anyv6_requested
);
494 * Bring up the ncu if we have the right combination of requested configuration
495 * and actual configuration and up is true, or bring down the ncu if no
496 * addresses are configured, and up is false.
499 interface_ncu_up_down(nwamd_ncu_t
*ncu
, boolean_t up
)
501 boolean_t ncu_online
;
504 assert(ncu
->ncu_type
== NWAM_NCU_TYPE_INTERFACE
);
507 * If V4 with or without V6 is configured then one of its interfaces
508 * needs to be up for the ncu to come online. If only V6 is requested
509 * then one of its interfaces needs to be up for the ncu to come online.
511 ncu_online
= B_FALSE
;
512 if (nwamd_v4_requested(ncu
)) {
513 if (nwamd_dhcp_managing(AF_INET
, ncu
) ||
514 nwamd_static_addresses_configured(ncu
, AF_INET
))
516 } else if (nwamd_v6_requested(ncu
)) {
517 if ((nwamd_dhcp_managing(AF_INET6
, ncu
) ||
518 stateless_running(ncu
) ||
519 nwamd_static_addresses_configured(ncu
, AF_INET6
)))
523 if (nwam_ncu_name_to_typed_name(ncu
->ncu_name
, ncu
->ncu_type
, &name
) !=
525 nlog(LOG_DEBUG
, "interface_ncu_up_down: "
526 "nwam_ncu_name_to_typed_name failed");
529 if (ncu_online
&& up
) {
530 nlog(LOG_DEBUG
, "interface_ncu_up_down: "
531 "bringing %s up", name
);
532 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
, name
,
533 NWAM_STATE_OFFLINE_TO_ONLINE
, NWAM_AUX_STATE_UP
);
534 } else if (!ncu_online
&& !up
) {
535 nlog(LOG_DEBUG
, "interface_ncu_up_down: "
536 "bringing %s down", name
);
537 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
, name
,
538 NWAM_STATE_ONLINE_TO_OFFLINE
,
539 NWAM_AUX_STATE_DOWN
);
546 interface_ncu_up(nwamd_ncu_t
*ncu
)
548 interface_ncu_up_down(ncu
, B_TRUE
);
552 interface_ncu_down(nwamd_ncu_t
*ncu
)
554 interface_ncu_up_down(ncu
, B_FALSE
);
558 stateless_running(const nwamd_ncu_t
*ncu
)
560 ipadm_addr_info_t
*ainfo
, *ainfop
;
561 ipadm_status_t ipstatus
;
562 boolean_t rv
= B_FALSE
;
565 if ((ipstatus
= ipadm_addr_info(ipadm_handle
, ncu
->ncu_name
, &ainfo
,
566 0, 0)) != IPADM_SUCCESS
) {
567 nlog(LOG_ERR
, "stateless_running: "
568 "ipadm_addr_info failed for %s: %s",
569 ncu
->ncu_name
, ipadm_status2str(ipstatus
));
573 for (ainfop
= ainfo
; ainfop
!= NULL
; ainfop
= IA_NEXT(ainfop
)) {
574 if (ainfop
->ia_ifa
.ifa_addr
->sa_family
!= AF_INET6
)
576 flags
= ainfop
->ia_ifa
.ifa_flags
;
577 if (flags
& STATELESS_RUNNING
) {
582 ipadm_free_addr_info(ainfo
);
587 * Returns the addrinfo associated with the given address. There is always
588 * only one addrinfo for each address.
591 addrinfo_for_addr(const struct sockaddr_storage
*caddr
, const char *ifname
,
592 ipadm_addr_info_t
**ainfo
)
594 ipadm_addr_info_t
*addrinfo
, *ainfop
, *last
= NULL
;
595 ipadm_status_t ipstatus
;
597 ipstatus
= ipadm_addr_info(ipadm_handle
, ifname
, &addrinfo
, 0, 0);
598 if (ipstatus
!= IPADM_SUCCESS
) {
599 nlog(LOG_INFO
, "addrinfo_for_addr: "
600 "ipadm_addr_info failed for %s: %s",
601 ifname
, ipadm_status2str(ipstatus
));
606 for (ainfop
= addrinfo
; ainfop
!= NULL
; ainfop
= IA_NEXT(ainfop
)) {
607 struct sockaddr_storage addr
;
609 (void) memcpy(&addr
, ainfop
->ia_ifa
.ifa_addr
, sizeof (addr
));
611 * If addresses match, rearrange pointers so that addrinfo
612 * does not contain a, and return a.
614 if (sockaddrcmp(&addr
, caddr
)) {
616 last
->ia_ifa
.ifa_next
= ainfop
->ia_ifa
.ifa_next
;
618 addrinfo
= IA_NEXT(ainfop
);
620 ainfop
->ia_ifa
.ifa_next
= NULL
;
626 ipadm_free_addr_info(addrinfo
);
627 return (*ainfo
== NULL
? B_FALSE
: B_TRUE
);
631 * Returns B_TRUE if the addrinfo associated with the given ipaddr using its
632 * aobjname is found. An addrinfo list is created and returned in ainfo.
633 * Stateless and stateful IPv6 addrinfo have the same aobjname, thus the need
634 * to create a list of addrinfo.
637 addrinfo_for_ipaddr(ipadm_addrobj_t ipaddr
, const char *ifname
,
638 ipadm_addr_info_t
**ainfo
)
640 char aobjname
[IPADM_AOBJSIZ
];
641 ipadm_addr_info_t
*addrinfo
, *ainfop
;
642 ipadm_addr_info_t
*last
= NULL
;
643 ipadm_status_t ipstatus
;
645 ipstatus
= ipadm_get_aobjname(ipaddr
, aobjname
, sizeof (aobjname
));
646 if (ipstatus
!= IPADM_SUCCESS
)
649 ipstatus
= ipadm_addr_info(ipadm_handle
, ifname
, &addrinfo
, 0, 0);
650 if (ipstatus
!= IPADM_SUCCESS
) {
651 nlog(LOG_INFO
, "addrinfo_for_ipaddr: "
652 "ipadm_addr_info failed for %s: %s",
653 ifname
, ipadm_status2str(ipstatus
));
659 while (ainfop
!= NULL
) {
660 /* If aobjnames match, rearrange pointers to create new list */
661 if (strcmp(ainfop
->ia_aobjname
, aobjname
) == 0) {
662 ipadm_addr_info_t
*match
= ainfop
;
664 ainfop
= IA_NEXT(ainfop
); /* move iterator */
666 last
->ia_ifa
.ifa_next
= match
->ia_ifa
.ifa_next
;
670 match
->ia_ifa
.ifa_next
= NULL
;
672 match
->ia_ifa
.ifa_next
= &(*ainfo
)->ia_ifa
;
676 ainfop
= IA_NEXT(ainfop
);
679 ipadm_free_addr_info(addrinfo
);
680 return (*ainfo
== NULL
? B_FALSE
: B_TRUE
);
684 * Add the address provided in the nwamd_if_address. If DHCP is required,
685 * start DHCP. If a static address is configured, create the address; then do
686 * a DHCP_INFORM (in a separate thread) to get other networking configuration
687 * parameters. RTM_NEWADDRs - translated into IF_STATE events - will then
688 * finish the job of bringing the NCU online.
691 add_ip_address(const char *ifname
, const struct nwamd_if_address
*nifa
,
692 boolean_t
*do_inform
)
694 ipadm_status_t ipstatus
;
695 ipadm_addr_info_t
*addrinfo
= NULL
;
698 if (nifa
->ipaddr_atype
== IPADM_ADDR_DHCP
) {
700 * To make getting a DHCP address asynchronous, call
701 * ipadm_create_addr() in a new thread.
703 nlog(LOG_DEBUG
, "add_ip_address: "
704 "adding IPv4 DHCP address on %s", ifname
);
705 nwamd_dhcp(ifname
, nifa
->ipaddr
, DHCP_START
);
707 nlog(LOG_DEBUG
, "add_ip_address: adding %s address on %s",
708 (nifa
->ipaddr_atype
== IPADM_ADDR_STATIC
?
709 "STATIC" : "IPv6 ADDRCONF"), ifname
);
710 if ((ipstatus
= ipadm_create_addr(ipadm_handle
, nifa
->ipaddr
,
711 IPADM_OPT_ACTIVE
| IPADM_OPT_UP
)) != IPADM_SUCCESS
) {
712 nlog(LOG_ERR
, "add_ip_address: "
713 "ipadm_create_addr failed on %s: %s",
714 ifname
, ipadm_status2str(ipstatus
));
718 * When creating a static address, ipadm_create_addr() returns
719 * SUCCESS even if duplicate address is detected. Retrieve
720 * the addrinfo to get the flags.
722 if (nifa
->ipaddr_atype
== IPADM_ADDR_STATIC
) {
724 * Since we are configuring a static address, there
725 * will be just *ONE* addrinfo with the aobjname in
728 if (!addrinfo_for_ipaddr(nifa
->ipaddr
, ifname
,
730 nlog(LOG_ERR
, "add_ip_address: "
731 "could not find addrinfo on %s", ifname
);
735 flags
= addrinfo
->ia_ifa
.ifa_flags
;
736 ipadm_free_addr_info(addrinfo
);
737 if (flags
& IFF_DUPLICATE
) {
741 nlog(LOG_INFO
, "add_ip_address: "
742 "duplicate address detected on %s", ifname
);
743 if ((err
= nwam_ncu_name_to_typed_name(ifname
,
744 NWAM_NCU_TYPE_INTERFACE
, &object_name
))
746 nwamd_object_set_state(
747 NWAM_OBJECT_TYPE_NCU
,
748 object_name
, NWAM_STATE_MAINTENANCE
,
749 NWAM_AUX_STATE_IF_DUPLICATE_ADDR
);
752 nlog(LOG_ERR
, "add_ip_address: "
753 "could not create state event "
755 ifname
, nwam_strerror(err
));
760 * Do DHCP_INFORM using async ipadm_refresh_addr().
761 * Only need to do this once per interface, and we
762 * do *not* need to do it if we are also getting a
763 * dhcp lease; so we only send the INFORM if the
764 * passed-in flag says to, and we clear the flag
765 * once we've initiated the INFORM transaction.
768 nwamd_dhcp(ifname
, nifa
->ipaddr
, DHCP_INFORM
);
769 *do_inform
= B_FALSE
;
778 * Adds addresses for the given NCU.
781 nwamd_configure_interface_addresses(nwamd_ncu_t
*ncu
)
783 struct nwamd_if_address
*nifap
, *nifa
= ncu
->ncu_if
.nwamd_if_list
;
786 /* only need an inform if we're not also getting a dhcp lease */
787 do_inform
= !ncu
->ncu_if
.nwamd_if_dhcp_requested
;
789 nlog(LOG_DEBUG
, "nwamd_configure_interface_addresses(%s)",
792 for (nifap
= nifa
; nifap
!= NULL
; nifap
= nifap
->next
) {
793 if (nifap
->configured
)
796 nifap
->configured
= add_ip_address(ncu
->ncu_name
, nifap
,
802 * This event tells us that an interface address has appeared or disappeared,
803 * or that the interface flags on an interface have changed.
806 nwamd_ncu_handle_if_state_event(nwamd_event_t event
)
809 nwamd_object_t ncu_obj
;
812 nwam_aux_state_t aux_state
;
814 ncu_obj
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
,
815 event
->event_object
);
816 if (ncu_obj
== NULL
) {
817 nlog(LOG_INFO
, "nwamd_ncu_handle_if_state_event: no object %s",
818 event
->event_object
);
819 nwamd_event_do_not_send(event
);
822 ncu
= ncu_obj
->nwamd_object_data
;
823 evm
= event
->event_msg
;
824 state
= ncu_obj
->nwamd_object_state
;
825 aux_state
= ncu_obj
->nwamd_object_aux_state
;
827 nlog(LOG_DEBUG
, "nwamd_ncu_handle_if_state_event: "
828 "if %s, state (%s, %s)", event
->event_object
,
829 nwam_state_to_string(state
), nwam_aux_state_to_string(aux_state
));
831 /* Ensure object is in correct state to handle IF state events */
833 case NWAM_STATE_OFFLINE_TO_ONLINE
:
834 if (aux_state
!= NWAM_AUX_STATE_IF_WAITING_FOR_ADDR
&&
835 aux_state
!= NWAM_AUX_STATE_IF_DHCP_TIMED_OUT
) {
836 nlog(LOG_DEBUG
, "nwamd_ncu_handle_if_state_event: "
837 "if %s is in invalid aux state %s for IF_STATE "
838 "events", event
->event_object
,
839 nwam_aux_state_to_string(aux_state
));
840 nwamd_event_do_not_send(event
);
841 nwamd_object_release(ncu_obj
);
845 case NWAM_STATE_ONLINE
:
847 * We can get addresses from DHCP after we've taken the interface down.
848 * We deal with those below.
850 case NWAM_STATE_ONLINE_TO_OFFLINE
:
851 case NWAM_STATE_OFFLINE
:
854 nlog(LOG_DEBUG
, "nwamd_ncu_handle_if_state_event: "
855 "if %s is in invalid state %s for IF_STATE events",
856 event
->event_object
, nwam_state_to_string(state
));
857 nwamd_event_do_not_send(event
);
858 nwamd_object_release(ncu_obj
);
862 if (evm
->nwe_data
.nwe_if_state
.nwe_addr_valid
) {
863 struct nwam_event_if_state
*if_state
;
864 char addrstr
[INET6_ADDRSTRLEN
];
865 boolean_t static_addr
, addr_added
;
866 boolean_t v4dhcp_running
, v6dhcp_running
, stateless_running
;
867 ipadm_addr_info_t
*ai
= NULL
, *addrinfo
= NULL
;
868 boolean_t stateless_ai_found
= B_FALSE
;
869 boolean_t stateful_ai_found
= B_FALSE
;
870 struct nwamd_if_address
*nifa
= NULL
;
872 struct sockaddr_storage
*addr
, ai_addr
, *aip
= NULL
;
876 if_state
= &evm
->nwe_data
.nwe_if_state
;
878 family
= if_state
->nwe_addr
.ss_family
;
879 addr
= &if_state
->nwe_addr
;
880 addr_added
= if_state
->nwe_addr_added
;
883 "nwamd_ncu_handle_if_state_event: addr %s %s",
884 nwamd_sockaddr2str((struct sockaddr
*)addr
, addrstr
,
885 sizeof (addrstr
)), addr_added
? "added" : "removed");
888 * Need to get flags for this interface. Get the addrinfo for
889 * the address that generated this IF_STATE event.
893 * Address was added. Find the addrinfo for this
894 * address and the nwamd_if_address corresponding to
897 if (!addrinfo_for_addr(addr
, ncu
->ncu_name
, &ai
)) {
899 "nwamd_ncu_handle_if_state_event: "
900 "addrinfo doesn't exist for %s", addrstr
);
901 nwamd_event_do_not_send(event
);
905 flags
= addrinfo
->ia_ifa
.ifa_flags
;
906 (void) memcpy(&ai_addr
, addrinfo
->ia_ifa
.ifa_addr
,
910 if (addrinfo
->ia_atype
== IPADM_ADDR_IPV6_ADDRCONF
||
911 addrinfo
->ia_atype
== IPADM_ADDR_DHCP
)
912 nifa
= find_nonstatic_address(ncu
, family
);
913 else if (addrinfo
->ia_atype
== IPADM_ADDR_STATIC
)
914 nifa
= find_static_address(addr
, ncu
);
917 * If nwamd_if_address is not found, then this address
918 * isn't one that nwamd created. Remove it.
922 "nwamd_ncu_handle_if_state_event: "
923 "address %s not managed by nwam added, "
924 "removing it", addrstr
);
925 nwamd_down_interface(addrinfo
->ia_aobjname
,
926 addrinfo
->ia_atype
, ncu
->ncu_name
);
927 nwamd_event_do_not_send(event
);
931 /* check flags to determine how intf is configured */
932 stateless_running
= (family
== AF_INET6
) &&
933 ((flags
& STATELESS_RUNNING
) == STATELESS_RUNNING
);
934 v4dhcp_running
= (family
== AF_INET
) &&
935 ((flags
& DHCP_RUNNING
) == DHCP_RUNNING
);
936 v6dhcp_running
= (family
== AF_INET6
) &&
937 ((flags
& DHCP_RUNNING
) == DHCP_RUNNING
);
938 static_addr
= (addrinfo
->ia_atype
== IPADM_ADDR_STATIC
);
940 /* copy the configured address into nwamd_if_address */
941 if (stateless_running
) {
942 (void) memcpy(&nifa
->conf_stateless_addr
,
943 addrinfo
->ia_ifa
.ifa_addr
,
944 sizeof (struct sockaddr_storage
));
946 (void) memcpy(&nifa
->conf_addr
,
947 addrinfo
->ia_ifa
.ifa_addr
,
948 sizeof (struct sockaddr_storage
));
953 * Address was removed. Find the nwamd_if_address
954 * that configured this address.
956 nifa
= find_configured_address(addr
, ncu
);
959 "nwamd_ncu_handle_if_state_event: "
960 "address %s not managed by nwam removed, "
961 "nothing to do", addrstr
);
962 nwamd_event_do_not_send(event
);
966 if (addrinfo_for_ipaddr(nifa
->ipaddr
, ncu
->ncu_name
,
968 ipadm_addr_info_t
*a
;
969 for (a
= ai
; a
!= NULL
; a
= IA_NEXT(a
)) {
970 struct sockaddr_storage stor
;
972 (void) memcpy(&stor
, a
->ia_ifa
.ifa_addr
,
975 * Since multiple addrinfo can have
976 * the same ipaddr, find the one for
977 * the address that generated this
980 if (sockaddrcmp(addr
, &stor
)) {
981 flags
= a
->ia_ifa
.ifa_flags
;
982 (void) memcpy(&ai_addr
,
989 * Stateful and stateless IPv6
990 * addrinfo have the same aobjname.
991 * Use the flags to determine which
992 * address is present in the system.
994 if (family
== AF_INET6
) {
996 (a
->ia_ifa
.ifa_flags
&
999 (a
->ia_ifa
.ifa_flags
&
1006 /* Set the flags in the event for listeners */
1007 evm
->nwe_data
.nwe_if_state
.nwe_flags
= flags
;
1009 if (family
== AF_INET
&& !addr_added
) {
1011 * Check for failure due to CR 6745448: if we get a
1012 * report that an address has been deleted, then check
1013 * for interface up, datalink down, and actual address
1014 * non-zero. If that combination is seen, then this is
1015 * a DHCP cached lease, and we need to remove it from
1016 * the system, or it'll louse up the kernel routes
1017 * (which aren't smart enough to avoid dead
1020 if (((struct sockaddr_in
*)addr
)->sin_addr
.s_addr
1021 == INADDR_ANY
&& aip
!= 0) {
1022 struct sockaddr_in
*a
;
1023 char astr
[INET6_ADDRSTRLEN
];
1024 a
= (struct sockaddr_in
*)aip
;
1026 if ((flags
& IFF_UP
) &&
1027 !(flags
& IFF_RUNNING
) &&
1028 a
->sin_addr
.s_addr
!= INADDR_ANY
) {
1030 "nwamd_ncu_handle_if_state_event: "
1031 "bug workaround: clear out addr "
1032 "%s on %s", nwamd_sockaddr2str
1033 ((struct sockaddr
*)a
, astr
,
1036 nwamd_down_interface(
1037 addrinfo
->ia_aobjname
,
1038 IPADM_ADDR_DHCP
, ncu
->ncu_name
);
1045 * If we received an RTM_NEWADDR and the IFF_UP flags has not
1046 * been set, ignore this IF_STATE event. Once the IFF_UP flag
1047 * is set, we'll get another RTM_NEWADDR message.
1049 if (addr_added
& !(flags
& IFF_UP
)) {
1050 nlog(LOG_INFO
, "nwamd_ncu_handle_if_state_event: "
1051 "address %s added on %s without IFF_UP flag (%x), "
1052 "ignoring IF_STATE event",
1053 addrstr
, ncu
->ncu_name
, flags
);
1054 nwamd_event_do_not_send(event
);
1059 * Has the address really been removed? Sometimes spurious
1060 * RTM_DELADDRs are generated, so we need to ensure that
1061 * the address is really gone. If IFF_DUPLICATE is set,
1062 * we're getting the RTM_DELADDR due to DAD, so don't test
1065 if (!addr_added
&& !(flags
& IFF_DUPLICATE
)) {
1066 if (aip
!= 0 && sockaddrcmp(addr
, aip
)) {
1068 "nwamd_ncu_handle_if_state_event: "
1069 "address %s is not really gone from %s, "
1070 "ignoring IF_STATE event",
1071 addrstr
, ncu
->ncu_name
);
1072 nwamd_event_do_not_send(event
);
1079 * Address has been added.
1081 * We need to make sure that we really want to keep
1082 * this address. There is a race where we requested an
1083 * address but by the time we got here we don't really
1084 * want it and need to remove it.
1086 * Once we decide we want the address adjust the ncu
1087 * state accordingly. For example if this address is
1088 * enough move online.
1090 if (u_if
->nwamd_if_dhcp_requested
&& v4dhcp_running
) {
1091 u_if
->nwamd_if_dhcp_configured
= B_TRUE
;
1092 } else if (u_if
->nwamd_if_stateful_requested
&&
1094 u_if
->nwamd_if_stateful_configured
= B_TRUE
;
1095 } else if (u_if
->nwamd_if_stateless_requested
&&
1096 stateless_running
) {
1097 u_if
->nwamd_if_stateless_configured
= B_TRUE
;
1098 } else if (!static_addr
) {
1100 * This is something we didn't expect. Remove
1103 nwamd_down_interface(addrinfo
->ia_aobjname
,
1104 addrinfo
->ia_atype
, ncu
->ncu_name
);
1105 nifa
->configured
= B_FALSE
;
1110 * The address looks valid so mark configured and
1111 * move online if we either have a v4 address if
1112 * v4 is configured or a v6 address if only v6 is
1115 nifa
->configured
= B_TRUE
;
1116 if (state
!= NWAM_STATE_ONLINE
)
1117 interface_ncu_up(ncu
);
1120 * Refresh network/location since we may also have other
1121 * DHCP information. We might have to restore it first
1122 * in case it is in maintenance.
1124 nlog(LOG_DEBUG
, "nwamd_handle_if_state_event: "
1125 "refreshing %s as we may have other "
1126 "DHCP information", NET_LOC_FMRI
);
1127 (void) smf_restore_instance(NET_LOC_FMRI
);
1128 if (smf_refresh_instance(NET_LOC_FMRI
) != 0) {
1130 "nwamd_ncu_handle_if_state_"
1131 "event: refresh of %s "
1132 "failed", NET_LOC_FMRI
);
1135 } else if (state
== NWAM_STATE_ONLINE
||
1136 state
== NWAM_STATE_OFFLINE_TO_ONLINE
) {
1138 * Address has been removed. Only pay attention to
1139 * disappearing addresses if we are online or coming
1142 * Undo whatever configuration is necessary. Note
1143 * that this may or may not cause the NCU to go down.
1144 * We can get RTM_DELADDRs for duplicate addresses
1145 * so deal with this seperately.
1147 nifa
->configured
= B_FALSE
;
1149 if (!static_addr
&& family
== AF_INET
) {
1150 u_if
->nwamd_if_dhcp_configured
= B_FALSE
;
1151 } else if (!static_addr
&& family
== AF_INET6
) {
1153 * The address is already gone. When looking
1154 * for the addrinfo (using aobjname in
1155 * ipaddr), we found addrinfo for either one
1156 * or both stateless and stateful. Using the
1157 * flags we determined whether each was
1158 * configured or not. Update the flags here
1161 u_if
->nwamd_if_stateful_configured
=
1163 u_if
->nwamd_if_stateless_configured
=
1167 if (flags
& IFF_DUPLICATE
) {
1169 "nwamd_ncu_handle_if_state_event: "
1170 "duplicate address detected on %s",
1172 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
1173 event
->event_object
,
1174 NWAM_STATE_MAINTENANCE
,
1175 NWAM_AUX_STATE_IF_DUPLICATE_ADDR
);
1177 interface_ncu_down(ncu
);
1181 ipadm_free_addr_info(ai
);
1183 nwamd_object_release(ncu_obj
);
1187 nwamd_ncu_handle_if_action_event(nwamd_event_t event
)
1189 nwamd_object_t ncu_obj
;
1191 nlog(LOG_DEBUG
, "if action event %s",
1192 event
->event_object
[0] == '\0' ? "n/a" : event
->event_object
);
1194 ncu_obj
= nwamd_object_find(NWAM_OBJECT_TYPE_NCU
, event
->event_object
);
1195 if (ncu_obj
== NULL
) {
1196 nlog(LOG_ERR
, "nwamd_ncu_handle_if_action_event: no object");
1197 nwamd_event_do_not_send(event
);
1200 nwamd_object_release(ncu_obj
);
1204 * Remove the address in the given aobjname. IPADM_OPT_RELEASE is specified
1205 * for a DHCP address and specifies that the DHCP lease should also be released.
1206 * ifname is only used for nlog().
1209 nwamd_down_interface(const char *aobjname
, ipadm_addr_type_t atype
,
1212 ipadm_status_t ipstatus
;
1213 uint32_t rflags
= (atype
== IPADM_ADDR_DHCP
? IPADM_OPT_RELEASE
: 0);
1215 nlog(LOG_DEBUG
, "nwamd_down_interface: %s [aobjname = %s]",
1217 if ((ipstatus
= ipadm_delete_addr(ipadm_handle
, aobjname
,
1218 IPADM_OPT_ACTIVE
| rflags
)) != IPADM_SUCCESS
) {
1219 nlog(LOG_ERR
, "nwamd_down_interface: "
1220 "ipadm_delete_addr failed on %s: %s",
1221 ifname
, ipadm_status2str(ipstatus
));
1226 unconfigure_addresses(nwamd_ncu_t
*ncu
, sa_family_t af
)
1228 struct nwamd_if_address
*nifap
, *nifa
= ncu
->ncu_if
.nwamd_if_list
;
1230 for (nifap
= nifa
; nifap
!= NULL
; nifap
= nifap
->next
)
1231 if (af
== AF_UNSPEC
|| nifap
->family
== af
)
1232 nifap
->configured
= B_FALSE
;
1236 dhcp_release(const char *ifname
)
1238 ipadm_addr_info_t
*ainfo
, *ainfop
;
1240 if (ipadm_addr_info(ipadm_handle
, ifname
, &ainfo
, 0, 0)
1244 for (ainfop
= ainfo
; ainfop
!= NULL
; ainfop
= IA_NEXT(ainfop
)) {
1245 if (ainfop
->ia_atype
== IPADM_ADDR_DHCP
)
1246 nwamd_down_interface(ainfop
->ia_aobjname
,
1247 ainfop
->ia_atype
, ifname
);
1249 ipadm_free_addr_info(ainfo
);
1253 nwamd_plumb_unplumb_interface(nwamd_ncu_t
*ncu
, sa_family_t af
, boolean_t plumb
)
1255 char *ifname
= ncu
->ncu_name
;
1256 nwamd_if_t
*u_if
= &ncu
->ncu_if
;
1257 ipadm_status_t ipstatus
;
1259 nlog(LOG_DEBUG
, "nwamd_plumb_unplumb_interface: %s %s %s",
1260 (plumb
? "plumb" : "unplumb"), (af
== AF_INET
? "IPv4" : "IPv6"),
1264 ipstatus
= ipadm_create_if(ipadm_handle
, ifname
, af
,
1267 /* release DHCP address, if any */
1269 dhcp_release(ifname
);
1270 ipstatus
= ipadm_delete_if(ipadm_handle
, ifname
, af
,
1274 if (ipstatus
!= IPADM_SUCCESS
) {
1275 if ((plumb
&& ipstatus
!= IPADM_IF_EXISTS
) ||
1276 (!plumb
&& ipstatus
!= IPADM_ENXIO
)) {
1277 nlog(LOG_ERR
, "nwamd_plumb_unplumb_interface: "
1278 "%s %s failed for %s: %s",
1279 (plumb
? "plumb" : "unplumb"),
1280 (af
== AF_INET
? "IPv4" : "IPv6"),
1281 ifname
, ipadm_status2str(ipstatus
));
1287 unconfigure_addresses(ncu
, af
);
1290 u_if
->nwamd_if_dhcp_configured
= B_FALSE
;
1293 u_if
->nwamd_if_stateful_configured
= B_FALSE
;
1294 u_if
->nwamd_if_stateless_configured
= B_FALSE
;
1301 nwamd_plumb_interface(nwamd_ncu_t
*ncu
, sa_family_t af
)
1304 * We get all posssible privs by calling nwamd_deescalate(). During
1305 * startup opening /dev/dld (data link management) needs all privs
1306 * because we don't have access to /etc/security/device_policy yet.
1309 nwamd_plumb_unplumb_interface(ncu
, af
, B_TRUE
);
1314 nwamd_unplumb_interface(nwamd_ncu_t
*ncu
, sa_family_t af
)
1316 nwamd_plumb_unplumb_interface(ncu
, af
, B_FALSE
);
1320 start_dhcp_thread(void *arg
)
1322 struct nwamd_dhcp_thread_arg
*thread_arg
= arg
;
1323 nwamd_object_t ncu_obj
;
1324 dhcp_ipc_type_t type
;
1326 ipadm_addrobj_t ipaddr
;
1327 ipadm_status_t ipstatus
;
1330 name
= thread_arg
->name
;
1331 type
= thread_arg
->type
;
1332 ipaddr
= thread_arg
->ipaddr
;
1335 /* Make sure the NCU is in appropriate state for DHCP command */
1336 ncu_obj
= nwamd_ncu_object_find(NWAM_NCU_TYPE_INTERFACE
, name
);
1337 if (ncu_obj
== NULL
) {
1338 nlog(LOG_ERR
, "start_dhcp: no IP object %s", name
);
1342 if (ncu_obj
->nwamd_object_state
!= NWAM_STATE_OFFLINE_TO_ONLINE
&&
1343 ncu_obj
->nwamd_object_state
!= NWAM_STATE_ONLINE
) {
1344 nlog(LOG_INFO
, "start_dhcp: IP NCU %s is in invalid state "
1345 "for DHCP command", ncu_obj
->nwamd_object_name
);
1346 nwamd_object_release(ncu_obj
);
1349 nwamd_object_release(ncu_obj
);
1354 char aobjname
[IPADM_AOBJSIZ
];
1356 if ((ipstatus
= ipadm_get_aobjname(ipaddr
, aobjname
,
1357 sizeof (aobjname
))) != IPADM_SUCCESS
) {
1358 nlog(LOG_ERR
, "start_dhcp: "
1359 "ipadm_get_aobjname failed for %s: %s",
1360 name
, ipadm_status2str(ipstatus
));
1363 ipstatus
= ipadm_refresh_addr(ipadm_handle
, aobjname
,
1364 IPADM_OPT_ACTIVE
| IPADM_OPT_INFORM
);
1368 ipstatus
= ipadm_create_addr(ipadm_handle
, ipaddr
,
1372 nlog(LOG_ERR
, "start_dhcp: invalid dhcp_ipc_type_t: %d", type
);
1376 if (ipstatus
== IPADM_DHCP_IPC_TIMEOUT
) {
1378 * DHCP timed out: for DHCP_START requests, change state for
1379 * this NCU and euqueue event to check NCU priority-groups;
1380 * for DHCP_INFORM requests, nothing to do.
1382 if (type
== DHCP_START
) {
1386 "start_dhcp: DHCP_START timed out for %s", name
);
1388 if (nwam_ncu_name_to_typed_name(name
,
1389 NWAM_NCU_TYPE_INTERFACE
, &object_name
)
1391 nlog(LOG_ERR
, "start_dhcp: "
1392 "nwam_ncu_name_to_typed_name failed for %s",
1396 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU
,
1397 object_name
, NWAM_STATE_OFFLINE_TO_ONLINE
,
1398 NWAM_AUX_STATE_IF_DHCP_TIMED_OUT
);
1399 nwamd_create_ncu_check_event(0);
1403 "start_dhcp: DHCP_INFORM timed out for %s", name
);
1406 } else if ((ipstatus
== IPADM_DHCP_IPC_ERROR
||
1407 ipstatus
== IPADM_IPC_ERROR
) && retries
++ < NWAMD_DHCP_RETRIES
) {
1409 * Retry DHCP request as we may have been unplumbing as part
1410 * of the configuration phase.
1412 nlog(LOG_ERR
, "start_dhcp: ipadm_%s_addr on %s returned: %s, "
1413 "retrying in %d sec",
1414 (type
== DHCP_START
? "create" : "refresh"), name
,
1415 ipadm_status2str(ipstatus
), NWAMD_DHCP_RETRY_WAIT_TIME
);
1416 (void) sleep(NWAMD_DHCP_RETRY_WAIT_TIME
);
1419 } else if (ipstatus
!= IPADM_SUCCESS
) {
1420 nlog(LOG_ERR
, "start_dhcp: ipadm_%s_addr failed for %s: %s",
1421 (type
== DHCP_START
? "create" : "refresh"), name
,
1422 ipadm_status2str(ipstatus
));
1432 nwamd_dhcp(const char *ifname
, ipadm_addrobj_t ipaddr
, dhcp_ipc_type_t cmd
)
1434 struct nwamd_dhcp_thread_arg
*arg
;
1435 pthread_attr_t attr
;
1437 nlog(LOG_DEBUG
, "nwamd_dhcp: starting DHCP %s thread for %s",
1438 dhcp_ipc_type_to_string(cmd
), ifname
);
1440 arg
= malloc(sizeof (*arg
));
1442 nlog(LOG_ERR
, "nwamd_dhcp: error allocating memory for "
1447 arg
->name
= strdup(ifname
);
1449 arg
->ipaddr
= ipaddr
;
1451 (void) pthread_attr_init(&attr
);
1452 (void) pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
1453 if (pthread_create(NULL
, &attr
, start_dhcp_thread
, arg
) == -1) {
1454 nlog(LOG_ERR
, "nwamd_dhcp: cannot start dhcp thread");
1457 (void) pthread_attr_destroy(&attr
);
1460 (void) pthread_attr_destroy(&attr
);