summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/ifconfig/Makefile1
-rw-r--r--sbin/ifconfig/ifconfig.829
-rw-r--r--sbin/ifconfig/ifconfig.c314
-rw-r--r--sbin/route/Makefile2
-rw-r--r--sbin/route/keywords3
-rw-r--r--sbin/route/route.825
-rw-r--r--sbin/route/route.c150
-rw-r--r--sys/conf/NOTES9
-rw-r--r--sys/conf/files43
-rw-r--r--sys/conf/options2
-rw-r--r--sys/i386/conf/LINT9
-rw-r--r--sys/i386/conf/NOTES9
-rw-r--r--sys/modules/if_disc/Makefile5
-rw-r--r--sys/net/if.c2
-rw-r--r--sys/net/if_atmsubr.c3
-rw-r--r--sys/net/if_disc.c5
-rw-r--r--sys/net/if_ethersubr.c1
-rw-r--r--sys/net/if_faith.c97
-rw-r--r--sys/net/if_fddisubr.c24
-rw-r--r--sys/net/if_gif.c468
-rw-r--r--sys/net/if_gif.h3
-rw-r--r--sys/net/if_loop.c9
-rw-r--r--sys/net/if_spppsubr.c19
-rw-r--r--sys/netinet/if_atm.c3
-rw-r--r--sys/netinet/in_gif.c311
-rw-r--r--sys/netinet/in_gif.h42
-rw-r--r--sys/netinet/in_pcb.c114
-rw-r--r--sys/netinet/in_pcb.h3
-rw-r--r--sys/netinet/in_proto.c22
-rw-r--r--sys/netinet/ip_fw.c12
-rw-r--r--sys/netinet/tcp_input.c9
-rw-r--r--sys/netinet/tcp_reass.c9
-rw-r--r--sys/netinet/tcp_subr.c4
-rw-r--r--sys/netinet/tcp_timewait.c4
-rw-r--r--sys/netinet/tcp_usrreq.c6
-rw-r--r--sys/netinet/udp_usrreq.c232
-rw-r--r--sys/netinet/udp_var.h2
-rw-r--r--sys/netinet6/icmp6.c14
-rw-r--r--sys/netinet6/icmp6.h3
-rw-r--r--sys/netinet6/in6.c31
-rw-r--r--sys/netinet6/in6.h66
-rw-r--r--sys/netinet6/in6_gif.c263
-rw-r--r--sys/netinet6/in6_gif.h40
-rw-r--r--sys/netinet6/in6_ifattach.c10
-rw-r--r--sys/netinet6/in6_pcb.c13
-rw-r--r--sys/netinet6/in6_prefix.c21
-rw-r--r--sys/netinet6/in6_proto.c24
-rw-r--r--sys/netinet6/in6_var.h11
-rw-r--r--sys/netinet6/ip6_forward.c6
-rw-r--r--sys/netinet6/ip6_input.c10
-rw-r--r--sys/netinet6/ip6_output.c16
-rw-r--r--sys/netinet6/mld6.c2
-rw-r--r--sys/netinet6/nd6.c40
-rw-r--r--sys/netinet6/nd6.h4
-rw-r--r--sys/netinet6/nd6_nbr.c4
-rw-r--r--sys/netinet6/nd6_rtr.c40
-rw-r--r--sys/netinet6/raw_ip6.c6
-rw-r--r--sys/netinet6/udp6_usrreq.c835
-rw-r--r--sys/netinet6/udp6_var.h2
-rw-r--r--usr.bin/netstat/Makefile3
-rw-r--r--usr.bin/netstat/if.c88
-rw-r--r--usr.bin/netstat/inet.c248
-rw-r--r--usr.bin/netstat/inet6.c962
-rw-r--r--usr.bin/netstat/main.c200
-rw-r--r--usr.bin/netstat/netstat.148
-rw-r--r--usr.bin/netstat/netstat.h24
-rw-r--r--usr.bin/netstat/route.c183
67 files changed, 4785 insertions, 437 deletions
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
index b1fe95b..385946d 100644
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -7,6 +7,7 @@ SRCS= ifconfig.c
#comment out to exclude SIOC[GS]IFMEDIA support
SRCS+= ifmedia.c
CFLAGS+=-DUSE_IF_MEDIA
+#CFLAGS+=-DINET6
#comment out to exclude SIOC[GS]ETVLAN support
SRCS+= ifvlan.c
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index a2b399a..6defcd4 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -109,6 +109,7 @@ with different naming schemes, specifying the address family is recommended.
The address or protocol families currently
supported are
.Dq inet ,
+.Dq inet6 ,
.Dq atalk ,
.\" .Dq iso ,
and
@@ -135,6 +136,13 @@ This is sometimes useful when changing network numbers, and
one wishes to accept packets addressed to the old interface.
If the alias is on the same subnet as the first network adress
for this interface, a netmask of 0xffffffff has to be specified.
+.It Cm anycast
+(Inet6 only)
+Specify that the address configured is an anycast address.
+Based on the current specification,
+only routers may configure anycast addresses.
+Anycast address will not be used as source address of any of outgoing
+IPv6 packets.
.It Cm arp
Enable the use of the Address Resolution Protocol in mapping
between network level addresses and link level addresses (default).
@@ -279,6 +287,16 @@ and 0's for the host part.
The mask should contain at least the standard network portion,
and the subnet field should be contiguous with the network
portion.
+.It Cm prefixlen Ar len
+(Inet6 only)
+Specify that
+.Ar len
+bits are reserved for subdividing networks into sub-networks.
+The
+.Ar len
+must be integer, and for syntactical reason it must be between 0 to 128.
+It is almost always 64 under the current IPv6 assignment rule.
+If the parameter is ommitted, 64 is used.
.\" see
.\" Xr eon 5 .
.\" .It Cm nsellength Ar n
@@ -345,6 +363,11 @@ will report only the details specific to that protocol family.
If the driver does supports the media selection system, the supported
media list will be included in the output.
.Pp
+If
+.Fl L
+flag is supplied, address lifetime is dislayed for IPv6 addresses,
+as time offset string.
+.Pp
Optionally, the
.Fl a
flag may be used instead of an interface name. This flag instructs
@@ -375,6 +398,12 @@ it (or have need for it).
Messages indicating the specified interface does not exist, the
requested address is unknown, or the user is not privileged and
tried to alter an interface's configuration.
+.Sh BUGS
+IPv6 link-local addresses are required for several basic communication
+between IPv6 node. If they are deleted by
+.Nm ifconfig
+manually, the kernel might show very strange behavior.
+So, such manuall deletions are strongly discouraged.
.Sh SEE ALSO
.Xr netstat 1 ,
.Xr netintro 4 ,
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 00fb30f..32c7ee8 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -96,6 +96,10 @@ static const char rcsid[] =
struct ifreq ifr, ridreq;
struct ifaliasreq addreq;
+#ifdef INET6
+struct in6_ifreq in6_ridreq;
+struct in6_aliasreq in6_addreq;
+#endif
struct sockaddr_in netmask;
struct netrange at_nr; /* AppleTalk net range */
@@ -108,9 +112,16 @@ int setipdst;
int doalias;
int clearaddr;
int newaddr = 1;
+#ifdef INET6
+static int ip6lifetime;
+#endif
struct afswtch;
+#ifdef INET6
+char ntop_buf[INET6_ADDRSTRLEN]; /*inet_ntop()*/
+#endif
+
void Perror __P((const char *cmd));
void checkatrange __P((struct sockaddr_at *));
int ifconfig __P((int argc, char *const *argv, const struct afswtch *afp));
@@ -123,9 +134,19 @@ void status __P((const struct afswtch *afp, int addrcount,
void usage __P((void));
void ifmaybeload __P((char *name));
+#ifdef INET6
+int prefix __P((void *, int));
+static char *sec2str __P((time_t));
+int explicit_prefix = 0;
+#endif
+
typedef void c_func __P((const char *cmd, int arg, int s, const struct afswtch *afp));
c_func setatphase, setatrange;
c_func setifaddr, setifbroadaddr, setifdstaddr, setifnetmask;
+#ifdef INET6
+c_func setifprefixlen;
+c_func setip6flags;
+#endif
c_func setifipdst;
c_func setifflags, setifmetric, setifmtu;
@@ -153,6 +174,12 @@ struct cmd {
{ "-swabips", -EN_SWABIPS, setifflags },
#endif
{ "netmask", NEXTARG, setifnetmask },
+#ifdef INET6
+ { "prefixlen", NEXTARG, setifprefixlen },
+ { "anycast", IN6_IFF_ANYCAST, setip6flags },
+ { "tentative", IN6_IFF_TENTATIVE, setip6flags },
+ { "-tentative", -IN6_IFF_TENTATIVE, setip6flags },
+#endif
{ "range", NEXTARG, setatrange },
{ "phase", NEXTARG, setatphase },
{ "metric", NEXTARG, setifmetric },
@@ -188,10 +215,16 @@ struct cmd {
*/
typedef void af_status __P((int, struct rt_addrinfo *));
typedef void af_getaddr __P((const char *, int));
+typedef void af_getprefix __P((const char *, int));
af_status in_status, ipx_status, at_status, ether_status;
af_getaddr in_getaddr, ipx_getaddr, at_getaddr;
+#ifdef INET6
+af_status in6_status;
+af_getaddr in6_getaddr;
+af_getprefix in6_getprefix;
+#endif /*INET6*/
#ifdef NS
af_status xns_status;
af_getaddr xns_getaddr;
@@ -204,29 +237,35 @@ struct afswtch {
short af_af;
af_status *af_status;
af_getaddr *af_getaddr;
+ af_getprefix *af_getprefix;
u_long af_difaddr;
u_long af_aifaddr;
caddr_t af_ridreq;
caddr_t af_addreq;
} afs[] = {
#define C(x) ((caddr_t) &x)
- { "inet", AF_INET, in_status, in_getaddr,
+ { "inet", AF_INET, in_status, in_getaddr, NULL,
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
- { "ipx", AF_IPX, ipx_status, ipx_getaddr,
+#ifdef INET6
+ { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
+ SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
+ C(in6_ridreq), C(in6_addreq) },
+#endif /*INET6*/
+ { "ipx", AF_IPX, ipx_status, ipx_getaddr, NULL,
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
- { "atalk", AF_APPLETALK, at_status, at_getaddr,
+ { "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) },
#ifdef NS
- { "ns", AF_NS, xns_status, xns_getaddr,
+ { "ns", AF_NS, xns_status, xns_getaddr, NULL,
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
#endif
- { "ether", AF_INET, ether_status, NULL }, /* XXX not real!! */
+ { "ether", AF_INET, ether_status, NULL, NULL }, /* XXX not real!! */
#if 0 /* XXX conflicts with the media command */
#ifdef USE_IF_MEDIA
- { "media", AF_INET, media_status, NULL }, /* XXX not real!! */
+ { "media", AF_INET, media_status, NULL, NULL, }, /* XXX not real!! */
#endif
#ifdef USE_VLANS
- { "vlan", AF_INET, media_status, NULL }, /* XXX not real!! */
+ { "vlan", AF_INET, media_status, NULL, NULL, }, /* XXX not real!! */
#endif
#endif
{ 0, 0, 0, 0 }
@@ -262,11 +301,19 @@ rt_xaddrs(cp, cplim, rtinfo)
void
usage()
{
+#ifndef INET6
fprintf(stderr, "%s\n%s\n%s\n%s\n",
"usage: ifconfig interface address_family [address [dest_address]]",
" [parameters]",
" ifconfig -a [-d] [-u] [address_family]",
" ifconfig -l [-d] [-u] [address_family]");
+#else
+ fprintf(stderr, "%s\n%s\n%s\n%s\n",
+ "usage: ifconfig [-L] interface address_family [address [dest_address]]",
+ " [parameters]",
+ " ifconfig -a [-L] [-d] [-u] [address_family]",
+ " ifconfig -l [-d] [-u] [address_family]");
+#endif
exit(1);
}
@@ -291,11 +338,20 @@ main(argc, argv)
/* Parse leading line options */
all = downonly = uponly = namesonly = 0;
- while ((c = getopt(argc, argv, "adlmu")) != -1) {
+ while ((c = getopt(argc, argv, "adlmu"
+#ifdef INET6
+ "L"
+#endif
+ )) != -1) {
switch (c) {
case 'a': /* scan all interfaces */
all++;
break;
+#ifdef INET6
+ case 'L':
+ ip6lifetime++; /* print IPv6 adress lifetime */
+ break;
+#endif
case 'l': /* scan interface names only */
namesonly++;
break;
@@ -502,6 +558,15 @@ ifconfig(argc, argv, afp)
}
argc--, argv++;
}
+#ifdef INET6
+ if (ifr.ifr_addr.sa_family == AF_INET6 && explicit_prefix == 0) {
+ /* Aggregatable address architecture defines all prefixes
+ are 64. So, it is convenient to set prefixlen to 64 if
+ it is not specified. */
+ setifprefixlen("64", 0, s, afp);
+ /* in6_getprefix("64", MASK) if MASK is available here... */
+ }
+#endif
if (setipdst && ifr.ifr_addr.sa_family == AF_IPX) {
struct ipxip_req rq;
int size = sizeof(rq);
@@ -592,6 +657,36 @@ setifnetmask(addr, dummy, s, afp)
(*afp->af_getaddr)(addr, MASK);
}
+#ifdef INET6
+void
+setifprefixlen(addr, dummy, s, afp)
+ const char *addr;
+ int dummy __unused;
+ int s;
+ const struct afswtch *afp;
+{
+ if (*afp->af_getprefix)
+ (*afp->af_getprefix)(addr, MASK);
+ explicit_prefix = 1;
+}
+
+void
+setip6flags(dummyaddr, flag, dummysoc, afp)
+ const char *dummyaddr __unused;
+ int flag;
+ int dummysoc __unused;
+ const struct afswtch *afp;
+{
+ if (afp->af_af != AF_INET6)
+ err(1, "address flags can be set only for inet6 addresses");
+
+ if (flag < 0)
+ in6_addreq.ifra_flags &= ~(-flag);
+ else
+ in6_addreq.ifra_flags |= flag;
+}
+#endif
+
void
setifbroadaddr(addr, dummy, s, afp)
const char *addr;
@@ -854,6 +949,99 @@ in_status(s, info)
putchar('\n');
}
+#ifdef INET6
+void
+in6_status(s, info)
+ int s __unused;
+ struct rt_addrinfo * info;
+{
+ struct sockaddr_in6 *sin, null_sin;
+ struct in6_ifreq ifr6;
+ int s6;
+ u_int32_t flags6;
+ struct in6_addrlifetime lifetime;
+ time_t t = time(NULL);
+
+ memset(&null_sin, 0, sizeof(null_sin));
+
+ sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA];
+ strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+ if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("ifconfig: socket");
+ return;
+ }
+ ifr6.ifr_addr = *sin;
+ if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+ perror("ifconfig: ioctl(SIOCGIFAFLAG_IN6)");
+ close(s6);
+ return;
+ }
+ flags6 = ifr6.ifr_ifru.ifru_flags6;
+ memset(&lifetime, 0, sizeof(lifetime));
+ ifr6.ifr_addr = *sin;
+ if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
+ perror("ifconfig: ioctl(SIOCGIFALIFETIME_IN6)");
+ close(s6);
+ return;
+ }
+ lifetime = ifr6.ifr_ifru.ifru_lifetime;
+ close(s6);
+
+ printf("\tinet6 %s ", inet_ntop(AF_INET6, &sin->sin6_addr,
+ ntop_buf, sizeof(ntop_buf)));
+
+
+ if (flags & IFF_POINTOPOINT) {
+ /* note RTAX_BRD overlap with IFF_BROADCAST */
+ sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD];
+ /*
+ * some of the interfaces do not have valid destination
+ * address.
+ */
+ if (sin && sin->sin6_family == AF_INET6) {
+ printf("--> %s ", inet_ntop(AF_INET6, &sin->sin6_addr,
+ ntop_buf, sizeof(ntop_buf)));
+ }
+ }
+
+ sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];
+ if (!sin)
+ sin = &null_sin;
+ printf("prefixlen %d ", prefix(&sin->sin6_addr,
+ sizeof(struct in6_addr)));
+
+ if (flags6 & IN6_IFF_ANYCAST)
+ printf("anycast ");
+ if (flags6 & IN6_IFF_TENTATIVE)
+ printf("tentative ");
+ if (flags6 & IN6_IFF_DUPLICATED)
+ printf("duplicated ");
+ if (flags6 & IN6_IFF_DETACHED)
+ printf("detached ");
+ if (flags6 & IN6_IFF_DEPRECATED)
+ printf("deprecated ");
+
+
+ if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
+ printf("pltime ");
+ if (lifetime.ia6t_preferred) {
+ printf("%s ", lifetime.ia6t_preferred < t
+ ? "0" : sec2str(lifetime.ia6t_preferred - t));
+ } else
+ printf("infty ");
+
+ printf("vltime ");
+ if (lifetime.ia6t_expire) {
+ printf("%s ", lifetime.ia6t_expire < t
+ ? "0" : sec2str(lifetime.ia6t_expire - t));
+ } else
+ printf("infty ");
+ }
+
+ putchar('\n');
+}
+#endif /*INET6*/
+
void
ipx_status(s, info)
int s __unused;
@@ -1005,6 +1193,54 @@ in_getaddr(s, which)
errx(1, "%s: bad value", s);
}
+#ifdef INET6
+#define SIN6(x) ((struct sockaddr_in6 *) &(x))
+struct sockaddr_in6 *sin6tab[] = {
+SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
+SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
+
+void
+in6_getaddr(s, which)
+ const char *s;
+ int which;
+{
+ register struct sockaddr_in6 *sin = sin6tab[which];
+
+ newaddr &= 1;
+
+ sin->sin6_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin6_family = AF_INET6;
+
+ if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
+ errx(1, "%s: bad value", s);
+}
+
+void
+in6_getprefix(plen, which)
+ const char *plen;
+ int which;
+{
+ register struct sockaddr_in6 *sin = sin6tab[which];
+ register u_char *cp;
+ int len = atoi(plen);
+
+ if ((len < 0) || (len > 128))
+ errx(1, "%s: bad value", plen);
+ sin->sin6_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin6_family = AF_INET6;
+ if ((len == 0) || (len == 128)) {
+ memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
+ return;
+ }
+ memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
+ for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
+ *cp++ = 0xff;
+ *cp = 0xff << (8 - len);
+}
+#endif
+
/*
* Print a value a la the %b format of the kernel's printf
*/
@@ -1150,6 +1386,68 @@ xns_getaddr(addr, which)
}
#endif
+#ifdef INET6
+int
+prefix(val, size)
+ void *val;
+ int size;
+{
+ register u_char *name = (u_char *)val;
+ register int byte, bit, plen = 0;
+
+ for (byte = 0; byte < size; byte++, plen += 8)
+ if (name[byte] != 0xff)
+ break;
+ if (byte == size)
+ return (plen);
+ for (bit = 7; bit != 0; bit--, plen++)
+ if (!(name[byte] & (1 << bit)))
+ break;
+ for (; bit != 0; bit--)
+ if (name[byte] & (1 << bit))
+ return(0);
+ byte++;
+ for (; byte < size; byte++)
+ if (name[byte])
+ return(0);
+ return (plen);
+}
+
+static char *
+sec2str(total)
+ time_t total;
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ if (0) {
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += sprintf(p, "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += sprintf(p, "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += sprintf(p, "%dm", mins);
+ }
+ sprintf(p, "%ds", secs);
+ } else
+ sprintf(result, "%lu", (unsigned long)total);
+
+ return(result);
+}
+#endif /*INET6*/
+
void
ifmaybeload(name)
char *name;
diff --git a/sbin/route/Makefile b/sbin/route/Makefile
index 56679e1..e581d8c 100644
--- a/sbin/route/Makefile
+++ b/sbin/route/Makefile
@@ -1,9 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 6/5/93
+# $FreeBSD$
PROG= route
MAN8= route.8
SRCS= route.c keywords.h
CFLAGS+=-I. -Wall -DNS
+#CFLAGS+=-DINET6
CLEANFILES+=keywords.h
BINMODE=4555
diff --git a/sbin/route/keywords b/sbin/route/keywords
index 07a0ddc..00080a7 100644
--- a/sbin/route/keywords
+++ b/sbin/route/keywords
@@ -1,4 +1,5 @@
# @(#)keywords 8.2 (Berkeley) 3/19/94
+# $FreeBSD$
add
atalk
@@ -19,6 +20,7 @@ interface
ifa
ifp
inet
+inet6
iso
link
llinfo
@@ -31,6 +33,7 @@ net
netmask
nostatic
osi
+prefixlen
proto1
proto2
recvpipe
diff --git a/sbin/route/route.8 b/sbin/route/route.8
index 04cd23a..d8a36b9 100644
--- a/sbin/route/route.8
+++ b/sbin/route/route.8
@@ -69,7 +69,7 @@ Bypass attempts to print host and network names symbolically
when reporting actions. (The process of translating between symbolic
names and numerical equivalents can be quite time consuming, and
may require correct operation of the network; thus it may be expedient
-to forgo this, especially when attempting to repair networking operations).
+to forgot this, especially when attempting to repair networking operations).
.It Fl v
(verbose) Print additional details.
.It Fl q
@@ -120,6 +120,7 @@ When the address family may is specified by any of the
.Fl osi ,
.Fl xns ,
.Fl atalk ,
+.Fl inet6 ,
or
.Fl inet
modifiers, only routes having destinations with addresses in the
@@ -225,6 +226,28 @@ One specifies an additional ensuing address parameter
The implicit network mask generated in the AF_INET case
can be overridden by making sure this option follows the destination parameter.
.Pp
+For
+.Dv AF_INET6 ,
+the
+.Fl prefixlen
+qualifier
+is available instead of the
+.Fl mask
+qualifier because non-continuous masks are not allowed in IPv6.
+For example,
+.Fl prefixlen Li 32
+specifies network mask of
+.Li ffff:ffff:0000:0000:0000:0000:0000:0000
+to be used.
+The default value of prefixlen is 64 to get along with
+the aggregatable address.
+But 0 is assumed if
+.Cm default
+is specified.
+Note that the qualifier works only for
+.Dv AF_INET6
+address family.
+.Pp
Routes have associated flags which influence operation of the protocols
when sending to destinations matched by the routes.
These flags may be set (or sometimes cleared)
diff --git a/sbin/route/route.c b/sbin/route/route.c
index e0260b1..8576d75 100644
--- a/sbin/route/route.c
+++ b/sbin/route/route.c
@@ -84,6 +84,9 @@ struct ortentry route;
union sockunion {
struct sockaddr sa;
struct sockaddr_in sin;
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+#endif
struct sockaddr_at sat;
#ifdef NS
struct sockaddr_ns sns;
@@ -105,10 +108,15 @@ char *routename(), *netname();
void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
int getaddr(), rtmsg(), x25_makemask();
+int prefixlen();
extern char *iso_ntoa();
void usage __P((const char *)) __dead2;
+#ifdef INET6
+char ntop_buf[INET6_ADDRSTRLEN]; /*for inet_ntop()*/
+#endif
+
void
usage(cp)
const char *cp;
@@ -219,6 +227,11 @@ flushroutes(argc, argv)
case K_INET:
af = AF_INET;
break;
+#ifdef INET6
+ case K_INET6:
+ af = AF_INET6;
+ break;
+#endif
case K_ATALK:
af = AF_APPLETALK;
break;
@@ -346,6 +359,21 @@ routename(sa)
break;
}
+#ifdef INET6
+ case AF_INET6:
+ { struct sockaddr_in6 *sin6;
+ int gap;
+
+ sin6 = (struct sockaddr_in6 *)sa;
+ gap = sizeof(struct sockaddr_in6) - sin6->sin6_len;
+ if (gap > 0)
+ bzero((char *)(sin6) + sin6->sin6_len, gap);
+ (void) snprintf(line, sizeof(line), "%s",
+ inet_ntop(AF_INET6, &sin6->sin6_addr,
+ ntop_buf, sizeof(ntop_buf)));
+ }
+#endif
+
case AF_APPLETALK:
(void) snprintf(line, sizeof(line), "atalk %s",
atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
@@ -443,6 +471,21 @@ netname(sa)
break;
}
+#ifdef INET6
+ case AF_INET6:
+ { struct in6_addr in6;
+ int gap;
+
+ in6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
+ gap = sizeof(struct sockaddr_in6) - sa->sa_len;
+ if (gap > 0)
+ bzero((char *)(&in6 + 1) - gap, gap);
+ (void)snprintf(line, sizeof(line), "%s",
+ inet_ntop(AF_INET6, &in6, ntop_buf,
+ sizeof(ntop_buf)));
+ }
+#endif
+
case AF_APPLETALK:
(void) snprintf(line, sizeof(line), "atalk %s",
atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
@@ -526,6 +569,19 @@ newroute(argc, argv)
af = AF_INET;
aflen = sizeof(struct sockaddr_in);
break;
+#ifdef INET6
+ case K_INET6:
+ af = AF_INET6;
+ aflen = sizeof(struct sockaddr_in6);
+ if (prefixlen("64") != 64) {
+ fprintf(stderr, "internal error: "
+ "setting prefixlen=64\n");
+ exit(1);
+ }
+ forcenet = 0;
+ ishost = 1;
+ break;
+#endif
case K_ATALK:
af = AF_APPLETALK;
aflen = sizeof(struct sockaddr_at);
@@ -614,6 +670,17 @@ newroute(argc, argv)
case K_NET:
forcenet++;
break;
+ case K_PREFIXLEN:
+ if (!--argc)
+ usage((char *)NULL);
+ if (prefixlen(*++argv) == -1) {
+ forcenet = 0;
+ ishost = 1;
+ } else {
+ forcenet = 1;
+ ishost = 0;
+ }
+ break;
case K_MTU:
case K_HOPCOUNT:
case K_EXPIRE:
@@ -641,8 +708,15 @@ newroute(argc, argv)
}
}
}
- if (forcehost)
+ if (forcehost) {
ishost = 1;
+#ifdef INET6
+ if (af == AF_INET6) {
+ rtm_addrs &= ~RTA_NETMASK;
+ memset((void *)&so_mask, 0, sizeof(so_mask));
+ }
+#endif
+ }
if (forcenet)
ishost = 0;
flags |= RTF_UP;
@@ -754,11 +828,13 @@ getaddr(which, s, hpp)
struct netent *np;
u_long val;
char *q,qs;
+ int afamily; /* local copy of af so we can change it */
if (af == 0) {
af = AF_INET;
aflen = sizeof(struct sockaddr_in);
}
+ afamily = af;
rtm_addrs |= which;
switch (which) {
case RTA_DST:
@@ -818,6 +894,7 @@ getaddr(which, s, hpp)
break;
case RTA_IFP:
su = &so_ifp;
+ afamily = AF_LINK;
break;
case RTA_IFA:
su = &so_ifa;
@@ -827,7 +904,7 @@ getaddr(which, s, hpp)
/*NOTREACHED*/
}
su->sa.sa_len = aflen;
- su->sa.sa_family = af; /* cases that don't want it have left already */
+ su->sa.sa_family = afamily; /* cases that don't want it have left already */
if (strcmp(s, "default") == 0) {
/*
* Default is net 0.0.0.0/0
@@ -844,7 +921,16 @@ getaddr(which, s, hpp)
}
return (0);
}
- switch (af) {
+ switch (afamily) {
+#ifdef INET6
+ case AF_INET6:
+ if (inet_pton(AF_INET6, s, (void *)&su->sin6.sin6_addr) == -1) {
+ (void) fprintf(stderr, "%s: bad value\n", s);
+ exit(1);
+ }
+ return 0;
+#endif
+
#ifdef NS
case AF_NS:
if (which == RTA_DST) {
@@ -926,6 +1012,51 @@ netdone:
errx(EX_NOHOST, "bad address: %s", s);
}
+int
+prefixlen(s)
+ char *s;
+{
+ int len = atoi(s), q, r;
+ int max;
+ char *p;
+
+ rtm_addrs |= RTA_NETMASK;
+ switch (af) {
+#ifdef INET6
+ case AF_INET6:
+ max = 128;
+ p = (char *)&so_mask.sin6.sin6_addr;
+ break;
+#endif
+ case AF_INET:
+ max = 32;
+ p = (char *)&so_mask.sin.sin_addr;
+ break;
+ default:
+ (void) fprintf(stderr, "prefixlen not supported in this af\n");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ if (len < 0 || max < len) {
+ (void) fprintf(stderr, "%s: bad value\n", s);
+ exit(1);
+ }
+
+ q = len >> 3;
+ r = len & 7;
+ so_mask.sa.sa_family = af;
+ so_mask.sa.sa_len = aflen;
+ memset((void *)p, 0, max / 8);
+ if (q > 0)
+ memset((void *)p, 0xff, q);
+ if (r > 0)
+ *((u_char *)p + q) = (0xff00 >> r) & 0xff;
+ if (len == max)
+ return -1;
+ else
+ return len;
+}
#ifdef NS
short ns_nullh[] = {0,0,0};
@@ -971,9 +1102,9 @@ ns_print(sns)
else
*cport = 0;
- (void) snprintf(mybuf, sizeof(mybuf), "%lxH.%s%s",
- (unsigned long)ntohl(net.long_e),
- host, cport);
+ (void) snprintf(mybuf, sizeof(mybuf), "%lxH.%s%s",
+ (unsigned long)ntohl(net.long_e),
+ host, cport);
return (mybuf);
}
#endif
@@ -1017,8 +1148,10 @@ monitor()
exit(0);
}
for(;;) {
+ time_t now;
n = read(s, msg, 2048);
- (void) printf("got message of size %d\n", n);
+ now = time(NULL);
+ (void) printf("got message of size %d on %s", n, ctime(&now));
print_rtmsg((struct rt_msghdr *)msg, n);
}
}
@@ -1115,6 +1248,9 @@ mask_addr()
case AF_NS:
#endif
case AF_INET:
+#ifdef INET6
+ case AF_INET6:
+#endif
case AF_APPLETALK:
case 0:
return;
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index db2f541..8ec43fc 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -437,6 +437,11 @@ device mn0 # Munich32x/Falc54 Nx64kbit/sec cards.
# included for testing purposes.
# The `tun' pseudo-device implements (user-)ppp and nos-tun
# The `streams' pseudo-device implements SysVR4 STREAMS emulation.
+# The `gif' pseudo-device implements IPv6 over IP4 tunneling,
+# IPv4 over IPv6 tunneling, IPv4 over IPv4 tunneling and
+# IPv6 over IPv6 tunneling.
+# The `faith' pseudo-device captures packets sent to it and diverts them
+# to the IPv4/IPv6 translation daemon.
#
# The PPP_BSDCOMP option enables support for compress(1) style entire
# packet compression, the PPP_DEFLATE is for zlib/gzip style compression.
@@ -459,6 +464,10 @@ options PPP_BSDCOMP #PPP BSD-compress support
options PPP_DEFLATE #PPP zlib/deflate/gzip support
options PPP_FILTER #enable bpf filtering (needs bpf)
+# for IPv6
+pseudo-device gif 4 #IPv6 and IPv4 tunneling
+pseudo-device faith 1 #for IPv6 and IPv4 translation
+
#
# Internet family options:
#
diff --git a/sys/conf/files b/sys/conf/files
index dc919b1..62700b5 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -465,7 +465,9 @@ net/if_atmsubr.c optional atm
net/if_disc.c optional disc
net/if_ethersubr.c optional ether
net/if_iso88025subr.c optional token
+net/if_faith.c optional faith
net/if_fddisubr.c optional fddi
+net/if_gif.c optional gif
net/if_loop.c optional loop
net/if_media.c standard
net/if_mib.c standard
@@ -474,6 +476,7 @@ net/if_sl.c optional sl
net/if_spppsubr.c optional sppp
net/if_tun.c optional tun
net/if_vlan.c optional vlan
+net/net_osdep.c standard
net/ppp_deflate.c optional ppp_deflate
net/ppp_tty.c optional ppp
net/radix.c standard
@@ -484,7 +487,6 @@ net/rtsock.c standard
net/slcompress.c optional ppp
net/slcompress.c optional sl
net/zlib.c optional ppp_deflate
-net/net_osdep.c standard
netatalk/aarp.c optional netatalk
netatalk/at_control.c optional netatalk
netatalk/at_proto.c optional netatalk
@@ -595,6 +597,7 @@ netgraph/ng_vjc.c optional netgraph_vjc
net/slcompress.c optional netgraph_vjc
netinet/if_atm.c optional atm
netinet/if_ether.c optional ether
+netinet/in_gif.c optional gif inet
netinet/igmp.c optional inet
netinet/in.c optional inet
#netinet/in_hostcache.c optional inet
@@ -617,34 +620,36 @@ netinet/tcp_subr.c optional inet
netinet/tcp_timer.c optional inet
netinet/tcp_usrreq.c optional inet
netinet/udp_usrreq.c optional inet
-netinet6/in6.c optional inet6
-netinet6/in6_ifattach.c optional inet6
-netinet6/in6_cksum.c optional inet6
-netinet6/in6_pcb.c optional inet6
-netinet6/in6_proto.c optional inet6
-netinet6/in6_rmx.c optional inet6
-netinet6/in6_prefix.c optional inet6
+netinet/ip_fil.c optional ipfilter inet
+netinet/fil.c optional ipfilter inet
+netinet/ip_nat.c optional ipfilter inet
+netinet/ip_frag.c optional ipfilter inet
+netinet/ip_state.c optional ipfilter inet
+netinet/ip_auth.c optional ipfilter inet
+netinet/ip_proxy.c optional ipfilter inet
+netinet/ip_log.c optional ipfilter inet
+netinet/mlfk_ipl.c optional ipfilter inet
netinet6/dest6.c optional inet6
netinet6/frag6.c optional inet6
netinet6/icmp6.c optional inet6
-netinet6/ip6_input.c optional inet6
+netinet6/in6.c optional inet6
+netinet6/in6_cksum.c optional inet6
+netinet6/in6_gif.c optional gif inet6
netinet6/ip6_forward.c optional inet6
+netinet6/in6_ifattach.c optional inet6
+netinet6/ip6_input.c optional inet6
netinet6/ip6_output.c optional inet6
-netinet6/route6.c optional inet6
+netinet6/in6_pcb.c optional inet6
+netinet6/in6_prefix.c optional inet6
+netinet6/in6_proto.c optional inet6
+netinet6/in6_rmx.c optional inet6
netinet6/mld6.c optional inet6
netinet6/nd6.c optional inet6
netinet6/nd6_nbr.c optional inet6
netinet6/nd6_rtr.c optional inet6
netinet6/raw_ip6.c optional inet6
-netinet/ip_fil.c optional ipfilter inet
-netinet/fil.c optional ipfilter inet
-netinet/ip_nat.c optional ipfilter inet
-netinet/ip_frag.c optional ipfilter inet
-netinet/ip_state.c optional ipfilter inet
-netinet/ip_auth.c optional ipfilter inet
-netinet/ip_proxy.c optional ipfilter inet
-netinet/ip_log.c optional ipfilter inet
-netinet/mlfk_ipl.c optional ipfilter inet
+netinet6/route6.c optional inet6
+netinet6/udp6_usrreq.c optional inet6
netipx/ipx.c optional ipx
netipx/ipx_cksum.c optional ipx
netipx/ipx_input.c optional ipx
diff --git a/sys/conf/options b/sys/conf/options
index ed76e00..3c7558b 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -217,7 +217,7 @@ BOOTP_WIRED_TO opt_bootp.h
BRIDGE opt_bdg.h
MROUTING opt_mrouting.h
INET opt_inet.h
-INET6 opt_inet.h
+INET6 opt_inet6.h
IPDIVERT
DUMMYNET opt_ipdn.h
IPFILTER opt_ipfilter.h
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index db2f541..8ec43fc 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -437,6 +437,11 @@ device mn0 # Munich32x/Falc54 Nx64kbit/sec cards.
# included for testing purposes.
# The `tun' pseudo-device implements (user-)ppp and nos-tun
# The `streams' pseudo-device implements SysVR4 STREAMS emulation.
+# The `gif' pseudo-device implements IPv6 over IP4 tunneling,
+# IPv4 over IPv6 tunneling, IPv4 over IPv4 tunneling and
+# IPv6 over IPv6 tunneling.
+# The `faith' pseudo-device captures packets sent to it and diverts them
+# to the IPv4/IPv6 translation daemon.
#
# The PPP_BSDCOMP option enables support for compress(1) style entire
# packet compression, the PPP_DEFLATE is for zlib/gzip style compression.
@@ -459,6 +464,10 @@ options PPP_BSDCOMP #PPP BSD-compress support
options PPP_DEFLATE #PPP zlib/deflate/gzip support
options PPP_FILTER #enable bpf filtering (needs bpf)
+# for IPv6
+pseudo-device gif 4 #IPv6 and IPv4 tunneling
+pseudo-device faith 1 #for IPv6 and IPv4 translation
+
#
# Internet family options:
#
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index db2f541..8ec43fc 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -437,6 +437,11 @@ device mn0 # Munich32x/Falc54 Nx64kbit/sec cards.
# included for testing purposes.
# The `tun' pseudo-device implements (user-)ppp and nos-tun
# The `streams' pseudo-device implements SysVR4 STREAMS emulation.
+# The `gif' pseudo-device implements IPv6 over IP4 tunneling,
+# IPv4 over IPv6 tunneling, IPv4 over IPv4 tunneling and
+# IPv6 over IPv6 tunneling.
+# The `faith' pseudo-device captures packets sent to it and diverts them
+# to the IPv4/IPv6 translation daemon.
#
# The PPP_BSDCOMP option enables support for compress(1) style entire
# packet compression, the PPP_DEFLATE is for zlib/gzip style compression.
@@ -459,6 +464,10 @@ options PPP_BSDCOMP #PPP BSD-compress support
options PPP_DEFLATE #PPP zlib/deflate/gzip support
options PPP_FILTER #enable bpf filtering (needs bpf)
+# for IPv6
+pseudo-device gif 4 #IPv6 and IPv4 tunneling
+pseudo-device faith 1 #for IPv6 and IPv4 translation
+
#
# Internet family options:
#
diff --git a/sys/modules/if_disc/Makefile b/sys/modules/if_disc/Makefile
index 63b8592..e33555d 100644
--- a/sys/modules/if_disc/Makefile
+++ b/sys/modules/if_disc/Makefile
@@ -2,7 +2,7 @@
.PATH: ${.CURDIR}/../../net
KMOD= if_disc
-SRCS= if_disc.c opt_inet.h
+SRCS= if_disc.c opt_inet.h opt_inet6.h
NOMAN=
NBPF?= 1
@@ -12,4 +12,7 @@ CFLAGS+= ${PROTOS}
opt_inet.h:
echo "#define INET 1" > opt_inet.h
+#opt_inet6.h:
+# echo "#define INET6 1" > opt_inet6.h
+
.include <bsd.kmod.mk>
diff --git a/sys/net/if.c b/sys/net/if.c
index 7c560bc..c0ba5ee 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -35,7 +35,7 @@
*/
#include "opt_compat.h"
-#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/malloc.h>
diff --git a/sys/net/if_atmsubr.c b/sys/net/if_atmsubr.c
index 66cd09d..0a357a6 100644
--- a/sys/net/if_atmsubr.c
+++ b/sys/net/if_atmsubr.c
@@ -30,6 +30,8 @@
* 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.
+ *
+ * $FreeBSD$
*/
/*
@@ -37,6 +39,7 @@
*/
#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_natm.h"
#include <sys/param.h>
diff --git a/sys/net/if_disc.c b/sys/net/if_disc.c
index b90a658..66bd5f8 100644
--- a/sys/net/if_disc.c
+++ b/sys/net/if_disc.c
@@ -52,6 +52,7 @@
#include <net/bpf.h>
#include "opt_inet.h"
+#include "opt_inet6.h"
#ifdef TINY_DSMTU
#define DSMTU (1024+512)
@@ -180,6 +181,10 @@ discioctl(ifp, cmd, data)
case AF_INET:
break;
#endif
+#ifdef INET6
+ case AF_INET6:
+ break;
+#endif
default:
error = EAFNOSUPPORT;
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index ec0f5cf..bf11e9d 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -36,6 +36,7 @@
#include "opt_atalk.h"
#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_ipx.h"
#include "opt_bdg.h"
#include "opt_netgraph.h"
diff --git a/sys/net/if_faith.c b/sys/net/if_faith.c
new file mode 100644
index 0000000..0e21af7
--- /dev/null
+++ b/sys/net/if_faith.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1982, 1986, 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.
+ *
+ * $FreeBSD$
+ */
+/*
+ * derived from
+ * @(#)if_loop.c 8.1 (Berkeley) 6/10/93
+ * Id: if_loop.c,v 1.22 1996/06/19 16:24:10 wollman Exp
+ */
+
+/*
+ * Loopback interface driver for protocol testing and timing.
+ */
+
+#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/sockio.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <net/bpf.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));
+
+void faithattach __P((void *));
+PSEUDO_SET(faithattach, if_faith);
+static struct ifnet faithif[NFAITH];
+
+#define FAITHMTU 1500
+
+/* ARGSUSED */
+void
+faithattach(faith)
+ void *faith;
+{
+ register struct ifnet *ifp;
+ register int i;
+
+ for (i = 0; i < NFAITH; i++) {
+ ifp = &faithif[i];
+ bzero(ifp, sizeof(faithif[i]));
+ ifp->if_name = "faith";
+ ifp->if_unit = i;
+ ifp->if_mtu = FAITHMTU;
+ /* Change to BROADCAST experimentaly to announce its prefix. */
+ ifp->if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST;
+ ifp->if_ioctl = loioctl;
+ ifp->if_output = looutput;
+ ifp->if_type = IFT_FAITH;
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+ ifp->if_hdrlen = 0;
+ ifp->if_addrlen = 0;
+ if_attach(ifp);
+ bpfattach(ifp, DLT_NULL, sizeof(u_int));
+ }
+}
+#endif /* NFAITH > 0 */
diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c
index eedc822..0b39131 100644
--- a/sys/net/if_fddisubr.c
+++ b/sys/net/if_fddisubr.c
@@ -38,6 +38,7 @@
#include "opt_atalk.h"
#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_ipx.h"
#include <sys/param.h>
@@ -52,11 +53,14 @@
#include <net/if_dl.h>
#include <net/if_types.h>
-#ifdef INET
+#if defined(INET) || defined(INET6)
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/if_ether.h>
#endif
+#ifdef INET6
+#include <netinet6/nd6.h>
+#endif
#if defined(__FreeBSD__)
#include <netinet/if_fddi.h>
#else
@@ -186,6 +190,16 @@ fddi_output(ifp, m0, dst, rt0)
break;
}
#endif
+#ifdef INET6
+ case AF_INET6:
+ if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) {
+ /* this must be impossible, so we bark */
+ printf("nd6_storelladdr failed\n");
+ return(0);
+ }
+ type = htons(ETHERTYPE_IPV6);
+ break;
+#endif
#ifdef IPX
case AF_IPX:
type = htons(ETHERTYPE_IPX);
@@ -481,7 +495,7 @@ fddi_input(ifp, fh, m)
l = mtod(m, struct llc *);
switch (l->llc_dsap) {
-#if defined(INET) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK)
+#if defined(INET) || defined(INET6) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK)
case LLC_SNAP_LSAP:
{
u_int16_t type;
@@ -528,6 +542,12 @@ fddi_input(ifp, fh, m)
return;
#endif
#endif
+#ifdef INET6
+ case ETHERTYPE_IPV6:
+ schednetisr(NETISR_IPV6);
+ inq = &ip6intrq;
+ break;
+#endif
#ifdef IPX
case ETHERTYPE_IPX:
schednetisr(NETISR_IPX);
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
new file mode 100644
index 0000000..3eaa703
--- /dev/null
+++ b/sys/net/if_gif.c
@@ -0,0 +1,468 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * gif.c
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#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>
+#include <netinet/in_gif.h>
+#endif /* INET */
+
+#ifdef INET6
+#ifndef INET
+#include <netinet/in.h>
+#endif
+#include <netinet6/in6_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/in6_gif.h>
+#endif /* INET6 */
+
+#include <net/if_gif.h>
+
+#include "gif.h"
+
+#include <net/net_osdep.h>
+
+#if NGIF > 0
+
+void gifattach __P((void *));
+
+/*
+ * gif global variable definitions
+ */
+int ngif = NGIF; /* number of interfaces */
+struct gif_softc *gif = 0;
+
+void
+gifattach(dummy)
+ void *dummy;
+{
+ register struct gif_softc *sc;
+ register int i;
+
+ gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAIT);
+ bzero(sc, ngif * sizeof(struct gif_softc));
+ for (i = 0; i < ngif; sc++, i++) {
+ sc->gif_if.if_name = "gif";
+ sc->gif_if.if_unit = i;
+ sc->gif_if.if_mtu = GIF_MTU;
+ sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
+ sc->gif_if.if_ioctl = gif_ioctl;
+ sc->gif_if.if_output = gif_output;
+ sc->gif_if.if_type = IFT_GIF;
+ sc->gif_if.if_snd.ifq_maxlen = ifqmaxlen;
+ if_attach(&sc->gif_if);
+ bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
+ }
+}
+
+PSEUDO_SET(gifattach, if_gif);
+
+int
+gif_output(ifp, m, dst, rt)
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct sockaddr *dst;
+ struct rtentry *rt; /* added in net2 */
+{
+ register struct gif_softc *sc = (struct gif_softc*)ifp;
+ int error = 0;
+ static int called = 0; /* XXX: MUTEX */
+ int calllimit = 10; /* XXX: adhoc */
+
+ /*
+ * gif may cause infinite recursion calls when misconfigured.
+ * We'll prevent this by introducing upper limit.
+ * XXX: this mechanism may introduce another problem about
+ * mutual exclusion of the variable CALLED, especially if we
+ * use kernel thread.
+ */
+ if (++called >= calllimit) {
+ log(LOG_NOTICE,
+ "gif_output: recursively called too many times(%d)\n",
+ called);
+ m_freem(m);
+ error = EIO; /* is there better errno? */
+ goto end;
+ }
+ getmicrotime(&ifp->if_lastchange);
+ m->m_flags &= ~(M_BCAST|M_MCAST);
+ if (!(ifp->if_flags & IFF_UP) ||
+ sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
+ m_freem(m);
+ error = ENETDOWN;
+ goto end;
+ }
+
+ if (ifp->if_bpf) {
+ /*
+ * 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).
+ */
+ struct mbuf m0;
+ u_int af = dst->sa_family;
+
+ m0.m_next = m;
+ m0.m_len = 4;
+ m0.m_data = (char *)&af;
+
+ bpf_mtap(ifp, &m0);
+ }
+ ifp->if_opackets++;
+ ifp->if_obytes += m->m_pkthdr.len;
+
+ switch (sc->gif_psrc->sa_family) {
+#ifdef INET
+ case AF_INET:
+ error = in_gif_output(ifp, dst->sa_family, m, rt);
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ error = in6_gif_output(ifp, dst->sa_family, m, rt);
+ break;
+#endif
+ default:
+ m_freem(m);
+ error = ENETDOWN;
+ }
+
+ end:
+ called = 0; /* reset recursion counter */
+ if (error) ifp->if_oerrors++;
+ return error;
+}
+
+void
+gif_input(m, af, gifp)
+ struct mbuf *m;
+ int af;
+ struct ifnet *gifp;
+{
+ int s, isr;
+ register struct ifqueue *ifq = 0;
+
+ if (gifp == NULL) {
+ /* just in case */
+ m_freem(m);
+ return;
+ }
+
+ if (m->m_pkthdr.rcvif)
+ m->m_pkthdr.rcvif = gifp;
+
+ if (gifp->if_bpf) {
+ /*
+ * 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).
+ */
+ struct mbuf m0;
+ u_int af = AF_INET6;
+
+ m0.m_next = m;
+ m0.m_len = 4;
+ m0.m_data = (char *)&af;
+
+ bpf_mtap(gifp, &m0);
+ }
+
+ /*
+ * Put the packet to the network layer input queue according to the
+ * specified address family.
+ * Note: older versions of gif_input directly called network layer
+ * input functions, e.g. ip6_input, here. We changed the policy to
+ * prevent too many recursive calls of such input functions, which
+ * might cause kernel panic. But the change may introduce another
+ * problem; if the input queue is full, packets are discarded.
+ * We believed it rarely occurs and changed the policy. If we find
+ * it occurs more times than we thought, we may change the policy
+ * again.
+ */
+ switch (af) {
+#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;
+ }
+
+ s = splimp();
+ if (IF_QFULL(ifq)) {
+ IF_DROP(ifq); /* update statistics */
+ m_freem(m);
+ splx(s);
+ return;
+ }
+ IF_ENQUEUE(ifq, m);
+ /* we need schednetisr since the address family may change */
+ schednetisr(isr);
+ gifp->if_ipackets++;
+ gifp->if_ibytes += m->m_pkthdr.len;
+ splx(s);
+
+ return;
+}
+
+
+int
+gif_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct gif_softc *sc = (struct gif_softc*)ifp;
+ struct ifreq *ifr = (struct ifreq*)data;
+ int error = 0, size;
+ struct sockaddr *sa, *dst, *src;
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ break;
+
+ case SIOCSIFDSTADDR:
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ break;
+
+ case SIOCGIFMTU:
+ break;
+ case SIOCSIFMTU:
+ {
+ u_long mtu;
+ mtu = ifr->ifr_mtu;
+ if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
+ return (EINVAL);
+ }
+ ifp->if_mtu = mtu;
+ }
+ break;
+
+ case SIOCSIFPHYADDR:
+#ifdef INET6
+ case SIOCSIFPHYADDR_IN6:
+#endif /* INET6 */
+ switch (ifr->ifr_addr.sa_family) {
+#ifdef INET
+ case AF_INET:
+ src = (struct sockaddr *)
+ &(((struct in_aliasreq *)data)->ifra_addr);
+ dst = (struct sockaddr *)
+ &(((struct in_aliasreq *)data)->ifra_dstaddr);
+
+ /* only one gif can have dst = INADDR_ANY */
+#define satosaddr(sa) (((struct sockaddr_in *)(sa))->sin_addr.s_addr)
+
+ if (satosaddr(dst) == INADDR_ANY) {
+ int i;
+ struct gif_softc *sc2;
+
+ for (i = 0, sc2 = gif; i < ngif; i++, sc2++) {
+ if (sc2 == sc) continue;
+ if (sc2->gif_pdst &&
+ satosaddr(sc2->gif_pdst)
+ == INADDR_ANY) {
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+ }
+ }
+ size = sizeof(struct sockaddr_in);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ src = (struct sockaddr *)
+ &(((struct in6_aliasreq *)data)->ifra_addr);
+ dst = (struct sockaddr *)
+ &(((struct in6_aliasreq *)data)->ifra_dstaddr);
+
+ /* only one gif can have dst = in6addr_any */
+#define satoin6(sa) (&((struct sockaddr_in6 *)(sa))->sin6_addr)
+
+ if (IN6_IS_ADDR_UNSPECIFIED(satoin6(dst))) {
+ int i;
+ struct gif_softc *sc2;
+
+ for (i = 0, sc2 = gif; i < ngif; i++, sc2++) {
+ if (sc2 == sc) continue;
+ if (sc2->gif_pdst &&
+ IN6_IS_ADDR_UNSPECIFIED(
+ satoin6(sc2->gif_pdst)
+ )) {
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+ }
+ }
+ size = sizeof(struct sockaddr_in6);
+ break;
+#endif /* INET6 */
+ default:
+ error = EPROTOTYPE;
+ goto bad;
+ break;
+ }
+ if (sc->gif_psrc != NULL)
+ free((caddr_t)sc->gif_psrc, M_IFADDR);
+ if (sc->gif_pdst != NULL)
+ free((caddr_t)sc->gif_pdst, M_IFADDR);
+
+ sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
+ bzero((caddr_t)sa, size);
+ bcopy((caddr_t)src, (caddr_t)sa, size);
+ sc->gif_psrc = sa;
+
+ sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
+ bzero((caddr_t)sa, size);
+ bcopy((caddr_t)dst, (caddr_t)sa, size);
+ sc->gif_pdst = sa;
+
+ ifp->if_flags |= (IFF_UP|IFF_RUNNING);
+ if_up(ifp); /* send up RTM_IFINFO */
+
+ break;
+
+ case SIOCGIFPSRCADDR:
+#ifdef INET6
+ case SIOCGIFPSRCADDR_IN6:
+#endif /* INET6 */
+ if (sc->gif_psrc == NULL) {
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+ src = sc->gif_psrc;
+ switch (sc->gif_psrc->sa_family) {
+#ifdef INET
+ case AF_INET:
+ dst = &ifr->ifr_addr;
+ size = sizeof(struct sockaddr_in);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ dst = (struct sockaddr *)
+ &(((struct in6_ifreq *)data)->ifr_addr);
+ size = sizeof(struct sockaddr_in6);
+ break;
+#endif /* INET6 */
+ default:
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+ bcopy((caddr_t)src, (caddr_t)dst, size);
+ break;
+
+ case SIOCGIFPDSTADDR:
+#ifdef INET6
+ case SIOCGIFPDSTADDR_IN6:
+#endif /* INET6 */
+ if (sc->gif_pdst == NULL) {
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+ src = sc->gif_pdst;
+ switch (sc->gif_pdst->sa_family) {
+#ifdef INET
+ case AF_INET:
+ dst = &ifr->ifr_addr;
+ size = sizeof(struct sockaddr_in);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ dst = (struct sockaddr *)
+ &(((struct in6_ifreq *)data)->ifr_addr);
+ size = sizeof(struct sockaddr_in6);
+ break;
+#endif /* INET6 */
+ default:
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+ bcopy((caddr_t)src, (caddr_t)dst, size);
+ break;
+
+ case SIOCSIFFLAGS:
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ bad:
+ return error;
+}
+#endif /*NGIF > 0*/
diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h
index a402471..cc26938 100644
--- a/sys/net/if_gif.h
+++ b/sys/net/if_gif.h
@@ -36,9 +36,6 @@
#ifndef _NET_IF_GIF_H_
#define _NET_IF_GIF_H_
-#include <netinet/in.h>
-/* xxx sigh, why route have struct route instead of pointer? */
-
struct gif_softc {
struct ifnet gif_if; /* common area */
struct sockaddr *gif_psrc; /* Physical src addr */
diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c
index c57f857..a714bf1 100644
--- a/sys/net/if_loop.c
+++ b/sys/net/if_loop.c
@@ -42,6 +42,7 @@
#include "opt_atalk.h"
#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_ipx.h"
#include <sys/param.h>
@@ -90,13 +91,13 @@
#include <netatalk/at_var.h>
#endif NETATALK
-static int loioctl __P((struct ifnet *, u_long, caddr_t));
+int loioctl __P((struct ifnet *, u_long, caddr_t));
static void lortrequest __P((int, struct rtentry *, struct sockaddr *));
static void loopattach __P((void *));
PSEUDO_SET(loopattach, if_loop);
-static int looutput __P((struct ifnet *ifp,
+int looutput __P((struct ifnet *ifp,
struct mbuf *m, struct sockaddr *dst, struct rtentry *rt));
#ifdef TINY_LOMTU
@@ -131,7 +132,7 @@ loopattach(dummy)
}
}
-static int
+int
looutput(ifp, m, dst, rt)
struct ifnet *ifp;
register struct mbuf *m;
@@ -341,7 +342,7 @@ lortrequest(cmd, rt, sa)
* Process an ioctl request.
*/
/* ARGSUSED */
-static int
+int
loioctl(ifp, cmd, data)
register struct ifnet *ifp;
u_long cmd;
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
index 133af2b..e02ef90 100644
--- a/sys/net/if_spppsubr.c
+++ b/sys/net/if_spppsubr.c
@@ -24,12 +24,14 @@
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_ipx.h"
#endif
#ifdef NetBSD1_3
# if NetBSD1_3 > 6
# include "opt_inet.h"
+# include "opt_inet6.h"
# include "opt_iso.h"
# endif
#endif
@@ -572,6 +574,12 @@ sppp_input(struct ifnet *ifp, struct mbuf *m)
inq = &ipintrq;
break;
#endif
+#ifdef INET6
+ case ETHERTYPE_IPV6:
+ schednetisr (NETISR_IPV6);
+ inq = &ip6intrq;
+ break;
+#endif
#ifdef IPX
case ETHERTYPE_IPX:
schednetisr (NETISR_IPX);
@@ -741,6 +749,15 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
}
break;
#endif
+#ifdef INET6
+ case AF_INET6: /* Internet Protocol */
+ if (sp->pp_mode == IFF_CISCO)
+ h->protocol = htons (ETHERTYPE_IPV6);
+ else {
+ goto nosupport;
+ }
+ break;
+#endif
#ifdef NS
case AF_NS: /* Xerox NS Protocol */
h->protocol = htons (sp->pp_mode == IFF_CISCO ?
@@ -759,8 +776,8 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
goto nosupport;
h->protocol = htons (PPP_ISO);
break;
-nosupport:
#endif
+nosupport:
default:
m_freem (m);
++ifp->if_oerrors;
diff --git a/sys/netinet/if_atm.c b/sys/netinet/if_atm.c
index 020e5ac..04b49bf 100644
--- a/sys/netinet/if_atm.c
+++ b/sys/netinet/if_atm.c
@@ -30,6 +30,8 @@
* 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.
+ *
+ * $FreeBSD$
*/
/*
@@ -37,6 +39,7 @@
*/
#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_natm.h"
#if defined(INET) || defined(INET6)
diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c
new file mode 100644
index 0000000..fd8317f
--- /dev/null
+++ b/sys/netinet/in_gif.c
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * in_gif.c
+ */
+
+#include "opt_mrouting.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/in_gif.h>
+
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+
+#ifdef MROUTING
+#include <netinet/ip_mroute.h>
+#endif /* MROUTING */
+
+#include <net/if_gif.h>
+
+#include "gif.h"
+
+#include <machine/stdarg.h>
+
+#include <net/net_osdep.h>
+
+#if NGIF > 0
+int ip_gif_ttl = GIF_TTL;
+#else
+int ip_gif_ttl = 0;
+#endif
+
+SYSCTL_DECL(_net_inet_ip);
+SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
+ &ip_gif_ttl, 0, "");
+
+int
+in_gif_output(ifp, family, m, rt)
+ struct ifnet *ifp;
+ int family;
+ struct mbuf *m;
+ struct rtentry *rt;
+{
+ register struct gif_softc *sc = (struct gif_softc*)ifp;
+ struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst;
+ struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
+ struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst;
+ struct ip iphdr; /* capsule IP header, host byte ordered */
+ int proto, error;
+ u_int8_t tos;
+
+ if (sin_src == NULL || sin_dst == NULL ||
+ sin_src->sin_family != AF_INET ||
+ sin_dst->sin_family != AF_INET) {
+ m_freem(m);
+ return EAFNOSUPPORT;
+ }
+
+ switch (family) {
+ case AF_INET:
+ {
+ struct ip *ip;
+
+ proto = IPPROTO_IPV4;
+ if (m->m_len < sizeof(*ip)) {
+ m = m_pullup(m, sizeof(*ip));
+ if (!m)
+ return ENOBUFS;
+ }
+ ip = mtod(m, struct ip *);
+ tos = ip->ip_tos;
+ break;
+ }
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct ip6_hdr *ip6;
+ proto = IPPROTO_IPV6;
+ if (m->m_len < sizeof(*ip6)) {
+ m = m_pullup(m, sizeof(*ip6));
+ if (!m)
+ return ENOBUFS;
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+ tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
+ break;
+ }
+#endif /*INET6*/
+ default:
+#ifdef DIAGNOSTIC
+ printf("in_gif_output: warning: unknown family %d passed\n",
+ family);
+#endif
+ m_freem(m);
+ return EAFNOSUPPORT;
+ }
+
+ bzero(&iphdr, sizeof(iphdr));
+ iphdr.ip_src = sin_src->sin_addr;
+ if (ifp->if_flags & IFF_LINK0) {
+ /* multi-destination mode */
+ if (sin_dst->sin_addr.s_addr != INADDR_ANY)
+ iphdr.ip_dst = sin_dst->sin_addr;
+ else if (rt) {
+ iphdr.ip_dst = ((struct sockaddr_in *)
+ (rt->rt_gateway))->sin_addr;
+ } else {
+ m_freem(m);
+ return ENETUNREACH;
+ }
+ } else {
+ /* bidirectional configured tunnel mode */
+ if (sin_dst->sin_addr.s_addr != INADDR_ANY)
+ iphdr.ip_dst = sin_dst->sin_addr;
+ else {
+ m_freem(m);
+ return ENETUNREACH;
+ }
+ }
+ iphdr.ip_p = proto;
+ /* version will be set in ip_output() */
+ iphdr.ip_ttl = ip_gif_ttl;
+ iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip);
+
+ /* prepend new IP header */
+ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
+ if (m && m->m_len < sizeof(struct ip))
+ m = m_pullup(m, sizeof(struct ip));
+ if (m == NULL) {
+ printf("ENOBUFS in in_gif_output %d\n", __LINE__);
+ return ENOBUFS;
+ }
+
+ *(mtod(m, struct ip *)) = iphdr;
+
+ if (dst->sin_family != sin_dst->sin_family ||
+ dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
+ /* cache route doesn't match */
+ dst->sin_family = sin_dst->sin_family;
+ dst->sin_len = sizeof(struct sockaddr_in);
+ dst->sin_addr = sin_dst->sin_addr;
+ if (sc->gif_ro.ro_rt) {
+ RTFREE(sc->gif_ro.ro_rt);
+ sc->gif_ro.ro_rt = NULL;
+ }
+ }
+
+ if (sc->gif_ro.ro_rt == NULL) {
+ rtalloc(&sc->gif_ro);
+ if (sc->gif_ro.ro_rt == NULL) {
+ m_freem(m);
+ return ENETUNREACH;
+ }
+ }
+
+#ifdef IPSEC
+ m->m_pkthdr.rcvif = NULL;
+#endif /*IPSEC*/
+ error = ip_output(m, 0, &sc->gif_ro, 0, 0);
+ return(error);
+}
+
+void
+#if __STDC__
+in_gif_input(struct mbuf *m, ...)
+#else
+in_gif_input(m, va_alist)
+ struct mbuf *m;
+ va_dcl
+#endif
+{
+ int off, proto;
+ struct gif_softc *sc;
+ struct ifnet *gifp = NULL;
+ struct ip *ip;
+ int i, af;
+ va_list ap;
+
+ va_start(ap, m);
+ off = va_arg(ap, int);
+ proto = va_arg(ap, int);
+ va_end(ap);
+
+ ip = mtod(m, struct ip *);
+
+ /* this code will be soon improved. */
+#define satosin(sa) ((struct sockaddr_in *)(sa))
+ for (i = 0, sc = gif; i < ngif; i++, sc++) {
+ if (sc->gif_psrc == NULL
+ || sc->gif_pdst == NULL
+ || sc->gif_psrc->sa_family != AF_INET
+ || sc->gif_pdst->sa_family != AF_INET) {
+ continue;
+ }
+
+ if ((sc->gif_if.if_flags & IFF_UP) == 0)
+ continue;
+
+ if ((sc->gif_if.if_flags & IFF_LINK0)
+ && satosin(sc->gif_psrc)->sin_addr.s_addr == ip->ip_dst.s_addr
+ && satosin(sc->gif_pdst)->sin_addr.s_addr == INADDR_ANY) {
+ gifp = &sc->gif_if;
+ continue;
+ }
+
+ if (satosin(sc->gif_psrc)->sin_addr.s_addr == ip->ip_dst.s_addr
+ && satosin(sc->gif_pdst)->sin_addr.s_addr == ip->ip_src.s_addr)
+ {
+ gifp = &sc->gif_if;
+ break;
+ }
+ }
+
+ if (gifp == NULL) {
+#ifdef MROUTING
+ /* for backward compatibility */
+ if (proto == IPPROTO_IPV4) {
+ ipip_input(m, off, proto);
+ return;
+ }
+#endif /*MROUTING*/
+ m_freem(m);
+ ipstat.ips_nogif++;
+ return;
+ }
+
+ m_adj(m, off);
+
+ switch (proto) {
+ case IPPROTO_IPV4:
+ {
+ struct ip *ip;
+ af = AF_INET;
+ if (m->m_len < sizeof(*ip)) {
+ m = m_pullup(m, sizeof(*ip));
+ if (!m)
+ return;
+ }
+ ip = mtod(m, struct ip *);
+ break;
+ }
+#ifdef INET6
+ case IPPROTO_IPV6:
+ {
+ struct ip6_hdr *ip6;
+ af = AF_INET6;
+ if (m->m_len < sizeof(*ip6)) {
+ m = m_pullup(m, sizeof(*ip6));
+ if (!m)
+ return;
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_flow &= ~htonl(0xff << 20);
+ break;
+ }
+#endif /* INET6 */
+ default:
+ ipstat.ips_nogif++;
+ m_freem(m);
+ return;
+ }
+ gif_input(m, af, gifp);
+ return;
+}
diff --git a/sys/netinet/in_gif.h b/sys/netinet/in_gif.h
new file mode 100644
index 0000000..b874524
--- /dev/null
+++ b/sys/netinet/in_gif.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NETINET_IN_GIF_H_
+#define _NETINET_IN_GIF_H_
+
+#define GIF_TTL 30
+
+extern int ip_gif_ttl;
+
+void in_gif_input __P((struct mbuf *, ...));
+int in_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *));
+
+#endif /*_NETINET_IN_GIF_H_*/
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index d19d449..71d091b 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -34,10 +34,13 @@
* $FreeBSD$
*/
+#include "opt_inet6.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
+#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
@@ -51,12 +54,25 @@
#include <vm/vm_zone.h>
#include <net/if.h>
+#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif /* INET6 */
+
+#include "faith.h"
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#include <netkey/key.h>
+#include <netkey/key_debug.h>
+#endif /* IPSEC */
struct in_addr zeroin_addr;
@@ -212,13 +228,34 @@ in_pcbbind(inp, nam, p)
(t->inp_socket->so_options &
SO_REUSEPORT) == 0) &&
(so->so_cred->cr_uid !=
- t->inp_socket->so_cred->cr_uid))
+ t->inp_socket->so_cred->cr_uid)) {
+#if defined(INET6)
+ if (ip6_mapped_addr_on == 0 ||
+ ntohl(sin->sin_addr.s_addr) !=
+ INADDR_ANY ||
+ ntohl(t->inp_laddr.s_addr) !=
+ INADDR_ANY ||
+ INP_SOCKAF(so) ==
+ INP_SOCKAF(t->inp_socket))
+#endif /* defined(INET6) */
return (EADDRINUSE);
+ }
}
t = in_pcblookup_local(pcbinfo, sin->sin_addr,
lport, prison ? 0 : wild);
- if (t && (reuseport & t->inp_socket->so_options) == 0)
+ if (t &&
+ (reuseport & t->inp_socket->so_options) == 0) {
+#if defined(INET6)
+ if (ip6_mapped_addr_on == 0 ||
+ ntohl(sin->sin_addr.s_addr) !=
+ INADDR_ANY ||
+ ntohl(t->inp_laddr.s_addr) !=
+ INADDR_ANY ||
+ INP_SOCKAF(so) ==
+ INP_SOCKAF(t->inp_socket))
+#endif /* defined(INET6) */
return (EADDRINUSE);
+ }
}
inp->inp_laddr = sin->sin_addr;
}
@@ -452,7 +489,7 @@ in_pcbconnect(inp, nam, p)
if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
- inp->inp_lport, 0) != NULL) {
+ inp->inp_lport, 0, NULL) != NULL) {
return (EADDRINUSE);
}
if (inp->inp_laddr.s_addr == INADDR_ANY) {
@@ -488,6 +525,9 @@ in_pcbdetach(inp)
struct socket *so = inp->inp_socket;
struct inpcbinfo *ipi = inp->inp_pcbinfo;
+#ifdef IPSEC
+ ipsec4_delete_pcbpolicy(inp);
+#endif /*IPSEC*/
inp->inp_gencnt = ++ipi->ipi_gencnt;
in_pcbremlists(inp);
so->so_pcb = 0;
@@ -497,6 +537,7 @@ in_pcbdetach(inp)
if (inp->inp_route.ro_rt)
rtfree(inp->inp_route.ro_rt);
ip_freemoptions(inp->inp_moptions);
+ inp->inp_vflag = 0;
zfreei(ipi->ipi_zone, inp);
}
@@ -620,6 +661,12 @@ in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
errno = inetctlerrmap[cmd];
s = splnet();
for (inp = head->lh_first; inp != NULL;) {
+#ifdef INET6
+ if ((inp->inp_vflag & INP_IPV4) == NULL) {
+ inp = LIST_NEXT(inp, inp_list);
+ continue;
+ }
+#endif
if (inp->inp_faddr.s_addr != faddr.s_addr ||
inp->inp_socket == 0 ||
(lport && inp->inp_lport != lport) ||
@@ -711,6 +758,10 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
*/
head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
+#ifdef INET6
+ if ((inp->inp_vflag & INP_IPV4) == NULL)
+ continue;
+#endif
if (inp->inp_faddr.s_addr == INADDR_ANY &&
inp->inp_laddr.s_addr == laddr.s_addr &&
inp->inp_lport == lport) {
@@ -748,6 +799,10 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
for (inp = phd->phd_pcblist.lh_first; inp != NULL;
inp = inp->inp_portlist.le_next) {
wildcard = 0;
+#ifdef INET6
+ if ((inp->inp_vflag & INP_IPV4) == NULL)
+ continue;
+#endif
if (inp->inp_faddr.s_addr != INADDR_ANY)
wildcard++;
if (inp->inp_laddr.s_addr != INADDR_ANY) {
@@ -776,11 +831,13 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
* Lookup PCB in hash list.
*/
struct inpcb *
-in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard)
+in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard,
+ ifp)
struct inpcbinfo *pcbinfo;
struct in_addr faddr, laddr;
u_int fport_arg, lport_arg;
int wildcard;
+ struct ifnet *ifp;
{
struct inpcbhead *head;
register struct inpcb *inp;
@@ -791,6 +848,10 @@ in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard)
*/
head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
+#ifdef INET6
+ if ((inp->inp_vflag & INP_IPV4) == NULL)
+ continue;
+#endif
if (inp->inp_faddr.s_addr == faddr.s_addr &&
inp->inp_laddr.s_addr == laddr.s_addr &&
inp->inp_fport == fport &&
@@ -803,17 +864,40 @@ in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard)
}
if (wildcard) {
struct inpcb *local_wild = NULL;
+#if defined(INET6)
+ struct inpcb *local_wild_mapped = NULL;
+#endif /* defined(INET6) */
head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
+#ifdef INET6
+ if ((inp->inp_vflag & INP_IPV4) == NULL)
+ continue;
+#endif
if (inp->inp_faddr.s_addr == INADDR_ANY &&
inp->inp_lport == lport) {
+#if defined(NFAITH) && NFAITH > 0
+ if (ifp && ifp->if_type == IFT_FAITH &&
+ (inp->inp_flags & INP_FAITH) == 0)
+ continue;
+#endif
if (inp->inp_laddr.s_addr == laddr.s_addr)
return (inp);
- else if (inp->inp_laddr.s_addr == INADDR_ANY)
+ else if (inp->inp_laddr.s_addr == INADDR_ANY) {
+#if defined(INET6)
+ if (INP_CHECK_SOCKAF(inp->inp_socket,
+ AF_INET6))
+ local_wild_mapped = inp;
+ else
+#endif /* defined(INET6) */
local_wild = inp;
+ }
}
}
+#if defined(INET6)
+ if (local_wild == NULL)
+ return (local_wild_mapped);
+#endif /* defined(INET6) */
return (local_wild);
}
@@ -834,8 +918,16 @@ in_pcbinshash(inp)
struct inpcbporthead *pcbporthash;
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
struct inpcbport *phd;
+ u_int32_t hashkey_faddr;
- pcbhash = &pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr,
+#ifdef INET6
+ if (inp->inp_vflag & INP_IPV6)
+ hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
+ else
+#endif /* INET6 */
+ hashkey_faddr = inp->inp_faddr.s_addr;
+
+ pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];
pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,
@@ -877,8 +969,16 @@ in_pcbrehash(inp)
struct inpcb *inp;
{
struct inpcbhead *head;
+ u_int32_t hashkey_faddr;
+
+#ifdef INET6
+ if (inp->inp_vflag & INP_IPV6)
+ hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
+ else
+#endif /* INET6 */
+ hashkey_faddr = inp->inp_faddr.s_addr;
- head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr,
+ head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];
LIST_REMOVE(inp, inp_hash);
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index adfa5fa..5aeb579 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -287,7 +287,8 @@ struct inpcb *
struct in_addr, u_int, int));
struct inpcb *
in_pcblookup_hash __P((struct inpcbinfo *,
- struct in_addr, u_int, struct in_addr, u_int, int));
+ struct in_addr, u_int, struct in_addr, u_int,
+ int, struct ifnet *));
void in_pcbnotify __P((struct inpcbhead *, struct sockaddr *,
u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int)));
void in_pcbrehash __P((struct inpcb *));
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index 22647d9..b9a9e4a 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -63,6 +63,11 @@
* TCP/IP protocol family: IP, ICMP, UDP, TCP.
*/
+#include "gif.h"
+#if NGIF > 0
+#include <netinet/in_gif.h>
+#endif
+
#ifdef IPXIP
#include <netipx/ipx_ip.h>
#endif
@@ -119,12 +124,29 @@ struct protosw inetsw[] = {
0, 0, 0, 0,
&rip_usrreqs
},
+#if NGIF > 0
+{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR,
+ in_gif_input, 0, 0, 0,
+ 0,
+ 0, 0, 0, 0,
+ &nousrreqs
+},
+# ifdef INET6
+{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR,
+ in_gif_input, 0, 0, 0,
+ 0,
+ 0, 0, 0, 0,
+ &nousrreqs
+},
+#endif
+#else /*NGIF*/
{ SOCK_RAW, &inetdomain, IPPROTO_IPIP, PR_ATOMIC|PR_ADDR,
ipip_input, 0, 0, rip_ctloutput,
0,
0, 0, 0, 0,
&rip_usrreqs
},
+#endif /*NGIF*/
#ifdef IPDIVERT
{ SOCK_RAW, &inetdomain, IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR,
div_input, 0, 0, ip_ctloutput,
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c
index a70822e..b897421 100644
--- a/sys/netinet/ip_fw.c
+++ b/sys/netinet/ip_fw.c
@@ -707,10 +707,12 @@ again:
if (oif)
P = in_pcblookup_hash(&tcbinfo, ip->ip_dst,
- tcp->th_dport, ip->ip_src, tcp->th_sport, 0);
+ tcp->th_dport, ip->ip_src, tcp->th_sport, 0,
+ oif);
else
P = in_pcblookup_hash(&tcbinfo, ip->ip_src,
- tcp->th_sport, ip->ip_dst, tcp->th_dport, 0);
+ tcp->th_sport, ip->ip_dst, tcp->th_dport, 0,
+ NULL);
if (P && P->inp_socket) {
if (f->fw_flg & IP_FW_F_UID) {
@@ -738,10 +740,12 @@ again:
if (oif)
P = in_pcblookup_hash(&udbinfo, ip->ip_dst,
- udp->uh_dport, ip->ip_src, udp->uh_sport, 1);
+ udp->uh_dport, ip->ip_src, udp->uh_sport, 1,
+ oif);
else
P = in_pcblookup_hash(&udbinfo, ip->ip_src,
- udp->uh_sport, ip->ip_dst, udp->uh_dport, 1);
+ udp->uh_sport, ip->ip_dst, udp->uh_dport, 1,
+ NULL);
if (P && P->inp_socket) {
if (f->fw_flg & IP_FW_F_UID) {
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 5f61ff3..909adf9 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -390,7 +390,7 @@ findpcb:
* already got one like this?
*/
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport,
- ti->ti_dst, ti->ti_dport, 0);
+ ti->ti_dst, ti->ti_dport, 0, m->m_pkthdr.rcvif);
if (!inp) {
/*
* No, then it's new. Try find the ambushing socket
@@ -398,12 +398,13 @@ findpcb:
if (!ip_fw_fwd_addr->sin_port) {
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src,
ti->ti_sport, ip_fw_fwd_addr->sin_addr,
- ti->ti_dport, 1);
+ ti->ti_dport, 1, m->m_pkthdr.rcvif);
} else {
inp = in_pcblookup_hash(&tcbinfo,
ti->ti_src, ti->ti_sport,
ip_fw_fwd_addr->sin_addr,
- ntohs(ip_fw_fwd_addr->sin_port), 1);
+ ntohs(ip_fw_fwd_addr->sin_port), 1,
+ m->m_pkthdr.rcvif);
}
}
ip_fw_fwd_addr = NULL;
@@ -411,7 +412,7 @@ findpcb:
#endif /* IPFIREWALL_FORWARD */
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport,
- ti->ti_dst, ti->ti_dport, 1);
+ ti->ti_dst, ti->ti_dport, 1, m->m_pkthdr.rcvif);
/*
* If the state is CLOSED (i.e., TCB does not exist) then
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 5f61ff3..909adf9 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -390,7 +390,7 @@ findpcb:
* already got one like this?
*/
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport,
- ti->ti_dst, ti->ti_dport, 0);
+ ti->ti_dst, ti->ti_dport, 0, m->m_pkthdr.rcvif);
if (!inp) {
/*
* No, then it's new. Try find the ambushing socket
@@ -398,12 +398,13 @@ findpcb:
if (!ip_fw_fwd_addr->sin_port) {
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src,
ti->ti_sport, ip_fw_fwd_addr->sin_addr,
- ti->ti_dport, 1);
+ ti->ti_dport, 1, m->m_pkthdr.rcvif);
} else {
inp = in_pcblookup_hash(&tcbinfo,
ti->ti_src, ti->ti_sport,
ip_fw_fwd_addr->sin_addr,
- ntohs(ip_fw_fwd_addr->sin_port), 1);
+ ntohs(ip_fw_fwd_addr->sin_port), 1,
+ m->m_pkthdr.rcvif);
}
}
ip_fw_fwd_addr = NULL;
@@ -411,7 +412,7 @@ findpcb:
#endif /* IPFIREWALL_FORWARD */
inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport,
- ti->ti_dst, ti->ti_dport, 1);
+ ti->ti_dst, ti->ti_dport, 1, m->m_pkthdr.rcvif);
/*
* If the state is CLOSED (i.e., TCB does not exist) then
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index b472de5..fd3e435 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -35,7 +35,7 @@
*/
#include "opt_compat.h"
-#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_tcpdebug.h"
#include <sys/param.h>
@@ -647,7 +647,7 @@ tcp_getcred SYSCTL_HANDLER_ARGS
return (error);
s = splnet();
inp = in_pcblookup_hash(&tcbinfo, addrs[1].sin_addr, addrs[1].sin_port,
- addrs[0].sin_addr, addrs[0].sin_port, 0);
+ addrs[0].sin_addr, addrs[0].sin_port, 0, NULL);
if (inp == NULL || inp->inp_socket == NULL) {
error = ENOENT;
goto out;
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index b472de5..fd3e435 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -35,7 +35,7 @@
*/
#include "opt_compat.h"
-#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_tcpdebug.h"
#include <sys/param.h>
@@ -647,7 +647,7 @@ tcp_getcred SYSCTL_HANDLER_ARGS
return (error);
s = splnet();
inp = in_pcblookup_hash(&tcbinfo, addrs[1].sin_addr, addrs[1].sin_port,
- addrs[0].sin_addr, addrs[0].sin_port, 0);
+ addrs[0].sin_addr, addrs[0].sin_port, 0, NULL);
if (inp == NULL || inp->inp_socket == NULL) {
error = ENOENT;
goto out;
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 49fca1e..af43fc3 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -34,6 +34,7 @@
* $FreeBSD$
*/
+#include "opt_inet6.h"
#include "opt_tcpdebug.h"
#include <sys/param.h>
@@ -535,7 +536,7 @@ tcp_connect(tp, nam, p)
sin->sin_addr, sin->sin_port,
inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr
: ifaddr->sin_addr,
- inp->inp_lport, 0);
+ inp->inp_lport, 0, NULL);
if (oinp) {
if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
otp->t_state == TCPS_TIME_WAIT &&
@@ -731,6 +732,9 @@ tcp_attach(so, p)
if (error)
return (error);
inp = sotoinpcb(so);
+#ifdef INET6
+ inp->inp_vflag |= INP_IPV4;
+#endif
tp = tcp_newtcpcb(inp);
if (tp == 0) {
int nofd = so->so_state & SS_NOFDREF; /* XXX */
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 2f0cb58..f49a128 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -34,11 +34,14 @@
* $FreeBSD$
*/
+#include "opt_inet6.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
+#include <sys/domain.h>
#include <sys/proc.h>
#include <sys/protosw.h>
#include <sys/socket.h>
@@ -54,14 +57,24 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
+#ifdef INET6
+#include <netinet6/ip6_var.h>
+#endif
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#endif /*IPSEC*/
+
/*
* UDP protocol implementation.
* Per RFC 768, August, 1980.
@@ -83,6 +96,7 @@ SYSCTL_INT(_net_inet_udp, OID_AUTO, blackhole, CTLFLAG_RW,
&blackhole, 0, "Do not send port unreachables for refused connects");
struct inpcbhead udb; /* from udp_var.h */
+#define udb6 udb /* for KAME src sync over BSD*'s */
struct inpcbinfo udbinfo;
#ifndef UDBHASHSIZE
@@ -94,7 +108,27 @@ SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD,
&udpstat, udpstat, "UDP statistics (struct udpstat, netinet/udp_var.h)");
static struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
+#ifdef INET6
+struct udp_in6 {
+ struct sockaddr_in6 uin6_sin;
+ u_char uin6_init_done : 1;
+} udp_in6 = {
+ { sizeof(udp_in6.uin6_sin), AF_INET6 },
+ 0
+};
+struct udp_ip6 {
+ struct ip6_hdr uip6_ip6;
+ u_char uip6_init_done : 1;
+} udp_ip6;
+#endif /* INET6 */
+
+static void udp_append __P((struct inpcb *last, struct ip *ip,
+ struct mbuf *n, int off));
+#ifdef INET6
+static void ip_2_ip6_hdr __P((struct ip6_hdr *ip6, struct ip *ip));
+#endif
+static int udp_detach __P((struct socket *so));
static int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *,
struct mbuf *, struct proc *));
@@ -111,16 +145,18 @@ udp_init()
}
void
-udp_input(m, iphlen)
+udp_input(m, off, proto)
register struct mbuf *m;
- int iphlen;
+ int off, proto;
{
+ int iphlen = off;
register struct ip *ip;
register struct udphdr *uh;
register struct inpcb *inp;
struct mbuf *opts = 0;
int len;
struct ip save_ip;
+ struct sockaddr *append_sa;
udpstat.udps_ipackets++;
@@ -205,14 +241,19 @@ udp_input(m, iphlen)
*/
udp_in.sin_port = uh->uh_sport;
udp_in.sin_addr = ip->ip_src;
- m->m_len -= sizeof (struct udpiphdr);
- m->m_data += sizeof (struct udpiphdr);
/*
* Locate pcb(s) for datagram.
* (Algorithm copied from raw_intr().)
*/
last = NULL;
- for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
+#ifdef INET6
+ udp_in6.uin6_init_done = udp_ip6.uip6_init_done = 0;
+#endif
+ LIST_FOREACH(inp, &udb, inp_list) {
+#ifdef INET6
+ if ((inp->inp_vflag & INP_IPV4) == NULL)
+ continue;
+#endif
if (inp->inp_lport != uh->uh_dport)
continue;
if (inp->inp_laddr.s_addr != INADDR_ANY) {
@@ -230,21 +271,17 @@ udp_input(m, iphlen)
if (last != NULL) {
struct mbuf *n;
- if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
- if (last->inp_flags & INP_CONTROLOPTS
- || last->inp_socket->so_options & SO_TIMESTAMP)
- ip_savecontrol(last, &opts, ip, n);
- if (sbappendaddr(&last->inp_socket->so_rcv,
- (struct sockaddr *)&udp_in,
- n, opts) == 0) {
- m_freem(n);
- if (opts)
- m_freem(opts);
- udpstat.udps_fullsock++;
- } else
- sorwakeup(last->inp_socket);
- opts = 0;
- }
+#ifdef IPSEC
+ /* check AH/ESP integrity. */
+ if (ipsec4_in_reject_so(m, last->inp_socket))
+ ipsecstat.in_polvio++;
+ /* do not inject data to pcb */
+ else
+#endif /*IPSEC*/
+ if ((n = m_copy(m, 0, M_COPYALL)) != NULL)
+ udp_append(last, ip, n,
+ iphlen +
+ sizeof(struct udphdr));
}
last = inp;
/*
@@ -268,23 +305,21 @@ udp_input(m, iphlen)
udpstat.udps_noportbcast++;
goto bad;
}
- if (last->inp_flags & INP_CONTROLOPTS
- || last->inp_socket->so_options & SO_TIMESTAMP)
- ip_savecontrol(last, &opts, ip, m);
- if (sbappendaddr(&last->inp_socket->so_rcv,
- (struct sockaddr *)&udp_in,
- m, opts) == 0) {
- udpstat.udps_fullsock++;
+#ifdef IPSEC
+ /* check AH/ESP integrity. */
+ if (ipsec4_in_reject_so(m, last->inp_socket)) {
+ ipsecstat.in_polvio++;
goto bad;
}
- sorwakeup(last->inp_socket);
+#endif /*IPSEC*/
+ udp_append(last, ip, m, iphlen + sizeof(struct udphdr));
return;
}
/*
* Locate pcb for datagram.
*/
inp = in_pcblookup_hash(&udbinfo, ip->ip_src, uh->uh_sport,
- ip->ip_dst, uh->uh_dport, 1);
+ ip->ip_dst, uh->uh_dport, 1, m->m_pkthdr.rcvif);
if (inp == NULL) {
if (log_in_vain) {
char buf[4*sizeof "123"];
@@ -311,6 +346,12 @@ udp_input(m, iphlen)
goto bad;
return;
}
+#ifdef IPSEC
+ if (ipsec4_in_reject_so(m, inp->inp_socket)) {
+ ipsecstat.in_polvio++;
+ goto bad;
+ }
+#endif /*IPSEC*/
/*
* Construct sockaddr format source address.
@@ -319,14 +360,30 @@ udp_input(m, iphlen)
udp_in.sin_port = uh->uh_sport;
udp_in.sin_addr = ip->ip_src;
if (inp->inp_flags & INP_CONTROLOPTS
- || inp->inp_socket->so_options & SO_TIMESTAMP)
+ || inp->inp_socket->so_options & SO_TIMESTAMP) {
+#ifdef INET6
+ if (inp->inp_vflag & INP_IPV6) {
+ int savedflags;
+
+ ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip);
+ savedflags = inp->inp_flags;
+ inp->inp_flags &= ~INP_UNMAPPABLEOPTS;
+ ip6_savecontrol(inp, &opts, &udp_ip6.uip6_ip6, m);
+ inp->inp_flags = savedflags;
+ } else
+#endif
ip_savecontrol(inp, &opts, ip, m);
+ }
iphlen += sizeof(struct udphdr);
- m->m_len -= iphlen;
- m->m_pkthdr.len -= iphlen;
- m->m_data += iphlen;
- if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
- m, opts) == 0) {
+ m_adj(m, iphlen);
+#ifdef INET6
+ if (inp->inp_vflag & INP_IPV6) {
+ in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin);
+ append_sa = (struct sockaddr *)&udp_in6;
+ } else
+#endif
+ append_sa = (struct sockaddr *)&udp_in;
+ if (sbappendaddr(&inp->inp_socket->so_rcv, append_sa, m, opts) == 0) {
udpstat.udps_fullsock++;
goto bad;
}
@@ -336,6 +393,78 @@ bad:
m_freem(m);
if (opts)
m_freem(opts);
+ return;
+}
+
+#if defined(INET6)
+static void
+ip_2_ip6_hdr(ip6, ip)
+ struct ip6_hdr *ip6;
+ struct ip *ip;
+{
+ bzero(ip6, sizeof(*ip6));
+
+ ip6->ip6_vfc = IPV6_VERSION;
+ ip6->ip6_plen = ip->ip_len;
+ ip6->ip6_nxt = ip->ip_p;
+ ip6->ip6_hlim = ip->ip_ttl;
+ ip6->ip6_src.s6_addr32[2] = ip6->ip6_dst.s6_addr32[2] =
+ IPV6_ADDR_INT32_SMP;
+ ip6->ip6_src.s6_addr32[3] = ip->ip_src.s_addr;
+ ip6->ip6_dst.s6_addr32[3] = ip->ip_dst.s_addr;
+}
+#endif
+
+/*
+ * subroutine of udp_input(), mainly for source code readability.
+ * caller must properly init udp_ip6 and udp_in6 beforehand.
+ */
+static void
+udp_append(last, ip, n, off)
+ struct inpcb *last;
+ struct ip *ip;
+ struct mbuf *n;
+ int off;
+{
+ struct sockaddr *append_sa;
+ struct mbuf *opts = 0;
+
+ if (last->inp_flags & INP_CONTROLOPTS ||
+ last->inp_socket->so_options & SO_TIMESTAMP) {
+#ifdef INET6
+ if (last->inp_vflag & INP_IPV6) {
+ int savedflags;
+
+ if (udp_ip6.uip6_init_done == 0) {
+ ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip);
+ udp_ip6.uip6_init_done = 1;
+ }
+ savedflags = last->inp_flags;
+ last->inp_flags &= ~INP_UNMAPPABLEOPTS;
+ ip6_savecontrol(last, &opts, &udp_ip6.uip6_ip6, n);
+ last->inp_flags = savedflags;
+ } else
+#endif
+ ip_savecontrol(last, &opts, ip, n);
+ }
+#ifdef INET6
+ if (last->inp_vflag & INP_IPV6) {
+ if (udp_in6.uin6_init_done == 0) {
+ in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin);
+ udp_in6.uin6_init_done = 1;
+ }
+ append_sa = (struct sockaddr *)&udp_in6.uin6_sin;
+ } else
+#endif
+ append_sa = (struct sockaddr *)&udp_in;
+ m_adj(n, off);
+ if (sbappendaddr(&last->inp_socket->so_rcv, append_sa, n, opts) == 0) {
+ m_freem(n);
+ if (opts)
+ m_freem(opts);
+ udpstat.udps_fullsock++;
+ } else
+ sorwakeup(last->inp_socket);
}
/*
@@ -473,7 +602,7 @@ udp_getcred SYSCTL_HANDLER_ARGS
return (error);
s = splnet();
inp = in_pcblookup_hash(&udbinfo, addrs[1].sin_addr, addrs[1].sin_port,
- addrs[0].sin_addr, addrs[0].sin_port, 1);
+ addrs[0].sin_addr, addrs[0].sin_port, 1, NULL);
if (inp == NULL || inp->inp_socket == NULL) {
error = ENOENT;
goto out;
@@ -570,6 +699,11 @@ udp_output(inp, m, addr, control, p)
((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */
((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
udpstat.udps_opackets++;
+
+#ifdef IPSEC
+ m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket;
+#endif /*IPSEC*/
+
error = ip_output(m, inp->inp_options, &inp->inp_route,
inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
inp->inp_moptions);
@@ -591,7 +725,13 @@ u_long udp_sendspace = 9216; /* really max datagram size */
SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
&udp_sendspace, 0, "Maximum outgoing UDP datagram size");
-u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
+u_long udp_recvspace = 40 * (1024 +
+#ifdef INET6
+ sizeof(struct sockaddr_in6)
+#else
+ sizeof(struct sockaddr_in)
+#endif
+ );
SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
&udp_recvspace, 0, "Maximum incoming UDP datagram size");
@@ -621,15 +761,27 @@ udp_attach(struct socket *so, int proto, struct proc *p)
if (inp != 0)
return EINVAL;
+ error = soreserve(so, udp_sendspace, udp_recvspace);
+ if (error)
+ return error;
s = splnet();
error = in_pcballoc(so, &udbinfo, p);
splx(s);
if (error)
return error;
- error = soreserve(so, udp_sendspace, udp_recvspace);
- if (error)
+
+ inp = (struct inpcb *)so->so_pcb;
+#ifdef INET6
+ inp->inp_vflag |= INP_IPV4;
+#endif
+ inp->inp_ip_ttl = ip_defttl;
+#ifdef IPSEC
+ error = ipsec_init_policy(so, &inp->inp_sp);
+ if (error != 0) {
+ in_pcbdetach(inp);
return error;
- ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl;
+ }
+#endif /*IPSEC*/
return 0;
}
diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h
index 0ee8258..491632e 100644
--- a/sys/netinet/udp_var.h
+++ b/sys/netinet/udp_var.h
@@ -115,7 +115,7 @@ extern int log_in_vain;
void udp_ctlinput __P((int, struct sockaddr *, void *));
void udp_init __P((void));
-void udp_input __P((struct mbuf *, int));
+void udp_input __P((struct mbuf *, int, int));
void udp_notify __P((struct inpcb *inp, int errno));
int udp_shutdown __P((struct socket *so));
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 425a5d5..943ddf7 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -64,7 +64,6 @@
* @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
*/
-#include "opt_inet.h"
#include "opt_key.h"
#include <sys/param.h>
@@ -97,15 +96,10 @@
#ifdef IPSEC
#include <netinet6/ipsec.h>
-#ifdef INET6
#include <netinet6/ipsec6.h>
-#endif /* INET6 */
#include <netkey/key.h>
#ifdef KEY_DEBUG
#include <netkey/key_debug.h>
-#ifdef INET6
-#include <netkey/key_debug6.h>
-#endif /* INET6 */
#else
#define DPRINTF(lev,arg)
#define DDO(lev, stmt)
@@ -113,7 +107,7 @@
#endif /* KEY_DEBUG */
#endif /* IPSEC */
-/* #include "faith.h" */
+#include "faith.h"
#include <net/net_osdep.h>
@@ -910,8 +904,7 @@ ni6_addrs(ni6, m, ifpp)
for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
{
addrsofif = 0;
- for (ifa = ifp->if_addrlist.tqh_first; ifa;
- ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -976,8 +969,7 @@ ni6_store_addrs(ni6, nni6, ifp0, resid)
for (; ifp; ifp = TAILQ_NEXT(ifp, if_list))
{
- for (ifa = ifp->if_addrlist.tqh_first; ifa;
- ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
docopy = 0;
diff --git a/sys/netinet6/icmp6.h b/sys/netinet6/icmp6.h
index 8fd63ff..2fdb28b 100644
--- a/sys/netinet6/icmp6.h
+++ b/sys/netinet6/icmp6.h
@@ -516,6 +516,9 @@ struct icmp6stat {
#define RTF_PROBEMTU RTF_PROTO1
#ifdef _KERNEL
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_net_inet6_icmp6);
+#endif
# ifdef __STDC__
struct rtentry;
struct rttimer;
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index e18b14f..a981c79 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -64,8 +64,6 @@
* @(#)in.c 8.2 (Berkeley) 11/15/93
*/
-#include "opt_inet.h"
-
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/malloc.h>
@@ -81,10 +79,8 @@
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
-/* #include "gif.h" */
-#if NGIF > 0
-#include <net/if_gif.h>
-#endif
+#include "gif.h"
+
#include <net/if_dl.h>
#include <netinet/in.h>
@@ -96,6 +92,9 @@
#include <netinet6/ip6_var.h>
#include <netinet6/mld6_var.h>
#include <netinet6/in6_ifattach.h>
+#if NGIF > 0
+#include <net/if_gif.h>
+#endif
#include <net/net_osdep.h>
@@ -348,7 +347,7 @@ in6_ifindex2scopeid(idx)
return -1;
ifp = ifindex2ifnet[idx];
- for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -1059,9 +1058,7 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
}
}
- for (ifa = ifp->if_addrlist.tqh_first;
- ifa;
- ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -1311,7 +1308,7 @@ in6ifa_ifpforlinklocal(ifp)
{
register struct ifaddr *ifa;
- for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr == NULL)
continue; /* just for safety */
@@ -1335,7 +1332,7 @@ in6ifa_ifpwithaddr(ifp, addr)
{
register struct ifaddr *ifa;
- for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr == NULL)
continue; /* just for safety */
@@ -1575,7 +1572,7 @@ in6_ifawithscope(ifp, dst)
* If two or more, return one which matches the dst longest.
* If none, return one of global addresses assigned other ifs.
*/
- for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -1661,7 +1658,7 @@ in6_ifawithifp(ifp, dst)
* If two or more, return one which matches the dst longest.
* If none, return one of global addresses assigned other ifs.
*/
- for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -1696,7 +1693,7 @@ in6_ifawithifp(ifp, dst)
if (besta)
return(besta);
- for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -1742,7 +1739,7 @@ in6_if_up(ifp)
bzero(&ea, sizeof(ea));
sdl = NULL;
- for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family == AF_INET6
&& IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) {
@@ -1789,7 +1786,7 @@ in6_if_up(ifp)
dad:
dad_delay = 0;
- for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h
index 1ca678e..b5266ce 100644
--- a/sys/netinet6/in6.h
+++ b/sys/netinet6/in6.h
@@ -74,6 +74,7 @@
* Identification of the network protocol stack
*/
#define __KAME__
+#define __KAME_VERSION "SNAP 19991101"
/*
* Local port number conventions:
@@ -343,13 +344,6 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
#endif
/*
- * Wildcard Socket
- */
-#if 0 /*pre-RFC2553*/
-#define IN6_IS_ADDR_ANY(a) IN6_IS_ADDR_UNSPECIFIED(a)
-#endif
-
-/*
* KAME Scope
*/
#ifdef _KERNEL /*nonstandard*/
@@ -522,65 +516,12 @@ struct in6_pktinfo {
#define IPV6CTL_AUTO_FLOWLABEL 17
#define IPV6CTL_DEFMCASTHLIM 18
#define IPV6CTL_GIF_HLIM 19 /* default HLIM for gif encap packet */
+#define IPV6CTL_KAME_VERSION 20
#define IPV6CTL_USE_DEPRECATED 21 /* use deprecated addr (RFC2462 5.5.4) */
#define IPV6CTL_RR_PRUNE 22 /* walk timer for router renumbering */
#define IPV6CTL_MAPPED_ADDR 23
/* New entries should be added here from current IPV6CTL_MAXID value. */
#define IPV6CTL_MAXID 24
-
-#define IPV6CTL_NAMES { \
- { 0, 0 }, \
- { "forwarding", CTLTYPE_INT }, \
- { "redirect", CTLTYPE_INT }, \
- { "hlim", CTLTYPE_INT }, \
- { "mtu", CTLTYPE_INT }, \
- { "forwsrcrt", CTLTYPE_INT }, \
- { 0, 0 }, \
- { 0, 0 }, \
- { "mrtproto", CTLTYPE_INT }, \
- { "maxfragpackets", CTLTYPE_INT }, \
- { "sourcecheck", CTLTYPE_INT }, \
- { "sourcecheck_logint", CTLTYPE_INT }, \
- { "accept_rtadv", CTLTYPE_INT }, \
- { "keepfaith", CTLTYPE_INT }, \
- { "log_interval", CTLTYPE_INT }, \
- { "hdrnestlimit", CTLTYPE_INT }, \
- { "dad_count", CTLTYPE_INT }, \
- { "auto_flowlabel", CTLTYPE_INT }, \
- { "defmcasthlim", CTLTYPE_INT }, \
- { "gifhlim", CTLTYPE_INT }, \
- { 0, 0 }, \
- { "use_deprecated", CTLTYPE_INT }, \
- { "rr_prune", CTLTYPE_INT }, \
- { "mapped_addr", CTLTYPE_INT }, \
-}
-
-#define IPV6CTL_VARS { \
- 0, \
- &ip6_forwarding, \
- &ip6_sendredirects, \
- &ip6_defhlim, \
- 0, \
- &ip6_forward_srcrt, \
- 0, \
- 0, \
- 0, \
- &ip6_maxfragpackets, \
- &ip6_sourcecheck, \
- &ip6_sourcecheck_interval, \
- &ip6_accept_rtadv, \
- &ip6_keepfaith, \
- &ip6_log_interval, \
- &ip6_hdrnestlimit, \
- &ip6_dad_count, \
- &ip6_auto_flowlabel, \
- &ip6_defmcasthlim, \
- &ip6_gif_hlim, \
- 0, \
- &ip6_use_deprecated, \
- &ip6_rr_prune, \
- &ip6_mapped_addr_on, \
-}
#endif /* !_XOPEN_SOURCE */
/*
@@ -633,9 +574,6 @@ extern struct cmsghdr *inet6_rthdr_init __P((void *, int));
extern int inet6_rthdr_add __P((struct cmsghdr *, const struct in6_addr *,
u_int));
extern int inet6_rthdr_lasthop __P((struct cmsghdr *, u_int));
-#if 0 /* not implemented yet */
-extern int inet6_rthdr_reverse __P((const struct cmsghdr *, struct cmsghdr *));
-#endif
extern int inet6_rthdr_segments __P((const struct cmsghdr *));
extern struct in6_addr *inet6_rthdr_getaddr __P((struct cmsghdr *, int));
extern int inet6_rthdr_getflags __P((const struct cmsghdr *, int));
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
new file mode 100644
index 0000000..dd7cd2f
--- /dev/null
+++ b/sys/netinet6/in6_gif.c
@@ -0,0 +1,263 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * in6_gif.c
+ */
+
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#ifdef INET
+#include <netinet/ip.h>
+#endif
+#include <netinet6/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/in6_gif.h>
+#include <netinet6/ip6.h>
+
+#include <net/if_gif.h>
+
+#include <net/net_osdep.h>
+
+int
+in6_gif_output(ifp, family, m, rt)
+ struct ifnet *ifp;
+ int family; /* family of the packet to be encapsulate. */
+ struct mbuf *m;
+ struct rtentry *rt;
+{
+ struct gif_softc *sc = (struct gif_softc*)ifp;
+ struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
+ struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
+ struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
+ struct ip6_hdr *ip6;
+ int proto;
+
+ if (sin6_src == NULL || sin6_dst == NULL ||
+ sin6_src->sin6_family != AF_INET6 ||
+ sin6_dst->sin6_family != AF_INET6) {
+ m_freem(m);
+ return EAFNOSUPPORT;
+ }
+
+ switch (family) {
+#ifdef INET
+ case AF_INET:
+ {
+ struct ip *ip;
+
+ proto = IPPROTO_IPV4;
+ if (m->m_len < sizeof(*ip)) {
+ m = m_pullup(m, sizeof(*ip));
+ if (!m)
+ return ENOBUFS;
+ }
+ ip = mtod(m, struct ip *);
+ break;
+ }
+#endif
+ case AF_INET6:
+ {
+ struct ip6_hdr *ip6;
+ proto = IPPROTO_IPV6;
+ if (m->m_len < sizeof(*ip6)) {
+ m = m_pullup(m, sizeof(*ip6));
+ if (!m)
+ return ENOBUFS;
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+ break;
+ }
+ default:
+#ifdef DIAGNOSTIC
+ printf("in6_gif_output: warning: unknown family %d passed\n",
+ family);
+#endif
+ m_freem(m);
+ return EAFNOSUPPORT;
+ }
+
+ /* prepend new IP header */
+ M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
+ if (m && m->m_len < sizeof(struct ip6_hdr))
+ m = m_pullup(m, sizeof(struct ip6_hdr));
+ if (m == NULL) {
+ printf("ENOBUFS in in6_gif_output %d\n", __LINE__);
+ return ENOBUFS;
+ }
+
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_flow = 0;
+ ip6->ip6_vfc = IPV6_VERSION;
+ ip6->ip6_plen = htons((u_short)m->m_pkthdr.len);
+ ip6->ip6_nxt = proto;
+ ip6->ip6_hlim = ip6_gif_hlim;
+ ip6->ip6_src = sin6_src->sin6_addr;
+ if (ifp->if_flags & IFF_LINK0) {
+ /* multi-destination mode */
+ if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
+ ip6->ip6_dst = sin6_dst->sin6_addr;
+ else if (rt) {
+ ip6->ip6_dst = ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr;
+ } else {
+ m_freem(m);
+ return ENETUNREACH;
+ }
+ } else {
+ /* bidirectional configured tunnel mode */
+ if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
+ ip6->ip6_dst = sin6_dst->sin6_addr;
+ else {
+ m_freem(m);
+ return ENETUNREACH;
+ }
+ }
+
+ if (dst->sin6_family != sin6_dst->sin6_family ||
+ !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
+ /* cache route doesn't match */
+ bzero(dst, sizeof(*dst));
+ dst->sin6_family = sin6_dst->sin6_family;
+ dst->sin6_len = sizeof(struct sockaddr_in6);
+ dst->sin6_addr = sin6_dst->sin6_addr;
+ if (sc->gif_ro6.ro_rt) {
+ RTFREE(sc->gif_ro6.ro_rt);
+ sc->gif_ro6.ro_rt = NULL;
+ }
+ }
+
+ if (sc->gif_ro6.ro_rt == NULL) {
+ rtalloc((struct route *)&sc->gif_ro6);
+ if (sc->gif_ro6.ro_rt == NULL) {
+ m_freem(m);
+ return ENETUNREACH;
+ }
+ }
+
+#ifdef IPSEC
+ m->m_pkthdr.rcvif = NULL;
+#endif /*IPSEC*/
+ return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL));
+}
+
+int in6_gif_input(mp, offp, proto)
+ struct mbuf **mp;
+ int *offp, proto;
+{
+ struct mbuf *m = *mp;
+ struct gif_softc *sc;
+ struct ifnet *gifp = NULL;
+ struct ip6_hdr *ip6;
+ int i;
+ int af = 0;
+
+ ip6 = mtod(m, struct ip6_hdr *);
+
+#define satoin6(sa) (((struct sockaddr_in6 *)(sa))->sin6_addr)
+ for (i = 0, sc = gif; i < ngif; i++, sc++) {
+ if (sc->gif_psrc == NULL ||
+ sc->gif_pdst == NULL ||
+ sc->gif_psrc->sa_family != AF_INET6 ||
+ sc->gif_pdst->sa_family != AF_INET6) {
+ continue;
+ }
+ if ((sc->gif_if.if_flags & IFF_UP) == 0)
+ continue;
+ if ((sc->gif_if.if_flags & IFF_LINK0) &&
+ IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) &&
+ IN6_IS_ADDR_UNSPECIFIED(&satoin6(sc->gif_pdst))) {
+ gifp = &sc->gif_if;
+ continue;
+ }
+ if (IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) &&
+ IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_pdst), &ip6->ip6_src)) {
+ gifp = &sc->gif_if;
+ break;
+ }
+ }
+
+ if (gifp == NULL) {
+ m_freem(m);
+ ip6stat.ip6s_nogif++;
+ return IPPROTO_DONE;
+ }
+
+ m_adj(m, *offp);
+
+ switch (proto) {
+#ifdef INET
+ case IPPROTO_IPV4:
+ {
+ struct ip *ip;
+ af = AF_INET;
+ if (m->m_len < sizeof(*ip)) {
+ m = m_pullup(m, sizeof(*ip));
+ if (!m)
+ return IPPROTO_DONE;
+ }
+ ip = mtod(m, struct ip *);
+ break;
+ }
+#endif /* INET */
+ case IPPROTO_IPV6:
+ {
+ struct ip6_hdr *ip6;
+ af = AF_INET6;
+ if (m->m_len < sizeof(*ip6)) {
+ m = m_pullup(m, sizeof(*ip6));
+ if (!m)
+ return IPPROTO_DONE;
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+ break;
+ }
+ default:
+ ip6stat.ip6s_nogif++;
+ m_freem(m);
+ return IPPROTO_DONE;
+ }
+
+ gif_input(m, af, gifp);
+ return IPPROTO_DONE;
+}
diff --git a/sys/netinet6/in6_gif.h b/sys/netinet6/in6_gif.h
new file mode 100644
index 0000000..7d06c3c
--- /dev/null
+++ b/sys/netinet6/in6_gif.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NETINET6_IN6_GIF_H_
+#define _NETINET6_IN6_GIF_H_
+
+#define GIF_HLIM 30
+
+int in6_gif_input __P((struct mbuf **, int *, int));
+int in6_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *));
+
+#endif /*_NETINET6_IN6_GIF_H_*/
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index 85ca75f..7d332ed 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -153,13 +153,11 @@ in6_ifattach_getifid(ifp0)
if (found_first_ifid)
return 0;
- for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
+ TAILQ_FOREACH(ifp, &ifnet, if_list)
{
if (ifp0 != NULL && ifp0 != ifp)
continue;
- for (ifa = ifp->if_addrlist.tqh_first;
- ifa;
- ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family != AF_LINK)
continue;
@@ -239,7 +237,7 @@ in6_ifattach_p2p()
if (found_first_ifid == 0)
return;
- for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
+ TAILQ_FOREACH(ifp, &ifnet, if_list)
{
switch (ifp->if_type) {
case IFT_GIF:
@@ -645,7 +643,7 @@ in6_ifdetach(ifp)
struct rtentry *rt;
short rtflags;
- for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family != AF_INET6
|| !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 8aee5b3..ac5b923 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -65,7 +65,6 @@
* $FreeBSD$
*/
-#include "opt_inet.h"
#include "opt_key.h"
#include <sys/param.h>
@@ -96,19 +95,14 @@
#include <netinet/in_pcb.h>
#include <netinet6/in6_pcb.h>
-/* #include "faith.h" */
+#include "faith.h"
#ifdef IPSEC
#include <netinet6/ipsec.h>
-#ifdef INET6
#include <netinet6/ipsec6.h>
-#endif /* INET6 */
#include <netkey/key.h>
#ifdef KEY_DEBUG
#include <netkey/key_debug.h>
-#ifdef INET6
-#include <netkey/key_debug6.h>
-#endif /* INET6 */
#else
#define DPRINTF(lev,arg)
#define DDO(lev, stmt)
@@ -1065,7 +1059,7 @@ in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp)
head = &pcbinfo->hashbase[INP_PCBHASH(faddr->s6_addr32[3] /* XXX */,
lport, fport,
pcbinfo->hashmask)];
- for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
+ LIST_FOREACH(inp, head, inp_hash) {
if ((inp->inp_vflag & INP_IPV6) == NULL)
continue;
if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) &&
@@ -1083,8 +1077,7 @@ in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp)
head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0,
pcbinfo->hashmask)];
- for (inp = head->lh_first; inp != NULL;
- inp = inp->inp_hash.le_next) {
+ LIST_FOREACH(inp, head, inp_hash) {
if ((inp->inp_vflag & INP_IPV6) == NULL)
continue;
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) &&
diff --git a/sys/netinet6/in6_prefix.c b/sys/netinet6/in6_prefix.c
index 8da07c4..6799d0d 100644
--- a/sys/netinet6/in6_prefix.c
+++ b/sys/netinet6/in6_prefix.c
@@ -184,7 +184,7 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr)
* which matches the addr
*/
- for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -249,7 +249,7 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr)
* search matched addr, and then search prefixes
* which matche the addr
*/
- for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
struct rr_prefix *rpp;
@@ -364,8 +364,7 @@ search_ifidwithprefix(struct rr_prefix *rpp, struct in6_addr *ifid)
{
struct rp_addr *rap;
- for (rap = rpp->rp_addrhead.lh_first; rap != NULL;
- rap = rap->ra_entry.le_next)
+ LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry)
if (rr_are_ifid_equal(ifid, &rap->ra_ifid,
(sizeof(struct in6_addr) << 3) -
rpp->rp_plen))
@@ -682,8 +681,7 @@ rrpr_update(struct socket *so, struct rr_prefix *new)
* If it existed but not pointing to the prefix yet,
* init the prefix pointer.
*/
- for (rap = rpp->rp_addrhead.lh_first; rap != NULL;
- rap = rap->ra_entry.le_next) {
+ LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry) {
if (rap->ra_addr != NULL) {
if (rap->ra_addr->ia6_ifpr == NULL)
rap->ra_addr->ia6_ifpr = rp2ifpr(rpp);
@@ -771,8 +769,7 @@ init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr,
irr->irr_u_uselen,
min(ifpr->ifpr_plen - irr->irr_u_uselen,
irr->irr_u_keeplen));
- for (orap = (ifpr2rp(ifpr)->rp_addrhead).lh_first; orap != NULL;
- orap = orap->ra_entry.le_next) {
+ LIST_FOREACH(orap, &(ifpr2rp(ifpr)->rp_addrhead), ra_entry) {
struct rp_addr *rap;
int error = 0;
@@ -845,8 +842,7 @@ unprefer_prefix(struct rr_prefix *rpp)
{
struct rp_addr *rap;
- for (rap = rpp->rp_addrhead.lh_first; rap != NULL;
- rap = rap->ra_entry.le_next) {
+ LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry) {
if (rap->ra_addr == NULL)
continue;
rap->ra_addr->ia6_lifetime.ia6t_preferred = time_second;
@@ -863,7 +859,7 @@ delete_each_prefix(struct socket *so, struct rr_prefix *rpp, u_char origin)
if (rpp->rp_origin > origin)
return(EPERM);
- while (rpp->rp_addrhead.lh_first != NULL) {
+ while (!LIST_EMPTY(&rpp->rp_addrhead)) {
struct rp_addr *rap;
int s;
@@ -923,8 +919,7 @@ link_stray_ia6s(struct rr_prefix *rpp)
{
struct ifaddr *ifa;
- for (ifa = rpp->rp_ifp->if_addrlist.tqh_first; ifa;
- ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &rpp->rp_ifp->if_addrlist, ifa_list)
{
struct rp_addr *rap;
struct rr_prefix *orpp;
diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c
index 1d1c7a3..3f59ec2 100644
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -64,8 +64,6 @@
* @(#)in_proto.c 8.1 (Berkeley) 6/10/93
*/
-#include "opt_inet.h"
-
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
@@ -104,9 +102,7 @@
#ifdef IPSEC
#include <netinet6/ipsec.h>
-#ifdef INET6
#include <netinet6/ipsec6.h>
-#endif /* INET6 */
#include <netinet6/ah.h>
#ifdef IPSEC_ESP
#include <netinet6/esp.h>
@@ -116,7 +112,7 @@
#include <netinet6/ip6protosw.h>
-/* #include "gif.h" */
+#include "gif.h"
#if NGIF > 0
#include <netinet6/in6_gif.h>
#endif
@@ -139,6 +135,12 @@ struct ip6protosw inet6sw[] = {
ip6_init, 0, frag6_slowtimo, frag6_drain,
&nousrreqs,
},
+{ SOCK_DGRAM, &inet6domain, IPPROTO_UDP, PR_ATOMIC | PR_ADDR,
+ udp6_input, 0, udp6_ctlinput, ip6_ctloutput,
+ 0,
+ 0, 0, 0, 0,
+ &udp6_usrreqs,
+},
{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC | PR_ADDR,
rip6_input, rip6_output, 0, rip6_ctloutput,
0,
@@ -194,18 +196,16 @@ struct ip6protosw inet6sw[] = {
#if NGIF > 0
{ SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR,
in6_gif_input,0, 0, 0,
- 0,
+ 0,
0, 0, 0, 0,
&nousrreqs
},
-#ifdef INET6
{ SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR,
in6_gif_input,0, 0, 0,
- 0,
+ 0,
0, 0, 0, 0,
&nousrreqs
},
-#endif /* INET6 */
#endif /* GIF */
/* raw wildcard */
{ SOCK_RAW, &inet6domain, 0, PR_ATOMIC | PR_ADDR,
@@ -334,8 +334,8 @@ sysctl_ip6_forwarding SYSCTL_HANDLER_ARGS
int s = splnet();
struct nd_prefix *pr, *next;
- for (pr = nd_prefix.lh_first; pr; pr = next) {
- next = pr->ndpr_next;
+ for (pr = LIST_FIRST(&nd_prefix); pr; pr = next) {
+ next = LIST_NEXT(pr, ndpr_entry);
if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr);
prelist_remove(pr);
@@ -379,6 +379,8 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_DEFMCASTHLIM,
defmcasthlim, CTLFLAG_RW, &ip6_defmcasthlim, 0, "");
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM,
gifhlim, CTLFLAG_RW, &ip6_gif_hlim, 0, "");
+SYSCTL_STRING(_net_inet6_ip6, IPV6CTL_KAME_VERSION,
+ kame_version, CTLFLAG_RD, __KAME_VERSION, 0, "");
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_USE_DEPRECATED,
use_deprecated, CTLFLAG_RW, &ip6_use_deprecated, 0, "");
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RR_PRUNE,
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index 4117c20..163c167 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -437,7 +437,7 @@ MALLOC_DECLARE(M_IPMADDR);
/* struct in6_ifaddr *ia; */ \
do { \
struct ifaddr *ifa; \
- for (ifa = (ifp)->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { \
+ TAILQ_FOREACH(ifa, &(ifp)->if_addrlist, ifa_list) { \
if (!ifa->ifa_addr) \
continue; \
if (ifa->ifa_addr->sa_family == AF_INET6) \
@@ -467,6 +467,11 @@ struct in6_multi {
};
#ifdef _KERNEL
+
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_net_inet6_ip6);
+#endif
+
extern LIST_HEAD(in6_multihead, in6_multi) in6_multihead;
/*
@@ -512,14 +517,14 @@ do { \
/* struct in6_multi *in6m; */ \
do { \
if (((in6m) = (step).i_in6m) != NULL) \
- (step).i_in6m = (step).i_in6m->in6m_entry.le_next; \
+ (step).i_in6m = LIST_NEXT((step).i_in6m, in6m_entry); \
} while(0)
#define IN6_FIRST_MULTI(step, in6m) \
/* struct in6_multistep step; */ \
/* struct in6_multi *in6m */ \
do { \
- (step).i_in6m = in6_multihead.lh_first; \
+ (step).i_in6m = LIST_FIRST(&in6_multihead); \
IN6_NEXT_MULTI((step), (in6m)); \
} while(0)
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index a50ba6c..46b3188 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -29,7 +29,6 @@
* $FreeBSD$
*/
-#include "opt_inet.h"
#include "opt_key.h"
#include <sys/param.h>
@@ -56,15 +55,10 @@
#ifdef IPSEC_IPV6FWD
#include <netinet6/ipsec.h>
-#ifdef INET6
#include <netinet6/ipsec6.h>
-#endif /* INET6 */
#include <netkey/key.h>
#ifdef KEY_DEBUG
#include <netkey/key_debug.h>
-#ifdef INET6
-#include <netkey/key_debug6.h>
-#endif /* INET6 */
#else
#define DPRINTF(lev,arg)
#define DDO(lev, stmt)
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 097d5a0..105b4bc 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -64,8 +64,6 @@
* @(#)ip_input.c 8.2 (Berkeley) 1/4/94
*/
-#include "opt_inet.h"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -88,10 +86,8 @@
#include <netinet/in.h>
#include <netinet/in_systm.h>
-#ifdef INET
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
-#endif /*INET*/
#include <netinet/in_pcb.h>
#include <netinet6/in6_var.h>
#include <netinet6/ip6.h>
@@ -113,9 +109,9 @@
/* we need it for NLOOP. */
#include "loop.h"
-/* #include "faith.h" */
-/* #include "gif.h" */
+#include "faith.h"
+#include "gif.h"
#include <net/net_osdep.h>
@@ -793,7 +789,6 @@ ip6_savecontrol(in6p, mp, ip6, m)
if (p && !suser(p))
privileged++;
-#ifdef SO_TIMESTAMP
if (in6p->in6p_socket->so_options & SO_TIMESTAMP) {
struct timeval tv;
@@ -803,7 +798,6 @@ ip6_savecontrol(in6p, mp, ip6, m)
if (*mp)
mp = &(*mp)->m_next;
}
-#endif
if (in6p->in6p_flags & IN6P_RECVDSTADDR) {
*mp = sbcreatecontrol((caddr_t) &ip6->ip6_dst,
sizeof(struct in6_addr), IPV6_RECVDSTADDR,
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index de85510..1524bc3 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -64,7 +64,6 @@
* @(#)ip_output.c 8.3 (Berkeley) 1/21/94
*/
-#include "opt_inet.h"
#include "opt_key.h"
#include <sys/param.h>
@@ -91,15 +90,10 @@
#ifdef IPSEC
#include <netinet6/ipsec.h>
-#ifdef INET6
#include <netinet6/ipsec6.h>
-#endif /* INET6 */
#include <netkey/key.h>
#ifdef KEY_DEBUG
#include <netkey/key_debug.h>
-#ifdef INET6
-#include <netkey/key_debug6.h>
-#endif /* INET6 */
#else
#define DPRINTF(lev,arg)
#define DDO(lev, stmt)
@@ -1764,8 +1758,7 @@ ip6_setmoptions(optname, im6op, m)
/*
* See if the membership already exists.
*/
- for (imm = im6o->im6o_memberships.lh_first;
- imm != NULL; imm = imm->i6mm_chain.le_next)
+ LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain)
if (imm->i6mm_maddr->in6m_ifp == ifp &&
IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
&mreq->ipv6mr_multiaddr))
@@ -1831,8 +1824,7 @@ ip6_setmoptions(optname, im6op, m)
/*
* Find the membership in the membership list.
*/
- for (imm = im6o->im6o_memberships.lh_first;
- imm != NULL; imm = imm->i6mm_chain.le_next) {
+ LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain) {
if ((ifp == NULL ||
imm->i6mm_maddr->in6m_ifp == ifp) &&
IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
@@ -1864,7 +1856,7 @@ ip6_setmoptions(optname, im6op, m)
if (im6o->im6o_multicast_ifp == NULL &&
im6o->im6o_multicast_hlim == ip6_defmcasthlim &&
im6o->im6o_multicast_loop == IPV6_DEFAULT_MULTICAST_LOOP &&
- im6o->im6o_memberships.lh_first == NULL) {
+ LIST_EMPTY(&im6o->im6o_memberships)) {
free(*im6op, M_IPMOPTS);
*im6op = NULL;
}
@@ -1931,7 +1923,7 @@ ip6_freemoptions(im6o)
if (im6o == NULL)
return;
- while ((imm = im6o->im6o_memberships.lh_first) != NULL) {
+ while ((imm = LIST_FIRST(&im6o->im6o_memberships)) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
if (imm->i6mm_maddr)
in6_delmulti(imm->i6mm_maddr);
diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c
index 43cb9b7..634f61b 100644
--- a/sys/netinet6/mld6.c
+++ b/sys/netinet6/mld6.c
@@ -68,8 +68,6 @@
* @(#)igmp.c 8.1 (Berkeley) 7/19/93
*/
-#include "opt_inet.h"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index 87eab9d..74787f2 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -458,17 +458,17 @@ nd6_timer(ignored_arg)
}
/* expire */
- dr = nd_defrouter.lh_first;
+ dr = LIST_FIRST(&nd_defrouter);
while (dr) {
if (dr->expire && dr->expire < time_second) {
struct nd_defrouter *t;
- t = dr->dr_next;
+ t = LIST_NEXT(dr, dr_entry);
defrtrlist_del(dr);
dr = t;
} else
- dr = dr->dr_next;
+ dr = LIST_NEXT(dr, dr_entry);
}
- pr = nd_prefix.lh_first;
+ pr = LIST_FIRST(&nd_prefix);
while (pr) {
struct in6_ifaddr *ia6;
struct in6_addrlifetime *lt6;
@@ -503,7 +503,7 @@ nd6_timer(ignored_arg)
if (pr->ndpr_expire
&& pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) {
struct nd_prefix *t;
- t = pr->ndpr_next;
+ t = LIST_NEXT(pr, ndpr_entry);
/*
* address expiration and prefix expiration are
@@ -513,7 +513,7 @@ nd6_timer(ignored_arg)
prelist_remove(pr);
pr = t;
} else
- pr = pr->ndpr_next;
+ pr = LIST_NEXT(pr, ndpr_entry);
}
splx(s);
}
@@ -627,9 +627,7 @@ nd6_is_addr_neighbor(addr, ifp)
* If the address matches one of our addresses,
* it should be a neighbor.
*/
- for (ifa = ifp->if_addrlist.tqh_first;
- ifa;
- ifa = ifa->ifa_list.tqe_next)
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
next: continue;
@@ -967,7 +965,7 @@ nd6_ioctl(cmd, data, ifp)
case SIOCGDRLST_IN6:
bzero(drl, sizeof(*drl));
s = splnet();
- dr = nd_defrouter.lh_first;
+ dr = LIST_FIRST(&nd_defrouter);
while (dr && i < DRLSTSIZ) {
drl->defrouter[i].rtaddr = dr->rtaddr;
if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) {
@@ -984,14 +982,14 @@ nd6_ioctl(cmd, data, ifp)
drl->defrouter[i].expire = dr->expire;
drl->defrouter[i].if_index = dr->ifp->if_index;
i++;
- dr = dr->dr_next;
+ dr = LIST_NEXT(dr, dr_entry);
}
splx(s);
break;
case SIOCGPRLST_IN6:
bzero(prl, sizeof(*prl));
s = splnet();
- pr = nd_prefix.lh_first;
+ pr = LIST_FIRST(&nd_prefix);
while (pr && i < PRLSTSIZ) {
struct nd_pfxrouter *pfr;
int j;
@@ -1004,7 +1002,7 @@ nd6_ioctl(cmd, data, ifp)
prl->prefix[i].if_index = pr->ndpr_ifp->if_index;
prl->prefix[i].expire = pr->ndpr_expire;
- pfr = pr->ndpr_advrtrs.lh_first;
+ pfr = LIST_FIRST(&pr->ndpr_advrtrs);
j = 0;
while(pfr) {
if (j < DRLSTSIZ) {
@@ -1022,12 +1020,12 @@ nd6_ioctl(cmd, data, ifp)
#undef RTRADDR
}
j++;
- pfr = pfr->pfr_next;
+ pfr = LIST_NEXT(pfr, pfr_entry);
}
prl->prefix[i].advrtrs = j;
i++;
- pr = pr->ndpr_next;
+ pr = LIST_NEXT(pr, ndpr_entry);
}
splx(s);
{
@@ -1069,8 +1067,8 @@ nd6_ioctl(cmd, data, ifp)
struct nd_prefix *pr, *next;
s = splnet();
- for (pr = nd_prefix.lh_first; pr; pr = next) {
- next = pr->ndpr_next;
+ for (pr = LIST_FIRST(&nd_prefix); pr; pr = next) {
+ next = LIST_NEXT(pr, ndpr_entry);
if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr);
prelist_remove(pr);
@@ -1084,16 +1082,16 @@ nd6_ioctl(cmd, data, ifp)
struct nd_defrouter *dr, *next;
s = splnet();
- if ((dr = nd_defrouter.lh_first) != NULL) {
+ if ((dr = LIST_FIRST(&nd_defrouter)) != NULL) {
/*
* The first entry of the list may be stored in
* the routing table, so we'll delete it later.
*/
- for (dr = dr->dr_next; dr; dr = next) {
- next = dr->dr_next;
+ for (dr = LIST_NEXT(dr, dr_entry); dr; dr = next) {
+ next = LIST_NEXT(dr, dr_entry);
defrtrlist_del(dr);
}
- defrtrlist_del(nd_defrouter.lh_first);
+ defrtrlist_del(LIST_FIRST(&nd_defrouter));
}
splx(s);
break;
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index 2bb4fe4..756f495 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -126,7 +126,6 @@ struct in6_ndireq {
struct nd_defrouter {
LIST_ENTRY(nd_defrouter) dr_entry;
-#define dr_next dr_entry.le_next
struct in6_addr rtaddr;
u_char flags;
u_short rtlifetime;
@@ -154,8 +153,6 @@ struct nd_prefix {
} ndpr_stateflags;
};
-#define ndpr_next ndpr_entry.le_next
-
#define ndpr_raf ndpr_flags
#define ndpr_raf_onlink ndpr_flags.onlink
#define ndpr_raf_auto ndpr_flags.autonomous
@@ -200,7 +197,6 @@ struct inet6_ndpr_msghdr {
struct nd_pfxrouter {
LIST_ENTRY(nd_pfxrouter) pfr_entry;
-#define pfr_next pfr_entry.le_next
struct nd_defrouter *router;
};
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index de09176..840f074 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -29,8 +29,6 @@
* $FreeBSD$
*/
-#include "opt_inet.h"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -818,7 +816,7 @@ nd6_dad_find(ifa)
{
struct dadq *dp;
- for (dp = dadq.tqh_first; dp; dp = dp->dad_list.tqe_next) {
+ TAILQ_FOREACH(dp, &dadq, dad_list) {
if (dp->dad_ifa == ifa)
return dp;
}
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index d177a66..da92879 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -374,7 +374,7 @@ defrouter_lookup(addr, ifp)
{
struct nd_defrouter *dr;
- for(dr = nd_defrouter.lh_first; dr; dr = dr->dr_next)
+ LIST_FOREACH(dr, &nd_defrouter, dr_entry)
if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
return(dr);
@@ -405,8 +405,8 @@ defrouter_delreq(dr, dofree)
if (dofree)
free(dr, M_IP6NDP);
- if (nd_defrouter.lh_first)
- defrouter_addreq(nd_defrouter.lh_first);
+ if (!LIST_EMPTY(&nd_defrouter))
+ defrouter_addreq(LIST_FIRST(&nd_defrouter));
/*
* xxx update the Destination Cache entries for all
@@ -430,7 +430,7 @@ defrtrlist_del(dr)
rt6_flush(&dr->rtaddr, dr->ifp);
}
- if (dr == nd_defrouter.lh_first)
+ if (dr == LIST_FIRST(&nd_defrouter))
deldr = dr; /* The router is primary. */
LIST_REMOVE(dr, dr_entry);
@@ -438,7 +438,7 @@ defrtrlist_del(dr)
/*
* Also delete all the pointers to the router in each prefix lists.
*/
- for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
+ LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
struct nd_pfxrouter *pfxrtr;
if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
pfxrtr_del(pfxrtr);
@@ -489,11 +489,11 @@ defrtrlist_update(new)
}
bzero(n, sizeof(*n));
*n = *new;
- if (nd_defrouter.lh_first == NULL) {
+ if (LIST_EMPTY(&nd_defrouter)) {
LIST_INSERT_HEAD(&nd_defrouter, n, dr_entry);
defrouter_addreq(n);
} else {
- LIST_INSERT_AFTER(nd_defrouter.lh_first, n, dr_entry);
+ LIST_INSERT_AFTER(LIST_FIRST(&nd_defrouter), n, dr_entry);
defrouter_addreq(n);
}
splx(s);
@@ -507,8 +507,8 @@ pfxrtr_lookup(pr, dr)
struct nd_defrouter *dr;
{
struct nd_pfxrouter *search;
-
- for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
+
+ LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) {
if (search->router == dr)
break;
}
@@ -548,7 +548,7 @@ prefix_lookup(pr)
{
struct nd_prefix *search;
- for (search = nd_prefix.lh_first; search; search = search->ndpr_next) {
+ LIST_FOREACH(search, &nd_prefix, ndpr_entry) {
if (pr->ndpr_ifp == search->ndpr_ifp &&
pr->ndpr_plen == search->ndpr_plen &&
in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
@@ -611,8 +611,8 @@ prelist_remove(pr)
splx(s);
/* free list of routers that adversed the prefix */
- for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
- next = pfr->pfr_next;
+ for (pfr = LIST_FIRST(&pr->ndpr_advrtrs); pfr; pfr = next) {
+ next = LIST_NEXT(pfr, pfr_entry);
free(pfr, M_IP6NDP);
}
@@ -809,8 +809,8 @@ pfxlist_onlink_check()
{
struct nd_prefix *pr;
- for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next)
- if (pr->ndpr_advrtrs.lh_first) /* pr has an available router */
+ LIST_FOREACH(pr, &nd_prefix, ndpr_entry)
+ if (!LIST_EMPTY(&pr->ndpr_advrtrs)) /* pr has an available router */
break;
if (pr) {
@@ -821,21 +821,21 @@ pfxlist_onlink_check()
* attached prefix and a detached prefix may have a same
* interface route.
*/
- for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
- if (pr->ndpr_advrtrs.lh_first == NULL &&
+ LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
+ if (LIST_EMPTY(&pr->ndpr_advrtrs) &&
pr->ndpr_statef_onlink) {
pr->ndpr_statef_onlink = 0;
nd6_detach_prefix(pr);
}
}
- for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
- if (pr->ndpr_advrtrs.lh_first &&
+ LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
+ if (!LIST_EMPTY(&pr->ndpr_advrtrs) &&
pr->ndpr_statef_onlink == 0)
nd6_attach_prefix(pr);
}
} else {
/* there is no prefix that has a router */
- for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next)
+ LIST_FOREACH(pr, &nd_prefix, ndpr_entry)
if (pr->ndpr_statef_onlink == 0)
nd6_attach_prefix(pr);
}
@@ -993,7 +993,7 @@ in6_ifadd(ifp, in6, addr, prefixlen)
in6_ifaddr = ia;
/* link to if_addrlist */
- if (ifp->if_addrlist.tqh_first != NULL) {
+ if (!TAILQ_EMPTY(&ifp->if_addrlist)) {
TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia,
ifa_list);
}
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index c54874e..3131e41 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -64,8 +64,6 @@
* @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
*/
-#include "opt_inet.h"
-
#include <stddef.h>
#include <sys/param.h>
@@ -94,14 +92,12 @@
#ifdef IPSEC
#include <netinet6/ipsec.h>
-#ifdef INET6
#include <netinet6/ipsec6.h>
-#endif /* INET6 */
#endif /*IPSEC*/
#include <machine/stdarg.h>
-/* #include "faith.h" */
+#include "faith.h"
#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
new file mode 100644
index 0000000..c22a719
--- /dev/null
+++ b/sys/netinet6/udp6_usrreq.c
@@ -0,0 +1,835 @@
+/*
+ * 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, 1989, 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.
+ *
+ * @(#)udp_var.h 8.1 (Berkeley) 6/10/93
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/systm.h>
+#include <sys/syslog.h>
+#include <sys/proc.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_types.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet6/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/icmp6.h>
+#include <netinet6/udp6_var.h>
+#include <netinet6/ip6protosw.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#endif /*IPSEC*/
+
+#include "faith.h"
+
+/*
+ * UDP protocol inplementation.
+ * Per RFC 768, August, 1980.
+ */
+
+extern struct protosw inetsw[];
+static int in6_mcmatch __P((struct inpcb *, struct in6_addr *, struct ifnet *));
+static int udp6_detach __P((struct socket *so));
+
+static int
+in6_mcmatch(in6p, ia6, ifp)
+ struct inpcb *in6p;
+ register struct in6_addr *ia6;
+ struct ifnet *ifp;
+{
+ struct ip6_moptions *im6o = in6p->in6p_moptions;
+ struct in6_multi_mship *imm;
+
+ if (im6o == NULL)
+ return 0;
+
+ for (imm = im6o->im6o_memberships.lh_first; imm != NULL;
+ imm = imm->i6mm_chain.le_next) {
+ if ((ifp == NULL ||
+ imm->i6mm_maddr->in6m_ifp == ifp) &&
+ IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
+ ia6))
+ return 1;
+ }
+ return 0;
+}
+
+int
+udp6_input(mp, offp, proto)
+ struct mbuf **mp;
+ int *offp, proto;
+{
+ struct mbuf *m = *mp;
+ register struct ip6_hdr *ip6;
+ register struct udphdr *uh;
+ register struct inpcb *in6p;
+ struct mbuf *opts = 0;
+ int off = *offp;
+ int plen, ulen;
+ struct sockaddr_in6 udp_in6;
+
+#if defined(NFAITH) && 0 < NFAITH
+ if (m->m_pkthdr.rcvif) {
+ if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
+ /* XXX send icmp6 host/port unreach? */
+ m_freem(m);
+ return IPPROTO_DONE;
+ }
+ }
+#endif
+ udpstat.udps_ipackets++;
+
+ IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
+
+ ip6 = mtod(m, struct ip6_hdr *);
+ plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
+ uh = (struct udphdr *)((caddr_t)ip6 + off);
+ ulen = ntohs((u_short)uh->uh_ulen);
+
+ if (plen != ulen) {
+ udpstat.udps_badlen++;
+ goto bad;
+ }
+
+ /*
+ * Checksum extended UDP header and data.
+ */
+ if (uh->uh_sum == 0)
+ udpstat.udps_nosum++;
+ else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
+ udpstat.udps_badsum++;
+ goto bad;
+ }
+
+ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
+ struct inpcb *last;
+
+ /*
+ * Deliver a multicast datagram to all sockets
+ * for which the local and remote addresses and ports match
+ * those of the incoming datagram. This allows more than
+ * one process to receive multicasts on the same port.
+ * (This really ought to be done for unicast datagrams as
+ * well, but that would cause problems with existing
+ * applications that open both address-specific sockets and
+ * a wildcard socket listening to the same port -- they would
+ * end up receiving duplicates of every unicast datagram.
+ * Those applications open the multiple sockets to overcome an
+ * inadequacy of the UDP socket interface, but for backwards
+ * compatibility we avoid the problem here rather than
+ * fixing the interface. Maybe 4.5BSD will remedy this?)
+ */
+
+ /*
+ * In a case that laddr should be set to the link-local
+ * address (this happens in RIPng), the multicast address
+ * specified in the received packet does not match with
+ * laddr. To cure this situation, the matching is relaxed
+ * if the receiving interface is the same as one specified
+ * in the socket and if the destination multicast address
+ * matches one of the multicast groups specified in the socket.
+ */
+
+ /*
+ * Construct sockaddr format source address.
+ */
+ init_sin6(&udp_in6, m); /* general init */
+ udp_in6.sin6_port = uh->uh_sport;
+ /*
+ * KAME note: usually we drop udphdr from mbuf here.
+ * We need udphdr for IPsec processing so we do that later.
+ */
+
+ /*
+ * Locate pcb(s) for datagram.
+ * (Algorithm copied from raw_intr().)
+ */
+ last = NULL;
+ LIST_FOREACH(in6p, &udb, inp_list) {
+ if ((in6p->inp_vflag & INP_IPV6) == NULL)
+ continue;
+ if (in6p->in6p_lport != uh->uh_dport)
+ continue;
+ if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
+ if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
+ &ip6->ip6_dst) &&
+ !in6_mcmatch(in6p, &ip6->ip6_dst,
+ m->m_pkthdr.rcvif))
+ continue;
+ }
+ if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
+ if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
+ &ip6->ip6_src) ||
+ in6p->in6p_fport != uh->uh_sport)
+ continue;
+ }
+
+ if (last != NULL) {
+ struct mbuf *n;
+
+#ifdef IPSEC
+ /*
+ * Check AH/ESP integrity.
+ */
+ if (last != NULL &&
+ ipsec6_in_reject_so(m, last->inp_socket)) {
+ ipsec6stat.in_polvio++;
+ /* do not inject data into pcb */
+ } else
+#endif /*IPSEC*/
+ if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
+ /*
+ * KAME NOTE: do not
+ * m_copy(m, offset, ...) above.
+ * sbappendaddr() expects M_PKTHDR,
+ * and m_copy() will copy M_PKTHDR
+ * only if offset is 0.
+ */
+ if (last->in6p_flags & IN6P_CONTROLOPTS
+ || last->in6p_socket->so_options & SO_TIMESTAMP)
+ ip6_savecontrol(last, &opts,
+ ip6, n);
+ m_adj(n, off + sizeof(struct udphdr));
+ if (sbappendaddr(&last->in6p_socket->so_rcv,
+ (struct sockaddr *)&udp_in6,
+ n, opts) == 0) {
+ m_freem(n);
+ if (opts)
+ m_freem(opts);
+ udpstat.udps_fullsock++;
+ } else
+ sorwakeup(last->in6p_socket);
+ opts = 0;
+ }
+ }
+ last = in6p;
+ /*
+ * Don't look for additional matches if this one does
+ * not have either the SO_REUSEPORT or SO_REUSEADDR
+ * socket options set. This heuristic avoids searching
+ * through all pcbs in the common case of a non-shared
+ * port. It assumes that an application will never
+ * clear these options after setting them.
+ */
+ if ((last->in6p_socket->so_options &
+ (SO_REUSEPORT|SO_REUSEADDR)) == 0)
+ break;
+ }
+
+ if (last == NULL) {
+ /*
+ * No matching pcb found; discard datagram.
+ * (No need to send an ICMP Port Unreachable
+ * for a broadcast or multicast datgram.)
+ */
+ udpstat.udps_noport++;
+ udpstat.udps_noportmcast++;
+ goto bad;
+ }
+#ifdef IPSEC
+ /*
+ * Check AH/ESP integrity.
+ */
+ if (last != NULL && ipsec6_in_reject_so(m, last->inp_socket)) {
+ ipsec6stat.in_polvio++;
+ goto bad;
+ }
+#endif /*IPSEC*/
+ if (last->in6p_flags & IN6P_CONTROLOPTS
+ || last->in6p_socket->so_options & SO_TIMESTAMP)
+ ip6_savecontrol(last, &opts, ip6, m);
+
+ m_adj(m, off + sizeof(struct udphdr));
+ if (sbappendaddr(&last->in6p_socket->so_rcv,
+ (struct sockaddr *)&udp_in6,
+ m, opts) == 0) {
+ udpstat.udps_fullsock++;
+ goto bad;
+ }
+ sorwakeup(last->in6p_socket);
+ return IPPROTO_DONE;
+ }
+ /*
+ * Locate pcb for datagram.
+ */
+ in6p = in6_pcblookup_hash(&udbinfo, &ip6->ip6_src, uh->uh_sport,
+ &ip6->ip6_dst, uh->uh_dport, 1,
+ m->m_pkthdr.rcvif);
+ if (in6p == 0) {
+ if (log_in_vain) {
+ char buf[INET6_ADDRSTRLEN];
+
+ strcpy(buf, ip6_sprintf(&ip6->ip6_dst));
+ log(LOG_INFO,
+ "Connection attempt to UDP %s:%d from %s:%d\n",
+ buf, ntohs(uh->uh_dport),
+ ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport));
+ }
+ udpstat.udps_noport++;
+ if (m->m_flags & M_MCAST) {
+ printf("UDP6: M_MCAST is set in a unicast packet.\n");
+ udpstat.udps_noportmcast++;
+ goto bad;
+ }
+ icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
+ return IPPROTO_DONE;
+ }
+#ifdef IPSEC
+ /*
+ * Check AH/ESP integrity.
+ */
+ if (in6p != NULL && ipsec6_in_reject_so(m, in6p->in6p_socket)) {
+ ipsec6stat.in_polvio++;
+ goto bad;
+ }
+#endif /*IPSEC*/
+
+ /*
+ * Construct sockaddr format source address.
+ * Stuff source address and datagram in user buffer.
+ */
+ init_sin6(&udp_in6, m); /* general init */
+ udp_in6.sin6_port = uh->uh_sport;
+ if (in6p->in6p_flags & IN6P_CONTROLOPTS
+ || in6p->in6p_socket->so_options & SO_TIMESTAMP)
+ ip6_savecontrol(in6p, &opts, ip6, m);
+ m_adj(m, off + sizeof(struct udphdr));
+ if (sbappendaddr(&in6p->in6p_socket->so_rcv,
+ (struct sockaddr *)&udp_in6,
+ m, opts) == 0) {
+ udpstat.udps_fullsock++;
+ goto bad;
+ }
+ sorwakeup(in6p->in6p_socket);
+ return IPPROTO_DONE;
+bad:
+ if (m)
+ m_freem(m);
+ if (opts)
+ m_freem(opts);
+ return IPPROTO_DONE;
+}
+
+void
+udp6_ctlinput(cmd, sa, d)
+ int cmd;
+ struct sockaddr *sa;
+ void *d;
+{
+ register struct udphdr *uhp;
+ struct udphdr uh;
+ struct sockaddr_in6 sa6;
+ struct ip6_hdr *ip6;
+ struct mbuf *m;
+ int off;
+
+ if (sa->sa_family != AF_INET6 ||
+ sa->sa_len != sizeof(struct sockaddr_in6))
+ return;
+
+ if (!PRC_IS_REDIRECT(cmd) &&
+ ((unsigned)cmd >= PRC_NCMDS || 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))
+ 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);
+
+ if (m->m_len < off + sizeof(uh)) {
+ /*
+ * this should be rare case,
+ * so we compromise on this copy...
+ */
+ m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
+ uhp = &uh;
+ } else
+ uhp = (struct udphdr *)(mtod(m, caddr_t) + off);
+ (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6,
+ uhp->uh_dport, &s,
+ uhp->uh_sport, cmd, udp_notify);
+ } else
+ (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, 0,
+ &zeroin6_addr, 0, cmd, udp_notify);
+}
+
+static int
+udp6_getcred SYSCTL_HANDLER_ARGS
+{
+ struct sockaddr_in6 addrs[2];
+ struct inpcb *inp;
+ int error, s;
+
+ error = suser(req->p);
+ if (error)
+ return (error);
+ error = SYSCTL_IN(req, addrs, sizeof(addrs));
+ if (error)
+ return (error);
+ s = splnet();
+ inp = in6_pcblookup_hash(&udbinfo, &addrs[1].sin6_addr,
+ addrs[1].sin6_port,
+ &addrs[0].sin6_addr, addrs[0].sin6_port,
+ 1, NULL);
+ if (!inp || !inp->inp_socket || !inp->inp_socket->so_cred) {
+ error = ENOENT;
+ goto out;
+ }
+ error = SYSCTL_OUT(req, inp->inp_socket->so_cred,
+ sizeof(struct ucred));
+
+out:
+ splx(s);
+ return (error);
+}
+
+SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
+ 0, 0,
+ udp6_getcred, "S,ucred", "Get the ucred of a UDP6 connection");
+
+int
+udp6_output(in6p, m, addr6, control, p)
+ register struct inpcb *in6p;
+ register struct mbuf *m;
+ struct sockaddr *addr6;
+ struct mbuf *control;
+ struct proc *p;
+{
+ register int ulen = m->m_pkthdr.len;
+ int plen = sizeof(struct udphdr) + ulen;
+ struct ip6_hdr *ip6;
+ struct udphdr *udp6;
+ struct in6_addr laddr6;
+ int s = 0, error = 0;
+ struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
+
+ if (control) {
+ if ((error = ip6_setpktoptions(control, &opt, suser(p))) != 0)
+ goto release;
+ in6p->in6p_outputopts = &opt;
+ }
+
+ if (addr6) {
+ laddr6 = in6p->in6p_laddr;
+ if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
+ error = EISCONN;
+ goto release;
+ }
+ /*
+ * Must block input while temporarily connected.
+ */
+ s = splnet();
+ /*
+ * XXX: the user might want to overwrite the local address
+ * via an ancillary data.
+ */
+ bzero(&in6p->in6p_laddr, sizeof(struct in6_addr));
+ error = in6_pcbconnect(in6p, addr6, p);
+ if (error) {
+ splx(s);
+ goto release;
+ }
+ } else {
+ if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
+ error = ENOTCONN;
+ goto release;
+ }
+ }
+ /*
+ * Calculate data length and get a mbuf
+ * for UDP and IP6 headers.
+ */
+ M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr),
+ M_DONTWAIT);
+ if (m == 0) {
+ error = ENOBUFS;
+ if (addr6)
+ splx(s);
+ goto release;
+ }
+
+ /*
+ * Stuff checksum and output datagram.
+ */
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
+ ip6->ip6_vfc = IPV6_VERSION;
+ /* ip6_plen will be filled in ip6_output. */
+ ip6->ip6_nxt = IPPROTO_UDP;
+ ip6->ip6_hlim = in6_selecthlim(in6p,
+ in6p->in6p_route.ro_rt ?
+ in6p->in6p_route.ro_rt->rt_ifp :
+ NULL);
+ ip6->ip6_src = in6p->in6p_laddr;
+ ip6->ip6_dst = in6p->in6p_faddr;
+
+ udp6 = (struct udphdr *)(ip6 + 1);
+ udp6->uh_sport = in6p->in6p_lport;
+ udp6->uh_dport = in6p->in6p_fport;
+ udp6->uh_ulen = htons((u_short)plen);
+ udp6->uh_sum = 0;
+
+ if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
+ sizeof(struct ip6_hdr), plen)) == 0) {
+ udp6->uh_sum = 0xffff;
+ }
+
+ udpstat.udps_opackets++;
+
+#ifdef IPSEC
+ m->m_pkthdr.rcvif = (struct ifnet *)in6p->in6p_socket;
+#endif /*IPSEC*/
+ error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
+ 0, in6p->in6p_moptions, NULL);
+
+ if (addr6) {
+ in6_pcbdisconnect(in6p);
+ in6p->in6p_laddr = laddr6;
+ splx(s);
+ }
+ goto releaseopt;
+
+release:
+ m_freem(m);
+
+releaseopt:
+ if (control) {
+ in6p->in6p_outputopts = stickyopt;
+ m_freem(control);
+ }
+ return(error);
+}
+
+static int
+udp6_abort(struct socket *so)
+{
+ struct inpcb *inp;
+ int s;
+
+ inp = sotoinpcb(so);
+ if (inp == 0)
+ return EINVAL; /* ??? possible? panic instead? */
+ soisdisconnected(so);
+ s = splnet();
+ in6_pcbdetach(inp);
+ splx(s);
+ return 0;
+}
+
+static int
+udp6_attach(struct socket *so, int proto, struct proc *p)
+{
+ struct inpcb *inp;
+ int s, error;
+
+ inp = sotoinpcb(so);
+ if (inp != 0)
+ return EINVAL;
+
+ if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
+ error = soreserve(so, udp_sendspace, udp_recvspace);
+ if (error)
+ return error;
+ }
+ s = splnet();
+ error = in_pcballoc(so, &udbinfo, p);
+ splx(s);
+ if (error)
+ return error;
+ inp = (struct inpcb *)so->so_pcb;
+ inp->inp_vflag |= INP_IPV6;
+ inp->in6p_hops = -1; /* use kernel default */
+ inp->in6p_cksum = -1; /* just to be sure */
+#ifdef IPSEC
+ error = ipsec_init_policy(so, &inp->in6p_sp);
+ if (error != 0) {
+ in6_pcbdetach(inp);
+ return (error);
+ }
+#endif /*IPSEC*/
+ return 0;
+}
+
+static int
+udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+ struct inpcb *inp;
+ int s, error;
+
+ inp = sotoinpcb(so);
+ if (inp == 0)
+ return EINVAL;
+
+ inp->inp_vflag &= ~INP_IPV4;
+ inp->inp_vflag |= INP_IPV6;
+ if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_BINDV6ONLY) == NULL) {
+ struct sockaddr_in6 *sin6_p;
+
+ sin6_p = (struct sockaddr_in6 *)nam;
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr))
+ inp->inp_vflag |= INP_IPV4;
+ else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
+ struct sockaddr_in sin;
+
+ in6_sin6_2_sin(&sin, sin6_p);
+ inp->inp_vflag |= INP_IPV4;
+ inp->inp_vflag &= ~INP_IPV6;
+ s = splnet();
+ error = in_pcbbind(inp, (struct sockaddr *)&sin, p);
+ splx(s);
+ return error;
+ }
+ }
+
+ s = splnet();
+ error = in6_pcbbind(inp, nam, p);
+ splx(s);
+ return error;
+}
+
+static int
+udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+ struct inpcb *inp;
+ int s, error;
+
+ inp = sotoinpcb(so);
+ if (inp == 0)
+ return EINVAL;
+
+ if (ip6_mapped_addr_on) {
+ struct sockaddr_in6 *sin6_p;
+
+ sin6_p = (struct sockaddr_in6 *)nam;
+ if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
+ struct sockaddr_in sin;
+
+ if (inp->inp_faddr.s_addr != INADDR_ANY)
+ return EISCONN;
+ in6_sin6_2_sin(&sin, sin6_p);
+ s = splnet();
+ error = in_pcbconnect(inp, (struct sockaddr *)&sin, p);
+ splx(s);
+ if (error == NULL) {
+ inp->inp_vflag |= INP_IPV4;
+ inp->inp_vflag &= ~INP_IPV6;
+ soisconnected(so);
+ }
+ return error;
+ }
+ }
+
+ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
+ return EISCONN;
+ s = splnet();
+ error = in6_pcbconnect(inp, nam, p);
+ if (ip6_auto_flowlabel) {
+ inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
+ inp->in6p_flowinfo |=
+ (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
+ }
+ splx(s);
+ if (error == NULL) {
+ if (ip6_mapped_addr_on) { /* should be non mapped addr */
+ inp->inp_vflag &= ~INP_IPV4;
+ inp->inp_vflag |= INP_IPV6;
+ }
+ soisconnected(so);
+ }
+ return error;
+}
+
+static int
+udp6_detach(struct socket *so)
+{
+ struct inpcb *inp;
+ int s;
+
+ inp = sotoinpcb(so);
+ if (inp == 0)
+ return EINVAL;
+ s = splnet();
+ in6_pcbdetach(inp);
+ splx(s);
+ return 0;
+}
+
+static int
+udp6_disconnect(struct socket *so)
+{
+ struct inpcb *inp;
+ int s;
+
+ inp = sotoinpcb(so);
+ if (inp == 0)
+ return EINVAL;
+
+ if (inp->inp_vflag & INP_IPV4) {
+ struct pr_usrreqs *pru;
+
+ pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
+ return ((*pru->pru_disconnect)(so));
+ }
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
+ return ENOTCONN;
+
+ s = splnet();
+ in6_pcbdisconnect(inp);
+ inp->in6p_laddr = in6addr_any;
+ splx(s);
+ so->so_state &= ~SS_ISCONNECTED; /* XXX */
+ return 0;
+}
+
+static int
+udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
+ struct mbuf *control, struct proc *p)
+{
+ struct inpcb *inp;
+
+ inp = sotoinpcb(so);
+ if (inp == 0) {
+ m_freem(m);
+ return EINVAL;
+ }
+
+ if (ip6_mapped_addr_on) {
+ int hasv4addr;
+ struct sockaddr_in6 *sin6 = 0;
+
+ if (addr == 0)
+ hasv4addr = (inp->inp_vflag & INP_IPV4);
+ else {
+ sin6 = (struct sockaddr_in6 *)addr;
+ hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)
+ ? 1 : 0;
+ }
+ if (hasv4addr) {
+ struct pr_usrreqs *pru;
+ int error;
+
+ if (sin6)
+ in6_sin6_2_sin_in_sock(addr);
+ pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
+ error = ((*pru->pru_send)(so, flags, m, addr, control,
+ p));
+ /* addr will just be freed in sendit(). */
+ return error;
+ }
+ }
+
+ return udp6_output(inp, m, addr, control, p);
+}
+
+struct pr_usrreqs udp6_usrreqs = {
+ udp6_abort, pru_accept_notsupp, udp6_attach, udp6_bind, udp6_connect,
+ pru_connect2_notsupp, in6_control, udp6_detach, udp6_disconnect,
+ pru_listen_notsupp, in6_mapped_peeraddr, pru_rcvd_notsupp,
+ pru_rcvoob_notsupp, udp6_send, pru_sense_null, udp_shutdown,
+ in6_mapped_sockaddr, sosend, soreceive, sopoll
+};
diff --git a/sys/netinet6/udp6_var.h b/sys/netinet6/udp6_var.h
index b95bc78..e0ade7a 100644
--- a/sys/netinet6/udp6_var.h
+++ b/sys/netinet6/udp6_var.h
@@ -68,6 +68,8 @@
#define _NETINET6_UDP6_VAR_H_
#ifdef KERNEL
+SYSCTL_DECL(_net_inet6_udp6);
+
extern struct pr_usrreqs udp6_usrreqs;
void udp6_ctlinput __P((int, struct sockaddr *, void *));
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile
index 3c8092a..78e80c7 100644
--- a/usr.bin/netstat/Makefile
+++ b/usr.bin/netstat/Makefile
@@ -2,7 +2,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/12/93
PROG= netstat
-SRCS= if.c inet.c main.c mbuf.c mroute.c ipx.c route.c \
+SRCS= if.c inet.c inet6.c main.c mbuf.c mroute.c ipx.c route.c \
unix.c atalk.c netgraph.c # iso.c ns.c tp_astring.c
CFLAGS+=-Wall
@@ -12,5 +12,6 @@ BINGRP= kmem
BINMODE=2555
DPADD= ${LIBKVM} ${LIBIPX} ${LIBNETGRAPH}
LDADD= -lkvm -lipx -lnetgraph
+#CFLAGS+= -DINET6
.include <bsd.prog.mk>
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
index 8343363..4366163 100644
--- a/usr.bin/netstat/if.c
+++ b/usr.bin/netstat/if.c
@@ -78,6 +78,12 @@ static const char rcsid[] =
static void sidewaysintpr __P((u_int, u_long));
static void catchalarm __P((int));
+#ifdef INET6
+char *netname6 __P((struct sockaddr_in6 *, struct in6_addr *));
+static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */
+static int bdg_done;
+#endif
+
void
bdg_stats(u_long dummy, char *name) /* print bridge statistics */
{
@@ -94,6 +100,12 @@ bdg_stats(u_long dummy, char *name) /* print bridge statistics */
mib[3] = PF_BDG ;
if (sysctl(mib,4, &s,&slen,NULL,0)==-1)
return ; /* no bridging */
+#ifdef INET6
+ if (bdg_done != 0)
+ return;
+ else
+ bdg_done = 1;
+#endif
printf("-- Bridging statistics (%s) --\n", name) ;
printf(
"Name In Out Forward Drop Bcast Mcast Local Unknown\n");
@@ -116,15 +128,19 @@ bdg_stats(u_long dummy, char *name) /* print bridge statistics */
* Print a description of the network interfaces.
*/
void
-intpr(interval, ifnetaddr)
+intpr(interval, ifnetaddr, pfunc)
int interval;
u_long ifnetaddr;
+ void (*pfunc)(char *);
{
struct ifnet ifnet;
struct ifnethead ifnethead;
union {
struct ifaddr ifa;
struct in_ifaddr in;
+#ifdef INET6
+ struct in6_ifaddr in6;
+#endif
struct ipx_ifaddr ipx;
#ifdef NS
struct ns_ifaddr ns;
@@ -153,22 +169,27 @@ intpr(interval, ifnetaddr)
if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
return;
- printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
- "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
- if (bflag)
- printf(" %10.10s","Ibytes");
- printf(" %8.8s %5.5s", "Opkts", "Oerrs");
- if (bflag)
- printf(" %10.10s","Obytes");
- printf(" %5s", "Coll");
- if (tflag)
- printf(" %s", "Time");
- if (dflag)
- printf(" %s", "Drop");
- putchar('\n');
+ if (!sflag && !pflag) {
+ printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
+ "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
+ if (bflag)
+ printf(" %10.10s","Ibytes");
+ printf(" %8.8s %5.5s", "Opkts", "Oerrs");
+ if (bflag)
+ printf(" %10.10s","Obytes");
+ printf(" %5s", "Coll");
+ if (tflag)
+ printf(" %s", "Time");
+ if (dflag)
+ printf(" %s", "Drop");
+ putchar('\n');
+ }
ifaddraddr = 0;
while (ifnetaddr || ifaddraddr) {
struct sockaddr_in *sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
register char *cp;
int n, m;
@@ -183,6 +204,12 @@ intpr(interval, ifnetaddr)
if (interface != 0 && (strcmp(name, interface) != 0))
continue;
cp = index(name, '\0');
+
+ if (pfunc) {
+ (*pfunc)(name);
+ continue;
+ }
+
if ((ifnet.if_flags&IFF_UP) == 0)
*cp++ = '*';
*cp = '\0';
@@ -225,6 +252,18 @@ intpr(interval, ifnetaddr)
printf("%-15.15s ",
routename(sin->sin_addr.s_addr));
break;
+#ifdef INET6
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)sa;
+ printf("%-11.11s ",
+ netname6(&ifaddr.in6.ia_addr,
+ &ifaddr.in6.ia_prefixmask.sin6_addr));
+ printf("%-17.17s ",
+ (char *)inet_ntop(AF_INET6,
+ &sin6->sin6_addr,
+ ntop_buf, sizeof(ntop_buf)));
+ break;
+#endif /*INET6*/
case AF_IPX:
{
struct sockaddr_ipx *sipx =
@@ -266,10 +305,12 @@ intpr(interval, ifnetaddr)
{
struct sockaddr_dl *sdl =
(struct sockaddr_dl *)sa;
- cp = (char *)LLADDR(sdl);
- n = sdl->sdl_alen;
+ char linknum[10];
+ cp = (char *)LLADDR(sdl);
+ n = sdl->sdl_alen;
+ sprintf(linknum, "<Link#%d>", sdl->sdl_index);
+ m = printf("%-11.11s ", linknum);
}
- m = printf("%-11.11s ", "<Link>");
goto hexprint;
default:
m = printf("(%d)", sa->sa_family);
@@ -311,6 +352,9 @@ intpr(interval, ifnetaddr)
union {
struct sockaddr sa;
struct sockaddr_in in;
+#ifdef INET6
+ struct sockaddr_in6 in6;
+#endif /* INET6 */
struct sockaddr_dl dl;
} msa;
const char *fmt;
@@ -332,7 +376,15 @@ intpr(interval, ifnetaddr)
case AF_INET:
fmt = routename(msa.in.sin_addr.s_addr);
break;
-
+#ifdef INET6
+ case AF_INET6:
+ printf("%23s %-19.19s(refs: %d)\n", "",
+ inet_ntop(AF_INET6,
+ &msa.in6.sin6_addr,
+ ntop_buf,
+ sizeof(ntop_buf)),
+ ifma.ifma_refcount);
+#endif /* INET6 */
case AF_LINK:
switch (ifnet.if_type) {
case IFT_ETHER:
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
index 783cbc7..4a8cda1 100644
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -50,6 +50,9 @@ static const char rcsid[] =
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif /* INET6 */
#include <netinet/in_pcb.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
@@ -65,6 +68,9 @@ static const char rcsid[] =
#include <netinet/tcp_debug.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#endif
#include <arpa/inet.h>
#include <err.h>
@@ -78,6 +84,10 @@ static const char rcsid[] =
char *inetname __P((struct in_addr *));
void inetprint __P((struct in_addr *, int, char *, int));
+#ifdef INET6
+extern void inet6print __P((struct in6_addr *, int, char *, int));
+static int udp_done, tcp_done;
+#endif /* INET6 */
/*
* Print a summary of connections related to an Internet
@@ -86,9 +96,10 @@ void inetprint __P((struct in_addr *, int, char *, int));
* -a (all) flag is specified.
*/
void
-protopr(proto, name)
+protopr(proto, name, af)
u_long proto; /* for sysctl version we pass proto # */
char *name;
+ int af;
{
int istcp;
static int first = 1;
@@ -103,10 +114,22 @@ protopr(proto, name)
istcp = 0;
switch (proto) {
case IPPROTO_TCP:
+#ifdef INET6
+ if (tcp_done != 0)
+ return;
+ else
+ tcp_done = 1;
+#endif
istcp = 1;
mibvar = "net.inet.tcp.pcblist";
break;
case IPPROTO_UDP:
+#ifdef INET6
+ if (udp_done != 0)
+ return;
+ else
+ udp_done = 1;
+#endif
mibvar = "net.inet.udp.pcblist";
break;
case IPPROTO_DIVERT:
@@ -153,7 +176,35 @@ protopr(proto, name)
if (inp->inp_gencnt > oxig->xig_gen)
continue;
- if (!aflag && inet_lnaof(inp->inp_laddr) == INADDR_ANY)
+ if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
+#ifdef INET6
+ || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
+#endif /* INET6 */
+ || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
+#ifdef INET6
+ && (inp->inp_vflag &
+ INP_IPV6) == 0
+#endif /* INET6 */
+ ))
+ )
+ continue;
+ if (!aflag &&
+ (
+ (af == AF_INET &&
+ inet_lnaof(inp->inp_laddr) == INADDR_ANY)
+#ifdef INET6
+ || (af == AF_INET6 &&
+ IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
+#endif /* INET6 */
+ || (af == AF_UNSPEC &&
+ (((inp->inp_vflag & INP_IPV4) != 0 &&
+ inet_lnaof(inp->inp_laddr) == INADDR_ANY)
+#ifdef INET6
+ || ((inp->inp_vflag & INP_IPV6) != 0 &&
+ IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
+#endif
+ ))
+ ))
continue;
if (first) {
@@ -163,7 +214,9 @@ protopr(proto, name)
putchar('\n');
if (Aflag)
printf("%-8.8s ", "Socket");
- printf("%-5.5s %-6.6s %-6.6s %-21.21s %-21.21s %s\n",
+ printf(Aflag ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
"Proto", "Recv-Q", "Send-Q",
"Local Address", "Foreign Address", "(state)");
first = 0;
@@ -174,23 +227,61 @@ protopr(proto, name)
else
printf("%8lx ", (u_long)so->so_pcb);
}
- printf("%-5.5s %6ld %6ld ", name, so->so_rcv.sb_cc,
- so->so_snd.sb_cc);
+ printf("%-3.3s%s%s %6ld %6ld ", name,
+ (inp->inp_vflag & INP_IPV4) ? "4" : "",
+#ifdef INET6
+ (inp->inp_vflag & INP_IPV6) ? "6" :
+#endif
+ "",
+ so->so_rcv.sb_cc,
+ so->so_snd.sb_cc);
if (nflag) {
- inetprint(&inp->inp_laddr, (int)inp->inp_lport,
- name, 1);
- inetprint(&inp->inp_faddr, (int)inp->inp_fport,
- name, 1);
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ inetprint(&inp->inp_faddr, (int)inp->inp_fport,
+ name, 1);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 1);
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 1);
+ } /* else nothing printed now */
+#endif /* INET6 */
} else if (inp->inp_flags & INP_ANONPORT) {
- inetprint(&inp->inp_laddr, (int)inp->inp_lport,
- name, 1);
- inetprint(&inp->inp_faddr, (int)inp->inp_fport,
- name, 0);
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ inetprint(&inp->inp_faddr, (int)inp->inp_fport,
+ name, 0);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 1);
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 0);
+ } /* else nothing printed now */
+#endif /* INET6 */
} else {
- inetprint(&inp->inp_laddr, (int)inp->inp_lport,
- name, 0);
- inetprint(&inp->inp_faddr, (int)inp->inp_fport,
- name, inp->inp_lport != inp->inp_fport);
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 0);
+ inetprint(&inp->inp_faddr, (int)inp->inp_fport,
+ name,
+ inp->inp_lport != inp->inp_fport);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 0);
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name,
+ inp->inp_lport != inp->inp_fport);
+ } /* else nothing printed now */
+#endif /* INET6 */
}
if (istcp) {
if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
@@ -237,6 +328,13 @@ tcp_stats(off, name)
return;
}
+#ifdef INET6
+ if (tcp_done != 0)
+ return;
+ else
+ tcp_done = 1;
+#endif
+
printf ("%s:\n", name);
#define p(f, m) if (tcpstat.f || sflag <= 1) \
@@ -331,6 +429,13 @@ udp_stats(off, name)
return;
}
+#ifdef INET6
+ if (udp_done != 0)
+ return;
+ else
+ udp_done = 1;
+#endif
+
printf("%s:\n", name);
#define p(f, m) if (udpstat.f || sflag <= 1) \
printf(m, udpstat.f, plural(udpstat.f))
@@ -386,6 +491,7 @@ ip_stats(off, name)
p(ips_badsum, "\t%lu bad header checksum%s\n");
p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
p1a(ips_tooshort, "\t%lu with data size < data length\n");
+ p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
p1a(ips_badhlen, "\t%lu with header length < data size\n");
p1a(ips_badlen, "\t%lu with data length < header length\n");
p1a(ips_badoptions, "\t%lu with bad options\n");
@@ -412,6 +518,7 @@ ip_stats(off, name)
p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
p(ips_ofragments, "\t%lu fragment%s created\n");
p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
+ p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
#undef p
#undef p1a
}
@@ -541,6 +648,109 @@ igmp_stats(off, name)
#undef py
}
+#ifdef IPSEC
+static char *ipsec_ahnames[] = {
+ "none",
+ "hmac MD5",
+ "hmac SHA1",
+ "keyed MD5",
+ "keyed SHA1",
+ "null",
+};
+
+static char *ipsec_espnames[] = {
+ "none",
+ "DES CBC",
+ "3DES CBC",
+ "simple",
+ "blowfish CBC",
+ "CAST128 CBC",
+ "RC5 CBC",
+};
+
+/*
+ * Dump IPSEC statistics structure.
+ */
+void
+ipsec_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct ipsecstat ipsecstat;
+ int first, proto;
+
+ if (off == 0)
+ return;
+ printf ("%s:\n", name);
+ kread(off, (char *)&ipsecstat, sizeof (ipsecstat));
+
+#define p(f, m) if (ipsecstat.f || sflag <= 1) \
+ printf(m, ipsecstat.f, plural(ipsecstat.f))
+
+ p(in_success, "\t%lu inbound packet%s processed successfully\n");
+ p(in_polvio, "\t%lu inbound packet%s violated process security "
+ "policy\n");
+ p(in_nosa, "\t%lu inbound packet%s with no SA available\n");
+ p(in_inval, "\t%lu inbound packet%s failed processing due to EINVAL\n");
+ p(in_badspi, "\t%lu inbound packet%s failed getting SPI\n");
+ p(in_ahreplay, "\t%lu inbound packet%s failed on AH replay check\n");
+ p(in_espreplay, "\t%lu inbound packet%s failed on ESP replay check\n");
+ p(in_ahauthsucc, "\t%lu inbound AH packet%s considered authentic\n");
+ p(in_ahauthfail, "\t%lu inbound AH packet%s failed on authentication\n");
+ p(in_espauthsucc, "\t%lu inbound ESP packet%s considered authentic\n");
+ p(in_espauthfail, "\t%lu inbound ESP packet%s failed on authentication\n");
+ for (first = 1, proto = 0; proto < SADB_AALG_MAX; proto++) {
+ if (ipsecstat.in_ahhist[proto] <= 0)
+ continue;
+ if (first) {
+ printf("\tAH input histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", ipsec_ahnames[proto],
+ ipsecstat.in_ahhist[proto]);
+ }
+ for (first = 1, proto = 0; proto < SADB_EALG_MAX; proto++) {
+ if (ipsecstat.in_esphist[proto] <= 0)
+ continue;
+ if (first) {
+ printf("\tESP input histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", ipsec_espnames[proto],
+ ipsecstat.in_esphist[proto]);
+ }
+
+ p(out_success, "\t%lu outbound packet%s processed successfully\n");
+ p(out_polvio, "\t%lu outbound packet%s violated process security "
+ "policy\n");
+ p(out_nosa, "\t%lu outbound packet%s with no SA available\n");
+ p(out_inval, "\t%lu outbound packet%s failed processing due to "
+ "EINVAL\n");
+ p(out_noroute, "\t%lu outbound packet%s with no route\n");
+ for (first = 1, proto = 0; proto < SADB_AALG_MAX; proto++) {
+ if (ipsecstat.out_ahhist[proto] <= 0)
+ continue;
+ if (first) {
+ printf("\tAH output histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", ipsec_ahnames[proto],
+ ipsecstat.out_ahhist[proto]);
+ }
+ for (first = 1, proto = 0; proto < SADB_EALG_MAX; proto++) {
+ if (ipsecstat.out_esphist[proto] <= 0)
+ continue;
+ if (first) {
+ printf("\tESP output histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", ipsec_espnames[proto],
+ ipsecstat.out_esphist[proto]);
+ }
+#undef p
+}
+#endif /*IPSEC*/
+
/*
* Pretty print an Internet address (net address + port).
*/
@@ -553,6 +763,7 @@ inetprint(in, port, proto,numeric)
{
struct servent *sp = 0;
char line[80], *cp;
+ int width;
sprintf(line, "%.*s.", (Aflag && !numeric) ? 12 : 16, inetname(in));
cp = index(line, '\0');
@@ -562,7 +773,8 @@ inetprint(in, port, proto,numeric)
sprintf(cp, "%.15s", sp ? sp->s_name : "*");
else
sprintf(cp, "%d", ntohs((u_short)port));
- printf("%-21.21s ", line);
+ width = Aflag ? 18 : 22;
+ printf(" %-*.*s", width, width, line);
}
/*
diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c
new file mode 100644
index 0000000..154ee32
--- /dev/null
+++ b/usr.bin/netstat/inet6.c
@@ -0,0 +1,962 @@
+/* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */
+/*
+ * Copyright (c) 1983, 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)inet6.c 8.4 (Berkeley) 4/20/94";
+*/
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/ioctl.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+
+#include <net/route.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/in_systm.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/pim6_var.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+struct socket sockb;
+
+char *inet6name __P((struct in6_addr *));
+void inet6print __P((struct in6_addr *, int, char *, int));
+
+static char ntop_buf[INET6_ADDRSTRLEN];
+
+static char *ip6nh[] = {
+ "hop by hop",
+ "ICMP",
+ "IGMP",
+ "#3",
+ "IP",
+ "#5",
+ "TCP",
+ "#7",
+ "#8",
+ "#9",
+ "#10",
+ "#11",
+ "#12",
+ "#13",
+ "#14",
+ "#15",
+ "#16",
+ "UDP",
+ "#18",
+ "#19",
+ "#20",
+ "#21",
+ "IDP",
+ "#23",
+ "#24",
+ "#25",
+ "#26",
+ "#27",
+ "#28",
+ "TP",
+ "#30",
+ "#31",
+ "#32",
+ "#33",
+ "#34",
+ "#35",
+ "#36",
+ "#37",
+ "#38",
+ "#39",
+ "#40",
+ "IP6",
+ "#42",
+ "routing",
+ "fragment",
+ "#45",
+ "#46",
+ "#47",
+ "#48",
+ "#49",
+ "ESP",
+ "AH",
+ "#52",
+ "#53",
+ "#54",
+ "#55",
+ "#56",
+ "#57",
+ "ICMP6",
+ "no next header",
+ "destination option",
+ "#61",
+ "#62",
+ "#63",
+ "#64",
+ "#65",
+ "#66",
+ "#67",
+ "#68",
+ "#69",
+ "#70",
+ "#71",
+ "#72",
+ "#73",
+ "#74",
+ "#75",
+ "#76",
+ "#77",
+ "#78",
+ "#79",
+ "ISOIP",
+ "#81",
+ "#82",
+ "#83",
+ "#84",
+ "#85",
+ "#86",
+ "#87",
+ "#88",
+ "#89",
+ "#80",
+ "#91",
+ "#92",
+ "#93",
+ "#94",
+ "#95",
+ "#96",
+ "Ethernet",
+ "#98",
+ "#99",
+ "#100",
+ "#101",
+ "#102",
+ "PIM",
+ "#104",
+ "#105",
+ "#106",
+ "#107",
+ "#108",
+ "#109",
+ "#110",
+ "#111",
+ "#112",
+ "#113",
+ "#114",
+ "#115",
+ "#116",
+ "#117",
+ "#118",
+ "#119",
+ "#120",
+ "#121",
+ "#122",
+ "#123",
+ "#124",
+ "#125",
+ "#126",
+ "#127",
+ "#128",
+ "#129",
+ "#130",
+ "#131",
+ "#132",
+ "#133",
+ "#134",
+ "#135",
+ "#136",
+ "#137",
+ "#138",
+ "#139",
+ "#140",
+ "#141",
+ "#142",
+ "#143",
+ "#144",
+ "#145",
+ "#146",
+ "#147",
+ "#148",
+ "#149",
+ "#150",
+ "#151",
+ "#152",
+ "#153",
+ "#154",
+ "#155",
+ "#156",
+ "#157",
+ "#158",
+ "#159",
+ "#160",
+ "#161",
+ "#162",
+ "#163",
+ "#164",
+ "#165",
+ "#166",
+ "#167",
+ "#168",
+ "#169",
+ "#170",
+ "#171",
+ "#172",
+ "#173",
+ "#174",
+ "#175",
+ "#176",
+ "#177",
+ "#178",
+ "#179",
+ "#180",
+ "#181",
+ "#182",
+ "#183",
+ "#184",
+ "#185",
+ "#186",
+ "#187",
+ "#188",
+ "#189",
+ "#180",
+ "#191",
+ "#192",
+ "#193",
+ "#194",
+ "#195",
+ "#196",
+ "#197",
+ "#198",
+ "#199",
+ "#200",
+ "#201",
+ "#202",
+ "#203",
+ "#204",
+ "#205",
+ "#206",
+ "#207",
+ "#208",
+ "#209",
+ "#210",
+ "#211",
+ "#212",
+ "#213",
+ "#214",
+ "#215",
+ "#216",
+ "#217",
+ "#218",
+ "#219",
+ "#220",
+ "#221",
+ "#222",
+ "#223",
+ "#224",
+ "#225",
+ "#226",
+ "#227",
+ "#228",
+ "#229",
+ "#230",
+ "#231",
+ "#232",
+ "#233",
+ "#234",
+ "#235",
+ "#236",
+ "#237",
+ "#238",
+ "#239",
+ "#240",
+ "#241",
+ "#242",
+ "#243",
+ "#244",
+ "#245",
+ "#246",
+ "#247",
+ "#248",
+ "#249",
+ "#250",
+ "#251",
+ "#252",
+ "#253",
+ "#254",
+ "#255",
+};
+
+/*
+ * Dump IP6 statistics structure.
+ */
+void
+ip6_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct ip6stat ip6stat;
+ int first, i;
+
+ if (off == 0)
+ return;
+
+ kread(off, (char *)&ip6stat, sizeof (ip6stat));
+ printf("%s:\n", name);
+
+#define p(f, m) if (ip6stat.f || sflag <= 1) \
+ printf(m, ip6stat.f, plural(ip6stat.f))
+#define p1a(f, m) if (ip6stat.f || sflag <= 1) \
+ printf(m, ip6stat.f)
+
+ p(ip6s_total, "\t%lu total packet%s received\n");
+ p1a(ip6s_toosmall, "\t%lu with size smaller than minimum\n");
+ p1a(ip6s_tooshort, "\t%lu with data size < data length\n");
+ p1a(ip6s_badoptions, "\t%lu with bad options\n");
+ p1a(ip6s_badvers, "\t%lu with incorrect version number\n");
+ p(ip6s_fragments, "\t%lu fragment%s received\n");
+ p(ip6s_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
+ p(ip6s_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
+ p(ip6s_fragoverflow, "\t%lu fragment%s that exceeded limit\n");
+ p(ip6s_reassembled, "\t%lu packet%s reassembled ok\n");
+ p(ip6s_delivered, "\t%lu packet%s for this host\n");
+ p(ip6s_forward, "\t%lu packet%s forwarded\n");
+ p(ip6s_cantforward, "\t%lu packet%s not forwardable\n");
+ p(ip6s_redirectsent, "\t%lu redirect%s sent\n");
+ p(ip6s_localout, "\t%lu packet%s sent from this host\n");
+ p(ip6s_rawout, "\t%lu packet%s sent with fabricated ip header\n");
+ p(ip6s_odropped, "\t%lu output packet%s dropped due to no bufs, etc.\n");
+ p(ip6s_noroute, "\t%lu output packet%s discarded due to no route\n");
+ p(ip6s_fragmented, "\t%lu output datagram%s fragmented\n");
+ p(ip6s_ofragments, "\t%lu fragment%s created\n");
+ p(ip6s_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
+ p(ip6s_badscope, "\t%lu packet%s that violated scope rules\n");
+ p(ip6s_notmember, "\t%lu multicast packet%s which we don't join\n");
+ for (first = 1, i = 0; i < 256; i++)
+ if (ip6stat.ip6s_nxthist[i] != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", ip6nh[i],
+ ip6stat.ip6s_nxthist[i]);
+ }
+ printf("\tMbuf statistics:\n");
+ printf("\t\t%lu one mbuf\n", ip6stat.ip6s_m1);
+ for (first = 1, i = 0; i < 32; i++) {
+ if (ip6stat.ip6s_m2m[i] != 0) {
+ if (first) {
+ printf("\t\ttwo or more mbuf:\n");
+ first = 0;
+ }
+ printf("\t\t\t"
+#ifdef notyet
+ "%s"
+#else
+ "if%d"
+#endif
+ "= %ld\n",
+#ifdef notyet
+ if_indextoname(i, ifbuf),
+#else
+ i,
+#endif
+ ip6stat.ip6s_m2m[i]);
+ }
+ }
+ printf("\t\t%lu one ext mbuf\n", ip6stat.ip6s_mext1);
+ printf("\t\t%lu two or more ext mbuf\n", ip6stat.ip6s_mext2m);
+ p(ip6s_exthdrtoolong, "\t%lu packet%s whose headers are not continuous\n");
+ p(ip6s_nogif, "\t%lu tunneling packet%s that can't find gif\n");
+ p(ip6s_toomanyhdr, "\t%lu packet%s discarded due to too may headers\n");
+#undef p
+}
+
+/*
+ * Dump IPv6 per-interface statistics based on RFC 2465.
+ */
+void
+ip6_ifstats(ifname)
+ char *ifname;
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
+ printf(m, ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f))
+#define p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
+ printf(m, ip6stat.f)
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET6)");
+ return;
+ }
+
+ strcpy(ifr.ifr_name, ifname);
+ printf("ip6 on %s:\n", ifr.ifr_name);
+
+ if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
+ perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
+ goto end;
+ }
+
+ p(ifs6_in_receive, "\t%qu total input datagram%s\n");
+ p(ifs6_in_hdrerr, "\t%qu datagram%s with invalid header received\n");
+ p(ifs6_in_toobig, "\t%qu datagram%s exceeded MTU received\n");
+ p(ifs6_in_noroute, "\t%qu datagram%s with no route received\n");
+ p(ifs6_in_addrerr, "\t%qu datagram%s with invalid dst received\n");
+ p(ifs6_in_protounknown, "\t%qu datagram%s with unknown proto received\n");
+ p(ifs6_in_truncated, "\t%qu truncated datagram%s received\n");
+ p(ifs6_in_discard, "\t%qu input datagram%s discarded\n");
+ p(ifs6_in_deliver,
+ "\t%qu datagram%s delivered to an upper layer protocol\n");
+ p(ifs6_out_forward, "\t%qu datagram%s forwarded to this interface\n");
+ p(ifs6_out_request,
+ "\t%qu datagram%s sent from an upper layer protocol\n");
+ p(ifs6_out_discard, "\t%qu total discarded output datagram%s\n");
+ p(ifs6_out_fragok, "\t%qu output datagram%s fragmented\n");
+ p(ifs6_out_fragfail, "\t%qu output datagram%s failed on fragment\n");
+ p(ifs6_out_fragcreat, "\t%qu output datagram%s succeeded on fragment\n");
+ p(ifs6_reass_reqd, "\t%qu incoming datagram%s fragmented\n");
+ p(ifs6_reass_ok, "\t%qu datagram%s reassembled\n");
+ p(ifs6_reass_fail, "\t%qu datagram%s failed on reassembling\n");
+ p(ifs6_in_mcast, "\t%qu multicast datagram%s received\n");
+ p(ifs6_out_mcast, "\t%qu multicast datagram%s sent\n");
+
+ end:
+ close(s);
+
+#undef p
+#undef p_5
+}
+
+static char *icmp6names[] = {
+ "#0",
+ "unreach",
+ "packet too big",
+ "time exceed",
+ "parameter problem",
+ "#5",
+ "#6",
+ "#7",
+ "#8",
+ "#9",
+ "#10",
+ "#11",
+ "#12",
+ "#13",
+ "#14",
+ "#15",
+ "#16",
+ "#17",
+ "#18",
+ "#19",
+ "#20",
+ "#21",
+ "#22",
+ "#23",
+ "#24",
+ "#25",
+ "#26",
+ "#27",
+ "#28",
+ "#29",
+ "#30",
+ "#31",
+ "#32",
+ "#33",
+ "#34",
+ "#35",
+ "#36",
+ "#37",
+ "#38",
+ "#39",
+ "#40",
+ "#41",
+ "#42",
+ "#43",
+ "#44",
+ "#45",
+ "#46",
+ "#47",
+ "#48",
+ "#49",
+ "#50",
+ "#51",
+ "#52",
+ "#53",
+ "#54",
+ "#55",
+ "#56",
+ "#57",
+ "#58",
+ "#59",
+ "#60",
+ "#61",
+ "#62",
+ "#63",
+ "#64",
+ "#65",
+ "#66",
+ "#67",
+ "#68",
+ "#69",
+ "#70",
+ "#71",
+ "#72",
+ "#73",
+ "#74",
+ "#75",
+ "#76",
+ "#77",
+ "#78",
+ "#79",
+ "#80",
+ "#81",
+ "#82",
+ "#83",
+ "#84",
+ "#85",
+ "#86",
+ "#87",
+ "#88",
+ "#89",
+ "#80",
+ "#91",
+ "#92",
+ "#93",
+ "#94",
+ "#95",
+ "#96",
+ "#97",
+ "#98",
+ "#99",
+ "#100",
+ "#101",
+ "#102",
+ "#103",
+ "#104",
+ "#105",
+ "#106",
+ "#107",
+ "#108",
+ "#109",
+ "#110",
+ "#111",
+ "#112",
+ "#113",
+ "#114",
+ "#115",
+ "#116",
+ "#117",
+ "#118",
+ "#119",
+ "#120",
+ "#121",
+ "#122",
+ "#123",
+ "#124",
+ "#125",
+ "#126",
+ "#127",
+ "echo",
+ "echo reply",
+ "multicast listener query",
+ "multicast listener report",
+ "multicast listener done",
+ "router solicitation",
+ "router advertisment",
+ "neighbor solicitation",
+ "neighbor advertisment",
+ "redirect",
+ "router renumbering",
+ "node information request",
+ "node information reply",
+ "#141",
+ "#142",
+ "#143",
+ "#144",
+ "#145",
+ "#146",
+ "#147",
+ "#148",
+ "#149",
+ "#150",
+ "#151",
+ "#152",
+ "#153",
+ "#154",
+ "#155",
+ "#156",
+ "#157",
+ "#158",
+ "#159",
+ "#160",
+ "#161",
+ "#162",
+ "#163",
+ "#164",
+ "#165",
+ "#166",
+ "#167",
+ "#168",
+ "#169",
+ "#170",
+ "#171",
+ "#172",
+ "#173",
+ "#174",
+ "#175",
+ "#176",
+ "#177",
+ "#178",
+ "#179",
+ "#180",
+ "#181",
+ "#182",
+ "#183",
+ "#184",
+ "#185",
+ "#186",
+ "#187",
+ "#188",
+ "#189",
+ "#180",
+ "#191",
+ "#192",
+ "#193",
+ "#194",
+ "#195",
+ "#196",
+ "#197",
+ "#198",
+ "#199",
+ "#200",
+ "#201",
+ "#202",
+ "#203",
+ "#204",
+ "#205",
+ "#206",
+ "#207",
+ "#208",
+ "#209",
+ "#210",
+ "#211",
+ "#212",
+ "#213",
+ "#214",
+ "#215",
+ "#216",
+ "#217",
+ "#218",
+ "#219",
+ "#220",
+ "#221",
+ "#222",
+ "#223",
+ "#224",
+ "#225",
+ "#226",
+ "#227",
+ "#228",
+ "#229",
+ "#230",
+ "#231",
+ "#232",
+ "#233",
+ "#234",
+ "#235",
+ "#236",
+ "#237",
+ "#238",
+ "#239",
+ "#240",
+ "#241",
+ "#242",
+ "#243",
+ "#244",
+ "#245",
+ "#246",
+ "#247",
+ "#248",
+ "#249",
+ "#250",
+ "#251",
+ "#252",
+ "#253",
+ "#254",
+ "#255",
+};
+
+/*
+ * Dump ICMP6 statistics.
+ */
+void
+icmp6_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct icmp6stat icmp6stat;
+ register int i, first;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&icmp6stat, sizeof (icmp6stat));
+ printf("%s:\n", name);
+
+#define p(f, m) if (icmp6stat.f || sflag <= 1) \
+ printf(m, icmp6stat.f, plural(icmp6stat.f))
+
+ p(icp6s_error, "\t%lu call%s to icmp_error\n");
+ p(icp6s_canterror,
+ "\t%lu error%s not generated because old message was icmp error or so\n");
+ p(icp6s_toofreq,
+ "\t%lu error%s not generated because rate limitation\n");
+ for (first = 1, i = 0; i < 256; i++)
+ if (icmp6stat.icp6s_outhist[i] != 0) {
+ if (first) {
+ printf("\tOutput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", icmp6names[i],
+ icmp6stat.icp6s_outhist[i]);
+ }
+ p(icp6s_badcode, "\t%lu message%s with bad code fields\n");
+ p(icp6s_tooshort, "\t%lu message%s < minimum length\n");
+ p(icp6s_checksum, "\t%lu bad checksum%s\n");
+ p(icp6s_badlen, "\t%lu message%s with bad length\n");
+ for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++)
+ if (icmp6stat.icp6s_inhist[i] != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", icmp6names[i],
+ icmp6stat.icp6s_inhist[i]);
+ }
+ p(icp6s_reflect, "\t%lu message response%s generated\n");
+#undef p
+#undef p_5
+}
+
+/*
+ * Dump ICMPv6 per-interface statistics based on RFC 2466.
+ */
+void
+icmp6_ifstats(ifname)
+ char *ifname;
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
+ printf(m, (u_quad_t)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET6)");
+ return;
+ }
+
+ strcpy(ifr.ifr_name, ifname);
+ printf("icmp6 on %s:\n", ifr.ifr_name);
+
+ if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
+ perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
+ goto end;
+ }
+
+ p(ifs6_in_msg, "\t%qu total input message%s\n");
+ p(ifs6_in_error, "\t%qu total input error message%s\n");
+ p(ifs6_in_dstunreach, "\t%qu input destination unreachable error%s\n");
+ p(ifs6_in_adminprohib, "\t%qu input administratively prohibited error%s\n");
+ p(ifs6_in_timeexceed, "\t%qu input time exceeded error%s\n");
+ p(ifs6_in_paramprob, "\t%qu input parameter problem error%s\n");
+ p(ifs6_in_pkttoobig, "\t%qu input packet too big error%s\n");
+ p(ifs6_in_echo, "\t%qu input echo request%s\n");
+ p(ifs6_in_echoreply, "\t%qu input echo reply%s\n");
+ p(ifs6_in_routersolicit, "\t%qu input router solicitation%s\n");
+ p(ifs6_in_routeradvert, "\t%qu input router advertisement%s\n");
+ p(ifs6_in_neighborsolicit, "\t%qu input neighbor solicitation%s\n");
+ p(ifs6_in_neighboradvert, "\t%qu input neighbor advertisement%s\n");
+ p(ifs6_in_redirect, "\t%qu input redirect%s\n");
+ p(ifs6_in_mldquery, "\t%qu input MLD query%s\n");
+ p(ifs6_in_mldreport, "\t%qu input MLD report%s\n");
+ p(ifs6_in_mlddone, "\t%qu input MLD done%s\n");
+
+ p(ifs6_out_msg, "\t%qu total output message%s\n");
+ p(ifs6_out_error, "\t%qu total output error message%s\n");
+ p(ifs6_out_dstunreach, "\t%qu output destination unreachable error%s\n");
+ p(ifs6_out_adminprohib, "\t%qu output administratively prohibited error%s\n");
+ p(ifs6_out_timeexceed, "\t%qu output time exceeded error%s\n");
+ p(ifs6_out_paramprob, "\t%qu output parameter problem error%s\n");
+ p(ifs6_out_pkttoobig, "\t%qu output packet too big error%s\n");
+ p(ifs6_out_echo, "\t%qu output echo request%s\n");
+ p(ifs6_out_echoreply, "\t%qu output echo reply%s\n");
+ p(ifs6_out_routersolicit, "\t%qu output router solicitation%s\n");
+ p(ifs6_out_routeradvert, "\t%qu output router advertisement%s\n");
+ p(ifs6_out_neighborsolicit, "\t%qu output neighbor solicitation%s\n");
+ p(ifs6_out_neighboradvert, "\t%qu output neighbor advertisement%s\n");
+ p(ifs6_out_redirect, "\t%qu output redirect%s\n");
+ p(ifs6_out_mldquery, "\t%qu output MLD query%s\n");
+ p(ifs6_out_mldreport, "\t%qu output MLD report%s\n");
+ p(ifs6_out_mlddone, "\t%qu output MLD done%s\n");
+
+ end:
+ close(s);
+#undef p
+}
+
+/*
+ * Dump PIM statistics structure.
+ */
+void
+pim6_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct pim6stat pim6stat;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&pim6stat, sizeof(pim6stat));
+ printf("%s:\n", name);
+
+#define p(f, m) if (pim6stat.f || sflag <= 1) \
+ printf(m, pim6stat.f, plural(pim6stat.f))
+ p(pim6s_rcv_total, "\t%u message%s received\n");
+ p(pim6s_rcv_tooshort, "\t%u message%s received with too few bytes\n");
+ p(pim6s_rcv_badsum, "\t%u message%s received with bad checksum\n");
+ p(pim6s_rcv_badversion, "\t%u message%s received with bad version\n");
+ p(pim6s_rcv_registers, "\t%u register%s received\n");
+ p(pim6s_rcv_badregisters, "\t%u bad register%s received\n");
+ p(pim6s_snd_registers, "\t%u register%s sent\n");
+#undef p
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ * If the nflag was specified, use numbers instead of names.
+ */
+#define GETSERVBYPORT6(port, proto, ret)\
+{\
+ if (strcmp((proto), "tcp6") == 0)\
+ (ret) = getservbyport((int)(port), "tcp");\
+ else if (strcmp((proto), "udp6") == 0)\
+ (ret) = getservbyport((int)(port), "udp");\
+ else\
+ (ret) = getservbyport((int)(port), (proto));\
+};
+
+void
+inet6print(in6, port, proto, numeric)
+ register struct in6_addr *in6;
+ int port;
+ char *proto;
+ int numeric;
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ sprintf(line, "%.*s.", lflag ? 39 :
+ (Aflag && !numeric) ? 12 : 16, inet6name(in6));
+ cp = index(line, '\0');
+ if (!numeric && port)
+ GETSERVBYPORT6(port, proto, sp);
+ if (sp || port == 0)
+ sprintf(cp, "%.8s", sp ? sp->s_name : "*");
+ else
+ sprintf(cp, "%d", ntohs((u_short)port));
+ width = lflag ? 45 : Aflag ? 18 : 22;
+ printf(" %-*.*s", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+
+char *
+inet6name(in6p)
+ struct in6_addr *in6p;
+{
+ register char *cp;
+ static char line[50];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.')))
+ (void) strcpy(domain, cp + 1);
+ else
+ domain[0] = 0;
+ }
+ cp = 0;
+ if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
+ hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
+ if (hp) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED(in6p))
+ strcpy(line, "*");
+ else if (cp)
+ strcpy(line, cp);
+ else
+ sprintf(line, "%s",
+ inet_ntop(AF_INET6, (void *)in6p, ntop_buf,
+ sizeof(ntop_buf)));
+ return (line);
+}
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c
index 1a5bc14..034ffbd 100644
--- a/usr.bin/netstat/main.c
+++ b/usr.bin/netstat/main.c
@@ -125,6 +125,26 @@ static struct nlist nl[] = {
{ "_ddpcb"},
#define N_NGSOCKS 27
{ "_ngsocklist"},
+#define N_IP6STAT 28
+ { "_ip6stat" },
+#define N_ICMP6STAT 29
+ { "_icmp6stat" },
+#ifdef notyet
+#define N_IPSECSTAT 30
+ { "_ipsecstat" },
+#define N_IPSEC6STAT 31
+ { "_ipsec6stat" },
+#define N_PIM6STAT 32
+ { "_pim6stat" },
+#define N_MRT6PROTO 33
+ { "_ip6_mrtproto" },
+#define N_MRT6STAT 34
+ { "_mrt6stat" },
+#define N_MF6CTABLE 35
+ { "_mf6ctable" },
+#define N_MIF6TABLE 36
+ { "_mif6table" },
+#endif
{ "" },
};
@@ -134,81 +154,116 @@ struct protox {
u_char pr_wanted; /* 1 if wanted, 0 otherwise */
void (*pr_cblocks)(); /* control blocks printing routine */
void (*pr_stats)(); /* statistics printing routine */
+ void (*pr_istats)(); /* per/if statistics printing routine */
char *pr_name; /* well-known name */
int pr_usesysctl; /* true if we use sysctl, not kvm */
} protox[] = {
{ -1, -1, 1, protopr,
- tcp_stats, "tcp", IPPROTO_TCP },
+ tcp_stats, NULL, "tcp", IPPROTO_TCP },
{ -1, -1, 1, protopr,
- udp_stats, "udp", IPPROTO_UDP },
+ udp_stats, NULL, "udp", IPPROTO_UDP },
{ -1, -1, 1, protopr,
- NULL, "divert", IPPROTO_DIVERT },
+ NULL, NULL, "divert",IPPROTO_DIVERT },
{ -1, -1, 1, protopr,
- ip_stats, "ip", IPPROTO_RAW },
+ ip_stats, NULL, "ip", IPPROTO_RAW },
{ -1, -1, 1, protopr,
- icmp_stats, "icmp", IPPROTO_ICMP },
+ icmp_stats, NULL, "icmp", IPPROTO_ICMP },
{ -1, -1, 1, protopr,
- igmp_stats, "igmp", IPPROTO_IGMP },
+ igmp_stats, NULL, "igmp", IPPROTO_IGMP },
+#ifdef IPSEC
+ { -1, N_IPSECSTAT, 1, 0,
+ ipsec_stats, NULL, "ipsec", 0},
+#endif
{ -1, -1, 1, protopr,
- bdg_stats, "bdg", 1 /* bridging... */ },
+ bdg_stats, NULL, "bdg", 1 /* bridging... */ },
{ -1, -1, 0, 0,
- 0, 0 }
+ 0, NULL, 0 }
};
+#ifdef INET6
+struct protox ip6protox[] = {
+ { -1, -1, 1, protopr,
+ tcp_stats, NULL, "tcp", IPPROTO_TCP },
+ { -1, -1, 1, protopr,
+ udp_stats, NULL, "udp", IPPROTO_UDP },
+ { -1, N_IP6STAT, 1, 0,
+ ip6_stats, ip6_ifstats, "ip6", 0 },
+ { -1, N_ICMP6STAT, 1, 0,
+ icmp6_stats, icmp6_ifstats, "icmp6",0 },
+#ifdef IPSEC
+ { -1, N_IPSEC6STAT, 1, 0,
+ ipsec_stats, NULL, "ipsec6",0 },
+#endif
+#ifdef notyet
+ { -1, N_PIM6STAT, 1, 0,
+ pim6_stats, NULL, "pim6", 0 },
+#endif
+ { -1, -1, 1, protopr,
+ bdg_stats, NULL, "bdg", 1 /* bridging... */ },
+ { -1, -1, 0, 0,
+ 0, NULL, 0, 0 }
+};
+#endif /*INET6*/
+
struct protox atalkprotox[] = {
{ N_DDPCB, N_DDPSTAT, 1, atalkprotopr,
- ddp_stats, "ddp" },
+ ddp_stats, NULL, "ddp" },
{ -1, -1, 0, 0,
- 0, 0 }
+ 0, NULL, 0 }
};
struct protox netgraphprotox[] = {
{ N_NGSOCKS, -1, 1, netgraphprotopr,
- NULL, "ctrl" },
+ NULL, NULL, "ctrl" },
{ N_NGSOCKS, -1, 1, netgraphprotopr,
- NULL, "data" },
- { -1, -1, 0, 0,
- 0, 0 }
+ NULL, NULL, "data" },
+ { -1, NULL, 0, 0,
+ 0, NULL, 0 }
};
struct protox ipxprotox[] = {
{ N_IPX, N_IPXSTAT, 1, ipxprotopr,
- ipx_stats, "ipx", 0 },
+ ipx_stats, NULL, "ipx", 0 },
{ N_IPX, N_SPXSTAT, 1, ipxprotopr,
- spx_stats, "spx", 0 },
+ spx_stats, NULL, "spx", 0 },
{ -1, -1, 0, 0,
- 0, 0, 0 }
+ 0, NULL, 0, 0 }
};
#ifdef NS
struct protox nsprotox[] = {
{ N_IDP, N_IDPSTAT, 1, nsprotopr,
- idp_stats, "idp" },
+ idp_stats, NULL, "idp" },
{ N_IDP, N_SPPSTAT, 1, nsprotopr,
- spp_stats, "spp" },
+ spp_stats, NULL, "spp" },
{ -1, N_NSERR, 1, 0,
- nserr_stats, "ns_err" },
+ nserr_stats, NULL, "ns_err" },
{ -1, -1, 0, 0,
- 0, 0 }
+ 0, NULL, 0 }
};
#endif
#ifdef ISO
struct protox isoprotox[] = {
{ ISO_TP, N_TPSTAT, 1, iso_protopr,
- tp_stats, "tp" },
+ tp_stats, NULL, "tp" },
{ N_CLTP, N_CLTPSTAT, 1, iso_protopr,
- cltp_stats, "cltp" },
+ cltp_stats, NULL, "cltp" },
{ -1, N_CLNPSTAT, 1, 0,
- clnp_stats, "clnp"},
+ clnp_stats, NULL, "clnp"},
{ -1, N_ESISSTAT, 1, 0,
- esis_stats, "esis"},
+ esis_stats, NULL, "esis"},
{ -1, -1, 0, 0,
- 0, 0 }
+ 0, NULL, 0 }
};
#endif
-struct protox *protoprotox[] = { protox, ipxprotox, atalkprotox,
+struct protox *protoprotox[] = {
+ protox,
+#ifdef INET6
+ ip6protox,
+#endif
+ ipxprotox, atalkprotox,
#ifdef NS
nsprotox,
#endif
@@ -230,13 +285,12 @@ main(argc, argv)
int argc;
char *argv[];
{
- register struct protoent *p;
register struct protox *tp = NULL; /* for printing cblocks & stats */
int ch;
af = AF_UNSPEC;
- while ((ch = getopt(argc, argv, "Aabdf:ghI:iM:mN:np:rstuw:")) != -1)
+ while ((ch = getopt(argc, argv, "Aabdf:ghI:liM:mN:np:rstuw:")) != -1)
switch(ch) {
case 'A':
Aflag = 1;
@@ -260,6 +314,10 @@ main(argc, argv)
af = AF_IPX;
else if (strcmp(optarg, "inet") == 0)
af = AF_INET;
+#ifdef INET6
+ else if (strcmp(optarg, "inet6") == 0)
+ af = AF_INET6;
+#endif /*INET6*/
else if (strcmp(optarg, "unix") == 0)
af = AF_UNIX;
else if (strcmp(optarg, "atalk") == 0)
@@ -290,6 +348,9 @@ main(argc, argv)
case 'i':
iflag = 1;
break;
+ case 'l':
+ lflag = 1;
+ break;
case 'M':
memf = optarg;
break;
@@ -363,6 +424,11 @@ main(argc, argv)
exit(0);
}
if (pflag) {
+ if (iflag && tp->pr_istats) {
+ kread(0, 0, 0);
+ intpr(interval, nl[N_IFNET].n_value, tp->pr_istats);
+ exit(0);
+ }
if (!tp->pr_stats) {
printf("%s: no stats routine\n", tp->pr_name);
exit(0);
@@ -391,8 +457,11 @@ main(argc, argv)
*/
#endif
if (iflag) {
+ if (af != AF_UNSPEC)
+ goto protostat;
+
kread(0, 0, 0);
- intpr(interval, nl[N_IFNET].n_value);
+ intpr(interval, nl[N_IFNET].n_value, NULL);
exit(0);
}
if (rflag) {
@@ -405,27 +474,40 @@ main(argc, argv)
}
if (gflag) {
kread(0, 0, 0);
- if (sflag)
- mrt_stats(nl[N_MRTSTAT].n_value);
- else
- mroutepr(nl[N_MFCTABLE].n_value,
- nl[N_VIFTABLE].n_value);
- exit(0);
- }
- if (af == AF_INET || af == AF_UNSPEC) {
- setprotoent(1);
- setservent(1);
- /* ugh, this is O(MN) ... why do we do this? */
- while ((p = getprotoent())) {
- for (tp = protox; tp->pr_name; tp++)
- if (strcmp(tp->pr_name, p->p_name) == 0)
- break;
- if (tp->pr_name == 0 || tp->pr_wanted == 0)
- continue;
- printproto(tp, p->p_name);
+ if (sflag) {
+ if (af == AF_INET || af == AF_UNSPEC)
+ mrt_stats(nl[N_MRTSTAT].n_value);
+#ifdef INET6
+#ifdef notyet
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ mrt6_stats(nl[N_MRT6STAT].n_value);
+#endif
+#endif
+ } else {
+ if (af == AF_INET || af == AF_UNSPEC)
+ mroutepr(nl[N_MFCTABLE].n_value,
+ nl[N_VIFTABLE].n_value);
+#ifdef INET6
+#ifdef notyet
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ mroute6pr(nl[N_MF6CTABLE].n_value,
+ nl[N_MIF6TABLE].n_value);
+#endif
+#endif
}
- endprotoent();
+ exit(0);
}
+
+ protostat:
+ kread(0, 0, 0);
+ if (af == AF_INET || af == AF_UNSPEC)
+ for (tp = protox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#ifdef INET6
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ for (tp = ip6protox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*INET6*/
if (af == AF_IPX || af == AF_UNSPEC) {
kread(0, 0, 0);
for (tp = ipxprotox; tp->pr_name; tp++)
@@ -466,16 +548,24 @@ printproto(tp, name)
u_long off;
if (sflag) {
- pr = tp->pr_stats;
- off = tp->pr_usesysctl ? tp->pr_usesysctl
- : nl[tp->pr_sindex].n_value;
+ if (iflag) {
+ if (tp->pr_istats)
+ intpr(interval, nl[N_IFNET].n_value,
+ tp->pr_istats);
+ return;
+ }
+ else {
+ pr = tp->pr_stats;
+ off = tp->pr_usesysctl ? tp->pr_usesysctl
+ : nl[tp->pr_sindex].n_value;
+ }
} else {
pr = tp->pr_cblocks;
off = tp->pr_usesysctl ? tp->pr_usesysctl
: nl[tp->pr_index].n_value;
}
if (pr != NULL && (off || af != AF_UNSPEC))
- (*pr)(off, name);
+ (*pr)(off, name, af);
}
/*
@@ -566,11 +656,11 @@ name2protox(name)
* Try to find the name in the list of "well-known" names. If that
* fails, check if name is an alias for an Internet protocol.
*/
- if ((tp = knownname(name)))
+ if ((tp = knownname(name)) != NULL)
return (tp);
setprotoent(1); /* make protocol lookup cheaper */
- while ((p = getprotoent())) {
+ while ((p = getprotoent()) != NULL) {
/* assert: name not same as p->name */
for (alias = p->p_aliases; *alias; alias++)
if (strcmp(name, *alias) == 0) {
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index 4eb0b5e..30a8249 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -45,7 +45,7 @@
.Op Fl M Ar core
.Op Fl N Ar system
.Nm netstat
-.Op Fl bdghimnrs
+.Op Fl bdghilmnrs
.Op Fl f Ar address_family
.Op Fl M Ar core
.Op Fl N Ar system
@@ -59,6 +59,15 @@
.Op Fl p Ar protocol
.Op Fl M Ar core
.Op Fl N Ar system
+.Nm netstat
+.Op Fl p Ar protocol
+.Op Fl i
+.Op Fl I Ar Interface
+.Nm netstat
+.Op Fl s
+.Op Fl f Ar address_family
+.Op Fl i
+.Op Fl I Ar Interface
.Sh DESCRIPTION
The
.Nm netstat
@@ -77,6 +86,8 @@ interval specified,
will continuously display the information regarding packet
traffic on the configured network interfaces.
The fourth form displays statistics about the named protocol.
+The fifth and sixth forms display per interface statistics for
+the specified protocol or address family.
.Pp
The options have the following meaning:
.Bl -tag -width flag
@@ -112,6 +123,9 @@ are recognized:
.Ar inet ,
for
.Dv AF_INET ,
+.Ar inet6 ,
+for
+.Dv AF_INET6 ,
.Ar ipx ,
for
.Dv AF_IPX ,
@@ -148,6 +162,19 @@ Show information about the specified interface;
used with a
.Ar wait
interval as described below.
+If the
+.Fl f Ar address_family
+option (with the
+.Fl s
+option) or the
+.Fl p Ar protocol
+option is present, show per-interface statistics on the
+.Ar interface
+for the specfied
+.Ar address_family
+or
+.Ar protocol,
+respectively.
.It Fl i
Show the state of interfaces which have been auto-configured
(interfaces statically configured into a system, but not
@@ -158,6 +185,18 @@ options is also present, multicast addresses currently in use are shown
for each Ethernet interface and for each IP interface address.
Multicast addresses are shown on separate lines following the interface
address with which they are associated.
+If the
+.Fl f Ar address_family
+option (with the
+.Fl s
+option) or the
+.Fl p Ar protocol
+option is present, show per-interface statistics on all interfaces
+for the specfied
+.Ar address_family
+or
+.Ar protocol,
+respectively.
.It Fl M
Extract values associated with the name list from the specified core
instead of the default
@@ -199,6 +238,11 @@ to show protocol-cloned routes.
When
.Fl s
is also present, show routing statistics instead.
+When
+.Fl l
+is also present,
+.Nm
+assumes more columns are there.
.It Fl w Ar wait
Show network interface statistics at intervals of
.Ar wait
@@ -317,6 +361,8 @@ The
.Nm netstat
command appeared in
.Bx 4.2 .
+.Pp
+IPv6 support was added by WIDE/KAME project.
.Sh FILES
.Bl -tag -width /dev/kmem -compact
.It Pa /kernel
diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h
index 1e67517..fc46dee 100644
--- a/usr.bin/netstat/netstat.h
+++ b/usr.bin/netstat/netstat.h
@@ -42,6 +42,7 @@ int bflag; /* show i/f total bytes in/out */
int dflag; /* show i/f dropped packets */
int gflag; /* show group (multicast) routing or stats */
int iflag; /* show interfaces */
+int lflag; /* show routing table with use and ref */
int mflag; /* show memory stats */
int nflag; /* show addresses numerically */
int pflag; /* show given protocol */
@@ -61,21 +62,36 @@ char *plural __P((int));
char *plurales __P((int));
void trimdomain __P((char *));
-void protopr __P((u_long, char *));
+void protopr __P((u_long, char *, int));
void tcp_stats __P((u_long, char *));
void udp_stats __P((u_long, char *));
void ip_stats __P((u_long, char *));
void icmp_stats __P((u_long, char *));
void igmp_stats __P((u_long, char *));
+#ifdef IPSEC
+void ipsec_stats __P((u_long, char *));
+#endif
+
+#ifdef INET6
+void ip6_stats __P((u_long, char *));
+void ip6_ifstats __P((char *));
+void icmp6_stats __P((u_long, char *));
+void icmp6_ifstats __P((char *));
+#ifdef notyet
+void pim6_stats __P((u_long, char *));
+void mroute6pr __P((u_long, u_long));
+void mrt6_stats __P((u_long));
+#endif
+#endif /*INET6*/
+
void bdg_stats __P((u_long, char *));
-void protopr __P((u_long, char *));
void mbpr __P((void));
void hostpr __P((u_long, u_long));
void impstats __P((u_long, u_long));
-void intpr __P((int, u_long));
+void intpr __P((int, u_long, void (*) __P((char *))));
void pr_rthdr __P(());
void pr_family __P((int));
@@ -108,8 +124,6 @@ void ddp_stats __P((u_long, char *));
void netgraphprotopr __P((u_long, char *));
-void intpr __P((int, u_long));
-
void unixpr __P((void));
void esis_stats __P((u_long, char *));
diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c
index 0cdbdf8..e41eec6 100644
--- a/usr.bin/netstat/route.c
+++ b/usr.bin/netstat/route.c
@@ -61,6 +61,7 @@ static const char rcsid[] =
#include <sys/sysctl.h>
+#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
@@ -127,6 +128,11 @@ static void p_rtentry __P((struct rtentry *));
static u_long forgemask __P((u_long));
static void domask __P((char *, u_long, u_long));
+#ifdef INET6
+char *routename6 __P((struct sockaddr_in6 *));
+char *netname6 __P((struct sockaddr_in6 *, struct in6_addr *));
+#endif /*INET6*/
+
/*
* Print routing tables.
*/
@@ -180,6 +186,11 @@ pr_family(af)
case AF_INET:
afname = "Internet";
break;
+#ifdef INET6
+ case AF_INET6:
+ afname = "Internet6";
+ break;
+#endif /*INET6*/
case AF_IPX:
afname = "IPX";
break;
@@ -211,8 +222,13 @@ pr_family(af)
}
/* column widths; each followed by one space */
-#define WID_DST 18 /* width of destination column */
+#ifndef INET6
+#define WID_DST 18 /* width of destination column */
#define WID_GW 18 /* width of gateway column */
+#else
+#define WID_DST (lflag ? 39 : (nflag ? 33: 18)) /* width of dest column */
+#define WID_GW (lflag ? 31 : (nflag ? 29 : 18)) /* width of gateway column */
+#endif /*INET6*/
/*
* Print header for routing table columns.
@@ -222,10 +238,16 @@ pr_rthdr()
{
if (Aflag)
printf("%-8.8s ","Address");
- printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %8.8s %6s\n",
- WID_DST, WID_DST, "Destination",
- WID_GW, WID_GW, "Gateway",
- "Flags", "Refs", "Use", "Netif", "Expire");
+ if (lflag)
+ printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %8.8s %6s\n",
+ WID_DST, WID_DST, "Destination",
+ WID_GW, WID_GW, "Gateway",
+ "Flags", "Refs", "Use", "Netif", "Expire");
+ else
+ printf("%-*.*s %-*.*s %-6.6s %8.8s %6s\n",
+ WID_DST, WID_DST, "Destination",
+ WID_GW, WID_GW, "Gateway",
+ "Flags", "Netif", "Expire");
}
static struct sockaddr *
@@ -379,8 +401,6 @@ np_rtentry(rtm)
p_sockaddr(sa, NULL, 0, 36);
else {
p_sockaddr(sa, NULL, rtm->rtm_flags, 16);
- if (sa->sa_len == 0)
- sa->sa_len = sizeof(long);
sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
p_sockaddr(sa, NULL, 0, 18);
}
@@ -414,6 +434,35 @@ p_sockaddr(sa, mask, flags, width)
break;
}
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
+ struct in6_addr *in6 = &sa6->sin6_addr;
+
+ /*
+ * XXX: This is a special workaround for KAME kernels.
+ * sin6_scope_id field of SA should be set in the future.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(in6) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
+ /* XXX: override is ok? */
+ sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
+ *(u_short *)&in6->s6_addr[2] = 0;
+ }
+
+ if (flags & RTF_HOST)
+ cp = routename6(sa6);
+ else if (mask)
+ cp = netname6(sa6,
+ &((struct sockaddr_in6 *)mask)->sin6_addr);
+ else {
+ cp = netname6(sa6, NULL);
+ }
+ break;
+ }
+#endif /*INET6*/
+
case AF_IPX:
{
struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
@@ -539,14 +588,15 @@ p_rtentry(rt)
p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, WID_DST);
p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, WID_GW);
p_flags(rt->rt_flags, "%-6.6s ");
- printf("%6ld %8ld ", rt->rt_refcnt, rt->rt_use);
+ if (lflag)
+ printf("%6ld %8ld ", rt->rt_refcnt, rt->rt_use);
if (rt->rt_ifp) {
if (rt->rt_ifp != lastif) {
kget(rt->rt_ifp, ifnet);
kread((u_long)ifnet.if_name, name, 16);
lastif = rt->rt_ifp;
snprintf(prettyname, sizeof prettyname,
- "%.6s%d", name, ifnet.if_unit);
+ "%s%d", name, ifnet.if_unit);
}
printf("%8.8s", prettyname);
if (rt->rt_rmx.rmx_expire) {
@@ -556,7 +606,10 @@ p_rtentry(rt)
rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0)
printf(" %6d%s", (int)expire_time,
rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
+ else
+ goto ifandkey;
} else if (rt->rt_nodes[0].rn_dupedkey) {
+ifandkey:;
printf(" =>");
}
@@ -679,6 +732,118 @@ netname(in, mask)
return (line);
}
+#ifdef INET6
+char *
+netname6(sa6, mask)
+ struct sockaddr_in6 *sa6;
+ struct in6_addr *mask;
+{
+ static char line[MAXHOSTNAMELEN + 1];
+ u_char *p = (u_char *)mask;
+ u_char *lim;
+ int masklen, illegal = 0;
+#ifdef notyet
+ int flag = NI_WITHSCOPEID;
+#endif
+
+ if (mask) {
+ for (masklen = 0, lim = p + 16; p < lim; p++) {
+ switch (*p) {
+ case 0xff:
+ masklen += 8;
+ break;
+ case 0xfe:
+ masklen += 7;
+ break;
+ case 0xfc:
+ masklen += 6;
+ break;
+ case 0xf8:
+ masklen += 5;
+ break;
+ case 0xf0:
+ masklen += 4;
+ break;
+ case 0xe0:
+ masklen += 3;
+ break;
+ case 0xc0:
+ masklen += 2;
+ break;
+ case 0x80:
+ masklen += 1;
+ break;
+ case 0x00:
+ break;
+ default:
+ illegal ++;
+ break;
+ }
+ }
+ if (illegal)
+ fprintf(stderr, "illegal prefixlen\n");
+ }
+ else
+ masklen = 128;
+
+ if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
+ return("default");
+
+#ifdef notyet
+ if (nflag)
+ flag |= NI_NUMERICHOST;
+ getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line),
+ NULL, 0, flag);
+#else
+ inet_ntop(AF_INET6, (void *)&sa6->sin6_addr, line, sizeof(line));
+#endif
+
+ if (nflag)
+ sprintf(&line[strlen(line)], "/%d", masklen);
+
+ return line;
+}
+
+char *
+routename6(sa6)
+ struct sockaddr_in6 *sa6;
+{
+#ifdef notyet
+ int flag = NI_WITHSCOPEID;
+
+ if (nflag)
+ flag |= NI_NUMERICHOST;
+#else
+ register char *cp;
+#endif
+ static char line[MAXHOSTNAMELEN + 1];
+ struct hostent *hp;
+
+#ifdef notyet
+ getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line),
+ NULL, 0, flag);
+#else
+ cp = 0;
+ if (!nflag) {
+ hp = gethostbyaddr((char *)&sa6->sin6_addr,
+ sizeof(sa6->sin6_addr), AF_INET6);
+ if (hp) {
+ cp = hp->h_name;
+ trimdomain(cp);
+ }
+ }
+ if (cp) {
+ strncpy(line, cp, sizeof(line) - 1);
+ line[sizeof(line) - 1] = '\0';
+ } else
+ inet_ntop(AF_INET6, (void *)&sa6->sin6_addr, line,
+ sizeof(line));
+#endif
+
+ return line;
+}
+#endif /*INET6*/
+
/*
* Print routing statistics
*/
OpenPOWER on IntegriCloud