14a5d661aSToomas Soome /* Taken from $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ 24a5d661aSToomas Soome 34a5d661aSToomas Soome /* 44a5d661aSToomas Soome * Copyright (c) 1992 Regents of the University of California. 54a5d661aSToomas Soome * All rights reserved. 64a5d661aSToomas Soome * 74a5d661aSToomas Soome * This software was developed by the Computer Systems Engineering group 84a5d661aSToomas Soome * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 94a5d661aSToomas Soome * contributed to Berkeley. 104a5d661aSToomas Soome * 114a5d661aSToomas Soome * Redistribution and use in source and binary forms, with or without 124a5d661aSToomas Soome * modification, are permitted provided that the following conditions 134a5d661aSToomas Soome * are met: 144a5d661aSToomas Soome * 1. Redistributions of source code must retain the above copyright 154a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer. 164a5d661aSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 174a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer in the 184a5d661aSToomas Soome * documentation and/or other materials provided with the distribution. 194a5d661aSToomas Soome * 4. Neither the name of the University nor the names of its contributors 204a5d661aSToomas Soome * may be used to endorse or promote products derived from this software 214a5d661aSToomas Soome * without specific prior written permission. 224a5d661aSToomas Soome * 234a5d661aSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 244a5d661aSToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 254a5d661aSToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 264a5d661aSToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 274a5d661aSToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 284a5d661aSToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 294a5d661aSToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 304a5d661aSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 314a5d661aSToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 324a5d661aSToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 334a5d661aSToomas Soome * SUCH DAMAGE. 344a5d661aSToomas Soome * 354a5d661aSToomas Soome * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) 364a5d661aSToomas Soome */ 374a5d661aSToomas Soome 384a5d661aSToomas Soome #include <sys/cdefs.h> 394a5d661aSToomas Soome 404a5d661aSToomas Soome #include <sys/param.h> 414a5d661aSToomas Soome #include <sys/socket.h> 424a5d661aSToomas Soome 434a5d661aSToomas Soome #include <string.h> 444a5d661aSToomas Soome 454a5d661aSToomas Soome #include <net/if.h> 464a5d661aSToomas Soome #include <netinet/in.h> 474a5d661aSToomas Soome #include <netinet/if_ether.h> 484a5d661aSToomas Soome #include <netinet/in_systm.h> 494a5d661aSToomas Soome 504a5d661aSToomas Soome #include <netinet/in_pcb.h> 514a5d661aSToomas Soome #include <netinet/ip.h> 524a5d661aSToomas Soome #include <netinet/ip_var.h> 534a5d661aSToomas Soome #include <netinet/udp.h> 544a5d661aSToomas Soome #include <netinet/udp_var.h> 554a5d661aSToomas Soome 564a5d661aSToomas Soome #include "stand.h" 574a5d661aSToomas Soome #include "net.h" 584a5d661aSToomas Soome 594a5d661aSToomas Soome /* Caller must leave room for ethernet, ip and udp headers in front!! */ 604a5d661aSToomas Soome ssize_t 61*7b2a1233SToomas Soome sendudp(struct iodesc *d, void *pkt, size_t len) 624a5d661aSToomas Soome { 634a5d661aSToomas Soome ssize_t cc; 644a5d661aSToomas Soome struct ip *ip; 654a5d661aSToomas Soome struct udphdr *uh; 664a5d661aSToomas Soome u_char *ea; 674a5d661aSToomas Soome 684a5d661aSToomas Soome #ifdef NET_DEBUG 694a5d661aSToomas Soome if (debug) { 704a5d661aSToomas Soome printf("sendudp: d=%lx called.\n", (long)d); 714a5d661aSToomas Soome if (d) { 724a5d661aSToomas Soome printf("saddr: %s:%d", 734a5d661aSToomas Soome inet_ntoa(d->myip), ntohs(d->myport)); 744a5d661aSToomas Soome printf(" daddr: %s:%d\n", 754a5d661aSToomas Soome inet_ntoa(d->destip), ntohs(d->destport)); 764a5d661aSToomas Soome } 774a5d661aSToomas Soome } 784a5d661aSToomas Soome #endif 794a5d661aSToomas Soome 804a5d661aSToomas Soome uh = (struct udphdr *)pkt - 1; 814a5d661aSToomas Soome ip = (struct ip *)uh - 1; 824a5d661aSToomas Soome len += sizeof(*ip) + sizeof(*uh); 834a5d661aSToomas Soome 844a5d661aSToomas Soome bzero(ip, sizeof(*ip) + sizeof(*uh)); 854a5d661aSToomas Soome 864a5d661aSToomas Soome ip->ip_v = IPVERSION; /* half-char */ 874a5d661aSToomas Soome ip->ip_hl = sizeof(*ip) >> 2; /* half-char */ 884a5d661aSToomas Soome ip->ip_len = htons(len); 894a5d661aSToomas Soome ip->ip_p = IPPROTO_UDP; /* char */ 904a5d661aSToomas Soome ip->ip_ttl = IPDEFTTL; /* char */ 914a5d661aSToomas Soome ip->ip_src = d->myip; 924a5d661aSToomas Soome ip->ip_dst = d->destip; 934a5d661aSToomas Soome ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */ 944a5d661aSToomas Soome 954a5d661aSToomas Soome uh->uh_sport = d->myport; 964a5d661aSToomas Soome uh->uh_dport = d->destport; 974a5d661aSToomas Soome uh->uh_ulen = htons(len - sizeof(*ip)); 984a5d661aSToomas Soome 994a5d661aSToomas Soome #ifndef UDP_NO_CKSUM 1004a5d661aSToomas Soome { 1014a5d661aSToomas Soome struct udpiphdr *ui; 1024a5d661aSToomas Soome struct ip tip; 1034a5d661aSToomas Soome 1044a5d661aSToomas Soome /* Calculate checksum (must save and restore ip header) */ 1054a5d661aSToomas Soome tip = *ip; 1064a5d661aSToomas Soome ui = (struct udpiphdr *)ip; 1074a5d661aSToomas Soome bzero(&ui->ui_x1, sizeof(ui->ui_x1)); 1084a5d661aSToomas Soome ui->ui_len = uh->uh_ulen; 1094a5d661aSToomas Soome uh->uh_sum = in_cksum(ui, len); 1104a5d661aSToomas Soome *ip = tip; 1114a5d661aSToomas Soome } 1124a5d661aSToomas Soome #endif 1134a5d661aSToomas Soome 1144a5d661aSToomas Soome if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 || 1154a5d661aSToomas Soome netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask)) 1164a5d661aSToomas Soome ea = arpwhohas(d, ip->ip_dst); 1174a5d661aSToomas Soome else 1184a5d661aSToomas Soome ea = arpwhohas(d, gateip); 1194a5d661aSToomas Soome 1204a5d661aSToomas Soome cc = sendether(d, ip, len, ea, ETHERTYPE_IP); 1214a5d661aSToomas Soome if (cc == -1) 1224a5d661aSToomas Soome return (-1); 1234a5d661aSToomas Soome if (cc != len) 1244a5d661aSToomas Soome panic("sendudp: bad write (%zd != %zd)", cc, len); 1254a5d661aSToomas Soome return (cc - (sizeof(*ip) + sizeof(*uh))); 1264a5d661aSToomas Soome } 1274a5d661aSToomas Soome 1284a5d661aSToomas Soome /* 1294a5d661aSToomas Soome * Receive a UDP packet and validate it is for us. 1304a5d661aSToomas Soome */ 1314a5d661aSToomas Soome ssize_t 132*7b2a1233SToomas Soome readudp(struct iodesc *d, void **pkt, void **payload, time_t tleft) 1334a5d661aSToomas Soome { 1344a5d661aSToomas Soome ssize_t n; 1354a5d661aSToomas Soome size_t hlen; 1364a5d661aSToomas Soome struct ip *ip; 1374a5d661aSToomas Soome struct udphdr *uh; 138*7b2a1233SToomas Soome uint16_t etype; /* host order */ 139*7b2a1233SToomas Soome void *ptr; 1404a5d661aSToomas Soome 1414a5d661aSToomas Soome #ifdef NET_DEBUG 1424a5d661aSToomas Soome if (debug) 1434a5d661aSToomas Soome printf("readudp: called\n"); 1444a5d661aSToomas Soome #endif 1454a5d661aSToomas Soome 146*7b2a1233SToomas Soome ip = NULL; 147*7b2a1233SToomas Soome ptr = NULL; 148*7b2a1233SToomas Soome n = readether(d, &ptr, (void **)&ip, tleft, &etype); 149*7b2a1233SToomas Soome if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) { 150*7b2a1233SToomas Soome free(ptr); 151*7b2a1233SToomas Soome return (-1); 152*7b2a1233SToomas Soome } 1534a5d661aSToomas Soome 1544a5d661aSToomas Soome /* Ethernet address checks now in readether() */ 1554a5d661aSToomas Soome 1564a5d661aSToomas Soome /* Need to respond to ARP requests. */ 1574a5d661aSToomas Soome if (etype == ETHERTYPE_ARP) { 1584a5d661aSToomas Soome struct arphdr *ah = (void *)ip; 1594a5d661aSToomas Soome if (ah->ar_op == htons(ARPOP_REQUEST)) { 1604a5d661aSToomas Soome /* Send ARP reply */ 1614a5d661aSToomas Soome arp_reply(d, ah); 1624a5d661aSToomas Soome } 163*7b2a1233SToomas Soome free(ptr); 164*7b2a1233SToomas Soome return (-1); 1654a5d661aSToomas Soome } 1664a5d661aSToomas Soome 1674a5d661aSToomas Soome if (etype != ETHERTYPE_IP) { 1684a5d661aSToomas Soome #ifdef NET_DEBUG 1694a5d661aSToomas Soome if (debug) 1704a5d661aSToomas Soome printf("readudp: not IP. ether_type=%x\n", etype); 1714a5d661aSToomas Soome #endif 172*7b2a1233SToomas Soome free(ptr); 173*7b2a1233SToomas Soome return (-1); 1744a5d661aSToomas Soome } 1754a5d661aSToomas Soome 1764a5d661aSToomas Soome /* Check ip header */ 1774a5d661aSToomas Soome if (ip->ip_v != IPVERSION || 1784a5d661aSToomas Soome ip->ip_p != IPPROTO_UDP) { /* half char */ 1794a5d661aSToomas Soome #ifdef NET_DEBUG 1804a5d661aSToomas Soome if (debug) 1814a5d661aSToomas Soome printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p); 1824a5d661aSToomas Soome #endif 183*7b2a1233SToomas Soome free(ptr); 184*7b2a1233SToomas Soome return (-1); 1854a5d661aSToomas Soome } 1864a5d661aSToomas Soome 1874a5d661aSToomas Soome hlen = ip->ip_hl << 2; 1884a5d661aSToomas Soome if (hlen < sizeof(*ip) || 1894a5d661aSToomas Soome in_cksum(ip, hlen) != 0) { 1904a5d661aSToomas Soome #ifdef NET_DEBUG 1914a5d661aSToomas Soome if (debug) 1924a5d661aSToomas Soome printf("readudp: short hdr or bad cksum.\n"); 1934a5d661aSToomas Soome #endif 194*7b2a1233SToomas Soome free(ptr); 195*7b2a1233SToomas Soome return (-1); 1964a5d661aSToomas Soome } 1974a5d661aSToomas Soome if (n < ntohs(ip->ip_len)) { 1984a5d661aSToomas Soome #ifdef NET_DEBUG 1994a5d661aSToomas Soome if (debug) 2004a5d661aSToomas Soome printf("readudp: bad length %d < %d.\n", 2014a5d661aSToomas Soome (int)n, ntohs(ip->ip_len)); 2024a5d661aSToomas Soome #endif 203*7b2a1233SToomas Soome free(ptr); 204*7b2a1233SToomas Soome return (-1); 2054a5d661aSToomas Soome } 2064a5d661aSToomas Soome if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) { 2074a5d661aSToomas Soome #ifdef NET_DEBUG 2084a5d661aSToomas Soome if (debug) { 2094a5d661aSToomas Soome printf("readudp: bad saddr %s != ", inet_ntoa(d->myip)); 2104a5d661aSToomas Soome printf("%s\n", inet_ntoa(ip->ip_dst)); 2114a5d661aSToomas Soome } 2124a5d661aSToomas Soome #endif 213*7b2a1233SToomas Soome free(ptr); 214*7b2a1233SToomas Soome return (-1); 2154a5d661aSToomas Soome } 2164a5d661aSToomas Soome 217*7b2a1233SToomas Soome uh = (struct udphdr *)((uintptr_t)ip + sizeof (*ip)); 2184a5d661aSToomas Soome /* If there were ip options, make them go away */ 2194a5d661aSToomas Soome if (hlen != sizeof(*ip)) { 220*7b2a1233SToomas Soome bcopy(((u_char *)ip) + hlen, uh, uh->uh_ulen - hlen); 2214a5d661aSToomas Soome ip->ip_len = htons(sizeof(*ip)); 2224a5d661aSToomas Soome n -= hlen - sizeof(*ip); 2234a5d661aSToomas Soome } 2244a5d661aSToomas Soome if (uh->uh_dport != d->myport) { 2254a5d661aSToomas Soome #ifdef NET_DEBUG 2264a5d661aSToomas Soome if (debug) 2274a5d661aSToomas Soome printf("readudp: bad dport %d != %d\n", 2284a5d661aSToomas Soome d->myport, ntohs(uh->uh_dport)); 2294a5d661aSToomas Soome #endif 230*7b2a1233SToomas Soome free(ptr); 231*7b2a1233SToomas Soome return (-1); 2324a5d661aSToomas Soome } 2334a5d661aSToomas Soome 2344a5d661aSToomas Soome #ifndef UDP_NO_CKSUM 2354a5d661aSToomas Soome if (uh->uh_sum) { 2364a5d661aSToomas Soome struct udpiphdr *ui; 2374a5d661aSToomas Soome struct ip tip; 2384a5d661aSToomas Soome 2394a5d661aSToomas Soome n = ntohs(uh->uh_ulen) + sizeof(*ip); 2404a5d661aSToomas Soome if (n > RECV_SIZE - ETHER_SIZE) { 2414a5d661aSToomas Soome printf("readudp: huge packet, udp len %d\n", (int)n); 242*7b2a1233SToomas Soome free(ptr); 243*7b2a1233SToomas Soome return (-1); 2444a5d661aSToomas Soome } 2454a5d661aSToomas Soome 2464a5d661aSToomas Soome /* Check checksum (must save and restore ip header) */ 2474a5d661aSToomas Soome tip = *ip; 2484a5d661aSToomas Soome ui = (struct udpiphdr *)ip; 2494a5d661aSToomas Soome bzero(&ui->ui_x1, sizeof(ui->ui_x1)); 2504a5d661aSToomas Soome ui->ui_len = uh->uh_ulen; 2514a5d661aSToomas Soome if (in_cksum(ui, n) != 0) { 2524a5d661aSToomas Soome #ifdef NET_DEBUG 2534a5d661aSToomas Soome if (debug) 2544a5d661aSToomas Soome printf("readudp: bad cksum\n"); 2554a5d661aSToomas Soome #endif 256*7b2a1233SToomas Soome free(ptr); 257*7b2a1233SToomas Soome return (-1); 2584a5d661aSToomas Soome } 2594a5d661aSToomas Soome *ip = tip; 2604a5d661aSToomas Soome } 2614a5d661aSToomas Soome #endif 2624a5d661aSToomas Soome if (ntohs(uh->uh_ulen) < sizeof(*uh)) { 2634a5d661aSToomas Soome #ifdef NET_DEBUG 2644a5d661aSToomas Soome if (debug) 2654a5d661aSToomas Soome printf("readudp: bad udp len %d < %d\n", 2664a5d661aSToomas Soome ntohs(uh->uh_ulen), (int)sizeof(*uh)); 2674a5d661aSToomas Soome #endif 268*7b2a1233SToomas Soome free(ptr); 269*7b2a1233SToomas Soome return (-1); 2704a5d661aSToomas Soome } 2714a5d661aSToomas Soome 2724a5d661aSToomas Soome n = (n > (ntohs(uh->uh_ulen) - sizeof(*uh))) ? 2734a5d661aSToomas Soome ntohs(uh->uh_ulen) - sizeof(*uh) : n; 274*7b2a1233SToomas Soome *pkt = ptr; 275*7b2a1233SToomas Soome *payload = (void *)((uintptr_t)uh + sizeof(*uh)); 2764a5d661aSToomas Soome return (n); 2774a5d661aSToomas Soome } 278