123199Smckusick /* 223199Smckusick * Copyright (c) 1982 Regents of the University of California. 323199Smckusick * All rights reserved. The Berkeley software License Agreement 423199Smckusick * specifies the terms and conditions for redistribution. 523199Smckusick * 6*26032Skarels * @(#)udp_usrreq.c 6.16 (Berkeley) 02/02/86 723199Smckusick */ 84784Swnj 917065Sbloom #include "param.h" 1017065Sbloom #include "dir.h" 1117065Sbloom #include "user.h" 1217065Sbloom #include "mbuf.h" 1317065Sbloom #include "protosw.h" 1417065Sbloom #include "socket.h" 1517065Sbloom #include "socketvar.h" 1617065Sbloom #include "errno.h" 1717065Sbloom #include "stat.h" 1810897Ssam 196584Ssam #include "../net/if.h" 206354Ssam #include "../net/route.h" 2110897Ssam 2217065Sbloom #include "in.h" 2317065Sbloom #include "in_pcb.h" 2417065Sbloom #include "in_systm.h" 2517065Sbloom #include "ip.h" 2617065Sbloom #include "ip_var.h" 2717065Sbloom #include "ip_icmp.h" 2817065Sbloom #include "udp.h" 2917065Sbloom #include "udp_var.h" 304784Swnj 314926Swnj /* 324926Swnj * UDP protocol implementation. 334926Swnj * Per RFC 768, August, 1980. 344926Swnj */ 354805Swnj udp_init() 364805Swnj { 374805Swnj 384901Swnj udb.inp_next = udb.inp_prev = &udb; 394805Swnj } 404805Swnj 4119519Skarels int udpcksum = 1; 424926Swnj struct sockaddr_in udp_in = { AF_INET }; 434901Swnj 44*26032Skarels udp_input(m0, ifp) 454926Swnj struct mbuf *m0; 46*26032Skarels struct ifnet *ifp; 474784Swnj { 484901Swnj register struct udpiphdr *ui; 494887Swnj register struct inpcb *inp; 504926Swnj register struct mbuf *m; 517844Sroot int len; 5224823Skarels struct ip ip; 534784Swnj 544926Swnj /* 555246Sroot * Get IP and UDP header together in first mbuf. 564926Swnj */ 574926Swnj m = m0; 585308Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 595308Sroot (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 604926Swnj udpstat.udps_hdrops++; 615308Sroot return; 624926Swnj } 635050Swnj ui = mtod(m, struct udpiphdr *); 645246Sroot if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 655220Swnj ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 664926Swnj 674926Swnj /* 685246Sroot * Make mbuf data length reflect UDP length. 695246Sroot * If not enough data to reflect UDP length, drop. 704926Swnj */ 717844Sroot len = ntohs((u_short)ui->ui_ulen); 724926Swnj if (((struct ip *)ui)->ip_len != len) { 734926Swnj if (len > ((struct ip *)ui)->ip_len) { 744926Swnj udpstat.udps_badlen++; 754926Swnj goto bad; 764926Swnj } 7715539Skarels m_adj(m, len - ((struct ip *)ui)->ip_len); 7824823Skarels /* ((struct ip *)ui)->ip_len = len; */ 794926Swnj } 8024823Skarels /* 8124823Skarels * Save a copy of the IP header in case we want restore it for ICMP. 8224823Skarels */ 8324823Skarels ip = *(struct ip*)ui; 844926Swnj 854926Swnj /* 865246Sroot * Checksum extended UDP header and data. 874926Swnj */ 8815539Skarels if (udpcksum && ui->ui_sum) { 894926Swnj ui->ui_next = ui->ui_prev = 0; 904926Swnj ui->ui_x1 = 0; 9121112Skarels ui->ui_len = ui->ui_ulen; 927844Sroot if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 934926Swnj udpstat.udps_badsum++; 944901Swnj m_freem(m); 954901Swnj return; 964901Swnj } 974901Swnj } 984926Swnj 994926Swnj /* 1007844Sroot * Locate pcb for datagram. 1014926Swnj */ 1024926Swnj inp = in_pcblookup(&udb, 1036029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 1046029Sroot INPLOOKUP_WILDCARD); 1056584Ssam if (inp == 0) { 10610144Ssam /* don't send ICMP response for broadcast packet */ 10721112Skarels if (in_broadcast(ui->ui_dst)) 1086584Ssam goto bad; 10924823Skarels *(struct ip *)ui = ip; 110*26032Skarels icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT, 111*26032Skarels ifp); 1126584Ssam return; 1136584Ssam } 1146584Ssam 1154926Swnj /* 1164926Swnj * Construct sockaddr format source address. 1174926Swnj * Stuff source address and datagram in user buffer. 1184926Swnj */ 1194926Swnj udp_in.sin_port = ui->ui_sport; 1204926Swnj udp_in.sin_addr = ui->ui_src; 1215050Swnj m->m_len -= sizeof (struct udpiphdr); 1225050Swnj m->m_off += sizeof (struct udpiphdr); 12312767Ssam if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 12412767Ssam m, (struct mbuf *)0) == 0) 1254926Swnj goto bad; 1265050Swnj sorwakeup(inp->inp_socket); 1274887Swnj return; 1284926Swnj bad: 1294887Swnj m_freem(m); 1304784Swnj } 1314784Swnj 13224823Skarels udp_ctlinput(cmd, sa) 1336591Ssam int cmd; 13424823Skarels struct sockaddr *sa; 1356591Ssam { 1366591Ssam extern u_char inetctlerrmap[]; 13724823Skarels struct sockaddr_in *sin; 13821121Skarels int in_rtchange(); 1396591Ssam 14024823Skarels if ((unsigned)cmd > PRC_NCMDS) 1416591Ssam return; 14224823Skarels if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 14324823Skarels return; 14424823Skarels sin = (struct sockaddr_in *)sa; 14524823Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 14624823Skarels return; 14724823Skarels 1486591Ssam switch (cmd) { 1496591Ssam 15024823Skarels case PRC_QUENCH: 1516591Ssam break; 1526591Ssam 15324823Skarels case PRC_ROUTEDEAD: 15421121Skarels case PRC_REDIRECT_NET: 15521121Skarels case PRC_REDIRECT_HOST: 15624823Skarels case PRC_REDIRECT_TOSNET: 15724823Skarels case PRC_REDIRECT_TOSHOST: 15824823Skarels in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange); 1596591Ssam break; 1606591Ssam 1616591Ssam default: 16221121Skarels if (inetctlerrmap[cmd] == 0) 16321121Skarels return; /* XXX */ 16424823Skarels in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd], 16524823Skarels (int (*)())0); 1666591Ssam } 1676591Ssam } 1686591Ssam 1694955Swnj udp_output(inp, m0) 1704926Swnj struct inpcb *inp; 1714926Swnj struct mbuf *m0; 1724784Swnj { 1734926Swnj register struct mbuf *m; 1744926Swnj register struct udpiphdr *ui; 17517165Skarels register struct socket *so; 17617165Skarels register int len = 0; 17716601Ssam register struct route *ro; 1784784Swnj 1794926Swnj /* 1804926Swnj * Calculate data length and get a mbuf 1815246Sroot * for UDP and IP headers. 1824926Swnj */ 1834926Swnj for (m = m0; m; m = m->m_next) 1844926Swnj len += m->m_len; 18521112Skarels MGET(m, M_DONTWAIT, MT_HEADER); 1866507Ssam if (m == 0) { 1876507Ssam m_freem(m0); 1886507Ssam return (ENOBUFS); 1896507Ssam } 1904784Swnj 1914926Swnj /* 1925246Sroot * Fill in mbuf with extended UDP header 1934926Swnj * and addresses and length put into network format. 1944926Swnj */ 1954926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1964926Swnj m->m_len = sizeof (struct udpiphdr); 1974926Swnj m->m_next = m0; 1984926Swnj ui = mtod(m, struct udpiphdr *); 1994926Swnj ui->ui_next = ui->ui_prev = 0; 2004926Swnj ui->ui_x1 = 0; 2014926Swnj ui->ui_pr = IPPROTO_UDP; 20215226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 2035050Swnj ui->ui_src = inp->inp_laddr; 2045050Swnj ui->ui_dst = inp->inp_faddr; 2055050Swnj ui->ui_sport = inp->inp_lport; 2065050Swnj ui->ui_dport = inp->inp_fport; 20715226Ssam ui->ui_ulen = ui->ui_len; 2084784Swnj 2094926Swnj /* 2104926Swnj * Stuff checksum and output datagram. 2114926Swnj */ 2124926Swnj ui->ui_sum = 0; 21319519Skarels if (udpcksum) { 21419519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 21515539Skarels ui->ui_sum = -1; 21621112Skarels } 2175050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 2185050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 21917165Skarels so = inp->inp_socket; 22017165Skarels if (so->so_options & SO_DONTROUTE) 22124823Skarels return (ip_output(m, inp->inp_options, (struct route *)0, 22217165Skarels (so->so_options & SO_BROADCAST) | IP_ROUTETOIF)); 22317165Skarels /* 22417165Skarels * Use cached route for previous datagram if 22517165Skarels * this is also to the same destination. 22617165Skarels * 22717165Skarels * NB: We don't handle broadcasts because that 22817165Skarels * would require 3 subroutine calls. 22917165Skarels */ 23017165Skarels ro = &inp->inp_route; 23116601Ssam #define satosin(sa) ((struct sockaddr_in *)(sa)) 23217165Skarels if (ro->ro_rt && 23317165Skarels satosin(&ro->ro_dst)->sin_addr.s_addr != ui->ui_dst.s_addr) { 23417165Skarels RTFREE(ro->ro_rt); 23517165Skarels ro->ro_rt = (struct rtentry *)0; 23617165Skarels } 23724823Skarels return (ip_output(m, inp->inp_options, ro, 23817165Skarels so->so_options & SO_BROADCAST)); 2394784Swnj } 2404784Swnj 24118368Skarels int udp_sendspace = 2048; /* really max datagram size */ 24218368Skarels int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ 24318368Skarels 2448602Sroot /*ARGSUSED*/ 24512767Ssam udp_usrreq(so, req, m, nam, rights) 2464887Swnj struct socket *so; 2474784Swnj int req; 24812767Ssam struct mbuf *m, *nam, *rights; 2494784Swnj { 2504887Swnj struct inpcb *inp = sotoinpcb(so); 2516507Ssam int error = 0; 2524784Swnj 25318368Skarels if (req == PRU_CONTROL) 25418368Skarels return (in_control(so, (int)m, (caddr_t)nam, 25518368Skarels (struct ifnet *)rights)); 25612767Ssam if (rights && rights->m_len) { 25712767Ssam error = EINVAL; 25812767Ssam goto release; 25912767Ssam } 26011080Ssam if (inp == NULL && req != PRU_ATTACH) { 26111080Ssam error = EINVAL; 26211080Ssam goto release; 26311080Ssam } 2644784Swnj switch (req) { 2654784Swnj 2664784Swnj case PRU_ATTACH: 26711080Ssam if (inp != NULL) { 26811080Ssam error = EINVAL; 26911080Ssam break; 27011080Ssam } 2718273Sroot error = in_pcballoc(so, &udb); 2728273Sroot if (error) 2738273Sroot break; 27418368Skarels error = soreserve(so, udp_sendspace, udp_recvspace); 2758273Sroot if (error) 2768273Sroot break; 2774887Swnj break; 2784784Swnj 2794784Swnj case PRU_DETACH: 28011080Ssam if (inp == NULL) { 28111080Ssam error = ENOTCONN; 28211080Ssam break; 28311080Ssam } 2845166Swnj in_pcbdetach(inp); 2854887Swnj break; 2864784Swnj 2878273Sroot case PRU_BIND: 2888273Sroot error = in_pcbbind(inp, nam); 2898273Sroot break; 2908273Sroot 2918273Sroot case PRU_LISTEN: 2928273Sroot error = EOPNOTSUPP; 2938273Sroot break; 2948273Sroot 2954784Swnj case PRU_CONNECT: 29611080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 29711080Ssam error = EISCONN; 29811080Ssam break; 29911080Ssam } 3008273Sroot error = in_pcbconnect(inp, nam); 3016507Ssam if (error == 0) 3026507Ssam soisconnected(so); 3034887Swnj break; 3044784Swnj 30513118Ssam case PRU_CONNECT2: 30613118Ssam error = EOPNOTSUPP; 30713118Ssam break; 30813118Ssam 3094926Swnj case PRU_ACCEPT: 31011080Ssam error = EOPNOTSUPP; 31111080Ssam break; 3124926Swnj 3134784Swnj case PRU_DISCONNECT: 31411080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 31511080Ssam error = ENOTCONN; 31611080Ssam break; 31711080Ssam } 3185166Swnj in_pcbdisconnect(inp); 3194887Swnj soisdisconnected(so); 3204784Swnj break; 3214784Swnj 3224912Swnj case PRU_SHUTDOWN: 3234912Swnj socantsendmore(so); 3244912Swnj break; 3254912Swnj 3265996Swnj case PRU_SEND: { 3275996Swnj struct in_addr laddr; 32816799Skarels int s; 3295996Swnj 3308273Sroot if (nam) { 3315996Swnj laddr = inp->inp_laddr; 33211080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 33311080Ssam error = EISCONN; 33411080Ssam break; 33511080Ssam } 33616799Skarels /* 33716799Skarels * Must block input while temporarily connected. 33816799Skarels */ 33916799Skarels s = splnet(); 3408273Sroot error = in_pcbconnect(inp, nam); 34116799Skarels if (error) { 34216799Skarels splx(s); 3436507Ssam break; 34416799Skarels } 3454955Swnj } else { 34611080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 34711080Ssam error = ENOTCONN; 34811080Ssam break; 34911080Ssam } 3504955Swnj } 3516507Ssam error = udp_output(inp, m); 35211080Ssam m = NULL; 3538273Sroot if (nam) { 3545166Swnj in_pcbdisconnect(inp); 35518368Skarels inp->inp_laddr = laddr; 35616799Skarels splx(s); 3575996Swnj } 3585996Swnj } 3594784Swnj break; 3604784Swnj 3614784Swnj case PRU_ABORT: 3625166Swnj in_pcbdetach(inp); 3634887Swnj sofree(so); 3644887Swnj soisdisconnected(so); 3654784Swnj break; 3664784Swnj 3676511Ssam case PRU_SOCKADDR: 3688273Sroot in_setsockaddr(inp, nam); 3696511Ssam break; 3706511Ssam 37114124Ssam case PRU_PEERADDR: 37214124Ssam in_setpeeraddr(inp, nam); 37314124Ssam break; 37414124Ssam 37516988Skarels case PRU_SENSE: 37616988Skarels /* 37716988Skarels * stat: don't bother with a blocksize. 37816988Skarels */ 37916988Skarels return (0); 38016988Skarels 38112205Ssam case PRU_SENDOOB: 38212205Ssam case PRU_FASTTIMO: 38312205Ssam case PRU_SLOWTIMO: 38412205Ssam case PRU_PROTORCV: 38512205Ssam case PRU_PROTOSEND: 38612205Ssam error = EOPNOTSUPP; 38712205Ssam break; 38813118Ssam 38916799Skarels case PRU_RCVD: 39016799Skarels case PRU_RCVOOB: 39116799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 39216799Skarels 39313118Ssam default: 39413118Ssam panic("udp_usrreq"); 3954805Swnj } 39611080Ssam release: 39711080Ssam if (m != NULL) 39811080Ssam m_freem(m); 3996507Ssam return (error); 4004784Swnj } 401