16e91bba0SGirish Moodalbail /* 26e91bba0SGirish Moodalbail * CDDL HEADER START 36e91bba0SGirish Moodalbail * 46e91bba0SGirish Moodalbail * The contents of this file are subject to the terms of the 56e91bba0SGirish Moodalbail * Common Development and Distribution License (the "License"). 66e91bba0SGirish Moodalbail * You may not use this file except in compliance with the License. 76e91bba0SGirish Moodalbail * 86e91bba0SGirish Moodalbail * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96e91bba0SGirish Moodalbail * or http://www.opensolaris.org/os/licensing. 106e91bba0SGirish Moodalbail * See the License for the specific language governing permissions 116e91bba0SGirish Moodalbail * and limitations under the License. 126e91bba0SGirish Moodalbail * 136e91bba0SGirish Moodalbail * When distributing Covered Code, include this CDDL HEADER in each 146e91bba0SGirish Moodalbail * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156e91bba0SGirish Moodalbail * If applicable, add the following below this CDDL HEADER, with the 166e91bba0SGirish Moodalbail * fields enclosed by brackets "[]" replaced with your own identifying 176e91bba0SGirish Moodalbail * information: Portions Copyright [yyyy] [name of copyright owner] 186e91bba0SGirish Moodalbail * 196e91bba0SGirish Moodalbail * CDDL HEADER END 206e91bba0SGirish Moodalbail */ 216e91bba0SGirish Moodalbail /* 22ec3706caSVasumathi Sundaram * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 236e91bba0SGirish Moodalbail */ 246e91bba0SGirish Moodalbail 256e91bba0SGirish Moodalbail /* 266e91bba0SGirish Moodalbail * This file contains the functions that are required for communicating 276e91bba0SGirish Moodalbail * with in.ndpd while creating autoconfigured addresses. 286e91bba0SGirish Moodalbail */ 296e91bba0SGirish Moodalbail 306e91bba0SGirish Moodalbail #include <stdio.h> 316e91bba0SGirish Moodalbail #include <stdlib.h> 326e91bba0SGirish Moodalbail #include <string.h> 336e91bba0SGirish Moodalbail #include <strings.h> 346e91bba0SGirish Moodalbail #include <errno.h> 356e91bba0SGirish Moodalbail #include <fcntl.h> 366e91bba0SGirish Moodalbail #include <unistd.h> 376e91bba0SGirish Moodalbail #include <sys/sockio.h> 386e91bba0SGirish Moodalbail #include <sys/types.h> 396e91bba0SGirish Moodalbail #include <sys/stat.h> 406e91bba0SGirish Moodalbail #include <sys/socket.h> 416e91bba0SGirish Moodalbail #include <netinet/in.h> 426e91bba0SGirish Moodalbail #include <inet/ip.h> 436e91bba0SGirish Moodalbail #include <arpa/inet.h> 446e91bba0SGirish Moodalbail #include <assert.h> 456e91bba0SGirish Moodalbail #include <poll.h> 466e91bba0SGirish Moodalbail #include <ipadm_ndpd.h> 476e91bba0SGirish Moodalbail #include "libipadm_impl.h" 486e91bba0SGirish Moodalbail 496e91bba0SGirish Moodalbail #define NDPDTIMEOUT 5000 506e91bba0SGirish Moodalbail #define PREFIXLEN_LINKLOCAL 10 516e91bba0SGirish Moodalbail 526e91bba0SGirish Moodalbail static ipadm_status_t i_ipadm_create_linklocal(ipadm_handle_t, 536e91bba0SGirish Moodalbail ipadm_addrobj_t); 546e91bba0SGirish Moodalbail static void i_ipadm_make_linklocal(struct sockaddr_in6 *, 556e91bba0SGirish Moodalbail const struct in6_addr *); 566e91bba0SGirish Moodalbail static ipadm_status_t i_ipadm_send_ndpd_cmd(const char *, 576e91bba0SGirish Moodalbail const struct ipadm_addrobj_s *, int); 586e91bba0SGirish Moodalbail 596e91bba0SGirish Moodalbail /* 606e91bba0SGirish Moodalbail * Sends message to in.ndpd asking not to do autoconf for the given interface, 616e91bba0SGirish Moodalbail * until IPADM_CREATE_ADDRS or IPADM_ENABLE_AUTOCONF is sent. 626e91bba0SGirish Moodalbail */ 636e91bba0SGirish Moodalbail ipadm_status_t 646e91bba0SGirish Moodalbail i_ipadm_disable_autoconf(const char *ifname) 656e91bba0SGirish Moodalbail { 666e91bba0SGirish Moodalbail return (i_ipadm_send_ndpd_cmd(ifname, NULL, IPADM_DISABLE_AUTOCONF)); 676e91bba0SGirish Moodalbail } 686e91bba0SGirish Moodalbail 696e91bba0SGirish Moodalbail /* 706e91bba0SGirish Moodalbail * Sends message to in.ndpd to enable autoconf for the given interface, 716e91bba0SGirish Moodalbail * until another IPADM_DISABLE_AUTOCONF is sent. 726e91bba0SGirish Moodalbail */ 736e91bba0SGirish Moodalbail ipadm_status_t 746e91bba0SGirish Moodalbail i_ipadm_enable_autoconf(const char *ifname) 756e91bba0SGirish Moodalbail { 766e91bba0SGirish Moodalbail return (i_ipadm_send_ndpd_cmd(ifname, NULL, IPADM_ENABLE_AUTOCONF)); 776e91bba0SGirish Moodalbail } 786e91bba0SGirish Moodalbail 796e91bba0SGirish Moodalbail ipadm_status_t 806e91bba0SGirish Moodalbail i_ipadm_create_ipv6addrs(ipadm_handle_t iph, ipadm_addrobj_t addr, 816e91bba0SGirish Moodalbail uint32_t i_flags) 826e91bba0SGirish Moodalbail { 836e91bba0SGirish Moodalbail ipadm_status_t status; 846e91bba0SGirish Moodalbail 856e91bba0SGirish Moodalbail /* 866e91bba0SGirish Moodalbail * Create the link local based on the given token. If the same intfid 876e91bba0SGirish Moodalbail * was already used with a different address object, this step will 886e91bba0SGirish Moodalbail * fail. 896e91bba0SGirish Moodalbail */ 906e91bba0SGirish Moodalbail status = i_ipadm_create_linklocal(iph, addr); 916e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 926e91bba0SGirish Moodalbail return (status); 936e91bba0SGirish Moodalbail 946e91bba0SGirish Moodalbail /* 956e91bba0SGirish Moodalbail * Request in.ndpd to start the autoconfiguration. 966e91bba0SGirish Moodalbail * If autoconfiguration was already started by another means (e.g. 976e91bba0SGirish Moodalbail * "ifconfig" ), in.ndpd will return EEXIST. 986e91bba0SGirish Moodalbail */ 996e91bba0SGirish Moodalbail if (addr->ipadm_stateless || addr->ipadm_stateful) { 1006e91bba0SGirish Moodalbail status = i_ipadm_send_ndpd_cmd(addr->ipadm_ifname, addr, 1016e91bba0SGirish Moodalbail IPADM_CREATE_ADDRS); 1026e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS && 1036e91bba0SGirish Moodalbail status != IPADM_NDPD_NOT_RUNNING) { 1046e91bba0SGirish Moodalbail (void) i_ipadm_delete_addr(iph, addr); 1056e91bba0SGirish Moodalbail return (status); 1066e91bba0SGirish Moodalbail } 1076e91bba0SGirish Moodalbail } 1086e91bba0SGirish Moodalbail 1096e91bba0SGirish Moodalbail /* Persist the intfid. */ 1106e91bba0SGirish Moodalbail status = i_ipadm_addr_persist(iph, addr, B_FALSE, i_flags); 1116e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) { 1126e91bba0SGirish Moodalbail (void) i_ipadm_delete_addr(iph, addr); 1136e91bba0SGirish Moodalbail (void) i_ipadm_send_ndpd_cmd(addr->ipadm_ifname, addr, 1146e91bba0SGirish Moodalbail IPADM_DELETE_ADDRS); 1156e91bba0SGirish Moodalbail } 1166e91bba0SGirish Moodalbail 1176e91bba0SGirish Moodalbail return (status); 1186e91bba0SGirish Moodalbail } 1196e91bba0SGirish Moodalbail 1206e91bba0SGirish Moodalbail ipadm_status_t 1216e91bba0SGirish Moodalbail i_ipadm_delete_ipv6addrs(ipadm_handle_t iph, ipadm_addrobj_t ipaddr) 1226e91bba0SGirish Moodalbail { 1236e91bba0SGirish Moodalbail ipadm_status_t status; 1246e91bba0SGirish Moodalbail 1256e91bba0SGirish Moodalbail /* 1266e91bba0SGirish Moodalbail * Send a msg to in.ndpd to remove the autoconfigured addresses, 1276e91bba0SGirish Moodalbail * and delete the link local that was created. 1286e91bba0SGirish Moodalbail */ 1296e91bba0SGirish Moodalbail status = i_ipadm_send_ndpd_cmd(ipaddr->ipadm_ifname, ipaddr, 1306e91bba0SGirish Moodalbail IPADM_DELETE_ADDRS); 1316e91bba0SGirish Moodalbail if (status == IPADM_NDPD_NOT_RUNNING) 1326e91bba0SGirish Moodalbail status = IPADM_SUCCESS; 1336e91bba0SGirish Moodalbail if (status == IPADM_SUCCESS) 1346e91bba0SGirish Moodalbail status = i_ipadm_delete_addr(iph, ipaddr); 1356e91bba0SGirish Moodalbail 1366e91bba0SGirish Moodalbail return (status); 1376e91bba0SGirish Moodalbail } 1386e91bba0SGirish Moodalbail 1396e91bba0SGirish Moodalbail static ipadm_status_t 1406e91bba0SGirish Moodalbail i_ipadm_create_linklocal(ipadm_handle_t iph, ipadm_addrobj_t addr) 1416e91bba0SGirish Moodalbail { 1426e91bba0SGirish Moodalbail boolean_t addif = B_FALSE; 1436e91bba0SGirish Moodalbail struct sockaddr_in6 *sin6; 1446e91bba0SGirish Moodalbail struct lifreq lifr; 1456e91bba0SGirish Moodalbail int err; 1466e91bba0SGirish Moodalbail ipadm_status_t status; 1476e91bba0SGirish Moodalbail in6_addr_t ll_template = {0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 1486e91bba0SGirish Moodalbail 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; 1496e91bba0SGirish Moodalbail 150ec3706caSVasumathi Sundaram /* 151ec3706caSVasumathi Sundaram * Create a logical interface if needed. 152ec3706caSVasumathi Sundaram */ 153ec3706caSVasumathi Sundaram retry: 154ec3706caSVasumathi Sundaram status = i_ipadm_do_addif(iph, addr); 155ec3706caSVasumathi Sundaram if (status != IPADM_SUCCESS) 156ec3706caSVasumathi Sundaram return (status); 157ec3706caSVasumathi Sundaram if (!(iph->iph_flags & IPH_INIT)) { 158ec3706caSVasumathi Sundaram status = i_ipadm_setlifnum_addrobj(iph, addr); 159ec3706caSVasumathi Sundaram if (status == IPADM_ADDROBJ_EXISTS) 160ec3706caSVasumathi Sundaram goto retry; 161ec3706caSVasumathi Sundaram if (status != IPADM_SUCCESS) 162ec3706caSVasumathi Sundaram return (status); 163ec3706caSVasumathi Sundaram } 164ec3706caSVasumathi Sundaram 1656e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 1666e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname, LIFNAMSIZ); 167ec3706caSVasumathi Sundaram i_ipadm_addrobj2lifname(addr, lifr.lifr_name, sizeof (lifr.lifr_name)); 1686e91bba0SGirish Moodalbail sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 169ec3706caSVasumathi Sundaram 1706e91bba0SGirish Moodalbail /* Create the link-local address */ 1716e91bba0SGirish Moodalbail bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr)); 172*64639aafSDarren Reed (void) plen2mask(PREFIXLEN_LINKLOCAL, AF_INET6, 173*64639aafSDarren Reed (struct sockaddr *)&lifr.lifr_addr); 1746e91bba0SGirish Moodalbail if ((err = ioctl(iph->iph_sock6, SIOCSLIFNETMASK, (caddr_t)&lifr)) < 0) 1756e91bba0SGirish Moodalbail goto fail; 1766e91bba0SGirish Moodalbail if (addr->ipadm_intfidlen == 0) { 1776e91bba0SGirish Moodalbail /* 1786e91bba0SGirish Moodalbail * If we have to use the default interface id, 1796e91bba0SGirish Moodalbail * we just need to set the prefix to the link-local prefix. 1806e91bba0SGirish Moodalbail * SIOCSLIFPREFIX sets the address with the given prefix 1816e91bba0SGirish Moodalbail * and the default interface id. 1826e91bba0SGirish Moodalbail */ 1836e91bba0SGirish Moodalbail sin6->sin6_addr = ll_template; 1846e91bba0SGirish Moodalbail err = ioctl(iph->iph_sock6, SIOCSLIFPREFIX, (caddr_t)&lifr); 1856e91bba0SGirish Moodalbail if (err < 0) 1866e91bba0SGirish Moodalbail goto fail; 1876e91bba0SGirish Moodalbail } else { 1886e91bba0SGirish Moodalbail /* Make a linklocal address in sin6 and set it */ 1896e91bba0SGirish Moodalbail i_ipadm_make_linklocal(sin6, &addr->ipadm_intfid.sin6_addr); 1906e91bba0SGirish Moodalbail err = ioctl(iph->iph_sock6, SIOCSLIFADDR, (caddr_t)&lifr); 1916e91bba0SGirish Moodalbail if (err < 0) 1926e91bba0SGirish Moodalbail goto fail; 1936e91bba0SGirish Moodalbail } 1946e91bba0SGirish Moodalbail if ((err = ioctl(iph->iph_sock6, SIOCGLIFFLAGS, (char *)&lifr)) < 0) 1956e91bba0SGirish Moodalbail goto fail; 1966e91bba0SGirish Moodalbail lifr.lifr_flags |= IFF_UP; 1976e91bba0SGirish Moodalbail if ((err = ioctl(iph->iph_sock6, SIOCSLIFFLAGS, (char *)&lifr)) < 0) 1986e91bba0SGirish Moodalbail goto fail; 1996e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 2006e91bba0SGirish Moodalbail 2016e91bba0SGirish Moodalbail fail: 2026e91bba0SGirish Moodalbail if (errno == EEXIST) 2036e91bba0SGirish Moodalbail status = IPADM_ADDRCONF_EXISTS; 2046e91bba0SGirish Moodalbail else 2056e91bba0SGirish Moodalbail status = ipadm_errno2status(errno); 2066e91bba0SGirish Moodalbail /* Remove the linklocal that was created. */ 2076e91bba0SGirish Moodalbail if (addif) { 2086e91bba0SGirish Moodalbail (void) ioctl(iph->iph_sock6, SIOCLIFREMOVEIF, (caddr_t)&lifr); 2096e91bba0SGirish Moodalbail } else { 2106e91bba0SGirish Moodalbail struct sockaddr_in6 *sin6; 2116e91bba0SGirish Moodalbail 2126e91bba0SGirish Moodalbail sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 2136e91bba0SGirish Moodalbail lifr.lifr_flags &= ~IFF_UP; 2146e91bba0SGirish Moodalbail (void) ioctl(iph->iph_sock6, SIOCSLIFFLAGS, (caddr_t)&lifr); 2156e91bba0SGirish Moodalbail sin6->sin6_family = AF_INET6; 2166e91bba0SGirish Moodalbail sin6->sin6_addr = in6addr_any; 2176e91bba0SGirish Moodalbail (void) ioctl(iph->iph_sock6, SIOCSLIFADDR, (caddr_t)&lifr); 2186e91bba0SGirish Moodalbail } 2196e91bba0SGirish Moodalbail return (status); 2206e91bba0SGirish Moodalbail } 2216e91bba0SGirish Moodalbail 2226e91bba0SGirish Moodalbail /* 2236e91bba0SGirish Moodalbail * Make a linklocal address based on the given intfid and copy it into 2246e91bba0SGirish Moodalbail * the output parameter `sin6'. 2256e91bba0SGirish Moodalbail */ 2266e91bba0SGirish Moodalbail static void 2276e91bba0SGirish Moodalbail i_ipadm_make_linklocal(struct sockaddr_in6 *sin6, const struct in6_addr *intfid) 2286e91bba0SGirish Moodalbail { 2296e91bba0SGirish Moodalbail int i; 2306e91bba0SGirish Moodalbail in6_addr_t ll_template = {0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2316e91bba0SGirish Moodalbail 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; 2326e91bba0SGirish Moodalbail 2336e91bba0SGirish Moodalbail sin6->sin6_family = AF_INET6; 2346e91bba0SGirish Moodalbail sin6->sin6_addr = *intfid; 2356e91bba0SGirish Moodalbail for (i = 0; i < 4; i++) { 2366e91bba0SGirish Moodalbail sin6->sin6_addr.s6_addr[i] = 2376e91bba0SGirish Moodalbail sin6->sin6_addr.s6_addr[i] | ll_template.s6_addr[i]; 2386e91bba0SGirish Moodalbail } 2396e91bba0SGirish Moodalbail } 2406e91bba0SGirish Moodalbail 2416e91bba0SGirish Moodalbail /* 2426e91bba0SGirish Moodalbail * Function that forms an ndpd msg and sends it to the in.ndpd daemon's loopback 2436e91bba0SGirish Moodalbail * listener socket. 2446e91bba0SGirish Moodalbail */ 2456e91bba0SGirish Moodalbail static ipadm_status_t 2466e91bba0SGirish Moodalbail i_ipadm_send_ndpd_cmd(const char *ifname, const struct ipadm_addrobj_s *addr, 2476e91bba0SGirish Moodalbail int cmd) 2486e91bba0SGirish Moodalbail { 2496e91bba0SGirish Moodalbail int fd; 2506e91bba0SGirish Moodalbail struct sockaddr_un servaddr; 2516e91bba0SGirish Moodalbail int flags; 2526e91bba0SGirish Moodalbail ipadm_ndpd_msg_t msg; 2536e91bba0SGirish Moodalbail int retval; 2546e91bba0SGirish Moodalbail 2556e91bba0SGirish Moodalbail if (addr == NULL && 2566e91bba0SGirish Moodalbail (cmd == IPADM_CREATE_ADDRS || cmd == IPADM_DELETE_ADDRS)) { 2576e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 2586e91bba0SGirish Moodalbail } 2596e91bba0SGirish Moodalbail 2606e91bba0SGirish Moodalbail fd = socket(AF_UNIX, SOCK_STREAM, 0); 2616e91bba0SGirish Moodalbail if (fd == -1) 2626e91bba0SGirish Moodalbail return (IPADM_FAILURE); 2636e91bba0SGirish Moodalbail 2646e91bba0SGirish Moodalbail /* Put the socket in non-blocking mode */ 2656e91bba0SGirish Moodalbail flags = fcntl(fd, F_GETFL, 0); 2666e91bba0SGirish Moodalbail if (flags != -1) 2676e91bba0SGirish Moodalbail (void) fcntl(fd, F_SETFL, flags | O_NONBLOCK); 2686e91bba0SGirish Moodalbail 2696e91bba0SGirish Moodalbail /* Connect to in.ndpd */ 2706e91bba0SGirish Moodalbail bzero(&servaddr, sizeof (servaddr)); 2716e91bba0SGirish Moodalbail servaddr.sun_family = AF_UNIX; 2726e91bba0SGirish Moodalbail (void) strlcpy(servaddr.sun_path, IPADM_UDS_PATH, 2736e91bba0SGirish Moodalbail sizeof (servaddr.sun_path)); 2746e91bba0SGirish Moodalbail if (connect(fd, (struct sockaddr *)&servaddr, sizeof (servaddr)) == -1) 2756e91bba0SGirish Moodalbail goto fail; 2766e91bba0SGirish Moodalbail 2776e91bba0SGirish Moodalbail bzero(&msg, sizeof (msg)); 2786e91bba0SGirish Moodalbail msg.inm_cmd = cmd; 2796e91bba0SGirish Moodalbail (void) strlcpy(msg.inm_ifname, ifname, sizeof (msg.inm_ifname)); 2806e91bba0SGirish Moodalbail if (addr != NULL) { 2816e91bba0SGirish Moodalbail msg.inm_intfid = addr->ipadm_intfid; 2826e91bba0SGirish Moodalbail msg.inm_intfidlen = addr->ipadm_intfidlen; 2836e91bba0SGirish Moodalbail msg.inm_stateless = addr->ipadm_stateless; 2846e91bba0SGirish Moodalbail msg.inm_stateful = addr->ipadm_stateful; 2856e91bba0SGirish Moodalbail if (cmd == IPADM_CREATE_ADDRS) { 2866e91bba0SGirish Moodalbail (void) strlcpy(msg.inm_aobjname, addr->ipadm_aobjname, 2876e91bba0SGirish Moodalbail sizeof (msg.inm_aobjname)); 2886e91bba0SGirish Moodalbail } 2896e91bba0SGirish Moodalbail } 2906e91bba0SGirish Moodalbail if (ipadm_ndpd_write(fd, &msg, sizeof (msg)) < 0) 2916e91bba0SGirish Moodalbail goto fail; 2926e91bba0SGirish Moodalbail if (ipadm_ndpd_read(fd, &retval, sizeof (retval)) < 0) 2936e91bba0SGirish Moodalbail goto fail; 2946e91bba0SGirish Moodalbail (void) close(fd); 2956e91bba0SGirish Moodalbail if (cmd == IPADM_CREATE_ADDRS && retval == EEXIST) 2966e91bba0SGirish Moodalbail return (IPADM_ADDRCONF_EXISTS); 2976e91bba0SGirish Moodalbail return (ipadm_errno2status(retval)); 2986e91bba0SGirish Moodalbail fail: 2996e91bba0SGirish Moodalbail (void) close(fd); 3006e91bba0SGirish Moodalbail return (IPADM_NDPD_NOT_RUNNING); 3016e91bba0SGirish Moodalbail } 3026e91bba0SGirish Moodalbail 3036e91bba0SGirish Moodalbail /* 3046e91bba0SGirish Moodalbail * Attempt to read `buflen' worth of bytes from `fd' into the buffer pointed 3056e91bba0SGirish Moodalbail * to by `buf'. 3066e91bba0SGirish Moodalbail */ 3076e91bba0SGirish Moodalbail int 3086e91bba0SGirish Moodalbail ipadm_ndpd_read(int fd, void *buffer, size_t buflen) 3096e91bba0SGirish Moodalbail { 3106e91bba0SGirish Moodalbail int retval; 3116e91bba0SGirish Moodalbail ssize_t nbytes = 0; /* total bytes processed */ 3126e91bba0SGirish Moodalbail ssize_t prbytes; /* per-round bytes processed */ 3136e91bba0SGirish Moodalbail struct pollfd pfd; 3146e91bba0SGirish Moodalbail 3156e91bba0SGirish Moodalbail while (nbytes < buflen) { 3166e91bba0SGirish Moodalbail 3176e91bba0SGirish Moodalbail pfd.fd = fd; 3186e91bba0SGirish Moodalbail pfd.events = POLLIN; 3196e91bba0SGirish Moodalbail 3206e91bba0SGirish Moodalbail /* 3216e91bba0SGirish Moodalbail * Wait for data to come in or for the timeout to fire. 3226e91bba0SGirish Moodalbail */ 3236e91bba0SGirish Moodalbail retval = poll(&pfd, 1, NDPDTIMEOUT); 3246e91bba0SGirish Moodalbail if (retval <= 0) { 3256e91bba0SGirish Moodalbail if (retval == 0) 3266e91bba0SGirish Moodalbail errno = ETIME; 3276e91bba0SGirish Moodalbail break; 3286e91bba0SGirish Moodalbail } 3296e91bba0SGirish Moodalbail 3306e91bba0SGirish Moodalbail /* 3316e91bba0SGirish Moodalbail * Descriptor is ready; have at it. 3326e91bba0SGirish Moodalbail */ 3336e91bba0SGirish Moodalbail prbytes = read(fd, (caddr_t)buffer + nbytes, buflen - nbytes); 3346e91bba0SGirish Moodalbail if (prbytes <= 0) { 3356e91bba0SGirish Moodalbail if (prbytes == -1 && errno == EINTR) 3366e91bba0SGirish Moodalbail continue; 3376e91bba0SGirish Moodalbail break; 3386e91bba0SGirish Moodalbail } 3396e91bba0SGirish Moodalbail nbytes += prbytes; 3406e91bba0SGirish Moodalbail } 3416e91bba0SGirish Moodalbail 3426e91bba0SGirish Moodalbail return (nbytes == buflen ? 0 : -1); 3436e91bba0SGirish Moodalbail } 3446e91bba0SGirish Moodalbail 3456e91bba0SGirish Moodalbail /* 3466e91bba0SGirish Moodalbail * Write `buflen' bytes from `buffer' to open file `fd'. Returns 0 3476e91bba0SGirish Moodalbail * if all requested bytes were written, or an error code if not. 3486e91bba0SGirish Moodalbail */ 3496e91bba0SGirish Moodalbail int 3506e91bba0SGirish Moodalbail ipadm_ndpd_write(int fd, const void *buffer, size_t buflen) 3516e91bba0SGirish Moodalbail { 3526e91bba0SGirish Moodalbail size_t nwritten; 3536e91bba0SGirish Moodalbail ssize_t nbytes; 3546e91bba0SGirish Moodalbail const char *buf = buffer; 3556e91bba0SGirish Moodalbail 3566e91bba0SGirish Moodalbail for (nwritten = 0; nwritten < buflen; nwritten += nbytes) { 3576e91bba0SGirish Moodalbail nbytes = write(fd, &buf[nwritten], buflen - nwritten); 3586e91bba0SGirish Moodalbail if (nbytes == -1) 3596e91bba0SGirish Moodalbail return (-1); 3606e91bba0SGirish Moodalbail if (nbytes == 0) { 3616e91bba0SGirish Moodalbail errno = EIO; 3626e91bba0SGirish Moodalbail return (-1); 3636e91bba0SGirish Moodalbail } 3646e91bba0SGirish Moodalbail } 3656e91bba0SGirish Moodalbail 3666e91bba0SGirish Moodalbail assert(nwritten == buflen); 3676e91bba0SGirish Moodalbail return (0); 3686e91bba0SGirish Moodalbail } 369