diff options
-rw-r--r-- | net/sched/act_csum.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index 945fb34ae721..c79aca29505e 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c | |||
@@ -559,8 +559,11 @@ static int tcf_csum_act(struct sk_buff *skb, const struct tc_action *a, | |||
559 | struct tcf_result *res) | 559 | struct tcf_result *res) |
560 | { | 560 | { |
561 | struct tcf_csum *p = to_tcf_csum(a); | 561 | struct tcf_csum *p = to_tcf_csum(a); |
562 | bool orig_vlan_tag_present = false; | ||
563 | unsigned int vlan_hdr_count = 0; | ||
562 | struct tcf_csum_params *params; | 564 | struct tcf_csum_params *params; |
563 | u32 update_flags; | 565 | u32 update_flags; |
566 | __be16 protocol; | ||
564 | int action; | 567 | int action; |
565 | 568 | ||
566 | params = rcu_dereference_bh(p->params); | 569 | params = rcu_dereference_bh(p->params); |
@@ -573,7 +576,9 @@ static int tcf_csum_act(struct sk_buff *skb, const struct tc_action *a, | |||
573 | goto drop; | 576 | goto drop; |
574 | 577 | ||
575 | update_flags = params->update_flags; | 578 | update_flags = params->update_flags; |
576 | switch (tc_skb_protocol(skb)) { | 579 | protocol = tc_skb_protocol(skb); |
580 | again: | ||
581 | switch (protocol) { | ||
577 | case cpu_to_be16(ETH_P_IP): | 582 | case cpu_to_be16(ETH_P_IP): |
578 | if (!tcf_csum_ipv4(skb, update_flags)) | 583 | if (!tcf_csum_ipv4(skb, update_flags)) |
579 | goto drop; | 584 | goto drop; |
@@ -582,13 +587,35 @@ static int tcf_csum_act(struct sk_buff *skb, const struct tc_action *a, | |||
582 | if (!tcf_csum_ipv6(skb, update_flags)) | 587 | if (!tcf_csum_ipv6(skb, update_flags)) |
583 | goto drop; | 588 | goto drop; |
584 | break; | 589 | break; |
590 | case cpu_to_be16(ETH_P_8021AD): /* fall through */ | ||
591 | case cpu_to_be16(ETH_P_8021Q): | ||
592 | if (skb_vlan_tag_present(skb) && !orig_vlan_tag_present) { | ||
593 | protocol = skb->protocol; | ||
594 | orig_vlan_tag_present = true; | ||
595 | } else { | ||
596 | struct vlan_hdr *vlan = (struct vlan_hdr *)skb->data; | ||
597 | |||
598 | protocol = vlan->h_vlan_encapsulated_proto; | ||
599 | skb_pull(skb, VLAN_HLEN); | ||
600 | skb_reset_network_header(skb); | ||
601 | vlan_hdr_count++; | ||
602 | } | ||
603 | goto again; | ||
604 | } | ||
605 | |||
606 | out: | ||
607 | /* Restore the skb for the pulled VLAN tags */ | ||
608 | while (vlan_hdr_count--) { | ||
609 | skb_push(skb, VLAN_HLEN); | ||
610 | skb_reset_network_header(skb); | ||
585 | } | 611 | } |
586 | 612 | ||
587 | return action; | 613 | return action; |
588 | 614 | ||
589 | drop: | 615 | drop: |
590 | qstats_drop_inc(this_cpu_ptr(p->common.cpu_qstats)); | 616 | qstats_drop_inc(this_cpu_ptr(p->common.cpu_qstats)); |
591 | return TC_ACT_SHOT; | 617 | action = TC_ACT_SHOT; |
618 | goto out; | ||
592 | } | 619 | } |
593 | 620 | ||
594 | static int tcf_csum_dump(struct sk_buff *skb, struct tc_action *a, int bind, | 621 | static int tcf_csum_dump(struct sk_buff *skb, struct tc_action *a, int bind, |