diff options
author | 1999-12-08 06:50:14 +0000 | |
---|---|---|
committer | 1999-12-08 06:50:14 +0000 | |
commit | 287546ea80ee896bda0c88b8a8c85a1dc6ff37f9 (patch) | |
tree | cef428e54b6d2bca56fb9b461aa0667c7fb5f6a2 /sys/net | |
parent | add GENERIC.v6 (IPv6 test configuration). to be integrated into GENREIC. (diff) | |
download | wireguard-openbsd-287546ea80ee896bda0c88b8a8c85a1dc6ff37f9.tar.xz wireguard-openbsd-287546ea80ee896bda0c88b8a8c85a1dc6ff37f9.zip |
bring in KAME IPv6 code, dated 19991208.
replaces NRL IPv6 layer. reuses NRL pcb layer. no IPsec-on-v6 support.
see sys/netinet6/{TODO,IMPLEMENTATION} for more details.
GENERIC configuration should work fine as before. GENERIC.v6 works fine
as well, but you'll need KAME userland tools to play with IPv6 (will be
bringed into soon).
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if.c | 149 | ||||
-rw-r--r-- | sys/net/if.h | 43 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 80 | ||||
-rw-r--r-- | sys/net/if_faith.c | 323 | ||||
-rw-r--r-- | sys/net/if_fddisubr.c | 26 | ||||
-rw-r--r-- | sys/net/if_gif.c | 552 | ||||
-rw-r--r-- | sys/net/if_gif.h | 86 | ||||
-rw-r--r-- | sys/net/if_loop.c | 106 | ||||
-rw-r--r-- | sys/net/if_ppp.c | 8 | ||||
-rw-r--r-- | sys/net/if_tun.c | 14 | ||||
-rw-r--r-- | sys/net/if_types.h | 8 | ||||
-rw-r--r-- | sys/net/net_osdep.c | 87 | ||||
-rw-r--r-- | sys/net/net_osdep.h | 149 | ||||
-rw-r--r-- | sys/net/ppp_defs.h | 3 | ||||
-rw-r--r-- | sys/net/route.c | 248 | ||||
-rw-r--r-- | sys/net/route.h | 38 | ||||
-rw-r--r-- | sys/net/rtsock.c | 126 |
17 files changed, 1990 insertions, 56 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index 2670eba4e5d..22ad590d968 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,7 +1,36 @@ -/* $OpenBSD: if.c,v 1.24 1999/11/20 18:51:58 espie Exp $ */ +/* $OpenBSD: if.c,v 1.25 1999/12/08 06:50:17 itojun Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* * Copyright (c) 1980, 1986, 1993 * The Regents of the University of California. All rights reserved. * @@ -53,6 +82,7 @@ #include <net/if_dl.h> #include <net/if_types.h> #include <net/radix.h> + #include <net/route.h> #ifdef INET @@ -65,6 +95,12 @@ #endif #endif +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#endif + #ifdef IPFILTER #include <netinet/ip_fil_compat.h> #include <netinet/ip_fil.h> @@ -85,6 +121,14 @@ int if_detach_rtdelete __P((struct radix_node *, void *)); int ifqmaxlen = IFQ_MAXLEN; void if_slowtimo __P((void *arg)); +#ifdef INET6 +/* + * XXX: declare here to avoid to include many inet6 related files.. + * should be more generalized? + */ +extern void nd6_setmtu __P((struct ifnet *)); +#endif + /* * Network interface utility routines. * @@ -103,7 +147,8 @@ ifinit() } int if_index = 0; -struct ifaddr **ifnet_addrs; +struct ifaddr **ifnet_addrs = NULL; +struct ifnet **ifindex2ifnet = NULL; /* * Attach an interface to the @@ -120,16 +165,43 @@ if_attachsetup(ifp) static int if_indexlim = 8; ifp->if_index = ++if_index; - if (ifnet_addrs == 0 || if_index >= if_indexlim) { - unsigned int n = (if_indexlim <<= 1) * sizeof(ifa); - struct ifaddr **q = (struct ifaddr **) - malloc(n, M_IFADDR, M_WAITOK); + + /* + * We have some arrays that should be indexed by if_index. + * since if_index will grow dynamically, they should grow too. + * struct ifadd **ifnet_addrs + * struct ifnet **ifindex2ifnet + */ + if (ifnet_addrs == 0 || ifindex2ifnet == 0 || if_index >= if_indexlim) { + size_t n; + caddr_t q; + + while (if_index >= if_indexlim) + if_indexlim <<= 1; + + /* grow ifnet_addrs */ + n = if_indexlim * sizeof(ifa); + q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK); + bzero(q, n); if (ifnet_addrs) { - bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); + bcopy((caddr_t)ifnet_addrs, q, n/2); free((caddr_t)ifnet_addrs, M_IFADDR); } - ifnet_addrs = q; + ifnet_addrs = (struct ifaddr **)q; + + /* grow ifindex2ifnet */ + n = if_indexlim * sizeof(struct ifnet *); + q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK); + bzero(q, n); + if (ifindex2ifnet) { + bcopy((caddr_t)ifindex2ifnet, q, n/2); + free((caddr_t)ifindex2ifnet, M_IFADDR); + } + ifindex2ifnet = (struct ifnet **)q; } + + ifindex2ifnet[if_index] = ifp; + /* * create a Link Level name for this device */ @@ -151,7 +223,7 @@ if_attachsetup(ifp) sdl->sdl_nlen = namelen; sdl->sdl_index = ifp->if_index; sdl->sdl_type = ifp->if_type; - ifnet_addrs[if_index - 1] = ifa; + ifnet_addrs[if_index] = ifa; ifa->ifa_ifp = ifp; ifa->ifa_rtrequest = link_rtrequest; TAILQ_INSERT_HEAD(&ifp->if_addrlist, ifa, ifa_list); @@ -301,6 +373,8 @@ ifa_ifwithaddr(addr) if (equal(addr, ifa->ifa_addr)) return (ifa); if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && + /* IP6 doesn't have broadcast */ + ifa->ifa_broadaddr->sa_len != 0 && equal(ifa->ifa_broadaddr, addr)) return (ifa); } @@ -346,7 +420,7 @@ ifa_ifwithnet(addr) if (af == AF_LINK) { register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; if (sdl->sdl_index && sdl->sdl_index <= if_index) - return (ifnet_addrs[sdl->sdl_index - 1]); + return (ifnet_addrs[sdl->sdl_index]); } for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next) for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) { @@ -495,6 +569,9 @@ if_up(ifp) pfctlinput(PRC_IFUP, ifa->ifa_addr); #endif rt_ifmsg(ifp); +#ifdef INET6 + in6_if_up(ifp); +#endif } /* @@ -555,6 +632,35 @@ ifunit(name) return (NULL); } + +/* + * Map interface name in a sockaddr_dl to + * interface structure pointer. + */ +struct ifnet * +if_withname(sa) + struct sockaddr *sa; +{ + char ifname[IFNAMSIZ+1]; + struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; + + if ( (sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) || + (sdl->sdl_nlen > IFNAMSIZ) ) + return NULL; + + /* + * ifunit wants a null-terminated name. It may not be null-terminated + * in the sockaddr. We don't want to change the caller's sockaddr, + * and there might not be room to put the trailing null anyway, so we + * make a local copy that we know we can null terminate safely. + */ + + bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen); + ifname[sdl->sdl_nlen] = '\0'; + return ifunit(ifname); +} + + /* * Interface ioctls. */ @@ -567,7 +673,8 @@ ifioctl(so, cmd, data, p) { register struct ifnet *ifp; register struct ifreq *ifr; - int error; + int error = 0; + short oif_flags; switch (cmd) { @@ -579,6 +686,7 @@ ifioctl(so, cmd, data, p) ifp = ifunit(ifr->ifr_name); if (ifp == 0) return (ENXIO); + oif_flags = ifp->if_flags; switch (cmd) { case SIOCGIFFLAGS: @@ -628,13 +736,14 @@ ifioctl(so, cmd, data, p) case SIOCGIFMEDIA: if (ifp->if_ioctl == 0) return (EOPNOTSUPP); - return ((*ifp->if_ioctl)(ifp, cmd, data)); + error = (*ifp->if_ioctl)(ifp, cmd, data); + break; default: if (so->so_proto == 0) return (EOPNOTSUPP); #if !defined(COMPAT_43) && !defined(COMPAT_LINUX) && !defined(COMPAT_SVR4) - return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, + error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, (struct mbuf *) cmd, (struct mbuf *) data, (struct mbuf *) ifp)); #else @@ -686,12 +795,22 @@ ifioctl(so, cmd, data, p) case OSIOCGIFNETMASK: *(u_int16_t *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; } - return (error); } #endif + break; } - return (0); + + if (((oif_flags ^ ifp->if_flags) & IFF_UP) != 0) { +#ifdef INET6 + if ((ifp->if_flags & IFF_UP) != 0) { + int s = splimp(); + in6_if_up(ifp); + splx(s); + } +#endif + } + return (error); } /* diff --git a/sys/net/if.h b/sys/net/if.h index 2fed82f3649..9c4c29acb00 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if.h,v 1.13 1999/08/08 00:43:00 niklas Exp $ */ +/* $OpenBSD: if.h,v 1.14 1999/12/08 06:50:17 itojun Exp $ */ /* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */ /* @@ -111,6 +111,7 @@ TAILQ_HEAD(ifnet_head, ifnet); /* the actual queue head */ * Note: this is the same size as a generic device's external name. */ #define IFNAMSIZ 16 +#define IF_NAMESIZE IFNAMSIZ struct ifnet { /* and the entries */ void *if_softc; /* lower-level data for this if */ @@ -143,6 +144,7 @@ struct ifnet { /* and the entries */ int ifq_maxlen; int ifq_drops; } if_snd; /* output queue */ + struct ifprefix *if_prefixlist; /* linked list of prefixes per if */ }; #define if_mtu if_data.ifi_mtu #define if_type if_data.ifi_type @@ -244,6 +246,20 @@ struct ifaddr { #define IFA_ROUTE RTF_UP /* route installed */ /* + * The prefix structure contains information about one prefix + * of an interface. They are maintained by the different address families, + * are allocated and attached when an prefix or an address is set, + * and are linked together so all prfefixes for an interface can be located. + */ +struct ifprefix { + struct sockaddr *ifpr_prefix; /* prefix of interface */ + struct ifnet *ifpr_ifp; /* back-pointer to interface */ + struct ifprefix *ifpr_next; + u_char ifpr_plen; /* prefix length in bits */ + u_char ifpr_type; /* protocol dependent prefix type */ +}; + +/* * Message format for use in obtaining information about interfaces * from sysctl and the routing socket. */ @@ -331,16 +347,31 @@ struct ifconf { #define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ }; +/* + * Structure for SIOC[AGD]LIFADDR + */ +struct if_laddrreq { + char iflr_name[IFNAMSIZ]; + unsigned int flags; +#define IFLR_PREFIX 0x8000 /* in: prefix given out: kernel fills id */ + unsigned int prefixlen; /* in/out */ + struct sockaddr_storage addr; /* in/out */ + struct sockaddr_storage dstaddr; /* out */ +}; + struct if_nameindex { unsigned int if_index; char *if_name; }; +#ifndef _KERNEL +__BEGIN_DECLS unsigned int if_nametoindex __P((const char *)); char *if_indextoname __P((unsigned int, char *)); struct if_nameindex *if_nameindex __P((void)); - -#define if_freenameindex(x) free(x) +__END_DECLS +#define if_freenameindex(x) free(x) +#endif #include <net/if_arp.h> @@ -353,6 +384,11 @@ struct if_nameindex *if_nameindex __P((void)); } struct ifnet_head ifnet; +struct ifnet **ifindex2ifnet; +#if 0 +struct ifnet loif[]; +#endif +int if_index; void ether_ifattach __P((struct ifnet *)); void ether_ifdetach __P((struct ifnet *)); @@ -375,6 +411,7 @@ void ifinit __P((void)); int ifioctl __P((struct socket *, u_long, caddr_t, struct proc *)); int ifpromisc __P((struct ifnet *, int)); struct ifnet *ifunit __P((char *)); +struct ifnet *if_withname __P((struct sockaddr *)); struct ifaddr *ifa_ifwithaddr __P((struct sockaddr *)); struct ifaddr *ifa_ifwithaf __P((int)); diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index c22ba6d04ea..3513c322bf5 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,7 +1,36 @@ -/* $OpenBSD: if_ethersubr.c,v 1.31 1999/09/01 21:38:48 jason Exp $ */ +/* $OpenBSD: if_ethersubr.c,v 1.32 1999/12/08 06:50:17 itojun Exp $ */ /* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */ /* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* * Copyright (c) 1982, 1989, 1993 * The Regents of the University of California. All rights reserved. * @@ -79,6 +108,14 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <net/if_bridge.h> #endif +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#include <netinet6/in6_var.h> +#include <netinet6/nd6.h> +#endif + #ifdef NS #include <netns/ns.h> #include <netns/ns_if.h> @@ -118,7 +155,7 @@ extern u_char aarp_org_code[ 3 ]; #include <sys/socketvar.h> #endif -#ifdef INET6 +#if 0 /*NRL INET6*/ #include <netinet6/in6.h> #include <netinet6/in6_var.h> #endif /* INET6 */ @@ -249,6 +286,18 @@ ether_output(ifp, m0, dst, rt0) etype = htons(ETHERTYPE_IP); break; #endif +#ifdef INET6 + case AF_INET6: +#ifndef OLDIP6OUTPUT + if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)) + return(0); /* it must be impossible, but... */ +#else + if (!nd6_resolve(ifp, rt, m, dst, (u_char *)edst)) + return(0); /* if not yet resolves */ +#endif + etype = htons(ETHERTYPE_IPV6); + break; +#endif #ifdef NS case AF_NS: etype = htons(ETHERTYPE_NS); @@ -273,7 +322,7 @@ ether_output(ifp, m0, dst, rt0) mcopy = m_copy(m, 0, (int)M_COPYALL); break; #endif -#ifdef INET6 +#if 0 /*NRL INET6*/ case AF_INET6: /* * The bottom line here is to either queue the outgoing packet @@ -285,7 +334,7 @@ ether_output(ifp, m0, dst, rt0) * If multicast dest., then use IPv6 -> Ethernet * mcast mapping. Really simple. */ - ETHER_MAP_IN6_MULTICAST(((struct sockaddr_in6 *)dst)->sin6_addr, + ETHER_MAP_IPV6_MULTICAST(&((struct sockaddr_in6 *)dst)->sin6_addr, edst); } else { /* Do unicast neighbor discovery stuff. */ @@ -583,7 +632,7 @@ decapsulate: */ case ETHERTYPE_IPV6: schednetisr(NETISR_IPV6); - inq = &ipv6intrq; + inq = &ip6intrq; break; #endif /* INET6 */ #ifdef IPX @@ -828,9 +877,9 @@ u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; u_char ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff }; #ifdef INET6 -u_char ether_ipv6multicast_min[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; -u_char ether_ipv6multicast_max[6] = { 0x33, 0x33, 0xff, 0xff, 0xff, 0xff }; -#endif /* INET6 */ +u_char ether_ip6multicast_min[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; +u_char ether_ip6multicast_max[6] = { 0x33, 0x33, 0xff, 0xff, 0xff, 0xff }; +#endif /* * Add an Ethernet multicast address or range of addresses to the list for a @@ -877,17 +926,18 @@ ether_addmulti(ifr, ac) #endif #ifdef INET6 case AF_INET6: - sin6 = (struct sockaddr_in6 *)&(ifr->ifr_addr); + sin6 = (struct sockaddr_in6 *) + &(((struct in6_ifreq *)ifr)->ifr_addr); if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { /* * An unspecified IPv6 address means listen to all * of the IPv6 multicast addresses on this Ethernet. * (Multicast routers like this.) */ - bcopy(ether_ipv6multicast_min, addrlo, ETHER_ADDR_LEN); - bcopy(ether_ipv6multicast_max, addrhi, ETHER_ADDR_LEN); + bcopy(ether_ip6multicast_min, addrlo, ETHER_ADDR_LEN); + bcopy(ether_ip6multicast_max, addrhi, ETHER_ADDR_LEN); } else { - ETHER_MAP_IN6_MULTICAST(sin6->sin6_addr, addrlo); + ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, addrlo); bcopy(addrlo, addrhi, ETHER_ADDR_LEN); } break; @@ -996,10 +1046,10 @@ ether_delmulti(ifr, ac) * possibly all-routers for this interface afterwards * is not a bad idea.) */ - bcopy(ether_ipv6multicast_min, addrlo, ETHER_ADDR_LEN); - bcopy(ether_ipv6multicast_max, addrhi, ETHER_ADDR_LEN); + bcopy(ether_ip6multicast_min, addrlo, ETHER_ADDR_LEN); + bcopy(ether_ip6multicast_max, addrhi, ETHER_ADDR_LEN); } else { - ETHER_MAP_IN6_MULTICAST(sin6->sin6_addr, addrlo); + ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, addrlo); bcopy(addrlo, addrhi, ETHER_ADDR_LEN); } break; diff --git a/sys/net/if_faith.c b/sys/net/if_faith.c new file mode 100644 index 00000000000..baadb22e398 --- /dev/null +++ b/sys/net/if_faith.c @@ -0,0 +1,323 @@ +/* + * 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. + */ +/* + * 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. + */ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include "opt_inet.h" +#endif + +#include "faith.h" +#if NFAITH > 0 + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/errno.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/sockio.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/time.h> +#ifdef __bsdi__ +#include <machine/cpu.h> +#endif + +#include <net/if.h> +#include <net/if_types.h> +#include <net/netisr.h> +#include <net/route.h> +#include <net/bpf.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#endif + +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#include <netinet6/in6_var.h> +#include <netinet6/ip6.h> +#endif + +#include "bpfilter.h" + +#include <net/net_osdep.h> + +#if defined(__FreeBSD__) && __FreeBSD__ < 3 +static int faithioctl __P((struct ifnet *, int, caddr_t)); +#else +static int faithioctl __P((struct ifnet *, u_long, caddr_t)); +#endif +int faithoutput __P((struct ifnet *, register struct mbuf *, struct sockaddr *, + register struct rtentry *)); +static void faithrtrequest __P((int, struct rtentry *, struct sockaddr *)); + +#ifdef __FreeBSD__ +void faithattach __P((void *)); +PSEUDO_SET(faithattach, if_faith); +#else +void faithattach __P((int)); +#endif + +static struct ifnet faithif[NFAITH]; + +#define FAITHMTU 1500 + +/* ARGSUSED */ +void +faithattach(faith) +#ifdef __FreeBSD__ + void *faith; +#else + int faith; +#endif +{ + register struct ifnet *ifp; + register int i; + + for (i = 0; i < NFAITH; i++) { + ifp = &faithif[i]; + bzero(ifp, sizeof(faithif[i])); +#if defined(__NetBSD__) || defined(__OpenBSD__) + sprintf(ifp->if_xname, "faith%d", i); +#else + ifp->if_name = "faith"; + ifp->if_unit = i; +#endif + ifp->if_mtu = FAITHMTU; + /* Change to BROADCAST experimentaly to announce its prefix. */ + ifp->if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST; + ifp->if_ioctl = faithioctl; + ifp->if_output = faithoutput; + ifp->if_type = IFT_FAITH; + ifp->if_hdrlen = 0; + ifp->if_addrlen = 0; + if_attach(ifp); +#if NBPFILTER > 0 +#ifdef HAVE_OLD_BPF + bpfattach(ifp, DLT_NULL, sizeof(u_int)); +#else + bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int)); +#endif +#endif + } +} + +int +faithoutput(ifp, m, dst, rt) + struct ifnet *ifp; + register struct mbuf *m; + struct sockaddr *dst; + register struct rtentry *rt; +{ + int s, isr; + register struct ifqueue *ifq = 0; + + if ((m->m_flags & M_PKTHDR) == 0) + panic("faithoutput no HDR"); +#if NBPFILTER > 0 + /* BPF write needs to be handled specially */ + if (dst->sa_family == AF_UNSPEC) { + dst->sa_family = *(mtod(m, int *)); + m->m_len -= sizeof(int); + m->m_pkthdr.len -= sizeof(int); + m->m_data += sizeof(int); + } + + if (ifp->if_bpf) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a faith header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer a to it). + */ + struct mbuf m0; + u_int af = dst->sa_family; + + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + +#ifdef HAVE_OLD_BPF + bpf_mtap(ifp, &m0); +#else + bpf_mtap(ifp->if_bpf, &m0); +#endif + } +#endif + + if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { + m_freem(m); + return (rt->rt_flags & RTF_BLACKHOLE ? 0 : + rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); + } + ifp->if_opackets++; + ifp->if_obytes += m->m_pkthdr.len; + switch (dst->sa_family) { +#ifdef INET + case AF_INET: + ifq = &ipintrq; + isr = NETISR_IP; + break; +#endif +#ifdef INET6 + case AF_INET6: + ifq = &ip6intrq; + isr = NETISR_IPV6; + break; +#endif + default: + m_freem(m); + return EAFNOSUPPORT; + } + + /* XXX do we need more sanity checks? */ + + m->m_pkthdr.rcvif = ifp; + s = splimp(); + if (IF_QFULL(ifq)) { + IF_DROP(ifq); + m_freem(m); + splx(s); + return (ENOBUFS); + } + IF_ENQUEUE(ifq, m); + schednetisr(isr); + ifp->if_ipackets++; + ifp->if_ibytes += m->m_pkthdr.len; + splx(s); + return (0); +} + +/* ARGSUSED */ +static void +faithrtrequest(cmd, rt, sa) + int cmd; + struct rtentry *rt; + struct sockaddr *sa; +{ + if (rt) { + rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */ + /* + * For optimal performance, the send and receive buffers + * should be at least twice the MTU plus a little more for + * overhead. + */ + rt->rt_rmx.rmx_recvpipe = + rt->rt_rmx.rmx_sendpipe = 3 * FAITHMTU; + } +} + +/* + * Process an ioctl request. + */ +/* ARGSUSED */ +static int +faithioctl(ifp, cmd, data) + register struct ifnet *ifp; +#if defined(__FreeBSD__) && __FreeBSD__ < 3 + int cmd; +#else + u_long cmd; +#endif + caddr_t data; +{ + register struct ifaddr *ifa; + register struct ifreq *ifr = (struct ifreq *)data; + register int error = 0; + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP | IFF_RUNNING; + ifa = (struct ifaddr *)data; + ifa->ifa_rtrequest = faithrtrequest; + /* + * Everything else is done at a higher level. + */ + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifr == 0) { + error = EAFNOSUPPORT; /* XXX */ + break; + } + switch (ifr->ifr_addr.sa_family) { +#ifdef INET + case AF_INET: + break; +#endif +#ifdef INET6 + case AF_INET6: + break; +#endif + + default: + error = EAFNOSUPPORT; + break; + } + break; + +#ifdef SIOCSIFMTU +#ifndef __OpenBSD__ + case SIOCSIFMTU: + ifp->if_mtu = ifr->ifr_mtu; + break; +#endif +#endif + + case SIOCSIFFLAGS: + break; + + default: + error = EINVAL; + } + return (error); +} +#endif /* NFAITH > 0 */ diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c index 4a3f3668307..74c7c0944b7 100644 --- a/sys/net/if_fddisubr.c +++ b/sys/net/if_fddisubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_fddisubr.c,v 1.19 1999/07/28 20:02:41 fgsch Exp $ */ +/* $OpenBSD: if_fddisubr.c,v 1.20 1999/12/08 06:50:18 itojun Exp $ */ /* $NetBSD: if_fddisubr.c,v 1.5 1996/05/07 23:20:21 christos Exp $ */ /* @@ -86,6 +86,14 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <netipx/ipx_if.h> #endif +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#include <netinet/in_var.h> +#endif +#include <netinet6/nd6.h> +#endif + #ifdef NS #include <netns/ns.h> #include <netns/ns_if.h> @@ -194,6 +202,19 @@ fddi_output(ifp, m0, dst, rt0) #endif #ifdef INET6 case AF_INET6: +#ifdef OLDIP6OUTPUT + if (!nd6_resolve(ifp, rt, m, dst, edst)) + return (0); /* if not yet resolved */ +#else + if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)) + return 0; +#endif + type = htons(ETHERTYPE_IPV6); + break; +#endif +#if 0 /*NRL IPv6*/ +#ifdef INET6 + case AF_INET6: /* * The bottom line here is to either queue the outgoing packet * in the discovery engine, or fill in edst with something @@ -214,6 +235,7 @@ fddi_output(ifp, m0, dst, rt0) type = htons(ETHERTYPE_IPV6); break; #endif /* INET6 */ +#endif #ifdef IPX case AF_IPX: type = htons(ETHERTYPE_IPX); @@ -492,7 +514,7 @@ fddi_input(ifp, fh, m) #ifdef INET6 case ETHERTYPE_IPV6: schednetisr(NETISR_IPV6); - inq = &ipv6intrq; + inq = &ip6intrq; break; #endif /* INET6 */ #ifdef IPX diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c new file mode 100644 index 00000000000..4be073575d3 --- /dev/null +++ b/sys/net/if_gif.c @@ -0,0 +1,552 @@ +/* $OpenBSD: if_gif.c,v 1.1 1999/12/08 06:50:18 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * gif.c + */ + +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) +#include "opt_inet.h" +#endif + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/malloc.h> +#endif +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/errno.h> +#if defined(__FreeBSD__) || __FreeBSD__ >= 3 +/*nothing*/ +#else +#include <sys/ioctl.h> +#endif +#include <sys/time.h> +#include <sys/syslog.h> +#include <machine/cpu.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/netisr.h> +#include <net/route.h> +#include <net/bpf.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/in_gif.h> +#endif /* INET */ + +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#include <netinet6/in6_var.h> +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/in6_gif.h> +#endif /* INET6 */ + +#include <net/if_gif.h> + +#include "gif.h" +#include "bpfilter.h" + +#include <net/net_osdep.h> + +#if NGIF > 0 + +#ifdef __FreeBSD__ +void gifattach __P((void *)); +#else +void gifattach __P((int)); +#endif + +/* + * gif global variable definitions + */ +int ngif = NGIF; /* number of interfaces */ +struct gif_softc *gif = 0; + +void +gifattach(dummy) +#ifdef __FreeBSD__ + void *dummy; +#else + int dummy; +#endif +{ + 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++) { +#if defined(__NetBSD__) || defined(__OpenBSD__) + sprintf(sc->gif_if.if_xname, "gif%d", i); +#else + sc->gif_if.if_name = "gif"; + sc->gif_if.if_unit = i; +#endif + 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; + if_attach(&sc->gif_if); +#if NBPFILTER > 0 +#ifdef HAVE_OLD_BPF + bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); +#else + bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, sizeof(u_int)); +#endif +#endif + } +} + +#ifdef __FreeBSD__ +PSEUDO_SET(gifattach, if_gif); +#endif + +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; + } + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + getmicrotime(&ifp->if_lastchange); +#else + ifp->if_lastchange = time; +#endif + m->m_flags &= ~(M_BCAST|M_MCAST); + if (!(ifp->if_flags & IFF_UP) || +#if 0 + sc->gif_flags & GIFF_INUSE || +#endif + sc->gif_psrc == NULL || sc->gif_pdst == NULL) { + m_freem(m); + error = ENETDOWN; + goto end; + } + +#if NBPFILTER > 0 + 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 *)⁡ + +#ifdef HAVE_OLD_BPF + bpf_mtap(ifp, &m0); +#else + bpf_mtap(ifp->if_bpf, &m0); +#endif + } +#endif + ifp->if_opackets++; + ifp->if_obytes += m->m_pkthdr.len; +#if 0 + s = splnet(); + sc->gif_flags |= GIFF_INUSE; +#endif + + 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; + } +#if 0 + sc->gif_flags &= ~GIFF_INUSE; + splx(s); +#endif + + 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 NBPFILTER > 0 + 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 *)⁡ + +#ifdef HAVE_OLD_BPF + bpf_mtap(gifp, &m0); +#else + bpf_mtap(gifp->if_bpf, &m0); +#endif + } +#endif /*NBPFILTER > 0*/ + + /* + * 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; +#if defined(__FreeBSD__) && __FreeBSD__ < 3 + int cmd; +#else + u_long cmd; +#endif + 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: +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) + switch (ifr->ifr_addr.sa_family) { +#ifdef INET + case AF_INET: /* IP supports Multicast */ + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: /* IP6 supports Multicast */ + break; +#endif /* INET6 */ + default: /* Other protocols doesn't support Multicast */ + error = EAFNOSUPPORT; + break; + } +#endif /*not FreeBSD3*/ + break; + +#ifdef SIOCSIFMTU /* xxx */ +#ifndef __OpenBSD__ + case SIOCGIFMTU: + break; + case SIOCSIFMTU: + { +#ifdef __bsdi__ + short mtu; + mtu = *(short *)ifr->ifr_data; +#else + u_long mtu; + mtu = ifr->ifr_mtu; +#endif + if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) { + return (EINVAL); + } + ifp->if_mtu = mtu; + } + break; +#endif +#endif /* SIOCSIFMTU */ + + 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 new file mode 100644 index 00000000000..1b4307d3642 --- /dev/null +++ b/sys/net/if_gif.h @@ -0,0 +1,86 @@ +/* $OpenBSD: if_gif.h,v 1.1 1999/12/08 06:50:18 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * if_gif.h + */ + +#ifndef _NET_IF_GIF_H_ +#define _NET_IF_GIF_H_ + + +#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) +#if defined(_KERNEL) && !defined(_LKM) +#include "opt_inet.h" +#endif +#endif + +#include <netinet/in.h> +/* xxx sigh, why route have struct route instead of pointer? */ + +struct gif_softc { + struct ifnet gif_if; /* common area */ + struct sockaddr *gif_psrc; /* Physical src addr */ + struct sockaddr *gif_pdst; /* Physical dst addr */ + union { + struct route gifscr_ro; /* xxx */ +#ifdef INET6 + struct route_in6 gifscr_ro6; /* xxx */ +#endif + } gifsc_gifscr; + int gif_flags; +}; + +#define gif_ro gifsc_gifscr.gifscr_ro +#ifdef INET6 +#define gif_ro6 gifsc_gifscr.gifscr_ro6 +#endif + +#define GIFF_INUSE 0x1 /* gif is in use */ + +#define GIF_MTU (1280) /* Default MTU */ +#define GIF_MTU_MIN (1280) /* Minimum MTU */ +#define GIF_MTU_MAX (8192) /* Maximum MTU */ + +extern int ngif; +extern struct gif_softc *gif; + +/* Prototypes */ +void gif_input __P((struct mbuf *, int, struct ifnet *)); +int gif_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *)); +#if defined(__FreeBSD__) && __FreeBSD__ < 3 +int gif_ioctl __P((struct ifnet *, int, caddr_t)); +#else +int gif_ioctl __P((struct ifnet *, u_long, caddr_t)); +#endif + +#endif /* _NET_IF_GIF_H_ */ diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index 57dbd3fe733..46eb07ec1fb 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -1,7 +1,36 @@ -/* $OpenBSD: if_loop.c,v 1.11 1999/01/08 00:56:45 deraadt Exp $ */ +/* $OpenBSD: if_loop.c,v 1.12 1999/12/08 06:50:18 itojun Exp $ */ /* $NetBSD: if_loop.c,v 1.15 1996/05/07 02:40:33 thorpej Exp $ */ /* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * @@ -78,6 +107,14 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <netinet/ip.h> #endif +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#include <netinet6/in6_var.h> +#include <netinet6/ip6.h> +#endif + #ifdef NS #include <netns/ns.h> #include <netns/ns_if.h> @@ -103,13 +140,12 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <net/bpf.h> #endif -#ifdef INET6 -#include <netinet6/in6.h> -#include <netinet6/in6_var.h> -#endif /* INET6 */ - -#define LOMTU (32768) - +#if defined(LARGE_LOMTU) +#define LOMTU (131072 + MHLEN + MLEN) +#else +#define LOMTU (32768 + MHLEN + MLEN) +#endif + struct ifnet loif[NLOOP]; void @@ -181,6 +217,55 @@ looutput(ifp, m, dst, rt) return (rt->rt_flags & RTF_BLACKHOLE ? 0 : rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); } + +#ifndef PULLDOWN_TEST + /* + * KAME requires that the packet to be contiguous on the + * mbuf. We need to make that sure. + * this kind of code should be avoided. + * XXX other conditions to avoid running this part? + */ + if (m && m->m_next != NULL) { + struct mbuf *n; + + MGETHDR(n, M_DONTWAIT, MT_HEADER); + if (n) { + MCLGET(n, M_DONTWAIT); + if ((n->m_flags & M_EXT) == 0) { + m_free(n); + n = NULL; + } + } + if (!n) { + printf("looutput: mbuf allocation failed\n"); + m_freem(m); + return ENOBUFS; + } + + n->m_pkthdr.rcvif = m->m_pkthdr.rcvif; + n->m_pkthdr.len = m->m_pkthdr.len; + if (m->m_pkthdr.len <= MCLBYTES) { + m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); + n->m_len = m->m_pkthdr.len; + m_freem(m); + } else { + m_copydata(m, 0, MCLBYTES, mtod(n, caddr_t)); + m_adj(m, MCLBYTES); + n->m_len = MCLBYTES; + n->m_next = m; + m->m_flags &= ~M_PKTHDR; + } + m = n; + } +#if 0 + if (m && m->m_next != NULL) { + printf("loop: not contiguous...\n"); + m_freem(m); + return ENOBUFS; + } +#endif +#endif + ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; switch (dst->sa_family) { @@ -193,7 +278,7 @@ looutput(ifp, m, dst, rt) #endif #ifdef INET6 case AF_INET6: - ifq = &ipv6intrq; + ifq = &ip6intrq; isr = NETISR_IPV6; break; #endif /* INET6 */ @@ -273,7 +358,7 @@ loioctl(ifp, cmd, data) case SIOCSIFADDR: ifp->if_flags |= IFF_UP; ifa = (struct ifaddr *)data; - if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO) + if (ifa != 0 /*&& ifa->ifa_addr->sa_family == AF_ISO*/) ifa->ifa_rtrequest = lortrequest; /* * Everything else is done at a higher level. @@ -293,7 +378,6 @@ loioctl(ifp, cmd, data) case AF_INET: break; #endif - #ifdef INET6 case AF_INET6: break; diff --git a/sys/net/if_ppp.c b/sys/net/if_ppp.c index 5aa095a7122..32d2aa9debf 100644 --- a/sys/net/if_ppp.c +++ b/sys/net/if_ppp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ppp.c,v 1.14 1998/07/12 04:33:20 angelos Exp $ */ +/* $OpenBSD: if_ppp.c,v 1.15 1999/12/08 06:50:18 itojun Exp $ */ /* $NetBSD: if_ppp.c,v 1.39 1997/05/17 21:11:59 christos Exp $ */ /* @@ -102,6 +102,12 @@ #include <netinet/in_systm.h> #include <netinet/in_var.h> #include <netinet/ip.h> +#else +#ifdef _KERNEL +#ifdef VJC +#error ppp device with VJC assumes INET +#endif +#endif #endif #include "bpfilter.h" diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c index 54965c3f782..05d51acf141 100644 --- a/sys/net/if_tun.c +++ b/sys/net/if_tun.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_tun.c,v 1.27 1999/09/29 04:30:39 deraadt Exp $ */ +/* $OpenBSD: if_tun.c,v 1.28 1999/12/08 06:50:18 itojun Exp $ */ /* $NetBSD: if_tun.c,v 1.24 1996/05/07 02:40:48 thorpej Exp $ */ /* @@ -221,11 +221,13 @@ tunclose(dev, flag, mode, p) register struct ifaddr *ifa; for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) { +#ifdef INET if (ifa->ifa_addr->sa_family == AF_INET) { rtinit(ifa, (int)RTM_DELETE, (tp->tun_flags & TUN_DSTADDR)? RTF_HOST : 0); } +#endif } } splx(s); @@ -251,6 +253,7 @@ tuninit(tp) tp->tun_flags &= ~(TUN_IASET|TUN_DSTADDR|TUN_BRDADDR); for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) { +#ifdef INET if (ifa->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *sin; @@ -272,6 +275,7 @@ tuninit(tp) } else tp->tun_flags &= ~TUN_BRDADDR; } +#endif } return 0; @@ -314,6 +318,8 @@ tun_ioctl(ifp, cmd, data) ((struct tun_softc *)(ifp->if_softc))->tun_if.if_mtu; break; #endif + case SIOCSIFFLAGS: + break; default: error = EINVAL; } @@ -612,6 +618,12 @@ tunwrite(dev, uio, ioflag) isr = NETISR_IP; break; #endif +#ifdef INET6 + case AF_INET6: + ifq = &ip6intrq; + isr = NETISR_IPV6; + break; +#endif #ifdef NS case AF_NS: ifq = &nsintrq; diff --git a/sys/net/if_types.h b/sys/net/if_types.h index 0ef92cfbf7e..01361c1f727 100644 --- a/sys/net/if_types.h +++ b/sys/net/if_types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_types.h,v 1.3 1997/02/24 13:34:02 niklas Exp $ */ +/* $OpenBSD: if_types.h,v 1.4 1999/12/08 06:50:18 itojun Exp $ */ /* $NetBSD: if_types.h,v 1.7 1995/02/27 09:10:24 glass Exp $ */ /* @@ -97,3 +97,9 @@ #define IFT_PROPVIRTUAL 0x35 /* Proprietary Virtual/internal */ #define IFT_PROPMUX 0x36 /* Proprietary Multiplexing */ #define IFT_ENC 0x37 /* Encapsulation */ + +/* private usage... how should we define these? */ +#define IFT_GIF 0xf0 +#define IFT_DUMMY 0xf1 +#define IFT_PVC 0xf2 +#define IFT_FAITH 0xf3 diff --git a/sys/net/net_osdep.c b/sys/net/net_osdep.c new file mode 100644 index 00000000000..55822ed49f3 --- /dev/null +++ b/sys/net/net_osdep.c @@ -0,0 +1,87 @@ +/* $OpenBSD: net_osdep.c,v 1.1 1999/12/08 06:50:18 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/errno.h> +#if !defined(__FreeBSD__) || __FreeBSD__ < 3 +#include <sys/ioctl.h> +#endif +#include <sys/time.h> +#include <sys/syslog.h> +#include <machine/cpu.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/netisr.h> +#include <net/route.h> +#include <net/bpf.h> + +#if 0 +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/in_gif.h> +#endif /* INET */ + +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#include <netinet6/in6_var.h> +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/in6_gif.h> +#include <netinet6/in6_ifattach.h> +#endif /* INET6 */ +#endif + +#if !(defined(__NetBSD__) || defined(__OpenBSD__)) +const char * +if_name(ifp) + struct ifnet *ifp; +{ + static char nam[IFNAMSIZ + 10]; /*enough?*/ + +#ifdef __bsdi__ + sprintf(nam, "%s%d", ifp->if_name, ifp->if_unit); +#else + snprintf(nam, sizeof(nam), "%s%d", ifp->if_name, ifp->if_unit); +#endif + return nam; +} +#endif diff --git a/sys/net/net_osdep.h b/sys/net/net_osdep.h new file mode 100644 index 00000000000..99a5b7ded1c --- /dev/null +++ b/sys/net/net_osdep.h @@ -0,0 +1,149 @@ +/* $OpenBSD: net_osdep.h,v 1.1 1999/12/08 06:50:18 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * glue for kernel code programming differences. + */ + +/* + * OS dependencies: + * + * - privileged process + * NetBSD, FreeBSD 3 + * struct proc *p; + * if (p && !suser(p->p_ucred, &p->p_acflag)) + * privileged; + * OpenBSD, BSDI [34], FreeBSD 2 + * struct socket *so; + * if (so->so_state & SS_PRIV) + * privileged; + * - foo_control + * NetBSD, FreeBSD 3 + * needs to give struct proc * as argument + * OpenBSD, BSDI [34], FreeBSD 2 + * do not need struct proc * + * - bpf: + * OpenBSD, NetBSD, BSDI [34] + * need caddr_t * (= if_bpf **) and struct ifnet * + * FreeBSD 2, FreeBSD 3 + * need only struct ifnet * as argument + * - struct ifnet + * use queue.h? member names if name + * --- --- --- + * FreeBSD 2 no old standard if_name+unit + * FreeBSD 3 yes strange if_name+unit + * OpenBSD yes standard if_xname + * NetBSD yes standard if_xname + * BSDI [34] no old standard if_name+unit + * - usrreq + * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 + * single function with PRU_xx, arguments are mbuf + * FreeBSD 3 + * separates functions, non-mbuf arguments + * - {set,get}sockopt + * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 + * manipulation based on mbuf + * FreeBSD 3 + * non-mbuf manipulation using sooptcopy{in,out}() + * - timeout() and untimeout() + * NetBSD, OpenBSD, BSDI [34], FreeBSD 2 + * timeout() is a void function + * FreeBSD 3 + * timeout() is non-void, must keep returned value for untimeuot() + * - sysctl + * NetBSD, OpenBSD + * foo_sysctl() + * BSDI [34] + * foo_sysctl() but with different style + * FreeBSD 2, FreeBSD 3 + * linker hack + * + * - if_ioctl + * NetBSD, FreeBSD 3, BSDI [34] + * 2nd argument is u_long cmd + * FreeBSD 2 + * 2nd argument is int cmd + * - if attach routines + * NetBSD + * void xxattach(int); + * FreeBSD 2, FreeBSD 3 + * void xxattach(void *); + * PSEUDO_SET(xxattach, if_xx); + * + * - ovbcopy() + * in NetBSD 1.4 or later, ovbcopy() is not supplied in the kernel. + * bcopy() is safe against overwrites. + * - splnet() + * NetBSD 1.4 or later requires splsoftnet(). + * other operating systems use splnet(). + * + * - dtom() + * NEVER USE IT! + * + * - struct ifnet for loopback interface + * BSDI3: struct ifnet loif; + * BSDI4: struct ifnet *loifp; + * NetBSD, OpenBSD, FreeBSD2: struct ifnet loif[NLOOP]; + * + * odd thing is that many of them refers loif as ifnet *loif, + * not loif[NLOOP], from outside of if_loop.c. + */ + +#ifndef __NET_NET_OSDEP_H_DEFINED_ +#define __NET_NET_OSDEP_H_DEFINED_ +#ifdef _KERNEL + +#if defined(__NetBSD__) || defined(__OpenBSD__) +#define if_name(ifp) ((ifp)->if_xname) +#else +struct ifnet; +extern char *if_name __P((struct ifnet *)); +#endif + +#ifdef __FreeBSD__ +#define HAVE_OLD_BPF +#endif + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#define ifa_list ifa_link +#define if_addrlist if_addrhead +#define if_list if_link +#endif + +#if defined(__NetBSD__) && __NetBSD_Version__ >= 104000000 +#define ovbcopy bcopy +#endif + +#if defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) +#define HAVE_NRL_INPCB +#endif + +#endif /*_KERNEL*/ +#endif /*__NET_NET_OSDEP_H_DEFINED_ */ diff --git a/sys/net/ppp_defs.h b/sys/net/ppp_defs.h index cd075e14020..e3a435e3e01 100644 --- a/sys/net/ppp_defs.h +++ b/sys/net/ppp_defs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ppp_defs.h,v 1.9 1999/02/11 19:52:11 mickey Exp $ */ +/* $OpenBSD: ppp_defs.h,v 1.10 1999/12/08 06:50:18 itojun Exp $ */ /* $NetBSD: ppp_defs.h,v 1.1 1995/07/04 06:28:26 paulus Exp $ */ /* @@ -65,6 +65,7 @@ #define PPP_IPCP 0x8021 /* IP Control Protocol */ #define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ #define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ #define PPP_CCP 0x80fd /* Compression Control Protocol */ #define PPP_LCP 0xc021 /* Link Control Protocol */ #define PPP_PAP 0xc023 /* Password Authentication Protocol */ diff --git a/sys/net/route.c b/sys/net/route.c index 6602c31f2fa..23fab89eea2 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -1,7 +1,36 @@ -/* $OpenBSD: route.c,v 1.15 1999/09/13 22:33:51 niklas Exp $ */ +/* $OpenBSD: route.c,v 1.16 1999/12/08 06:50:18 itojun Exp $ */ /* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */ /* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* * Copyright (c) 1980, 1986, 1991, 1993 * The Regents of the University of California. All rights reserved. * @@ -57,6 +86,7 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <sys/domain.h> #include <sys/protosw.h> #include <sys/ioctl.h> +#include <sys/kernel.h> #include <net/if.h> #include <net/route.h> @@ -250,6 +280,7 @@ rtfree(rt) printf("rtfree: %p not freed (neg refs)\n", rt); return; } + rt_timer_remove_all(rt); ifa = rt->rt_ifa; if (ifa) IFAFREE(ifa); @@ -496,12 +527,18 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) case RTM_ADD: if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == NULL) senderr(ENETUNREACH); + + /* The interface found in the previous statement may + * be overridden later by rt_setif. See the code + * for case RTM_ADD in rtsock.c:route_output. + */ makeroute: R_Malloc(rt, struct rtentry *, sizeof(*rt)); if (rt == NULL) senderr(ENOBUFS); Bzero(rt, sizeof(*rt)); rt->rt_flags = RTF_UP | flags; + LIST_INIT(&rt->rt_timer); if (rt_setgate(rt, dst, gateway)) { Free(rt); senderr(ENOBUFS); @@ -511,6 +548,9 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt) rt_maskedcopy(dst, ndst, netmask); } else Bcopy(dst, ndst, dst->sa_len); +if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { /* XXX */ + rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu; +} rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask, rnh, rt->rt_nodes); if (rn == NULL) { @@ -646,7 +686,9 @@ rtinit(ifa, cmd, flags) dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; if (cmd == RTM_DELETE) { if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { - m = m_get(M_WAIT, MT_SONAME); + m = m_get(M_DONTWAIT, MT_SONAME); + if (m == NULL) + return(ENOBUFS); deldst = mtod(m, struct sockaddr *); rt_maskedcopy(dst, deldst, ifa->ifa_netmask); dst = deldst; @@ -689,6 +731,7 @@ rtinit(ifa, cmd, flags) IFAFREE(rt->rt_ifa); rt->rt_ifa = ifa; rt->rt_ifp = ifa->ifa_ifp; + rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu; /*XXX*/ ifa->ifa_refcnt++; if (ifa->ifa_rtrequest) ifa->ifa_rtrequest(RTM_ADD, rt, SA(NULL)); @@ -697,3 +740,204 @@ rtinit(ifa, cmd, flags) } return (error); } + +/* + * Route timer routines. These routes allow functions to be called + * for various routes at any time. This is useful in supporting + * path MTU discovery and redirect route deletion. + * + * This is similar to some BSDI internal functions, but it provides + * for multiple queues for efficiency's sake... + */ + +LIST_HEAD(, rttimer_queue) rttimer_queue_head; +static int rt_init_done = 0; + +#define RTTIMER_CALLOUT(r) { \ + if (r->rtt_func != NULL) { \ + (*r->rtt_func)(r->rtt_rt, r); \ + } else { \ + rtrequest((int) RTM_DELETE, \ + (struct sockaddr *)rt_key(r->rtt_rt), \ + 0, 0, 0, 0); \ + } \ +} + +/* + * Some subtle order problems with domain initialization mean that + * we cannot count on this being run from rt_init before various + * protocol initializations are done. Therefore, we make sure + * that this is run when the first queue is added... + */ + +void +rt_timer_init() +{ + assert(rt_init_done == 0); + +#if 0 + pool_init(&rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", + 0, NULL, NULL, M_RTABLE); +#endif + + LIST_INIT(&rttimer_queue_head); + timeout(rt_timer_timer, NULL, hz); /* every second */ + rt_init_done = 1; +} + +struct rttimer_queue * +rt_timer_queue_create(timeout) + u_int timeout; +{ + struct rttimer_queue *rtq; + + if (rt_init_done == 0) + rt_timer_init(); + + R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq); + if (rtq == NULL) + return (NULL); + + rtq->rtq_timeout = timeout; + TAILQ_INIT(&rtq->rtq_head); + LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link); + + return (rtq); +} + +void +rt_timer_queue_change(rtq, timeout) + struct rttimer_queue *rtq; + long timeout; +{ + + rtq->rtq_timeout = timeout; +} + + +void +rt_timer_queue_destroy(rtq, destroy) + struct rttimer_queue *rtq; + int destroy; +{ + struct rttimer *r; + + while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) { + LIST_REMOVE(r, rtt_link); + TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); + if (destroy) + RTTIMER_CALLOUT(r); +#if 0 + pool_put(&rttimer_pool, r); +#else + free(r, M_RTABLE); +#endif + } + + LIST_REMOVE(rtq, rtq_link); + + /* + * Caller is responsible for freeing the rttimer_queue structure. + */ +} + +void +rt_timer_remove_all(rt) + struct rtentry *rt; +{ + struct rttimer *r; + + while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) { + LIST_REMOVE(r, rtt_link); + TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); +#if 0 + pool_put(&rttimer_pool, r); +#else + free(r, M_RTABLE); +#endif + } +} + +int +rt_timer_add(rt, func, queue) + struct rtentry *rt; + void(*func) __P((struct rtentry *, struct rttimer *)); + struct rttimer_queue *queue; +{ + struct rttimer *r; + long current_time; + int s; + + s = splclock(); + current_time = mono_time.tv_sec; + splx(s); + + /* + * If there's already a timer with this action, destroy it before + * we add a new one. + */ + for (r = LIST_FIRST(&rt->rt_timer); r != NULL; + r = LIST_NEXT(r, rtt_link)) { + if (r->rtt_func == func) { + LIST_REMOVE(r, rtt_link); + TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); +#if 0 + pool_put(&rttimer_pool, r); +#else + free(r, M_RTABLE); +#endif + break; /* only one per list, so we can quit... */ + } + } + +#if 0 + r = pool_get(&rttimer_pool, PR_NOWAIT); +#else + r = (struct rttimer *)malloc(sizeof(*r), M_RTABLE, M_NOWAIT); +#endif + if (r == NULL) + return (ENOBUFS); + + r->rtt_rt = rt; + r->rtt_time = current_time; + r->rtt_func = func; + r->rtt_queue = queue; + LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link); + TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next); + + return (0); +} + +/* ARGSUSED */ +void +rt_timer_timer(arg) + void *arg; +{ + struct rttimer_queue *rtq; + struct rttimer *r; + long current_time; + int s; + + s = splclock(); + current_time = mono_time.tv_sec; + splx(s); + + s = splsoftnet(); + for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL; + rtq = LIST_NEXT(rtq, rtq_link)) { + while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL && + (r->rtt_time + rtq->rtq_timeout) < current_time) { + LIST_REMOVE(r, rtt_link); + TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); + RTTIMER_CALLOUT(r); +#if 0 + pool_put(&rttimer_pool, r); +#else + free(r, M_RTABLE); +#endif + } + } + splx(s); + + timeout(rt_timer_timer, NULL, hz); /* every second */ +} diff --git a/sys/net/route.h b/sys/net/route.h index cd880ad239b..2165d8330f6 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -1,4 +1,4 @@ -/* $OpenBSD: route.h,v 1.6 1999/05/16 00:34:40 ho Exp $ */ +/* $OpenBSD: route.h,v 1.7 1999/12/08 06:50:18 itojun Exp $ */ /* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */ /* @@ -36,6 +36,8 @@ * @(#)route.h 8.3 (Berkeley) 4/19/94 */ +#include <sys/queue.h> + /* * Kernel resident routing tables. * @@ -105,6 +107,7 @@ struct rtentry { struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */ struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */ struct rtentry *rt_parent; /* If cloned, parent of this route. */ + LIST_HEAD(, rttimer) rt_timer; /* queue of timeouts for misc funcs */ }; #define rt_use rt_rmx.rmx_pksent @@ -233,11 +236,34 @@ struct rt_addrinfo { struct route_cb { int ip_count; + int ip6_count; int ns_count; int iso_count; int any_count; }; +/* + * This structure, and the prototypes for the rt_timer_{init,remove_all, + * add,timer} functions all used with the kind permission of BSDI. + * These allow functions to be called for routes at specific times. + */ + +struct rttimer { + TAILQ_ENTRY(rttimer) rtt_next; /* entry on timer queue */ + LIST_ENTRY(rttimer) rtt_link; /* multiple timers per rtentry */ + struct rttimer_queue *rtt_queue;/* back pointer to queue */ + struct rtentry *rtt_rt; /* Back pointer to the route */ + void (*rtt_func) __P((struct rtentry *, + struct rttimer *)); + time_t rtt_time; /* When this timer was registered */ +}; + +struct rttimer_queue { + long rtq_timeout; + TAILQ_HEAD(, rttimer) rtq_head; + LIST_ENTRY(rttimer_queue) rtq_link; +}; + #ifdef _KERNEL #define RTFREE(rt) do { \ if ((rt)->rt_refcnt <= 1) \ @@ -270,6 +296,16 @@ void rt_newaddrmsg __P((int, struct ifaddr *, int, struct rtentry *)); int rt_setgate __P((struct rtentry *, struct sockaddr *, struct sockaddr *)); void rt_setmetrics __P((u_long, struct rt_metrics *, struct rt_metrics *)); +int rt_timer_add __P((struct rtentry *, + void(*)(struct rtentry *, struct rttimer *), + struct rttimer_queue *)); +void rt_timer_init __P((void)); +struct rttimer_queue * + rt_timer_queue_create __P((u_int)); +void rt_timer_queue_change __P((struct rttimer_queue *, long)); +void rt_timer_queue_destroy __P((struct rttimer_queue *, int)); +void rt_timer_remove_all __P((struct rtentry *)); +void rt_timer_timer __P((void *)); void rtable_init __P((void **)); void rtalloc __P((struct route *)); struct rtentry * diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index f842f8be969..57303703912 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -1,7 +1,36 @@ -/* $OpenBSD: rtsock.c,v 1.7 1998/08/24 20:39:40 downsj Exp $ */ +/* $OpenBSD: rtsock.c,v 1.8 1999/12/08 06:50:18 itojun Exp $ */ /* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */ /* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* * Copyright (c) 1988, 1991, 1993 * The Regents of the University of California. All rights reserved. * @@ -68,6 +97,8 @@ static struct mbuf * static int rt_msg2 __P((int, struct rt_addrinfo *, caddr_t, struct walkarg *)); static void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); +static void rt_setif __P((struct rtentry *, struct sockaddr *, + struct sockaddr *, struct sockaddr *)); /* Sleazy use of local variables throughout file, warning!!!! */ #define dst info.rti_info[RTAX_DST] @@ -99,6 +130,8 @@ route_usrreq(so, req, m, nam, control) int af = rp->rcb_proto.sp_protocol; if (af == AF_INET) route_cb.ip_count--; + else if (af == AF_INET6) + route_cb.ip6_count--; else if (af == AF_NS) route_cb.ns_count--; else if (af == AF_ISO) @@ -129,6 +162,8 @@ route_usrreq(so, req, m, nam, control) } if (af == AF_INET) route_cb.ip_count++; + else if (af == AF_INET6) + route_cb.ip6_count++; else if (af == AF_NS) route_cb.ns_count++; else if (af == AF_ISO) @@ -159,7 +194,6 @@ route_output(m, va_alist) struct rt_addrinfo info; int len, error = 0; struct ifnet *ifp = 0; - struct ifaddr *ifa = 0; struct socket *so; va_list ap; @@ -167,7 +201,7 @@ route_output(m, va_alist) so = va_arg(ap, struct socket *); va_end(ap); - + bzero(&info, sizeof(info)); #define senderr(e) { error = e; goto flush;} if (m == 0 || ((m->m_len < sizeof(int32_t)) && (m = m_pullup(m, sizeof(int32_t))) == 0)) @@ -219,6 +253,35 @@ route_output(m, va_alist) error = rtrequest(RTM_ADD, dst, gate, netmask, rtm->rtm_flags, &saved_nrt); if (error == 0 && saved_nrt) { + /* + * If the route request specified an interface with + * IFA and/or IFP, we set the requested interface on + * the route with rt_setif. It would be much better + * to do this inside rtrequest, but that would + * require passing the desired interface, in some + * form, to rtrequest. Since rtrequest is called in + * so many places (roughly 40 in our source), adding + * a parameter is to much for us to swallow; this is + * something for the FreeBSD developers to tackle. + * Instead, we let rtrequest compute whatever + * interface it wants, then come in behind it and + * stick in the interface that we really want. This + * works reasonably well except when rtrequest can't + * figure out what interface to use (with + * ifa_withroute) and returns ENETUNREACH. Ideally + * it shouldn't matter if rtrequest can't figure out + * the interface if we're going to explicitly set it + * ourselves anyway. But practically we can't + * recover here because rtrequest will not do any of + * the work necessary to add the route if it can't + * find an interface. As long as there is a default + * route that leads to some interface, rtrequest will + * find an interface, so this problem should be + * rarely encountered. + * dwiggins@bbn.com + */ + + rt_setif(saved_nrt, ifpaddr, ifaaddr, gate); rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &saved_nrt->rt_rmx); saved_nrt->rt_refcnt--; @@ -287,6 +350,10 @@ route_output(m, va_alist) case RTM_CHANGE: if (gate && rt_setgate(rt, rt_key(rt), gate)) senderr(EDQUOT); + +#if 1 + rt_setif(rt, ifpaddr, ifaaddr, gate); +#else /* new gateway could require new ifaddr, ifp; flags may also be different; ifp may be specified by ll sockaddr when protocol address is ambiguous */ @@ -310,10 +377,13 @@ route_output(m, va_alist) rt->rt_ifp = ifp; } } +#endif rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &rt->rt_rmx); +#if 0 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); +#endif if (genmask) rt->rt_genmask = genmask; /* @@ -387,6 +457,56 @@ rt_setmetrics(which, in, out) #undef metric } +/* + * Set route's interface given ifpaddr, ifaaddr, and gateway. + */ +static void +rt_setif(rt, Ifpaddr, Ifaaddr, Gate) + struct rtentry *rt; + struct sockaddr *Ifpaddr, *Ifaaddr, *Gate; +{ + struct ifaddr *ifa = 0; + struct ifnet *ifp = 0; + + /* new gateway could require new ifaddr, ifp; + flags may also be different; ifp may be specified + by ll sockaddr when protocol address is ambiguous */ + if (Ifpaddr && (ifa = ifa_ifwithnet(Ifpaddr)) && + (ifp = ifa->ifa_ifp) && (Ifaaddr || Gate)) + ifa = ifaof_ifpforaddr(Ifaaddr ? Ifaaddr : Gate, + ifp); + else if (Ifpaddr && (ifp = if_withname(Ifpaddr)) ) { + ifa = Gate ? ifaof_ifpforaddr(Gate, ifp) : + TAILQ_FIRST(&ifp->if_addrlist); + } + else if ((Ifaaddr && (ifa = ifa_ifwithaddr(Ifaaddr))) || + (Gate && (ifa = ifa_ifwithroute(rt->rt_flags, + rt_key(rt), Gate)))) + ifp = ifa->ifa_ifp; + if (ifa) { + register struct ifaddr *oifa = rt->rt_ifa; + if (oifa != ifa) { + if (oifa && oifa->ifa_rtrequest) + oifa->ifa_rtrequest(RTM_DELETE, + rt, Gate); + IFAFREE(rt->rt_ifa); + rt->rt_ifa = ifa; + ifa->ifa_refcnt++; + rt->rt_ifp = ifp; + rt->rt_rmx.rmx_mtu = ifp->if_mtu; + if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) + rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, Gate); + } else + goto call_ifareq; + return; + } + call_ifareq: + /* XXX: to reset gateway to correct value, at RTM_CHANGE */ + if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) + rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, Gate); +} + + #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) |