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