blob: 3ba1ff43579886c38a20b5552ea9abe1167c9e78 [file] [log] [blame]
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001/*
2 * net/dccp/proto.c
3 *
4 * An implementation of the DCCP protocol
5 * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/config.h>
13#include <linux/dccp.h>
14#include <linux/module.h>
15#include <linux/types.h>
16#include <linux/sched.h>
17#include <linux/kernel.h>
18#include <linux/skbuff.h>
19#include <linux/netdevice.h>
20#include <linux/in.h>
21#include <linux/if_arp.h>
22#include <linux/init.h>
23#include <linux/random.h>
24#include <net/checksum.h>
25
26#include <net/inet_common.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020027#include <net/inet_sock.h>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070028#include <net/protocol.h>
29#include <net/sock.h>
30#include <net/xfrm.h>
31
32#include <asm/semaphore.h>
33#include <linux/spinlock.h>
34#include <linux/timer.h>
35#include <linux/delay.h>
36#include <linux/poll.h>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070037
38#include "ccid.h"
39#include "dccp.h"
Andrea Bittauafe00252006-03-20 17:43:56 -080040#include "feat.h"
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070041
Eric Dumazetba899662005-08-26 12:05:31 -070042DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070043
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -080044EXPORT_SYMBOL_GPL(dccp_statistics);
45
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070046atomic_t dccp_orphan_count = ATOMIC_INIT(0);
47
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -080048EXPORT_SYMBOL_GPL(dccp_orphan_count);
49
Arnaldo Carvalho de Melo075ae862006-03-20 21:24:19 -080050struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
51 .lhash_lock = RW_LOCK_UNLOCKED,
52 .lhash_users = ATOMIC_INIT(0),
53 .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait),
54};
55
56EXPORT_SYMBOL_GPL(dccp_hashinfo);
57
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070058static struct net_protocol dccp_protocol = {
59 .handler = dccp_v4_rcv,
60 .err_handler = dccp_v4_err,
Patrick McHardya516b042005-11-20 21:16:13 -080061 .no_policy = 1,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070062};
63
64const char *dccp_packet_name(const int type)
65{
66 static const char *dccp_packet_names[] = {
67 [DCCP_PKT_REQUEST] = "REQUEST",
68 [DCCP_PKT_RESPONSE] = "RESPONSE",
69 [DCCP_PKT_DATA] = "DATA",
70 [DCCP_PKT_ACK] = "ACK",
71 [DCCP_PKT_DATAACK] = "DATAACK",
72 [DCCP_PKT_CLOSEREQ] = "CLOSEREQ",
73 [DCCP_PKT_CLOSE] = "CLOSE",
74 [DCCP_PKT_RESET] = "RESET",
75 [DCCP_PKT_SYNC] = "SYNC",
76 [DCCP_PKT_SYNCACK] = "SYNCACK",
77 };
78
79 if (type >= DCCP_NR_PKT_TYPES)
80 return "INVALID";
81 else
82 return dccp_packet_names[type];
83}
84
85EXPORT_SYMBOL_GPL(dccp_packet_name);
86
87const char *dccp_state_name(const int state)
88{
89 static char *dccp_state_names[] = {
90 [DCCP_OPEN] = "OPEN",
91 [DCCP_REQUESTING] = "REQUESTING",
92 [DCCP_PARTOPEN] = "PARTOPEN",
93 [DCCP_LISTEN] = "LISTEN",
94 [DCCP_RESPOND] = "RESPOND",
95 [DCCP_CLOSING] = "CLOSING",
96 [DCCP_TIME_WAIT] = "TIME_WAIT",
97 [DCCP_CLOSED] = "CLOSED",
98 };
99
100 if (state >= DCCP_MAX_STATES)
101 return "INVALID STATE!";
102 else
103 return dccp_state_names[state];
104}
105
106EXPORT_SYMBOL_GPL(dccp_state_name);
107
Arnaldo Carvalho de Meloc985ed72006-03-20 21:23:39 -0800108void dccp_hash(struct sock *sk)
109{
110 inet_hash(&dccp_hashinfo, sk);
111}
112
113EXPORT_SYMBOL_GPL(dccp_hash);
114
115void dccp_unhash(struct sock *sk)
116{
117 inet_unhash(&dccp_hashinfo, sk);
118}
119
120EXPORT_SYMBOL_GPL(dccp_unhash);
121
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800122int dccp_init_sock(struct sock *sk)
123{
124 struct dccp_sock *dp = dccp_sk(sk);
125 struct inet_connection_sock *icsk = inet_csk(sk);
126 static int dccp_ctl_socket_init = 1;
127
128 dccp_options_init(&dp->dccps_options);
129 do_gettimeofday(&dp->dccps_epoch);
130
131 /*
132 * FIXME: We're hardcoding the CCID, and doing this at this point makes
133 * the listening (master) sock get CCID control blocks, which is not
134 * necessary, but for now, to not mess with the test userspace apps,
135 * lets leave it here, later the real solution is to do this in a
136 * setsockopt(CCIDs-I-want/accept). -acme
137 */
138 if (likely(!dccp_ctl_socket_init)) {
139 int rc = dccp_feat_init(sk);
140
141 if (rc)
142 return rc;
143
144 if (dp->dccps_options.dccpo_send_ack_vector) {
145 dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
146 if (dp->dccps_hc_rx_ackvec == NULL)
147 return -ENOMEM;
148 }
149 dp->dccps_hc_rx_ccid =
150 ccid_hc_rx_new(dp->dccps_options.dccpo_rx_ccid,
151 sk, GFP_KERNEL);
152 dp->dccps_hc_tx_ccid =
153 ccid_hc_tx_new(dp->dccps_options.dccpo_tx_ccid,
154 sk, GFP_KERNEL);
155 if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
156 dp->dccps_hc_tx_ccid == NULL)) {
157 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
158 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
159 if (dp->dccps_options.dccpo_send_ack_vector) {
160 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
161 dp->dccps_hc_rx_ackvec = NULL;
162 }
163 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
164 return -ENOMEM;
165 }
166 } else {
167 /* control socket doesn't need feat nego */
168 INIT_LIST_HEAD(&dp->dccps_options.dccpo_pending);
169 INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
170 dccp_ctl_socket_init = 0;
171 }
172
173 dccp_init_xmit_timers(sk);
174 icsk->icsk_rto = DCCP_TIMEOUT_INIT;
175 sk->sk_state = DCCP_CLOSED;
176 sk->sk_write_space = dccp_write_space;
177 icsk->icsk_sync_mss = dccp_sync_mss;
178 dp->dccps_mss_cache = 536;
179 dp->dccps_role = DCCP_ROLE_UNDEFINED;
180 dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
181 dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
182
183 return 0;
184}
185
186EXPORT_SYMBOL_GPL(dccp_init_sock);
187
188int dccp_destroy_sock(struct sock *sk)
189{
190 struct dccp_sock *dp = dccp_sk(sk);
191
192 /*
193 * DCCP doesn't use sk_write_queue, just sk_send_head
194 * for retransmissions
195 */
196 if (sk->sk_send_head != NULL) {
197 kfree_skb(sk->sk_send_head);
198 sk->sk_send_head = NULL;
199 }
200
201 /* Clean up a referenced DCCP bind bucket. */
202 if (inet_csk(sk)->icsk_bind_hash != NULL)
203 inet_put_port(&dccp_hashinfo, sk);
204
205 kfree(dp->dccps_service_list);
206 dp->dccps_service_list = NULL;
207
208 if (dp->dccps_options.dccpo_send_ack_vector) {
209 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
210 dp->dccps_hc_rx_ackvec = NULL;
211 }
212 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
213 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
214 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
215
216 /* clean up feature negotiation state */
217 dccp_feat_clean(sk);
218
219 return 0;
220}
221
222EXPORT_SYMBOL_GPL(dccp_destroy_sock);
223
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700224static inline int dccp_listen_start(struct sock *sk)
225{
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700226 struct dccp_sock *dp = dccp_sk(sk);
227
228 dp->dccps_role = DCCP_ROLE_LISTEN;
229 /*
230 * Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE)
231 * before calling listen()
232 */
233 if (dccp_service_not_initialized(sk))
234 return -EPROTO;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700235 return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
236}
237
238int dccp_disconnect(struct sock *sk, int flags)
239{
240 struct inet_connection_sock *icsk = inet_csk(sk);
241 struct inet_sock *inet = inet_sk(sk);
242 int err = 0;
243 const int old_state = sk->sk_state;
244
245 if (old_state != DCCP_CLOSED)
246 dccp_set_state(sk, DCCP_CLOSED);
247
248 /* ABORT function of RFC793 */
249 if (old_state == DCCP_LISTEN) {
250 inet_csk_listen_stop(sk);
251 /* FIXME: do the active reset thing */
252 } else if (old_state == DCCP_REQUESTING)
253 sk->sk_err = ECONNRESET;
254
255 dccp_clear_xmit_timers(sk);
256 __skb_queue_purge(&sk->sk_receive_queue);
257 if (sk->sk_send_head != NULL) {
258 __kfree_skb(sk->sk_send_head);
259 sk->sk_send_head = NULL;
260 }
261
262 inet->dport = 0;
263
264 if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
265 inet_reset_saddr(sk);
266
267 sk->sk_shutdown = 0;
268 sock_reset_flag(sk, SOCK_DONE);
269
270 icsk->icsk_backoff = 0;
271 inet_csk_delack_init(sk);
272 __sk_dst_reset(sk);
273
274 BUG_TRAP(!inet->num || icsk->icsk_bind_hash);
275
276 sk->sk_error_report(sk);
277 return err;
278}
279
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800280EXPORT_SYMBOL_GPL(dccp_disconnect);
281
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700282/*
283 * Wait for a DCCP event.
284 *
285 * Note that we don't need to lock the socket, as the upper poll layers
286 * take care of normal races (between the test and the event) and we don't
287 * go look at any of the socket buffers directly.
288 */
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800289unsigned int dccp_poll(struct file *file, struct socket *sock,
290 poll_table *wait)
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700291{
292 unsigned int mask;
293 struct sock *sk = sock->sk;
294
295 poll_wait(file, sk->sk_sleep, wait);
296 if (sk->sk_state == DCCP_LISTEN)
297 return inet_csk_listen_poll(sk);
298
299 /* Socket is not locked. We are protected from async events
300 by poll logic and correct handling of state changes
301 made by another threads is impossible in any case.
302 */
303
304 mask = 0;
305 if (sk->sk_err)
306 mask = POLLERR;
307
308 if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
309 mask |= POLLHUP;
310 if (sk->sk_shutdown & RCV_SHUTDOWN)
311 mask |= POLLIN | POLLRDNORM;
312
313 /* Connected? */
314 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
315 if (atomic_read(&sk->sk_rmem_alloc) > 0)
316 mask |= POLLIN | POLLRDNORM;
317
318 if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
319 if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
320 mask |= POLLOUT | POLLWRNORM;
321 } else { /* send SIGIO later */
322 set_bit(SOCK_ASYNC_NOSPACE,
323 &sk->sk_socket->flags);
324 set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
325
326 /* Race breaker. If space is freed after
327 * wspace test but before the flags are set,
328 * IO signal will be lost.
329 */
330 if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk))
331 mask |= POLLOUT | POLLWRNORM;
332 }
333 }
334 }
335 return mask;
336}
337
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800338EXPORT_SYMBOL_GPL(dccp_poll);
339
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700340int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
341{
342 dccp_pr_debug("entry\n");
343 return -ENOIOCTLCMD;
344}
345
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800346EXPORT_SYMBOL_GPL(dccp_ioctl);
347
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800348static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700349 char __user *optval, int optlen)
350{
351 struct dccp_sock *dp = dccp_sk(sk);
352 struct dccp_service_list *sl = NULL;
353
354 if (service == DCCP_SERVICE_INVALID_VALUE ||
355 optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32))
356 return -EINVAL;
357
358 if (optlen > sizeof(service)) {
359 sl = kmalloc(optlen, GFP_KERNEL);
360 if (sl == NULL)
361 return -ENOMEM;
362
363 sl->dccpsl_nr = optlen / sizeof(u32) - 1;
364 if (copy_from_user(sl->dccpsl_list,
365 optval + sizeof(service),
366 optlen - sizeof(service)) ||
367 dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) {
368 kfree(sl);
369 return -EFAULT;
370 }
371 }
372
373 lock_sock(sk);
374 dp->dccps_service = service;
375
Jesper Juhla51482b2005-11-08 09:41:34 -0800376 kfree(dp->dccps_service_list);
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700377
378 dp->dccps_service_list = sl;
379 release_sock(sk);
380 return 0;
381}
382
Andrea Bittauafe00252006-03-20 17:43:56 -0800383/* byte 1 is feature. the rest is the preference list */
384static int dccp_setsockopt_change(struct sock *sk, int type,
385 struct dccp_so_feat __user *optval)
386{
387 struct dccp_so_feat opt;
388 u8 *val;
389 int rc;
390
391 if (copy_from_user(&opt, optval, sizeof(opt)))
392 return -EFAULT;
393
394 val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
395 if (!val)
396 return -ENOMEM;
397
398 if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) {
399 rc = -EFAULT;
400 goto out_free_val;
401 }
402
403 rc = dccp_feat_change(sk, type, opt.dccpsf_feat, val, opt.dccpsf_len,
404 GFP_KERNEL);
405 if (rc)
406 goto out_free_val;
407
408out:
409 return rc;
410
411out_free_val:
412 kfree(val);
413 goto out;
414}
415
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700416int dccp_setsockopt(struct sock *sk, int level, int optname,
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -0300417 char __user *optval, int optlen)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700418{
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300419 struct dccp_sock *dp;
420 int err;
421 int val;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700422
423 if (level != SOL_DCCP)
Arnaldo Carvalho de Melo57cca052005-12-13 23:16:16 -0800424 return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
425 optname, optval,
426 optlen);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700427
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300428 if (optlen < sizeof(int))
429 return -EINVAL;
430
431 if (get_user(val, (int __user *)optval))
432 return -EFAULT;
433
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700434 if (optname == DCCP_SOCKOPT_SERVICE)
435 return dccp_setsockopt_service(sk, val, optval, optlen);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300436
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700437 lock_sock(sk);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300438 dp = dccp_sk(sk);
439 err = 0;
440
441 switch (optname) {
442 case DCCP_SOCKOPT_PACKET_SIZE:
443 dp->dccps_packet_size = val;
444 break;
Andrea Bittauafe00252006-03-20 17:43:56 -0800445
446 case DCCP_SOCKOPT_CHANGE_L:
447 if (optlen != sizeof(struct dccp_so_feat))
448 err = -EINVAL;
449 else
450 err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
451 (struct dccp_so_feat *)
452 optval);
453 break;
454
455 case DCCP_SOCKOPT_CHANGE_R:
456 if (optlen != sizeof(struct dccp_so_feat))
457 err = -EINVAL;
458 else
459 err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
460 (struct dccp_so_feat *)
461 optval);
462 break;
463
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300464 default:
465 err = -ENOPROTOOPT;
466 break;
467 }
468
469 release_sock(sk);
470 return err;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700471}
472
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800473EXPORT_SYMBOL_GPL(dccp_setsockopt);
474
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700475static int dccp_getsockopt_service(struct sock *sk, int len,
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800476 __be32 __user *optval,
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700477 int __user *optlen)
478{
479 const struct dccp_sock *dp = dccp_sk(sk);
480 const struct dccp_service_list *sl;
481 int err = -ENOENT, slen = 0, total_len = sizeof(u32);
482
483 lock_sock(sk);
484 if (dccp_service_not_initialized(sk))
485 goto out;
486
487 if ((sl = dp->dccps_service_list) != NULL) {
488 slen = sl->dccpsl_nr * sizeof(u32);
489 total_len += slen;
490 }
491
492 err = -EINVAL;
493 if (total_len > len)
494 goto out;
495
496 err = 0;
497 if (put_user(total_len, optlen) ||
498 put_user(dp->dccps_service, optval) ||
499 (sl != NULL && copy_to_user(optval + 1, sl->dccpsl_list, slen)))
500 err = -EFAULT;
501out:
502 release_sock(sk);
503 return err;
504}
505
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700506int dccp_getsockopt(struct sock *sk, int level, int optname,
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -0300507 char __user *optval, int __user *optlen)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700508{
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300509 struct dccp_sock *dp;
510 int val, len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700511
512 if (level != SOL_DCCP)
Arnaldo Carvalho de Melo57cca052005-12-13 23:16:16 -0800513 return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
514 optname, optval,
515 optlen);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300516 if (get_user(len, optlen))
517 return -EFAULT;
518
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700519 if (len < sizeof(int))
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300520 return -EINVAL;
521
522 dp = dccp_sk(sk);
523
524 switch (optname) {
525 case DCCP_SOCKOPT_PACKET_SIZE:
526 val = dp->dccps_packet_size;
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700527 len = sizeof(dp->dccps_packet_size);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300528 break;
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700529 case DCCP_SOCKOPT_SERVICE:
530 return dccp_getsockopt_service(sk, len,
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800531 (__be32 __user *)optval, optlen);
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700532 case 128 ... 191:
533 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
534 len, (u32 __user *)optval, optlen);
535 case 192 ... 255:
536 return ccid_hc_tx_getsockopt(dp->dccps_hc_tx_ccid, sk, optname,
537 len, (u32 __user *)optval, optlen);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300538 default:
539 return -ENOPROTOOPT;
540 }
541
542 if (put_user(len, optlen) || copy_to_user(optval, &val, len))
543 return -EFAULT;
544
545 return 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700546}
547
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800548EXPORT_SYMBOL_GPL(dccp_getsockopt);
549
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700550int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
551 size_t len)
552{
553 const struct dccp_sock *dp = dccp_sk(sk);
554 const int flags = msg->msg_flags;
555 const int noblock = flags & MSG_DONTWAIT;
556 struct sk_buff *skb;
557 int rc, size;
558 long timeo;
559
560 if (len > dp->dccps_mss_cache)
561 return -EMSGSIZE;
562
563 lock_sock(sk);
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700564 timeo = sock_sndtimeo(sk, noblock);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700565
566 /*
567 * We have to use sk_stream_wait_connect here to set sk_write_pending,
568 * so that the trick in dccp_rcv_request_sent_state_process.
569 */
570 /* Wait for a connection to finish. */
571 if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN | DCCPF_CLOSING))
572 if ((rc = sk_stream_wait_connect(sk, &timeo)) != 0)
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700573 goto out_release;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700574
575 size = sk->sk_prot->max_header + len;
576 release_sock(sk);
577 skb = sock_alloc_send_skb(sk, size, noblock, &rc);
578 lock_sock(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700579 if (skb == NULL)
580 goto out_release;
581
582 skb_reserve(skb, sk->sk_prot->max_header);
583 rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700584 if (rc != 0)
585 goto out_discard;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700586
Arnaldo Carvalho de Melod6809c12005-08-27 03:06:35 -0300587 rc = dccp_write_xmit(sk, skb, &timeo);
Arnaldo Carvalho de Melo20472af2005-08-23 21:50:21 -0700588 /*
589 * XXX we don't use sk_write_queue, so just discard the packet.
590 * Current plan however is to _use_ sk_write_queue with
591 * an algorith similar to tcp_sendmsg, where the main difference
592 * is that in DCCP we have to respect packet boundaries, so
593 * no coalescing of skbs.
594 *
595 * This bug was _quickly_ found & fixed by just looking at an OSTRA
596 * generated callgraph 8) -acme
597 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700598out_release:
599 release_sock(sk);
600 return rc ? : len;
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700601out_discard:
602 kfree_skb(skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700603 goto out_release;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700604}
605
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800606EXPORT_SYMBOL_GPL(dccp_sendmsg);
607
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700608int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
609 size_t len, int nonblock, int flags, int *addr_len)
610{
611 const struct dccp_hdr *dh;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700612 long timeo;
613
614 lock_sock(sk);
615
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300616 if (sk->sk_state == DCCP_LISTEN) {
617 len = -ENOTCONN;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700618 goto out;
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300619 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700620
621 timeo = sock_rcvtimeo(sk, nonblock);
622
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700623 do {
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300624 struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700625
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300626 if (skb == NULL)
627 goto verify_sock_status;
628
629 dh = dccp_hdr(skb);
630
631 if (dh->dccph_type == DCCP_PKT_DATA ||
632 dh->dccph_type == DCCP_PKT_DATAACK)
633 goto found_ok_skb;
634
635 if (dh->dccph_type == DCCP_PKT_RESET ||
636 dh->dccph_type == DCCP_PKT_CLOSE) {
637 dccp_pr_debug("found fin ok!\n");
638 len = 0;
639 goto found_fin_ok;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700640 }
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300641 dccp_pr_debug("packet_type=%s\n",
642 dccp_packet_name(dh->dccph_type));
643 sk_eat_skb(sk, skb);
644verify_sock_status:
645 if (sock_flag(sk, SOCK_DONE)) {
646 len = 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700647 break;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700648 }
649
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300650 if (sk->sk_err) {
651 len = sock_error(sk);
652 break;
653 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700654
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300655 if (sk->sk_shutdown & RCV_SHUTDOWN) {
656 len = 0;
657 break;
658 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700659
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300660 if (sk->sk_state == DCCP_CLOSED) {
661 if (!sock_flag(sk, SOCK_DONE)) {
662 /* This occurs when user tries to read
663 * from never connected socket.
664 */
665 len = -ENOTCONN;
666 break;
667 }
668 len = 0;
669 break;
670 }
671
672 if (!timeo) {
673 len = -EAGAIN;
674 break;
675 }
676
677 if (signal_pending(current)) {
678 len = sock_intr_errno(timeo);
679 break;
680 }
681
682 sk_wait_data(sk, &timeo);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700683 continue;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700684 found_ok_skb:
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300685 if (len > skb->len)
686 len = skb->len;
687 else if (len < skb->len)
688 msg->msg_flags |= MSG_TRUNC;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700689
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300690 if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len)) {
691 /* Exception. Bailout! */
692 len = -EFAULT;
693 break;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700694 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700695 found_fin_ok:
696 if (!(flags & MSG_PEEK))
697 sk_eat_skb(sk, skb);
698 break;
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300699 } while (1);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700700out:
701 release_sock(sk);
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300702 return len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700703}
704
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800705EXPORT_SYMBOL_GPL(dccp_recvmsg);
706
707int inet_dccp_listen(struct socket *sock, int backlog)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700708{
709 struct sock *sk = sock->sk;
710 unsigned char old_state;
711 int err;
712
713 lock_sock(sk);
714
715 err = -EINVAL;
716 if (sock->state != SS_UNCONNECTED || sock->type != SOCK_DCCP)
717 goto out;
718
719 old_state = sk->sk_state;
720 if (!((1 << old_state) & (DCCPF_CLOSED | DCCPF_LISTEN)))
721 goto out;
722
723 /* Really, if the socket is already in listen state
724 * we can only allow the backlog to be adjusted.
725 */
726 if (old_state != DCCP_LISTEN) {
727 /*
728 * FIXME: here it probably should be sk->sk_prot->listen_start
729 * see tcp_listen_start
730 */
731 err = dccp_listen_start(sk);
732 if (err)
733 goto out;
734 }
735 sk->sk_max_ack_backlog = backlog;
736 err = 0;
737
738out:
739 release_sock(sk);
740 return err;
741}
742
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800743EXPORT_SYMBOL_GPL(inet_dccp_listen);
744
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700745static const unsigned char dccp_new_state[] = {
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300746 /* current state: new state: action: */
747 [0] = DCCP_CLOSED,
748 [DCCP_OPEN] = DCCP_CLOSING | DCCP_ACTION_FIN,
749 [DCCP_REQUESTING] = DCCP_CLOSED,
750 [DCCP_PARTOPEN] = DCCP_CLOSING | DCCP_ACTION_FIN,
751 [DCCP_LISTEN] = DCCP_CLOSED,
752 [DCCP_RESPOND] = DCCP_CLOSED,
753 [DCCP_CLOSING] = DCCP_CLOSED,
754 [DCCP_TIME_WAIT] = DCCP_CLOSED,
755 [DCCP_CLOSED] = DCCP_CLOSED,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700756};
757
758static int dccp_close_state(struct sock *sk)
759{
760 const int next = dccp_new_state[sk->sk_state];
761 const int ns = next & DCCP_STATE_MASK;
762
763 if (ns != sk->sk_state)
764 dccp_set_state(sk, ns);
765
766 return next & DCCP_ACTION_FIN;
767}
768
769void dccp_close(struct sock *sk, long timeout)
770{
771 struct sk_buff *skb;
772
773 lock_sock(sk);
774
775 sk->sk_shutdown = SHUTDOWN_MASK;
776
777 if (sk->sk_state == DCCP_LISTEN) {
778 dccp_set_state(sk, DCCP_CLOSED);
779
780 /* Special case. */
781 inet_csk_listen_stop(sk);
782
783 goto adjudge_to_death;
784 }
785
786 /*
787 * We need to flush the recv. buffs. We do this only on the
788 * descriptor close, not protocol-sourced closes, because the
789 *reader process may not have drained the data yet!
790 */
791 /* FIXME: check for unread data */
792 while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
793 __kfree_skb(skb);
794 }
795
796 if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
797 /* Check zero linger _after_ checking for unread data. */
798 sk->sk_prot->disconnect(sk, 0);
799 } else if (dccp_close_state(sk)) {
Arnaldo Carvalho de Melo7ad07e72005-08-23 21:50:06 -0700800 dccp_send_close(sk, 1);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700801 }
802
803 sk_stream_wait_close(sk, timeout);
804
805adjudge_to_death:
Arnaldo Carvalho de Melo7ad07e72005-08-23 21:50:06 -0700806 /*
807 * It is the last release_sock in its life. It will remove backlog.
808 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700809 release_sock(sk);
810 /*
811 * Now socket is owned by kernel and we acquire BH lock
812 * to finish close. No need to check for user refs.
813 */
814 local_bh_disable();
815 bh_lock_sock(sk);
816 BUG_TRAP(!sock_owned_by_user(sk));
817
818 sock_hold(sk);
819 sock_orphan(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700820
Arnaldo Carvalho de Melo7ad07e72005-08-23 21:50:06 -0700821 /*
822 * The last release_sock may have processed the CLOSE or RESET
823 * packet moving sock to CLOSED state, if not we have to fire
824 * the CLOSE/CLOSEREQ retransmission timer, see "8.3. Termination"
825 * in draft-ietf-dccp-spec-11. -acme
826 */
827 if (sk->sk_state == DCCP_CLOSING) {
828 /* FIXME: should start at 2 * RTT */
829 /* Timer for repeating the CLOSE/CLOSEREQ until an answer. */
830 inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
831 inet_csk(sk)->icsk_rto,
832 DCCP_RTO_MAX);
833#if 0
834 /* Yeah, we should use sk->sk_prot->orphan_count, etc */
835 dccp_set_state(sk, DCCP_CLOSED);
836#endif
837 }
838
839 atomic_inc(sk->sk_prot->orphan_count);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700840 if (sk->sk_state == DCCP_CLOSED)
841 inet_csk_destroy_sock(sk);
842
843 /* Otherwise, socket is reprieved until protocol close. */
844
845 bh_unlock_sock(sk);
846 local_bh_enable();
847 sock_put(sk);
848}
849
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800850EXPORT_SYMBOL_GPL(dccp_close);
851
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700852void dccp_shutdown(struct sock *sk, int how)
853{
854 dccp_pr_debug("entry\n");
855}
856
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800857EXPORT_SYMBOL_GPL(dccp_shutdown);
858
Eric Dumazet90ddc4f2005-12-22 12:49:22 -0800859static const struct proto_ops inet_dccp_ops = {
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700860 .family = PF_INET,
861 .owner = THIS_MODULE,
862 .release = inet_release,
863 .bind = inet_bind,
864 .connect = inet_stream_connect,
865 .socketpair = sock_no_socketpair,
866 .accept = inet_accept,
867 .getname = inet_getname,
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700868 /* FIXME: work on tcp_poll to rename it to inet_csk_poll */
869 .poll = dccp_poll,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700870 .ioctl = inet_ioctl,
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300871 /* FIXME: work on inet_listen to rename it to sock_common_listen */
872 .listen = inet_dccp_listen,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700873 .shutdown = inet_shutdown,
874 .setsockopt = sock_common_setsockopt,
875 .getsockopt = sock_common_getsockopt,
876 .sendmsg = inet_sendmsg,
877 .recvmsg = sock_common_recvmsg,
878 .mmap = sock_no_mmap,
879 .sendpage = sock_no_sendpage,
880};
881
882extern struct net_proto_family inet_family_ops;
883
884static struct inet_protosw dccp_v4_protosw = {
885 .type = SOCK_DCCP,
886 .protocol = IPPROTO_DCCP,
Arnaldo Carvalho de Melo34ca6862005-12-13 23:23:32 -0800887 .prot = &dccp_prot,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700888 .ops = &inet_dccp_ops,
889 .capability = -1,
890 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800891 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700892};
893
894/*
895 * This is the global socket data structure used for responding to
896 * the Out-of-the-blue (OOTB) packets. A control sock will be created
897 * for this socket at the initialization time.
898 */
899struct socket *dccp_ctl_socket;
900
901static char dccp_ctl_socket_err_msg[] __initdata =
902 KERN_ERR "DCCP: Failed to create the control socket.\n";
903
904static int __init dccp_ctl_sock_init(void)
905{
906 int rc = sock_create_kern(PF_INET, SOCK_DCCP, IPPROTO_DCCP,
907 &dccp_ctl_socket);
908 if (rc < 0)
909 printk(dccp_ctl_socket_err_msg);
910 else {
911 dccp_ctl_socket->sk->sk_allocation = GFP_ATOMIC;
912 inet_sk(dccp_ctl_socket->sk)->uc_ttl = -1;
913
914 /* Unhash it so that IP input processing does not even
915 * see it, we do not wish this socket to see incoming
916 * packets.
917 */
918 dccp_ctl_socket->sk->sk_prot->unhash(dccp_ctl_socket->sk);
919 }
920
921 return rc;
922}
923
Arnaldo Carvalho de Melo725ba8e2005-08-13 20:35:39 -0300924#ifdef CONFIG_IP_DCCP_UNLOAD_HACK
925void dccp_ctl_sock_exit(void)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700926{
Arnaldo Carvalho de Melo54808552005-08-18 20:47:02 -0300927 if (dccp_ctl_socket != NULL) {
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700928 sock_release(dccp_ctl_socket);
Arnaldo Carvalho de Melo54808552005-08-18 20:47:02 -0300929 dccp_ctl_socket = NULL;
930 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700931}
932
Arnaldo Carvalho de Melo725ba8e2005-08-13 20:35:39 -0300933EXPORT_SYMBOL_GPL(dccp_ctl_sock_exit);
934#endif
935
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700936static int __init init_dccp_v4_mibs(void)
937{
938 int rc = -ENOMEM;
939
940 dccp_statistics[0] = alloc_percpu(struct dccp_mib);
941 if (dccp_statistics[0] == NULL)
942 goto out;
943
944 dccp_statistics[1] = alloc_percpu(struct dccp_mib);
945 if (dccp_statistics[1] == NULL)
946 goto out_free_one;
947
948 rc = 0;
949out:
950 return rc;
951out_free_one:
952 free_percpu(dccp_statistics[0]);
953 dccp_statistics[0] = NULL;
954 goto out;
955
956}
957
958static int thash_entries;
959module_param(thash_entries, int, 0444);
960MODULE_PARM_DESC(thash_entries, "Number of ehash buckets");
961
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -0300962#ifdef CONFIG_IP_DCCP_DEBUG
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700963int dccp_debug;
964module_param(dccp_debug, int, 0444);
965MODULE_PARM_DESC(dccp_debug, "Enable debug messages");
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800966
967EXPORT_SYMBOL_GPL(dccp_debug);
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -0300968#endif
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700969
970static int __init dccp_init(void)
971{
972 unsigned long goal;
973 int ehash_order, bhash_order, i;
Arnaldo Carvalho de Melo34ca6862005-12-13 23:23:32 -0800974 int rc = proto_register(&dccp_prot, 1);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700975
976 if (rc)
977 goto out;
978
Arnaldo Carvalho de Melofa23e2e2006-03-20 17:16:01 -0800979 rc = -ENOBUFS;
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300980 dccp_hashinfo.bind_bucket_cachep =
981 kmem_cache_create("dccp_bind_bucket",
982 sizeof(struct inet_bind_bucket), 0,
983 SLAB_HWCACHE_ALIGN, NULL, NULL);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700984 if (!dccp_hashinfo.bind_bucket_cachep)
985 goto out_proto_unregister;
986
987 /*
988 * Size and allocate the main established and bind bucket
989 * hash tables.
990 *
991 * The methodology is similar to that of the buffer cache.
992 */
993 if (num_physpages >= (128 * 1024))
994 goal = num_physpages >> (21 - PAGE_SHIFT);
995 else
996 goal = num_physpages >> (23 - PAGE_SHIFT);
997
998 if (thash_entries)
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300999 goal = (thash_entries *
1000 sizeof(struct inet_ehash_bucket)) >> PAGE_SHIFT;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001001 for (ehash_order = 0; (1UL << ehash_order) < goal; ehash_order++)
1002 ;
1003 do {
1004 dccp_hashinfo.ehash_size = (1UL << ehash_order) * PAGE_SIZE /
1005 sizeof(struct inet_ehash_bucket);
1006 dccp_hashinfo.ehash_size >>= 1;
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -03001007 while (dccp_hashinfo.ehash_size &
1008 (dccp_hashinfo.ehash_size - 1))
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001009 dccp_hashinfo.ehash_size--;
1010 dccp_hashinfo.ehash = (struct inet_ehash_bucket *)
1011 __get_free_pages(GFP_ATOMIC, ehash_order);
1012 } while (!dccp_hashinfo.ehash && --ehash_order > 0);
1013
1014 if (!dccp_hashinfo.ehash) {
1015 printk(KERN_CRIT "Failed to allocate DCCP "
1016 "established hash table\n");
1017 goto out_free_bind_bucket_cachep;
1018 }
1019
1020 for (i = 0; i < (dccp_hashinfo.ehash_size << 1); i++) {
1021 rwlock_init(&dccp_hashinfo.ehash[i].lock);
1022 INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].chain);
1023 }
1024
1025 bhash_order = ehash_order;
1026
1027 do {
1028 dccp_hashinfo.bhash_size = (1UL << bhash_order) * PAGE_SIZE /
1029 sizeof(struct inet_bind_hashbucket);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -03001030 if ((dccp_hashinfo.bhash_size > (64 * 1024)) &&
1031 bhash_order > 0)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001032 continue;
1033 dccp_hashinfo.bhash = (struct inet_bind_hashbucket *)
1034 __get_free_pages(GFP_ATOMIC, bhash_order);
1035 } while (!dccp_hashinfo.bhash && --bhash_order >= 0);
1036
1037 if (!dccp_hashinfo.bhash) {
1038 printk(KERN_CRIT "Failed to allocate DCCP bind hash table\n");
1039 goto out_free_dccp_ehash;
1040 }
1041
1042 for (i = 0; i < dccp_hashinfo.bhash_size; i++) {
1043 spin_lock_init(&dccp_hashinfo.bhash[i].lock);
1044 INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain);
1045 }
1046
Arnaldo Carvalho de Melofa23e2e2006-03-20 17:16:01 -08001047 rc = init_dccp_v4_mibs();
1048 if (rc)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001049 goto out_free_dccp_bhash;
1050
1051 rc = -EAGAIN;
1052 if (inet_add_protocol(&dccp_protocol, IPPROTO_DCCP))
1053 goto out_free_dccp_v4_mibs;
1054
1055 inet_register_protosw(&dccp_v4_protosw);
1056
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001057 rc = dccp_ackvec_init();
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001058 if (rc)
1059 goto out_unregister_protosw;
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001060
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001061 rc = dccp_sysctl_init();
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001062 if (rc)
1063 goto out_ackvec_exit;
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001064
1065 rc = dccp_ctl_sock_init();
1066 if (rc)
1067 goto out_sysctl_exit;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001068out:
1069 return rc;
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001070out_sysctl_exit:
1071 dccp_sysctl_exit();
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001072out_ackvec_exit:
1073 dccp_ackvec_exit();
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001074out_unregister_protosw:
1075 inet_unregister_protosw(&dccp_v4_protosw);
1076 inet_del_protocol(&dccp_protocol, IPPROTO_DCCP);
1077out_free_dccp_v4_mibs:
1078 free_percpu(dccp_statistics[0]);
1079 free_percpu(dccp_statistics[1]);
1080 dccp_statistics[0] = dccp_statistics[1] = NULL;
1081out_free_dccp_bhash:
1082 free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
1083 dccp_hashinfo.bhash = NULL;
1084out_free_dccp_ehash:
1085 free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order);
1086 dccp_hashinfo.ehash = NULL;
1087out_free_bind_bucket_cachep:
1088 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
1089 dccp_hashinfo.bind_bucket_cachep = NULL;
1090out_proto_unregister:
Arnaldo Carvalho de Melo34ca6862005-12-13 23:23:32 -08001091 proto_unregister(&dccp_prot);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001092 goto out;
1093}
1094
1095static const char dccp_del_proto_err_msg[] __exitdata =
1096 KERN_ERR "can't remove dccp net_protocol\n";
1097
1098static void __exit dccp_fini(void)
1099{
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001100 inet_unregister_protosw(&dccp_v4_protosw);
1101
1102 if (inet_del_protocol(&dccp_protocol, IPPROTO_DCCP) < 0)
1103 printk(dccp_del_proto_err_msg);
1104
Arnaldo Carvalho de Melo725ba8e2005-08-13 20:35:39 -03001105 free_percpu(dccp_statistics[0]);
1106 free_percpu(dccp_statistics[1]);
1107 free_pages((unsigned long)dccp_hashinfo.bhash,
1108 get_order(dccp_hashinfo.bhash_size *
1109 sizeof(struct inet_bind_hashbucket)));
1110 free_pages((unsigned long)dccp_hashinfo.ehash,
1111 get_order(dccp_hashinfo.ehash_size *
1112 sizeof(struct inet_ehash_bucket)));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001113 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
Arnaldo Carvalho de Melo34ca6862005-12-13 23:23:32 -08001114 proto_unregister(&dccp_prot);
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001115 dccp_ackvec_exit();
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001116 dccp_sysctl_exit();
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001117}
1118
1119module_init(dccp_init);
1120module_exit(dccp_fini);
1121
Arnaldo Carvalho de Melobb97d312005-08-09 20:19:14 -07001122/*
1123 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1124 * values directly, Also cover the case where the protocol is not specified,
1125 * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
1126 */
1127MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
1128MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001129MODULE_LICENSE("GPL");
1130MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>");
1131MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");