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