1*6507Ssam /* udp_usrreq.c 4.25 82/04/10 */ 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" 116354Ssam #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" 18*6507Ssam #include <errno.h> 194784Swnj 204926Swnj /* 214926Swnj * UDP protocol implementation. 224926Swnj * Per RFC 768, August, 1980. 234926Swnj */ 244805Swnj udp_init() 254805Swnj { 264805Swnj 275094Swnj COUNT(UDP_INIT); 284901Swnj udb.inp_next = udb.inp_prev = &udb; 294805Swnj } 304805Swnj 314901Swnj int udpcksum; 324926Swnj struct sockaddr_in udp_in = { AF_INET }; 334901Swnj 344926Swnj udp_input(m0) 354926Swnj struct mbuf *m0; 364784Swnj { 374901Swnj register struct udpiphdr *ui; 384887Swnj register struct inpcb *inp; 394926Swnj register struct mbuf *m; 404926Swnj int len, ulen; 414784Swnj 425094Swnj COUNT(UDP_INPUT); 434926Swnj /* 445246Sroot * Get IP and UDP header together in first mbuf. 454926Swnj */ 464926Swnj m = m0; 475308Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 485308Sroot (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 494926Swnj udpstat.udps_hdrops++; 505308Sroot return; 514926Swnj } 525050Swnj ui = mtod(m, struct udpiphdr *); 535246Sroot if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 545220Swnj ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 554926Swnj 564926Swnj /* 575246Sroot * Make mbuf data length reflect UDP length. 585246Sroot * If not enough data to reflect UDP length, drop. 594926Swnj */ 604955Swnj ulen = ntohs((u_short)ui->ui_ulen); 615220Swnj len = sizeof (struct udphdr) + ulen; 624926Swnj if (((struct ip *)ui)->ip_len != len) { 634926Swnj if (len > ((struct ip *)ui)->ip_len) { 644926Swnj udpstat.udps_badlen++; 654926Swnj goto bad; 664926Swnj } 674926Swnj m_adj(m, ((struct ip *)ui)->ip_len - len); 684926Swnj /* (struct ip *)ui->ip_len = len; */ 694926Swnj } 704926Swnj 714926Swnj /* 725246Sroot * Checksum extended UDP header and data. 734926Swnj */ 744901Swnj if (udpcksum) { 754926Swnj ui->ui_next = ui->ui_prev = 0; 764926Swnj ui->ui_x1 = 0; 775220Swnj ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen)); 785220Swnj if (ui->ui_sum = in_cksum(m, len)) { 794926Swnj udpstat.udps_badsum++; 804901Swnj printf("udp cksum %x\n", ui->ui_sum); 814901Swnj m_freem(m); 824901Swnj return; 834901Swnj } 844901Swnj } 854926Swnj 864926Swnj /* 875996Swnj * Locate pcb for datagram. On wildcard match, update 885996Swnj * control block to anchor network and host address. 894926Swnj */ 904926Swnj inp = in_pcblookup(&udb, 916029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 926029Sroot INPLOOKUP_WILDCARD); 935051Swnj if (inp == 0) 944926Swnj goto bad; 954926Swnj 964926Swnj /* 974926Swnj * Construct sockaddr format source address. 984926Swnj * Stuff source address and datagram in user buffer. 994926Swnj */ 1004926Swnj udp_in.sin_port = ui->ui_sport; 1014926Swnj udp_in.sin_addr = ui->ui_src; 1025050Swnj m->m_len -= sizeof (struct udpiphdr); 1035050Swnj m->m_off += sizeof (struct udpiphdr); 1045050Swnj if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 1054926Swnj goto bad; 1065050Swnj sorwakeup(inp->inp_socket); 1074887Swnj return; 1084926Swnj bad: 1094887Swnj m_freem(m); 1104784Swnj } 1114784Swnj 1124887Swnj udp_ctlinput(m) 1134887Swnj struct mbuf *m; 1144887Swnj { 1154887Swnj 1165094Swnj COUNT(UDP_CTLINPUT); 1174887Swnj m_freem(m); 1184887Swnj } 1194887Swnj 1204955Swnj udp_output(inp, m0) 1214926Swnj struct inpcb *inp; 1224926Swnj struct mbuf *m0; 1234784Swnj { 1244926Swnj register struct mbuf *m; 1254926Swnj register struct udpiphdr *ui; 1264926Swnj register int len = 0; 1274784Swnj 1285094Swnj COUNT(UDP_OUTPUT); 1294926Swnj /* 1304926Swnj * Calculate data length and get a mbuf 1315246Sroot * for UDP and IP headers. 1324926Swnj */ 1334926Swnj for (m = m0; m; m = m->m_next) 1344926Swnj len += m->m_len; 1355585Sroot m = m_get(M_DONTWAIT); 136*6507Ssam if (m == 0) { 137*6507Ssam m_freem(m0); 138*6507Ssam return (ENOBUFS); 139*6507Ssam } 1404784Swnj 1414926Swnj /* 1425246Sroot * Fill in mbuf with extended UDP header 1434926Swnj * and addresses and length put into network format. 1444926Swnj */ 1454926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1464926Swnj m->m_len = sizeof (struct udpiphdr); 1474926Swnj m->m_next = m0; 1484926Swnj ui = mtod(m, struct udpiphdr *); 1494926Swnj ui->ui_next = ui->ui_prev = 0; 1504926Swnj ui->ui_x1 = 0; 1514926Swnj ui->ui_pr = IPPROTO_UDP; 1525050Swnj ui->ui_len = sizeof (struct udpiphdr) + len; 1535050Swnj ui->ui_src = inp->inp_laddr; 1545050Swnj ui->ui_dst = inp->inp_faddr; 1555050Swnj ui->ui_sport = inp->inp_lport; 1565050Swnj ui->ui_dport = inp->inp_fport; 1574955Swnj ui->ui_ulen = htons((u_short)len); 1584784Swnj 1594926Swnj /* 1604926Swnj * Stuff checksum and output datagram. 1614926Swnj */ 1624926Swnj ui->ui_sum = 0; 1635094Swnj ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 1645050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 1655050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 166*6507Ssam return (ip_output(m, (struct mbuf *)0, 0, 167*6507Ssam inp->inp_socket->so_state & SS_PRIV)); 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); 177*6507Ssam int error = 0; 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); 187*6507Ssam error = in_pcbattach(so, &udb, 2048, 2048, 188*6507Ssam (struct sockaddr_in *)addr); 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); 201*6507Ssam if (error == 0) 202*6507Ssam 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 2195996Swnj case PRU_SEND: { 2205996Swnj struct in_addr laddr; 2215996Swnj 2224887Swnj if (addr) { 2235996Swnj laddr = inp->inp_laddr; 2245224Swnj if (inp->inp_faddr.s_addr) 2254887Swnj return (EISCONN); 2265166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 2275224Swnj if (error) 228*6507Ssam break; 2294955Swnj } else { 2304955Swnj if (inp->inp_faddr.s_addr == 0) 2314955Swnj return (ENOTCONN); 2324955Swnj } 233*6507Ssam error = udp_output(inp, m); 2345996Swnj if (addr) { 2355166Swnj in_pcbdisconnect(inp); 2365996Swnj inp->inp_laddr = laddr; 2376029Sroot in_setsockaddr(inp); 2385996Swnj } 2395996Swnj } 2404784Swnj break; 2414784Swnj 2424784Swnj case PRU_ABORT: 2435166Swnj in_pcbdetach(inp); 2444887Swnj sofree(so); 2454887Swnj soisdisconnected(so); 2464784Swnj break; 2474784Swnj 2484784Swnj case PRU_CONTROL: 2494887Swnj return (EOPNOTSUPP); 2504784Swnj 2514784Swnj default: 2524784Swnj panic("udp_usrreq"); 2534805Swnj } 254*6507Ssam return (error); 2554784Swnj } 256