X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=include%2Fnet%2Finet_ecn.h;h=f87845e2e96589a30791dac5af7603779f2c355a;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=4b9c7556273ae877578b6821c0e2868667a167f5;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h index 4b9c75562..f87845e2e 100644 --- a/include/net/inet_ecn.h +++ b/include/net/inet_ecn.h @@ -2,6 +2,7 @@ #define _INET_ECN_H_ #include +#include enum { INET_ECN_NOT_ECT = 0, @@ -16,9 +17,9 @@ static inline int INET_ECN_is_ce(__u8 dsfield) return (dsfield & INET_ECN_MASK) == INET_ECN_CE; } -static inline int INET_ECN_is_not_ce(__u8 dsfield) +static inline int INET_ECN_is_not_ect(__u8 dsfield) { - return (dsfield & INET_ECN_MASK) == INET_ECN_ECT_0; + return (dsfield & INET_ECN_MASK) == INET_ECN_NOT_ECT; } static inline int INET_ECN_is_capable(__u8 dsfield) @@ -29,8 +30,8 @@ static inline int INET_ECN_is_capable(__u8 dsfield) static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) { outer &= ~INET_ECN_MASK; - if (INET_ECN_is_capable(inner)) - outer |= (inner & INET_ECN_MASK); + outer |= !INET_ECN_is_ce(inner) ? (inner & INET_ECN_MASK) : + INET_ECN_ECT_0; return outer; } @@ -50,7 +51,25 @@ static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) static inline void IP_ECN_set_ce(struct iphdr *iph) { u32 check = iph->check; - check += __constant_htons(0xFFFE); + u32 ecn = (iph->tos + 1) & INET_ECN_MASK; + + /* + * After the last operation we have (in binary): + * INET_ECN_NOT_ECT => 01 + * INET_ECN_ECT_1 => 10 + * INET_ECN_ECT_0 => 11 + * INET_ECN_CE => 00 + */ + if (!(ecn & 2)) + return; + + /* + * The following gives us: + * INET_ECN_ECT_1 => check += htons(0xFFFD) + * INET_ECN_ECT_0 => check += htons(0xFFFE) + */ + check += htons(0xFFFB) + htons(ecn); + iph->check = check + (check>=0xFFFF); iph->tos |= INET_ECN_CE; } @@ -60,10 +79,18 @@ static inline void IP_ECN_clear(struct iphdr *iph) iph->tos &= ~INET_ECN_MASK; } +static inline void ipv4_copy_dscp(struct iphdr *outer, struct iphdr *inner) +{ + u32 dscp = ipv4_get_dsfield(outer) & ~INET_ECN_MASK; + ipv4_change_dsfield(inner, INET_ECN_MASK, dscp); +} + struct ipv6hdr; static inline void IP6_ECN_set_ce(struct ipv6hdr *iph) { + if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph))) + return; *(u32*)iph |= htonl(INET_ECN_CE << 20); } @@ -72,6 +99,10 @@ static inline void IP6_ECN_clear(struct ipv6hdr *iph) *(u32*)iph &= ~htonl(INET_ECN_MASK << 20); } -#define ip6_get_dsfield(iph) ((ntohs(*(u16*)(iph)) >> 4) & 0xFF) +static inline void ipv6_copy_dscp(struct ipv6hdr *outer, struct ipv6hdr *inner) +{ + u32 dscp = ipv6_get_dsfield(outer) & ~INET_ECN_MASK; + ipv6_change_dsfield(inner, INET_ECN_MASK, dscp); +} #endif