Annotation of src/sys/netinet6/raw_ip6.c, Revision 1.49
1.49 ! itojun 1: /* $NetBSD: raw_ip6.c,v 1.48 2002/06/09 14:43:14 itojun 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.
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: * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
66: */
1.39 lukem 67:
68: #include <sys/cdefs.h>
1.49 ! itojun 69: __KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.48 2002/06/09 14:43:14 itojun Exp $");
1.6 thorpej 70:
71: #include "opt_ipsec.h"
1.2 itojun 72:
73: #include <sys/param.h>
74: #include <sys/malloc.h>
75: #include <sys/mbuf.h>
76: #include <sys/socket.h>
77: #include <sys/protosw.h>
78: #include <sys/socketvar.h>
79: #include <sys/errno.h>
80: #include <sys/systm.h>
81: #include <sys/proc.h>
82:
83: #include <net/if.h>
84: #include <net/route.h>
85: #include <net/if_types.h>
86:
87: #include <netinet/in.h>
88: #include <netinet/in_var.h>
1.19 itojun 89: #include <netinet/ip6.h>
1.2 itojun 90: #include <netinet6/ip6_var.h>
91: #include <netinet6/ip6_mroute.h>
1.19 itojun 92: #include <netinet/icmp6.h>
1.2 itojun 93: #include <netinet6/in6_pcb.h>
94: #include <netinet6/nd6.h>
1.20 itojun 95: #include <netinet6/ip6protosw.h>
1.24 itojun 96: #ifdef ENABLE_DEFAULT_SCOPE
97: #include <netinet6/scope6_var.h>
98: #endif
1.37 itojun 99: #include <netinet6/raw_ip6.h>
1.2 itojun 100:
101: #ifdef IPSEC
102: #include <netinet6/ipsec.h>
1.38 itojun 103: #endif /* IPSEC */
1.2 itojun 104:
105: #include <machine/stdarg.h>
106:
107: #include "faith.h"
1.32 itojun 108: #if defined(NFAITH) && 0 < NFAITH
109: #include <net/if_faith.h>
110: #endif
1.2 itojun 111:
112: struct in6pcb rawin6pcb;
113: #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
114:
115: /*
116: * Raw interface to IP6 protocol.
117: */
118:
1.37 itojun 119: struct rip6stat rip6stat;
120:
1.2 itojun 121: /*
122: * Initialize raw connection block queue.
123: */
124: void
125: rip6_init()
126: {
1.47 itojun 127:
1.2 itojun 128: rawin6pcb.in6p_next = rawin6pcb.in6p_prev = &rawin6pcb;
129: }
130:
131: /*
132: * Setup generic address and protocol structures
133: * for raw_input routine, then pass them along with
134: * mbuf chain.
135: */
136: int
137: rip6_input(mp, offp, proto)
138: struct mbuf **mp;
139: int *offp, proto;
140: {
141: struct mbuf *m = *mp;
1.27 itojun 142: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
143: struct in6pcb *in6p;
1.2 itojun 144: struct in6pcb *last = NULL;
145: struct sockaddr_in6 rip6src;
146: struct mbuf *opts = NULL;
147:
1.37 itojun 148: rip6stat.rip6s_ipackets++;
149:
1.2 itojun 150: #if defined(NFAITH) && 0 < NFAITH
1.32 itojun 151: if (faithprefix(&ip6->ip6_dst)) {
152: /* send icmp6 host unreach? */
153: m_freem(m);
154: return IPPROTO_DONE;
1.2 itojun 155: }
156: #endif
1.14 itojun 157:
158: /* Be proactive about malicious use of IPv4 mapped address */
159: if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
160: IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
161: /* XXX stat */
162: m_freem(m);
163: return IPPROTO_DONE;
164: }
165:
1.2 itojun 166: bzero(&rip6src, sizeof(rip6src));
167: rip6src.sin6_len = sizeof(struct sockaddr_in6);
168: rip6src.sin6_family = AF_INET6;
1.36 itojun 169: #if 0 /* XXX inbound flowlabel */
1.24 itojun 170: rip6src.sin6_flowinfo = ip6->ip6_flow & IPV6_FLOWINFO_MASK;
171: #endif
172: /* KAME hack: recover scopeid */
173: (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif);
1.2 itojun 174:
175: for (in6p = rawin6pcb.in6p_next;
1.28 itojun 176: in6p != &rawin6pcb; in6p = in6p->in6p_next)
177: {
1.2 itojun 178: if (in6p->in6p_ip6.ip6_nxt &&
179: in6p->in6p_ip6.ip6_nxt != proto)
180: continue;
1.12 itojun 181: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
1.37 itojun 182: !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
1.2 itojun 183: continue;
1.12 itojun 184: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
1.37 itojun 185: !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
1.2 itojun 186: continue;
1.37 itojun 187: if (in6p->in6p_cksum != -1) {
188: rip6stat.rip6s_isum++;
189: if (in6_cksum(m, ip6->ip6_nxt, *offp,
190: m->m_pkthdr.len - *offp)) {
191: rip6stat.rip6s_badsum++;
192: continue;
193: }
1.2 itojun 194: }
195: if (last) {
196: struct mbuf *n;
1.30 itojun 197:
198: #ifdef IPSEC
199: /*
200: * Check AH/ESP integrity.
201: */
202: if (ipsec6_in_reject(m, last)) {
203: ipsec6stat.in_polvio++;
204: /* do not inject data into pcb */
205: } else
1.38 itojun 206: #endif /* IPSEC */
1.2 itojun 207: if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
208: if (last->in6p_flags & IN6P_CONTROLOPTS)
209: ip6_savecontrol(last, &opts, ip6, n);
210: /* strip intermediate headers */
211: m_adj(n, *offp);
212: if (sbappendaddr(&last->in6p_socket->so_rcv,
1.43 itojun 213: (struct sockaddr *)&rip6src, n, opts) == 0) {
1.2 itojun 214: /* should notify about lost packet */
215: m_freem(n);
216: if (opts)
217: m_freem(opts);
1.37 itojun 218: rip6stat.rip6s_fullsock++;
1.2 itojun 219: } else
220: sorwakeup(last->in6p_socket);
221: opts = NULL;
222: }
223: }
224: last = in6p;
225: }
1.30 itojun 226: #ifdef IPSEC
227: /*
228: * Check AH/ESP integrity.
229: */
230: if (last && ipsec6_in_reject(m, last)) {
231: m_freem(m);
232: ipsec6stat.in_polvio++;
233: ip6stat.ip6s_delivered--;
234: /* do not inject data into pcb */
235: } else
1.38 itojun 236: #endif /* IPSEC */
1.2 itojun 237: if (last) {
238: if (last->in6p_flags & IN6P_CONTROLOPTS)
239: ip6_savecontrol(last, &opts, ip6, m);
240: /* strip intermediate headers */
241: m_adj(m, *offp);
242: if (sbappendaddr(&last->in6p_socket->so_rcv,
1.43 itojun 243: (struct sockaddr *)&rip6src, m, opts) == 0) {
1.2 itojun 244: m_freem(m);
245: if (opts)
246: m_freem(opts);
1.37 itojun 247: rip6stat.rip6s_fullsock++;
1.2 itojun 248: } else
249: sorwakeup(last->in6p_socket);
250: } else {
1.37 itojun 251: rip6stat.rip6s_nosock++;
252: if (m->m_flags & M_MCAST)
253: rip6stat.rip6s_nosockmcast++;
1.2 itojun 254: if (proto == IPPROTO_NONE)
255: m_freem(m);
256: else {
257: char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
1.27 itojun 258: in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_protounknown);
1.2 itojun 259: icmp6_error(m, ICMP6_PARAM_PROB,
1.43 itojun 260: ICMP6_PARAMPROB_NEXTHEADER,
261: prvnxtp - mtod(m, char *));
1.2 itojun 262: }
263: ip6stat.ip6s_delivered--;
264: }
265: return IPPROTO_DONE;
266: }
267:
1.20 itojun 268: void
269: rip6_ctlinput(cmd, sa, d)
270: int cmd;
271: struct sockaddr *sa;
272: void *d;
273: {
1.27 itojun 274: struct ip6_hdr *ip6;
1.20 itojun 275: struct mbuf *m;
276: int off;
1.29 itojun 277: struct ip6ctlparam *ip6cp = NULL;
278: const struct sockaddr_in6 *sa6_src = NULL;
279: void *cmdarg;
1.21 itojun 280: void (*notify) __P((struct in6pcb *, int)) = in6_rtchange;
1.29 itojun 281: int nxt;
1.20 itojun 282:
283: if (sa->sa_family != AF_INET6 ||
284: sa->sa_len != sizeof(struct sockaddr_in6))
285: return;
286:
1.21 itojun 287: if ((unsigned)cmd >= PRC_NCMDS)
288: return;
289: if (PRC_IS_REDIRECT(cmd))
290: notify = in6_rtchange, d = NULL;
291: else if (cmd == PRC_HOSTDEAD)
292: d = NULL;
1.29 itojun 293: else if (cmd == PRC_MSGSIZE)
294: ; /* special code is present, see below */
1.21 itojun 295: else if (inet6ctlerrmap[cmd] == 0)
1.20 itojun 296: return;
297:
298: /* if the parameter is from icmp6, decode it. */
299: if (d != NULL) {
1.29 itojun 300: ip6cp = (struct ip6ctlparam *)d;
1.20 itojun 301: m = ip6cp->ip6c_m;
302: ip6 = ip6cp->ip6c_ip6;
303: off = ip6cp->ip6c_off;
1.29 itojun 304: cmdarg = ip6cp->ip6c_cmdarg;
305: sa6_src = ip6cp->ip6c_src;
306: nxt = ip6cp->ip6c_nxt;
1.20 itojun 307: } else {
308: m = NULL;
309: ip6 = NULL;
1.29 itojun 310: cmdarg = NULL;
311: sa6_src = &sa6_any;
312: nxt = -1;
1.20 itojun 313: }
314:
1.29 itojun 315: if (ip6 && cmd == PRC_MSGSIZE) {
316: struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
317: int valid = 0;
318: struct in6pcb *in6p;
1.20 itojun 319:
320: /*
1.29 itojun 321: * Check to see if we have a valid raw IPv6 socket
322: * corresponding to the address in the ICMPv6 message
323: * payload, and the protocol (ip6_nxt) meets the socket.
324: * XXX chase extension headers, or pass final nxt value
325: * from icmp6_notify_error()
1.20 itojun 326: */
1.29 itojun 327: in6p = NULL;
1.43 itojun 328: in6p = in6_pcblookup_connect(&rawin6pcb, &sa6->sin6_addr, 0,
1.29 itojun 329: (struct in6_addr *)&sa6_src->sin6_addr, 0, 0);
330: #if 0
331: if (!in6p) {
332: /*
333: * As the use of sendto(2) is fairly popular,
334: * we may want to allow non-connected pcb too.
335: * But it could be too weak against attacks...
336: * We should at least check if the local
337: * address (= s) is really ours.
338: */
339: in6p = in6_pcblookup_bind(&rawin6pcb,
340: &sa6->sin6_addr, 0, 0))
341: }
342: #endif
343:
344: if (in6p && in6p->in6p_ip6.ip6_nxt &&
345: in6p->in6p_ip6.ip6_nxt == nxt)
346: valid++;
1.20 itojun 347:
1.29 itojun 348: /*
349: * Depending on the value of "valid" and routing table
350: * size (mtudisc_{hi,lo}wat), we will:
1.44 itojun 351: * - recalculate the new MTU and create the
1.29 itojun 352: * corresponding routing entry, or
353: * - ignore the MTU change notification.
354: */
355: icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1.20 itojun 356:
1.29 itojun 357: /*
358: * regardless of if we called icmp6_mtudisc_update(),
359: * we need to call in6_pcbnotify(), to notify path
360: * MTU change to the userland (2292bis-02), because
361: * some unconnected sockets may share the same
362: * destination and want to know the path MTU.
363: */
1.20 itojun 364: }
1.29 itojun 365:
366: (void) in6_pcbnotify(&rawin6pcb, sa, 0,
367: (struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
1.20 itojun 368: }
369:
1.2 itojun 370: /*
371: * Generate IPv6 header and pass packet to ip6_output.
372: * Tack on options user may have setup with control call.
373: */
374: int
375: #if __STDC__
376: rip6_output(struct mbuf *m, ...)
377: #else
378: rip6_output(m, va_alist)
379: struct mbuf *m;
380: va_dcl
381: #endif
382: {
383: struct socket *so;
384: struct sockaddr_in6 *dstsock;
385: struct mbuf *control;
386: struct in6_addr *dst;
387: struct ip6_hdr *ip6;
388: struct in6pcb *in6p;
389: u_int plen = m->m_pkthdr.len;
390: int error = 0;
1.24 itojun 391: struct ip6_pktopts opt, *optp = NULL, *origoptp;
1.2 itojun 392: struct ifnet *oifp = NULL;
1.12 itojun 393: int type, code; /* for ICMPv6 output statistics only */
1.20 itojun 394: int priv = 0;
1.2 itojun 395: va_list ap;
1.27 itojun 396: int flags;
1.2 itojun 397:
398: va_start(ap, m);
399: so = va_arg(ap, struct socket *);
400: dstsock = va_arg(ap, struct sockaddr_in6 *);
401: control = va_arg(ap, struct mbuf *);
402: va_end(ap);
403:
404: in6p = sotoin6pcb(so);
405:
1.12 itojun 406: priv = 0;
407: {
408: struct proc *p = curproc; /* XXX */
409:
410: if (p && !suser(p->p_ucred, &p->p_acflag))
411: priv = 1;
412: }
1.2 itojun 413: dst = &dstsock->sin6_addr;
414: if (control) {
415: if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
416: goto bad;
417: optp = &opt;
418: } else
419: optp = in6p->in6p_outputopts;
420:
1.12 itojun 421: /*
422: * For an ICMPv6 packet, we should know its type and code
423: * to update statistics.
424: */
425: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
426: struct icmp6_hdr *icmp6;
427: if (m->m_len < sizeof(struct icmp6_hdr) &&
428: (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
429: error = ENOBUFS;
430: goto bad;
431: }
432: icmp6 = mtod(m, struct icmp6_hdr *);
433: type = icmp6->icmp6_type;
434: code = icmp6->icmp6_code;
435: }
436:
1.2 itojun 437: M_PREPEND(m, sizeof(*ip6), M_WAIT);
438: ip6 = mtod(m, struct ip6_hdr *);
439:
440: /*
441: * Next header might not be ICMP6 but use its pseudo header anyway.
442: */
443: ip6->ip6_dst = *dst;
444:
1.24 itojun 445: /* KAME hack: embed scopeid */
446: origoptp = in6p->in6p_outputopts;
447: in6p->in6p_outputopts = optp;
448: if (in6_embedscope(&ip6->ip6_dst, dstsock, in6p, &oifp) != 0) {
449: error = EINVAL;
450: goto bad;
1.2 itojun 451: }
1.24 itojun 452: in6p->in6p_outputopts = origoptp;
1.2 itojun 453:
1.12 itojun 454: /*
455: * Source address selection.
456: */
457: {
1.2 itojun 458: struct in6_addr *in6a;
459:
1.43 itojun 460: if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions,
461: &in6p->in6p_route, &in6p->in6p_laddr, &error)) == 0) {
1.2 itojun 462: if (error == 0)
463: error = EADDRNOTAVAIL;
464: goto bad;
465: }
466: ip6->ip6_src = *in6a;
1.24 itojun 467: if (in6p->in6p_route.ro_rt) {
468: /* what if oifp contradicts ? */
1.2 itojun 469: oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index];
1.24 itojun 470: }
1.12 itojun 471: }
1.2 itojun 472:
473: ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
1.20 itojun 474: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
475: ip6->ip6_vfc |= IPV6_VERSION;
1.2 itojun 476: #if 0 /* ip6_plen will be filled in ip6_output. */
477: ip6->ip6_plen = htons((u_short)plen);
478: #endif
479: ip6->ip6_nxt = in6p->in6p_ip6.ip6_nxt;
1.12 itojun 480: ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
1.2 itojun 481:
482: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
483: in6p->in6p_cksum != -1) {
484: int off;
1.31 itojun 485: u_int16_t sum;
1.2 itojun 486:
487: /* compute checksum */
488: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
489: off = offsetof(struct icmp6_hdr, icmp6_cksum);
490: else
491: off = in6p->in6p_cksum;
492: if (plen < off + 1) {
493: error = EINVAL;
494: goto bad;
495: }
496: off += sizeof(struct ip6_hdr);
497:
1.31 itojun 498: sum = 0;
499: m_copyback(m, off, sizeof(sum), (caddr_t)&sum);
500: sum = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
501: m_copyback(m, off, sizeof(sum), (caddr_t)&sum);
1.2 itojun 502: }
503:
1.24 itojun 504: #ifdef IPSEC
1.26 itojun 505: if (ipsec_setsocket(m, so) != 0) {
506: error = ENOBUFS;
507: goto bad;
508: }
1.38 itojun 509: #endif /* IPSEC */
1.27 itojun 510:
511: flags = 0;
1.41 itojun 512: #ifdef IN6P_MINMTU
1.27 itojun 513: if (in6p->in6p_flags & IN6P_MINMTU)
514: flags |= IPV6_MINMTU;
515: #endif
1.48 itojun 516:
1.27 itojun 517: error = ip6_output(m, optp, &in6p->in6p_route, flags,
518: in6p->in6p_moptions, &oifp);
1.12 itojun 519: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
520: if (oifp)
521: icmp6_ifoutstat_inc(oifp, type, code);
522: icmp6stat.icp6s_outhist[type]++;
1.37 itojun 523: } else
524: rip6stat.rip6s_opackets++;
1.2 itojun 525:
526: goto freectl;
527:
528: bad:
529: if (m)
530: m_freem(m);
531:
532: freectl:
533: if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt)
534: RTFREE(optp->ip6po_route.ro_rt);
535: if (control)
536: m_freem(control);
537: return(error);
538: }
539:
1.40 itojun 540: /*
1.2 itojun 541: * Raw IPv6 socket option processing.
1.40 itojun 542: */
1.2 itojun 543: int
1.36 itojun 544: rip6_ctloutput(op, so, level, optname, mp)
1.2 itojun 545: int op;
546: struct socket *so;
547: int level, optname;
1.36 itojun 548: struct mbuf **mp;
1.2 itojun 549: {
550: int error = 0;
551:
1.27 itojun 552: switch (level) {
553: case IPPROTO_IPV6:
554: switch (optname) {
555: case MRT6_INIT:
556: case MRT6_DONE:
557: case MRT6_ADD_MIF:
558: case MRT6_DEL_MIF:
559: case MRT6_ADD_MFC:
560: case MRT6_DEL_MFC:
561: case MRT6_PIM:
562: if (op == PRCO_SETOPT) {
1.36 itojun 563: error = ip6_mrouter_set(optname, so, *mp);
564: if (*mp)
565: (void)m_free(*mp);
566: } else if (op == PRCO_GETOPT)
567: error = ip6_mrouter_get(optname, so, mp);
568: else
569: error = EINVAL;
570: return (error);
571: case IPV6_CHECKSUM:
1.43 itojun 572: return (ip6_raw_ctloutput(op, so, level, optname, mp));
1.36 itojun 573: default:
574: return (ip6_ctloutput(op, so, level, optname, mp));
1.27 itojun 575: }
576:
577: case IPPROTO_ICMPV6:
578: /*
579: * XXX: is it better to call icmp6_ctloutput() directly
580: * from protosw?
581: */
1.43 itojun 582: return (icmp6_ctloutput(op, so, level, optname, mp));
1.27 itojun 583:
584: default:
1.36 itojun 585: if (op == PRCO_SETOPT && *mp)
586: m_free(*mp);
587: return EINVAL;
1.2 itojun 588: }
589: }
590:
591: extern u_long rip6_sendspace;
592: extern u_long rip6_recvspace;
593:
594: int
595: rip6_usrreq(so, req, m, nam, control, p)
1.27 itojun 596: struct socket *so;
1.2 itojun 597: int req;
598: struct mbuf *m, *nam, *control;
599: struct proc *p;
600: {
1.27 itojun 601: struct in6pcb *in6p = sotoin6pcb(so);
1.2 itojun 602: int s;
603: int error = 0;
1.12 itojun 604: int priv;
605:
606: priv = 0;
607: if (p && !suser(p->p_ucred, &p->p_acflag))
608: priv++;
1.2 itojun 609:
610: if (req == PRU_CONTROL)
611: return (in6_control(so, (u_long)m, (caddr_t)nam,
1.46 itojun 612: (struct ifnet *)control, p));
1.17 thorpej 613:
1.18 thorpej 614: if (req == PRU_PURGEIF) {
1.33 itojun 615: in6_pcbpurgeif0(&rawin6pcb, (struct ifnet *)control);
1.18 thorpej 616: in6_purgeif((struct ifnet *)control);
617: in6_pcbpurgeif(&rawin6pcb, (struct ifnet *)control);
1.17 thorpej 618: return (0);
619: }
1.2 itojun 620:
621: switch (req) {
622: case PRU_ATTACH:
623: if (in6p)
624: panic("rip6_attach");
1.12 itojun 625: if (!priv) {
1.2 itojun 626: error = EACCES;
627: break;
628: }
1.4 itojun 629: s = splsoftnet();
1.27 itojun 630: if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) != 0) {
631: splx(s);
632: break;
633: }
634: if ((error = in6_pcballoc(so, &rawin6pcb)) != 0)
635: {
1.2 itojun 636: splx(s);
637: break;
638: }
639: splx(s);
640: in6p = sotoin6pcb(so);
1.5 itojun 641: in6p->in6p_ip6.ip6_nxt = (long)nam;
1.2 itojun 642: in6p->in6p_cksum = -1;
1.48 itojun 643:
1.2 itojun 644: MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
1.43 itojun 645: sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
1.12 itojun 646: if (in6p->in6p_icmp6filt == NULL) {
647: in6_pcbdetach(in6p);
648: error = ENOMEM;
649: break;
650: }
1.2 itojun 651: ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
652: break;
653:
654: case PRU_DISCONNECT:
655: if ((so->so_state & SS_ISCONNECTED) == 0) {
656: error = ENOTCONN;
657: break;
658: }
659: in6p->in6p_faddr = in6addr_any;
660: so->so_state &= ~SS_ISCONNECTED; /* XXX */
661: break;
662:
663: case PRU_ABORT:
664: soisdisconnected(so);
665: /* Fallthrough */
666: case PRU_DETACH:
667: if (in6p == 0)
668: panic("rip6_detach");
669: if (so == ip6_mrouter)
670: ip6_mrouter_done();
671: /* xxx: RSVP */
672: if (in6p->in6p_icmp6filt) {
673: FREE(in6p->in6p_icmp6filt, M_PCB);
674: in6p->in6p_icmp6filt = NULL;
675: }
676: in6_pcbdetach(in6p);
677: break;
678:
679: case PRU_BIND:
680: {
681: struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
682: struct ifaddr *ia = NULL;
683:
684: if (nam->m_len != sizeof(*addr)) {
685: error = EINVAL;
686: break;
687: }
1.24 itojun 688: if ((ifnet.tqh_first == 0) || (addr->sin6_family != AF_INET6)) {
689: error = EADDRNOTAVAIL;
690: break;
691: }
692: #ifdef ENABLE_DEFAULT_SCOPE
693: if (addr->sin6_scope_id == 0) /* not change if specified */
694: addr->sin6_scope_id =
1.43 itojun 695: scope6_addr2default(&addr->sin6_addr);
1.24 itojun 696: #endif
1.34 itojun 697: /* KAME hack: embed scopeid */
698: if (in6_embedscope(&addr->sin6_addr, addr, in6p, NULL) != 0)
699: return EINVAL;
700: #ifndef SCOPEDROUTING
701: addr->sin6_scope_id = 0; /* for ifa_ifwithaddr */
702: #endif
703:
1.23 itojun 704: /*
705: * we don't support mapped address here, it would confuse
706: * users so reject it
707: */
708: if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
709: error = EADDRNOTAVAIL;
710: break;
711: }
1.24 itojun 712: if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
713: (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) {
1.2 itojun 714: error = EADDRNOTAVAIL;
715: break;
716: }
1.46 itojun 717: if (ia && ((struct in6_ifaddr *)ia)->ia6_flags &
1.2 itojun 718: (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
719: IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
720: error = EADDRNOTAVAIL;
721: break;
722: }
723: in6p->in6p_laddr = addr->sin6_addr;
724: break;
725: }
1.36 itojun 726:
1.2 itojun 727: case PRU_CONNECT:
1.40 itojun 728: {
1.2 itojun 729: struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
730: struct in6_addr *in6a = NULL;
1.24 itojun 731: #ifdef ENABLE_DEFAULT_SCOPE
732: struct sockaddr_in6 sin6;
733: #endif
1.2 itojun 734:
735: if (nam->m_len != sizeof(*addr)) {
736: error = EINVAL;
737: break;
738: }
1.24 itojun 739: if (ifnet.tqh_first == 0)
740: {
1.2 itojun 741: error = EADDRNOTAVAIL;
742: break;
743: }
744: if (addr->sin6_family != AF_INET6) {
745: error = EAFNOSUPPORT;
746: break;
747: }
748:
1.24 itojun 749: #ifdef ENABLE_DEFAULT_SCOPE
750: if (addr->sin6_scope_id == 0) {
751: /* protect *addr */
752: sin6 = *addr;
753: addr = &sin6;
754: addr->sin6_scope_id =
1.46 itojun 755: scope6_addr2default(&addr->sin6_addr);
1.24 itojun 756: }
757: #endif
758:
1.2 itojun 759: /* Source address selection. XXX: need pcblookup? */
1.12 itojun 760: in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
1.43 itojun 761: in6p->in6p_moptions, &in6p->in6p_route,
762: &in6p->in6p_laddr, &error);
1.12 itojun 763: if (in6a == NULL) {
1.2 itojun 764: if (error == 0)
765: error = EADDRNOTAVAIL;
766: break;
767: }
768: in6p->in6p_laddr = *in6a;
769: in6p->in6p_faddr = addr->sin6_addr;
770: soisconnected(so);
771: break;
1.40 itojun 772: }
1.2 itojun 773:
774: case PRU_CONNECT2:
775: error = EOPNOTSUPP;
776: break;
777:
778: /*
779: * Mark the connection as being incapable of futther input.
780: */
781: case PRU_SHUTDOWN:
782: socantsendmore(so);
783: break;
784: /*
785: * Ship a packet out. The appropriate raw output
786: * routine handles any messaging necessary.
787: */
788: case PRU_SEND:
1.40 itojun 789: {
1.2 itojun 790: struct sockaddr_in6 tmp;
791: struct sockaddr_in6 *dst;
792:
1.24 itojun 793: /* always copy sockaddr to avoid overwrites */
1.2 itojun 794: if (so->so_state & SS_ISCONNECTED) {
795: if (nam) {
796: error = EISCONN;
797: break;
798: }
799: /* XXX */
800: bzero(&tmp, sizeof(tmp));
801: tmp.sin6_family = AF_INET6;
802: tmp.sin6_len = sizeof(struct sockaddr_in6);
803: bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
1.46 itojun 804: sizeof(struct in6_addr));
1.2 itojun 805: dst = &tmp;
806: } else {
807: if (nam == NULL) {
808: error = ENOTCONN;
809: break;
810: }
1.42 itojun 811: if (nam->m_len != sizeof(tmp)) {
812: error = EINVAL;
813: break;
814: }
815:
1.24 itojun 816: tmp = *mtod(nam, struct sockaddr_in6 *);
817: dst = &tmp;
1.42 itojun 818:
819: if (dst->sin6_family != AF_INET6) {
820: error = EAFNOSUPPORT;
821: break;
822: }
1.2 itojun 823: }
1.24 itojun 824: #ifdef ENABLE_DEFAULT_SCOPE
825: if (dst->sin6_scope_id == 0) {
826: dst->sin6_scope_id =
1.43 itojun 827: scope6_addr2default(&dst->sin6_addr);
1.24 itojun 828: }
829: #endif
1.2 itojun 830: error = rip6_output(m, so, dst, control);
831: m = NULL;
832: break;
1.40 itojun 833: }
1.2 itojun 834:
835: case PRU_SENSE:
836: /*
837: * stat: don't bother with a blocksize
838: */
839: return(0);
840: /*
841: * Not supported.
842: */
843: case PRU_RCVOOB:
844: case PRU_RCVD:
845: case PRU_LISTEN:
846: case PRU_ACCEPT:
847: case PRU_SENDOOB:
848: error = EOPNOTSUPP;
849: break;
850:
851: case PRU_SOCKADDR:
852: in6_setsockaddr(in6p, nam);
853: break;
854:
855: case PRU_PEERADDR:
856: in6_setpeeraddr(in6p, nam);
857: break;
858:
859: default:
860: panic("rip6_usrreq");
861: }
862: if (m != NULL)
863: m_freem(m);
864: return(error);
865: }
CVSweb <webmaster@jp.NetBSD.org>