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*26118Skarels * @(#)udp_usrreq.c 6.19 (Berkeley) 02/08/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 41*26118Skarels #ifndef COMPAT_42 4219519Skarels int udpcksum = 1; 43*26118Skarels #else 44*26118Skarels int udpcksum = 0; /* XXX */ 45*26118Skarels #endif 46*26118Skarels 474926Swnj struct sockaddr_in udp_in = { AF_INET }; 484901Swnj 4926032Skarels udp_input(m0, ifp) 504926Swnj struct mbuf *m0; 5126032Skarels struct ifnet *ifp; 524784Swnj { 534901Swnj register struct udpiphdr *ui; 544887Swnj register struct inpcb *inp; 554926Swnj register struct mbuf *m; 567844Sroot int len; 5724823Skarels struct ip ip; 584784Swnj 594926Swnj /* 605246Sroot * Get IP and UDP header together in first mbuf. 614926Swnj */ 624926Swnj m = m0; 635308Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 645308Sroot (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 654926Swnj udpstat.udps_hdrops++; 665308Sroot return; 674926Swnj } 685050Swnj ui = mtod(m, struct udpiphdr *); 695246Sroot if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 705220Swnj ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 714926Swnj 724926Swnj /* 735246Sroot * Make mbuf data length reflect UDP length. 745246Sroot * If not enough data to reflect UDP length, drop. 754926Swnj */ 767844Sroot len = ntohs((u_short)ui->ui_ulen); 774926Swnj if (((struct ip *)ui)->ip_len != len) { 784926Swnj if (len > ((struct ip *)ui)->ip_len) { 794926Swnj udpstat.udps_badlen++; 804926Swnj goto bad; 814926Swnj } 8215539Skarels m_adj(m, len - ((struct ip *)ui)->ip_len); 8324823Skarels /* ((struct ip *)ui)->ip_len = len; */ 844926Swnj } 8524823Skarels /* 8624823Skarels * Save a copy of the IP header in case we want restore it for ICMP. 8724823Skarels */ 8824823Skarels ip = *(struct ip*)ui; 894926Swnj 904926Swnj /* 915246Sroot * Checksum extended UDP header and data. 924926Swnj */ 9315539Skarels if (udpcksum && ui->ui_sum) { 944926Swnj ui->ui_next = ui->ui_prev = 0; 954926Swnj ui->ui_x1 = 0; 9621112Skarels ui->ui_len = ui->ui_ulen; 977844Sroot if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 984926Swnj udpstat.udps_badsum++; 994901Swnj m_freem(m); 1004901Swnj return; 1014901Swnj } 1024901Swnj } 1034926Swnj 1044926Swnj /* 1057844Sroot * Locate pcb for datagram. 1064926Swnj */ 1074926Swnj inp = in_pcblookup(&udb, 1086029Sroot ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 1096029Sroot INPLOOKUP_WILDCARD); 1106584Ssam if (inp == 0) { 11110144Ssam /* don't send ICMP response for broadcast packet */ 11221112Skarels if (in_broadcast(ui->ui_dst)) 1136584Ssam goto bad; 11424823Skarels *(struct ip *)ui = ip; 11526032Skarels icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT, 11626032Skarels ifp); 1176584Ssam return; 1186584Ssam } 1196584Ssam 1204926Swnj /* 1214926Swnj * Construct sockaddr format source address. 1224926Swnj * Stuff source address and datagram in user buffer. 1234926Swnj */ 1244926Swnj udp_in.sin_port = ui->ui_sport; 1254926Swnj udp_in.sin_addr = ui->ui_src; 1265050Swnj m->m_len -= sizeof (struct udpiphdr); 1275050Swnj m->m_off += sizeof (struct udpiphdr); 12812767Ssam if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 12912767Ssam m, (struct mbuf *)0) == 0) 1304926Swnj goto bad; 1315050Swnj sorwakeup(inp->inp_socket); 1324887Swnj return; 1334926Swnj bad: 1344887Swnj m_freem(m); 1354784Swnj } 1364784Swnj 13724823Skarels udp_ctlinput(cmd, sa) 1386591Ssam int cmd; 13924823Skarels struct sockaddr *sa; 1406591Ssam { 1416591Ssam extern u_char inetctlerrmap[]; 14224823Skarels struct sockaddr_in *sin; 14321121Skarels int in_rtchange(); 1446591Ssam 14524823Skarels if ((unsigned)cmd > PRC_NCMDS) 1466591Ssam return; 14724823Skarels if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 14824823Skarels return; 14924823Skarels sin = (struct sockaddr_in *)sa; 15024823Skarels if (sin->sin_addr.s_addr == INADDR_ANY) 15124823Skarels return; 15224823Skarels 1536591Ssam switch (cmd) { 1546591Ssam 15524823Skarels case PRC_QUENCH: 1566591Ssam break; 1576591Ssam 15824823Skarels case PRC_ROUTEDEAD: 15921121Skarels case PRC_REDIRECT_NET: 16021121Skarels case PRC_REDIRECT_HOST: 16124823Skarels case PRC_REDIRECT_TOSNET: 16224823Skarels case PRC_REDIRECT_TOSHOST: 16324823Skarels in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange); 1646591Ssam break; 1656591Ssam 1666591Ssam default: 16721121Skarels if (inetctlerrmap[cmd] == 0) 16821121Skarels return; /* XXX */ 16924823Skarels in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd], 17024823Skarels (int (*)())0); 1716591Ssam } 1726591Ssam } 1736591Ssam 1744955Swnj udp_output(inp, m0) 17526060Skarels register struct inpcb *inp; 1764926Swnj struct mbuf *m0; 1774784Swnj { 1784926Swnj register struct mbuf *m; 1794926Swnj register struct udpiphdr *ui; 18017165Skarels register int len = 0; 1814784Swnj 1824926Swnj /* 1834926Swnj * Calculate data length and get a mbuf 1845246Sroot * for UDP and IP headers. 1854926Swnj */ 1864926Swnj for (m = m0; m; m = m->m_next) 1874926Swnj len += m->m_len; 18821112Skarels MGET(m, M_DONTWAIT, MT_HEADER); 1896507Ssam if (m == 0) { 1906507Ssam m_freem(m0); 1916507Ssam return (ENOBUFS); 1926507Ssam } 1934784Swnj 1944926Swnj /* 1955246Sroot * Fill in mbuf with extended UDP header 1964926Swnj * and addresses and length put into network format. 1974926Swnj */ 1984926Swnj m->m_off = MMAXOFF - sizeof (struct udpiphdr); 1994926Swnj m->m_len = sizeof (struct udpiphdr); 2004926Swnj m->m_next = m0; 2014926Swnj ui = mtod(m, struct udpiphdr *); 2024926Swnj ui->ui_next = ui->ui_prev = 0; 2034926Swnj ui->ui_x1 = 0; 2044926Swnj ui->ui_pr = IPPROTO_UDP; 20515226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 2065050Swnj ui->ui_src = inp->inp_laddr; 2075050Swnj ui->ui_dst = inp->inp_faddr; 2085050Swnj ui->ui_sport = inp->inp_lport; 2095050Swnj ui->ui_dport = inp->inp_fport; 21015226Ssam ui->ui_ulen = ui->ui_len; 2114784Swnj 2124926Swnj /* 2134926Swnj * Stuff checksum and output datagram. 2144926Swnj */ 2154926Swnj ui->ui_sum = 0; 21619519Skarels if (udpcksum) { 21719519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 21815539Skarels ui->ui_sum = -1; 21921112Skarels } 2205050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 22126086Skarels ((struct ip *)ui)->ip_ttl = UDP_TTL; 22226060Skarels return (ip_output(m, inp->inp_options, &inp->inp_route, 22326060Skarels inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST))); 2244784Swnj } 2254784Swnj 22618368Skarels int udp_sendspace = 2048; /* really max datagram size */ 22718368Skarels int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ 22818368Skarels 2298602Sroot /*ARGSUSED*/ 23012767Ssam udp_usrreq(so, req, m, nam, rights) 2314887Swnj struct socket *so; 2324784Swnj int req; 23312767Ssam struct mbuf *m, *nam, *rights; 2344784Swnj { 2354887Swnj struct inpcb *inp = sotoinpcb(so); 2366507Ssam int error = 0; 2374784Swnj 23818368Skarels if (req == PRU_CONTROL) 23918368Skarels return (in_control(so, (int)m, (caddr_t)nam, 24018368Skarels (struct ifnet *)rights)); 24112767Ssam if (rights && rights->m_len) { 24212767Ssam error = EINVAL; 24312767Ssam goto release; 24412767Ssam } 24511080Ssam if (inp == NULL && req != PRU_ATTACH) { 24611080Ssam error = EINVAL; 24711080Ssam goto release; 24811080Ssam } 2494784Swnj switch (req) { 2504784Swnj 2514784Swnj case PRU_ATTACH: 25211080Ssam if (inp != NULL) { 25311080Ssam error = EINVAL; 25411080Ssam break; 25511080Ssam } 2568273Sroot error = in_pcballoc(so, &udb); 2578273Sroot if (error) 2588273Sroot break; 25918368Skarels error = soreserve(so, udp_sendspace, udp_recvspace); 2608273Sroot if (error) 2618273Sroot break; 2624887Swnj break; 2634784Swnj 2644784Swnj case PRU_DETACH: 26511080Ssam if (inp == NULL) { 26611080Ssam error = ENOTCONN; 26711080Ssam break; 26811080Ssam } 2695166Swnj in_pcbdetach(inp); 2704887Swnj break; 2714784Swnj 2728273Sroot case PRU_BIND: 2738273Sroot error = in_pcbbind(inp, nam); 2748273Sroot break; 2758273Sroot 2768273Sroot case PRU_LISTEN: 2778273Sroot error = EOPNOTSUPP; 2788273Sroot break; 2798273Sroot 2804784Swnj case PRU_CONNECT: 28111080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 28211080Ssam error = EISCONN; 28311080Ssam break; 28411080Ssam } 2858273Sroot error = in_pcbconnect(inp, nam); 2866507Ssam if (error == 0) 2876507Ssam soisconnected(so); 2884887Swnj break; 2894784Swnj 29013118Ssam case PRU_CONNECT2: 29113118Ssam error = EOPNOTSUPP; 29213118Ssam break; 29313118Ssam 2944926Swnj case PRU_ACCEPT: 29511080Ssam error = EOPNOTSUPP; 29611080Ssam break; 2974926Swnj 2984784Swnj case PRU_DISCONNECT: 29911080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 30011080Ssam error = ENOTCONN; 30111080Ssam break; 30211080Ssam } 3035166Swnj in_pcbdisconnect(inp); 3044887Swnj soisdisconnected(so); 3054784Swnj break; 3064784Swnj 3074912Swnj case PRU_SHUTDOWN: 3084912Swnj socantsendmore(so); 3094912Swnj break; 3104912Swnj 3115996Swnj case PRU_SEND: { 3125996Swnj struct in_addr laddr; 31316799Skarels int s; 3145996Swnj 3158273Sroot if (nam) { 3165996Swnj laddr = inp->inp_laddr; 31711080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 31811080Ssam error = EISCONN; 31911080Ssam break; 32011080Ssam } 32116799Skarels /* 32216799Skarels * Must block input while temporarily connected. 32316799Skarels */ 32416799Skarels s = splnet(); 3258273Sroot error = in_pcbconnect(inp, nam); 32616799Skarels if (error) { 32716799Skarels splx(s); 3286507Ssam break; 32916799Skarels } 3304955Swnj } else { 33111080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 33211080Ssam error = ENOTCONN; 33311080Ssam break; 33411080Ssam } 3354955Swnj } 3366507Ssam error = udp_output(inp, m); 33711080Ssam m = NULL; 3388273Sroot if (nam) { 3395166Swnj in_pcbdisconnect(inp); 34018368Skarels inp->inp_laddr = laddr; 34116799Skarels splx(s); 3425996Swnj } 3435996Swnj } 3444784Swnj break; 3454784Swnj 3464784Swnj case PRU_ABORT: 3475166Swnj in_pcbdetach(inp); 3484887Swnj sofree(so); 3494887Swnj soisdisconnected(so); 3504784Swnj break; 3514784Swnj 3526511Ssam case PRU_SOCKADDR: 3538273Sroot in_setsockaddr(inp, nam); 3546511Ssam break; 3556511Ssam 35614124Ssam case PRU_PEERADDR: 35714124Ssam in_setpeeraddr(inp, nam); 35814124Ssam break; 35914124Ssam 36016988Skarels case PRU_SENSE: 36116988Skarels /* 36216988Skarels * stat: don't bother with a blocksize. 36316988Skarels */ 36416988Skarels return (0); 36516988Skarels 36612205Ssam case PRU_SENDOOB: 36712205Ssam case PRU_FASTTIMO: 36812205Ssam case PRU_SLOWTIMO: 36912205Ssam case PRU_PROTORCV: 37012205Ssam case PRU_PROTOSEND: 37112205Ssam error = EOPNOTSUPP; 37212205Ssam break; 37313118Ssam 37416799Skarels case PRU_RCVD: 37516799Skarels case PRU_RCVOOB: 37616799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 37716799Skarels 37813118Ssam default: 37913118Ssam panic("udp_usrreq"); 3804805Swnj } 38111080Ssam release: 38211080Ssam if (m != NULL) 38311080Ssam m_freem(m); 3846507Ssam return (error); 3854784Swnj } 386