blob: 64806fbf44de7667ececbc749a10e485432bc4a4 [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 Melo7c657872005-08-09 20:14:34 -070050static struct net_protocol dccp_protocol = {
51 .handler = dccp_v4_rcv,
52 .err_handler = dccp_v4_err,
Patrick McHardya516b042005-11-20 21:16:13 -080053 .no_policy = 1,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070054};
55
56const char *dccp_packet_name(const int type)
57{
58 static const char *dccp_packet_names[] = {
59 [DCCP_PKT_REQUEST] = "REQUEST",
60 [DCCP_PKT_RESPONSE] = "RESPONSE",
61 [DCCP_PKT_DATA] = "DATA",
62 [DCCP_PKT_ACK] = "ACK",
63 [DCCP_PKT_DATAACK] = "DATAACK",
64 [DCCP_PKT_CLOSEREQ] = "CLOSEREQ",
65 [DCCP_PKT_CLOSE] = "CLOSE",
66 [DCCP_PKT_RESET] = "RESET",
67 [DCCP_PKT_SYNC] = "SYNC",
68 [DCCP_PKT_SYNCACK] = "SYNCACK",
69 };
70
71 if (type >= DCCP_NR_PKT_TYPES)
72 return "INVALID";
73 else
74 return dccp_packet_names[type];
75}
76
77EXPORT_SYMBOL_GPL(dccp_packet_name);
78
79const char *dccp_state_name(const int state)
80{
81 static char *dccp_state_names[] = {
82 [DCCP_OPEN] = "OPEN",
83 [DCCP_REQUESTING] = "REQUESTING",
84 [DCCP_PARTOPEN] = "PARTOPEN",
85 [DCCP_LISTEN] = "LISTEN",
86 [DCCP_RESPOND] = "RESPOND",
87 [DCCP_CLOSING] = "CLOSING",
88 [DCCP_TIME_WAIT] = "TIME_WAIT",
89 [DCCP_CLOSED] = "CLOSED",
90 };
91
92 if (state >= DCCP_MAX_STATES)
93 return "INVALID STATE!";
94 else
95 return dccp_state_names[state];
96}
97
98EXPORT_SYMBOL_GPL(dccp_state_name);
99
Arnaldo Carvalho de Meloc985ed72006-03-20 21:23:39 -0800100void dccp_hash(struct sock *sk)
101{
102 inet_hash(&dccp_hashinfo, sk);
103}
104
105EXPORT_SYMBOL_GPL(dccp_hash);
106
107void dccp_unhash(struct sock *sk)
108{
109 inet_unhash(&dccp_hashinfo, sk);
110}
111
112EXPORT_SYMBOL_GPL(dccp_unhash);
113
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800114int dccp_init_sock(struct sock *sk)
115{
116 struct dccp_sock *dp = dccp_sk(sk);
117 struct inet_connection_sock *icsk = inet_csk(sk);
118 static int dccp_ctl_socket_init = 1;
119
120 dccp_options_init(&dp->dccps_options);
121 do_gettimeofday(&dp->dccps_epoch);
122
123 /*
124 * FIXME: We're hardcoding the CCID, and doing this at this point makes
125 * the listening (master) sock get CCID control blocks, which is not
126 * necessary, but for now, to not mess with the test userspace apps,
127 * lets leave it here, later the real solution is to do this in a
128 * setsockopt(CCIDs-I-want/accept). -acme
129 */
130 if (likely(!dccp_ctl_socket_init)) {
131 int rc = dccp_feat_init(sk);
132
133 if (rc)
134 return rc;
135
136 if (dp->dccps_options.dccpo_send_ack_vector) {
137 dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
138 if (dp->dccps_hc_rx_ackvec == NULL)
139 return -ENOMEM;
140 }
141 dp->dccps_hc_rx_ccid =
142 ccid_hc_rx_new(dp->dccps_options.dccpo_rx_ccid,
143 sk, GFP_KERNEL);
144 dp->dccps_hc_tx_ccid =
145 ccid_hc_tx_new(dp->dccps_options.dccpo_tx_ccid,
146 sk, GFP_KERNEL);
147 if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
148 dp->dccps_hc_tx_ccid == NULL)) {
149 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
150 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
151 if (dp->dccps_options.dccpo_send_ack_vector) {
152 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
153 dp->dccps_hc_rx_ackvec = NULL;
154 }
155 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
156 return -ENOMEM;
157 }
158 } else {
159 /* control socket doesn't need feat nego */
160 INIT_LIST_HEAD(&dp->dccps_options.dccpo_pending);
161 INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
162 dccp_ctl_socket_init = 0;
163 }
164
165 dccp_init_xmit_timers(sk);
166 icsk->icsk_rto = DCCP_TIMEOUT_INIT;
167 sk->sk_state = DCCP_CLOSED;
168 sk->sk_write_space = dccp_write_space;
169 icsk->icsk_sync_mss = dccp_sync_mss;
170 dp->dccps_mss_cache = 536;
171 dp->dccps_role = DCCP_ROLE_UNDEFINED;
172 dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
173 dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
174
175 return 0;
176}
177
178EXPORT_SYMBOL_GPL(dccp_init_sock);
179
180int dccp_destroy_sock(struct sock *sk)
181{
182 struct dccp_sock *dp = dccp_sk(sk);
183
184 /*
185 * DCCP doesn't use sk_write_queue, just sk_send_head
186 * for retransmissions
187 */
188 if (sk->sk_send_head != NULL) {
189 kfree_skb(sk->sk_send_head);
190 sk->sk_send_head = NULL;
191 }
192
193 /* Clean up a referenced DCCP bind bucket. */
194 if (inet_csk(sk)->icsk_bind_hash != NULL)
195 inet_put_port(&dccp_hashinfo, sk);
196
197 kfree(dp->dccps_service_list);
198 dp->dccps_service_list = NULL;
199
200 if (dp->dccps_options.dccpo_send_ack_vector) {
201 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
202 dp->dccps_hc_rx_ackvec = NULL;
203 }
204 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
205 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
206 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
207
208 /* clean up feature negotiation state */
209 dccp_feat_clean(sk);
210
211 return 0;
212}
213
214EXPORT_SYMBOL_GPL(dccp_destroy_sock);
215
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700216static inline int dccp_listen_start(struct sock *sk)
217{
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700218 struct dccp_sock *dp = dccp_sk(sk);
219
220 dp->dccps_role = DCCP_ROLE_LISTEN;
221 /*
222 * Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE)
223 * before calling listen()
224 */
225 if (dccp_service_not_initialized(sk))
226 return -EPROTO;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700227 return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
228}
229
230int dccp_disconnect(struct sock *sk, int flags)
231{
232 struct inet_connection_sock *icsk = inet_csk(sk);
233 struct inet_sock *inet = inet_sk(sk);
234 int err = 0;
235 const int old_state = sk->sk_state;
236
237 if (old_state != DCCP_CLOSED)
238 dccp_set_state(sk, DCCP_CLOSED);
239
240 /* ABORT function of RFC793 */
241 if (old_state == DCCP_LISTEN) {
242 inet_csk_listen_stop(sk);
243 /* FIXME: do the active reset thing */
244 } else if (old_state == DCCP_REQUESTING)
245 sk->sk_err = ECONNRESET;
246
247 dccp_clear_xmit_timers(sk);
248 __skb_queue_purge(&sk->sk_receive_queue);
249 if (sk->sk_send_head != NULL) {
250 __kfree_skb(sk->sk_send_head);
251 sk->sk_send_head = NULL;
252 }
253
254 inet->dport = 0;
255
256 if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
257 inet_reset_saddr(sk);
258
259 sk->sk_shutdown = 0;
260 sock_reset_flag(sk, SOCK_DONE);
261
262 icsk->icsk_backoff = 0;
263 inet_csk_delack_init(sk);
264 __sk_dst_reset(sk);
265
266 BUG_TRAP(!inet->num || icsk->icsk_bind_hash);
267
268 sk->sk_error_report(sk);
269 return err;
270}
271
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800272EXPORT_SYMBOL_GPL(dccp_disconnect);
273
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700274/*
275 * Wait for a DCCP event.
276 *
277 * Note that we don't need to lock the socket, as the upper poll layers
278 * take care of normal races (between the test and the event) and we don't
279 * go look at any of the socket buffers directly.
280 */
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800281unsigned int dccp_poll(struct file *file, struct socket *sock,
282 poll_table *wait)
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700283{
284 unsigned int mask;
285 struct sock *sk = sock->sk;
286
287 poll_wait(file, sk->sk_sleep, wait);
288 if (sk->sk_state == DCCP_LISTEN)
289 return inet_csk_listen_poll(sk);
290
291 /* Socket is not locked. We are protected from async events
292 by poll logic and correct handling of state changes
293 made by another threads is impossible in any case.
294 */
295
296 mask = 0;
297 if (sk->sk_err)
298 mask = POLLERR;
299
300 if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
301 mask |= POLLHUP;
302 if (sk->sk_shutdown & RCV_SHUTDOWN)
303 mask |= POLLIN | POLLRDNORM;
304
305 /* Connected? */
306 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
307 if (atomic_read(&sk->sk_rmem_alloc) > 0)
308 mask |= POLLIN | POLLRDNORM;
309
310 if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
311 if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
312 mask |= POLLOUT | POLLWRNORM;
313 } else { /* send SIGIO later */
314 set_bit(SOCK_ASYNC_NOSPACE,
315 &sk->sk_socket->flags);
316 set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
317
318 /* Race breaker. If space is freed after
319 * wspace test but before the flags are set,
320 * IO signal will be lost.
321 */
322 if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk))
323 mask |= POLLOUT | POLLWRNORM;
324 }
325 }
326 }
327 return mask;
328}
329
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800330EXPORT_SYMBOL_GPL(dccp_poll);
331
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700332int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
333{
334 dccp_pr_debug("entry\n");
335 return -ENOIOCTLCMD;
336}
337
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800338EXPORT_SYMBOL_GPL(dccp_ioctl);
339
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800340static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700341 char __user *optval, int optlen)
342{
343 struct dccp_sock *dp = dccp_sk(sk);
344 struct dccp_service_list *sl = NULL;
345
346 if (service == DCCP_SERVICE_INVALID_VALUE ||
347 optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32))
348 return -EINVAL;
349
350 if (optlen > sizeof(service)) {
351 sl = kmalloc(optlen, GFP_KERNEL);
352 if (sl == NULL)
353 return -ENOMEM;
354
355 sl->dccpsl_nr = optlen / sizeof(u32) - 1;
356 if (copy_from_user(sl->dccpsl_list,
357 optval + sizeof(service),
358 optlen - sizeof(service)) ||
359 dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) {
360 kfree(sl);
361 return -EFAULT;
362 }
363 }
364
365 lock_sock(sk);
366 dp->dccps_service = service;
367
Jesper Juhla51482b2005-11-08 09:41:34 -0800368 kfree(dp->dccps_service_list);
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700369
370 dp->dccps_service_list = sl;
371 release_sock(sk);
372 return 0;
373}
374
Andrea Bittauafe00252006-03-20 17:43:56 -0800375/* byte 1 is feature. the rest is the preference list */
376static int dccp_setsockopt_change(struct sock *sk, int type,
377 struct dccp_so_feat __user *optval)
378{
379 struct dccp_so_feat opt;
380 u8 *val;
381 int rc;
382
383 if (copy_from_user(&opt, optval, sizeof(opt)))
384 return -EFAULT;
385
386 val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
387 if (!val)
388 return -ENOMEM;
389
390 if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) {
391 rc = -EFAULT;
392 goto out_free_val;
393 }
394
395 rc = dccp_feat_change(sk, type, opt.dccpsf_feat, val, opt.dccpsf_len,
396 GFP_KERNEL);
397 if (rc)
398 goto out_free_val;
399
400out:
401 return rc;
402
403out_free_val:
404 kfree(val);
405 goto out;
406}
407
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700408int dccp_setsockopt(struct sock *sk, int level, int optname,
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -0300409 char __user *optval, int optlen)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700410{
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300411 struct dccp_sock *dp;
412 int err;
413 int val;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700414
415 if (level != SOL_DCCP)
Arnaldo Carvalho de Melo57cca052005-12-13 23:16:16 -0800416 return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
417 optname, optval,
418 optlen);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700419
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300420 if (optlen < sizeof(int))
421 return -EINVAL;
422
423 if (get_user(val, (int __user *)optval))
424 return -EFAULT;
425
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700426 if (optname == DCCP_SOCKOPT_SERVICE)
427 return dccp_setsockopt_service(sk, val, optval, optlen);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300428
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700429 lock_sock(sk);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300430 dp = dccp_sk(sk);
431 err = 0;
432
433 switch (optname) {
434 case DCCP_SOCKOPT_PACKET_SIZE:
435 dp->dccps_packet_size = val;
436 break;
Andrea Bittauafe00252006-03-20 17:43:56 -0800437
438 case DCCP_SOCKOPT_CHANGE_L:
439 if (optlen != sizeof(struct dccp_so_feat))
440 err = -EINVAL;
441 else
442 err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
443 (struct dccp_so_feat *)
444 optval);
445 break;
446
447 case DCCP_SOCKOPT_CHANGE_R:
448 if (optlen != sizeof(struct dccp_so_feat))
449 err = -EINVAL;
450 else
451 err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
452 (struct dccp_so_feat *)
453 optval);
454 break;
455
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300456 default:
457 err = -ENOPROTOOPT;
458 break;
459 }
460
461 release_sock(sk);
462 return err;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700463}
464
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800465EXPORT_SYMBOL_GPL(dccp_setsockopt);
466
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700467static int dccp_getsockopt_service(struct sock *sk, int len,
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800468 __be32 __user *optval,
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700469 int __user *optlen)
470{
471 const struct dccp_sock *dp = dccp_sk(sk);
472 const struct dccp_service_list *sl;
473 int err = -ENOENT, slen = 0, total_len = sizeof(u32);
474
475 lock_sock(sk);
476 if (dccp_service_not_initialized(sk))
477 goto out;
478
479 if ((sl = dp->dccps_service_list) != NULL) {
480 slen = sl->dccpsl_nr * sizeof(u32);
481 total_len += slen;
482 }
483
484 err = -EINVAL;
485 if (total_len > len)
486 goto out;
487
488 err = 0;
489 if (put_user(total_len, optlen) ||
490 put_user(dp->dccps_service, optval) ||
491 (sl != NULL && copy_to_user(optval + 1, sl->dccpsl_list, slen)))
492 err = -EFAULT;
493out:
494 release_sock(sk);
495 return err;
496}
497
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700498int dccp_getsockopt(struct sock *sk, int level, int optname,
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -0300499 char __user *optval, int __user *optlen)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700500{
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300501 struct dccp_sock *dp;
502 int val, len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700503
504 if (level != SOL_DCCP)
Arnaldo Carvalho de Melo57cca052005-12-13 23:16:16 -0800505 return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
506 optname, optval,
507 optlen);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300508 if (get_user(len, optlen))
509 return -EFAULT;
510
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700511 if (len < sizeof(int))
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300512 return -EINVAL;
513
514 dp = dccp_sk(sk);
515
516 switch (optname) {
517 case DCCP_SOCKOPT_PACKET_SIZE:
518 val = dp->dccps_packet_size;
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700519 len = sizeof(dp->dccps_packet_size);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300520 break;
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700521 case DCCP_SOCKOPT_SERVICE:
522 return dccp_getsockopt_service(sk, len,
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800523 (__be32 __user *)optval, optlen);
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700524 case 128 ... 191:
525 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
526 len, (u32 __user *)optval, optlen);
527 case 192 ... 255:
528 return ccid_hc_tx_getsockopt(dp->dccps_hc_tx_ccid, sk, optname,
529 len, (u32 __user *)optval, optlen);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300530 default:
531 return -ENOPROTOOPT;
532 }
533
534 if (put_user(len, optlen) || copy_to_user(optval, &val, len))
535 return -EFAULT;
536
537 return 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700538}
539
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800540EXPORT_SYMBOL_GPL(dccp_getsockopt);
541
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700542int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
543 size_t len)
544{
545 const struct dccp_sock *dp = dccp_sk(sk);
546 const int flags = msg->msg_flags;
547 const int noblock = flags & MSG_DONTWAIT;
548 struct sk_buff *skb;
549 int rc, size;
550 long timeo;
551
552 if (len > dp->dccps_mss_cache)
553 return -EMSGSIZE;
554
555 lock_sock(sk);
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700556 timeo = sock_sndtimeo(sk, noblock);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700557
558 /*
559 * We have to use sk_stream_wait_connect here to set sk_write_pending,
560 * so that the trick in dccp_rcv_request_sent_state_process.
561 */
562 /* Wait for a connection to finish. */
563 if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN | DCCPF_CLOSING))
564 if ((rc = sk_stream_wait_connect(sk, &timeo)) != 0)
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700565 goto out_release;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700566
567 size = sk->sk_prot->max_header + len;
568 release_sock(sk);
569 skb = sock_alloc_send_skb(sk, size, noblock, &rc);
570 lock_sock(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700571 if (skb == NULL)
572 goto out_release;
573
574 skb_reserve(skb, sk->sk_prot->max_header);
575 rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700576 if (rc != 0)
577 goto out_discard;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700578
Arnaldo Carvalho de Melod6809c12005-08-27 03:06:35 -0300579 rc = dccp_write_xmit(sk, skb, &timeo);
Arnaldo Carvalho de Melo20472af2005-08-23 21:50:21 -0700580 /*
581 * XXX we don't use sk_write_queue, so just discard the packet.
582 * Current plan however is to _use_ sk_write_queue with
583 * an algorith similar to tcp_sendmsg, where the main difference
584 * is that in DCCP we have to respect packet boundaries, so
585 * no coalescing of skbs.
586 *
587 * This bug was _quickly_ found & fixed by just looking at an OSTRA
588 * generated callgraph 8) -acme
589 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700590out_release:
591 release_sock(sk);
592 return rc ? : len;
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700593out_discard:
594 kfree_skb(skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700595 goto out_release;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700596}
597
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800598EXPORT_SYMBOL_GPL(dccp_sendmsg);
599
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700600int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
601 size_t len, int nonblock, int flags, int *addr_len)
602{
603 const struct dccp_hdr *dh;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700604 long timeo;
605
606 lock_sock(sk);
607
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300608 if (sk->sk_state == DCCP_LISTEN) {
609 len = -ENOTCONN;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700610 goto out;
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300611 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700612
613 timeo = sock_rcvtimeo(sk, nonblock);
614
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700615 do {
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300616 struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700617
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300618 if (skb == NULL)
619 goto verify_sock_status;
620
621 dh = dccp_hdr(skb);
622
623 if (dh->dccph_type == DCCP_PKT_DATA ||
624 dh->dccph_type == DCCP_PKT_DATAACK)
625 goto found_ok_skb;
626
627 if (dh->dccph_type == DCCP_PKT_RESET ||
628 dh->dccph_type == DCCP_PKT_CLOSE) {
629 dccp_pr_debug("found fin ok!\n");
630 len = 0;
631 goto found_fin_ok;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700632 }
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300633 dccp_pr_debug("packet_type=%s\n",
634 dccp_packet_name(dh->dccph_type));
635 sk_eat_skb(sk, skb);
636verify_sock_status:
637 if (sock_flag(sk, SOCK_DONE)) {
638 len = 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700639 break;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700640 }
641
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300642 if (sk->sk_err) {
643 len = sock_error(sk);
644 break;
645 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700646
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300647 if (sk->sk_shutdown & RCV_SHUTDOWN) {
648 len = 0;
649 break;
650 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700651
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300652 if (sk->sk_state == DCCP_CLOSED) {
653 if (!sock_flag(sk, SOCK_DONE)) {
654 /* This occurs when user tries to read
655 * from never connected socket.
656 */
657 len = -ENOTCONN;
658 break;
659 }
660 len = 0;
661 break;
662 }
663
664 if (!timeo) {
665 len = -EAGAIN;
666 break;
667 }
668
669 if (signal_pending(current)) {
670 len = sock_intr_errno(timeo);
671 break;
672 }
673
674 sk_wait_data(sk, &timeo);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700675 continue;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700676 found_ok_skb:
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300677 if (len > skb->len)
678 len = skb->len;
679 else if (len < skb->len)
680 msg->msg_flags |= MSG_TRUNC;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700681
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300682 if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len)) {
683 /* Exception. Bailout! */
684 len = -EFAULT;
685 break;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700686 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700687 found_fin_ok:
688 if (!(flags & MSG_PEEK))
689 sk_eat_skb(sk, skb);
690 break;
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300691 } while (1);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700692out:
693 release_sock(sk);
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300694 return len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700695}
696
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800697EXPORT_SYMBOL_GPL(dccp_recvmsg);
698
699int inet_dccp_listen(struct socket *sock, int backlog)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700700{
701 struct sock *sk = sock->sk;
702 unsigned char old_state;
703 int err;
704
705 lock_sock(sk);
706
707 err = -EINVAL;
708 if (sock->state != SS_UNCONNECTED || sock->type != SOCK_DCCP)
709 goto out;
710
711 old_state = sk->sk_state;
712 if (!((1 << old_state) & (DCCPF_CLOSED | DCCPF_LISTEN)))
713 goto out;
714
715 /* Really, if the socket is already in listen state
716 * we can only allow the backlog to be adjusted.
717 */
718 if (old_state != DCCP_LISTEN) {
719 /*
720 * FIXME: here it probably should be sk->sk_prot->listen_start
721 * see tcp_listen_start
722 */
723 err = dccp_listen_start(sk);
724 if (err)
725 goto out;
726 }
727 sk->sk_max_ack_backlog = backlog;
728 err = 0;
729
730out:
731 release_sock(sk);
732 return err;
733}
734
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800735EXPORT_SYMBOL_GPL(inet_dccp_listen);
736
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700737static const unsigned char dccp_new_state[] = {
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300738 /* current state: new state: action: */
739 [0] = DCCP_CLOSED,
740 [DCCP_OPEN] = DCCP_CLOSING | DCCP_ACTION_FIN,
741 [DCCP_REQUESTING] = DCCP_CLOSED,
742 [DCCP_PARTOPEN] = DCCP_CLOSING | DCCP_ACTION_FIN,
743 [DCCP_LISTEN] = DCCP_CLOSED,
744 [DCCP_RESPOND] = DCCP_CLOSED,
745 [DCCP_CLOSING] = DCCP_CLOSED,
746 [DCCP_TIME_WAIT] = DCCP_CLOSED,
747 [DCCP_CLOSED] = DCCP_CLOSED,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700748};
749
750static int dccp_close_state(struct sock *sk)
751{
752 const int next = dccp_new_state[sk->sk_state];
753 const int ns = next & DCCP_STATE_MASK;
754
755 if (ns != sk->sk_state)
756 dccp_set_state(sk, ns);
757
758 return next & DCCP_ACTION_FIN;
759}
760
761void dccp_close(struct sock *sk, long timeout)
762{
763 struct sk_buff *skb;
764
765 lock_sock(sk);
766
767 sk->sk_shutdown = SHUTDOWN_MASK;
768
769 if (sk->sk_state == DCCP_LISTEN) {
770 dccp_set_state(sk, DCCP_CLOSED);
771
772 /* Special case. */
773 inet_csk_listen_stop(sk);
774
775 goto adjudge_to_death;
776 }
777
778 /*
779 * We need to flush the recv. buffs. We do this only on the
780 * descriptor close, not protocol-sourced closes, because the
781 *reader process may not have drained the data yet!
782 */
783 /* FIXME: check for unread data */
784 while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
785 __kfree_skb(skb);
786 }
787
788 if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
789 /* Check zero linger _after_ checking for unread data. */
790 sk->sk_prot->disconnect(sk, 0);
791 } else if (dccp_close_state(sk)) {
Arnaldo Carvalho de Melo7ad07e72005-08-23 21:50:06 -0700792 dccp_send_close(sk, 1);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700793 }
794
795 sk_stream_wait_close(sk, timeout);
796
797adjudge_to_death:
Arnaldo Carvalho de Melo7ad07e72005-08-23 21:50:06 -0700798 /*
799 * It is the last release_sock in its life. It will remove backlog.
800 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700801 release_sock(sk);
802 /*
803 * Now socket is owned by kernel and we acquire BH lock
804 * to finish close. No need to check for user refs.
805 */
806 local_bh_disable();
807 bh_lock_sock(sk);
808 BUG_TRAP(!sock_owned_by_user(sk));
809
810 sock_hold(sk);
811 sock_orphan(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700812
Arnaldo Carvalho de Melo7ad07e72005-08-23 21:50:06 -0700813 /*
814 * The last release_sock may have processed the CLOSE or RESET
815 * packet moving sock to CLOSED state, if not we have to fire
816 * the CLOSE/CLOSEREQ retransmission timer, see "8.3. Termination"
817 * in draft-ietf-dccp-spec-11. -acme
818 */
819 if (sk->sk_state == DCCP_CLOSING) {
820 /* FIXME: should start at 2 * RTT */
821 /* Timer for repeating the CLOSE/CLOSEREQ until an answer. */
822 inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
823 inet_csk(sk)->icsk_rto,
824 DCCP_RTO_MAX);
825#if 0
826 /* Yeah, we should use sk->sk_prot->orphan_count, etc */
827 dccp_set_state(sk, DCCP_CLOSED);
828#endif
829 }
830
831 atomic_inc(sk->sk_prot->orphan_count);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700832 if (sk->sk_state == DCCP_CLOSED)
833 inet_csk_destroy_sock(sk);
834
835 /* Otherwise, socket is reprieved until protocol close. */
836
837 bh_unlock_sock(sk);
838 local_bh_enable();
839 sock_put(sk);
840}
841
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800842EXPORT_SYMBOL_GPL(dccp_close);
843
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700844void dccp_shutdown(struct sock *sk, int how)
845{
846 dccp_pr_debug("entry\n");
847}
848
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800849EXPORT_SYMBOL_GPL(dccp_shutdown);
850
Eric Dumazet90ddc4f2005-12-22 12:49:22 -0800851static const struct proto_ops inet_dccp_ops = {
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700852 .family = PF_INET,
853 .owner = THIS_MODULE,
854 .release = inet_release,
855 .bind = inet_bind,
856 .connect = inet_stream_connect,
857 .socketpair = sock_no_socketpair,
858 .accept = inet_accept,
859 .getname = inet_getname,
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700860 /* FIXME: work on tcp_poll to rename it to inet_csk_poll */
861 .poll = dccp_poll,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700862 .ioctl = inet_ioctl,
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300863 /* FIXME: work on inet_listen to rename it to sock_common_listen */
864 .listen = inet_dccp_listen,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700865 .shutdown = inet_shutdown,
866 .setsockopt = sock_common_setsockopt,
867 .getsockopt = sock_common_getsockopt,
868 .sendmsg = inet_sendmsg,
869 .recvmsg = sock_common_recvmsg,
870 .mmap = sock_no_mmap,
871 .sendpage = sock_no_sendpage,
872};
873
874extern struct net_proto_family inet_family_ops;
875
876static struct inet_protosw dccp_v4_protosw = {
877 .type = SOCK_DCCP,
878 .protocol = IPPROTO_DCCP,
Arnaldo Carvalho de Melo34ca6862005-12-13 23:23:32 -0800879 .prot = &dccp_prot,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700880 .ops = &inet_dccp_ops,
881 .capability = -1,
882 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800883 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700884};
885
886/*
887 * This is the global socket data structure used for responding to
888 * the Out-of-the-blue (OOTB) packets. A control sock will be created
889 * for this socket at the initialization time.
890 */
891struct socket *dccp_ctl_socket;
892
893static char dccp_ctl_socket_err_msg[] __initdata =
894 KERN_ERR "DCCP: Failed to create the control socket.\n";
895
896static int __init dccp_ctl_sock_init(void)
897{
898 int rc = sock_create_kern(PF_INET, SOCK_DCCP, IPPROTO_DCCP,
899 &dccp_ctl_socket);
900 if (rc < 0)
901 printk(dccp_ctl_socket_err_msg);
902 else {
903 dccp_ctl_socket->sk->sk_allocation = GFP_ATOMIC;
904 inet_sk(dccp_ctl_socket->sk)->uc_ttl = -1;
905
906 /* Unhash it so that IP input processing does not even
907 * see it, we do not wish this socket to see incoming
908 * packets.
909 */
910 dccp_ctl_socket->sk->sk_prot->unhash(dccp_ctl_socket->sk);
911 }
912
913 return rc;
914}
915
Arnaldo Carvalho de Melo725ba8e2005-08-13 20:35:39 -0300916#ifdef CONFIG_IP_DCCP_UNLOAD_HACK
917void dccp_ctl_sock_exit(void)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700918{
Arnaldo Carvalho de Melo54808552005-08-18 20:47:02 -0300919 if (dccp_ctl_socket != NULL) {
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700920 sock_release(dccp_ctl_socket);
Arnaldo Carvalho de Melo54808552005-08-18 20:47:02 -0300921 dccp_ctl_socket = NULL;
922 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700923}
924
Arnaldo Carvalho de Melo725ba8e2005-08-13 20:35:39 -0300925EXPORT_SYMBOL_GPL(dccp_ctl_sock_exit);
926#endif
927
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700928static int __init init_dccp_v4_mibs(void)
929{
930 int rc = -ENOMEM;
931
932 dccp_statistics[0] = alloc_percpu(struct dccp_mib);
933 if (dccp_statistics[0] == NULL)
934 goto out;
935
936 dccp_statistics[1] = alloc_percpu(struct dccp_mib);
937 if (dccp_statistics[1] == NULL)
938 goto out_free_one;
939
940 rc = 0;
941out:
942 return rc;
943out_free_one:
944 free_percpu(dccp_statistics[0]);
945 dccp_statistics[0] = NULL;
946 goto out;
947
948}
949
950static int thash_entries;
951module_param(thash_entries, int, 0444);
952MODULE_PARM_DESC(thash_entries, "Number of ehash buckets");
953
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -0300954#ifdef CONFIG_IP_DCCP_DEBUG
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700955int dccp_debug;
956module_param(dccp_debug, int, 0444);
957MODULE_PARM_DESC(dccp_debug, "Enable debug messages");
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800958
959EXPORT_SYMBOL_GPL(dccp_debug);
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -0300960#endif
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700961
962static int __init dccp_init(void)
963{
964 unsigned long goal;
965 int ehash_order, bhash_order, i;
Arnaldo Carvalho de Melo34ca6862005-12-13 23:23:32 -0800966 int rc = proto_register(&dccp_prot, 1);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700967
968 if (rc)
969 goto out;
970
Arnaldo Carvalho de Melofa23e2e2006-03-20 17:16:01 -0800971 rc = -ENOBUFS;
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300972 dccp_hashinfo.bind_bucket_cachep =
973 kmem_cache_create("dccp_bind_bucket",
974 sizeof(struct inet_bind_bucket), 0,
975 SLAB_HWCACHE_ALIGN, NULL, NULL);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700976 if (!dccp_hashinfo.bind_bucket_cachep)
977 goto out_proto_unregister;
978
979 /*
980 * Size and allocate the main established and bind bucket
981 * hash tables.
982 *
983 * The methodology is similar to that of the buffer cache.
984 */
985 if (num_physpages >= (128 * 1024))
986 goal = num_physpages >> (21 - PAGE_SHIFT);
987 else
988 goal = num_physpages >> (23 - PAGE_SHIFT);
989
990 if (thash_entries)
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300991 goal = (thash_entries *
992 sizeof(struct inet_ehash_bucket)) >> PAGE_SHIFT;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700993 for (ehash_order = 0; (1UL << ehash_order) < goal; ehash_order++)
994 ;
995 do {
996 dccp_hashinfo.ehash_size = (1UL << ehash_order) * PAGE_SIZE /
997 sizeof(struct inet_ehash_bucket);
998 dccp_hashinfo.ehash_size >>= 1;
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -0300999 while (dccp_hashinfo.ehash_size &
1000 (dccp_hashinfo.ehash_size - 1))
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001001 dccp_hashinfo.ehash_size--;
1002 dccp_hashinfo.ehash = (struct inet_ehash_bucket *)
1003 __get_free_pages(GFP_ATOMIC, ehash_order);
1004 } while (!dccp_hashinfo.ehash && --ehash_order > 0);
1005
1006 if (!dccp_hashinfo.ehash) {
1007 printk(KERN_CRIT "Failed to allocate DCCP "
1008 "established hash table\n");
1009 goto out_free_bind_bucket_cachep;
1010 }
1011
1012 for (i = 0; i < (dccp_hashinfo.ehash_size << 1); i++) {
1013 rwlock_init(&dccp_hashinfo.ehash[i].lock);
1014 INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].chain);
1015 }
1016
1017 bhash_order = ehash_order;
1018
1019 do {
1020 dccp_hashinfo.bhash_size = (1UL << bhash_order) * PAGE_SIZE /
1021 sizeof(struct inet_bind_hashbucket);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -03001022 if ((dccp_hashinfo.bhash_size > (64 * 1024)) &&
1023 bhash_order > 0)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001024 continue;
1025 dccp_hashinfo.bhash = (struct inet_bind_hashbucket *)
1026 __get_free_pages(GFP_ATOMIC, bhash_order);
1027 } while (!dccp_hashinfo.bhash && --bhash_order >= 0);
1028
1029 if (!dccp_hashinfo.bhash) {
1030 printk(KERN_CRIT "Failed to allocate DCCP bind hash table\n");
1031 goto out_free_dccp_ehash;
1032 }
1033
1034 for (i = 0; i < dccp_hashinfo.bhash_size; i++) {
1035 spin_lock_init(&dccp_hashinfo.bhash[i].lock);
1036 INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain);
1037 }
1038
Arnaldo Carvalho de Melofa23e2e2006-03-20 17:16:01 -08001039 rc = init_dccp_v4_mibs();
1040 if (rc)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001041 goto out_free_dccp_bhash;
1042
1043 rc = -EAGAIN;
1044 if (inet_add_protocol(&dccp_protocol, IPPROTO_DCCP))
1045 goto out_free_dccp_v4_mibs;
1046
1047 inet_register_protosw(&dccp_v4_protosw);
1048
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001049 rc = dccp_ackvec_init();
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001050 if (rc)
1051 goto out_unregister_protosw;
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001052
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001053 rc = dccp_sysctl_init();
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001054 if (rc)
1055 goto out_ackvec_exit;
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001056
1057 rc = dccp_ctl_sock_init();
1058 if (rc)
1059 goto out_sysctl_exit;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001060out:
1061 return rc;
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001062out_sysctl_exit:
1063 dccp_sysctl_exit();
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001064out_ackvec_exit:
1065 dccp_ackvec_exit();
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001066out_unregister_protosw:
1067 inet_unregister_protosw(&dccp_v4_protosw);
1068 inet_del_protocol(&dccp_protocol, IPPROTO_DCCP);
1069out_free_dccp_v4_mibs:
1070 free_percpu(dccp_statistics[0]);
1071 free_percpu(dccp_statistics[1]);
1072 dccp_statistics[0] = dccp_statistics[1] = NULL;
1073out_free_dccp_bhash:
1074 free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
1075 dccp_hashinfo.bhash = NULL;
1076out_free_dccp_ehash:
1077 free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order);
1078 dccp_hashinfo.ehash = NULL;
1079out_free_bind_bucket_cachep:
1080 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
1081 dccp_hashinfo.bind_bucket_cachep = NULL;
1082out_proto_unregister:
Arnaldo Carvalho de Melo34ca6862005-12-13 23:23:32 -08001083 proto_unregister(&dccp_prot);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001084 goto out;
1085}
1086
1087static const char dccp_del_proto_err_msg[] __exitdata =
1088 KERN_ERR "can't remove dccp net_protocol\n";
1089
1090static void __exit dccp_fini(void)
1091{
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001092 inet_unregister_protosw(&dccp_v4_protosw);
1093
1094 if (inet_del_protocol(&dccp_protocol, IPPROTO_DCCP) < 0)
1095 printk(dccp_del_proto_err_msg);
1096
Arnaldo Carvalho de Melo725ba8e2005-08-13 20:35:39 -03001097 free_percpu(dccp_statistics[0]);
1098 free_percpu(dccp_statistics[1]);
1099 free_pages((unsigned long)dccp_hashinfo.bhash,
1100 get_order(dccp_hashinfo.bhash_size *
1101 sizeof(struct inet_bind_hashbucket)));
1102 free_pages((unsigned long)dccp_hashinfo.ehash,
1103 get_order(dccp_hashinfo.ehash_size *
1104 sizeof(struct inet_ehash_bucket)));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001105 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
Arnaldo Carvalho de Melo34ca6862005-12-13 23:23:32 -08001106 proto_unregister(&dccp_prot);
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001107 dccp_ackvec_exit();
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001108 dccp_sysctl_exit();
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001109}
1110
1111module_init(dccp_init);
1112module_exit(dccp_fini);
1113
Arnaldo Carvalho de Melobb97d312005-08-09 20:19:14 -07001114/*
1115 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1116 * values directly, Also cover the case where the protocol is not specified,
1117 * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
1118 */
1119MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
1120MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001121MODULE_LICENSE("GPL");
1122MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>");
1123MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");