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*24823Skarels * @(#)udp_usrreq.c 6.15 (Berkeley) 09/16/85 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 444926Swnj udp_input(m0) 454926Swnj struct mbuf *m0; 464784Swnj { 474901Swnj register struct udpiphdr *ui; 484887Swnj register struct inpcb *inp; 494926Swnj register struct mbuf *m; 507844Sroot int len; 51*24823Skarels struct ip ip; 524784Swnj 534926Swnj /* 545246Sroot * Get IP and UDP header together in first mbuf. 554926Swnj */ 564926Swnj m = m0; 575308Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 585308Sroot (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 594926Swnj udpstat.udps_hdrops++; 605308Sroot return; 614926Swnj } 625050Swnj ui = mtod(m, struct udpiphdr *); 635246Sroot if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 645220Swnj ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 654926Swnj 664926Swnj /* 675246Sroot * Make mbuf data length reflect UDP length. 685246Sroot * If not enough data to reflect UDP length, drop. 694926Swnj */ 707844Sroot len = ntohs((u_short)ui->ui_ulen); 714926Swnj if (((struct ip *)ui)->ip_len != len) { 724926Swnj if (len > ((struct ip *)ui)->ip_len) { 734926Swnj udpstat.udps_badlen++; 744926Swnj goto bad; 754926Swnj } 7615539Skarels m_adj(m, len - ((struct ip *)ui)->ip_len); 77*24823Skarels /* ((struct ip *)ui)->ip_len = len; */ 784926Swnj } 79*24823Skarels /* 80*24823Skarels * Save a copy of the IP header in case we want restore it for ICMP. 81*24823Skarels */ 82*24823Skarels ip = *(struct ip*)ui; 834926Swnj 844926Swnj /* 855246Sroot * Checksum extended UDP header and data. 864926Swnj */ 8715539Skarels if (udpcksum && ui->ui_sum) { 884926Swnj ui->ui_next = ui->ui_prev = 0; 894926Swnj ui->ui_x1 = 0; 9021112Skarels ui->ui_len = ui->ui_ulen; 917844Sroot if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 924926Swnj udpstat.udps_badsum++; 934901Swnj m_freem(m); 944901Swnj return; 954901Swnj } 964901Swnj } 974926Swnj 984926Swnj /* 997844Sroot * Locate pcb for datagram. 1004926Swnj */ 1014926Swnj inp = in_pcblookup(&udb, 1026029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 1036029Sroot INPLOOKUP_WILDCARD); 1046584Ssam if (inp == 0) { 10510144Ssam /* don't send ICMP response for broadcast packet */ 10621112Skarels if (in_broadcast(ui->ui_dst)) 1076584Ssam goto bad; 108*24823Skarels *(struct ip *)ui = ip; 1096584Ssam icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT); 1106584Ssam return; 1116584Ssam } 1126584Ssam 1134926Swnj /* 1144926Swnj * Construct sockaddr format source address. 1154926Swnj * Stuff source address and datagram in user buffer. 1164926Swnj */ 1174926Swnj udp_in.sin_port = ui->ui_sport; 1184926Swnj udp_in.sin_addr = ui->ui_src; 1195050Swnj m->m_len -= sizeof (struct udpiphdr); 1205050Swnj m->m_off += sizeof (struct udpiphdr); 12112767Ssam if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 12212767Ssam m, (struct mbuf *)0) == 0) 1234926Swnj goto bad; 1245050Swnj sorwakeup(inp->inp_socket); 1254887Swnj return; 1264926Swnj bad: 1274887Swnj m_freem(m); 1284784Swnj } 1294784Swnj 130*24823Skarels udp_ctlinput(cmd, sa) 1316591Ssam int cmd; 132*24823Skarels struct sockaddr *sa; 1336591Ssam { 1346591Ssam extern u_char inetctlerrmap[]; 135*24823Skarels struct sockaddr_in *sin; 13621121Skarels int in_rtchange(); 1376591Ssam 138*24823Skarels if ((unsigned)cmd > PRC_NCMDS) 1396591Ssam return; 140*24823Skarels if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 141*24823Skarels return; 142*24823Skarels sin = (struct sockaddr_in *)sa; 143*24823Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 144*24823Skarels return; 145*24823Skarels 1466591Ssam switch (cmd) { 1476591Ssam 148*24823Skarels case PRC_QUENCH: 1496591Ssam break; 1506591Ssam 151*24823Skarels case PRC_ROUTEDEAD: 15221121Skarels case PRC_REDIRECT_NET: 15321121Skarels case PRC_REDIRECT_HOST: 154*24823Skarels case PRC_REDIRECT_TOSNET: 155*24823Skarels case PRC_REDIRECT_TOSHOST: 156*24823Skarels in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange); 1576591Ssam break; 1586591Ssam 1596591Ssam default: 16021121Skarels if (inetctlerrmap[cmd] == 0) 16121121Skarels return; /* XXX */ 162*24823Skarels in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd], 163*24823Skarels (int (*)())0); 1646591Ssam } 1656591Ssam } 1666591Ssam 1674955Swnj udp_output(inp, m0) 1684926Swnj struct inpcb *inp; 1694926Swnj struct mbuf *m0; 1704784Swnj { 1714926Swnj register struct mbuf *m; 1724926Swnj register struct udpiphdr *ui; 17317165Skarels register struct socket *so; 17417165Skarels register int len = 0; 17516601Ssam register struct route *ro; 1764784Swnj 1774926Swnj /* 1784926Swnj * Calculate data length and get a mbuf 1795246Sroot * for UDP and IP headers. 1804926Swnj */ 1814926Swnj for (m = m0; m; m = m->m_next) 1824926Swnj len += m->m_len; 18321112Skarels MGET(m, M_DONTWAIT, MT_HEADER); 1846507Ssam if (m == 0) { 1856507Ssam m_freem(m0); 1866507Ssam return (ENOBUFS); 1876507Ssam } 1884784Swnj 1894926Swnj /* 1905246Sroot * Fill in mbuf with extended UDP header 1914926Swnj * and addresses and length put into network format. 1924926Swnj */ 1934926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1944926Swnj m->m_len = sizeof (struct udpiphdr); 1954926Swnj m->m_next = m0; 1964926Swnj ui = mtod(m, struct udpiphdr *); 1974926Swnj ui->ui_next = ui->ui_prev = 0; 1984926Swnj ui->ui_x1 = 0; 1994926Swnj ui->ui_pr = IPPROTO_UDP; 20015226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 2015050Swnj ui->ui_src = inp->inp_laddr; 2025050Swnj ui->ui_dst = inp->inp_faddr; 2035050Swnj ui->ui_sport = inp->inp_lport; 2045050Swnj ui->ui_dport = inp->inp_fport; 20515226Ssam ui->ui_ulen = ui->ui_len; 2064784Swnj 2074926Swnj /* 2084926Swnj * Stuff checksum and output datagram. 2094926Swnj */ 2104926Swnj ui->ui_sum = 0; 21119519Skarels if (udpcksum) { 21219519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 21315539Skarels ui->ui_sum = -1; 21421112Skarels } 2155050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 2165050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 21717165Skarels so = inp->inp_socket; 21817165Skarels if (so->so_options & SO_DONTROUTE) 219*24823Skarels return (ip_output(m, inp->inp_options, (struct route *)0, 22017165Skarels (so->so_options & SO_BROADCAST) | IP_ROUTETOIF)); 22117165Skarels /* 22217165Skarels * Use cached route for previous datagram if 22317165Skarels * this is also to the same destination. 22417165Skarels * 22517165Skarels * NB: We don't handle broadcasts because that 22617165Skarels * would require 3 subroutine calls. 22717165Skarels */ 22817165Skarels ro = &inp->inp_route; 22916601Ssam #define satosin(sa) ((struct sockaddr_in *)(sa)) 23017165Skarels if (ro->ro_rt && 23117165Skarels satosin(&ro->ro_dst)->sin_addr.s_addr != ui->ui_dst.s_addr) { 23217165Skarels RTFREE(ro->ro_rt); 23317165Skarels ro->ro_rt = (struct rtentry *)0; 23417165Skarels } 235*24823Skarels return (ip_output(m, inp->inp_options, ro, 23617165Skarels so->so_options & SO_BROADCAST)); 2374784Swnj } 2384784Swnj 23918368Skarels int udp_sendspace = 2048; /* really max datagram size */ 24018368Skarels int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ 24118368Skarels 2428602Sroot /*ARGSUSED*/ 24312767Ssam udp_usrreq(so, req, m, nam, rights) 2444887Swnj struct socket *so; 2454784Swnj int req; 24612767Ssam struct mbuf *m, *nam, *rights; 2474784Swnj { 2484887Swnj struct inpcb *inp = sotoinpcb(so); 2496507Ssam int error = 0; 2504784Swnj 25118368Skarels if (req == PRU_CONTROL) 25218368Skarels return (in_control(so, (int)m, (caddr_t)nam, 25318368Skarels (struct ifnet *)rights)); 25412767Ssam if (rights && rights->m_len) { 25512767Ssam error = EINVAL; 25612767Ssam goto release; 25712767Ssam } 25811080Ssam if (inp == NULL && req != PRU_ATTACH) { 25911080Ssam error = EINVAL; 26011080Ssam goto release; 26111080Ssam } 2624784Swnj switch (req) { 2634784Swnj 2644784Swnj case PRU_ATTACH: 26511080Ssam if (inp != NULL) { 26611080Ssam error = EINVAL; 26711080Ssam break; 26811080Ssam } 2698273Sroot error = in_pcballoc(so, &udb); 2708273Sroot if (error) 2718273Sroot break; 27218368Skarels error = soreserve(so, udp_sendspace, udp_recvspace); 2738273Sroot if (error) 2748273Sroot break; 2754887Swnj break; 2764784Swnj 2774784Swnj case PRU_DETACH: 27811080Ssam if (inp == NULL) { 27911080Ssam error = ENOTCONN; 28011080Ssam break; 28111080Ssam } 2825166Swnj in_pcbdetach(inp); 2834887Swnj break; 2844784Swnj 2858273Sroot case PRU_BIND: 2868273Sroot error = in_pcbbind(inp, nam); 2878273Sroot break; 2888273Sroot 2898273Sroot case PRU_LISTEN: 2908273Sroot error = EOPNOTSUPP; 2918273Sroot break; 2928273Sroot 2934784Swnj case PRU_CONNECT: 29411080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 29511080Ssam error = EISCONN; 29611080Ssam break; 29711080Ssam } 2988273Sroot error = in_pcbconnect(inp, nam); 2996507Ssam if (error == 0) 3006507Ssam soisconnected(so); 3014887Swnj break; 3024784Swnj 30313118Ssam case PRU_CONNECT2: 30413118Ssam error = EOPNOTSUPP; 30513118Ssam break; 30613118Ssam 3074926Swnj case PRU_ACCEPT: 30811080Ssam error = EOPNOTSUPP; 30911080Ssam break; 3104926Swnj 3114784Swnj case PRU_DISCONNECT: 31211080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 31311080Ssam error = ENOTCONN; 31411080Ssam break; 31511080Ssam } 3165166Swnj in_pcbdisconnect(inp); 3174887Swnj soisdisconnected(so); 3184784Swnj break; 3194784Swnj 3204912Swnj case PRU_SHUTDOWN: 3214912Swnj socantsendmore(so); 3224912Swnj break; 3234912Swnj 3245996Swnj case PRU_SEND: { 3255996Swnj struct in_addr laddr; 32616799Skarels int s; 3275996Swnj 3288273Sroot if (nam) { 3295996Swnj laddr = inp->inp_laddr; 33011080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 33111080Ssam error = EISCONN; 33211080Ssam break; 33311080Ssam } 33416799Skarels /* 33516799Skarels * Must block input while temporarily connected. 33616799Skarels */ 33716799Skarels s = splnet(); 3388273Sroot error = in_pcbconnect(inp, nam); 33916799Skarels if (error) { 34016799Skarels splx(s); 3416507Ssam break; 34216799Skarels } 3434955Swnj } else { 34411080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 34511080Ssam error = ENOTCONN; 34611080Ssam break; 34711080Ssam } 3484955Swnj } 3496507Ssam error = udp_output(inp, m); 35011080Ssam m = NULL; 3518273Sroot if (nam) { 3525166Swnj in_pcbdisconnect(inp); 35318368Skarels inp->inp_laddr = laddr; 35416799Skarels splx(s); 3555996Swnj } 3565996Swnj } 3574784Swnj break; 3584784Swnj 3594784Swnj case PRU_ABORT: 3605166Swnj in_pcbdetach(inp); 3614887Swnj sofree(so); 3624887Swnj soisdisconnected(so); 3634784Swnj break; 3644784Swnj 3656511Ssam case PRU_SOCKADDR: 3668273Sroot in_setsockaddr(inp, nam); 3676511Ssam break; 3686511Ssam 36914124Ssam case PRU_PEERADDR: 37014124Ssam in_setpeeraddr(inp, nam); 37114124Ssam break; 37214124Ssam 37316988Skarels case PRU_SENSE: 37416988Skarels /* 37516988Skarels * stat: don't bother with a blocksize. 37616988Skarels */ 37716988Skarels return (0); 37816988Skarels 37912205Ssam case PRU_SENDOOB: 38012205Ssam case PRU_FASTTIMO: 38112205Ssam case PRU_SLOWTIMO: 38212205Ssam case PRU_PROTORCV: 38312205Ssam case PRU_PROTOSEND: 38412205Ssam error = EOPNOTSUPP; 38512205Ssam break; 38613118Ssam 38716799Skarels case PRU_RCVD: 38816799Skarels case PRU_RCVOOB: 38916799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 39016799Skarels 39113118Ssam default: 39213118Ssam panic("udp_usrreq"); 3934805Swnj } 39411080Ssam release: 39511080Ssam if (m != NULL) 39611080Ssam m_freem(m); 3976507Ssam return (error); 3984784Swnj } 399