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