xref: /illumos-gate/usr/src/lib/libipadm/common/ipadm_ndpd.c (revision 6e91bba0d6c6bdabbba62cefae583715a4a58e2a)
1*6e91bba0SGirish Moodalbail /*
2*6e91bba0SGirish Moodalbail  * CDDL HEADER START
3*6e91bba0SGirish Moodalbail  *
4*6e91bba0SGirish Moodalbail  * The contents of this file are subject to the terms of the
5*6e91bba0SGirish Moodalbail  * Common Development and Distribution License (the "License").
6*6e91bba0SGirish Moodalbail  * You may not use this file except in compliance with the License.
7*6e91bba0SGirish Moodalbail  *
8*6e91bba0SGirish Moodalbail  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6e91bba0SGirish Moodalbail  * or http://www.opensolaris.org/os/licensing.
10*6e91bba0SGirish Moodalbail  * See the License for the specific language governing permissions
11*6e91bba0SGirish Moodalbail  * and limitations under the License.
12*6e91bba0SGirish Moodalbail  *
13*6e91bba0SGirish Moodalbail  * When distributing Covered Code, include this CDDL HEADER in each
14*6e91bba0SGirish Moodalbail  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6e91bba0SGirish Moodalbail  * If applicable, add the following below this CDDL HEADER, with the
16*6e91bba0SGirish Moodalbail  * fields enclosed by brackets "[]" replaced with your own identifying
17*6e91bba0SGirish Moodalbail  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6e91bba0SGirish Moodalbail  *
19*6e91bba0SGirish Moodalbail  * CDDL HEADER END
20*6e91bba0SGirish Moodalbail  */
21*6e91bba0SGirish Moodalbail /*
22*6e91bba0SGirish Moodalbail  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23*6e91bba0SGirish Moodalbail  * Use is subject to license terms.
24*6e91bba0SGirish Moodalbail  */
25*6e91bba0SGirish Moodalbail 
26*6e91bba0SGirish Moodalbail /*
27*6e91bba0SGirish Moodalbail  * This file contains the functions that are required for communicating
28*6e91bba0SGirish Moodalbail  * with in.ndpd while creating autoconfigured addresses.
29*6e91bba0SGirish Moodalbail  */
30*6e91bba0SGirish Moodalbail 
31*6e91bba0SGirish Moodalbail #include <stdio.h>
32*6e91bba0SGirish Moodalbail #include <stdlib.h>
33*6e91bba0SGirish Moodalbail #include <string.h>
34*6e91bba0SGirish Moodalbail #include <strings.h>
35*6e91bba0SGirish Moodalbail #include <errno.h>
36*6e91bba0SGirish Moodalbail #include <fcntl.h>
37*6e91bba0SGirish Moodalbail #include <unistd.h>
38*6e91bba0SGirish Moodalbail #include <sys/sockio.h>
39*6e91bba0SGirish Moodalbail #include <sys/types.h>
40*6e91bba0SGirish Moodalbail #include <sys/stat.h>
41*6e91bba0SGirish Moodalbail #include <sys/socket.h>
42*6e91bba0SGirish Moodalbail #include <netinet/in.h>
43*6e91bba0SGirish Moodalbail #include <inet/ip.h>
44*6e91bba0SGirish Moodalbail #include <arpa/inet.h>
45*6e91bba0SGirish Moodalbail #include <assert.h>
46*6e91bba0SGirish Moodalbail #include <poll.h>
47*6e91bba0SGirish Moodalbail #include <ipadm_ndpd.h>
48*6e91bba0SGirish Moodalbail #include "libipadm_impl.h"
49*6e91bba0SGirish Moodalbail 
50*6e91bba0SGirish Moodalbail #define	NDPDTIMEOUT		5000
51*6e91bba0SGirish Moodalbail #define	PREFIXLEN_LINKLOCAL	10
52*6e91bba0SGirish Moodalbail 
53*6e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_create_linklocal(ipadm_handle_t,
54*6e91bba0SGirish Moodalbail 			    ipadm_addrobj_t);
55*6e91bba0SGirish Moodalbail static void		i_ipadm_make_linklocal(struct sockaddr_in6 *,
56*6e91bba0SGirish Moodalbail 			    const struct in6_addr *);
57*6e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_send_ndpd_cmd(const char *,
58*6e91bba0SGirish Moodalbail 			    const struct ipadm_addrobj_s *, int);
59*6e91bba0SGirish Moodalbail 
60*6e91bba0SGirish Moodalbail /*
61*6e91bba0SGirish Moodalbail  * Sends message to in.ndpd asking not to do autoconf for the given interface,
62*6e91bba0SGirish Moodalbail  * until IPADM_CREATE_ADDRS or IPADM_ENABLE_AUTOCONF is sent.
63*6e91bba0SGirish Moodalbail  */
64*6e91bba0SGirish Moodalbail ipadm_status_t
65*6e91bba0SGirish Moodalbail i_ipadm_disable_autoconf(const char *ifname)
66*6e91bba0SGirish Moodalbail {
67*6e91bba0SGirish Moodalbail 	return (i_ipadm_send_ndpd_cmd(ifname, NULL, IPADM_DISABLE_AUTOCONF));
68*6e91bba0SGirish Moodalbail }
69*6e91bba0SGirish Moodalbail 
70*6e91bba0SGirish Moodalbail /*
71*6e91bba0SGirish Moodalbail  * Sends message to in.ndpd to enable autoconf for the given interface,
72*6e91bba0SGirish Moodalbail  * until another IPADM_DISABLE_AUTOCONF is sent.
73*6e91bba0SGirish Moodalbail  */
74*6e91bba0SGirish Moodalbail ipadm_status_t
75*6e91bba0SGirish Moodalbail i_ipadm_enable_autoconf(const char *ifname)
76*6e91bba0SGirish Moodalbail {
77*6e91bba0SGirish Moodalbail 	return (i_ipadm_send_ndpd_cmd(ifname, NULL, IPADM_ENABLE_AUTOCONF));
78*6e91bba0SGirish Moodalbail }
79*6e91bba0SGirish Moodalbail 
80*6e91bba0SGirish Moodalbail ipadm_status_t
81*6e91bba0SGirish Moodalbail i_ipadm_create_ipv6addrs(ipadm_handle_t iph, ipadm_addrobj_t addr,
82*6e91bba0SGirish Moodalbail     uint32_t i_flags)
83*6e91bba0SGirish Moodalbail {
84*6e91bba0SGirish Moodalbail 	ipadm_status_t status;
85*6e91bba0SGirish Moodalbail 
86*6e91bba0SGirish Moodalbail 	/*
87*6e91bba0SGirish Moodalbail 	 * Create the link local based on the given token. If the same intfid
88*6e91bba0SGirish Moodalbail 	 * was already used with a different address object, this step will
89*6e91bba0SGirish Moodalbail 	 * fail.
90*6e91bba0SGirish Moodalbail 	 */
91*6e91bba0SGirish Moodalbail 	status = i_ipadm_create_linklocal(iph, addr);
92*6e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
93*6e91bba0SGirish Moodalbail 		return (status);
94*6e91bba0SGirish Moodalbail 
95*6e91bba0SGirish Moodalbail 	/*
96*6e91bba0SGirish Moodalbail 	 * Request in.ndpd to start the autoconfiguration.
97*6e91bba0SGirish Moodalbail 	 * If autoconfiguration was already started by another means (e.g.
98*6e91bba0SGirish Moodalbail 	 * "ifconfig" ), in.ndpd will return EEXIST.
99*6e91bba0SGirish Moodalbail 	 */
100*6e91bba0SGirish Moodalbail 	if (addr->ipadm_stateless || addr->ipadm_stateful) {
101*6e91bba0SGirish Moodalbail 		status = i_ipadm_send_ndpd_cmd(addr->ipadm_ifname, addr,
102*6e91bba0SGirish Moodalbail 		    IPADM_CREATE_ADDRS);
103*6e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS &&
104*6e91bba0SGirish Moodalbail 		    status != IPADM_NDPD_NOT_RUNNING) {
105*6e91bba0SGirish Moodalbail 			(void) i_ipadm_delete_addr(iph, addr);
106*6e91bba0SGirish Moodalbail 			return (status);
107*6e91bba0SGirish Moodalbail 		}
108*6e91bba0SGirish Moodalbail 	}
109*6e91bba0SGirish Moodalbail 
110*6e91bba0SGirish Moodalbail 	/* Persist the intfid. */
111*6e91bba0SGirish Moodalbail 	status = i_ipadm_addr_persist(iph, addr, B_FALSE, i_flags);
112*6e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS) {
113*6e91bba0SGirish Moodalbail 		(void) i_ipadm_delete_addr(iph, addr);
114*6e91bba0SGirish Moodalbail 		(void) i_ipadm_send_ndpd_cmd(addr->ipadm_ifname, addr,
115*6e91bba0SGirish Moodalbail 		    IPADM_DELETE_ADDRS);
116*6e91bba0SGirish Moodalbail 	}
117*6e91bba0SGirish Moodalbail 
118*6e91bba0SGirish Moodalbail 	return (status);
119*6e91bba0SGirish Moodalbail }
120*6e91bba0SGirish Moodalbail 
121*6e91bba0SGirish Moodalbail ipadm_status_t
122*6e91bba0SGirish Moodalbail i_ipadm_delete_ipv6addrs(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
123*6e91bba0SGirish Moodalbail {
124*6e91bba0SGirish Moodalbail 	ipadm_status_t status;
125*6e91bba0SGirish Moodalbail 
126*6e91bba0SGirish Moodalbail 	/*
127*6e91bba0SGirish Moodalbail 	 * Send a msg to in.ndpd to remove the autoconfigured addresses,
128*6e91bba0SGirish Moodalbail 	 * and delete the link local that was created.
129*6e91bba0SGirish Moodalbail 	 */
130*6e91bba0SGirish Moodalbail 	status = i_ipadm_send_ndpd_cmd(ipaddr->ipadm_ifname, ipaddr,
131*6e91bba0SGirish Moodalbail 	    IPADM_DELETE_ADDRS);
132*6e91bba0SGirish Moodalbail 	if (status == IPADM_NDPD_NOT_RUNNING)
133*6e91bba0SGirish Moodalbail 		status = IPADM_SUCCESS;
134*6e91bba0SGirish Moodalbail 	if (status == IPADM_SUCCESS)
135*6e91bba0SGirish Moodalbail 		status = i_ipadm_delete_addr(iph, ipaddr);
136*6e91bba0SGirish Moodalbail 
137*6e91bba0SGirish Moodalbail 	return (status);
138*6e91bba0SGirish Moodalbail }
139*6e91bba0SGirish Moodalbail 
140*6e91bba0SGirish Moodalbail static ipadm_status_t
141*6e91bba0SGirish Moodalbail i_ipadm_create_linklocal(ipadm_handle_t iph, ipadm_addrobj_t addr)
142*6e91bba0SGirish Moodalbail {
143*6e91bba0SGirish Moodalbail 	boolean_t addif = B_FALSE;
144*6e91bba0SGirish Moodalbail 	struct sockaddr_in6 *sin6;
145*6e91bba0SGirish Moodalbail 	struct lifreq lifr;
146*6e91bba0SGirish Moodalbail 	int err;
147*6e91bba0SGirish Moodalbail 	ipadm_status_t status;
148*6e91bba0SGirish Moodalbail 	in6_addr_t ll_template = {0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
149*6e91bba0SGirish Moodalbail 	    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
150*6e91bba0SGirish Moodalbail 
151*6e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
152*6e91bba0SGirish Moodalbail 	(void) strlcpy(lifr.lifr_name, addr->ipadm_ifname, LIFNAMSIZ);
153*6e91bba0SGirish Moodalbail 
154*6e91bba0SGirish Moodalbail 	if ((err = ioctl(iph->iph_sock6, SIOCGLIFADDR, (caddr_t)&lifr)) < 0)
155*6e91bba0SGirish Moodalbail 		return (ipadm_errno2status(errno));
156*6e91bba0SGirish Moodalbail 
157*6e91bba0SGirish Moodalbail 	/*
158*6e91bba0SGirish Moodalbail 	 * If no address exists on 0th logical interface,
159*6e91bba0SGirish Moodalbail 	 * create link-local address on it. Else, create a new
160*6e91bba0SGirish Moodalbail 	 * logical interface.
161*6e91bba0SGirish Moodalbail 	 */
162*6e91bba0SGirish Moodalbail 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
163*6e91bba0SGirish Moodalbail 	if (!IN6_IS_ADDR_UNSPECIFIED((&sin6->sin6_addr))) {
164*6e91bba0SGirish Moodalbail 		if (ioctl(iph->iph_sock6, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
165*6e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
166*6e91bba0SGirish Moodalbail 		addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
167*6e91bba0SGirish Moodalbail 		addif = B_TRUE;
168*6e91bba0SGirish Moodalbail 	}
169*6e91bba0SGirish Moodalbail 	/* Create the link-local address */
170*6e91bba0SGirish Moodalbail 	bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
171*6e91bba0SGirish Moodalbail 	(void) plen2mask(PREFIXLEN_LINKLOCAL, AF_INET6, &lifr.lifr_addr);
172*6e91bba0SGirish Moodalbail 	if ((err = ioctl(iph->iph_sock6, SIOCSLIFNETMASK, (caddr_t)&lifr)) < 0)
173*6e91bba0SGirish Moodalbail 		goto fail;
174*6e91bba0SGirish Moodalbail 	if (addr->ipadm_intfidlen == 0) {
175*6e91bba0SGirish Moodalbail 		/*
176*6e91bba0SGirish Moodalbail 		 * If we have to use the default interface id,
177*6e91bba0SGirish Moodalbail 		 * we just need to set the prefix to the link-local prefix.
178*6e91bba0SGirish Moodalbail 		 * SIOCSLIFPREFIX sets the address with the given prefix
179*6e91bba0SGirish Moodalbail 		 * and the default interface id.
180*6e91bba0SGirish Moodalbail 		 */
181*6e91bba0SGirish Moodalbail 		sin6->sin6_addr = ll_template;
182*6e91bba0SGirish Moodalbail 		err = ioctl(iph->iph_sock6, SIOCSLIFPREFIX, (caddr_t)&lifr);
183*6e91bba0SGirish Moodalbail 		if (err < 0)
184*6e91bba0SGirish Moodalbail 			goto fail;
185*6e91bba0SGirish Moodalbail 	} else {
186*6e91bba0SGirish Moodalbail 		/* Make a linklocal address in sin6 and set it */
187*6e91bba0SGirish Moodalbail 		i_ipadm_make_linklocal(sin6, &addr->ipadm_intfid.sin6_addr);
188*6e91bba0SGirish Moodalbail 		err = ioctl(iph->iph_sock6, SIOCSLIFADDR, (caddr_t)&lifr);
189*6e91bba0SGirish Moodalbail 		if (err < 0)
190*6e91bba0SGirish Moodalbail 			goto fail;
191*6e91bba0SGirish Moodalbail 	}
192*6e91bba0SGirish Moodalbail 	if ((err = ioctl(iph->iph_sock6, SIOCGLIFFLAGS, (char *)&lifr)) < 0)
193*6e91bba0SGirish Moodalbail 		goto fail;
194*6e91bba0SGirish Moodalbail 	lifr.lifr_flags |= IFF_UP;
195*6e91bba0SGirish Moodalbail 	if ((err = ioctl(iph->iph_sock6, SIOCSLIFFLAGS, (char *)&lifr)) < 0)
196*6e91bba0SGirish Moodalbail 		goto fail;
197*6e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
198*6e91bba0SGirish Moodalbail 
199*6e91bba0SGirish Moodalbail fail:
200*6e91bba0SGirish Moodalbail 	if (errno == EEXIST)
201*6e91bba0SGirish Moodalbail 		status = IPADM_ADDRCONF_EXISTS;
202*6e91bba0SGirish Moodalbail 	else
203*6e91bba0SGirish Moodalbail 		status = ipadm_errno2status(errno);
204*6e91bba0SGirish Moodalbail 	/* Remove the linklocal that was created. */
205*6e91bba0SGirish Moodalbail 	if (addif) {
206*6e91bba0SGirish Moodalbail 		(void) ioctl(iph->iph_sock6, SIOCLIFREMOVEIF, (caddr_t)&lifr);
207*6e91bba0SGirish Moodalbail 	} else {
208*6e91bba0SGirish Moodalbail 		struct sockaddr_in6 *sin6;
209*6e91bba0SGirish Moodalbail 
210*6e91bba0SGirish Moodalbail 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
211*6e91bba0SGirish Moodalbail 		lifr.lifr_flags &= ~IFF_UP;
212*6e91bba0SGirish Moodalbail 		(void) ioctl(iph->iph_sock6, SIOCSLIFFLAGS, (caddr_t)&lifr);
213*6e91bba0SGirish Moodalbail 		sin6->sin6_family = AF_INET6;
214*6e91bba0SGirish Moodalbail 		sin6->sin6_addr = in6addr_any;
215*6e91bba0SGirish Moodalbail 		(void) ioctl(iph->iph_sock6, SIOCSLIFADDR, (caddr_t)&lifr);
216*6e91bba0SGirish Moodalbail 	}
217*6e91bba0SGirish Moodalbail 	return (status);
218*6e91bba0SGirish Moodalbail }
219*6e91bba0SGirish Moodalbail 
220*6e91bba0SGirish Moodalbail /*
221*6e91bba0SGirish Moodalbail  * Make a linklocal address based on the given intfid and copy it into
222*6e91bba0SGirish Moodalbail  * the output parameter `sin6'.
223*6e91bba0SGirish Moodalbail  */
224*6e91bba0SGirish Moodalbail static void
225*6e91bba0SGirish Moodalbail i_ipadm_make_linklocal(struct sockaddr_in6 *sin6, const struct in6_addr *intfid)
226*6e91bba0SGirish Moodalbail {
227*6e91bba0SGirish Moodalbail 	int i;
228*6e91bba0SGirish Moodalbail 	in6_addr_t ll_template = {0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
229*6e91bba0SGirish Moodalbail 	    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
230*6e91bba0SGirish Moodalbail 
231*6e91bba0SGirish Moodalbail 	sin6->sin6_family = AF_INET6;
232*6e91bba0SGirish Moodalbail 	sin6->sin6_addr = *intfid;
233*6e91bba0SGirish Moodalbail 	for (i = 0; i < 4; i++) {
234*6e91bba0SGirish Moodalbail 		sin6->sin6_addr.s6_addr[i] =
235*6e91bba0SGirish Moodalbail 		    sin6->sin6_addr.s6_addr[i] | ll_template.s6_addr[i];
236*6e91bba0SGirish Moodalbail 	}
237*6e91bba0SGirish Moodalbail }
238*6e91bba0SGirish Moodalbail 
239*6e91bba0SGirish Moodalbail /*
240*6e91bba0SGirish Moodalbail  * Function that forms an ndpd msg and sends it to the in.ndpd daemon's loopback
241*6e91bba0SGirish Moodalbail  * listener socket.
242*6e91bba0SGirish Moodalbail  */
243*6e91bba0SGirish Moodalbail static ipadm_status_t
244*6e91bba0SGirish Moodalbail i_ipadm_send_ndpd_cmd(const char *ifname, const struct ipadm_addrobj_s *addr,
245*6e91bba0SGirish Moodalbail     int cmd)
246*6e91bba0SGirish Moodalbail {
247*6e91bba0SGirish Moodalbail 	int fd;
248*6e91bba0SGirish Moodalbail 	struct sockaddr_un servaddr;
249*6e91bba0SGirish Moodalbail 	int flags;
250*6e91bba0SGirish Moodalbail 	ipadm_ndpd_msg_t msg;
251*6e91bba0SGirish Moodalbail 	int retval;
252*6e91bba0SGirish Moodalbail 
253*6e91bba0SGirish Moodalbail 	if (addr == NULL &&
254*6e91bba0SGirish Moodalbail 	    (cmd == IPADM_CREATE_ADDRS || cmd == IPADM_DELETE_ADDRS)) {
255*6e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
256*6e91bba0SGirish Moodalbail 	}
257*6e91bba0SGirish Moodalbail 
258*6e91bba0SGirish Moodalbail 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
259*6e91bba0SGirish Moodalbail 	if (fd == -1)
260*6e91bba0SGirish Moodalbail 		return (IPADM_FAILURE);
261*6e91bba0SGirish Moodalbail 
262*6e91bba0SGirish Moodalbail 	/* Put the socket in non-blocking mode */
263*6e91bba0SGirish Moodalbail 	flags = fcntl(fd, F_GETFL, 0);
264*6e91bba0SGirish Moodalbail 	if (flags != -1)
265*6e91bba0SGirish Moodalbail 		(void) fcntl(fd, F_SETFL, flags | O_NONBLOCK);
266*6e91bba0SGirish Moodalbail 
267*6e91bba0SGirish Moodalbail 	/* Connect to in.ndpd */
268*6e91bba0SGirish Moodalbail 	bzero(&servaddr, sizeof (servaddr));
269*6e91bba0SGirish Moodalbail 	servaddr.sun_family = AF_UNIX;
270*6e91bba0SGirish Moodalbail 	(void) strlcpy(servaddr.sun_path, IPADM_UDS_PATH,
271*6e91bba0SGirish Moodalbail 	    sizeof (servaddr.sun_path));
272*6e91bba0SGirish Moodalbail 	if (connect(fd, (struct sockaddr *)&servaddr, sizeof (servaddr)) == -1)
273*6e91bba0SGirish Moodalbail 		goto fail;
274*6e91bba0SGirish Moodalbail 
275*6e91bba0SGirish Moodalbail 	bzero(&msg, sizeof (msg));
276*6e91bba0SGirish Moodalbail 	msg.inm_cmd = cmd;
277*6e91bba0SGirish Moodalbail 	(void) strlcpy(msg.inm_ifname, ifname, sizeof (msg.inm_ifname));
278*6e91bba0SGirish Moodalbail 	if (addr != NULL) {
279*6e91bba0SGirish Moodalbail 		msg.inm_intfid = addr->ipadm_intfid;
280*6e91bba0SGirish Moodalbail 		msg.inm_intfidlen = addr->ipadm_intfidlen;
281*6e91bba0SGirish Moodalbail 		msg.inm_stateless = addr->ipadm_stateless;
282*6e91bba0SGirish Moodalbail 		msg.inm_stateful = addr->ipadm_stateful;
283*6e91bba0SGirish Moodalbail 		if (cmd == IPADM_CREATE_ADDRS) {
284*6e91bba0SGirish Moodalbail 			(void) strlcpy(msg.inm_aobjname, addr->ipadm_aobjname,
285*6e91bba0SGirish Moodalbail 			    sizeof (msg.inm_aobjname));
286*6e91bba0SGirish Moodalbail 		}
287*6e91bba0SGirish Moodalbail 	}
288*6e91bba0SGirish Moodalbail 	if (ipadm_ndpd_write(fd, &msg, sizeof (msg)) < 0)
289*6e91bba0SGirish Moodalbail 		goto fail;
290*6e91bba0SGirish Moodalbail 	if (ipadm_ndpd_read(fd, &retval, sizeof (retval)) < 0)
291*6e91bba0SGirish Moodalbail 		goto fail;
292*6e91bba0SGirish Moodalbail 	(void) close(fd);
293*6e91bba0SGirish Moodalbail 	if (cmd == IPADM_CREATE_ADDRS && retval == EEXIST)
294*6e91bba0SGirish Moodalbail 		return (IPADM_ADDRCONF_EXISTS);
295*6e91bba0SGirish Moodalbail 	return (ipadm_errno2status(retval));
296*6e91bba0SGirish Moodalbail fail:
297*6e91bba0SGirish Moodalbail 	(void) close(fd);
298*6e91bba0SGirish Moodalbail 	return (IPADM_NDPD_NOT_RUNNING);
299*6e91bba0SGirish Moodalbail }
300*6e91bba0SGirish Moodalbail 
301*6e91bba0SGirish Moodalbail /*
302*6e91bba0SGirish Moodalbail  * Attempt to read `buflen' worth of bytes from `fd' into the buffer pointed
303*6e91bba0SGirish Moodalbail  * to by `buf'.
304*6e91bba0SGirish Moodalbail  */
305*6e91bba0SGirish Moodalbail int
306*6e91bba0SGirish Moodalbail ipadm_ndpd_read(int fd, void *buffer, size_t buflen)
307*6e91bba0SGirish Moodalbail {
308*6e91bba0SGirish Moodalbail 	int		retval;
309*6e91bba0SGirish Moodalbail 	ssize_t		nbytes = 0;	/* total bytes processed */
310*6e91bba0SGirish Moodalbail 	ssize_t		prbytes;	/* per-round bytes processed */
311*6e91bba0SGirish Moodalbail 	struct pollfd	pfd;
312*6e91bba0SGirish Moodalbail 
313*6e91bba0SGirish Moodalbail 	while (nbytes < buflen) {
314*6e91bba0SGirish Moodalbail 
315*6e91bba0SGirish Moodalbail 		pfd.fd = fd;
316*6e91bba0SGirish Moodalbail 		pfd.events = POLLIN;
317*6e91bba0SGirish Moodalbail 
318*6e91bba0SGirish Moodalbail 		/*
319*6e91bba0SGirish Moodalbail 		 * Wait for data to come in or for the timeout to fire.
320*6e91bba0SGirish Moodalbail 		 */
321*6e91bba0SGirish Moodalbail 		retval = poll(&pfd, 1, NDPDTIMEOUT);
322*6e91bba0SGirish Moodalbail 		if (retval <= 0) {
323*6e91bba0SGirish Moodalbail 			if (retval == 0)
324*6e91bba0SGirish Moodalbail 				errno = ETIME;
325*6e91bba0SGirish Moodalbail 			break;
326*6e91bba0SGirish Moodalbail 		}
327*6e91bba0SGirish Moodalbail 
328*6e91bba0SGirish Moodalbail 		/*
329*6e91bba0SGirish Moodalbail 		 * Descriptor is ready; have at it.
330*6e91bba0SGirish Moodalbail 		 */
331*6e91bba0SGirish Moodalbail 		prbytes = read(fd, (caddr_t)buffer + nbytes, buflen - nbytes);
332*6e91bba0SGirish Moodalbail 		if (prbytes <= 0) {
333*6e91bba0SGirish Moodalbail 			if (prbytes == -1 && errno == EINTR)
334*6e91bba0SGirish Moodalbail 				continue;
335*6e91bba0SGirish Moodalbail 			break;
336*6e91bba0SGirish Moodalbail 		}
337*6e91bba0SGirish Moodalbail 		nbytes += prbytes;
338*6e91bba0SGirish Moodalbail 	}
339*6e91bba0SGirish Moodalbail 
340*6e91bba0SGirish Moodalbail 	return (nbytes == buflen ? 0 : -1);
341*6e91bba0SGirish Moodalbail }
342*6e91bba0SGirish Moodalbail 
343*6e91bba0SGirish Moodalbail /*
344*6e91bba0SGirish Moodalbail  * Write `buflen' bytes from `buffer' to open file `fd'.  Returns 0
345*6e91bba0SGirish Moodalbail  * if all requested bytes were written, or an error code if not.
346*6e91bba0SGirish Moodalbail  */
347*6e91bba0SGirish Moodalbail int
348*6e91bba0SGirish Moodalbail ipadm_ndpd_write(int fd, const void *buffer, size_t buflen)
349*6e91bba0SGirish Moodalbail {
350*6e91bba0SGirish Moodalbail 	size_t		nwritten;
351*6e91bba0SGirish Moodalbail 	ssize_t		nbytes;
352*6e91bba0SGirish Moodalbail 	const char	*buf = buffer;
353*6e91bba0SGirish Moodalbail 
354*6e91bba0SGirish Moodalbail 	for (nwritten = 0; nwritten < buflen; nwritten += nbytes) {
355*6e91bba0SGirish Moodalbail 		nbytes = write(fd, &buf[nwritten], buflen - nwritten);
356*6e91bba0SGirish Moodalbail 		if (nbytes == -1)
357*6e91bba0SGirish Moodalbail 			return (-1);
358*6e91bba0SGirish Moodalbail 		if (nbytes == 0) {
359*6e91bba0SGirish Moodalbail 			errno = EIO;
360*6e91bba0SGirish Moodalbail 			return (-1);
361*6e91bba0SGirish Moodalbail 		}
362*6e91bba0SGirish Moodalbail 	}
363*6e91bba0SGirish Moodalbail 
364*6e91bba0SGirish Moodalbail 	assert(nwritten == buflen);
365*6e91bba0SGirish Moodalbail 	return (0);
366*6e91bba0SGirish Moodalbail }
367