e1000: fix concurrent accesses to PHY from watchdog and ethtool
[firefly-linux-kernel-4.4.55.git] / net / ipv6 / netfilter / nf_conntrack_l3proto_ipv6.c
1 /*
2  * Copyright (C)2004 USAGI/WIDE Project
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * Author:
9  *      Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
10  */
11
12 #include <linux/types.h>
13 #include <linux/ipv6.h>
14 #include <linux/in6.h>
15 #include <linux/netfilter.h>
16 #include <linux/module.h>
17 #include <linux/skbuff.h>
18 #include <linux/icmp.h>
19 #include <net/ipv6.h>
20 #include <net/inet_frag.h>
21
22 #include <linux/netfilter_bridge.h>
23 #include <linux/netfilter_ipv6.h>
24 #include <net/netfilter/nf_conntrack.h>
25 #include <net/netfilter/nf_conntrack_helper.h>
26 #include <net/netfilter/nf_conntrack_l4proto.h>
27 #include <net/netfilter/nf_conntrack_l3proto.h>
28 #include <net/netfilter/nf_conntrack_core.h>
29 #include <net/netfilter/nf_conntrack_zones.h>
30 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
31 #include <net/netfilter/nf_nat_helper.h>
32 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
33 #include <net/netfilter/nf_log.h>
34
35 static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
36                               struct nf_conntrack_tuple *tuple)
37 {
38         const u_int32_t *ap;
39         u_int32_t _addrs[8];
40
41         ap = skb_header_pointer(skb, nhoff + offsetof(struct ipv6hdr, saddr),
42                                 sizeof(_addrs), _addrs);
43         if (ap == NULL)
44                 return false;
45
46         memcpy(tuple->src.u3.ip6, ap, sizeof(tuple->src.u3.ip6));
47         memcpy(tuple->dst.u3.ip6, ap + 4, sizeof(tuple->dst.u3.ip6));
48
49         return true;
50 }
51
52 static bool ipv6_invert_tuple(struct nf_conntrack_tuple *tuple,
53                               const struct nf_conntrack_tuple *orig)
54 {
55         memcpy(tuple->src.u3.ip6, orig->dst.u3.ip6, sizeof(tuple->src.u3.ip6));
56         memcpy(tuple->dst.u3.ip6, orig->src.u3.ip6, sizeof(tuple->dst.u3.ip6));
57
58         return true;
59 }
60
61 static int ipv6_print_tuple(struct seq_file *s,
62                             const struct nf_conntrack_tuple *tuple)
63 {
64         return seq_printf(s, "src=%pI6 dst=%pI6 ",
65                           tuple->src.u3.ip6, tuple->dst.u3.ip6);
66 }
67
68 static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
69                             unsigned int *dataoff, u_int8_t *protonum)
70 {
71         unsigned int extoff = nhoff + sizeof(struct ipv6hdr);
72         __be16 frag_off;
73         int protoff;
74         u8 nexthdr;
75
76         if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr),
77                           &nexthdr, sizeof(nexthdr)) != 0) {
78                 pr_debug("ip6_conntrack_core: can't get nexthdr\n");
79                 return -NF_ACCEPT;
80         }
81         protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off);
82         /*
83          * (protoff == skb->len) mean that the packet doesn't have no data
84          * except of IPv6 & ext headers. but it's tracked anyway. - YK
85          */
86         if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
87                 pr_debug("ip6_conntrack_core: can't find proto in pkt\n");
88                 return -NF_ACCEPT;
89         }
90
91         *dataoff = protoff;
92         *protonum = nexthdr;
93         return NF_ACCEPT;
94 }
95
96 static unsigned int ipv6_helper(unsigned int hooknum,
97                                 struct sk_buff *skb,
98                                 const struct net_device *in,
99                                 const struct net_device *out,
100                                 int (*okfn)(struct sk_buff *))
101 {
102         struct nf_conn *ct;
103         const struct nf_conn_help *help;
104         const struct nf_conntrack_helper *helper;
105         enum ip_conntrack_info ctinfo;
106         unsigned int ret;
107         __be16 frag_off;
108         int protoff;
109         u8 nexthdr;
110
111         /* This is where we call the helper: as the packet goes out. */
112         ct = nf_ct_get(skb, &ctinfo);
113         if (!ct || ctinfo == IP_CT_RELATED_REPLY)
114                 return NF_ACCEPT;
115
116         help = nfct_help(ct);
117         if (!help)
118                 return NF_ACCEPT;
119         /* rcu_read_lock()ed by nf_hook_slow */
120         helper = rcu_dereference(help->helper);
121         if (!helper)
122                 return NF_ACCEPT;
123
124         nexthdr = ipv6_hdr(skb)->nexthdr;
125         protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
126                                    &frag_off);
127         if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
128                 pr_debug("proto header not found\n");
129                 return NF_ACCEPT;
130         }
131
132         ret = helper->help(skb, protoff, ct, ctinfo);
133         if (ret != NF_ACCEPT && (ret & NF_VERDICT_MASK) != NF_QUEUE) {
134                 nf_log_packet(NFPROTO_IPV6, hooknum, skb, in, out, NULL,
135                               "nf_ct_%s: dropping packet", helper->name);
136         }
137         return ret;
138 }
139
140 static unsigned int ipv6_confirm(unsigned int hooknum,
141                                  struct sk_buff *skb,
142                                  const struct net_device *in,
143                                  const struct net_device *out,
144                                  int (*okfn)(struct sk_buff *))
145 {
146         struct nf_conn *ct;
147         enum ip_conntrack_info ctinfo;
148         unsigned char pnum = ipv6_hdr(skb)->nexthdr;
149         int protoff;
150         __be16 frag_off;
151
152         ct = nf_ct_get(skb, &ctinfo);
153         if (!ct || ctinfo == IP_CT_RELATED_REPLY)
154                 goto out;
155
156         protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum,
157                                    &frag_off);
158         if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
159                 pr_debug("proto header not found\n");
160                 goto out;
161         }
162
163         /* adjust seqs for loopback traffic only in outgoing direction */
164         if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
165             !nf_is_loopback_packet(skb)) {
166                 typeof(nf_nat_seq_adjust_hook) seq_adjust;
167
168                 seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
169                 if (!seq_adjust ||
170                     !seq_adjust(skb, ct, ctinfo, protoff)) {
171                         NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
172                         return NF_DROP;
173                 }
174         }
175 out:
176         /* We've seen it coming out the other side: confirm it */
177         return nf_conntrack_confirm(skb);
178 }
179
180 static unsigned int __ipv6_conntrack_in(struct net *net,
181                                         unsigned int hooknum,
182                                         struct sk_buff *skb,
183                                         const struct net_device *in,
184                                         const struct net_device *out,
185                                         int (*okfn)(struct sk_buff *))
186 {
187         struct sk_buff *reasm = skb->nfct_reasm;
188         const struct nf_conn_help *help;
189         struct nf_conn *ct;
190         enum ip_conntrack_info ctinfo;
191
192         /* This packet is fragmented and has reassembled packet. */
193         if (reasm) {
194                 /* Reassembled packet isn't parsed yet ? */
195                 if (!reasm->nfct) {
196                         unsigned int ret;
197
198                         ret = nf_conntrack_in(net, PF_INET6, hooknum, reasm);
199                         if (ret != NF_ACCEPT)
200                                 return ret;
201                 }
202
203                 /* Conntrack helpers need the entire reassembled packet in the
204                  * POST_ROUTING hook. In case of unconfirmed connections NAT
205                  * might reassign a helper, so the entire packet is also
206                  * required.
207                  */
208                 ct = nf_ct_get(reasm, &ctinfo);
209                 if (ct != NULL && !nf_ct_is_untracked(ct)) {
210                         help = nfct_help(ct);
211                         if ((help && help->helper) || !nf_ct_is_confirmed(ct)) {
212                                 nf_conntrack_get_reasm(skb);
213                                 NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
214                                                (struct net_device *)in,
215                                                (struct net_device *)out,
216                                                okfn, NF_IP6_PRI_CONNTRACK + 1);
217                                 return NF_DROP_ERR(-ECANCELED);
218                         }
219                 }
220
221                 nf_conntrack_get(reasm->nfct);
222                 skb->nfct = reasm->nfct;
223                 skb->nfctinfo = reasm->nfctinfo;
224                 return NF_ACCEPT;
225         }
226
227         return nf_conntrack_in(net, PF_INET6, hooknum, skb);
228 }
229
230 static unsigned int ipv6_conntrack_in(unsigned int hooknum,
231                                       struct sk_buff *skb,
232                                       const struct net_device *in,
233                                       const struct net_device *out,
234                                       int (*okfn)(struct sk_buff *))
235 {
236         return __ipv6_conntrack_in(dev_net(in), hooknum, skb, in, out, okfn);
237 }
238
239 static unsigned int ipv6_conntrack_local(unsigned int hooknum,
240                                          struct sk_buff *skb,
241                                          const struct net_device *in,
242                                          const struct net_device *out,
243                                          int (*okfn)(struct sk_buff *))
244 {
245         /* root is playing with raw sockets. */
246         if (skb->len < sizeof(struct ipv6hdr)) {
247                 net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
248                 return NF_ACCEPT;
249         }
250         return __ipv6_conntrack_in(dev_net(out), hooknum, skb, in, out, okfn);
251 }
252
253 static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
254         {
255                 .hook           = ipv6_conntrack_in,
256                 .owner          = THIS_MODULE,
257                 .pf             = NFPROTO_IPV6,
258                 .hooknum        = NF_INET_PRE_ROUTING,
259                 .priority       = NF_IP6_PRI_CONNTRACK,
260         },
261         {
262                 .hook           = ipv6_conntrack_local,
263                 .owner          = THIS_MODULE,
264                 .pf             = NFPROTO_IPV6,
265                 .hooknum        = NF_INET_LOCAL_OUT,
266                 .priority       = NF_IP6_PRI_CONNTRACK,
267         },
268         {
269                 .hook           = ipv6_helper,
270                 .owner          = THIS_MODULE,
271                 .pf             = NFPROTO_IPV6,
272                 .hooknum        = NF_INET_POST_ROUTING,
273                 .priority       = NF_IP6_PRI_CONNTRACK_HELPER,
274         },
275         {
276                 .hook           = ipv6_confirm,
277                 .owner          = THIS_MODULE,
278                 .pf             = NFPROTO_IPV6,
279                 .hooknum        = NF_INET_POST_ROUTING,
280                 .priority       = NF_IP6_PRI_LAST,
281         },
282         {
283                 .hook           = ipv6_helper,
284                 .owner          = THIS_MODULE,
285                 .pf             = NFPROTO_IPV6,
286                 .hooknum        = NF_INET_LOCAL_IN,
287                 .priority       = NF_IP6_PRI_CONNTRACK_HELPER,
288         },
289         {
290                 .hook           = ipv6_confirm,
291                 .owner          = THIS_MODULE,
292                 .pf             = NFPROTO_IPV6,
293                 .hooknum        = NF_INET_LOCAL_IN,
294                 .priority       = NF_IP6_PRI_LAST-1,
295         },
296 };
297
298 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
299
300 #include <linux/netfilter/nfnetlink.h>
301 #include <linux/netfilter/nfnetlink_conntrack.h>
302
303 static int ipv6_tuple_to_nlattr(struct sk_buff *skb,
304                                 const struct nf_conntrack_tuple *tuple)
305 {
306         if (nla_put(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4,
307                     &tuple->src.u3.ip6) ||
308             nla_put(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4,
309                     &tuple->dst.u3.ip6))
310                 goto nla_put_failure;
311         return 0;
312
313 nla_put_failure:
314         return -1;
315 }
316
317 static const struct nla_policy ipv6_nla_policy[CTA_IP_MAX+1] = {
318         [CTA_IP_V6_SRC] = { .len = sizeof(u_int32_t)*4 },
319         [CTA_IP_V6_DST] = { .len = sizeof(u_int32_t)*4 },
320 };
321
322 static int ipv6_nlattr_to_tuple(struct nlattr *tb[],
323                                 struct nf_conntrack_tuple *t)
324 {
325         if (!tb[CTA_IP_V6_SRC] || !tb[CTA_IP_V6_DST])
326                 return -EINVAL;
327
328         memcpy(&t->src.u3.ip6, nla_data(tb[CTA_IP_V6_SRC]),
329                sizeof(u_int32_t) * 4);
330         memcpy(&t->dst.u3.ip6, nla_data(tb[CTA_IP_V6_DST]),
331                sizeof(u_int32_t) * 4);
332
333         return 0;
334 }
335
336 static int ipv6_nlattr_tuple_size(void)
337 {
338         return nla_policy_len(ipv6_nla_policy, CTA_IP_MAX + 1);
339 }
340 #endif
341
342 struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = {
343         .l3proto                = PF_INET6,
344         .name                   = "ipv6",
345         .pkt_to_tuple           = ipv6_pkt_to_tuple,
346         .invert_tuple           = ipv6_invert_tuple,
347         .print_tuple            = ipv6_print_tuple,
348         .get_l4proto            = ipv6_get_l4proto,
349 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
350         .tuple_to_nlattr        = ipv6_tuple_to_nlattr,
351         .nlattr_tuple_size      = ipv6_nlattr_tuple_size,
352         .nlattr_to_tuple        = ipv6_nlattr_to_tuple,
353         .nla_policy             = ipv6_nla_policy,
354 #endif
355         .me                     = THIS_MODULE,
356 };
357
358 MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
359 MODULE_LICENSE("GPL");
360 MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
361
362 static int ipv6_net_init(struct net *net)
363 {
364         int ret = 0;
365
366         ret = nf_conntrack_l4proto_register(net,
367                                             &nf_conntrack_l4proto_tcp6);
368         if (ret < 0) {
369                 printk(KERN_ERR "nf_conntrack_l4proto_tcp6: protocol register failed\n");
370                 goto out;
371         }
372         ret = nf_conntrack_l4proto_register(net,
373                                             &nf_conntrack_l4proto_udp6);
374         if (ret < 0) {
375                 printk(KERN_ERR "nf_conntrack_l4proto_udp6: protocol register failed\n");
376                 goto cleanup_tcp6;
377         }
378         ret = nf_conntrack_l4proto_register(net,
379                                             &nf_conntrack_l4proto_icmpv6);
380         if (ret < 0) {
381                 printk(KERN_ERR "nf_conntrack_l4proto_icmp6: protocol register failed\n");
382                 goto cleanup_udp6;
383         }
384         ret = nf_conntrack_l3proto_register(net,
385                                             &nf_conntrack_l3proto_ipv6);
386         if (ret < 0) {
387                 printk(KERN_ERR "nf_conntrack_l3proto_ipv6: protocol register failed\n");
388                 goto cleanup_icmpv6;
389         }
390         return 0;
391  cleanup_icmpv6:
392         nf_conntrack_l4proto_unregister(net,
393                                         &nf_conntrack_l4proto_icmpv6);
394  cleanup_udp6:
395         nf_conntrack_l4proto_unregister(net,
396                                         &nf_conntrack_l4proto_udp6);
397  cleanup_tcp6:
398         nf_conntrack_l4proto_unregister(net,
399                                         &nf_conntrack_l4proto_tcp6);
400  out:
401         return ret;
402 }
403
404 static void ipv6_net_exit(struct net *net)
405 {
406         nf_conntrack_l3proto_unregister(net,
407                                         &nf_conntrack_l3proto_ipv6);
408         nf_conntrack_l4proto_unregister(net,
409                                         &nf_conntrack_l4proto_icmpv6);
410         nf_conntrack_l4proto_unregister(net,
411                                         &nf_conntrack_l4proto_udp6);
412         nf_conntrack_l4proto_unregister(net,
413                                         &nf_conntrack_l4proto_tcp6);
414 }
415
416 static struct pernet_operations ipv6_net_ops = {
417         .init = ipv6_net_init,
418         .exit = ipv6_net_exit,
419 };
420
421 static int __init nf_conntrack_l3proto_ipv6_init(void)
422 {
423         int ret = 0;
424
425         need_conntrack();
426         nf_defrag_ipv6_enable();
427
428         ret = register_pernet_subsys(&ipv6_net_ops);
429         if (ret < 0)
430                 goto cleanup_pernet;
431         ret = nf_register_hooks(ipv6_conntrack_ops,
432                                 ARRAY_SIZE(ipv6_conntrack_ops));
433         if (ret < 0) {
434                 pr_err("nf_conntrack_ipv6: can't register pre-routing defrag "
435                        "hook.\n");
436                 goto cleanup_ipv6;
437         }
438         return ret;
439
440  cleanup_ipv6:
441         unregister_pernet_subsys(&ipv6_net_ops);
442  cleanup_pernet:
443         return ret;
444 }
445
446 static void __exit nf_conntrack_l3proto_ipv6_fini(void)
447 {
448         synchronize_net();
449         nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
450         unregister_pernet_subsys(&ipv6_net_ops);
451 }
452
453 module_init(nf_conntrack_l3proto_ipv6_init);
454 module_exit(nf_conntrack_l3proto_ipv6_fini);