1
2
3
4
5
6
7
8
9
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/sysctl.h>
15#include <linux/spinlock.h>
16#include <linux/skbuff.h>
17#include <linux/dccp.h>
18
19#include <net/net_namespace.h>
20#include <net/netns/generic.h>
21
22#include <linux/netfilter/nfnetlink_conntrack.h>
23#include <net/netfilter/nf_conntrack.h>
24#include <net/netfilter/nf_conntrack_l4proto.h>
25#include <net/netfilter/nf_conntrack_ecache.h>
26#include <net/netfilter/nf_log.h>
27
28static DEFINE_RWLOCK(dccp_lock);
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75#define DCCP_MSL (2 * 60 * HZ)
76
77static const char * const dccp_state_names[] = {
78 [CT_DCCP_NONE] = "NONE",
79 [CT_DCCP_REQUEST] = "REQUEST",
80 [CT_DCCP_RESPOND] = "RESPOND",
81 [CT_DCCP_PARTOPEN] = "PARTOPEN",
82 [CT_DCCP_OPEN] = "OPEN",
83 [CT_DCCP_CLOSEREQ] = "CLOSEREQ",
84 [CT_DCCP_CLOSING] = "CLOSING",
85 [CT_DCCP_TIMEWAIT] = "TIMEWAIT",
86 [CT_DCCP_IGNORE] = "IGNORE",
87 [CT_DCCP_INVALID] = "INVALID",
88};
89
90#define sNO CT_DCCP_NONE
91#define sRQ CT_DCCP_REQUEST
92#define sRS CT_DCCP_RESPOND
93#define sPO CT_DCCP_PARTOPEN
94#define sOP CT_DCCP_OPEN
95#define sCR CT_DCCP_CLOSEREQ
96#define sCG CT_DCCP_CLOSING
97#define sTW CT_DCCP_TIMEWAIT
98#define sIG CT_DCCP_IGNORE
99#define sIV CT_DCCP_INVALID
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133static const u_int8_t
134dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = {
135 [CT_DCCP_ROLE_CLIENT] = {
136 [DCCP_PKT_REQUEST] = {
137
138
139
140
141
142
143
144
145
146
147
148
149 sRQ, sRQ, sRS, sIG, sIG, sIG, sIG, sRQ,
150 },
151 [DCCP_PKT_RESPONSE] = {
152
153
154
155
156
157
158
159
160
161
162
163
164 sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIV,
165 },
166 [DCCP_PKT_ACK] = {
167
168
169
170
171
172
173
174
175
176
177
178 sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV
179 },
180 [DCCP_PKT_DATA] = {
181
182
183
184
185
186
187
188
189
190
191
192 sIV, sIV, sIV, sIV, sOP, sCR, sCG, sIV,
193 },
194 [DCCP_PKT_DATAACK] = {
195
196
197
198
199
200
201
202
203
204
205
206 sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV
207 },
208 [DCCP_PKT_CLOSEREQ] = {
209
210
211
212
213 sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV
214 },
215 [DCCP_PKT_CLOSE] = {
216
217
218
219
220
221
222
223
224
225
226
227 sIV, sIV, sIV, sCG, sCG, sCG, sIV, sIV
228 },
229 [DCCP_PKT_RESET] = {
230
231
232
233
234
235
236
237
238
239
240
241 sIV, sTW, sTW, sTW, sTW, sTW, sTW, sIG
242 },
243 [DCCP_PKT_SYNC] = {
244
245
246
247
248 sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
249 },
250 [DCCP_PKT_SYNCACK] = {
251
252
253
254
255 sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
256 },
257 },
258 [CT_DCCP_ROLE_SERVER] = {
259 [DCCP_PKT_REQUEST] = {
260
261
262
263
264
265
266
267
268
269
270
271 sIV, sIG, sIG, sIG, sIG, sIG, sIG, sRQ
272 },
273 [DCCP_PKT_RESPONSE] = {
274
275
276
277
278
279
280
281
282
283
284
285 sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIV
286 },
287 [DCCP_PKT_ACK] = {
288
289
290
291
292
293
294
295
296
297
298
299 sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
300 },
301 [DCCP_PKT_DATA] = {
302
303
304
305
306
307
308
309
310
311
312
313 sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
314 },
315 [DCCP_PKT_DATAACK] = {
316
317
318
319
320
321
322
323
324
325
326
327 sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
328 },
329 [DCCP_PKT_CLOSEREQ] = {
330
331
332
333
334
335
336
337
338
339
340
341 sIV, sIV, sIV, sCR, sCR, sCR, sCR, sIV
342 },
343 [DCCP_PKT_CLOSE] = {
344
345
346
347
348
349
350
351
352
353
354
355 sIV, sIV, sIV, sCG, sCG, sIV, sCG, sIV
356 },
357 [DCCP_PKT_RESET] = {
358
359
360
361
362
363
364
365
366
367
368
369 sIV, sTW, sTW, sTW, sTW, sTW, sTW, sTW, sIG
370 },
371 [DCCP_PKT_SYNC] = {
372
373
374
375
376 sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
377 },
378 [DCCP_PKT_SYNCACK] = {
379
380
381
382
383 sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
384 },
385 },
386};
387
388
389static int dccp_net_id;
390struct dccp_net {
391 int dccp_loose;
392 unsigned int dccp_timeout[CT_DCCP_MAX + 1];
393#ifdef CONFIG_SYSCTL
394 struct ctl_table_header *sysctl_header;
395 struct ctl_table *sysctl_table;
396#endif
397};
398
399static inline struct dccp_net *dccp_pernet(struct net *net)
400{
401 return net_generic(net, dccp_net_id);
402}
403
404static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
405 struct nf_conntrack_tuple *tuple)
406{
407 struct dccp_hdr _hdr, *dh;
408
409 dh = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
410 if (dh == NULL)
411 return false;
412
413 tuple->src.u.dccp.port = dh->dccph_sport;
414 tuple->dst.u.dccp.port = dh->dccph_dport;
415 return true;
416}
417
418static bool dccp_invert_tuple(struct nf_conntrack_tuple *inv,
419 const struct nf_conntrack_tuple *tuple)
420{
421 inv->src.u.dccp.port = tuple->dst.u.dccp.port;
422 inv->dst.u.dccp.port = tuple->src.u.dccp.port;
423 return true;
424}
425
426static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
427 unsigned int dataoff)
428{
429 struct net *net = nf_ct_net(ct);
430 struct dccp_net *dn;
431 struct dccp_hdr _dh, *dh;
432 const char *msg;
433 u_int8_t state;
434
435 dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
436 BUG_ON(dh == NULL);
437
438 state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE];
439 switch (state) {
440 default:
441 dn = dccp_pernet(net);
442 if (dn->dccp_loose == 0) {
443 msg = "nf_ct_dccp: not picking up existing connection ";
444 goto out_invalid;
445 }
446 case CT_DCCP_REQUEST:
447 break;
448 case CT_DCCP_INVALID:
449 msg = "nf_ct_dccp: invalid state transition ";
450 goto out_invalid;
451 }
452
453 ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
454 ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
455 ct->proto.dccp.state = CT_DCCP_NONE;
456 return true;
457
458out_invalid:
459 if (LOG_INVALID(net, IPPROTO_DCCP))
460 nf_log_packet(nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL, msg);
461 return false;
462}
463
464static u64 dccp_ack_seq(const struct dccp_hdr *dh)
465{
466 const struct dccp_hdr_ack_bits *dhack;
467
468 dhack = (void *)dh + __dccp_basic_hdr_len(dh);
469 return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) +
470 ntohl(dhack->dccph_ack_nr_low);
471}
472
473static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
474 unsigned int dataoff, enum ip_conntrack_info ctinfo,
475 u_int8_t pf, unsigned int hooknum)
476{
477 struct net *net = nf_ct_net(ct);
478 struct dccp_net *dn;
479 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
480 struct dccp_hdr _dh, *dh;
481 u_int8_t type, old_state, new_state;
482 enum ct_dccp_roles role;
483
484 dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
485 BUG_ON(dh == NULL);
486 type = dh->dccph_type;
487
488 if (type == DCCP_PKT_RESET &&
489 !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
490
491 nf_ct_kill_acct(ct, ctinfo, skb);
492 return NF_ACCEPT;
493 }
494
495 write_lock_bh(&dccp_lock);
496
497 role = ct->proto.dccp.role[dir];
498 old_state = ct->proto.dccp.state;
499 new_state = dccp_state_table[role][type][old_state];
500
501 switch (new_state) {
502 case CT_DCCP_REQUEST:
503 if (old_state == CT_DCCP_TIMEWAIT &&
504 role == CT_DCCP_ROLE_SERVER) {
505
506
507 ct->proto.dccp.role[dir] = CT_DCCP_ROLE_CLIENT;
508 ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_SERVER;
509 }
510 break;
511 case CT_DCCP_RESPOND:
512 if (old_state == CT_DCCP_REQUEST)
513 ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh);
514 break;
515 case CT_DCCP_PARTOPEN:
516 if (old_state == CT_DCCP_RESPOND &&
517 type == DCCP_PKT_ACK &&
518 dccp_ack_seq(dh) == ct->proto.dccp.handshake_seq)
519 set_bit(IPS_ASSURED_BIT, &ct->status);
520 break;
521 case CT_DCCP_IGNORE:
522
523
524
525
526
527 if (ct->proto.dccp.last_dir == !dir &&
528 ct->proto.dccp.last_pkt == DCCP_PKT_REQUEST &&
529 type == DCCP_PKT_RESPONSE) {
530 ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_CLIENT;
531 ct->proto.dccp.role[dir] = CT_DCCP_ROLE_SERVER;
532 ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh);
533 new_state = CT_DCCP_RESPOND;
534 break;
535 }
536 ct->proto.dccp.last_dir = dir;
537 ct->proto.dccp.last_pkt = type;
538
539 write_unlock_bh(&dccp_lock);
540 if (LOG_INVALID(net, IPPROTO_DCCP))
541 nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
542 "nf_ct_dccp: invalid packet ignored ");
543 return NF_ACCEPT;
544 case CT_DCCP_INVALID:
545 write_unlock_bh(&dccp_lock);
546 if (LOG_INVALID(net, IPPROTO_DCCP))
547 nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
548 "nf_ct_dccp: invalid state transition ");
549 return -NF_ACCEPT;
550 }
551
552 ct->proto.dccp.last_dir = dir;
553 ct->proto.dccp.last_pkt = type;
554 ct->proto.dccp.state = new_state;
555 write_unlock_bh(&dccp_lock);
556
557 if (new_state != old_state)
558 nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
559
560 dn = dccp_pernet(net);
561 nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]);
562
563 return NF_ACCEPT;
564}
565
566static int dccp_error(struct net *net, struct sk_buff *skb,
567 unsigned int dataoff, enum ip_conntrack_info *ctinfo,
568 u_int8_t pf, unsigned int hooknum)
569{
570 struct dccp_hdr _dh, *dh;
571 unsigned int dccp_len = skb->len - dataoff;
572 unsigned int cscov;
573 const char *msg;
574
575 dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
576 if (dh == NULL) {
577 msg = "nf_ct_dccp: short packet ";
578 goto out_invalid;
579 }
580
581 if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) ||
582 dh->dccph_doff * 4 > dccp_len) {
583 msg = "nf_ct_dccp: truncated/malformed packet ";
584 goto out_invalid;
585 }
586
587 cscov = dccp_len;
588 if (dh->dccph_cscov) {
589 cscov = (dh->dccph_cscov - 1) * 4;
590 if (cscov > dccp_len) {
591 msg = "nf_ct_dccp: bad checksum coverage ";
592 goto out_invalid;
593 }
594 }
595
596 if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
597 nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_DCCP,
598 pf)) {
599 msg = "nf_ct_dccp: bad checksum ";
600 goto out_invalid;
601 }
602
603 if (dh->dccph_type >= DCCP_PKT_INVALID) {
604 msg = "nf_ct_dccp: reserved packet type ";
605 goto out_invalid;
606 }
607
608 return NF_ACCEPT;
609
610out_invalid:
611 if (LOG_INVALID(net, IPPROTO_DCCP))
612 nf_log_packet(pf, 0, skb, NULL, NULL, NULL, msg);
613 return -NF_ACCEPT;
614}
615
616static int dccp_print_tuple(struct seq_file *s,
617 const struct nf_conntrack_tuple *tuple)
618{
619 return seq_printf(s, "sport=%hu dport=%hu ",
620 ntohs(tuple->src.u.dccp.port),
621 ntohs(tuple->dst.u.dccp.port));
622}
623
624static int dccp_print_conntrack(struct seq_file *s, const struct nf_conn *ct)
625{
626 return seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]);
627}
628
629#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
630static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
631 const struct nf_conn *ct)
632{
633 struct nlattr *nest_parms;
634
635 read_lock_bh(&dccp_lock);
636 nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED);
637 if (!nest_parms)
638 goto nla_put_failure;
639 NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state);
640 NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_ROLE,
641 ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]);
642 nla_nest_end(skb, nest_parms);
643 read_unlock_bh(&dccp_lock);
644 return 0;
645
646nla_put_failure:
647 read_unlock_bh(&dccp_lock);
648 return -1;
649}
650
651static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = {
652 [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 },
653 [CTA_PROTOINFO_DCCP_ROLE] = { .type = NLA_U8 },
654};
655
656static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
657{
658 struct nlattr *attr = cda[CTA_PROTOINFO_DCCP];
659 struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX + 1];
660 int err;
661
662 if (!attr)
663 return 0;
664
665 err = nla_parse_nested(tb, CTA_PROTOINFO_DCCP_MAX, attr,
666 dccp_nla_policy);
667 if (err < 0)
668 return err;
669
670 if (!tb[CTA_PROTOINFO_DCCP_STATE] ||
671 !tb[CTA_PROTOINFO_DCCP_ROLE] ||
672 nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) > CT_DCCP_ROLE_MAX ||
673 nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) {
674 return -EINVAL;
675 }
676
677 write_lock_bh(&dccp_lock);
678 ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]);
679 if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) {
680 ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
681 ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
682 } else {
683 ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER;
684 ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT;
685 }
686 write_unlock_bh(&dccp_lock);
687 return 0;
688}
689
690static int dccp_nlattr_size(void)
691{
692 return nla_total_size(0)
693 + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1);
694}
695#endif
696
697#ifdef CONFIG_SYSCTL
698
699static struct ctl_table dccp_sysctl_table[] = {
700 {
701 .ctl_name = CTL_UNNUMBERED,
702 .procname = "nf_conntrack_dccp_timeout_request",
703 .maxlen = sizeof(unsigned int),
704 .mode = 0644,
705 .proc_handler = proc_dointvec_jiffies,
706 },
707 {
708 .ctl_name = CTL_UNNUMBERED,
709 .procname = "nf_conntrack_dccp_timeout_respond",
710 .maxlen = sizeof(unsigned int),
711 .mode = 0644,
712 .proc_handler = proc_dointvec_jiffies,
713 },
714 {
715 .ctl_name = CTL_UNNUMBERED,
716 .procname = "nf_conntrack_dccp_timeout_partopen",
717 .maxlen = sizeof(unsigned int),
718 .mode = 0644,
719 .proc_handler = proc_dointvec_jiffies,
720 },
721 {
722 .ctl_name = CTL_UNNUMBERED,
723 .procname = "nf_conntrack_dccp_timeout_open",
724 .maxlen = sizeof(unsigned int),
725 .mode = 0644,
726 .proc_handler = proc_dointvec_jiffies,
727 },
728 {
729 .ctl_name = CTL_UNNUMBERED,
730 .procname = "nf_conntrack_dccp_timeout_closereq",
731 .maxlen = sizeof(unsigned int),
732 .mode = 0644,
733 .proc_handler = proc_dointvec_jiffies,
734 },
735 {
736 .ctl_name = CTL_UNNUMBERED,
737 .procname = "nf_conntrack_dccp_timeout_closing",
738 .maxlen = sizeof(unsigned int),
739 .mode = 0644,
740 .proc_handler = proc_dointvec_jiffies,
741 },
742 {
743 .ctl_name = CTL_UNNUMBERED,
744 .procname = "nf_conntrack_dccp_timeout_timewait",
745 .maxlen = sizeof(unsigned int),
746 .mode = 0644,
747 .proc_handler = proc_dointvec_jiffies,
748 },
749 {
750 .ctl_name = CTL_UNNUMBERED,
751 .procname = "nf_conntrack_dccp_loose",
752 .maxlen = sizeof(int),
753 .mode = 0644,
754 .proc_handler = proc_dointvec,
755 },
756 {
757 .ctl_name = 0,
758 }
759};
760#endif
761
762static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
763 .l3proto = AF_INET,
764 .l4proto = IPPROTO_DCCP,
765 .name = "dccp",
766 .pkt_to_tuple = dccp_pkt_to_tuple,
767 .invert_tuple = dccp_invert_tuple,
768 .new = dccp_new,
769 .packet = dccp_packet,
770 .error = dccp_error,
771 .print_tuple = dccp_print_tuple,
772 .print_conntrack = dccp_print_conntrack,
773#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
774 .to_nlattr = dccp_to_nlattr,
775 .nlattr_size = dccp_nlattr_size,
776 .from_nlattr = nlattr_to_dccp,
777 .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
778 .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
779 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
780 .nla_policy = nf_ct_port_nla_policy,
781#endif
782};
783
784static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
785 .l3proto = AF_INET6,
786 .l4proto = IPPROTO_DCCP,
787 .name = "dccp",
788 .pkt_to_tuple = dccp_pkt_to_tuple,
789 .invert_tuple = dccp_invert_tuple,
790 .new = dccp_new,
791 .packet = dccp_packet,
792 .error = dccp_error,
793 .print_tuple = dccp_print_tuple,
794 .print_conntrack = dccp_print_conntrack,
795#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
796 .to_nlattr = dccp_to_nlattr,
797 .nlattr_size = dccp_nlattr_size,
798 .from_nlattr = nlattr_to_dccp,
799 .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
800 .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
801 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
802 .nla_policy = nf_ct_port_nla_policy,
803#endif
804};
805
806static __net_init int dccp_net_init(struct net *net)
807{
808 struct dccp_net *dn;
809 int err;
810
811 dn = kmalloc(sizeof(*dn), GFP_KERNEL);
812 if (!dn)
813 return -ENOMEM;
814
815
816 dn->dccp_loose = 1;
817 dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL;
818 dn->dccp_timeout[CT_DCCP_RESPOND] = 4 * DCCP_MSL;
819 dn->dccp_timeout[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL;
820 dn->dccp_timeout[CT_DCCP_OPEN] = 12 * 3600 * HZ;
821 dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ;
822 dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ;
823 dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL;
824
825 err = net_assign_generic(net, dccp_net_id, dn);
826 if (err)
827 goto out;
828
829#ifdef CONFIG_SYSCTL
830 err = -ENOMEM;
831 dn->sysctl_table = kmemdup(dccp_sysctl_table,
832 sizeof(dccp_sysctl_table), GFP_KERNEL);
833 if (!dn->sysctl_table)
834 goto out;
835
836 dn->sysctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
837 dn->sysctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
838 dn->sysctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
839 dn->sysctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
840 dn->sysctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
841 dn->sysctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
842 dn->sysctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
843 dn->sysctl_table[7].data = &dn->dccp_loose;
844
845 dn->sysctl_header = register_net_sysctl_table(net,
846 nf_net_netfilter_sysctl_path, dn->sysctl_table);
847 if (!dn->sysctl_header) {
848 kfree(dn->sysctl_table);
849 goto out;
850 }
851#endif
852
853 return 0;
854
855out:
856 kfree(dn);
857 return err;
858}
859
860static __net_exit void dccp_net_exit(struct net *net)
861{
862 struct dccp_net *dn = dccp_pernet(net);
863#ifdef CONFIG_SYSCTL
864 unregister_net_sysctl_table(dn->sysctl_header);
865 kfree(dn->sysctl_table);
866#endif
867 kfree(dn);
868
869 net_assign_generic(net, dccp_net_id, NULL);
870}
871
872static struct pernet_operations dccp_net_ops = {
873 .init = dccp_net_init,
874 .exit = dccp_net_exit,
875};
876
877static int __init nf_conntrack_proto_dccp_init(void)
878{
879 int err;
880
881 err = register_pernet_gen_subsys(&dccp_net_id, &dccp_net_ops);
882 if (err < 0)
883 goto err1;
884
885 err = nf_conntrack_l4proto_register(&dccp_proto4);
886 if (err < 0)
887 goto err2;
888
889 err = nf_conntrack_l4proto_register(&dccp_proto6);
890 if (err < 0)
891 goto err3;
892 return 0;
893
894err3:
895 nf_conntrack_l4proto_unregister(&dccp_proto4);
896err2:
897 unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops);
898err1:
899 return err;
900}
901
902static void __exit nf_conntrack_proto_dccp_fini(void)
903{
904 unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops);
905 nf_conntrack_l4proto_unregister(&dccp_proto6);
906 nf_conntrack_l4proto_unregister(&dccp_proto4);
907}
908
909module_init(nf_conntrack_proto_dccp_init);
910module_exit(nf_conntrack_proto_dccp_fini);
911
912MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
913MODULE_DESCRIPTION("DCCP connection tracking protocol helper");
914MODULE_LICENSE("GPL");
915