blob: b68168fcc06aa1981258eca4857511329af62f9a [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
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070012#include <linux/dccp.h>
13#include <linux/module.h>
14#include <linux/types.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/skbuff.h>
18#include <linux/netdevice.h>
19#include <linux/in.h>
20#include <linux/if_arp.h>
21#include <linux/init.h>
22#include <linux/random.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070024#include <net/checksum.h>
25
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020026#include <net/inet_sock.h>
Eric Dumazet120e9da2017-08-16 07:03:15 -070027#include <net/inet_common.h>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070028#include <net/sock.h>
29#include <net/xfrm.h>
30
Arnaldo Carvalho de Melo62731722007-10-23 20:23:30 -070031#include <asm/ioctls.h>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070032#include <linux/spinlock.h>
33#include <linux/timer.h>
34#include <linux/delay.h>
35#include <linux/poll.h>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070036
37#include "ccid.h"
38#include "dccp.h"
Andrea Bittauafe00252006-03-20 17:43:56 -080039#include "feat.h"
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070040
Eric Dumazetba899662005-08-26 12:05:31 -070041DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070042
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -080043EXPORT_SYMBOL_GPL(dccp_statistics);
44
Eric Dumazetdd24c002008-11-25 21:17:14 -080045struct percpu_counter dccp_orphan_count;
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -080046EXPORT_SYMBOL_GPL(dccp_orphan_count);
47
Eric Dumazet5caea4e2008-11-20 00:40:07 -080048struct inet_hashinfo dccp_hashinfo;
Arnaldo Carvalho de Melo075ae862006-03-20 21:24:19 -080049EXPORT_SYMBOL_GPL(dccp_hashinfo);
50
Ian McDonaldb1308dc2006-11-20 18:30:17 -020051/* the maximum queue length for tx in packets. 0 is no limit */
52int sysctl_dccp_tx_qlen __read_mostly = 5;
53
stephen hemminger1f4f0f62010-10-05 04:24:09 +000054#ifdef CONFIG_IP_DCCP_DEBUG
55static const char *dccp_state_name(const int state)
56{
57 static const char *const dccp_state_names[] = {
58 [DCCP_OPEN] = "OPEN",
59 [DCCP_REQUESTING] = "REQUESTING",
60 [DCCP_PARTOPEN] = "PARTOPEN",
61 [DCCP_LISTEN] = "LISTEN",
62 [DCCP_RESPOND] = "RESPOND",
63 [DCCP_CLOSING] = "CLOSING",
64 [DCCP_ACTIVE_CLOSEREQ] = "CLOSEREQ",
65 [DCCP_PASSIVE_CLOSE] = "PASSIVE_CLOSE",
66 [DCCP_PASSIVE_CLOSEREQ] = "PASSIVE_CLOSEREQ",
67 [DCCP_TIME_WAIT] = "TIME_WAIT",
68 [DCCP_CLOSED] = "CLOSED",
69 };
70
71 if (state >= DCCP_MAX_STATES)
72 return "INVALID STATE!";
73 else
74 return dccp_state_names[state];
75}
76#endif
77
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -080078void dccp_set_state(struct sock *sk, const int state)
79{
80 const int oldstate = sk->sk_state;
81
Gerrit Renkerf11135a2007-11-28 11:34:53 -020082 dccp_pr_debug("%s(%p) %s --> %s\n", dccp_role(sk), sk,
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -080083 dccp_state_name(oldstate), dccp_state_name(state));
84 WARN_ON(state == oldstate);
85
86 switch (state) {
87 case DCCP_OPEN:
88 if (oldstate != DCCP_OPEN)
89 DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
Gerrit Renker6eb55d12008-12-08 01:15:26 -080090 /* Client retransmits all Confirm options until entering OPEN */
91 if (oldstate == DCCP_PARTOPEN)
92 dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg);
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -080093 break;
94
95 case DCCP_CLOSED:
Gerrit Renker0c869622007-11-28 11:59:48 -020096 if (oldstate == DCCP_OPEN || oldstate == DCCP_ACTIVE_CLOSEREQ ||
97 oldstate == DCCP_CLOSING)
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -080098 DCCP_INC_STATS(DCCP_MIB_ESTABRESETS);
99
100 sk->sk_prot->unhash(sk);
101 if (inet_csk(sk)->icsk_bind_hash != NULL &&
102 !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -0800103 inet_put_port(sk);
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -0800104 /* fall through */
105 default:
106 if (oldstate == DCCP_OPEN)
107 DCCP_DEC_STATS(DCCP_MIB_CURRESTAB);
108 }
109
110 /* Change state AFTER socket is unhashed to avoid closed
111 * socket sitting in hash tables.
112 */
113 sk->sk_state = state;
114}
115
116EXPORT_SYMBOL_GPL(dccp_set_state);
117
Gerrit Renker0c869622007-11-28 11:59:48 -0200118static void dccp_finish_passive_close(struct sock *sk)
119{
120 switch (sk->sk_state) {
121 case DCCP_PASSIVE_CLOSE:
122 /* Node (client or server) has received Close packet. */
123 dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
124 dccp_set_state(sk, DCCP_CLOSED);
125 break;
126 case DCCP_PASSIVE_CLOSEREQ:
127 /*
128 * Client received CloseReq. We set the `active' flag so that
129 * dccp_send_close() retransmits the Close as per RFC 4340, 8.3.
130 */
131 dccp_send_close(sk, 1);
132 dccp_set_state(sk, DCCP_CLOSING);
133 }
134}
135
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -0800136void dccp_done(struct sock *sk)
137{
138 dccp_set_state(sk, DCCP_CLOSED);
139 dccp_clear_xmit_timers(sk);
140
141 sk->sk_shutdown = SHUTDOWN_MASK;
142
143 if (!sock_flag(sk, SOCK_DEAD))
144 sk->sk_state_change(sk);
145 else
146 inet_csk_destroy_sock(sk);
147}
148
149EXPORT_SYMBOL_GPL(dccp_done);
150
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700151const char *dccp_packet_name(const int type)
152{
Jan Engelhardt36cbd3d2009-08-05 10:42:58 -0700153 static const char *const dccp_packet_names[] = {
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700154 [DCCP_PKT_REQUEST] = "REQUEST",
155 [DCCP_PKT_RESPONSE] = "RESPONSE",
156 [DCCP_PKT_DATA] = "DATA",
157 [DCCP_PKT_ACK] = "ACK",
158 [DCCP_PKT_DATAACK] = "DATAACK",
159 [DCCP_PKT_CLOSEREQ] = "CLOSEREQ",
160 [DCCP_PKT_CLOSE] = "CLOSE",
161 [DCCP_PKT_RESET] = "RESET",
162 [DCCP_PKT_SYNC] = "SYNC",
163 [DCCP_PKT_SYNCACK] = "SYNCACK",
164 };
165
166 if (type >= DCCP_NR_PKT_TYPES)
167 return "INVALID";
168 else
169 return dccp_packet_names[type];
170}
171
172EXPORT_SYMBOL_GPL(dccp_packet_name);
173
Eric Dumazet120e9da2017-08-16 07:03:15 -0700174static void dccp_sk_destruct(struct sock *sk)
175{
176 struct dccp_sock *dp = dccp_sk(sk);
177
178 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
179 dp->dccps_hc_tx_ccid = NULL;
180 inet_sock_destruct(sk);
181}
182
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800183int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800184{
185 struct dccp_sock *dp = dccp_sk(sk);
186 struct inet_connection_sock *icsk = inet_csk(sk);
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800187
Arnaldo Carvalho de Meloe18d7a92007-11-24 21:42:53 -0200188 icsk->icsk_rto = DCCP_TIMEOUT_INIT;
189 icsk->icsk_syn_retries = sysctl_dccp_request_retries;
190 sk->sk_state = DCCP_CLOSED;
191 sk->sk_write_space = dccp_write_space;
Eric Dumazet120e9da2017-08-16 07:03:15 -0700192 sk->sk_destruct = dccp_sk_destruct;
Arnaldo Carvalho de Meloe18d7a92007-11-24 21:42:53 -0200193 icsk->icsk_sync_mss = dccp_sync_mss;
Gerrit Renker410e27a2008-09-09 13:27:22 +0200194 dp->dccps_mss_cache = 536;
Arnaldo Carvalho de Meloe18d7a92007-11-24 21:42:53 -0200195 dp->dccps_rate_last = jiffies;
196 dp->dccps_role = DCCP_ROLE_UNDEFINED;
197 dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100198 dp->dccps_tx_qlen = sysctl_dccp_tx_qlen;
Arnaldo Carvalho de Meloe18d7a92007-11-24 21:42:53 -0200199
200 dccp_init_xmit_timers(sk);
201
Gerrit Renkerac757732008-11-04 23:55:49 -0800202 INIT_LIST_HEAD(&dp->dccps_featneg);
Gerrit Renker6eb55d12008-12-08 01:15:26 -0800203 /* control socket doesn't need feat nego */
204 if (likely(ctl_sock_initialized))
205 return dccp_feat_init(sk);
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800206 return 0;
207}
208
209EXPORT_SYMBOL_GPL(dccp_init_sock);
210
Brian Haley7d06b2e2008-06-14 17:04:49 -0700211void dccp_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800212{
213 struct dccp_sock *dp = dccp_sk(sk);
214
Eric Dumazet7749d4f2017-08-14 14:10:25 -0700215 __skb_queue_purge(&sk->sk_write_queue);
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800216 if (sk->sk_send_head != NULL) {
217 kfree_skb(sk->sk_send_head);
218 sk->sk_send_head = NULL;
219 }
220
221 /* Clean up a referenced DCCP bind bucket. */
222 if (inet_csk(sk)->icsk_bind_hash != NULL)
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -0800223 inet_put_port(sk);
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800224
225 kfree(dp->dccps_service_list);
226 dp->dccps_service_list = NULL;
227
Gerrit Renker6fdd34d2008-12-08 01:19:06 -0800228 if (dp->dccps_hc_rx_ackvec != NULL) {
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800229 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
230 dp->dccps_hc_rx_ackvec = NULL;
231 }
232 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
Eric Dumazet120e9da2017-08-16 07:03:15 -0700233 dp->dccps_hc_rx_ccid = NULL;
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800234
235 /* clean up feature negotiation state */
Gerrit Renkerd99a7bd2008-11-04 23:56:30 -0800236 dccp_feat_list_purge(&dp->dccps_featneg);
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800237}
238
239EXPORT_SYMBOL_GPL(dccp_destroy_sock);
240
Eric Dumazet72a3eff2006-11-16 02:30:37 -0800241static inline int dccp_listen_start(struct sock *sk, int backlog)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700242{
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700243 struct dccp_sock *dp = dccp_sk(sk);
244
245 dp->dccps_role = DCCP_ROLE_LISTEN;
Gerrit Renker9eca0a42008-11-12 00:48:44 -0800246 /* do not start to listen if feature negotiation setup fails */
247 if (dccp_feat_finalise_settings(dp))
248 return -EPROTO;
Eric Dumazet72a3eff2006-11-16 02:30:37 -0800249 return inet_csk_listen_start(sk, backlog);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700250}
251
Gerrit Renkerce865a62007-11-24 22:14:15 -0200252static inline int dccp_need_reset(int state)
253{
254 return state != DCCP_CLOSED && state != DCCP_LISTEN &&
255 state != DCCP_REQUESTING;
256}
257
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700258int dccp_disconnect(struct sock *sk, int flags)
259{
260 struct inet_connection_sock *icsk = inet_csk(sk);
261 struct inet_sock *inet = inet_sk(sk);
262 int err = 0;
263 const int old_state = sk->sk_state;
264
265 if (old_state != DCCP_CLOSED)
266 dccp_set_state(sk, DCCP_CLOSED);
267
Gerrit Renkerce865a62007-11-24 22:14:15 -0200268 /*
269 * This corresponds to the ABORT function of RFC793, sec. 3.8
270 * TCP uses a RST segment, DCCP a Reset packet with Code 2, "Aborted".
271 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700272 if (old_state == DCCP_LISTEN) {
273 inet_csk_listen_stop(sk);
Gerrit Renkerce865a62007-11-24 22:14:15 -0200274 } else if (dccp_need_reset(old_state)) {
275 dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);
276 sk->sk_err = ECONNRESET;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700277 } else if (old_state == DCCP_REQUESTING)
278 sk->sk_err = ECONNRESET;
279
280 dccp_clear_xmit_timers(sk);
Gerrit Renker48816322008-08-23 13:28:27 +0200281
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700282 __skb_queue_purge(&sk->sk_receive_queue);
Gerrit Renker48816322008-08-23 13:28:27 +0200283 __skb_queue_purge(&sk->sk_write_queue);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700284 if (sk->sk_send_head != NULL) {
285 __kfree_skb(sk->sk_send_head);
286 sk->sk_send_head = NULL;
287 }
288
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000289 inet->inet_dport = 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700290
291 if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
292 inet_reset_saddr(sk);
293
294 sk->sk_shutdown = 0;
295 sock_reset_flag(sk, SOCK_DONE);
296
297 icsk->icsk_backoff = 0;
298 inet_csk_delack_init(sk);
299 __sk_dst_reset(sk);
300
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000301 WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700302
303 sk->sk_error_report(sk);
304 return err;
305}
306
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800307EXPORT_SYMBOL_GPL(dccp_disconnect);
308
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700309/*
310 * Wait for a DCCP event.
311 *
312 * Note that we don't need to lock the socket, as the upper poll layers
313 * take care of normal races (between the test and the event) and we don't
314 * go look at any of the socket buffers directly.
315 */
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800316unsigned int dccp_poll(struct file *file, struct socket *sock,
317 poll_table *wait)
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700318{
319 unsigned int mask;
320 struct sock *sk = sock->sk;
321
Eric Dumazetaa395142010-04-20 13:03:51 +0000322 sock_poll_wait(file, sk_sleep(sk), wait);
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700323 if (sk->sk_state == DCCP_LISTEN)
324 return inet_csk_listen_poll(sk);
325
326 /* Socket is not locked. We are protected from async events
327 by poll logic and correct handling of state changes
328 made by another threads is impossible in any case.
329 */
330
331 mask = 0;
332 if (sk->sk_err)
333 mask = POLLERR;
334
335 if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
336 mask |= POLLHUP;
337 if (sk->sk_shutdown & RCV_SHUTDOWN)
Davide Libenzif348d702006-03-25 03:07:39 -0800338 mask |= POLLIN | POLLRDNORM | POLLRDHUP;
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700339
340 /* Connected? */
341 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
342 if (atomic_read(&sk->sk_rmem_alloc) > 0)
343 mask |= POLLIN | POLLRDNORM;
344
345 if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
Eric Dumazet64dc6132013-07-22 20:26:31 -0700346 if (sk_stream_is_writeable(sk)) {
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700347 mask |= POLLOUT | POLLWRNORM;
348 } else { /* send SIGIO later */
Eric Dumazet9cd3e072015-11-29 20:03:10 -0800349 sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700350 set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
351
352 /* Race breaker. If space is freed after
353 * wspace test but before the flags are set,
354 * IO signal will be lost.
355 */
Eric Dumazet64dc6132013-07-22 20:26:31 -0700356 if (sk_stream_is_writeable(sk))
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700357 mask |= POLLOUT | POLLWRNORM;
358 }
359 }
360 }
361 return mask;
362}
363
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800364EXPORT_SYMBOL_GPL(dccp_poll);
365
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700366int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
367{
Arnaldo Carvalho de Melo62731722007-10-23 20:23:30 -0700368 int rc = -ENOTCONN;
369
370 lock_sock(sk);
371
372 if (sk->sk_state == DCCP_LISTEN)
373 goto out;
374
375 switch (cmd) {
376 case SIOCINQ: {
377 struct sk_buff *skb;
378 unsigned long amount = 0;
379
380 skb = skb_peek(&sk->sk_receive_queue);
381 if (skb != NULL) {
382 /*
383 * We will only return the amount of this packet since
384 * that is all that will be read.
385 */
386 amount = skb->len;
387 }
388 rc = put_user(amount, (int __user *)arg);
389 }
390 break;
391 default:
392 rc = -ENOIOCTLCMD;
393 break;
394 }
395out:
396 release_sock(sk);
397 return rc;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700398}
399
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800400EXPORT_SYMBOL_GPL(dccp_ioctl);
401
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800402static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
David S. Millerb7058842009-09-30 16:12:20 -0700403 char __user *optval, unsigned int optlen)
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700404{
405 struct dccp_sock *dp = dccp_sk(sk);
406 struct dccp_service_list *sl = NULL;
407
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200408 if (service == DCCP_SERVICE_INVALID_VALUE ||
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700409 optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32))
410 return -EINVAL;
411
412 if (optlen > sizeof(service)) {
413 sl = kmalloc(optlen, GFP_KERNEL);
414 if (sl == NULL)
415 return -ENOMEM;
416
417 sl->dccpsl_nr = optlen / sizeof(u32) - 1;
418 if (copy_from_user(sl->dccpsl_list,
419 optval + sizeof(service),
420 optlen - sizeof(service)) ||
421 dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) {
422 kfree(sl);
423 return -EFAULT;
424 }
425 }
426
427 lock_sock(sk);
428 dp->dccps_service = service;
429
Jesper Juhla51482b2005-11-08 09:41:34 -0800430 kfree(dp->dccps_service_list);
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700431
432 dp->dccps_service_list = sl;
433 release_sock(sk);
434 return 0;
435}
436
Gerrit Renker29450552008-11-16 22:53:48 -0800437static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
438{
439 u8 *list, len;
440 int i, rc;
441
442 if (cscov < 0 || cscov > 15)
443 return -EINVAL;
444 /*
445 * Populate a list of permissible values, in the range cscov...15. This
446 * is necessary since feature negotiation of single values only works if
447 * both sides incidentally choose the same value. Since the list starts
448 * lowest-value first, negotiation will pick the smallest shared value.
449 */
450 if (cscov == 0)
451 return 0;
452 len = 16 - cscov;
453
454 list = kmalloc(len, GFP_KERNEL);
455 if (list == NULL)
456 return -ENOBUFS;
457
458 for (i = 0; i < len; i++)
459 list[i] = cscov++;
460
461 rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
462
463 if (rc == 0) {
464 if (rx)
465 dccp_sk(sk)->dccps_pcrlen = cscov;
466 else
467 dccp_sk(sk)->dccps_pcslen = cscov;
468 }
469 kfree(list);
470 return rc;
471}
472
Gerrit Renkerb20a9c22008-11-23 16:02:31 -0800473static int dccp_setsockopt_ccid(struct sock *sk, int type,
David S. Millerb7058842009-09-30 16:12:20 -0700474 char __user *optval, unsigned int optlen)
Gerrit Renkerb20a9c22008-11-23 16:02:31 -0800475{
476 u8 *val;
477 int rc = 0;
478
479 if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
480 return -EINVAL;
481
Julia Lawall042604d2010-05-21 22:25:19 +0000482 val = memdup_user(optval, optlen);
483 if (IS_ERR(val))
484 return PTR_ERR(val);
Gerrit Renkerb20a9c22008-11-23 16:02:31 -0800485
486 lock_sock(sk);
487 if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
488 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
489
490 if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
491 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
492 release_sock(sk);
493
494 kfree(val);
495 return rc;
496}
497
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800498static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
David S. Millerb7058842009-09-30 16:12:20 -0700499 char __user *optval, unsigned int optlen)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700500{
Gerrit Renker09dbc382006-11-14 12:57:34 -0200501 struct dccp_sock *dp = dccp_sk(sk);
502 int val, err = 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700503
Gerrit Renker19102992008-11-16 22:56:55 -0800504 switch (optname) {
505 case DCCP_SOCKOPT_PACKET_SIZE:
506 DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
507 return 0;
508 case DCCP_SOCKOPT_CHANGE_L:
509 case DCCP_SOCKOPT_CHANGE_R:
510 DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
511 return 0;
Gerrit Renkerb20a9c22008-11-23 16:02:31 -0800512 case DCCP_SOCKOPT_CCID:
513 case DCCP_SOCKOPT_RX_CCID:
514 case DCCP_SOCKOPT_TX_CCID:
515 return dccp_setsockopt_ccid(sk, optname, optval, optlen);
Gerrit Renker19102992008-11-16 22:56:55 -0800516 }
517
518 if (optlen < (int)sizeof(int))
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300519 return -EINVAL;
520
521 if (get_user(val, (int __user *)optval))
522 return -EFAULT;
523
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700524 if (optname == DCCP_SOCKOPT_SERVICE)
525 return dccp_setsockopt_service(sk, val, optval, optlen);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300526
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700527 lock_sock(sk);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300528 switch (optname) {
Gerrit Renkerb8599d22007-12-13 12:25:01 -0200529 case DCCP_SOCKOPT_SERVER_TIMEWAIT:
530 if (dp->dccps_role != DCCP_ROLE_SERVER)
531 err = -EOPNOTSUPP;
532 else
533 dp->dccps_server_timewait = (val != 0);
534 break;
Gerrit Renker29450552008-11-16 22:53:48 -0800535 case DCCP_SOCKOPT_SEND_CSCOV:
536 err = dccp_setsockopt_cscov(sk, val, false);
Tomasz Grobelnyd6da3512008-09-04 07:30:19 +0200537 break;
Gerrit Renker29450552008-11-16 22:53:48 -0800538 case DCCP_SOCKOPT_RECV_CSCOV:
539 err = dccp_setsockopt_cscov(sk, val, true);
Tomasz Grobelnyd6da3512008-09-04 07:30:19 +0200540 break;
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100541 case DCCP_SOCKOPT_QPOLICY_ID:
542 if (sk->sk_state != DCCP_CLOSED)
543 err = -EISCONN;
544 else if (val < 0 || val >= DCCPQ_POLICY_MAX)
545 err = -EINVAL;
546 else
547 dp->dccps_qpolicy = val;
548 break;
549 case DCCP_SOCKOPT_QPOLICY_TXQLEN:
550 if (val < 0)
551 err = -EINVAL;
552 else
553 dp->dccps_tx_qlen = val;
554 break;
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300555 default:
556 err = -ENOPROTOOPT;
557 break;
558 }
Gerrit Renker410e27a2008-09-09 13:27:22 +0200559 release_sock(sk);
Gerrit Renker19102992008-11-16 22:56:55 -0800560
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300561 return err;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700562}
563
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800564int dccp_setsockopt(struct sock *sk, int level, int optname,
David S. Millerb7058842009-09-30 16:12:20 -0700565 char __user *optval, unsigned int optlen)
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800566{
567 if (level != SOL_DCCP)
568 return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
569 optname, optval,
570 optlen);
571 return do_dccp_setsockopt(sk, level, optname, optval, optlen);
572}
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800573
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800574EXPORT_SYMBOL_GPL(dccp_setsockopt);
575
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800576#ifdef CONFIG_COMPAT
577int compat_dccp_setsockopt(struct sock *sk, int level, int optname,
David S. Millerb7058842009-09-30 16:12:20 -0700578 char __user *optval, unsigned int optlen)
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800579{
Arnaldo Carvalho de Melodec73ff2006-03-20 22:46:16 -0800580 if (level != SOL_DCCP)
581 return inet_csk_compat_setsockopt(sk, level, optname,
582 optval, optlen);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800583 return do_dccp_setsockopt(sk, level, optname, optval, optlen);
584}
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800585
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800586EXPORT_SYMBOL_GPL(compat_dccp_setsockopt);
587#endif
588
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700589static int dccp_getsockopt_service(struct sock *sk, int len,
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800590 __be32 __user *optval,
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700591 int __user *optlen)
592{
593 const struct dccp_sock *dp = dccp_sk(sk);
594 const struct dccp_service_list *sl;
595 int err = -ENOENT, slen = 0, total_len = sizeof(u32);
596
597 lock_sock(sk);
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700598 if ((sl = dp->dccps_service_list) != NULL) {
599 slen = sl->dccpsl_nr * sizeof(u32);
600 total_len += slen;
601 }
602
603 err = -EINVAL;
604 if (total_len > len)
605 goto out;
606
607 err = 0;
608 if (put_user(total_len, optlen) ||
609 put_user(dp->dccps_service, optval) ||
610 (sl != NULL && copy_to_user(optval + 1, sl->dccpsl_list, slen)))
611 err = -EFAULT;
612out:
613 release_sock(sk);
614 return err;
615}
616
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800617static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -0300618 char __user *optval, int __user *optlen)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700619{
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300620 struct dccp_sock *dp;
621 int val, len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700622
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300623 if (get_user(len, optlen))
624 return -EFAULT;
625
Arnaldo Carvalho de Melo39ebc022007-03-28 11:54:32 -0700626 if (len < (int)sizeof(int))
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300627 return -EINVAL;
628
629 dp = dccp_sk(sk);
630
631 switch (optname) {
632 case DCCP_SOCKOPT_PACKET_SIZE:
Gerrit Renker5aed3242006-11-28 19:33:36 -0200633 DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
Arnaldo Carvalho de Melo841bac12006-11-28 19:42:03 -0200634 return 0;
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700635 case DCCP_SOCKOPT_SERVICE:
636 return dccp_getsockopt_service(sk, len,
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800637 (__be32 __user *)optval, optlen);
Gerrit Renker7c559a92007-10-04 14:39:22 -0700638 case DCCP_SOCKOPT_GET_CUR_MPS:
639 val = dp->dccps_mss_cache;
Gerrit Renker7c559a92007-10-04 14:39:22 -0700640 break;
Gerrit Renkerd90ebcb2008-11-12 00:47:26 -0800641 case DCCP_SOCKOPT_AVAILABLE_CCIDS:
642 return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
Gerrit Renker71c262a2008-11-23 16:04:59 -0800643 case DCCP_SOCKOPT_TX_CCID:
644 val = ccid_get_current_tx_ccid(dp);
645 if (val < 0)
646 return -ENOPROTOOPT;
647 break;
648 case DCCP_SOCKOPT_RX_CCID:
649 val = ccid_get_current_rx_ccid(dp);
650 if (val < 0)
651 return -ENOPROTOOPT;
652 break;
Gerrit Renkerb8599d22007-12-13 12:25:01 -0200653 case DCCP_SOCKOPT_SERVER_TIMEWAIT:
654 val = dp->dccps_server_timewait;
Gerrit Renkerb8599d22007-12-13 12:25:01 -0200655 break;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200656 case DCCP_SOCKOPT_SEND_CSCOV:
657 val = dp->dccps_pcslen;
658 break;
659 case DCCP_SOCKOPT_RECV_CSCOV:
660 val = dp->dccps_pcrlen;
661 break;
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100662 case DCCP_SOCKOPT_QPOLICY_ID:
663 val = dp->dccps_qpolicy;
664 break;
665 case DCCP_SOCKOPT_QPOLICY_TXQLEN:
666 val = dp->dccps_tx_qlen;
667 break;
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700668 case 128 ... 191:
669 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
670 len, (u32 __user *)optval, optlen);
671 case 192 ... 255:
672 return ccid_hc_tx_getsockopt(dp->dccps_hc_tx_ccid, sk, optname,
673 len, (u32 __user *)optval, optlen);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300674 default:
675 return -ENOPROTOOPT;
676 }
677
Gerrit Renker79133502007-12-13 12:27:14 -0200678 len = sizeof(val);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300679 if (put_user(len, optlen) || copy_to_user(optval, &val, len))
680 return -EFAULT;
681
682 return 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700683}
684
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800685int dccp_getsockopt(struct sock *sk, int level, int optname,
686 char __user *optval, int __user *optlen)
687{
688 if (level != SOL_DCCP)
689 return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
690 optname, optval,
691 optlen);
692 return do_dccp_getsockopt(sk, level, optname, optval, optlen);
693}
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800694
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800695EXPORT_SYMBOL_GPL(dccp_getsockopt);
696
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800697#ifdef CONFIG_COMPAT
698int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800699 char __user *optval, int __user *optlen)
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800700{
Arnaldo Carvalho de Melodec73ff2006-03-20 22:46:16 -0800701 if (level != SOL_DCCP)
702 return inet_csk_compat_getsockopt(sk, level, optname,
703 optval, optlen);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800704 return do_dccp_getsockopt(sk, level, optname, optval, optlen);
705}
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800706
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800707EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
708#endif
709
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100710static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb)
711{
Gu Zhengf95b4142014-12-11 11:22:04 +0800712 struct cmsghdr *cmsg;
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100713
714 /*
715 * Assign an (opaque) qpolicy priority value to skb->priority.
716 *
717 * We are overloading this skb field for use with the qpolicy subystem.
718 * The skb->priority is normally used for the SO_PRIORITY option, which
719 * is initialised from sk_priority. Since the assignment of sk_priority
720 * to skb->priority happens later (on layer 3), we overload this field
721 * for use with queueing priorities as long as the skb is on layer 4.
722 * The default priority value (if nothing is set) is 0.
723 */
724 skb->priority = 0;
725
Gu Zhengf95b4142014-12-11 11:22:04 +0800726 for_each_cmsghdr(cmsg, msg) {
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100727 if (!CMSG_OK(msg, cmsg))
728 return -EINVAL;
729
730 if (cmsg->cmsg_level != SOL_DCCP)
731 continue;
732
Tomasz Grobelny04910262010-12-04 13:39:13 +0100733 if (cmsg->cmsg_type <= DCCP_SCM_QPOLICY_MAX &&
734 !dccp_qpolicy_param_ok(skb->sk, cmsg->cmsg_type))
735 return -EINVAL;
736
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100737 switch (cmsg->cmsg_type) {
738 case DCCP_SCM_PRIORITY:
739 if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u32)))
740 return -EINVAL;
741 skb->priority = *(__u32 *)CMSG_DATA(cmsg);
742 break;
743 default:
744 return -EINVAL;
745 }
746 }
747 return 0;
748}
749
Ying Xue1b784142015-03-02 15:37:48 +0800750int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700751{
752 const struct dccp_sock *dp = dccp_sk(sk);
753 const int flags = msg->msg_flags;
754 const int noblock = flags & MSG_DONTWAIT;
755 struct sk_buff *skb;
756 int rc, size;
757 long timeo;
758
759 if (len > dp->dccps_mss_cache)
760 return -EMSGSIZE;
761
762 lock_sock(sk);
Ian McDonaldb1308dc2006-11-20 18:30:17 -0200763
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100764 if (dccp_qpolicy_full(sk)) {
Ian McDonaldb1308dc2006-11-20 18:30:17 -0200765 rc = -EAGAIN;
766 goto out_release;
767 }
768
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700769 timeo = sock_sndtimeo(sk, noblock);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700770
771 /*
772 * We have to use sk_stream_wait_connect here to set sk_write_pending,
773 * so that the trick in dccp_rcv_request_sent_state_process.
774 */
775 /* Wait for a connection to finish. */
Gerrit Renkercecd8d02007-09-26 19:36:08 -0300776 if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN))
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700777 if ((rc = sk_stream_wait_connect(sk, &timeo)) != 0)
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700778 goto out_release;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700779
780 size = sk->sk_prot->max_header + len;
781 release_sock(sk);
782 skb = sock_alloc_send_skb(sk, size, noblock, &rc);
783 lock_sock(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700784 if (skb == NULL)
785 goto out_release;
786
787 skb_reserve(skb, sk->sk_prot->max_header);
Al Viro6ce8e9c2014-04-06 21:25:44 -0400788 rc = memcpy_from_msg(skb_put(skb, len), msg, len);
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700789 if (rc != 0)
790 goto out_discard;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700791
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100792 rc = dccp_msghdr_parse(msg, skb);
793 if (rc != 0)
794 goto out_discard;
795
796 dccp_qpolicy_push(sk, skb);
Gerrit Renkerb1fcf552010-10-27 19:16:27 +0000797 /*
798 * The xmit_timer is set if the TX CCID is rate-based and will expire
799 * when congestion control permits to release further packets into the
800 * network. Window-based CCIDs do not use this timer.
801 */
802 if (!timer_pending(&dp->dccps_xmit_timer))
803 dccp_write_xmit(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700804out_release:
805 release_sock(sk);
806 return rc ? : len;
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700807out_discard:
808 kfree_skb(skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700809 goto out_release;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700810}
811
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800812EXPORT_SYMBOL_GPL(dccp_sendmsg);
813
Ying Xue1b784142015-03-02 15:37:48 +0800814int dccp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
815 int flags, int *addr_len)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700816{
817 const struct dccp_hdr *dh;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700818 long timeo;
819
820 lock_sock(sk);
821
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300822 if (sk->sk_state == DCCP_LISTEN) {
823 len = -ENOTCONN;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700824 goto out;
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300825 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700826
827 timeo = sock_rcvtimeo(sk, nonblock);
828
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700829 do {
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300830 struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700831
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300832 if (skb == NULL)
833 goto verify_sock_status;
834
835 dh = dccp_hdr(skb);
836
Gerrit Renker0c869622007-11-28 11:59:48 -0200837 switch (dh->dccph_type) {
838 case DCCP_PKT_DATA:
839 case DCCP_PKT_DATAACK:
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300840 goto found_ok_skb;
841
Gerrit Renker0c869622007-11-28 11:59:48 -0200842 case DCCP_PKT_CLOSE:
843 case DCCP_PKT_CLOSEREQ:
844 if (!(flags & MSG_PEEK))
845 dccp_finish_passive_close(sk);
846 /* fall through */
847 case DCCP_PKT_RESET:
848 dccp_pr_debug("found fin (%s) ok!\n",
849 dccp_packet_name(dh->dccph_type));
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300850 len = 0;
851 goto found_fin_ok;
Gerrit Renker0c869622007-11-28 11:59:48 -0200852 default:
853 dccp_pr_debug("packet_type=%s\n",
854 dccp_packet_name(dh->dccph_type));
Dan Williams7bced392013-12-30 12:37:29 -0800855 sk_eat_skb(sk, skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700856 }
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300857verify_sock_status:
858 if (sock_flag(sk, SOCK_DONE)) {
859 len = 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700860 break;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700861 }
862
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300863 if (sk->sk_err) {
864 len = sock_error(sk);
865 break;
866 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700867
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300868 if (sk->sk_shutdown & RCV_SHUTDOWN) {
869 len = 0;
870 break;
871 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700872
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300873 if (sk->sk_state == DCCP_CLOSED) {
874 if (!sock_flag(sk, SOCK_DONE)) {
875 /* This occurs when user tries to read
876 * from never connected socket.
877 */
878 len = -ENOTCONN;
879 break;
880 }
881 len = 0;
882 break;
883 }
884
885 if (!timeo) {
886 len = -EAGAIN;
887 break;
888 }
889
890 if (signal_pending(current)) {
891 len = sock_intr_errno(timeo);
892 break;
893 }
894
Sabrina Dubrocadfbafc92015-07-24 18:19:25 +0200895 sk_wait_data(sk, &timeo, NULL);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700896 continue;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700897 found_ok_skb:
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300898 if (len > skb->len)
899 len = skb->len;
900 else if (len < skb->len)
901 msg->msg_flags |= MSG_TRUNC;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700902
David S. Miller51f3d022014-11-05 16:46:40 -0500903 if (skb_copy_datagram_msg(skb, 0, msg, len)) {
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300904 /* Exception. Bailout! */
905 len = -EFAULT;
906 break;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700907 }
Gerrit Renker55d95592010-02-10 20:26:18 +0000908 if (flags & MSG_TRUNC)
909 len = skb->len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700910 found_fin_ok:
911 if (!(flags & MSG_PEEK))
Dan Williams7bced392013-12-30 12:37:29 -0800912 sk_eat_skb(sk, skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700913 break;
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300914 } while (1);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700915out:
916 release_sock(sk);
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300917 return len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700918}
919
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800920EXPORT_SYMBOL_GPL(dccp_recvmsg);
921
922int inet_dccp_listen(struct socket *sock, int backlog)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700923{
924 struct sock *sk = sock->sk;
925 unsigned char old_state;
926 int err;
927
928 lock_sock(sk);
929
930 err = -EINVAL;
931 if (sock->state != SS_UNCONNECTED || sock->type != SOCK_DCCP)
932 goto out;
933
934 old_state = sk->sk_state;
935 if (!((1 << old_state) & (DCCPF_CLOSED | DCCPF_LISTEN)))
936 goto out;
937
938 /* Really, if the socket is already in listen state
939 * we can only allow the backlog to be adjusted.
940 */
941 if (old_state != DCCP_LISTEN) {
942 /*
943 * FIXME: here it probably should be sk->sk_prot->listen_start
944 * see tcp_listen_start
945 */
Eric Dumazet72a3eff2006-11-16 02:30:37 -0800946 err = dccp_listen_start(sk, backlog);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700947 if (err)
948 goto out;
949 }
950 sk->sk_max_ack_backlog = backlog;
951 err = 0;
952
953out:
954 release_sock(sk);
955 return err;
956}
957
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800958EXPORT_SYMBOL_GPL(inet_dccp_listen);
959
Gerrit Renker0c869622007-11-28 11:59:48 -0200960static void dccp_terminate_connection(struct sock *sk)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700961{
Gerrit Renker0c869622007-11-28 11:59:48 -0200962 u8 next_state = DCCP_CLOSED;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700963
Gerrit Renker0c869622007-11-28 11:59:48 -0200964 switch (sk->sk_state) {
965 case DCCP_PASSIVE_CLOSE:
966 case DCCP_PASSIVE_CLOSEREQ:
967 dccp_finish_passive_close(sk);
968 break;
969 case DCCP_PARTOPEN:
970 dccp_pr_debug("Stop PARTOPEN timer (%p)\n", sk);
971 inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
972 /* fall through */
973 case DCCP_OPEN:
974 dccp_send_close(sk, 1);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700975
Gerrit Renkerb8599d22007-12-13 12:25:01 -0200976 if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER &&
977 !dccp_sk(sk)->dccps_server_timewait)
Gerrit Renker0c869622007-11-28 11:59:48 -0200978 next_state = DCCP_ACTIVE_CLOSEREQ;
979 else
980 next_state = DCCP_CLOSING;
981 /* fall through */
982 default:
983 dccp_set_state(sk, next_state);
984 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700985}
986
987void dccp_close(struct sock *sk, long timeout)
988{
Ian McDonald97e58482006-08-26 19:16:45 -0700989 struct dccp_sock *dp = dccp_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700990 struct sk_buff *skb;
Gerrit Renkerd83bd952007-12-16 16:06:03 -0800991 u32 data_was_unread = 0;
Herbert Xu134af342006-05-05 17:09:13 -0700992 int state;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700993
994 lock_sock(sk);
995
996 sk->sk_shutdown = SHUTDOWN_MASK;
997
998 if (sk->sk_state == DCCP_LISTEN) {
999 dccp_set_state(sk, DCCP_CLOSED);
1000
1001 /* Special case. */
1002 inet_csk_listen_stop(sk);
1003
1004 goto adjudge_to_death;
1005 }
1006
Ian McDonald97e58482006-08-26 19:16:45 -07001007 sk_stop_timer(sk, &dp->dccps_xmit_timer);
1008
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001009 /*
1010 * We need to flush the recv. buffs. We do this only on the
1011 * descriptor close, not protocol-sourced closes, because the
1012 *reader process may not have drained the data yet!
1013 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001014 while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
Gerrit Renkerd83bd952007-12-16 16:06:03 -08001015 data_was_unread += skb->len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001016 __kfree_skb(skb);
1017 }
1018
Eric Dumazet346da622016-11-02 18:04:24 -07001019 /* If socket has been already reset kill it. */
1020 if (sk->sk_state == DCCP_CLOSED)
1021 goto adjudge_to_death;
1022
Gerrit Renkerd83bd952007-12-16 16:06:03 -08001023 if (data_was_unread) {
1024 /* Unread data was tossed, send an appropriate Reset Code */
Gerrit Renker2f34b322010-10-11 20:44:42 +02001025 DCCP_WARN("ABORT with %u bytes unread\n", data_was_unread);
Gerrit Renkerd83bd952007-12-16 16:06:03 -08001026 dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);
1027 dccp_set_state(sk, DCCP_CLOSED);
1028 } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001029 /* Check zero linger _after_ checking for unread data. */
1030 sk->sk_prot->disconnect(sk, 0);
Gerrit Renker0c869622007-11-28 11:59:48 -02001031 } else if (sk->sk_state != DCCP_CLOSED) {
Gerrit Renkerb1fcf552010-10-27 19:16:27 +00001032 /*
1033 * Normal connection termination. May need to wait if there are
1034 * still packets in the TX queue that are delayed by the CCID.
1035 */
1036 dccp_flush_write_queue(sk, &timeout);
Gerrit Renker0c869622007-11-28 11:59:48 -02001037 dccp_terminate_connection(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001038 }
1039
Gerrit Renkerb1fcf552010-10-27 19:16:27 +00001040 /*
1041 * Flush write queue. This may be necessary in several cases:
1042 * - we have been closed by the peer but still have application data;
1043 * - abortive termination (unread data or zero linger time),
1044 * - normal termination but queue could not be flushed within time limit
1045 */
1046 __skb_queue_purge(&sk->sk_write_queue);
1047
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001048 sk_stream_wait_close(sk, timeout);
1049
1050adjudge_to_death:
Herbert Xu134af342006-05-05 17:09:13 -07001051 state = sk->sk_state;
1052 sock_hold(sk);
1053 sock_orphan(sk);
Herbert Xu134af342006-05-05 17:09:13 -07001054
Arnaldo Carvalho de Melo7ad07e72005-08-23 21:50:06 -07001055 /*
1056 * It is the last release_sock in its life. It will remove backlog.
1057 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001058 release_sock(sk);
1059 /*
1060 * Now socket is owned by kernel and we acquire BH lock
1061 * to finish close. No need to check for user refs.
1062 */
1063 local_bh_disable();
1064 bh_lock_sock(sk);
Ilpo Järvinen547b7922008-07-25 21:43:18 -07001065 WARN_ON(sock_owned_by_user(sk));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001066
Herbert Xueb4dea52008-12-29 23:04:08 -08001067 percpu_counter_inc(sk->sk_prot->orphan_count);
1068
Herbert Xu134af342006-05-05 17:09:13 -07001069 /* Have we already been destroyed by a softirq or backlog? */
1070 if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED)
1071 goto out;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001072
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001073 if (sk->sk_state == DCCP_CLOSED)
1074 inet_csk_destroy_sock(sk);
1075
1076 /* Otherwise, socket is reprieved until protocol close. */
1077
Herbert Xu134af342006-05-05 17:09:13 -07001078out:
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001079 bh_unlock_sock(sk);
1080 local_bh_enable();
1081 sock_put(sk);
1082}
1083
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -08001084EXPORT_SYMBOL_GPL(dccp_close);
1085
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001086void dccp_shutdown(struct sock *sk, int how)
1087{
Gerrit Renker8e8c71f2007-11-21 09:56:48 -02001088 dccp_pr_debug("called shutdown(%x)\n", how);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001089}
1090
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -08001091EXPORT_SYMBOL_GPL(dccp_shutdown);
1092
Fabian Frederick0c5b8a42014-10-01 06:48:03 +02001093static inline int __init dccp_mib_init(void)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001094{
WANG Cong698365f2014-05-05 15:55:55 -07001095 dccp_statistics = alloc_percpu(struct dccp_mib);
1096 if (!dccp_statistics)
1097 return -ENOMEM;
1098 return 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001099}
1100
YOSHIFUJI Hideaki24e8b7e2008-04-10 03:48:43 -07001101static inline void dccp_mib_exit(void)
Arnaldo Carvalho de Melo46f09ff2006-03-20 21:24:42 -08001102{
WANG Cong698365f2014-05-05 15:55:55 -07001103 free_percpu(dccp_statistics);
Arnaldo Carvalho de Melo46f09ff2006-03-20 21:24:42 -08001104}
1105
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001106static int thash_entries;
1107module_param(thash_entries, int, 0444);
1108MODULE_PARM_DESC(thash_entries, "Number of ehash buckets");
1109
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -03001110#ifdef CONFIG_IP_DCCP_DEBUG
Rusty Russelleb939922011-12-19 14:08:01 +00001111bool dccp_debug;
Gerrit Renker43264992008-08-23 13:28:27 +02001112module_param(dccp_debug, bool, 0644);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001113MODULE_PARM_DESC(dccp_debug, "Enable debug messages");
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -08001114
1115EXPORT_SYMBOL_GPL(dccp_debug);
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -03001116#endif
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001117
1118static int __init dccp_init(void)
1119{
1120 unsigned long goal;
1121 int ehash_order, bhash_order, i;
Eric Dumazetdd24c002008-11-25 21:17:14 -08001122 int rc;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001123
Patrick McHardy028b0272008-04-12 18:35:41 -07001124 BUILD_BUG_ON(sizeof(struct dccp_skb_cb) >
1125 FIELD_SIZEOF(struct sk_buff, cb));
Tejun Heo908c7f12014-09-08 09:51:29 +09001126 rc = percpu_counter_init(&dccp_orphan_count, 0, GFP_KERNEL);
Eric Dumazetdd24c002008-11-25 21:17:14 -08001127 if (rc)
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001128 goto out_fail;
Eric Dumazetdd24c002008-11-25 21:17:14 -08001129 rc = -ENOBUFS;
Eric Dumazet5caea4e2008-11-20 00:40:07 -08001130 inet_hashinfo_init(&dccp_hashinfo);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -03001131 dccp_hashinfo.bind_bucket_cachep =
1132 kmem_cache_create("dccp_bind_bucket",
1133 sizeof(struct inet_bind_bucket), 0,
Paul Mundt20c2df82007-07-20 10:11:58 +09001134 SLAB_HWCACHE_ALIGN, NULL);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001135 if (!dccp_hashinfo.bind_bucket_cachep)
Eric Dumazetdd24c002008-11-25 21:17:14 -08001136 goto out_free_percpu;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001137
1138 /*
1139 * Size and allocate the main established and bind bucket
1140 * hash tables.
1141 *
1142 * The methodology is similar to that of the buffer cache.
1143 */
Jan Beulich44813742009-09-21 17:03:05 -07001144 if (totalram_pages >= (128 * 1024))
1145 goal = totalram_pages >> (21 - PAGE_SHIFT);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001146 else
Jan Beulich44813742009-09-21 17:03:05 -07001147 goal = totalram_pages >> (23 - PAGE_SHIFT);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001148
1149 if (thash_entries)
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -03001150 goal = (thash_entries *
1151 sizeof(struct inet_ehash_bucket)) >> PAGE_SHIFT;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001152 for (ehash_order = 0; (1UL << ehash_order) < goal; ehash_order++)
1153 ;
1154 do {
Eric Dumazetf373b532009-10-09 00:16:19 +00001155 unsigned long hash_size = (1UL << ehash_order) * PAGE_SIZE /
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001156 sizeof(struct inet_ehash_bucket);
Eric Dumazetf373b532009-10-09 00:16:19 +00001157
1158 while (hash_size & (hash_size - 1))
1159 hash_size--;
1160 dccp_hashinfo.ehash_mask = hash_size - 1;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001161 dccp_hashinfo.ehash = (struct inet_ehash_bucket *)
Mel Gorman1c29b3f2009-07-29 15:04:10 -07001162 __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, ehash_order);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001163 } while (!dccp_hashinfo.ehash && --ehash_order > 0);
1164
1165 if (!dccp_hashinfo.ehash) {
Gerrit Renker59348b12006-11-20 18:39:23 -02001166 DCCP_CRIT("Failed to allocate DCCP established hash table");
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001167 goto out_free_bind_bucket_cachep;
1168 }
1169
Eric Dumazet05dbc7b2013-10-03 00:22:02 -07001170 for (i = 0; i <= dccp_hashinfo.ehash_mask; i++)
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08001171 INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].chain, i);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001172
Eric Dumazet230140c2007-11-07 02:40:20 -08001173 if (inet_ehash_locks_alloc(&dccp_hashinfo))
1174 goto out_free_dccp_ehash;
1175
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001176 bhash_order = ehash_order;
1177
1178 do {
1179 dccp_hashinfo.bhash_size = (1UL << bhash_order) * PAGE_SIZE /
1180 sizeof(struct inet_bind_hashbucket);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -03001181 if ((dccp_hashinfo.bhash_size > (64 * 1024)) &&
1182 bhash_order > 0)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001183 continue;
1184 dccp_hashinfo.bhash = (struct inet_bind_hashbucket *)
Mel Gorman1c29b3f2009-07-29 15:04:10 -07001185 __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, bhash_order);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001186 } while (!dccp_hashinfo.bhash && --bhash_order >= 0);
1187
1188 if (!dccp_hashinfo.bhash) {
Gerrit Renker59348b12006-11-20 18:39:23 -02001189 DCCP_CRIT("Failed to allocate DCCP bind hash table");
Eric Dumazet230140c2007-11-07 02:40:20 -08001190 goto out_free_dccp_locks;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001191 }
1192
1193 for (i = 0; i < dccp_hashinfo.bhash_size; i++) {
1194 spin_lock_init(&dccp_hashinfo.bhash[i].lock);
1195 INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain);
1196 }
1197
Arnaldo Carvalho de Melo46f09ff2006-03-20 21:24:42 -08001198 rc = dccp_mib_init();
Arnaldo Carvalho de Melofa23e2e2006-03-20 17:16:01 -08001199 if (rc)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001200 goto out_free_dccp_bhash;
1201
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001202 rc = dccp_ackvec_init();
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001203 if (rc)
Arnaldo Carvalho de Melob61fafc2006-03-20 21:25:11 -08001204 goto out_free_dccp_mib;
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001205
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001206 rc = dccp_sysctl_init();
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001207 if (rc)
1208 goto out_ackvec_exit;
Gerrit Renker4c70f382007-09-25 22:40:13 -07001209
Gerrit Renkerddebc972009-01-04 21:42:53 -08001210 rc = ccid_initialize_builtins();
1211 if (rc)
1212 goto out_sysctl_exit;
1213
Gerrit Renker4c70f382007-09-25 22:40:13 -07001214 dccp_timestamping_init();
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001215
1216 return 0;
1217
Gerrit Renkerddebc972009-01-04 21:42:53 -08001218out_sysctl_exit:
1219 dccp_sysctl_exit();
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001220out_ackvec_exit:
1221 dccp_ackvec_exit();
Arnaldo Carvalho de Melob61fafc2006-03-20 21:25:11 -08001222out_free_dccp_mib:
Arnaldo Carvalho de Melo46f09ff2006-03-20 21:24:42 -08001223 dccp_mib_exit();
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001224out_free_dccp_bhash:
1225 free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
Eric Dumazet230140c2007-11-07 02:40:20 -08001226out_free_dccp_locks:
1227 inet_ehash_locks_free(&dccp_hashinfo);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001228out_free_dccp_ehash:
1229 free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001230out_free_bind_bucket_cachep:
1231 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
Eric Dumazetdd24c002008-11-25 21:17:14 -08001232out_free_percpu:
1233 percpu_counter_destroy(&dccp_orphan_count);
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001234out_fail:
1235 dccp_hashinfo.bhash = NULL;
1236 dccp_hashinfo.ehash = NULL;
1237 dccp_hashinfo.bind_bucket_cachep = NULL;
1238 return rc;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001239}
1240
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001241static void __exit dccp_fini(void)
1242{
Gerrit Renkerddebc972009-01-04 21:42:53 -08001243 ccid_cleanup_builtins();
Arnaldo Carvalho de Melo46f09ff2006-03-20 21:24:42 -08001244 dccp_mib_exit();
Arnaldo Carvalho de Melo725ba8e2005-08-13 20:35:39 -03001245 free_pages((unsigned long)dccp_hashinfo.bhash,
1246 get_order(dccp_hashinfo.bhash_size *
1247 sizeof(struct inet_bind_hashbucket)));
1248 free_pages((unsigned long)dccp_hashinfo.ehash,
Eric Dumazetf373b532009-10-09 00:16:19 +00001249 get_order((dccp_hashinfo.ehash_mask + 1) *
Arnaldo Carvalho de Melo725ba8e2005-08-13 20:35:39 -03001250 sizeof(struct inet_ehash_bucket)));
Eric Dumazet230140c2007-11-07 02:40:20 -08001251 inet_ehash_locks_free(&dccp_hashinfo);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001252 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001253 dccp_ackvec_exit();
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001254 dccp_sysctl_exit();
Wei Yongjun476181c2009-08-04 21:44:39 +00001255 percpu_counter_destroy(&dccp_orphan_count);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001256}
1257
1258module_init(dccp_init);
1259module_exit(dccp_fini);
1260
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001261MODULE_LICENSE("GPL");
1262MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>");
1263MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");