1*5308Sroot /* udp_usrreq.c 4.18 81/12/23 */ 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; 45*5308Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 46*5308Sroot (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 474926Swnj udpstat.udps_hdrops++; 48*5308Sroot 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 /* 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 1164955Swnj udp_output(inp, m0) 1174926Swnj struct inpcb *inp; 1184926Swnj struct mbuf *m0; 1194784Swnj { 1204926Swnj register struct mbuf *m; 1214926Swnj register struct udpiphdr *ui; 1224926Swnj register int len = 0; 1234784Swnj 1245094Swnj COUNT(UDP_OUTPUT); 1254926Swnj /* 1264926Swnj * Calculate data length and get a mbuf 1275246Sroot * for UDP and IP headers. 1284926Swnj */ 1294926Swnj for (m = m0; m; m = m->m_next) 1304926Swnj len += m->m_len; 1314926Swnj m = m_get(0); 1325051Swnj if (m == 0) 1334926Swnj goto bad; 1344784Swnj 1354926Swnj /* 1365246Sroot * Fill in mbuf with extended UDP header 1374926Swnj * and addresses and length put into network format. 1384926Swnj */ 1394926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1404926Swnj m->m_len = sizeof (struct udpiphdr); 1414926Swnj m->m_next = m0; 1424926Swnj ui = mtod(m, struct udpiphdr *); 1434926Swnj ui->ui_next = ui->ui_prev = 0; 1444926Swnj ui->ui_x1 = 0; 1454926Swnj ui->ui_pr = IPPROTO_UDP; 1465050Swnj ui->ui_len = sizeof (struct udpiphdr) + len; 1475050Swnj ui->ui_src = inp->inp_laddr; 1485050Swnj ui->ui_dst = inp->inp_faddr; 1495050Swnj ui->ui_sport = inp->inp_lport; 1505050Swnj ui->ui_dport = inp->inp_fport; 1514955Swnj ui->ui_ulen = htons((u_short)len); 1524784Swnj 1534926Swnj /* 1544926Swnj * Stuff checksum and output datagram. 1554926Swnj */ 1564926Swnj ui->ui_sum = 0; 1575094Swnj ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 1585050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 1595050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 1605115Swnj (void) ip_output(m, (struct mbuf *)0); 1614926Swnj return; 1624926Swnj bad: 1634926Swnj m_freem(m); 1644784Swnj } 1654784Swnj 1664887Swnj udp_usrreq(so, req, m, addr) 1674887Swnj struct socket *so; 1684784Swnj int req; 1694784Swnj struct mbuf *m; 1704912Swnj caddr_t addr; 1714784Swnj { 1724887Swnj struct inpcb *inp = sotoinpcb(so); 1734887Swnj int error; 1744784Swnj 1755094Swnj COUNT(UDP_USRREQ); 1765051Swnj if (inp == 0 && req != PRU_ATTACH) 1775050Swnj return (EINVAL); 1784784Swnj switch (req) { 1794784Swnj 1804784Swnj case PRU_ATTACH: 1814887Swnj if (inp != 0) 1824887Swnj return (EINVAL); 1835166Swnj error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); 1845051Swnj if (error) 1854955Swnj return (error); 1864887Swnj break; 1874784Swnj 1884784Swnj case PRU_DETACH: 1894887Swnj if (inp == 0) 1904887Swnj return (ENOTCONN); 1915166Swnj in_pcbdetach(inp); 1924887Swnj break; 1934784Swnj 1944784Swnj case PRU_CONNECT: 1954955Swnj if (inp->inp_faddr.s_addr) 1964887Swnj return (EISCONN); 1975166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 1985051Swnj if (error) 1994887Swnj return (error); 2004887Swnj soisconnected(so); 2014887Swnj break; 2024784Swnj 2034926Swnj case PRU_ACCEPT: 2044926Swnj return (EOPNOTSUPP); 2054926Swnj 2064784Swnj case PRU_DISCONNECT: 2074955Swnj if (inp->inp_faddr.s_addr == 0) 2084887Swnj return (ENOTCONN); 2095166Swnj in_pcbdisconnect(inp); 2104887Swnj soisdisconnected(so); 2114784Swnj break; 2124784Swnj 2134912Swnj case PRU_SHUTDOWN: 2144912Swnj socantsendmore(so); 2154912Swnj break; 2164912Swnj 2174784Swnj case PRU_SEND: 2184887Swnj if (addr) { 2195224Swnj if (inp->inp_faddr.s_addr) 2204887Swnj return (EISCONN); 2215166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 2225224Swnj if (error) 2234955Swnj return (error); 2244955Swnj } else { 2254955Swnj if (inp->inp_faddr.s_addr == 0) 2264955Swnj return (ENOTCONN); 2274955Swnj } 2284955Swnj udp_output(inp, m); 2294955Swnj if (addr) 2305166Swnj in_pcbdisconnect(inp); 2314784Swnj break; 2324784Swnj 2334784Swnj case PRU_ABORT: 2345166Swnj in_pcbdetach(inp); 2354887Swnj sofree(so); 2364887Swnj soisdisconnected(so); 2374784Swnj break; 2384784Swnj 2394784Swnj case PRU_CONTROL: 2404887Swnj return (EOPNOTSUPP); 2414784Swnj 2424784Swnj default: 2434784Swnj panic("udp_usrreq"); 2444805Swnj } 2454887Swnj return (0); 2464784Swnj } 247