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