1df8bae1dSRodney W. Grimes /* 26dfab5b1SGarrett Wollman * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 336dfab5b1SGarrett Wollman * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 34592071e8SBruce Evans * $Id: udp_usrreq.c,v 1.41 1997/10/28 15:58:54 bde Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 3826f9a767SRodney W. Grimes #include <sys/systm.h> 39b110a8a2SGarrett Wollman #include <sys/kernel.h> 40df8bae1dSRodney W. Grimes #include <sys/malloc.h> 41df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 42df8bae1dSRodney W. Grimes #include <sys/protosw.h> 43df8bae1dSRodney W. Grimes #include <sys/socket.h> 44df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 45b5e8ce9fSBruce Evans #include <sys/sysctl.h> 46816a3d83SPoul-Henning Kamp #include <sys/syslog.h> 47df8bae1dSRodney W. Grimes 48df8bae1dSRodney W. Grimes #include <net/if.h> 49df8bae1dSRodney W. Grimes #include <net/route.h> 50df8bae1dSRodney W. Grimes 51df8bae1dSRodney W. Grimes #include <netinet/in.h> 52df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 53df8bae1dSRodney W. Grimes #include <netinet/ip.h> 54df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 55b5e8ce9fSBruce Evans #include <netinet/in_var.h> 56df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 57df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 58df8bae1dSRodney W. Grimes #include <netinet/udp.h> 59df8bae1dSRodney W. Grimes #include <netinet/udp_var.h> 60df8bae1dSRodney W. Grimes 61df8bae1dSRodney W. Grimes /* 62df8bae1dSRodney W. Grimes * UDP protocol implementation. 63df8bae1dSRodney W. Grimes * Per RFC 768, August, 1980. 64df8bae1dSRodney W. Grimes */ 65df8bae1dSRodney W. Grimes #ifndef COMPAT_42 660312fbe9SPoul-Henning Kamp static int udpcksum = 1; 67df8bae1dSRodney W. Grimes #else 680312fbe9SPoul-Henning Kamp static int udpcksum = 0; /* XXX */ 69df8bae1dSRodney W. Grimes #endif 700312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW, 710312fbe9SPoul-Henning Kamp &udpcksum, 0, ""); 72df8bae1dSRodney W. Grimes 73d78a37adSPaul Traina static int log_in_vain = 0; 74816a3d83SPoul-Henning Kamp SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW, 75816a3d83SPoul-Henning Kamp &log_in_vain, 0, ""); 76816a3d83SPoul-Henning Kamp 77f708ef1bSPoul-Henning Kamp static struct inpcbhead udb; /* from udp_var.h */ 78f708ef1bSPoul-Henning Kamp static struct inpcbinfo udbinfo; 7915bd2b43SDavid Greenman 8015bd2b43SDavid Greenman #ifndef UDBHASHSIZE 8115bd2b43SDavid Greenman #define UDBHASHSIZE 64 8215bd2b43SDavid Greenman #endif 8315bd2b43SDavid Greenman 84f708ef1bSPoul-Henning Kamp static struct udpstat udpstat; /* from udp_var.h */ 850312fbe9SPoul-Henning Kamp SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD, 860312fbe9SPoul-Henning Kamp &udpstat, udpstat, ""); 87f2ea20e6SGarrett Wollman 880312fbe9SPoul-Henning Kamp static struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; 89df8bae1dSRodney W. Grimes 9057bf258eSGarrett Wollman static int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *, 91a29f300eSGarrett Wollman struct mbuf *, struct proc *)); 92df8bae1dSRodney W. Grimes static void udp_notify __P((struct inpcb *, int)); 93df8bae1dSRodney W. Grimes 94df8bae1dSRodney W. Grimes void 95df8bae1dSRodney W. Grimes udp_init() 96df8bae1dSRodney W. Grimes { 9715bd2b43SDavid Greenman LIST_INIT(&udb); 9815bd2b43SDavid Greenman udbinfo.listhead = &udb; 99ddd79a97SDavid Greenman udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask); 100df8bae1dSRodney W. Grimes } 101df8bae1dSRodney W. Grimes 102df8bae1dSRodney W. Grimes void 103df8bae1dSRodney W. Grimes udp_input(m, iphlen) 104df8bae1dSRodney W. Grimes register struct mbuf *m; 105df8bae1dSRodney W. Grimes int iphlen; 106df8bae1dSRodney W. Grimes { 107df8bae1dSRodney W. Grimes register struct ip *ip; 108df8bae1dSRodney W. Grimes register struct udphdr *uh; 109df8bae1dSRodney W. Grimes register struct inpcb *inp; 110df8bae1dSRodney W. Grimes struct mbuf *opts = 0; 111df8bae1dSRodney W. Grimes int len; 112df8bae1dSRodney W. Grimes struct ip save_ip; 113df8bae1dSRodney W. Grimes 114df8bae1dSRodney W. Grimes udpstat.udps_ipackets++; 115df8bae1dSRodney W. Grimes 116df8bae1dSRodney W. Grimes /* 117df8bae1dSRodney W. Grimes * Strip IP options, if any; should skip this, 118df8bae1dSRodney W. Grimes * make available to user, and use on returned packets, 119df8bae1dSRodney W. Grimes * but we don't yet have a way to check the checksum 120df8bae1dSRodney W. Grimes * with options still present. 121df8bae1dSRodney W. Grimes */ 122df8bae1dSRodney W. Grimes if (iphlen > sizeof (struct ip)) { 123df8bae1dSRodney W. Grimes ip_stripoptions(m, (struct mbuf *)0); 124df8bae1dSRodney W. Grimes iphlen = sizeof(struct ip); 125df8bae1dSRodney W. Grimes } 126df8bae1dSRodney W. Grimes 127df8bae1dSRodney W. Grimes /* 128df8bae1dSRodney W. Grimes * Get IP and UDP header together in first mbuf. 129df8bae1dSRodney W. Grimes */ 130df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 131df8bae1dSRodney W. Grimes if (m->m_len < iphlen + sizeof(struct udphdr)) { 132df8bae1dSRodney W. Grimes if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { 133df8bae1dSRodney W. Grimes udpstat.udps_hdrops++; 134df8bae1dSRodney W. Grimes return; 135df8bae1dSRodney W. Grimes } 136df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 137df8bae1dSRodney W. Grimes } 138df8bae1dSRodney W. Grimes uh = (struct udphdr *)((caddr_t)ip + iphlen); 139df8bae1dSRodney W. Grimes 140df8bae1dSRodney W. Grimes /* 141df8bae1dSRodney W. Grimes * Make mbuf data length reflect UDP length. 142df8bae1dSRodney W. Grimes * If not enough data to reflect UDP length, drop. 143df8bae1dSRodney W. Grimes */ 144df8bae1dSRodney W. Grimes len = ntohs((u_short)uh->uh_ulen); 145df8bae1dSRodney W. Grimes if (ip->ip_len != len) { 1467eb7a449SAndras Olah if (len > ip->ip_len || len < sizeof(struct udphdr)) { 147df8bae1dSRodney W. Grimes udpstat.udps_badlen++; 148df8bae1dSRodney W. Grimes goto bad; 149df8bae1dSRodney W. Grimes } 150df8bae1dSRodney W. Grimes m_adj(m, len - ip->ip_len); 151df8bae1dSRodney W. Grimes /* ip->ip_len = len; */ 152df8bae1dSRodney W. Grimes } 153df8bae1dSRodney W. Grimes /* 154df8bae1dSRodney W. Grimes * Save a copy of the IP header in case we want restore it 155df8bae1dSRodney W. Grimes * for sending an ICMP error message in response. 156df8bae1dSRodney W. Grimes */ 157df8bae1dSRodney W. Grimes save_ip = *ip; 158df8bae1dSRodney W. Grimes 159df8bae1dSRodney W. Grimes /* 160df8bae1dSRodney W. Grimes * Checksum extended UDP header and data. 161df8bae1dSRodney W. Grimes */ 1626dfab5b1SGarrett Wollman if (uh->uh_sum) { 163df8bae1dSRodney W. Grimes ((struct ipovly *)ip)->ih_next = 0; 164df8bae1dSRodney W. Grimes ((struct ipovly *)ip)->ih_prev = 0; 165df8bae1dSRodney W. Grimes ((struct ipovly *)ip)->ih_x1 = 0; 166df8bae1dSRodney W. Grimes ((struct ipovly *)ip)->ih_len = uh->uh_ulen; 167623ae52eSPoul-Henning Kamp uh->uh_sum = in_cksum(m, len + sizeof (struct ip)); 168623ae52eSPoul-Henning Kamp if (uh->uh_sum) { 169df8bae1dSRodney W. Grimes udpstat.udps_badsum++; 170df8bae1dSRodney W. Grimes m_freem(m); 171df8bae1dSRodney W. Grimes return; 172df8bae1dSRodney W. Grimes } 173df8bae1dSRodney W. Grimes } 174df8bae1dSRodney W. Grimes 175df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || 176df8bae1dSRodney W. Grimes in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { 17782c23ebaSBill Fenner struct inpcb *last; 178df8bae1dSRodney W. Grimes /* 179df8bae1dSRodney W. Grimes * Deliver a multicast or broadcast datagram to *all* sockets 180df8bae1dSRodney W. Grimes * for which the local and remote addresses and ports match 181df8bae1dSRodney W. Grimes * those of the incoming datagram. This allows more than 182df8bae1dSRodney W. Grimes * one process to receive multi/broadcasts on the same port. 183df8bae1dSRodney W. Grimes * (This really ought to be done for unicast datagrams as 184df8bae1dSRodney W. Grimes * well, but that would cause problems with existing 185df8bae1dSRodney W. Grimes * applications that open both address-specific sockets and 186df8bae1dSRodney W. Grimes * a wildcard socket listening to the same port -- they would 187df8bae1dSRodney W. Grimes * end up receiving duplicates of every unicast datagram. 188df8bae1dSRodney W. Grimes * Those applications open the multiple sockets to overcome an 189df8bae1dSRodney W. Grimes * inadequacy of the UDP socket interface, but for backwards 190df8bae1dSRodney W. Grimes * compatibility we avoid the problem here rather than 191df8bae1dSRodney W. Grimes * fixing the interface. Maybe 4.5BSD will remedy this?) 192df8bae1dSRodney W. Grimes */ 193df8bae1dSRodney W. Grimes 194df8bae1dSRodney W. Grimes /* 195df8bae1dSRodney W. Grimes * Construct sockaddr format source address. 196df8bae1dSRodney W. Grimes */ 197df8bae1dSRodney W. Grimes udp_in.sin_port = uh->uh_sport; 198df8bae1dSRodney W. Grimes udp_in.sin_addr = ip->ip_src; 199df8bae1dSRodney W. Grimes m->m_len -= sizeof (struct udpiphdr); 200df8bae1dSRodney W. Grimes m->m_data += sizeof (struct udpiphdr); 201df8bae1dSRodney W. Grimes /* 202df8bae1dSRodney W. Grimes * Locate pcb(s) for datagram. 203df8bae1dSRodney W. Grimes * (Algorithm copied from raw_intr().) 204df8bae1dSRodney W. Grimes */ 205df8bae1dSRodney W. Grimes last = NULL; 20615bd2b43SDavid Greenman for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { 207df8bae1dSRodney W. Grimes if (inp->inp_lport != uh->uh_dport) 208df8bae1dSRodney W. Grimes continue; 209df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr != INADDR_ANY) { 210df8bae1dSRodney W. Grimes if (inp->inp_laddr.s_addr != 211df8bae1dSRodney W. Grimes ip->ip_dst.s_addr) 212df8bae1dSRodney W. Grimes continue; 213df8bae1dSRodney W. Grimes } 214df8bae1dSRodney W. Grimes if (inp->inp_faddr.s_addr != INADDR_ANY) { 215df8bae1dSRodney W. Grimes if (inp->inp_faddr.s_addr != 216df8bae1dSRodney W. Grimes ip->ip_src.s_addr || 217df8bae1dSRodney W. Grimes inp->inp_fport != uh->uh_sport) 218df8bae1dSRodney W. Grimes continue; 219df8bae1dSRodney W. Grimes } 220df8bae1dSRodney W. Grimes 221df8bae1dSRodney W. Grimes if (last != NULL) { 222df8bae1dSRodney W. Grimes struct mbuf *n; 223df8bae1dSRodney W. Grimes 224df8bae1dSRodney W. Grimes if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 22582c23ebaSBill Fenner if (last->inp_flags & INP_CONTROLOPTS 22682c23ebaSBill Fenner || last->inp_socket->so_options & SO_TIMESTAMP) 22782c23ebaSBill Fenner ip_savecontrol(last, &opts, ip, n); 22882c23ebaSBill Fenner if (sbappendaddr(&last->inp_socket->so_rcv, 229df8bae1dSRodney W. Grimes (struct sockaddr *)&udp_in, 23082c23ebaSBill Fenner n, opts) == 0) { 231df8bae1dSRodney W. Grimes m_freem(n); 23282c23ebaSBill Fenner if (opts) 23382c23ebaSBill Fenner m_freem(opts); 234df8bae1dSRodney W. Grimes udpstat.udps_fullsock++; 235df8bae1dSRodney W. Grimes } else 23682c23ebaSBill Fenner sorwakeup(last->inp_socket); 23782c23ebaSBill Fenner opts = 0; 238df8bae1dSRodney W. Grimes } 239df8bae1dSRodney W. Grimes } 24082c23ebaSBill Fenner last = inp; 241df8bae1dSRodney W. Grimes /* 242df8bae1dSRodney W. Grimes * Don't look for additional matches if this one does 243df8bae1dSRodney W. Grimes * not have either the SO_REUSEPORT or SO_REUSEADDR 244df8bae1dSRodney W. Grimes * socket options set. This heuristic avoids searching 245df8bae1dSRodney W. Grimes * through all pcbs in the common case of a non-shared 246df8bae1dSRodney W. Grimes * port. It * assumes that an application will never 247df8bae1dSRodney W. Grimes * clear these options after setting them. 248df8bae1dSRodney W. Grimes */ 24982c23ebaSBill Fenner if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0)) 250df8bae1dSRodney W. Grimes break; 251df8bae1dSRodney W. Grimes } 252df8bae1dSRodney W. Grimes 253df8bae1dSRodney W. Grimes if (last == NULL) { 254df8bae1dSRodney W. Grimes /* 255df8bae1dSRodney W. Grimes * No matching pcb found; discard datagram. 256df8bae1dSRodney W. Grimes * (No need to send an ICMP Port Unreachable 257df8bae1dSRodney W. Grimes * for a broadcast or multicast datgram.) 258df8bae1dSRodney W. Grimes */ 259df8bae1dSRodney W. Grimes udpstat.udps_noportbcast++; 260df8bae1dSRodney W. Grimes goto bad; 261df8bae1dSRodney W. Grimes } 26282c23ebaSBill Fenner if (last->inp_flags & INP_CONTROLOPTS 26382c23ebaSBill Fenner || last->inp_socket->so_options & SO_TIMESTAMP) 26482c23ebaSBill Fenner ip_savecontrol(last, &opts, ip, m); 26582c23ebaSBill Fenner if (sbappendaddr(&last->inp_socket->so_rcv, 26682c23ebaSBill Fenner (struct sockaddr *)&udp_in, 26782c23ebaSBill Fenner m, opts) == 0) { 268df8bae1dSRodney W. Grimes udpstat.udps_fullsock++; 269df8bae1dSRodney W. Grimes goto bad; 270df8bae1dSRodney W. Grimes } 27182c23ebaSBill Fenner sorwakeup(last->inp_socket); 272df8bae1dSRodney W. Grimes return; 273df8bae1dSRodney W. Grimes } 274df8bae1dSRodney W. Grimes /* 2756d6a026bSDavid Greenman * Locate pcb for datagram. 276df8bae1dSRodney W. Grimes */ 27715bd2b43SDavid Greenman inp = in_pcblookuphash(&udbinfo, ip->ip_src, uh->uh_sport, 2786d6a026bSDavid Greenman ip->ip_dst, uh->uh_dport, 1); 27915bd2b43SDavid Greenman if (inp == NULL) { 28075cfc95fSAndrey A. Chernov if (log_in_vain) { 281df5c0b8aSBill Fenner char buf[4*sizeof "123"]; 28275cfc95fSAndrey A. Chernov 28375cfc95fSAndrey A. Chernov strcpy(buf, inet_ntoa(ip->ip_dst)); 284592071e8SBruce Evans log(LOG_INFO, 285592071e8SBruce Evans "Connection attempt to UDP %s:%d from %s:%d\n", 286592071e8SBruce Evans buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src), 287592071e8SBruce Evans ntohs(uh->uh_sport)); 28875cfc95fSAndrey A. Chernov } 289df8bae1dSRodney W. Grimes udpstat.udps_noport++; 290df8bae1dSRodney W. Grimes if (m->m_flags & (M_BCAST | M_MCAST)) { 291df8bae1dSRodney W. Grimes udpstat.udps_noportbcast++; 292df8bae1dSRodney W. Grimes goto bad; 293df8bae1dSRodney W. Grimes } 294df8bae1dSRodney W. Grimes *ip = save_ip; 295df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); 296df8bae1dSRodney W. Grimes return; 297df8bae1dSRodney W. Grimes } 298df8bae1dSRodney W. Grimes 299df8bae1dSRodney W. Grimes /* 300df8bae1dSRodney W. Grimes * Construct sockaddr format source address. 301df8bae1dSRodney W. Grimes * Stuff source address and datagram in user buffer. 302df8bae1dSRodney W. Grimes */ 303df8bae1dSRodney W. Grimes udp_in.sin_port = uh->uh_sport; 304df8bae1dSRodney W. Grimes udp_in.sin_addr = ip->ip_src; 30582dab6ceSGarrett Wollman if (inp->inp_flags & INP_CONTROLOPTS 30682c23ebaSBill Fenner || inp->inp_socket->so_options & SO_TIMESTAMP) 30782c23ebaSBill Fenner ip_savecontrol(inp, &opts, ip, m); 308df8bae1dSRodney W. Grimes iphlen += sizeof(struct udphdr); 309df8bae1dSRodney W. Grimes m->m_len -= iphlen; 310df8bae1dSRodney W. Grimes m->m_pkthdr.len -= iphlen; 311df8bae1dSRodney W. Grimes m->m_data += iphlen; 312df8bae1dSRodney W. Grimes if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 313df8bae1dSRodney W. Grimes m, opts) == 0) { 314df8bae1dSRodney W. Grimes udpstat.udps_fullsock++; 315df8bae1dSRodney W. Grimes goto bad; 316df8bae1dSRodney W. Grimes } 317df8bae1dSRodney W. Grimes sorwakeup(inp->inp_socket); 318df8bae1dSRodney W. Grimes return; 319df8bae1dSRodney W. Grimes bad: 320df8bae1dSRodney W. Grimes m_freem(m); 321df8bae1dSRodney W. Grimes if (opts) 322df8bae1dSRodney W. Grimes m_freem(opts); 323df8bae1dSRodney W. Grimes } 324df8bae1dSRodney W. Grimes 325df8bae1dSRodney W. Grimes /* 326df8bae1dSRodney W. Grimes * Notify a udp user of an asynchronous error; 327df8bae1dSRodney W. Grimes * just wake up so that he can collect error status. 328df8bae1dSRodney W. Grimes */ 329df8bae1dSRodney W. Grimes static void 330df8bae1dSRodney W. Grimes udp_notify(inp, errno) 331df8bae1dSRodney W. Grimes register struct inpcb *inp; 332df8bae1dSRodney W. Grimes int errno; 333df8bae1dSRodney W. Grimes { 334df8bae1dSRodney W. Grimes inp->inp_socket->so_error = errno; 335df8bae1dSRodney W. Grimes sorwakeup(inp->inp_socket); 336df8bae1dSRodney W. Grimes sowwakeup(inp->inp_socket); 337df8bae1dSRodney W. Grimes } 338df8bae1dSRodney W. Grimes 339df8bae1dSRodney W. Grimes void 340b62d102cSBruce Evans udp_ctlinput(cmd, sa, vip) 341df8bae1dSRodney W. Grimes int cmd; 342df8bae1dSRodney W. Grimes struct sockaddr *sa; 343b62d102cSBruce Evans void *vip; 344df8bae1dSRodney W. Grimes { 345b62d102cSBruce Evans register struct ip *ip = vip; 346df8bae1dSRodney W. Grimes register struct udphdr *uh; 347df8bae1dSRodney W. Grimes 348df8bae1dSRodney W. Grimes if (!PRC_IS_REDIRECT(cmd) && 349df8bae1dSRodney W. Grimes ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) 350df8bae1dSRodney W. Grimes return; 351df8bae1dSRodney W. Grimes if (ip) { 352df8bae1dSRodney W. Grimes uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 353df8bae1dSRodney W. Grimes in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, 354df8bae1dSRodney W. Grimes cmd, udp_notify); 355df8bae1dSRodney W. Grimes } else 356df8bae1dSRodney W. Grimes in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); 357df8bae1dSRodney W. Grimes } 358df8bae1dSRodney W. Grimes 3590312fbe9SPoul-Henning Kamp static int 360a29f300eSGarrett Wollman udp_output(inp, m, addr, control, p) 361df8bae1dSRodney W. Grimes register struct inpcb *inp; 362df8bae1dSRodney W. Grimes register struct mbuf *m; 36357bf258eSGarrett Wollman struct sockaddr *addr; 36457bf258eSGarrett Wollman struct mbuf *control; 365a29f300eSGarrett Wollman struct proc *p; 366df8bae1dSRodney W. Grimes { 367df8bae1dSRodney W. Grimes register struct udpiphdr *ui; 368df8bae1dSRodney W. Grimes register int len = m->m_pkthdr.len; 369df8bae1dSRodney W. Grimes struct in_addr laddr; 37026f9a767SRodney W. Grimes int s = 0, error = 0; 371df8bae1dSRodney W. Grimes 372df8bae1dSRodney W. Grimes if (control) 373df8bae1dSRodney W. Grimes m_freem(control); /* XXX */ 374df8bae1dSRodney W. Grimes 375430d30d8SBill Fenner if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) { 376430d30d8SBill Fenner error = EMSGSIZE; 377430d30d8SBill Fenner goto release; 378430d30d8SBill Fenner } 379430d30d8SBill Fenner 380df8bae1dSRodney W. Grimes if (addr) { 381df8bae1dSRodney W. Grimes laddr = inp->inp_laddr; 382df8bae1dSRodney W. Grimes if (inp->inp_faddr.s_addr != INADDR_ANY) { 383df8bae1dSRodney W. Grimes error = EISCONN; 384df8bae1dSRodney W. Grimes goto release; 385df8bae1dSRodney W. Grimes } 386df8bae1dSRodney W. Grimes /* 387df8bae1dSRodney W. Grimes * Must block input while temporarily connected. 388df8bae1dSRodney W. Grimes */ 389df8bae1dSRodney W. Grimes s = splnet(); 390a29f300eSGarrett Wollman error = in_pcbconnect(inp, addr, p); 391df8bae1dSRodney W. Grimes if (error) { 392df8bae1dSRodney W. Grimes splx(s); 393df8bae1dSRodney W. Grimes goto release; 394df8bae1dSRodney W. Grimes } 395df8bae1dSRodney W. Grimes } else { 396df8bae1dSRodney W. Grimes if (inp->inp_faddr.s_addr == INADDR_ANY) { 397df8bae1dSRodney W. Grimes error = ENOTCONN; 398df8bae1dSRodney W. Grimes goto release; 399df8bae1dSRodney W. Grimes } 400df8bae1dSRodney W. Grimes } 401df8bae1dSRodney W. Grimes /* 402df8bae1dSRodney W. Grimes * Calculate data length and get a mbuf 403df8bae1dSRodney W. Grimes * for UDP and IP headers. 404df8bae1dSRodney W. Grimes */ 405df8bae1dSRodney W. Grimes M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); 406df8bae1dSRodney W. Grimes if (m == 0) { 407df8bae1dSRodney W. Grimes error = ENOBUFS; 4081c09f774SGarrett Wollman if (addr) 4091c09f774SGarrett Wollman splx(s); 410df8bae1dSRodney W. Grimes goto release; 411df8bae1dSRodney W. Grimes } 412df8bae1dSRodney W. Grimes 413df8bae1dSRodney W. Grimes /* 414df8bae1dSRodney W. Grimes * Fill in mbuf with extended UDP header 415df8bae1dSRodney W. Grimes * and addresses and length put into network format. 416df8bae1dSRodney W. Grimes */ 417df8bae1dSRodney W. Grimes ui = mtod(m, struct udpiphdr *); 418df8bae1dSRodney W. Grimes ui->ui_next = ui->ui_prev = 0; 419df8bae1dSRodney W. Grimes ui->ui_x1 = 0; 420df8bae1dSRodney W. Grimes ui->ui_pr = IPPROTO_UDP; 421df8bae1dSRodney W. Grimes ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 422df8bae1dSRodney W. Grimes ui->ui_src = inp->inp_laddr; 423df8bae1dSRodney W. Grimes ui->ui_dst = inp->inp_faddr; 424df8bae1dSRodney W. Grimes ui->ui_sport = inp->inp_lport; 425df8bae1dSRodney W. Grimes ui->ui_dport = inp->inp_fport; 426df8bae1dSRodney W. Grimes ui->ui_ulen = ui->ui_len; 427df8bae1dSRodney W. Grimes 428df8bae1dSRodney W. Grimes /* 429df8bae1dSRodney W. Grimes * Stuff checksum and output datagram. 430df8bae1dSRodney W. Grimes */ 431df8bae1dSRodney W. Grimes ui->ui_sum = 0; 432df8bae1dSRodney W. Grimes if (udpcksum) { 433df8bae1dSRodney W. Grimes if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 434df8bae1dSRodney W. Grimes ui->ui_sum = 0xffff; 435df8bae1dSRodney W. Grimes } 436df8bae1dSRodney W. Grimes ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 437ca98b82cSDavid Greenman ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */ 438ca98b82cSDavid Greenman ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */ 439df8bae1dSRodney W. Grimes udpstat.udps_opackets++; 440df8bae1dSRodney W. Grimes error = ip_output(m, inp->inp_options, &inp->inp_route, 441df8bae1dSRodney W. Grimes inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), 442df8bae1dSRodney W. Grimes inp->inp_moptions); 443df8bae1dSRodney W. Grimes 444df8bae1dSRodney W. Grimes if (addr) { 445df8bae1dSRodney W. Grimes in_pcbdisconnect(inp); 44657bf258eSGarrett Wollman inp->inp_laddr = laddr; /* XXX rehash? */ 447df8bae1dSRodney W. Grimes splx(s); 448df8bae1dSRodney W. Grimes } 449df8bae1dSRodney W. Grimes return (error); 450df8bae1dSRodney W. Grimes 451df8bae1dSRodney W. Grimes release: 452df8bae1dSRodney W. Grimes m_freem(m); 453df8bae1dSRodney W. Grimes return (error); 454df8bae1dSRodney W. Grimes } 455df8bae1dSRodney W. Grimes 4560312fbe9SPoul-Henning Kamp static u_long udp_sendspace = 9216; /* really max datagram size */ 457df8bae1dSRodney W. Grimes /* 40 1K datagrams */ 4580312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW, 4590312fbe9SPoul-Henning Kamp &udp_sendspace, 0, ""); 4600312fbe9SPoul-Henning Kamp 4610312fbe9SPoul-Henning Kamp static u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 4620312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW, 4630312fbe9SPoul-Henning Kamp &udp_recvspace, 0, ""); 464df8bae1dSRodney W. Grimes 465d0390e05SGarrett Wollman static int 466d0390e05SGarrett Wollman udp_abort(struct socket *so) 467df8bae1dSRodney W. Grimes { 468d0390e05SGarrett Wollman struct inpcb *inp; 469df8bae1dSRodney W. Grimes int s; 470df8bae1dSRodney W. Grimes 471d0390e05SGarrett Wollman inp = sotoinpcb(so); 472d0390e05SGarrett Wollman if (inp == 0) 473d0390e05SGarrett Wollman return EINVAL; /* ??? possible? panic instead? */ 474d0390e05SGarrett Wollman soisdisconnected(so); 475d0390e05SGarrett Wollman s = splnet(); 476d0390e05SGarrett Wollman in_pcbdetach(inp); 477d0390e05SGarrett Wollman splx(s); 478d0390e05SGarrett Wollman return 0; 479df8bae1dSRodney W. Grimes } 480df8bae1dSRodney W. Grimes 481d0390e05SGarrett Wollman static int 482a29f300eSGarrett Wollman udp_attach(struct socket *so, int proto, struct proc *p) 483d0390e05SGarrett Wollman { 484d0390e05SGarrett Wollman struct inpcb *inp; 485d0390e05SGarrett Wollman int s, error; 486d0390e05SGarrett Wollman 487d0390e05SGarrett Wollman inp = sotoinpcb(so); 488d0390e05SGarrett Wollman if (inp != 0) 489d0390e05SGarrett Wollman return EINVAL; 490d0390e05SGarrett Wollman 491df8bae1dSRodney W. Grimes s = splnet(); 492a29f300eSGarrett Wollman error = in_pcballoc(so, &udbinfo, p); 493df8bae1dSRodney W. Grimes splx(s); 494df8bae1dSRodney W. Grimes if (error) 495d0390e05SGarrett Wollman return error; 496df8bae1dSRodney W. Grimes error = soreserve(so, udp_sendspace, udp_recvspace); 497df8bae1dSRodney W. Grimes if (error) 498d0390e05SGarrett Wollman return error; 499ca98b82cSDavid Greenman ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl; 500d0390e05SGarrett Wollman return 0; 501df8bae1dSRodney W. Grimes } 502d0390e05SGarrett Wollman 503d0390e05SGarrett Wollman static int 50457bf258eSGarrett Wollman udp_bind(struct socket *so, struct sockaddr *nam, struct proc *p) 505d0390e05SGarrett Wollman { 506d0390e05SGarrett Wollman struct inpcb *inp; 507d0390e05SGarrett Wollman int s, error; 508d0390e05SGarrett Wollman 509d0390e05SGarrett Wollman inp = sotoinpcb(so); 510d0390e05SGarrett Wollman if (inp == 0) 511d0390e05SGarrett Wollman return EINVAL; 512df8bae1dSRodney W. Grimes s = splnet(); 513a29f300eSGarrett Wollman error = in_pcbbind(inp, nam, p); 514d0390e05SGarrett Wollman splx(s); 515d0390e05SGarrett Wollman return error; 516d0390e05SGarrett Wollman } 517d0390e05SGarrett Wollman 518d0390e05SGarrett Wollman static int 51957bf258eSGarrett Wollman udp_connect(struct socket *so, struct sockaddr *nam, struct proc *p) 520d0390e05SGarrett Wollman { 521d0390e05SGarrett Wollman struct inpcb *inp; 522d0390e05SGarrett Wollman int s, error; 523d0390e05SGarrett Wollman 524d0390e05SGarrett Wollman inp = sotoinpcb(so); 525d0390e05SGarrett Wollman if (inp == 0) 526d0390e05SGarrett Wollman return EINVAL; 527d0390e05SGarrett Wollman if (inp->inp_faddr.s_addr != INADDR_ANY) 528d0390e05SGarrett Wollman return EISCONN; 529d0390e05SGarrett Wollman s = splnet(); 530a29f300eSGarrett Wollman error = in_pcbconnect(inp, nam, p); 531df8bae1dSRodney W. Grimes splx(s); 532df8bae1dSRodney W. Grimes if (error == 0) 533df8bae1dSRodney W. Grimes soisconnected(so); 534d0390e05SGarrett Wollman return error; 535df8bae1dSRodney W. Grimes } 536d0390e05SGarrett Wollman 537d0390e05SGarrett Wollman static int 538d0390e05SGarrett Wollman udp_detach(struct socket *so) 539d0390e05SGarrett Wollman { 540d0390e05SGarrett Wollman struct inpcb *inp; 541d0390e05SGarrett Wollman int s; 542d0390e05SGarrett Wollman 543d0390e05SGarrett Wollman inp = sotoinpcb(so); 544d0390e05SGarrett Wollman if (inp == 0) 545d0390e05SGarrett Wollman return EINVAL; 546d0390e05SGarrett Wollman s = splnet(); 547d0390e05SGarrett Wollman in_pcbdetach(inp); 548d0390e05SGarrett Wollman splx(s); 549d0390e05SGarrett Wollman return 0; 550d0390e05SGarrett Wollman } 551d0390e05SGarrett Wollman 552d0390e05SGarrett Wollman static int 553d0390e05SGarrett Wollman udp_disconnect(struct socket *so) 554d0390e05SGarrett Wollman { 555d0390e05SGarrett Wollman struct inpcb *inp; 556d0390e05SGarrett Wollman int s; 557d0390e05SGarrett Wollman 558d0390e05SGarrett Wollman inp = sotoinpcb(so); 559d0390e05SGarrett Wollman if (inp == 0) 560d0390e05SGarrett Wollman return EINVAL; 561d0390e05SGarrett Wollman if (inp->inp_faddr.s_addr == INADDR_ANY) 562d0390e05SGarrett Wollman return ENOTCONN; 563d0390e05SGarrett Wollman 564df8bae1dSRodney W. Grimes s = splnet(); 565df8bae1dSRodney W. Grimes in_pcbdisconnect(inp); 566df8bae1dSRodney W. Grimes inp->inp_laddr.s_addr = INADDR_ANY; 567df8bae1dSRodney W. Grimes splx(s); 568df8bae1dSRodney W. Grimes so->so_state &= ~SS_ISCONNECTED; /* XXX */ 569d0390e05SGarrett Wollman return 0; 570df8bae1dSRodney W. Grimes } 571df8bae1dSRodney W. Grimes 572d0390e05SGarrett Wollman static int 57357bf258eSGarrett Wollman udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 574a29f300eSGarrett Wollman struct mbuf *control, struct proc *p) 575d0390e05SGarrett Wollman { 576d0390e05SGarrett Wollman struct inpcb *inp; 577d0390e05SGarrett Wollman 578d0390e05SGarrett Wollman inp = sotoinpcb(so); 579d0390e05SGarrett Wollman if (inp == 0) { 580d0390e05SGarrett Wollman m_freem(m); 581d0390e05SGarrett Wollman return EINVAL; 582d0390e05SGarrett Wollman } 583a29f300eSGarrett Wollman return udp_output(inp, m, addr, control, p); 584d0390e05SGarrett Wollman } 585d0390e05SGarrett Wollman 586d0390e05SGarrett Wollman static int 587d0390e05SGarrett Wollman udp_shutdown(struct socket *so) 588d0390e05SGarrett Wollman { 589d0390e05SGarrett Wollman struct inpcb *inp; 590d0390e05SGarrett Wollman 591d0390e05SGarrett Wollman inp = sotoinpcb(so); 592d0390e05SGarrett Wollman if (inp == 0) 593d0390e05SGarrett Wollman return EINVAL; 594d0390e05SGarrett Wollman socantsendmore(so); 595d0390e05SGarrett Wollman return 0; 596d0390e05SGarrett Wollman } 597d0390e05SGarrett Wollman 598d0390e05SGarrett Wollman struct pr_usrreqs udp_usrreqs = { 599117bcae7SGarrett Wollman udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect, 600117bcae7SGarrett Wollman pru_connect2_notsupp, in_control, udp_detach, udp_disconnect, 601117bcae7SGarrett Wollman pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, 602117bcae7SGarrett Wollman pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown, 603f8f6cbbaSPeter Wemm in_setsockaddr, sosend, soreceive, sopoll 604d0390e05SGarrett Wollman }; 605