Annotation of src/sys/netinet/udp_usrreq.c, Revision 1.37
1.37 ! ws 1: /* $NetBSD: udp_usrreq.c,v 1.36 1996/09/16 17:45:19 mycroft Exp $ */
1.14 cgd 2:
1.1 cgd 3: /*
1.13 mycroft 4: * Copyright (c) 1982, 1986, 1988, 1990, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: *
1.14 cgd 35: * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94
1.1 cgd 36: */
1.37 ! ws 37: #include "kgdb.h"
1.1 cgd 38:
1.5 mycroft 39: #include <sys/param.h>
40: #include <sys/malloc.h>
41: #include <sys/mbuf.h>
42: #include <sys/protosw.h>
43: #include <sys/socket.h>
44: #include <sys/socketvar.h>
1.13 mycroft 45: #include <sys/errno.h>
1.5 mycroft 46: #include <sys/stat.h>
1.27 christos 47: #include <sys/systm.h>
48: #include <sys/proc.h>
49:
50: #include <vm/vm.h>
51: #include <sys/sysctl.h>
1.1 cgd 52:
1.5 mycroft 53: #include <net/if.h>
54: #include <net/route.h>
1.1 cgd 55:
1.5 mycroft 56: #include <netinet/in.h>
57: #include <netinet/in_systm.h>
1.15 cgd 58: #include <netinet/in_var.h>
1.5 mycroft 59: #include <netinet/ip.h>
60: #include <netinet/in_pcb.h>
61: #include <netinet/ip_var.h>
62: #include <netinet/ip_icmp.h>
63: #include <netinet/udp.h>
64: #include <netinet/udp_var.h>
1.1 cgd 65:
1.27 christos 66: #include <machine/stdarg.h>
67:
1.8 mycroft 68: /*
69: * UDP protocol implementation.
70: * Per RFC 768, August, 1980.
71: */
72: #ifndef COMPAT_42
73: int udpcksum = 1;
74: #else
75: int udpcksum = 0; /* XXX */
76: #endif
77:
1.13 mycroft 78: static void udp_notify __P((struct inpcb *, int));
79: static struct mbuf *udp_saveopt __P((caddr_t, int, int));
1.7 mycroft 80:
1.26 mycroft 81: #ifndef UDBHASHSIZE
82: #define UDBHASHSIZE 128
83: #endif
84: int udbhashsize = UDBHASHSIZE;
85:
1.7 mycroft 86: void
1.1 cgd 87: udp_init()
88: {
1.18 mycroft 89:
1.35 mycroft 90: in_pcbinit(&udbtable, udbhashsize, udbhashsize);
1.1 cgd 91: }
92:
1.7 mycroft 93: void
1.27 christos 94: #if __STDC__
95: udp_input(struct mbuf *m, ...)
96: #else
97: udp_input(m, va_alist)
98: struct mbuf *m;
99: va_dcl
100: #endif
1.1 cgd 101: {
102: register struct ip *ip;
103: register struct udphdr *uh;
104: register struct inpcb *inp;
105: struct mbuf *opts = 0;
106: int len;
107: struct ip save_ip;
1.27 christos 108: int iphlen;
109: va_list ap;
1.34 mycroft 110: struct sockaddr_in udpsrc;
1.27 christos 111:
112: va_start(ap, m);
113: iphlen = va_arg(ap, int);
114: va_end(ap);
1.1 cgd 115:
116: udpstat.udps_ipackets++;
117:
118: /*
119: * Strip IP options, if any; should skip this,
120: * make available to user, and use on returned packets,
121: * but we don't yet have a way to check the checksum
122: * with options still present.
123: */
124: if (iphlen > sizeof (struct ip)) {
125: ip_stripoptions(m, (struct mbuf *)0);
126: iphlen = sizeof(struct ip);
127: }
128:
129: /*
130: * Get IP and UDP header together in first mbuf.
131: */
132: ip = mtod(m, struct ip *);
133: if (m->m_len < iphlen + sizeof(struct udphdr)) {
134: if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
135: udpstat.udps_hdrops++;
136: return;
137: }
138: ip = mtod(m, struct ip *);
139: }
140: uh = (struct udphdr *)((caddr_t)ip + iphlen);
141:
142: /*
143: * Make mbuf data length reflect UDP length.
144: * If not enough data to reflect UDP length, drop.
145: */
1.15 cgd 146: len = ntohs((u_int16_t)uh->uh_ulen);
1.1 cgd 147: if (ip->ip_len != len) {
148: if (len > ip->ip_len) {
149: udpstat.udps_badlen++;
150: goto bad;
151: }
152: m_adj(m, len - ip->ip_len);
153: /* ip->ip_len = len; */
154: }
155: /*
156: * Save a copy of the IP header in case we want restore it
157: * for sending an ICMP error message in response.
158: */
159: save_ip = *ip;
160:
161: /*
162: * Checksum extended UDP header and data.
163: */
1.29 mrg 164: if (uh->uh_sum) {
1.25 cgd 165: bzero(((struct ipovly *)ip)->ih_x1,
166: sizeof ((struct ipovly *)ip)->ih_x1);
1.1 cgd 167: ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
1.27 christos 168: if ((uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) != 0) {
1.1 cgd 169: udpstat.udps_badsum++;
170: m_freem(m);
171: return;
172: }
173: }
1.13 mycroft 174:
1.16 mycroft 175: if (IN_MULTICAST(ip->ip_dst.s_addr) ||
1.13 mycroft 176: in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
1.4 hpeyerl 177: struct socket *last;
178: /*
179: * Deliver a multicast or broadcast datagram to *all* sockets
180: * for which the local and remote addresses and ports match
181: * those of the incoming datagram. This allows more than
182: * one process to receive multi/broadcasts on the same port.
183: * (This really ought to be done for unicast datagrams as
184: * well, but that would cause problems with existing
185: * applications that open both address-specific sockets and
186: * a wildcard socket listening to the same port -- they would
187: * end up receiving duplicates of every unicast datagram.
188: * Those applications open the multiple sockets to overcome an
189: * inadequacy of the UDP socket interface, but for backwards
190: * compatibility we avoid the problem here rather than
1.13 mycroft 191: * fixing the interface. Maybe 4.5BSD will remedy this?)
1.4 hpeyerl 192: */
1.13 mycroft 193:
1.4 hpeyerl 194: /*
195: * Construct sockaddr format source address.
196: */
1.34 mycroft 197: udpsrc.sin_family = AF_INET;
198: udpsrc.sin_len = sizeof(struct sockaddr_in);
1.36 mycroft 199: udpsrc.sin_addr = ip->ip_src;
1.34 mycroft 200: udpsrc.sin_port = uh->uh_sport;
1.36 mycroft 201: bzero((caddr_t)udpsrc.sin_zero, sizeof(udpsrc.sin_zero));
1.34 mycroft 202:
1.4 hpeyerl 203: m->m_len -= sizeof (struct udpiphdr);
204: m->m_data += sizeof (struct udpiphdr);
205: /*
206: * Locate pcb(s) for datagram.
207: * (Algorithm copied from raw_intr().)
208: */
209: last = NULL;
1.22 cgd 210: for (inp = udbtable.inpt_queue.cqh_first;
211: inp != (struct inpcb *)&udbtable.inpt_queue;
212: inp = inp->inp_queue.cqe_next) {
1.4 hpeyerl 213: if (inp->inp_lport != uh->uh_dport)
214: continue;
1.34 mycroft 215: if (!in_nullhost(inp->inp_laddr)) {
216: if (!in_hosteq(inp->inp_laddr, ip->ip_dst))
1.4 hpeyerl 217: continue;
218: }
1.34 mycroft 219: if (!in_nullhost(inp->inp_faddr)) {
220: if (!in_hosteq(inp->inp_faddr, ip->ip_src) ||
1.4 hpeyerl 221: inp->inp_fport != uh->uh_sport)
222: continue;
223: }
224:
225: if (last != NULL) {
226: struct mbuf *n;
227:
228: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
229: if (sbappendaddr(&last->so_rcv,
1.34 mycroft 230: sintosa(&udpsrc), n,
1.17 mycroft 231: (struct mbuf *)0) == 0) {
1.4 hpeyerl 232: m_freem(n);
1.13 mycroft 233: udpstat.udps_fullsock++;
234: } else
1.4 hpeyerl 235: sorwakeup(last);
236: }
237: }
238: last = inp->inp_socket;
239: /*
1.13 mycroft 240: * Don't look for additional matches if this one does
241: * not have either the SO_REUSEPORT or SO_REUSEADDR
242: * socket options set. This heuristic avoids searching
243: * through all pcbs in the common case of a non-shared
244: * port. It * assumes that an application will never
245: * clear these options after setting them.
1.4 hpeyerl 246: */
1.28 christos 247: if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0)
1.4 hpeyerl 248: break;
249: }
1.6 mycroft 250:
1.4 hpeyerl 251: if (last == NULL) {
252: /*
253: * No matching pcb found; discard datagram.
254: * (No need to send an ICMP Port Unreachable
255: * for a broadcast or multicast datgram.)
256: */
1.13 mycroft 257: udpstat.udps_noportbcast++;
1.4 hpeyerl 258: goto bad;
259: }
1.34 mycroft 260: if (sbappendaddr(&last->so_rcv, sintosa(&udpsrc), m,
1.17 mycroft 261: (struct mbuf *)0) == 0) {
1.13 mycroft 262: udpstat.udps_fullsock++;
1.4 hpeyerl 263: goto bad;
1.13 mycroft 264: }
1.4 hpeyerl 265: sorwakeup(last);
266: return;
267: }
1.1 cgd 268: /*
269: * Locate pcb for datagram.
270: */
1.35 mycroft 271: inp = in_pcblookup_connect(&udbtable, ip->ip_src, uh->uh_sport,
1.26 mycroft 272: ip->ip_dst, uh->uh_dport);
273: if (inp == 0) {
274: ++udpstat.udps_pcbhashmiss;
1.35 mycroft 275: inp = in_pcblookup_bind(&udbtable, ip->ip_dst, uh->uh_dport);
1.18 mycroft 276: if (inp == 0) {
277: udpstat.udps_noport++;
278: if (m->m_flags & (M_BCAST | M_MCAST)) {
279: udpstat.udps_noportbcast++;
280: goto bad;
281: }
282: *ip = save_ip;
283: ip->ip_len += iphlen;
1.37 ! ws 284: #if NKGDB > 0
! 285: if (checkkgdb(&ip->ip_src,
! 286: uh->uh_sport,
! 287: uh->uh_dport,
! 288: m,
! 289: iphlen + sizeof(struct udphdr),
! 290: len - sizeof(struct udphdr)))
! 291: /* It was a debugger connect packet, just drop it now */
! 292: goto bad;
! 293: #endif
1.18 mycroft 294: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
295: return;
1.13 mycroft 296: }
1.1 cgd 297: }
298:
299: /*
300: * Construct sockaddr format source address.
301: * Stuff source address and datagram in user buffer.
302: */
1.34 mycroft 303: udpsrc.sin_family = AF_INET;
304: udpsrc.sin_len = sizeof(struct sockaddr_in);
1.36 mycroft 305: udpsrc.sin_addr = ip->ip_src;
1.34 mycroft 306: udpsrc.sin_port = uh->uh_sport;
1.36 mycroft 307: bzero((caddr_t)udpsrc.sin_zero, sizeof(udpsrc.sin_zero));
1.34 mycroft 308:
1.1 cgd 309: if (inp->inp_flags & INP_CONTROLOPTS) {
310: struct mbuf **mp = &opts;
311:
312: if (inp->inp_flags & INP_RECVDSTADDR) {
313: *mp = udp_saveopt((caddr_t) &ip->ip_dst,
314: sizeof(struct in_addr), IP_RECVDSTADDR);
315: if (*mp)
316: mp = &(*mp)->m_next;
317: }
318: #ifdef notyet
319: /* options were tossed above */
320: if (inp->inp_flags & INP_RECVOPTS) {
321: *mp = udp_saveopt((caddr_t) opts_deleted_above,
322: sizeof(struct in_addr), IP_RECVOPTS);
323: if (*mp)
324: mp = &(*mp)->m_next;
325: }
326: /* ip_srcroute doesn't do what we want here, need to fix */
327: if (inp->inp_flags & INP_RECVRETOPTS) {
328: *mp = udp_saveopt((caddr_t) ip_srcroute(),
329: sizeof(struct in_addr), IP_RECVRETOPTS);
330: if (*mp)
331: mp = &(*mp)->m_next;
332: }
333: #endif
334: }
335: iphlen += sizeof(struct udphdr);
336: m->m_len -= iphlen;
337: m->m_pkthdr.len -= iphlen;
338: m->m_data += iphlen;
1.34 mycroft 339: if (sbappendaddr(&inp->inp_socket->so_rcv, sintosa(&udpsrc), m,
1.17 mycroft 340: opts) == 0) {
1.1 cgd 341: udpstat.udps_fullsock++;
342: goto bad;
343: }
344: sorwakeup(inp->inp_socket);
345: return;
346: bad:
347: m_freem(m);
348: if (opts)
349: m_freem(opts);
350: }
351:
352: /*
353: * Create a "control" mbuf containing the specified data
354: * with the specified type for presentation with a datagram.
355: */
1.13 mycroft 356: struct mbuf *
1.1 cgd 357: udp_saveopt(p, size, type)
358: caddr_t p;
359: register int size;
360: int type;
361: {
362: register struct cmsghdr *cp;
363: struct mbuf *m;
364:
365: if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
366: return ((struct mbuf *) NULL);
367: cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
1.13 mycroft 368: bcopy(p, CMSG_DATA(cp), size);
1.1 cgd 369: size += sizeof(*cp);
370: m->m_len = size;
371: cp->cmsg_len = size;
372: cp->cmsg_level = IPPROTO_IP;
373: cp->cmsg_type = type;
374: return (m);
375: }
376:
377: /*
378: * Notify a udp user of an asynchronous error;
379: * just wake up so that he can collect error status.
380: */
1.7 mycroft 381: static void
1.1 cgd 382: udp_notify(inp, errno)
383: register struct inpcb *inp;
1.7 mycroft 384: int errno;
1.1 cgd 385: {
1.34 mycroft 386:
1.1 cgd 387: inp->inp_socket->so_error = errno;
388: sorwakeup(inp->inp_socket);
389: sowwakeup(inp->inp_socket);
390: }
391:
1.27 christos 392: void *
393: udp_ctlinput(cmd, sa, v)
1.1 cgd 394: int cmd;
395: struct sockaddr *sa;
1.27 christos 396: void *v;
1.1 cgd 397: {
1.27 christos 398: register struct ip *ip = v;
1.1 cgd 399: register struct udphdr *uh;
1.21 mycroft 400: extern int inetctlerrmap[];
1.18 mycroft 401: void (*notify) __P((struct inpcb *, int)) = udp_notify;
1.21 mycroft 402: int errno;
1.1 cgd 403:
1.20 mycroft 404: if ((unsigned)cmd >= PRC_NCMDS)
1.27 christos 405: return NULL;
1.20 mycroft 406: errno = inetctlerrmap[cmd];
1.18 mycroft 407: if (PRC_IS_REDIRECT(cmd))
1.19 mycroft 408: notify = in_rtchange, ip = 0;
1.18 mycroft 409: else if (cmd == PRC_HOSTDEAD)
1.19 mycroft 410: ip = 0;
1.23 cgd 411: else if (errno == 0)
1.27 christos 412: return NULL;
1.19 mycroft 413: if (ip) {
1.1 cgd 414: uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
1.34 mycroft 415: in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
416: ip->ip_src, uh->uh_sport, errno, notify);
1.19 mycroft 417: } else
1.34 mycroft 418: in_pcbnotifyall(&udbtable, satosin(sa)->sin_addr, errno,
419: notify);
1.27 christos 420: return NULL;
1.1 cgd 421: }
422:
1.7 mycroft 423: int
1.27 christos 424: #if __STDC__
425: udp_output(struct mbuf *m, ...)
426: #else
427: udp_output(m, va_alist)
428: struct mbuf *m;
429: va_dcl
430: #endif
431: {
1.1 cgd 432: register struct inpcb *inp;
433: register struct udpiphdr *ui;
434: register int len = m->m_pkthdr.len;
1.31 mycroft 435: int error = 0;
1.27 christos 436: va_list ap;
437:
438: va_start(ap, m);
439: inp = va_arg(ap, struct inpcb *);
440: va_end(ap);
1.1 cgd 441:
442: /*
443: * Calculate data length and get a mbuf
444: * for UDP and IP headers.
445: */
1.13 mycroft 446: M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
447: if (m == 0) {
448: error = ENOBUFS;
449: goto release;
450: }
1.1 cgd 451:
452: /*
453: * Fill in mbuf with extended UDP header
454: * and addresses and length put into network format.
455: */
456: ui = mtod(m, struct udpiphdr *);
1.25 cgd 457: bzero(ui->ui_x1, sizeof ui->ui_x1);
1.1 cgd 458: ui->ui_pr = IPPROTO_UDP;
1.15 cgd 459: ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
1.1 cgd 460: ui->ui_src = inp->inp_laddr;
461: ui->ui_dst = inp->inp_faddr;
462: ui->ui_sport = inp->inp_lport;
463: ui->ui_dport = inp->inp_fport;
464: ui->ui_ulen = ui->ui_len;
465:
466: /*
467: * Stuff checksum and output datagram.
468: */
469: ui->ui_sum = 0;
470: if (udpcksum) {
471: if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
472: ui->ui_sum = 0xffff;
473: }
474: ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
475: ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
476: ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
477: udpstat.udps_opackets++;
1.31 mycroft 478: return (ip_output(m, inp->inp_options, &inp->inp_route,
1.12 mycroft 479: inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
1.31 mycroft 480: inp->inp_moptions));
1.1 cgd 481:
482: release:
483: m_freem(m);
484: return (error);
485: }
486:
487: u_long udp_sendspace = 9216; /* really max datagram size */
488: u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
489: /* 40 1K datagrams */
490:
491: /*ARGSUSED*/
1.7 mycroft 492: int
1.31 mycroft 493: udp_usrreq(so, req, m, nam, control, p)
1.1 cgd 494: struct socket *so;
495: int req;
1.31 mycroft 496: struct mbuf *m, *nam, *control;
1.30 mycroft 497: struct proc *p;
1.1 cgd 498: {
1.31 mycroft 499: register struct inpcb *inp;
1.1 cgd 500: int s;
1.31 mycroft 501: register int error = 0;
1.1 cgd 502:
503: if (req == PRU_CONTROL)
1.31 mycroft 504: return (in_control(so, (long)m, (caddr_t)nam,
1.30 mycroft 505: (struct ifnet *)control, p));
1.31 mycroft 506:
507: s = splsoftnet();
508: inp = sotoinpcb(so);
1.32 mycroft 509: #ifdef DIAGNOSTIC
510: if (req != PRU_SEND && req != PRU_SENDOOB && control)
511: panic("udp_usrreq: unexpected control mbuf");
512: #endif
1.31 mycroft 513: if (inp == 0 && req != PRU_ATTACH) {
514: error = EINVAL;
515: goto release;
516: }
517:
1.1 cgd 518: /*
519: * Note: need to block udp_input while changing
520: * the udp pcb queue and/or pcb addresses.
521: */
522: switch (req) {
523:
524: case PRU_ATTACH:
1.31 mycroft 525: if (inp != 0) {
526: error = EISCONN;
1.1 cgd 527: break;
528: }
1.31 mycroft 529: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
530: error = soreserve(so, udp_sendspace, udp_recvspace);
531: if (error)
532: break;
533: }
1.18 mycroft 534: error = in_pcballoc(so, &udbtable);
1.1 cgd 535: if (error)
536: break;
1.31 mycroft 537: inp = sotoinpcb(so);
538: inp->inp_ip.ip_ttl = ip_defttl;
1.1 cgd 539: break;
540:
541: case PRU_DETACH:
1.31 mycroft 542: in_pcbdetach(inp);
1.1 cgd 543: break;
544:
545: case PRU_BIND:
1.31 mycroft 546: error = in_pcbbind(inp, nam, p);
1.1 cgd 547: break;
548:
549: case PRU_LISTEN:
550: error = EOPNOTSUPP;
551: break;
552:
553: case PRU_CONNECT:
1.31 mycroft 554: error = in_pcbconnect(inp, nam);
555: if (error)
1.1 cgd 556: break;
1.31 mycroft 557: soisconnected(so);
1.1 cgd 558: break;
559:
560: case PRU_CONNECT2:
561: error = EOPNOTSUPP;
562: break;
563:
564: case PRU_DISCONNECT:
1.31 mycroft 565: /*soisdisconnected(so);*/
566: so->so_state &= ~SS_ISCONNECTED; /* XXX */
1.1 cgd 567: in_pcbdisconnect(inp);
1.34 mycroft 568: inp->inp_laddr = zeroin_addr; /* XXX */
1.35 mycroft 569: in_pcbstate(inp, INP_BOUND); /* XXX */
1.1 cgd 570: break;
571:
572: case PRU_SHUTDOWN:
573: socantsendmore(so);
574: break;
575:
1.31 mycroft 576: case PRU_RCVD:
577: error = EOPNOTSUPP;
1.1 cgd 578: break;
579:
1.31 mycroft 580: case PRU_SEND:
1.32 mycroft 581: if (control && control->m_len) {
582: m_freem(control);
583: m_freem(m);
584: error = EINVAL;
585: break;
586: }
1.31 mycroft 587: {
1.35 mycroft 588: struct in_addr laddr; /* XXX */
1.1 cgd 589:
1.31 mycroft 590: if (nam) {
1.35 mycroft 591: laddr = inp->inp_laddr; /* XXX */
1.31 mycroft 592: if ((so->so_state & SS_ISCONNECTED) != 0) {
593: error = EISCONN;
1.32 mycroft 594: goto die;
1.31 mycroft 595: }
596: error = in_pcbconnect(inp, nam);
1.32 mycroft 597: if (error) {
598: die:
599: m_freem(m);
1.31 mycroft 600: break;
1.32 mycroft 601: }
1.31 mycroft 602: } else {
603: if ((so->so_state & SS_ISCONNECTED) == 0) {
604: error = ENOTCONN;
1.32 mycroft 605: goto die;
1.31 mycroft 606: }
607: }
1.33 mycroft 608: error = udp_output(m, inp);
1.31 mycroft 609: if (nam) {
610: in_pcbdisconnect(inp);
1.35 mycroft 611: inp->inp_laddr = laddr; /* XXX */
612: in_pcbstate(inp, INP_BOUND); /* XXX */
1.31 mycroft 613: }
614: }
1.1 cgd 615: break;
616:
617: case PRU_SENSE:
618: /*
619: * stat: don't bother with a blocksize.
620: */
1.31 mycroft 621: splx(s);
1.1 cgd 622: return (0);
623:
1.31 mycroft 624: case PRU_RCVOOB:
625: error = EOPNOTSUPP;
626: break;
627:
1.1 cgd 628: case PRU_SENDOOB:
1.32 mycroft 629: m_freem(control);
1.31 mycroft 630: m_freem(m);
1.1 cgd 631: error = EOPNOTSUPP;
632: break;
633:
1.31 mycroft 634: case PRU_SOCKADDR:
635: in_setsockaddr(inp, nam);
636: break;
637:
638: case PRU_PEERADDR:
639: in_setpeeraddr(inp, nam);
640: break;
1.1 cgd 641:
642: default:
643: panic("udp_usrreq");
644: }
645:
646: release:
1.31 mycroft 647: splx(s);
1.1 cgd 648: return (error);
1.13 mycroft 649: }
650:
651: /*
652: * Sysctl for udp variables.
653: */
1.27 christos 654: int
1.13 mycroft 655: udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
656: int *name;
657: u_int namelen;
658: void *oldp;
659: size_t *oldlenp;
660: void *newp;
661: size_t newlen;
662: {
663: /* All sysctl names at this level are terminal. */
664: if (namelen != 1)
665: return (ENOTDIR);
666:
667: switch (name[0]) {
668: case UDPCTL_CHECKSUM:
669: return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
670: default:
671: return (ENOPROTOOPT);
672: }
673: /* NOTREACHED */
1.1 cgd 674: }
CVSweb <webmaster@jp.NetBSD.org>