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