Annotation of src/sys/netinet/udp_usrreq.c, Revision 1.62
1.62 ! itojun 1: /* $NetBSD: udp_usrreq.c,v 1.61 2000/02/11 10:43:36 itojun Exp $ */
1.48 itojun 2:
3: /*
4: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5: * All rights reserved.
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. Neither the name of the project nor the names of its contributors
16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
1.14 cgd 31:
1.1 cgd 32: /*
1.44 thorpej 33: * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
1.13 mycroft 34: * The Regents of the University of California. All rights reserved.
1.1 cgd 35: *
36: * Redistribution and use in source and binary forms, with or without
37: * modification, are permitted provided that the following conditions
38: * are met:
39: * 1. Redistributions of source code must retain the above copyright
40: * notice, this list of conditions and the following disclaimer.
41: * 2. Redistributions in binary form must reproduce the above copyright
42: * notice, this list of conditions and the following disclaimer in the
43: * documentation and/or other materials provided with the distribution.
44: * 3. All advertising materials mentioning features or use of this software
45: * must display the following acknowledgement:
46: * This product includes software developed by the University of
47: * California, Berkeley and its contributors.
48: * 4. Neither the name of the University nor the names of its contributors
49: * may be used to endorse or promote products derived from this software
50: * without specific prior written permission.
51: *
52: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62: * SUCH DAMAGE.
63: *
1.44 thorpej 64: * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95
1.1 cgd 65: */
1.50 thorpej 66:
67: #include "opt_ipsec.h"
68:
1.38 ws 69: #include "ipkdb.h"
1.1 cgd 70:
1.5 mycroft 71: #include <sys/param.h>
72: #include <sys/malloc.h>
73: #include <sys/mbuf.h>
74: #include <sys/protosw.h>
75: #include <sys/socket.h>
76: #include <sys/socketvar.h>
1.13 mycroft 77: #include <sys/errno.h>
1.5 mycroft 78: #include <sys/stat.h>
1.27 christos 79: #include <sys/systm.h>
80: #include <sys/proc.h>
1.53 itojun 81: #include <sys/domain.h>
1.27 christos 82:
83: #include <vm/vm.h>
84: #include <sys/sysctl.h>
1.1 cgd 85:
1.5 mycroft 86: #include <net/if.h>
87: #include <net/route.h>
1.1 cgd 88:
1.5 mycroft 89: #include <netinet/in.h>
90: #include <netinet/in_systm.h>
1.15 cgd 91: #include <netinet/in_var.h>
1.5 mycroft 92: #include <netinet/ip.h>
93: #include <netinet/in_pcb.h>
94: #include <netinet/ip_var.h>
95: #include <netinet/ip_icmp.h>
96: #include <netinet/udp.h>
97: #include <netinet/udp_var.h>
1.1 cgd 98:
1.53 itojun 99: #ifdef INET6
100: #include <netinet/ip6.h>
101: #include <netinet/icmp6.h>
102: #include <netinet6/ip6_var.h>
103: #include <netinet6/in6_pcb.h>
104: #include <netinet6/udp6_var.h>
105: #endif
106:
107: #ifdef PULLDOWN_TEST
108: #ifndef INET6
109: /* always need ip6.h for IP6_EXTHDR_GET */
110: #include <netinet/ip6.h>
111: #endif
112: #endif
113:
1.27 christos 114: #include <machine/stdarg.h>
115:
1.48 itojun 116: #ifdef IPSEC
117: #include <netinet6/ipsec.h>
118: #include <netkey/key.h>
119: #include <netkey/key_debug.h>
120: #endif /*IPSEC*/
121:
1.8 mycroft 122: /*
123: * UDP protocol implementation.
124: * Per RFC 768, August, 1980.
125: */
126: #ifndef COMPAT_42
127: int udpcksum = 1;
128: #else
129: int udpcksum = 0; /* XXX */
130: #endif
131:
1.53 itojun 132: static void udp4_sendup __P((struct mbuf *, int, struct sockaddr *,
133: struct socket *));
134: static int udp4_realinput __P((struct sockaddr_in *, struct sockaddr_in *,
135: struct mbuf *, int));
136: #ifdef INET6
137: static void udp6_sendup __P((struct mbuf *, int, struct sockaddr *,
138: struct socket *));
139: static int in6_mcmatch __P((struct in6pcb *, struct in6_addr *,
140: struct ifnet *));
141: static int udp6_realinput __P((int, struct sockaddr_in6 *,
142: struct sockaddr_in6 *, struct mbuf *, int));
143: #endif
1.13 mycroft 144: static void udp_notify __P((struct inpcb *, int));
1.7 mycroft 145:
1.26 mycroft 146: #ifndef UDBHASHSIZE
147: #define UDBHASHSIZE 128
148: #endif
149: int udbhashsize = UDBHASHSIZE;
150:
1.7 mycroft 151: void
1.1 cgd 152: udp_init()
153: {
1.18 mycroft 154:
1.35 mycroft 155: in_pcbinit(&udbtable, udbhashsize, udbhashsize);
1.1 cgd 156: }
157:
1.56 itojun 158: #ifndef UDP6
1.7 mycroft 159: void
1.27 christos 160: #if __STDC__
161: udp_input(struct mbuf *m, ...)
162: #else
163: udp_input(m, va_alist)
164: struct mbuf *m;
165: va_dcl
166: #endif
1.1 cgd 167: {
1.53 itojun 168: va_list ap;
169: struct sockaddr_in src, dst;
170: struct ip *ip;
171: struct udphdr *uh;
172: int iphlen, proto;
173: int len;
174: int n;
175:
176: va_start(ap, m);
177: iphlen = va_arg(ap, int);
178: proto = va_arg(ap, int);
179: va_end(ap);
180:
181: udpstat.udps_ipackets++;
182:
183: #ifndef PULLDOWN_TEST
184: /*
185: * Strip IP options, if any; should skip this,
186: * make available to user, and use on returned packets,
187: * but we don't yet have a way to check the checksum
188: * with options still present.
189: */
190: if (iphlen > sizeof (struct ip)) {
191: ip_stripoptions(m, (struct mbuf *)0);
192: iphlen = sizeof(struct ip);
193: }
194: #else
195: /*
196: * we may enable the above code if we save and pass IPv4 options
197: * to the userland.
198: */
199: #endif
200:
201: /*
202: * Get IP and UDP header together in first mbuf.
203: */
204: ip = mtod(m, struct ip *);
205: #ifndef PULLDOWN_TEST
206: if (m->m_len < iphlen + sizeof(struct udphdr)) {
207: if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
208: udpstat.udps_hdrops++;
209: return;
210: }
211: ip = mtod(m, struct ip *);
212: }
213: uh = (struct udphdr *)((caddr_t)ip + iphlen);
214: #else
215: IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr));
216: if (uh == NULL) {
217: udpstat.udps_hdrops++;
218: return;
219: }
220: #endif
221:
1.57 itojun 222: /* destination port of 0 is illegal, based on RFC768. */
223: if (uh->uh_dport == 0)
224: goto bad;
225:
1.53 itojun 226: /*
227: * Make mbuf data length reflect UDP length.
228: * If not enough data to reflect UDP length, drop.
229: */
230: len = ntohs((u_int16_t)uh->uh_ulen);
231: if (ip->ip_len != iphlen + len) {
232: if (ip->ip_len < iphlen + len) {
233: udpstat.udps_badlen++;
234: goto bad;
235: }
236: m_adj(m, iphlen + len - ip->ip_len);
237: }
238:
239: /*
240: * Checksum extended UDP header and data.
241: */
242: if (uh->uh_sum) {
243: if (in4_cksum(m, IPPROTO_UDP, iphlen, len) != 0) {
244: udpstat.udps_badsum++;
245: m_freem(m);
246: return;
247: }
248: }
249:
250: /* construct source and dst sockaddrs. */
251: bzero(&src, sizeof(src));
252: src.sin_family = AF_INET;
253: src.sin_len = sizeof(struct sockaddr_in);
254: bcopy(&ip->ip_src, &src.sin_addr, sizeof(src.sin_addr));
255: src.sin_port = uh->uh_sport;
256: bzero(&dst, sizeof(dst));
257: dst.sin_family = AF_INET;
258: dst.sin_len = sizeof(struct sockaddr_in);
259: bcopy(&ip->ip_dst, &dst.sin_addr, sizeof(dst.sin_addr));
260: dst.sin_port = uh->uh_dport;
261:
262: n = udp4_realinput(&src, &dst, m, iphlen);
263: #ifdef INET6
264: if (IN_MULTICAST(ip->ip_dst.s_addr) || n == 0) {
265: struct sockaddr_in6 src6, dst6;
266:
267: bzero(&src6, sizeof(src6));
268: src6.sin6_family = AF_INET6;
269: src6.sin6_len = sizeof(struct sockaddr_in6);
270: src6.sin6_addr.s6_addr[10] = src6.sin6_addr.s6_addr[11] = 0xff;
271: bcopy(&ip->ip_src, &src6.sin6_addr.s6_addr[12],
272: sizeof(ip->ip_src));
273: src6.sin6_port = uh->uh_sport;
274: bzero(&dst6, sizeof(dst6));
275: dst6.sin6_family = AF_INET6;
276: dst6.sin6_len = sizeof(struct sockaddr_in6);
277: dst6.sin6_addr.s6_addr[10] = dst6.sin6_addr.s6_addr[11] = 0xff;
278: bcopy(&ip->ip_dst, &dst6.sin6_addr.s6_addr[12],
279: sizeof(ip->ip_dst));
280: dst6.sin6_port = uh->uh_dport;
281:
282: n += udp6_realinput(AF_INET, &src6, &dst6, m, iphlen);
283: }
284: #endif
285:
286: if (n == 0) {
287: if (m->m_flags & (M_BCAST | M_MCAST)) {
288: udpstat.udps_noportbcast++;
289: goto bad;
290: }
1.61 itojun 291: udpstat.udps_noport++;
1.53 itojun 292: #if NIPKDB > 0
293: if (checkipkdb(&ip->ip_src, uh->uh_sport, uh->uh_dport,
294: m, iphlen + sizeof(struct udphdr),
295: m->m_pkthdr.len - iphlen - sizeof(struct udphdr))) {
296: /*
297: * It was a debugger connect packet,
298: * just drop it now
299: */
300: goto bad;
301: }
302: #endif
303: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
304: m = NULL;
305: }
306:
307: bad:
308: if (m)
309: m_freem(m);
310: }
311:
312: #ifdef INET6
313: int
314: udp6_input(mp, offp, proto)
315: struct mbuf **mp;
316: int *offp, proto;
317: {
318: struct mbuf *m = *mp;
319: int off = *offp;
320: struct sockaddr_in6 src, dst;
321: struct ip6_hdr *ip6;
322: struct udphdr *uh;
323: u_int32_t plen, ulen;
324:
325: #if defined(NFAITH) && 0 < NFAITH
326: if (m->m_pkthdr.rcvif) {
327: if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
328: /* send icmp6 host unreach? */
329: m_freem(m);
330: return IPPROTO_DONE;
331: }
332: }
333: #endif
334:
335: udp6stat.udp6s_ipackets++;
336:
337: #ifndef PULLDOWN_TEST
338: IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
339: #endif
340:
341: ip6 = mtod(m, struct ip6_hdr *);
342: /* check for jumbogram is done in ip6_input. we can trust pkthdr.len */
343: plen = m->m_pkthdr.len - off;
344: #ifndef PULLDOWN_TEST
345: uh = (struct udphdr *)((caddr_t)ip6 + off);
346: #else
347: IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr));
348: if (uh == NULL) {
349: ip6stat.ip6s_tooshort++;
350: return IPPROTO_DONE;
351: }
352: #endif
353: ulen = ntohs((u_short)uh->uh_ulen);
354: if (ulen == 0 && plen > 0xffff)
355: ulen = plen;
356:
357: if (plen != ulen) {
358: udp6stat.udp6s_badlen++;
1.54 itojun 359: goto bad;
360: }
361:
1.57 itojun 362: /* destination port of 0 is illegal, based on RFC768. */
363: if (uh->uh_dport == 0)
364: goto bad;
365:
1.54 itojun 366: /* Be proactive about malicious use of IPv4 mapped address */
367: if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
368: IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
369: /* XXX stat */
1.53 itojun 370: goto bad;
371: }
372:
373: /*
374: * Checksum extended UDP header and data.
375: */
376: if (uh->uh_sum == 0)
377: udp6stat.udp6s_nosum++;
378: else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
379: udp6stat.udp6s_badsum++;
380: goto bad;
381: }
382:
383: /*
384: * Construct source and dst sockaddrs.
385: * Note that ifindex (s6_addr16[1]) is already filled.
386: */
387: bzero(&src, sizeof(src));
388: src.sin6_family = AF_INET6;
389: src.sin6_len = sizeof(struct sockaddr_in6);
390: bcopy(&ip6->ip6_src, &src.sin6_addr, sizeof(src.sin6_addr));
391: if (IN6_IS_SCOPE_LINKLOCAL(&src.sin6_addr))
392: src.sin6_addr.s6_addr16[1] = 0;
393: if (m->m_pkthdr.rcvif) {
394: if (IN6_IS_SCOPE_LINKLOCAL(&src.sin6_addr))
395: src.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
396: else
397: src.sin6_scope_id = 0;
398: }
399: src.sin6_port = uh->uh_sport;
400: bzero(&dst, sizeof(dst));
401: dst.sin6_family = AF_INET6;
402: dst.sin6_len = sizeof(struct sockaddr_in6);
403: bcopy(&ip6->ip6_dst, &dst.sin6_addr, sizeof(dst.sin6_addr));
404: if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr))
405: dst.sin6_addr.s6_addr16[1] = 0;
406: if (m->m_pkthdr.rcvif) {
407: if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr))
408: dst.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
409: else
410: dst.sin6_scope_id = 0;
411: }
412: dst.sin6_port = uh->uh_dport;
413:
414: if (udp6_realinput(AF_INET6, &src, &dst, m, off) == 0) {
415: if (m->m_flags & M_MCAST) {
416: udp6stat.udp6s_noportmcast++;
417: goto bad;
418: }
1.61 itojun 419: udp6stat.udp6s_noport++;
1.53 itojun 420: icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
421: m = NULL;
422: }
423:
424: bad:
425: if (m)
426: m_freem(m);
427: return IPPROTO_DONE;
428: }
429: #endif
430:
431: static void
432: udp4_sendup(m, off, src, so)
433: struct mbuf *m;
434: int off; /* offset of data portion */
435: struct sockaddr *src;
436: struct socket *so;
437: {
438: struct mbuf *opts = NULL;
439: struct mbuf *n;
440: struct inpcb *inp = NULL;
441: #ifdef INET6
442: struct in6pcb *in6p = NULL;
443: #endif
444:
445: if (!so)
446: return;
447: switch (so->so_proto->pr_domain->dom_family) {
448: case AF_INET:
449: inp = sotoinpcb(so);
450: break;
451: #ifdef INET6
452: case AF_INET6:
453: in6p = sotoin6pcb(so);
454: break;
455: #endif
456: default:
457: return;
458: }
459:
460: #ifdef IPSEC
461: /* check AH/ESP integrity. */
462: if (so != NULL && ipsec4_in_reject_so(m, so)) {
463: ipsecstat.in_polvio++;
464: return;
465: }
466: #endif /*IPSEC*/
467:
468: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
469: if (inp && (inp->inp_flags & INP_CONTROLOPTS
470: || so->so_options & SO_TIMESTAMP)) {
471: struct ip *ip = mtod(n, struct ip *);
472: ip_savecontrol(inp, &opts, ip, n);
473: }
474:
475: m_adj(n, off);
476: if (sbappendaddr(&so->so_rcv, src, n,
477: opts) == 0) {
478: m_freem(n);
479: if (opts)
480: m_freem(opts);
481: } else
482: sorwakeup(so);
483: }
484: }
485:
486: #ifdef INET6
487: static void
488: udp6_sendup(m, off, src, so)
489: struct mbuf *m;
490: int off; /* offset of data portion */
491: struct sockaddr *src;
492: struct socket *so;
493: {
494: struct mbuf *opts = NULL;
495: struct mbuf *n;
496: struct in6pcb *in6p = NULL;
497:
498: if (!so)
499: return;
500: if (so->so_proto->pr_domain->dom_family != AF_INET6)
501: return;
502: in6p = sotoin6pcb(so);
503:
504: #ifdef IPSEC
505: /* check AH/ESP integrity. */
506: if (so != NULL && ipsec6_in_reject_so(m, so)) {
507: ipsec6stat.in_polvio++;
508: return;
509: }
510: #endif /*IPSEC*/
511:
512: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
513: if (in6p && (in6p->in6p_flags & IN6P_CONTROLOPTS
514: || in6p->in6p_socket->so_options & SO_TIMESTAMP)) {
515: struct ip6_hdr *ip6 = mtod(n, struct ip6_hdr *);
516: ip6_savecontrol(in6p, &opts, ip6, n);
517: }
518:
519: m_adj(n, off);
520: if (sbappendaddr(&so->so_rcv, src, n, opts) == 0) {
521: m_freem(n);
522: if (opts)
523: m_freem(opts);
524: udp6stat.udp6s_fullsock++;
525: } else
526: sorwakeup(so);
527: }
528: }
529: #endif
530:
531: static int
532: udp4_realinput(src, dst, m, off)
533: struct sockaddr_in *src;
534: struct sockaddr_in *dst;
535: struct mbuf *m;
536: int off; /* offset of udphdr */
537: {
538: u_int16_t *sport, *dport;
539: int rcvcnt;
540: struct in_addr *src4, *dst4;
541: struct inpcb *inp;
542:
543: rcvcnt = 0;
544: off += sizeof(struct udphdr); /* now, offset of payload */
545:
546: if (src->sin_family != AF_INET || dst->sin_family != AF_INET)
547: goto bad;
548:
549: src4 = &src->sin_addr;
550: sport = &src->sin_port;
551: dst4 = &dst->sin_addr;
552: dport = &dst->sin_port;
553:
554: if (IN_MULTICAST(src4->s_addr) ||
555: in_broadcast(*dst4, m->m_pkthdr.rcvif)) {
556: struct inpcb *last;
557: /*
558: * Deliver a multicast or broadcast datagram to *all* sockets
559: * for which the local and remote addresses and ports match
560: * those of the incoming datagram. This allows more than
561: * one process to receive multi/broadcasts on the same port.
562: * (This really ought to be done for unicast datagrams as
563: * well, but that would cause problems with existing
564: * applications that open both address-specific sockets and
565: * a wildcard socket listening to the same port -- they would
566: * end up receiving duplicates of every unicast datagram.
567: * Those applications open the multiple sockets to overcome an
568: * inadequacy of the UDP socket interface, but for backwards
569: * compatibility we avoid the problem here rather than
570: * fixing the interface. Maybe 4.5BSD will remedy this?)
571: */
572:
573: /*
574: * KAME note: usually we drop udpiphdr from mbuf here.
575: * we need udpiphdr for iPsec processing so we do that later.
576: */
577: /*
578: * Locate pcb(s) for datagram.
579: */
580: for (inp = udbtable.inpt_queue.cqh_first;
581: inp != (struct inpcb *)&udbtable.inpt_queue;
582: inp = inp->inp_queue.cqe_next) {
583: if (inp->inp_lport != *dport)
584: continue;
585: if (!in_nullhost(inp->inp_laddr)) {
586: if (!in_hosteq(inp->inp_laddr, *dst4))
587: continue;
588: }
589: if (!in_nullhost(inp->inp_faddr)) {
590: if (!in_hosteq(inp->inp_faddr, *src4) ||
591: inp->inp_fport != *sport)
592: continue;
593: }
594:
595: last = inp;
596: udp4_sendup(m, off, (struct sockaddr *)src,
597: inp->inp_socket);
598: rcvcnt++;
599:
600: /*
601: * Don't look for additional matches if this one does
602: * not have either the SO_REUSEPORT or SO_REUSEADDR
603: * socket options set. This heuristic avoids searching
604: * through all pcbs in the common case of a non-shared
605: * port. It assumes that an application will never
606: * clear these options after setting them.
607: */
608: if ((inp->inp_socket->so_options &
609: (SO_REUSEPORT|SO_REUSEADDR)) == 0)
610: break;
611: }
612:
613: #if 0
614: if (last == NULL) {
615: /*
616: * No matching pcb found; discard datagram.
617: * (No need to send an ICMP Port Unreachable
618: * for a broadcast or multicast datgram.)
619: */
620: udpstat.udps_noportbcast++;
621: goto bad;
622: }
623: #endif
624: } else {
625: /*
626: * Locate pcb for datagram.
627: */
628: inp = in_pcblookup_connect(&udbtable, *src4, *sport, *dst4, *dport);
629: if (inp == 0) {
630: ++udpstat.udps_pcbhashmiss;
631: inp = in_pcblookup_bind(&udbtable, *dst4, *dport);
632: if (inp == 0) {
633: #if 0
634: struct mbuf *n;
635:
636: if (m->m_flags & (M_BCAST | M_MCAST)) {
637: udpstat.udps_noportbcast++;
638: goto bad;
639: }
1.61 itojun 640: udpstat.udps_noport++;
1.53 itojun 641: #if NIPKDB > 0
642: if (checkipkdb(src4, *sport, *dport, m, off,
643: m->m_pkthdr.len - off)) {
644: /*
645: * It was a debugger connect packet,
646: * just drop it now
647: */
648: goto bad;
649: }
650: #endif
651: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
652: icmp_error(n, ICMP_UNREACH,
653: ICMP_UNREACH_PORT, 0, 0);
654: }
655: #endif
656: return rcvcnt;
657: }
658: }
659:
660: udp4_sendup(m, off, (struct sockaddr *)src, inp->inp_socket);
661: rcvcnt++;
662: }
663:
664: bad:
665: return rcvcnt;
666: }
667:
668: #ifdef INET6
669: static int
670: in6_mcmatch(in6p, ia6, ifp)
671: struct in6pcb *in6p;
672: register struct in6_addr *ia6;
673: struct ifnet *ifp;
674: {
675: struct ip6_moptions *im6o = in6p->in6p_moptions;
676: struct in6_multi_mship *imm;
677:
678: if (im6o == NULL)
679: return 0;
680:
681: for (imm = im6o->im6o_memberships.lh_first; imm != NULL;
682: imm = imm->i6mm_chain.le_next) {
683: if ((ifp == NULL ||
684: imm->i6mm_maddr->in6m_ifp == ifp) &&
685: IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
686: ia6))
687: return 1;
688: }
689: return 0;
690: }
691:
692: static int
693: udp6_realinput(af, src, dst, m, off)
694: int af; /* af on packet */
695: struct sockaddr_in6 *src;
696: struct sockaddr_in6 *dst;
697: struct mbuf *m;
698: int off; /* offset of udphdr */
699: {
700: u_int16_t *sport, *dport;
701: int rcvcnt;
702: struct in6_addr *src6, *dst6;
703: struct in_addr *src4;
704: struct in6pcb *in6p;
705:
706: rcvcnt = 0;
707: off += sizeof(struct udphdr); /* now, offset of payload */
708:
709: if (af != AF_INET && af != AF_INET6)
710: goto bad;
711: if (src->sin6_family != AF_INET6 || dst->sin6_family != AF_INET6)
712: goto bad;
713:
714: src6 = &src->sin6_addr;
715: sport = &src->sin6_port;
716: dst6 = &dst->sin6_addr;
717: dport = &dst->sin6_port;
718: src4 = (struct in_addr *)&src->sin6_addr.s6_addr32[12];
719:
720: if (IN6_IS_ADDR_MULTICAST(dst6)
721: || (af == AF_INET && IN_MULTICAST(src4->s_addr))) {
722: struct in6pcb *last;
723: /*
724: * Deliver a multicast or broadcast datagram to *all* sockets
725: * for which the local and remote addresses and ports match
726: * those of the incoming datagram. This allows more than
727: * one process to receive multi/broadcasts on the same port.
728: * (This really ought to be done for unicast datagrams as
729: * well, but that would cause problems with existing
730: * applications that open both address-specific sockets and
731: * a wildcard socket listening to the same port -- they would
732: * end up receiving duplicates of every unicast datagram.
733: * Those applications open the multiple sockets to overcome an
734: * inadequacy of the UDP socket interface, but for backwards
735: * compatibility we avoid the problem here rather than
736: * fixing the interface. Maybe 4.5BSD will remedy this?)
737: */
738:
739: /*
740: * KAME note: usually we drop udpiphdr from mbuf here.
741: * we need udpiphdr for iPsec processing so we do that later.
742: */
743: /*
744: * Locate pcb(s) for datagram.
745: */
746: for (in6p = udb6.in6p_next; in6p != &udb6;
747: in6p = in6p->in6p_next) {
748: if (in6p->in6p_lport != *dport)
749: continue;
750: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
751: if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, dst6)
752: && !in6_mcmatch(in6p, dst6, m->m_pkthdr.rcvif))
753: continue;
754: }
1.55 itojun 755: #ifndef INET6_BINDV6ONLY
756: else {
757: if (IN6_IS_ADDR_V4MAPPED(dst6)
758: && (in6p->in6p_flags & IN6P_BINDV6ONLY))
759: continue;
760: }
761: #endif
1.53 itojun 762: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
763: if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, src6)
764: || in6p->in6p_fport != *sport)
765: continue;
766: }
1.55 itojun 767: #ifndef INET6_BINDV6ONLY
768: else {
769: if (IN6_IS_ADDR_V4MAPPED(src6)
770: && (in6p->in6p_flags & IN6P_BINDV6ONLY))
771: continue;
772: }
773: #endif
1.53 itojun 774:
775: last = in6p;
776: udp6_sendup(m, off, (struct sockaddr *)src,
777: in6p->in6p_socket);
778: rcvcnt++;
779:
780: /*
781: * Don't look for additional matches if this one does
782: * not have either the SO_REUSEPORT or SO_REUSEADDR
783: * socket options set. This heuristic avoids searching
784: * through all pcbs in the common case of a non-shared
785: * port. It assumes that an application will never
786: * clear these options after setting them.
787: */
788: if ((in6p->in6p_socket->so_options &
789: (SO_REUSEPORT|SO_REUSEADDR)) == 0)
790: break;
791: }
792:
793: #if 0
794: if (last == NULL) {
795: /*
796: * No matching pcb found; discard datagram.
797: * (No need to send an ICMP Port Unreachable
798: * for a broadcast or multicast datgram.)
799: */
800: switch (af) {
801: case AF_INET:
802: udpstat.udps_noportbcast++;
803: break;
804: case AF_INET6:
805: udp6stat.udp6s_noportmcast++;
806: break;
807: }
808: goto bad;
809: }
810: #endif
811: } else {
812: /*
813: * Locate pcb for datagram.
814: */
815: in6p = in6_pcblookup_connect(&udb6, src6, *sport,
816: dst6, *dport, 0);
817: if (in6p == 0) {
818: ++udpstat.udps_pcbhashmiss;
819: in6p = in6_pcblookup_bind(&udb6, dst6, *dport, 0);
820: if (in6p == 0) {
821: #if 0
822: struct mbuf *n;
823: n = m_copy(m, 0, M_COPYALL);
824: switch (af) {
825: case AF_INET:
826: if (m->m_flags & (M_BCAST | M_MCAST)) {
827: udpstat.udps_noportbcast++;
828: goto bad;
829: }
1.61 itojun 830: udpstat.udps_noport++;
1.53 itojun 831: if (n != NULL)
832: icmp_error(n, ICMP_UNREACH,
833: ICMP_UNREACH_PORT, 0, 0);
834: break;
835: case AF_INET6:
836: if (m->m_flags & M_MCAST) {
837: udp6stat.udp6s_noportmcast++;
838: goto bad;
839: }
1.61 itojun 840: udp6stat.udp6s_noport++;
1.53 itojun 841: if (n != NULL)
842: icmp6_error(n, ICMP6_DST_UNREACH,
843: ICMP6_DST_UNREACH_NOPORT, 0);
844: break;
845: }
846: #endif
847:
848: return rcvcnt;
849: }
850: }
851:
852: udp6_sendup(m, off, (struct sockaddr *)src, in6p->in6p_socket);
853: rcvcnt++;
854: }
855:
856: bad:
857: return rcvcnt;
858: }
859: #endif
860:
1.56 itojun 861: #else /*UDP6*/
862:
1.53 itojun 863: void
864: #if __STDC__
865: udp_input(struct mbuf *m, ...)
866: #else
867: udp_input(m, va_alist)
868: struct mbuf *m;
869: va_dcl
870: #endif
871: {
1.48 itojun 872: int proto;
1.1 cgd 873: register struct ip *ip;
874: register struct udphdr *uh;
875: register struct inpcb *inp;
876: struct mbuf *opts = 0;
877: int len;
878: struct ip save_ip;
1.27 christos 879: int iphlen;
880: va_list ap;
1.34 mycroft 881: struct sockaddr_in udpsrc;
1.48 itojun 882: struct sockaddr *sa;
1.27 christos 883:
884: va_start(ap, m);
885: iphlen = va_arg(ap, int);
1.48 itojun 886: proto = va_arg(ap, int);
1.27 christos 887: va_end(ap);
1.1 cgd 888:
889: udpstat.udps_ipackets++;
890:
891: /*
892: * Strip IP options, if any; should skip this,
893: * make available to user, and use on returned packets,
894: * but we don't yet have a way to check the checksum
895: * with options still present.
896: */
897: if (iphlen > sizeof (struct ip)) {
898: ip_stripoptions(m, (struct mbuf *)0);
899: iphlen = sizeof(struct ip);
900: }
901:
902: /*
903: * Get IP and UDP header together in first mbuf.
904: */
905: ip = mtod(m, struct ip *);
906: if (m->m_len < iphlen + sizeof(struct udphdr)) {
907: if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
908: udpstat.udps_hdrops++;
909: return;
910: }
911: ip = mtod(m, struct ip *);
912: }
913: uh = (struct udphdr *)((caddr_t)ip + iphlen);
1.57 itojun 914:
915: /* destination port of 0 is illegal, based on RFC768. */
916: if (uh->uh_dport == 0)
917: goto bad;
1.1 cgd 918:
919: /*
920: * Make mbuf data length reflect UDP length.
921: * If not enough data to reflect UDP length, drop.
922: */
1.15 cgd 923: len = ntohs((u_int16_t)uh->uh_ulen);
1.47 mycroft 924: if (ip->ip_len != iphlen + len) {
925: if (ip->ip_len < iphlen + len) {
1.1 cgd 926: udpstat.udps_badlen++;
927: goto bad;
928: }
1.47 mycroft 929: m_adj(m, iphlen + len - ip->ip_len);
1.1 cgd 930: }
931: /*
932: * Save a copy of the IP header in case we want restore it
933: * for sending an ICMP error message in response.
934: */
935: save_ip = *ip;
936:
937: /*
938: * Checksum extended UDP header and data.
939: */
1.29 mrg 940: if (uh->uh_sum) {
1.25 cgd 941: bzero(((struct ipovly *)ip)->ih_x1,
942: sizeof ((struct ipovly *)ip)->ih_x1);
1.1 cgd 943: ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
1.46 mycroft 944: if (in_cksum(m, len + sizeof (struct ip)) != 0) {
1.1 cgd 945: udpstat.udps_badsum++;
946: m_freem(m);
947: return;
948: }
949: }
1.13 mycroft 950:
1.48 itojun 951: /*
952: * Construct sockaddr format source address.
953: */
954: udpsrc.sin_family = AF_INET;
955: udpsrc.sin_len = sizeof(struct sockaddr_in);
956: udpsrc.sin_addr = ip->ip_src;
957: udpsrc.sin_port = uh->uh_sport;
958: bzero((caddr_t)udpsrc.sin_zero, sizeof(udpsrc.sin_zero));
959:
1.16 mycroft 960: if (IN_MULTICAST(ip->ip_dst.s_addr) ||
1.13 mycroft 961: in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
1.40 thorpej 962: struct inpcb *last;
1.4 hpeyerl 963: /*
964: * Deliver a multicast or broadcast datagram to *all* sockets
965: * for which the local and remote addresses and ports match
966: * those of the incoming datagram. This allows more than
967: * one process to receive multi/broadcasts on the same port.
968: * (This really ought to be done for unicast datagrams as
969: * well, but that would cause problems with existing
970: * applications that open both address-specific sockets and
971: * a wildcard socket listening to the same port -- they would
972: * end up receiving duplicates of every unicast datagram.
973: * Those applications open the multiple sockets to overcome an
974: * inadequacy of the UDP socket interface, but for backwards
975: * compatibility we avoid the problem here rather than
1.13 mycroft 976: * fixing the interface. Maybe 4.5BSD will remedy this?)
1.4 hpeyerl 977: */
1.13 mycroft 978:
1.48 itojun 979: iphlen += sizeof(struct udphdr);
1.4 hpeyerl 980: /*
1.48 itojun 981: * KAME note: usually we drop udpiphdr from mbuf here.
982: * we need udpiphdr for iPsec processing so we do that later.
1.4 hpeyerl 983: */
984: /*
985: * Locate pcb(s) for datagram.
986: * (Algorithm copied from raw_intr().)
987: */
988: last = NULL;
1.22 cgd 989: for (inp = udbtable.inpt_queue.cqh_first;
990: inp != (struct inpcb *)&udbtable.inpt_queue;
991: inp = inp->inp_queue.cqe_next) {
1.4 hpeyerl 992: if (inp->inp_lport != uh->uh_dport)
993: continue;
1.34 mycroft 994: if (!in_nullhost(inp->inp_laddr)) {
995: if (!in_hosteq(inp->inp_laddr, ip->ip_dst))
1.4 hpeyerl 996: continue;
997: }
1.34 mycroft 998: if (!in_nullhost(inp->inp_faddr)) {
999: if (!in_hosteq(inp->inp_faddr, ip->ip_src) ||
1.4 hpeyerl 1000: inp->inp_fport != uh->uh_sport)
1001: continue;
1002: }
1003:
1004: if (last != NULL) {
1005: struct mbuf *n;
1006:
1.48 itojun 1007: #ifdef IPSEC
1008: /* check AH/ESP integrity. */
1009: if (last != NULL && ipsec4_in_reject(m, last)) {
1010: ipsecstat.in_polvio++;
1011: /* do not inject data to pcb */
1012: } else
1013: #endif /*IPSEC*/
1.4 hpeyerl 1014: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
1.40 thorpej 1015: if (last->inp_flags & INP_CONTROLOPTS
1016: || last->inp_socket->so_options &
1017: SO_TIMESTAMP) {
1018: ip_savecontrol(last, &opts,
1019: ip, n);
1020: }
1.49 drochner 1021: m_adj(n, iphlen);
1.48 itojun 1022: sa = (struct sockaddr *)&udpsrc;
1.40 thorpej 1023: if (sbappendaddr(
1024: &last->inp_socket->so_rcv,
1.48 itojun 1025: sa, n, opts) == 0) {
1.4 hpeyerl 1026: m_freem(n);
1.40 thorpej 1027: if (opts)
1028: m_freem(opts);
1.13 mycroft 1029: } else
1.40 thorpej 1030: sorwakeup(last->inp_socket);
1031: opts = 0;
1.4 hpeyerl 1032: }
1033: }
1.40 thorpej 1034: last = inp;
1.4 hpeyerl 1035: /*
1.13 mycroft 1036: * Don't look for additional matches if this one does
1037: * not have either the SO_REUSEPORT or SO_REUSEADDR
1038: * socket options set. This heuristic avoids searching
1039: * through all pcbs in the common case of a non-shared
1040: * port. It * assumes that an application will never
1041: * clear these options after setting them.
1.4 hpeyerl 1042: */
1.40 thorpej 1043: if ((last->inp_socket->so_options &
1044: (SO_REUSEPORT|SO_REUSEADDR)) == 0)
1.4 hpeyerl 1045: break;
1046: }
1.6 mycroft 1047:
1.4 hpeyerl 1048: if (last == NULL) {
1049: /*
1050: * No matching pcb found; discard datagram.
1051: * (No need to send an ICMP Port Unreachable
1052: * for a broadcast or multicast datgram.)
1053: */
1.13 mycroft 1054: udpstat.udps_noportbcast++;
1.4 hpeyerl 1055: goto bad;
1056: }
1.48 itojun 1057: #ifdef IPSEC
1058: /* check AH/ESP integrity. */
1059: if (last != NULL && ipsec4_in_reject(m, last)) {
1060: ipsecstat.in_polvio++;
1061: goto bad;
1062: }
1063: #endif /*IPSEC*/
1.40 thorpej 1064: if (last->inp_flags & INP_CONTROLOPTS ||
1065: last->inp_socket->so_options & SO_TIMESTAMP)
1066: ip_savecontrol(last, &opts, ip, m);
1.49 drochner 1067: m->m_len -= iphlen;
1068: m->m_pkthdr.len -= iphlen;
1069: m->m_data += iphlen;
1.48 itojun 1070: sa = (struct sockaddr *)&udpsrc;
1071: if (sbappendaddr(&last->inp_socket->so_rcv, sa, m, opts) == 0) {
1.13 mycroft 1072: udpstat.udps_fullsock++;
1.4 hpeyerl 1073: goto bad;
1.13 mycroft 1074: }
1.40 thorpej 1075: sorwakeup(last->inp_socket);
1.4 hpeyerl 1076: return;
1077: }
1.1 cgd 1078: /*
1079: * Locate pcb for datagram.
1080: */
1.35 mycroft 1081: inp = in_pcblookup_connect(&udbtable, ip->ip_src, uh->uh_sport,
1.26 mycroft 1082: ip->ip_dst, uh->uh_dport);
1083: if (inp == 0) {
1084: ++udpstat.udps_pcbhashmiss;
1.35 mycroft 1085: inp = in_pcblookup_bind(&udbtable, ip->ip_dst, uh->uh_dport);
1.18 mycroft 1086: if (inp == 0) {
1087: if (m->m_flags & (M_BCAST | M_MCAST)) {
1088: udpstat.udps_noportbcast++;
1089: goto bad;
1090: }
1.61 itojun 1091: udpstat.udps_noport++;
1.18 mycroft 1092: *ip = save_ip;
1.38 ws 1093: #if NIPKDB > 0
1094: if (checkipkdb(&ip->ip_src,
1095: uh->uh_sport,
1096: uh->uh_dport,
1097: m,
1098: iphlen + sizeof(struct udphdr),
1099: len - sizeof(struct udphdr)))
1.37 ws 1100: /* It was a debugger connect packet, just drop it now */
1101: goto bad;
1102: #endif
1.18 mycroft 1103: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
1104: return;
1.13 mycroft 1105: }
1.1 cgd 1106: }
1.48 itojun 1107: #ifdef IPSEC
1108: if (inp != NULL && ipsec4_in_reject(m, inp)) {
1109: ipsecstat.in_polvio++;
1110: goto bad;
1111: }
1112: #endif /*IPSEC*/
1.1 cgd 1113:
1114: /*
1115: * Stuff source address and datagram in user buffer.
1116: */
1.40 thorpej 1117: if (inp->inp_flags & INP_CONTROLOPTS ||
1118: inp->inp_socket->so_options & SO_TIMESTAMP)
1119: ip_savecontrol(inp, &opts, ip, m);
1.1 cgd 1120: iphlen += sizeof(struct udphdr);
1121: m->m_len -= iphlen;
1122: m->m_pkthdr.len -= iphlen;
1123: m->m_data += iphlen;
1.48 itojun 1124: sa = (struct sockaddr *)&udpsrc;
1125: if (sbappendaddr(&inp->inp_socket->so_rcv, sa, m, opts) == 0) {
1.1 cgd 1126: udpstat.udps_fullsock++;
1127: goto bad;
1128: }
1129: sorwakeup(inp->inp_socket);
1130: return;
1131: bad:
1132: m_freem(m);
1133: if (opts)
1134: m_freem(opts);
1135: }
1.56 itojun 1136: #endif /*UDP6*/
1.1 cgd 1137:
1138: /*
1139: * Notify a udp user of an asynchronous error;
1140: * just wake up so that he can collect error status.
1141: */
1.7 mycroft 1142: static void
1.1 cgd 1143: udp_notify(inp, errno)
1144: register struct inpcb *inp;
1.7 mycroft 1145: int errno;
1.1 cgd 1146: {
1.34 mycroft 1147:
1.1 cgd 1148: inp->inp_socket->so_error = errno;
1149: sorwakeup(inp->inp_socket);
1150: sowwakeup(inp->inp_socket);
1151: }
1152:
1.27 christos 1153: void *
1154: udp_ctlinput(cmd, sa, v)
1.1 cgd 1155: int cmd;
1156: struct sockaddr *sa;
1.27 christos 1157: void *v;
1.1 cgd 1158: {
1.27 christos 1159: register struct ip *ip = v;
1.1 cgd 1160: register struct udphdr *uh;
1.21 mycroft 1161: extern int inetctlerrmap[];
1.18 mycroft 1162: void (*notify) __P((struct inpcb *, int)) = udp_notify;
1.21 mycroft 1163: int errno;
1.1 cgd 1164:
1.53 itojun 1165: if (sa->sa_family != AF_INET
1166: || sa->sa_len != sizeof(struct sockaddr_in))
1.51 itojun 1167: return NULL;
1.20 mycroft 1168: if ((unsigned)cmd >= PRC_NCMDS)
1.27 christos 1169: return NULL;
1.20 mycroft 1170: errno = inetctlerrmap[cmd];
1.18 mycroft 1171: if (PRC_IS_REDIRECT(cmd))
1.19 mycroft 1172: notify = in_rtchange, ip = 0;
1.18 mycroft 1173: else if (cmd == PRC_HOSTDEAD)
1.19 mycroft 1174: ip = 0;
1.23 cgd 1175: else if (errno == 0)
1.27 christos 1176: return NULL;
1.19 mycroft 1177: if (ip) {
1.1 cgd 1178: uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
1.34 mycroft 1179: in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
1180: ip->ip_src, uh->uh_sport, errno, notify);
1.53 itojun 1181:
1182: /* XXX mapped address case */
1.19 mycroft 1183: } else
1.34 mycroft 1184: in_pcbnotifyall(&udbtable, satosin(sa)->sin_addr, errno,
1185: notify);
1.27 christos 1186: return NULL;
1.1 cgd 1187: }
1188:
1.7 mycroft 1189: int
1.27 christos 1190: #if __STDC__
1191: udp_output(struct mbuf *m, ...)
1192: #else
1193: udp_output(m, va_alist)
1194: struct mbuf *m;
1195: va_dcl
1196: #endif
1197: {
1.1 cgd 1198: register struct inpcb *inp;
1199: register struct udpiphdr *ui;
1200: register int len = m->m_pkthdr.len;
1.31 mycroft 1201: int error = 0;
1.27 christos 1202: va_list ap;
1203:
1204: va_start(ap, m);
1205: inp = va_arg(ap, struct inpcb *);
1206: va_end(ap);
1.1 cgd 1207:
1208: /*
1209: * Calculate data length and get a mbuf
1210: * for UDP and IP headers.
1211: */
1.13 mycroft 1212: M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
1213: if (m == 0) {
1214: error = ENOBUFS;
1.39 thorpej 1215: goto release;
1216: }
1217:
1218: /*
1219: * Compute the packet length of the IP header, and
1220: * punt if the length looks bogus.
1221: */
1222: if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) {
1223: error = EMSGSIZE;
1.13 mycroft 1224: goto release;
1225: }
1.1 cgd 1226:
1227: /*
1228: * Fill in mbuf with extended UDP header
1229: * and addresses and length put into network format.
1230: */
1231: ui = mtod(m, struct udpiphdr *);
1.25 cgd 1232: bzero(ui->ui_x1, sizeof ui->ui_x1);
1.1 cgd 1233: ui->ui_pr = IPPROTO_UDP;
1.15 cgd 1234: ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
1.1 cgd 1235: ui->ui_src = inp->inp_laddr;
1236: ui->ui_dst = inp->inp_faddr;
1237: ui->ui_sport = inp->inp_lport;
1238: ui->ui_dport = inp->inp_fport;
1239: ui->ui_ulen = ui->ui_len;
1240:
1241: /*
1242: * Stuff checksum and output datagram.
1243: */
1244: ui->ui_sum = 0;
1245: if (udpcksum) {
1246: if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
1247: ui->ui_sum = 0xffff;
1248: }
1249: ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
1250: ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
1251: ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
1252: udpstat.udps_opackets++;
1.48 itojun 1253:
1254: #ifdef IPSEC
1255: m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket;
1256: #endif /*IPSEC*/
1257:
1.31 mycroft 1258: return (ip_output(m, inp->inp_options, &inp->inp_route,
1.12 mycroft 1259: inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
1.31 mycroft 1260: inp->inp_moptions));
1.1 cgd 1261:
1262: release:
1263: m_freem(m);
1264: return (error);
1265: }
1266:
1.42 thorpej 1267: int udp_sendspace = 9216; /* really max datagram size */
1268: int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
1.1 cgd 1269: /* 40 1K datagrams */
1270:
1271: /*ARGSUSED*/
1.7 mycroft 1272: int
1.31 mycroft 1273: udp_usrreq(so, req, m, nam, control, p)
1.1 cgd 1274: struct socket *so;
1275: int req;
1.31 mycroft 1276: struct mbuf *m, *nam, *control;
1.30 mycroft 1277: struct proc *p;
1.1 cgd 1278: {
1.31 mycroft 1279: register struct inpcb *inp;
1.1 cgd 1280: int s;
1.31 mycroft 1281: register int error = 0;
1.1 cgd 1282:
1283: if (req == PRU_CONTROL)
1.31 mycroft 1284: return (in_control(so, (long)m, (caddr_t)nam,
1.30 mycroft 1285: (struct ifnet *)control, p));
1.59 thorpej 1286:
1.60 thorpej 1287: if (req == PRU_PURGEIF) {
1288: in_purgeif((struct ifnet *)control);
1289: in_pcbpurgeif(&udbtable, (struct ifnet *)control);
1.59 thorpej 1290: return (0);
1291: }
1.31 mycroft 1292:
1293: s = splsoftnet();
1294: inp = sotoinpcb(so);
1.32 mycroft 1295: #ifdef DIAGNOSTIC
1296: if (req != PRU_SEND && req != PRU_SENDOOB && control)
1297: panic("udp_usrreq: unexpected control mbuf");
1298: #endif
1.31 mycroft 1299: if (inp == 0 && req != PRU_ATTACH) {
1300: error = EINVAL;
1301: goto release;
1302: }
1303:
1.1 cgd 1304: /*
1305: * Note: need to block udp_input while changing
1306: * the udp pcb queue and/or pcb addresses.
1307: */
1308: switch (req) {
1309:
1310: case PRU_ATTACH:
1.31 mycroft 1311: if (inp != 0) {
1312: error = EISCONN;
1.1 cgd 1313: break;
1314: }
1.31 mycroft 1315: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
1316: error = soreserve(so, udp_sendspace, udp_recvspace);
1317: if (error)
1318: break;
1319: }
1.18 mycroft 1320: error = in_pcballoc(so, &udbtable);
1.1 cgd 1321: if (error)
1322: break;
1.31 mycroft 1323: inp = sotoinpcb(so);
1324: inp->inp_ip.ip_ttl = ip_defttl;
1.48 itojun 1325: #ifdef IPSEC
1.58 itojun 1326: error = ipsec_init_policy(so, &inp->inp_sp);
1.53 itojun 1327: if (error != 0) {
1.52 itojun 1328: in_pcbdetach(inp);
1.53 itojun 1329: break;
1330: }
1.48 itojun 1331: #endif /*IPSEC*/
1.1 cgd 1332: break;
1333:
1334: case PRU_DETACH:
1.31 mycroft 1335: in_pcbdetach(inp);
1.1 cgd 1336: break;
1337:
1338: case PRU_BIND:
1.31 mycroft 1339: error = in_pcbbind(inp, nam, p);
1.1 cgd 1340: break;
1341:
1342: case PRU_LISTEN:
1343: error = EOPNOTSUPP;
1344: break;
1345:
1346: case PRU_CONNECT:
1.31 mycroft 1347: error = in_pcbconnect(inp, nam);
1348: if (error)
1.1 cgd 1349: break;
1.31 mycroft 1350: soisconnected(so);
1.1 cgd 1351: break;
1352:
1353: case PRU_CONNECT2:
1354: error = EOPNOTSUPP;
1355: break;
1356:
1357: case PRU_DISCONNECT:
1.31 mycroft 1358: /*soisdisconnected(so);*/
1359: so->so_state &= ~SS_ISCONNECTED; /* XXX */
1.1 cgd 1360: in_pcbdisconnect(inp);
1.34 mycroft 1361: inp->inp_laddr = zeroin_addr; /* XXX */
1.35 mycroft 1362: in_pcbstate(inp, INP_BOUND); /* XXX */
1.1 cgd 1363: break;
1364:
1365: case PRU_SHUTDOWN:
1366: socantsendmore(so);
1367: break;
1368:
1.31 mycroft 1369: case PRU_RCVD:
1370: error = EOPNOTSUPP;
1.1 cgd 1371: break;
1372:
1.31 mycroft 1373: case PRU_SEND:
1.32 mycroft 1374: if (control && control->m_len) {
1375: m_freem(control);
1376: m_freem(m);
1377: error = EINVAL;
1378: break;
1379: }
1.31 mycroft 1380: {
1.35 mycroft 1381: struct in_addr laddr; /* XXX */
1.1 cgd 1382:
1.31 mycroft 1383: if (nam) {
1.35 mycroft 1384: laddr = inp->inp_laddr; /* XXX */
1.31 mycroft 1385: if ((so->so_state & SS_ISCONNECTED) != 0) {
1386: error = EISCONN;
1.32 mycroft 1387: goto die;
1.31 mycroft 1388: }
1389: error = in_pcbconnect(inp, nam);
1.32 mycroft 1390: if (error) {
1391: die:
1392: m_freem(m);
1.31 mycroft 1393: break;
1.32 mycroft 1394: }
1.31 mycroft 1395: } else {
1396: if ((so->so_state & SS_ISCONNECTED) == 0) {
1397: error = ENOTCONN;
1.32 mycroft 1398: goto die;
1.31 mycroft 1399: }
1400: }
1.33 mycroft 1401: error = udp_output(m, inp);
1.31 mycroft 1402: if (nam) {
1403: in_pcbdisconnect(inp);
1.35 mycroft 1404: inp->inp_laddr = laddr; /* XXX */
1405: in_pcbstate(inp, INP_BOUND); /* XXX */
1.31 mycroft 1406: }
1407: }
1.1 cgd 1408: break;
1409:
1410: case PRU_SENSE:
1411: /*
1412: * stat: don't bother with a blocksize.
1413: */
1.31 mycroft 1414: splx(s);
1.1 cgd 1415: return (0);
1416:
1.31 mycroft 1417: case PRU_RCVOOB:
1418: error = EOPNOTSUPP;
1419: break;
1420:
1.1 cgd 1421: case PRU_SENDOOB:
1.32 mycroft 1422: m_freem(control);
1.31 mycroft 1423: m_freem(m);
1.1 cgd 1424: error = EOPNOTSUPP;
1425: break;
1426:
1.31 mycroft 1427: case PRU_SOCKADDR:
1428: in_setsockaddr(inp, nam);
1429: break;
1430:
1431: case PRU_PEERADDR:
1432: in_setpeeraddr(inp, nam);
1433: break;
1.1 cgd 1434:
1435: default:
1436: panic("udp_usrreq");
1437: }
1438:
1439: release:
1.31 mycroft 1440: splx(s);
1.1 cgd 1441: return (error);
1.13 mycroft 1442: }
1443:
1444: /*
1445: * Sysctl for udp variables.
1446: */
1.27 christos 1447: int
1.13 mycroft 1448: udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
1449: int *name;
1450: u_int namelen;
1451: void *oldp;
1452: size_t *oldlenp;
1453: void *newp;
1454: size_t newlen;
1455: {
1456: /* All sysctl names at this level are terminal. */
1457: if (namelen != 1)
1458: return (ENOTDIR);
1459:
1460: switch (name[0]) {
1461: case UDPCTL_CHECKSUM:
1462: return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
1.42 thorpej 1463: case UDPCTL_SENDSPACE:
1464: return (sysctl_int(oldp, oldlenp, newp, newlen,
1465: &udp_sendspace));
1466: case UDPCTL_RECVSPACE:
1467: return (sysctl_int(oldp, oldlenp, newp, newlen,
1468: &udp_recvspace));
1.13 mycroft 1469: default:
1470: return (ENOPROTOOPT);
1471: }
1472: /* NOTREACHED */
1.1 cgd 1473: }
CVSweb <webmaster@jp.NetBSD.org>