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