1*7157Swnj /* udp_usrreq.c 4.29 82/06/12 */ 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" 116584Ssam #include "../net/if.h" 126354Ssam #include "../net/route.h" 135094Swnj #include "../net/in_pcb.h" 145094Swnj #include "../net/in_systm.h" 154901Swnj #include "../net/ip.h" 164901Swnj #include "../net/ip_var.h" 176584Ssam #include "../net/ip_icmp.h" 184887Swnj #include "../net/udp.h" 194887Swnj #include "../net/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 295094Swnj COUNT(UDP_INIT); 304901Swnj udb.inp_next = udb.inp_prev = &udb; 314805Swnj } 324805Swnj 334901Swnj int udpcksum; 344926Swnj struct sockaddr_in udp_in = { AF_INET }; 354901Swnj 364926Swnj udp_input(m0) 374926Swnj struct mbuf *m0; 384784Swnj { 394901Swnj register struct udpiphdr *ui; 404887Swnj register struct inpcb *inp; 414926Swnj register struct mbuf *m; 424926Swnj int len, ulen; 434784Swnj 445094Swnj COUNT(UDP_INPUT); 454926Swnj /* 465246Sroot * Get IP and UDP header together in first mbuf. 474926Swnj */ 484926Swnj m = m0; 495308Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 505308Sroot (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 514926Swnj udpstat.udps_hdrops++; 525308Sroot return; 534926Swnj } 545050Swnj ui = mtod(m, struct udpiphdr *); 555246Sroot if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 565220Swnj ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 574926Swnj 584926Swnj /* 595246Sroot * Make mbuf data length reflect UDP length. 605246Sroot * If not enough data to reflect UDP length, drop. 614926Swnj */ 624955Swnj ulen = ntohs((u_short)ui->ui_ulen); 635220Swnj len = sizeof (struct udphdr) + ulen; 644926Swnj if (((struct ip *)ui)->ip_len != len) { 654926Swnj if (len > ((struct ip *)ui)->ip_len) { 664926Swnj udpstat.udps_badlen++; 674926Swnj goto bad; 684926Swnj } 694926Swnj m_adj(m, ((struct ip *)ui)->ip_len - len); 704926Swnj /* (struct ip *)ui->ip_len = len; */ 714926Swnj } 724926Swnj 734926Swnj /* 745246Sroot * Checksum extended UDP header and data. 754926Swnj */ 764901Swnj if (udpcksum) { 774926Swnj ui->ui_next = ui->ui_prev = 0; 784926Swnj ui->ui_x1 = 0; 795220Swnj ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen)); 805220Swnj if (ui->ui_sum = in_cksum(m, len)) { 814926Swnj udpstat.udps_badsum++; 824901Swnj printf("udp cksum %x\n", ui->ui_sum); 834901Swnj m_freem(m); 844901Swnj return; 854901Swnj } 864901Swnj } 874926Swnj 884926Swnj /* 895996Swnj * Locate pcb for datagram. On wildcard match, update 905996Swnj * control block to anchor network and host address. 914926Swnj */ 924926Swnj inp = in_pcblookup(&udb, 936029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 946029Sroot INPLOOKUP_WILDCARD); 956584Ssam if (inp == 0) { 966584Ssam struct in_addr broadcastaddr; 974926Swnj 986584Ssam broadcastaddr = if_makeaddr(ui->ui_dst.s_net, INADDR_ANY); 996591Ssam if (ui->ui_dst.s_addr == broadcastaddr.s_addr) 1006584Ssam goto bad; 1016584Ssam icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT); 1026584Ssam return; 1036584Ssam } 1046584Ssam 1054926Swnj /* 1064926Swnj * Construct sockaddr format source address. 1074926Swnj * Stuff source address and datagram in user buffer. 1084926Swnj */ 1094926Swnj udp_in.sin_port = ui->ui_sport; 1104926Swnj udp_in.sin_addr = ui->ui_src; 1115050Swnj m->m_len -= sizeof (struct udpiphdr); 1125050Swnj m->m_off += sizeof (struct udpiphdr); 1135050Swnj if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 1144926Swnj goto bad; 1155050Swnj sorwakeup(inp->inp_socket); 1164887Swnj return; 1174926Swnj bad: 1184887Swnj m_freem(m); 1194784Swnj } 1204784Swnj 1216584Ssam udp_abort(inp) 1226584Ssam struct inpcb *inp; 1236584Ssam { 1246584Ssam struct socket *so = inp->inp_socket; 1256584Ssam 1266584Ssam in_pcbdisconnect(inp); 1276584Ssam soisdisconnected(so); 1286584Ssam } 1296584Ssam 1306591Ssam udp_ctlinput(cmd, arg) 1316591Ssam int cmd; 1326591Ssam caddr_t arg; 1336591Ssam { 1346591Ssam struct in_addr *sin; 1356591Ssam extern u_char inetctlerrmap[]; 1366591Ssam COUNT(UDP_CTLINPUT); 1376591Ssam 1386591Ssam if (cmd < 0 || cmd > PRC_NCMDS) 1396591Ssam return; 1406591Ssam switch (cmd) { 1416591Ssam 1426591Ssam case PRC_ROUTEDEAD: 1436591Ssam break; 1446591Ssam 1456591Ssam case PRC_QUENCH: 1466591Ssam break; 1476591Ssam 1486591Ssam /* these are handled by ip */ 1496591Ssam case PRC_IFDOWN: 1506591Ssam case PRC_HOSTDEAD: 1516591Ssam case PRC_HOSTUNREACH: 1526591Ssam break; 1536591Ssam 1546591Ssam default: 1556591Ssam sin = &((struct icmp *)arg)->icmp_ip.ip_dst; 1566591Ssam in_pcbnotify(&udb, sin, inetctlerrmap[cmd], udp_abort); 1576591Ssam } 1586591Ssam } 1596591Ssam 1604955Swnj udp_output(inp, m0) 1614926Swnj struct inpcb *inp; 1624926Swnj struct mbuf *m0; 1634784Swnj { 1644926Swnj register struct mbuf *m; 1654926Swnj register struct udpiphdr *ui; 166*7157Swnj register struct socket *so; 1674926Swnj register int len = 0; 1684784Swnj 1695094Swnj COUNT(UDP_OUTPUT); 1704926Swnj /* 1714926Swnj * Calculate data length and get a mbuf 1725246Sroot * for UDP and IP headers. 1734926Swnj */ 1744926Swnj for (m = m0; m; m = m->m_next) 1754926Swnj len += m->m_len; 1765585Sroot m = m_get(M_DONTWAIT); 1776507Ssam if (m == 0) { 1786507Ssam m_freem(m0); 1796507Ssam return (ENOBUFS); 1806507Ssam } 1814784Swnj 1824926Swnj /* 1835246Sroot * Fill in mbuf with extended UDP header 1844926Swnj * and addresses and length put into network format. 1854926Swnj */ 1864926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1874926Swnj m->m_len = sizeof (struct udpiphdr); 1884926Swnj m->m_next = m0; 1894926Swnj ui = mtod(m, struct udpiphdr *); 1904926Swnj ui->ui_next = ui->ui_prev = 0; 1914926Swnj ui->ui_x1 = 0; 1924926Swnj ui->ui_pr = IPPROTO_UDP; 1935050Swnj ui->ui_len = sizeof (struct udpiphdr) + len; 1945050Swnj ui->ui_src = inp->inp_laddr; 1955050Swnj ui->ui_dst = inp->inp_faddr; 1965050Swnj ui->ui_sport = inp->inp_lport; 1975050Swnj ui->ui_dport = inp->inp_fport; 198*7157Swnj ui->ui_ulen = len; 199*7157Swnj #if vax 200*7157Swnj ui->ui_ulen = htons(ui->ui_ulen); 201*7157Swnj #endif 2024784Swnj 2034926Swnj /* 2044926Swnj * Stuff checksum and output datagram. 2054926Swnj */ 2064926Swnj ui->ui_sum = 0; 2075094Swnj ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 2085050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 2095050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 210*7157Swnj so = inp->inp_socket; 211*7157Swnj return (ip_output(m, (struct mbuf *)0, 212*7157Swnj (so->so_options & SO_DONTROUTE) ? &routetoif : (struct route *)0, 213*7157Swnj so->so_state & SS_PRIV)); 2144784Swnj } 2154784Swnj 2164887Swnj udp_usrreq(so, req, m, addr) 2174887Swnj struct socket *so; 2184784Swnj int req; 2194784Swnj struct mbuf *m; 2204912Swnj caddr_t addr; 2214784Swnj { 2224887Swnj struct inpcb *inp = sotoinpcb(so); 2236507Ssam int error = 0; 2244784Swnj 2255094Swnj COUNT(UDP_USRREQ); 2265051Swnj if (inp == 0 && req != PRU_ATTACH) 2275050Swnj return (EINVAL); 2284784Swnj switch (req) { 2294784Swnj 2304784Swnj case PRU_ATTACH: 2314887Swnj if (inp != 0) 2324887Swnj return (EINVAL); 2336507Ssam error = in_pcbattach(so, &udb, 2048, 2048, 2346507Ssam (struct sockaddr_in *)addr); 2354887Swnj break; 2364784Swnj 2374784Swnj case PRU_DETACH: 2384887Swnj if (inp == 0) 2394887Swnj return (ENOTCONN); 2405166Swnj in_pcbdetach(inp); 2414887Swnj break; 2424784Swnj 2434784Swnj case PRU_CONNECT: 2444955Swnj if (inp->inp_faddr.s_addr) 2454887Swnj return (EISCONN); 2465166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 2476507Ssam if (error == 0) 2486507Ssam soisconnected(so); 2494887Swnj break; 2504784Swnj 2514926Swnj case PRU_ACCEPT: 2524926Swnj return (EOPNOTSUPP); 2534926Swnj 2544784Swnj case PRU_DISCONNECT: 2554955Swnj if (inp->inp_faddr.s_addr == 0) 2564887Swnj return (ENOTCONN); 2575166Swnj in_pcbdisconnect(inp); 2584887Swnj soisdisconnected(so); 2594784Swnj break; 2604784Swnj 2614912Swnj case PRU_SHUTDOWN: 2624912Swnj socantsendmore(so); 2634912Swnj break; 2644912Swnj 2655996Swnj case PRU_SEND: { 2665996Swnj struct in_addr laddr; 2675996Swnj 2684887Swnj if (addr) { 2695996Swnj laddr = inp->inp_laddr; 2705224Swnj if (inp->inp_faddr.s_addr) 2714887Swnj return (EISCONN); 2725166Swnj error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 2735224Swnj if (error) 2746507Ssam break; 2754955Swnj } else { 2764955Swnj if (inp->inp_faddr.s_addr == 0) 2774955Swnj return (ENOTCONN); 2784955Swnj } 2796507Ssam error = udp_output(inp, m); 2805996Swnj if (addr) { 2815166Swnj in_pcbdisconnect(inp); 2825996Swnj inp->inp_laddr = laddr; 2835996Swnj } 2845996Swnj } 2854784Swnj break; 2864784Swnj 2874784Swnj case PRU_ABORT: 2885166Swnj in_pcbdetach(inp); 2894887Swnj sofree(so); 2904887Swnj soisdisconnected(so); 2914784Swnj break; 2924784Swnj 2934784Swnj case PRU_CONTROL: 2944887Swnj return (EOPNOTSUPP); 2954784Swnj 2966511Ssam case PRU_SOCKADDR: 2976511Ssam in_setsockaddr((struct sockaddr_in *)addr, inp); 2986511Ssam break; 2996511Ssam 3004784Swnj default: 3014784Swnj panic("udp_usrreq"); 3024805Swnj } 3036507Ssam return (error); 3044784Swnj } 305