1*5224Swnj /* udp_usrreq.c 4.16 81/12/09 */ 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 /* 424926Swnj * Get ip and udp header together in first mbuf. 434926Swnj */ 444926Swnj m = m0; 454926Swnj if (m->m_len < sizeof (struct udpiphdr) && 464926Swnj m_pullup(m, sizeof (struct udpiphdr)) == 0) { 474926Swnj udpstat.udps_hdrops++; 484926Swnj goto bad; 494926Swnj } 505050Swnj ui = mtod(m, struct udpiphdr *); 515050Swnj if (ui->ui_len > sizeof (struct ip)) 525220Swnj ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 534926Swnj 544926Swnj /* 554926Swnj * Make mbuf data length reflect udp length. 564926Swnj * 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 /* 704926Swnj * 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 /* 854926Swnj * Locate pcb for datagram. 864926Swnj */ 874926Swnj inp = in_pcblookup(&udb, 884926Swnj ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport); 895051Swnj if (inp == 0) 904926Swnj goto bad; 914926Swnj 924926Swnj /* 934926Swnj * Construct sockaddr format source address. 944926Swnj * Stuff source address and datagram in user buffer. 954926Swnj */ 964926Swnj udp_in.sin_port = ui->ui_sport; 974926Swnj udp_in.sin_addr = ui->ui_src; 985050Swnj m->m_len -= sizeof (struct udpiphdr); 995050Swnj m->m_off += sizeof (struct udpiphdr); 1005050Swnj if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 1014926Swnj goto bad; 1025050Swnj sorwakeup(inp->inp_socket); 1034887Swnj return; 1044926Swnj bad: 1054887Swnj m_freem(m); 1064784Swnj } 1074784Swnj 1084887Swnj udp_ctlinput(m) 1094887Swnj struct mbuf *m; 1104887Swnj { 1114887Swnj 1125094Swnj COUNT(UDP_CTLINPUT); 1134887Swnj m_freem(m); 1144887Swnj } 1154887Swnj 1164926Swnj /*ARGSUSED*/ 1174955Swnj udp_output(inp, m0) 1184926Swnj struct inpcb *inp; 1194926Swnj struct mbuf *m0; 1204784Swnj { 1214926Swnj register struct mbuf *m; 1224926Swnj register struct udpiphdr *ui; 1234926Swnj register int len = 0; 1244784Swnj 1255094Swnj COUNT(UDP_OUTPUT); 1264926Swnj /* 1274926Swnj * Calculate data length and get a mbuf 1284926Swnj * for udp and ip headers. 1294926Swnj */ 1304926Swnj for (m = m0; m; m = m->m_next) 1314926Swnj len += m->m_len; 1324926Swnj m = m_get(0); 1335051Swnj if (m == 0) 1344926Swnj goto bad; 1354784Swnj 1364926Swnj /* 1374926Swnj * Fill in mbuf with extended udp header 1384926Swnj * and addresses and length put into network format. 1394926Swnj */ 1404926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1414926Swnj m->m_len = sizeof (struct udpiphdr); 1424926Swnj m->m_next = m0; 1434926Swnj ui = mtod(m, struct udpiphdr *); 1444926Swnj ui->ui_next = ui->ui_prev = 0; 1454926Swnj ui->ui_x1 = 0; 1464926Swnj ui->ui_pr = IPPROTO_UDP; 1475050Swnj ui->ui_len = sizeof (struct udpiphdr) + len; 1485050Swnj ui->ui_src = inp->inp_laddr; 1495050Swnj ui->ui_dst = inp->inp_faddr; 1505050Swnj ui->ui_sport = inp->inp_lport; 1515050Swnj ui->ui_dport = inp->inp_fport; 1524955Swnj ui->ui_ulen = htons((u_short)len); 1534784Swnj 1544926Swnj /* 1554926Swnj * Stuff checksum and output datagram. 1564926Swnj */ 1574926Swnj ui->ui_sum = 0; 1585094Swnj ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 1595050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 1605050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 1615115Swnj (void) ip_output(m, (struct mbuf *)0); 1624926Swnj return; 1634926Swnj bad: 1644926Swnj m_freem(m); 1654784Swnj } 1664784Swnj 1674912Swnj /*ARGSUSED*/ 1684887Swnj udp_usrreq(so, req, m, addr) 1694887Swnj struct socket *so; 1704784Swnj int req; 1714784Swnj struct mbuf *m; 1724912Swnj caddr_t addr; 1734784Swnj { 1744887Swnj struct inpcb *inp = sotoinpcb(so); 1754887Swnj int error; 1764784Swnj 1775094Swnj COUNT(UDP_USRREQ); 1785051Swnj if (inp == 0 && req != PRU_ATTACH) 1795050Swnj return (EINVAL); 1804784Swnj switch (req) { 1814784Swnj 1824784Swnj case PRU_ATTACH: 1834887Swnj if (inp != 0) 1844887Swnj return (EINVAL); 1855166Swnj error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); 1865051Swnj if (error) 1874955Swnj return (error); 1884887Swnj break; 1894784Swnj 1904784Swnj case PRU_DETACH: 1914887Swnj if (inp == 0) 1924887Swnj return (ENOTCONN); 1935166Swnj in_pcbdetach(inp); 1944887Swnj break; 1954784Swnj 1964784Swnj case PRU_CONNECT: 1974955Swnj if (inp->inp_faddr.s_addr) 1984887Swnj return (EISCONN); 1995166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 2005051Swnj if (error) 2014887Swnj return (error); 2024887Swnj soisconnected(so); 2034887Swnj break; 2044784Swnj 2054926Swnj case PRU_ACCEPT: 2064926Swnj return (EOPNOTSUPP); 2074926Swnj 2084784Swnj case PRU_DISCONNECT: 2094955Swnj if (inp->inp_faddr.s_addr == 0) 2104887Swnj return (ENOTCONN); 2115166Swnj in_pcbdisconnect(inp); 2124887Swnj soisdisconnected(so); 2134784Swnj break; 2144784Swnj 2154912Swnj case PRU_SHUTDOWN: 2164912Swnj socantsendmore(so); 2174912Swnj break; 2184912Swnj 2194784Swnj case PRU_SEND: 2204887Swnj if (addr) { 221*5224Swnj if (inp->inp_faddr.s_addr) 2224887Swnj return (EISCONN); 2235166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 224*5224Swnj if (error) 2254955Swnj return (error); 2264955Swnj } else { 2274955Swnj if (inp->inp_faddr.s_addr == 0) 2284955Swnj return (ENOTCONN); 2294955Swnj } 2304955Swnj udp_output(inp, m); 2314955Swnj if (addr) 2325166Swnj in_pcbdisconnect(inp); 2334784Swnj break; 2344784Swnj 2354784Swnj case PRU_ABORT: 2365166Swnj in_pcbdetach(inp); 2374887Swnj sofree(so); 2384887Swnj soisdisconnected(so); 2394784Swnj break; 2404784Swnj 2414784Swnj case PRU_CONTROL: 2424887Swnj return (EOPNOTSUPP); 2434784Swnj 2444784Swnj default: 2454784Swnj panic("udp_usrreq"); 2464805Swnj } 2474887Swnj return (0); 2484784Swnj } 249