1 /* $NetBSD: net.c,v 1.19 1997/09/17 16:30:51 drochner 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 * 282 * The receive routine can indicate success by returning the number of 283 * bytes read; it can return 0 to indicate EOF; it can return -1 with a 284 * non-zero errno to indicate failure; finally, it can return -1 with a 285 * zero errno to indicate it isn't done yet. 286 */ 287 ssize_t 288 sendrecv(d, sproc, sbuf, ssize, rproc, rbuf, rsize) 289 register struct iodesc *d; 290 register ssize_t (*sproc)(struct iodesc *, void *, size_t); 291 register void *sbuf; 292 register size_t ssize; 293 register ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t); 294 register void *rbuf; 295 register size_t rsize; 296 { 297 register ssize_t cc; 298 register time_t t, tmo, tlast; 299 long tleft; 300 301 #ifdef NET_DEBUG 302 if (debug) 303 printf("sendrecv: called\n"); 304 #endif 305 306 tmo = MINTMO; 307 tlast = tleft = 0; 308 t = getsecs(); 309 for (;;) { 310 if (tleft <= 0) { 311 if (tmo >= MAXTMO) { 312 errno = ETIMEDOUT; 313 return -1; 314 } 315 cc = (*sproc)(d, sbuf, ssize); 316 if (cc == -1 || cc < ssize) 317 panic("sendrecv: short write! (%d < %d)", 318 cc, ssize); 319 320 tleft = tmo; 321 tmo <<= 1; 322 if (tmo > MAXTMO) 323 tmo = MAXTMO; 324 tlast = t; 325 } 326 327 /* Try to get a packet and process it. */ 328 cc = (*rproc)(d, rbuf, rsize, tleft); 329 /* Return on data, EOF or real error. */ 330 if (cc != -1 || errno != 0) 331 return (cc); 332 333 /* Timed out or didn't get the packet we're waiting for */ 334 t = getsecs(); 335 tleft -= t - tlast; 336 tlast = t; 337 } 338 } 339 340 /* 341 * Like inet_addr() in the C library, but we only accept base-10. 342 * Return values are in network order. 343 */ 344 n_long 345 inet_addr(cp) 346 char *cp; 347 { 348 register u_long val; 349 register int n; 350 register char c; 351 u_int parts[4]; 352 register u_int *pp = parts; 353 354 for (;;) { 355 /* 356 * Collect number up to ``.''. 357 * Values are specified as for C: 358 * 0x=hex, 0=octal, other=decimal. 359 */ 360 val = 0; 361 while ((c = *cp) != '\0') { 362 if (c >= '0' && c <= '9') { 363 val = (val * 10) + (c - '0'); 364 cp++; 365 continue; 366 } 367 break; 368 } 369 if (*cp == '.') { 370 /* 371 * Internet format: 372 * a.b.c.d 373 * a.b.c (with c treated as 16-bits) 374 * a.b (with b treated as 24 bits) 375 */ 376 if (pp >= parts + 3 || val > 0xff) 377 goto bad; 378 *pp++ = val, cp++; 379 } else 380 break; 381 } 382 /* 383 * Check for trailing characters. 384 */ 385 if (*cp != '\0') 386 goto bad; 387 388 /* 389 * Concoct the address according to 390 * the number of parts specified. 391 */ 392 n = pp - parts + 1; 393 switch (n) { 394 395 case 1: /* a -- 32 bits */ 396 break; 397 398 case 2: /* a.b -- 8.24 bits */ 399 if (val > 0xffffff) 400 goto bad; 401 val |= parts[0] << 24; 402 break; 403 404 case 3: /* a.b.c -- 8.8.16 bits */ 405 if (val > 0xffff) 406 goto bad; 407 val |= (parts[0] << 24) | (parts[1] << 16); 408 break; 409 410 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 411 if (val > 0xff) 412 goto bad; 413 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 414 break; 415 } 416 417 return (htonl(val)); 418 bad: 419 return (htonl(INADDR_NONE)); 420 } 421 422 char * 423 inet_ntoa(ia) 424 struct in_addr ia; 425 { 426 return (intoa(ia.s_addr)); 427 } 428 429 /* Similar to inet_ntoa() */ 430 char * 431 intoa(addr) 432 register n_long addr; 433 { 434 register char *cp; 435 register u_int byte; 436 register int n; 437 static char buf[17]; /* strlen(".255.255.255.255") + 1 */ 438 439 NTOHL(addr); 440 cp = &buf[sizeof buf]; 441 *--cp = '\0'; 442 443 n = 4; 444 do { 445 byte = addr & 0xff; 446 *--cp = byte % 10 + '0'; 447 byte /= 10; 448 if (byte > 0) { 449 *--cp = byte % 10 + '0'; 450 byte /= 10; 451 if (byte > 0) 452 *--cp = byte + '0'; 453 } 454 *--cp = '.'; 455 addr >>= 8; 456 } while (--n > 0); 457 458 return (cp+1); 459 } 460 461 static char * 462 number(s, n) 463 char *s; 464 int *n; 465 { 466 for (*n = 0; isdigit(*s); s++) 467 *n = (*n * 10) + *s - '0'; 468 return s; 469 } 470 471 n_long 472 ip_convertaddr(p) 473 char *p; 474 { 475 #define IP_ANYADDR 0 476 n_long addr = 0, n; 477 478 if (p == (char *)0 || *p == '\0') 479 return IP_ANYADDR; 480 p = number(p, &n); 481 addr |= (n << 24) & 0xff000000; 482 if (*p == '\0' || *p++ != '.') 483 return IP_ANYADDR; 484 p = number(p, &n); 485 addr |= (n << 16) & 0xff0000; 486 if (*p == '\0' || *p++ != '.') 487 return IP_ANYADDR; 488 p = number(p, &n); 489 addr |= (n << 8) & 0xff00; 490 if (*p == '\0' || *p++ != '.') 491 return IP_ANYADDR; 492 p = number(p, &n); 493 addr |= n & 0xff; 494 if (*p != '\0') 495 return IP_ANYADDR; 496 497 return htonl(addr); 498 } 499