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