net.c revision 331251
1/* $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ 2 3/* 4 * Copyright (c) 1992 Regents of the University of California. 5 * All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) 36 */ 37 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD: stable/11/stand/libsa/net.c 331251 2018-03-20 17:41:54Z kevans $"); 40 41#include <sys/param.h> 42#include <sys/socket.h> 43 44#include <string.h> 45 46#include <net/if.h> 47#include <netinet/in.h> 48#include <netinet/if_ether.h> 49#include <netinet/in_systm.h> 50 51#include <netinet/in_pcb.h> 52#include <netinet/ip.h> 53#include <netinet/ip_var.h> 54#include <netinet/udp.h> 55#include <netinet/udp_var.h> 56 57#include "stand.h" 58#include "net.h" 59 60/* 61 * Send a packet and wait for a reply, with exponential backoff. 62 * 63 * The send routine must return the actual number of bytes written, 64 * or -1 on error. 65 * 66 * The receive routine can indicate success by returning the number of 67 * bytes read; it can return 0 to indicate EOF; it can return -1 with a 68 * non-zero errno to indicate failure; finally, it can return -1 with a 69 * zero errno to indicate it isn't done yet. 70 */ 71ssize_t 72sendrecv(struct iodesc *d, 73 ssize_t (*sproc)(struct iodesc *, void *, size_t), 74 void *sbuf, size_t ssize, 75 ssize_t (*rproc)(struct iodesc *, void **, void **, time_t, void *), 76 void **pkt, void **payload, void *recv_extra) 77{ 78 ssize_t cc; 79 time_t t, tmo, tlast; 80 time_t tref; 81 long tleft; 82 83#ifdef NET_DEBUG 84 if (debug) 85 printf("sendrecv: called\n"); 86#endif 87 88 tmo = MINTMO; 89 tlast = 0; 90 tleft = 0; 91 tref = getsecs(); 92 t = getsecs(); 93 for (;;) { 94 if (MAXWAIT > 0 && (getsecs() - tref) >= MAXWAIT) { 95 errno = ETIMEDOUT; 96 return -1; 97 } 98 if (tleft <= 0) { 99 if (tmo >= MAXTMO) { 100 errno = ETIMEDOUT; 101 return -1; 102 } 103 cc = (*sproc)(d, sbuf, ssize); 104 if (cc != -1 && cc < ssize) 105 panic("sendrecv: short write! (%zd < %zd)", 106 cc, ssize); 107 108 tleft = tmo; 109 tmo += MINTMO; 110 if (tmo > MAXTMO) 111 tmo = MAXTMO; 112 113 if (cc == -1) { 114 /* Error on transmit; wait before retrying */ 115 while ((getsecs() - t) < tmo) 116 ; 117 tleft = 0; 118 continue; 119 } 120 121 tlast = t; 122 } 123 124 /* Try to get a packet and process it. */ 125 cc = (*rproc)(d, pkt, payload, tleft, recv_extra); 126 /* Return on data, EOF or real error. */ 127 if (cc != -1 || (errno != 0 && errno != ETIMEDOUT)) 128 return (cc); 129 130 /* Timed out or didn't get the packet we're waiting for */ 131 t = getsecs(); 132 tleft -= t - tlast; 133 tlast = t; 134 } 135} 136 137/* 138 * Like inet_addr() in the C library, but we only accept base-10. 139 * Return values are in network order. 140 */ 141n_long 142inet_addr(char *cp) 143{ 144 u_long val; 145 int n; 146 char c; 147 u_int parts[4]; 148 u_int *pp = parts; 149 150 for (;;) { 151 /* 152 * Collect number up to ``.''. 153 * Values are specified as for C: 154 * 0x=hex, 0=octal, other=decimal. 155 */ 156 val = 0; 157 while ((c = *cp) != '\0') { 158 if (c >= '0' && c <= '9') { 159 val = (val * 10) + (c - '0'); 160 cp++; 161 continue; 162 } 163 break; 164 } 165 if (*cp == '.') { 166 /* 167 * Internet format: 168 * a.b.c.d 169 * a.b.c (with c treated as 16-bits) 170 * a.b (with b treated as 24 bits) 171 */ 172 if (pp >= parts + 3 || val > 0xff) 173 goto bad; 174 *pp++ = val, cp++; 175 } else 176 break; 177 } 178 /* 179 * Check for trailing characters. 180 */ 181 if (*cp != '\0') 182 goto bad; 183 184 /* 185 * Concoct the address according to 186 * the number of parts specified. 187 */ 188 n = pp - parts + 1; 189 switch (n) { 190 191 case 1: /* a -- 32 bits */ 192 break; 193 194 case 2: /* a.b -- 8.24 bits */ 195 if (val > 0xffffff) 196 goto bad; 197 val |= parts[0] << 24; 198 break; 199 200 case 3: /* a.b.c -- 8.8.16 bits */ 201 if (val > 0xffff) 202 goto bad; 203 val |= (parts[0] << 24) | (parts[1] << 16); 204 break; 205 206 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 207 if (val > 0xff) 208 goto bad; 209 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 210 break; 211 } 212 213 return (htonl(val)); 214 bad: 215 return (htonl(INADDR_NONE)); 216} 217 218char * 219inet_ntoa(struct in_addr ia) 220{ 221 return (intoa(ia.s_addr)); 222} 223 224/* Similar to inet_ntoa() */ 225char * 226intoa(n_long addr) 227{ 228 char *cp; 229 u_int byte; 230 int n; 231 static char buf[17]; /* strlen(".255.255.255.255") + 1 */ 232 233 addr = ntohl(addr); 234 cp = &buf[sizeof buf]; 235 *--cp = '\0'; 236 237 n = 4; 238 do { 239 byte = addr & 0xff; 240 *--cp = byte % 10 + '0'; 241 byte /= 10; 242 if (byte > 0) { 243 *--cp = byte % 10 + '0'; 244 byte /= 10; 245 if (byte > 0) 246 *--cp = byte + '0'; 247 } 248 *--cp = '.'; 249 addr >>= 8; 250 } while (--n > 0); 251 252 return (cp+1); 253} 254 255static char * 256number(char *s, int *n) 257{ 258 for (*n = 0; isdigit(*s); s++) 259 *n = (*n * 10) + *s - '0'; 260 return s; 261} 262 263n_long 264ip_convertaddr(char *p) 265{ 266#define IP_ANYADDR 0 267 n_long addr = 0, n; 268 269 if (p == (char *)0 || *p == '\0') 270 return IP_ANYADDR; 271 p = number(p, &n); 272 addr |= (n << 24) & 0xff000000; 273 if (*p == '\0' || *p++ != '.') 274 return IP_ANYADDR; 275 p = number(p, &n); 276 addr |= (n << 16) & 0xff0000; 277 if (*p == '\0' || *p++ != '.') 278 return IP_ANYADDR; 279 p = number(p, &n); 280 addr |= (n << 8) & 0xff00; 281 if (*p == '\0' || *p++ != '.') 282 return IP_ANYADDR; 283 p = number(p, &n); 284 addr |= n & 0xff; 285 if (*p != '\0') 286 return IP_ANYADDR; 287 288 return htonl(addr); 289} 290