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