diff options
-rw-r--r-- | drivers/net/macvlan.c | 3 | ||||
-rw-r--r-- | include/net/ip.h | 9 | ||||
-rw-r--r-- | net/ipv4/ip_fragment.c | 36 | ||||
-rw-r--r-- | net/packet/af_packet.c | 39 |
4 files changed, 49 insertions, 38 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 24cf942e1316..a3ce3d4561ed 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c | |||
@@ -169,6 +169,9 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) | |||
169 | 169 | ||
170 | port = macvlan_port_get_rcu(skb->dev); | 170 | port = macvlan_port_get_rcu(skb->dev); |
171 | if (is_multicast_ether_addr(eth->h_dest)) { | 171 | if (is_multicast_ether_addr(eth->h_dest)) { |
172 | skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN); | ||
173 | if (!skb) | ||
174 | return RX_HANDLER_CONSUMED; | ||
172 | src = macvlan_hash_lookup(port, eth->h_source); | 175 | src = macvlan_hash_lookup(port, eth->h_source); |
173 | if (!src) | 176 | if (!src) |
174 | /* frame comes from an external address */ | 177 | /* frame comes from an external address */ |
diff --git a/include/net/ip.h b/include/net/ip.h index aa76c7a4d9c3..c7e066a1c611 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
@@ -406,9 +406,18 @@ enum ip_defrag_users { | |||
406 | IP_DEFRAG_VS_OUT, | 406 | IP_DEFRAG_VS_OUT, |
407 | IP_DEFRAG_VS_FWD, | 407 | IP_DEFRAG_VS_FWD, |
408 | IP_DEFRAG_AF_PACKET, | 408 | IP_DEFRAG_AF_PACKET, |
409 | IP_DEFRAG_MACVLAN, | ||
409 | }; | 410 | }; |
410 | 411 | ||
411 | int ip_defrag(struct sk_buff *skb, u32 user); | 412 | int ip_defrag(struct sk_buff *skb, u32 user); |
413 | #ifdef CONFIG_INET | ||
414 | struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user); | ||
415 | #else | ||
416 | static inline struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user) | ||
417 | { | ||
418 | return skb; | ||
419 | } | ||
420 | #endif | ||
412 | int ip_frag_mem(struct net *net); | 421 | int ip_frag_mem(struct net *net); |
413 | int ip_frag_nqueues(struct net *net); | 422 | int ip_frag_nqueues(struct net *net); |
414 | 423 | ||
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 0e0ab98abc6f..763589ad673d 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
@@ -682,6 +682,42 @@ int ip_defrag(struct sk_buff *skb, u32 user) | |||
682 | } | 682 | } |
683 | EXPORT_SYMBOL(ip_defrag); | 683 | EXPORT_SYMBOL(ip_defrag); |
684 | 684 | ||
685 | struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user) | ||
686 | { | ||
687 | const struct iphdr *iph; | ||
688 | u32 len; | ||
689 | |||
690 | if (skb->protocol != htons(ETH_P_IP)) | ||
691 | return skb; | ||
692 | |||
693 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | ||
694 | return skb; | ||
695 | |||
696 | iph = ip_hdr(skb); | ||
697 | if (iph->ihl < 5 || iph->version != 4) | ||
698 | return skb; | ||
699 | if (!pskb_may_pull(skb, iph->ihl*4)) | ||
700 | return skb; | ||
701 | iph = ip_hdr(skb); | ||
702 | len = ntohs(iph->tot_len); | ||
703 | if (skb->len < len || len < (iph->ihl * 4)) | ||
704 | return skb; | ||
705 | |||
706 | if (ip_is_fragment(ip_hdr(skb))) { | ||
707 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
708 | if (skb) { | ||
709 | if (pskb_trim_rcsum(skb, len)) | ||
710 | return skb; | ||
711 | memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); | ||
712 | if (ip_defrag(skb, user)) | ||
713 | return NULL; | ||
714 | skb->rxhash = 0; | ||
715 | } | ||
716 | } | ||
717 | return skb; | ||
718 | } | ||
719 | EXPORT_SYMBOL(ip_check_defrag); | ||
720 | |||
685 | #ifdef CONFIG_SYSCTL | 721 | #ifdef CONFIG_SYSCTL |
686 | static int zero; | 722 | static int zero; |
687 | 723 | ||
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 7b5f03253016..03bb45adf2fc 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -1213,43 +1213,6 @@ static struct sock *fanout_demux_cpu(struct packet_fanout *f, struct sk_buff *sk | |||
1213 | return f->arr[cpu % num]; | 1213 | return f->arr[cpu % num]; |
1214 | } | 1214 | } |
1215 | 1215 | ||
1216 | static struct sk_buff *fanout_check_defrag(struct sk_buff *skb) | ||
1217 | { | ||
1218 | #ifdef CONFIG_INET | ||
1219 | const struct iphdr *iph; | ||
1220 | u32 len; | ||
1221 | |||
1222 | if (skb->protocol != htons(ETH_P_IP)) | ||
1223 | return skb; | ||
1224 | |||
1225 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | ||
1226 | return skb; | ||
1227 | |||
1228 | iph = ip_hdr(skb); | ||
1229 | if (iph->ihl < 5 || iph->version != 4) | ||
1230 | return skb; | ||
1231 | if (!pskb_may_pull(skb, iph->ihl*4)) | ||
1232 | return skb; | ||
1233 | iph = ip_hdr(skb); | ||
1234 | len = ntohs(iph->tot_len); | ||
1235 | if (skb->len < len || len < (iph->ihl * 4)) | ||
1236 | return skb; | ||
1237 | |||
1238 | if (ip_is_fragment(ip_hdr(skb))) { | ||
1239 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
1240 | if (skb) { | ||
1241 | if (pskb_trim_rcsum(skb, len)) | ||
1242 | return skb; | ||
1243 | memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); | ||
1244 | if (ip_defrag(skb, IP_DEFRAG_AF_PACKET)) | ||
1245 | return NULL; | ||
1246 | skb->rxhash = 0; | ||
1247 | } | ||
1248 | } | ||
1249 | #endif | ||
1250 | return skb; | ||
1251 | } | ||
1252 | |||
1253 | static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev, | 1216 | static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev, |
1254 | struct packet_type *pt, struct net_device *orig_dev) | 1217 | struct packet_type *pt, struct net_device *orig_dev) |
1255 | { | 1218 | { |
@@ -1268,7 +1231,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev, | |||
1268 | case PACKET_FANOUT_HASH: | 1231 | case PACKET_FANOUT_HASH: |
1269 | default: | 1232 | default: |
1270 | if (f->defrag) { | 1233 | if (f->defrag) { |
1271 | skb = fanout_check_defrag(skb); | 1234 | skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET); |
1272 | if (!skb) | 1235 | if (!skb) |
1273 | return 0; | 1236 | return 0; |
1274 | } | 1237 | } |