summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/ip6_output.c
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2003-10-20 15:27:48 +0000
committerume <ume@FreeBSD.org>2003-10-20 15:27:48 +0000
commit1bfb4986099befab26dc0c1e40e47e89f92f62fb (patch)
tree9f0a5ced322cdbe6ab2dbce0993f3b61ac529326 /sys/netinet6/ip6_output.c
parent1ebf2012445124bd775073056a9019ead10872fa (diff)
downloadFreeBSD-src-1bfb4986099befab26dc0c1e40e47e89f92f62fb.zip
FreeBSD-src-1bfb4986099befab26dc0c1e40e47e89f92f62fb.tar.gz
correct linkmtu handling.
Obtained from: KAME
Diffstat (limited to 'sys/netinet6/ip6_output.c')
-rw-r--r--sys/netinet6/ip6_output.c113
1 files changed, 68 insertions, 45 deletions
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 1f0c0cc..12dd282 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -137,6 +137,8 @@ static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int,
struct ip6_frag **));
static int ip6_insert_jumboopt __P((struct ip6_exthdrs *, u_int32_t));
static int ip6_splithdr __P((struct mbuf *, struct ip6_exthdrs *));
+static int ip6_getpmtu __P((struct route_in6 *, struct route_in6 *,
+ struct ifnet *, struct in6_addr *, u_long *));
/*
@@ -771,51 +773,9 @@ skip_ipsec2:;
if (ifpp)
*ifpp = ifp;
- /*
- * Determine path MTU.
- */
- if (ro_pmtu != ro) {
- /* The first hop and the final destination may differ. */
- struct sockaddr_in6 *sin6_fin =
- (struct sockaddr_in6 *)&ro_pmtu->ro_dst;
- if (ro_pmtu->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
- !IN6_ARE_ADDR_EQUAL(&sin6_fin->sin6_addr,
- &finaldst))) {
- RTFREE(ro_pmtu->ro_rt);
- ro_pmtu->ro_rt = (struct rtentry *)0;
- }
- if (ro_pmtu->ro_rt == 0) {
- bzero(sin6_fin, sizeof(*sin6_fin));
- sin6_fin->sin6_family = AF_INET6;
- sin6_fin->sin6_len = sizeof(struct sockaddr_in6);
- sin6_fin->sin6_addr = finaldst;
-
- rtalloc((struct route *)ro_pmtu);
- }
- }
- if (ro_pmtu->ro_rt != NULL) {
- u_int32_t ifmtu = ND_IFINFO(ifp)->linkmtu;
-
- mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu;
- if (mtu > ifmtu || mtu == 0) {
- /*
- * The MTU on the route is larger than the MTU on
- * the interface! This shouldn't happen, unless the
- * MTU of the interface has been changed after the
- * interface was brought up. Change the MTU in the
- * route to match the interface MTU (as long as the
- * field isn't locked).
- *
- * if MTU on the route is 0, we need to fix the MTU.
- * this case happens with path MTU discovery timeouts.
- */
- mtu = ifmtu;
- if ((ro_pmtu->ro_rt->rt_rmx.rmx_locks & RTV_MTU) == 0)
- ro_pmtu->ro_rt->rt_rmx.rmx_mtu = mtu; /* XXX */
- }
- } else {
- mtu = ND_IFINFO(ifp)->linkmtu;
- }
+ /* Determine path MTU. */
+ if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu)) != 0)
+ goto bad;
/*
* advanced API (IPV6_USE_MIN_MTU) overrides mtu setting
@@ -1300,6 +1260,69 @@ ip6_insertfraghdr(m0, m, hlen, frghdrp)
return (0);
}
+static int
+ip6_getpmtu(ro_pmtu, ro, ifp, dst, mtup)
+ struct route_in6 *ro_pmtu, *ro;
+ struct ifnet *ifp;
+ struct in6_addr *dst;
+ u_long *mtup;
+{
+ u_int32_t mtu = 0;
+ int error = 0;
+
+ /*
+ * Determine path MTU.
+ */
+ if (ro_pmtu != ro) {
+ /* The first hop and the final destination may differ. */
+ struct sockaddr_in6 *sa6_dst =
+ (struct sockaddr_in6 *)&ro_pmtu->ro_dst;
+ if (ro_pmtu->ro_rt &&
+ ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
+ !IN6_ARE_ADDR_EQUAL(&sa6_dst->sin6_addr, dst))) {
+ RTFREE(ro_pmtu->ro_rt);
+ ro_pmtu->ro_rt = (struct rtentry *)NULL;
+ }
+ if (ro_pmtu->ro_rt == NULL) {
+ bzero(sa6_dst, sizeof(*sa6_dst));
+ sa6_dst->sin6_family = AF_INET6;
+ sa6_dst->sin6_len = sizeof(struct sockaddr_in6);
+ sa6_dst->sin6_addr = *dst;
+
+ rtalloc((struct route *)ro_pmtu);
+ }
+ }
+ if (ro_pmtu->ro_rt) {
+ u_int32_t ifmtu;
+
+ if (ifp == NULL)
+ ifp = ro_pmtu->ro_rt->rt_ifp;
+ ifmtu = IN6_LINKMTU(ifp);
+ mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu;
+ if (mtu == 0)
+ mtu = ifmtu;
+ else if (mtu > ifmtu || mtu == 0) {
+ /*
+ * The MTU on the route is larger than the MTU on
+ * the interface! This shouldn't happen, unless the
+ * MTU of the interface has been changed after the
+ * interface was brought up. Change the MTU in the
+ * route to match the interface MTU (as long as the
+ * field isn't locked).
+ */
+ mtu = ifmtu;
+ if (!(ro_pmtu->ro_rt->rt_rmx.rmx_locks & RTV_MTU))
+ ro_pmtu->ro_rt->rt_rmx.rmx_mtu = mtu;
+ }
+ } else if (ifp) {
+ mtu = IN6_LINKMTU(ifp);
+ } else
+ error = EHOSTUNREACH; /* XXX */
+
+ *mtup = mtu;
+ return (error);
+}
+
/*
* IP6 socket option processing.
*/
OpenPOWER on IntegriCloud