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