1*6354Ssam /* udp_usrreq.c 4.24 82/03/29 */ 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" 11*6354Ssam #include "../net/route.h" 125094Swnj #include "../net/in_pcb.h" 135094Swnj #include "../net/in_systm.h" 144901Swnj #include "../net/ip.h" 154901Swnj #include "../net/ip_var.h" 164887Swnj #include "../net/udp.h" 174887Swnj #include "../net/udp_var.h" 184784Swnj 194926Swnj /* 204926Swnj * UDP protocol implementation. 214926Swnj * Per RFC 768, August, 1980. 224926Swnj */ 234805Swnj udp_init() 244805Swnj { 254805Swnj 265094Swnj COUNT(UDP_INIT); 274901Swnj udb.inp_next = udb.inp_prev = &udb; 284805Swnj } 294805Swnj 304901Swnj int udpcksum; 314926Swnj struct sockaddr_in udp_in = { AF_INET }; 324901Swnj 334926Swnj udp_input(m0) 344926Swnj struct mbuf *m0; 354784Swnj { 364901Swnj register struct udpiphdr *ui; 374887Swnj register struct inpcb *inp; 384926Swnj register struct mbuf *m; 394926Swnj int len, ulen; 404784Swnj 415094Swnj COUNT(UDP_INPUT); 424926Swnj /* 435246Sroot * Get IP and UDP header together in first mbuf. 444926Swnj */ 454926Swnj m = m0; 465308Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 475308Sroot (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 484926Swnj udpstat.udps_hdrops++; 495308Sroot return; 504926Swnj } 515050Swnj ui = mtod(m, struct udpiphdr *); 525246Sroot if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 535220Swnj ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 544926Swnj 554926Swnj /* 565246Sroot * Make mbuf data length reflect UDP length. 575246Sroot * If not enough data to reflect UDP length, drop. 584926Swnj */ 594955Swnj ulen = ntohs((u_short)ui->ui_ulen); 605220Swnj len = sizeof (struct udphdr) + ulen; 614926Swnj if (((struct ip *)ui)->ip_len != len) { 624926Swnj if (len > ((struct ip *)ui)->ip_len) { 634926Swnj udpstat.udps_badlen++; 644926Swnj goto bad; 654926Swnj } 664926Swnj m_adj(m, ((struct ip *)ui)->ip_len - len); 674926Swnj /* (struct ip *)ui->ip_len = len; */ 684926Swnj } 694926Swnj 704926Swnj /* 715246Sroot * Checksum extended UDP header and data. 724926Swnj */ 734901Swnj if (udpcksum) { 744926Swnj ui->ui_next = ui->ui_prev = 0; 754926Swnj ui->ui_x1 = 0; 765220Swnj ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen)); 775220Swnj if (ui->ui_sum = in_cksum(m, len)) { 784926Swnj udpstat.udps_badsum++; 794901Swnj printf("udp cksum %x\n", ui->ui_sum); 804901Swnj m_freem(m); 814901Swnj return; 824901Swnj } 834901Swnj } 844926Swnj 854926Swnj /* 865996Swnj * Locate pcb for datagram. On wildcard match, update 875996Swnj * control block to anchor network and host address. 884926Swnj */ 894926Swnj inp = in_pcblookup(&udb, 906029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 916029Sroot INPLOOKUP_WILDCARD); 925051Swnj if (inp == 0) 934926Swnj goto bad; 944926Swnj 954926Swnj /* 964926Swnj * Construct sockaddr format source address. 974926Swnj * Stuff source address and datagram in user buffer. 984926Swnj */ 994926Swnj udp_in.sin_port = ui->ui_sport; 1004926Swnj udp_in.sin_addr = ui->ui_src; 1015050Swnj m->m_len -= sizeof (struct udpiphdr); 1025050Swnj m->m_off += sizeof (struct udpiphdr); 1035050Swnj if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 1044926Swnj goto bad; 1055050Swnj sorwakeup(inp->inp_socket); 1064887Swnj return; 1074926Swnj bad: 1084887Swnj m_freem(m); 1094784Swnj } 1104784Swnj 1114887Swnj udp_ctlinput(m) 1124887Swnj struct mbuf *m; 1134887Swnj { 1144887Swnj 1155094Swnj COUNT(UDP_CTLINPUT); 1164887Swnj m_freem(m); 1174887Swnj } 1184887Swnj 1194955Swnj udp_output(inp, m0) 1204926Swnj struct inpcb *inp; 1214926Swnj struct mbuf *m0; 1224784Swnj { 1234926Swnj register struct mbuf *m; 1244926Swnj register struct udpiphdr *ui; 1254926Swnj register int len = 0; 1264784Swnj 1275094Swnj COUNT(UDP_OUTPUT); 1284926Swnj /* 1294926Swnj * Calculate data length and get a mbuf 1305246Sroot * for UDP and IP headers. 1314926Swnj */ 1324926Swnj for (m = m0; m; m = m->m_next) 1334926Swnj len += m->m_len; 1345585Sroot m = m_get(M_DONTWAIT); 1355051Swnj if (m == 0) 1364926Swnj goto bad; 1374784Swnj 1384926Swnj /* 1395246Sroot * Fill in mbuf with extended UDP header 1404926Swnj * and addresses and length put into network format. 1414926Swnj */ 1424926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1434926Swnj m->m_len = sizeof (struct udpiphdr); 1444926Swnj m->m_next = m0; 1454926Swnj ui = mtod(m, struct udpiphdr *); 1464926Swnj ui->ui_next = ui->ui_prev = 0; 1474926Swnj ui->ui_x1 = 0; 1484926Swnj ui->ui_pr = IPPROTO_UDP; 1495050Swnj ui->ui_len = sizeof (struct udpiphdr) + len; 1505050Swnj ui->ui_src = inp->inp_laddr; 1515050Swnj ui->ui_dst = inp->inp_faddr; 1525050Swnj ui->ui_sport = inp->inp_lport; 1535050Swnj ui->ui_dport = inp->inp_fport; 1544955Swnj ui->ui_ulen = htons((u_short)len); 1554784Swnj 1564926Swnj /* 1574926Swnj * Stuff checksum and output datagram. 1584926Swnj */ 1594926Swnj ui->ui_sum = 0; 1605094Swnj ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 1615050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 1625050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 1636340Ssam (void) ip_output(m, (struct mbuf *)0, 0, 1646212Swnj inp->inp_socket->so_state & SS_PRIV); 1654926Swnj return; 1664926Swnj bad: 1674926Swnj m_freem(m); 1684784Swnj } 1694784Swnj 1704887Swnj udp_usrreq(so, req, m, addr) 1714887Swnj struct socket *so; 1724784Swnj int req; 1734784Swnj struct mbuf *m; 1744912Swnj caddr_t addr; 1754784Swnj { 1764887Swnj struct inpcb *inp = sotoinpcb(so); 1774887Swnj int error; 1784784Swnj 1795094Swnj COUNT(UDP_USRREQ); 1805051Swnj if (inp == 0 && req != PRU_ATTACH) 1815050Swnj return (EINVAL); 1824784Swnj switch (req) { 1834784Swnj 1844784Swnj case PRU_ATTACH: 1854887Swnj if (inp != 0) 1864887Swnj return (EINVAL); 1875166Swnj error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); 1885051Swnj if (error) 1894955Swnj return (error); 1904887Swnj break; 1914784Swnj 1924784Swnj case PRU_DETACH: 1934887Swnj if (inp == 0) 1944887Swnj return (ENOTCONN); 1955166Swnj in_pcbdetach(inp); 1964887Swnj break; 1974784Swnj 1984784Swnj case PRU_CONNECT: 1994955Swnj if (inp->inp_faddr.s_addr) 2004887Swnj return (EISCONN); 2015166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 2025051Swnj if (error) 2034887Swnj return (error); 2044887Swnj soisconnected(so); 2054887Swnj break; 2064784Swnj 2074926Swnj case PRU_ACCEPT: 2084926Swnj return (EOPNOTSUPP); 2094926Swnj 2104784Swnj case PRU_DISCONNECT: 2114955Swnj if (inp->inp_faddr.s_addr == 0) 2124887Swnj return (ENOTCONN); 2135166Swnj in_pcbdisconnect(inp); 2144887Swnj soisdisconnected(so); 2154784Swnj break; 2164784Swnj 2174912Swnj case PRU_SHUTDOWN: 2184912Swnj socantsendmore(so); 2194912Swnj break; 2204912Swnj 2215996Swnj case PRU_SEND: { 2225996Swnj struct in_addr laddr; 2235996Swnj 2244887Swnj if (addr) { 2255996Swnj laddr = inp->inp_laddr; 2265224Swnj if (inp->inp_faddr.s_addr) 2274887Swnj return (EISCONN); 2285166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 2295224Swnj if (error) 2304955Swnj return (error); 2314955Swnj } else { 2324955Swnj if (inp->inp_faddr.s_addr == 0) 2334955Swnj return (ENOTCONN); 2344955Swnj } 2354955Swnj udp_output(inp, m); 2365996Swnj if (addr) { 2375166Swnj in_pcbdisconnect(inp); 2385996Swnj inp->inp_laddr = laddr; 2396029Sroot in_setsockaddr(inp); 2405996Swnj } 2415996Swnj } 2424784Swnj break; 2434784Swnj 2444784Swnj case PRU_ABORT: 2455166Swnj in_pcbdetach(inp); 2464887Swnj sofree(so); 2474887Swnj soisdisconnected(so); 2484784Swnj break; 2494784Swnj 2504784Swnj case PRU_CONTROL: 2514887Swnj return (EOPNOTSUPP); 2524784Swnj 2534784Swnj default: 2544784Swnj panic("udp_usrreq"); 2554805Swnj } 2564887Swnj return (0); 2574784Swnj } 258