summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ipv6.h2
-rw-r--r--net/ipv4/ip_input.c23
-rw-r--r--net/ipv6/af_inet6.c1
-rw-r--r--net/ipv6/ip6_input.c131
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
923int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, 923int 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);
925void ipv6_list_rcv(struct list_head *head, struct packet_type *pt,
926 struct net_device *orig_dev);
925 927
926int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb); 928int 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
409static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 402static 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);
764static struct packet_type ipv6_packet_type __read_mostly = { 764static 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
769static int __init ipv6_packet_init(void) 770static 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
50int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 50static 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
66int 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
74int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) 79static 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
87static 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
121static 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);
211err: 256err:
212 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 257 __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
213drop: 258drop:
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
264int 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
276static 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 */
285void 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/*