1*16988Skarels /* udp_usrreq.c 6.6 84/08/21 */ 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" 11*16988Skarels #include "../h/stat.h" 1210897Ssam 136584Ssam #include "../net/if.h" 146354Ssam #include "../net/route.h" 1510897Ssam 1610897Ssam #include "../netinet/in.h" 178411Swnj #include "../netinet/in_pcb.h" 188411Swnj #include "../netinet/in_systm.h" 198411Swnj #include "../netinet/ip.h" 208411Swnj #include "../netinet/ip_var.h" 218411Swnj #include "../netinet/ip_icmp.h" 228411Swnj #include "../netinet/udp.h" 238411Swnj #include "../netinet/udp_var.h" 244784Swnj 254926Swnj /* 264926Swnj * UDP protocol implementation. 274926Swnj * Per RFC 768, August, 1980. 284926Swnj */ 294805Swnj udp_init() 304805Swnj { 314805Swnj 324901Swnj udb.inp_next = udb.inp_prev = &udb; 334805Swnj } 344805Swnj 3515539Skarels int udpcksum = 0; 364926Swnj struct sockaddr_in udp_in = { AF_INET }; 374901Swnj 384926Swnj udp_input(m0) 394926Swnj struct mbuf *m0; 404784Swnj { 414901Swnj register struct udpiphdr *ui; 424887Swnj register struct inpcb *inp; 434926Swnj register struct mbuf *m; 447844Sroot int len; 454784Swnj 464926Swnj /* 475246Sroot * Get IP and UDP header together in first mbuf. 484926Swnj */ 494926Swnj m = m0; 505308Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 515308Sroot (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 524926Swnj udpstat.udps_hdrops++; 535308Sroot return; 544926Swnj } 555050Swnj ui = mtod(m, struct udpiphdr *); 565246Sroot if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 575220Swnj ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 584926Swnj 594926Swnj /* 605246Sroot * Make mbuf data length reflect UDP length. 615246Sroot * If not enough data to reflect UDP length, drop. 624926Swnj */ 637844Sroot len = ntohs((u_short)ui->ui_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 } 6915539Skarels m_adj(m, len - ((struct ip *)ui)->ip_len); 704926Swnj /* (struct ip *)ui->ip_len = len; */ 714926Swnj } 724926Swnj 734926Swnj /* 745246Sroot * Checksum extended UDP header and data. 754926Swnj */ 7615539Skarels if (udpcksum && ui->ui_sum) { 774926Swnj ui->ui_next = ui->ui_prev = 0; 784926Swnj ui->ui_x1 = 0; 797844Sroot ui->ui_len = htons((u_short)len); 807844Sroot if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 814926Swnj udpstat.udps_badsum++; 824901Swnj m_freem(m); 834901Swnj return; 844901Swnj } 854901Swnj } 864926Swnj 874926Swnj /* 887844Sroot * Locate pcb for datagram. 894926Swnj */ 904926Swnj inp = in_pcblookup(&udb, 916029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 926029Sroot INPLOOKUP_WILDCARD); 936584Ssam if (inp == 0) { 9410144Ssam /* don't send ICMP response for broadcast packet */ 9510144Ssam if (in_lnaof(ui->ui_dst) == INADDR_ANY) 966584Ssam goto bad; 976584Ssam icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT); 986584Ssam return; 996584Ssam } 1006584Ssam 1014926Swnj /* 1024926Swnj * Construct sockaddr format source address. 1034926Swnj * Stuff source address and datagram in user buffer. 1044926Swnj */ 1054926Swnj udp_in.sin_port = ui->ui_sport; 1064926Swnj udp_in.sin_addr = ui->ui_src; 1075050Swnj m->m_len -= sizeof (struct udpiphdr); 1085050Swnj m->m_off += sizeof (struct udpiphdr); 10912767Ssam if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 11012767Ssam m, (struct mbuf *)0) == 0) 1114926Swnj goto bad; 1125050Swnj sorwakeup(inp->inp_socket); 1134887Swnj return; 1144926Swnj bad: 1154887Swnj m_freem(m); 1164784Swnj } 1174784Swnj 1186584Ssam udp_abort(inp) 1196584Ssam struct inpcb *inp; 1206584Ssam { 1216584Ssam struct socket *so = inp->inp_socket; 1226584Ssam 1236584Ssam in_pcbdisconnect(inp); 1246584Ssam soisdisconnected(so); 1256584Ssam } 1266584Ssam 1276591Ssam udp_ctlinput(cmd, arg) 1286591Ssam int cmd; 1296591Ssam caddr_t arg; 1306591Ssam { 1316591Ssam struct in_addr *sin; 1326591Ssam extern u_char inetctlerrmap[]; 1336591Ssam 1346591Ssam if (cmd < 0 || cmd > PRC_NCMDS) 1356591Ssam return; 1366591Ssam switch (cmd) { 1376591Ssam 1386591Ssam case PRC_ROUTEDEAD: 1396591Ssam break; 1406591Ssam 1416591Ssam case PRC_QUENCH: 1426591Ssam break; 1436591Ssam 1446591Ssam /* these are handled by ip */ 1456591Ssam case PRC_IFDOWN: 1466591Ssam case PRC_HOSTDEAD: 1476591Ssam case PRC_HOSTUNREACH: 1486591Ssam break; 1496591Ssam 1506591Ssam default: 1516591Ssam sin = &((struct icmp *)arg)->icmp_ip.ip_dst; 1528641Sroot in_pcbnotify(&udb, sin, (int)inetctlerrmap[cmd], udp_abort); 1536591Ssam } 1546591Ssam } 1556591Ssam 1564955Swnj udp_output(inp, m0) 1574926Swnj struct inpcb *inp; 1584926Swnj struct mbuf *m0; 1594784Swnj { 1604926Swnj register struct mbuf *m; 1614926Swnj register struct udpiphdr *ui; 1627157Swnj register struct socket *so; 1634926Swnj register int len = 0; 16416601Ssam register struct route *ro; 1654784Swnj 1664926Swnj /* 1674926Swnj * Calculate data length and get a mbuf 1685246Sroot * for UDP and IP headers. 1694926Swnj */ 1704926Swnj for (m = m0; m; m = m->m_next) 1714926Swnj len += m->m_len; 1729644Ssam m = m_get(M_DONTWAIT, MT_HEADER); 1736507Ssam if (m == 0) { 1746507Ssam m_freem(m0); 1756507Ssam return (ENOBUFS); 1766507Ssam } 1774784Swnj 1784926Swnj /* 1795246Sroot * Fill in mbuf with extended UDP header 1804926Swnj * and addresses and length put into network format. 1814926Swnj */ 1824926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1834926Swnj m->m_len = sizeof (struct udpiphdr); 1844926Swnj m->m_next = m0; 1854926Swnj ui = mtod(m, struct udpiphdr *); 1864926Swnj ui->ui_next = ui->ui_prev = 0; 1874926Swnj ui->ui_x1 = 0; 1884926Swnj ui->ui_pr = IPPROTO_UDP; 18915226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 1905050Swnj ui->ui_src = inp->inp_laddr; 1915050Swnj ui->ui_dst = inp->inp_faddr; 1925050Swnj ui->ui_sport = inp->inp_lport; 1935050Swnj ui->ui_dport = inp->inp_fport; 19415226Ssam ui->ui_ulen = ui->ui_len; 1954784Swnj 1964926Swnj /* 1974926Swnj * Stuff checksum and output datagram. 1984926Swnj */ 1994926Swnj ui->ui_sum = 0; 20015539Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 20115539Skarels ui->ui_sum = -1; 2025050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 2035050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 2047157Swnj so = inp->inp_socket; 20516601Ssam if (so->so_options & SO_DONTROUTE) 20616601Ssam return (ip_output(m, (struct mbuf *)0, (struct route *)0, 20716799Skarels (so->so_state & SS_PRIV) | IP_ROUTETOIF)); 20816601Ssam /* 20916601Ssam * Use cached route for previous datagram if 21016601Ssam * this is also to the same destination. 21116601Ssam * 21216601Ssam * NB: We don't handle broadcasts because that 21316601Ssam * would require 3 subroutine calls. 21416601Ssam */ 21516601Ssam ro = &inp->inp_route; 21616601Ssam #define satosin(sa) ((struct sockaddr_in *)(sa)) 21716601Ssam if (ro->ro_rt && 21816601Ssam satosin(&ro->ro_dst)->sin_addr.s_addr != ui->ui_dst.s_addr) { 21916601Ssam RTFREE(ro->ro_rt); 22016601Ssam ro->ro_rt = (struct rtentry *)0; 22116601Ssam } 22216601Ssam return (ip_output(m, (struct mbuf *)0, ro, so->so_state & SS_PRIV)); 2234784Swnj } 2244784Swnj 2258602Sroot /*ARGSUSED*/ 22612767Ssam udp_usrreq(so, req, m, nam, rights) 2274887Swnj struct socket *so; 2284784Swnj int req; 22912767Ssam struct mbuf *m, *nam, *rights; 2304784Swnj { 2314887Swnj struct inpcb *inp = sotoinpcb(so); 2326507Ssam int error = 0; 2334784Swnj 23412767Ssam if (rights && rights->m_len) { 23512767Ssam error = EINVAL; 23612767Ssam goto release; 23712767Ssam } 23811080Ssam if (inp == NULL && req != PRU_ATTACH) { 23911080Ssam error = EINVAL; 24011080Ssam goto release; 24111080Ssam } 2424784Swnj switch (req) { 2434784Swnj 2444784Swnj case PRU_ATTACH: 24511080Ssam if (inp != NULL) { 24611080Ssam error = EINVAL; 24711080Ssam break; 24811080Ssam } 2498273Sroot error = in_pcballoc(so, &udb); 2508273Sroot if (error) 2518273Sroot break; 2529032Sroot error = soreserve(so, 2048, 2048); 2538273Sroot if (error) 2548273Sroot break; 2554887Swnj break; 2564784Swnj 2574784Swnj case PRU_DETACH: 25811080Ssam if (inp == NULL) { 25911080Ssam error = ENOTCONN; 26011080Ssam break; 26111080Ssam } 2625166Swnj in_pcbdetach(inp); 2634887Swnj break; 2644784Swnj 2658273Sroot case PRU_BIND: 2668273Sroot error = in_pcbbind(inp, nam); 2678273Sroot break; 2688273Sroot 2698273Sroot case PRU_LISTEN: 2708273Sroot error = EOPNOTSUPP; 2718273Sroot break; 2728273Sroot 2734784Swnj case PRU_CONNECT: 27411080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 27511080Ssam error = EISCONN; 27611080Ssam break; 27711080Ssam } 2788273Sroot error = in_pcbconnect(inp, nam); 2796507Ssam if (error == 0) 2806507Ssam soisconnected(so); 2814887Swnj break; 2824784Swnj 28313118Ssam case PRU_CONNECT2: 28413118Ssam error = EOPNOTSUPP; 28513118Ssam break; 28613118Ssam 2874926Swnj case PRU_ACCEPT: 28811080Ssam error = EOPNOTSUPP; 28911080Ssam break; 2904926Swnj 2914784Swnj case PRU_DISCONNECT: 29211080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 29311080Ssam error = ENOTCONN; 29411080Ssam break; 29511080Ssam } 2965166Swnj in_pcbdisconnect(inp); 2974887Swnj soisdisconnected(so); 2984784Swnj break; 2994784Swnj 3004912Swnj case PRU_SHUTDOWN: 3014912Swnj socantsendmore(so); 3024912Swnj break; 3034912Swnj 3045996Swnj case PRU_SEND: { 3055996Swnj struct in_addr laddr; 30616799Skarels int s; 3075996Swnj 3088273Sroot if (nam) { 3095996Swnj laddr = inp->inp_laddr; 31011080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 31111080Ssam error = EISCONN; 31211080Ssam break; 31311080Ssam } 31416799Skarels /* 31516799Skarels * Must block input while temporarily connected. 31616799Skarels */ 31716799Skarels s = splnet(); 3188273Sroot error = in_pcbconnect(inp, nam); 31916799Skarels if (error) { 32016799Skarels splx(s); 3216507Ssam break; 32216799Skarels } 3234955Swnj } else { 32411080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 32511080Ssam error = ENOTCONN; 32611080Ssam break; 32711080Ssam } 3284955Swnj } 3296507Ssam error = udp_output(inp, m); 33011080Ssam m = NULL; 3318273Sroot if (nam) { 3325166Swnj in_pcbdisconnect(inp); 33316799Skarels splx(s); 3345996Swnj inp->inp_laddr = laddr; 3355996Swnj } 3365996Swnj } 3374784Swnj break; 3384784Swnj 3394784Swnj case PRU_ABORT: 3405166Swnj in_pcbdetach(inp); 3414887Swnj sofree(so); 3424887Swnj soisdisconnected(so); 3434784Swnj break; 3444784Swnj 3456511Ssam case PRU_SOCKADDR: 3468273Sroot in_setsockaddr(inp, nam); 3476511Ssam break; 3486511Ssam 34914124Ssam case PRU_PEERADDR: 35014124Ssam in_setpeeraddr(inp, nam); 35114124Ssam break; 35214124Ssam 353*16988Skarels case PRU_SENSE: 354*16988Skarels /* 355*16988Skarels * stat: don't bother with a blocksize. 356*16988Skarels */ 357*16988Skarels return (0); 358*16988Skarels 35912205Ssam case PRU_SENDOOB: 36012205Ssam case PRU_FASTTIMO: 36112205Ssam case PRU_SLOWTIMO: 36212205Ssam case PRU_PROTORCV: 36312205Ssam case PRU_PROTOSEND: 36412205Ssam error = EOPNOTSUPP; 36512205Ssam break; 36613118Ssam 36716799Skarels case PRU_CONTROL: 36816799Skarels case PRU_RCVD: 36916799Skarels case PRU_RCVOOB: 37016799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 37116799Skarels 37213118Ssam default: 37313118Ssam panic("udp_usrreq"); 3744805Swnj } 37511080Ssam release: 37611080Ssam if (m != NULL) 37711080Ssam m_freem(m); 3786507Ssam return (error); 3794784Swnj } 380