blob: 86bc40ba6ba5b4a006c6c2f74939b8d259da850a [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>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070027#include <net/sock.h>
28#include <net/xfrm.h>
29
Arnaldo Carvalho de Melo62731722007-10-23 20:23:30 -070030#include <asm/ioctls.h>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070031#include <linux/spinlock.h>
32#include <linux/timer.h>
33#include <linux/delay.h>
34#include <linux/poll.h>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070035
36#include "ccid.h"
37#include "dccp.h"
Andrea Bittauafe00252006-03-20 17:43:56 -080038#include "feat.h"
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070039
Eric Dumazetba899662005-08-26 12:05:31 -070040DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070041
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -080042EXPORT_SYMBOL_GPL(dccp_statistics);
43
Eric Dumazetdd24c002008-11-25 21:17:14 -080044struct percpu_counter dccp_orphan_count;
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -080045EXPORT_SYMBOL_GPL(dccp_orphan_count);
46
Eric Dumazet5caea4e2008-11-20 00:40:07 -080047struct inet_hashinfo dccp_hashinfo;
Arnaldo Carvalho de Melo075ae862006-03-20 21:24:19 -080048EXPORT_SYMBOL_GPL(dccp_hashinfo);
49
Ian McDonaldb1308dc2006-11-20 18:30:17 -020050/* the maximum queue length for tx in packets. 0 is no limit */
51int sysctl_dccp_tx_qlen __read_mostly = 5;
52
stephen hemminger1f4f0f62010-10-05 04:24:09 +000053#ifdef CONFIG_IP_DCCP_DEBUG
54static const char *dccp_state_name(const int state)
55{
56 static const char *const dccp_state_names[] = {
57 [DCCP_OPEN] = "OPEN",
58 [DCCP_REQUESTING] = "REQUESTING",
59 [DCCP_PARTOPEN] = "PARTOPEN",
60 [DCCP_LISTEN] = "LISTEN",
61 [DCCP_RESPOND] = "RESPOND",
62 [DCCP_CLOSING] = "CLOSING",
63 [DCCP_ACTIVE_CLOSEREQ] = "CLOSEREQ",
64 [DCCP_PASSIVE_CLOSE] = "PASSIVE_CLOSE",
65 [DCCP_PASSIVE_CLOSEREQ] = "PASSIVE_CLOSEREQ",
66 [DCCP_TIME_WAIT] = "TIME_WAIT",
67 [DCCP_CLOSED] = "CLOSED",
68 };
69
70 if (state >= DCCP_MAX_STATES)
71 return "INVALID STATE!";
72 else
73 return dccp_state_names[state];
74}
75#endif
76
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -080077void dccp_set_state(struct sock *sk, const int state)
78{
79 const int oldstate = sk->sk_state;
80
Gerrit Renkerf11135a2007-11-28 11:34:53 -020081 dccp_pr_debug("%s(%p) %s --> %s\n", dccp_role(sk), sk,
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -080082 dccp_state_name(oldstate), dccp_state_name(state));
83 WARN_ON(state == oldstate);
84
85 switch (state) {
86 case DCCP_OPEN:
87 if (oldstate != DCCP_OPEN)
88 DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
Gerrit Renker6eb55d12008-12-08 01:15:26 -080089 /* Client retransmits all Confirm options until entering OPEN */
90 if (oldstate == DCCP_PARTOPEN)
91 dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg);
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -080092 break;
93
94 case DCCP_CLOSED:
Gerrit Renker0c869622007-11-28 11:59:48 -020095 if (oldstate == DCCP_OPEN || oldstate == DCCP_ACTIVE_CLOSEREQ ||
96 oldstate == DCCP_CLOSING)
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -080097 DCCP_INC_STATS(DCCP_MIB_ESTABRESETS);
98
99 sk->sk_prot->unhash(sk);
100 if (inet_csk(sk)->icsk_bind_hash != NULL &&
101 !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -0800102 inet_put_port(sk);
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -0800103 /* fall through */
104 default:
105 if (oldstate == DCCP_OPEN)
106 DCCP_DEC_STATS(DCCP_MIB_CURRESTAB);
107 }
108
109 /* Change state AFTER socket is unhashed to avoid closed
110 * socket sitting in hash tables.
111 */
112 sk->sk_state = state;
113}
114
115EXPORT_SYMBOL_GPL(dccp_set_state);
116
Gerrit Renker0c869622007-11-28 11:59:48 -0200117static void dccp_finish_passive_close(struct sock *sk)
118{
119 switch (sk->sk_state) {
120 case DCCP_PASSIVE_CLOSE:
121 /* Node (client or server) has received Close packet. */
122 dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
123 dccp_set_state(sk, DCCP_CLOSED);
124 break;
125 case DCCP_PASSIVE_CLOSEREQ:
126 /*
127 * Client received CloseReq. We set the `active' flag so that
128 * dccp_send_close() retransmits the Close as per RFC 4340, 8.3.
129 */
130 dccp_send_close(sk, 1);
131 dccp_set_state(sk, DCCP_CLOSING);
132 }
133}
134
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -0800135void dccp_done(struct sock *sk)
136{
137 dccp_set_state(sk, DCCP_CLOSED);
138 dccp_clear_xmit_timers(sk);
139
140 sk->sk_shutdown = SHUTDOWN_MASK;
141
142 if (!sock_flag(sk, SOCK_DEAD))
143 sk->sk_state_change(sk);
144 else
145 inet_csk_destroy_sock(sk);
146}
147
148EXPORT_SYMBOL_GPL(dccp_done);
149
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700150const char *dccp_packet_name(const int type)
151{
Jan Engelhardt36cbd3d2009-08-05 10:42:58 -0700152 static const char *const dccp_packet_names[] = {
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700153 [DCCP_PKT_REQUEST] = "REQUEST",
154 [DCCP_PKT_RESPONSE] = "RESPONSE",
155 [DCCP_PKT_DATA] = "DATA",
156 [DCCP_PKT_ACK] = "ACK",
157 [DCCP_PKT_DATAACK] = "DATAACK",
158 [DCCP_PKT_CLOSEREQ] = "CLOSEREQ",
159 [DCCP_PKT_CLOSE] = "CLOSE",
160 [DCCP_PKT_RESET] = "RESET",
161 [DCCP_PKT_SYNC] = "SYNC",
162 [DCCP_PKT_SYNCACK] = "SYNCACK",
163 };
164
165 if (type >= DCCP_NR_PKT_TYPES)
166 return "INVALID";
167 else
168 return dccp_packet_names[type];
169}
170
171EXPORT_SYMBOL_GPL(dccp_packet_name);
172
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800173int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800174{
175 struct dccp_sock *dp = dccp_sk(sk);
176 struct inet_connection_sock *icsk = inet_csk(sk);
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800177
Arnaldo Carvalho de Meloe18d7a92007-11-24 21:42:53 -0200178 icsk->icsk_rto = DCCP_TIMEOUT_INIT;
179 icsk->icsk_syn_retries = sysctl_dccp_request_retries;
180 sk->sk_state = DCCP_CLOSED;
181 sk->sk_write_space = dccp_write_space;
182 icsk->icsk_sync_mss = dccp_sync_mss;
Gerrit Renker410e27a2008-09-09 13:27:22 +0200183 dp->dccps_mss_cache = 536;
Arnaldo Carvalho de Meloe18d7a92007-11-24 21:42:53 -0200184 dp->dccps_rate_last = jiffies;
185 dp->dccps_role = DCCP_ROLE_UNDEFINED;
186 dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100187 dp->dccps_tx_qlen = sysctl_dccp_tx_qlen;
Arnaldo Carvalho de Meloe18d7a92007-11-24 21:42:53 -0200188
189 dccp_init_xmit_timers(sk);
190
Gerrit Renkerac757732008-11-04 23:55:49 -0800191 INIT_LIST_HEAD(&dp->dccps_featneg);
Gerrit Renker6eb55d12008-12-08 01:15:26 -0800192 /* control socket doesn't need feat nego */
193 if (likely(ctl_sock_initialized))
194 return dccp_feat_init(sk);
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800195 return 0;
196}
197
198EXPORT_SYMBOL_GPL(dccp_init_sock);
199
Brian Haley7d06b2e2008-06-14 17:04:49 -0700200void dccp_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800201{
202 struct dccp_sock *dp = dccp_sk(sk);
203
Eric Dumazet7749d4f2017-08-14 14:10:25 -0700204 __skb_queue_purge(&sk->sk_write_queue);
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800205 if (sk->sk_send_head != NULL) {
206 kfree_skb(sk->sk_send_head);
207 sk->sk_send_head = NULL;
208 }
209
210 /* Clean up a referenced DCCP bind bucket. */
211 if (inet_csk(sk)->icsk_bind_hash != NULL)
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -0800212 inet_put_port(sk);
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800213
214 kfree(dp->dccps_service_list);
215 dp->dccps_service_list = NULL;
216
Gerrit Renker6fdd34d2008-12-08 01:19:06 -0800217 if (dp->dccps_hc_rx_ackvec != NULL) {
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800218 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
219 dp->dccps_hc_rx_ackvec = NULL;
220 }
221 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
222 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
223 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
224
225 /* clean up feature negotiation state */
Gerrit Renkerd99a7bd2008-11-04 23:56:30 -0800226 dccp_feat_list_purge(&dp->dccps_featneg);
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800227}
228
229EXPORT_SYMBOL_GPL(dccp_destroy_sock);
230
Eric Dumazet72a3eff2006-11-16 02:30:37 -0800231static inline int dccp_listen_start(struct sock *sk, int backlog)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700232{
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700233 struct dccp_sock *dp = dccp_sk(sk);
234
235 dp->dccps_role = DCCP_ROLE_LISTEN;
Gerrit Renker9eca0a42008-11-12 00:48:44 -0800236 /* do not start to listen if feature negotiation setup fails */
237 if (dccp_feat_finalise_settings(dp))
238 return -EPROTO;
Eric Dumazet72a3eff2006-11-16 02:30:37 -0800239 return inet_csk_listen_start(sk, backlog);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700240}
241
Gerrit Renkerce865a62007-11-24 22:14:15 -0200242static inline int dccp_need_reset(int state)
243{
244 return state != DCCP_CLOSED && state != DCCP_LISTEN &&
245 state != DCCP_REQUESTING;
246}
247
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700248int dccp_disconnect(struct sock *sk, int flags)
249{
250 struct inet_connection_sock *icsk = inet_csk(sk);
251 struct inet_sock *inet = inet_sk(sk);
252 int err = 0;
253 const int old_state = sk->sk_state;
254
255 if (old_state != DCCP_CLOSED)
256 dccp_set_state(sk, DCCP_CLOSED);
257
Gerrit Renkerce865a62007-11-24 22:14:15 -0200258 /*
259 * This corresponds to the ABORT function of RFC793, sec. 3.8
260 * TCP uses a RST segment, DCCP a Reset packet with Code 2, "Aborted".
261 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700262 if (old_state == DCCP_LISTEN) {
263 inet_csk_listen_stop(sk);
Gerrit Renkerce865a62007-11-24 22:14:15 -0200264 } else if (dccp_need_reset(old_state)) {
265 dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);
266 sk->sk_err = ECONNRESET;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700267 } else if (old_state == DCCP_REQUESTING)
268 sk->sk_err = ECONNRESET;
269
270 dccp_clear_xmit_timers(sk);
Gerrit Renker48816322008-08-23 13:28:27 +0200271
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700272 __skb_queue_purge(&sk->sk_receive_queue);
Gerrit Renker48816322008-08-23 13:28:27 +0200273 __skb_queue_purge(&sk->sk_write_queue);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700274 if (sk->sk_send_head != NULL) {
275 __kfree_skb(sk->sk_send_head);
276 sk->sk_send_head = NULL;
277 }
278
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000279 inet->inet_dport = 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700280
281 if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
282 inet_reset_saddr(sk);
283
284 sk->sk_shutdown = 0;
285 sock_reset_flag(sk, SOCK_DONE);
286
287 icsk->icsk_backoff = 0;
288 inet_csk_delack_init(sk);
289 __sk_dst_reset(sk);
290
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000291 WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700292
293 sk->sk_error_report(sk);
294 return err;
295}
296
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800297EXPORT_SYMBOL_GPL(dccp_disconnect);
298
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700299/*
300 * Wait for a DCCP event.
301 *
302 * Note that we don't need to lock the socket, as the upper poll layers
303 * take care of normal races (between the test and the event) and we don't
304 * go look at any of the socket buffers directly.
305 */
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800306unsigned int dccp_poll(struct file *file, struct socket *sock,
307 poll_table *wait)
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700308{
309 unsigned int mask;
310 struct sock *sk = sock->sk;
311
Eric Dumazetaa395142010-04-20 13:03:51 +0000312 sock_poll_wait(file, sk_sleep(sk), wait);
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700313 if (sk->sk_state == DCCP_LISTEN)
314 return inet_csk_listen_poll(sk);
315
316 /* Socket is not locked. We are protected from async events
317 by poll logic and correct handling of state changes
318 made by another threads is impossible in any case.
319 */
320
321 mask = 0;
322 if (sk->sk_err)
323 mask = POLLERR;
324
325 if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
326 mask |= POLLHUP;
327 if (sk->sk_shutdown & RCV_SHUTDOWN)
Davide Libenzif348d702006-03-25 03:07:39 -0800328 mask |= POLLIN | POLLRDNORM | POLLRDHUP;
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700329
330 /* Connected? */
331 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
332 if (atomic_read(&sk->sk_rmem_alloc) > 0)
333 mask |= POLLIN | POLLRDNORM;
334
335 if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
Eric Dumazet64dc6132013-07-22 20:26:31 -0700336 if (sk_stream_is_writeable(sk)) {
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700337 mask |= POLLOUT | POLLWRNORM;
338 } else { /* send SIGIO later */
Eric Dumazet9cd3e072015-11-29 20:03:10 -0800339 sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
Arnaldo Carvalho de Melo331968b2005-08-23 21:54:23 -0700340 set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
341
342 /* Race breaker. If space is freed after
343 * wspace test but before the flags are set,
344 * IO signal will be lost.
345 */
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 }
349 }
350 }
351 return mask;
352}
353
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800354EXPORT_SYMBOL_GPL(dccp_poll);
355
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700356int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
357{
Arnaldo Carvalho de Melo62731722007-10-23 20:23:30 -0700358 int rc = -ENOTCONN;
359
360 lock_sock(sk);
361
362 if (sk->sk_state == DCCP_LISTEN)
363 goto out;
364
365 switch (cmd) {
366 case SIOCINQ: {
367 struct sk_buff *skb;
368 unsigned long amount = 0;
369
370 skb = skb_peek(&sk->sk_receive_queue);
371 if (skb != NULL) {
372 /*
373 * We will only return the amount of this packet since
374 * that is all that will be read.
375 */
376 amount = skb->len;
377 }
378 rc = put_user(amount, (int __user *)arg);
379 }
380 break;
381 default:
382 rc = -ENOIOCTLCMD;
383 break;
384 }
385out:
386 release_sock(sk);
387 return rc;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700388}
389
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800390EXPORT_SYMBOL_GPL(dccp_ioctl);
391
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800392static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
David S. Millerb7058842009-09-30 16:12:20 -0700393 char __user *optval, unsigned int optlen)
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700394{
395 struct dccp_sock *dp = dccp_sk(sk);
396 struct dccp_service_list *sl = NULL;
397
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200398 if (service == DCCP_SERVICE_INVALID_VALUE ||
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700399 optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32))
400 return -EINVAL;
401
402 if (optlen > sizeof(service)) {
403 sl = kmalloc(optlen, GFP_KERNEL);
404 if (sl == NULL)
405 return -ENOMEM;
406
407 sl->dccpsl_nr = optlen / sizeof(u32) - 1;
408 if (copy_from_user(sl->dccpsl_list,
409 optval + sizeof(service),
410 optlen - sizeof(service)) ||
411 dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) {
412 kfree(sl);
413 return -EFAULT;
414 }
415 }
416
417 lock_sock(sk);
418 dp->dccps_service = service;
419
Jesper Juhla51482b2005-11-08 09:41:34 -0800420 kfree(dp->dccps_service_list);
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700421
422 dp->dccps_service_list = sl;
423 release_sock(sk);
424 return 0;
425}
426
Gerrit Renker29450552008-11-16 22:53:48 -0800427static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
428{
429 u8 *list, len;
430 int i, rc;
431
432 if (cscov < 0 || cscov > 15)
433 return -EINVAL;
434 /*
435 * Populate a list of permissible values, in the range cscov...15. This
436 * is necessary since feature negotiation of single values only works if
437 * both sides incidentally choose the same value. Since the list starts
438 * lowest-value first, negotiation will pick the smallest shared value.
439 */
440 if (cscov == 0)
441 return 0;
442 len = 16 - cscov;
443
444 list = kmalloc(len, GFP_KERNEL);
445 if (list == NULL)
446 return -ENOBUFS;
447
448 for (i = 0; i < len; i++)
449 list[i] = cscov++;
450
451 rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
452
453 if (rc == 0) {
454 if (rx)
455 dccp_sk(sk)->dccps_pcrlen = cscov;
456 else
457 dccp_sk(sk)->dccps_pcslen = cscov;
458 }
459 kfree(list);
460 return rc;
461}
462
Gerrit Renkerb20a9c22008-11-23 16:02:31 -0800463static int dccp_setsockopt_ccid(struct sock *sk, int type,
David S. Millerb7058842009-09-30 16:12:20 -0700464 char __user *optval, unsigned int optlen)
Gerrit Renkerb20a9c22008-11-23 16:02:31 -0800465{
466 u8 *val;
467 int rc = 0;
468
469 if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
470 return -EINVAL;
471
Julia Lawall042604d2010-05-21 22:25:19 +0000472 val = memdup_user(optval, optlen);
473 if (IS_ERR(val))
474 return PTR_ERR(val);
Gerrit Renkerb20a9c22008-11-23 16:02:31 -0800475
476 lock_sock(sk);
477 if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
478 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
479
480 if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
481 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
482 release_sock(sk);
483
484 kfree(val);
485 return rc;
486}
487
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800488static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
David S. Millerb7058842009-09-30 16:12:20 -0700489 char __user *optval, unsigned int optlen)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700490{
Gerrit Renker09dbc382006-11-14 12:57:34 -0200491 struct dccp_sock *dp = dccp_sk(sk);
492 int val, err = 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700493
Gerrit Renker19102992008-11-16 22:56:55 -0800494 switch (optname) {
495 case DCCP_SOCKOPT_PACKET_SIZE:
496 DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
497 return 0;
498 case DCCP_SOCKOPT_CHANGE_L:
499 case DCCP_SOCKOPT_CHANGE_R:
500 DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
501 return 0;
Gerrit Renkerb20a9c22008-11-23 16:02:31 -0800502 case DCCP_SOCKOPT_CCID:
503 case DCCP_SOCKOPT_RX_CCID:
504 case DCCP_SOCKOPT_TX_CCID:
505 return dccp_setsockopt_ccid(sk, optname, optval, optlen);
Gerrit Renker19102992008-11-16 22:56:55 -0800506 }
507
508 if (optlen < (int)sizeof(int))
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300509 return -EINVAL;
510
511 if (get_user(val, (int __user *)optval))
512 return -EFAULT;
513
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700514 if (optname == DCCP_SOCKOPT_SERVICE)
515 return dccp_setsockopt_service(sk, val, optval, optlen);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300516
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700517 lock_sock(sk);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300518 switch (optname) {
Gerrit Renkerb8599d22007-12-13 12:25:01 -0200519 case DCCP_SOCKOPT_SERVER_TIMEWAIT:
520 if (dp->dccps_role != DCCP_ROLE_SERVER)
521 err = -EOPNOTSUPP;
522 else
523 dp->dccps_server_timewait = (val != 0);
524 break;
Gerrit Renker29450552008-11-16 22:53:48 -0800525 case DCCP_SOCKOPT_SEND_CSCOV:
526 err = dccp_setsockopt_cscov(sk, val, false);
Tomasz Grobelnyd6da3512008-09-04 07:30:19 +0200527 break;
Gerrit Renker29450552008-11-16 22:53:48 -0800528 case DCCP_SOCKOPT_RECV_CSCOV:
529 err = dccp_setsockopt_cscov(sk, val, true);
Tomasz Grobelnyd6da3512008-09-04 07:30:19 +0200530 break;
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100531 case DCCP_SOCKOPT_QPOLICY_ID:
532 if (sk->sk_state != DCCP_CLOSED)
533 err = -EISCONN;
534 else if (val < 0 || val >= DCCPQ_POLICY_MAX)
535 err = -EINVAL;
536 else
537 dp->dccps_qpolicy = val;
538 break;
539 case DCCP_SOCKOPT_QPOLICY_TXQLEN:
540 if (val < 0)
541 err = -EINVAL;
542 else
543 dp->dccps_tx_qlen = val;
544 break;
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300545 default:
546 err = -ENOPROTOOPT;
547 break;
548 }
Gerrit Renker410e27a2008-09-09 13:27:22 +0200549 release_sock(sk);
Gerrit Renker19102992008-11-16 22:56:55 -0800550
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300551 return err;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700552}
553
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800554int dccp_setsockopt(struct sock *sk, int level, int optname,
David S. Millerb7058842009-09-30 16:12:20 -0700555 char __user *optval, unsigned int optlen)
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800556{
557 if (level != SOL_DCCP)
558 return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
559 optname, optval,
560 optlen);
561 return do_dccp_setsockopt(sk, level, optname, optval, optlen);
562}
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800563
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800564EXPORT_SYMBOL_GPL(dccp_setsockopt);
565
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800566#ifdef CONFIG_COMPAT
567int compat_dccp_setsockopt(struct sock *sk, int level, int optname,
David S. Millerb7058842009-09-30 16:12:20 -0700568 char __user *optval, unsigned int optlen)
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800569{
Arnaldo Carvalho de Melodec73ff2006-03-20 22:46:16 -0800570 if (level != SOL_DCCP)
571 return inet_csk_compat_setsockopt(sk, level, optname,
572 optval, optlen);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800573 return do_dccp_setsockopt(sk, level, optname, optval, optlen);
574}
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800575
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800576EXPORT_SYMBOL_GPL(compat_dccp_setsockopt);
577#endif
578
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700579static int dccp_getsockopt_service(struct sock *sk, int len,
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800580 __be32 __user *optval,
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700581 int __user *optlen)
582{
583 const struct dccp_sock *dp = dccp_sk(sk);
584 const struct dccp_service_list *sl;
585 int err = -ENOENT, slen = 0, total_len = sizeof(u32);
586
587 lock_sock(sk);
Arnaldo Carvalho de Melo67e6b622005-09-16 16:58:40 -0700588 if ((sl = dp->dccps_service_list) != NULL) {
589 slen = sl->dccpsl_nr * sizeof(u32);
590 total_len += slen;
591 }
592
593 err = -EINVAL;
594 if (total_len > len)
595 goto out;
596
597 err = 0;
598 if (put_user(total_len, optlen) ||
599 put_user(dp->dccps_service, optval) ||
600 (sl != NULL && copy_to_user(optval + 1, sl->dccpsl_list, slen)))
601 err = -EFAULT;
602out:
603 release_sock(sk);
604 return err;
605}
606
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800607static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -0300608 char __user *optval, int __user *optlen)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700609{
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300610 struct dccp_sock *dp;
611 int val, len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700612
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300613 if (get_user(len, optlen))
614 return -EFAULT;
615
Arnaldo Carvalho de Melo39ebc022007-03-28 11:54:32 -0700616 if (len < (int)sizeof(int))
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300617 return -EINVAL;
618
619 dp = dccp_sk(sk);
620
621 switch (optname) {
622 case DCCP_SOCKOPT_PACKET_SIZE:
Gerrit Renker5aed3242006-11-28 19:33:36 -0200623 DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
Arnaldo Carvalho de Melo841bac12006-11-28 19:42:03 -0200624 return 0;
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700625 case DCCP_SOCKOPT_SERVICE:
626 return dccp_getsockopt_service(sk, len,
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800627 (__be32 __user *)optval, optlen);
Gerrit Renker7c559a92007-10-04 14:39:22 -0700628 case DCCP_SOCKOPT_GET_CUR_MPS:
629 val = dp->dccps_mss_cache;
Gerrit Renker7c559a92007-10-04 14:39:22 -0700630 break;
Gerrit Renkerd90ebcb2008-11-12 00:47:26 -0800631 case DCCP_SOCKOPT_AVAILABLE_CCIDS:
632 return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
Gerrit Renker71c262a2008-11-23 16:04:59 -0800633 case DCCP_SOCKOPT_TX_CCID:
634 val = ccid_get_current_tx_ccid(dp);
635 if (val < 0)
636 return -ENOPROTOOPT;
637 break;
638 case DCCP_SOCKOPT_RX_CCID:
639 val = ccid_get_current_rx_ccid(dp);
640 if (val < 0)
641 return -ENOPROTOOPT;
642 break;
Gerrit Renkerb8599d22007-12-13 12:25:01 -0200643 case DCCP_SOCKOPT_SERVER_TIMEWAIT:
644 val = dp->dccps_server_timewait;
Gerrit Renkerb8599d22007-12-13 12:25:01 -0200645 break;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200646 case DCCP_SOCKOPT_SEND_CSCOV:
647 val = dp->dccps_pcslen;
648 break;
649 case DCCP_SOCKOPT_RECV_CSCOV:
650 val = dp->dccps_pcrlen;
651 break;
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100652 case DCCP_SOCKOPT_QPOLICY_ID:
653 val = dp->dccps_qpolicy;
654 break;
655 case DCCP_SOCKOPT_QPOLICY_TXQLEN:
656 val = dp->dccps_tx_qlen;
657 break;
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -0700658 case 128 ... 191:
659 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
660 len, (u32 __user *)optval, optlen);
661 case 192 ... 255:
662 return ccid_hc_tx_getsockopt(dp->dccps_hc_tx_ccid, sk, optname,
663 len, (u32 __user *)optval, optlen);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300664 default:
665 return -ENOPROTOOPT;
666 }
667
Gerrit Renker79133502007-12-13 12:27:14 -0200668 len = sizeof(val);
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300669 if (put_user(len, optlen) || copy_to_user(optval, &val, len))
670 return -EFAULT;
671
672 return 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700673}
674
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800675int dccp_getsockopt(struct sock *sk, int level, int optname,
676 char __user *optval, int __user *optlen)
677{
678 if (level != SOL_DCCP)
679 return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
680 optname, optval,
681 optlen);
682 return do_dccp_getsockopt(sk, level, optname, optval, optlen);
683}
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800684
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800685EXPORT_SYMBOL_GPL(dccp_getsockopt);
686
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800687#ifdef CONFIG_COMPAT
688int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800689 char __user *optval, int __user *optlen)
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800690{
Arnaldo Carvalho de Melodec73ff2006-03-20 22:46:16 -0800691 if (level != SOL_DCCP)
692 return inet_csk_compat_getsockopt(sk, level, optname,
693 optval, optlen);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800694 return do_dccp_getsockopt(sk, level, optname, optval, optlen);
695}
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800696
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800697EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
698#endif
699
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100700static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb)
701{
Gu Zhengf95b4142014-12-11 11:22:04 +0800702 struct cmsghdr *cmsg;
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100703
704 /*
705 * Assign an (opaque) qpolicy priority value to skb->priority.
706 *
707 * We are overloading this skb field for use with the qpolicy subystem.
708 * The skb->priority is normally used for the SO_PRIORITY option, which
709 * is initialised from sk_priority. Since the assignment of sk_priority
710 * to skb->priority happens later (on layer 3), we overload this field
711 * for use with queueing priorities as long as the skb is on layer 4.
712 * The default priority value (if nothing is set) is 0.
713 */
714 skb->priority = 0;
715
Gu Zhengf95b4142014-12-11 11:22:04 +0800716 for_each_cmsghdr(cmsg, msg) {
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100717 if (!CMSG_OK(msg, cmsg))
718 return -EINVAL;
719
720 if (cmsg->cmsg_level != SOL_DCCP)
721 continue;
722
Tomasz Grobelny04910262010-12-04 13:39:13 +0100723 if (cmsg->cmsg_type <= DCCP_SCM_QPOLICY_MAX &&
724 !dccp_qpolicy_param_ok(skb->sk, cmsg->cmsg_type))
725 return -EINVAL;
726
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100727 switch (cmsg->cmsg_type) {
728 case DCCP_SCM_PRIORITY:
729 if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u32)))
730 return -EINVAL;
731 skb->priority = *(__u32 *)CMSG_DATA(cmsg);
732 break;
733 default:
734 return -EINVAL;
735 }
736 }
737 return 0;
738}
739
Ying Xue1b784142015-03-02 15:37:48 +0800740int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700741{
742 const struct dccp_sock *dp = dccp_sk(sk);
743 const int flags = msg->msg_flags;
744 const int noblock = flags & MSG_DONTWAIT;
745 struct sk_buff *skb;
746 int rc, size;
747 long timeo;
748
749 if (len > dp->dccps_mss_cache)
750 return -EMSGSIZE;
751
752 lock_sock(sk);
Ian McDonaldb1308dc2006-11-20 18:30:17 -0200753
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100754 if (dccp_qpolicy_full(sk)) {
Ian McDonaldb1308dc2006-11-20 18:30:17 -0200755 rc = -EAGAIN;
756 goto out_release;
757 }
758
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700759 timeo = sock_sndtimeo(sk, noblock);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700760
761 /*
762 * We have to use sk_stream_wait_connect here to set sk_write_pending,
763 * so that the trick in dccp_rcv_request_sent_state_process.
764 */
765 /* Wait for a connection to finish. */
Gerrit Renkercecd8d02007-09-26 19:36:08 -0300766 if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN))
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700767 if ((rc = sk_stream_wait_connect(sk, &timeo)) != 0)
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700768 goto out_release;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700769
770 size = sk->sk_prot->max_header + len;
771 release_sock(sk);
772 skb = sock_alloc_send_skb(sk, size, noblock, &rc);
773 lock_sock(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700774 if (skb == NULL)
775 goto out_release;
776
777 skb_reserve(skb, sk->sk_prot->max_header);
Al Viro6ce8e9c2014-04-06 21:25:44 -0400778 rc = memcpy_from_msg(skb_put(skb, len), msg, len);
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700779 if (rc != 0)
780 goto out_discard;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700781
Tomasz Grobelny871a2c12010-12-04 13:38:01 +0100782 rc = dccp_msghdr_parse(msg, skb);
783 if (rc != 0)
784 goto out_discard;
785
786 dccp_qpolicy_push(sk, skb);
Gerrit Renkerb1fcf552010-10-27 19:16:27 +0000787 /*
788 * The xmit_timer is set if the TX CCID is rate-based and will expire
789 * when congestion control permits to release further packets into the
790 * network. Window-based CCIDs do not use this timer.
791 */
792 if (!timer_pending(&dp->dccps_xmit_timer))
793 dccp_write_xmit(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700794out_release:
795 release_sock(sk);
796 return rc ? : len;
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700797out_discard:
798 kfree_skb(skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700799 goto out_release;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700800}
801
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800802EXPORT_SYMBOL_GPL(dccp_sendmsg);
803
Ying Xue1b784142015-03-02 15:37:48 +0800804int dccp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
805 int flags, int *addr_len)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700806{
807 const struct dccp_hdr *dh;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700808 long timeo;
809
810 lock_sock(sk);
811
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300812 if (sk->sk_state == DCCP_LISTEN) {
813 len = -ENOTCONN;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700814 goto out;
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300815 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700816
817 timeo = sock_rcvtimeo(sk, nonblock);
818
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700819 do {
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300820 struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700821
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300822 if (skb == NULL)
823 goto verify_sock_status;
824
825 dh = dccp_hdr(skb);
826
Gerrit Renker0c869622007-11-28 11:59:48 -0200827 switch (dh->dccph_type) {
828 case DCCP_PKT_DATA:
829 case DCCP_PKT_DATAACK:
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300830 goto found_ok_skb;
831
Gerrit Renker0c869622007-11-28 11:59:48 -0200832 case DCCP_PKT_CLOSE:
833 case DCCP_PKT_CLOSEREQ:
834 if (!(flags & MSG_PEEK))
835 dccp_finish_passive_close(sk);
836 /* fall through */
837 case DCCP_PKT_RESET:
838 dccp_pr_debug("found fin (%s) ok!\n",
839 dccp_packet_name(dh->dccph_type));
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300840 len = 0;
841 goto found_fin_ok;
Gerrit Renker0c869622007-11-28 11:59:48 -0200842 default:
843 dccp_pr_debug("packet_type=%s\n",
844 dccp_packet_name(dh->dccph_type));
Dan Williams7bced392013-12-30 12:37:29 -0800845 sk_eat_skb(sk, skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700846 }
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300847verify_sock_status:
848 if (sock_flag(sk, SOCK_DONE)) {
849 len = 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700850 break;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700851 }
852
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300853 if (sk->sk_err) {
854 len = sock_error(sk);
855 break;
856 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700857
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300858 if (sk->sk_shutdown & RCV_SHUTDOWN) {
859 len = 0;
860 break;
861 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700862
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300863 if (sk->sk_state == DCCP_CLOSED) {
864 if (!sock_flag(sk, SOCK_DONE)) {
865 /* This occurs when user tries to read
866 * from never connected socket.
867 */
868 len = -ENOTCONN;
869 break;
870 }
871 len = 0;
872 break;
873 }
874
875 if (!timeo) {
876 len = -EAGAIN;
877 break;
878 }
879
880 if (signal_pending(current)) {
881 len = sock_intr_errno(timeo);
882 break;
883 }
884
Sabrina Dubrocadfbafc92015-07-24 18:19:25 +0200885 sk_wait_data(sk, &timeo, NULL);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700886 continue;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700887 found_ok_skb:
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300888 if (len > skb->len)
889 len = skb->len;
890 else if (len < skb->len)
891 msg->msg_flags |= MSG_TRUNC;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700892
David S. Miller51f3d022014-11-05 16:46:40 -0500893 if (skb_copy_datagram_msg(skb, 0, msg, len)) {
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300894 /* Exception. Bailout! */
895 len = -EFAULT;
896 break;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700897 }
Gerrit Renker55d95592010-02-10 20:26:18 +0000898 if (flags & MSG_TRUNC)
899 len = skb->len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700900 found_fin_ok:
901 if (!(flags & MSG_PEEK))
Dan Williams7bced392013-12-30 12:37:29 -0800902 sk_eat_skb(sk, skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700903 break;
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300904 } while (1);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700905out:
906 release_sock(sk);
Arnaldo Carvalho de Melo531669a2005-08-13 20:35:17 -0300907 return len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700908}
909
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800910EXPORT_SYMBOL_GPL(dccp_recvmsg);
911
912int inet_dccp_listen(struct socket *sock, int backlog)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700913{
914 struct sock *sk = sock->sk;
915 unsigned char old_state;
916 int err;
917
918 lock_sock(sk);
919
920 err = -EINVAL;
921 if (sock->state != SS_UNCONNECTED || sock->type != SOCK_DCCP)
922 goto out;
923
924 old_state = sk->sk_state;
925 if (!((1 << old_state) & (DCCPF_CLOSED | DCCPF_LISTEN)))
926 goto out;
927
928 /* Really, if the socket is already in listen state
929 * we can only allow the backlog to be adjusted.
930 */
931 if (old_state != DCCP_LISTEN) {
932 /*
933 * FIXME: here it probably should be sk->sk_prot->listen_start
934 * see tcp_listen_start
935 */
Eric Dumazet72a3eff2006-11-16 02:30:37 -0800936 err = dccp_listen_start(sk, backlog);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700937 if (err)
938 goto out;
939 }
940 sk->sk_max_ack_backlog = backlog;
941 err = 0;
942
943out:
944 release_sock(sk);
945 return err;
946}
947
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -0800948EXPORT_SYMBOL_GPL(inet_dccp_listen);
949
Gerrit Renker0c869622007-11-28 11:59:48 -0200950static void dccp_terminate_connection(struct sock *sk)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700951{
Gerrit Renker0c869622007-11-28 11:59:48 -0200952 u8 next_state = DCCP_CLOSED;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700953
Gerrit Renker0c869622007-11-28 11:59:48 -0200954 switch (sk->sk_state) {
955 case DCCP_PASSIVE_CLOSE:
956 case DCCP_PASSIVE_CLOSEREQ:
957 dccp_finish_passive_close(sk);
958 break;
959 case DCCP_PARTOPEN:
960 dccp_pr_debug("Stop PARTOPEN timer (%p)\n", sk);
961 inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
962 /* fall through */
963 case DCCP_OPEN:
964 dccp_send_close(sk, 1);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700965
Gerrit Renkerb8599d22007-12-13 12:25:01 -0200966 if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER &&
967 !dccp_sk(sk)->dccps_server_timewait)
Gerrit Renker0c869622007-11-28 11:59:48 -0200968 next_state = DCCP_ACTIVE_CLOSEREQ;
969 else
970 next_state = DCCP_CLOSING;
971 /* fall through */
972 default:
973 dccp_set_state(sk, next_state);
974 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700975}
976
977void dccp_close(struct sock *sk, long timeout)
978{
Ian McDonald97e58482006-08-26 19:16:45 -0700979 struct dccp_sock *dp = dccp_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700980 struct sk_buff *skb;
Gerrit Renkerd83bd952007-12-16 16:06:03 -0800981 u32 data_was_unread = 0;
Herbert Xu134af342006-05-05 17:09:13 -0700982 int state;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700983
984 lock_sock(sk);
985
986 sk->sk_shutdown = SHUTDOWN_MASK;
987
988 if (sk->sk_state == DCCP_LISTEN) {
989 dccp_set_state(sk, DCCP_CLOSED);
990
991 /* Special case. */
992 inet_csk_listen_stop(sk);
993
994 goto adjudge_to_death;
995 }
996
Ian McDonald97e58482006-08-26 19:16:45 -0700997 sk_stop_timer(sk, &dp->dccps_xmit_timer);
998
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700999 /*
1000 * We need to flush the recv. buffs. We do this only on the
1001 * descriptor close, not protocol-sourced closes, because the
1002 *reader process may not have drained the data yet!
1003 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001004 while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
Gerrit Renkerd83bd952007-12-16 16:06:03 -08001005 data_was_unread += skb->len;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001006 __kfree_skb(skb);
1007 }
1008
Eric Dumazet346da622016-11-02 18:04:24 -07001009 /* If socket has been already reset kill it. */
1010 if (sk->sk_state == DCCP_CLOSED)
1011 goto adjudge_to_death;
1012
Gerrit Renkerd83bd952007-12-16 16:06:03 -08001013 if (data_was_unread) {
1014 /* Unread data was tossed, send an appropriate Reset Code */
Gerrit Renker2f34b322010-10-11 20:44:42 +02001015 DCCP_WARN("ABORT with %u bytes unread\n", data_was_unread);
Gerrit Renkerd83bd952007-12-16 16:06:03 -08001016 dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);
1017 dccp_set_state(sk, DCCP_CLOSED);
1018 } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001019 /* Check zero linger _after_ checking for unread data. */
1020 sk->sk_prot->disconnect(sk, 0);
Gerrit Renker0c869622007-11-28 11:59:48 -02001021 } else if (sk->sk_state != DCCP_CLOSED) {
Gerrit Renkerb1fcf552010-10-27 19:16:27 +00001022 /*
1023 * Normal connection termination. May need to wait if there are
1024 * still packets in the TX queue that are delayed by the CCID.
1025 */
1026 dccp_flush_write_queue(sk, &timeout);
Gerrit Renker0c869622007-11-28 11:59:48 -02001027 dccp_terminate_connection(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001028 }
1029
Gerrit Renkerb1fcf552010-10-27 19:16:27 +00001030 /*
1031 * Flush write queue. This may be necessary in several cases:
1032 * - we have been closed by the peer but still have application data;
1033 * - abortive termination (unread data or zero linger time),
1034 * - normal termination but queue could not be flushed within time limit
1035 */
1036 __skb_queue_purge(&sk->sk_write_queue);
1037
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001038 sk_stream_wait_close(sk, timeout);
1039
1040adjudge_to_death:
Herbert Xu134af342006-05-05 17:09:13 -07001041 state = sk->sk_state;
1042 sock_hold(sk);
1043 sock_orphan(sk);
Herbert Xu134af342006-05-05 17:09:13 -07001044
Arnaldo Carvalho de Melo7ad07e72005-08-23 21:50:06 -07001045 /*
1046 * It is the last release_sock in its life. It will remove backlog.
1047 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001048 release_sock(sk);
1049 /*
1050 * Now socket is owned by kernel and we acquire BH lock
1051 * to finish close. No need to check for user refs.
1052 */
1053 local_bh_disable();
1054 bh_lock_sock(sk);
Ilpo Järvinen547b7922008-07-25 21:43:18 -07001055 WARN_ON(sock_owned_by_user(sk));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001056
Herbert Xueb4dea52008-12-29 23:04:08 -08001057 percpu_counter_inc(sk->sk_prot->orphan_count);
1058
Herbert Xu134af342006-05-05 17:09:13 -07001059 /* Have we already been destroyed by a softirq or backlog? */
1060 if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED)
1061 goto out;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001062
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001063 if (sk->sk_state == DCCP_CLOSED)
1064 inet_csk_destroy_sock(sk);
1065
1066 /* Otherwise, socket is reprieved until protocol close. */
1067
Herbert Xu134af342006-05-05 17:09:13 -07001068out:
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001069 bh_unlock_sock(sk);
1070 local_bh_enable();
1071 sock_put(sk);
1072}
1073
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -08001074EXPORT_SYMBOL_GPL(dccp_close);
1075
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001076void dccp_shutdown(struct sock *sk, int how)
1077{
Gerrit Renker8e8c71f2007-11-21 09:56:48 -02001078 dccp_pr_debug("called shutdown(%x)\n", how);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001079}
1080
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -08001081EXPORT_SYMBOL_GPL(dccp_shutdown);
1082
Fabian Frederick0c5b8a42014-10-01 06:48:03 +02001083static inline int __init dccp_mib_init(void)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001084{
WANG Cong698365f2014-05-05 15:55:55 -07001085 dccp_statistics = alloc_percpu(struct dccp_mib);
1086 if (!dccp_statistics)
1087 return -ENOMEM;
1088 return 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001089}
1090
YOSHIFUJI Hideaki24e8b7e2008-04-10 03:48:43 -07001091static inline void dccp_mib_exit(void)
Arnaldo Carvalho de Melo46f09ff2006-03-20 21:24:42 -08001092{
WANG Cong698365f2014-05-05 15:55:55 -07001093 free_percpu(dccp_statistics);
Arnaldo Carvalho de Melo46f09ff2006-03-20 21:24:42 -08001094}
1095
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001096static int thash_entries;
1097module_param(thash_entries, int, 0444);
1098MODULE_PARM_DESC(thash_entries, "Number of ehash buckets");
1099
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -03001100#ifdef CONFIG_IP_DCCP_DEBUG
Rusty Russelleb939922011-12-19 14:08:01 +00001101bool dccp_debug;
Gerrit Renker43264992008-08-23 13:28:27 +02001102module_param(dccp_debug, bool, 0644);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001103MODULE_PARM_DESC(dccp_debug, "Enable debug messages");
Arnaldo Carvalho de Melof21e68c2005-12-13 23:24:16 -08001104
1105EXPORT_SYMBOL_GPL(dccp_debug);
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -03001106#endif
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001107
1108static int __init dccp_init(void)
1109{
1110 unsigned long goal;
1111 int ehash_order, bhash_order, i;
Eric Dumazetdd24c002008-11-25 21:17:14 -08001112 int rc;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001113
Patrick McHardy028b0272008-04-12 18:35:41 -07001114 BUILD_BUG_ON(sizeof(struct dccp_skb_cb) >
1115 FIELD_SIZEOF(struct sk_buff, cb));
Tejun Heo908c7f12014-09-08 09:51:29 +09001116 rc = percpu_counter_init(&dccp_orphan_count, 0, GFP_KERNEL);
Eric Dumazetdd24c002008-11-25 21:17:14 -08001117 if (rc)
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001118 goto out_fail;
Eric Dumazetdd24c002008-11-25 21:17:14 -08001119 rc = -ENOBUFS;
Eric Dumazet5caea4e2008-11-20 00:40:07 -08001120 inet_hashinfo_init(&dccp_hashinfo);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -03001121 dccp_hashinfo.bind_bucket_cachep =
1122 kmem_cache_create("dccp_bind_bucket",
1123 sizeof(struct inet_bind_bucket), 0,
Paul Mundt20c2df82007-07-20 10:11:58 +09001124 SLAB_HWCACHE_ALIGN, NULL);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001125 if (!dccp_hashinfo.bind_bucket_cachep)
Eric Dumazetdd24c002008-11-25 21:17:14 -08001126 goto out_free_percpu;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001127
1128 /*
1129 * Size and allocate the main established and bind bucket
1130 * hash tables.
1131 *
1132 * The methodology is similar to that of the buffer cache.
1133 */
Jan Beulich44813742009-09-21 17:03:05 -07001134 if (totalram_pages >= (128 * 1024))
1135 goal = totalram_pages >> (21 - PAGE_SHIFT);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001136 else
Jan Beulich44813742009-09-21 17:03:05 -07001137 goal = totalram_pages >> (23 - PAGE_SHIFT);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001138
1139 if (thash_entries)
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -03001140 goal = (thash_entries *
1141 sizeof(struct inet_ehash_bucket)) >> PAGE_SHIFT;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001142 for (ehash_order = 0; (1UL << ehash_order) < goal; ehash_order++)
1143 ;
1144 do {
Eric Dumazetf373b532009-10-09 00:16:19 +00001145 unsigned long hash_size = (1UL << ehash_order) * PAGE_SIZE /
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001146 sizeof(struct inet_ehash_bucket);
Eric Dumazetf373b532009-10-09 00:16:19 +00001147
1148 while (hash_size & (hash_size - 1))
1149 hash_size--;
1150 dccp_hashinfo.ehash_mask = hash_size - 1;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001151 dccp_hashinfo.ehash = (struct inet_ehash_bucket *)
Mel Gorman1c29b3f2009-07-29 15:04:10 -07001152 __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, ehash_order);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001153 } while (!dccp_hashinfo.ehash && --ehash_order > 0);
1154
1155 if (!dccp_hashinfo.ehash) {
Gerrit Renker59348b12006-11-20 18:39:23 -02001156 DCCP_CRIT("Failed to allocate DCCP established hash table");
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001157 goto out_free_bind_bucket_cachep;
1158 }
1159
Eric Dumazet05dbc7b2013-10-03 00:22:02 -07001160 for (i = 0; i <= dccp_hashinfo.ehash_mask; i++)
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08001161 INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].chain, i);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001162
Eric Dumazet230140c2007-11-07 02:40:20 -08001163 if (inet_ehash_locks_alloc(&dccp_hashinfo))
1164 goto out_free_dccp_ehash;
1165
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001166 bhash_order = ehash_order;
1167
1168 do {
1169 dccp_hashinfo.bhash_size = (1UL << bhash_order) * PAGE_SIZE /
1170 sizeof(struct inet_bind_hashbucket);
Arnaldo Carvalho de Melo7690af32005-08-13 20:34:54 -03001171 if ((dccp_hashinfo.bhash_size > (64 * 1024)) &&
1172 bhash_order > 0)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001173 continue;
1174 dccp_hashinfo.bhash = (struct inet_bind_hashbucket *)
Mel Gorman1c29b3f2009-07-29 15:04:10 -07001175 __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, bhash_order);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001176 } while (!dccp_hashinfo.bhash && --bhash_order >= 0);
1177
1178 if (!dccp_hashinfo.bhash) {
Gerrit Renker59348b12006-11-20 18:39:23 -02001179 DCCP_CRIT("Failed to allocate DCCP bind hash table");
Eric Dumazet230140c2007-11-07 02:40:20 -08001180 goto out_free_dccp_locks;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001181 }
1182
1183 for (i = 0; i < dccp_hashinfo.bhash_size; i++) {
1184 spin_lock_init(&dccp_hashinfo.bhash[i].lock);
1185 INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain);
1186 }
1187
Arnaldo Carvalho de Melo46f09ff2006-03-20 21:24:42 -08001188 rc = dccp_mib_init();
Arnaldo Carvalho de Melofa23e2e2006-03-20 17:16:01 -08001189 if (rc)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001190 goto out_free_dccp_bhash;
1191
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001192 rc = dccp_ackvec_init();
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001193 if (rc)
Arnaldo Carvalho de Melob61fafc2006-03-20 21:25:11 -08001194 goto out_free_dccp_mib;
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001195
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001196 rc = dccp_sysctl_init();
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001197 if (rc)
1198 goto out_ackvec_exit;
Gerrit Renker4c70f382007-09-25 22:40:13 -07001199
Gerrit Renkerddebc972009-01-04 21:42:53 -08001200 rc = ccid_initialize_builtins();
1201 if (rc)
1202 goto out_sysctl_exit;
1203
Gerrit Renker4c70f382007-09-25 22:40:13 -07001204 dccp_timestamping_init();
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001205
1206 return 0;
1207
Gerrit Renkerddebc972009-01-04 21:42:53 -08001208out_sysctl_exit:
1209 dccp_sysctl_exit();
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001210out_ackvec_exit:
1211 dccp_ackvec_exit();
Arnaldo Carvalho de Melob61fafc2006-03-20 21:25:11 -08001212out_free_dccp_mib:
Arnaldo Carvalho de Melo46f09ff2006-03-20 21:24:42 -08001213 dccp_mib_exit();
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001214out_free_dccp_bhash:
1215 free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
Eric Dumazet230140c2007-11-07 02:40:20 -08001216out_free_dccp_locks:
1217 inet_ehash_locks_free(&dccp_hashinfo);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001218out_free_dccp_ehash:
1219 free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001220out_free_bind_bucket_cachep:
1221 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
Eric Dumazetdd24c002008-11-25 21:17:14 -08001222out_free_percpu:
1223 percpu_counter_destroy(&dccp_orphan_count);
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001224out_fail:
1225 dccp_hashinfo.bhash = NULL;
1226 dccp_hashinfo.ehash = NULL;
1227 dccp_hashinfo.bind_bucket_cachep = NULL;
1228 return rc;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001229}
1230
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001231static void __exit dccp_fini(void)
1232{
Gerrit Renkerddebc972009-01-04 21:42:53 -08001233 ccid_cleanup_builtins();
Arnaldo Carvalho de Melo46f09ff2006-03-20 21:24:42 -08001234 dccp_mib_exit();
Arnaldo Carvalho de Melo725ba8e2005-08-13 20:35:39 -03001235 free_pages((unsigned long)dccp_hashinfo.bhash,
1236 get_order(dccp_hashinfo.bhash_size *
1237 sizeof(struct inet_bind_hashbucket)));
1238 free_pages((unsigned long)dccp_hashinfo.ehash,
Eric Dumazetf373b532009-10-09 00:16:19 +00001239 get_order((dccp_hashinfo.ehash_mask + 1) *
Arnaldo Carvalho de Melo725ba8e2005-08-13 20:35:39 -03001240 sizeof(struct inet_ehash_bucket)));
Eric Dumazet230140c2007-11-07 02:40:20 -08001241 inet_ehash_locks_free(&dccp_hashinfo);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001242 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
Arnaldo Carvalho de Melo9b07ef52006-03-20 17:16:17 -08001243 dccp_ackvec_exit();
Arnaldo Carvalho de Meloe55d9122006-03-20 19:25:02 -08001244 dccp_sysctl_exit();
Wei Yongjun476181c2009-08-04 21:44:39 +00001245 percpu_counter_destroy(&dccp_orphan_count);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001246}
1247
1248module_init(dccp_init);
1249module_exit(dccp_fini);
1250
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001251MODULE_LICENSE("GPL");
1252MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>");
1253MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");