summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2001-06-11 12:39:29 +0000
committerume <ume@FreeBSD.org>2001-06-11 12:39:29 +0000
commit832f8d224926758a9ae0b23a6b45353e44fbc87a (patch)
treea79fc7ad2b97862c4a404f352f0211ad93a7b5f1 /sys/net
parent2693854b01a52b0395a91322aa3edf926bddff38 (diff)
downloadFreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.zip
FreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.tar.gz
Sync with recent KAME.
This work was based on kame-20010528-freebsd43-snap.tgz and some critical problem after the snap was out were fixed. There are many many changes since last KAME merge. TODO: - The definitions of SADB_* in sys/net/pfkeyv2.h are still different from RFC2407/IANA assignment because of binary compatibility issue. It should be fixed under 5-CURRENT. - ip6po_m member of struct ip6_pktopts is no longer used. But, it is still there because of binary compatibility issue. It should be removed under 5-CURRENT. Reviewed by: itojun Obtained from: KAME MFC after: 3 weeks
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if.c21
-rw-r--r--sys/net/if_faith.c241
-rw-r--r--sys/net/if_faith.h41
-rw-r--r--sys/net/if_gif.c184
-rw-r--r--sys/net/if_gif.h4
-rw-r--r--sys/net/if_loop.c29
-rw-r--r--sys/net/if_sppp.h14
-rw-r--r--sys/net/if_spppsubr.c795
-rw-r--r--sys/net/if_stf.c93
-rw-r--r--sys/net/net_osdep.c16
-rw-r--r--sys/net/net_osdep.h111
-rw-r--r--sys/net/pfkeyv2.h46
-rw-r--r--sys/net/ppp_defs.h2
-rw-r--r--sys/net/rtsock.c15
14 files changed, 1435 insertions, 177 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index f98d85e..f52d74d 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -269,7 +269,7 @@ if_detach(ifp)
#endif /* INET */
#ifdef INET6
if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
- in6_purgeaddr(ifa, ifp);
+ in6_purgeaddr(ifa);
/* ifp_addrhead is already updated */
continue;
}
@@ -278,6 +278,16 @@ if_detach(ifp)
IFAFREE(ifa);
}
+#ifdef INET6
+ /*
+ * Remove all IPv6 kernel structs related to ifp. This should be done
+ * before removing routing entries below, since IPv6 interface direct
+ * routes are expected to be removed by the IPv6-specific kernel API.
+ * Otherwise, the kernel will detect some inconsistency and bark it.
+ */
+ in6_ifdetach(ifp);
+#endif
+
/*
* Delete all remaining routes using this interface
* Unfortuneatly the only way to do this is to slog through
@@ -290,11 +300,6 @@ if_detach(ifp)
(void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
}
-#ifdef INET6
- /* nuke all IPv6 kernel structs related to ifp */
- in6_ifdetach(ifp);
-#endif
-
TAILQ_REMOVE(&ifnet, ifp, if_link);
mtx_destroy(&ifp->if_snd.ifq_mtx);
splx(s);
@@ -897,6 +902,7 @@ ifioctl(so, cmd, data, p)
#ifdef INET6
case SIOCSIFPHYADDR_IN6:
#endif
+ case SIOCSLIFPHYADDR:
case SIOCSIFMEDIA:
case SIOCSIFGENERIC:
error = suser(p);
@@ -913,6 +919,9 @@ ifioctl(so, cmd, data, p)
ifs = (struct ifstat *)data;
ifs->ascii[0] = '\0';
+ case SIOCGIFPSRCADDR:
+ case SIOCGIFPDSTADDR:
+ case SIOCGLIFPHYADDR:
case SIOCGIFMEDIA:
case SIOCGIFGENERIC:
if (ifp->if_ioctl == 0)
diff --git a/sys/net/if_faith.c b/sys/net/if_faith.c
index b28fecd..840b77b 100644
--- a/sys/net/if_faith.c
+++ b/sys/net/if_faith.c
@@ -1,3 +1,5 @@
+/* $KAME: if_faith.c,v 1.21 2001/02/20 07:59:26 itojun Exp $ */
+
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
@@ -41,30 +43,58 @@
/*
* Loopback interface driver for protocol testing and timing.
*/
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include "faith.h"
+#if NFAITH > 0
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
+#include <sys/errno.h>
#include <sys/sockio.h>
+#include <sys/time.h>
+#include <sys/queue.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/route.h>
#include <net/bpf.h>
+#include <net/if_faith.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#ifdef INET6
+#ifndef INET
+#include <netinet/in.h>
+#endif
+#include <netinet6/in6_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif
+
+#include "bpf.h"
+#define NBPFILTER NBPF
#include <net/net_osdep.h>
-extern int loioctl __P((struct ifnet *, u_long, caddr_t));
-extern int looutput __P((struct ifnet *ifp,
- struct mbuf *m, struct sockaddr *dst, struct rtentry *rt));
+static int faithioctl __P((struct ifnet *, u_long, caddr_t));
+int faithoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
+ struct rtentry *));
+static void faithrtrequest __P((int, struct rtentry *, struct sockaddr *));
void faithattach __P((void *));
PSEUDO_SET(faithattach, if_faith);
+
static struct ifnet faithif[NFAITH];
#define FAITHMTU 1500
@@ -74,8 +104,8 @@ void
faithattach(faith)
void *faith;
{
- register struct ifnet *ifp;
- register int i;
+ struct ifnet *ifp;
+ int i;
for (i = 0; i < NFAITH; i++) {
ifp = &faithif[i];
@@ -85,13 +115,210 @@ faithattach(faith)
ifp->if_mtu = FAITHMTU;
/* LOOPBACK commented out to announce IPv6 routes to faith */
ifp->if_flags = /* IFF_LOOPBACK | */ IFF_MULTICAST;
- ifp->if_ioctl = loioctl;
- ifp->if_output = looutput;
+ ifp->if_ioctl = faithioctl;
+ ifp->if_output = faithoutput;
ifp->if_type = IFT_FAITH;
ifp->if_snd.ifq_maxlen = ifqmaxlen;
ifp->if_hdrlen = 0;
ifp->if_addrlen = 0;
if_attach(ifp);
+#if NBPFILTER > 0
+#ifdef HAVE_OLD_BPF
bpfattach(ifp, DLT_NULL, sizeof(u_int));
+#else
+ bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
+#endif
+#endif
+ }
+}
+
+int
+faithoutput(ifp, m, dst, rt)
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct sockaddr *dst;
+ struct rtentry *rt;
+{
+ int isr;
+ struct ifqueue *ifq = 0;
+
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic("faithoutput no HDR");
+#if NBPFILTER > 0
+ /* BPF write needs to be handled specially */
+ if (dst->sa_family == AF_UNSPEC) {
+ dst->sa_family = *(mtod(m, int *));
+ m->m_len -= sizeof(int);
+ m->m_pkthdr.len -= sizeof(int);
+ m->m_data += sizeof(int);
}
+
+ if (ifp->if_bpf) {
+ /*
+ * We need to prepend the address family as
+ * a four byte field. Cons up a faith header
+ * to pacify bpf. This is safe because bpf
+ * will only read from the mbuf (i.e., it won't
+ * try to free it or keep a pointer a to it).
+ */
+ struct mbuf m0;
+ u_int32_t af = dst->sa_family;
+
+ m0.m_next = m;
+ m0.m_len = 4;
+ m0.m_data = (char *)&af;
+
+#ifdef HAVE_OLD_BPF
+ bpf_mtap(ifp, &m0);
+#else
+ bpf_mtap(ifp->if_bpf, &m0);
+#endif
+ }
+#endif
+
+ if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
+ m_freem(m);
+ return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
+ rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
+ }
+ ifp->if_opackets++;
+ ifp->if_obytes += m->m_pkthdr.len;
+ switch (dst->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ifq = &ipintrq;
+ isr = NETISR_IP;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ifq = &ip6intrq;
+ isr = NETISR_IPV6;
+ break;
+#endif
+ default:
+ m_freem(m);
+ return EAFNOSUPPORT;
+ }
+
+ /* XXX do we need more sanity checks? */
+
+ m->m_pkthdr.rcvif = ifp;
+ ifp->if_ipackets++;
+ ifp->if_ibytes += m->m_pkthdr.len;
+ (void) IF_HANDOFF(ifq, m, NULL);
+ schednetisr(isr);
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+faithrtrequest(cmd, rt, sa)
+ int cmd;
+ struct rtentry *rt;
+ struct sockaddr *sa;
+{
+ if (rt) {
+ rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
+ /*
+ * For optimal performance, the send and receive buffers
+ * should be at least twice the MTU plus a little more for
+ * overhead.
+ */
+ rt->rt_rmx.rmx_recvpipe =
+ rt->rt_rmx.rmx_sendpipe = 3 * FAITHMTU;
+ }
+}
+
+/*
+ * Process an ioctl request.
+ */
+/* ARGSUSED */
+static int
+faithioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct ifaddr *ifa;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int error = 0;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP | IFF_RUNNING;
+ ifa = (struct ifaddr *)data;
+ ifa->ifa_rtrequest = faithrtrequest;
+ /*
+ * Everything else is done at a higher level.
+ */
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if (ifr == 0) {
+ error = EAFNOSUPPORT; /* XXX */
+ break;
+ }
+ switch (ifr->ifr_addr.sa_family) {
+#ifdef INET
+ case AF_INET:
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ break;
+#endif
+
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
+ break;
+
+#ifdef SIOCSIFMTU
+ case SIOCSIFMTU:
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+#endif
+
+ case SIOCSIFFLAGS:
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
+
+/*
+ * XXX could be slow
+ * XXX could be layer violation to call sys/net from sys/netinet6
+ */
+int
+faithprefix(in6)
+ struct in6_addr *in6;
+{
+ struct rtentry *rt;
+ struct sockaddr_in6 sin6;
+ int ret;
+
+ if (ip6_keepfaith == 0)
+ return 0;
+
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_addr = *in6;
+ rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+ if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH &&
+ (rt->rt_ifp->if_flags & IFF_UP) != 0)
+ ret = 1;
+ else
+ ret = 0;
+ if (rt)
+ RTFREE(rt);
+ return ret;
}
+#endif /* NFAITH > 0 */
diff --git a/sys/net/if_faith.h b/sys/net/if_faith.h
new file mode 100644
index 0000000..1e30bfb
--- /dev/null
+++ b/sys/net/if_faith.h
@@ -0,0 +1,41 @@
+/* $FreeBSD$ */
+/* $KAME: if_faith.h,v 1.1 2000/07/26 05:49:21 itojun Exp $ */
+
+/*
+ * Copyright (C) 2000 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.
+ */
+
+#ifndef _NET_IF_FAITH_H_
+#define _NET_IF_FAITH_H_
+
+#ifdef _KERNEL
+struct in6_addr;
+int faithprefix __P((struct in6_addr *));
+#endif
+
+#endif /* _NET_IF_FAITH_H_ */
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 68031cb..465063c 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: if_gif.c,v 1.28 2000/06/20 12:30:03 jinmei Exp $ */
+/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -52,11 +52,11 @@
#include <net/route.h>
#include <net/bpf.h>
-#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
-#include <netinet/in_var.h>
#include <netinet/ip.h>
+#ifdef INET
+#include <netinet/in_var.h>
#include <netinet/in_gif.h>
#endif /* INET */
@@ -114,11 +114,11 @@ void
gifattach(dummy)
void *dummy;
{
- register struct gif_softc *sc;
- register int i;
+ struct gif_softc *sc;
+ int i;
ngif = NGIF;
- gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
+ gif = sc = malloc(ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
bzero(sc, ngif * sizeof(struct gif_softc));
for (i = 0; i < ngif; sc++, i++) {
sc->gif_if.if_name = "gif";
@@ -148,6 +148,10 @@ gifattach(dummy)
sc->gif_if.if_mtu = GIF_MTU;
sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
+#if 0
+ /* turn off ingress filter */
+ sc->gif_if.if_flags |= IFF_LINK2;
+#endif
sc->gif_if.if_ioctl = gif_ioctl;
sc->gif_if.if_output = gif_output;
sc->gif_if.if_type = IFT_GIF;
@@ -229,7 +233,7 @@ gif_output(ifp, m, dst, rt)
struct sockaddr *dst;
struct rtentry *rt; /* added in net2 */
{
- register struct gif_softc *sc = (struct gif_softc*)ifp;
+ struct gif_softc *sc = (struct gif_softc*)ifp;
int error = 0;
static int called = 0; /* XXX: MUTEX */
@@ -268,7 +272,7 @@ gif_output(ifp, m, dst, rt)
* try to free it or keep a pointer a to it).
*/
struct mbuf m0;
- u_int af = dst->sa_family;
+ u_int32_t af = dst->sa_family;
m0.m_next = m;
m0.m_len = 4;
@@ -284,8 +288,11 @@ gif_output(ifp, m, dst, rt)
ifp->if_opackets++;
ifp->if_obytes += m->m_pkthdr.len;
+ /* inner AF-specific encapsulation */
+
/* XXX should we check if our outer source is legal? */
+ /* dispatch to output logic based on outer AF */
switch (sc->gif_psrc->sa_family) {
#ifdef INET
case AF_INET:
@@ -300,11 +307,13 @@ gif_output(ifp, m, dst, rt)
default:
m_freem(m);
error = ENETDOWN;
+ goto end;
}
end:
called = 0; /* reset recursion counter */
- if (error) ifp->if_oerrors++;
+ if (error)
+ ifp->if_oerrors++;
return error;
}
@@ -315,7 +324,7 @@ gif_input(m, af, gifp)
struct ifnet *gifp;
{
int isr;
- register struct ifqueue *ifq = 0;
+ struct ifqueue *ifq = 0;
if (gifp == NULL) {
/* just in case */
@@ -335,11 +344,11 @@ gif_input(m, af, gifp)
* try to free it or keep a pointer a to it).
*/
struct mbuf m0;
- u_int af = AF_INET6;
+ u_int32_t af1 = af;
m0.m_next = m;
m0.m_len = 4;
- m0.m_data = (char *)&af;
+ m0.m_data = (char *)&af1;
#ifdef HAVE_OLD_BPF
bpf_mtap(gifp, &m0);
@@ -435,13 +444,16 @@ gif_ioctl(ifp, cmd, data)
#ifdef INET6
case SIOCSIFPHYADDR_IN6:
#endif /* INET6 */
+ case SIOCSLIFPHYADDR:
switch (cmd) {
+#ifdef INET
case SIOCSIFPHYADDR:
src = (struct sockaddr *)
&(((struct in_aliasreq *)data)->ifra_addr);
dst = (struct sockaddr *)
&(((struct in_aliasreq *)data)->ifra_dstaddr);
break;
+#endif
#ifdef INET6
case SIOCSIFPHYADDR_IN6:
src = (struct sockaddr *)
@@ -450,6 +462,66 @@ gif_ioctl(ifp, cmd, data)
&(((struct in6_aliasreq *)data)->ifra_dstaddr);
break;
#endif
+ case SIOCSLIFPHYADDR:
+ src = (struct sockaddr *)
+ &(((struct if_laddrreq *)data)->addr);
+ dst = (struct sockaddr *)
+ &(((struct if_laddrreq *)data)->dstaddr);
+ }
+
+ /* sa_family must be equal */
+ if (src->sa_family != dst->sa_family)
+ return EINVAL;
+
+ /* validate sa_len */
+ switch (src->sa_family) {
+#ifdef INET
+ case AF_INET:
+ if (src->sa_len != sizeof(struct sockaddr_in))
+ return EINVAL;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (src->sa_len != sizeof(struct sockaddr_in6))
+ return EINVAL;
+ break;
+#endif
+ default:
+ return EAFNOSUPPORT;
+ }
+ switch (dst->sa_family) {
+#ifdef INET
+ case AF_INET:
+ if (dst->sa_len != sizeof(struct sockaddr_in))
+ return EINVAL;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (dst->sa_len != sizeof(struct sockaddr_in6))
+ return EINVAL;
+ break;
+#endif
+ default:
+ return EAFNOSUPPORT;
+ }
+
+ /* check sa_family looks sane for the cmd */
+ switch (cmd) {
+ case SIOCSIFPHYADDR:
+ if (src->sa_family == AF_INET)
+ break;
+ return EAFNOSUPPORT;
+#ifdef INET6
+ case SIOCSIFPHYADDR_IN6:
+ if (src->sa_family == AF_INET6)
+ break;
+ return EAFNOSUPPORT;
+#endif /* INET6 */
+ case SIOCSLIFPHYADDR:
+ /* checks done in the above */
+ break;
}
for (i = 0; i < ngif; i++) {
@@ -493,41 +565,16 @@ gif_ioctl(ifp, cmd, data)
#endif
}
- if (src->sa_family != dst->sa_family ||
- src->sa_len != dst->sa_len) {
- error = EINVAL;
- break;
- }
- switch (src->sa_family) {
-#ifdef INET
- case AF_INET:
- size = sizeof(struct sockaddr_in);
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- size = sizeof(struct sockaddr_in6);
- break;
-#endif
- default:
- error = EAFNOSUPPORT;
- goto bad;
- }
- if (src->sa_len != size) {
- error = EINVAL;
- break;
- }
-
if (sc->gif_psrc)
free((caddr_t)sc->gif_psrc, M_IFADDR);
- sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
- bcopy((caddr_t)src, (caddr_t)sa, size);
+ sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
+ bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
sc->gif_psrc = sa;
if (sc->gif_pdst)
free((caddr_t)sc->gif_pdst, M_IFADDR);
- sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
- bcopy((caddr_t)dst, (caddr_t)sa, size);
+ sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
+ bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
sc->gif_pdst = sa;
ifp->if_flags |= IFF_RUNNING;
@@ -548,7 +595,7 @@ gif_ioctl(ifp, cmd, data)
free((caddr_t)sc->gif_pdst, M_IFADDR);
sc->gif_pdst = NULL;
}
- /* change the IFF_UP flag as well? */
+ /* change the IFF_{UP, RUNNING} flag as well? */
break;
#endif
@@ -561,25 +608,27 @@ gif_ioctl(ifp, cmd, data)
goto bad;
}
src = sc->gif_psrc;
- switch (sc->gif_psrc->sa_family) {
+ switch (cmd) {
#ifdef INET
- case AF_INET:
+ case SIOCGIFPSRCADDR:
dst = &ifr->ifr_addr;
- size = sizeof(struct sockaddr_in);
+ size = sizeof(ifr->ifr_addr);
break;
#endif /* INET */
#ifdef INET6
- case AF_INET6:
+ case SIOCGIFPSRCADDR_IN6:
dst = (struct sockaddr *)
&(((struct in6_ifreq *)data)->ifr_addr);
- size = sizeof(struct sockaddr_in6);
+ size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
break;
#endif /* INET6 */
default:
error = EADDRNOTAVAIL;
goto bad;
}
- bcopy((caddr_t)src, (caddr_t)dst, size);
+ if (src->sa_len > size)
+ return EINVAL;
+ bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
break;
case SIOCGIFPDSTADDR:
@@ -591,25 +640,52 @@ gif_ioctl(ifp, cmd, data)
goto bad;
}
src = sc->gif_pdst;
- switch (sc->gif_pdst->sa_family) {
+ switch (cmd) {
#ifdef INET
- case AF_INET:
+ case SIOCGIFPDSTADDR:
dst = &ifr->ifr_addr;
- size = sizeof(struct sockaddr_in);
+ size = sizeof(ifr->ifr_addr);
break;
#endif /* INET */
#ifdef INET6
- case AF_INET6:
+ case SIOCGIFPDSTADDR_IN6:
dst = (struct sockaddr *)
&(((struct in6_ifreq *)data)->ifr_addr);
- size = sizeof(struct sockaddr_in6);
+ size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
break;
#endif /* INET6 */
default:
error = EADDRNOTAVAIL;
goto bad;
}
- bcopy((caddr_t)src, (caddr_t)dst, size);
+ if (src->sa_len > size)
+ return EINVAL;
+ bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
+ break;
+
+ case SIOCGLIFPHYADDR:
+ if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+
+ /* copy src */
+ src = sc->gif_psrc;
+ dst = (struct sockaddr *)
+ &(((struct if_laddrreq *)data)->addr);
+ size = sizeof(((struct if_laddrreq *)data)->addr);
+ if (src->sa_len > size)
+ return EINVAL;
+ bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
+
+ /* copy dst */
+ src = sc->gif_pdst;
+ dst = (struct sockaddr *)
+ &(((struct if_laddrreq *)data)->dstaddr);
+ size = sizeof(((struct if_laddrreq *)data)->dstaddr);
+ if (src->sa_len > size)
+ return EINVAL;
+ bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
break;
case SIOCSIFFLAGS:
diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h
index 3699286..3978e7b 100644
--- a/sys/net/if_gif.h
+++ b/sys/net/if_gif.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: if_gif.h,v 1.13 2000/06/17 20:34:24 itojun Exp $ */
+/* $KAME: if_gif.h,v 1.17 2000/09/11 11:36:41 sumikawa Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -38,11 +38,9 @@
#define _NET_IF_GIF_H_
-#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
#if defined(_KERNEL) && !defined(_LKM)
#include "opt_inet.h"
#endif
-#endif
#include <netinet/in.h>
/* xxx sigh, why route have struct route instead of pointer? */
diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c
index 0e9ac65..f8e11f7 100644
--- a/sys/net/if_loop.c
+++ b/sys/net/if_loop.c
@@ -58,6 +58,7 @@
#include <net/netisr.h>
#include <net/route.h>
#include <net/bpf.h>
+#include <net/bpfdesc.h>
#ifdef INET
#include <netinet/in.h>
@@ -236,6 +237,8 @@ looutput(ifp, m, dst, rt)
m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t));
n->m_pkthdr = m->m_pkthdr;
n->m_len = m->m_pkthdr.len;
+ n->m_pkthdr.aux = m->m_pkthdr.aux;
+ m->m_pkthdr.aux = (struct mbuf *)NULL;
m_freem(m);
m = n;
}
@@ -277,7 +280,7 @@ contiguousfail:
int
if_simloop(ifp, m, af, hlen)
struct ifnet *ifp;
- register struct mbuf *m;
+ struct mbuf *m;
int af;
int hlen;
{
@@ -300,17 +303,19 @@ if_simloop(ifp, m, af, hlen)
if (ifp->if_bpf) {
struct mbuf m0, *n = m;
- /*
- * We need to prepend the address family as
- * a four byte field. Cons up a dummy header
- * to pacify bpf. This is safe because bpf
- * will only read from the mbuf (i.e., it won't
- * try to free it or keep a pointer a to it).
- */
- m0.m_next = m;
- m0.m_len = 4;
- m0.m_data = (char *)&af;
- n = &m0;
+ if (ifp->if_bpf->bif_dlt == DLT_NULL) {
+ /*
+ * We need to prepend the address family as
+ * a four byte field. Cons up a dummy header
+ * to pacify bpf. This is safe because bpf
+ * will only read from the mbuf (i.e., it won't
+ * try to free it or keep a pointer a to it).
+ */
+ m0.m_next = m;
+ m0.m_len = 4;
+ m0.m_data = (char *)&af;
+ n = &m0;
+ }
bpf_mtap(ifp, n);
}
diff --git a/sys/net/if_sppp.h b/sys/net/if_sppp.h
index 84fede3..0c2a201 100644
--- a/sys/net/if_sppp.h
+++ b/sys/net/if_sppp.h
@@ -39,6 +39,7 @@ struct slcp {
};
#define IDX_IPCP 1 /* idx into state table */
+#define IDX_IPV6CP 2 /* idx into state table */
struct sipcp {
u_long opts; /* IPCP options to send (bitfield) */
@@ -46,6 +47,10 @@ struct sipcp {
#define IPCP_HISADDR_SEEN 1 /* have seen his address already */
#define IPCP_MYADDR_DYN 2 /* my address is dynamically assigned */
#define IPCP_MYADDR_SEEN 4 /* have seen his address already */
+#ifdef notdef
+#define IPV6CP_MYIFID_DYN 2 /* my ifid is dynamically assigned */
+#endif
+#define IPV6CP_MYIFID_SEEN 4 /* have seen his ifid already */
};
#define AUTHNAMELEN 32
@@ -62,8 +67,8 @@ struct sauth {
u_char challenge[AUTHKEYLEN]; /* random challenge */
};
-#define IDX_PAP 2
-#define IDX_CHAP 3
+#define IDX_PAP 3
+#define IDX_CHAP 4
#define IDX_COUNT (IDX_CHAP + 1) /* bump this when adding cp's! */
@@ -87,8 +92,8 @@ struct sppp {
u_int pp_flags; /* sub modes */
u_short pp_alivecnt; /* keepalive packets counter */
u_short pp_loopcnt; /* loopback detection counter */
- u_long pp_seq; /* local sequence number */
- u_long pp_rseq; /* remote sequence number */
+ u_long pp_seq[IDX_COUNT]; /* local sequence number */
+ u_long pp_rseq[IDX_COUNT]; /* remote sequence number */
enum ppp_phase pp_phase; /* phase we're currently in */
int state[IDX_COUNT]; /* state machine */
u_char confid[IDX_COUNT]; /* id of last configuration request */
@@ -98,6 +103,7 @@ struct sppp {
struct callout_handle pap_my_to_ch; /* PAP needs one more... */
struct slcp lcp; /* LCP params */
struct sipcp ipcp; /* IPCP params */
+ struct sipcp ipv6cp; /* IPv6CP params */
struct sauth myauth; /* auth params, i'm peer */
struct sauth hisauth; /* auth params, i'm authenticator */
/*
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
index 6928c95..e489c58 100644
--- a/sys/net/if_spppsubr.c
+++ b/sys/net/if_spppsubr.c
@@ -135,10 +135,12 @@
#define PPP_ISO 0x0023 /* ISO OSI Protocol */
#define PPP_XNS 0x0025 /* Xerox NS Protocol */
#define PPP_IPX 0x002b /* Novell IPX Protocol */
+#define PPP_IPV6 0x0057 /* Internet Protocol Version 6 */
#define PPP_LCP 0xc021 /* Link Control Protocol */
#define PPP_PAP 0xc023 /* Password Authentication Protocol */
#define PPP_CHAP 0xc223 /* Challenge-Handshake Auth Protocol */
#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */
+#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */
#define CONF_REQ 1 /* PPP configure request */
#define CONF_ACK 2 /* PPP configure acknowledge */
@@ -165,6 +167,9 @@
#define IPCP_OPT_COMPRESSION 2 /* IP compression protocol (VJ) */
#define IPCP_OPT_ADDRESS 3 /* local IP address */
+#define IPV6CP_OPT_IFID 1 /* interface identifier */
+#define IPV6CP_OPT_COMPRESSION 2 /* IPv6 compression protocol */
+
#define PAP_REQ 1 /* PAP name/password request */
#define PAP_ACK 2 /* PAP acknowledge */
#define PAP_NAK 3 /* PAP fail */
@@ -340,6 +345,21 @@ static void sppp_ipcp_tls(struct sppp *sp);
static void sppp_ipcp_tlf(struct sppp *sp);
static void sppp_ipcp_scr(struct sppp *sp);
+static void sppp_ipv6cp_init(struct sppp *sp);
+static void sppp_ipv6cp_up(struct sppp *sp);
+static void sppp_ipv6cp_down(struct sppp *sp);
+static void sppp_ipv6cp_open(struct sppp *sp);
+static void sppp_ipv6cp_close(struct sppp *sp);
+static void sppp_ipv6cp_TO(void *sp);
+static int sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
+static void sppp_ipv6cp_tlu(struct sppp *sp);
+static void sppp_ipv6cp_tld(struct sppp *sp);
+static void sppp_ipv6cp_tls(struct sppp *sp);
+static void sppp_ipv6cp_tlf(struct sppp *sp);
+static void sppp_ipv6cp_scr(struct sppp *sp);
+
static void sppp_pap_input(struct sppp *sp, struct mbuf *m);
static void sppp_pap_init(struct sppp *sp);
static void sppp_pap_open(struct sppp *sp);
@@ -363,6 +383,9 @@ static const char *sppp_auth_type_name(u_short proto, u_char type);
static const char *sppp_cp_type_name(u_char type);
static const char *sppp_dotted_quad(u_long addr);
static const char *sppp_ipcp_opt_name(u_char opt);
+#ifdef INET6
+static const char *sppp_ipv6cp_opt_name(u_char opt);
+#endif
static const char *sppp_lcp_opt_name(u_char opt);
static const char *sppp_phase_name(enum ppp_phase phase);
static const char *sppp_proto_name(u_short proto);
@@ -377,6 +400,15 @@ static void sppp_print_bytes(const u_char *p, u_short len);
static void sppp_print_string(const char *p, u_short len);
static void sppp_qflush(struct ifqueue *ifq);
static void sppp_set_ip_addr(struct sppp *sp, u_long src);
+#ifdef INET6
+static void sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src,
+ struct in6_addr *dst, struct in6_addr *srcmask);
+#ifdef IPV6CP_MYIFID_DYN
+static void sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src);
+static void sppp_gen_ip6_addr(struct sppp *sp, const struct in6_addr *src);
+#endif
+static void sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *src);
+#endif
/* our control protocol descriptors */
static const struct cp lcp = {
@@ -395,6 +427,20 @@ static const struct cp ipcp = {
sppp_ipcp_scr
};
+static const struct cp ipv6cp = {
+ PPP_IPV6CP, IDX_IPV6CP,
+#ifdef INET6 /*don't run IPv6CP if there's no IPv6 support*/
+ CP_NCP,
+#else
+ 0,
+#endif
+ "ipv6cp",
+ sppp_ipv6cp_up, sppp_ipv6cp_down, sppp_ipv6cp_open, sppp_ipv6cp_close,
+ sppp_ipv6cp_TO, sppp_ipv6cp_RCR, sppp_ipv6cp_RCN_rej, sppp_ipv6cp_RCN_nak,
+ sppp_ipv6cp_tlu, sppp_ipv6cp_tld, sppp_ipv6cp_tls, sppp_ipv6cp_tlf,
+ sppp_ipv6cp_scr
+};
+
static const struct cp pap = {
PPP_PAP, IDX_PAP, CP_AUTH, "pap",
sppp_null, sppp_null, sppp_pap_open, sppp_pap_close,
@@ -414,6 +460,7 @@ static const struct cp chap = {
static const struct cp *cps[IDX_COUNT] = {
&lcp, /* IDX_LCP */
&ipcp, /* IDX_IPCP */
+ &ipv6cp, /* IDX_IPV6CP */
&pap, /* IDX_PAP */
&chap, /* IDX_CHAP */
};
@@ -499,7 +546,7 @@ sppp_input(struct ifnet *ifp, struct mbuf *m)
h->address, h->control, ntohs(h->protocol));
if (sp->state[IDX_LCP] == STATE_OPENED)
sppp_cp_send (sp, PPP_LCP, PROTO_REJ,
- ++sp->pp_seq, m->m_pkthdr.len + 2,
+ ++sp->pp_seq[IDX_LCP], m->m_pkthdr.len + 2,
&h->protocol);
++ifp->if_noproto;
goto drop;
@@ -530,6 +577,20 @@ sppp_input(struct ifnet *ifp, struct mbuf *m)
}
break;
#endif
+#ifdef INET6
+ case PPP_IPV6CP:
+ if (sp->pp_phase == PHASE_NETWORK)
+ sppp_cp_input(&ipv6cp, sp, m);
+ m_freem (m);
+ return;
+
+ case PPP_IPV6:
+ if (sp->state[IDX_IPV6CP] == STATE_OPENED) {
+ schednetisr (NETISR_IPV6);
+ inq = &ip6intrq;
+ }
+ break;
+#endif
#ifdef IPX
case PPP_IPX:
/* IPX IPXCP not implemented yet */
@@ -628,7 +689,7 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
{
struct sppp *sp = (struct sppp*) ifp;
struct ppp_header *h;
- struct ifqueue *ifq;
+ struct ifqueue *ifq = NULL;
int s, rv = 0;
int debug = ifp->if_flags & IFF_DEBUG;
@@ -652,7 +713,6 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
s = splimp();
}
- ifq = &ifp->if_snd;
#ifdef INET
if (dst->sa_family == AF_INET) {
/* XXX Check mbuf length here? */
@@ -699,6 +759,12 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
}
#endif
+#ifdef INET6
+ if (dst->sa_family == AF_INET6) {
+ /* XXX do something tricky here? */
+ }
+#endif
+
/*
* Prepend general data packet PPP header. For now, IP only.
*/
@@ -750,7 +816,18 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
if (sp->pp_mode == IFF_CISCO)
h->protocol = htons (ETHERTYPE_IPV6);
else {
- goto nosupport;
+ /*
+ * Don't choke with an ENETDOWN early. It's
+ * possible that we just started dialing out,
+ * so don't drop the packet immediately. If
+ * we notice that we run out of buffer space
+ * below, we will however remember that we are
+ * not ready to carry IP packets, and return
+ * ENETDOWN, as opposed to ENOBUFS.
+ */
+ h->protocol = htons(PPP_IPV6);
+ if (sp->state[IDX_IPV6CP] != STATE_OPENED)
+ rv = ENETDOWN;
}
break;
#endif
@@ -812,8 +889,8 @@ sppp_attach(struct ifnet *ifp)
sp->pp_cpq.ifq_maxlen = 20;
sp->pp_loopcnt = 0;
sp->pp_alivecnt = 0;
- sp->pp_seq = 0;
- sp->pp_rseq = 0;
+ bzero(&sp->pp_seq[0], sizeof(sp->pp_seq));
+ bzero(&sp->pp_rseq[0], sizeof(sp->pp_rseq));
sp->pp_phase = PHASE_DEAD;
sp->pp_up = lcp.Up;
sp->pp_down = lcp.Down;
@@ -822,6 +899,7 @@ sppp_attach(struct ifnet *ifp)
sppp_lcp_init(sp);
sppp_ipcp_init(sp);
+ sppp_ipv6cp_init(sp);
sppp_pap_init(sp);
sppp_chap_init(sp);
}
@@ -1079,8 +1157,8 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m)
break;
case CISCO_KEEPALIVE_REQ:
sp->pp_alivecnt = 0;
- sp->pp_rseq = ntohl (h->par1);
- if (sp->pp_seq == sp->pp_rseq) {
+ sp->pp_rseq[IDX_LCP] = ntohl (h->par1);
+ if (sp->pp_seq[IDX_LCP] == sp->pp_rseq[IDX_LCP]) {
/* Local and remote sequence numbers are equal.
* Probably, the line is in loopback mode. */
if (sp->pp_loopcnt >= MAXALIVECNT) {
@@ -1096,9 +1174,9 @@ sppp_cisco_input(struct sppp *sp, struct mbuf *m)
/* Generate new local sequence number */
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
- sp->pp_seq = random();
+ sp->pp_seq[IDX_LCP] = random();
#else
- sp->pp_seq ^= time.tv_sec ^ time.tv_usec;
+ sp->pp_seq[IDX_LCP] ^= time.tv_sec ^ time.tv_usec;
#endif
break;
}
@@ -1574,8 +1652,8 @@ sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m)
if (debug)
log(-1, SPP_FMT "%s send code-rej for 0x%x\n",
SPP_ARGS(ifp), cp->name, h->type);
- sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq,
- m->m_pkthdr.len, h);
+ sppp_cp_send(sp, cp->proto, CODE_REJ,
+ ++sp->pp_seq[cp->protoidx], m->m_pkthdr.len, h);
++ifp->if_ierrors;
}
}
@@ -1730,7 +1808,8 @@ sppp_close_event(const struct cp *cp, struct sppp *sp)
case STATE_ACK_RCVD:
case STATE_ACK_SENT:
sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate;
- sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0);
+ sppp_cp_send(sp, cp->proto, TERM_REQ,
+ ++sp->pp_seq[cp->protoidx], 0, 0);
sppp_cp_change_state(cp, sp, STATE_CLOSING);
break;
}
@@ -1772,8 +1851,8 @@ sppp_to_event(const struct cp *cp, struct sppp *sp)
switch (sp->state[cp->protoidx]) {
case STATE_CLOSING:
case STATE_STOPPING:
- sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq,
- 0, 0);
+ sppp_cp_send(sp, cp->proto, TERM_REQ,
+ ++sp->pp_seq[cp->protoidx], 0, 0);
TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout,
sp->ch[cp->protoidx]);
break;
@@ -1835,6 +1914,8 @@ sppp_lcp_init(struct sppp *sp)
sp->lcp.magic = 0;
sp->state[IDX_LCP] = STATE_INITIAL;
sp->fail_counter[IDX_LCP] = 0;
+ sp->pp_seq[IDX_LCP] = 0;
+ sp->pp_rseq[IDX_LCP] = 0;
sp->lcp.protos = 0;
sp->lcp.mru = sp->lcp.their_mru = PP_MTU;
@@ -2468,7 +2549,7 @@ sppp_lcp_scr(struct sppp *sp)
opt[i++] = CHAP_MD5;
}
- sp->confid[IDX_LCP] = ++sp->pp_seq;
+ sp->confid[IDX_LCP] = ++sp->pp_seq[IDX_LCP];
sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt);
}
@@ -2519,6 +2600,8 @@ sppp_ipcp_init(struct sppp *sp)
sp->ipcp.flags = 0;
sp->state[IDX_IPCP] = STATE_INITIAL;
sp->fail_counter[IDX_IPCP] = 0;
+ sp->pp_seq[IDX_IPCP] = 0;
+ sp->pp_rseq[IDX_IPCP] = 0;
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
callout_handle_init(&sp->ch[IDX_IPCP]);
#endif
@@ -2894,13 +2977,516 @@ sppp_ipcp_scr(struct sppp *sp)
opt[i++] = ouraddr;
}
- sp->confid[IDX_IPCP] = ++sp->pp_seq;
+ sp->confid[IDX_IPCP] = ++sp->pp_seq[IDX_IPCP];
sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt);
}
/*
*--------------------------------------------------------------------------*
* *
+ * The IPv6CP implementation. *
+ * *
+ *--------------------------------------------------------------------------*
+ */
+
+#ifdef INET6
+static void
+sppp_ipv6cp_init(struct sppp *sp)
+{
+ sp->ipv6cp.opts = 0;
+ sp->ipv6cp.flags = 0;
+ sp->state[IDX_IPV6CP] = STATE_INITIAL;
+ sp->fail_counter[IDX_IPV6CP] = 0;
+ sp->pp_seq[IDX_IPV6CP] = 0;
+ sp->pp_rseq[IDX_IPV6CP] = 0;
+#if defined(__NetBSD__)
+ callout_init(&sp->ch[IDX_IPV6CP]);
+#endif
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+ callout_handle_init(&sp->ch[IDX_IPV6CP]);
+#endif
+}
+
+static void
+sppp_ipv6cp_up(struct sppp *sp)
+{
+ sppp_up_event(&ipv6cp, sp);
+}
+
+static void
+sppp_ipv6cp_down(struct sppp *sp)
+{
+ sppp_down_event(&ipv6cp, sp);
+}
+
+static void
+sppp_ipv6cp_open(struct sppp *sp)
+{
+ STDDCL;
+ struct in6_addr myaddr, hisaddr;
+
+#ifdef IPV6CP_MYIFID_DYN
+ sp->ipv6cp.flags &= ~(IPV6CP_MYIFID_SEEN|IPV6CP_MYIFID_DYN);
+#else
+ sp->ipv6cp.flags &= ~IPV6CP_MYIFID_SEEN;
+#endif
+
+ sppp_get_ip6_addrs(sp, &myaddr, &hisaddr, 0);
+ /*
+ * If we don't have our address, this probably means our
+ * interface doesn't want to talk IPv6 at all. (This could
+ * be the case if somebody wants to speak only IPX, for
+ * example.) Don't open IPv6CP in this case.
+ */
+ if (IN6_IS_ADDR_UNSPECIFIED(&myaddr)) {
+ /* XXX this message should go away */
+ if (debug)
+ log(LOG_DEBUG, SPP_FMT "ipv6cp_open(): no IPv6 interface\n",
+ SPP_ARGS(ifp));
+ return;
+ }
+
+ sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN;
+ sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID);
+ sppp_open_event(&ipv6cp, sp);
+}
+
+static void
+sppp_ipv6cp_close(struct sppp *sp)
+{
+ sppp_close_event(&ipv6cp, sp);
+}
+
+static void
+sppp_ipv6cp_TO(void *cookie)
+{
+ sppp_to_event(&ipv6cp, (struct sppp *)cookie);
+}
+
+/*
+ * Analyze a configure request. Return true if it was agreeable, and
+ * caused action sca, false if it has been rejected or nak'ed, and
+ * caused action scn. (The return value is used to make the state
+ * transition decision in the state automaton.)
+ */
+static int
+sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len)
+{
+ u_char *buf, *r, *p;
+ struct ifnet *ifp = &sp->pp_if;
+ int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
+ struct in6_addr myaddr, desiredaddr, suggestaddr;
+ int ifidcount;
+ int type;
+ int collision, nohisaddr;
+
+ len -= 4;
+ origlen = len;
+ /*
+ * Make sure to allocate a buf that can at least hold a
+ * conf-nak with an `address' option. We might need it below.
+ */
+ buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
+ if (! buf)
+ return (0);
+
+ /* pass 1: see if we can recognize them */
+ if (debug)
+ log(LOG_DEBUG, SPP_FMT "ipv6cp parse opts:",
+ SPP_ARGS(ifp));
+ p = (void*) (h+1);
+ ifidcount = 0;
+ for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+ if (debug)
+ addlog(" %s", sppp_ipv6cp_opt_name(*p));
+ switch (*p) {
+ case IPV6CP_OPT_IFID:
+ if (len >= 10 && p[1] == 10 && ifidcount == 0) {
+ /* correctly formed address option */
+ ifidcount++;
+ continue;
+ }
+ if (debug)
+ addlog(" [invalid]");
+ break;
+#ifdef notyet
+ case IPV6CP_OPT_COMPRESSION:
+ if (len >= 4 && p[1] >= 4) {
+ /* correctly formed compress option */
+ continue;
+ }
+ if (debug)
+ addlog(" [invalid]");
+ break;
+#endif
+ default:
+ /* Others not supported. */
+ if (debug)
+ addlog(" [rej]");
+ break;
+ }
+ /* Add the option to rejected list. */
+ bcopy (p, r, p[1]);
+ r += p[1];
+ rlen += p[1];
+ }
+ if (rlen) {
+ if (debug)
+ addlog(" send conf-rej\n");
+ sppp_cp_send (sp, PPP_IPV6CP, CONF_REJ, h->ident, rlen, buf);
+ goto end;
+ } else if (debug)
+ addlog("\n");
+
+ /* pass 2: parse option values */
+ sppp_get_ip6_addrs(sp, &myaddr, 0, 0);
+ if (debug)
+ log(LOG_DEBUG, SPP_FMT "ipv6cp parse opt values: ",
+ SPP_ARGS(ifp));
+ p = (void*) (h+1);
+ len = origlen;
+ type = CONF_ACK;
+ for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+ if (debug)
+ addlog(" %s", sppp_ipv6cp_opt_name(*p));
+ switch (*p) {
+#ifdef notyet
+ case IPV6CP_OPT_COMPRESSION:
+ continue;
+#endif
+ case IPV6CP_OPT_IFID:
+ bzero(&desiredaddr, sizeof(desiredaddr));
+ bcopy(&p[2], &desiredaddr.s6_addr[8], 8);
+ collision = (bcmp(&desiredaddr.s6_addr[8],
+ &myaddr.s6_addr[8], 8) == 0);
+ nohisaddr = IN6_IS_ADDR_UNSPECIFIED(&desiredaddr);
+
+ desiredaddr.s6_addr16[0] = htons(0xfe80);
+ desiredaddr.s6_addr16[1] = htons(sp->pp_if.if_index);
+
+ if (!collision && !nohisaddr) {
+ /* no collision, hisaddr known - Conf-Ack */
+ type = CONF_ACK;
+
+ if (debug) {
+ addlog(" %s [%s]",
+ ip6_sprintf(&desiredaddr),
+ sppp_cp_type_name(type));
+ }
+ continue;
+ }
+
+ bzero(&suggestaddr, sizeof(&suggestaddr));
+ if (collision && nohisaddr) {
+ /* collision, hisaddr unknown - Conf-Rej */
+ type = CONF_REJ;
+ bzero(&p[2], 8);
+ } else {
+ /*
+ * - no collision, hisaddr unknown, or
+ * - collision, hisaddr known
+ * Conf-Nak, suggest hisaddr
+ */
+ type = CONF_NAK;
+ sppp_suggest_ip6_addr(sp, &suggestaddr);
+ bcopy(&suggestaddr.s6_addr[8], &p[2], 8);
+ }
+ if (debug)
+ addlog(" %s [%s]", ip6_sprintf(&desiredaddr),
+ sppp_cp_type_name(type));
+ break;
+ }
+ /* Add the option to nak'ed list. */
+ bcopy (p, r, p[1]);
+ r += p[1];
+ rlen += p[1];
+ }
+
+ if (rlen == 0 && type == CONF_ACK) {
+ if (debug)
+ addlog(" send %s\n", sppp_cp_type_name(type));
+ sppp_cp_send (sp, PPP_IPV6CP, type, h->ident, origlen, h+1);
+ } else {
+#ifdef DIAGNOSTIC
+ if (type == CONF_ACK)
+ panic("IPv6CP RCR: CONF_ACK with non-zero rlen");
+#endif
+
+ if (debug) {
+ addlog(" send %s suggest %s\n",
+ sppp_cp_type_name(type), ip6_sprintf(&suggestaddr));
+ }
+ sppp_cp_send (sp, PPP_IPV6CP, type, h->ident, rlen, buf);
+ }
+
+ end:
+ free (buf, M_TEMP);
+ return (rlen == 0);
+}
+
+/*
+ * Analyze the IPv6CP Configure-Reject option list, and adjust our
+ * negotiation.
+ */
+static void
+sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
+{
+ u_char *buf, *p;
+ struct ifnet *ifp = &sp->pp_if;
+ int debug = ifp->if_flags & IFF_DEBUG;
+
+ len -= 4;
+ buf = malloc (len, M_TEMP, M_NOWAIT);
+ if (!buf)
+ return;
+
+ if (debug)
+ log(LOG_DEBUG, SPP_FMT "ipv6cp rej opts:",
+ SPP_ARGS(ifp));
+
+ p = (void*) (h+1);
+ for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
+ if (debug)
+ addlog(" %s", sppp_ipv6cp_opt_name(*p));
+ switch (*p) {
+ case IPV6CP_OPT_IFID:
+ /*
+ * Peer doesn't grok address option. This is
+ * bad. XXX Should we better give up here?
+ */
+ sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_IFID);
+ break;
+#ifdef notyet
+ case IPV6CP_OPT_COMPRESS:
+ sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_COMPRESS);
+ break;
+#endif
+ }
+ }
+ if (debug)
+ addlog("\n");
+ free (buf, M_TEMP);
+ return;
+}
+
+/*
+ * Analyze the IPv6CP Configure-NAK option list, and adjust our
+ * negotiation.
+ */
+static void
+sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
+{
+ u_char *buf, *p;
+ struct ifnet *ifp = &sp->pp_if;
+ int debug = ifp->if_flags & IFF_DEBUG;
+ struct in6_addr suggestaddr;
+
+ len -= 4;
+ buf = malloc (len, M_TEMP, M_NOWAIT);
+ if (!buf)
+ return;
+
+ if (debug)
+ log(LOG_DEBUG, SPP_FMT "ipv6cp nak opts:",
+ SPP_ARGS(ifp));
+
+ p = (void*) (h+1);
+ for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
+ if (debug)
+ addlog(" %s", sppp_ipv6cp_opt_name(*p));
+ switch (*p) {
+ case IPV6CP_OPT_IFID:
+ /*
+ * Peer doesn't like our local ifid. See
+ * if we can do something for him. We'll drop
+ * him our address then.
+ */
+ if (len < 10 || p[1] != 10)
+ break;
+ bzero(&suggestaddr, sizeof(suggestaddr));
+ suggestaddr.s6_addr16[0] = htons(0xfe80);
+ suggestaddr.s6_addr16[1] = htons(sp->pp_if.if_index);
+ bcopy(&p[2], &suggestaddr.s6_addr[8], 8);
+
+ sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID);
+ if (debug)
+ addlog(" [suggestaddr %s]",
+ ip6_sprintf(&suggestaddr));
+#ifdef IPV6CP_MYIFID_DYN
+ /*
+ * When doing dynamic address assignment,
+ * we accept his offer.
+ */
+ if (sp->ipv6cp.flags & IPV6CP_MYIFID_DYN) {
+ struct in6_addr lastsuggest;
+ /*
+ * If <suggested myaddr from peer> equals to
+ * <hisaddr we have suggested last time>,
+ * we have a collision. generate new random
+ * ifid.
+ */
+ sppp_suggest_ip6_addr(&lastsuggest);
+ if (IN6_ARE_ADDR_EQUAL(&suggestaddr,
+ lastsuggest)) {
+ if (debug)
+ addlog(" [random]");
+ sppp_gen_ip6_addr(sp, &suggestaddr);
+ }
+ sppp_set_ip6_addr(sp, &suggestaddr, 0);
+ if (debug)
+ addlog(" [agree]");
+ sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN;
+ }
+#else
+ /*
+ * Since we do not do dynamic address assignment,
+ * we ignore it and thus continue to negotiate
+ * our already existing value. This can possibly
+ * go into infinite request-reject loop.
+ *
+ * This is not likely because we normally use
+ * ifid based on MAC-address.
+ * If you have no ethernet card on the node, too bad.
+ * XXX should we use fail_counter?
+ */
+#endif
+ break;
+#ifdef notyet
+ case IPV6CP_OPT_COMPRESS:
+ /*
+ * Peer wants different compression parameters.
+ */
+ break;
+#endif
+ }
+ }
+ if (debug)
+ addlog("\n");
+ free (buf, M_TEMP);
+ return;
+}
+static void
+sppp_ipv6cp_tlu(struct sppp *sp)
+{
+ /* we are up - notify isdn daemon */
+ if (sp->pp_con)
+ sp->pp_con(sp);
+}
+
+static void
+sppp_ipv6cp_tld(struct sppp *sp)
+{
+}
+
+static void
+sppp_ipv6cp_tls(struct sppp *sp)
+{
+ /* indicate to LCP that it must stay alive */
+ sp->lcp.protos |= (1 << IDX_IPV6CP);
+}
+
+static void
+sppp_ipv6cp_tlf(struct sppp *sp)
+{
+
+#if 0 /* need #if 0 to close IPv6CP properly */
+ /* we no longer need LCP */
+ sp->lcp.protos &= ~(1 << IDX_IPV6CP);
+ sppp_lcp_check_and_close(sp);
+#endif
+}
+
+static void
+sppp_ipv6cp_scr(struct sppp *sp)
+{
+ char opt[10 /* ifid */ + 4 /* compression, minimum */];
+ struct in6_addr ouraddr;
+ int i = 0;
+
+ if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_IFID)) {
+ sppp_get_ip6_addrs(sp, &ouraddr, 0, 0);
+ opt[i++] = IPV6CP_OPT_IFID;
+ opt[i++] = 10;
+ bcopy(&ouraddr.s6_addr[8], &opt[i], 8);
+ i += 8;
+ }
+
+#ifdef notyet
+ if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_COMPRESSION)) {
+ opt[i++] = IPV6CP_OPT_COMPRESSION;
+ opt[i++] = 4;
+ opt[i++] = 0; /* TBD */
+ opt[i++] = 0; /* TBD */
+ /* variable length data may follow */
+ }
+#endif
+
+ sp->confid[IDX_IPV6CP] = ++sp->pp_seq[IDX_IPV6CP];
+ sppp_cp_send(sp, PPP_IPV6CP, CONF_REQ, sp->confid[IDX_IPV6CP], i, &opt);
+}
+#else /*INET6*/
+static void sppp_ipv6cp_init(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_up(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_down(struct sppp *sp)
+{
+}
+
+
+static void sppp_ipv6cp_open(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_close(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_TO(void *sp)
+{
+}
+
+static int sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len)
+{
+ return 0;
+}
+
+static void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
+{
+}
+
+static void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
+{
+}
+
+static void sppp_ipv6cp_tlu(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_tld(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_tls(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_tlf(struct sppp *sp)
+{
+}
+
+static void sppp_ipv6cp_scr(struct sppp *sp)
+{
+}
+#endif /*INET6*/
+
+/*
+ *--------------------------------------------------------------------------*
+ * *
* The CHAP implementation. *
* *
*--------------------------------------------------------------------------*
@@ -3213,6 +3799,8 @@ sppp_chap_init(struct sppp *sp)
/* Chap doesn't have STATE_INITIAL at all. */
sp->state[IDX_CHAP] = STATE_CLOSED;
sp->fail_counter[IDX_CHAP] = 0;
+ sp->pp_seq[IDX_CHAP] = 0;
+ sp->pp_rseq[IDX_CHAP] = 0;
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
callout_handle_init(&sp->ch[IDX_CHAP]);
#endif
@@ -3371,7 +3959,7 @@ sppp_chap_scr(struct sppp *sp)
ch[3] = seed ^ random();
clen = AUTHKEYLEN;
- sp->confid[IDX_CHAP] = ++sp->pp_seq;
+ sp->confid[IDX_CHAP] = ++sp->pp_seq[IDX_CHAP];
sppp_auth_send(&chap, sp, CHAP_CHALLENGE, sp->confid[IDX_CHAP],
sizeof clen, (const char *)&clen,
@@ -3544,6 +4132,8 @@ sppp_pap_init(struct sppp *sp)
/* PAP doesn't have STATE_INITIAL at all. */
sp->state[IDX_PAP] = STATE_CLOSED;
sp->fail_counter[IDX_PAP] = 0;
+ sp->pp_seq[IDX_PAP] = 0;
+ sp->pp_rseq[IDX_PAP] = 0;
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
callout_handle_init(&sp->ch[IDX_PAP]);
callout_handle_init(&sp->pap_my_to_ch);
@@ -3678,7 +4268,7 @@ sppp_pap_scr(struct sppp *sp)
{
u_char idlen, pwdlen;
- sp->confid[IDX_PAP] = ++sp->pp_seq;
+ sp->confid[IDX_PAP] = ++sp->pp_seq[IDX_PAP];
pwdlen = sppp_strnlen(sp->myauth.secret, AUTHKEYLEN);
idlen = sppp_strnlen(sp->myauth.name, AUTHNAMELEN);
@@ -3824,11 +4414,11 @@ sppp_keepalive(void *dummy)
if (sp->pp_alivecnt <= MAXALIVECNT)
++sp->pp_alivecnt;
if (sp->pp_mode == IFF_CISCO)
- sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
- sp->pp_rseq);
+ sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ,
+ ++sp->pp_seq[IDX_LCP], sp->pp_rseq[IDX_LCP]);
else if (sp->pp_phase >= PHASE_AUTHENTICATE) {
long nmagic = htonl (sp->lcp.magic);
- sp->lcp.echoid = ++sp->pp_seq;
+ sp->lcp.echoid = ++sp->pp_seq[IDX_LCP];
sppp_cp_send (sp, PPP_LCP, ECHO_REQ,
sp->lcp.echoid, 4, &nmagic);
}
@@ -3957,8 +4547,154 @@ sppp_set_ip_addr(struct sppp *sp, u_long src)
}
#endif
}
+}
+
+#ifdef INET6
+/*
+ * Get both IPv6 addresses.
+ */
+static void
+sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src, struct in6_addr *dst,
+ struct in6_addr *srcmask)
+{
+ struct ifnet *ifp = &sp->pp_if;
+ struct ifaddr *ifa;
+ struct sockaddr_in6 *si, *sm;
+ struct in6_addr ssrc, ddst;
+
+ sm = NULL;
+ bzero(&ssrc, sizeof(ssrc));
+ bzero(&ddst, sizeof(ddst));
+ /*
+ * Pick the first link-local AF_INET6 address from the list,
+ * aliases don't make any sense on a p2p link anyway.
+ */
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+ for (ifa = ifp->if_addrhead.tqh_first, si = 0;
+ ifa;
+ ifa = ifa->ifa_link.tqe_next)
+#elif defined(__NetBSD__) || defined (__OpenBSD__)
+ for (ifa = ifp->if_addrlist.tqh_first, si = 0;
+ ifa;
+ ifa = ifa->ifa_list.tqe_next)
+#else
+ for (ifa = ifp->if_addrlist, si = 0;
+ ifa;
+ ifa = ifa->ifa_next)
+#endif
+ if (ifa->ifa_addr->sa_family == AF_INET6) {
+ si = (struct sockaddr_in6 *)ifa->ifa_addr;
+ sm = (struct sockaddr_in6 *)ifa->ifa_netmask;
+ if (si && IN6_IS_ADDR_LINKLOCAL(&si->sin6_addr))
+ break;
+ }
+ if (ifa) {
+ if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr)) {
+ bcopy(&si->sin6_addr, &ssrc, sizeof(ssrc));
+ if (srcmask) {
+ bcopy(&sm->sin6_addr, srcmask,
+ sizeof(*srcmask));
+ }
+ }
+
+ si = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
+ if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr))
+ bcopy(&si->sin6_addr, &ddst, sizeof(ddst));
+ }
+
+ if (dst)
+ bcopy(&ddst, dst, sizeof(*dst));
+ if (src)
+ bcopy(&ssrc, src, sizeof(*src));
}
+#ifdef IPV6CP_MYIFID_DYN
+/*
+ * Generate random ifid.
+ */
+static void
+sppp_gen_ip6_addr(struct sppp *sp, struct in6_addr *addr)
+{
+ /* TBD */
+}
+
+/*
+ * Set my IPv6 address. Must be called at splimp.
+ */
+static void
+sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src)
+{
+ STDDCL;
+ struct ifaddr *ifa;
+ struct sockaddr_in6 *sin6;
+
+ /*
+ * Pick the first link-local AF_INET6 address from the list,
+ * aliases don't make any sense on a p2p link anyway.
+ */
+
+ sin6 = NULL;
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+ for (ifa = ifp->if_addrhead.tqh_first;
+ ifa;
+ ifa = ifa->ifa_link.tqe_next)
+#elif defined(__NetBSD__) || defined (__OpenBSD__)
+ for (ifa = ifp->if_addrlist.tqh_first;
+ ifa;
+ ifa = ifa->ifa_list.tqe_next)
+#else
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
+#endif
+ {
+ if (ifa->ifa_addr->sa_family == AF_INET6)
+ {
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (sin6 && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ break;
+ }
+ }
+
+ if (ifa && sin6)
+ {
+ int error;
+ struct sockaddr_in6 new_sin6 = *sin6;
+
+ bcopy(src, &new_sin6.sin6_addr, sizeof(new_sin6.sin6_addr));
+ error = in6_ifinit(ifp, ifatoia6(ifa), &new_sin6, 1);
+ if (debug && error)
+ {
+ log(LOG_DEBUG, SPP_FMT "sppp_set_ip6_addr: in6_ifinit "
+ " failed, error=%d\n", SPP_ARGS(ifp), error);
+ }
+ }
+}
+#endif
+
+/*
+ * Suggest a candidate address to be used by peer.
+ */
+static void
+sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *suggest)
+{
+ struct in6_addr myaddr;
+ struct timeval tv;
+
+ sppp_get_ip6_addrs(sp, &myaddr, 0, 0);
+
+ myaddr.s6_addr[8] &= ~0x02; /* u bit to "local" */
+ microtime(&tv);
+ if ((tv.tv_usec & 0xff) == 0 && (tv.tv_sec & 0xff) == 0) {
+ myaddr.s6_addr[14] ^= 0xff;
+ myaddr.s6_addr[15] ^= 0xff;
+ } else {
+ myaddr.s6_addr[14] ^= (tv.tv_usec & 0xff);
+ myaddr.s6_addr[15] ^= (tv.tv_sec & 0xff);
+ }
+ if (suggest)
+ bcopy(&myaddr, suggest, sizeof(myaddr));
+}
+#endif /*INET6*/
+
static int
sppp_params(struct sppp *sp, u_long cmd, void *data)
{
@@ -4165,6 +4901,20 @@ sppp_ipcp_opt_name(u_char opt)
return buf;
}
+#ifdef INET6
+static const char *
+sppp_ipv6cp_opt_name(u_char opt)
+{
+ static char buf[12];
+ switch (opt) {
+ case IPV6CP_OPT_IFID: return "ifid";
+ case IPV6CP_OPT_COMPRESSION: return "compression";
+ }
+ sprintf (buf, "0x%x", opt);
+ return buf;
+}
+#endif
+
static const char *
sppp_state_name(int state)
{
@@ -4205,6 +4955,7 @@ sppp_proto_name(u_short proto)
case PPP_IPCP: return "ipcp";
case PPP_PAP: return "pap";
case PPP_CHAP: return "chap";
+ case PPP_IPV6CP: return "ipv6cp";
}
snprintf(buf, sizeof(buf), "proto/0x%x", (unsigned)proto);
return buf;
diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c
index d6a6495..979e6c5 100644
--- a/sys/net/if_stf.c
+++ b/sys/net/if_stf.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: if_stf.c,v 1.42 2000/08/15 07:24:23 itojun Exp $ */
+/* $KAME: if_stf.c,v 1.60 2001/05/03 14:51:47 itojun Exp $ */
/*
* Copyright (C) 2000 WIDE Project.
@@ -31,7 +31,7 @@
*/
/*
- * 6to4 interface, based on draft-ietf-ngtrans-6to4-06.txt.
+ * 6to4 interface, based on RFC3056.
*
* 6to4 interface is NOT capable of link-layer (I mean, IPv4) multicasting.
* There is no address mapping defined from IPv6 multicast address to IPv4
@@ -60,12 +60,13 @@
* ICMPv6:
* - Redirects cannot be used due to the lack of link-local address.
*
- * Starting from 04 draft, the specification suggests how to construct
- * link-local address for 6to4 interface.
- * However, it seems to have no real use and does not help the above symptom
- * much. Even if we assign link-locals to interface, we cannot really
- * use link-local unicast/multicast on top of 6to4 cloud, and the above
- * analysis does not change.
+ * stf interface does not have, and will not need, a link-local address.
+ * It seems to have no real benefit and does not help the above symptoms much.
+ * Even if we assign link-locals to interface, we cannot really
+ * use link-local unicast/multicast on top of 6to4 cloud (since there's no
+ * encapsulation defined for link-local address), and the above analysis does
+ * not change. RFC3056 does not mandate the assignment of link-local address
+ * either.
*
* 6to4 interface has security issues. Refer to
* http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt
@@ -159,8 +160,10 @@ static int stf_encapcheck __P((const struct mbuf *, int, int, void *));
static struct in6_ifaddr *stf_getsrcifa6 __P((struct ifnet *));
static int stf_output __P((struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *));
-static int stf_checkaddr4 __P((struct in_addr *, struct ifnet *));
-static int stf_checkaddr6 __P((struct in6_addr *, struct ifnet *));
+static int stf_checkaddr4 __P((struct stf_softc *, struct in_addr *,
+ struct ifnet *));
+static int stf_checkaddr6 __P((struct stf_softc *, struct in6_addr *,
+ struct ifnet *));
static void stf_rtrequest __P((int, struct rtentry *, struct sockaddr *));
static int stf_ioctl __P((struct ifnet *, u_long, caddr_t));
@@ -197,6 +200,10 @@ stfattach(dummy)
sc->sc_if.if_ioctl = stf_ioctl;
sc->sc_if.if_output = stf_output;
sc->sc_if.if_type = IFT_STF;
+#if 0
+ /* turn off ingress filter */
+ sc->sc_if.if_flags |= IFF_LINK2;
+#endif
sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
if_attach(&sc->sc_if);
#if NBPFILTER > 0
@@ -230,6 +237,10 @@ stf_encapcheck(m, off, proto, arg)
if ((sc->sc_if.if_flags & IFF_UP) == 0)
return 0;
+ /* IFF_LINK0 means "no decapsulation" */
+ if ((sc->sc_if.if_flags & IFF_LINK0) != 0)
+ return 0;
+
if (proto != IPPROTO_IPV6)
return 0;
@@ -317,6 +328,7 @@ stf_output(ifp, m, dst, rt)
{
struct stf_softc *sc;
struct sockaddr_in6 *dst6;
+ struct in_addr *in4;
struct sockaddr_in *dst4;
u_int8_t tos;
struct ip *ip;
@@ -351,6 +363,19 @@ stf_output(ifp, m, dst, rt)
ip6 = mtod(m, struct ip6_hdr *);
tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
+ /*
+ * Pickup the right outer dst addr from the list of candidates.
+ * ip6_dst has priority as it may be able to give us shorter IPv4 hops.
+ */
+ if (IN6_IS_ADDR_6TO4(&ip6->ip6_dst))
+ in4 = GET_V4(&ip6->ip6_dst);
+ else if (IN6_IS_ADDR_6TO4(&dst6->sin6_addr))
+ in4 = GET_V4(&dst6->sin6_addr);
+ else {
+ m_freem(m);
+ return ENETUNREACH;
+ }
+
M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
if (m && m->m_len < sizeof(struct ip))
m = m_pullup(m, sizeof(struct ip));
@@ -362,12 +387,14 @@ stf_output(ifp, m, dst, rt)
bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr),
&ip->ip_src, sizeof(ip->ip_src));
- bcopy(GET_V4(&dst6->sin6_addr), &ip->ip_dst, sizeof(ip->ip_dst));
+ bcopy(in4, &ip->ip_dst, sizeof(ip->ip_dst));
ip->ip_p = IPPROTO_IPV6;
ip->ip_ttl = ip_gif_ttl; /*XXX*/
ip->ip_len = m->m_pkthdr.len; /*host order*/
if (ifp->if_flags & IFF_LINK1)
ip_ecn_ingress(ECN_ALLOWED, &ip->ip_tos, &tos);
+ else
+ ip_ecn_ingress(ECN_NOCARE, &ip->ip_tos, &tos);
dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst;
if (dst4->sin_family != AF_INET ||
@@ -394,9 +421,10 @@ stf_output(ifp, m, dst, rt)
}
static int
-stf_checkaddr4(in, ifp)
+stf_checkaddr4(sc, in, inifp)
+ struct stf_softc *sc;
struct in_addr *in;
- struct ifnet *ifp; /* incoming interface */
+ struct ifnet *inifp; /* incoming interface */
{
struct in_ifaddr *ia4;
@@ -427,7 +455,7 @@ stf_checkaddr4(in, ifp)
/*
* perform ingress filter
*/
- if (ifp) {
+ if (sc && (sc->sc_if.if_flags & IFF_LINK2) == 0 && inifp) {
struct sockaddr_in sin;
struct rtentry *rt;
@@ -436,10 +464,14 @@ stf_checkaddr4(in, ifp)
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_addr = *in;
rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
- if (!rt)
- return -1;
- if (rt->rt_ifp != ifp) {
- rtfree(rt);
+ if (!rt || rt->rt_ifp != inifp) {
+#if 0
+ log(LOG_WARNING, "%s: packet from 0x%x dropped "
+ "due to ingress filter\n", if_name(&sc->sc_if),
+ (u_int32_t)ntohl(sin.sin_addr.s_addr));
+#endif
+ if (rt)
+ rtfree(rt);
return -1;
}
rtfree(rt);
@@ -449,15 +481,16 @@ stf_checkaddr4(in, ifp)
}
static int
-stf_checkaddr6(in6, ifp)
+stf_checkaddr6(sc, in6, inifp)
+ struct stf_softc *sc;
struct in6_addr *in6;
- struct ifnet *ifp; /* incoming interface */
+ struct ifnet *inifp; /* incoming interface */
{
/*
* check 6to4 addresses
*/
if (IN6_IS_ADDR_6TO4(in6))
- return stf_checkaddr4(GET_V4(in6), ifp);
+ return stf_checkaddr4(sc, GET_V4(in6), inifp);
/*
* reject anything that look suspicious. the test is implemented
@@ -476,7 +509,7 @@ void
in_stf_input(struct mbuf *m, ...)
#else
in_stf_input(m, va_alist)
- register struct mbuf *m;
+ struct mbuf *m;
#endif
{
int off, proto;
@@ -514,8 +547,8 @@ in_stf_input(m, va_alist)
* perform sanity check against outer src/dst.
* for source, perform ingress filter as well.
*/
- if (stf_checkaddr4(&ip->ip_dst, NULL) < 0 ||
- stf_checkaddr4(&ip->ip_src, m->m_pkthdr.rcvif) < 0) {
+ if (stf_checkaddr4(sc, &ip->ip_dst, NULL) < 0 ||
+ stf_checkaddr4(sc, &ip->ip_src, m->m_pkthdr.rcvif) < 0) {
m_freem(m);
return;
}
@@ -534,8 +567,8 @@ in_stf_input(m, va_alist)
* perform sanity check against inner src/dst.
* for source, perform ingress filter as well.
*/
- if (stf_checkaddr6(&ip6->ip6_dst, NULL) < 0 ||
- stf_checkaddr6(&ip6->ip6_src, m->m_pkthdr.rcvif) < 0) {
+ if (stf_checkaddr6(sc, &ip6->ip6_dst, NULL) < 0 ||
+ stf_checkaddr6(sc, &ip6->ip6_src, m->m_pkthdr.rcvif) < 0) {
m_freem(m);
return;
}
@@ -543,6 +576,8 @@ in_stf_input(m, va_alist)
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
if ((ifp->if_flags & IFF_LINK1) != 0)
ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
+ else
+ ip_ecn_egress(ECN_NOCARE, &otos, &itos);
ip6->ip6_flow &= ~htonl(0xff << 20);
ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
@@ -558,7 +593,7 @@ in_stf_input(m, va_alist)
* try to free it or keep a pointer a to it).
*/
struct mbuf m0;
- u_int af = AF_INET6;
+ u_int32_t af = AF_INET6;
m0.m_next = m;
m0.m_len = 4;
@@ -594,11 +629,7 @@ static void
stf_rtrequest(cmd, rt, sa)
int cmd;
struct rtentry *rt;
-#if defined(__bsdi__) && _BSDI_VERSION >= 199802
- struct rt_addrinfo *sa;
-#else
struct sockaddr *sa;
-#endif
{
if (rt)
diff --git a/sys/net/net_osdep.c b/sys/net/net_osdep.c
index 02000f6..ef3bb01 100644
--- a/sys/net/net_osdep.c
+++ b/sys/net/net_osdep.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: net_osdep.c,v 1.4 2000/03/25 07:23:34 sumikawa Exp $ */
+/* $KAME: net_osdep.c,v 1.9 2001/04/06 09:22:05 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -32,6 +32,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
@@ -52,8 +53,15 @@ const char *
if_name(ifp)
struct ifnet *ifp;
{
- static char nam[IFNAMSIZ + 10]; /*enough?*/
+#define MAXNUMBUF 8
+ static char nam[MAXNUMBUF][IFNAMSIZ + 10]; /*enough?*/
+ static int ifbufround = 0;
+ char *cp;
- snprintf(nam, sizeof(nam), "%s%d", ifp->if_name, ifp->if_unit);
- return nam;
+ ifbufround = (ifbufround + 1) % MAXNUMBUF;
+ cp = nam[ifbufround];
+
+ snprintf(cp, sizeof(nam), "%s%d", ifp->if_name, ifp->if_unit);
+ return((const char *)cp);
+#undef MAXNUMBUF
}
diff --git a/sys/net/net_osdep.h b/sys/net/net_osdep.h
index 3bb3c18..399dd31 100644
--- a/sys/net/net_osdep.h
+++ b/sys/net/net_osdep.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: net_osdep.h,v 1.22 2000/08/15 07:23:10 itojun Exp $ */
+/* $KAME: net_osdep.h,v 1.44 2001/05/16 03:13:40 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -36,16 +36,40 @@
/*
* OS dependencies:
*
+ * - whether the IPv4 input routine convert the byte order of some fileds
+ * of the IP header (x: convert to the host byte order, s: strip the header
+ * length for possible reassembly)
+ * ip_len ip_id ip_off
+ * bsdi3: xs x x
+ * bsdi4: xs x
+ * FreeBSD: xs x
+ * NetBSD: x x
+ * OpenBSD: xs x x
+ *
+ * - ifa_ifwithaf()
+ * bsdi[34], netbsd, and openbsd define it in sys/net/if.c
+ * freebsd (all versions) does not have it.
+ *
* - struct rt_addrinfo
- * all *BSDs except bsdi4 only have two members; rti_addrs and rti_info[].
- * bsdi4 has additional members; rti_flags, rti_ifa, rti_ifp, and rti_rtm.
+ * bsdi4, netbsd 1.5R and beyond: rti_addrs, rti_info[], rti_flags, rti_ifa,
+ * rti_ifp, and rti_rtm.
+ * others: rti_addrs and rti_info[] only.
+ *
+ * - ifa->ifa_rtrequest
+ * bsdi4, netbsd 1.5R and beyond: rt_addrinfo *
+ * others: sockaddr * (note that sys/net/route.c:rtrequest() has an unsafe
+ * typecast code, from 4.3BSD-reno)
*
- * - side effects of rtrequest[1](RTM_DELETE)
+ * - side effects of rtrequest{,1}(RTM_DELETE)
* BSDI[34]: delete all cloned routes underneath the route.
* FreeBSD[234]: delete all protocol-cloned routes underneath the route.
* note that cloned routes from an interface direct route
* still remain.
- * NetBSD, OpenBSD: no side effects.
+ * NetBSD: 1.5 have no side effects. KAME/netbsd15, and post-1.5R, have
+ * the same effects as of BSDI.
+ * OpenBSD: have no side effects. KAME/openbsd has the same effects as
+ * of BSDI (the change is not merged - yet).
+ *
* - privileged process
* NetBSD, FreeBSD 3
* struct proc *p;
@@ -64,11 +88,13 @@
* needs to give struct proc * as argument
* OpenBSD, BSDI [34], FreeBSD 2
* do not need struct proc *
+ *
* - bpf:
- * OpenBSD, NetBSD, BSDI [34]
+ * OpenBSD, NetBSD 1.5, BSDI [34]
* need caddr_t * (= if_bpf **) and struct ifnet *
- * FreeBSD 2, FreeBSD 3
+ * FreeBSD 2, FreeBSD 3, NetBSD post-1.5N
* need only struct ifnet * as argument
+ *
* - struct ifnet
* use queue.h? member names if name
* --- --- ---
@@ -77,34 +103,57 @@
* OpenBSD yes standard if_xname
* NetBSD yes standard if_xname
* BSDI [34] no old standard if_name+unit
+ *
* - usrreq
* NetBSD, OpenBSD, BSDI [34], FreeBSD 2
* single function with PRU_xx, arguments are mbuf
* FreeBSD 3
* separates functions, non-mbuf arguments
+ *
* - {set,get}sockopt
* NetBSD, OpenBSD, BSDI [34], FreeBSD 2
* manipulation based on mbuf
* FreeBSD 3
* non-mbuf manipulation using sooptcopy{in,out}()
+ *
* - timeout() and untimeout()
- * NetBSD, OpenBSD, BSDI [34], FreeBSD 2
+ * NetBSD 1.4.x, OpenBSD, BSDI [34], FreeBSD 2
* timeout() is a void function
* FreeBSD 3
* timeout() is non-void, must keep returned value for untimeout()
+ * callout_xx is also available (sys/callout.h)
+ * NetBSD 1.5
+ * timeout() is obsoleted, use callout_xx (sys/callout.h)
+ * OpenBSD 2.8
+ * timeout_{add,set,del} is encouraged (sys/timeout.h)
+ *
* - sysctl
* NetBSD, OpenBSD
* foo_sysctl()
* BSDI [34]
- * foo_sysctl() but with different style
- * FreeBSD 2, FreeBSD 3
- * linker hack
+ * foo_sysctl() but with different style. sysctl_int_arr() takes
+ * care of most of the cases.
+ * FreeBSD
+ * linker hack. however, there are freebsd version differences
+ * (how wonderful!).
+ * on FreeBSD[23] function arg #define includes paren.
+ * int foo SYSCTL_HANDLER_ARGS;
+ * on FreeBSD4, function arg #define does not include paren.
+ * int foo(SYSCTL_HANDLER_ARGS);
+ * on some versions, forward reference to the tree is okay.
+ * on some versions, you need SYSCTL_DECL(). you need things
+ * like this.
+ * #ifdef SYSCTL_DECL
+ * SYSCTL_DECL(net_inet_ip6);
+ * #endif
+ * it is hard to share functions between freebsd and non-freebsd.
*
* - if_ioctl
* NetBSD, FreeBSD 3, BSDI [34]
* 2nd argument is u_long cmd
* FreeBSD 2
* 2nd argument is int cmd
+ *
* - if attach routines
* NetBSD
* void xxattach(int);
@@ -115,6 +164,7 @@
* - ovbcopy()
* in NetBSD 1.4 or later, ovbcopy() is not supplied in the kernel.
* bcopy() is safe against overwrites.
+ *
* - splnet()
* NetBSD 1.4 or later requires splsoftnet().
* other operating systems use splnet().
@@ -125,7 +175,8 @@
* - struct ifnet for loopback interface
* BSDI3: struct ifnet loif;
* BSDI4: struct ifnet *loifp;
- * NetBSD, OpenBSD, FreeBSD2: struct ifnet loif[NLOOP];
+ * NetBSD, OpenBSD 2.8, FreeBSD2: struct ifnet loif[NLOOP];
+ * OpenBSD 2.9: struct ifnet *lo0ifp;
*
* odd thing is that many of them refers loif as ifnet *loif,
* not loif[NLOOP], from outside of if_loop.c.
@@ -145,6 +196,12 @@
* FreeBSD4: struct ipprotosw in netinet/ipprotosw.h
* others: struct protosw in sys/protosw.h
*
+ * - protosw in general.
+ * NetBSD 1.5 has extra member for ipfilter (netbsd-current dropped
+ * it so it will go away in 1.6).
+ * NetBSD 1.5 requires PR_LISTEN flag bit with protocols that permit
+ * listen/accept (like tcp).
+ *
* - header files with defopt (opt_xx.h)
* FreeBSD3: opt_{inet,ipsec,ip6fw,altq}.h
* FreeBSD4: opt_{inet,inet6,ipsec,ip6fw,altq}.h
@@ -154,6 +211,23 @@
* - IN_MULTICAST/IN_CLASS[A-D] macro.
* OpenBSD and NetBSD: net endian (kernel) or host endian (userland)
* others: always host endian
+ *
+ * - (m->m_flags & M_EXT) != 0 does *not* mean that the max data length of
+ * the mbuf == MCLBYTES.
+ *
+ * - sys/kern/uipc_mbuf.c:m_dup()
+ * freebsd[34]: copies the whole mbuf chain.
+ * netbsd: similar arg with m_copym().
+ * others: no m_dup().
+ *
+ * - ifa_refcnt (struct ifaddr) management (IFAREF/IFAFREE).
+ * NetBSD 1.5: always use IFAREF whenever reference gets added.
+ * always use IFAFREE whenever reference gets freed.
+ * IFAFREE frees ifaddr when ifa_refcnt reaches 0.
+ * others: do not increase refcnt for ifp->if_addrlist and in_ifaddr.
+ * use IFAFREE once when ifaddr is disconnected from
+ * ifp->if_addrlist and in_ifaddr. IFAFREE frees ifaddr when
+ * ifa_refcnt goes negative.
*/
#ifndef __NET_NET_OSDEP_H_DEFINED_
@@ -165,6 +239,19 @@ extern const char *if_name __P((struct ifnet *));
#define HAVE_OLD_BPF
+#define ifa_list ifa_link
+#define if_addrlist if_addrhead
+#define if_list if_link
+
+/* sys/net/if.h */
+#define IFAREF(ifa) do { ++(ifa)->ifa_refcnt; } while (0)
+
+#define WITH_CONVERT_AND_STRIP_IP_LEN
+
+#if 1 /* at this moment, all OSes do this */
+#define WITH_CONVERT_IP_OFF
+#endif
+
/*
* Deprecated.
*/
diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h
index 4c41c80..f1c22ad 100644
--- a/sys/net/pfkeyv2.h
+++ b/sys/net/pfkeyv2.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: pfkeyv2.h,v 1.17 2000/06/22 08:38:33 sakane Exp $ */
+/* $KAME: pfkeyv2.h,v 1.25 2001/03/12 08:34:06 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -73,7 +73,7 @@ you leave this credit intact on any copies of this file.
#define SADB_X_SPDDUMP 18
#define SADB_X_SPDFLUSH 19
#define SADB_X_SPDSETIDX 20
-#define SADB_X_SPDEXPIRE 21 /* not yet */
+#define SADB_X_SPDEXPIRE 21
#define SADB_X_SPDDELETE2 22 /* by policy id */
#define SADB_MAX 22
@@ -298,22 +298,32 @@ struct sadb_x_ipsecrequest {
#define SADB_SAFLAGS_PFS 1
-#define SADB_AALG_NONE 0
-#define SADB_AALG_MD5HMAC 1 /* 2 */
-#define SADB_AALG_SHA1HMAC 2 /* 3 */
-#define SADB_AALG_MD5 3 /* Keyed MD5 */
-#define SADB_AALG_SHA 4 /* Keyed SHA */
-#define SADB_AALG_NULL 5 /* null authentication */
-#define SADB_AALG_MAX 6
-
-#define SADB_EALG_NONE 0
-#define SADB_EALG_DESCBC 1 /* 2 */
-#define SADB_EALG_3DESCBC 2 /* 3 */
-#define SADB_EALG_NULL 3 /* 11 */
-#define SADB_EALG_BLOWFISHCBC 4
-#define SADB_EALG_CAST128CBC 5
-#define SADB_EALG_RC5CBC 6
-#define SADB_EALG_MAX 7
+/* RFC2367 numbers - meets RFC2407 */
+#define SADB_AALG_NONE 0
+#define SADB_AALG_MD5HMAC 1 /*2*/
+#define SADB_AALG_SHA1HMAC 2 /*3*/
+#define SADB_AALG_MAX 8
+/* private allocations - based on RFC2407/IANA assignment */
+#define SADB_X_AALG_SHA2_256 6 /*5*/
+#define SADB_X_AALG_SHA2_384 7 /*6*/
+#define SADB_X_AALG_SHA2_512 8 /*7*/
+/* private allocations should use 249-255 (RFC2407) */
+#define SADB_X_AALG_MD5 3 /*249*/ /* Keyed MD5 */
+#define SADB_X_AALG_SHA 4 /*250*/ /* Keyed SHA */
+#define SADB_X_AALG_NULL 5 /*251*/ /* null authentication */
+
+/* RFC2367 numbers - meets RFC2407 */
+#define SADB_EALG_NONE 0
+#define SADB_EALG_DESCBC 1 /*2*/
+#define SADB_EALG_3DESCBC 2 /*3*/
+#define SADB_EALG_NULL 3 /*11*/
+#define SADB_EALG_MAX 12
+/* private allocations - based on RFC2407/IANA assignment */
+#define SADB_X_EALG_CAST128CBC 5 /*6*/
+#define SADB_X_EALG_BLOWFISHCBC 4 /*7*/
+#define SADB_X_EALG_RIJNDAELCBC 12
+#define SADB_X_EALG_AES 12
+/* private allocations should use 249-255 (RFC2407) */
#if 1 /*nonstandard */
#define SADB_X_CALG_NONE 0
diff --git a/sys/net/ppp_defs.h b/sys/net/ppp_defs.h
index ac86be2..be891ee 100644
--- a/sys/net/ppp_defs.h
+++ b/sys/net/ppp_defs.h
@@ -69,6 +69,8 @@
#define PPP_LQR 0xc025 /* Link Quality Report protocol */
#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
#define PPP_CBCP 0xc029 /* Callback Control Protocol */
+#define PPP_IPV6 0x57 /* Internet Protocol version 6*/
+#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */
/*
* Values for FCS calculations.
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index dc4ae26..6588f56 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -573,9 +573,6 @@ rt_msg1(type, rtinfo)
register struct sockaddr *sa;
int len, dlen;
- m = m_gethdr(M_DONTWAIT, MT_DATA);
- if (m == 0)
- return (m);
switch (type) {
case RTM_DELADDR:
@@ -595,8 +592,18 @@ rt_msg1(type, rtinfo)
default:
len = sizeof(struct rt_msghdr);
}
- if (len > MHLEN)
+ if (len > MCLBYTES)
panic("rt_msg1");
+ m = m_gethdr(M_DONTWAIT, MT_DATA);
+ if (m && len > MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_free(m);
+ m = NULL;
+ }
+ }
+ if (m == 0)
+ return (m);
m->m_pkthdr.len = m->m_len = len;
m->m_pkthdr.rcvif = 0;
rtm = mtod(m, struct rt_msghdr *);
OpenPOWER on IntegriCloud