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. 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 #include <sys/param.h> 40 #include <sys/socket.h> 41 42 #include <string.h> 43 44 #include <net/if.h> 45 #include <netinet/in.h> 46 #include <netinet/if_ether.h> 47 #include <netinet/in_systm.h> 48 49 #include <netinet/ip.h> 50 #include <netinet/ip_var.h> 51 #include <netinet/udp.h> 52 #include <netinet/udp_var.h> 53 54 #include "stand.h" 55 #include "net.h" 56 57 /* 58 * Maximum wait time for sending and receiving before we give up and timeout. 59 * If set to 0, operations will eventually timeout completely, but send/recv 60 * timeouts must progress exponentially from MINTMO to MAXTMO before final 61 * timeout is hit. 62 */ 63 #ifndef MAXWAIT 64 #define MAXWAIT 300 /* seconds */ 65 #endif 66 67 #if MAXWAIT < 0 68 #error MAXWAIT must not be a negative number 69 #endif 70 71 /* 72 * Send a packet and wait for a reply, with exponential backoff. 73 * 74 * The send routine must return the actual number of bytes written, 75 * or -1 on error. 76 * 77 * The receive routine can indicate success by returning the number of 78 * bytes read; it can return 0 to indicate EOF; it can return -1 with a 79 * non-zero errno to indicate failure; finally, it can return -1 with a 80 * zero errno to indicate it isn't done yet. 81 */ 82 ssize_t 83 sendrecv(struct iodesc *d, 84 ssize_t (*sproc)(struct iodesc *, void *, size_t), 85 void *sbuf, size_t ssize, 86 ssize_t (*rproc)(struct iodesc *, void **, void **, time_t, void *), 87 void **pkt, void **payload, void *recv_extra) 88 { 89 ssize_t cc; 90 time_t t, tmo, tlast; 91 time_t tref; 92 long tleft; 93 94 #ifdef NET_DEBUG 95 if (debug) 96 printf("sendrecv: called\n"); 97 #endif 98 99 tmo = MINTMO; 100 tlast = 0; 101 tleft = 0; 102 tref = t = getsecs(); 103 for (;;) { 104 if (MAXWAIT > 0 && (t - tref) >= MAXWAIT) { 105 errno = ETIMEDOUT; 106 return -1; 107 } 108 if (tleft <= 0) { 109 if (tmo >= MAXTMO) { 110 errno = ETIMEDOUT; 111 return -1; 112 } 113 cc = (*sproc)(d, sbuf, ssize); 114 if (cc != -1 && cc < ssize) 115 panic("sendrecv: short write! (%zd < %zd)", 116 cc, ssize); 117 118 tleft = tmo; 119 tmo += MINTMO; 120 if (tmo > MAXTMO) 121 tmo = MAXTMO; 122 123 if (cc == -1) { 124 /* Error on transmit; wait before retrying */ 125 while ((getsecs() - t) < tmo) 126 ; 127 tleft = 0; 128 continue; 129 } 130 131 tlast = t; 132 } 133 134 /* Try to get a packet and process it. */ 135 cc = (*rproc)(d, pkt, payload, tleft, recv_extra); 136 /* Return on data, EOF or real error. */ 137 if (cc != -1 || (errno != 0 && errno != ETIMEDOUT)) 138 return (cc); 139 140 /* Timed out or didn't get the packet we're waiting for */ 141 t = getsecs(); 142 tleft -= t - tlast; 143 tlast = t; 144 } 145 } 146 147 /* 148 * Like inet_addr() in the C library, but we only accept base-10. 149 * Return values are in network order. 150 */ 151 n_long 152 inet_addr(char *cp) 153 { 154 u_long val; 155 int n; 156 char c; 157 u_int parts[4]; 158 u_int *pp = parts; 159 160 for (;;) { 161 /* 162 * Collect number up to ``.''. 163 * Values are specified as for C: 164 * 0x=hex, 0=octal, other=decimal. 165 */ 166 val = 0; 167 while ((c = *cp) != '\0') { 168 if (c >= '0' && c <= '9') { 169 val = (val * 10) + (c - '0'); 170 cp++; 171 continue; 172 } 173 break; 174 } 175 if (*cp == '.') { 176 /* 177 * Internet format: 178 * a.b.c.d 179 * a.b.c (with c treated as 16-bits) 180 * a.b (with b treated as 24 bits) 181 */ 182 if (pp >= parts + 3 || val > 0xff) 183 goto bad; 184 *pp++ = val, cp++; 185 } else 186 break; 187 } 188 /* 189 * Check for trailing characters. 190 */ 191 if (*cp != '\0') 192 goto bad; 193 194 /* 195 * Concoct the address according to 196 * the number of parts specified. 197 */ 198 n = pp - parts + 1; 199 switch (n) { 200 201 case 1: /* a -- 32 bits */ 202 break; 203 204 case 2: /* a.b -- 8.24 bits */ 205 if (val > 0xffffff) 206 goto bad; 207 val |= parts[0] << 24; 208 break; 209 210 case 3: /* a.b.c -- 8.8.16 bits */ 211 if (val > 0xffff) 212 goto bad; 213 val |= (parts[0] << 24) | (parts[1] << 16); 214 break; 215 216 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 217 if (val > 0xff) 218 goto bad; 219 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 220 break; 221 } 222 223 return (htonl(val)); 224 bad: 225 return (htonl(INADDR_NONE)); 226 } 227 228 char * 229 inet_ntoa(struct in_addr ia) 230 { 231 return (intoa(ia.s_addr)); 232 } 233 234 /* Similar to inet_ntoa() */ 235 char * 236 intoa(n_long addr) 237 { 238 char *cp; 239 u_int byte; 240 int n; 241 static char buf[17]; /* strlen(".255.255.255.255") + 1 */ 242 243 addr = ntohl(addr); 244 cp = &buf[sizeof buf]; 245 *--cp = '\0'; 246 247 n = 4; 248 do { 249 byte = addr & 0xff; 250 *--cp = byte % 10 + '0'; 251 byte /= 10; 252 if (byte > 0) { 253 *--cp = byte % 10 + '0'; 254 byte /= 10; 255 if (byte > 0) 256 *--cp = byte + '0'; 257 } 258 *--cp = '.'; 259 addr >>= 8; 260 } while (--n > 0); 261 262 return (cp+1); 263 } 264 265 static char * 266 number(char *s, n_long *n) 267 { 268 for (*n = 0; isdigit(*s); s++) 269 *n = (*n * 10) + *s - '0'; 270 return s; 271 } 272 273 n_long 274 ip_convertaddr(char *p) 275 { 276 #define IP_ANYADDR 0 277 n_long addr = 0, n; 278 279 if (p == NULL || *p == '\0') 280 return IP_ANYADDR; 281 p = number(p, &n); 282 addr |= (n << 24) & 0xff000000; 283 if (*p == '\0' || *p++ != '.') 284 return IP_ANYADDR; 285 p = number(p, &n); 286 addr |= (n << 16) & 0xff0000; 287 if (*p == '\0' || *p++ != '.') 288 return IP_ANYADDR; 289 p = number(p, &n); 290 addr |= (n << 8) & 0xff00; 291 if (*p == '\0' || *p++ != '.') 292 return IP_ANYADDR; 293 p = number(p, &n); 294 addr |= n & 0xff; 295 if (*p != '\0') 296 return IP_ANYADDR; 297 298 return htonl(addr); 299 } 300