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