[NETFILTER]: ip_nat_tftp: Fix expectation NAT
[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_int8_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_int8_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                 ct->timeout.function((unsigned long)ct);
733
734         ip_conntrack_put(ct);
735         DEBUGP("leaving\n");
736
737         return 0;
738 }
739
740 static int
741 ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, 
742                         struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
743 {
744         struct ip_conntrack_tuple_hash *h;
745         struct ip_conntrack_tuple tuple;
746         struct ip_conntrack *ct;
747         struct sk_buff *skb2 = NULL;
748         int err = 0;
749
750         DEBUGP("entered %s\n", __FUNCTION__);
751
752         if (nlh->nlmsg_flags & NLM_F_DUMP) {
753                 struct nfgenmsg *msg = NLMSG_DATA(nlh);
754                 u32 rlen;
755
756                 if (msg->nfgen_family != AF_INET)
757                         return -EAFNOSUPPORT;
758
759                 if (NFNL_MSG_TYPE(nlh->nlmsg_type) ==
760                                         IPCTNL_MSG_CT_GET_CTRZERO) {
761 #ifdef CONFIG_IP_NF_CT_ACCT
762                         if ((*errp = netlink_dump_start(ctnl, skb, nlh,
763                                                 ctnetlink_dump_table_w,
764                                                 ctnetlink_done)) != 0)
765                                 return -EINVAL;
766 #else
767                         return -ENOTSUPP;
768 #endif
769                 } else {
770                         if ((*errp = netlink_dump_start(ctnl, skb, nlh,
771                                                         ctnetlink_dump_table,
772                                                         ctnetlink_done)) != 0)
773                         return -EINVAL;
774                 }
775
776                 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
777                 if (rlen > skb->len)
778                         rlen = skb->len;
779                 skb_pull(skb, rlen);
780                 return 0;
781         }
782
783         if (nfattr_bad_size(cda, CTA_MAX, cta_min))
784                 return -EINVAL;
785
786         if (cda[CTA_TUPLE_ORIG-1])
787                 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
788         else if (cda[CTA_TUPLE_REPLY-1])
789                 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY);
790         else
791                 return -EINVAL;
792
793         if (err < 0)
794                 return err;
795
796         h = ip_conntrack_find_get(&tuple, NULL);
797         if (!h) {
798                 DEBUGP("tuple not found in conntrack hash");
799                 return -ENOENT;
800         }
801         DEBUGP("tuple found\n");
802         ct = tuplehash_to_ctrack(h);
803
804         err = -ENOMEM;
805         skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
806         if (!skb2) {
807                 ip_conntrack_put(ct);
808                 return -ENOMEM;
809         }
810         NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
811
812         err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 
813                                   IPCTNL_MSG_CT_NEW, 1, ct);
814         ip_conntrack_put(ct);
815         if (err <= 0)
816                 goto free;
817
818         err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
819         if (err < 0)
820                 goto out;
821
822         DEBUGP("leaving\n");
823         return 0;
824
825 free:
826         kfree_skb(skb2);
827 out:
828         return err;
829 }
830
831 static inline int
832 ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
833 {
834         unsigned long d;
835         unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));
836         d = ct->status ^ status;
837
838         if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
839                 /* unchangeable */
840                 return -EINVAL;
841         
842         if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
843                 /* SEEN_REPLY bit can only be set */
844                 return -EINVAL;
845
846         
847         if (d & IPS_ASSURED && !(status & IPS_ASSURED))
848                 /* ASSURED bit can only be set */
849                 return -EINVAL;
850
851         if (cda[CTA_NAT-1]) {
852 #ifndef CONFIG_IP_NF_NAT_NEEDED
853                 return -EINVAL;
854 #else
855                 unsigned int hooknum;
856                 struct ip_nat_range range;
857
858                 if (ctnetlink_parse_nat(cda, ct, &range) < 0)
859                         return -EINVAL;
860
861                 DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", 
862                        NIPQUAD(range.min_ip), NIPQUAD(range.max_ip),
863                        htons(range.min.all), htons(range.max.all));
864                 
865                 /* This is tricky but it works. ip_nat_setup_info needs the
866                  * hook number as parameter, so let's do the correct 
867                  * conversion and run away */
868                 if (status & IPS_SRC_NAT_DONE)
869                         hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */
870                 else if (status & IPS_DST_NAT_DONE)
871                         hooknum = NF_IP_PRE_ROUTING;  /* IP_NAT_MANIP_DST */
872                 else 
873                         return -EINVAL; /* Missing NAT flags */
874
875                 DEBUGP("NAT status: %lu\n", 
876                        status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
877                 
878                 if (ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
879                         return -EEXIST;
880                 ip_nat_setup_info(ct, &range, hooknum);
881
882                 DEBUGP("NAT status after setup_info: %lu\n",
883                        ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
884 #endif
885         }
886
887         /* Be careful here, modifying NAT bits can screw up things,
888          * so don't let users modify them directly if they don't pass
889          * ip_nat_range. */
890         ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
891         return 0;
892 }
893
894
895 static inline int
896 ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[])
897 {
898         struct ip_conntrack_helper *helper;
899         char *helpname;
900         int err;
901
902         DEBUGP("entered %s\n", __FUNCTION__);
903
904         /* don't change helper of sibling connections */
905         if (ct->master)
906                 return -EINVAL;
907
908         err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname);
909         if (err < 0)
910                 return err;
911
912         helper = __ip_conntrack_helper_find_byname(helpname);
913         if (!helper) {
914                 if (!strcmp(helpname, ""))
915                         helper = NULL;
916                 else
917                         return -EINVAL;
918         }
919
920         if (ct->helper) {
921                 if (!helper) {
922                         /* we had a helper before ... */
923                         ip_ct_remove_expectations(ct);
924                         ct->helper = NULL;
925                 } else {
926                         /* need to zero data of old helper */
927                         memset(&ct->help, 0, sizeof(ct->help));
928                 }
929         }
930         
931         ct->helper = helper;
932
933         return 0;
934 }
935
936 static inline int
937 ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[])
938 {
939         u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
940         
941         if (!del_timer(&ct->timeout))
942                 return -ETIME;
943
944         ct->timeout.expires = jiffies + timeout * HZ;
945         add_timer(&ct->timeout);
946
947         return 0;
948 }
949
950 static inline int
951 ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[])
952 {
953         struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1];
954         struct ip_conntrack_protocol *proto;
955         u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
956         int err = 0;
957
958         nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr);
959
960         proto = ip_conntrack_proto_find_get(npt);
961
962         if (proto->from_nfattr)
963                 err = proto->from_nfattr(tb, ct);
964         ip_conntrack_proto_put(proto); 
965
966         return err;
967 }
968
969 static int
970 ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
971 {
972         int err;
973
974         DEBUGP("entered %s\n", __FUNCTION__);
975
976         if (cda[CTA_HELP-1]) {
977                 err = ctnetlink_change_helper(ct, cda);
978                 if (err < 0)
979                         return err;
980         }
981
982         if (cda[CTA_TIMEOUT-1]) {
983                 err = ctnetlink_change_timeout(ct, cda);
984                 if (err < 0)
985                         return err;
986         }
987
988         if (cda[CTA_STATUS-1]) {
989                 err = ctnetlink_change_status(ct, cda);
990                 if (err < 0)
991                         return err;
992         }
993
994         if (cda[CTA_PROTOINFO-1]) {
995                 err = ctnetlink_change_protoinfo(ct, cda);
996                 if (err < 0)
997                         return err;
998         }
999
1000 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
1001         if (cda[CTA_MARK-1])
1002                 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
1003 #endif
1004
1005         DEBUGP("all done\n");
1006         return 0;
1007 }
1008
1009 static int
1010 ctnetlink_create_conntrack(struct nfattr *cda[], 
1011                            struct ip_conntrack_tuple *otuple,
1012                            struct ip_conntrack_tuple *rtuple)
1013 {
1014         struct ip_conntrack *ct;
1015         int err = -EINVAL;
1016
1017         DEBUGP("entered %s\n", __FUNCTION__);
1018
1019         ct = ip_conntrack_alloc(otuple, rtuple);
1020         if (ct == NULL || IS_ERR(ct))
1021                 return -ENOMEM; 
1022
1023         if (!cda[CTA_TIMEOUT-1])
1024                 goto err;
1025         ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
1026
1027         ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
1028         ct->status |= IPS_CONFIRMED;
1029
1030         err = ctnetlink_change_status(ct, cda);
1031         if (err < 0)
1032                 goto err;
1033
1034         if (cda[CTA_PROTOINFO-1]) {
1035                 err = ctnetlink_change_protoinfo(ct, cda);
1036                 if (err < 0)
1037                         return err;
1038         }
1039
1040         ct->helper = ip_conntrack_helper_find_get(rtuple);
1041
1042         add_timer(&ct->timeout);
1043         ip_conntrack_hash_insert(ct);
1044
1045         if (ct->helper)
1046                 ip_conntrack_helper_put(ct->helper);
1047
1048 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
1049         if (cda[CTA_MARK-1])
1050                 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
1051 #endif
1052
1053         DEBUGP("conntrack with id %u inserted\n", ct->id);
1054         return 0;
1055
1056 err:    
1057         ip_conntrack_free(ct);
1058         return err;
1059 }
1060
1061 static int 
1062 ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, 
1063                         struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1064 {
1065         struct ip_conntrack_tuple otuple, rtuple;
1066         struct ip_conntrack_tuple_hash *h = NULL;
1067         int err = 0;
1068
1069         DEBUGP("entered %s\n", __FUNCTION__);
1070
1071         if (nfattr_bad_size(cda, CTA_MAX, cta_min))
1072                 return -EINVAL;
1073
1074         if (cda[CTA_TUPLE_ORIG-1]) {
1075                 err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG);
1076                 if (err < 0)
1077                         return err;
1078         }
1079
1080         if (cda[CTA_TUPLE_REPLY-1]) {
1081                 err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY);
1082                 if (err < 0)
1083                         return err;
1084         }
1085
1086         write_lock_bh(&ip_conntrack_lock);
1087         if (cda[CTA_TUPLE_ORIG-1])
1088                 h = __ip_conntrack_find(&otuple, NULL);
1089         else if (cda[CTA_TUPLE_REPLY-1])
1090                 h = __ip_conntrack_find(&rtuple, NULL);
1091
1092         if (h == NULL) {
1093                 write_unlock_bh(&ip_conntrack_lock);
1094                 DEBUGP("no such conntrack, create new\n");
1095                 err = -ENOENT;
1096                 if (nlh->nlmsg_flags & NLM_F_CREATE)
1097                         err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
1098                 return err;
1099         }
1100         /* implicit 'else' */
1101
1102         /* we only allow nat config for new conntracks */
1103         if (cda[CTA_NAT-1]) {
1104                 err = -EINVAL;
1105                 goto out_unlock;
1106         }
1107
1108         /* We manipulate the conntrack inside the global conntrack table lock,
1109          * so there's no need to increase the refcount */
1110         DEBUGP("conntrack found\n");
1111         err = -EEXIST;
1112         if (!(nlh->nlmsg_flags & NLM_F_EXCL))
1113                 err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda);
1114
1115 out_unlock:
1116         write_unlock_bh(&ip_conntrack_lock);
1117         return err;
1118 }
1119
1120 /*********************************************************************** 
1121  * EXPECT 
1122  ***********************************************************************/ 
1123
1124 static inline int
1125 ctnetlink_exp_dump_tuple(struct sk_buff *skb,
1126                          const struct ip_conntrack_tuple *tuple,
1127                          enum ctattr_expect type)
1128 {
1129         struct nfattr *nest_parms = NFA_NEST(skb, type);
1130         
1131         if (ctnetlink_dump_tuples(skb, tuple) < 0)
1132                 goto nfattr_failure;
1133
1134         NFA_NEST_END(skb, nest_parms);
1135
1136         return 0;
1137
1138 nfattr_failure:
1139         return -1;
1140 }                       
1141
1142 static inline int
1143 ctnetlink_exp_dump_expect(struct sk_buff *skb,
1144                           const struct ip_conntrack_expect *exp)
1145 {
1146         struct ip_conntrack *master = exp->master;
1147         u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ);
1148         u_int32_t id = htonl(exp->id);
1149
1150         if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
1151                 goto nfattr_failure;
1152         if (ctnetlink_exp_dump_tuple(skb, &exp->mask, CTA_EXPECT_MASK) < 0)
1153                 goto nfattr_failure;
1154         if (ctnetlink_exp_dump_tuple(skb,
1155                                  &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
1156                                  CTA_EXPECT_MASTER) < 0)
1157                 goto nfattr_failure;
1158         
1159         NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout);
1160         NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id);
1161
1162         return 0;
1163         
1164 nfattr_failure:
1165         return -1;
1166 }
1167
1168 static int
1169 ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
1170                     int event, 
1171                     int nowait, 
1172                     const struct ip_conntrack_expect *exp)
1173 {
1174         struct nlmsghdr *nlh;
1175         struct nfgenmsg *nfmsg;
1176         unsigned char *b;
1177
1178         b = skb->tail;
1179
1180         event |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
1181         nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
1182         nfmsg  = NLMSG_DATA(nlh);
1183
1184         nlh->nlmsg_flags    = (nowait && pid) ? NLM_F_MULTI : 0;
1185         nfmsg->nfgen_family = AF_INET;
1186         nfmsg->version      = NFNETLINK_V0;
1187         nfmsg->res_id       = 0;
1188
1189         if (ctnetlink_exp_dump_expect(skb, exp) < 0)
1190                 goto nfattr_failure;
1191
1192         nlh->nlmsg_len = skb->tail - b;
1193         return skb->len;
1194
1195 nlmsg_failure:
1196 nfattr_failure:
1197         skb_trim(skb, b - skb->data);
1198         return -1;
1199 }
1200
1201 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1202 static int ctnetlink_expect_event(struct notifier_block *this,
1203                                   unsigned long events, void *ptr)
1204 {
1205         struct nlmsghdr *nlh;
1206         struct nfgenmsg *nfmsg;
1207         struct ip_conntrack_expect *exp = (struct ip_conntrack_expect *)ptr;
1208         struct sk_buff *skb;
1209         unsigned int type;
1210         unsigned char *b;
1211         int flags = 0;
1212         u16 proto;
1213
1214         if (events & IPEXP_NEW) {
1215                 type = IPCTNL_MSG_EXP_NEW;
1216                 flags = NLM_F_CREATE|NLM_F_EXCL;
1217         } else
1218                 return NOTIFY_DONE;
1219
1220         skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
1221         if (!skb)
1222                 return NOTIFY_DONE;
1223
1224         b = skb->tail;
1225
1226         type |= NFNL_SUBSYS_CTNETLINK << 8;
1227         nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
1228         nfmsg = NLMSG_DATA(nlh);
1229
1230         nlh->nlmsg_flags    = flags;
1231         nfmsg->nfgen_family = AF_INET;
1232         nfmsg->version      = NFNETLINK_V0;
1233         nfmsg->res_id       = 0;
1234
1235         if (ctnetlink_exp_dump_expect(skb, exp) < 0)
1236                 goto nfattr_failure;
1237
1238         nlh->nlmsg_len = skb->tail - b;
1239         proto = exp->tuple.dst.protonum;
1240         nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0);
1241         return NOTIFY_DONE;
1242
1243 nlmsg_failure:
1244 nfattr_failure:
1245         kfree_skb(skb);
1246         return NOTIFY_DONE;
1247 }
1248 #endif
1249
1250 static int
1251 ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
1252 {
1253         struct ip_conntrack_expect *exp = NULL;
1254         struct list_head *i;
1255         u_int32_t *id = (u_int32_t *) &cb->args[0];
1256
1257         DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
1258
1259         read_lock_bh(&ip_conntrack_lock);
1260         list_for_each_prev(i, &ip_conntrack_expect_list) {
1261                 exp = (struct ip_conntrack_expect *) i;
1262                 if (exp->id <= *id)
1263                         continue;
1264                 if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid,
1265                                             cb->nlh->nlmsg_seq,
1266                                             IPCTNL_MSG_EXP_NEW,
1267                                             1, exp) < 0)
1268                         goto out;
1269                 *id = exp->id;
1270         }
1271 out:    
1272         read_unlock_bh(&ip_conntrack_lock);
1273
1274         DEBUGP("leaving, last id=%llu\n", *id);
1275
1276         return skb->len;
1277 }
1278
1279 static const size_t cta_min_exp[CTA_EXPECT_MAX] = {
1280         [CTA_EXPECT_TIMEOUT-1]          = sizeof(u_int32_t),
1281         [CTA_EXPECT_ID-1]               = sizeof(u_int32_t)
1282 };
1283
1284 static int
1285 ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, 
1286                      struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1287 {
1288         struct ip_conntrack_tuple tuple;
1289         struct ip_conntrack_expect *exp;
1290         struct sk_buff *skb2;
1291         int err = 0;
1292
1293         DEBUGP("entered %s\n", __FUNCTION__);
1294
1295         if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1296                 return -EINVAL;
1297
1298         if (nlh->nlmsg_flags & NLM_F_DUMP) {
1299                 struct nfgenmsg *msg = NLMSG_DATA(nlh);
1300                 u32 rlen;
1301
1302                 if (msg->nfgen_family != AF_INET)
1303                         return -EAFNOSUPPORT;
1304
1305                 if ((*errp = netlink_dump_start(ctnl, skb, nlh,
1306                                                 ctnetlink_exp_dump_table,
1307                                                 ctnetlink_done)) != 0)
1308                         return -EINVAL;
1309                 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
1310                 if (rlen > skb->len)
1311                         rlen = skb->len;
1312                 skb_pull(skb, rlen);
1313                 return 0;
1314         }
1315
1316         if (cda[CTA_EXPECT_MASTER-1])
1317                 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER);
1318         else
1319                 return -EINVAL;
1320
1321         if (err < 0)
1322                 return err;
1323
1324         exp = ip_conntrack_expect_find(&tuple);
1325         if (!exp)
1326                 return -ENOENT;
1327
1328         if (cda[CTA_EXPECT_ID-1]) {
1329                 u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
1330                 if (exp->id != ntohl(id)) {
1331                         ip_conntrack_expect_put(exp);
1332                         return -ENOENT;
1333                 }
1334         }       
1335
1336         err = -ENOMEM;
1337         skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1338         if (!skb2)
1339                 goto out;
1340         NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
1341         
1342         err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, 
1343                                       nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
1344                                       1, exp);
1345         if (err <= 0)
1346                 goto free;
1347
1348         ip_conntrack_expect_put(exp);
1349
1350         return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
1351
1352 free:
1353         kfree_skb(skb2);
1354 out:
1355         ip_conntrack_expect_put(exp);
1356         return err;
1357 }
1358
1359 static int
1360 ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, 
1361                      struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1362 {
1363         struct ip_conntrack_expect *exp, *tmp;
1364         struct ip_conntrack_tuple tuple;
1365         struct ip_conntrack_helper *h;
1366         int err;
1367
1368         if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1369                 return -EINVAL;
1370
1371         if (cda[CTA_EXPECT_TUPLE-1]) {
1372                 /* delete a single expect by tuple */
1373                 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
1374                 if (err < 0)
1375                         return err;
1376
1377                 /* bump usage count to 2 */
1378                 exp = ip_conntrack_expect_find(&tuple);
1379                 if (!exp)
1380                         return -ENOENT;
1381
1382                 if (cda[CTA_EXPECT_ID-1]) {
1383                         u_int32_t id = 
1384                                 *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
1385                         if (exp->id != ntohl(id)) {
1386                                 ip_conntrack_expect_put(exp);
1387                                 return -ENOENT;
1388                         }
1389                 }
1390
1391                 /* after list removal, usage count == 1 */
1392                 ip_conntrack_unexpect_related(exp);
1393                 /* have to put what we 'get' above. 
1394                  * after this line usage count == 0 */
1395                 ip_conntrack_expect_put(exp);
1396         } else if (cda[CTA_EXPECT_HELP_NAME-1]) {
1397                 char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]);
1398
1399                 /* delete all expectations for this helper */
1400                 write_lock_bh(&ip_conntrack_lock);
1401                 h = __ip_conntrack_helper_find_byname(name);
1402                 if (!h) {
1403                         write_unlock_bh(&ip_conntrack_lock);
1404                         return -EINVAL;
1405                 }
1406                 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
1407                                          list) {
1408                         if (exp->master->helper == h 
1409                             && del_timer(&exp->timeout)) {
1410                                 ip_ct_unlink_expect(exp);
1411                                 ip_conntrack_expect_put(exp);
1412                         }
1413                 }
1414                 write_unlock_bh(&ip_conntrack_lock);
1415         } else {
1416                 /* This basically means we have to flush everything*/
1417                 write_lock_bh(&ip_conntrack_lock);
1418                 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
1419                                          list) {
1420                         if (del_timer(&exp->timeout)) {
1421                                 ip_ct_unlink_expect(exp);
1422                                 ip_conntrack_expect_put(exp);
1423                         }
1424                 }
1425                 write_unlock_bh(&ip_conntrack_lock);
1426         }
1427
1428         return 0;
1429 }
1430 static int
1431 ctnetlink_change_expect(struct ip_conntrack_expect *x, struct nfattr *cda[])
1432 {
1433         return -EOPNOTSUPP;
1434 }
1435
1436 static int
1437 ctnetlink_create_expect(struct nfattr *cda[])
1438 {
1439         struct ip_conntrack_tuple tuple, mask, master_tuple;
1440         struct ip_conntrack_tuple_hash *h = NULL;
1441         struct ip_conntrack_expect *exp;
1442         struct ip_conntrack *ct;
1443         int err = 0;
1444
1445         DEBUGP("entered %s\n", __FUNCTION__);
1446
1447         /* caller guarantees that those three CTA_EXPECT_* exist */
1448         err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
1449         if (err < 0)
1450                 return err;
1451         err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK);
1452         if (err < 0)
1453                 return err;
1454         err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER);
1455         if (err < 0)
1456                 return err;
1457
1458         /* Look for master conntrack of this expectation */
1459         h = ip_conntrack_find_get(&master_tuple, NULL);
1460         if (!h)
1461                 return -ENOENT;
1462         ct = tuplehash_to_ctrack(h);
1463
1464         if (!ct->helper) {
1465                 /* such conntrack hasn't got any helper, abort */
1466                 err = -EINVAL;
1467                 goto out;
1468         }
1469
1470         exp = ip_conntrack_expect_alloc(ct);
1471         if (!exp) {
1472                 err = -ENOMEM;
1473                 goto out;
1474         }
1475         
1476         exp->expectfn = NULL;
1477         exp->flags = 0;
1478         exp->master = ct;
1479         memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple));
1480         memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple));
1481
1482         err = ip_conntrack_expect_related(exp);
1483         ip_conntrack_expect_put(exp);
1484
1485 out:    
1486         ip_conntrack_put(tuplehash_to_ctrack(h));
1487         return err;
1488 }
1489
1490 static int
1491 ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
1492                      struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1493 {
1494         struct ip_conntrack_tuple tuple;
1495         struct ip_conntrack_expect *exp;
1496         int err = 0;
1497
1498         DEBUGP("entered %s\n", __FUNCTION__);   
1499
1500         if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1501                 return -EINVAL;
1502
1503         if (!cda[CTA_EXPECT_TUPLE-1]
1504             || !cda[CTA_EXPECT_MASK-1]
1505             || !cda[CTA_EXPECT_MASTER-1])
1506                 return -EINVAL;
1507
1508         err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
1509         if (err < 0)
1510                 return err;
1511
1512         write_lock_bh(&ip_conntrack_lock);
1513         exp = __ip_conntrack_expect_find(&tuple);
1514
1515         if (!exp) {
1516                 write_unlock_bh(&ip_conntrack_lock);
1517                 err = -ENOENT;
1518                 if (nlh->nlmsg_flags & NLM_F_CREATE)
1519                         err = ctnetlink_create_expect(cda);
1520                 return err;
1521         }
1522
1523         err = -EEXIST;
1524         if (!(nlh->nlmsg_flags & NLM_F_EXCL))
1525                 err = ctnetlink_change_expect(exp, cda);
1526         write_unlock_bh(&ip_conntrack_lock);
1527
1528         DEBUGP("leaving\n");
1529         
1530         return err;
1531 }
1532
1533 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1534 static struct notifier_block ctnl_notifier = {
1535         .notifier_call  = ctnetlink_conntrack_event,
1536 };
1537
1538 static struct notifier_block ctnl_notifier_exp = {
1539         .notifier_call  = ctnetlink_expect_event,
1540 };
1541 #endif
1542
1543 static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
1544         [IPCTNL_MSG_CT_NEW]             = { .call = ctnetlink_new_conntrack,
1545                                             .attr_count = CTA_MAX, },
1546         [IPCTNL_MSG_CT_GET]             = { .call = ctnetlink_get_conntrack,
1547                                             .attr_count = CTA_MAX, },
1548         [IPCTNL_MSG_CT_DELETE]          = { .call = ctnetlink_del_conntrack,
1549                                             .attr_count = CTA_MAX, },
1550         [IPCTNL_MSG_CT_GET_CTRZERO]     = { .call = ctnetlink_get_conntrack,
1551                                             .attr_count = CTA_MAX, },
1552 };
1553
1554 static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
1555         [IPCTNL_MSG_EXP_GET]            = { .call = ctnetlink_get_expect,
1556                                             .attr_count = CTA_EXPECT_MAX, },
1557         [IPCTNL_MSG_EXP_NEW]            = { .call = ctnetlink_new_expect,
1558                                             .attr_count = CTA_EXPECT_MAX, },
1559         [IPCTNL_MSG_EXP_DELETE]         = { .call = ctnetlink_del_expect,
1560                                             .attr_count = CTA_EXPECT_MAX, },
1561 };
1562
1563 static struct nfnetlink_subsystem ctnl_subsys = {
1564         .name                           = "conntrack",
1565         .subsys_id                      = NFNL_SUBSYS_CTNETLINK,
1566         .cb_count                       = IPCTNL_MSG_MAX,
1567         .cb                             = ctnl_cb,
1568 };
1569
1570 static struct nfnetlink_subsystem ctnl_exp_subsys = {
1571         .name                           = "conntrack_expect",
1572         .subsys_id                      = NFNL_SUBSYS_CTNETLINK_EXP,
1573         .cb_count                       = IPCTNL_MSG_EXP_MAX,
1574         .cb                             = ctnl_exp_cb,
1575 };
1576
1577 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
1578
1579 static int __init ctnetlink_init(void)
1580 {
1581         int ret;
1582
1583         printk("ctnetlink v%s: registering with nfnetlink.\n", version);
1584         ret = nfnetlink_subsys_register(&ctnl_subsys);
1585         if (ret < 0) {
1586                 printk("ctnetlink_init: cannot register with nfnetlink.\n");
1587                 goto err_out;
1588         }
1589
1590         ret = nfnetlink_subsys_register(&ctnl_exp_subsys);
1591         if (ret < 0) {
1592                 printk("ctnetlink_init: cannot register exp with nfnetlink.\n");
1593                 goto err_unreg_subsys;
1594         }
1595
1596 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1597         ret = ip_conntrack_register_notifier(&ctnl_notifier);
1598         if (ret < 0) {
1599                 printk("ctnetlink_init: cannot register notifier.\n");
1600                 goto err_unreg_exp_subsys;
1601         }
1602
1603         ret = ip_conntrack_expect_register_notifier(&ctnl_notifier_exp);
1604         if (ret < 0) {
1605                 printk("ctnetlink_init: cannot expect register notifier.\n");
1606                 goto err_unreg_notifier;
1607         }
1608 #endif
1609
1610         return 0;
1611
1612 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1613 err_unreg_notifier:
1614         ip_conntrack_unregister_notifier(&ctnl_notifier);
1615 err_unreg_exp_subsys:
1616         nfnetlink_subsys_unregister(&ctnl_exp_subsys);
1617 #endif
1618 err_unreg_subsys:
1619         nfnetlink_subsys_unregister(&ctnl_subsys);
1620 err_out:
1621         return ret;
1622 }
1623
1624 static void __exit ctnetlink_exit(void)
1625 {
1626         printk("ctnetlink: unregistering from nfnetlink.\n");
1627
1628 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1629         ip_conntrack_unregister_notifier(&ctnl_notifier_exp);
1630         ip_conntrack_unregister_notifier(&ctnl_notifier);
1631 #endif
1632
1633         nfnetlink_subsys_unregister(&ctnl_exp_subsys);
1634         nfnetlink_subsys_unregister(&ctnl_subsys);
1635         return;
1636 }
1637
1638 module_init(ctnetlink_init);
1639 module_exit(ctnetlink_exit);