|
@@ -236,6 +236,7 @@ resubmit:
|
|
nhoff = IP6CB(skb)->nhoff;
|
|
nhoff = IP6CB(skb)->nhoff;
|
|
nexthdr = skb_network_header(skb)[nhoff];
|
|
nexthdr = skb_network_header(skb)[nhoff];
|
|
|
|
|
|
|
|
+resubmit_final:
|
|
raw = raw6_local_deliver(skb, nexthdr);
|
|
raw = raw6_local_deliver(skb, nexthdr);
|
|
ipprot = rcu_dereference(inet6_protos[nexthdr]);
|
|
ipprot = rcu_dereference(inet6_protos[nexthdr]);
|
|
if (ipprot) {
|
|
if (ipprot) {
|
|
@@ -263,10 +264,21 @@ resubmit:
|
|
goto discard;
|
|
goto discard;
|
|
|
|
|
|
ret = ipprot->handler(skb);
|
|
ret = ipprot->handler(skb);
|
|
- if (ret > 0)
|
|
|
|
- goto resubmit;
|
|
|
|
- else if (ret == 0)
|
|
|
|
|
|
+ if (ret > 0) {
|
|
|
|
+ if (ipprot->flags & INET6_PROTO_FINAL) {
|
|
|
|
+ /* Not an extension header, most likely UDP
|
|
|
|
+ * encapsulation. Use return value as nexthdr
|
|
|
|
+ * protocol not nhoff (which presumably is
|
|
|
|
+ * not set by handler).
|
|
|
|
+ */
|
|
|
|
+ nexthdr = ret;
|
|
|
|
+ goto resubmit_final;
|
|
|
|
+ } else {
|
|
|
|
+ goto resubmit;
|
|
|
|
+ }
|
|
|
|
+ } else if (ret == 0) {
|
|
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDELIVERS);
|
|
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDELIVERS);
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
if (!raw) {
|
|
if (!raw) {
|
|
if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
|
|
if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
|