From cfa1ca9dfa0ee5bed5cc1cb0b07820701abbb431 Mon Sep 17 00:00:00 2001 From: Yoshinobu Inoue Date: Tue, 7 Dec 1999 17:39:16 +0000 Subject: [PATCH] udp IPv6 support, IPv6/IPv4 tunneling support in kernel, packet divert at kernel for IPv6/IPv4 translater daemon This includes queue related patch submitted by jburkhol@home.com. Submitted by: queue related patch from jburkhol@home.com Reviewed by: freebsd-arch, cvs-committers Obtained from: KAME project --- sbin/ifconfig/Makefile | 1 + sbin/ifconfig/ifconfig.8 | 29 ++ sbin/ifconfig/ifconfig.c | 314 +++++++++++- sbin/route/Makefile | 2 + sbin/route/keywords | 3 + sbin/route/route.8 | 25 +- sbin/route/route.c | 150 +++++- sys/conf/NOTES | 9 + sys/conf/files | 45 +- sys/conf/options | 2 +- sys/i386/conf/LINT | 9 + sys/i386/conf/NOTES | 9 + sys/modules/if_disc/Makefile | 5 +- sys/net/if.c | 2 +- sys/net/if_atmsubr.c | 3 + sys/net/if_disc.c | 5 + sys/net/if_ethersubr.c | 1 + sys/net/if_faith.c | 97 ++++ sys/net/if_fddisubr.c | 24 +- sys/net/if_gif.c | 468 +++++++++++++++++ sys/net/if_gif.h | 3 - sys/net/if_loop.c | 9 +- sys/net/if_spppsubr.c | 19 +- sys/netinet/if_atm.c | 3 + sys/netinet/in_gif.c | 311 +++++++++++ sys/netinet/in_gif.h | 42 ++ sys/netinet/in_pcb.c | 114 ++++- sys/netinet/in_pcb.h | 3 +- sys/netinet/in_proto.c | 22 + sys/netinet/ip_fw.c | 12 +- sys/netinet/tcp_input.c | 9 +- sys/netinet/tcp_reass.c | 9 +- sys/netinet/tcp_subr.c | 4 +- sys/netinet/tcp_timewait.c | 4 +- sys/netinet/tcp_usrreq.c | 6 +- sys/netinet/udp_usrreq.c | 232 +++++++-- sys/netinet/udp_var.h | 2 +- sys/netinet6/icmp6.c | 14 +- sys/netinet6/icmp6.h | 3 + sys/netinet6/in6.c | 31 +- sys/netinet6/in6.h | 66 +-- sys/netinet6/in6_gif.c | 263 ++++++++++ sys/netinet6/in6_gif.h | 40 ++ sys/netinet6/in6_ifattach.c | 10 +- sys/netinet6/in6_pcb.c | 13 +- sys/netinet6/in6_prefix.c | 21 +- sys/netinet6/in6_proto.c | 32 +- sys/netinet6/in6_var.h | 11 +- sys/netinet6/ip6_forward.c | 6 - sys/netinet6/ip6_input.c | 10 +- sys/netinet6/ip6_output.c | 16 +- sys/netinet6/mld6.c | 2 - sys/netinet6/nd6.c | 40 +- sys/netinet6/nd6.h | 4 - sys/netinet6/nd6_nbr.c | 4 +- sys/netinet6/nd6_rtr.c | 40 +- sys/netinet6/raw_ip6.c | 6 +- sys/netinet6/udp6_usrreq.c | 835 ++++++++++++++++++++++++++++++ sys/netinet6/udp6_var.h | 2 + usr.bin/netstat/Makefile | 3 +- usr.bin/netstat/if.c | 88 +++- usr.bin/netstat/inet.c | 248 ++++++++- usr.bin/netstat/inet6.c | 962 +++++++++++++++++++++++++++++++++++ usr.bin/netstat/main.c | 200 ++++++-- usr.bin/netstat/netstat.1 | 48 +- usr.bin/netstat/netstat.h | 24 +- usr.bin/netstat/route.c | 183 ++++++- 67 files changed, 4790 insertions(+), 442 deletions(-) create mode 100644 sys/net/if_faith.c create mode 100644 sys/net/if_gif.c create mode 100644 sys/netinet/in_gif.c create mode 100644 sys/netinet/in_gif.h create mode 100644 sys/netinet6/in6_gif.c create mode 100644 sys/netinet6/in6_gif.h create mode 100644 sys/netinet6/udp6_usrreq.c create mode 100644 usr.bin/netstat/inet6.c diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile index b1fe95b06e84..385946d2982b 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 a2b399a7302d..6defcd488e6d 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 00fb30f1a483..32c7ee81a3fb 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 56679e1fd5ab..e581d8ccc079 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 07a0ddcbd095..00080a797483 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 04cd23ae80c9..d8a36b9e0f74 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 e0260b1cd0ab..8576d75ea432 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 @@ getaddr(which, s, hpp) 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 db2f5414d474..8ec43fc20a0e 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 dc919b1cb5f9..62700b5cb5c2 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,25 +620,6 @@ 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 -netinet6/dest6.c optional inet6 -netinet6/frag6.c optional inet6 -netinet6/icmp6.c optional inet6 -netinet6/ip6_input.c optional inet6 -netinet6/ip6_forward.c optional inet6 -netinet6/ip6_output.c optional inet6 -netinet6/route6.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 @@ -645,6 +629,27 @@ 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/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/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 +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 ed76e00ff3ff..3c7558b0c00b 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 db2f5414d474..8ec43fc20a0e 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 db2f5414d474..8ec43fc20a0e 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 63b859263dff..e33555dbddac 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 diff --git a/sys/net/if.c b/sys/net/if.c index 7c560bcaa9eb..c0ba5eebdd71 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 #include diff --git a/sys/net/if_atmsubr.c b/sys/net/if_atmsubr.c index 66cd09d7dbd5..0a357a6f6151 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 diff --git a/sys/net/if_disc.c b/sys/net/if_disc.c index b90a6581621d..66bd5f8e1416 100644 --- a/sys/net/if_disc.c +++ b/sys/net/if_disc.c @@ -52,6 +52,7 @@ #include #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 ec0f5cf27900..bf11e9d9f4df 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 000000000000..0e21af77db7c --- /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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 eedc822e09d3..0b3913102212 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 @@ -52,11 +53,14 @@ #include #include -#ifdef INET +#if defined(INET) || defined(INET6) #include #include #include #endif +#ifdef INET6 +#include +#endif #if defined(__FreeBSD__) #include #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 000000000000..3eaa703a5ebe --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#include +#include +#include +#endif /* INET */ + +#ifdef INET6 +#ifndef INET +#include +#endif +#include +#include +#include +#include +#endif /* INET6 */ + +#include + +#include "gif.h" + +#include + +#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 *)⁡ + + 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 *)⁡ + + 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 a402471b3402..cc26938b1951 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 -/* 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 c57f8578876f..a714bf1c7214 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 @@ -90,13 +91,13 @@ #include #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 133af2b92a8e..e02ef90f238d 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 020e5ace3b28..04b49bf7573f 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 000000000000..fd8317f52285 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#ifdef INET6 +#include +#endif + +#ifdef MROUTING +#include +#endif /* MROUTING */ + +#include + +#include "gif.h" + +#include + +#include + +#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 000000000000..b8745245d51c --- /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 d19d4496d6c2..71d091b953fc 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -34,10 +34,13 @@ * $FreeBSD$ */ +#include "opt_inet6.h" + #include #include #include #include +#include #include #include #include @@ -51,12 +54,25 @@ #include #include +#include #include #include #include #include #include +#ifdef INET6 +#include +#include +#endif /* INET6 */ + +#include "faith.h" + +#ifdef IPSEC +#include +#include +#include +#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; - head = &inp->inp_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; + + 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 adfa5fae0e64..5aeb579989e9 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 22647d966aa7..b9a9e4ad1f0a 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 +#endif + #ifdef IPXIP #include #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 a70822ebcd75..b897421e4021 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -707,10 +707,12 @@ non_ip: ip = NULL ; 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 @@ non_ip: ip = NULL ; 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 5f61ff38cb01..909adf998ede 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -390,7 +390,7 @@ tcp_input(m, iphlen) * 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 @@ tcp_input(m, iphlen) 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 @@ tcp_input(m, iphlen) #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 5f61ff38cb01..909adf998ede 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -390,7 +390,7 @@ tcp_input(m, iphlen) * 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 @@ tcp_input(m, iphlen) 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 @@ tcp_input(m, iphlen) #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 b472de52accb..fd3e43517b79 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 @@ -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 b472de52accb..fd3e43517b79 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 @@ -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 49fca1e066c4..af43fc346e4c 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 @@ -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 2f0cb58f1abe..f49a12844833 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -34,11 +34,14 @@ * $FreeBSD$ */ +#include "opt_inet6.h" + #include #include #include #include #include +#include #include #include #include @@ -54,14 +57,24 @@ #include #include #include +#ifdef INET6 +#include +#endif #include #include #include +#ifdef INET6 +#include +#endif #include #include #include #include +#ifdef IPSEC +#include +#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 @@ udp_input(m, iphlen) 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 0ee825863905..491632e6cc0d 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 425a5d57cc1c..943ddf7f20d5 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 @@ -97,15 +96,10 @@ #ifdef IPSEC #include -#ifdef INET6 #include -#endif /* INET6 */ #include #ifdef KEY_DEBUG #include -#ifdef INET6 -#include -#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 @@ -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 8fd63ffaefbd..2fdb28bf5701 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 e18b14f95804..a981c792f75d 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 #include #include @@ -81,10 +79,8 @@ #include #include #include -/* #include "gif.h" */ -#if NGIF > 0 -#include -#endif +#include "gif.h" + #include #include @@ -96,6 +92,9 @@ #include #include #include +#if NGIF > 0 +#include +#endif #include @@ -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 1ca678e25db7..b5266cee7abd 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: @@ -342,13 +343,6 @@ extern const struct in6_addr in6addr_linklocal_allrouters; (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_GLOBAL)) #endif -/* - * Wildcard Socket - */ -#if 0 /*pre-RFC2553*/ -#define IN6_IS_ADDR_ANY(a) IN6_IS_ADDR_UNSPECIFIED(a) -#endif - /* * KAME Scope */ @@ -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 000000000000..dd7cd2f204c1 --- /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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#ifdef INET +#include +#endif +#include +#include +#include +#include + +#include + +#include + +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 000000000000..7d06c3c4cba9 --- /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 85ca75fb2c49..7d332eda14bd 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 8aee5b300804..ac5b9238200a 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 @@ -96,19 +95,14 @@ #include #include -/* #include "faith.h" */ +#include "faith.h" #ifdef IPSEC #include -#ifdef INET6 #include -#endif /* INET6 */ #include #ifdef KEY_DEBUG #include -#ifdef INET6 -#include -#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 8da07c435678..6799d0d3247c 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 1d1c7a3e2662..3f59ec260903 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 #include #include @@ -104,9 +102,7 @@ #ifdef IPSEC #include -#ifdef INET6 #include -#endif /* INET6 */ #include #ifdef IPSEC_ESP #include @@ -116,7 +112,7 @@ #include -/* #include "gif.h" */ +#include "gif.h" #if NGIF > 0 #include #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, @@ -193,19 +195,17 @@ struct ip6protosw inet6sw[] = { #endif /* IPSEC */ #if NGIF > 0 { SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, - in6_gif_input,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, &nousrreqs }, -#endif /* INET6 */ +{ SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, + in6_gif_input,0, 0, 0, + 0, + 0, 0, 0, 0, + &nousrreqs +}, #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 4117c207ec2a..163c1679ccee 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 a50ba6c04521..46b318879ac5 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 @@ -56,15 +55,10 @@ #ifdef IPSEC_IPV6FWD #include -#ifdef INET6 #include -#endif /* INET6 */ #include #ifdef KEY_DEBUG #include -#ifdef INET6 -#include -#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 097d5a0c0fb7..105b4bc6889d 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 #include #include @@ -88,10 +86,8 @@ #include #include -#ifdef INET #include #include -#endif /*INET*/ #include #include #include @@ -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 @@ -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 de85510975d0..1524bc33939c 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 @@ -91,15 +90,10 @@ #ifdef IPSEC #include -#ifdef INET6 #include -#endif /* INET6 */ #include #ifdef KEY_DEBUG #include -#ifdef INET6 -#include -#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 43cb9b7a36a2..634f61b1bbf1 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 #include #include diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 87eab9de3ff4..74787f2a3bf6 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 2bb4fe4c3817..756f49585a3c 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 de09176c0a7f..840f07467e97 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -29,8 +29,6 @@ * $FreeBSD$ */ -#include "opt_inet.h" - #include #include #include @@ -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 d177a6601a06..da92879f5bed 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 c54874e8a3cd..3131e417b40b 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 #include @@ -94,14 +92,12 @@ #ifdef IPSEC #include -#ifdef INET6 #include -#endif /* INET6 */ #endif /*IPSEC*/ #include -/* #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 000000000000..c22a719823b2 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef IPSEC +#include +#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 b95bc782e4ce..e0ade7afc635 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 3c8092a5de22..78e80c77bb49 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 diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c index 8343363b4a57..43661639aa2b 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, "", sdl->sdl_index); + m = printf("%-11.11s ", linknum); } - m = printf("%-11.11s ", ""); 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 783cbc7fb51a..4a8cda188f54 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -50,6 +50,9 @@ static const char rcsid[] = #include #include #include +#ifdef INET6 +#include +#endif /* INET6 */ #include #include #include @@ -65,6 +68,9 @@ static const char rcsid[] = #include #include #include +#ifdef IPSEC +#include +#endif #include #include @@ -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 000000000000..154ee32d8ae1 --- /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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#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 1a5bc1494855..034ffbd1f039 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); + 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 + } 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); - } - endprotoent(); - } + + 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 4eb0b5e0417c..30a8249b3143 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 1e675171cfd7..fc46dee33722 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 0cdbdf8c7f44..e41eec67a45d 100644 --- a/usr.bin/netstat/route.c +++ b/usr.bin/netstat/route.c @@ -61,6 +61,7 @@ static const char rcsid[] = #include +#include #include #include #include @@ -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 */