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