1*9644Ssam /* udp_usrreq.c 4.41 82/12/14 */ 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" 108411Swnj #include "../netinet/in.h" 116584Ssam #include "../net/if.h" 126354Ssam #include "../net/route.h" 138411Swnj #include "../netinet/in_pcb.h" 148411Swnj #include "../netinet/in_systm.h" 158411Swnj #include "../netinet/ip.h" 168411Swnj #include "../netinet/ip_var.h" 178411Swnj #include "../netinet/ip_icmp.h" 188411Swnj #include "../netinet/udp.h" 198411Swnj #include "../netinet/udp_var.h" 206507Ssam #include <errno.h> 214784Swnj 224926Swnj /* 234926Swnj * UDP protocol implementation. 244926Swnj * Per RFC 768, August, 1980. 254926Swnj */ 264805Swnj udp_init() 274805Swnj { 284805Swnj 294901Swnj udb.inp_next = udb.inp_prev = &udb; 304805Swnj } 314805Swnj 324901Swnj int udpcksum; 334926Swnj struct sockaddr_in udp_in = { AF_INET }; 344901Swnj 354926Swnj udp_input(m0) 364926Swnj struct mbuf *m0; 374784Swnj { 384901Swnj register struct udpiphdr *ui; 394887Swnj register struct inpcb *inp; 404926Swnj register struct mbuf *m; 417844Sroot int len; 424784Swnj 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 */ 607844Sroot len = ntohs((u_short)ui->ui_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; 767844Sroot ui->ui_len = htons((u_short)len); 777844Sroot if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 784926Swnj udpstat.udps_badsum++; 794901Swnj printf("udp cksum %x\n", ui->ui_sum); 804901Swnj m_freem(m); 814901Swnj return; 824901Swnj } 834901Swnj } 844926Swnj 854926Swnj /* 867844Sroot * Locate pcb for datagram. 874926Swnj */ 884926Swnj inp = in_pcblookup(&udb, 896029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 906029Sroot INPLOOKUP_WILDCARD); 916584Ssam if (inp == 0) { 926584Ssam struct in_addr broadcastaddr; 934926Swnj 948602Sroot broadcastaddr = 958812Sroot if_makeaddr(in_netof(ui->ui_dst), INADDR_ANY); 966591Ssam if (ui->ui_dst.s_addr == broadcastaddr.s_addr) 976584Ssam goto bad; 986584Ssam icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT); 996584Ssam return; 1006584Ssam } 1016584Ssam 1024926Swnj /* 1034926Swnj * Construct sockaddr format source address. 1044926Swnj * Stuff source address and datagram in user buffer. 1054926Swnj */ 1064926Swnj udp_in.sin_port = ui->ui_sport; 1074926Swnj udp_in.sin_addr = ui->ui_src; 1085050Swnj m->m_len -= sizeof (struct udpiphdr); 1095050Swnj m->m_off += sizeof (struct udpiphdr); 1108551Sroot SBCHECK(&inp->inp_socket->so_rcv, "udpinput before"); 1115050Swnj if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 1124926Swnj goto bad; 1138551Sroot SBCHECK(&inp->inp_socket->so_rcv, "udpinput after"); 1145050Swnj sorwakeup(inp->inp_socket); 1154887Swnj return; 1164926Swnj bad: 1174887Swnj m_freem(m); 1184784Swnj } 1194784Swnj 1206584Ssam udp_abort(inp) 1216584Ssam struct inpcb *inp; 1226584Ssam { 1236584Ssam struct socket *so = inp->inp_socket; 1246584Ssam 1256584Ssam in_pcbdisconnect(inp); 1266584Ssam soisdisconnected(so); 1276584Ssam } 1286584Ssam 1296591Ssam udp_ctlinput(cmd, arg) 1306591Ssam int cmd; 1316591Ssam caddr_t arg; 1326591Ssam { 1336591Ssam struct in_addr *sin; 1346591Ssam extern u_char inetctlerrmap[]; 1356591Ssam 1366591Ssam if (cmd < 0 || cmd > PRC_NCMDS) 1376591Ssam return; 1386591Ssam switch (cmd) { 1396591Ssam 1406591Ssam case PRC_ROUTEDEAD: 1416591Ssam break; 1426591Ssam 1436591Ssam case PRC_QUENCH: 1446591Ssam break; 1456591Ssam 1466591Ssam /* these are handled by ip */ 1476591Ssam case PRC_IFDOWN: 1486591Ssam case PRC_HOSTDEAD: 1496591Ssam case PRC_HOSTUNREACH: 1506591Ssam break; 1516591Ssam 1526591Ssam default: 1536591Ssam sin = &((struct icmp *)arg)->icmp_ip.ip_dst; 1548641Sroot in_pcbnotify(&udb, sin, (int)inetctlerrmap[cmd], udp_abort); 1556591Ssam } 1566591Ssam } 1576591Ssam 1584955Swnj udp_output(inp, m0) 1594926Swnj struct inpcb *inp; 1604926Swnj struct mbuf *m0; 1614784Swnj { 1624926Swnj register struct mbuf *m; 1634926Swnj register struct udpiphdr *ui; 1647157Swnj register struct socket *so; 1654926Swnj register int len = 0; 1664784Swnj 1674926Swnj /* 1684926Swnj * Calculate data length and get a mbuf 1695246Sroot * for UDP and IP headers. 1704926Swnj */ 1714926Swnj for (m = m0; m; m = m->m_next) 1724926Swnj len += m->m_len; 173*9644Ssam m = m_get(M_DONTWAIT, MT_HEADER); 1746507Ssam if (m == 0) { 1756507Ssam m_freem(m0); 1766507Ssam return (ENOBUFS); 1776507Ssam } 1784784Swnj 1794926Swnj /* 1805246Sroot * Fill in mbuf with extended UDP header 1814926Swnj * and addresses and length put into network format. 1824926Swnj */ 1834926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1844926Swnj m->m_len = sizeof (struct udpiphdr); 1854926Swnj m->m_next = m0; 1864926Swnj ui = mtod(m, struct udpiphdr *); 1874926Swnj ui->ui_next = ui->ui_prev = 0; 1884926Swnj ui->ui_x1 = 0; 1894926Swnj ui->ui_pr = IPPROTO_UDP; 1907844Sroot ui->ui_len = len + sizeof (struct udphdr); 1915050Swnj ui->ui_src = inp->inp_laddr; 1925050Swnj ui->ui_dst = inp->inp_faddr; 1935050Swnj ui->ui_sport = inp->inp_lport; 1945050Swnj ui->ui_dport = inp->inp_fport; 1957844Sroot ui->ui_ulen = htons((u_short)ui->ui_len); 1964784Swnj 1974926Swnj /* 1984926Swnj * Stuff checksum and output datagram. 1994926Swnj */ 2004926Swnj ui->ui_sum = 0; 2015094Swnj ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 2025050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 2035050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 2047157Swnj so = inp->inp_socket; 2057157Swnj return (ip_output(m, (struct mbuf *)0, 2067157Swnj (so->so_options & SO_DONTROUTE) ? &routetoif : (struct route *)0, 2077157Swnj so->so_state & SS_PRIV)); 2084784Swnj } 2094784Swnj 2108602Sroot /*ARGSUSED*/ 2118273Sroot udp_usrreq(so, req, m, nam, opt) 2124887Swnj struct socket *so; 2134784Swnj int req; 2148273Sroot struct mbuf *m, *nam; 2158273Sroot struct socketopt *opt; 2164784Swnj { 2174887Swnj struct inpcb *inp = sotoinpcb(so); 2186507Ssam int error = 0; 2194784Swnj 2205051Swnj if (inp == 0 && req != PRU_ATTACH) 2215050Swnj return (EINVAL); 2224784Swnj switch (req) { 2234784Swnj 2244784Swnj case PRU_ATTACH: 2254887Swnj if (inp != 0) 2264887Swnj return (EINVAL); 2278273Sroot error = in_pcballoc(so, &udb); 2288273Sroot if (error) 2298273Sroot break; 2309032Sroot error = soreserve(so, 2048, 2048); 2318273Sroot if (error) 2328273Sroot break; 2334887Swnj break; 2344784Swnj 2354784Swnj case PRU_DETACH: 2364887Swnj if (inp == 0) 2374887Swnj return (ENOTCONN); 2385166Swnj in_pcbdetach(inp); 2394887Swnj break; 2404784Swnj 2418273Sroot case PRU_BIND: 2428273Sroot error = in_pcbbind(inp, nam); 2438273Sroot break; 2448273Sroot 2458273Sroot case PRU_LISTEN: 2468273Sroot error = EOPNOTSUPP; 2478273Sroot break; 2488273Sroot 2494784Swnj case PRU_CONNECT: 2504955Swnj if (inp->inp_faddr.s_addr) 2514887Swnj return (EISCONN); 2528273Sroot error = in_pcbconnect(inp, nam); 2536507Ssam if (error == 0) 2546507Ssam soisconnected(so); 2554887Swnj break; 2564784Swnj 2574926Swnj case PRU_ACCEPT: 2584926Swnj return (EOPNOTSUPP); 2594926Swnj 2604784Swnj case PRU_DISCONNECT: 2614955Swnj if (inp->inp_faddr.s_addr == 0) 2624887Swnj return (ENOTCONN); 2635166Swnj in_pcbdisconnect(inp); 2644887Swnj soisdisconnected(so); 2654784Swnj break; 2664784Swnj 2674912Swnj case PRU_SHUTDOWN: 2684912Swnj socantsendmore(so); 2694912Swnj break; 2704912Swnj 2715996Swnj case PRU_SEND: { 2725996Swnj struct in_addr laddr; 2735996Swnj 2748273Sroot if (nam) { 2755996Swnj laddr = inp->inp_laddr; 2765224Swnj if (inp->inp_faddr.s_addr) 2774887Swnj return (EISCONN); 2788273Sroot error = in_pcbconnect(inp, nam); 2795224Swnj if (error) 2806507Ssam break; 2814955Swnj } else { 2824955Swnj if (inp->inp_faddr.s_addr == 0) 2834955Swnj return (ENOTCONN); 2844955Swnj } 2856507Ssam error = udp_output(inp, m); 2868273Sroot if (nam) { 2875166Swnj in_pcbdisconnect(inp); 2885996Swnj inp->inp_laddr = laddr; 2895996Swnj } 2905996Swnj } 2914784Swnj break; 2924784Swnj 2934784Swnj case PRU_ABORT: 2945166Swnj in_pcbdetach(inp); 2954887Swnj sofree(so); 2964887Swnj soisdisconnected(so); 2974784Swnj break; 2984784Swnj 2994784Swnj case PRU_CONTROL: 3004887Swnj return (EOPNOTSUPP); 3014784Swnj 3026511Ssam case PRU_SOCKADDR: 3038273Sroot in_setsockaddr(inp, nam); 3046511Ssam break; 3056511Ssam 3064784Swnj default: 3074784Swnj panic("udp_usrreq"); 3084805Swnj } 3096507Ssam return (error); 3104784Swnj } 311