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