1*21121Skarels /* udp_usrreq.c 6.13 85/05/28 */ 24784Swnj 317065Sbloom #include "param.h" 417065Sbloom #include "dir.h" 517065Sbloom #include "user.h" 617065Sbloom #include "mbuf.h" 717065Sbloom #include "protosw.h" 817065Sbloom #include "socket.h" 917065Sbloom #include "socketvar.h" 1017065Sbloom #include "errno.h" 1117065Sbloom #include "stat.h" 1210897Ssam 136584Ssam #include "../net/if.h" 146354Ssam #include "../net/route.h" 1510897Ssam 1617065Sbloom #include "in.h" 1717065Sbloom #include "in_pcb.h" 1817065Sbloom #include "in_systm.h" 1917065Sbloom #include "ip.h" 2017065Sbloom #include "ip_var.h" 2117065Sbloom #include "ip_icmp.h" 2217065Sbloom #include "udp.h" 2317065Sbloom #include "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 3519519Skarels int udpcksum = 1; 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; 7921112Skarels ui->ui_len = ui->ui_ulen; 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 */ 9521112Skarels if (in_broadcast(ui->ui_dst)) 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 { 131*21121Skarels struct in_addr *in; 1326591Ssam extern u_char inetctlerrmap[]; 133*21121Skarels int in_rtchange(); 1346591Ssam 1356591Ssam if (cmd < 0 || cmd > PRC_NCMDS) 1366591Ssam return; 1376591Ssam switch (cmd) { 1386591Ssam 1396591Ssam case PRC_ROUTEDEAD: 1406591Ssam break; 1416591Ssam 142*21121Skarels case PRC_REDIRECT_NET: 143*21121Skarels case PRC_REDIRECT_HOST: 144*21121Skarels in = &((struct icmp *)arg)->icmp_ip.ip_dst; 145*21121Skarels in_pcbnotify(&udb, in, 0, in_rtchange); 1466591Ssam break; 1476591Ssam 1486591Ssam case PRC_IFDOWN: 149*21121Skarels in = &((struct sockaddr_in *)arg)->sin_addr; 150*21121Skarels goto notify; 151*21121Skarels 1526591Ssam case PRC_HOSTDEAD: 1536591Ssam case PRC_HOSTUNREACH: 154*21121Skarels in = (struct in_addr *)arg; 155*21121Skarels goto notify; 1566591Ssam 1576591Ssam default: 158*21121Skarels if (inetctlerrmap[cmd] == 0) 159*21121Skarels return; /* XXX */ 160*21121Skarels in = &((struct icmp *)arg)->icmp_ip.ip_dst; 161*21121Skarels notify: 162*21121Skarels in_pcbnotify(&udb, in, (int)inetctlerrmap[cmd], udp_abort); 1636591Ssam } 1646591Ssam } 1656591Ssam 1664955Swnj udp_output(inp, m0) 1674926Swnj struct inpcb *inp; 1684926Swnj struct mbuf *m0; 1694784Swnj { 1704926Swnj register struct mbuf *m; 1714926Swnj register struct udpiphdr *ui; 17217165Skarels register struct socket *so; 17317165Skarels register int len = 0; 17416601Ssam register struct route *ro; 1754784Swnj 1764926Swnj /* 1774926Swnj * Calculate data length and get a mbuf 1785246Sroot * for UDP and IP headers. 1794926Swnj */ 1804926Swnj for (m = m0; m; m = m->m_next) 1814926Swnj len += m->m_len; 18221112Skarels MGET(m, M_DONTWAIT, MT_HEADER); 1836507Ssam if (m == 0) { 1846507Ssam m_freem(m0); 1856507Ssam return (ENOBUFS); 1866507Ssam } 1874784Swnj 1884926Swnj /* 1895246Sroot * Fill in mbuf with extended UDP header 1904926Swnj * and addresses and length put into network format. 1914926Swnj */ 1924926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1934926Swnj m->m_len = sizeof (struct udpiphdr); 1944926Swnj m->m_next = m0; 1954926Swnj ui = mtod(m, struct udpiphdr *); 1964926Swnj ui->ui_next = ui->ui_prev = 0; 1974926Swnj ui->ui_x1 = 0; 1984926Swnj ui->ui_pr = IPPROTO_UDP; 19915226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 2005050Swnj ui->ui_src = inp->inp_laddr; 2015050Swnj ui->ui_dst = inp->inp_faddr; 2025050Swnj ui->ui_sport = inp->inp_lport; 2035050Swnj ui->ui_dport = inp->inp_fport; 20415226Ssam ui->ui_ulen = ui->ui_len; 2054784Swnj 2064926Swnj /* 2074926Swnj * Stuff checksum and output datagram. 2084926Swnj */ 2094926Swnj ui->ui_sum = 0; 21019519Skarels if (udpcksum) { 21119519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 21215539Skarels ui->ui_sum = -1; 21321112Skarels } 2145050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 2155050Swnj ((struct ip *)ui)->ip_ttl = MAXTTL; 21617165Skarels so = inp->inp_socket; 21717165Skarels if (so->so_options & SO_DONTROUTE) 21817165Skarels return (ip_output(m, (struct mbuf *)0, (struct route *)0, 21917165Skarels (so->so_options & SO_BROADCAST) | IP_ROUTETOIF)); 22017165Skarels /* 22117165Skarels * Use cached route for previous datagram if 22217165Skarels * this is also to the same destination. 22317165Skarels * 22417165Skarels * NB: We don't handle broadcasts because that 22517165Skarels * would require 3 subroutine calls. 22617165Skarels */ 22717165Skarels ro = &inp->inp_route; 22816601Ssam #define satosin(sa) ((struct sockaddr_in *)(sa)) 22917165Skarels if (ro->ro_rt && 23017165Skarels satosin(&ro->ro_dst)->sin_addr.s_addr != ui->ui_dst.s_addr) { 23117165Skarels RTFREE(ro->ro_rt); 23217165Skarels ro->ro_rt = (struct rtentry *)0; 23317165Skarels } 23417165Skarels return (ip_output(m, (struct mbuf *)0, ro, 23517165Skarels so->so_options & SO_BROADCAST)); 2364784Swnj } 2374784Swnj 23818368Skarels int udp_sendspace = 2048; /* really max datagram size */ 23918368Skarels int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ 24018368Skarels 2418602Sroot /*ARGSUSED*/ 24212767Ssam udp_usrreq(so, req, m, nam, rights) 2434887Swnj struct socket *so; 2444784Swnj int req; 24512767Ssam struct mbuf *m, *nam, *rights; 2464784Swnj { 2474887Swnj struct inpcb *inp = sotoinpcb(so); 2486507Ssam int error = 0; 2494784Swnj 25018368Skarels if (req == PRU_CONTROL) 25118368Skarels return (in_control(so, (int)m, (caddr_t)nam, 25218368Skarels (struct ifnet *)rights)); 25312767Ssam if (rights && rights->m_len) { 25412767Ssam error = EINVAL; 25512767Ssam goto release; 25612767Ssam } 25711080Ssam if (inp == NULL && req != PRU_ATTACH) { 25811080Ssam error = EINVAL; 25911080Ssam goto release; 26011080Ssam } 2614784Swnj switch (req) { 2624784Swnj 2634784Swnj case PRU_ATTACH: 26411080Ssam if (inp != NULL) { 26511080Ssam error = EINVAL; 26611080Ssam break; 26711080Ssam } 2688273Sroot error = in_pcballoc(so, &udb); 2698273Sroot if (error) 2708273Sroot break; 27118368Skarels error = soreserve(so, udp_sendspace, udp_recvspace); 2728273Sroot if (error) 2738273Sroot break; 2744887Swnj break; 2754784Swnj 2764784Swnj case PRU_DETACH: 27711080Ssam if (inp == NULL) { 27811080Ssam error = ENOTCONN; 27911080Ssam break; 28011080Ssam } 2815166Swnj in_pcbdetach(inp); 2824887Swnj break; 2834784Swnj 2848273Sroot case PRU_BIND: 2858273Sroot error = in_pcbbind(inp, nam); 2868273Sroot break; 2878273Sroot 2888273Sroot case PRU_LISTEN: 2898273Sroot error = EOPNOTSUPP; 2908273Sroot break; 2918273Sroot 2924784Swnj case PRU_CONNECT: 29311080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 29411080Ssam error = EISCONN; 29511080Ssam break; 29611080Ssam } 2978273Sroot error = in_pcbconnect(inp, nam); 2986507Ssam if (error == 0) 2996507Ssam soisconnected(so); 3004887Swnj break; 3014784Swnj 30213118Ssam case PRU_CONNECT2: 30313118Ssam error = EOPNOTSUPP; 30413118Ssam break; 30513118Ssam 3064926Swnj case PRU_ACCEPT: 30711080Ssam error = EOPNOTSUPP; 30811080Ssam break; 3094926Swnj 3104784Swnj case PRU_DISCONNECT: 31111080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 31211080Ssam error = ENOTCONN; 31311080Ssam break; 31411080Ssam } 3155166Swnj in_pcbdisconnect(inp); 3164887Swnj soisdisconnected(so); 3174784Swnj break; 3184784Swnj 3194912Swnj case PRU_SHUTDOWN: 3204912Swnj socantsendmore(so); 3214912Swnj break; 3224912Swnj 3235996Swnj case PRU_SEND: { 3245996Swnj struct in_addr laddr; 32516799Skarels int s; 3265996Swnj 3278273Sroot if (nam) { 3285996Swnj laddr = inp->inp_laddr; 32911080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 33011080Ssam error = EISCONN; 33111080Ssam break; 33211080Ssam } 33316799Skarels /* 33416799Skarels * Must block input while temporarily connected. 33516799Skarels */ 33616799Skarels s = splnet(); 3378273Sroot error = in_pcbconnect(inp, nam); 33816799Skarels if (error) { 33916799Skarels splx(s); 3406507Ssam break; 34116799Skarels } 3424955Swnj } else { 34311080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 34411080Ssam error = ENOTCONN; 34511080Ssam break; 34611080Ssam } 3474955Swnj } 3486507Ssam error = udp_output(inp, m); 34911080Ssam m = NULL; 3508273Sroot if (nam) { 3515166Swnj in_pcbdisconnect(inp); 35218368Skarels inp->inp_laddr = laddr; 35316799Skarels splx(s); 3545996Swnj } 3555996Swnj } 3564784Swnj break; 3574784Swnj 3584784Swnj case PRU_ABORT: 3595166Swnj in_pcbdetach(inp); 3604887Swnj sofree(so); 3614887Swnj soisdisconnected(so); 3624784Swnj break; 3634784Swnj 3646511Ssam case PRU_SOCKADDR: 3658273Sroot in_setsockaddr(inp, nam); 3666511Ssam break; 3676511Ssam 36814124Ssam case PRU_PEERADDR: 36914124Ssam in_setpeeraddr(inp, nam); 37014124Ssam break; 37114124Ssam 37216988Skarels case PRU_SENSE: 37316988Skarels /* 37416988Skarels * stat: don't bother with a blocksize. 37516988Skarels */ 37616988Skarels return (0); 37716988Skarels 37812205Ssam case PRU_SENDOOB: 37912205Ssam case PRU_FASTTIMO: 38012205Ssam case PRU_SLOWTIMO: 38112205Ssam case PRU_PROTORCV: 38212205Ssam case PRU_PROTOSEND: 38312205Ssam error = EOPNOTSUPP; 38412205Ssam break; 38513118Ssam 38616799Skarels case PRU_RCVD: 38716799Skarels case PRU_RCVOOB: 38816799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 38916799Skarels 39013118Ssam default: 39113118Ssam panic("udp_usrreq"); 3924805Swnj } 39311080Ssam release: 39411080Ssam if (m != NULL) 39511080Ssam m_freem(m); 3966507Ssam return (error); 3974784Swnj } 398