diff options
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 55 |
1 files changed, 30 insertions, 25 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a61a760484f7..dea8ce20fea4 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -3296,20 +3296,22 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count) | |||
3296 | */ | 3296 | */ |
3297 | static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count) | 3297 | static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count) |
3298 | { | 3298 | { |
3299 | struct ethhdr *data = (struct ethhdr *)skb->data; | 3299 | const struct ethhdr *data; |
3300 | struct iphdr *iph; | 3300 | const struct iphdr *iph; |
3301 | struct ipv6hdr *ipv6h; | 3301 | const struct ipv6hdr *ipv6h; |
3302 | u32 v6hash; | 3302 | u32 v6hash; |
3303 | __be32 *s, *d; | 3303 | const __be32 *s, *d; |
3304 | 3304 | ||
3305 | if (skb->protocol == htons(ETH_P_IP) && | 3305 | if (skb->protocol == htons(ETH_P_IP) && |
3306 | skb_network_header_len(skb) >= sizeof(*iph)) { | 3306 | pskb_network_may_pull(skb, sizeof(*iph))) { |
3307 | iph = ip_hdr(skb); | 3307 | iph = ip_hdr(skb); |
3308 | data = (struct ethhdr *)skb->data; | ||
3308 | return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^ | 3309 | return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^ |
3309 | (data->h_dest[5] ^ data->h_source[5])) % count; | 3310 | (data->h_dest[5] ^ data->h_source[5])) % count; |
3310 | } else if (skb->protocol == htons(ETH_P_IPV6) && | 3311 | } else if (skb->protocol == htons(ETH_P_IPV6) && |
3311 | skb_network_header_len(skb) >= sizeof(*ipv6h)) { | 3312 | pskb_network_may_pull(skb, sizeof(*ipv6h))) { |
3312 | ipv6h = ipv6_hdr(skb); | 3313 | ipv6h = ipv6_hdr(skb); |
3314 | data = (struct ethhdr *)skb->data; | ||
3313 | s = &ipv6h->saddr.s6_addr32[0]; | 3315 | s = &ipv6h->saddr.s6_addr32[0]; |
3314 | d = &ipv6h->daddr.s6_addr32[0]; | 3316 | d = &ipv6h->daddr.s6_addr32[0]; |
3315 | v6hash = (s[1] ^ d[1]) ^ (s[2] ^ d[2]) ^ (s[3] ^ d[3]); | 3317 | v6hash = (s[1] ^ d[1]) ^ (s[2] ^ d[2]) ^ (s[3] ^ d[3]); |
@@ -3328,33 +3330,36 @@ static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count) | |||
3328 | static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count) | 3330 | static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count) |
3329 | { | 3331 | { |
3330 | u32 layer4_xor = 0; | 3332 | u32 layer4_xor = 0; |
3331 | struct iphdr *iph; | 3333 | const struct iphdr *iph; |
3332 | struct ipv6hdr *ipv6h; | 3334 | const struct ipv6hdr *ipv6h; |
3333 | __be32 *s, *d; | 3335 | const __be32 *s, *d; |
3334 | __be16 *layer4hdr; | 3336 | const __be16 *l4 = NULL; |
3337 | __be16 _l4[2]; | ||
3338 | int noff = skb_network_offset(skb); | ||
3339 | int poff; | ||
3335 | 3340 | ||
3336 | if (skb->protocol == htons(ETH_P_IP) && | 3341 | if (skb->protocol == htons(ETH_P_IP) && |
3337 | skb_network_header_len(skb) >= sizeof(*iph)) { | 3342 | pskb_may_pull(skb, noff + sizeof(*iph))) { |
3338 | iph = ip_hdr(skb); | 3343 | iph = ip_hdr(skb); |
3339 | if (!ip_is_fragment(iph) && | 3344 | poff = proto_ports_offset(iph->protocol); |
3340 | (iph->protocol == IPPROTO_TCP || | 3345 | |
3341 | iph->protocol == IPPROTO_UDP) && | 3346 | if (!ip_is_fragment(iph) && poff >= 0) { |
3342 | (skb_headlen(skb) - skb_network_offset(skb) >= | 3347 | l4 = skb_header_pointer(skb, noff + (iph->ihl << 2) + poff, |
3343 | iph->ihl * sizeof(u32) + sizeof(*layer4hdr) * 2)) { | 3348 | sizeof(_l4), &_l4); |
3344 | layer4hdr = (__be16 *)((u32 *)iph + iph->ihl); | 3349 | if (l4) |
3345 | layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1)); | 3350 | layer4_xor = ntohs(l4[0] ^ l4[1]); |
3346 | } | 3351 | } |
3347 | return (layer4_xor ^ | 3352 | return (layer4_xor ^ |
3348 | ((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count; | 3353 | ((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count; |
3349 | } else if (skb->protocol == htons(ETH_P_IPV6) && | 3354 | } else if (skb->protocol == htons(ETH_P_IPV6) && |
3350 | skb_network_header_len(skb) >= sizeof(*ipv6h)) { | 3355 | pskb_may_pull(skb, noff + sizeof(*ipv6h))) { |
3351 | ipv6h = ipv6_hdr(skb); | 3356 | ipv6h = ipv6_hdr(skb); |
3352 | if ((ipv6h->nexthdr == IPPROTO_TCP || | 3357 | poff = proto_ports_offset(ipv6h->nexthdr); |
3353 | ipv6h->nexthdr == IPPROTO_UDP) && | 3358 | if (poff >= 0) { |
3354 | (skb_headlen(skb) - skb_network_offset(skb) >= | 3359 | l4 = skb_header_pointer(skb, noff + sizeof(*ipv6h) + poff, |
3355 | sizeof(*ipv6h) + sizeof(*layer4hdr) * 2)) { | 3360 | sizeof(_l4), &_l4); |
3356 | layer4hdr = (__be16 *)(ipv6h + 1); | 3361 | if (l4) |
3357 | layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1)); | 3362 | layer4_xor = ntohs(l4[0] ^ l4[1]); |
3358 | } | 3363 | } |
3359 | s = &ipv6h->saddr.s6_addr32[0]; | 3364 | s = &ipv6h->saddr.s6_addr32[0]; |
3360 | d = &ipv6h->daddr.s6_addr32[0]; | 3365 | d = &ipv6h->daddr.s6_addr32[0]; |