aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/proto.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/proto.c')
-rw-r--r--net/dccp/proto.c440
1 files changed, 301 insertions, 139 deletions
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 65b11ea90d85..d4b293e16283 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -23,9 +23,7 @@
23#include <linux/random.h> 23#include <linux/random.h>
24#include <net/checksum.h> 24#include <net/checksum.h>
25 25
26#include <net/inet_common.h>
27#include <net/inet_sock.h> 26#include <net/inet_sock.h>
28#include <net/protocol.h>
29#include <net/sock.h> 27#include <net/sock.h>
30#include <net/xfrm.h> 28#include <net/xfrm.h>
31 29
@@ -37,6 +35,7 @@
37 35
38#include "ccid.h" 36#include "ccid.h"
39#include "dccp.h" 37#include "dccp.h"
38#include "feat.h"
40 39
41DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly; 40DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
42 41
@@ -46,12 +45,66 @@ atomic_t dccp_orphan_count = ATOMIC_INIT(0);
46 45
47EXPORT_SYMBOL_GPL(dccp_orphan_count); 46EXPORT_SYMBOL_GPL(dccp_orphan_count);
48 47
49static struct net_protocol dccp_protocol = { 48struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
50 .handler = dccp_v4_rcv, 49 .lhash_lock = RW_LOCK_UNLOCKED,
51 .err_handler = dccp_v4_err, 50 .lhash_users = ATOMIC_INIT(0),
52 .no_policy = 1, 51 .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait),
53}; 52};
54 53
54EXPORT_SYMBOL_GPL(dccp_hashinfo);
55
56void dccp_set_state(struct sock *sk, const int state)
57{
58 const int oldstate = sk->sk_state;
59
60 dccp_pr_debug("%s(%p) %-10.10s -> %s\n",
61 dccp_role(sk), sk,
62 dccp_state_name(oldstate), dccp_state_name(state));
63 WARN_ON(state == oldstate);
64
65 switch (state) {
66 case DCCP_OPEN:
67 if (oldstate != DCCP_OPEN)
68 DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
69 break;
70
71 case DCCP_CLOSED:
72 if (oldstate == DCCP_CLOSING || oldstate == DCCP_OPEN)
73 DCCP_INC_STATS(DCCP_MIB_ESTABRESETS);
74
75 sk->sk_prot->unhash(sk);
76 if (inet_csk(sk)->icsk_bind_hash != NULL &&
77 !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
78 inet_put_port(&dccp_hashinfo, sk);
79 /* fall through */
80 default:
81 if (oldstate == DCCP_OPEN)
82 DCCP_DEC_STATS(DCCP_MIB_CURRESTAB);
83 }
84
85 /* Change state AFTER socket is unhashed to avoid closed
86 * socket sitting in hash tables.
87 */
88 sk->sk_state = state;
89}
90
91EXPORT_SYMBOL_GPL(dccp_set_state);
92
93void dccp_done(struct sock *sk)
94{
95 dccp_set_state(sk, DCCP_CLOSED);
96 dccp_clear_xmit_timers(sk);
97
98 sk->sk_shutdown = SHUTDOWN_MASK;
99
100 if (!sock_flag(sk, SOCK_DEAD))
101 sk->sk_state_change(sk);
102 else
103 inet_csk_destroy_sock(sk);
104}
105
106EXPORT_SYMBOL_GPL(dccp_done);
107
55const char *dccp_packet_name(const int type) 108const char *dccp_packet_name(const int type)
56{ 109{
57 static const char *dccp_packet_names[] = { 110 static const char *dccp_packet_names[] = {
@@ -96,6 +149,120 @@ const char *dccp_state_name(const int state)
96 149
97EXPORT_SYMBOL_GPL(dccp_state_name); 150EXPORT_SYMBOL_GPL(dccp_state_name);
98 151
152void dccp_hash(struct sock *sk)
153{
154 inet_hash(&dccp_hashinfo, sk);
155}
156
157EXPORT_SYMBOL_GPL(dccp_hash);
158
159void dccp_unhash(struct sock *sk)
160{
161 inet_unhash(&dccp_hashinfo, sk);
162}
163
164EXPORT_SYMBOL_GPL(dccp_unhash);
165
166int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
167{
168 struct dccp_sock *dp = dccp_sk(sk);
169 struct dccp_minisock *dmsk = dccp_msk(sk);
170 struct inet_connection_sock *icsk = inet_csk(sk);
171
172 dccp_minisock_init(&dp->dccps_minisock);
173 do_gettimeofday(&dp->dccps_epoch);
174
175 /*
176 * FIXME: We're hardcoding the CCID, and doing this at this point makes
177 * the listening (master) sock get CCID control blocks, which is not
178 * necessary, but for now, to not mess with the test userspace apps,
179 * lets leave it here, later the real solution is to do this in a
180 * setsockopt(CCIDs-I-want/accept). -acme
181 */
182 if (likely(ctl_sock_initialized)) {
183 int rc = dccp_feat_init(dmsk);
184
185 if (rc)
186 return rc;
187
188 if (dmsk->dccpms_send_ack_vector) {
189 dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
190 if (dp->dccps_hc_rx_ackvec == NULL)
191 return -ENOMEM;
192 }
193 dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid,
194 sk, GFP_KERNEL);
195 dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
196 sk, GFP_KERNEL);
197 if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
198 dp->dccps_hc_tx_ccid == NULL)) {
199 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
200 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
201 if (dmsk->dccpms_send_ack_vector) {
202 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
203 dp->dccps_hc_rx_ackvec = NULL;
204 }
205 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
206 return -ENOMEM;
207 }
208 } else {
209 /* control socket doesn't need feat nego */
210 INIT_LIST_HEAD(&dmsk->dccpms_pending);
211 INIT_LIST_HEAD(&dmsk->dccpms_conf);
212 }
213
214 dccp_init_xmit_timers(sk);
215 icsk->icsk_rto = DCCP_TIMEOUT_INIT;
216 sk->sk_state = DCCP_CLOSED;
217 sk->sk_write_space = dccp_write_space;
218 icsk->icsk_sync_mss = dccp_sync_mss;
219 dp->dccps_mss_cache = 536;
220 dp->dccps_role = DCCP_ROLE_UNDEFINED;
221 dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
222 dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
223
224 return 0;
225}
226
227EXPORT_SYMBOL_GPL(dccp_init_sock);
228
229int dccp_destroy_sock(struct sock *sk)
230{
231 struct dccp_sock *dp = dccp_sk(sk);
232 struct dccp_minisock *dmsk = dccp_msk(sk);
233
234 /*
235 * DCCP doesn't use sk_write_queue, just sk_send_head
236 * for retransmissions
237 */
238 if (sk->sk_send_head != NULL) {
239 kfree_skb(sk->sk_send_head);
240 sk->sk_send_head = NULL;
241 }
242
243 /* Clean up a referenced DCCP bind bucket. */
244 if (inet_csk(sk)->icsk_bind_hash != NULL)
245 inet_put_port(&dccp_hashinfo, sk);
246
247 kfree(dp->dccps_service_list);
248 dp->dccps_service_list = NULL;
249
250 if (dmsk->dccpms_send_ack_vector) {
251 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
252 dp->dccps_hc_rx_ackvec = NULL;
253 }
254 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
255 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
256 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
257
258 /* clean up feature negotiation state */
259 dccp_feat_clean(dmsk);
260
261 return 0;
262}
263
264EXPORT_SYMBOL_GPL(dccp_destroy_sock);
265
99static inline int dccp_listen_start(struct sock *sk) 266static inline int dccp_listen_start(struct sock *sk)
100{ 267{
101 struct dccp_sock *dp = dccp_sk(sk); 268 struct dccp_sock *dp = dccp_sk(sk);
@@ -220,7 +387,7 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
220 387
221EXPORT_SYMBOL_GPL(dccp_ioctl); 388EXPORT_SYMBOL_GPL(dccp_ioctl);
222 389
223static int dccp_setsockopt_service(struct sock *sk, const u32 service, 390static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
224 char __user *optval, int optlen) 391 char __user *optval, int optlen)
225{ 392{
226 struct dccp_sock *dp = dccp_sk(sk); 393 struct dccp_sock *dp = dccp_sk(sk);
@@ -255,18 +422,46 @@ static int dccp_setsockopt_service(struct sock *sk, const u32 service,
255 return 0; 422 return 0;
256} 423}
257 424
258int dccp_setsockopt(struct sock *sk, int level, int optname, 425/* byte 1 is feature. the rest is the preference list */
259 char __user *optval, int optlen) 426static int dccp_setsockopt_change(struct sock *sk, int type,
427 struct dccp_so_feat __user *optval)
428{
429 struct dccp_so_feat opt;
430 u8 *val;
431 int rc;
432
433 if (copy_from_user(&opt, optval, sizeof(opt)))
434 return -EFAULT;
435
436 val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
437 if (!val)
438 return -ENOMEM;
439
440 if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) {
441 rc = -EFAULT;
442 goto out_free_val;
443 }
444
445 rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat,
446 val, opt.dccpsf_len, GFP_KERNEL);
447 if (rc)
448 goto out_free_val;
449
450out:
451 return rc;
452
453out_free_val:
454 kfree(val);
455 goto out;
456}
457
458static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
459 char __user *optval, int optlen)
260{ 460{
261 struct dccp_sock *dp; 461 struct dccp_sock *dp;
262 int err; 462 int err;
263 int val; 463 int val;
264 464
265 if (level != SOL_DCCP)
266 return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
267 optname, optval,
268 optlen);
269
270 if (optlen < sizeof(int)) 465 if (optlen < sizeof(int))
271 return -EINVAL; 466 return -EINVAL;
272 467
@@ -284,6 +479,25 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
284 case DCCP_SOCKOPT_PACKET_SIZE: 479 case DCCP_SOCKOPT_PACKET_SIZE:
285 dp->dccps_packet_size = val; 480 dp->dccps_packet_size = val;
286 break; 481 break;
482
483 case DCCP_SOCKOPT_CHANGE_L:
484 if (optlen != sizeof(struct dccp_so_feat))
485 err = -EINVAL;
486 else
487 err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
488 (struct dccp_so_feat *)
489 optval);
490 break;
491
492 case DCCP_SOCKOPT_CHANGE_R:
493 if (optlen != sizeof(struct dccp_so_feat))
494 err = -EINVAL;
495 else
496 err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
497 (struct dccp_so_feat *)
498 optval);
499 break;
500
287 default: 501 default:
288 err = -ENOPROTOOPT; 502 err = -ENOPROTOOPT;
289 break; 503 break;
@@ -293,10 +507,33 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
293 return err; 507 return err;
294} 508}
295 509
510int dccp_setsockopt(struct sock *sk, int level, int optname,
511 char __user *optval, int optlen)
512{
513 if (level != SOL_DCCP)
514 return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
515 optname, optval,
516 optlen);
517 return do_dccp_setsockopt(sk, level, optname, optval, optlen);
518}
519
296EXPORT_SYMBOL_GPL(dccp_setsockopt); 520EXPORT_SYMBOL_GPL(dccp_setsockopt);
297 521
522#ifdef CONFIG_COMPAT
523int compat_dccp_setsockopt(struct sock *sk, int level, int optname,
524 char __user *optval, int optlen)
525{
526 if (level != SOL_DCCP)
527 return inet_csk_compat_setsockopt(sk, level, optname,
528 optval, optlen);
529 return do_dccp_setsockopt(sk, level, optname, optval, optlen);
530}
531
532EXPORT_SYMBOL_GPL(compat_dccp_setsockopt);
533#endif
534
298static int dccp_getsockopt_service(struct sock *sk, int len, 535static int dccp_getsockopt_service(struct sock *sk, int len,
299 u32 __user *optval, 536 __be32 __user *optval,
300 int __user *optlen) 537 int __user *optlen)
301{ 538{
302 const struct dccp_sock *dp = dccp_sk(sk); 539 const struct dccp_sock *dp = dccp_sk(sk);
@@ -326,16 +563,12 @@ out:
326 return err; 563 return err;
327} 564}
328 565
329int dccp_getsockopt(struct sock *sk, int level, int optname, 566static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
330 char __user *optval, int __user *optlen) 567 char __user *optval, int __user *optlen)
331{ 568{
332 struct dccp_sock *dp; 569 struct dccp_sock *dp;
333 int val, len; 570 int val, len;
334 571
335 if (level != SOL_DCCP)
336 return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
337 optname, optval,
338 optlen);
339 if (get_user(len, optlen)) 572 if (get_user(len, optlen))
340 return -EFAULT; 573 return -EFAULT;
341 574
@@ -351,7 +584,7 @@ int dccp_getsockopt(struct sock *sk, int level, int optname,
351 break; 584 break;
352 case DCCP_SOCKOPT_SERVICE: 585 case DCCP_SOCKOPT_SERVICE:
353 return dccp_getsockopt_service(sk, len, 586 return dccp_getsockopt_service(sk, len,
354 (u32 __user *)optval, optlen); 587 (__be32 __user *)optval, optlen);
355 case 128 ... 191: 588 case 128 ... 191:
356 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, 589 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
357 len, (u32 __user *)optval, optlen); 590 len, (u32 __user *)optval, optlen);
@@ -368,8 +601,31 @@ int dccp_getsockopt(struct sock *sk, int level, int optname,
368 return 0; 601 return 0;
369} 602}
370 603
604int dccp_getsockopt(struct sock *sk, int level, int optname,
605 char __user *optval, int __user *optlen)
606{
607 if (level != SOL_DCCP)
608 return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
609 optname, optval,
610 optlen);
611 return do_dccp_getsockopt(sk, level, optname, optval, optlen);
612}
613
371EXPORT_SYMBOL_GPL(dccp_getsockopt); 614EXPORT_SYMBOL_GPL(dccp_getsockopt);
372 615
616#ifdef CONFIG_COMPAT
617int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
618 char __user *optval, int __user *optlen)
619{
620 if (level != SOL_DCCP)
621 return inet_csk_compat_getsockopt(sk, level, optname,
622 optval, optlen);
623 return do_dccp_getsockopt(sk, level, optname, optval, optlen);
624}
625
626EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
627#endif
628
373int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 629int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
374 size_t len) 630 size_t len)
375{ 631{
@@ -679,84 +935,7 @@ void dccp_shutdown(struct sock *sk, int how)
679 935
680EXPORT_SYMBOL_GPL(dccp_shutdown); 936EXPORT_SYMBOL_GPL(dccp_shutdown);
681 937
682static const struct proto_ops inet_dccp_ops = { 938static int __init dccp_mib_init(void)
683 .family = PF_INET,
684 .owner = THIS_MODULE,
685 .release = inet_release,
686 .bind = inet_bind,
687 .connect = inet_stream_connect,
688 .socketpair = sock_no_socketpair,
689 .accept = inet_accept,
690 .getname = inet_getname,
691 /* FIXME: work on tcp_poll to rename it to inet_csk_poll */
692 .poll = dccp_poll,
693 .ioctl = inet_ioctl,
694 /* FIXME: work on inet_listen to rename it to sock_common_listen */
695 .listen = inet_dccp_listen,
696 .shutdown = inet_shutdown,
697 .setsockopt = sock_common_setsockopt,
698 .getsockopt = sock_common_getsockopt,
699 .sendmsg = inet_sendmsg,
700 .recvmsg = sock_common_recvmsg,
701 .mmap = sock_no_mmap,
702 .sendpage = sock_no_sendpage,
703};
704
705extern struct net_proto_family inet_family_ops;
706
707static struct inet_protosw dccp_v4_protosw = {
708 .type = SOCK_DCCP,
709 .protocol = IPPROTO_DCCP,
710 .prot = &dccp_prot,
711 .ops = &inet_dccp_ops,
712 .capability = -1,
713 .no_check = 0,
714 .flags = INET_PROTOSW_ICSK,
715};
716
717/*
718 * This is the global socket data structure used for responding to
719 * the Out-of-the-blue (OOTB) packets. A control sock will be created
720 * for this socket at the initialization time.
721 */
722struct socket *dccp_ctl_socket;
723
724static char dccp_ctl_socket_err_msg[] __initdata =
725 KERN_ERR "DCCP: Failed to create the control socket.\n";
726
727static int __init dccp_ctl_sock_init(void)
728{
729 int rc = sock_create_kern(PF_INET, SOCK_DCCP, IPPROTO_DCCP,
730 &dccp_ctl_socket);
731 if (rc < 0)
732 printk(dccp_ctl_socket_err_msg);
733 else {
734 dccp_ctl_socket->sk->sk_allocation = GFP_ATOMIC;
735 inet_sk(dccp_ctl_socket->sk)->uc_ttl = -1;
736
737 /* Unhash it so that IP input processing does not even
738 * see it, we do not wish this socket to see incoming
739 * packets.
740 */
741 dccp_ctl_socket->sk->sk_prot->unhash(dccp_ctl_socket->sk);
742 }
743
744 return rc;
745}
746
747#ifdef CONFIG_IP_DCCP_UNLOAD_HACK
748void dccp_ctl_sock_exit(void)
749{
750 if (dccp_ctl_socket != NULL) {
751 sock_release(dccp_ctl_socket);
752 dccp_ctl_socket = NULL;
753 }
754}
755
756EXPORT_SYMBOL_GPL(dccp_ctl_sock_exit);
757#endif
758
759static int __init init_dccp_v4_mibs(void)
760{ 939{
761 int rc = -ENOMEM; 940 int rc = -ENOMEM;
762 941
@@ -778,6 +957,13 @@ out_free_one:
778 957
779} 958}
780 959
960static void dccp_mib_exit(void)
961{
962 free_percpu(dccp_statistics[0]);
963 free_percpu(dccp_statistics[1]);
964 dccp_statistics[0] = dccp_statistics[1] = NULL;
965}
966
781static int thash_entries; 967static int thash_entries;
782module_param(thash_entries, int, 0444); 968module_param(thash_entries, int, 0444);
783MODULE_PARM_DESC(thash_entries, "Number of ehash buckets"); 969MODULE_PARM_DESC(thash_entries, "Number of ehash buckets");
@@ -794,17 +980,14 @@ static int __init dccp_init(void)
794{ 980{
795 unsigned long goal; 981 unsigned long goal;
796 int ehash_order, bhash_order, i; 982 int ehash_order, bhash_order, i;
797 int rc = proto_register(&dccp_prot, 1); 983 int rc = -ENOBUFS;
798
799 if (rc)
800 goto out;
801 984
802 dccp_hashinfo.bind_bucket_cachep = 985 dccp_hashinfo.bind_bucket_cachep =
803 kmem_cache_create("dccp_bind_bucket", 986 kmem_cache_create("dccp_bind_bucket",
804 sizeof(struct inet_bind_bucket), 0, 987 sizeof(struct inet_bind_bucket), 0,
805 SLAB_HWCACHE_ALIGN, NULL, NULL); 988 SLAB_HWCACHE_ALIGN, NULL, NULL);
806 if (!dccp_hashinfo.bind_bucket_cachep) 989 if (!dccp_hashinfo.bind_bucket_cachep)
807 goto out_proto_unregister; 990 goto out;
808 991
809 /* 992 /*
810 * Size and allocate the main established and bind bucket 993 * Size and allocate the main established and bind bucket
@@ -866,27 +1049,23 @@ static int __init dccp_init(void)
866 INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain); 1049 INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain);
867 } 1050 }
868 1051
869 if (init_dccp_v4_mibs()) 1052 rc = dccp_mib_init();
1053 if (rc)
870 goto out_free_dccp_bhash; 1054 goto out_free_dccp_bhash;
871 1055
872 rc = -EAGAIN; 1056 rc = dccp_ackvec_init();
873 if (inet_add_protocol(&dccp_protocol, IPPROTO_DCCP)) 1057 if (rc)
874 goto out_free_dccp_v4_mibs; 1058 goto out_free_dccp_mib;
875
876 inet_register_protosw(&dccp_v4_protosw);
877 1059
878 rc = dccp_ctl_sock_init(); 1060 rc = dccp_sysctl_init();
879 if (rc) 1061 if (rc)
880 goto out_unregister_protosw; 1062 goto out_ackvec_exit;
881out: 1063out:
882 return rc; 1064 return rc;
883out_unregister_protosw: 1065out_ackvec_exit:
884 inet_unregister_protosw(&dccp_v4_protosw); 1066 dccp_ackvec_exit();
885 inet_del_protocol(&dccp_protocol, IPPROTO_DCCP); 1067out_free_dccp_mib:
886out_free_dccp_v4_mibs: 1068 dccp_mib_exit();
887 free_percpu(dccp_statistics[0]);
888 free_percpu(dccp_statistics[1]);
889 dccp_statistics[0] = dccp_statistics[1] = NULL;
890out_free_dccp_bhash: 1069out_free_dccp_bhash:
891 free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order); 1070 free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
892 dccp_hashinfo.bhash = NULL; 1071 dccp_hashinfo.bhash = NULL;
@@ -896,23 +1075,12 @@ out_free_dccp_ehash:
896out_free_bind_bucket_cachep: 1075out_free_bind_bucket_cachep:
897 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); 1076 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
898 dccp_hashinfo.bind_bucket_cachep = NULL; 1077 dccp_hashinfo.bind_bucket_cachep = NULL;
899out_proto_unregister:
900 proto_unregister(&dccp_prot);
901 goto out; 1078 goto out;
902} 1079}
903 1080
904static const char dccp_del_proto_err_msg[] __exitdata =
905 KERN_ERR "can't remove dccp net_protocol\n";
906
907static void __exit dccp_fini(void) 1081static void __exit dccp_fini(void)
908{ 1082{
909 inet_unregister_protosw(&dccp_v4_protosw); 1083 dccp_mib_exit();
910
911 if (inet_del_protocol(&dccp_protocol, IPPROTO_DCCP) < 0)
912 printk(dccp_del_proto_err_msg);
913
914 free_percpu(dccp_statistics[0]);
915 free_percpu(dccp_statistics[1]);
916 free_pages((unsigned long)dccp_hashinfo.bhash, 1084 free_pages((unsigned long)dccp_hashinfo.bhash,
917 get_order(dccp_hashinfo.bhash_size * 1085 get_order(dccp_hashinfo.bhash_size *
918 sizeof(struct inet_bind_hashbucket))); 1086 sizeof(struct inet_bind_hashbucket)));
@@ -920,19 +1088,13 @@ static void __exit dccp_fini(void)
920 get_order(dccp_hashinfo.ehash_size * 1088 get_order(dccp_hashinfo.ehash_size *
921 sizeof(struct inet_ehash_bucket))); 1089 sizeof(struct inet_ehash_bucket)));
922 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); 1090 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
923 proto_unregister(&dccp_prot); 1091 dccp_ackvec_exit();
1092 dccp_sysctl_exit();
924} 1093}
925 1094
926module_init(dccp_init); 1095module_init(dccp_init);
927module_exit(dccp_fini); 1096module_exit(dccp_fini);
928 1097
929/*
930 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
931 * values directly, Also cover the case where the protocol is not specified,
932 * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
933 */
934MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
935MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
936MODULE_LICENSE("GPL"); 1098MODULE_LICENSE("GPL");
937MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>"); 1099MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>");
938MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol"); 1100MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");