123199Smckusick /* 229158Smckusick * Copyright (c) 1982, 1986 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*31398Skarels * @(#)udp_usrreq.c 7.2 (Berkeley) 06/04/87 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 4126118Skarels #ifndef COMPAT_42 4219519Skarels int udpcksum = 1; 4326118Skarels #else 4426118Skarels int udpcksum = 0; /* XXX */ 4526118Skarels #endif 46*31398Skarels int udp_ttl = UDP_TTL; 4726118Skarels 484926Swnj struct sockaddr_in udp_in = { AF_INET }; 494901Swnj 5026032Skarels udp_input(m0, ifp) 514926Swnj struct mbuf *m0; 5226032Skarels struct ifnet *ifp; 534784Swnj { 544901Swnj register struct udpiphdr *ui; 554887Swnj register struct inpcb *inp; 564926Swnj register struct mbuf *m; 577844Sroot int len; 5824823Skarels struct ip ip; 594784Swnj 604926Swnj /* 615246Sroot * Get IP and UDP header together in first mbuf. 624926Swnj */ 634926Swnj m = m0; 645308Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 655308Sroot (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 664926Swnj udpstat.udps_hdrops++; 675308Sroot return; 684926Swnj } 695050Swnj ui = mtod(m, struct udpiphdr *); 705246Sroot if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 715220Swnj ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 724926Swnj 734926Swnj /* 745246Sroot * Make mbuf data length reflect UDP length. 755246Sroot * If not enough data to reflect UDP length, drop. 764926Swnj */ 777844Sroot len = ntohs((u_short)ui->ui_ulen); 784926Swnj if (((struct ip *)ui)->ip_len != len) { 794926Swnj if (len > ((struct ip *)ui)->ip_len) { 804926Swnj udpstat.udps_badlen++; 814926Swnj goto bad; 824926Swnj } 8315539Skarels m_adj(m, len - ((struct ip *)ui)->ip_len); 8424823Skarels /* ((struct ip *)ui)->ip_len = len; */ 854926Swnj } 8624823Skarels /* 8724823Skarels * Save a copy of the IP header in case we want restore it for ICMP. 8824823Skarels */ 8924823Skarels ip = *(struct ip*)ui; 904926Swnj 914926Swnj /* 925246Sroot * Checksum extended UDP header and data. 934926Swnj */ 9415539Skarels if (udpcksum && ui->ui_sum) { 954926Swnj ui->ui_next = ui->ui_prev = 0; 964926Swnj ui->ui_x1 = 0; 9721112Skarels ui->ui_len = ui->ui_ulen; 987844Sroot if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 994926Swnj udpstat.udps_badsum++; 1004901Swnj m_freem(m); 1014901Swnj return; 1024901Swnj } 1034901Swnj } 1044926Swnj 1054926Swnj /* 1067844Sroot * Locate pcb for datagram. 1074926Swnj */ 1084926Swnj inp = in_pcblookup(&udb, 1096029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 1106029Sroot INPLOOKUP_WILDCARD); 1116584Ssam if (inp == 0) { 11210144Ssam /* don't send ICMP response for broadcast packet */ 11321112Skarels if (in_broadcast(ui->ui_dst)) 1146584Ssam goto bad; 11524823Skarels *(struct ip *)ui = ip; 11626032Skarels icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT, 11726032Skarels ifp); 1186584Ssam return; 1196584Ssam } 1206584Ssam 1214926Swnj /* 1224926Swnj * Construct sockaddr format source address. 1234926Swnj * Stuff source address and datagram in user buffer. 1244926Swnj */ 1254926Swnj udp_in.sin_port = ui->ui_sport; 1264926Swnj udp_in.sin_addr = ui->ui_src; 1275050Swnj m->m_len -= sizeof (struct udpiphdr); 1285050Swnj m->m_off += sizeof (struct udpiphdr); 12912767Ssam if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 13012767Ssam m, (struct mbuf *)0) == 0) 1314926Swnj goto bad; 1325050Swnj sorwakeup(inp->inp_socket); 1334887Swnj return; 1344926Swnj bad: 1354887Swnj m_freem(m); 1364784Swnj } 1374784Swnj 13826426Skarels /* 13926426Skarels * Notify a udp user of an asynchronous error; 14026426Skarels * just wake up so that he can collect error status. 14126426Skarels */ 14226426Skarels udp_notify(inp) 14326426Skarels register struct inpcb *inp; 14426426Skarels { 14526426Skarels 14626426Skarels sorwakeup(inp->inp_socket); 14726426Skarels sowwakeup(inp->inp_socket); 14826426Skarels } 14926426Skarels 15024823Skarels udp_ctlinput(cmd, sa) 1516591Ssam int cmd; 15224823Skarels struct sockaddr *sa; 1536591Ssam { 1546591Ssam extern u_char inetctlerrmap[]; 15524823Skarels struct sockaddr_in *sin; 15621121Skarels int in_rtchange(); 1576591Ssam 15824823Skarels if ((unsigned)cmd > PRC_NCMDS) 1596591Ssam return; 16024823Skarels if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 16124823Skarels return; 16224823Skarels sin = (struct sockaddr_in *)sa; 16324823Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 16424823Skarels return; 16524823Skarels 1666591Ssam switch (cmd) { 1676591Ssam 16824823Skarels case PRC_QUENCH: 1696591Ssam break; 1706591Ssam 17124823Skarels case PRC_ROUTEDEAD: 17221121Skarels case PRC_REDIRECT_NET: 17321121Skarels case PRC_REDIRECT_HOST: 17424823Skarels case PRC_REDIRECT_TOSNET: 17524823Skarels case PRC_REDIRECT_TOSHOST: 17624823Skarels in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange); 1776591Ssam break; 1786591Ssam 1796591Ssam default: 18021121Skarels if (inetctlerrmap[cmd] == 0) 18121121Skarels return; /* XXX */ 18224823Skarels in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd], 18326426Skarels udp_notify); 1846591Ssam } 1856591Ssam } 1866591Ssam 1874955Swnj udp_output(inp, m0) 18826060Skarels register struct inpcb *inp; 1894926Swnj struct mbuf *m0; 1904784Swnj { 1914926Swnj register struct mbuf *m; 1924926Swnj register struct udpiphdr *ui; 19317165Skarels register int len = 0; 1944784Swnj 1954926Swnj /* 1964926Swnj * Calculate data length and get a mbuf 1975246Sroot * for UDP and IP headers. 1984926Swnj */ 1994926Swnj for (m = m0; m; m = m->m_next) 2004926Swnj len += m->m_len; 20121112Skarels MGET(m, M_DONTWAIT, MT_HEADER); 2026507Ssam if (m == 0) { 2036507Ssam m_freem(m0); 2046507Ssam return (ENOBUFS); 2056507Ssam } 2064784Swnj 2074926Swnj /* 2085246Sroot * Fill in mbuf with extended UDP header 2094926Swnj * and addresses and length put into network format. 2104926Swnj */ 2114926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 2124926Swnj m->m_len = sizeof (struct udpiphdr); 2134926Swnj m->m_next = m0; 2144926Swnj ui = mtod(m, struct udpiphdr *); 2154926Swnj ui->ui_next = ui->ui_prev = 0; 2164926Swnj ui->ui_x1 = 0; 2174926Swnj ui->ui_pr = IPPROTO_UDP; 21815226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 2195050Swnj ui->ui_src = inp->inp_laddr; 2205050Swnj ui->ui_dst = inp->inp_faddr; 2215050Swnj ui->ui_sport = inp->inp_lport; 2225050Swnj ui->ui_dport = inp->inp_fport; 22315226Ssam ui->ui_ulen = ui->ui_len; 2244784Swnj 2254926Swnj /* 2264926Swnj * Stuff checksum and output datagram. 2274926Swnj */ 2284926Swnj ui->ui_sum = 0; 22919519Skarels if (udpcksum) { 23019519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 23115539Skarels ui->ui_sum = -1; 23221112Skarels } 2335050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 234*31398Skarels ((struct ip *)ui)->ip_ttl = udp_ttl; 23526060Skarels return (ip_output(m, inp->inp_options, &inp->inp_route, 23626060Skarels inp->inp_socket->so_options & (SO_DONTROUTE | 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: 2785166Swnj in_pcbdetach(inp); 2794887Swnj break; 2804784Swnj 2818273Sroot case PRU_BIND: 2828273Sroot error = in_pcbbind(inp, nam); 2838273Sroot break; 2848273Sroot 2858273Sroot case PRU_LISTEN: 2868273Sroot error = EOPNOTSUPP; 2878273Sroot break; 2888273Sroot 2894784Swnj case PRU_CONNECT: 29011080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 29111080Ssam error = EISCONN; 29211080Ssam break; 29311080Ssam } 2948273Sroot error = in_pcbconnect(inp, nam); 2956507Ssam if (error == 0) 2966507Ssam soisconnected(so); 2974887Swnj break; 2984784Swnj 29913118Ssam case PRU_CONNECT2: 30013118Ssam error = EOPNOTSUPP; 30113118Ssam break; 30213118Ssam 3034926Swnj case PRU_ACCEPT: 30411080Ssam error = EOPNOTSUPP; 30511080Ssam break; 3064926Swnj 3074784Swnj case PRU_DISCONNECT: 30811080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 30911080Ssam error = ENOTCONN; 31011080Ssam break; 31111080Ssam } 3125166Swnj in_pcbdisconnect(inp); 31326404Skarels so->so_state &= ~SS_ISCONNECTED; /* XXX */ 3144784Swnj break; 3154784Swnj 3164912Swnj case PRU_SHUTDOWN: 3174912Swnj socantsendmore(so); 3184912Swnj break; 3194912Swnj 3205996Swnj case PRU_SEND: { 3215996Swnj struct in_addr laddr; 32216799Skarels int s; 3235996Swnj 3248273Sroot if (nam) { 3255996Swnj laddr = inp->inp_laddr; 32611080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 32711080Ssam error = EISCONN; 32811080Ssam break; 32911080Ssam } 33016799Skarels /* 33116799Skarels * Must block input while temporarily connected. 33216799Skarels */ 33316799Skarels s = splnet(); 3348273Sroot error = in_pcbconnect(inp, nam); 33516799Skarels if (error) { 33616799Skarels splx(s); 3376507Ssam break; 33816799Skarels } 3394955Swnj } else { 34011080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 34111080Ssam error = ENOTCONN; 34211080Ssam break; 34311080Ssam } 3444955Swnj } 3456507Ssam error = udp_output(inp, m); 34611080Ssam m = NULL; 3478273Sroot if (nam) { 3485166Swnj in_pcbdisconnect(inp); 34918368Skarels inp->inp_laddr = laddr; 35016799Skarels splx(s); 3515996Swnj } 3525996Swnj } 3534784Swnj break; 3544784Swnj 3554784Swnj case PRU_ABORT: 3565166Swnj in_pcbdetach(inp); 3574887Swnj sofree(so); 3584887Swnj soisdisconnected(so); 3594784Swnj break; 3604784Swnj 3616511Ssam case PRU_SOCKADDR: 3628273Sroot in_setsockaddr(inp, nam); 3636511Ssam break; 3646511Ssam 36514124Ssam case PRU_PEERADDR: 36614124Ssam in_setpeeraddr(inp, nam); 36714124Ssam break; 36814124Ssam 36916988Skarels case PRU_SENSE: 37016988Skarels /* 37116988Skarels * stat: don't bother with a blocksize. 37216988Skarels */ 37316988Skarels return (0); 37416988Skarels 37512205Ssam case PRU_SENDOOB: 37612205Ssam case PRU_FASTTIMO: 37712205Ssam case PRU_SLOWTIMO: 37812205Ssam case PRU_PROTORCV: 37912205Ssam case PRU_PROTOSEND: 38012205Ssam error = EOPNOTSUPP; 38112205Ssam break; 38213118Ssam 38316799Skarels case PRU_RCVD: 38416799Skarels case PRU_RCVOOB: 38516799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 38616799Skarels 38713118Ssam default: 38813118Ssam panic("udp_usrreq"); 3894805Swnj } 39011080Ssam release: 39111080Ssam if (m != NULL) 39211080Ssam m_freem(m); 3936507Ssam return (error); 3944784Swnj } 395