1 /* 2 * Copyright (c) 1992 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Lawrence Berkeley Laboratory and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * from @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) 38 */ 39 40 #include <sys/param.h> 41 #include <sys/socket.h> 42 43 #include <string.h> 44 45 #include <net/if.h> 46 47 #include <netinet/in.h> 48 #include <netinet/if_ether.h> 49 #include <netinet/in_systm.h> 50 #include <netinet/ip.h> 51 #include <netinet/ip_var.h> 52 #include <netinet/udp.h> 53 #include <netinet/udp_var.h> 54 55 #include "stand.h" 56 #include "net.h" 57 #include "netif.h" 58 59 n_long myip; 60 61 /* Caller must leave room for ethernet, ip and udp headers in front!! */ 62 int 63 sendudp(d, buf, len) 64 register struct iodesc *d; 65 register void *buf; 66 register int len; 67 { 68 register int cc; 69 register struct ip *ip; 70 register struct udpiphdr *ui; 71 register struct udphdr *uh; 72 register u_char *ea; 73 struct ip tip; 74 75 #ifdef NET_DEBUG 76 if (debug) { 77 printf("sendudp: d=%x called.\n", (u_int)d); 78 if (d) { 79 printf("saddr: %s:%d", 80 intoa(d->myip), d->myport); 81 printf(" daddr: %s:%d\n", 82 intoa(d->destip), d->destport); 83 } 84 } 85 #endif 86 uh = ((struct udphdr *)buf) - 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.s_addr = htonl(d->myip); 98 ip->ip_dst.s_addr = htonl(d->destip); 99 ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */ 100 101 uh->uh_sport = htons(d->myport); 102 uh->uh_dport = htons(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 ui->ui_next = 0; 109 ui->ui_prev = 0; 110 ui->ui_x1 = 0; 111 ui->ui_len = uh->uh_ulen; 112 uh->uh_sum = in_cksum(ui, len); 113 *ip = tip; 114 115 if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 || 116 mask == 0 || SAMENET(ip->ip_src.s_addr, ip->ip_dst.s_addr, mask)) 117 ea = arpwhohas(d, ip->ip_dst.s_addr); 118 else 119 ea = arpwhohas(d, htonl(gateip)); 120 121 cc = sendether(d, ip, len, ea, ETHERTYPE_IP); 122 if (cc < 0) 123 return (cc); 124 if (cc != len) 125 panic("sendudp: bad write (%d != %d)", cc, len); 126 return (cc - (sizeof(*ip) + sizeof(*uh))); 127 } 128 129 /* Check that packet is a valid udp packet for us */ 130 void * 131 checkudp(d, pkt, lenp) 132 register struct iodesc *d; 133 register void *pkt; 134 register int *lenp; 135 { 136 register int hlen, len; 137 register struct ether_header *eh; 138 register struct ip *ip; 139 register struct udphdr *uh; 140 register struct udpiphdr *ui; 141 struct ip tip; 142 143 #ifdef NET_DEBUG 144 if (debug) 145 printf("checkudp: called\n"); 146 #endif 147 eh = pkt; 148 ip = (struct ip *)(eh + 1); 149 uh = (struct udphdr *)(ip + 1); 150 151 /* Must be to us */ 152 if (bcmp(d->myea, eh->ether_dhost, 6) != 0 && /* by byte */ 153 bcmp(bcea, eh->ether_dhost, 6) != 0) { /* by byte */ 154 #ifdef NET_DEBUG 155 if (debug) 156 printf("checkudp: not ours. myea=%s bcea=%s\n", 157 ether_sprintf(d->myea), ether_sprintf(bcea)); 158 #endif 159 return (NULL); 160 } 161 162 /* And ip */ 163 if (ntohs(eh->ether_type) != ETHERTYPE_IP) { 164 #ifdef NET_DEBUG 165 if (debug) 166 printf("checkudp: not IP. ether_type=%x\n", eh->ether_type); 167 #endif 168 return (NULL); 169 } 170 171 /* Check ip header */ 172 if (ip->ip_v != IPVERSION || ip->ip_p != IPPROTO_UDP) { /* half char */ 173 #ifdef NET_DEBUG 174 if (debug) 175 printf("checkudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p); 176 #endif 177 return (NULL); 178 } 179 180 hlen = ip->ip_hl << 2; 181 if (hlen < sizeof(*ip) || in_cksum(ip, hlen) != 0) { 182 #ifdef NET_DEBUG 183 if (debug) 184 printf("checkudp: short hdr or bad cksum.\n"); 185 #endif 186 return (NULL); 187 } 188 NTOHS(ip->ip_len); 189 if (*lenp - sizeof(*eh) < ip->ip_len) { 190 #ifdef NET_DEBUG 191 if (debug) 192 printf("checkudp: bad length %d < %d.\n", 193 *lenp - sizeof(*eh), ip->ip_len); 194 #endif 195 return (NULL); 196 } 197 if (d->myip && ntohl(ip->ip_dst.s_addr) != d->myip) { 198 #ifdef NET_DEBUG 199 if (debug) { 200 printf("checkudp: bad saddr %s != ", 201 intoa(d->myip)); 202 printf("%s\n", 203 intoa(ntohl(ip->ip_dst.s_addr))); 204 } 205 #endif 206 return (NULL); 207 } 208 209 /* If there were ip options, make them go away */ 210 if (hlen != sizeof(*ip)) { 211 bcopy(((u_char *)ip) + hlen, uh, 212 *lenp - (sizeof(*eh) + hlen)); 213 ip->ip_len = sizeof(*ip); 214 *lenp -= hlen - sizeof(*ip); 215 } 216 if (ntohs(uh->uh_dport) != d->myport) { 217 #ifdef NET_DEBUG 218 if (debug) 219 printf("checkudp: bad dport %d != %d\n", 220 d->myport, ntohs(uh->uh_dport)); 221 #endif 222 return (NULL); 223 } 224 225 if (uh->uh_sum) { 226 len = ntohs(uh->uh_ulen); 227 if (len > RECV_SIZE - (sizeof(*eh) + sizeof(*ip))) { 228 printf("checkudp: huge packet, udp len %d\n", len); 229 return (NULL); 230 } 231 232 /* Check checksum (must save and restore ip header) */ 233 tip = *ip; 234 ui = (struct udpiphdr *)ip; 235 ui->ui_next = 0; 236 ui->ui_prev = 0; 237 ui->ui_x1 = 0; 238 ui->ui_len = uh->uh_ulen; 239 if (in_cksum(ui, len + sizeof(*ip)) != 0) { 240 #ifdef NET_DEBUG 241 if (debug) 242 printf("checkudp: bad cksum\n"); 243 #endif 244 *ip = tip; 245 return (NULL); 246 } 247 *ip = tip; 248 } 249 NTOHS(uh->uh_dport); 250 NTOHS(uh->uh_sport); 251 NTOHS(uh->uh_ulen); 252 if (uh->uh_ulen < sizeof(*uh)) { 253 #ifdef NET_DEBUG 254 if (debug) 255 printf("checkudp: bad udp len %d < %d\n", 256 uh->uh_ulen, sizeof(*uh)); 257 #endif 258 return (NULL); 259 } 260 *lenp -= sizeof(*eh) + sizeof(*ip) + sizeof(*uh); 261 return (uh + 1); 262 } 263 264 /* 265 * Send a packet and wait for a reply, with exponential backoff. 266 * 267 * The send routine must return the actual number of bytes written. 268 * 269 * The receive routine can indicate success by returning the number of 270 * bytes read; it can return 0 to indicate EOF; it can return -1 with a 271 * non-zero errno to indicate failure; finally, it can return -1 with a 272 * zero errno to indicate it isn't done yet. 273 */ 274 int 275 sendrecv(d, sproc, sbuf, ssize, rproc, rbuf, rsize) 276 register struct iodesc *d; 277 register int (*sproc)(struct iodesc *, void *, int); 278 register void *sbuf; 279 register int ssize; 280 register int (*rproc)(struct iodesc *, void *, int); 281 register void *rbuf; 282 register int rsize; 283 { 284 register int cc; 285 register time_t t, tmo, tlast, tleft; 286 287 #ifdef NET_DEBUG 288 if (debug) 289 printf("sendrecv: called\n"); 290 #endif 291 tmo = MINTMO; 292 tlast = tleft = 0; 293 t = getsecs(); 294 for (;;) { 295 if (tleft <= 0) { 296 cc = (*sproc)(d, sbuf, ssize); 297 if (cc < ssize) 298 panic("sendrecv: short write! (%d < %d)", 299 cc, ssize); 300 301 tleft = tmo; 302 tmo <<= 1; 303 if (tmo > MAXTMO) 304 tmo = MAXTMO; 305 tlast = t; 306 } 307 308 cc = netif_get(d, rbuf, rsize, tleft); 309 if (cc >= 0) { 310 /* Got a packet, process it */ 311 cc = (*rproc)(d, rbuf, cc); 312 /* Return on data, EOF or real error */ 313 if (cc >= 0 || errno != 0) 314 return (cc); 315 } 316 /* Timed out or didn't get the packet we're waiting for */ 317 t = getsecs(); 318 tleft -= t - tlast; 319 tlast = t; 320 } 321 } 322 323 /* Similar to inet_ntoa() */ 324 char * 325 intoa(addr) 326 n_long addr; 327 { 328 register char *cp; 329 register u_int byte; 330 register int n; 331 static char buf[17]; /* strlen(".255.255.255.255") + 1 */ 332 333 cp = &buf[sizeof buf]; 334 *--cp = '\0'; 335 336 n = 4; 337 do { 338 byte = addr & 0xff; 339 *--cp = byte % 10 + '0'; 340 byte /= 10; 341 if (byte > 0) { 342 *--cp = byte % 10 + '0'; 343 byte /= 10; 344 if (byte > 0) 345 *--cp = byte + '0'; 346 } 347 *--cp = '.'; 348 addr >>= 8; 349 } while (--n > 0); 350 351 return (cp+1); 352 } 353 354 static char * 355 number(s, n) 356 char *s; 357 int *n; 358 { 359 for (*n = 0; isdigit(*s); s++) 360 *n = (*n * 10) + *s - '0'; 361 return s; 362 } 363 364 n_long 365 ip_convertaddr(p) 366 char *p; 367 { 368 #define IP_ANYADDR 0 369 n_long addr = 0, n; 370 371 if (p == (char *)0 || *p == '\0') 372 return IP_ANYADDR; 373 p = number(p, &n); 374 addr |= (n << 24) & 0xff000000; 375 if (*p == '\0' || *p++ != '.') 376 return IP_ANYADDR; 377 p = number(p, &n); 378 addr |= (n << 16) & 0xff0000; 379 if (*p == '\0' || *p++ != '.') 380 return IP_ANYADDR; 381 p = number(p, &n); 382 addr |= (n << 8) & 0xff00; 383 if (*p == '\0' || *p++ != '.') 384 return IP_ANYADDR; 385 p = number(p, &n); 386 addr |= n & 0xff; 387 if (*p != '\0') 388 return IP_ANYADDR; 389 390 return ntohl(addr); 391 } 392