diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2001-02-08 18:46:24 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2001-02-08 18:46:24 +0000 |
commit | f9fa672495585c79543cdd9769b41fd356007d99 (patch) | |
tree | 1c2abb7bedbe8d53b59e8a067aa727a5dee7c090 /sys/netinet6 | |
parent | 94c2e39d9c043a96996b2dca0a037baa86e1b2b9 (diff) |
witch raw ip6 socket code from NRL to kame.
makes upgrades/code sharing much easier.
Diffstat (limited to 'sys/netinet6')
-rw-r--r-- | sys/netinet6/icmp6.c | 219 | ||||
-rw-r--r-- | sys/netinet6/in6_pcb.c | 3 | ||||
-rw-r--r-- | sys/netinet6/ip6_output.c | 6 | ||||
-rw-r--r-- | sys/netinet6/ip6_var.h | 4 | ||||
-rw-r--r-- | sys/netinet6/raw_ip6.c | 813 | ||||
-rw-r--r-- | sys/netinet6/raw_ipv6.c | 910 | ||||
-rw-r--r-- | sys/netinet6/udp6_output.c | 2 |
7 files changed, 1037 insertions, 920 deletions
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 8c19c99fa7a..f94b6df8dba 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1,5 +1,5 @@ -/* $OpenBSD: icmp6.c,v 1.31 2001/02/08 16:07:59 itojun Exp $ */ -/* $KAME: icmp6.c,v 1.194 2001/02/08 15:19:12 itojun Exp $ */ +/* $OpenBSD: icmp6.c,v 1.32 2001/02/08 18:46:22 itojun Exp $ */ +/* $KAME: icmp6.c,v 1.195 2001/02/08 15:35:31 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -101,12 +101,40 @@ #include <net/net_osdep.h> +/* inpcb members */ +#define in6pcb inpcb +#define in6p_laddr inp_laddr6 +#define in6p_faddr inp_faddr6 +#define in6p_icmp6filt inp_icmp6filt +#define in6p_route inp_route +#define in6p_socket inp_socket +#define in6p_flags inp_flags +#define in6p_moptions inp_moptions6 +#define in6p_outputopts inp_outputopts6 +#define in6p_ip6 inp_ipv6 +#define in6p_flowinfo inp_flowinfo +#define in6p_sp inp_sp +#define in6p_next inp_next +#define in6p_prev inp_prev +/* macro names */ +#define sotoin6pcb sotoinpcb +/* function names */ +#define in6_pcbdetach in_pcbdetach +#define in6_rtchange in_rtchange + +/* + * for KAME src sync over BSD*'s. XXX: FreeBSD (>=3) are VERY different from + * others... + */ +#define in6p_ip6_nxt inp_ipv6.ip6_nxt + extern struct domain inet6domain; extern struct ip6protosw inet6sw[]; extern u_char ip6_protox[]; struct icmp6stat icmp6stat; +extern struct inpcbtable rawin6pcbtable; extern int icmp6errppslim; static int icmp6errpps_count = 0; static struct timeval icmp6errppslim_last; @@ -140,6 +168,7 @@ static int icmp6_redirect_hiwat = -1; static int icmp6_redirect_lowat = -1; static void icmp6_errcount __P((struct icmp6errstat *, int, int)); +static int icmp6_rip6_input __P((struct mbuf **, int)); static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int)); static const char *icmp6_redirect_diag __P((struct in6_addr *, struct in6_addr *, struct in6_addr *)); @@ -1027,7 +1056,7 @@ icmp6_input(mp, offp, proto) break; } - rip6_input(&m, offp, IPPROTO_ICMPV6); + icmp6_rip6_input(&m, *offp); return IPPROTO_DONE; freeit: @@ -1805,6 +1834,98 @@ ni6_store_addrs(ni6, nni6, ifp0, resid) } /* + * XXX almost dup'ed code with rip6_input. + */ +static int +icmp6_rip6_input(mp, off) + struct mbuf **mp; + int off; +{ + struct mbuf *m = *mp; + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct in6pcb *in6p; + struct in6pcb *last = NULL; + struct sockaddr_in6 rip6src; + struct icmp6_hdr *icmp6; + struct mbuf *opts = NULL; + +#ifndef PULLDOWN_TEST + /* this is assumed to be safe. */ + icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off); +#else + IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6)); + if (icmp6 == NULL) { + /* m is already reclaimed */ + return IPPROTO_DONE; + } +#endif + + bzero(&rip6src, sizeof(rip6src)); + rip6src.sin6_len = sizeof(struct sockaddr_in6); + rip6src.sin6_family = AF_INET6; + /* KAME hack: recover scopeid */ + (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif); + + for (in6p = rawin6pcbtable.inpt_queue.cqh_first; + in6p != (struct inpcb *)&rawin6pcbtable.inpt_queue; + in6p = in6p->inp_queue.cqe_next) + { + if (!(in6p->in6p_flags & INP_IPV6)) + continue; + if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6) + continue; + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && + !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) + continue; + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && + !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) + continue; + if (in6p->in6p_icmp6filt + && ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type, + in6p->in6p_icmp6filt)) + continue; + if (last) { + struct mbuf *n; + if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { + if (last->in6p_flags & IN6P_CONTROLOPTS) + ip6_savecontrol(last, &opts, ip6, n); + /* strip intermediate headers */ + m_adj(n, off); + if (sbappendaddr(&last->in6p_socket->so_rcv, + (struct sockaddr *)&rip6src, + n, opts) == 0) { + /* should notify about lost packet */ + m_freem(n); + if (opts) + m_freem(opts); + } else + sorwakeup(last->in6p_socket); + opts = NULL; + } + } + last = in6p; + } + if (last) { + if (last->in6p_flags & IN6P_CONTROLOPTS) + ip6_savecontrol(last, &opts, ip6, m); + /* strip intermediate headers */ + m_adj(m, off); + if (sbappendaddr(&last->in6p_socket->so_rcv, + (struct sockaddr *)&rip6src, + m, opts) == 0) { + m_freem(m); + if (opts) + m_freem(opts); + } else + sorwakeup(last->in6p_socket); + } else { + m_freem(m); + ip6stat.ip6s_delivered--; + } + return IPPROTO_DONE; +} + +/* * Reflect the ip6 packet back to the source. * OFF points to the icmp6 header, counted from the top of the mbuf. */ @@ -2537,6 +2658,98 @@ fail: m_freem(m0); } +#ifdef HAVE_NRL_INPCB +#define sotoin6pcb sotoinpcb +#define in6pcb inpcb +#define in6p_icmp6filt inp_icmp6filt +#endif +/* + * ICMPv6 socket option processing. + */ +int +icmp6_ctloutput(op, so, level, optname, mp) + int op; + struct socket *so; + int level, optname; + struct mbuf **mp; +{ + int error = 0; + int optlen; + struct in6pcb *in6p = sotoin6pcb(so); + struct mbuf *m = *mp; + + optlen = m ? m->m_len : 0; + + if (level != IPPROTO_ICMPV6) { + if (op == PRCO_SETOPT && m) + (void)m_free(m); + return EINVAL; + } + + switch(op) { + case PRCO_SETOPT: + switch (optname) { + case ICMP6_FILTER: + { + struct icmp6_filter *p; + + if (optlen != sizeof(*p)) { + error = EMSGSIZE; + break; + } + p = mtod(m, struct icmp6_filter *); + if (!p || !in6p->in6p_icmp6filt) { + error = EINVAL; + break; + } + bcopy(p, in6p->in6p_icmp6filt, + sizeof(struct icmp6_filter)); + error = 0; + break; + } + + default: + error = ENOPROTOOPT; + break; + } + if (m) + (void)m_freem(m); + break; + + case PRCO_GETOPT: + switch (optname) { + case ICMP6_FILTER: + { + struct icmp6_filter *p; + + if (!in6p->in6p_icmp6filt) { + error = EINVAL; + break; + } + *mp = m = m_get(M_WAIT, MT_SOOPTS); + m->m_len = sizeof(struct icmp6_filter); + p = mtod(m, struct icmp6_filter *); + bcopy(in6p->in6p_icmp6filt, p, + sizeof(struct icmp6_filter)); + error = 0; + break; + } + + default: + error = ENOPROTOOPT; + break; + } + break; + } + + return(error); +} +#ifdef HAVE_NRL_INPCB +#undef sotoin6pcb +#undef in6pcb +#undef in6p_icmp6filt +#endif + /* * Perform rate limit check. * Returns 0 if it is okay to send the icmp6 packet. diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index fcfecb8ee3f..38923886da3 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_pcb.c,v 1.22 2001/01/06 16:07:45 itojun Exp $ */ +/* $OpenBSD: in6_pcb.c,v 1.23 2001/02/08 18:46:23 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -681,7 +681,6 @@ in6_setpeeraddr(inp, nam) sin6->sin6_len = sizeof(struct sockaddr_in6); sin6->sin6_port = inp->inp_fport; sin6->sin6_addr = inp->inp_faddr6; - sin6->sin6_flowinfo = inp->inp_fflowinfo; return 0; } diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 664186cd623..89c30cf2b3d 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_output.c,v 1.20 2001/02/06 01:26:58 itojun Exp $ */ +/* $OpenBSD: ip6_output.c,v 1.21 2001/02/08 18:46:23 itojun Exp $ */ /* $KAME: ip6_output.c,v 1.152 2001/02/02 15:36:33 jinmei Exp $ */ /* @@ -1379,7 +1379,7 @@ ip6_ctloutput(op, so, level, optname, mp) break; case IPV6_CHECKSUM: - inp->inp_csumoffset = optval; + inp->in6p_cksum = optval; break; case IPV6_FAITH: @@ -1623,7 +1623,7 @@ ip6_ctloutput(op, so, level, optname, mp) break; case IPV6_CHECKSUM: - optval = inp->inp_csumoffset; + optval = inp->in6p_cksum; break; case IPV6_FAITH: diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 48132c50d9b..c035ced0bfc 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_var.h,v 1.11 2000/07/12 16:41:31 itojun Exp $ */ +/* $OpenBSD: ip6_var.h,v 1.12 2001/02/08 18:46:23 itojun Exp $ */ /* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */ /* @@ -232,6 +232,8 @@ extern int ip6_auto_flowlabel; struct in6pcb; struct inpcb; +int icmp6_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); + void ip6_init __P((void)); void ip6intr __P((void)); void ip6_input __P((struct mbuf *)); diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c new file mode 100644 index 00000000000..783be6eb8b8 --- /dev/null +++ b/sys/netinet6/raw_ip6.c @@ -0,0 +1,813 @@ +/* $OpenBSD: raw_ip6.c,v 1.1 2001/02/08 18:46:23 itojun Exp $ */ +/* $KAME: raw_ip6.c,v 1.65 2001/02/08 18:36:17 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 + */ + +#include <sys/param.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/protosw.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/systm.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/if_types.h> + +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/ip6_mroute.h> +#include <netinet/icmp6.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet6/nd6.h> +#include <netinet6/ip6protosw.h> +#ifdef ENABLE_DEFAULT_SCOPE +#include <netinet6/scope6_var.h> +#endif + +#ifdef __OpenBSD__ +#undef IPSEC +#endif + +#ifdef IPSEC +#include <netinet6/ipsec.h> +#endif /*IPSEC*/ + +#include <machine/stdarg.h> + +#include "faith.h" + +/* + * Raw interface to IP6 protocol. + */ +/* inpcb members */ +#define in6pcb inpcb +#define in6p_laddr inp_laddr6 +#define in6p_faddr inp_faddr6 +#define in6p_icmp6filt inp_icmp6filt +#define in6p_route inp_route6 +#define in6p_socket inp_socket +#define in6p_flags inp_flags +#define in6p_moptions inp_moptions6 +#define in6p_outputopts inp_outputopts6 +#define in6p_ip6 inp_ipv6 +#define in6p_flowinfo inp_flowinfo +#define in6p_sp inp_sp +#define in6p_next inp_next +#define in6p_prev inp_prev +/* macro names */ +#define sotoin6pcb sotoinpcb +/* function names */ +#define in6_pcbdetach in_pcbdetach +#define in6_rtchange in_rtchange + +struct inpcbtable rawin6pcbtable; +#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) + +/* + * Initialize raw connection block queue. + */ +void +rip6_init() +{ + + in_pcbinit(&rawin6pcbtable, 1); +} + +/* + * Setup generic address and protocol structures + * for raw_input routine, then pass them along with + * mbuf chain. + */ +int +rip6_input(mp, offp, proto) + struct mbuf **mp; + int *offp, proto; +{ + struct mbuf *m = *mp; + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct in6pcb *in6p; + struct in6pcb *last = NULL; + struct sockaddr_in6 rip6src; + struct mbuf *opts = NULL; + +#if defined(NFAITH) && 0 < NFAITH + if (m->m_pkthdr.rcvif) { + if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { + /* send icmp6 host unreach? */ + m_freem(m); + return IPPROTO_DONE; + } + } +#endif + + /* Be proactive about malicious use of IPv4 mapped address */ + if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || + IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { + /* XXX stat */ + m_freem(m); + return IPPROTO_DONE; + } + + bzero(&rip6src, sizeof(rip6src)); + rip6src.sin6_len = sizeof(struct sockaddr_in6); + rip6src.sin6_family = AF_INET6; +#if 0 /*XXX inbound flowlabel */ + rip6src.sin6_flowinfo = ip6->ip6_flow & IPV6_FLOWINFO_MASK; +#endif + /* KAME hack: recover scopeid */ + (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif); + + for (in6p = rawin6pcbtable.inpt_queue.cqh_first; + in6p != (struct inpcb *)&rawin6pcbtable.inpt_queue; + in6p = in6p->inp_queue.cqe_next) + { + if (!(in6p->in6p_flags & INP_IPV6)) + continue; + if (in6p->in6p_ip6.ip6_nxt && + in6p->in6p_ip6.ip6_nxt != proto) + continue; + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && + !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) + continue; + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && + !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) + continue; + if (in6p->in6p_cksum != -1 + && in6_cksum(m, ip6->ip6_nxt, *offp, m->m_pkthdr.len - *offp)) + { + /* XXX bark something */ + continue; + } + if (last) { + struct mbuf *n; + if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { + if (last->in6p_flags & IN6P_CONTROLOPTS) + ip6_savecontrol(last, &opts, ip6, n); + /* strip intermediate headers */ + m_adj(n, *offp); + if (sbappendaddr(&last->in6p_socket->so_rcv, + (struct sockaddr *)&rip6src, + n, opts) == 0) { + /* should notify about lost packet */ + m_freem(n); + if (opts) + m_freem(opts); + } else + sorwakeup(last->in6p_socket); + opts = NULL; + } + } + last = in6p; + } + if (last) { + if (last->in6p_flags & IN6P_CONTROLOPTS) + ip6_savecontrol(last, &opts, ip6, m); + /* strip intermediate headers */ + m_adj(m, *offp); + if (sbappendaddr(&last->in6p_socket->so_rcv, + (struct sockaddr *)&rip6src, m, opts) == 0) { + m_freem(m); + if (opts) + m_freem(opts); + } else + sorwakeup(last->in6p_socket); + } else { + if (proto == IPPROTO_NONE) + m_freem(m); + else { + char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_protounknown); + icmp6_error(m, ICMP6_PARAM_PROB, + ICMP6_PARAMPROB_NEXTHEADER, + prvnxtp - mtod(m, char *)); + } + ip6stat.ip6s_delivered--; + } + return IPPROTO_DONE; +} + +void +rip6_ctlinput(cmd, sa, d) + int cmd; + struct sockaddr *sa; + void *d; +{ + struct sockaddr_in6 sa6; + struct ip6_hdr *ip6; + struct mbuf *m; + int off; + void (*notify) __P((struct in6pcb *, int)) = in6_rtchange; + + if (sa->sa_family != AF_INET6 || + sa->sa_len != sizeof(struct sockaddr_in6)) + return; + + if ((unsigned)cmd >= PRC_NCMDS) + return; + if (PRC_IS_REDIRECT(cmd)) + notify = in6_rtchange, d = NULL; + else if (cmd == PRC_HOSTDEAD) + d = NULL; + else if (inet6ctlerrmap[cmd] == 0) + return; + + /* if the parameter is from icmp6, decode it. */ + if (d != NULL) { + struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + } else { + m = NULL; + ip6 = NULL; + } + + /* translate addresses into internal form */ + sa6 = *(struct sockaddr_in6 *)sa; + if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) + sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + + if (ip6) { + /* + * XXX: We assume that when IPV6 is non NULL, + * M and OFF are valid. + */ + struct in6_addr s; + + /* translate addresses into internal form */ + bcopy(&ip6->ip6_src, &s, sizeof(s)); + if (IN6_IS_ADDR_LINKLOCAL(&s)) + s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + + (void) in6_pcbnotify(&rawin6pcbtable, (struct sockaddr *)&sa6, + 0, &s, 0, cmd, notify); + } else { + (void) in6_pcbnotify(&rawin6pcbtable, (struct sockaddr *)&sa6, 0, + &zeroin6_addr, 0, cmd, notify); + } +} + +/* + * Generate IPv6 header and pass packet to ip6_output. + * Tack on options user may have setup with control call. + */ +int +#if __STDC__ +rip6_output(struct mbuf *m, ...) +#else +rip6_output(m, va_alist) + struct mbuf *m; + va_dcl +#endif +{ + struct socket *so; + struct sockaddr_in6 *dstsock; + struct mbuf *control; + struct in6_addr *dst; + struct ip6_hdr *ip6; + struct in6pcb *in6p; + u_int plen = m->m_pkthdr.len; + int error = 0; + struct ip6_pktopts opt, *optp = NULL, *origoptp; + struct ifnet *oifp = NULL; + int type, code; /* for ICMPv6 output statistics only */ + int priv = 0; + va_list ap; + int flags; + + va_start(ap, m); + so = va_arg(ap, struct socket *); + dstsock = va_arg(ap, struct sockaddr_in6 *); + control = va_arg(ap, struct mbuf *); + va_end(ap); + + in6p = sotoin6pcb(so); + + priv = 0; + if ((so->so_state & SS_PRIV) != 0) + priv = 1; + dst = &dstsock->sin6_addr; + if (control) { + if ((error = ip6_setpktoptions(control, &opt, priv)) != 0) + goto bad; + optp = &opt; + } else + optp = in6p->in6p_outputopts; + + /* + * For an ICMPv6 packet, we should know its type and code + * to update statistics. + */ + if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { + struct icmp6_hdr *icmp6; + if (m->m_len < sizeof(struct icmp6_hdr) && + (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { + error = ENOBUFS; + goto bad; + } + icmp6 = mtod(m, struct icmp6_hdr *); + type = icmp6->icmp6_type; + code = icmp6->icmp6_code; + } + + M_PREPEND(m, sizeof(*ip6), M_WAIT); + ip6 = mtod(m, struct ip6_hdr *); + + /* + * Next header might not be ICMP6 but use its pseudo header anyway. + */ + ip6->ip6_dst = *dst; + + /* KAME hack: embed scopeid */ + origoptp = in6p->in6p_outputopts; + in6p->in6p_outputopts = optp; + if (in6_embedscope(&ip6->ip6_dst, dstsock, in6p, &oifp) != 0) { + error = EINVAL; + goto bad; + } + in6p->in6p_outputopts = origoptp; + + /* + * Source address selection. + */ + { + struct in6_addr *in6a; + + if ((in6a = in6_selectsrc(dstsock, optp, + in6p->in6p_moptions, + &in6p->in6p_route, + &in6p->in6p_laddr, + &error)) == 0) { + if (error == 0) + error = EADDRNOTAVAIL; + goto bad; + } + ip6->ip6_src = *in6a; + if (in6p->in6p_route.ro_rt) { + /* what if oifp contradicts ? */ + oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index]; + } + } + + ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; + ip6->ip6_vfc &= ~IPV6_VERSION_MASK; + ip6->ip6_vfc |= IPV6_VERSION; +#if 0 /* ip6_plen will be filled in ip6_output. */ + ip6->ip6_plen = htons((u_short)plen); +#endif + ip6->ip6_nxt = in6p->in6p_ip6.ip6_nxt; + ip6->ip6_hlim = in6_selecthlim(in6p, oifp); + + if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || + in6p->in6p_cksum != -1) { + struct mbuf *n; + int off; + u_int16_t *p; + +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) /* XXX */ + + /* compute checksum */ + if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) + off = offsetof(struct icmp6_hdr, icmp6_cksum); + else + off = in6p->in6p_cksum; + if (plen < off + 1) { + error = EINVAL; + goto bad; + } + off += sizeof(struct ip6_hdr); + + n = m; + while (n && n->m_len <= off) { + off -= n->m_len; + n = n->m_next; + } + if (!n) + goto bad; + p = (u_int16_t *)(mtod(n, caddr_t) + off); + *p = 0; + *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); + } + +#ifdef IPSEC + if (ipsec_setsocket(m, so) != 0) { + error = ENOBUFS; + goto bad; + } +#endif /*IPSEC*/ + + flags = 0; +#ifdef IN6P_MINMTU + if (in6p->in6p_flags & IN6P_MINMTU) + flags |= IPV6_MINMTU; +#endif + + error = ip6_output(m, optp, &in6p->in6p_route, flags, + in6p->in6p_moptions, &oifp); + if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { + if (oifp) + icmp6_ifoutstat_inc(oifp, type, code); + icmp6stat.icp6s_outhist[type]++; + } + + goto freectl; + + bad: + if (m) + m_freem(m); + + freectl: + if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) + RTFREE(optp->ip6po_route.ro_rt); + if (control) + m_freem(control); + return(error); +} + +/* + * Raw IPv6 socket option processing. + */ +int +rip6_ctloutput(op, so, level, optname, m) + int op; + struct socket *so; + int level, optname; + struct mbuf **m; +{ + int error = 0; + + switch (level) { + case IPPROTO_IPV6: + switch (optname) { + case MRT6_INIT: + case MRT6_DONE: + case MRT6_ADD_MIF: + case MRT6_DEL_MIF: + case MRT6_ADD_MFC: + case MRT6_DEL_MFC: + case MRT6_PIM: + if (op == PRCO_SETOPT) { + error = ip6_mrouter_set(optname, so, *m); + if (*m) + (void)m_free(*m); + } else if (op == PRCO_GETOPT) { + error = ip6_mrouter_get(optname, so, m); + } else + error = EINVAL; + return (error); + } + return (ip6_ctloutput(op, so, level, optname, m)); + /* NOTREACHED */ + + case IPPROTO_ICMPV6: + /* + * XXX: is it better to call icmp6_ctloutput() directly + * from protosw? + */ + return(icmp6_ctloutput(op, so, level, optname, m)); + + default: + if (op == PRCO_SETOPT && *m) + (void)m_free(*m); + return(EINVAL); + } +} + +extern u_long rip6_sendspace; +extern u_long rip6_recvspace; + +int +rip6_usrreq(so, req, m, nam, control, p) + struct socket *so; + int req; + struct mbuf *m, *nam, *control; + struct proc *p; +{ + struct in6pcb *in6p = sotoin6pcb(so); + int s; + int error = 0; +/* extern struct socket *ip6_mrouter; */ /* xxx */ + int priv; + + priv = 0; + if ((so->so_state & SS_PRIV) != 0) + priv++; + + if (req == PRU_CONTROL) + return (in6_control(so, (u_long)m, (caddr_t)nam, + (struct ifnet *)control, p)); + + switch (req) { + case PRU_ATTACH: + if (in6p) + panic("rip6_attach"); + if (!priv) { + error = EACCES; + break; + } + s = splnet(); + if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) != 0) { + splx(s); + break; + } + if ((error = in_pcballoc(so, &rawin6pcbtable)) != 0) + { + splx(s); + break; + } + splx(s); + in6p = sotoin6pcb(so); + in6p->in6p_ip6.ip6_nxt = (long)nam; + in6p->in6p_cksum = -1; +#ifdef IPSEC + error = ipsec_init_policy(so, &in6p->in6p_sp); + if (error != 0) { + in6_pcbdetach(in6p); + break; + } +#endif /*IPSEC*/ + + MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *, + sizeof(struct icmp6_filter), M_PCB, M_NOWAIT); + if (in6p->in6p_icmp6filt == NULL) { + in6_pcbdetach(in6p); + error = ENOMEM; + break; + } + ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt); + break; + + case PRU_DISCONNECT: + if ((so->so_state & SS_ISCONNECTED) == 0) { + error = ENOTCONN; + break; + } + in6p->in6p_faddr = in6addr_any; + so->so_state &= ~SS_ISCONNECTED; /* XXX */ + break; + + case PRU_ABORT: + soisdisconnected(so); + /* Fallthrough */ + case PRU_DETACH: + if (in6p == 0) + panic("rip6_detach"); + if (so == ip6_mrouter) + ip6_mrouter_done(); + /* xxx: RSVP */ + if (in6p->in6p_icmp6filt) { + FREE(in6p->in6p_icmp6filt, M_PCB); + in6p->in6p_icmp6filt = NULL; + } + in6_pcbdetach(in6p); + break; + + case PRU_BIND: + { + struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *); + struct ifaddr *ia = NULL; + + if (nam->m_len != sizeof(*addr)) { + error = EINVAL; + break; + } + if ((ifnet.tqh_first == 0) || (addr->sin6_family != AF_INET6)) { + error = EADDRNOTAVAIL; + break; + } +#ifdef ENABLE_DEFAULT_SCOPE + if (addr->sin6_scope_id == 0) /* not change if specified */ + addr->sin6_scope_id = + scope6_addr2default(&addr->sin6_addr); +#endif + /* + * we don't support mapped address here, it would confuse + * users so reject it + */ + if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) { + error = EADDRNOTAVAIL; + break; + } + /* + * Currently, ifa_ifwithaddr tends to fail for a link-local + * address, since it implicitly expects that the link ID + * for the address is embedded in the sin6_addr part. + * For now, we'd rather keep this "as is". We'll eventually fix + * this in a more natural way. + */ + if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && + (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) { + error = EADDRNOTAVAIL; + break; + } + if (ia && + ((struct in6_ifaddr *)ia)->ia6_flags & + (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| + IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { + error = EADDRNOTAVAIL; + break; + } + in6p->in6p_laddr = addr->sin6_addr; + break; + } + + case PRU_CONNECT: + { + struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *); + struct in6_addr *in6a = NULL; +#ifdef ENABLE_DEFAULT_SCOPE + struct sockaddr_in6 sin6; +#endif + + if (nam->m_len != sizeof(*addr)) { + error = EINVAL; + break; + } + if (ifnet.tqh_first == 0) + { + error = EADDRNOTAVAIL; + break; + } + if (addr->sin6_family != AF_INET6) { + error = EAFNOSUPPORT; + break; + } + +#ifdef ENABLE_DEFAULT_SCOPE + if (addr->sin6_scope_id == 0) { + /* protect *addr */ + sin6 = *addr; + addr = &sin6; + addr->sin6_scope_id = + scope6_addr2default(&addr->sin6_addr); + } +#endif + + /* Source address selection. XXX: need pcblookup? */ + in6a = in6_selectsrc(addr, in6p->in6p_outputopts, + in6p->in6p_moptions, + &in6p->in6p_route, + &in6p->in6p_laddr, + &error); + if (in6a == NULL) { + if (error == 0) + error = EADDRNOTAVAIL; + break; + } + in6p->in6p_laddr = *in6a; + in6p->in6p_faddr = addr->sin6_addr; + soisconnected(so); + break; + } + + case PRU_CONNECT2: + error = EOPNOTSUPP; + break; + + /* + * Mark the connection as being incapable of futther input. + */ + case PRU_SHUTDOWN: + socantsendmore(so); + break; + /* + * Ship a packet out. The appropriate raw output + * routine handles any messaging necessary. + */ + case PRU_SEND: + { + struct sockaddr_in6 tmp; + struct sockaddr_in6 *dst; + + /* always copy sockaddr to avoid overwrites */ + if (so->so_state & SS_ISCONNECTED) { + if (nam) { + error = EISCONN; + break; + } + /* XXX */ + bzero(&tmp, sizeof(tmp)); + tmp.sin6_family = AF_INET6; + tmp.sin6_len = sizeof(struct sockaddr_in6); + bcopy(&in6p->in6p_faddr, &tmp.sin6_addr, + sizeof(struct in6_addr)); + dst = &tmp; + } else { + if (nam == NULL) { + error = ENOTCONN; + break; + } + tmp = *mtod(nam, struct sockaddr_in6 *); + dst = &tmp; + } +#ifdef ENABLE_DEFAULT_SCOPE + if (dst->sin6_scope_id == 0) { + dst->sin6_scope_id = + scope6_addr2default(&dst->sin6_addr); + } +#endif + error = rip6_output(m, so, dst, control); + m = NULL; + break; + } + + case PRU_SENSE: + /* + * stat: don't bother with a blocksize + */ + return(0); + /* + * Not supported. + */ + case PRU_RCVOOB: + case PRU_RCVD: + case PRU_LISTEN: + case PRU_ACCEPT: + case PRU_SENDOOB: + error = EOPNOTSUPP; + break; + + case PRU_SOCKADDR: + in6_setsockaddr(in6p, nam); + break; + + case PRU_PEERADDR: + in6_setpeeraddr(in6p, nam); + break; + + default: + panic("rip6_usrreq"); + } + if (m != NULL) + m_freem(m); + return(error); +} diff --git a/sys/netinet6/raw_ipv6.c b/sys/netinet6/raw_ipv6.c deleted file mode 100644 index f4af285d65c..00000000000 --- a/sys/netinet6/raw_ipv6.c +++ /dev/null @@ -1,910 +0,0 @@ -/* $OpenBSD: raw_ipv6.c,v 1.27 2000/07/27 06:29:10 itojun Exp $ */ - -/* -%%% copyright-nrl-95 -This software is Copyright 1995-1998 by Randall Atkinson, Ronald Lee, -Daniel McDonald, Bao Phan, and Chris Winters. All Rights Reserved. All -rights under this copyright have been assigned to the US Naval Research -Laboratory (NRL). The NRL Copyright Notice and License Agreement Version -1.1 (January 17, 1995) applies to this software. -You should have received a copy of the license with this software. If you -didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. - -*/ -/* - * Copyright (c) 1982, 1986, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 - * $Id: raw_ipv6.c,v 1.27 2000/07/27 06:29:10 itojun Exp $ - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/domain.h> -#include <sys/protosw.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/kernel.h> -#include <net/if.h> -#include <net/route.h> - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/in_pcb.h> - -#include <netinet6/in6_var.h> -#include <netinet/ip6.h> -#include <netinet6/ip6_var.h> -#include <netinet/icmp6.h> -#include <netinet6/ip6_mroute.h> -#include <netinet6/ip6protosw.h> - -#undef IPSEC - -/* - * Globals - */ - -struct inpcbtable rawin6pcbtable; -struct sockaddr_in6 rip6src = { sizeof(struct sockaddr_in6), AF_INET6 }; - -/* - * Nominal space allocated to a raw ip socket. - */ - -#define RIPV6SNDQ 8192 -#define RIPV6RCVQ 8192 - -#if 0 -u_long rip6_sendspace = RIPV6SNDQ; -u_long rip6_recvspace = RIPV6RCVQ; -#else -extern u_long rip6_sendspace; -extern u_long rip6_recvspace; -#endif - -/* - * External globals - */ - -#if 0 -extern struct ip6_hdrstat ipv6stat; -#endif - -/* - * Raw IPv6 PCB initialization. - */ -void -rip6_init() -{ - in_pcbinit(&rawin6pcbtable, 1); -} - -/* - * At the point where this function gets called, we don't know the nexthdr of - * the current header to be processed, only its offset. So we have to go find - * it the hard way. In the case where there's no chained headers, this is not - * really painful. - * - * The good news is that all fields have been sanity checked. - * - * Assumes m has already been pulled up by extra. -cmetz - */ -#if __GNUC__ && __GNUC__ >= 2 && __OPTIMIZE__ -static __inline__ int -#else /* __GNUC__ && __GNUC__ >= 2 && __OPTIMIZE__ */ -static int -#endif /* __GNUC__ && __GNUC__ >= 2 && __OPTIMIZE__ */ -ipv6_findnexthdr(struct mbuf *m, size_t extra) -{ - caddr_t p = mtod(m, caddr_t); - int nexthdr = IPPROTO_IPV6; - unsigned int hl; - - do { - switch (nexthdr) { - case IPPROTO_IPV6: - hl = sizeof(struct ip6_hdr); - - if ((extra -= hl) < 0) - return -1; - - nexthdr = ((struct ip6_hdr *)p)->ip6_nxt; - break; - case IPPROTO_HOPOPTS: - case IPPROTO_DSTOPTS: - if (extra < sizeof(struct ip6_ext)) - return -1; - - hl = sizeof(struct ip6_ext) + - (((struct ip6_ext *)p)->ip6e_len << 3); - - if ((extra -= hl) < 0) - return -1; - - nexthdr = ((struct ip6_ext *)p)->ip6e_nxt; - break; - case IPPROTO_ROUTING: - if (extra < sizeof(struct ip6_rthdr0)) - return -1; - - hl = sizeof(struct ip6_rthdr0) + - (((struct ip6_rthdr0 *)p)->ip6r0_len << 3); - - if ((extra -= hl) < 0) - return -1; - - nexthdr = ((struct ip6_rthdr0 *)p)->ip6r0_nxt; - break; -#ifdef IPSEC - case IPPROTO_AH: - if (extra < sizeof(struct ip6_hdr_srcroute0)) - return -1; - - hl = sizeof(struct ip6_hdr_srcroute0) + - ((struct ip6_hdr_srcroute0 *)p)->i6sr_len << 3; - - if ((extra -= hl) < 0) - return -1; - - nexthdr = ((struct ip6_hdr_srcroute0 *)p)->i6sr_nexthdr; - break; -#endif /* IPSEC */ - default: - return -1; - } - p += hl; - } while (extra > 0); - - return nexthdr; -} - -/* - * If no HLP's are found for an IPv6 datagram, this routine is called. - */ -int -rip6_input(mp, offp, proto) - struct mbuf **mp; - int *offp, proto; -{ - struct mbuf *m = *mp; - /* Will have been pulled up by ipv6_input(). */ - register struct ip6_hdr *ip6; - register struct inpcb *inp; - int nexthdr, icmp6type; - int foundone = 0; - struct mbuf *m2 = NULL, *opts = NULL; - struct sockaddr_in6 srcsa; - int extra = *offp; - -#ifdef DIAGNOSTIC - if (m->m_len < sizeof(*ip6)) - panic("too short mbuf to rip6_input"); -#endif - ip6 = mtod(m, struct ip6_hdr *); - - /* Be proactive about malicious use of IPv4 mapped address */ - if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || - IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { - /* XXX stat */ - goto ret; - } - - bzero(&opts, sizeof(opts)); - bzero(&srcsa, sizeof(struct sockaddr_in6)); - srcsa.sin6_family = AF_INET6; - srcsa.sin6_len = sizeof(struct sockaddr_in6); -#if 0 /*XXX inbound flowinfo */ - srcsa.sin6_flowinfo = ip6->ip6_flow & IPV6_FLOWINFO_MASK; -#endif - /* KAME hack: recover scopeid */ - (void)in6_recoverscope(&srcsa, &ip6->ip6_src, m->m_pkthdr.rcvif); - - if (m->m_len < extra) { - if (!(m = m_pullup2(m, extra))) - return IPPROTO_DONE; - ip6 = mtod(m, struct ip6_hdr *); - } - - if ((nexthdr = ipv6_findnexthdr(m, extra)) < 0) - goto ret; - - if (nexthdr == IPPROTO_ICMPV6) { - if (m->m_len < extra + sizeof(struct icmp6_hdr)) { - m = m_pullup2(m, extra + sizeof(struct icmp6_hdr)); - if (!m) - goto ret; - - ip6 = mtod(m, struct ip6_hdr *); - } - icmp6type = ((struct icmp6_hdr *)(mtod(m, caddr_t) + extra))->icmp6_type; - } else - icmp6type = -1; - - /* - * Locate raw PCB for incoming datagram. - */ - for (inp = rawin6pcbtable.inpt_queue.cqh_first; - inp != (struct inpcb *)&rawin6pcbtable.inpt_queue; - inp = inp->inp_queue.cqe_next) { - if (!(inp->inp_flags & INP_IPV6)) - continue; - if (inp->inp_ipv6.ip6_nxt && inp->inp_ipv6.ip6_nxt != nexthdr) - continue; - if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) && - !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &ip6->ip6_dst)) - continue; - if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6) && - !IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, &ip6->ip6_src)) - continue; - /* - * inp_icmp6filt must not be NULL, but we add a check for - * safety - */ - if (icmp6type >= 0 && inp->inp_icmp6filt && - ICMP6_FILTER_WILLBLOCK(icmp6type, inp->inp_icmp6filt)) - continue; - - foundone = 1; - - /* - * Note the inefficiency here; this is a consequence of the - * interfaces of the functions being used. The raw code is - * not performance critical enough to require an immediate fix. - * - cmetz - */ - if ((m2 = m_copym(m, 0, (int)M_COPYALL, M_DONTWAIT))) { - m_adj(m2, extra); - if (inp->inp_flags & IN6P_CONTROLOPTS) - ip6_savecontrol(inp, &opts, ip6, m); - else - opts = NULL; - if (sbappendaddr(&inp->inp_socket->so_rcv, - (struct sockaddr *)&srcsa, m2, opts)) { - sorwakeup(inp->inp_socket); - } else { - m_freem(m2); - } - } - } - - if (!foundone) { - /* - * We should send an ICMPv6 protocol unreachable here, - * though original UCB 4.4-lite BSD's IPv4 does not do so. - */ -#if 0 - ipv6stat.ips_noproto++; - ipv6stat.ips_delivered--; -#endif - } - -ret: - if (m) - m_freem(m); - - return IPPROTO_DONE; -} - -void -rip6_ctlinput(cmd, sa, d) - int cmd; - struct sockaddr *sa; - void *d; -{ - struct sockaddr_in6 sa6; - register struct ip6_hdr *ip6; - struct mbuf *m; - int off; - void (*notify) __P((struct inpcb *, int)) = in_rtchange; - - if (sa->sa_family != AF_INET6 || - sa->sa_len != sizeof(struct sockaddr_in6)) - return; - - if ((unsigned)cmd >= PRC_NCMDS) - return; - if (PRC_IS_REDIRECT(cmd)) - notify = in_rtchange, d = NULL; - else if (cmd == PRC_HOSTDEAD) - d = NULL; - else if (inet6ctlerrmap[cmd] == 0) - return; - - /* if the parameter is from icmp6, decode it. */ - if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; - m = ip6cp->ip6c_m; - ip6 = ip6cp->ip6c_ip6; - off = ip6cp->ip6c_off; - } else { - m = NULL; - ip6 = NULL; - } - - /* translate addresses into internal form */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - - if (ip6) { - /* - * XXX: We assume that when IPV6 is non NULL, - * M and OFF are valid. - */ - struct in6_addr s; - - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s)) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - - (void) in6_pcbnotify(&rawin6pcbtable, (struct sockaddr *)&sa6, - 0, &s, 0, cmd, notify); - } else { - (void) in6_pcbnotify(&rawin6pcbtable, (struct sockaddr *)&sa6, - 0, &zeroin6_addr, 0, cmd, notify); - } -} - -/* - * Output function for raw IPv6. Called from rip6_usrreq(), and - * ipv6_icmp_usrreq(). - */ -int -rip6_output(struct mbuf *m, ...) -{ - register struct ip6_hdr *ip6; - register struct inpcb *inp; - int flags; - int error = 0; -#if 0 - struct ifnet *forceif = NULL; -#endif - struct ip6_pktopts opt, *optp = NULL, *origoptp; - struct ifnet *oifp = NULL; - va_list ap; - struct socket *so; - struct sockaddr_in6 *dst; - struct mbuf *control; - struct in6_addr *in6a; - u_int8_t type, code; - int plen = m->m_pkthdr.len; - - va_start(ap, m); - so = va_arg(ap, struct socket *); - dst = va_arg(ap, struct sockaddr_in6 *); - control = va_arg(ap, struct mbuf *); - va_end(ap); - - inp = sotoinpcb(so); - flags = (so->so_options & SO_DONTROUTE); - - if (control) { - error = ip6_setpktoptions(control, &opt, - so->so_state & SS_PRIV); - if (error != 0) - goto bad; - optp = &opt; - } else - optp = NULL; - - /* - * For an ICMPv6 packet, we should know its type and code - * to update statistics. - */ - if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { - struct icmp6_hdr *icmp6; - if (m->m_len < sizeof(struct icmp6_hdr) && - (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { - error = ENOBUFS; - goto bad; - } - icmp6 = mtod(m, struct icmp6_hdr *); - type = icmp6->icmp6_type; - code = icmp6->icmp6_code; - } - - M_PREPEND(m, sizeof(struct ip6_hdr), M_WAIT); - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_flow = dst->sin6_flowinfo & IPV6_FLOWINFO_MASK; - ip6->ip6_vfc &= ~IPV6_VERSION_MASK; - ip6->ip6_vfc |= IPV6_VERSION; - ip6->ip6_nxt = inp->inp_ipv6.ip6_nxt; - /* ip6_src will be filled in later */ - - /* KAME hack: embed scopeid */ - origoptp = inp->inp_outputopts6; - inp->inp_outputopts6 = optp; - if (in6_embedscope(&ip6->ip6_dst, dst, inp, &oifp) != 0) { - error = EINVAL; - goto bad; - } - inp->inp_outputopts6 = origoptp; - - /* source address selection */ - in6a = in6_selectsrc(dst, optp, inp->inp_moptions6, &inp->inp_route6, - &inp->inp_laddr6, &error); - if (in6a == NULL) { - if (error == 0) - error = EADDRNOTAVAIL; - goto bad; - } - ip6->ip6_src = *in6a; - if (inp->inp_route6.ro_rt) /* what if oifp contradicts ? */ - oifp = ifindex2ifnet[inp->inp_route6.ro_rt->rt_ifp->if_index]; - - ip6->ip6_hlim = in6_selecthlim(inp, oifp); - - if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || - inp->inp_csumoffset != -1) { - struct mbuf *n; - int off; - u_int16_t *p; - -#define offsetof(type, member) ((size_t)(&((type *)0)->member)) /* XXX */ - /* compute checksum */ - if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) - off = offsetof(struct icmp6_hdr, icmp6_cksum); - else - off = inp->inp_csumoffset; - if (plen < off + 1) { - error = EINVAL; - goto bad; - } - off += sizeof(struct ip6_hdr); - - n = m; - while (n && n->m_len <= off) { - off -= n->m_len; - n = n->m_next; - } - if (!n) - goto bad; - p = (u_int16_t *)(mtod(n, caddr_t) + off); - *p = 0; - *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); - } - - error = ip6_output(m, optp, &inp->inp_route6, flags, - inp->inp_moptions6, &oifp); - if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { - if (oifp) - icmp6_ifoutstat_inc(oifp, type, code); - icmp6stat.icp6s_outhist[type]++; - } - - goto freectl; - -bad: - if (m) - m_freem(m); - -freectl: - if (control) - m_freem(control); - return error; -} - -/* - * Handles [gs]etsockopt() calls. - */ -int -rip6_ctloutput(op, so, level, optname, m) - int op; - struct socket *so; - int level, optname; - struct mbuf **m; -{ - register struct inpcb *inp = sotoinpcb(so); - int error; - - if ((level != IPPROTO_IPV6) && (level != IPPROTO_ICMPV6)) { - if (op == PRCO_SETOPT && *m) - (void)m_free(*m); - return(EINVAL); - } - - switch (optname) { - case MRT6_INIT: - case MRT6_DONE: - case MRT6_ADD_MIF: - case MRT6_DEL_MIF: - case MRT6_ADD_MFC: - case MRT6_DEL_MFC: - case MRT6_PIM: - if (level != IPPROTO_IPV6) { - if (op == PRCO_SETOPT && *m) - (void)m_free(*m); - return EINVAL; - } - - if (op == PRCO_SETOPT) { - error = ip6_mrouter_set(optname, so, *m); - if (*m) - (void)m_free(*m); - } else if (op == PRCO_GETOPT) - error = ip6_mrouter_get(optname, so, m); - else - error = EINVAL; - return (error); - - case IPV6_CHECKSUM: - if (op == PRCO_SETOPT || op == PRCO_GETOPT) { - if (op == PRCO_SETOPT) { - if (!m || !*m || (*m)->m_len != sizeof(int)) - return(EINVAL); - inp->inp_csumoffset = *(mtod(*m, int *)); - m_freem(*m); - } else { - *m = m_get(M_WAIT, MT_SOOPTS); - (*m)->m_len = sizeof(int); - *(mtod(*m, int *)) = inp->inp_csumoffset; - } - return 0; - } - break; - - case ICMP6_FILTER: - if (level != IPPROTO_ICMPV6) { - if (op == PRCO_SETOPT && *m) - (void)m_free(*m); - return EINVAL; - } - - if (op == PRCO_SETOPT || op == PRCO_GETOPT) { - if (op == PRCO_SETOPT) { - if (!m || !*m || - (*m)->m_len != sizeof(struct icmp6_filter)) - return(EINVAL); - bcopy(mtod(*m, struct icmp6_filter *), - inp->inp_icmp6filt, - sizeof(struct icmp6_filter)); - m_freem(*m); - } else { - *m = m_get(M_WAIT, MT_SOOPTS); - (*m)->m_len = sizeof(struct icmp6_filter); - *mtod(*m, struct icmp6_filter *) = - *inp->inp_icmp6filt; - } - return 0; - } - break; - - default: - break; - } - return ip6_ctloutput(op, so, level, optname, m); -} - -#if 1 -#define MAYBESTATIC static -#define MAYBEINLINE __inline__ -#else /* __GNUC__ && __GNUC__ >= 2 && __OPTIMIZE__ */ -#define MAYBESTATIC -#define MAYBEINLINE -#endif /* __GNUC__ && __GNUC__ >= 2 && __OPTIMIZE__ */ - -MAYBESTATIC MAYBEINLINE int -rip6_usrreq_attach(struct socket *so, int proto) -{ - register struct inpcb *inp = sotoinpcb(so); - register int error = 0; - - if (inp) - panic("rip6_attach - Already got PCB"); - - if ((so->so_state & SS_PRIV) == 0) { - error = EACCES; - return error; - } - if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) || - (error = in_pcballoc(so, &rawin6pcbtable))) { - return error; - } - - inp = sotoinpcb(so); - /*nam; Nam contains protocol type, apparently. */ -#ifdef __alpha__ - inp->inp_ipv6.ip6_nxt = (u_long)proto; -#else - inp->inp_ipv6.ip6_nxt = (int)proto; -#endif - if (inp->inp_ipv6.ip6_nxt == IPPROTO_ICMPV6) - inp->inp_csumoffset = 2; - inp->inp_icmp6filt = (struct icmp6_filter *) - malloc(sizeof(struct icmp6_filter), M_PCB, M_NOWAIT); - ICMP6_FILTER_SETPASSALL(inp->inp_icmp6filt); - return error; -} - -MAYBESTATIC MAYBEINLINE int -rip6_usrreq_detach(struct socket *so) -{ - register struct inpcb *inp = sotoinpcb(so); - - if (inp == 0) - panic("rip6_detach"); -#ifdef MROUTING - /* More MROUTING stuff. */ -#endif - if (inp->inp_icmp6filt) { - free(inp->inp_icmp6filt, M_PCB); - inp->inp_icmp6filt = NULL; - } - in_pcbdetach(inp); - return 0; -} - -MAYBESTATIC MAYBEINLINE int -rip6_usrreq_abort(struct socket *so) -{ - soisdisconnected(so); - return rip6_usrreq_detach(so); -} - -MAYBESTATIC MAYBEINLINE int -rip6_usrreq_disconnect(struct socket *so) -{ - if ((so->so_state & SS_ISCONNECTED) == 0) - return ENOTCONN; - return rip6_usrreq_abort(so); -} - -MAYBESTATIC MAYBEINLINE int -rip6_usrreq_bind(struct socket *so, struct sockaddr *nam) -{ - register struct inpcb *inp = sotoinpcb(so); - register struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; - - /* 'ifnet' is declared in one of the net/ header files. */ - if ((ifnet.tqh_first == 0) || (addr->sin6_family != AF_INET6)) - return EADDRNOTAVAIL; - - /* - * Currently, ifa_ifwithaddr tends to fail for a link-local - * address, since it implicitly expects that the link identifier - * for the address is embedded in the sin6_addr part. - * For now, we'd rather keep this "as is". We'll eventually fix - * this in a more natural way. - */ - if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && - ifa_ifwithaddr((struct sockaddr *)addr) == 0) { - return EADDRNOTAVAIL; - } - - inp->inp_laddr6 = addr->sin6_addr; - return 0; -} - -MAYBESTATIC MAYBEINLINE int -rip6_usrreq_connect(struct socket *so, struct sockaddr *nam) -{ - register struct inpcb *inp = sotoinpcb(so); - register struct sockaddr_in6 *addr = (struct sockaddr_in6 *) nam; - int error; - struct in6_addr *in6a; - - if (addr->sin6_family != AF_INET6) - return EAFNOSUPPORT; - - in6a = in6_selectsrc(addr, inp->inp_outputopts6, inp->inp_moptions6, - &inp->inp_route6, &inp->inp_laddr6, &error); - if (in6a == NULL) { - if (error == 0) - error = EADDRNOTAVAIL; - return error; - } - inp->inp_laddr6 = *in6a; - - /* Will structure assignment work with this compiler? */ - inp->inp_faddr6 = addr->sin6_addr; - - soisconnected(so); - return 0; -} - -MAYBESTATIC MAYBEINLINE int -rip6_usrreq_shutdown(struct socket *so) -{ - socantsendmore(so); - return 0; -} - -static int rip6_usrreq_send __P((struct socket *so, int flags, struct mbuf *m, - struct sockaddr *addr, struct mbuf *control)); - -static int -rip6_usrreq_send(struct socket *so, int flags, struct mbuf *m, - struct sockaddr *addr, struct mbuf *control) -{ - register struct inpcb *inp = sotoinpcb(so); - register int error = 0; - struct sockaddr_in6 *dst, tmp; - - if (inp == 0) { - m_freem(m); - return EINVAL; - } - - /* - * Check "connected" status, and if there is a supplied destination - * address. - */ - if (so->so_state & SS_ISCONNECTED) { - if (addr) - return EISCONN; - - bzero(&tmp, sizeof(tmp)); - tmp.sin6_family = AF_INET6; - tmp.sin6_len = sizeof(tmp); - tmp.sin6_addr = inp->inp_faddr6; - dst = &tmp; - } else { - if (addr == NULL) - return ENOTCONN; - - dst = (struct sockaddr_in6 *)addr; - } - - error = rip6_output(m,so,dst,control); - /* m = NULL; */ - return error; -} - -MAYBESTATIC MAYBEINLINE int -rip6_usrreq_control(struct socket *so, u_long cmd, caddr_t data, - struct ifnet *ifp) -{ - /* - * Notice that IPv4 raw sockets don't pass PRU_CONTROL. I wonder - * if they panic as well? - */ - return in6_control(so, cmd, data, ifp, 0); -} - -MAYBESTATIC MAYBEINLINE int -rip6_usrreq_sense(struct socket *so, struct stat *sb) -{ - /* services stat(2) call. */ - return 0; -} - -MAYBESTATIC MAYBEINLINE int -rip6_usrreq_sockaddr(struct socket *so, struct mbuf *nam) -{ - register struct inpcb *inp = sotoinpcb(so); - return in6_setsockaddr(inp, nam); -} - -MAYBESTATIC MAYBEINLINE int -rip6_usrreq_peeraddr(struct socket *so, struct mbuf *nam) -{ - register struct inpcb *inp = sotoinpcb(so); - return in6_setpeeraddr(inp, nam); -} - -/* - * Handles PRU_* for raw IPv6 sockets. - */ -int -rip6_usrreq(so, req, m, nam, control, p) - struct socket *so; - int req; - struct mbuf *m, *nam, *control; - struct proc *p; -{ - register int error = 0; - -#ifdef MROUTING - /* - * Ummm, like, multicast routing stuff goes here, huh huh huh. - * - * Seriously, this would be for user-level multicast routing daemons. - * With multicast being a requirement for IPv6, code like what might go - * here may go away. - */ -#endif - - switch (req) { - case PRU_ATTACH: - error = rip6_usrreq_attach(so, (long)nam); - break; - case PRU_DISCONNECT: - error = rip6_usrreq_disconnect(so); - break; - case PRU_ABORT: - error = rip6_usrreq_abort(so); - break; - case PRU_DETACH: - error = rip6_usrreq_detach(so); - break; - case PRU_BIND: - if (nam->m_len != sizeof(struct sockaddr_in6)) - return EINVAL; - /* - * Be strict regarding sockaddr_in6 fields. - */ - error = rip6_usrreq_bind(so, mtod(nam, struct sockaddr *)); - break; - case PRU_CONNECT: - /* - * Be strict regarding sockaddr_in6 fields. - */ - if (nam->m_len != sizeof(struct sockaddr_in6)) - return EINVAL; - error = rip6_usrreq_connect(so, mtod(nam, struct sockaddr *)); - break; - case PRU_SHUTDOWN: - error = rip6_usrreq_shutdown(so); - break; - case PRU_SEND: - /* - * Be strict regarding sockaddr_in6 fields. - */ - if (nam->m_len != sizeof(struct sockaddr_in6)) - return EINVAL; - error = rip6_usrreq_send(so, 0, m, mtod(nam, struct sockaddr *), - control); - m = NULL; - break; - case PRU_CONTROL: - return rip6_usrreq_control(so, (u_long)m, (caddr_t) nam, - (struct ifnet *) control); - case PRU_SENSE: - return rip6_usrreq_sense(so, NULL); /* XXX */ - case PRU_CONNECT2: - case PRU_RCVOOB: - case PRU_LISTEN: - case PRU_SENDOOB: - case PRU_RCVD: - case PRU_ACCEPT: - error = EOPNOTSUPP; - break; - case PRU_SOCKADDR: - error = rip6_usrreq_sockaddr(so, nam); - break; - case PRU_PEERADDR: - error = rip6_usrreq_peeraddr(so, nam); - break; - default: - panic("rip6_usrreq - unknown req\n"); - } - if (m != NULL) - m_freem(m); - return error; -} diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c index 1a2b5e5d853..c0a519c6db8 100644 --- a/sys/netinet6/udp6_output.c +++ b/sys/netinet6/udp6_output.c @@ -113,7 +113,7 @@ #define in6p_flags inp_flags #define in6p_moptions inp_moptions6 #define in6p_route inp_route6 -#define in6p_flowinfo inp_fflowinfo +#define in6p_flowinfo inp_flowinfo #define udp6stat udpstat #define udp6s_opackets udps_opackets |