1*12205Ssam /* udp_usrreq.c 4.46 83/05/03 */ 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" 1010897Ssam #include "../h/errno.h" 1110897Ssam 126584Ssam #include "../net/if.h" 136354Ssam #include "../net/route.h" 1410897Ssam 1510897Ssam #include "../netinet/in.h" 168411Swnj #include "../netinet/in_pcb.h" 178411Swnj #include "../netinet/in_systm.h" 188411Swnj #include "../netinet/ip.h" 198411Swnj #include "../netinet/ip_var.h" 208411Swnj #include "../netinet/ip_icmp.h" 218411Swnj #include "../netinet/udp.h" 228411Swnj #include "../netinet/udp_var.h" 234784Swnj 244926Swnj /* 254926Swnj * UDP protocol implementation. 264926Swnj * Per RFC 768, August, 1980. 274926Swnj */ 284805Swnj udp_init() 294805Swnj { 304805Swnj 314901Swnj udb.inp_next = udb.inp_prev = &udb; 324805Swnj } 334805Swnj 344901Swnj int udpcksum; 354926Swnj struct sockaddr_in udp_in = { AF_INET }; 364901Swnj 374926Swnj udp_input(m0) 384926Swnj struct mbuf *m0; 394784Swnj { 404901Swnj register struct udpiphdr *ui; 414887Swnj register struct inpcb *inp; 424926Swnj register struct mbuf *m; 437844Sroot int len; 444784Swnj 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 */ 627844Sroot len = ntohs((u_short)ui->ui_ulen); 634926Swnj if (((struct ip *)ui)->ip_len != len) { 644926Swnj if (len > ((struct ip *)ui)->ip_len) { 654926Swnj udpstat.udps_badlen++; 664926Swnj goto bad; 674926Swnj } 684926Swnj m_adj(m, ((struct ip *)ui)->ip_len - len); 694926Swnj /* (struct ip *)ui->ip_len = len; */ 704926Swnj } 714926Swnj 724926Swnj /* 735246Sroot * Checksum extended UDP header and data. 744926Swnj */ 754901Swnj if (udpcksum) { 764926Swnj ui->ui_next = ui->ui_prev = 0; 774926Swnj ui->ui_x1 = 0; 787844Sroot ui->ui_len = htons((u_short)len); 797844Sroot if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 804926Swnj udpstat.udps_badsum++; 814901Swnj m_freem(m); 824901Swnj return; 834901Swnj } 844901Swnj } 854926Swnj 864926Swnj /* 877844Sroot * Locate pcb for datagram. 884926Swnj */ 894926Swnj inp = in_pcblookup(&udb, 906029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 916029Sroot INPLOOKUP_WILDCARD); 926584Ssam if (inp == 0) { 9310144Ssam /* don't send ICMP response for broadcast packet */ 9410144Ssam if (in_lnaof(ui->ui_dst) == INADDR_ANY) 956584Ssam goto bad; 966584Ssam icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT); 976584Ssam return; 986584Ssam } 996584Ssam 1004926Swnj /* 1014926Swnj * Construct sockaddr format source address. 1024926Swnj * Stuff source address and datagram in user buffer. 1034926Swnj */ 1044926Swnj udp_in.sin_port = ui->ui_sport; 1054926Swnj udp_in.sin_addr = ui->ui_src; 1065050Swnj m->m_len -= sizeof (struct udpiphdr); 1075050Swnj m->m_off += sizeof (struct udpiphdr); 1085050Swnj if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 1094926Swnj goto bad; 1105050Swnj sorwakeup(inp->inp_socket); 1114887Swnj return; 1124926Swnj bad: 1134887Swnj m_freem(m); 1144784Swnj } 1154784Swnj 1166584Ssam udp_abort(inp) 1176584Ssam struct inpcb *inp; 1186584Ssam { 1196584Ssam struct socket *so = inp->inp_socket; 1206584Ssam 1216584Ssam in_pcbdisconnect(inp); 1226584Ssam soisdisconnected(so); 1236584Ssam } 1246584Ssam 1256591Ssam udp_ctlinput(cmd, arg) 1266591Ssam int cmd; 1276591Ssam caddr_t arg; 1286591Ssam { 1296591Ssam struct in_addr *sin; 1306591Ssam extern u_char inetctlerrmap[]; 1316591Ssam 1326591Ssam if (cmd < 0 || cmd > PRC_NCMDS) 1336591Ssam return; 1346591Ssam switch (cmd) { 1356591Ssam 1366591Ssam case PRC_ROUTEDEAD: 1376591Ssam break; 1386591Ssam 1396591Ssam case PRC_QUENCH: 1406591Ssam break; 1416591Ssam 1426591Ssam /* these are handled by ip */ 1436591Ssam case PRC_IFDOWN: 1446591Ssam case PRC_HOSTDEAD: 1456591Ssam case PRC_HOSTUNREACH: 1466591Ssam break; 1476591Ssam 1486591Ssam default: 1496591Ssam sin = &((struct icmp *)arg)->icmp_ip.ip_dst; 1508641Sroot in_pcbnotify(&udb, sin, (int)inetctlerrmap[cmd], udp_abort); 1516591Ssam } 1526591Ssam } 1536591Ssam 1544955Swnj udp_output(inp, m0) 1554926Swnj struct inpcb *inp; 1564926Swnj struct mbuf *m0; 1574784Swnj { 1584926Swnj register struct mbuf *m; 1594926Swnj register struct udpiphdr *ui; 1607157Swnj register struct socket *so; 1614926Swnj register int len = 0; 1624784Swnj 1634926Swnj /* 1644926Swnj * Calculate data length and get a mbuf 1655246Sroot * for UDP and IP headers. 1664926Swnj */ 1674926Swnj for (m = m0; m; m = m->m_next) 1684926Swnj len += m->m_len; 1699644Ssam m = m_get(M_DONTWAIT, MT_HEADER); 1706507Ssam if (m == 0) { 1716507Ssam m_freem(m0); 1726507Ssam return (ENOBUFS); 1736507Ssam } 1744784Swnj 1754926Swnj /* 1765246Sroot * Fill in mbuf with extended UDP header 1774926Swnj * and addresses and length put into network format. 1784926Swnj */ 1794926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1804926Swnj m->m_len = sizeof (struct udpiphdr); 1814926Swnj m->m_next = m0; 1824926Swnj ui = mtod(m, struct udpiphdr *); 1834926Swnj ui->ui_next = ui->ui_prev = 0; 1844926Swnj ui->ui_x1 = 0; 1854926Swnj ui->ui_pr = IPPROTO_UDP; 1867844Sroot ui->ui_len = len + sizeof (struct udphdr); 1875050Swnj ui->ui_src = inp->inp_laddr; 1885050Swnj ui->ui_dst = inp->inp_faddr; 1895050Swnj ui->ui_sport = inp->inp_lport; 1905050Swnj ui->ui_dport = inp->inp_fport; 1917844Sroot ui->ui_ulen = htons((u_short)ui->ui_len); 1924784Swnj 1934926Swnj /* 1944926Swnj * Stuff checksum and output datagram. 1954926Swnj */ 1964926Swnj ui->ui_sum = 0; 1975094Swnj ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 1985050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 1995050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 2007157Swnj so = inp->inp_socket; 2017157Swnj return (ip_output(m, (struct mbuf *)0, 2027157Swnj (so->so_options & SO_DONTROUTE) ? &routetoif : (struct route *)0, 2037157Swnj so->so_state & SS_PRIV)); 2044784Swnj } 2054784Swnj 2068602Sroot /*ARGSUSED*/ 20710262Ssam udp_usrreq(so, req, m, nam) 2084887Swnj struct socket *so; 2094784Swnj int req; 2108273Sroot struct mbuf *m, *nam; 2114784Swnj { 2124887Swnj struct inpcb *inp = sotoinpcb(so); 2136507Ssam int error = 0; 2144784Swnj 21511080Ssam if (inp == NULL && req != PRU_ATTACH) { 21611080Ssam error = EINVAL; 21711080Ssam goto release; 21811080Ssam } 2194784Swnj switch (req) { 2204784Swnj 2214784Swnj case PRU_ATTACH: 22211080Ssam if (inp != NULL) { 22311080Ssam error = EINVAL; 22411080Ssam break; 22511080Ssam } 2268273Sroot error = in_pcballoc(so, &udb); 2278273Sroot if (error) 2288273Sroot break; 2299032Sroot error = soreserve(so, 2048, 2048); 2308273Sroot if (error) 2318273Sroot break; 2324887Swnj break; 2334784Swnj 2344784Swnj case PRU_DETACH: 23511080Ssam if (inp == NULL) { 23611080Ssam error = ENOTCONN; 23711080Ssam break; 23811080Ssam } 2395166Swnj in_pcbdetach(inp); 2404887Swnj break; 2414784Swnj 2428273Sroot case PRU_BIND: 2438273Sroot error = in_pcbbind(inp, nam); 2448273Sroot break; 2458273Sroot 2468273Sroot case PRU_LISTEN: 2478273Sroot error = EOPNOTSUPP; 2488273Sroot break; 2498273Sroot 2504784Swnj case PRU_CONNECT: 25111080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 25211080Ssam error = EISCONN; 25311080Ssam break; 25411080Ssam } 2558273Sroot error = in_pcbconnect(inp, nam); 2566507Ssam if (error == 0) 2576507Ssam soisconnected(so); 2584887Swnj break; 2594784Swnj 2604926Swnj case PRU_ACCEPT: 26111080Ssam error = EOPNOTSUPP; 26211080Ssam break; 2634926Swnj 2644784Swnj case PRU_DISCONNECT: 26511080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 26611080Ssam error = ENOTCONN; 26711080Ssam break; 26811080Ssam } 2695166Swnj in_pcbdisconnect(inp); 2704887Swnj soisdisconnected(so); 2714784Swnj break; 2724784Swnj 2734912Swnj case PRU_SHUTDOWN: 2744912Swnj socantsendmore(so); 2754912Swnj break; 2764912Swnj 2775996Swnj case PRU_SEND: { 2785996Swnj struct in_addr laddr; 2795996Swnj 2808273Sroot if (nam) { 2815996Swnj laddr = inp->inp_laddr; 28211080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 28311080Ssam error = EISCONN; 28411080Ssam break; 28511080Ssam } 2868273Sroot error = in_pcbconnect(inp, nam); 2875224Swnj if (error) 2886507Ssam break; 2894955Swnj } else { 29011080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 29111080Ssam error = ENOTCONN; 29211080Ssam break; 29311080Ssam } 2944955Swnj } 2956507Ssam error = udp_output(inp, m); 29611080Ssam m = NULL; 2978273Sroot if (nam) { 2985166Swnj in_pcbdisconnect(inp); 2995996Swnj inp->inp_laddr = laddr; 3005996Swnj } 3015996Swnj } 3024784Swnj break; 3034784Swnj 3044784Swnj case PRU_ABORT: 3055166Swnj in_pcbdetach(inp); 3064887Swnj sofree(so); 3074887Swnj soisdisconnected(so); 3084784Swnj break; 3094784Swnj 3106511Ssam case PRU_SOCKADDR: 3118273Sroot in_setsockaddr(inp, nam); 3126511Ssam break; 3136511Ssam 3144784Swnj default: 315*12205Ssam printf("request %d\n", req); 3164784Swnj panic("udp_usrreq"); 317*12205Ssam 318*12205Ssam case PRU_RCVD: 319*12205Ssam case PRU_CONTROL: 320*12205Ssam case PRU_SENSE: 321*12205Ssam case PRU_RCVOOB: 322*12205Ssam case PRU_SENDOOB: 323*12205Ssam case PRU_FASTTIMO: 324*12205Ssam case PRU_SLOWTIMO: 325*12205Ssam case PRU_PROTORCV: 326*12205Ssam case PRU_PROTOSEND: 327*12205Ssam error = EOPNOTSUPP; 328*12205Ssam break; 3294805Swnj } 33011080Ssam release: 33111080Ssam if (m != NULL) 33211080Ssam m_freem(m); 3336507Ssam return (error); 3344784Swnj } 335