1*6212Swnj /* udp_usrreq.c 4.22 82/03/15 */ 24784Swnj 34784Swnj #include "../h/param.h" 44887Swnj #include "../h/dir.h" 54887Swnj #include "../h/user.h" 64784Swnj #include "../h/mbuf.h" 74805Swnj #include "../h/protosw.h" 84887Swnj #include "../h/socket.h" 94887Swnj #include "../h/socketvar.h" 105094Swnj #include "../net/in.h" 115094Swnj #include "../net/in_pcb.h" 125094Swnj #include "../net/in_systm.h" 134901Swnj #include "../net/ip.h" 144901Swnj #include "../net/ip_var.h" 154887Swnj #include "../net/udp.h" 164887Swnj #include "../net/udp_var.h" 174784Swnj 184926Swnj /* 194926Swnj * UDP protocol implementation. 204926Swnj * Per RFC 768, August, 1980. 214926Swnj */ 224805Swnj udp_init() 234805Swnj { 244805Swnj 255094Swnj COUNT(UDP_INIT); 264901Swnj udb.inp_next = udb.inp_prev = &udb; 274805Swnj } 284805Swnj 294901Swnj int udpcksum; 304926Swnj struct sockaddr_in udp_in = { AF_INET }; 314901Swnj 324926Swnj udp_input(m0) 334926Swnj struct mbuf *m0; 344784Swnj { 354901Swnj register struct udpiphdr *ui; 364887Swnj register struct inpcb *inp; 374926Swnj register struct mbuf *m; 384926Swnj int len, ulen; 394784Swnj 405094Swnj COUNT(UDP_INPUT); 414926Swnj /* 425246Sroot * Get IP and UDP header together in first mbuf. 434926Swnj */ 444926Swnj m = m0; 455308Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 465308Sroot (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 474926Swnj udpstat.udps_hdrops++; 485308Sroot return; 494926Swnj } 505050Swnj ui = mtod(m, struct udpiphdr *); 515246Sroot if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 525220Swnj ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 534926Swnj 544926Swnj /* 555246Sroot * Make mbuf data length reflect UDP length. 565246Sroot * If not enough data to reflect UDP length, drop. 574926Swnj */ 584955Swnj ulen = ntohs((u_short)ui->ui_ulen); 595220Swnj len = sizeof (struct udphdr) + ulen; 604926Swnj if (((struct ip *)ui)->ip_len != len) { 614926Swnj if (len > ((struct ip *)ui)->ip_len) { 624926Swnj udpstat.udps_badlen++; 634926Swnj goto bad; 644926Swnj } 654926Swnj m_adj(m, ((struct ip *)ui)->ip_len - len); 664926Swnj /* (struct ip *)ui->ip_len = len; */ 674926Swnj } 684926Swnj 694926Swnj /* 705246Sroot * Checksum extended UDP header and data. 714926Swnj */ 724901Swnj if (udpcksum) { 734926Swnj ui->ui_next = ui->ui_prev = 0; 744926Swnj ui->ui_x1 = 0; 755220Swnj ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen)); 765220Swnj if (ui->ui_sum = in_cksum(m, len)) { 774926Swnj udpstat.udps_badsum++; 784901Swnj printf("udp cksum %x\n", ui->ui_sum); 794901Swnj m_freem(m); 804901Swnj return; 814901Swnj } 824901Swnj } 834926Swnj 844926Swnj /* 855996Swnj * Locate pcb for datagram. On wildcard match, update 865996Swnj * control block to anchor network and host address. 874926Swnj */ 884926Swnj inp = in_pcblookup(&udb, 896029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 906029Sroot INPLOOKUP_WILDCARD); 915051Swnj if (inp == 0) 924926Swnj goto bad; 934926Swnj 944926Swnj /* 954926Swnj * Construct sockaddr format source address. 964926Swnj * Stuff source address and datagram in user buffer. 974926Swnj */ 984926Swnj udp_in.sin_port = ui->ui_sport; 994926Swnj udp_in.sin_addr = ui->ui_src; 1005050Swnj m->m_len -= sizeof (struct udpiphdr); 1015050Swnj m->m_off += sizeof (struct udpiphdr); 1025050Swnj if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 1034926Swnj goto bad; 1045050Swnj sorwakeup(inp->inp_socket); 1054887Swnj return; 1064926Swnj bad: 1074887Swnj m_freem(m); 1084784Swnj } 1094784Swnj 1104887Swnj udp_ctlinput(m) 1114887Swnj struct mbuf *m; 1124887Swnj { 1134887Swnj 1145094Swnj COUNT(UDP_CTLINPUT); 1154887Swnj m_freem(m); 1164887Swnj } 1174887Swnj 1184955Swnj udp_output(inp, m0) 1194926Swnj struct inpcb *inp; 1204926Swnj struct mbuf *m0; 1214784Swnj { 1224926Swnj register struct mbuf *m; 1234926Swnj register struct udpiphdr *ui; 1244926Swnj register int len = 0; 1254784Swnj 1265094Swnj COUNT(UDP_OUTPUT); 1274926Swnj /* 1284926Swnj * Calculate data length and get a mbuf 1295246Sroot * for UDP and IP headers. 1304926Swnj */ 1314926Swnj for (m = m0; m; m = m->m_next) 1324926Swnj len += m->m_len; 1335585Sroot m = m_get(M_DONTWAIT); 1345051Swnj if (m == 0) 1354926Swnj goto bad; 1364784Swnj 1374926Swnj /* 1385246Sroot * Fill in mbuf with extended UDP header 1394926Swnj * and addresses and length put into network format. 1404926Swnj */ 1414926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1424926Swnj m->m_len = sizeof (struct udpiphdr); 1434926Swnj m->m_next = m0; 1444926Swnj ui = mtod(m, struct udpiphdr *); 1454926Swnj ui->ui_next = ui->ui_prev = 0; 1464926Swnj ui->ui_x1 = 0; 1474926Swnj ui->ui_pr = IPPROTO_UDP; 1485050Swnj ui->ui_len = sizeof (struct udpiphdr) + len; 1495050Swnj ui->ui_src = inp->inp_laddr; 1505050Swnj ui->ui_dst = inp->inp_faddr; 1515050Swnj ui->ui_sport = inp->inp_lport; 1525050Swnj ui->ui_dport = inp->inp_fport; 1534955Swnj ui->ui_ulen = htons((u_short)len); 1544784Swnj 1554926Swnj /* 1564926Swnj * Stuff checksum and output datagram. 1574926Swnj */ 1584926Swnj ui->ui_sum = 0; 1595094Swnj ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 1605050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 1615050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 162*6212Swnj (void) ip_output(m, (struct mbuf *)0, 163*6212Swnj inp->inp_socket->so_state & SS_PRIV); 1644926Swnj return; 1654926Swnj bad: 1664926Swnj m_freem(m); 1674784Swnj } 1684784Swnj 1694887Swnj udp_usrreq(so, req, m, addr) 1704887Swnj struct socket *so; 1714784Swnj int req; 1724784Swnj struct mbuf *m; 1734912Swnj caddr_t addr; 1744784Swnj { 1754887Swnj struct inpcb *inp = sotoinpcb(so); 1764887Swnj int error; 1774784Swnj 1785094Swnj COUNT(UDP_USRREQ); 1795051Swnj if (inp == 0 && req != PRU_ATTACH) 1805050Swnj return (EINVAL); 1814784Swnj switch (req) { 1824784Swnj 1834784Swnj case PRU_ATTACH: 1844887Swnj if (inp != 0) 1854887Swnj return (EINVAL); 1865166Swnj error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); 1875051Swnj if (error) 1884955Swnj return (error); 1894887Swnj break; 1904784Swnj 1914784Swnj case PRU_DETACH: 1924887Swnj if (inp == 0) 1934887Swnj return (ENOTCONN); 1945166Swnj in_pcbdetach(inp); 1954887Swnj break; 1964784Swnj 1974784Swnj case PRU_CONNECT: 1984955Swnj if (inp->inp_faddr.s_addr) 1994887Swnj return (EISCONN); 2005166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 2015051Swnj if (error) 2024887Swnj return (error); 2034887Swnj soisconnected(so); 2044887Swnj break; 2054784Swnj 2064926Swnj case PRU_ACCEPT: 2074926Swnj return (EOPNOTSUPP); 2084926Swnj 2094784Swnj case PRU_DISCONNECT: 2104955Swnj if (inp->inp_faddr.s_addr == 0) 2114887Swnj return (ENOTCONN); 2125166Swnj in_pcbdisconnect(inp); 2134887Swnj soisdisconnected(so); 2144784Swnj break; 2154784Swnj 2164912Swnj case PRU_SHUTDOWN: 2174912Swnj socantsendmore(so); 2184912Swnj break; 2194912Swnj 2205996Swnj case PRU_SEND: { 2215996Swnj struct in_addr laddr; 2225996Swnj 2234887Swnj if (addr) { 2245996Swnj laddr = inp->inp_laddr; 2255224Swnj if (inp->inp_faddr.s_addr) 2264887Swnj return (EISCONN); 2275166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 2285224Swnj if (error) 2294955Swnj return (error); 2304955Swnj } else { 2314955Swnj if (inp->inp_faddr.s_addr == 0) 2324955Swnj return (ENOTCONN); 2334955Swnj } 2344955Swnj udp_output(inp, m); 2355996Swnj if (addr) { 2365166Swnj in_pcbdisconnect(inp); 2375996Swnj inp->inp_laddr = laddr; 2386029Sroot in_setsockaddr(inp); 2395996Swnj } 2405996Swnj } 2414784Swnj break; 2424784Swnj 2434784Swnj case PRU_ABORT: 2445166Swnj in_pcbdetach(inp); 2454887Swnj sofree(so); 2464887Swnj soisdisconnected(so); 2474784Swnj break; 2484784Swnj 2494784Swnj case PRU_CONTROL: 2504887Swnj return (EOPNOTSUPP); 2514784Swnj 2524784Swnj default: 2534784Swnj panic("udp_usrreq"); 2544805Swnj } 2554887Swnj return (0); 2564784Swnj } 257