[NETFILTER]: Fix recent match jiffies wrap mismatches
[safe/jmp/linux-2.6] / net / ipv4 / netfilter / ip_conntrack_netlink.c
1 /* Connection tracking via netlink socket. Allows for user space
2  * protocol helpers and general trouble making from userspace.
3  *
4  * (C) 2001 by Jay Schulist <jschlst@samba.org>
5  * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
6  * (C) 2003 by Patrick Mchardy <kaber@trash.net>
7  * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
8  *
9  * I've reworked this stuff to use attributes instead of conntrack 
10  * structures. 5.44 am. I need more tea. --pablo 05/07/11.
11  *
12  * Initial connection tracking via netlink development funded and 
13  * generally made possible by Network Robots, Inc. (www.networkrobots.com)
14  *
15  * Further development of this code funded by Astaro AG (http://www.astaro.com)
16  *
17  * This software may be used and distributed according to the terms
18  * of the GNU General Public License, incorporated herein by reference.
19  */
20
21 #include <linux/init.h>
22 #include <linux/module.h>
23 #include <linux/kernel.h>
24 #include <linux/types.h>
25 #include <linux/timer.h>
26 #include <linux/skbuff.h>
27 #include <linux/errno.h>
28 #include <linux/netlink.h>
29 #include <linux/spinlock.h>
30 #include <linux/interrupt.h>
31 #include <linux/notifier.h>
32
33 #include <linux/netfilter.h>
34 #include <linux/netfilter_ipv4/ip_conntrack.h>
35 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
36 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
37 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
38 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
39
40 #include <linux/netfilter/nfnetlink.h>
41 #include <linux/netfilter/nfnetlink_conntrack.h>
42
43 MODULE_LICENSE("GPL");
44
45 static char __initdata version[] = "0.90";
46
47 #if 0
48 #define DEBUGP printk
49 #else
50 #define DEBUGP(format, args...)
51 #endif
52
53
54 static inline int
55 ctnetlink_dump_tuples_proto(struct sk_buff *skb, 
56                             const struct ip_conntrack_tuple *tuple)
57 {
58         struct ip_conntrack_protocol *proto;
59         int ret = 0;
60
61         NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);
62
63         /* If no protocol helper is found, this function will return the
64          * generic protocol helper, so proto won't *ever* be NULL */
65         proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
66         if (likely(proto->tuple_to_nfattr))
67                 ret = proto->tuple_to_nfattr(skb, tuple);
68         
69         ip_conntrack_proto_put(proto);
70
71         return ret;
72
73 nfattr_failure:
74         return -1;
75 }
76
77 static inline int
78 ctnetlink_dump_tuples(struct sk_buff *skb, 
79                       const struct ip_conntrack_tuple *tuple)
80 {
81         struct nfattr *nest_parms;
82         
83         nest_parms = NFA_NEST(skb, CTA_TUPLE_IP);
84         NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip);
85         NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip);
86         NFA_NEST_END(skb, nest_parms);
87
88         nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO);
89         ctnetlink_dump_tuples_proto(skb, tuple);
90         NFA_NEST_END(skb, nest_parms);
91
92         return 0;
93
94 nfattr_failure:
95         return -1;
96 }
97
98 static inline int
99 ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct)
100 {
101         u_int32_t status = htonl((u_int32_t) ct->status);
102         NFA_PUT(skb, CTA_STATUS, sizeof(status), &status);
103         return 0;
104
105 nfattr_failure:
106         return -1;
107 }
108
109 static inline int
110 ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct)
111 {
112         long timeout_l = ct->timeout.expires - jiffies;
113         u_int32_t timeout;
114
115         if (timeout_l < 0)
116                 timeout = 0;
117         else
118                 timeout = htonl(timeout_l / HZ);
119         
120         NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout);
121         return 0;
122
123 nfattr_failure:
124         return -1;
125 }
126
127 static inline int
128 ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
129 {
130         struct ip_conntrack_protocol *proto = ip_conntrack_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
131
132         struct nfattr *nest_proto;
133         int ret;
134
135         if (!proto->to_nfattr) {
136                 ip_conntrack_proto_put(proto);
137                 return 0;
138         }
139         
140         nest_proto = NFA_NEST(skb, CTA_PROTOINFO);
141
142         ret = proto->to_nfattr(skb, nest_proto, ct);
143
144         ip_conntrack_proto_put(proto);
145
146         NFA_NEST_END(skb, nest_proto);
147
148         return ret;
149
150 nfattr_failure:
151         return -1;
152 }
153
154 static inline int
155 ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
156 {
157         struct nfattr *nest_helper;
158
159         if (!ct->helper)
160                 return 0;
161                 
162         nest_helper = NFA_NEST(skb, CTA_HELP);
163         NFA_PUT(skb, CTA_HELP_NAME, CTA_HELP_MAXNAMESIZE, &ct->helper->name);
164
165         if (ct->helper->to_nfattr)
166                 ct->helper->to_nfattr(skb, ct);
167
168         NFA_NEST_END(skb, nest_helper);
169
170         return 0;
171
172 nfattr_failure:
173         return -1;
174 }
175
176 #ifdef CONFIG_IP_NF_CT_ACCT
177 static inline int
178 ctnetlink_dump_counters(struct sk_buff *skb, const struct ip_conntrack *ct,
179                         enum ip_conntrack_dir dir)
180 {
181         enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
182         struct nfattr *nest_count = NFA_NEST(skb, type);
183         u_int32_t tmp;
184
185         tmp = htonl(ct->counters[dir].packets);
186         NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);
187
188         tmp = htonl(ct->counters[dir].bytes);
189         NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp);
190
191         NFA_NEST_END(skb, nest_count);
192
193         return 0;
194
195 nfattr_failure:
196         return -1;
197 }
198 #else
199 #define ctnetlink_dump_counters(a, b, c) (0)
200 #endif
201
202 #ifdef CONFIG_IP_NF_CONNTRACK_MARK
203 static inline int
204 ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct)
205 {
206         u_int32_t mark = htonl(ct->mark);
207
208         NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark);
209         return 0;
210
211 nfattr_failure:
212         return -1;
213 }
214 #else
215 #define ctnetlink_dump_mark(a, b) (0)
216 #endif
217
218 static inline int
219 ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct)
220 {
221         u_int32_t id = htonl(ct->id);
222         NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id);
223         return 0;
224
225 nfattr_failure:
226         return -1;
227 }
228
229 static inline int
230 ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct)
231 {
232         unsigned int use = htonl(atomic_read(&ct->ct_general.use));
233         
234         NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use);
235         return 0;
236
237 nfattr_failure:
238         return -1;
239 }
240
241 #define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple)
242
243 static int
244 ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
245                     int event, int nowait, 
246                     const struct ip_conntrack *ct)
247 {
248         struct nlmsghdr *nlh;
249         struct nfgenmsg *nfmsg;
250         struct nfattr *nest_parms;
251         unsigned char *b;
252
253         b = skb->tail;
254
255         event |= NFNL_SUBSYS_CTNETLINK << 8;
256         nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
257         nfmsg  = NLMSG_DATA(nlh);
258
259         nlh->nlmsg_flags    = (nowait && pid) ? NLM_F_MULTI : 0;
260         nfmsg->nfgen_family = AF_INET;
261         nfmsg->version      = NFNETLINK_V0;
262         nfmsg->res_id       = 0;
263
264         nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);
265         if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
266                 goto nfattr_failure;
267         NFA_NEST_END(skb, nest_parms);
268         
269         nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);
270         if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)
271                 goto nfattr_failure;
272         NFA_NEST_END(skb, nest_parms);
273
274         if (ctnetlink_dump_status(skb, ct) < 0 ||
275             ctnetlink_dump_timeout(skb, ct) < 0 ||
276             ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
277             ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 ||
278             ctnetlink_dump_protoinfo(skb, ct) < 0 ||
279             ctnetlink_dump_helpinfo(skb, ct) < 0 ||
280             ctnetlink_dump_mark(skb, ct) < 0 ||
281             ctnetlink_dump_id(skb, ct) < 0 ||
282             ctnetlink_dump_use(skb, ct) < 0)
283                 goto nfattr_failure;
284
285         nlh->nlmsg_len = skb->tail - b;
286         return skb->len;
287
288 nlmsg_failure:
289 nfattr_failure:
290         skb_trim(skb, b - skb->data);
291         return -1;
292 }
293
294 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
295 static int ctnetlink_conntrack_event(struct notifier_block *this,
296                                      unsigned long events, void *ptr)
297 {
298         struct nlmsghdr *nlh;
299         struct nfgenmsg *nfmsg;
300         struct nfattr *nest_parms;
301         struct ip_conntrack *ct = (struct ip_conntrack *)ptr;
302         struct sk_buff *skb;
303         unsigned int type;
304         unsigned char *b;
305         unsigned int flags = 0, group;
306
307         /* ignore our fake conntrack entry */
308         if (ct == &ip_conntrack_untracked)
309                 return NOTIFY_DONE;
310
311         if (events & IPCT_DESTROY) {
312                 type = IPCTNL_MSG_CT_DELETE;
313                 group = NFNLGRP_CONNTRACK_DESTROY;
314                 goto alloc_skb;
315         }
316         if (events & (IPCT_NEW | IPCT_RELATED)) {
317                 type = IPCTNL_MSG_CT_NEW;
318                 flags = NLM_F_CREATE|NLM_F_EXCL;
319                 /* dump everything */
320                 events = ~0UL;
321                 group = NFNLGRP_CONNTRACK_NEW;
322                 goto alloc_skb;
323         }
324         if (events & (IPCT_STATUS |
325                       IPCT_PROTOINFO |
326                       IPCT_HELPER |
327                       IPCT_HELPINFO |
328                       IPCT_NATINFO)) {
329                 type = IPCTNL_MSG_CT_NEW;
330                 group = NFNLGRP_CONNTRACK_UPDATE;
331                 goto alloc_skb;
332         } 
333         
334         return NOTIFY_DONE;
335
336 alloc_skb:
337   /* FIXME: Check if there are any listeners before, don't hurt performance */
338         
339         skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
340         if (!skb)
341                 return NOTIFY_DONE;
342
343         b = skb->tail;
344
345         type |= NFNL_SUBSYS_CTNETLINK << 8;
346         nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
347         nfmsg = NLMSG_DATA(nlh);
348
349         nlh->nlmsg_flags    = flags;
350         nfmsg->nfgen_family = AF_INET;
351         nfmsg->version  = NFNETLINK_V0;
352         nfmsg->res_id   = 0;
353
354         nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);
355         if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
356                 goto nfattr_failure;
357         NFA_NEST_END(skb, nest_parms);
358         
359         nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);
360         if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)
361                 goto nfattr_failure;
362         NFA_NEST_END(skb, nest_parms);
363         
364         /* NAT stuff is now a status flag */
365         if ((events & IPCT_STATUS || events & IPCT_NATINFO)
366             && ctnetlink_dump_status(skb, ct) < 0)
367                 goto nfattr_failure;
368         if (events & IPCT_REFRESH
369             && ctnetlink_dump_timeout(skb, ct) < 0)
370                 goto nfattr_failure;
371         if (events & IPCT_PROTOINFO
372             && ctnetlink_dump_protoinfo(skb, ct) < 0)
373                 goto nfattr_failure;
374         if (events & IPCT_HELPINFO
375             && ctnetlink_dump_helpinfo(skb, ct) < 0)
376                 goto nfattr_failure;
377
378         if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
379             ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
380                 goto nfattr_failure;
381
382         nlh->nlmsg_len = skb->tail - b;
383         nfnetlink_send(skb, 0, group, 0);
384         return NOTIFY_DONE;
385
386 nlmsg_failure:
387 nfattr_failure:
388         kfree_skb(skb);
389         return NOTIFY_DONE;
390 }
391 #endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
392
393 static int ctnetlink_done(struct netlink_callback *cb)
394 {
395         DEBUGP("entered %s\n", __FUNCTION__);
396         return 0;
397 }
398
399 static int
400 ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
401 {
402         struct ip_conntrack *ct = NULL;
403         struct ip_conntrack_tuple_hash *h;
404         struct list_head *i;
405         u_int32_t *id = (u_int32_t *) &cb->args[1];
406
407         DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__, 
408                         cb->args[0], *id);
409
410         read_lock_bh(&ip_conntrack_lock);
411         for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {
412                 list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {
413                         h = (struct ip_conntrack_tuple_hash *) i;
414                         if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
415                                 continue;
416                         ct = tuplehash_to_ctrack(h);
417                         if (ct->id <= *id)
418                                 continue;
419                         if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
420                                                 cb->nlh->nlmsg_seq,
421                                                 IPCTNL_MSG_CT_NEW,
422                                                 1, ct) < 0)
423                                 goto out;
424                         *id = ct->id;
425                 }
426         }
427 out:    
428         read_unlock_bh(&ip_conntrack_lock);
429
430         DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
431
432         return skb->len;
433 }
434
435 #ifdef CONFIG_IP_NF_CT_ACCT
436 static int
437 ctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb)
438 {
439         struct ip_conntrack *ct = NULL;
440         struct ip_conntrack_tuple_hash *h;
441         struct list_head *i;
442         u_int32_t *id = (u_int32_t *) &cb->args[1];
443
444         DEBUGP("entered %s, last bucket=%u id=%u\n", __FUNCTION__, 
445                         cb->args[0], *id);
446
447         write_lock_bh(&ip_conntrack_lock);
448         for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {
449                 list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {
450                         h = (struct ip_conntrack_tuple_hash *) i;
451                         if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
452                                 continue;
453                         ct = tuplehash_to_ctrack(h);
454                         if (ct->id <= *id)
455                                 continue;
456                         if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
457                                                 cb->nlh->nlmsg_seq,
458                                                 IPCTNL_MSG_CT_NEW,
459                                                 1, ct) < 0)
460                                 goto out;
461                         *id = ct->id;
462
463                         memset(&ct->counters, 0, sizeof(ct->counters));
464                 }
465         }
466 out:    
467         write_unlock_bh(&ip_conntrack_lock);
468
469         DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
470
471         return skb->len;
472 }
473 #endif
474
475 static const size_t cta_min_ip[CTA_IP_MAX] = {
476         [CTA_IP_V4_SRC-1]       = sizeof(u_int32_t),
477         [CTA_IP_V4_DST-1]       = sizeof(u_int32_t),
478 };
479
480 static inline int
481 ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple)
482 {
483         struct nfattr *tb[CTA_IP_MAX];
484
485         DEBUGP("entered %s\n", __FUNCTION__);
486
487         nfattr_parse_nested(tb, CTA_IP_MAX, attr);
488
489         if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
490                 return -EINVAL;
491
492         if (!tb[CTA_IP_V4_SRC-1])
493                 return -EINVAL;
494         tuple->src.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
495
496         if (!tb[CTA_IP_V4_DST-1])
497                 return -EINVAL;
498         tuple->dst.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
499
500         DEBUGP("leaving\n");
501
502         return 0;
503 }
504
505 static const size_t cta_min_proto[CTA_PROTO_MAX] = {
506         [CTA_PROTO_NUM-1]       = sizeof(u_int16_t),
507         [CTA_PROTO_SRC_PORT-1]  = sizeof(u_int16_t),
508         [CTA_PROTO_DST_PORT-1]  = sizeof(u_int16_t),
509         [CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t),
510         [CTA_PROTO_ICMP_CODE-1] = sizeof(u_int8_t),
511         [CTA_PROTO_ICMP_ID-1]   = sizeof(u_int16_t),
512 };
513
514 static inline int
515 ctnetlink_parse_tuple_proto(struct nfattr *attr, 
516                             struct ip_conntrack_tuple *tuple)
517 {
518         struct nfattr *tb[CTA_PROTO_MAX];
519         struct ip_conntrack_protocol *proto;
520         int ret = 0;
521
522         DEBUGP("entered %s\n", __FUNCTION__);
523
524         nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
525
526         if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
527                 return -EINVAL;
528
529         if (!tb[CTA_PROTO_NUM-1])
530                 return -EINVAL;
531         tuple->dst.protonum = *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]);
532
533         proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
534
535         if (likely(proto->nfattr_to_tuple))
536                 ret = proto->nfattr_to_tuple(tb, tuple);
537         
538         ip_conntrack_proto_put(proto);
539         
540         return ret;
541 }
542
543 static inline int
544 ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple,
545                       enum ctattr_tuple type)
546 {
547         struct nfattr *tb[CTA_TUPLE_MAX];
548         int err;
549
550         DEBUGP("entered %s\n", __FUNCTION__);
551
552         memset(tuple, 0, sizeof(*tuple));
553
554         nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
555
556         if (!tb[CTA_TUPLE_IP-1])
557                 return -EINVAL;
558
559         err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple);
560         if (err < 0)
561                 return err;
562
563         if (!tb[CTA_TUPLE_PROTO-1])
564                 return -EINVAL;
565
566         err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple);
567         if (err < 0)
568                 return err;
569
570         /* orig and expect tuples get DIR_ORIGINAL */
571         if (type == CTA_TUPLE_REPLY)
572                 tuple->dst.dir = IP_CT_DIR_REPLY;
573         else
574                 tuple->dst.dir = IP_CT_DIR_ORIGINAL;
575
576         DUMP_TUPLE(tuple);
577
578         DEBUGP("leaving\n");
579
580         return 0;
581 }
582
583 #ifdef CONFIG_IP_NF_NAT_NEEDED
584 static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = {
585         [CTA_PROTONAT_PORT_MIN-1]       = sizeof(u_int16_t),
586         [CTA_PROTONAT_PORT_MAX-1]       = sizeof(u_int16_t),
587 };
588
589 static int ctnetlink_parse_nat_proto(struct nfattr *attr,
590                                      const struct ip_conntrack *ct,
591                                      struct ip_nat_range *range)
592 {
593         struct nfattr *tb[CTA_PROTONAT_MAX];
594         struct ip_nat_protocol *npt;
595
596         DEBUGP("entered %s\n", __FUNCTION__);
597
598         nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
599
600         if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
601                 return -EINVAL;
602
603         npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
604
605         if (!npt->nfattr_to_range) {
606                 ip_nat_proto_put(npt);
607                 return 0;
608         }
609
610         /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */
611         if (npt->nfattr_to_range(tb, range) > 0)
612                 range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
613
614         ip_nat_proto_put(npt);
615
616         DEBUGP("leaving\n");
617         return 0;
618 }
619
620 static const size_t cta_min_nat[CTA_NAT_MAX] = {
621         [CTA_NAT_MINIP-1]       = sizeof(u_int32_t),
622         [CTA_NAT_MAXIP-1]       = sizeof(u_int32_t),
623 };
624
625 static inline int
626 ctnetlink_parse_nat(struct nfattr *cda[],
627                     const struct ip_conntrack *ct, struct ip_nat_range *range)
628 {
629         struct nfattr *tb[CTA_NAT_MAX];
630         int err;
631
632         DEBUGP("entered %s\n", __FUNCTION__);
633
634         memset(range, 0, sizeof(*range));
635         
636         nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);
637
638         if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))
639                 return -EINVAL;
640
641         if (tb[CTA_NAT_MINIP-1])
642                 range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
643
644         if (!tb[CTA_NAT_MAXIP-1])
645                 range->max_ip = range->min_ip;
646         else
647                 range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);
648
649         if (range->min_ip)
650                 range->flags |= IP_NAT_RANGE_MAP_IPS;
651
652         if (!tb[CTA_NAT_PROTO-1])
653                 return 0;
654
655         err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range);
656         if (err < 0)
657                 return err;
658
659         DEBUGP("leaving\n");
660         return 0;
661 }
662 #endif
663
664 static inline int
665 ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
666 {
667         struct nfattr *tb[CTA_HELP_MAX];
668
669         DEBUGP("entered %s\n", __FUNCTION__);
670
671         nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
672
673         if (!tb[CTA_HELP_NAME-1])
674                 return -EINVAL;
675
676         *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]);
677
678         return 0;
679 }
680
681 static const size_t cta_min[CTA_MAX] = {
682         [CTA_STATUS-1]          = sizeof(u_int32_t),
683         [CTA_TIMEOUT-1]         = sizeof(u_int32_t),
684         [CTA_MARK-1]            = sizeof(u_int32_t),
685         [CTA_USE-1]             = sizeof(u_int32_t),
686         [CTA_ID-1]              = sizeof(u_int32_t)
687 };
688
689 static int
690 ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, 
691                         struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
692 {
693         struct ip_conntrack_tuple_hash *h;
694         struct ip_conntrack_tuple tuple;
695         struct ip_conntrack *ct;
696         int err = 0;
697
698         DEBUGP("entered %s\n", __FUNCTION__);
699
700         if (nfattr_bad_size(cda, CTA_MAX, cta_min))
701                 return -EINVAL;
702
703         if (cda[CTA_TUPLE_ORIG-1])
704                 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
705         else if (cda[CTA_TUPLE_REPLY-1])
706                 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY);
707         else {
708                 /* Flush the whole table */
709                 ip_conntrack_flush();
710                 return 0;
711         }
712
713         if (err < 0)
714                 return err;
715
716         h = ip_conntrack_find_get(&tuple, NULL);
717         if (!h) {
718                 DEBUGP("tuple not found in conntrack hash\n");
719                 return -ENOENT;
720         }
721
722         ct = tuplehash_to_ctrack(h);
723         
724         if (cda[CTA_ID-1]) {
725                 u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1]));
726                 if (ct->id != id) {
727                         ip_conntrack_put(ct);
728                         return -ENOENT;
729                 }
730         }       
731         if (del_timer(&ct->timeout)) {
732                 ip_conntrack_put(ct);
733                 ct->timeout.function((unsigned long)ct);
734                 return 0;
735         }
736         ip_conntrack_put(ct);
737         DEBUGP("leaving\n");
738
739         return 0;
740 }
741
742 static int
743 ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, 
744                         struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
745 {
746         struct ip_conntrack_tuple_hash *h;
747         struct ip_conntrack_tuple tuple;
748         struct ip_conntrack *ct;
749         struct sk_buff *skb2 = NULL;
750         int err = 0;
751
752         DEBUGP("entered %s\n", __FUNCTION__);
753
754         if (nlh->nlmsg_flags & NLM_F_DUMP) {
755                 struct nfgenmsg *msg = NLMSG_DATA(nlh);
756                 u32 rlen;
757
758                 if (msg->nfgen_family != AF_INET)
759                         return -EAFNOSUPPORT;
760
761                 if (NFNL_MSG_TYPE(nlh->nlmsg_type) ==
762                                         IPCTNL_MSG_CT_GET_CTRZERO) {
763 #ifdef CONFIG_IP_NF_CT_ACCT
764                         if ((*errp = netlink_dump_start(ctnl, skb, nlh,
765                                                 ctnetlink_dump_table_w,
766                                                 ctnetlink_done)) != 0)
767                                 return -EINVAL;
768 #else
769                         return -ENOTSUPP;
770 #endif
771                 } else {
772                         if ((*errp = netlink_dump_start(ctnl, skb, nlh,
773                                                         ctnetlink_dump_table,
774                                                         ctnetlink_done)) != 0)
775                         return -EINVAL;
776                 }
777
778                 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
779                 if (rlen > skb->len)
780                         rlen = skb->len;
781                 skb_pull(skb, rlen);
782                 return 0;
783         }
784
785         if (nfattr_bad_size(cda, CTA_MAX, cta_min))
786                 return -EINVAL;
787
788         if (cda[CTA_TUPLE_ORIG-1])
789                 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
790         else if (cda[CTA_TUPLE_REPLY-1])
791                 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY);
792         else
793                 return -EINVAL;
794
795         if (err < 0)
796                 return err;
797
798         h = ip_conntrack_find_get(&tuple, NULL);
799         if (!h) {
800                 DEBUGP("tuple not found in conntrack hash");
801                 return -ENOENT;
802         }
803         DEBUGP("tuple found\n");
804         ct = tuplehash_to_ctrack(h);
805
806         err = -ENOMEM;
807         skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
808         if (!skb2) {
809                 ip_conntrack_put(ct);
810                 return -ENOMEM;
811         }
812         NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
813
814         err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 
815                                   IPCTNL_MSG_CT_NEW, 1, ct);
816         ip_conntrack_put(ct);
817         if (err <= 0)
818                 goto free;
819
820         err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
821         if (err < 0)
822                 goto out;
823
824         DEBUGP("leaving\n");
825         return 0;
826
827 free:
828         kfree_skb(skb2);
829 out:
830         return err;
831 }
832
833 static inline int
834 ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
835 {
836         unsigned long d;
837         unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));
838         d = ct->status ^ status;
839
840         if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
841                 /* unchangeable */
842                 return -EINVAL;
843         
844         if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
845                 /* SEEN_REPLY bit can only be set */
846                 return -EINVAL;
847
848         
849         if (d & IPS_ASSURED && !(status & IPS_ASSURED))
850                 /* ASSURED bit can only be set */
851                 return -EINVAL;
852
853         if (cda[CTA_NAT-1]) {
854 #ifndef CONFIG_IP_NF_NAT_NEEDED
855                 return -EINVAL;
856 #else
857                 unsigned int hooknum;
858                 struct ip_nat_range range;
859
860                 if (ctnetlink_parse_nat(cda, ct, &range) < 0)
861                         return -EINVAL;
862
863                 DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", 
864                        NIPQUAD(range.min_ip), NIPQUAD(range.max_ip),
865                        htons(range.min.all), htons(range.max.all));
866                 
867                 /* This is tricky but it works. ip_nat_setup_info needs the
868                  * hook number as parameter, so let's do the correct 
869                  * conversion and run away */
870                 if (status & IPS_SRC_NAT_DONE)
871                         hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */
872                 else if (status & IPS_DST_NAT_DONE)
873                         hooknum = NF_IP_PRE_ROUTING;  /* IP_NAT_MANIP_DST */
874                 else 
875                         return -EINVAL; /* Missing NAT flags */
876
877                 DEBUGP("NAT status: %lu\n", 
878                        status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
879                 
880                 if (ip_nat_initialized(ct, hooknum))
881                         return -EEXIST;
882                 ip_nat_setup_info(ct, &range, hooknum);
883
884                 DEBUGP("NAT status after setup_info: %lu\n",
885                        ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
886 #endif
887         }
888
889         /* Be careful here, modifying NAT bits can screw up things,
890          * so don't let users modify them directly if they don't pass
891          * ip_nat_range. */
892         ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
893         return 0;
894 }
895
896
897 static inline int
898 ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[])
899 {
900         struct ip_conntrack_helper *helper;
901         char *helpname;
902         int err;
903
904         DEBUGP("entered %s\n", __FUNCTION__);
905
906         /* don't change helper of sibling connections */
907         if (ct->master)
908                 return -EINVAL;
909
910         err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname);
911         if (err < 0)
912                 return err;
913
914         helper = __ip_conntrack_helper_find_byname(helpname);
915         if (!helper) {
916                 if (!strcmp(helpname, ""))
917                         helper = NULL;
918                 else
919                         return -EINVAL;
920         }
921
922         if (ct->helper) {
923                 if (!helper) {
924                         /* we had a helper before ... */
925                         ip_ct_remove_expectations(ct);
926                         ct->helper = NULL;
927                 } else {
928                         /* need to zero data of old helper */
929                         memset(&ct->help, 0, sizeof(ct->help));
930                 }
931         }
932         
933         ct->helper = helper;
934
935         return 0;
936 }
937
938 static inline int
939 ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[])
940 {
941         u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
942         
943         if (!del_timer(&ct->timeout))
944                 return -ETIME;
945
946         ct->timeout.expires = jiffies + timeout * HZ;
947         add_timer(&ct->timeout);
948
949         return 0;
950 }
951
952 static inline int
953 ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[])
954 {
955         struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1];
956         struct ip_conntrack_protocol *proto;
957         u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
958         int err = 0;
959
960         nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr);
961
962         proto = ip_conntrack_proto_find_get(npt);
963
964         if (proto->from_nfattr)
965                 err = proto->from_nfattr(tb, ct);
966         ip_conntrack_proto_put(proto); 
967
968         return err;
969 }
970
971 static int
972 ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
973 {
974         int err;
975
976         DEBUGP("entered %s\n", __FUNCTION__);
977
978         if (cda[CTA_HELP-1]) {
979                 err = ctnetlink_change_helper(ct, cda);
980                 if (err < 0)
981                         return err;
982         }
983
984         if (cda[CTA_TIMEOUT-1]) {
985                 err = ctnetlink_change_timeout(ct, cda);
986                 if (err < 0)
987                         return err;
988         }
989
990         if (cda[CTA_STATUS-1]) {
991                 err = ctnetlink_change_status(ct, cda);
992                 if (err < 0)
993                         return err;
994         }
995
996         if (cda[CTA_PROTOINFO-1]) {
997                 err = ctnetlink_change_protoinfo(ct, cda);
998                 if (err < 0)
999                         return err;
1000         }
1001
1002 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
1003         if (cda[CTA_MARK-1])
1004                 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
1005 #endif
1006
1007         DEBUGP("all done\n");
1008         return 0;
1009 }
1010
1011 static int
1012 ctnetlink_create_conntrack(struct nfattr *cda[], 
1013                            struct ip_conntrack_tuple *otuple,
1014                            struct ip_conntrack_tuple *rtuple)
1015 {
1016         struct ip_conntrack *ct;
1017         int err = -EINVAL;
1018
1019         DEBUGP("entered %s\n", __FUNCTION__);
1020
1021         ct = ip_conntrack_alloc(otuple, rtuple);
1022         if (ct == NULL || IS_ERR(ct))
1023                 return -ENOMEM; 
1024
1025         if (!cda[CTA_TIMEOUT-1])
1026                 goto err;
1027         ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
1028
1029         ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
1030         ct->status |= IPS_CONFIRMED;
1031
1032         err = ctnetlink_change_status(ct, cda);
1033         if (err < 0)
1034                 goto err;
1035
1036         if (cda[CTA_PROTOINFO-1]) {
1037                 err = ctnetlink_change_protoinfo(ct, cda);
1038                 if (err < 0)
1039                         return err;
1040         }
1041
1042         ct->helper = ip_conntrack_helper_find_get(rtuple);
1043
1044         add_timer(&ct->timeout);
1045         ip_conntrack_hash_insert(ct);
1046
1047         if (ct->helper)
1048                 ip_conntrack_helper_put(ct->helper);
1049
1050 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
1051         if (cda[CTA_MARK-1])
1052                 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
1053 #endif
1054
1055         DEBUGP("conntrack with id %u inserted\n", ct->id);
1056         return 0;
1057
1058 err:    
1059         ip_conntrack_free(ct);
1060         return err;
1061 }
1062
1063 static int 
1064 ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, 
1065                         struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1066 {
1067         struct ip_conntrack_tuple otuple, rtuple;
1068         struct ip_conntrack_tuple_hash *h = NULL;
1069         int err = 0;
1070
1071         DEBUGP("entered %s\n", __FUNCTION__);
1072
1073         if (nfattr_bad_size(cda, CTA_MAX, cta_min))
1074                 return -EINVAL;
1075
1076         if (cda[CTA_TUPLE_ORIG-1]) {
1077                 err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG);
1078                 if (err < 0)
1079                         return err;
1080         }
1081
1082         if (cda[CTA_TUPLE_REPLY-1]) {
1083                 err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY);
1084                 if (err < 0)
1085                         return err;
1086         }
1087
1088         write_lock_bh(&ip_conntrack_lock);
1089         if (cda[CTA_TUPLE_ORIG-1])
1090                 h = __ip_conntrack_find(&otuple, NULL);
1091         else if (cda[CTA_TUPLE_REPLY-1])
1092                 h = __ip_conntrack_find(&rtuple, NULL);
1093
1094         if (h == NULL) {
1095                 write_unlock_bh(&ip_conntrack_lock);
1096                 DEBUGP("no such conntrack, create new\n");
1097                 err = -ENOENT;
1098                 if (nlh->nlmsg_flags & NLM_F_CREATE)
1099                         err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
1100                 return err;
1101         }
1102         /* implicit 'else' */
1103
1104         /* we only allow nat config for new conntracks */
1105         if (cda[CTA_NAT-1]) {
1106                 err = -EINVAL;
1107                 goto out_unlock;
1108         }
1109
1110         /* We manipulate the conntrack inside the global conntrack table lock,
1111          * so there's no need to increase the refcount */
1112         DEBUGP("conntrack found\n");
1113         err = -EEXIST;
1114         if (!(nlh->nlmsg_flags & NLM_F_EXCL))
1115                 err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda);
1116
1117 out_unlock:
1118         write_unlock_bh(&ip_conntrack_lock);
1119         return err;
1120 }
1121
1122 /*********************************************************************** 
1123  * EXPECT 
1124  ***********************************************************************/ 
1125
1126 static inline int
1127 ctnetlink_exp_dump_tuple(struct sk_buff *skb,
1128                          const struct ip_conntrack_tuple *tuple,
1129                          enum ctattr_expect type)
1130 {
1131         struct nfattr *nest_parms = NFA_NEST(skb, type);
1132         
1133         if (ctnetlink_dump_tuples(skb, tuple) < 0)
1134                 goto nfattr_failure;
1135
1136         NFA_NEST_END(skb, nest_parms);
1137
1138         return 0;
1139
1140 nfattr_failure:
1141         return -1;
1142 }                       
1143
1144 static inline int
1145 ctnetlink_exp_dump_expect(struct sk_buff *skb,
1146                           const struct ip_conntrack_expect *exp)
1147 {
1148         struct ip_conntrack *master = exp->master;
1149         u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ);
1150         u_int32_t id = htonl(exp->id);
1151
1152         if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
1153                 goto nfattr_failure;
1154         if (ctnetlink_exp_dump_tuple(skb, &exp->mask, CTA_EXPECT_MASK) < 0)
1155                 goto nfattr_failure;
1156         if (ctnetlink_exp_dump_tuple(skb,
1157                                  &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
1158                                  CTA_EXPECT_MASTER) < 0)
1159                 goto nfattr_failure;
1160         
1161         NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout);
1162         NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id);
1163
1164         return 0;
1165         
1166 nfattr_failure:
1167         return -1;
1168 }
1169
1170 static int
1171 ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
1172                     int event, 
1173                     int nowait, 
1174                     const struct ip_conntrack_expect *exp)
1175 {
1176         struct nlmsghdr *nlh;
1177         struct nfgenmsg *nfmsg;
1178         unsigned char *b;
1179
1180         b = skb->tail;
1181
1182         event |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
1183         nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
1184         nfmsg  = NLMSG_DATA(nlh);
1185
1186         nlh->nlmsg_flags    = (nowait && pid) ? NLM_F_MULTI : 0;
1187         nfmsg->nfgen_family = AF_INET;
1188         nfmsg->version      = NFNETLINK_V0;
1189         nfmsg->res_id       = 0;
1190
1191         if (ctnetlink_exp_dump_expect(skb, exp) < 0)
1192                 goto nfattr_failure;
1193
1194         nlh->nlmsg_len = skb->tail - b;
1195         return skb->len;
1196
1197 nlmsg_failure:
1198 nfattr_failure:
1199         skb_trim(skb, b - skb->data);
1200         return -1;
1201 }
1202
1203 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1204 static int ctnetlink_expect_event(struct notifier_block *this,
1205                                   unsigned long events, void *ptr)
1206 {
1207         struct nlmsghdr *nlh;
1208         struct nfgenmsg *nfmsg;
1209         struct ip_conntrack_expect *exp = (struct ip_conntrack_expect *)ptr;
1210         struct sk_buff *skb;
1211         unsigned int type;
1212         unsigned char *b;
1213         int flags = 0;
1214         u16 proto;
1215
1216         if (events & IPEXP_NEW) {
1217                 type = IPCTNL_MSG_EXP_NEW;
1218                 flags = NLM_F_CREATE|NLM_F_EXCL;
1219         } else
1220                 return NOTIFY_DONE;
1221
1222         skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
1223         if (!skb)
1224                 return NOTIFY_DONE;
1225
1226         b = skb->tail;
1227
1228         type |= NFNL_SUBSYS_CTNETLINK << 8;
1229         nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
1230         nfmsg = NLMSG_DATA(nlh);
1231
1232         nlh->nlmsg_flags    = flags;
1233         nfmsg->nfgen_family = AF_INET;
1234         nfmsg->version      = NFNETLINK_V0;
1235         nfmsg->res_id       = 0;
1236
1237         if (ctnetlink_exp_dump_expect(skb, exp) < 0)
1238                 goto nfattr_failure;
1239
1240         nlh->nlmsg_len = skb->tail - b;
1241         proto = exp->tuple.dst.protonum;
1242         nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0);
1243         return NOTIFY_DONE;
1244
1245 nlmsg_failure:
1246 nfattr_failure:
1247         kfree_skb(skb);
1248         return NOTIFY_DONE;
1249 }
1250 #endif
1251
1252 static int
1253 ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
1254 {
1255         struct ip_conntrack_expect *exp = NULL;
1256         struct list_head *i;
1257         u_int32_t *id = (u_int32_t *) &cb->args[0];
1258
1259         DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
1260
1261         read_lock_bh(&ip_conntrack_lock);
1262         list_for_each_prev(i, &ip_conntrack_expect_list) {
1263                 exp = (struct ip_conntrack_expect *) i;
1264                 if (exp->id <= *id)
1265                         continue;
1266                 if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid,
1267                                             cb->nlh->nlmsg_seq,
1268                                             IPCTNL_MSG_EXP_NEW,
1269                                             1, exp) < 0)
1270                         goto out;
1271                 *id = exp->id;
1272         }
1273 out:    
1274         read_unlock_bh(&ip_conntrack_lock);
1275
1276         DEBUGP("leaving, last id=%llu\n", *id);
1277
1278         return skb->len;
1279 }
1280
1281 static const size_t cta_min_exp[CTA_EXPECT_MAX] = {
1282         [CTA_EXPECT_TIMEOUT-1]          = sizeof(u_int32_t),
1283         [CTA_EXPECT_ID-1]               = sizeof(u_int32_t)
1284 };
1285
1286 static int
1287 ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, 
1288                      struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1289 {
1290         struct ip_conntrack_tuple tuple;
1291         struct ip_conntrack_expect *exp;
1292         struct sk_buff *skb2;
1293         int err = 0;
1294
1295         DEBUGP("entered %s\n", __FUNCTION__);
1296
1297         if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1298                 return -EINVAL;
1299
1300         if (nlh->nlmsg_flags & NLM_F_DUMP) {
1301                 struct nfgenmsg *msg = NLMSG_DATA(nlh);
1302                 u32 rlen;
1303
1304                 if (msg->nfgen_family != AF_INET)
1305                         return -EAFNOSUPPORT;
1306
1307                 if ((*errp = netlink_dump_start(ctnl, skb, nlh,
1308                                                 ctnetlink_exp_dump_table,
1309                                                 ctnetlink_done)) != 0)
1310                         return -EINVAL;
1311                 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
1312                 if (rlen > skb->len)
1313                         rlen = skb->len;
1314                 skb_pull(skb, rlen);
1315                 return 0;
1316         }
1317
1318         if (cda[CTA_EXPECT_MASTER-1])
1319                 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER);
1320         else
1321                 return -EINVAL;
1322
1323         if (err < 0)
1324                 return err;
1325
1326         exp = ip_conntrack_expect_find(&tuple);
1327         if (!exp)
1328                 return -ENOENT;
1329
1330         if (cda[CTA_EXPECT_ID-1]) {
1331                 u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
1332                 if (exp->id != ntohl(id)) {
1333                         ip_conntrack_expect_put(exp);
1334                         return -ENOENT;
1335                 }
1336         }       
1337
1338         err = -ENOMEM;
1339         skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1340         if (!skb2)
1341                 goto out;
1342         NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
1343         
1344         err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, 
1345                                       nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
1346                                       1, exp);
1347         if (err <= 0)
1348                 goto free;
1349
1350         ip_conntrack_expect_put(exp);
1351
1352         return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
1353
1354 free:
1355         kfree_skb(skb2);
1356 out:
1357         ip_conntrack_expect_put(exp);
1358         return err;
1359 }
1360
1361 static int
1362 ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, 
1363                      struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1364 {
1365         struct ip_conntrack_expect *exp, *tmp;
1366         struct ip_conntrack_tuple tuple;
1367         struct ip_conntrack_helper *h;
1368         int err;
1369
1370         if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1371                 return -EINVAL;
1372
1373         if (cda[CTA_EXPECT_TUPLE-1]) {
1374                 /* delete a single expect by tuple */
1375                 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
1376                 if (err < 0)
1377                         return err;
1378
1379                 /* bump usage count to 2 */
1380                 exp = ip_conntrack_expect_find(&tuple);
1381                 if (!exp)
1382                         return -ENOENT;
1383
1384                 if (cda[CTA_EXPECT_ID-1]) {
1385                         u_int32_t id = 
1386                                 *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
1387                         if (exp->id != ntohl(id)) {
1388                                 ip_conntrack_expect_put(exp);
1389                                 return -ENOENT;
1390                         }
1391                 }
1392
1393                 /* after list removal, usage count == 1 */
1394                 ip_conntrack_unexpect_related(exp);
1395                 /* have to put what we 'get' above. 
1396                  * after this line usage count == 0 */
1397                 ip_conntrack_expect_put(exp);
1398         } else if (cda[CTA_EXPECT_HELP_NAME-1]) {
1399                 char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]);
1400
1401                 /* delete all expectations for this helper */
1402                 write_lock_bh(&ip_conntrack_lock);
1403                 h = __ip_conntrack_helper_find_byname(name);
1404                 if (!h) {
1405                         write_unlock_bh(&ip_conntrack_lock);
1406                         return -EINVAL;
1407                 }
1408                 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
1409                                          list) {
1410                         if (exp->master->helper == h 
1411                             && del_timer(&exp->timeout)) {
1412                                 ip_ct_unlink_expect(exp);
1413                                 ip_conntrack_expect_put(exp);
1414                         }
1415                 }
1416                 write_unlock_bh(&ip_conntrack_lock);
1417         } else {
1418                 /* This basically means we have to flush everything*/
1419                 write_lock_bh(&ip_conntrack_lock);
1420                 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
1421                                          list) {
1422                         if (del_timer(&exp->timeout)) {
1423                                 ip_ct_unlink_expect(exp);
1424                                 ip_conntrack_expect_put(exp);
1425                         }
1426                 }
1427                 write_unlock_bh(&ip_conntrack_lock);
1428         }
1429
1430         return 0;
1431 }
1432 static int
1433 ctnetlink_change_expect(struct ip_conntrack_expect *x, struct nfattr *cda[])
1434 {
1435         return -EOPNOTSUPP;
1436 }
1437
1438 static int
1439 ctnetlink_create_expect(struct nfattr *cda[])
1440 {
1441         struct ip_conntrack_tuple tuple, mask, master_tuple;
1442         struct ip_conntrack_tuple_hash *h = NULL;
1443         struct ip_conntrack_expect *exp;
1444         struct ip_conntrack *ct;
1445         int err = 0;
1446
1447         DEBUGP("entered %s\n", __FUNCTION__);
1448
1449         /* caller guarantees that those three CTA_EXPECT_* exist */
1450         err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
1451         if (err < 0)
1452                 return err;
1453         err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK);
1454         if (err < 0)
1455                 return err;
1456         err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER);
1457         if (err < 0)
1458                 return err;
1459
1460         /* Look for master conntrack of this expectation */
1461         h = ip_conntrack_find_get(&master_tuple, NULL);
1462         if (!h)
1463                 return -ENOENT;
1464         ct = tuplehash_to_ctrack(h);
1465
1466         if (!ct->helper) {
1467                 /* such conntrack hasn't got any helper, abort */
1468                 err = -EINVAL;
1469                 goto out;
1470         }
1471
1472         exp = ip_conntrack_expect_alloc(ct);
1473         if (!exp) {
1474                 err = -ENOMEM;
1475                 goto out;
1476         }
1477         
1478         exp->expectfn = NULL;
1479         exp->flags = 0;
1480         exp->master = ct;
1481         memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple));
1482         memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple));
1483
1484         err = ip_conntrack_expect_related(exp);
1485         ip_conntrack_expect_put(exp);
1486
1487 out:    
1488         ip_conntrack_put(tuplehash_to_ctrack(h));
1489         return err;
1490 }
1491
1492 static int
1493 ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
1494                      struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1495 {
1496         struct ip_conntrack_tuple tuple;
1497         struct ip_conntrack_expect *exp;
1498         int err = 0;
1499
1500         DEBUGP("entered %s\n", __FUNCTION__);   
1501
1502         if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1503                 return -EINVAL;
1504
1505         if (!cda[CTA_EXPECT_TUPLE-1]
1506             || !cda[CTA_EXPECT_MASK-1]
1507             || !cda[CTA_EXPECT_MASTER-1])
1508                 return -EINVAL;
1509
1510         err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
1511         if (err < 0)
1512                 return err;
1513
1514         write_lock_bh(&ip_conntrack_lock);
1515         exp = __ip_conntrack_expect_find(&tuple);
1516
1517         if (!exp) {
1518                 write_unlock_bh(&ip_conntrack_lock);
1519                 err = -ENOENT;
1520                 if (nlh->nlmsg_flags & NLM_F_CREATE)
1521                         err = ctnetlink_create_expect(cda);
1522                 return err;
1523         }
1524
1525         err = -EEXIST;
1526         if (!(nlh->nlmsg_flags & NLM_F_EXCL))
1527                 err = ctnetlink_change_expect(exp, cda);
1528         write_unlock_bh(&ip_conntrack_lock);
1529
1530         DEBUGP("leaving\n");
1531         
1532         return err;
1533 }
1534
1535 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1536 static struct notifier_block ctnl_notifier = {
1537         .notifier_call  = ctnetlink_conntrack_event,
1538 };
1539
1540 static struct notifier_block ctnl_notifier_exp = {
1541         .notifier_call  = ctnetlink_expect_event,
1542 };
1543 #endif
1544
1545 static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
1546         [IPCTNL_MSG_CT_NEW]             = { .call = ctnetlink_new_conntrack,
1547                                             .attr_count = CTA_MAX, },
1548         [IPCTNL_MSG_CT_GET]             = { .call = ctnetlink_get_conntrack,
1549                                             .attr_count = CTA_MAX, },
1550         [IPCTNL_MSG_CT_DELETE]          = { .call = ctnetlink_del_conntrack,
1551                                             .attr_count = CTA_MAX, },
1552         [IPCTNL_MSG_CT_GET_CTRZERO]     = { .call = ctnetlink_get_conntrack,
1553                                             .attr_count = CTA_MAX, },
1554 };
1555
1556 static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
1557         [IPCTNL_MSG_EXP_GET]            = { .call = ctnetlink_get_expect,
1558                                             .attr_count = CTA_EXPECT_MAX, },
1559         [IPCTNL_MSG_EXP_NEW]            = { .call = ctnetlink_new_expect,
1560                                             .attr_count = CTA_EXPECT_MAX, },
1561         [IPCTNL_MSG_EXP_DELETE]         = { .call = ctnetlink_del_expect,
1562                                             .attr_count = CTA_EXPECT_MAX, },
1563 };
1564
1565 static struct nfnetlink_subsystem ctnl_subsys = {
1566         .name                           = "conntrack",
1567         .subsys_id                      = NFNL_SUBSYS_CTNETLINK,
1568         .cb_count                       = IPCTNL_MSG_MAX,
1569         .cb                             = ctnl_cb,
1570 };
1571
1572 static struct nfnetlink_subsystem ctnl_exp_subsys = {
1573         .name                           = "conntrack_expect",
1574         .subsys_id                      = NFNL_SUBSYS_CTNETLINK_EXP,
1575         .cb_count                       = IPCTNL_MSG_EXP_MAX,
1576         .cb                             = ctnl_exp_cb,
1577 };
1578
1579 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
1580
1581 static int __init ctnetlink_init(void)
1582 {
1583         int ret;
1584
1585         printk("ctnetlink v%s: registering with nfnetlink.\n", version);
1586         ret = nfnetlink_subsys_register(&ctnl_subsys);
1587         if (ret < 0) {
1588                 printk("ctnetlink_init: cannot register with nfnetlink.\n");
1589                 goto err_out;
1590         }
1591
1592         ret = nfnetlink_subsys_register(&ctnl_exp_subsys);
1593         if (ret < 0) {
1594                 printk("ctnetlink_init: cannot register exp with nfnetlink.\n");
1595                 goto err_unreg_subsys;
1596         }
1597
1598 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1599         ret = ip_conntrack_register_notifier(&ctnl_notifier);
1600         if (ret < 0) {
1601                 printk("ctnetlink_init: cannot register notifier.\n");
1602                 goto err_unreg_exp_subsys;
1603         }
1604
1605         ret = ip_conntrack_expect_register_notifier(&ctnl_notifier_exp);
1606         if (ret < 0) {
1607                 printk("ctnetlink_init: cannot expect register notifier.\n");
1608                 goto err_unreg_notifier;
1609         }
1610 #endif
1611
1612         return 0;
1613
1614 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1615 err_unreg_notifier:
1616         ip_conntrack_unregister_notifier(&ctnl_notifier);
1617 err_unreg_exp_subsys:
1618         nfnetlink_subsys_unregister(&ctnl_exp_subsys);
1619 #endif
1620 err_unreg_subsys:
1621         nfnetlink_subsys_unregister(&ctnl_subsys);
1622 err_out:
1623         return ret;
1624 }
1625
1626 static void __exit ctnetlink_exit(void)
1627 {
1628         printk("ctnetlink: unregistering from nfnetlink.\n");
1629
1630 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1631         ip_conntrack_unregister_notifier(&ctnl_notifier_exp);
1632         ip_conntrack_unregister_notifier(&ctnl_notifier);
1633 #endif
1634
1635         nfnetlink_subsys_unregister(&ctnl_exp_subsys);
1636         nfnetlink_subsys_unregister(&ctnl_subsys);
1637         return;
1638 }
1639
1640 module_init(ctnetlink_init);
1641 module_exit(ctnetlink_exit);