123199Smckusick /* 2*63220Sbostic * Copyright (c) 1982, 1986, 1988, 1990, 1993 3*63220Sbostic * Regents of the University of California. All rights reserved. 423199Smckusick * 544642Sbostic * %sccs.include.redist.c% 632789Sbostic * 7*63220Sbostic * @(#)udp_usrreq.c 8.1 (Berkeley) 06/10/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 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++; 23140688Skarels *ip = save_ip; 23244828Skarels ip->ip_len += iphlen; 23360637Smckusick icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); 2346584Ssam return; 2356584Ssam } 2366584Ssam 2374926Swnj /* 2384926Swnj * Construct sockaddr format source address. 2394926Swnj * Stuff source address and datagram in user buffer. 2404926Swnj */ 24140688Skarels udp_in.sin_port = uh->uh_sport; 24240688Skarels udp_in.sin_addr = ip->ip_src; 24344596Skarels if (inp->inp_flags & INP_CONTROLOPTS) { 24444596Skarels struct mbuf **mp = &opts; 24544596Skarels 24644596Skarels if (inp->inp_flags & INP_RECVDSTADDR) { 24744596Skarels *mp = udp_saveopt((caddr_t) &ip->ip_dst, 24844596Skarels sizeof(struct in_addr), IP_RECVDSTADDR); 24944596Skarels if (*mp) 25044596Skarels mp = &(*mp)->m_next; 25144596Skarels } 25244596Skarels #ifdef notyet 25344596Skarels /* options were tossed above */ 25444596Skarels if (inp->inp_flags & INP_RECVOPTS) { 25544596Skarels *mp = udp_saveopt((caddr_t) opts_deleted_above, 25644596Skarels sizeof(struct in_addr), IP_RECVOPTS); 25744596Skarels if (*mp) 25844596Skarels mp = &(*mp)->m_next; 25944596Skarels } 26044596Skarels /* ip_srcroute doesn't do what we want here, need to fix */ 26144596Skarels if (inp->inp_flags & INP_RECVRETOPTS) { 26244596Skarels *mp = udp_saveopt((caddr_t) ip_srcroute(), 26344596Skarels sizeof(struct in_addr), IP_RECVRETOPTS); 26444596Skarels if (*mp) 26544596Skarels mp = &(*mp)->m_next; 26644596Skarels } 26744596Skarels #endif 26844596Skarels } 26940688Skarels iphlen += sizeof(struct udphdr); 27040688Skarels m->m_len -= iphlen; 27140688Skarels m->m_pkthdr.len -= iphlen; 27240688Skarels m->m_data += iphlen; 27312767Ssam if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 27444596Skarels m, opts) == 0) { 27544596Skarels udpstat.udps_fullsock++; 2764926Swnj goto bad; 27744596Skarels } 2785050Swnj sorwakeup(inp->inp_socket); 2794887Swnj return; 2804926Swnj bad: 2814887Swnj m_freem(m); 28244596Skarels if (opts) 28344596Skarels m_freem(opts); 2844784Swnj } 2854784Swnj 28626426Skarels /* 28744596Skarels * Create a "control" mbuf containing the specified data 28844596Skarels * with the specified type for presentation with a datagram. 28944596Skarels */ 29044596Skarels struct mbuf * 29144596Skarels udp_saveopt(p, size, type) 29244596Skarels caddr_t p; 29344596Skarels register int size; 29444596Skarels int type; 29544596Skarels { 29644596Skarels register struct cmsghdr *cp; 29744596Skarels struct mbuf *m; 29844596Skarels 29944596Skarels if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) 30044596Skarels return ((struct mbuf *) NULL); 30144596Skarels cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); 30260501Smckusick bcopy(p, CMSG_DATA(cp), size); 30344596Skarels size += sizeof(*cp); 30444596Skarels m->m_len = size; 30544596Skarels cp->cmsg_len = size; 30644596Skarels cp->cmsg_level = IPPROTO_IP; 30744596Skarels cp->cmsg_type = type; 30844596Skarels return (m); 30944596Skarels } 31044596Skarels 31144596Skarels /* 31226426Skarels * Notify a udp user of an asynchronous error; 31326426Skarels * just wake up so that he can collect error status. 31426426Skarels */ 31561335Sbostic static void 31644596Skarels udp_notify(inp, errno) 31726426Skarels register struct inpcb *inp; 31852949Storek int errno; 31926426Skarels { 32044596Skarels inp->inp_socket->so_error = errno; 32126426Skarels sorwakeup(inp->inp_socket); 32226426Skarels sowwakeup(inp->inp_socket); 32326426Skarels } 32426426Skarels 32561335Sbostic void 32640688Skarels udp_ctlinput(cmd, sa, ip) 3276591Ssam int cmd; 32824823Skarels struct sockaddr *sa; 32940688Skarels register struct ip *ip; 3306591Ssam { 33140688Skarels register struct udphdr *uh; 33240688Skarels extern struct in_addr zeroin_addr; 3336591Ssam extern u_char inetctlerrmap[]; 3346591Ssam 33557433Sandrew if (!PRC_IS_REDIRECT(cmd) && 33657433Sandrew ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)) 3376591Ssam return; 33840688Skarels if (ip) { 33940688Skarels uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 34040688Skarels in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, 34140688Skarels cmd, udp_notify); 34240688Skarels } else 34340688Skarels in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); 3446591Ssam } 3456591Ssam 34661335Sbostic int 34742184Skarels udp_output(inp, m, addr, control) 34826060Skarels register struct inpcb *inp; 34935794Skarels register struct mbuf *m; 35042184Skarels struct mbuf *addr, *control; 3514784Swnj { 3524926Swnj register struct udpiphdr *ui; 35335794Skarels register int len = m->m_pkthdr.len; 35442184Skarels struct in_addr laddr; 35542184Skarels int s, error = 0; 3564784Swnj 35742184Skarels if (control) 35842184Skarels m_freem(control); /* XXX */ 35942184Skarels 36042184Skarels if (addr) { 36142184Skarels laddr = inp->inp_laddr; 36242184Skarels if (inp->inp_faddr.s_addr != INADDR_ANY) { 36342184Skarels error = EISCONN; 36442184Skarels goto release; 36542184Skarels } 36642184Skarels /* 36742184Skarels * Must block input while temporarily connected. 36842184Skarels */ 36942184Skarels s = splnet(); 37042184Skarels error = in_pcbconnect(inp, addr); 37142184Skarels if (error) { 37242184Skarels splx(s); 37342184Skarels goto release; 37442184Skarels } 37542184Skarels } else { 37642184Skarels if (inp->inp_faddr.s_addr == INADDR_ANY) { 37742184Skarels error = ENOTCONN; 37842184Skarels goto release; 37942184Skarels } 38042184Skarels } 3814926Swnj /* 3824926Swnj * Calculate data length and get a mbuf 3835246Sroot * for UDP and IP headers. 3844926Swnj */ 38550715Smckusick M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); 38650715Smckusick if (m == 0) { 38750715Smckusick error = ENOBUFS; 38850715Smckusick goto release; 38950715Smckusick } 3904784Swnj 3914926Swnj /* 3925246Sroot * Fill in mbuf with extended UDP header 3934926Swnj * and addresses and length put into network format. 3944926Swnj */ 3954926Swnj ui = mtod(m, struct udpiphdr *); 3964926Swnj ui->ui_next = ui->ui_prev = 0; 3974926Swnj ui->ui_x1 = 0; 3984926Swnj ui->ui_pr = IPPROTO_UDP; 39915226Ssam ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 4005050Swnj ui->ui_src = inp->inp_laddr; 4015050Swnj ui->ui_dst = inp->inp_faddr; 4025050Swnj ui->ui_sport = inp->inp_lport; 4035050Swnj ui->ui_dport = inp->inp_fport; 40415226Ssam ui->ui_ulen = ui->ui_len; 4054784Swnj 4064926Swnj /* 4074926Swnj * Stuff checksum and output datagram. 4084926Swnj */ 4094926Swnj ui->ui_sum = 0; 41019519Skarels if (udpcksum) { 41119519Skarels if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 41233715Skarels ui->ui_sum = 0xffff; 41321112Skarels } 4145050Swnj ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 41544596Skarels ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ 41644596Skarels ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ 41740688Skarels udpstat.udps_opackets++; 41842184Skarels error = ip_output(m, inp->inp_options, &inp->inp_route, 41957433Sandrew inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), 42057433Sandrew inp->inp_moptions); 42142184Skarels 42242184Skarels if (addr) { 42342184Skarels in_pcbdisconnect(inp); 42442184Skarels inp->inp_laddr = laddr; 42542184Skarels splx(s); 42642184Skarels } 42742184Skarels return (error); 42842184Skarels 42942184Skarels release: 43042184Skarels m_freem(m); 43142184Skarels return (error); 4324784Swnj } 4334784Swnj 43438354Smckusick u_long udp_sendspace = 9216; /* really max datagram size */ 43538354Smckusick u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 43638354Smckusick /* 40 1K datagrams */ 43718368Skarels 4388602Sroot /*ARGSUSED*/ 43961335Sbostic int 44042184Skarels udp_usrreq(so, req, m, addr, control) 4414887Swnj struct socket *so; 4424784Swnj int req; 44342184Skarels struct mbuf *m, *addr, *control; 4444784Swnj { 4454887Swnj struct inpcb *inp = sotoinpcb(so); 4466507Ssam int error = 0; 44744596Skarels int s; 4484784Swnj 44918368Skarels if (req == PRU_CONTROL) 45042184Skarels return (in_control(so, (int)m, (caddr_t)addr, 45140688Skarels (struct ifnet *)control)); 45211080Ssam if (inp == NULL && req != PRU_ATTACH) { 45311080Ssam error = EINVAL; 45411080Ssam goto release; 45511080Ssam } 45644596Skarels /* 45744968Skarels * Note: need to block udp_input while changing 45844968Skarels * the udp pcb queue and/or pcb addresses. 45944596Skarels */ 4604784Swnj switch (req) { 4614784Swnj 4624784Swnj case PRU_ATTACH: 46311080Ssam if (inp != NULL) { 46411080Ssam error = EINVAL; 46511080Ssam break; 46611080Ssam } 46744596Skarels s = splnet(); 4688273Sroot error = in_pcballoc(so, &udb); 46944596Skarels splx(s); 4708273Sroot if (error) 4718273Sroot break; 47218368Skarels error = soreserve(so, udp_sendspace, udp_recvspace); 4738273Sroot if (error) 4748273Sroot break; 47559133Smckusick ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl; 4764887Swnj break; 4774784Swnj 4784784Swnj case PRU_DETACH: 47944968Skarels udp_detach(inp); 4804887Swnj break; 4814784Swnj 4828273Sroot case PRU_BIND: 48344968Skarels s = splnet(); 48442184Skarels error = in_pcbbind(inp, addr); 48544968Skarels splx(s); 4868273Sroot break; 4878273Sroot 4888273Sroot case PRU_LISTEN: 4898273Sroot error = EOPNOTSUPP; 4908273Sroot break; 4918273Sroot 4924784Swnj case PRU_CONNECT: 49311080Ssam if (inp->inp_faddr.s_addr != INADDR_ANY) { 49411080Ssam error = EISCONN; 49511080Ssam break; 49611080Ssam } 49744968Skarels s = splnet(); 49842184Skarels error = in_pcbconnect(inp, addr); 49944968Skarels splx(s); 5006507Ssam if (error == 0) 5016507Ssam soisconnected(so); 5024887Swnj break; 5034784Swnj 50413118Ssam case PRU_CONNECT2: 50513118Ssam error = EOPNOTSUPP; 50613118Ssam break; 50713118Ssam 5084926Swnj case PRU_ACCEPT: 50911080Ssam error = EOPNOTSUPP; 51011080Ssam break; 5114926Swnj 5124784Swnj case PRU_DISCONNECT: 51311080Ssam if (inp->inp_faddr.s_addr == INADDR_ANY) { 51411080Ssam error = ENOTCONN; 51511080Ssam break; 51611080Ssam } 51744968Skarels s = splnet(); 5185166Swnj in_pcbdisconnect(inp); 51940688Skarels inp->inp_laddr.s_addr = INADDR_ANY; 52044968Skarels splx(s); 52126404Skarels so->so_state &= ~SS_ISCONNECTED; /* XXX */ 5224784Swnj break; 5234784Swnj 5244912Swnj case PRU_SHUTDOWN: 5254912Swnj socantsendmore(so); 5264912Swnj break; 5274912Swnj 52842184Skarels case PRU_SEND: 52944596Skarels return (udp_output(inp, m, addr, control)); 5304784Swnj 5314784Swnj case PRU_ABORT: 53231750Skarels soisdisconnected(so); 53344968Skarels udp_detach(inp); 5344784Swnj break; 5354784Swnj 5366511Ssam case PRU_SOCKADDR: 53742184Skarels in_setsockaddr(inp, addr); 5386511Ssam break; 5396511Ssam 54014124Ssam case PRU_PEERADDR: 54142184Skarels in_setpeeraddr(inp, addr); 54214124Ssam break; 54314124Ssam 54416988Skarels case PRU_SENSE: 54516988Skarels /* 54616988Skarels * stat: don't bother with a blocksize. 54716988Skarels */ 54816988Skarels return (0); 54916988Skarels 55012205Ssam case PRU_SENDOOB: 55112205Ssam case PRU_FASTTIMO: 55212205Ssam case PRU_SLOWTIMO: 55312205Ssam case PRU_PROTORCV: 55412205Ssam case PRU_PROTOSEND: 55512205Ssam error = EOPNOTSUPP; 55612205Ssam break; 55713118Ssam 55816799Skarels case PRU_RCVD: 55916799Skarels case PRU_RCVOOB: 56016799Skarels return (EOPNOTSUPP); /* do not free mbuf's */ 56116799Skarels 56213118Ssam default: 56313118Ssam panic("udp_usrreq"); 5644805Swnj } 56544596Skarels 56611080Ssam release: 56742184Skarels if (control) { 56842184Skarels printf("udp control data unexpectedly retained\n"); 56942184Skarels m_freem(control); 57042184Skarels } 57142184Skarels if (m) 57211080Ssam m_freem(m); 5736507Ssam return (error); 5744784Swnj } 57544968Skarels 57661335Sbostic static void 57744968Skarels udp_detach(inp) 57844968Skarels struct inpcb *inp; 57944968Skarels { 58044968Skarels int s = splnet(); 58144968Skarels 58244968Skarels if (inp == udp_last_inpcb) 58344968Skarels udp_last_inpcb = &udb; 58444968Skarels in_pcbdetach(inp); 58544968Skarels splx(s); 58644968Skarels } 58759309Smckusick 58859309Smckusick /* 58959309Smckusick * Sysctl for udp variables. 59059309Smckusick */ 59159309Smckusick udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 59259309Smckusick int *name; 59359309Smckusick u_int namelen; 59459309Smckusick void *oldp; 59559309Smckusick size_t *oldlenp; 59659309Smckusick void *newp; 59759309Smckusick size_t newlen; 59859309Smckusick { 59959309Smckusick extern int ip_ttl; 60059309Smckusick 60159309Smckusick /* all sysctl names at this level are terminal */ 60259309Smckusick if (namelen != 1) 60359309Smckusick return (ENOTDIR); 60459309Smckusick 60559309Smckusick switch (name[0]) { 60659309Smckusick case UDPCTL_CHECKSUM: 60759309Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); 60859309Smckusick default: 60959309Smckusick return (ENOPROTOOPT); 61059309Smckusick } 61159309Smckusick /* NOTREACHED */ 61259309Smckusick } 613