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/param.h> 43 #include <sys/socket.h> 44 45 #ifdef _STANDALONE 46 #include <lib/libkern/libkern.h> 47 #else 48 #include <string.h> 49 #endif 50 51 #include <net/if.h> 52 #include <net/if_ether.h> 53 54 #include <netinet/in.h> 55 #include <netinet/in_systm.h> 56 #include <netinet/ip.h> 57 #include <netinet/ip_var.h> 58 #include <netinet/udp.h> 59 #include <netinet/udp_var.h> 60 61 #include "stand.h" 62 #include "net.h" 63 64 /* Caller must leave room for ethernet, ip and udp headers in front!! */ 65 ssize_t 66 sendudp(d, pkt, len) 67 register struct iodesc *d; 68 register void *pkt; 69 register size_t len; 70 { 71 register ssize_t cc; 72 register struct ip *ip; 73 register struct udphdr *uh; 74 register u_char *ea; 75 76 #ifdef NET_DEBUG 77 if (debug) { 78 printf("sendudp: d=%lx called.\n", (long)d); 79 if (d) { 80 printf("saddr: %s:%d", 81 inet_ntoa(d->myip), ntohs(d->myport)); 82 printf(" daddr: %s:%d\n", 83 inet_ntoa(d->destip), ntohs(d->destport)); 84 } 85 } 86 #endif 87 88 uh = (struct udphdr *)pkt - 1; 89 ip = (struct ip *)uh - 1; 90 len += sizeof(*ip) + sizeof(*uh); 91 92 bzero(ip, sizeof(*ip) + sizeof(*uh)); 93 94 ip->ip_v = IPVERSION; /* half-char */ 95 ip->ip_hl = sizeof(*ip) >> 2; /* half-char */ 96 ip->ip_len = htons(len); 97 ip->ip_p = IPPROTO_UDP; /* char */ 98 ip->ip_ttl = IP_TTL; /* char */ 99 ip->ip_src = d->myip; 100 ip->ip_dst = d->destip; 101 ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */ 102 103 uh->uh_sport = d->myport; 104 uh->uh_dport = d->destport; 105 uh->uh_ulen = htons(len - sizeof(*ip)); 106 107 #ifndef UDP_NO_CKSUM 108 { 109 register struct udpiphdr *ui; 110 struct ip tip; 111 112 /* Calculate checksum (must save and restore ip header) */ 113 tip = *ip; 114 ui = (struct udpiphdr *)ip; 115 bzero(ui->ui_x1, sizeof(ui->ui_x1)); 116 ui->ui_len = uh->uh_ulen; 117 uh->uh_sum = in_cksum(ui, len); 118 *ip = tip; 119 } 120 #endif 121 122 if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 || 123 netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask)) 124 ea = arpwhohas(d, ip->ip_dst); 125 else 126 ea = arpwhohas(d, gateip); 127 128 cc = sendether(d, ip, len, ea, ETHERTYPE_IP); 129 if (cc == -1) 130 return (-1); 131 if (cc != len) 132 panic("sendudp: bad write (%d != %d)", cc, len); 133 return (cc - (sizeof(*ip) + sizeof(*uh))); 134 } 135 136 /* 137 * Receive a UDP packet and validate it is for us. 138 * Caller leaves room for the headers (Ether, IP, UDP) 139 */ 140 ssize_t 141 readudp(d, pkt, len, tleft) 142 register struct iodesc *d; 143 register void *pkt; 144 register size_t len; 145 time_t tleft; 146 { 147 register ssize_t n; 148 register size_t hlen; 149 register struct ip *ip; 150 register struct udphdr *uh; 151 u_int16_t etype; /* host order */ 152 153 #ifdef NET_DEBUG 154 if (debug) 155 printf("readudp: called\n"); 156 #endif 157 158 uh = (struct udphdr *)pkt - 1; 159 ip = (struct ip *)uh - 1; 160 161 n = readether(d, ip, len + sizeof(*ip) + sizeof(*uh), tleft, &etype); 162 if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) 163 return -1; 164 165 /* Ethernet address checks now in readether() */ 166 167 /* Need to respond to ARP requests. */ 168 if (etype == ETHERTYPE_ARP) { 169 struct arphdr *ah = (void *)ip; 170 if (ah->ar_op == htons(ARPOP_REQUEST)) { 171 /* Send ARP reply */ 172 arp_reply(d, ah); 173 } 174 return -1; 175 } 176 177 if (etype != ETHERTYPE_IP) { 178 #ifdef NET_DEBUG 179 if (debug) 180 printf("readudp: not IP. ether_type=%x\n", etype); 181 #endif 182 return -1; 183 } 184 185 /* Check ip header */ 186 if (ip->ip_v != IPVERSION || 187 ip->ip_p != IPPROTO_UDP) { /* half char */ 188 #ifdef NET_DEBUG 189 if (debug) 190 printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p); 191 #endif 192 return -1; 193 } 194 195 hlen = ip->ip_hl << 2; 196 if (hlen < sizeof(*ip) || 197 in_cksum(ip, hlen) != 0) { 198 #ifdef NET_DEBUG 199 if (debug) 200 printf("readudp: short hdr or bad cksum.\n"); 201 #endif 202 return -1; 203 } 204 if (n < ntohs(ip->ip_len)) { 205 #ifdef NET_DEBUG 206 if (debug) 207 printf("readudp: bad length %d < %d.\n", 208 (int)n, ntohs(ip->ip_len)); 209 #endif 210 return -1; 211 } 212 if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) { 213 #ifdef NET_DEBUG 214 if (debug) { 215 printf("readudp: bad saddr %s != ", inet_ntoa(d->myip)); 216 printf("%s\n", inet_ntoa(ip->ip_dst)); 217 } 218 #endif 219 return -1; 220 } 221 222 /* If there were ip options, make them go away */ 223 if (hlen != sizeof(*ip)) { 224 bcopy(((u_char *)ip) + hlen, uh, len - hlen); 225 ip->ip_len = htons(sizeof(*ip)); 226 n -= hlen - sizeof(*ip); 227 } 228 if (uh->uh_dport != d->myport) { 229 #ifdef NET_DEBUG 230 if (debug) 231 printf("readudp: bad dport %d != %d\n", 232 d->myport, ntohs(uh->uh_dport)); 233 #endif 234 return -1; 235 } 236 237 #ifndef UDP_NO_CKSUM 238 if (uh->uh_sum) { 239 register struct udpiphdr *ui; 240 struct ip tip; 241 242 n = ntohs(uh->uh_ulen) + sizeof(*ip); 243 if (n > RECV_SIZE - ETHER_SIZE) { 244 printf("readudp: huge packet, udp len %d\n", (int)n); 245 return -1; 246 } 247 248 /* Check checksum (must save and restore ip header) */ 249 tip = *ip; 250 ui = (struct udpiphdr *)ip; 251 bzero(ui->ui_x1, sizeof(ui->ui_x1)); 252 ui->ui_len = uh->uh_ulen; 253 if (in_cksum(ui, n) != 0) { 254 #ifdef NET_DEBUG 255 if (debug) 256 printf("readudp: bad cksum\n"); 257 #endif 258 *ip = tip; 259 return -1; 260 } 261 *ip = tip; 262 } 263 #endif 264 if (ntohs(uh->uh_ulen) < sizeof(*uh)) { 265 #ifdef NET_DEBUG 266 if (debug) 267 printf("readudp: bad udp len %d < %d\n", 268 ntohs(uh->uh_ulen), (int)sizeof(*uh)); 269 #endif 270 return -1; 271 } 272 273 n -= sizeof(*ip) + sizeof(*uh); 274 return (n); 275 } 276 277 /* 278 * Send a packet and wait for a reply, with exponential backoff. 279 * 280 * The send routine must return the actual number of bytes written, 281 * or -1 on error. 282 * 283 * The receive routine can indicate success by returning the number of 284 * bytes read; it can return 0 to indicate EOF; it can return -1 with a 285 * non-zero errno to indicate failure; finally, it can return -1 with a 286 * zero errno to indicate it isn't done yet. 287 */ 288 ssize_t 289 sendrecv(d, sproc, sbuf, ssize, rproc, rbuf, rsize) 290 register struct iodesc *d; 291 register ssize_t (*sproc)(struct iodesc *, void *, size_t); 292 register void *sbuf; 293 register size_t ssize; 294 register ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t); 295 register void *rbuf; 296 register size_t rsize; 297 { 298 register ssize_t cc; 299 register time_t t, tmo, tlast; 300 long tleft; 301 302 #ifdef NET_DEBUG 303 if (debug) 304 printf("sendrecv: called\n"); 305 #endif 306 307 tmo = MINTMO; 308 tlast = tleft = 0; 309 t = getsecs(); 310 for (;;) { 311 if (tleft <= 0) { 312 if (tmo >= MAXTMO) { 313 errno = ETIMEDOUT; 314 return -1; 315 } 316 cc = (*sproc)(d, sbuf, ssize); 317 if (cc != -1 && cc < ssize) 318 panic("sendrecv: short write! (%d < %d)", 319 cc, ssize); 320 321 tleft = tmo; 322 tmo <<= 1; 323 if (tmo > MAXTMO) 324 tmo = MAXTMO; 325 326 if (cc == -1) { 327 /* Error on transmit; wait before retrying */ 328 while ((getsecs() - t) < tmo); 329 tleft = 0; 330 continue; 331 } 332 333 tlast = t; 334 } 335 336 /* Try to get a packet and process it. */ 337 cc = (*rproc)(d, rbuf, rsize, tleft); 338 /* Return on data, EOF or real error. */ 339 if (cc != -1 || errno != 0) 340 return (cc); 341 342 /* Timed out or didn't get the packet we're waiting for */ 343 t = getsecs(); 344 tleft -= t - tlast; 345 tlast = t; 346 } 347 } 348 349 /* 350 * Like inet_addr() in the C library, but we only accept base-10. 351 * Return values are in network order. 352 */ 353 n_long 354 inet_addr(cp) 355 char *cp; 356 { 357 register u_long val; 358 register int n; 359 register char c; 360 u_int parts[4]; 361 register u_int *pp = parts; 362 363 for (;;) { 364 /* 365 * Collect number up to ``.''. 366 * Values are specified as for C: 367 * 0x=hex, 0=octal, other=decimal. 368 */ 369 val = 0; 370 while ((c = *cp) != '\0') { 371 if (c >= '0' && c <= '9') { 372 val = (val * 10) + (c - '0'); 373 cp++; 374 continue; 375 } 376 break; 377 } 378 if (*cp == '.') { 379 /* 380 * Internet format: 381 * a.b.c.d 382 * a.b.c (with c treated as 16-bits) 383 * a.b (with b treated as 24 bits) 384 */ 385 if (pp >= parts + 3 || val > 0xff) 386 goto bad; 387 *pp++ = val, cp++; 388 } else 389 break; 390 } 391 /* 392 * Check for trailing characters. 393 */ 394 if (*cp != '\0') 395 goto bad; 396 397 /* 398 * Concoct the address according to 399 * the number of parts specified. 400 */ 401 n = pp - parts + 1; 402 switch (n) { 403 404 case 1: /* a -- 32 bits */ 405 break; 406 407 case 2: /* a.b -- 8.24 bits */ 408 if (val > 0xffffff) 409 goto bad; 410 val |= parts[0] << 24; 411 break; 412 413 case 3: /* a.b.c -- 8.8.16 bits */ 414 if (val > 0xffff) 415 goto bad; 416 val |= (parts[0] << 24) | (parts[1] << 16); 417 break; 418 419 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 420 if (val > 0xff) 421 goto bad; 422 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 423 break; 424 } 425 426 return (htonl(val)); 427 bad: 428 return (htonl(INADDR_NONE)); 429 } 430 431 char * 432 inet_ntoa(ia) 433 struct in_addr ia; 434 { 435 return (intoa(ia.s_addr)); 436 } 437 438 /* Similar to inet_ntoa() */ 439 char * 440 intoa(addr) 441 register n_long addr; 442 { 443 register char *cp; 444 register u_int byte; 445 register int n; 446 static char buf[17]; /* strlen(".255.255.255.255") + 1 */ 447 448 NTOHL(addr); 449 cp = &buf[sizeof buf]; 450 *--cp = '\0'; 451 452 n = 4; 453 do { 454 byte = addr & 0xff; 455 *--cp = byte % 10 + '0'; 456 byte /= 10; 457 if (byte > 0) { 458 *--cp = byte % 10 + '0'; 459 byte /= 10; 460 if (byte > 0) 461 *--cp = byte + '0'; 462 } 463 *--cp = '.'; 464 addr >>= 8; 465 } while (--n > 0); 466 467 return (cp+1); 468 } 469 470 static char * 471 number(s, n) 472 char *s; 473 int *n; 474 { 475 for (*n = 0; isdigit(*s); s++) 476 *n = (*n * 10) + *s - '0'; 477 return s; 478 } 479 480 n_long 481 ip_convertaddr(p) 482 char *p; 483 { 484 #define IP_ANYADDR 0 485 n_long addr = 0, n; 486 487 if (p == (char *)0 || *p == '\0') 488 return IP_ANYADDR; 489 p = number(p, &n); 490 addr |= (n << 24) & 0xff000000; 491 if (*p == '\0' || *p++ != '.') 492 return IP_ANYADDR; 493 p = number(p, &n); 494 addr |= (n << 16) & 0xff0000; 495 if (*p == '\0' || *p++ != '.') 496 return IP_ANYADDR; 497 p = number(p, &n); 498 addr |= (n << 8) & 0xff00; 499 if (*p == '\0' || *p++ != '.') 500 return IP_ANYADDR; 501 p = number(p, &n); 502 addr |= n & 0xff; 503 if (*p != '\0') 504 return IP_ANYADDR; 505 506 return htonl(addr); 507 } 508