1 /* $OpenBSD: net.c,v 1.7 1996/12/08 15:15:51 niklas Exp $ */ 2 /* $NetBSD: net.c,v 1.14 1996/10/13 02:29:02 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1992 Regents of the University of California. 6 * All rights reserved. 7 * 8 * This software was developed by the Computer Systems Engineering group 9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 10 * contributed to Berkeley. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Lawrence Berkeley Laboratory and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) 41 */ 42 43 #include <sys/param.h> 44 #include <sys/socket.h> 45 46 #include <net/if.h> 47 #include <netinet/in.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; 290 long tleft; 291 292 #ifdef NET_DEBUG 293 if (debug) 294 printf("sendrecv: called\n"); 295 #endif 296 297 tmo = MINTMO; 298 tlast = tleft = 0; 299 t = getsecs(); 300 for (;;) { 301 if (tleft <= 0) { 302 if (tmo >= MAXTMO) { 303 errno = ETIMEDOUT; 304 return -1; 305 } 306 cc = (*sproc)(d, sbuf, ssize); 307 if (cc == -1 || cc < ssize) 308 panic("sendrecv: short write! (%d < %d)", 309 cc, ssize); 310 311 tleft = tmo; 312 tmo <<= 1; 313 if (tmo > MAXTMO) 314 tmo = MAXTMO; 315 tlast = t; 316 } 317 318 /* Try to get a packet and process it. */ 319 cc = (*rproc)(d, rbuf, rsize, tleft); 320 /* Return on data, EOF or real error. */ 321 if (cc != -1 || errno != 0) 322 return (cc); 323 324 /* Timed out or didn't get the packet we're waiting for */ 325 t = getsecs(); 326 tleft -= t - tlast; 327 tlast = t; 328 } 329 } 330 331 /* 332 * Like inet_addr() in the C library, but we only accept base-10. 333 * Return values are in network order. 334 */ 335 n_long 336 inet_addr(cp) 337 char *cp; 338 { 339 register u_long val; 340 register int n; 341 register char c; 342 u_int parts[4]; 343 register u_int *pp = parts; 344 345 for (;;) { 346 /* 347 * Collect number up to ``.''. 348 * Values are specified as for C: 349 * 0x=hex, 0=octal, other=decimal. 350 */ 351 val = 0; 352 while ((c = *cp) != '\0') { 353 if (c >= '0' && c <= '9') { 354 val = (val * 10) + (c - '0'); 355 cp++; 356 continue; 357 } 358 break; 359 } 360 if (*cp == '.') { 361 /* 362 * Internet format: 363 * a.b.c.d 364 * a.b.c (with c treated as 16-bits) 365 * a.b (with b treated as 24 bits) 366 */ 367 if (pp >= parts + 3 || val > 0xff) 368 goto bad; 369 *pp++ = val, cp++; 370 } else 371 break; 372 } 373 /* 374 * Check for trailing characters. 375 */ 376 if (*cp != '\0') 377 goto bad; 378 379 /* 380 * Concoct the address according to 381 * the number of parts specified. 382 */ 383 n = pp - parts + 1; 384 switch (n) { 385 386 case 1: /* a -- 32 bits */ 387 break; 388 389 case 2: /* a.b -- 8.24 bits */ 390 if (val > 0xffffff) 391 goto bad; 392 val |= parts[0] << 24; 393 break; 394 395 case 3: /* a.b.c -- 8.8.16 bits */ 396 if (val > 0xffff) 397 goto bad; 398 val |= (parts[0] << 24) | (parts[1] << 16); 399 break; 400 401 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 402 if (val > 0xff) 403 goto bad; 404 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 405 break; 406 } 407 408 return (htonl(val)); 409 bad: 410 return (htonl(INADDR_NONE)); 411 } 412 413 char * 414 inet_ntoa(ia) 415 struct in_addr ia; 416 { 417 return (intoa(ia.s_addr)); 418 } 419 420 /* Similar to inet_ntoa() */ 421 char * 422 intoa(addr) 423 register n_long addr; 424 { 425 register char *cp; 426 register u_int byte; 427 register int n; 428 static char buf[sizeof(".255.255.255.255")]; 429 430 NTOHL(addr); 431 cp = &buf[sizeof buf]; 432 *--cp = '\0'; 433 434 n = 4; 435 do { 436 byte = addr & 0xff; 437 *--cp = byte % 10 + '0'; 438 byte /= 10; 439 if (byte > 0) { 440 *--cp = byte % 10 + '0'; 441 byte /= 10; 442 if (byte > 0) 443 *--cp = byte + '0'; 444 } 445 *--cp = '.'; 446 addr >>= 8; 447 } while (--n > 0); 448 449 return (cp+1); 450 } 451 452 static char * 453 number(s, n) 454 char *s; 455 int *n; 456 { 457 for (*n = 0; isdigit(*s); s++) 458 *n = (*n * 10) + *s - '0'; 459 return s; 460 } 461 462 n_long 463 ip_convertaddr(p) 464 char *p; 465 { 466 #define IP_ANYADDR 0 467 n_long addr = 0, n; 468 469 if (p == (char *)0 || *p == '\0') 470 return IP_ANYADDR; 471 p = number(p, &n); 472 addr |= (n << 24) & 0xff000000; 473 if (*p == '\0' || *p++ != '.') 474 return IP_ANYADDR; 475 p = number(p, &n); 476 addr |= (n << 16) & 0xff0000; 477 if (*p == '\0' || *p++ != '.') 478 return IP_ANYADDR; 479 p = number(p, &n); 480 addr |= (n << 8) & 0xff00; 481 if (*p == '\0' || *p++ != '.') 482 return IP_ANYADDR; 483 p = number(p, &n); 484 addr |= n & 0xff; 485 if (*p != '\0') 486 return IP_ANYADDR; 487 488 return htonl(addr); 489 } 490