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*57433Sandrew * @(#)udp_usrreq.c 7.27 (Berkeley) 01/08/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 4731398Skarels int udp_ttl = UDP_TTL; 4826118Skarels 4937324Skarels struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; 504901Swnj 5135794Skarels udp_input(m, iphlen) 5235794Skarels register struct mbuf *m; 5335794Skarels int iphlen; 544784Swnj { 5540688Skarels register struct ip *ip; 5640688Skarels register struct udphdr *uh; 574887Swnj register struct inpcb *inp; 5844596Skarels struct mbuf *opts = 0; 597844Sroot int len; 6040688Skarels struct ip save_ip; 614784Swnj 6244596Skarels udpstat.udps_ipackets++; 6344828Skarels 6444828Skarels /* 6544828Skarels * Strip IP options, if any; should skip this, 6644828Skarels * make available to user, and use on returned packets, 6744828Skarels * but we don't yet have a way to check the checksum 6844828Skarels * with options still present. 6944828Skarels */ 7044828Skarels if (iphlen > sizeof (struct ip)) { 7140688Skarels ip_stripoptions(m, (struct mbuf *)0); 7244828Skarels iphlen = sizeof(struct ip); 7344828Skarels } 7444828Skarels 754926Swnj /* 765246Sroot * Get IP and UDP header together in first mbuf. 774926Swnj */ 7840688Skarels ip = mtod(m, struct ip *); 7940688Skarels if (m->m_len < iphlen + sizeof(struct udphdr)) { 8040688Skarels if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { 8135288Skarels udpstat.udps_hdrops++; 8235288Skarels return; 8335288Skarels } 8440688Skarels ip = mtod(m, struct ip *); 8535288Skarels } 8640688Skarels uh = (struct udphdr *)((caddr_t)ip + iphlen); 874926Swnj 884926Swnj /* 895246Sroot * Make mbuf data length reflect UDP length. 905246Sroot * If not enough data to reflect UDP length, drop. 914926Swnj */ 9240688Skarels len = ntohs((u_short)uh->uh_ulen); 9340688Skarels if (ip->ip_len != len) { 9440688Skarels if (len > ip->ip_len) { 954926Swnj udpstat.udps_badlen++; 964926Swnj goto bad; 974926Swnj } 9840688Skarels m_adj(m, len - ip->ip_len); 9940688Skarels /* ip->ip_len = len; */ 1004926Swnj } 10124823Skarels /* 10240688Skarels * Save a copy of the IP header in case we want restore it 10340688Skarels * for sending an ICMP error message in response. 10424823Skarels */ 10540688Skarels save_ip = *ip; 1064926Swnj 1074926Swnj /* 1085246Sroot * Checksum extended UDP header and data. 1094926Swnj */ 11040688Skarels if (udpcksum && uh->uh_sum) { 11140688Skarels ((struct ipovly *)ip)->ih_next = 0; 11240688Skarels ((struct ipovly *)ip)->ih_prev = 0; 11340688Skarels ((struct ipovly *)ip)->ih_x1 = 0; 11440688Skarels ((struct ipovly *)ip)->ih_len = uh->uh_ulen; 11540688Skarels if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) { 1164926Swnj udpstat.udps_badsum++; 1174901Swnj m_freem(m); 1184901Swnj return; 1194901Swnj } 1204901Swnj } 1214926Swnj 12254716Ssklower if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)) || 12354716Ssklower in_broadcast(ip->ip_dst)) { 12454716Ssklower struct socket *last; 12554716Ssklower /* 12654716Ssklower * Deliver a multicast or broadcast datagram to *all* sockets 12754716Ssklower * for which the local and remote addresses and ports match 12854716Ssklower * those of the incoming datagram. This allows more than 12954716Ssklower * one process to receive multi/broadcasts on the same port. 13054716Ssklower * (This really ought to be done for unicast datagrams as 13154716Ssklower * well, but that would cause problems with existing 13254716Ssklower * applications that open both address-specific sockets and 13354716Ssklower * a wildcard socket listening to the same port -- they would 13454716Ssklower * end up receiving duplicates of every unicast datagram. 13554716Ssklower * Those applications open the multiple sockets to overcome an 13654716Ssklower * inadequacy of the UDP socket interface, but for backwards 13754716Ssklower * compatibility we avoid the problem here rather than 138*57433Sandrew * fixing the interface. Maybe 4.5BSD will remedy this?) 13954716Ssklower */ 14054716Ssklower 14154716Ssklower /* 14254716Ssklower * Construct sockaddr format source address. 14354716Ssklower */ 14454716Ssklower udp_in.sin_port = uh->uh_sport; 14554716Ssklower udp_in.sin_addr = ip->ip_src; 14654716Ssklower m->m_len -= sizeof (struct udpiphdr); 14754716Ssklower m->m_data += sizeof (struct udpiphdr); 14854716Ssklower /* 14954716Ssklower * Locate pcb(s) for datagram. 15054716Ssklower * (Algorithm copied from raw_intr().) 15154716Ssklower */ 15254716Ssklower last = NULL; 15354716Ssklower for (inp = udb.inp_next; inp != &udb; inp = inp->inp_next) { 15454716Ssklower if (inp->inp_lport != uh->uh_dport) 15554716Ssklower continue; 15654716Ssklower if (inp->inp_laddr.s_addr != INADDR_ANY) { 15754716Ssklower if (inp->inp_laddr.s_addr != 15854716Ssklower ip->ip_dst.s_addr) 15954716Ssklower continue; 16054716Ssklower } 16154716Ssklower if (inp->inp_faddr.s_addr != INADDR_ANY) { 16254716Ssklower if (inp->inp_faddr.s_addr != 16354716Ssklower ip->ip_src.s_addr || 16454716Ssklower inp->inp_fport != uh->uh_sport) 16554716Ssklower continue; 16654716Ssklower } 16754716Ssklower 16854716Ssklower if (last != NULL) { 16954716Ssklower struct mbuf *n; 17054716Ssklower 17154716Ssklower if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 17254716Ssklower if (sbappendaddr(&last->so_rcv, 17354716Ssklower (struct sockaddr *)&udp_in, 174*57433Sandrew n, (struct mbuf *)0) == 0) { 17554716Ssklower m_freem(n); 176*57433Sandrew udpstat.udps_fullsock++; 177*57433Sandrew } else 17854716Ssklower sorwakeup(last); 17954716Ssklower } 18054716Ssklower } 18154716Ssklower last = inp->inp_socket; 18254716Ssklower /* 18354716Ssklower * Don't look for additional matches if this one 18455348Ssklower * does not have the SO_REUSEPORT socket option set. 18554716Ssklower * This heuristic avoids searching through all pcbs 18654716Ssklower * in the common case of a non-shared port. It 18754716Ssklower * assumes that an application will never clear 18855348Ssklower * the SO_REUSEPORT option after setting it. 18954716Ssklower */ 19055348Ssklower if ((last->so_options & SO_REUSEPORT) == 0) 19154716Ssklower break; 19254716Ssklower } 19354716Ssklower 19454716Ssklower if (last == NULL) { 19554716Ssklower /* 19654716Ssklower * No matching pcb found; discard datagram. 19754716Ssklower * (No need to send an ICMP Port Unreachable 19854716Ssklower * for a broadcast or multicast datgram.) 19954716Ssklower */ 200*57433Sandrew udpstat.udps_noportbcast++; 20154716Ssklower goto bad; 20254716Ssklower } 20354716Ssklower if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in, 204*57433Sandrew m, (struct mbuf *)0) == 0) { 205*57433Sandrew udpstat.udps_fullsock++; 20654716Ssklower goto bad; 207*57433Sandrew } 20854716Ssklower sorwakeup(last); 20954716Ssklower return; 21054716Ssklower } 2114926Swnj /* 2127844Sroot * Locate pcb for datagram. 2134926Swnj */ 21444596Skarels inp = udp_last_inpcb; 21544596Skarels if (inp->inp_lport != uh->uh_dport || 21644596Skarels inp->inp_fport != uh->uh_sport || 21744596Skarels inp->inp_faddr.s_addr != ip->ip_src.s_addr || 21844596Skarels inp->inp_laddr.s_addr != ip->ip_dst.s_addr) { 21944596Skarels inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport, 22044596Skarels ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD); 22144596Skarels if (inp) 22244596Skarels udp_last_inpcb = inp; 22344596Skarels udpstat.udpps_pcbcachemiss++; 22444596Skarels } 2256584Ssam if (inp == 0) { 22640688Skarels udpstat.udps_noport++; 22740688Skarels *ip = save_ip; 22844828Skarels ip->ip_len += iphlen; 22935794Skarels icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT); 2306584Ssam return; 2316584Ssam } 2326584Ssam 2334926Swnj /* 2344926Swnj * Construct sockaddr format source address. 2354926Swnj * Stuff source address and datagram in user buffer. 2364926Swnj */ 23740688Skarels udp_in.sin_port = uh->uh_sport; 23840688Skarels udp_in.sin_addr = ip->ip_src; 23944596Skarels if (inp->inp_flags & INP_CONTROLOPTS) { 24044596Skarels struct mbuf **mp = &opts; 24144596Skarels struct mbuf *udp_saveopt(); 24244596Skarels 24344596Skarels if (inp->inp_flags & INP_RECVDSTADDR) { 24444596Skarels *mp = udp_saveopt((caddr_t) &ip->ip_dst, 24544596Skarels sizeof(struct in_addr), IP_RECVDSTADDR); 24644596Skarels if (*mp) 24744596Skarels mp = &(*mp)->m_next; 24844596Skarels } 24944596Skarels #ifdef notyet 25044596Skarels /* options were tossed above */ 25144596Skarels if (inp->inp_flags & INP_RECVOPTS) { 25244596Skarels *mp = udp_saveopt((caddr_t) opts_deleted_above, 25344596Skarels sizeof(struct in_addr), IP_RECVOPTS); 25444596Skarels if (*mp) 25544596Skarels mp = &(*mp)->m_next; 25644596Skarels } 25744596Skarels /* ip_srcroute doesn't do what we want here, need to fix */ 25844596Skarels if (inp->inp_flags & INP_RECVRETOPTS) { 25944596Skarels *mp = udp_saveopt((caddr_t) ip_srcroute(), 26044596Skarels sizeof(struct in_addr), IP_RECVRETOPTS); 26144596Skarels if (*mp) 26244596Skarels mp = &(*mp)->m_next; 26344596Skarels } 26444596Skarels #endif 26544596Skarels } 26640688Skarels iphlen += sizeof(struct udphdr); 26740688Skarels m->m_len -= iphlen; 26840688Skarels m->m_pkthdr.len -= iphlen; 26940688Skarels m->m_data += iphlen; 27012767Ssam if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 27144596Skarels m, opts) == 0) { 27244596Skarels udpstat.udps_fullsock++; 2734926Swnj goto bad; 27444596Skarels } 2755050Swnj sorwakeup(inp->inp_socket); 2764887Swnj return; 2774926Swnj bad: 2784887Swnj m_freem(m); 27944596Skarels if (opts) 28044596Skarels m_freem(opts); 2814784Swnj } 2824784Swnj 28326426Skarels /* 28444596Skarels * Create a "control" mbuf containing the specified data 28544596Skarels * with the specified type for presentation with a datagram. 28644596Skarels */ 28744596Skarels struct mbuf * 28844596Skarels udp_saveopt(p, size, type) 28944596Skarels caddr_t p; 29044596Skarels register int size; 29144596Skarels int type; 29244596Skarels { 29344596Skarels register struct cmsghdr *cp; 29444596Skarels struct mbuf *m; 29544596Skarels 29644596Skarels if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) 29744596Skarels return ((struct mbuf *) NULL); 29844596Skarels cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); 29945645Ssklower bcopy(p, (caddr_t)(cp + 1), size); 30044596Skarels size += sizeof(*cp); 30144596Skarels m->m_len = size; 30244596Skarels cp->cmsg_len = size; 30344596Skarels cp->cmsg_level = IPPROTO_IP; 30444596Skarels cp->cmsg_type = type; 30544596Skarels return (m); 30644596Skarels } 30744596Skarels 30844596Skarels /* 30926426Skarels * Notify a udp user of an asynchronous error; 31026426Skarels * just wake up so that he can collect error status. 31126426Skarels */ 31244596Skarels udp_notify(inp, errno) 31326426Skarels register struct inpcb *inp; 31452949Storek int errno; 31526426Skarels { 31644596Skarels inp->inp_socket->so_error = errno; 31726426Skarels sorwakeup(inp->inp_socket); 31826426Skarels sowwakeup(inp->inp_socket); 31926426Skarels } 32026426Skarels 32140688Skarels udp_ctlinput(cmd, sa, ip) 3226591Ssam int cmd; 32324823Skarels struct sockaddr *sa; 32440688Skarels register struct ip *ip; 3256591Ssam { 32640688Skarels register struct udphdr *uh; 32740688Skarels extern struct in_addr zeroin_addr; 3286591Ssam extern u_char inetctlerrmap[]; 3296591Ssam 330*57433Sandrew if (!PRC_IS_REDIRECT(cmd) && 331*57433Sandrew ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) 3326591Ssam return; 33340688Skarels if (ip) { 33440688Skarels uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 33540688Skarels in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, 33640688Skarels cmd, udp_notify); 33740688Skarels } else 33840688Skarels in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); 3396591Ssam } 3406591Ssam 34142184Skarels udp_output(inp, m, addr, control) 34226060Skarels register struct inpcb *inp; 34335794Skarels register struct mbuf *m; 34442184Skarels struct mbuf *addr, *control; 3454784Swnj { 3464926Swnj register struct udpiphdr *ui; 34735794Skarels register int len = m->m_pkthdr.len; 34842184Skarels struct in_addr laddr; 34942184Skarels int s, error = 0; 3504784Swnj 35142184Skarels if (control) 35242184Skarels m_freem(control); /* XXX */ 35342184Skarels 35442184Skarels if (addr) { 35542184Skarels laddr = inp->inp_laddr; 35642184Skarels if (inp->inp_faddr.s_addr != INADDR_ANY) { 35742184Skarels error = EISCONN; 35842184Skarels goto release; 35942184Skarels } 36042184Skarels /* 36142184Skarels * Must block input while temporarily connected. 36242184Skarels */ 36342184Skarels s = splnet(); 36442184Skarels error = in_pcbconnect(inp, addr); 36542184Skarels if (error) { 36642184Skarels splx(s); 36742184Skarels goto release; 36842184Skarels } 36942184Skarels } else { 37042184Skarels if (inp->inp_faddr.s_addr == INADDR_ANY) { 37142184Skarels error = ENOTCONN; 37242184Skarels goto release; 37342184Skarels } 37442184Skarels } 3754926Swnj /* 3764926Swnj * Calculate data length and get a mbuf 3775246Sroot * for UDP and IP headers. 3784926Swnj */ 37950715Smckusick M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); 38050715Smckusick if (m == 0) { 38150715Smckusick error = ENOBUFS; 38250715Smckusick goto release; 38350715Smckusick } 3844784Swnj 3854926Swnj /* 3865246Sroot * Fill in mbuf with extended UDP header 3874926Swnj * and addresses and length put into network format. 3884926Swnj */ 3894926Swnj ui = mtod(m, struct udpiphdr *); 3904926Swnj ui->ui_next = ui->ui_prev = 0; 3914926Swnj ui->ui_x1 = 0; 3924926Swnj ui->ui_pr = IPPROTO_UDP; 39315226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 3945050Swnj ui->ui_src = inp->inp_laddr; 3955050Swnj ui->ui_dst = inp->inp_faddr; 3965050Swnj ui->ui_sport = inp->inp_lport; 3975050Swnj ui->ui_dport = inp->inp_fport; 39815226Ssam ui->ui_ulen = ui->ui_len; 3994784Swnj 4004926Swnj /* 4014926Swnj * Stuff checksum and output datagram. 4024926Swnj */ 4034926Swnj ui->ui_sum = 0; 40419519Skarels if (udpcksum) { 40519519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 40633715Skarels ui->ui_sum = 0xffff; 40721112Skarels } 4085050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 40944596Skarels ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ 41044596Skarels ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ 41140688Skarels udpstat.udps_opackets++; 41242184Skarels error = ip_output(m, inp->inp_options, &inp->inp_route, 413*57433Sandrew inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), 414*57433Sandrew inp->inp_moptions); 41542184Skarels 41642184Skarels if (addr) { 41742184Skarels in_pcbdisconnect(inp); 41842184Skarels inp->inp_laddr = laddr; 41942184Skarels splx(s); 42042184Skarels } 42142184Skarels return (error); 42242184Skarels 42342184Skarels release: 42442184Skarels m_freem(m); 42542184Skarels return (error); 4264784Swnj } 4274784Swnj 42838354Smckusick u_long udp_sendspace = 9216; /* really max datagram size */ 42938354Smckusick u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 43038354Smckusick /* 40 1K datagrams */ 43118368Skarels 4328602Sroot /*ARGSUSED*/ 43342184Skarels udp_usrreq(so, req, m, addr, control) 4344887Swnj struct socket *so; 4354784Swnj int req; 43642184Skarels struct mbuf *m, *addr, *control; 4374784Swnj { 4384887Swnj struct inpcb *inp = sotoinpcb(so); 4396507Ssam int error = 0; 44044596Skarels int s; 4414784Swnj 44218368Skarels if (req == PRU_CONTROL) 44342184Skarels return (in_control(so, (int)m, (caddr_t)addr, 44440688Skarels (struct ifnet *)control)); 44511080Ssam if (inp == NULL && req != PRU_ATTACH) { 44611080Ssam error = EINVAL; 44711080Ssam goto release; 44811080Ssam } 44944596Skarels /* 45044968Skarels * Note: need to block udp_input while changing 45144968Skarels * the udp pcb queue and/or pcb addresses. 45244596Skarels */ 4534784Swnj switch (req) { 4544784Swnj 4554784Swnj case PRU_ATTACH: 45611080Ssam if (inp != NULL) { 45711080Ssam error = EINVAL; 45811080Ssam break; 45911080Ssam } 46044596Skarels s = splnet(); 4618273Sroot error = in_pcballoc(so, &udb); 46244596Skarels splx(s); 4638273Sroot if (error) 4648273Sroot break; 46518368Skarels error = soreserve(so, udp_sendspace, udp_recvspace); 4668273Sroot if (error) 4678273Sroot break; 46844596Skarels ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = udp_ttl; 4694887Swnj break; 4704784Swnj 4714784Swnj case PRU_DETACH: 47244968Skarels udp_detach(inp); 4734887Swnj break; 4744784Swnj 4758273Sroot case PRU_BIND: 47644968Skarels s = splnet(); 47742184Skarels error = in_pcbbind(inp, addr); 47844968Skarels splx(s); 4798273Sroot break; 4808273Sroot 4818273Sroot case PRU_LISTEN: 4828273Sroot error = EOPNOTSUPP; 4838273Sroot break; 4848273Sroot 4854784Swnj case PRU_CONNECT: 48611080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 48711080Ssam error = EISCONN; 48811080Ssam break; 48911080Ssam } 49044968Skarels s = splnet(); 49142184Skarels error = in_pcbconnect(inp, addr); 49244968Skarels splx(s); 4936507Ssam if (error == 0) 4946507Ssam soisconnected(so); 4954887Swnj break; 4964784Swnj 49713118Ssam case PRU_CONNECT2: 49813118Ssam error = EOPNOTSUPP; 49913118Ssam break; 50013118Ssam 5014926Swnj case PRU_ACCEPT: 50211080Ssam error = EOPNOTSUPP; 50311080Ssam break; 5044926Swnj 5054784Swnj case PRU_DISCONNECT: 50611080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 50711080Ssam error = ENOTCONN; 50811080Ssam break; 50911080Ssam } 51044968Skarels s = splnet(); 5115166Swnj in_pcbdisconnect(inp); 51240688Skarels inp->inp_laddr.s_addr = INADDR_ANY; 51344968Skarels splx(s); 51426404Skarels so->so_state &= ~SS_ISCONNECTED; /* XXX */ 5154784Swnj break; 5164784Swnj 5174912Swnj case PRU_SHUTDOWN: 5184912Swnj socantsendmore(so); 5194912Swnj break; 5204912Swnj 52142184Skarels case PRU_SEND: 52244596Skarels return (udp_output(inp, m, addr, control)); 5234784Swnj 5244784Swnj case PRU_ABORT: 52531750Skarels soisdisconnected(so); 52644968Skarels udp_detach(inp); 5274784Swnj break; 5284784Swnj 5296511Ssam case PRU_SOCKADDR: 53042184Skarels in_setsockaddr(inp, addr); 5316511Ssam break; 5326511Ssam 53314124Ssam case PRU_PEERADDR: 53442184Skarels in_setpeeraddr(inp, addr); 53514124Ssam break; 53614124Ssam 53716988Skarels case PRU_SENSE: 53816988Skarels /* 53916988Skarels * stat: don't bother with a blocksize. 54016988Skarels */ 54116988Skarels return (0); 54216988Skarels 54312205Ssam case PRU_SENDOOB: 54412205Ssam case PRU_FASTTIMO: 54512205Ssam case PRU_SLOWTIMO: 54612205Ssam case PRU_PROTORCV: 54712205Ssam case PRU_PROTOSEND: 54812205Ssam error = EOPNOTSUPP; 54912205Ssam break; 55013118Ssam 55116799Skarels case PRU_RCVD: 55216799Skarels case PRU_RCVOOB: 55316799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 55416799Skarels 55513118Ssam default: 55613118Ssam panic("udp_usrreq"); 5574805Swnj } 55844596Skarels 55911080Ssam release: 56042184Skarels if (control) { 56142184Skarels printf("udp control data unexpectedly retained\n"); 56242184Skarels m_freem(control); 56342184Skarels } 56442184Skarels if (m) 56511080Ssam m_freem(m); 5666507Ssam return (error); 5674784Swnj } 56844968Skarels 56944968Skarels udp_detach(inp) 57044968Skarels struct inpcb *inp; 57144968Skarels { 57244968Skarels int s = splnet(); 57344968Skarels 57444968Skarels if (inp == udp_last_inpcb) 57544968Skarels udp_last_inpcb = &udb; 57644968Skarels in_pcbdetach(inp); 57744968Skarels splx(s); 57844968Skarels } 579