Replace kfree_skb() which is used in ip6_forward() and ip_forward() with kfree_skb_reason(). The new drop reason 'SKB_DROP_REASON_PKT_TOO_BIG' is introduced for the case that the length of the packet exceeds MTU and can't fragment.
Unified · Split
| @@ -453,6 +453,9 @@ enum skb_drop_reason { · 452 unmodified lines | ||
| 453 | 453 | SKB_DROP_REASON_IP_INNOROUTES, /* network unreachable, corresponding |
| 454 | 454 | * to IPSTATS_MIB_INADDRERRORS |
| 455 | 455 | */ |
| 456 | + SKB_DROP_REASON_PKT_TOO_BIG, /* packet size is too big (maybe exceed | |
| 457 | + * the MTU) | |
| 458 | + */ | |
| 456 | 459 | SKB_DROP_REASON_MAX, |
| 457 | 460 | }; |
| 458 | 461 | |
| @@ -65,6 +65,7 @@ · 64 unmodified lines | ||
| 65 | 65 | EM(SKB_DROP_REASON_INVALID_PROTO, INVALID_PROTO) \ |
| 66 | 66 | EM(SKB_DROP_REASON_IP_INADDRERRORS, IP_INADDRERRORS) \ |
| 67 | 67 | EM(SKB_DROP_REASON_IP_INNOROUTES, IP_INNOROUTES) \ |
| 68 | + EM(SKB_DROP_REASON_PKT_TOO_BIG, PKT_TOO_BIG) \ | |
| 68 | 69 | EMe(SKB_DROP_REASON_MAX, MAX) |
| 69 | 70 | |
| 70 | 71 | #undef EM |
| @@ -90,6 +90,7 @@ int ip_forward(struct sk_buff *skb) · 89 unmodified lines | ||
| 90 | 90 | struct rtable *rt; /* Route we use */ |
| 91 | 91 | struct ip_options *opt = &(IPCB(skb)->opt); |
| 92 | 92 | struct net *net; |
| 93 | + SKB_DR(reason); | |
| 93 | 94 | |
| 94 | 95 | /* that should never happen */ |
| 95 | 96 | if (skb->pkt_type != PACKET_HOST) |
| @@ -101,8 +102,10 @@ int ip_forward(struct sk_buff *skb) · 5 unmodified lines | ||
| 101 | 102 | if (skb_warn_if_lro(skb)) |
| 102 | 103 | goto drop; |
| 103 | 104 | |
| 104 | − if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb)) | |
| 105 | + if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb)) { | |
| 106 | + SKB_DR_SET(reason, XFRM_POLICY); | |
| 105 | 107 | goto drop; |
| 108 | + } | |
| 106 | 109 | |
| 107 | 110 | if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb)) |
| 108 | 111 | return NET_RX_SUCCESS; |
| @@ -118,8 +121,10 @@ int ip_forward(struct sk_buff *skb) · 9 unmodified lines | ||
| 118 | 121 | if (ip_hdr(skb)->ttl <= 1) |
| 119 | 122 | goto too_many_hops; |
| 120 | 123 | |
| 121 | − if (!xfrm4_route_forward(skb)) | |
| 124 | + if (!xfrm4_route_forward(skb)) { | |
| 125 | + SKB_DR_SET(reason, XFRM_POLICY); | |
| 122 | 126 | goto drop; |
| 127 | + } | |
| 123 | 128 | |
| 124 | 129 | rt = skb_rtable(skb); |
| 125 | 130 | |
| @@ -132,6 +137,7 @@ int ip_forward(struct sk_buff *skb) · 6 unmodified lines | ||
| 132 | 137 | IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS); |
| 133 | 138 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, |
| 134 | 139 | htonl(mtu)); |
| 140 | + SKB_DR_SET(reason, PKT_TOO_BIG); | |
| 135 | 141 | goto drop; |
| 136 | 142 | } |
| 137 | 143 | |
| @@ -169,7 +175,8 @@ too_many_hops: · 31 unmodified lines | ||
| 169 | 175 | /* Tell the sender its packet died... */ |
| 170 | 176 | __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS); |
| 171 | 177 | icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0); |
| 178 | + SKB_DR_SET(reason, IP_INHDR); | |
| 172 | 179 | drop: |
| 173 | − kfree_skb(skb); | |
| 180 | + kfree_skb_reason(skb, reason); | |
| 174 | 181 | return NET_RX_DROP; |
| 175 | 182 | } |
| @@ -469,6 +469,7 @@ int ip6_forward(struct sk_buff *skb) · 468 unmodified lines | ||
| 469 | 469 | struct inet6_skb_parm *opt = IP6CB(skb); |
| 470 | 470 | struct net *net = dev_net(dst->dev); |
| 471 | 471 | struct inet6_dev *idev; |
| 472 | + SKB_DR(reason); | |
| 472 | 473 | u32 mtu; |
| 473 | 474 | |
| 474 | 475 | idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif)); |
| @@ -518,7 +519,7 @@ int ip6_forward(struct sk_buff *skb) · 43 unmodified lines | ||
| 518 | 519 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); |
| 519 | 520 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
| 520 | 521 | |
| 521 | − kfree_skb(skb); | |
| 522 | + kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR); | |
| 522 | 523 | return -ETIMEDOUT; |
| 523 | 524 | } |
| 524 | 525 | |
| @@ -537,6 +538,7 @@ int ip6_forward(struct sk_buff *skb) · 12 unmodified lines | ||
| 537 | 538 | |
| 538 | 539 | if (!xfrm6_route_forward(skb)) { |
| 539 | 540 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); |
| 541 | + SKB_DR_SET(reason, XFRM_POLICY); | |
| 540 | 542 | goto drop; |
| 541 | 543 | } |
| 542 | 544 | dst = skb_dst(skb); |
| @@ -596,7 +598,7 @@ int ip6_forward(struct sk_buff *skb) · 53 unmodified lines | ||
| 596 | 598 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INTOOBIGERRORS); |
| 597 | 599 | __IP6_INC_STATS(net, ip6_dst_idev(dst), |
| 598 | 600 | IPSTATS_MIB_FRAGFAILS); |
| 599 | − kfree_skb(skb); | |
| 601 | + kfree_skb_reason(skb, SKB_DROP_REASON_PKT_TOO_BIG); | |
| 600 | 602 | return -EMSGSIZE; |
| 601 | 603 | } |
| 602 | 604 | |
| @@ -618,8 +620,9 @@ int ip6_forward(struct sk_buff *skb) · 15 unmodified lines | ||
| 618 | 620 | |
| 619 | 621 | error: |
| 620 | 622 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); |
| 623 | + SKB_DR_SET(reason, IP_INADDRERRORS); | |
| 621 | 624 | drop: |
| 622 | − kfree_skb(skb); | |
| 625 | + kfree_skb_reason(skb, reason); | |
| 623 | 626 | return -EINVAL; |
| 624 | 627 | } |
| 625 | 628 | |