summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/raw_ip6.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet6/raw_ip6.c')
-rw-r--r--sys/netinet6/raw_ip6.c98
1 files changed, 92 insertions, 6 deletions
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 9fb94d5..a846b3c 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -85,13 +85,17 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/in_systm.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/ip6_mroute.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#include <netinet/in_pcb.h>
#include <netinet6/in6_pcb.h>
#include <netinet6/nd6.h>
+#include <netinet6/ip6protosw.h>
+#ifdef ENABLE_DEFAULT_SCOPE
+#include <netinet6/scope6_var.h>
+#endif
#ifdef IPSEC
#include <netinet6/ipsec.h>
@@ -209,6 +213,66 @@ rip6_input(mp, offp, proto)
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 = 0;
+ void (*notify) __P((struct inpcb *, 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 */
+ 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(&ripcb, (struct sockaddr *)&sa6,
+ 0, &s, 0, cmd, notify);
+ } else
+ (void) in6_pcbnotify(&ripcb, (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.
@@ -371,10 +435,10 @@ rip6_output(m, va_alist)
}
#ifdef IPSEC
- m->m_pkthdr.rcvif = (struct ifnet *)so;
+ ipsec_setsocket(m, so);
#endif /*IPSEC*/
- error = ip6_output(m, optp, &in6p->in6p_route, IPV6_SOCKINMRCVIF,
+ error = ip6_output(m, optp, &in6p->in6p_route, 0,
in6p->in6p_moptions, &oifp);
if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
if (oifp)
@@ -543,6 +607,11 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6)
return EADDRNOTAVAIL;
+#ifdef ENABLE_DEFAULT_SCOPE
+ if (addr->sin6_scope_id == 0) { /* not change if specified */
+ addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr);
+ }
+#endif
if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
(ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)
return EADDRNOTAVAIL;
@@ -563,6 +632,9 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
struct in6_addr *in6a = NULL;
int error = 0;
+#ifdef ENABLE_DEFAULT_SCOPE
+ struct sockaddr_in6 tmp;
+#endif
if (nam->sa_len != sizeof(*addr))
return EINVAL;
@@ -570,7 +642,14 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
return EADDRNOTAVAIL;
if (addr->sin6_family != AF_INET6)
return EAFNOSUPPORT;
-
+#ifdef ENABLE_DEFAULT_SCOPE
+ if (addr->sin6_scope_id == 0) { /* not change if specified */
+ /* avoid overwrites */
+ tmp = *addr;
+ addr = &tmp;
+ addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr);
+ }
+#endif
/* Source address selection. XXX: need pcblookup? */
in6a = in6_selectsrc(addr, inp->in6p_outputopts,
inp->in6p_moptions, &inp->in6p_route,
@@ -598,6 +677,7 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
struct sockaddr_in6 tmp;
struct sockaddr_in6 *dst;
+ /* always copy sockaddr to avoid overwrites */
if (so->so_state & SS_ISCONNECTED) {
if (nam) {
m_freem(m);
@@ -615,8 +695,14 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
m_freem(m);
return ENOTCONN;
}
- dst = (struct sockaddr_in6 *)nam;
+ tmp = *(struct sockaddr_in6 *)nam;
+ dst = &tmp;
+ }
+#ifdef ENABLE_DEFAULT_SCOPE
+ if (dst->sin6_scope_id == 0) { /* not change if specified */
+ dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr);
}
+#endif
return rip6_output(m, so, dst, control);
}
OpenPOWER on IntegriCloud