1*5996Swnj /* udp_usrreq.c 4.20 82/02/27 */ 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 /* 85*5996Swnj * Locate pcb for datagram. On wildcard match, update 86*5996Swnj * control block to anchor network and host address. 874926Swnj */ 884926Swnj inp = in_pcblookup(&udb, 89*5996Swnj ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 1); 905051Swnj if (inp == 0) 914926Swnj goto bad; 924926Swnj 934926Swnj /* 944926Swnj * Construct sockaddr format source address. 954926Swnj * Stuff source address and datagram in user buffer. 964926Swnj */ 974926Swnj udp_in.sin_port = ui->ui_sport; 984926Swnj udp_in.sin_addr = ui->ui_src; 995050Swnj m->m_len -= sizeof (struct udpiphdr); 1005050Swnj m->m_off += sizeof (struct udpiphdr); 1015050Swnj if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 1024926Swnj goto bad; 1035050Swnj sorwakeup(inp->inp_socket); 1044887Swnj return; 1054926Swnj bad: 1064887Swnj m_freem(m); 1074784Swnj } 1084784Swnj 1094887Swnj udp_ctlinput(m) 1104887Swnj struct mbuf *m; 1114887Swnj { 1124887Swnj 1135094Swnj COUNT(UDP_CTLINPUT); 1144887Swnj m_freem(m); 1154887Swnj } 1164887Swnj 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 1285246Sroot * for UDP and IP headers. 1294926Swnj */ 1304926Swnj for (m = m0; m; m = m->m_next) 1314926Swnj len += m->m_len; 1325585Sroot m = m_get(M_DONTWAIT); 1335051Swnj if (m == 0) 1344926Swnj goto bad; 1354784Swnj 1364926Swnj /* 1375246Sroot * 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 1674887Swnj udp_usrreq(so, req, m, addr) 1684887Swnj struct socket *so; 1694784Swnj int req; 1704784Swnj struct mbuf *m; 1714912Swnj caddr_t addr; 1724784Swnj { 1734887Swnj struct inpcb *inp = sotoinpcb(so); 1744887Swnj int error; 1754784Swnj 1765094Swnj COUNT(UDP_USRREQ); 1775051Swnj if (inp == 0 && req != PRU_ATTACH) 1785050Swnj return (EINVAL); 1794784Swnj switch (req) { 1804784Swnj 1814784Swnj case PRU_ATTACH: 1824887Swnj if (inp != 0) 1834887Swnj return (EINVAL); 1845166Swnj error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); 1855051Swnj if (error) 1864955Swnj return (error); 1874887Swnj break; 1884784Swnj 1894784Swnj case PRU_DETACH: 1904887Swnj if (inp == 0) 1914887Swnj return (ENOTCONN); 1925166Swnj in_pcbdetach(inp); 1934887Swnj break; 1944784Swnj 1954784Swnj case PRU_CONNECT: 1964955Swnj if (inp->inp_faddr.s_addr) 1974887Swnj return (EISCONN); 1985166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 1995051Swnj if (error) 2004887Swnj return (error); 2014887Swnj soisconnected(so); 2024887Swnj break; 2034784Swnj 2044926Swnj case PRU_ACCEPT: 2054926Swnj return (EOPNOTSUPP); 2064926Swnj 2074784Swnj case PRU_DISCONNECT: 2084955Swnj if (inp->inp_faddr.s_addr == 0) 2094887Swnj return (ENOTCONN); 2105166Swnj in_pcbdisconnect(inp); 2114887Swnj soisdisconnected(so); 2124784Swnj break; 2134784Swnj 2144912Swnj case PRU_SHUTDOWN: 2154912Swnj socantsendmore(so); 2164912Swnj break; 2174912Swnj 218*5996Swnj case PRU_SEND: { 219*5996Swnj struct in_addr laddr; 220*5996Swnj 2214887Swnj if (addr) { 222*5996Swnj laddr = inp->inp_laddr; 2235224Swnj if (inp->inp_faddr.s_addr) 2244887Swnj return (EISCONN); 2255166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 2265224Swnj if (error) 2274955Swnj return (error); 2284955Swnj } else { 2294955Swnj if (inp->inp_faddr.s_addr == 0) 2304955Swnj return (ENOTCONN); 2314955Swnj } 2324955Swnj udp_output(inp, m); 233*5996Swnj if (addr) { 2345166Swnj in_pcbdisconnect(inp); 235*5996Swnj inp->inp_laddr = laddr; 236*5996Swnj } 237*5996Swnj } 2384784Swnj break; 2394784Swnj 2404784Swnj case PRU_ABORT: 2415166Swnj in_pcbdetach(inp); 2424887Swnj sofree(so); 2434887Swnj soisdisconnected(so); 2444784Swnj break; 2454784Swnj 2464784Swnj case PRU_CONTROL: 2474887Swnj return (EOPNOTSUPP); 2484784Swnj 2494784Swnj default: 2504784Swnj panic("udp_usrreq"); 2514805Swnj } 2524887Swnj return (0); 2534784Swnj } 254