123199Smckusick /* 244596Skarels * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. 332789Sbostic * All rights reserved. 423199Smckusick * 544642Sbostic * %sccs.include.redist.c% 632789Sbostic * 7*59309Smckusick * @(#)udp_usrreq.c 7.31 (Berkeley) 04/26/93 823199Smckusick */ 94784Swnj 1056531Sbostic #include <sys/param.h> 1156531Sbostic #include <sys/malloc.h> 1256531Sbostic #include <sys/mbuf.h> 1356531Sbostic #include <sys/protosw.h> 1456531Sbostic #include <sys/socket.h> 1556531Sbostic #include <sys/socketvar.h> 1656531Sbostic #include <sys/errno.h> 1756531Sbostic #include <sys/stat.h> 1810897Ssam 1956531Sbostic #include <net/if.h> 2056531Sbostic #include <net/route.h> 2110897Ssam 2256531Sbostic #include <netinet/in.h> 2356531Sbostic #include <netinet/in_systm.h> 2456531Sbostic #include <netinet/ip.h> 2556531Sbostic #include <netinet/in_pcb.h> 2656531Sbostic #include <netinet/ip_var.h> 2756531Sbostic #include <netinet/ip_icmp.h> 2856531Sbostic #include <netinet/udp.h> 2956531Sbostic #include <netinet/udp_var.h> 304784Swnj 3144596Skarels struct inpcb *udp_last_inpcb = &udb; 3244596Skarels 334926Swnj /* 344926Swnj * UDP protocol implementation. 354926Swnj * Per RFC 768, August, 1980. 364926Swnj */ 374805Swnj udp_init() 384805Swnj { 394901Swnj udb.inp_next = udb.inp_prev = &udb; 404805Swnj } 414805Swnj 4226118Skarels #ifndef COMPAT_42 4319519Skarels int udpcksum = 1; 4426118Skarels #else 4526118Skarels int udpcksum = 0; /* XXX */ 4626118Skarels #endif 4726118Skarels 4837324Skarels struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; 494901Swnj 5035794Skarels udp_input(m, iphlen) 5135794Skarels register struct mbuf *m; 5235794Skarels int iphlen; 534784Swnj { 5440688Skarels register struct ip *ip; 5540688Skarels register struct udphdr *uh; 564887Swnj register struct inpcb *inp; 5744596Skarels struct mbuf *opts = 0; 587844Sroot int len; 5940688Skarels struct ip save_ip; 604784Swnj 6144596Skarels udpstat.udps_ipackets++; 6244828Skarels 6344828Skarels /* 6444828Skarels * Strip IP options, if any; should skip this, 6544828Skarels * make available to user, and use on returned packets, 6644828Skarels * but we don't yet have a way to check the checksum 6744828Skarels * with options still present. 6844828Skarels */ 6944828Skarels if (iphlen > sizeof (struct ip)) { 7040688Skarels ip_stripoptions(m, (struct mbuf *)0); 7144828Skarels iphlen = sizeof(struct ip); 7244828Skarels } 7344828Skarels 744926Swnj /* 755246Sroot * Get IP and UDP header together in first mbuf. 764926Swnj */ 7740688Skarels ip = mtod(m, struct ip *); 7840688Skarels if (m->m_len < iphlen + sizeof(struct udphdr)) { 7940688Skarels if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { 8035288Skarels udpstat.udps_hdrops++; 8135288Skarels return; 8235288Skarels } 8340688Skarels ip = mtod(m, struct ip *); 8435288Skarels } 8540688Skarels uh = (struct udphdr *)((caddr_t)ip + iphlen); 864926Swnj 874926Swnj /* 885246Sroot * Make mbuf data length reflect UDP length. 895246Sroot * If not enough data to reflect UDP length, drop. 904926Swnj */ 9140688Skarels len = ntohs((u_short)uh->uh_ulen); 9240688Skarels if (ip->ip_len != len) { 9340688Skarels if (len > ip->ip_len) { 944926Swnj udpstat.udps_badlen++; 954926Swnj goto bad; 964926Swnj } 9740688Skarels m_adj(m, len - ip->ip_len); 9840688Skarels /* ip->ip_len = len; */ 994926Swnj } 10024823Skarels /* 10140688Skarels * Save a copy of the IP header in case we want restore it 10240688Skarels * for sending an ICMP error message in response. 10324823Skarels */ 10440688Skarels save_ip = *ip; 1054926Swnj 1064926Swnj /* 1075246Sroot * Checksum extended UDP header and data. 1084926Swnj */ 10940688Skarels if (udpcksum && uh->uh_sum) { 11040688Skarels ((struct ipovly *)ip)->ih_next = 0; 11140688Skarels ((struct ipovly *)ip)->ih_prev = 0; 11240688Skarels ((struct ipovly *)ip)->ih_x1 = 0; 11340688Skarels ((struct ipovly *)ip)->ih_len = uh->uh_ulen; 11440688Skarels if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) { 1154926Swnj udpstat.udps_badsum++; 1164901Swnj m_freem(m); 1174901Swnj return; 1184901Swnj } 1194901Swnj } 1204926Swnj 12157587Sandrew if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || 12258998Ssklower in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { 12354716Ssklower struct socket *last; 12454716Ssklower /* 12554716Ssklower * Deliver a multicast or broadcast datagram to *all* sockets 12654716Ssklower * for which the local and remote addresses and ports match 12754716Ssklower * those of the incoming datagram. This allows more than 12854716Ssklower * one process to receive multi/broadcasts on the same port. 12954716Ssklower * (This really ought to be done for unicast datagrams as 13054716Ssklower * well, but that would cause problems with existing 13154716Ssklower * applications that open both address-specific sockets and 13254716Ssklower * a wildcard socket listening to the same port -- they would 13354716Ssklower * end up receiving duplicates of every unicast datagram. 13454716Ssklower * Those applications open the multiple sockets to overcome an 13554716Ssklower * inadequacy of the UDP socket interface, but for backwards 13654716Ssklower * compatibility we avoid the problem here rather than 13757433Sandrew * fixing the interface. Maybe 4.5BSD will remedy this?) 13854716Ssklower */ 13954716Ssklower 14054716Ssklower /* 14154716Ssklower * Construct sockaddr format source address. 14254716Ssklower */ 14354716Ssklower udp_in.sin_port = uh->uh_sport; 14454716Ssklower udp_in.sin_addr = ip->ip_src; 14554716Ssklower m->m_len -= sizeof (struct udpiphdr); 14654716Ssklower m->m_data += sizeof (struct udpiphdr); 14754716Ssklower /* 14854716Ssklower * Locate pcb(s) for datagram. 14954716Ssklower * (Algorithm copied from raw_intr().) 15054716Ssklower */ 15154716Ssklower last = NULL; 15254716Ssklower for (inp = udb.inp_next; inp != &udb; inp = inp->inp_next) { 15354716Ssklower if (inp->inp_lport != uh->uh_dport) 15454716Ssklower continue; 15554716Ssklower if (inp->inp_laddr.s_addr != INADDR_ANY) { 15654716Ssklower if (inp->inp_laddr.s_addr != 15754716Ssklower ip->ip_dst.s_addr) 15854716Ssklower continue; 15954716Ssklower } 16054716Ssklower if (inp->inp_faddr.s_addr != INADDR_ANY) { 16154716Ssklower if (inp->inp_faddr.s_addr != 16254716Ssklower ip->ip_src.s_addr || 16354716Ssklower inp->inp_fport != uh->uh_sport) 16454716Ssklower continue; 16554716Ssklower } 16654716Ssklower 16754716Ssklower if (last != NULL) { 16854716Ssklower struct mbuf *n; 16954716Ssklower 17054716Ssklower if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 17154716Ssklower if (sbappendaddr(&last->so_rcv, 17254716Ssklower (struct sockaddr *)&udp_in, 17357433Sandrew n, (struct mbuf *)0) == 0) { 17454716Ssklower m_freem(n); 17557433Sandrew udpstat.udps_fullsock++; 17657433Sandrew } else 17754716Ssklower sorwakeup(last); 17854716Ssklower } 17954716Ssklower } 18054716Ssklower last = inp->inp_socket; 18154716Ssklower /* 18254716Ssklower * Don't look for additional matches if this one 18355348Ssklower * does not have the SO_REUSEPORT socket option set. 18454716Ssklower * This heuristic avoids searching through all pcbs 18554716Ssklower * in the common case of a non-shared port. It 18654716Ssklower * assumes that an application will never clear 18755348Ssklower * the SO_REUSEPORT option after setting it. 18854716Ssklower */ 18955348Ssklower if ((last->so_options & SO_REUSEPORT) == 0) 19054716Ssklower break; 19154716Ssklower } 19254716Ssklower 19354716Ssklower if (last == NULL) { 19454716Ssklower /* 19554716Ssklower * No matching pcb found; discard datagram. 19654716Ssklower * (No need to send an ICMP Port Unreachable 19754716Ssklower * for a broadcast or multicast datgram.) 19854716Ssklower */ 19957433Sandrew udpstat.udps_noportbcast++; 20054716Ssklower goto bad; 20154716Ssklower } 20254716Ssklower if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in, 20357433Sandrew m, (struct mbuf *)0) == 0) { 20457433Sandrew udpstat.udps_fullsock++; 20554716Ssklower goto bad; 20657433Sandrew } 20754716Ssklower sorwakeup(last); 20854716Ssklower return; 20954716Ssklower } 2104926Swnj /* 2117844Sroot * Locate pcb for datagram. 2124926Swnj */ 21344596Skarels inp = udp_last_inpcb; 21444596Skarels if (inp->inp_lport != uh->uh_dport || 21544596Skarels inp->inp_fport != uh->uh_sport || 21644596Skarels inp->inp_faddr.s_addr != ip->ip_src.s_addr || 21744596Skarels inp->inp_laddr.s_addr != ip->ip_dst.s_addr) { 21844596Skarels inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport, 21944596Skarels ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD); 22044596Skarels if (inp) 22144596Skarels udp_last_inpcb = inp; 22244596Skarels udpstat.udpps_pcbcachemiss++; 22344596Skarels } 2246584Ssam if (inp == 0) { 22540688Skarels udpstat.udps_noport++; 22640688Skarels *ip = save_ip; 22744828Skarels ip->ip_len += iphlen; 22835794Skarels icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT); 2296584Ssam return; 2306584Ssam } 2316584Ssam 2324926Swnj /* 2334926Swnj * Construct sockaddr format source address. 2344926Swnj * Stuff source address and datagram in user buffer. 2354926Swnj */ 23640688Skarels udp_in.sin_port = uh->uh_sport; 23740688Skarels udp_in.sin_addr = ip->ip_src; 23844596Skarels if (inp->inp_flags & INP_CONTROLOPTS) { 23944596Skarels struct mbuf **mp = &opts; 24044596Skarels struct mbuf *udp_saveopt(); 24144596Skarels 24244596Skarels if (inp->inp_flags & INP_RECVDSTADDR) { 24344596Skarels *mp = udp_saveopt((caddr_t) &ip->ip_dst, 24444596Skarels sizeof(struct in_addr), IP_RECVDSTADDR); 24544596Skarels if (*mp) 24644596Skarels mp = &(*mp)->m_next; 24744596Skarels } 24844596Skarels #ifdef notyet 24944596Skarels /* options were tossed above */ 25044596Skarels if (inp->inp_flags & INP_RECVOPTS) { 25144596Skarels *mp = udp_saveopt((caddr_t) opts_deleted_above, 25244596Skarels sizeof(struct in_addr), IP_RECVOPTS); 25344596Skarels if (*mp) 25444596Skarels mp = &(*mp)->m_next; 25544596Skarels } 25644596Skarels /* ip_srcroute doesn't do what we want here, need to fix */ 25744596Skarels if (inp->inp_flags & INP_RECVRETOPTS) { 25844596Skarels *mp = udp_saveopt((caddr_t) ip_srcroute(), 25944596Skarels sizeof(struct in_addr), IP_RECVRETOPTS); 26044596Skarels if (*mp) 26144596Skarels mp = &(*mp)->m_next; 26244596Skarels } 26344596Skarels #endif 26444596Skarels } 26540688Skarels iphlen += sizeof(struct udphdr); 26640688Skarels m->m_len -= iphlen; 26740688Skarels m->m_pkthdr.len -= iphlen; 26840688Skarels m->m_data += iphlen; 26912767Ssam if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 27044596Skarels m, opts) == 0) { 27144596Skarels udpstat.udps_fullsock++; 2724926Swnj goto bad; 27344596Skarels } 2745050Swnj sorwakeup(inp->inp_socket); 2754887Swnj return; 2764926Swnj bad: 2774887Swnj m_freem(m); 27844596Skarels if (opts) 27944596Skarels m_freem(opts); 2804784Swnj } 2814784Swnj 28226426Skarels /* 28344596Skarels * Create a "control" mbuf containing the specified data 28444596Skarels * with the specified type for presentation with a datagram. 28544596Skarels */ 28644596Skarels struct mbuf * 28744596Skarels udp_saveopt(p, size, type) 28844596Skarels caddr_t p; 28944596Skarels register int size; 29044596Skarels int type; 29144596Skarels { 29244596Skarels register struct cmsghdr *cp; 29344596Skarels struct mbuf *m; 29444596Skarels 29544596Skarels if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) 29644596Skarels return ((struct mbuf *) NULL); 29744596Skarels cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); 29845645Ssklower bcopy(p, (caddr_t)(cp + 1), size); 29944596Skarels size += sizeof(*cp); 30044596Skarels m->m_len = size; 30144596Skarels cp->cmsg_len = size; 30244596Skarels cp->cmsg_level = IPPROTO_IP; 30344596Skarels cp->cmsg_type = type; 30444596Skarels return (m); 30544596Skarels } 30644596Skarels 30744596Skarels /* 30826426Skarels * Notify a udp user of an asynchronous error; 30926426Skarels * just wake up so that he can collect error status. 31026426Skarels */ 31144596Skarels udp_notify(inp, errno) 31226426Skarels register struct inpcb *inp; 31352949Storek int errno; 31426426Skarels { 31544596Skarels inp->inp_socket->so_error = errno; 31626426Skarels sorwakeup(inp->inp_socket); 31726426Skarels sowwakeup(inp->inp_socket); 31826426Skarels } 31926426Skarels 32040688Skarels udp_ctlinput(cmd, sa, ip) 3216591Ssam int cmd; 32224823Skarels struct sockaddr *sa; 32340688Skarels register struct ip *ip; 3246591Ssam { 32540688Skarels register struct udphdr *uh; 32640688Skarels extern struct in_addr zeroin_addr; 3276591Ssam extern u_char inetctlerrmap[]; 3286591Ssam 32957433Sandrew if (!PRC_IS_REDIRECT(cmd) && 33057433Sandrew ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) 3316591Ssam return; 33240688Skarels if (ip) { 33340688Skarels uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 33440688Skarels in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, 33540688Skarels cmd, udp_notify); 33640688Skarels } else 33740688Skarels in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); 3386591Ssam } 3396591Ssam 34042184Skarels udp_output(inp, m, addr, control) 34126060Skarels register struct inpcb *inp; 34235794Skarels register struct mbuf *m; 34342184Skarels struct mbuf *addr, *control; 3444784Swnj { 3454926Swnj register struct udpiphdr *ui; 34635794Skarels register int len = m->m_pkthdr.len; 34742184Skarels struct in_addr laddr; 34842184Skarels int s, error = 0; 3494784Swnj 35042184Skarels if (control) 35142184Skarels m_freem(control); /* XXX */ 35242184Skarels 35342184Skarels if (addr) { 35442184Skarels laddr = inp->inp_laddr; 35542184Skarels if (inp->inp_faddr.s_addr != INADDR_ANY) { 35642184Skarels error = EISCONN; 35742184Skarels goto release; 35842184Skarels } 35942184Skarels /* 36042184Skarels * Must block input while temporarily connected. 36142184Skarels */ 36242184Skarels s = splnet(); 36342184Skarels error = in_pcbconnect(inp, addr); 36442184Skarels if (error) { 36542184Skarels splx(s); 36642184Skarels goto release; 36742184Skarels } 36842184Skarels } else { 36942184Skarels if (inp->inp_faddr.s_addr == INADDR_ANY) { 37042184Skarels error = ENOTCONN; 37142184Skarels goto release; 37242184Skarels } 37342184Skarels } 3744926Swnj /* 3754926Swnj * Calculate data length and get a mbuf 3765246Sroot * for UDP and IP headers. 3774926Swnj */ 37850715Smckusick M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); 37950715Smckusick if (m == 0) { 38050715Smckusick error = ENOBUFS; 38150715Smckusick goto release; 38250715Smckusick } 3834784Swnj 3844926Swnj /* 3855246Sroot * Fill in mbuf with extended UDP header 3864926Swnj * and addresses and length put into network format. 3874926Swnj */ 3884926Swnj ui = mtod(m, struct udpiphdr *); 3894926Swnj ui->ui_next = ui->ui_prev = 0; 3904926Swnj ui->ui_x1 = 0; 3914926Swnj ui->ui_pr = IPPROTO_UDP; 39215226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 3935050Swnj ui->ui_src = inp->inp_laddr; 3945050Swnj ui->ui_dst = inp->inp_faddr; 3955050Swnj ui->ui_sport = inp->inp_lport; 3965050Swnj ui->ui_dport = inp->inp_fport; 39715226Ssam ui->ui_ulen = ui->ui_len; 3984784Swnj 3994926Swnj /* 4004926Swnj * Stuff checksum and output datagram. 4014926Swnj */ 4024926Swnj ui->ui_sum = 0; 40319519Skarels if (udpcksum) { 40419519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 40533715Skarels ui->ui_sum = 0xffff; 40621112Skarels } 4075050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 40844596Skarels ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ 40944596Skarels ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ 41040688Skarels udpstat.udps_opackets++; 41142184Skarels error = ip_output(m, inp->inp_options, &inp->inp_route, 41257433Sandrew inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), 41357433Sandrew inp->inp_moptions); 41442184Skarels 41542184Skarels if (addr) { 41642184Skarels in_pcbdisconnect(inp); 41742184Skarels inp->inp_laddr = laddr; 41842184Skarels splx(s); 41942184Skarels } 42042184Skarels return (error); 42142184Skarels 42242184Skarels release: 42342184Skarels m_freem(m); 42442184Skarels return (error); 4254784Swnj } 4264784Swnj 42738354Smckusick u_long udp_sendspace = 9216; /* really max datagram size */ 42838354Smckusick u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 42938354Smckusick /* 40 1K datagrams */ 43018368Skarels 4318602Sroot /*ARGSUSED*/ 43242184Skarels udp_usrreq(so, req, m, addr, control) 4334887Swnj struct socket *so; 4344784Swnj int req; 43542184Skarels struct mbuf *m, *addr, *control; 4364784Swnj { 4374887Swnj struct inpcb *inp = sotoinpcb(so); 4386507Ssam int error = 0; 43944596Skarels int s; 4404784Swnj 44118368Skarels if (req == PRU_CONTROL) 44242184Skarels return (in_control(so, (int)m, (caddr_t)addr, 44340688Skarels (struct ifnet *)control)); 44411080Ssam if (inp == NULL && req != PRU_ATTACH) { 44511080Ssam error = EINVAL; 44611080Ssam goto release; 44711080Ssam } 44844596Skarels /* 44944968Skarels * Note: need to block udp_input while changing 45044968Skarels * the udp pcb queue and/or pcb addresses. 45144596Skarels */ 4524784Swnj switch (req) { 4534784Swnj 4544784Swnj case PRU_ATTACH: 45511080Ssam if (inp != NULL) { 45611080Ssam error = EINVAL; 45711080Ssam break; 45811080Ssam } 45944596Skarels s = splnet(); 4608273Sroot error = in_pcballoc(so, &udb); 46144596Skarels splx(s); 4628273Sroot if (error) 4638273Sroot break; 46418368Skarels error = soreserve(so, udp_sendspace, udp_recvspace); 4658273Sroot if (error) 4668273Sroot break; 46759133Smckusick ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl; 4684887Swnj break; 4694784Swnj 4704784Swnj case PRU_DETACH: 47144968Skarels udp_detach(inp); 4724887Swnj break; 4734784Swnj 4748273Sroot case PRU_BIND: 47544968Skarels s = splnet(); 47642184Skarels error = in_pcbbind(inp, addr); 47744968Skarels splx(s); 4788273Sroot break; 4798273Sroot 4808273Sroot case PRU_LISTEN: 4818273Sroot error = EOPNOTSUPP; 4828273Sroot break; 4838273Sroot 4844784Swnj case PRU_CONNECT: 48511080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 48611080Ssam error = EISCONN; 48711080Ssam break; 48811080Ssam } 48944968Skarels s = splnet(); 49042184Skarels error = in_pcbconnect(inp, addr); 49144968Skarels splx(s); 4926507Ssam if (error == 0) 4936507Ssam soisconnected(so); 4944887Swnj break; 4954784Swnj 49613118Ssam case PRU_CONNECT2: 49713118Ssam error = EOPNOTSUPP; 49813118Ssam break; 49913118Ssam 5004926Swnj case PRU_ACCEPT: 50111080Ssam error = EOPNOTSUPP; 50211080Ssam break; 5034926Swnj 5044784Swnj case PRU_DISCONNECT: 50511080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 50611080Ssam error = ENOTCONN; 50711080Ssam break; 50811080Ssam } 50944968Skarels s = splnet(); 5105166Swnj in_pcbdisconnect(inp); 51140688Skarels inp->inp_laddr.s_addr = INADDR_ANY; 51244968Skarels splx(s); 51326404Skarels so->so_state &= ~SS_ISCONNECTED; /* XXX */ 5144784Swnj break; 5154784Swnj 5164912Swnj case PRU_SHUTDOWN: 5174912Swnj socantsendmore(so); 5184912Swnj break; 5194912Swnj 52042184Skarels case PRU_SEND: 52144596Skarels return (udp_output(inp, m, addr, control)); 5224784Swnj 5234784Swnj case PRU_ABORT: 52431750Skarels soisdisconnected(so); 52544968Skarels udp_detach(inp); 5264784Swnj break; 5274784Swnj 5286511Ssam case PRU_SOCKADDR: 52942184Skarels in_setsockaddr(inp, addr); 5306511Ssam break; 5316511Ssam 53214124Ssam case PRU_PEERADDR: 53342184Skarels in_setpeeraddr(inp, addr); 53414124Ssam break; 53514124Ssam 53616988Skarels case PRU_SENSE: 53716988Skarels /* 53816988Skarels * stat: don't bother with a blocksize. 53916988Skarels */ 54016988Skarels return (0); 54116988Skarels 54212205Ssam case PRU_SENDOOB: 54312205Ssam case PRU_FASTTIMO: 54412205Ssam case PRU_SLOWTIMO: 54512205Ssam case PRU_PROTORCV: 54612205Ssam case PRU_PROTOSEND: 54712205Ssam error = EOPNOTSUPP; 54812205Ssam break; 54913118Ssam 55016799Skarels case PRU_RCVD: 55116799Skarels case PRU_RCVOOB: 55216799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 55316799Skarels 55413118Ssam default: 55513118Ssam panic("udp_usrreq"); 5564805Swnj } 55744596Skarels 55811080Ssam release: 55942184Skarels if (control) { 56042184Skarels printf("udp control data unexpectedly retained\n"); 56142184Skarels m_freem(control); 56242184Skarels } 56342184Skarels if (m) 56411080Ssam m_freem(m); 5656507Ssam return (error); 5664784Swnj } 56744968Skarels 56844968Skarels udp_detach(inp) 56944968Skarels struct inpcb *inp; 57044968Skarels { 57144968Skarels int s = splnet(); 57244968Skarels 57344968Skarels if (inp == udp_last_inpcb) 57444968Skarels udp_last_inpcb = &udb; 57544968Skarels in_pcbdetach(inp); 57644968Skarels splx(s); 57744968Skarels } 578*59309Smckusick 579*59309Smckusick /* 580*59309Smckusick * Sysctl for udp variables. 581*59309Smckusick */ 582*59309Smckusick udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 583*59309Smckusick int *name; 584*59309Smckusick u_int namelen; 585*59309Smckusick void *oldp; 586*59309Smckusick size_t *oldlenp; 587*59309Smckusick void *newp; 588*59309Smckusick size_t newlen; 589*59309Smckusick { 590*59309Smckusick extern int ip_ttl; 591*59309Smckusick 592*59309Smckusick /* all sysctl names at this level are terminal */ 593*59309Smckusick if (namelen != 1) 594*59309Smckusick return (ENOTDIR); 595*59309Smckusick 596*59309Smckusick switch (name[0]) { 597*59309Smckusick case UDPCTL_CHECKSUM: 598*59309Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); 599*59309Smckusick default: 600*59309Smckusick return (ENOPROTOOPT); 601*59309Smckusick } 602*59309Smckusick /* NOTREACHED */ 603*59309Smckusick } 604