123199Smckusick /* 263220Sbostic * Copyright (c) 1982, 1986, 1988, 1990, 1993 365801Sbostic * The Regents of the University of California. All rights reserved. 423199Smckusick * 544642Sbostic * %sccs.include.redist.c% 632789Sbostic * 7*68170Scgd * @(#)udp_usrreq.c 8.5 (Berkeley) 01/09/95 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 314926Swnj /* 324926Swnj * UDP protocol implementation. 334926Swnj * Per RFC 768, August, 1980. 344926Swnj */ 3526118Skarels #ifndef COMPAT_42 3619519Skarels int udpcksum = 1; 3726118Skarels #else 3826118Skarels int udpcksum = 0; /* XXX */ 3926118Skarels #endif 4026118Skarels 4137324Skarels struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; 4261335Sbostic struct inpcb *udp_last_inpcb = &udb; 434901Swnj 4461335Sbostic static void udp_detach __P((struct inpcb *)); 4561335Sbostic static void udp_notify __P((struct inpcb *, int)); 4661335Sbostic static struct mbuf *udp_saveopt __P((caddr_t, int, int)); 4761335Sbostic 4861335Sbostic void 4961335Sbostic udp_init() 5061335Sbostic { 5161335Sbostic udb.inp_next = udb.inp_prev = &udb; 5261335Sbostic } 5361335Sbostic 5461335Sbostic void 5535794Skarels udp_input(m, iphlen) 5635794Skarels register struct mbuf *m; 5735794Skarels int iphlen; 584784Swnj { 5940688Skarels register struct ip *ip; 6040688Skarels register struct udphdr *uh; 614887Swnj register struct inpcb *inp; 6244596Skarels struct mbuf *opts = 0; 637844Sroot int len; 6440688Skarels struct ip save_ip; 654784Swnj 6644596Skarels udpstat.udps_ipackets++; 6744828Skarels 6844828Skarels /* 6944828Skarels * Strip IP options, if any; should skip this, 7044828Skarels * make available to user, and use on returned packets, 7144828Skarels * but we don't yet have a way to check the checksum 7244828Skarels * with options still present. 7344828Skarels */ 7444828Skarels if (iphlen > sizeof (struct ip)) { 7540688Skarels ip_stripoptions(m, (struct mbuf *)0); 7644828Skarels iphlen = sizeof(struct ip); 7744828Skarels } 7844828Skarels 794926Swnj /* 805246Sroot * Get IP and UDP header together in first mbuf. 814926Swnj */ 8240688Skarels ip = mtod(m, struct ip *); 8340688Skarels if (m->m_len < iphlen + sizeof(struct udphdr)) { 8440688Skarels if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { 8535288Skarels udpstat.udps_hdrops++; 8635288Skarels return; 8735288Skarels } 8840688Skarels ip = mtod(m, struct ip *); 8935288Skarels } 9040688Skarels uh = (struct udphdr *)((caddr_t)ip + iphlen); 914926Swnj 924926Swnj /* 935246Sroot * Make mbuf data length reflect UDP length. 945246Sroot * If not enough data to reflect UDP length, drop. 954926Swnj */ 9640688Skarels len = ntohs((u_short)uh->uh_ulen); 9740688Skarels if (ip->ip_len != len) { 9840688Skarels if (len > ip->ip_len) { 994926Swnj udpstat.udps_badlen++; 1004926Swnj goto bad; 1014926Swnj } 10240688Skarels m_adj(m, len - ip->ip_len); 10340688Skarels /* ip->ip_len = len; */ 1044926Swnj } 10524823Skarels /* 10640688Skarels * Save a copy of the IP header in case we want restore it 10740688Skarels * for sending an ICMP error message in response. 10824823Skarels */ 10940688Skarels save_ip = *ip; 1104926Swnj 1114926Swnj /* 1125246Sroot * Checksum extended UDP header and data. 1134926Swnj */ 11440688Skarels if (udpcksum && uh->uh_sum) { 11540688Skarels ((struct ipovly *)ip)->ih_next = 0; 11640688Skarels ((struct ipovly *)ip)->ih_prev = 0; 11740688Skarels ((struct ipovly *)ip)->ih_x1 = 0; 11840688Skarels ((struct ipovly *)ip)->ih_len = uh->uh_ulen; 11940688Skarels if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) { 1204926Swnj udpstat.udps_badsum++; 1214901Swnj m_freem(m); 1224901Swnj return; 1234901Swnj } 1244901Swnj } 1254926Swnj 12657587Sandrew if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || 12758998Ssklower in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { 12854716Ssklower struct socket *last; 12954716Ssklower /* 13054716Ssklower * Deliver a multicast or broadcast datagram to *all* sockets 13154716Ssklower * for which the local and remote addresses and ports match 13254716Ssklower * those of the incoming datagram. This allows more than 13354716Ssklower * one process to receive multi/broadcasts on the same port. 13454716Ssklower * (This really ought to be done for unicast datagrams as 13554716Ssklower * well, but that would cause problems with existing 13654716Ssklower * applications that open both address-specific sockets and 13754716Ssklower * a wildcard socket listening to the same port -- they would 13854716Ssklower * end up receiving duplicates of every unicast datagram. 13954716Ssklower * Those applications open the multiple sockets to overcome an 14054716Ssklower * inadequacy of the UDP socket interface, but for backwards 14154716Ssklower * compatibility we avoid the problem here rather than 14257433Sandrew * fixing the interface. Maybe 4.5BSD will remedy this?) 14354716Ssklower */ 14454716Ssklower 14554716Ssklower /* 14654716Ssklower * Construct sockaddr format source address. 14754716Ssklower */ 14854716Ssklower udp_in.sin_port = uh->uh_sport; 14954716Ssklower udp_in.sin_addr = ip->ip_src; 15054716Ssklower m->m_len -= sizeof (struct udpiphdr); 15154716Ssklower m->m_data += sizeof (struct udpiphdr); 15254716Ssklower /* 15354716Ssklower * Locate pcb(s) for datagram. 15454716Ssklower * (Algorithm copied from raw_intr().) 15554716Ssklower */ 15654716Ssklower last = NULL; 15754716Ssklower for (inp = udb.inp_next; inp != &udb; inp = inp->inp_next) { 15854716Ssklower if (inp->inp_lport != uh->uh_dport) 15954716Ssklower continue; 16054716Ssklower if (inp->inp_laddr.s_addr != INADDR_ANY) { 16154716Ssklower if (inp->inp_laddr.s_addr != 16254716Ssklower ip->ip_dst.s_addr) 16354716Ssklower continue; 16454716Ssklower } 16554716Ssklower if (inp->inp_faddr.s_addr != INADDR_ANY) { 16654716Ssklower if (inp->inp_faddr.s_addr != 16754716Ssklower ip->ip_src.s_addr || 16854716Ssklower inp->inp_fport != uh->uh_sport) 16954716Ssklower continue; 17054716Ssklower } 17154716Ssklower 17254716Ssklower if (last != NULL) { 17354716Ssklower struct mbuf *n; 17454716Ssklower 17554716Ssklower if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 17654716Ssklower if (sbappendaddr(&last->so_rcv, 17754716Ssklower (struct sockaddr *)&udp_in, 17857433Sandrew n, (struct mbuf *)0) == 0) { 17954716Ssklower m_freem(n); 18057433Sandrew udpstat.udps_fullsock++; 18157433Sandrew } else 18254716Ssklower sorwakeup(last); 18354716Ssklower } 18454716Ssklower } 18554716Ssklower last = inp->inp_socket; 18654716Ssklower /* 18760849Skarels * Don't look for additional matches if this one does 18860849Skarels * not have either the SO_REUSEPORT or SO_REUSEADDR 18960849Skarels * socket options set. This heuristic avoids searching 19060849Skarels * through all pcbs in the common case of a non-shared 19160849Skarels * port. It * assumes that an application will never 19260849Skarels * clear these options after setting them. 19354716Ssklower */ 19460849Skarels if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0)) 19554716Ssklower break; 19654716Ssklower } 19754716Ssklower 19854716Ssklower if (last == NULL) { 19954716Ssklower /* 20054716Ssklower * No matching pcb found; discard datagram. 20154716Ssklower * (No need to send an ICMP Port Unreachable 20254716Ssklower * for a broadcast or multicast datgram.) 20354716Ssklower */ 20457433Sandrew udpstat.udps_noportbcast++; 20554716Ssklower goto bad; 20654716Ssklower } 20754716Ssklower if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in, 20857433Sandrew m, (struct mbuf *)0) == 0) { 20957433Sandrew udpstat.udps_fullsock++; 21054716Ssklower goto bad; 21157433Sandrew } 21254716Ssklower sorwakeup(last); 21354716Ssklower return; 21454716Ssklower } 2154926Swnj /* 2167844Sroot * Locate pcb for datagram. 2174926Swnj */ 21844596Skarels inp = udp_last_inpcb; 21944596Skarels if (inp->inp_lport != uh->uh_dport || 22044596Skarels inp->inp_fport != uh->uh_sport || 22144596Skarels inp->inp_faddr.s_addr != ip->ip_src.s_addr || 22244596Skarels inp->inp_laddr.s_addr != ip->ip_dst.s_addr) { 22344596Skarels inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport, 22444596Skarels ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD); 22544596Skarels if (inp) 22644596Skarels udp_last_inpcb = inp; 22744596Skarels udpstat.udpps_pcbcachemiss++; 22844596Skarels } 2296584Ssam if (inp == 0) { 23040688Skarels udpstat.udps_noport++; 23165264Smckusick if (m->m_flags & (M_BCAST | M_MCAST)) { 23265264Smckusick udpstat.udps_noportbcast++; 23365264Smckusick goto bad; 23465264Smckusick } 23540688Skarels *ip = save_ip; 23644828Skarels ip->ip_len += iphlen; 23760637Smckusick icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); 2386584Ssam return; 2396584Ssam } 2406584Ssam 2414926Swnj /* 2424926Swnj * Construct sockaddr format source address. 2434926Swnj * Stuff source address and datagram in user buffer. 2444926Swnj */ 24540688Skarels udp_in.sin_port = uh->uh_sport; 24640688Skarels udp_in.sin_addr = ip->ip_src; 24744596Skarels if (inp->inp_flags & INP_CONTROLOPTS) { 24844596Skarels struct mbuf **mp = &opts; 24944596Skarels 25044596Skarels if (inp->inp_flags & INP_RECVDSTADDR) { 25144596Skarels *mp = udp_saveopt((caddr_t) &ip->ip_dst, 25244596Skarels sizeof(struct in_addr), IP_RECVDSTADDR); 25344596Skarels if (*mp) 25444596Skarels mp = &(*mp)->m_next; 25544596Skarels } 25644596Skarels #ifdef notyet 25744596Skarels /* options were tossed above */ 25844596Skarels if (inp->inp_flags & INP_RECVOPTS) { 25944596Skarels *mp = udp_saveopt((caddr_t) opts_deleted_above, 26044596Skarels sizeof(struct in_addr), IP_RECVOPTS); 26144596Skarels if (*mp) 26244596Skarels mp = &(*mp)->m_next; 26344596Skarels } 26444596Skarels /* ip_srcroute doesn't do what we want here, need to fix */ 26544596Skarels if (inp->inp_flags & INP_RECVRETOPTS) { 26644596Skarels *mp = udp_saveopt((caddr_t) ip_srcroute(), 26744596Skarels sizeof(struct in_addr), IP_RECVRETOPTS); 26844596Skarels if (*mp) 26944596Skarels mp = &(*mp)->m_next; 27044596Skarels } 27144596Skarels #endif 27244596Skarels } 27340688Skarels iphlen += sizeof(struct udphdr); 27440688Skarels m->m_len -= iphlen; 27540688Skarels m->m_pkthdr.len -= iphlen; 27640688Skarels m->m_data += iphlen; 27712767Ssam if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 27844596Skarels m, opts) == 0) { 27944596Skarels udpstat.udps_fullsock++; 2804926Swnj goto bad; 28144596Skarels } 2825050Swnj sorwakeup(inp->inp_socket); 2834887Swnj return; 2844926Swnj bad: 2854887Swnj m_freem(m); 28644596Skarels if (opts) 28744596Skarels m_freem(opts); 2884784Swnj } 2894784Swnj 29026426Skarels /* 29144596Skarels * Create a "control" mbuf containing the specified data 29244596Skarels * with the specified type for presentation with a datagram. 29344596Skarels */ 29444596Skarels struct mbuf * 29544596Skarels udp_saveopt(p, size, type) 29644596Skarels caddr_t p; 29744596Skarels register int size; 29844596Skarels int type; 29944596Skarels { 30044596Skarels register struct cmsghdr *cp; 30144596Skarels struct mbuf *m; 30244596Skarels 30344596Skarels if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) 30444596Skarels return ((struct mbuf *) NULL); 30544596Skarels cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); 30660501Smckusick bcopy(p, CMSG_DATA(cp), size); 30744596Skarels size += sizeof(*cp); 30844596Skarels m->m_len = size; 30944596Skarels cp->cmsg_len = size; 31044596Skarels cp->cmsg_level = IPPROTO_IP; 31144596Skarels cp->cmsg_type = type; 31244596Skarels return (m); 31344596Skarels } 31444596Skarels 31544596Skarels /* 31626426Skarels * Notify a udp user of an asynchronous error; 31726426Skarels * just wake up so that he can collect error status. 31826426Skarels */ 31961335Sbostic static void 32044596Skarels udp_notify(inp, errno) 32126426Skarels register struct inpcb *inp; 32252949Storek int errno; 32326426Skarels { 32444596Skarels inp->inp_socket->so_error = errno; 32526426Skarels sorwakeup(inp->inp_socket); 32626426Skarels sowwakeup(inp->inp_socket); 32726426Skarels } 32826426Skarels 32961335Sbostic void 33040688Skarels udp_ctlinput(cmd, sa, ip) 3316591Ssam int cmd; 33224823Skarels struct sockaddr *sa; 33340688Skarels register struct ip *ip; 3346591Ssam { 33540688Skarels register struct udphdr *uh; 33640688Skarels extern struct in_addr zeroin_addr; 3376591Ssam extern u_char inetctlerrmap[]; 3386591Ssam 33957433Sandrew if (!PRC_IS_REDIRECT(cmd) && 34057433Sandrew ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) 3416591Ssam return; 34240688Skarels if (ip) { 34340688Skarels uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 34440688Skarels in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, 34540688Skarels cmd, udp_notify); 34640688Skarels } else 34740688Skarels in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); 3486591Ssam } 3496591Ssam 35061335Sbostic int 35142184Skarels udp_output(inp, m, addr, control) 35226060Skarels register struct inpcb *inp; 35335794Skarels register struct mbuf *m; 35442184Skarels struct mbuf *addr, *control; 3554784Swnj { 3564926Swnj register struct udpiphdr *ui; 35735794Skarels register int len = m->m_pkthdr.len; 35842184Skarels struct in_addr laddr; 35942184Skarels int s, error = 0; 3604784Swnj 36142184Skarels if (control) 36242184Skarels m_freem(control); /* XXX */ 36342184Skarels 36442184Skarels if (addr) { 36542184Skarels laddr = inp->inp_laddr; 36642184Skarels if (inp->inp_faddr.s_addr != INADDR_ANY) { 36742184Skarels error = EISCONN; 36842184Skarels goto release; 36942184Skarels } 37042184Skarels /* 37142184Skarels * Must block input while temporarily connected. 37242184Skarels */ 37342184Skarels s = splnet(); 37442184Skarels error = in_pcbconnect(inp, addr); 37542184Skarels if (error) { 37642184Skarels splx(s); 37742184Skarels goto release; 37842184Skarels } 37942184Skarels } else { 38042184Skarels if (inp->inp_faddr.s_addr == INADDR_ANY) { 38142184Skarels error = ENOTCONN; 38242184Skarels goto release; 38342184Skarels } 38442184Skarels } 3854926Swnj /* 3864926Swnj * Calculate data length and get a mbuf 3875246Sroot * for UDP and IP headers. 3884926Swnj */ 38950715Smckusick M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); 39050715Smckusick if (m == 0) { 39150715Smckusick error = ENOBUFS; 39250715Smckusick goto release; 39350715Smckusick } 3944784Swnj 3954926Swnj /* 3965246Sroot * Fill in mbuf with extended UDP header 3974926Swnj * and addresses and length put into network format. 3984926Swnj */ 3994926Swnj ui = mtod(m, struct udpiphdr *); 4004926Swnj ui->ui_next = ui->ui_prev = 0; 4014926Swnj ui->ui_x1 = 0; 4024926Swnj ui->ui_pr = IPPROTO_UDP; 40315226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 4045050Swnj ui->ui_src = inp->inp_laddr; 4055050Swnj ui->ui_dst = inp->inp_faddr; 4065050Swnj ui->ui_sport = inp->inp_lport; 4075050Swnj ui->ui_dport = inp->inp_fport; 40815226Ssam ui->ui_ulen = ui->ui_len; 4094784Swnj 4104926Swnj /* 4114926Swnj * Stuff checksum and output datagram. 4124926Swnj */ 4134926Swnj ui->ui_sum = 0; 41419519Skarels if (udpcksum) { 41519519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 41633715Skarels ui->ui_sum = 0xffff; 41721112Skarels } 4185050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 41944596Skarels ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ 42044596Skarels ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ 42140688Skarels udpstat.udps_opackets++; 42242184Skarels error = ip_output(m, inp->inp_options, &inp->inp_route, 42357433Sandrew inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), 42457433Sandrew inp->inp_moptions); 42542184Skarels 42642184Skarels if (addr) { 42742184Skarels in_pcbdisconnect(inp); 42842184Skarels inp->inp_laddr = laddr; 42942184Skarels splx(s); 43042184Skarels } 43142184Skarels return (error); 43242184Skarels 43342184Skarels release: 43442184Skarels m_freem(m); 43542184Skarels return (error); 4364784Swnj } 4374784Swnj 43838354Smckusick u_long udp_sendspace = 9216; /* really max datagram size */ 43938354Smckusick u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 44038354Smckusick /* 40 1K datagrams */ 44118368Skarels 4428602Sroot /*ARGSUSED*/ 44361335Sbostic int 44442184Skarels udp_usrreq(so, req, m, addr, control) 4454887Swnj struct socket *so; 4464784Swnj int req; 44742184Skarels struct mbuf *m, *addr, *control; 4484784Swnj { 4494887Swnj struct inpcb *inp = sotoinpcb(so); 4506507Ssam int error = 0; 45144596Skarels int s; 4524784Swnj 45318368Skarels if (req == PRU_CONTROL) 454*68170Scgd return (in_control(so, (u_long)m, (caddr_t)addr, 45540688Skarels (struct ifnet *)control)); 45611080Ssam if (inp == NULL && req != PRU_ATTACH) { 45711080Ssam error = EINVAL; 45811080Ssam goto release; 45911080Ssam } 46044596Skarels /* 46144968Skarels * Note: need to block udp_input while changing 46244968Skarels * the udp pcb queue and/or pcb addresses. 46344596Skarels */ 4644784Swnj switch (req) { 4654784Swnj 4664784Swnj case PRU_ATTACH: 46711080Ssam if (inp != NULL) { 46811080Ssam error = EINVAL; 46911080Ssam break; 47011080Ssam } 47144596Skarels s = splnet(); 4728273Sroot error = in_pcballoc(so, &udb); 47344596Skarels splx(s); 4748273Sroot if (error) 4758273Sroot break; 47618368Skarels error = soreserve(so, udp_sendspace, udp_recvspace); 4778273Sroot if (error) 4788273Sroot break; 47959133Smckusick ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl; 4804887Swnj break; 4814784Swnj 4824784Swnj case PRU_DETACH: 48344968Skarels udp_detach(inp); 4844887Swnj break; 4854784Swnj 4868273Sroot case PRU_BIND: 48744968Skarels s = splnet(); 48842184Skarels error = in_pcbbind(inp, addr); 48944968Skarels splx(s); 4908273Sroot break; 4918273Sroot 4928273Sroot case PRU_LISTEN: 4938273Sroot error = EOPNOTSUPP; 4948273Sroot break; 4958273Sroot 4964784Swnj case PRU_CONNECT: 49711080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 49811080Ssam error = EISCONN; 49911080Ssam break; 50011080Ssam } 50144968Skarels s = splnet(); 50242184Skarels error = in_pcbconnect(inp, addr); 50344968Skarels splx(s); 5046507Ssam if (error == 0) 5056507Ssam soisconnected(so); 5064887Swnj break; 5074784Swnj 50813118Ssam case PRU_CONNECT2: 50913118Ssam error = EOPNOTSUPP; 51013118Ssam break; 51113118Ssam 5124926Swnj case PRU_ACCEPT: 51311080Ssam error = EOPNOTSUPP; 51411080Ssam break; 5154926Swnj 5164784Swnj case PRU_DISCONNECT: 51711080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 51811080Ssam error = ENOTCONN; 51911080Ssam break; 52011080Ssam } 52144968Skarels s = splnet(); 5225166Swnj in_pcbdisconnect(inp); 52340688Skarels inp->inp_laddr.s_addr = INADDR_ANY; 52444968Skarels splx(s); 52526404Skarels so->so_state &= ~SS_ISCONNECTED; /* XXX */ 5264784Swnj break; 5274784Swnj 5284912Swnj case PRU_SHUTDOWN: 5294912Swnj socantsendmore(so); 5304912Swnj break; 5314912Swnj 53242184Skarels case PRU_SEND: 53344596Skarels return (udp_output(inp, m, addr, control)); 5344784Swnj 5354784Swnj case PRU_ABORT: 53631750Skarels soisdisconnected(so); 53744968Skarels udp_detach(inp); 5384784Swnj break; 5394784Swnj 5406511Ssam case PRU_SOCKADDR: 54142184Skarels in_setsockaddr(inp, addr); 5426511Ssam break; 5436511Ssam 54414124Ssam case PRU_PEERADDR: 54542184Skarels in_setpeeraddr(inp, addr); 54614124Ssam break; 54714124Ssam 54816988Skarels case PRU_SENSE: 54916988Skarels /* 55016988Skarels * stat: don't bother with a blocksize. 55116988Skarels */ 55216988Skarels return (0); 55316988Skarels 55412205Ssam case PRU_SENDOOB: 55512205Ssam case PRU_FASTTIMO: 55612205Ssam case PRU_SLOWTIMO: 55712205Ssam case PRU_PROTORCV: 55812205Ssam case PRU_PROTOSEND: 55912205Ssam error = EOPNOTSUPP; 56012205Ssam break; 56113118Ssam 56216799Skarels case PRU_RCVD: 56316799Skarels case PRU_RCVOOB: 56416799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 56516799Skarels 56613118Ssam default: 56713118Ssam panic("udp_usrreq"); 5684805Swnj } 56944596Skarels 57011080Ssam release: 57142184Skarels if (control) { 57242184Skarels printf("udp control data unexpectedly retained\n"); 57342184Skarels m_freem(control); 57442184Skarels } 57542184Skarels if (m) 57611080Ssam m_freem(m); 5776507Ssam return (error); 5784784Swnj } 57944968Skarels 58061335Sbostic static void 58144968Skarels udp_detach(inp) 58244968Skarels struct inpcb *inp; 58344968Skarels { 58444968Skarels int s = splnet(); 58544968Skarels 58644968Skarels if (inp == udp_last_inpcb) 58744968Skarels udp_last_inpcb = &udb; 58844968Skarels in_pcbdetach(inp); 58944968Skarels splx(s); 59044968Skarels } 59159309Smckusick 59259309Smckusick /* 59359309Smckusick * Sysctl for udp variables. 59459309Smckusick */ 59559309Smckusick udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 59659309Smckusick int *name; 59759309Smckusick u_int namelen; 59859309Smckusick void *oldp; 59959309Smckusick size_t *oldlenp; 60059309Smckusick void *newp; 60159309Smckusick size_t newlen; 60259309Smckusick { 60365461Sbostic /* All sysctl names at this level are terminal. */ 60459309Smckusick if (namelen != 1) 60559309Smckusick return (ENOTDIR); 60659309Smckusick 60759309Smckusick switch (name[0]) { 60859309Smckusick case UDPCTL_CHECKSUM: 60959309Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); 61059309Smckusick default: 61159309Smckusick return (ENOPROTOOPT); 61259309Smckusick } 61359309Smckusick /* NOTREACHED */ 61459309Smckusick } 615