Annotation of src/sys/netinet6/raw_ip6.c, Revision 1.82
1.82 ! dyoung 1: /* $NetBSD: raw_ip6.c,v 1.81 2007/02/10 09:43:05 degroote Exp $ */
1.34 itojun 2: /* $KAME: raw_ip6.c,v 1.82 2001/07/23 18:57:56 jinmei Exp $ */
1.3 thorpej 3:
1.2 itojun 4: /*
5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6: * All rights reserved.
1.24 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.24 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, 1988, 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.
1.55 agc 45: * 3. Neither the name of the University nor the names of its contributors
1.2 itojun 46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: *
61: * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
62: */
1.39 lukem 63:
64: #include <sys/cdefs.h>
1.82 ! dyoung 65: __KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.81 2007/02/10 09:43:05 degroote Exp $");
1.6 thorpej 66:
67: #include "opt_ipsec.h"
1.2 itojun 68:
69: #include <sys/param.h>
1.69 atatat 70: #include <sys/sysctl.h>
1.2 itojun 71: #include <sys/malloc.h>
72: #include <sys/mbuf.h>
73: #include <sys/socket.h>
74: #include <sys/protosw.h>
75: #include <sys/socketvar.h>
76: #include <sys/errno.h>
77: #include <sys/systm.h>
78: #include <sys/proc.h>
1.77 elad 79: #include <sys/kauth.h>
1.2 itojun 80:
81: #include <net/if.h>
82: #include <net/route.h>
83: #include <net/if_types.h>
84:
85: #include <netinet/in.h>
86: #include <netinet/in_var.h>
1.19 itojun 87: #include <netinet/ip6.h>
1.2 itojun 88: #include <netinet6/ip6_var.h>
89: #include <netinet6/ip6_mroute.h>
1.19 itojun 90: #include <netinet/icmp6.h>
1.2 itojun 91: #include <netinet6/in6_pcb.h>
92: #include <netinet6/nd6.h>
1.20 itojun 93: #include <netinet6/ip6protosw.h>
1.24 itojun 94: #include <netinet6/scope6_var.h>
1.37 itojun 95: #include <netinet6/raw_ip6.h>
1.2 itojun 96:
97: #ifdef IPSEC
98: #include <netinet6/ipsec.h>
1.38 itojun 99: #endif /* IPSEC */
1.2 itojun 100:
1.81 degroote 101: #ifdef FAST_IPSEC
102: #include <netipsec/ipsec.h>
103: #include <netipsec/ipsec_var.h> /* XXX ipsecstat namespace */
104: #include <netipsec/ipsec6.h>
105: #endif
106:
1.2 itojun 107: #include <machine/stdarg.h>
108:
109: #include "faith.h"
1.32 itojun 110: #if defined(NFAITH) && 0 < NFAITH
111: #include <net/if_faith.h>
112: #endif
1.2 itojun 113:
1.59 itojun 114: extern struct inpcbtable rawcbtable;
115: struct inpcbtable raw6cbtable;
1.2 itojun 116: #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
117:
118: /*
119: * Raw interface to IP6 protocol.
120: */
121:
1.37 itojun 122: struct rip6stat rip6stat;
123:
1.2 itojun 124: /*
125: * Initialize raw connection block queue.
126: */
127: void
128: rip6_init()
129: {
1.47 itojun 130:
1.59 itojun 131: in6_pcbinit(&raw6cbtable, 1, 1);
1.2 itojun 132: }
133:
134: /*
135: * Setup generic address and protocol structures
136: * for raw_input routine, then pass them along with
137: * mbuf chain.
138: */
139: int
140: rip6_input(mp, offp, proto)
141: struct mbuf **mp;
142: int *offp, proto;
143: {
144: struct mbuf *m = *mp;
1.27 itojun 145: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1.59 itojun 146: struct inpcb_hdr *inph;
1.27 itojun 147: struct in6pcb *in6p;
1.2 itojun 148: struct in6pcb *last = NULL;
149: struct sockaddr_in6 rip6src;
150: struct mbuf *opts = NULL;
151:
1.37 itojun 152: rip6stat.rip6s_ipackets++;
153:
1.2 itojun 154: #if defined(NFAITH) && 0 < NFAITH
1.32 itojun 155: if (faithprefix(&ip6->ip6_dst)) {
156: /* send icmp6 host unreach? */
157: m_freem(m);
158: return IPPROTO_DONE;
1.2 itojun 159: }
160: #endif
1.14 itojun 161:
162: /* Be proactive about malicious use of IPv4 mapped address */
163: if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
164: IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
165: /* XXX stat */
166: m_freem(m);
167: return IPPROTO_DONE;
168: }
169:
1.2 itojun 170: bzero(&rip6src, sizeof(rip6src));
171: rip6src.sin6_len = sizeof(struct sockaddr_in6);
172: rip6src.sin6_family = AF_INET6;
1.75 rpaulo 173: rip6src.sin6_addr = ip6->ip6_src;
174: if (sa6_recoverscope(&rip6src) != 0) {
175: /* XXX: should be impossible. */
176: m_freem(m);
177: return IPPROTO_DONE;
178: }
1.2 itojun 179:
1.59 itojun 180: CIRCLEQ_FOREACH(inph, &raw6cbtable.inpt_queue, inph_queue) {
181: in6p = (struct in6pcb *)inph;
182: if (in6p->in6p_af != AF_INET6)
183: continue;
1.2 itojun 184: if (in6p->in6p_ip6.ip6_nxt &&
185: in6p->in6p_ip6.ip6_nxt != proto)
186: continue;
1.12 itojun 187: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
1.37 itojun 188: !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
1.2 itojun 189: continue;
1.12 itojun 190: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
1.37 itojun 191: !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
1.2 itojun 192: continue;
1.37 itojun 193: if (in6p->in6p_cksum != -1) {
194: rip6stat.rip6s_isum++;
1.64 itojun 195: if (in6_cksum(m, proto, *offp,
1.37 itojun 196: m->m_pkthdr.len - *offp)) {
197: rip6stat.rip6s_badsum++;
198: continue;
199: }
1.2 itojun 200: }
201: if (last) {
202: struct mbuf *n;
1.30 itojun 203:
204: #ifdef IPSEC
205: /*
206: * Check AH/ESP integrity.
207: */
208: if (ipsec6_in_reject(m, last)) {
209: ipsec6stat.in_polvio++;
210: /* do not inject data into pcb */
211: } else
1.38 itojun 212: #endif /* IPSEC */
1.81 degroote 213: #ifdef FAST_IPSEC
214: /*
215: * Check AH/ESP integrity
216: */
217: if (!ipsec6_in_reject(m,last))
218: #endif /* FAST_IPSEC */
1.2 itojun 219: if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
220: if (last->in6p_flags & IN6P_CONTROLOPTS)
221: ip6_savecontrol(last, &opts, ip6, n);
222: /* strip intermediate headers */
223: m_adj(n, *offp);
224: if (sbappendaddr(&last->in6p_socket->so_rcv,
1.43 itojun 225: (struct sockaddr *)&rip6src, n, opts) == 0) {
1.2 itojun 226: /* should notify about lost packet */
227: m_freem(n);
228: if (opts)
229: m_freem(opts);
1.37 itojun 230: rip6stat.rip6s_fullsock++;
1.2 itojun 231: } else
232: sorwakeup(last->in6p_socket);
233: opts = NULL;
234: }
235: }
236: last = in6p;
237: }
1.30 itojun 238: #ifdef IPSEC
239: /*
240: * Check AH/ESP integrity.
241: */
242: if (last && ipsec6_in_reject(m, last)) {
243: m_freem(m);
244: ipsec6stat.in_polvio++;
245: ip6stat.ip6s_delivered--;
246: /* do not inject data into pcb */
247: } else
1.38 itojun 248: #endif /* IPSEC */
1.81 degroote 249: #ifdef FAST_IPSEC
250: if (last && ipsec6_in_reject(m, last)) {
251: m_freem(m);
252: /*
253: * XXX ipsec6_in_reject update stat if there is an error
254: * so we just need to update stats by hand in the case of last is
255: * NULL
256: */
257: if (!last)
258: ipsec6stat.in_polvio++;
259: ip6stat.ip6s_delivered--;
260: /* do not inject data into pcb */
261: } else
262: #endif /* FAST_IPSEC */
1.2 itojun 263: if (last) {
264: if (last->in6p_flags & IN6P_CONTROLOPTS)
265: ip6_savecontrol(last, &opts, ip6, m);
266: /* strip intermediate headers */
267: m_adj(m, *offp);
268: if (sbappendaddr(&last->in6p_socket->so_rcv,
1.43 itojun 269: (struct sockaddr *)&rip6src, m, opts) == 0) {
1.2 itojun 270: m_freem(m);
271: if (opts)
272: m_freem(opts);
1.37 itojun 273: rip6stat.rip6s_fullsock++;
1.2 itojun 274: } else
275: sorwakeup(last->in6p_socket);
276: } else {
1.37 itojun 277: rip6stat.rip6s_nosock++;
278: if (m->m_flags & M_MCAST)
279: rip6stat.rip6s_nosockmcast++;
1.2 itojun 280: if (proto == IPPROTO_NONE)
281: m_freem(m);
282: else {
1.50 itojun 283: u_int8_t *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
1.27 itojun 284: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_protounknown);
1.2 itojun 285: icmp6_error(m, ICMP6_PARAM_PROB,
1.43 itojun 286: ICMP6_PARAMPROB_NEXTHEADER,
1.50 itojun 287: prvnxtp - mtod(m, u_int8_t *));
1.2 itojun 288: }
289: ip6stat.ip6s_delivered--;
290: }
291: return IPPROTO_DONE;
292: }
293:
1.20 itojun 294: void
1.82 ! dyoung 295: rip6_ctlinput(int cmd, const struct sockaddr *sa, void *d)
1.20 itojun 296: {
1.27 itojun 297: struct ip6_hdr *ip6;
1.29 itojun 298: struct ip6ctlparam *ip6cp = NULL;
299: const struct sockaddr_in6 *sa6_src = NULL;
300: void *cmdarg;
1.21 itojun 301: void (*notify) __P((struct in6pcb *, int)) = in6_rtchange;
1.29 itojun 302: int nxt;
1.20 itojun 303:
304: if (sa->sa_family != AF_INET6 ||
305: sa->sa_len != sizeof(struct sockaddr_in6))
306: return;
307:
1.21 itojun 308: if ((unsigned)cmd >= PRC_NCMDS)
309: return;
310: if (PRC_IS_REDIRECT(cmd))
311: notify = in6_rtchange, d = NULL;
312: else if (cmd == PRC_HOSTDEAD)
313: d = NULL;
1.29 itojun 314: else if (cmd == PRC_MSGSIZE)
315: ; /* special code is present, see below */
1.21 itojun 316: else if (inet6ctlerrmap[cmd] == 0)
1.20 itojun 317: return;
318:
319: /* if the parameter is from icmp6, decode it. */
320: if (d != NULL) {
1.29 itojun 321: ip6cp = (struct ip6ctlparam *)d;
1.20 itojun 322: ip6 = ip6cp->ip6c_ip6;
1.29 itojun 323: cmdarg = ip6cp->ip6c_cmdarg;
324: sa6_src = ip6cp->ip6c_src;
325: nxt = ip6cp->ip6c_nxt;
1.20 itojun 326: } else {
327: ip6 = NULL;
1.29 itojun 328: cmdarg = NULL;
329: sa6_src = &sa6_any;
330: nxt = -1;
1.20 itojun 331: }
332:
1.29 itojun 333: if (ip6 && cmd == PRC_MSGSIZE) {
1.82 ! dyoung 334: const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *)sa;
1.29 itojun 335: int valid = 0;
336: struct in6pcb *in6p;
1.20 itojun 337:
338: /*
1.29 itojun 339: * Check to see if we have a valid raw IPv6 socket
340: * corresponding to the address in the ICMPv6 message
341: * payload, and the protocol (ip6_nxt) meets the socket.
342: * XXX chase extension headers, or pass final nxt value
343: * from icmp6_notify_error()
1.20 itojun 344: */
1.29 itojun 345: in6p = NULL;
1.59 itojun 346: in6p = in6_pcblookup_connect(&raw6cbtable, &sa6->sin6_addr, 0,
1.72 christos 347: (const struct in6_addr *)&sa6_src->sin6_addr, 0, 0);
1.29 itojun 348: #if 0
349: if (!in6p) {
350: /*
351: * As the use of sendto(2) is fairly popular,
352: * we may want to allow non-connected pcb too.
353: * But it could be too weak against attacks...
354: * We should at least check if the local
355: * address (= s) is really ours.
356: */
1.59 itojun 357: in6p = in6_pcblookup_bind(&raw6cbtable,
1.75 rpaulo 358: &sa6->sin6_addr, 0, 0);
1.29 itojun 359: }
360: #endif
361:
362: if (in6p && in6p->in6p_ip6.ip6_nxt &&
363: in6p->in6p_ip6.ip6_nxt == nxt)
364: valid++;
1.20 itojun 365:
1.29 itojun 366: /*
367: * Depending on the value of "valid" and routing table
368: * size (mtudisc_{hi,lo}wat), we will:
1.44 itojun 369: * - recalculate the new MTU and create the
1.29 itojun 370: * corresponding routing entry, or
371: * - ignore the MTU change notification.
372: */
373: icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1.20 itojun 374:
1.29 itojun 375: /*
376: * regardless of if we called icmp6_mtudisc_update(),
1.76 rpaulo 377: * we need to call in6_pcbnotify(), to notify path MTU
378: * change to the userland (RFC3542), because some
379: * unconnected sockets may share the same destination
380: * and want to know the path MTU.
1.29 itojun 381: */
1.20 itojun 382: }
1.29 itojun 383:
1.59 itojun 384: (void) in6_pcbnotify(&raw6cbtable, sa, 0,
1.72 christos 385: (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
1.20 itojun 386: }
387:
1.2 itojun 388: /*
389: * Generate IPv6 header and pass packet to ip6_output.
390: * Tack on options user may have setup with control call.
391: */
392: int
393: #if __STDC__
394: rip6_output(struct mbuf *m, ...)
395: #else
396: rip6_output(m, va_alist)
397: struct mbuf *m;
398: va_dcl
399: #endif
400: {
401: struct socket *so;
402: struct sockaddr_in6 *dstsock;
403: struct mbuf *control;
404: struct in6_addr *dst;
405: struct ip6_hdr *ip6;
406: struct in6pcb *in6p;
407: u_int plen = m->m_pkthdr.len;
408: int error = 0;
1.75 rpaulo 409: struct ip6_pktopts opt, *optp = NULL;
1.2 itojun 410: struct ifnet *oifp = NULL;
1.12 itojun 411: int type, code; /* for ICMPv6 output statistics only */
1.20 itojun 412: int priv = 0;
1.75 rpaulo 413: int scope_ambiguous = 0;
414: struct in6_addr *in6a;
1.2 itojun 415: va_list ap;
416:
417: va_start(ap, m);
418: so = va_arg(ap, struct socket *);
419: dstsock = va_arg(ap, struct sockaddr_in6 *);
420: control = va_arg(ap, struct mbuf *);
421: va_end(ap);
422:
423: in6p = sotoin6pcb(so);
424:
1.12 itojun 425: priv = 0;
1.78 ad 426: if (curlwp && !kauth_authorize_generic(curlwp->l_cred,
1.80 elad 427: KAUTH_GENERIC_ISSUSER, NULL))
1.75 rpaulo 428: priv = 1;
1.12 itojun 429:
1.2 itojun 430: dst = &dstsock->sin6_addr;
431: if (control) {
1.76 rpaulo 432: if ((error = ip6_setpktopts(control, &opt,
433: in6p->in6p_outputopts,
434: priv, so->so_proto->pr_protocol)) != 0) {
1.2 itojun 435: goto bad;
1.76 rpaulo 436: }
1.2 itojun 437: optp = &opt;
438: } else
439: optp = in6p->in6p_outputopts;
440:
1.12 itojun 441: /*
1.75 rpaulo 442: * Check and convert scope zone ID into internal form.
443: * XXX: we may still need to determine the zone later.
444: */
445: if (!(so->so_state & SS_ISCONNECTED)) {
446: if (dstsock->sin6_scope_id == 0 && !ip6_use_defzone)
447: scope_ambiguous = 1;
448: if ((error = sa6_embedscope(dstsock, ip6_use_defzone)) != 0)
449: goto bad;
450: }
451:
452: /*
1.12 itojun 453: * For an ICMPv6 packet, we should know its type and code
454: * to update statistics.
455: */
456: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
457: struct icmp6_hdr *icmp6;
458: if (m->m_len < sizeof(struct icmp6_hdr) &&
459: (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
460: error = ENOBUFS;
461: goto bad;
462: }
463: icmp6 = mtod(m, struct icmp6_hdr *);
464: type = icmp6->icmp6_type;
465: code = icmp6->icmp6_code;
1.62 christos 466: } else {
467: type = 0;
468: code = 0;
1.12 itojun 469: }
470:
1.52 itojun 471: M_PREPEND(m, sizeof(*ip6), M_DONTWAIT);
472: if (!m) {
473: error = ENOBUFS;
474: goto bad;
475: }
1.2 itojun 476: ip6 = mtod(m, struct ip6_hdr *);
477:
478: /*
479: * Next header might not be ICMP6 but use its pseudo header anyway.
480: */
481: ip6->ip6_dst = *dst;
482:
1.12 itojun 483: /*
484: * Source address selection.
485: */
1.75 rpaulo 486: if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions,
1.82 ! dyoung 487: (struct route *)&in6p->in6p_route, &in6p->in6p_laddr, &oifp,
! 488: &error)) == 0) {
1.75 rpaulo 489: if (error == 0)
490: error = EADDRNOTAVAIL;
491: goto bad;
492: }
493: ip6->ip6_src = *in6a;
1.2 itojun 494:
1.75 rpaulo 495: if (oifp && scope_ambiguous) {
496: /*
497: * Application should provide a proper zone ID or the use of
498: * default zone IDs should be enabled. Unfortunately, some
499: * applications do not behave as it should, so we need a
500: * workaround. Even if an appropriate ID is not determined
501: * (when it's required), if we can determine the outgoing
502: * interface. determine the zone ID based on the interface.
503: */
504: error = in6_setscope(&dstsock->sin6_addr, oifp, NULL);
505: if (error != 0)
1.2 itojun 506: goto bad;
1.12 itojun 507: }
1.75 rpaulo 508: ip6->ip6_dst = dstsock->sin6_addr;
1.2 itojun 509:
1.75 rpaulo 510: /* fill in the rest of the IPv6 header fields */
1.2 itojun 511: ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
1.20 itojun 512: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
513: ip6->ip6_vfc |= IPV6_VERSION;
1.75 rpaulo 514: /* ip6_plen will be filled in ip6_output, so not fill it here. */
1.2 itojun 515: ip6->ip6_nxt = in6p->in6p_ip6.ip6_nxt;
1.12 itojun 516: ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
1.2 itojun 517:
518: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
519: in6p->in6p_cksum != -1) {
520: int off;
1.67 yamt 521: u_int16_t sum;
1.2 itojun 522:
523: /* compute checksum */
524: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
525: off = offsetof(struct icmp6_hdr, icmp6_cksum);
526: else
527: off = in6p->in6p_cksum;
528: if (plen < off + 1) {
529: error = EINVAL;
530: goto bad;
531: }
532: off += sizeof(struct ip6_hdr);
533:
1.68 yamt 534: sum = 0;
535: m = m_copyback_cow(m, off, sizeof(sum), (caddr_t)&sum,
536: M_DONTWAIT);
537: if (m == NULL) {
1.66 yamt 538: error = ENOBUFS;
539: goto bad;
540: }
1.67 yamt 541: sum = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
1.68 yamt 542: m = m_copyback_cow(m, off, sizeof(sum), (caddr_t)&sum,
543: M_DONTWAIT);
544: if (m == NULL) {
545: error = ENOBUFS;
546: goto bad;
547: }
1.2 itojun 548: }
1.27 itojun 549:
1.76 rpaulo 550: error = ip6_output(m, optp, &in6p->in6p_route, 0,
1.57 itojun 551: in6p->in6p_moptions, so, &oifp);
1.12 itojun 552: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
553: if (oifp)
554: icmp6_ifoutstat_inc(oifp, type, code);
555: icmp6stat.icp6s_outhist[type]++;
1.37 itojun 556: } else
557: rip6stat.rip6s_opackets++;
1.2 itojun 558:
559: goto freectl;
560:
561: bad:
562: if (m)
563: m_freem(m);
564:
565: freectl:
1.76 rpaulo 566: if (control) {
567: ip6_clearpktopts(&opt, -1);
1.2 itojun 568: m_freem(control);
1.76 rpaulo 569: }
1.51 itojun 570: return (error);
1.2 itojun 571: }
572:
1.40 itojun 573: /*
1.2 itojun 574: * Raw IPv6 socket option processing.
1.40 itojun 575: */
1.2 itojun 576: int
1.82 ! dyoung 577: rip6_ctloutput(int op, struct socket *so, int level, int optname,
! 578: struct mbuf **mp)
1.2 itojun 579: {
580: int error = 0;
581:
1.27 itojun 582: switch (level) {
583: case IPPROTO_IPV6:
584: switch (optname) {
585: case MRT6_INIT:
586: case MRT6_DONE:
587: case MRT6_ADD_MIF:
588: case MRT6_DEL_MIF:
589: case MRT6_ADD_MFC:
590: case MRT6_DEL_MFC:
591: case MRT6_PIM:
592: if (op == PRCO_SETOPT) {
1.36 itojun 593: error = ip6_mrouter_set(optname, so, *mp);
594: if (*mp)
595: (void)m_free(*mp);
596: } else if (op == PRCO_GETOPT)
597: error = ip6_mrouter_get(optname, so, mp);
598: else
599: error = EINVAL;
600: return (error);
601: case IPV6_CHECKSUM:
1.43 itojun 602: return (ip6_raw_ctloutput(op, so, level, optname, mp));
1.36 itojun 603: default:
604: return (ip6_ctloutput(op, so, level, optname, mp));
1.27 itojun 605: }
606:
607: case IPPROTO_ICMPV6:
608: /*
609: * XXX: is it better to call icmp6_ctloutput() directly
610: * from protosw?
611: */
1.43 itojun 612: return (icmp6_ctloutput(op, so, level, optname, mp));
1.27 itojun 613:
614: default:
1.36 itojun 615: if (op == PRCO_SETOPT && *mp)
616: m_free(*mp);
617: return EINVAL;
1.2 itojun 618: }
619: }
620:
621: extern u_long rip6_sendspace;
622: extern u_long rip6_recvspace;
623:
624: int
1.74 christos 625: rip6_usrreq(so, req, m, nam, control, l)
1.27 itojun 626: struct socket *so;
1.2 itojun 627: int req;
628: struct mbuf *m, *nam, *control;
1.74 christos 629: struct lwp *l;
1.2 itojun 630: {
1.27 itojun 631: struct in6pcb *in6p = sotoin6pcb(so);
1.2 itojun 632: int s;
633: int error = 0;
1.12 itojun 634: int priv;
635:
636: priv = 0;
1.78 ad 637: if (l && !kauth_authorize_generic(l->l_cred,
1.80 elad 638: KAUTH_GENERIC_ISSUSER, NULL))
1.12 itojun 639: priv++;
1.2 itojun 640:
641: if (req == PRU_CONTROL)
642: return (in6_control(so, (u_long)m, (caddr_t)nam,
1.78 ad 643: (struct ifnet *)control, l));
1.17 thorpej 644:
1.18 thorpej 645: if (req == PRU_PURGEIF) {
1.59 itojun 646: in6_pcbpurgeif0(&raw6cbtable, (struct ifnet *)control);
1.18 thorpej 647: in6_purgeif((struct ifnet *)control);
1.59 itojun 648: in6_pcbpurgeif(&raw6cbtable, (struct ifnet *)control);
1.17 thorpej 649: return (0);
650: }
1.2 itojun 651:
652: switch (req) {
653: case PRU_ATTACH:
654: if (in6p)
655: panic("rip6_attach");
1.12 itojun 656: if (!priv) {
1.2 itojun 657: error = EACCES;
658: break;
659: }
1.4 itojun 660: s = splsoftnet();
1.27 itojun 661: if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) != 0) {
662: splx(s);
663: break;
664: }
1.59 itojun 665: if ((error = in6_pcballoc(so, &raw6cbtable)) != 0)
1.27 itojun 666: {
1.2 itojun 667: splx(s);
668: break;
669: }
670: splx(s);
671: in6p = sotoin6pcb(so);
1.5 itojun 672: in6p->in6p_ip6.ip6_nxt = (long)nam;
1.2 itojun 673: in6p->in6p_cksum = -1;
1.48 itojun 674:
1.2 itojun 675: MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
1.43 itojun 676: sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
1.12 itojun 677: if (in6p->in6p_icmp6filt == NULL) {
678: in6_pcbdetach(in6p);
679: error = ENOMEM;
680: break;
681: }
1.2 itojun 682: ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
683: break;
684:
685: case PRU_DISCONNECT:
686: if ((so->so_state & SS_ISCONNECTED) == 0) {
687: error = ENOTCONN;
688: break;
689: }
690: in6p->in6p_faddr = in6addr_any;
691: so->so_state &= ~SS_ISCONNECTED; /* XXX */
692: break;
693:
694: case PRU_ABORT:
695: soisdisconnected(so);
696: /* Fallthrough */
697: case PRU_DETACH:
698: if (in6p == 0)
699: panic("rip6_detach");
700: if (so == ip6_mrouter)
701: ip6_mrouter_done();
702: /* xxx: RSVP */
703: if (in6p->in6p_icmp6filt) {
704: FREE(in6p->in6p_icmp6filt, M_PCB);
705: in6p->in6p_icmp6filt = NULL;
706: }
707: in6_pcbdetach(in6p);
708: break;
709:
710: case PRU_BIND:
711: {
712: struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
713: struct ifaddr *ia = NULL;
714:
715: if (nam->m_len != sizeof(*addr)) {
716: error = EINVAL;
717: break;
718: }
1.79 dyoung 719: if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6) {
1.24 itojun 720: error = EADDRNOTAVAIL;
721: break;
722: }
1.75 rpaulo 723: if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0)
724: break;
1.34 itojun 725:
1.23 itojun 726: /*
727: * we don't support mapped address here, it would confuse
728: * users so reject it
729: */
730: if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
731: error = EADDRNOTAVAIL;
732: break;
733: }
1.24 itojun 734: if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
735: (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) {
1.2 itojun 736: error = EADDRNOTAVAIL;
737: break;
738: }
1.46 itojun 739: if (ia && ((struct in6_ifaddr *)ia)->ia6_flags &
1.2 itojun 740: (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
741: IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
742: error = EADDRNOTAVAIL;
743: break;
744: }
745: in6p->in6p_laddr = addr->sin6_addr;
746: break;
747: }
1.36 itojun 748:
1.2 itojun 749: case PRU_CONNECT:
1.40 itojun 750: {
1.2 itojun 751: struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
752: struct in6_addr *in6a = NULL;
1.75 rpaulo 753: struct ifnet *ifp = NULL;
754: int scope_ambiguous = 0;
1.2 itojun 755:
756: if (nam->m_len != sizeof(*addr)) {
757: error = EINVAL;
758: break;
759: }
1.79 dyoung 760: if (TAILQ_EMPTY(&ifnet)) {
1.2 itojun 761: error = EADDRNOTAVAIL;
762: break;
763: }
764: if (addr->sin6_family != AF_INET6) {
765: error = EAFNOSUPPORT;
766: break;
767: }
768:
1.75 rpaulo 769: /*
770: * Application should provide a proper zone ID or the use of
771: * default zone IDs should be enabled. Unfortunately, some
772: * applications do not behave as it should, so we need a
773: * workaround. Even if an appropriate ID is not determined,
774: * we'll see if we can determine the outgoing interface. If we
775: * can, determine the zone ID based on the interface below.
776: */
777: if (addr->sin6_scope_id == 0 && !ip6_use_defzone)
778: scope_ambiguous = 1;
779: if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0)
780: return(error);
1.24 itojun 781:
1.2 itojun 782: /* Source address selection. XXX: need pcblookup? */
1.12 itojun 783: in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
1.82 ! dyoung 784: in6p->in6p_moptions, (struct route *)&in6p->in6p_route,
1.75 rpaulo 785: &in6p->in6p_laddr, &ifp, &error);
1.12 itojun 786: if (in6a == NULL) {
1.2 itojun 787: if (error == 0)
788: error = EADDRNOTAVAIL;
789: break;
790: }
1.75 rpaulo 791: /* XXX: see above */
792: if (ifp && scope_ambiguous &&
793: (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) {
794: break;
795: }
1.2 itojun 796: in6p->in6p_laddr = *in6a;
797: in6p->in6p_faddr = addr->sin6_addr;
798: soisconnected(so);
799: break;
1.40 itojun 800: }
1.2 itojun 801:
802: case PRU_CONNECT2:
803: error = EOPNOTSUPP;
804: break;
805:
806: /*
807: * Mark the connection as being incapable of futther input.
808: */
809: case PRU_SHUTDOWN:
810: socantsendmore(so);
811: break;
812: /*
813: * Ship a packet out. The appropriate raw output
814: * routine handles any messaging necessary.
815: */
816: case PRU_SEND:
1.40 itojun 817: {
1.2 itojun 818: struct sockaddr_in6 tmp;
819: struct sockaddr_in6 *dst;
820:
1.24 itojun 821: /* always copy sockaddr to avoid overwrites */
1.2 itojun 822: if (so->so_state & SS_ISCONNECTED) {
823: if (nam) {
824: error = EISCONN;
825: break;
826: }
827: /* XXX */
828: bzero(&tmp, sizeof(tmp));
829: tmp.sin6_family = AF_INET6;
830: tmp.sin6_len = sizeof(struct sockaddr_in6);
831: bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
1.46 itojun 832: sizeof(struct in6_addr));
1.2 itojun 833: dst = &tmp;
834: } else {
835: if (nam == NULL) {
836: error = ENOTCONN;
837: break;
838: }
1.42 itojun 839: if (nam->m_len != sizeof(tmp)) {
840: error = EINVAL;
841: break;
842: }
843:
1.24 itojun 844: tmp = *mtod(nam, struct sockaddr_in6 *);
845: dst = &tmp;
1.42 itojun 846:
847: if (dst->sin6_family != AF_INET6) {
848: error = EAFNOSUPPORT;
849: break;
850: }
1.2 itojun 851: }
852: error = rip6_output(m, so, dst, control);
853: m = NULL;
854: break;
1.40 itojun 855: }
1.2 itojun 856:
857: case PRU_SENSE:
858: /*
859: * stat: don't bother with a blocksize
860: */
1.51 itojun 861: return (0);
1.2 itojun 862: /*
863: * Not supported.
864: */
865: case PRU_RCVOOB:
866: case PRU_RCVD:
867: case PRU_LISTEN:
868: case PRU_ACCEPT:
869: case PRU_SENDOOB:
870: error = EOPNOTSUPP;
871: break;
872:
873: case PRU_SOCKADDR:
874: in6_setsockaddr(in6p, nam);
875: break;
876:
877: case PRU_PEERADDR:
878: in6_setpeeraddr(in6p, nam);
879: break;
880:
881: default:
882: panic("rip6_usrreq");
883: }
884: if (m != NULL)
885: m_freem(m);
1.51 itojun 886: return (error);
1.2 itojun 887: }
1.69 atatat 888:
889: SYSCTL_SETUP(sysctl_net_inet6_raw6_setup, "sysctl net.inet6.raw6 subtree setup")
890: {
891:
892: sysctl_createv(clog, 0, NULL, NULL,
893: CTLFLAG_PERMANENT,
894: CTLTYPE_NODE, "net", NULL,
895: NULL, 0, NULL, 0,
896: CTL_NET, CTL_EOL);
897: sysctl_createv(clog, 0, NULL, NULL,
898: CTLFLAG_PERMANENT,
899: CTLTYPE_NODE, "inet6", NULL,
900: NULL, 0, NULL, 0,
901: CTL_NET, PF_INET6, CTL_EOL);
902: sysctl_createv(clog, 0, NULL, NULL,
903: CTLFLAG_PERMANENT,
904: CTLTYPE_NODE, "raw6",
905: SYSCTL_DESCR("Raw IPv6 settings"),
906: NULL, 0, NULL, 0,
907: CTL_NET, PF_INET6, IPPROTO_RAW, CTL_EOL);
908:
909: sysctl_createv(clog, 0, NULL, NULL,
910: CTLFLAG_PERMANENT,
1.71 atatat 911: CTLTYPE_STRUCT, "pcblist",
1.69 atatat 912: SYSCTL_DESCR("Raw IPv6 control block list"),
913: sysctl_inpcblist, 0, &raw6cbtable, 0,
914: CTL_NET, PF_INET6, IPPROTO_RAW,
915: CTL_CREATE, CTL_EOL);
1.73 rpaulo 916: sysctl_createv(clog, 0, NULL, NULL,
917: CTLFLAG_PERMANENT,
918: CTLTYPE_STRUCT, "stats",
919: SYSCTL_DESCR("Raw IPv6 statistics"),
920: NULL, 0, &rip6stat, sizeof(rip6stat),
921: CTL_NET, PF_INET6, IPPROTO_RAW, RAW6CTL_STATS,
922: CTL_EOL);
1.69 atatat 923: }
CVSweb <webmaster@jp.NetBSD.org>