diff options
-rw-r--r-- | include/net/ipv6.h | 2 | ||||
-rw-r--r-- | net/ipv4/ip_input.c | 23 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 1 | ||||
-rw-r--r-- | net/ipv6/ip6_input.c | 131 |
4 files changed, 133 insertions, 24 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 16475c269749..b7843e0b16ee 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -922,6 +922,8 @@ static inline __be32 flowi6_get_flowlabel(const struct flowi6 *fl6) | |||
922 | 922 | ||
923 | int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, | 923 | int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, |
924 | struct packet_type *pt, struct net_device *orig_dev); | 924 | struct packet_type *pt, struct net_device *orig_dev); |
925 | void ipv6_list_rcv(struct list_head *head, struct packet_type *pt, | ||
926 | struct net_device *orig_dev); | ||
925 | 927 | ||
926 | int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb); | 928 | int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb); |
927 | 929 | ||
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 14ba628b2761..1a3b6f32b1c9 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c | |||
@@ -316,13 +316,6 @@ static int ip_rcv_finish_core(struct net *net, struct sock *sk, | |||
316 | struct rtable *rt; | 316 | struct rtable *rt; |
317 | int err; | 317 | int err; |
318 | 318 | ||
319 | /* if ingress device is enslaved to an L3 master device pass the | ||
320 | * skb to its handler for processing | ||
321 | */ | ||
322 | skb = l3mdev_ip_rcv(skb); | ||
323 | if (!skb) | ||
324 | return NET_RX_SUCCESS; | ||
325 | |||
326 | if (net->ipv4.sysctl_ip_early_demux && | 319 | if (net->ipv4.sysctl_ip_early_demux && |
327 | !skb_dst(skb) && | 320 | !skb_dst(skb) && |
328 | !skb->sk && | 321 | !skb->sk && |
@@ -408,8 +401,16 @@ drop_error: | |||
408 | 401 | ||
409 | static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) | 402 | static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) |
410 | { | 403 | { |
411 | int ret = ip_rcv_finish_core(net, sk, skb); | 404 | int ret; |
405 | |||
406 | /* if ingress device is enslaved to an L3 master device pass the | ||
407 | * skb to its handler for processing | ||
408 | */ | ||
409 | skb = l3mdev_ip_rcv(skb); | ||
410 | if (!skb) | ||
411 | return NET_RX_SUCCESS; | ||
412 | 412 | ||
413 | ret = ip_rcv_finish_core(net, sk, skb); | ||
413 | if (ret != NET_RX_DROP) | 414 | if (ret != NET_RX_DROP) |
414 | ret = dst_input(skb); | 415 | ret = dst_input(skb); |
415 | return ret; | 416 | return ret; |
@@ -545,6 +546,12 @@ static void ip_list_rcv_finish(struct net *net, struct sock *sk, | |||
545 | struct dst_entry *dst; | 546 | struct dst_entry *dst; |
546 | 547 | ||
547 | list_del(&skb->list); | 548 | list_del(&skb->list); |
549 | /* if ingress device is enslaved to an L3 master device pass the | ||
550 | * skb to its handler for processing | ||
551 | */ | ||
552 | skb = l3mdev_ip_rcv(skb); | ||
553 | if (!skb) | ||
554 | continue; | ||
548 | if (ip_rcv_finish_core(net, sk, skb) == NET_RX_DROP) | 555 | if (ip_rcv_finish_core(net, sk, skb) == NET_RX_DROP) |
549 | continue; | 556 | continue; |
550 | 557 | ||
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 9ed0eae91758..c9535354149f 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -764,6 +764,7 @@ EXPORT_SYMBOL_GPL(ipv6_opt_accepted); | |||
764 | static struct packet_type ipv6_packet_type __read_mostly = { | 764 | static struct packet_type ipv6_packet_type __read_mostly = { |
765 | .type = cpu_to_be16(ETH_P_IPV6), | 765 | .type = cpu_to_be16(ETH_P_IPV6), |
766 | .func = ipv6_rcv, | 766 | .func = ipv6_rcv, |
767 | .list_func = ipv6_list_rcv, | ||
767 | }; | 768 | }; |
768 | 769 | ||
769 | static int __init ipv6_packet_init(void) | 770 | static int __init ipv6_packet_init(void) |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index f08d34491ece..6242682be876 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -47,17 +47,11 @@ | |||
47 | #include <net/inet_ecn.h> | 47 | #include <net/inet_ecn.h> |
48 | #include <net/dst_metadata.h> | 48 | #include <net/dst_metadata.h> |
49 | 49 | ||
50 | int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) | 50 | static void ip6_rcv_finish_core(struct net *net, struct sock *sk, |
51 | struct sk_buff *skb) | ||
51 | { | 52 | { |
52 | void (*edemux)(struct sk_buff *skb); | 53 | void (*edemux)(struct sk_buff *skb); |
53 | 54 | ||
54 | /* if ingress device is enslaved to an L3 master device pass the | ||
55 | * skb to its handler for processing | ||
56 | */ | ||
57 | skb = l3mdev_ip6_rcv(skb); | ||
58 | if (!skb) | ||
59 | return NET_RX_SUCCESS; | ||
60 | |||
61 | if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) { | 55 | if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) { |
62 | const struct inet6_protocol *ipprot; | 56 | const struct inet6_protocol *ipprot; |
63 | 57 | ||
@@ -67,20 +61,73 @@ int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) | |||
67 | } | 61 | } |
68 | if (!skb_valid_dst(skb)) | 62 | if (!skb_valid_dst(skb)) |
69 | ip6_route_input(skb); | 63 | ip6_route_input(skb); |
64 | } | ||
65 | |||
66 | int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) | ||
67 | { | ||
68 | /* if ingress device is enslaved to an L3 master device pass the | ||
69 | * skb to its handler for processing | ||
70 | */ | ||
71 | skb = l3mdev_ip6_rcv(skb); | ||
72 | if (!skb) | ||
73 | return NET_RX_SUCCESS; | ||
74 | ip6_rcv_finish_core(net, sk, skb); | ||
70 | 75 | ||
71 | return dst_input(skb); | 76 | return dst_input(skb); |
72 | } | 77 | } |
73 | 78 | ||
74 | int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) | 79 | static void ip6_sublist_rcv_finish(struct list_head *head) |
80 | { | ||
81 | struct sk_buff *skb, *next; | ||
82 | |||
83 | list_for_each_entry_safe(skb, next, head, list) | ||
84 | dst_input(skb); | ||
85 | } | ||
86 | |||
87 | static void ip6_list_rcv_finish(struct net *net, struct sock *sk, | ||
88 | struct list_head *head) | ||
89 | { | ||
90 | struct dst_entry *curr_dst = NULL; | ||
91 | struct sk_buff *skb, *next; | ||
92 | struct list_head sublist; | ||
93 | |||
94 | INIT_LIST_HEAD(&sublist); | ||
95 | list_for_each_entry_safe(skb, next, head, list) { | ||
96 | struct dst_entry *dst; | ||
97 | |||
98 | list_del(&skb->list); | ||
99 | /* if ingress device is enslaved to an L3 master device pass the | ||
100 | * skb to its handler for processing | ||
101 | */ | ||
102 | skb = l3mdev_ip6_rcv(skb); | ||
103 | if (!skb) | ||
104 | continue; | ||
105 | ip6_rcv_finish_core(net, sk, skb); | ||
106 | dst = skb_dst(skb); | ||
107 | if (curr_dst != dst) { | ||
108 | /* dispatch old sublist */ | ||
109 | if (!list_empty(&sublist)) | ||
110 | ip6_sublist_rcv_finish(&sublist); | ||
111 | /* start new sublist */ | ||
112 | INIT_LIST_HEAD(&sublist); | ||
113 | curr_dst = dst; | ||
114 | } | ||
115 | list_add_tail(&skb->list, &sublist); | ||
116 | } | ||
117 | /* dispatch final sublist */ | ||
118 | ip6_sublist_rcv_finish(&sublist); | ||
119 | } | ||
120 | |||
121 | static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, | ||
122 | struct net *net) | ||
75 | { | 123 | { |
76 | const struct ipv6hdr *hdr; | 124 | const struct ipv6hdr *hdr; |
77 | u32 pkt_len; | 125 | u32 pkt_len; |
78 | struct inet6_dev *idev; | 126 | struct inet6_dev *idev; |
79 | struct net *net = dev_net(skb->dev); | ||
80 | 127 | ||
81 | if (skb->pkt_type == PACKET_OTHERHOST) { | 128 | if (skb->pkt_type == PACKET_OTHERHOST) { |
82 | kfree_skb(skb); | 129 | kfree_skb(skb); |
83 | return NET_RX_DROP; | 130 | return NULL; |
84 | } | 131 | } |
85 | 132 | ||
86 | rcu_read_lock(); | 133 | rcu_read_lock(); |
@@ -196,7 +243,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
196 | if (ipv6_parse_hopopts(skb) < 0) { | 243 | if (ipv6_parse_hopopts(skb) < 0) { |
197 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); | 244 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
198 | rcu_read_unlock(); | 245 | rcu_read_unlock(); |
199 | return NET_RX_DROP; | 246 | return NULL; |
200 | } | 247 | } |
201 | } | 248 | } |
202 | 249 | ||
@@ -205,15 +252,67 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
205 | /* Must drop socket now because of tproxy. */ | 252 | /* Must drop socket now because of tproxy. */ |
206 | skb_orphan(skb); | 253 | skb_orphan(skb); |
207 | 254 | ||
208 | return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, | 255 | return skb; |
209 | net, NULL, skb, dev, NULL, | ||
210 | ip6_rcv_finish); | ||
211 | err: | 256 | err: |
212 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); | 257 | __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); |
213 | drop: | 258 | drop: |
214 | rcu_read_unlock(); | 259 | rcu_read_unlock(); |
215 | kfree_skb(skb); | 260 | kfree_skb(skb); |
216 | return NET_RX_DROP; | 261 | return NULL; |
262 | } | ||
263 | |||
264 | int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) | ||
265 | { | ||
266 | struct net *net = dev_net(skb->dev); | ||
267 | |||
268 | skb = ip6_rcv_core(skb, dev, net); | ||
269 | if (skb == NULL) | ||
270 | return NET_RX_DROP; | ||
271 | return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, | ||
272 | net, NULL, skb, dev, NULL, | ||
273 | ip6_rcv_finish); | ||
274 | } | ||
275 | |||
276 | static void ip6_sublist_rcv(struct list_head *head, struct net_device *dev, | ||
277 | struct net *net) | ||
278 | { | ||
279 | NF_HOOK_LIST(NFPROTO_IPV6, NF_INET_PRE_ROUTING, net, NULL, | ||
280 | head, dev, NULL, ip6_rcv_finish); | ||
281 | ip6_list_rcv_finish(net, NULL, head); | ||
282 | } | ||
283 | |||
284 | /* Receive a list of IPv6 packets */ | ||
285 | void ipv6_list_rcv(struct list_head *head, struct packet_type *pt, | ||
286 | struct net_device *orig_dev) | ||
287 | { | ||
288 | struct net_device *curr_dev = NULL; | ||
289 | struct net *curr_net = NULL; | ||
290 | struct sk_buff *skb, *next; | ||
291 | struct list_head sublist; | ||
292 | |||
293 | INIT_LIST_HEAD(&sublist); | ||
294 | list_for_each_entry_safe(skb, next, head, list) { | ||
295 | struct net_device *dev = skb->dev; | ||
296 | struct net *net = dev_net(dev); | ||
297 | |||
298 | list_del(&skb->list); | ||
299 | skb = ip6_rcv_core(skb, dev, net); | ||
300 | if (skb == NULL) | ||
301 | continue; | ||
302 | |||
303 | if (curr_dev != dev || curr_net != net) { | ||
304 | /* dispatch old sublist */ | ||
305 | if (!list_empty(&sublist)) | ||
306 | ip6_sublist_rcv(&sublist, curr_dev, curr_net); | ||
307 | /* start new sublist */ | ||
308 | INIT_LIST_HEAD(&sublist); | ||
309 | curr_dev = dev; | ||
310 | curr_net = net; | ||
311 | } | ||
312 | list_add_tail(&skb->list, &sublist); | ||
313 | } | ||
314 | /* dispatch final sublist */ | ||
315 | ip6_sublist_rcv(&sublist, curr_dev, curr_net); | ||
217 | } | 316 | } |
218 | 317 | ||
219 | /* | 318 | /* |