123199Smckusick /*
2*69618Skarels * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
365801Sbostic * The Regents of the University of California. All rights reserved.
423199Smckusick *
544642Sbostic * %sccs.include.redist.c%
632789Sbostic *
7*69618Skarels * @(#)udp_usrreq.c 8.6 (Berkeley) 05/23/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
udp_init()4961335Sbostic udp_init()
5061335Sbostic {
5161335Sbostic udb.inp_next = udb.inp_prev = &udb;
5261335Sbostic }
5361335Sbostic
5461335Sbostic void
udp_input(m,iphlen)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 */
114*69618Skarels if (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 *
udp_saveopt(p,size,type)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
udp_notify(inp,errno)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
udp_ctlinput(cmd,sa,ip)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
udp_output(inp,m,addr,control)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
udp_usrreq(so,req,m,addr,control)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)
45468170Scgd 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
udp_detach(inp)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 */
udp_sysctl(name,namelen,oldp,oldlenp,newp,newlen)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