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