diff options
Diffstat (limited to 'sys/netinet6/frag6.c')
-rw-r--r-- | sys/netinet6/frag6.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c index 3bb425f..f8a86a1 100644 --- a/sys/netinet6/frag6.c +++ b/sys/netinet6/frag6.c @@ -52,6 +52,8 @@ #include <netinet/ip6.h> #include <netinet6/ip6_var.h> #include <netinet/icmp6.h> +#include <netinet/in_systm.h> /* for ECN definitions */ +#include <netinet/ip.h> /* for ECN definitions */ #include <net/net_osdep.h> @@ -151,6 +153,7 @@ frag6_input(mp, offp, proto) int first_frag = 0; int fragoff, frgpartlen; /* must be larger than u_int16_t */ struct ifnet *dstifp; + u_int8_t ecn, ecn0; ip6 = mtod(m, struct ip6_hdr *); #ifndef PULLDOWN_TEST @@ -350,6 +353,26 @@ frag6_input(mp, offp, proto) } /* + * Handle ECN by comparing this segment with the first one; + * if CE is set, do not lose CE. + * drop if CE and not-ECT are mixed for the same packet. + */ + ecn = (ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK; + ecn0 = (ntohl(q6->ip6q_down->ip6af_head) >> 20) & IPTOS_ECN_MASK; + if (ecn == IPTOS_ECN_CE) { + if (ecn0 == IPTOS_ECN_NOTECT) { + free(ip6af, M_FTABLE); + goto dropfrag; + } + if (ecn0 != IPTOS_ECN_CE) + q6->ip6q_down->ip6af_head |= htonl(IPTOS_ECN_CE << 20); + } + if (ecn == IPTOS_ECN_NOTECT && ecn0 != IPTOS_ECN_NOTECT) { + free(ip6af, M_FTABLE); + goto dropfrag; + } + + /* * Find a segment which begins after this one does. */ for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; |