diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1999-01-06 23:26:59 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1999-01-06 23:26:59 +0000 |
commit | 003294c571f5404cf3bb2ab3cf33eba8643b932b (patch) | |
tree | 0efc8463ff2d3c2555c4a6a830fe508568cc5e07 /sys/netinet6/ipv6_trans.c | |
parent | 21e642825078d715499c3110ace9c6e61f6c6db4 (diff) |
first few files of NRL ipv6. This NRL release was officially exported
to me by US DOD officials, with the crypto already removed.
Diffstat (limited to 'sys/netinet6/ipv6_trans.c')
-rw-r--r-- | sys/netinet6/ipv6_trans.c | 669 |
1 files changed, 669 insertions, 0 deletions
diff --git a/sys/netinet6/ipv6_trans.c b/sys/netinet6/ipv6_trans.c new file mode 100644 index 00000000000..adfd61710b9 --- /dev/null +++ b/sys/netinet6/ipv6_trans.c @@ -0,0 +1,669 @@ +/* +%%% copyright-nrl-95 +This software is Copyright 1995-1998 by Randall Atkinson, Ronald Lee, +Daniel McDonald, Bao Phan, and Chris Winters. All Rights Reserved. All +rights under this copyright have been assigned to the US Naval Research +Laboratory (NRL). The NRL Copyright Notice and License Agreement Version +1.1 (January 17, 1995) applies to this software. +You should have received a copy of the license with this software. If you +didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. + +*/ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/protosw.h> +#include <sys/domain.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/ip_icmp.h> + +#include <netinet6/in6.h> +#include <netinet6/in6_var.h> +#include <netinet6/ipv6.h> +#include <netinet6/ipv6_var.h> + +#include <sys/debug.h> + +#if __OpenBSD__ && defined(NRL_IPSEC) +#define IPSEC 1 +#endif /* __OpenBSD__ && defined(NRL_IPSEC) */ + +/* + * External globals. + */ + +extern struct in6_ifaddr *in6_ifaddr; +extern int ipv6_defhoplmt; + +int ipv6_trans_mtu __P((struct mbuf **, int, int)); +int ipv6_trans_output __P((struct mbuf *, struct sockaddr_in *, struct rtentry *)); +int ipv6_encaps_output __P((struct mbuf *, struct sockaddr_in6 *, struct rtentry *)); +int ipv6_tunnel_output __P((struct mbuf *, struct sockaddr_in6 *, struct rtentry *)); +int ipv4_trans_output __P((struct mbuf *, struct sockaddr_in6 *, struct rtentry *)); +int ipv4_encaps_output __P((struct mbuf *, struct sockaddr_in *, struct rtentry *)); +int ipv4_tunnel_output __P((struct mbuf *, struct sockaddr_in *, struct rtentry *)); + +/*---------------------------------------------------------------------- + * Called from ip_icmp.c, this function will reduce the tunnel path MTU + * precisely. I know I have enough to reconstruct the IPv6 header, which + * is all I care about for this case. Return 1 if m0 is intact, and 0 if + * m0 is corrupted somehow. Don't forget to update m0. + ----------------------------------------------------------------------*/ + +int +ipv6_trans_mtu(m0, newmtu, len) + struct mbuf **m0; + int newmtu,len; +{ + struct ip *ip,*iip; + struct ipv6 *ipv6; + struct icmp *icp; + struct rtentry *rt; + struct sockaddr_in6 sin6; + struct in6_ifaddr *i6a; + + /* + * Make packet contiguous into one block of memory. If the IPv6 header is + * beyond MCLBYTES into the packet, then I'm in big trouble. + */ + *m0 = m_pullup2(*m0,min(len,MCLBYTES)); + if (*m0 == NULL) + return 0; + + ip = mtod(*m0,struct ip *); + icp = (struct icmp *) ((caddr_t)ip + (ip->ip_hl << 2)); + iip = &icp->icmp_ip; + ipv6 = (struct ipv6 *) ((caddr_t)iip + (iip->ip_hl << 2)); + + /* + * Verify source is one of mine? + */ + for (i6a = in6_ifaddr; i6a != NULL; i6a = i6a->i6a_next) + if (IN6_ARE_ADDR_EQUAL(&i6a->i6a_addr.sin6_addr, &ipv6->ipv6_src)) + break; + if (i6a == NULL) + { + /* Packet didn't originate with me. Drop it. */ + return 1; + } + + /* + * Find route for this destination and update it. + */ + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(sin6); + sin6.sin6_port = 0; + sin6.sin6_flowinfo = 0; + sin6.sin6_addr = ipv6->ipv6_dst; + +#ifdef __FreeBSD__ + rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); +#else /* __FreeBSD__ */ + rt = rtalloc1((struct sockaddr *)&sin6, 0); +#endif /* __FreeBSD__ */ + + if (rt == NULL) + return 1; + rt->rt_refcnt--; + /* + * Update path MTU. + */ + if (!(rt->rt_flags & RTF_HOST)) + return 1; /* Can't update path MTU on non-host-route. */ + if (rt->rt_rmx.rmx_mtu < newmtu - sizeof(struct ip)) + panic("MTU WEIRDNESS !!!"); + rt->rt_rmx.rmx_mtu = newmtu - sizeof(struct ip); + return 1; +} + +/*---------------------------------------------------------------------- + * Handle ICMP errors for IPv6-in-IPv4 tunnels. + * + * Security processing should be put in here, as it was with the other + * ctlinput() functions, but with current ICMP implementations returning + * only sizeof(struct ip) + 64 bits of offending packet. + ----------------------------------------------------------------------*/ +#if __OpenBSD__ +void *ipv6_trans_ctlinput(int cmd, struct sockaddr *sa, void *vp, struct mbuf *incoming) +#else /* __OpenBSD__ */ +void ipv6_trans_ctlinput(int cmd, struct sockaddr *sa, register struct ip *ip, struct mbuf *incoming) +#endif /* __OpenBSD__ */ +{ + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + struct sockaddr_in6 sin6; + struct ipv6 *ipv6; + struct rtentry *rt; + struct in6_ifaddr *i6a; +#if __OpenBSD__ + struct ip *ip = (struct ip *)vp; +#endif /* __OpenBSD__ */ + + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(sin6); + sin6.sin6_port = 0; + sin6.sin6_flowinfo = 0; + DPRINTF(IDL_EVENT,("Entered ipv6_trans_ctlinput().\n")); + + /* + * Do standard checks to see that all parameters are here. + */ + if ((unsigned)cmd > PRC_NCMDS || sa->sa_family != AF_INET || + sin->sin_addr.s_addr == INADDR_ANY || ip == NULL) + { + DPRINTF(IDL_EVENT,("Failed one of the four checks. Returning.\n")); +#ifdef __OpenBSD__ + return NULL; +#else /* __OpenBSD__ */ + return; +#endif /* __OpenBSD__ */ + } + + /* + * Okay, at this point I have a contiguous IPv6 in IPv4 datagram. + * I achieved this effect by convincing ip_icmp.[ch] to pull up + * more than the first 64 bits. + */ + + ipv6 = (struct ipv6 *) ((caddr_t)ip + (ip->ip_hl << 2)); + /* + * Verify source address is one of mine. + */ + for (i6a = in6_ifaddr; i6a != NULL; i6a = i6a->i6a_next) + if (IN6_ARE_ADDR_EQUAL(&i6a->i6a_addr.sin6_addr, &ipv6->ipv6_src)) + break; + if (i6a == NULL) + { + /* + * Packet didn't originate with me. Drop it. + */ +#ifdef __OpenBSD__ + return NULL; +#else /* __OpenBSD__ */ + return; +#endif /* __OpenBSD__ */ + } + + sin6.sin6_addr = ipv6->ipv6_dst; +#ifdef __FreeBSD__ + rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); +#else /* __FreeBSD__ */ + rt = rtalloc1((struct sockaddr *)&sin6, 0); +#endif /* __FreeBSD__ */ + if (rt == NULL) +#ifdef __OpenBSD__ + return NULL; +#else /* __OpenBSD__ */ + return; +#endif /* __OpenBSD__ */ + rt->rt_refcnt--; + + switch (cmd) + { + case PRC_MSGSIZE: + /* + * This function was called because the actual MTU wasn't grokked + * from the ICMP packet. + * + * If I get this, drop to IPV6_MINMTU. If the actual MTU was in the + * ICMP packet and was read correctly, it went up a different codepath. + * + * RFC 1191 talks about a plateau table. Here's the place to do it, + * either that, or on increase. + */ + if (rt->rt_flags & RTF_HOST) + { + /* + * Only attempt path MTU update if I'm a host. + */ + if (rt->rt_rmx.rmx_mtu == IPV6_MINMTU) + panic("Too big on v6 MTU of 576!!!"); + rt->rt_rmx.rmx_mtu = IPV6_MINMTU; + } + break; + case PRC_UNREACH_NET: + rt->rt_flags &= ~RTF_HOST; /* Is this wise? I'm doing this to return + the right error on future requests. */ + /* FALLTHROUGH */ + case PRC_UNREACH_HOST: + case PRC_UNREACH_PROTOCOL: + /* + * Other end isn't a v6/v4 node. + */ + rt->rt_flags |= RTF_REJECT; /* Don't want to send any packets. */ + break; + default: + break; + } +#ifdef __OpenBSD__ + return NULL; +#endif /* __OpenBSD__ */ +} + +/*---------------------------------------------------------------------- + *"IPv6 in IPv4 tunnelling." + * + * Output routine for IPv6 in IPv4. Uses M_PREPEND to prepend an IPv4 + * header, and call ip_output(). + * + * Called in: (only) ipv6_tunnel_output() from this file. + ----------------------------------------------------------------------*/ + +int +ipv6_trans_output(outgoing, v4dst, v6rt) + struct mbuf *outgoing; + struct sockaddr_in *v4dst; + struct rtentry *v6rt; +{ + struct route v4route; + struct ip *ip; + struct ipv6 *ipv6 = mtod(outgoing,struct ipv6 *); + int rc; +#ifdef IPSEC + struct socket *socket; +#endif /* IPSEC */ + + /* + * Like all below-IP(v6) output routines, check RTF_REJECT flag. + */ + if (v6rt->rt_flags & RTF_REJECT) + { + m_freem(outgoing); + return (v6rt->rt_flags & RTF_HOST) ? EHOSTUNREACH : ENETUNREACH; + } + + if (v6rt->rt_gwroute) + v6rt->rt_gwroute->rt_refcnt++; + v4route.ro_rt = v6rt->rt_gwroute; + bcopy(v4dst,&v4route.ro_dst,v4dst->sin_len); + + /* + * Prepend IPv4 header. + */ + M_PREPEND(outgoing,sizeof(struct ip), M_DONTWAIT); + if (outgoing == NULL) + return ENOBUFS; + + ip = mtod(outgoing,struct ip *); + bzero(ip,sizeof(*ip)); + + /* + * Following four lines are done here rather than ip_output() because of + * the *&*&%^^& don't fragment bit. + */ + ip->ip_v = IPVERSION; + ip->ip_id = htons(ip_id++); + ip->ip_hl = sizeof(*ip)>>2; + if (v6rt->rt_rmx.rmx_mtu > IPV6_MINMTU) + ip->ip_off |= IP_DF; + ipstat.ips_localout++; + + if (v6rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) + ip->ip_dst = v4dst->sin_addr; + else + { + /* + * If I'm in here, this means I'm not a host route, but when I was + * supposed to clone, I was supposed to change the v4dst addr. + * + * This will only happen if I'm a v6-in-v4 router-to-host route, + * in which case I have to do the translation on the fly, based on + * the data in the IPv6 header. + */ + if (!IN6_IS_ADDR_V4COMPAT(&ipv6->ipv6_dst)) + { + printf("Oooh boy, v6-in-v4 tunnel ( trans_output() ) trouble!!!\n"); + } + ip->ip_dst.s_addr = ipv6->ipv6_dst.in6a_words[3]; + } + + ip->ip_src.s_addr = INADDR_ANY; + ip->ip_p = IPPROTO_IPV6; + ip->ip_ttl = ip_defttl; + ip->ip_len = outgoing->m_pkthdr.len; + +#ifdef IPSEC + if (v6rt->rt_flags & (RTF_CRYPT|RTF_AUTH)) { + /* + * A secure route has hanging off its rt_netproc field something which + * can be tagged onto an outgoing mbuf such that ipv4_output can + * secure the IPv6-in-IPv4 packet. + */ + DPRINTF(IDL_EVENT,("Secure route, sending cheesy socket.\n")); + socket = v6rt->rt_netproc; + } else + socket = NULL; + + rc = ip_output(outgoing, NULL, &v4route, IP_RAWOUTPUT, NULL, socket); +#else /* IPSEC */ +#if __bsdi__ + rc = ip_output(outgoing, NULL, &v4route, IP_RAWOUTPUT, NULL, NULL); +#else /* __bsdi__ */ + rc = ip_output(outgoing, NULL, &v4route, IP_RAWOUTPUT, NULL); +#endif /* __bsdi__ */ +#endif /* IPSEC */ + + if (rc == EMSGSIZE) + { + DPRINTF(IDL_ERROR,("Path MTU adjustment needed in trans_output().\n")); + } + if (v4route.ro_rt != NULL) + RTFREE(v4route.ro_rt); + return rc; +} + +/*---------------------------------------------------------------------- + * "IPv6 in IPv6 tunnelling." + * + * Encapsulate IPv6 packet in another IPv6 packet. This, in combination + * with passing on a fake socket with a security request, can enable a + * configured secure tunnel. + * + * Called in: (only) ipv6_tunnel_output() from this file. + ----------------------------------------------------------------------*/ + +int +ipv6_encaps_output(outgoing, tundst, tunrt) + struct mbuf *outgoing; + struct sockaddr_in6 *tundst; + struct rtentry *tunrt; +{ + struct route6 actroute; + struct ipv6 *ipv6; + int rc; +#ifdef IPSEC + struct socket *socket; +#endif /* IPSEC */ + +DPRINTF(IDL_GROSS_EVENT,("\n\nipv6_encaps_output():0000-Hey! I'm in IPV6_in_IPV6 tunnelling code!!\n")); + if (tunrt->rt_flags & RTF_REJECT) + { + m_freem(outgoing); + return (tunrt->rt_flags & RTF_HOST) ? EHOSTUNREACH : ENETUNREACH; + } + + if (tunrt->rt_gwroute) + tunrt->rt_gwroute->rt_refcnt++; + actroute.ro_rt = tunrt->rt_gwroute; + bcopy(tundst,&actroute.ro_dst,tundst->sin6_len); + + M_PREPEND(outgoing,sizeof(struct ipv6), M_DONTWAIT); + if (outgoing == NULL) + return ENOBUFS; + + ipv6 = mtod(outgoing,struct ipv6 *); + bzero(ipv6,sizeof(*ipv6)); + + ipv6->ipv6_versfl = htonl(0x60000000); + ipv6->ipv6_length = outgoing->m_pkthdr.len - sizeof(struct ipv6); + ipv6->ipv6_nexthdr = IPPROTO_IPV6; + ipv6->ipv6_hoplimit = ipv6_defhoplmt; + ipv6->ipv6_dst = tundst->sin6_addr; + +#ifdef IPSEC + if (tunrt->rt_flags & (RTF_CRYPT|RTF_AUTH)) { + /* + * A secure route has hanging off its rt_netproc field something which + * can be tagged onto an outgoing mbuf such that ipv6_output can + * secure the IPv6-in-IPv6 packet. + */ + DPRINTF(IDL_EVENT,("ipv6_encaps_output():0500-Secure route, sending cheesy socket.\n")); + socket = tunrt->rt_netproc; + } else + socket = NULL; + + rc = ipv6_output(outgoing, &actroute, IPV6_RAWOUTPUT, NULL, NULL, socket); +#else /* IPSEC */ + rc = ipv6_output(outgoing, &actroute, IPV6_RAWOUTPUT, NULL, NULL, NULL); +#endif /* IPSEC */ + + if (rc == EMSGSIZE) + { + DPRINTF(IDL_ERROR,("Path MTU adjustment needed in trans_output().\n")); + } + if (actroute.ro_rt != NULL) + RTFREE(actroute.ro_rt); + return rc; + +} +/*---------------------------------------------------------------------- + * "IPv4 in IPv4 tunnelling" + * + * Output routine for IPv4 in IPv4. Uses M_PREPEND to prepend an IPv4 + * header (i.e. the tunnel header), and then call ip_output() to + * send the tunnel packet. The v4 in v4 tunnel seems redundant, but is + * useful for setting up secure tunnels. + * + * Called in: (only) ipv4_tunnel_output() from this file. + ----------------------------------------------------------------------*/ + +int +ipv4_encaps_output(outgoing, v4tundst, v4rt) + struct mbuf *outgoing; + struct sockaddr_in *v4tundst; /* Goto to destination tunnel endpoint. */ + struct rtentry *v4rt; /* The encapsulated (i.e. passenger) IPv4 + * packet's route. */ +{ + struct route v4tunroute; /* The tunnel- (i.e. actual) route to the tunnel's + * destination endpoint (i.e. to the other + * side of the tunnel). */ + struct ip *ip; /* For setting up the IPv4 data needed for the + * tunnel IPv4 packet. */ + int rc; /* Return Code */ +#ifdef IPSEC + struct socket *socket; +#endif /* IPSEC */ + + /* + * Like all below-IP(v4) output routines, check RTF_REJECT flag. + * Why? We need to make sure the logical (i.e. encapsulated packet's) + * route to the final destination is reachable. + */ + if (v4rt->rt_flags & RTF_REJECT) + { + m_freem(outgoing); + return (v4rt->rt_flags & RTF_HOST) ? EHOSTUNREACH : ENETUNREACH; + } + + if (v4rt->rt_gwroute) + v4rt->rt_gwroute->rt_refcnt++; + v4tunroute.ro_rt = v4rt->rt_gwroute; + bcopy(v4tundst,&v4tunroute.ro_dst,v4tundst->sin_len); + + /* + * Prepend IPv4 header. + */ + M_PREPEND(outgoing,sizeof(struct ip), M_DONTWAIT); + if (outgoing == NULL) + return ENOBUFS; + + ip = mtod(outgoing,struct ip *); + bzero(ip,sizeof(*ip)); + + /* + * Initialization of IP header: We'll let ip_output() fill in + * IP's version, ip, offset, and header length as well as update + * ipstat.ips_localout. + * + * Of course, we need to do the rest ... + */ + + ip->ip_src.s_addr = INADDR_ANY; + ip->ip_p = IPPROTO_IPV4; + ip->ip_ttl = ip_defttl; + ip->ip_len = outgoing->m_pkthdr.len; + + ip->ip_dst = v4tundst->sin_addr; + +#ifdef IPSEC + if (v4rt->rt_flags & (RTF_CRYPT|RTF_AUTH)) { + /* + * A secure route has hanging off its rt_netproc field something which + * can be tagged onto an outgoing mbuf such that ipv4_output can + * secure the IPv4-in-IPv4 packet. + */ + DPRINTF(IDL_EVENT,("ipv4_encaps_output():0500-Secure route, sending cheesy socket.\n")); + socket = v4rt->rt_netproc; + } else + socket = NULL; + + rc = ip_output(outgoing, NULL, &v4tunroute, 0, NULL, socket); +#else /* IPSEC */ +#if __bsdi__ + rc = ip_output(outgoing, NULL, &v4tunroute, 0, NULL, NULL); +#else /* __bsdi__ */ + rc = ip_output(outgoing, NULL, &v4tunroute, 0, NULL); +#endif /* __bsdi__ */ +#endif /* IPSEC */ + + if (v4tunroute.ro_rt != NULL) + RTFREE(v4tunroute.ro_rt); + return rc; +} + +/*---------------------------------------------------------------------- + *"IPv4 in IPv6" + * + * Encapsulate IPv4 packet in a IPv6 packet. + * + * Called in: (only) ipv4_tunnel_output() from this file. + *---------------------------------------------------------------------*/ + +int +ipv4_trans_output(outgoing, tunv6dst, v4rt) + struct mbuf *outgoing; + struct sockaddr_in6 *tunv6dst; + struct rtentry *v4rt; +{ + struct route6 tunv6route; + struct ipv6 *ipv6; + int rc; +#ifdef IPSEC + struct socket *socket; +#endif /* IPSEC */ + + if (v4rt->rt_flags & RTF_REJECT) + { + m_freem(outgoing); + return (v4rt->rt_flags & RTF_HOST) ? EHOSTUNREACH : ENETUNREACH; + } + + if (v4rt->rt_gwroute) + v4rt->rt_gwroute->rt_refcnt++; + tunv6route.ro_rt = v4rt->rt_gwroute; + bcopy(tunv6dst,&tunv6route.ro_dst,tunv6dst->sin6_len); + + M_PREPEND(outgoing,sizeof(struct ipv6), M_DONTWAIT); + if (outgoing == NULL) + return ENOBUFS; + + ipv6 = mtod(outgoing,struct ipv6 *); + bzero(ipv6,sizeof(*ipv6)); + + ipv6->ipv6_versfl = htonl(0x60000000); + ipv6->ipv6_length = outgoing->m_pkthdr.len - sizeof(struct ipv6); + ipv6->ipv6_nexthdr = IPPROTO_IPV4; + ipv6->ipv6_hoplimit = ipv6_defhoplmt; + ipv6->ipv6_dst = tunv6dst->sin6_addr; + +#ifdef IPSEC + if (v4rt->rt_flags & (RTF_CRYPT|RTF_AUTH)) { + /* + * A secure route has hanging off its rt_netproc field something which + * can be tagged onto an outgoing mbuf such that ipv6_output can + * secure the IPv4-in-IPv6 packet. + */ + DPRINTF(IDL_EVENT,("ipv4_trans_output():0500-Secure route, sending cheesy socket.\n")); + socket = v4rt->rt_netproc; + } else + socket = NULL; + + rc = ipv6_output(outgoing, &tunv6route, IPV6_RAWOUTPUT, NULL, NULL, socket); +#else /* IPSEC */ + rc = ipv6_output(outgoing, &tunv6route, IPV6_RAWOUTPUT, NULL, NULL, NULL); +#endif /* IPSEC */ + + if (rc == EMSGSIZE) + { + DPRINTF(IDL_ERROR,("Path MTU adjustment needed in trans_output().\n")); + } + if (tunv6route.ro_rt != NULL) + RTFREE(tunv6route.ro_rt); + return rc; +} + + +/*---------------------------------------------------------------------- + * Called by ipv6_output if the RTF_TUNNEL bit is set on a route, + * this function examines the route, and sees what sort of encapsulation is + * needed. Often, the rt->rt_gateway sockaddr is used to figure this out. + ----------------------------------------------------------------------*/ + +int +ipv6_tunnel_output(outgoing, dst, rt) + struct mbuf *outgoing; + struct sockaddr_in6 *dst; + struct rtentry *rt; +{ + DPRINTF(IDL_EVENT,("\n\nipv6_tunnel_output():0000-Just entered.\n")); + + /* + * Determine what type of tunnel it is with rt. Perform correct kind + * of encapsulation (in IPv4, ESP, etc.) and call output routine of + * what you want encapsulated. + */ + + /* IPv6 in IPv4. */ + if (rt->rt_gateway != NULL && rt->rt_gateway->sa_family == AF_INET) + return ipv6_trans_output(outgoing,(struct sockaddr_in *)rt->rt_gateway,rt); + + /* IPv6 in IPv6. */ + if (rt->rt_gateway != NULL && rt->rt_gateway->sa_family == AF_INET6) + return ipv6_encaps_output(outgoing,(struct sockaddr_in6 *)rt->rt_gateway,rt); + + m_freem(outgoing); + return EHOSTUNREACH; +} + + +/*---------------------------------------------------------------------- + * Called by ip_output if the RTF_TUNNEL bit is set on a route, + * this function examines the route, and sees what sort of encapsulation is + * needed. Often, the rt->rt_gateway sockaddr is used to figure this out. + ----------------------------------------------------------------------*/ + +int +ipv4_tunnel_output(outgoing, dst, rt) + struct mbuf *outgoing; + struct sockaddr_in *dst; + struct rtentry *rt; +{ + DPRINTF(IDL_EVENT,("\n\nipv4_tunnel_output():0000-Just entered.\n")); + + /* + * Determine what type of tunnel it is with rt. Perform correct kind + * of encapsulation (in IPv4, ESP, etc.) and call output routine of + * what you want encapsulated. + */ + + /* IPv4 in IPv6. */ + if (rt->rt_gateway != NULL && rt->rt_gateway->sa_family == AF_INET6) + return ipv4_trans_output(outgoing,(struct sockaddr_in6 *)rt->rt_gateway,rt); + + /* IPv4 in IPv4. */ + if (rt->rt_gateway != NULL && rt->rt_gateway->sa_family == AF_INET) + return ipv4_encaps_output(outgoing,(struct sockaddr_in *)rt->rt_gateway,rt); + + m_freem(outgoing); + return EHOSTUNREACH; +} |