Annotation of src/sys/netinet6/udp6_usrreq.c, Revision 1.30
1.30 ! itojun 1: /* $NetBSD: udp6_usrreq.c,v 1.29 2000/06/05 06:38:23 itojun Exp $ */
1.29 itojun 2: /* $KAME: udp6_usrreq.c,v 1.52 2000/06/05 00:41:58 itojun Exp $ */
1.3 thorpej 3:
1.2 itojun 4: /*
5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6: * All rights reserved.
1.27 itojun 7: *
1.2 itojun 8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the project nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
1.27 itojun 19: *
1.2 itojun 20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
34: * Copyright (c) 1982, 1986, 1989, 1993
35: * The Regents of the University of California. All rights reserved.
36: *
37: * Redistribution and use in source and binary forms, with or without
38: * modification, are permitted provided that the following conditions
39: * are met:
40: * 1. Redistributions of source code must retain the above copyright
41: * notice, this list of conditions and the following disclaimer.
42: * 2. Redistributions in binary form must reproduce the above copyright
43: * notice, this list of conditions and the following disclaimer in the
44: * documentation and/or other materials provided with the distribution.
45: * 3. All advertising materials mentioning features or use of this software
46: * must display the following acknowledgement:
47: * This product includes software developed by the University of
48: * California, Berkeley and its contributors.
49: * 4. Neither the name of the University nor the names of its contributors
50: * may be used to endorse or promote products derived from this software
51: * without specific prior written permission.
52: *
53: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63: * SUCH DAMAGE.
64: *
65: * @(#)udp_var.h 8.1 (Berkeley) 6/10/93
66: */
1.5 thorpej 67:
68: #include "opt_ipsec.h"
1.2 itojun 69:
70: #include <sys/param.h>
71: #include <sys/malloc.h>
72: #include <sys/mbuf.h>
73: #include <sys/protosw.h>
74: #include <sys/socket.h>
75: #include <sys/socketvar.h>
76: #include <sys/errno.h>
77: #include <sys/stat.h>
78: #include <sys/systm.h>
79: #include <sys/proc.h>
1.8 itojun 80: #include <sys/syslog.h>
1.2 itojun 81:
82: #include <net/if.h>
83: #include <net/route.h>
84: #include <net/if_types.h>
85:
86: #include <netinet/in.h>
87: #include <netinet/in_var.h>
1.14 itojun 88: #include <netinet/in_systm.h>
89: #include <netinet/ip.h>
90: #include <netinet/ip_var.h>
91: #include <netinet/in_pcb.h>
92: #include <netinet/udp.h>
93: #include <netinet/udp_var.h>
1.23 itojun 94: #include <netinet/ip6.h>
1.27 itojun 95: #include <netinet6/ip6_var.h>
1.2 itojun 96: #include <netinet6/in6_pcb.h>
1.23 itojun 97: #include <netinet/icmp6.h>
1.2 itojun 98: #include <netinet6/udp6_var.h>
1.14 itojun 99: #include <netinet6/ip6protosw.h>
1.2 itojun 100:
101: #ifdef IPSEC
102: #include <netinet6/ipsec.h>
103: #endif /*IPSEC*/
104:
105: #include "faith.h"
106:
107: /*
108: * UDP protocol inplementation.
109: * Per RFC 768, August, 1980.
110: */
111:
112: struct in6pcb *udp6_last_in6pcb = &udb6;
113:
1.17 itojun 114: #ifdef UDP6
1.2 itojun 115: static int in6_mcmatch __P((struct in6pcb *, struct in6_addr *, struct ifnet *));
1.14 itojun 116: #endif
1.2 itojun 117: static void udp6_detach __P((struct in6pcb *));
118: static void udp6_notify __P((struct in6pcb *, int));
119:
120: void
121: udp6_init()
122: {
123: udb6.in6p_next = udb6.in6p_prev = &udb6;
124: }
125:
1.17 itojun 126: #ifdef UDP6
1.2 itojun 127: static int
128: in6_mcmatch(in6p, ia6, ifp)
129: struct in6pcb *in6p;
130: register struct in6_addr *ia6;
131: struct ifnet *ifp;
132: {
133: struct ip6_moptions *im6o = in6p->in6p_moptions;
134: struct in6_multi_mship *imm;
135:
136: if (im6o == NULL)
137: return 0;
138:
139: for (imm = im6o->im6o_memberships.lh_first; imm != NULL;
140: imm = imm->i6mm_chain.le_next) {
141: if ((ifp == NULL ||
142: imm->i6mm_maddr->in6m_ifp == ifp) &&
143: IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
144: ia6))
145: return 1;
146: }
147: return 0;
148: }
149:
150: int
151: udp6_input(mp, offp, proto)
152: struct mbuf **mp;
153: int *offp, proto;
154: {
155: struct mbuf *m = *mp;
156: register struct ip6_hdr *ip6;
157: register struct udphdr *uh;
158: register struct in6pcb *in6p;
159: struct mbuf *opts = 0;
160: int off = *offp;
1.14 itojun 161: u_int32_t plen, ulen;
1.2 itojun 162: struct sockaddr_in6 udp_in6;
163:
164: #if defined(NFAITH) && 0 < NFAITH
165: if (m->m_pkthdr.rcvif) {
166: if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
167: /* send icmp6 host unreach? */
168: m_freem(m);
169: return IPPROTO_DONE;
170: }
171: }
172: #endif
173: udp6stat.udp6s_ipackets++;
174:
1.14 itojun 175: ip6 = mtod(m, struct ip6_hdr *);
176: /* check for jumbogram is done in ip6_input. we can trust pkthdr.len */
177: plen = m->m_pkthdr.len - off;
178: #ifndef PULLDOWN_TEST
1.2 itojun 179: IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
180: uh = (struct udphdr *)((caddr_t)ip6 + off);
1.14 itojun 181: #else
1.24 itojun 182: IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr));
1.14 itojun 183: if (uh == NULL) {
184: udp6stat.udp6s_hdrops++;
185: return IPPROTO_DONE;
186: }
187: #endif
1.2 itojun 188: ulen = ntohs((u_short)uh->uh_ulen);
1.27 itojun 189: /*
190: * RFC2675 section 4: jumbograms will have 0 in the UDP header field,
191: * iff payload length > 0xffff.
192: */
193: if (ulen == 0 && plen > 0xffff)
1.14 itojun 194: ulen = plen;
1.2 itojun 195:
196: if (plen != ulen) {
197: udp6stat.udp6s_badlen++;
1.16 itojun 198: goto bad;
199: }
1.18 itojun 200:
201: /* destination port of 0 is illegal, based on RFC768. */
202: if (uh->uh_dport == 0)
203: goto bad;
1.16 itojun 204:
205: /* Be proactive about malicious use of IPv4 mapped address */
206: if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
207: IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
208: /* XXX stat */
1.2 itojun 209: goto bad;
210: }
211:
212: /*
213: * Checksum extended UDP header and data.
214: */
215: if (uh->uh_sum == 0)
216: udp6stat.udp6s_nosum++;
217: else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
218: udp6stat.udp6s_badsum++;
219: goto bad;
220: }
221:
222: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
223: struct in6pcb *last;
224:
225: /*
226: * Deliver a multicast datagram to all sockets
227: * for which the local and remote addresses and ports match
228: * those of the incoming datagram. This allows more than
229: * one process to receive multicasts on the same port.
230: * (This really ought to be done for unicast datagrams as
231: * well, but that would cause problems with existing
232: * applications that open both address-specific sockets and
233: * a wildcard socket listening to the same port -- they would
234: * end up receiving duplicates of every unicast datagram.
235: * Those applications open the multiple sockets to overcome an
236: * inadequacy of the UDP socket interface, but for backwards
237: * compatibility we avoid the problem here rather than
238: * fixing the interface. Maybe 4.5BSD will remedy this?)
239: */
240:
241: /*
242: * In a case that laddr should be set to the link-local
243: * address (this happens in RIPng), the multicast address
244: * specified in the received packet does not match with
245: * laddr. To cure this situation, the matching is relaxed
246: * if the receiving interface is the same as one specified
247: * in the socket and if the destination multicast address
248: * matches one of the multicast groups specified in the socket.
249: */
250:
1.27 itojun 251: /*
1.2 itojun 252: * Construct sockaddr format source address.
253: */
254: bzero(&udp_in6, sizeof(udp_in6));
255: udp_in6.sin6_len = sizeof(struct sockaddr_in6);
256: udp_in6.sin6_family = AF_INET6;
257: udp_in6.sin6_port = uh->uh_sport;
258: udp_in6.sin6_addr = ip6->ip6_src;
259: if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
260: udp_in6.sin6_addr.s6_addr16[1] = 0;
261: if (m->m_pkthdr.rcvif) {
262: if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr)) {
263: udp_in6.sin6_scope_id =
264: m->m_pkthdr.rcvif->if_index;
265: } else
266: udp_in6.sin6_scope_id = 0;
267: } else
268: udp_in6.sin6_scope_id = 0;
269: /*
270: * KAME note: usually we drop udphdr from mbuf here.
271: * We need udphdr for IPsec processing so we do that later.
272: */
273:
274: /*
275: * Locate pcb(s) for datagram.
276: * (Algorithm copied from raw_intr().)
277: */
278: last = NULL;
279: for (in6p = udb6.in6p_next;
280: in6p != &udb6;
281: in6p = in6p->in6p_next) {
282: if (in6p->in6p_lport != uh->uh_dport)
283: continue;
1.14 itojun 284: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
1.2 itojun 285: if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
286: &ip6->ip6_dst) &&
287: !in6_mcmatch(in6p, &ip6->ip6_dst,
288: m->m_pkthdr.rcvif))
289: continue;
290: }
1.14 itojun 291: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
1.2 itojun 292: if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
293: &ip6->ip6_src) ||
294: in6p->in6p_fport != uh->uh_sport)
295: continue;
296: }
297:
298: if (last != NULL) {
299: struct mbuf *n;
300:
301: #ifdef IPSEC
302: /*
303: * Check AH/ESP integrity.
304: */
1.24 itojun 305: if (ipsec6_in_reject(m, last)) {
1.2 itojun 306: ipsec6stat.in_polvio++;
307: /* do not inject data into pcb */
308: } else
309: #endif /*IPSEC*/
310: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
311: /*
312: * KAME NOTE: do not
313: * m_copy(m, offset, ...) above.
314: * sbappendaddr() expects M_PKTHDR,
315: * and m_copy() will copy M_PKTHDR
316: * only if offset is 0.
317: */
1.8 itojun 318: if (last->in6p_flags & IN6P_CONTROLOPTS
319: || last->in6p_socket->so_options & SO_TIMESTAMP) {
1.2 itojun 320: ip6_savecontrol(last, &opts,
321: ip6, n);
322: }
323:
1.11 itojun 324: m_adj(n, off + sizeof(struct udphdr));
1.2 itojun 325: if (sbappendaddr(&last->in6p_socket->so_rcv,
326: (struct sockaddr *)&udp_in6,
327: n, opts) == 0) {
328: m_freem(n);
329: if (opts)
330: m_freem(opts);
331: udp6stat.udp6s_fullsock++;
332: } else
333: sorwakeup(last->in6p_socket);
334: opts = 0;
335: }
336: }
337: last = in6p;
338: /*
339: * Don't look for additional matches if this one does
340: * not have either the SO_REUSEPORT or SO_REUSEADDR
341: * socket options set. This heuristic avoids searching
342: * through all pcbs in the common case of a non-shared
343: * port. It assumes that an application will never
344: * clear these options after setting them.
345: */
346: if ((last->in6p_socket->so_options &
347: (SO_REUSEPORT|SO_REUSEADDR)) == 0)
348: break;
349: }
350:
351: if (last == NULL) {
352: /*
353: * No matching pcb found; discard datagram.
354: * (No need to send an ICMP Port Unreachable
355: * for a broadcast or multicast datgram.)
356: */
357: udp6stat.udp6s_noport++;
358: udp6stat.udp6s_noportmcast++;
359: goto bad;
360: }
361: #ifdef IPSEC
362: /*
363: * Check AH/ESP integrity.
364: */
365: if (last != NULL && ipsec6_in_reject(m, last)) {
366: ipsec6stat.in_polvio++;
367: goto bad;
368: }
369: #endif /*IPSEC*/
1.8 itojun 370: if (last->in6p_flags & IN6P_CONTROLOPTS
371: || last->in6p_socket->so_options & SO_TIMESTAMP) {
1.2 itojun 372: ip6_savecontrol(last, &opts, ip6, m);
1.8 itojun 373: }
1.2 itojun 374:
375: m_adj(m, off + sizeof(struct udphdr));
376: if (sbappendaddr(&last->in6p_socket->so_rcv,
377: (struct sockaddr *)&udp_in6,
378: m, opts) == 0) {
379: udp6stat.udp6s_fullsock++;
380: goto bad;
381: }
382: sorwakeup(last->in6p_socket);
383: return IPPROTO_DONE;
384: }
385: /*
386: * Locate pcb for datagram.
387: */
388: in6p = udp6_last_in6pcb;
389: if (in6p->in6p_lport != uh->uh_dport ||
390: in6p->in6p_fport != uh->uh_sport ||
391: !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src) ||
392: !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) {
393: in6p = in6_pcblookup(&udb6,
394: &ip6->ip6_src, uh->uh_sport,
395: &ip6->ip6_dst, uh->uh_dport,
396: IN6PLOOKUP_WILDCARD);
397: if (in6p)
398: udp6_last_in6pcb = in6p;
399: udp6stat.udp6ps_pcbcachemiss++;
400: }
401: if (in6p == 0) {
402: udp6stat.udp6s_noport++;
403: if (m->m_flags & M_MCAST) {
404: printf("UDP6: M_MCAST is set in a unicast packet.\n");
405: udp6stat.udp6s_noportmcast++;
406: goto bad;
407: }
408: icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
409: return IPPROTO_DONE;
410: }
411: #ifdef IPSEC
412: /*
413: * Check AH/ESP integrity.
414: */
415: if (in6p != NULL && ipsec6_in_reject(m, in6p)) {
416: ipsec6stat.in_polvio++;
417: goto bad;
418: }
419: #endif /*IPSEC*/
420:
421: /*
422: * Construct sockaddr format source address.
423: * Stuff source address and datagram in user buffer.
424: */
425: bzero(&udp_in6, sizeof(udp_in6));
426: udp_in6.sin6_len = sizeof(struct sockaddr_in6);
427: udp_in6.sin6_family = AF_INET6;
428: udp_in6.sin6_port = uh->uh_sport;
429: udp_in6.sin6_addr = ip6->ip6_src;
430: if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
431: udp_in6.sin6_addr.s6_addr16[1] = 0;
432: if (m->m_pkthdr.rcvif) {
433: if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
434: udp_in6.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
435: else
436: udp_in6.sin6_scope_id = 0;
437: } else
438: udp_in6.sin6_scope_id = 0;
1.8 itojun 439: if (in6p->in6p_flags & IN6P_CONTROLOPTS
440: || in6p->in6p_socket->so_options & SO_TIMESTAMP) {
1.2 itojun 441: ip6_savecontrol(in6p, &opts, ip6, m);
1.8 itojun 442: }
1.2 itojun 443:
444: m_adj(m, off + sizeof(struct udphdr));
445: if (sbappendaddr(&in6p->in6p_socket->so_rcv,
446: (struct sockaddr *)&udp_in6,
447: m, opts) == 0) {
448: udp6stat.udp6s_fullsock++;
449: goto bad;
450: }
451: sorwakeup(in6p->in6p_socket);
452: return IPPROTO_DONE;
453: bad:
454: if (m)
455: m_freem(m);
456: if (opts)
457: m_freem(opts);
458: return IPPROTO_DONE;
459: }
1.14 itojun 460: #endif
1.2 itojun 461:
462: /*
463: * Notify a udp user of an asynchronous error;
1.27 itojun 464: * just wake up so that he can collect error status.
1.2 itojun 465: */
466: static void
467: udp6_notify(in6p, errno)
468: register struct in6pcb *in6p;
469: int errno;
470: {
471: in6p->in6p_socket->so_error = errno;
472: sorwakeup(in6p->in6p_socket);
473: sowwakeup(in6p->in6p_socket);
474: }
475:
476: void
1.14 itojun 477: udp6_ctlinput(cmd, sa, d)
1.2 itojun 478: int cmd;
479: struct sockaddr *sa;
1.14 itojun 480: void *d;
1.2 itojun 481: {
482: register struct udphdr *uhp;
483: struct udphdr uh;
1.7 itojun 484: struct sockaddr_in6 sa6;
1.14 itojun 485: register struct ip6_hdr *ip6;
486: struct mbuf *m;
487: int off;
1.25 itojun 488: void (*notify) __P((struct in6pcb *, int)) = udp6_notify;
1.2 itojun 489:
1.10 itojun 490: if (sa->sa_family != AF_INET6 ||
491: sa->sa_len != sizeof(struct sockaddr_in6))
492: return;
1.14 itojun 493:
1.25 itojun 494: if ((unsigned)cmd >= PRC_NCMDS)
495: return;
496: if (PRC_IS_REDIRECT(cmd))
497: notify = in6_rtchange, d = NULL;
498: else if (cmd == PRC_HOSTDEAD)
499: d = NULL;
500: else if (inet6ctlerrmap[cmd] == 0)
1.2 itojun 501: return;
1.7 itojun 502:
1.14 itojun 503: /* if the parameter is from icmp6, decode it. */
504: if (d != NULL) {
505: struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
506: m = ip6cp->ip6c_m;
507: ip6 = ip6cp->ip6c_ip6;
508: off = ip6cp->ip6c_off;
509: } else {
510: m = NULL;
511: ip6 = NULL;
512: }
513:
1.7 itojun 514: /* translate addresses into internal form */
515: sa6 = *(struct sockaddr_in6 *)sa;
1.22 itojun 516: if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
1.7 itojun 517: sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
518:
1.2 itojun 519: if (ip6) {
520: /*
521: * XXX: We assume that when IPV6 is non NULL,
522: * M and OFF are valid.
523: */
1.7 itojun 524: struct in6_addr s;
525:
526: /* translate addresses into internal form */
1.12 itojun 527: memcpy(&s, &ip6->ip6_src, sizeof(s));
1.7 itojun 528: if (IN6_IS_ADDR_LINKLOCAL(&s))
529: s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
530:
1.2 itojun 531: if (m->m_len < off + sizeof(uh)) {
532: /*
533: * this should be rare case,
534: * so we compromise on this copy...
535: */
536: m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
537: uhp = &uh;
538: } else
539: uhp = (struct udphdr *)(mtod(m, caddr_t) + off);
1.7 itojun 540: (void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6,
541: uhp->uh_dport, &s,
1.25 itojun 542: uhp->uh_sport, cmd, notify);
1.2 itojun 543: } else {
1.7 itojun 544: (void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6, 0,
1.25 itojun 545: &zeroin6_addr, 0, cmd, notify);
1.2 itojun 546: }
547: }
548:
549: int
1.29 itojun 550: udp6_output(in6p, m, addr6, control, p)
1.2 itojun 551: register struct in6pcb *in6p;
552: register struct mbuf *m;
553: struct mbuf *addr6, *control;
1.29 itojun 554: struct proc *p;
1.2 itojun 555: {
1.14 itojun 556: register u_int32_t ulen = m->m_pkthdr.len;
557: u_int32_t plen = sizeof(struct udphdr) + ulen;
1.2 itojun 558: struct ip6_hdr *ip6;
559: struct udphdr *udp6;
1.14 itojun 560: struct in6_addr *laddr, *faddr;
561: u_short fport;
562: int error = 0;
1.2 itojun 563: struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
1.14 itojun 564: int priv;
565: int af, hlen;
566: #ifdef INET
567: struct ip *ip;
568: #endif
1.30 ! itojun 569: struct sockaddr_in6 tmp;
1.2 itojun 570:
1.14 itojun 571: priv = 0;
1.2 itojun 572: if (p && !suser(p->p_ucred, &p->p_acflag))
573: priv = 1;
574: if (control) {
575: if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
576: goto release;
577: in6p->in6p_outputopts = &opt;
578: }
579:
580: if (addr6) {
1.14 itojun 581: /*
582: * IPv4 version of udp_output calls in_pcbconnect in this case,
583: * which needs splnet and affects performance.
584: * Since we saw no essential reason for calling in_pcbconnect,
585: * we get rid of such kind of logic, and call in6_selectsrc
586: * and In6_pcbsetport in order to fill in the local address
587: * and the local port.
588: */
589: struct sockaddr_in6 *sin6 = mtod(addr6, struct sockaddr_in6 *);
590:
591: if (addr6->m_len != sizeof(*sin6)) {
592: error = EINVAL;
593: goto release;
594: }
595: if (sin6->sin6_family != AF_INET6) {
596: error = EAFNOSUPPORT;
597: goto release;
598: }
599: if (sin6->sin6_port == 0) {
600: error = EADDRNOTAVAIL;
601: goto release;
602: }
603:
604: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
1.2 itojun 605: error = EISCONN;
606: goto release;
607: }
1.30 ! itojun 608:
! 609: /* protect *sin6 from overwrites */
! 610: tmp = *sin6;
! 611: sin6 = &tmp;
1.14 itojun 612:
613: faddr = &sin6->sin6_addr;
614: fport = sin6->sin6_port; /* allow 0 port */
1.2 itojun 615: /*
1.14 itojun 616: * If the scope of the destination is link-local,
1.27 itojun 617: * embed the interface index in the address.
1.14 itojun 618: *
1.27 itojun 619: * XXX advanced-api value overrides sin6_scope_id
1.2 itojun 620: */
1.14 itojun 621: if (IN6_IS_ADDR_LINKLOCAL(faddr) ||
622: IN6_IS_ADDR_MC_LINKLOCAL(faddr)) {
623: struct ip6_pktopts *optp = in6p->in6p_outputopts;
624: struct in6_pktinfo *pi = NULL;
625: struct ifnet *oifp = NULL;
626: struct ip6_moptions *mopt = NULL;
627:
628: /*
629: * XXX Boundary check is assumed to be already done in
630: * ip6_setpktoptions().
631: */
632: if (optp && (pi = optp->ip6po_pktinfo) &&
633: pi->ipi6_ifindex) {
634: faddr->s6_addr16[1] = htons(pi->ipi6_ifindex);
635: oifp = ifindex2ifnet[pi->ipi6_ifindex];
1.27 itojun 636: } else if (IN6_IS_ADDR_MULTICAST(faddr) &&
1.14 itojun 637: (mopt = in6p->in6p_moptions) &&
638: mopt->im6o_multicast_ifp) {
639: oifp = mopt->im6o_multicast_ifp;
1.27 itojun 640: faddr->s6_addr16[1] = htons(oifp->if_index);
1.14 itojun 641: } else if (sin6->sin6_scope_id) {
642: /* boundary check */
1.27 itojun 643: if (sin6->sin6_scope_id < 0
1.14 itojun 644: || if_index < sin6->sin6_scope_id) {
645: error = ENXIO; /* XXX EINVAL? */
646: goto release;
647: }
648: /* XXX */
649: faddr->s6_addr16[1] =
650: htons(sin6->sin6_scope_id & 0xffff);
651: }
652: }
653:
654: if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
655: laddr = in6_selectsrc(sin6, in6p->in6p_outputopts,
656: in6p->in6p_moptions,
657: &in6p->in6p_route,
658: &in6p->in6p_laddr, &error);
659: } else
660: laddr = &in6p->in6p_laddr; /*XXX*/
661: if (laddr == NULL) {
662: if (error == 0)
663: error = EADDRNOTAVAIL;
1.2 itojun 664: goto release;
665: }
1.14 itojun 666: if (in6p->in6p_lport == 0 &&
667: (error = in6_pcbsetport(laddr, in6p)) != 0)
668: goto release;
1.2 itojun 669: } else {
1.14 itojun 670: if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
1.2 itojun 671: error = ENOTCONN;
672: goto release;
673: }
1.14 itojun 674: laddr = &in6p->in6p_laddr;
675: faddr = &in6p->in6p_faddr;
676: fport = in6p->in6p_fport;
1.2 itojun 677: }
1.14 itojun 678:
679: if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
680: af = AF_INET6;
681: hlen = sizeof(struct ip6_hdr);
682: } else {
683: af = AF_INET;
684: hlen = sizeof(struct ip);
685: }
686:
1.2 itojun 687: /*
688: * Calculate data length and get a mbuf
689: * for UDP and IP6 headers.
690: */
1.14 itojun 691: M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
1.2 itojun 692: if (m == 0) {
693: error = ENOBUFS;
694: goto release;
695: }
696:
697: /*
698: * Stuff checksum and output datagram.
699: */
1.14 itojun 700: udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
701: udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */
702: udp6->uh_dport = fport;
703: if (plen <= 0xffff)
704: udp6->uh_ulen = htons((u_short)plen);
705: else
706: udp6->uh_ulen = 0;
707: udp6->uh_sum = 0;
708:
709: switch (af) {
710: case AF_INET6:
711: ip6 = mtod(m, struct ip6_hdr *);
712: ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
1.15 itojun 713: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
714: ip6->ip6_vfc |= IPV6_VERSION;
1.2 itojun 715: #if 0 /* ip6_plen will be filled in ip6_output. */
1.14 itojun 716: ip6->ip6_plen = htons((u_short)plen);
1.2 itojun 717: #endif
1.14 itojun 718: ip6->ip6_nxt = IPPROTO_UDP;
719: ip6->ip6_hlim = in6_selecthlim(in6p,
720: in6p->in6p_route.ro_rt ?
721: in6p->in6p_route.ro_rt->rt_ifp : NULL);
722: ip6->ip6_src = *laddr;
723: ip6->ip6_dst = *faddr;
724:
725: if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
726: sizeof(struct ip6_hdr), plen)) == 0) {
727: udp6->uh_sum = 0xffff;
728: }
729:
730: udp6stat.udp6s_opackets++;
731: #ifdef IPSEC
1.26 itojun 732: ipsec_setsocket(m, in6p->in6p_socket);
1.14 itojun 733: #endif /*IPSEC*/
734: error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
735: 0, in6p->in6p_moptions, NULL);
736: break;
737: case AF_INET:
738: #ifdef INET
739: /* can't transmit jumbogram over IPv4 */
740: if (plen > 0xffff) {
741: error = EMSGSIZE;
742: goto release;
743: }
744:
745: ip = mtod(m, struct ip *);
1.2 itojun 746:
1.14 itojun 747: ip->ip_len = plen;
748: ip->ip_p = IPPROTO_UDP;
749: ip->ip_ttl = in6p->in6p_hops; /*XXX*/
750: ip->ip_tos = 0; /*XXX*/
751: bcopy(&laddr->s6_addr[12], &ip->ip_src, sizeof(ip->ip_src));
752: bcopy(&faddr->s6_addr[12], &ip->ip_dst, sizeof(ip->ip_dst));
753:
754: udp6->uh_sum = 0;
755: if ((udp6->uh_sum = in_cksum(m, ulen)) == 0)
756: udp6->uh_sum = 0xffff;
1.2 itojun 757:
1.14 itojun 758: udpstat.udps_opackets++;
1.2 itojun 759: #ifdef IPSEC
1.26 itojun 760: ipsec_setsocket(m, NULL); /*XXX*/
1.2 itojun 761: #endif /*IPSEC*/
1.14 itojun 762: error = ip_output(m, NULL, &in6p->in6p_route, 0 /*XXX*/);
763: break;
764: #else
765: error = EAFNOSUPPORT;
766: goto release;
767: #endif
1.2 itojun 768: }
769: goto releaseopt;
770:
771: release:
772: m_freem(m);
773:
774: releaseopt:
775: if (control) {
776: in6p->in6p_outputopts = stickyopt;
777: m_freem(control);
778: }
779: return(error);
780: }
781:
782: extern int udp6_sendspace;
783: extern int udp6_recvspace;
784:
785: int
786: udp6_usrreq(so, req, m, addr6, control, p)
787: struct socket *so;
788: int req;
789: struct mbuf *m, *addr6, *control;
790: struct proc *p;
791: {
792: struct in6pcb *in6p = sotoin6pcb(so);
793: int error = 0;
794: int s;
795:
1.27 itojun 796: /*
1.2 itojun 797: * MAPPED_ADDR implementation info:
798: * Mapped addr support for PRU_CONTROL is not necessary.
799: * Because typical user of PRU_CONTROL is such as ifconfig,
800: * and they don't associate any addr to their socket. Then
801: * socket family is only hint about the PRU_CONTROL'ed address
802: * family, especially when getting addrs from kernel.
803: * So AF_INET socket need to be used to control AF_INET addrs,
804: * and AF_INET6 socket for AF_INET6 addrs.
805: */
806: if (req == PRU_CONTROL)
807: return(in6_control(so, (u_long)m, (caddr_t)addr6,
808: (struct ifnet *)control, p));
1.20 thorpej 809:
1.21 thorpej 810: if (req == PRU_PURGEIF) {
811: in6_purgeif((struct ifnet *)control);
812: in6_pcbpurgeif(&udb6, (struct ifnet *)control);
1.20 thorpej 813: return (0);
814: }
1.2 itojun 815:
816: if (in6p == NULL && req != PRU_ATTACH) {
817: error = EINVAL;
818: goto release;
819: }
820:
821: switch (req) {
822: case PRU_ATTACH:
823: /*
824: * MAPPED_ADDR implementation spec:
1.27 itojun 825: * Always attach for IPv6,
1.2 itojun 826: * and only when necessary for IPv4.
827: */
828: if (in6p != NULL) {
829: error = EINVAL;
830: break;
831: }
1.4 itojun 832: s = splsoftnet();
1.2 itojun 833: error = in6_pcballoc(so, &udb6);
834: splx(s);
835: if (error)
836: break;
837: error = soreserve(so, udp6_sendspace, udp6_recvspace);
838: if (error)
839: break;
840: in6p = sotoin6pcb(so);
841: in6p->in6p_cksum = -1; /* just to be sure */
842: #ifdef IPSEC
1.19 itojun 843: error = ipsec_init_policy(so, &in6p->in6p_sp);
1.14 itojun 844: if (error != 0) {
1.13 itojun 845: in6_pcbdetach(in6p);
1.14 itojun 846: break;
847: }
1.2 itojun 848: #endif /*IPSEC*/
849: break;
850:
851: case PRU_DETACH:
852: udp6_detach(in6p);
853: break;
854:
855: case PRU_BIND:
1.4 itojun 856: s = splsoftnet();
1.29 itojun 857: error = in6_pcbbind(in6p, addr6, p);
1.2 itojun 858: splx(s);
859: break;
860:
861: case PRU_LISTEN:
862: error = EOPNOTSUPP;
863: break;
864:
865: case PRU_CONNECT:
1.14 itojun 866: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
1.2 itojun 867: error = EISCONN;
868: break;
869: }
1.4 itojun 870: s = splsoftnet();
1.2 itojun 871: error = in6_pcbconnect(in6p, addr6);
872: if (ip6_auto_flowlabel) {
873: in6p->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
1.27 itojun 874: in6p->in6p_flowinfo |=
1.2 itojun 875: (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
876: }
877: splx(s);
878: if (error == 0)
879: soisconnected(so);
880: break;
881:
882: case PRU_CONNECT2:
883: error = EOPNOTSUPP;
884: break;
885:
886: case PRU_ACCEPT:
887: error = EOPNOTSUPP;
888: break;
889:
890: case PRU_DISCONNECT:
891: if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
892: error = ENOTCONN;
893: break;
894: }
1.4 itojun 895: s = splsoftnet();
1.2 itojun 896: in6_pcbdisconnect(in6p);
897: bzero((caddr_t)&in6p->in6p_laddr, sizeof(in6p->in6p_laddr));
898: splx(s);
899: so->so_state &= ~SS_ISCONNECTED; /* XXX */
900: break;
901:
902: case PRU_SHUTDOWN:
903: socantsendmore(so);
904: break;
905:
906: case PRU_SEND:
1.29 itojun 907: return(udp6_output(in6p, m, addr6, control, p));
1.2 itojun 908:
909: case PRU_ABORT:
910: soisdisconnected(so);
911: udp6_detach(in6p);
912: break;
913:
914: case PRU_SOCKADDR:
915: in6_setsockaddr(in6p, addr6);
916: break;
917:
918: case PRU_PEERADDR:
919: in6_setpeeraddr(in6p, addr6);
920: break;
921:
922: case PRU_SENSE:
923: /*
924: * stat: don't bother with a blocksize
925: */
926: return(0);
927:
928: case PRU_SENDOOB:
929: case PRU_FASTTIMO:
930: case PRU_SLOWTIMO:
931: case PRU_PROTORCV:
932: case PRU_PROTOSEND:
933: error = EOPNOTSUPP;
934: break;
935:
936: case PRU_RCVD:
937: case PRU_RCVOOB:
938: return(EOPNOTSUPP); /* do not free mbuf's */
939:
940: default:
941: panic("udp6_usrreq");
942: }
943:
944: release:
945: if (control) {
946: printf("udp control data unexpectedly retained\n");
947: m_freem(control);
948: }
949: if (m)
950: m_freem(m);
951: return(error);
952: }
953:
954: static void
955: udp6_detach(in6p)
956: struct in6pcb *in6p;
957: {
1.27 itojun 958: int s = splsoftnet();
1.2 itojun 959:
960: if (in6p == udp6_last_in6pcb)
961: udp6_last_in6pcb = &udb6;
962: in6_pcbdetach(in6p);
963: splx(s);
964: }
965:
966: #include <vm/vm.h>
967: #include <sys/sysctl.h>
968:
969: int
970: udp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
971: int *name;
972: u_int namelen;
973: void *oldp;
974: size_t *oldlenp;
975: void *newp;
976: size_t newlen;
977: {
978: /* All sysctl names at this level are terminal. */
979: if (namelen != 1)
980: return ENOTDIR;
981:
982: switch (name[0]) {
983:
1.28 itojun 984: case UDP6CTL_SENDSPACE:
1.2 itojun 985: return sysctl_int(oldp, oldlenp, newp, newlen,
986: &udp6_sendspace);
987: case UDP6CTL_RECVSPACE:
1.27 itojun 988: return sysctl_int(oldp, oldlenp, newp, newlen,
1.2 itojun 989: &udp6_recvspace);
990: default:
991: return ENOPROTOOPT;
992: }
993: /* NOTREACHED */
994: }
CVSweb <webmaster@jp.NetBSD.org>