aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/proto.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/proto.c')
-rw-r--r--net/dccp/proto.c224
1 files changed, 109 insertions, 115 deletions
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index d0bd34819761..d5c2bacb713c 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -40,16 +40,10 @@ DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
40 40
41EXPORT_SYMBOL_GPL(dccp_statistics); 41EXPORT_SYMBOL_GPL(dccp_statistics);
42 42
43atomic_t dccp_orphan_count = ATOMIC_INIT(0); 43struct percpu_counter dccp_orphan_count;
44
45EXPORT_SYMBOL_GPL(dccp_orphan_count); 44EXPORT_SYMBOL_GPL(dccp_orphan_count);
46 45
47struct inet_hashinfo __cacheline_aligned dccp_hashinfo = { 46struct inet_hashinfo dccp_hashinfo;
48 .lhash_lock = RW_LOCK_UNLOCKED,
49 .lhash_users = ATOMIC_INIT(0),
50 .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait),
51};
52
53EXPORT_SYMBOL_GPL(dccp_hashinfo); 47EXPORT_SYMBOL_GPL(dccp_hashinfo);
54 48
55/* the maximum queue length for tx in packets. 0 is no limit */ 49/* the maximum queue length for tx in packets. 0 is no limit */
@@ -67,6 +61,9 @@ void dccp_set_state(struct sock *sk, const int state)
67 case DCCP_OPEN: 61 case DCCP_OPEN:
68 if (oldstate != DCCP_OPEN) 62 if (oldstate != DCCP_OPEN)
69 DCCP_INC_STATS(DCCP_MIB_CURRESTAB); 63 DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
64 /* Client retransmits all Confirm options until entering OPEN */
65 if (oldstate == DCCP_PARTOPEN)
66 dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg);
70 break; 67 break;
71 68
72 case DCCP_CLOSED: 69 case DCCP_CLOSED:
@@ -175,7 +172,6 @@ EXPORT_SYMBOL_GPL(dccp_state_name);
175int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) 172int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
176{ 173{
177 struct dccp_sock *dp = dccp_sk(sk); 174 struct dccp_sock *dp = dccp_sk(sk);
178 struct dccp_minisock *dmsk = dccp_msk(sk);
179 struct inet_connection_sock *icsk = inet_csk(sk); 175 struct inet_connection_sock *icsk = inet_csk(sk);
180 176
181 dccp_minisock_init(&dp->dccps_minisock); 177 dccp_minisock_init(&dp->dccps_minisock);
@@ -193,45 +189,10 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
193 189
194 dccp_init_xmit_timers(sk); 190 dccp_init_xmit_timers(sk);
195 191
196 /* 192 INIT_LIST_HEAD(&dp->dccps_featneg);
197 * FIXME: We're hardcoding the CCID, and doing this at this point makes 193 /* control socket doesn't need feat nego */
198 * the listening (master) sock get CCID control blocks, which is not 194 if (likely(ctl_sock_initialized))
199 * necessary, but for now, to not mess with the test userspace apps, 195 return dccp_feat_init(sk);
200 * lets leave it here, later the real solution is to do this in a
201 * setsockopt(CCIDs-I-want/accept). -acme
202 */
203 if (likely(ctl_sock_initialized)) {
204 int rc = dccp_feat_init(dmsk);
205
206 if (rc)
207 return rc;
208
209 if (dmsk->dccpms_send_ack_vector) {
210 dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
211 if (dp->dccps_hc_rx_ackvec == NULL)
212 return -ENOMEM;
213 }
214 dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid,
215 sk, GFP_KERNEL);
216 dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
217 sk, GFP_KERNEL);
218 if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
219 dp->dccps_hc_tx_ccid == NULL)) {
220 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
221 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
222 if (dmsk->dccpms_send_ack_vector) {
223 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
224 dp->dccps_hc_rx_ackvec = NULL;
225 }
226 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
227 return -ENOMEM;
228 }
229 } else {
230 /* control socket doesn't need feat nego */
231 INIT_LIST_HEAD(&dmsk->dccpms_pending);
232 INIT_LIST_HEAD(&dmsk->dccpms_conf);
233 }
234
235 return 0; 196 return 0;
236} 197}
237 198
@@ -240,7 +201,6 @@ EXPORT_SYMBOL_GPL(dccp_init_sock);
240void dccp_destroy_sock(struct sock *sk) 201void dccp_destroy_sock(struct sock *sk)
241{ 202{
242 struct dccp_sock *dp = dccp_sk(sk); 203 struct dccp_sock *dp = dccp_sk(sk);
243 struct dccp_minisock *dmsk = dccp_msk(sk);
244 204
245 /* 205 /*
246 * DCCP doesn't use sk_write_queue, just sk_send_head 206 * DCCP doesn't use sk_write_queue, just sk_send_head
@@ -258,7 +218,7 @@ void dccp_destroy_sock(struct sock *sk)
258 kfree(dp->dccps_service_list); 218 kfree(dp->dccps_service_list);
259 dp->dccps_service_list = NULL; 219 dp->dccps_service_list = NULL;
260 220
261 if (dmsk->dccpms_send_ack_vector) { 221 if (dp->dccps_hc_rx_ackvec != NULL) {
262 dccp_ackvec_free(dp->dccps_hc_rx_ackvec); 222 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
263 dp->dccps_hc_rx_ackvec = NULL; 223 dp->dccps_hc_rx_ackvec = NULL;
264 } 224 }
@@ -267,7 +227,7 @@ void dccp_destroy_sock(struct sock *sk)
267 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; 227 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
268 228
269 /* clean up feature negotiation state */ 229 /* clean up feature negotiation state */
270 dccp_feat_clean(dmsk); 230 dccp_feat_list_purge(&dp->dccps_featneg);
271} 231}
272 232
273EXPORT_SYMBOL_GPL(dccp_destroy_sock); 233EXPORT_SYMBOL_GPL(dccp_destroy_sock);
@@ -277,6 +237,9 @@ static inline int dccp_listen_start(struct sock *sk, int backlog)
277 struct dccp_sock *dp = dccp_sk(sk); 237 struct dccp_sock *dp = dccp_sk(sk);
278 238
279 dp->dccps_role = DCCP_ROLE_LISTEN; 239 dp->dccps_role = DCCP_ROLE_LISTEN;
240 /* do not start to listen if feature negotiation setup fails */
241 if (dccp_feat_finalise_settings(dp))
242 return -EPROTO;
280 return inet_csk_listen_start(sk, backlog); 243 return inet_csk_listen_start(sk, backlog);
281} 244}
282 245
@@ -466,42 +429,70 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
466 return 0; 429 return 0;
467} 430}
468 431
469/* byte 1 is feature. the rest is the preference list */ 432static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
470static int dccp_setsockopt_change(struct sock *sk, int type,
471 struct dccp_so_feat __user *optval)
472{ 433{
473 struct dccp_so_feat opt; 434 u8 *list, len;
474 u8 *val; 435 int i, rc;
475 int rc;
476 436
477 if (copy_from_user(&opt, optval, sizeof(opt))) 437 if (cscov < 0 || cscov > 15)
478 return -EFAULT; 438 return -EINVAL;
479 /* 439 /*
480 * rfc4340: 6.1. Change Options 440 * Populate a list of permissible values, in the range cscov...15. This
441 * is necessary since feature negotiation of single values only works if
442 * both sides incidentally choose the same value. Since the list starts
443 * lowest-value first, negotiation will pick the smallest shared value.
481 */ 444 */
482 if (opt.dccpsf_len < 1) 445 if (cscov == 0)
446 return 0;
447 len = 16 - cscov;
448
449 list = kmalloc(len, GFP_KERNEL);
450 if (list == NULL)
451 return -ENOBUFS;
452
453 for (i = 0; i < len; i++)
454 list[i] = cscov++;
455
456 rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
457
458 if (rc == 0) {
459 if (rx)
460 dccp_sk(sk)->dccps_pcrlen = cscov;
461 else
462 dccp_sk(sk)->dccps_pcslen = cscov;
463 }
464 kfree(list);
465 return rc;
466}
467
468static int dccp_setsockopt_ccid(struct sock *sk, int type,
469 char __user *optval, int optlen)
470{
471 u8 *val;
472 int rc = 0;
473
474 if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
483 return -EINVAL; 475 return -EINVAL;
484 476
485 val = kmalloc(opt.dccpsf_len, GFP_KERNEL); 477 val = kmalloc(optlen, GFP_KERNEL);
486 if (!val) 478 if (val == NULL)
487 return -ENOMEM; 479 return -ENOMEM;
488 480
489 if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) { 481 if (copy_from_user(val, optval, optlen)) {
490 rc = -EFAULT; 482 kfree(val);
491 goto out_free_val; 483 return -EFAULT;
492 } 484 }
493 485
494 rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat, 486 lock_sock(sk);
495 val, opt.dccpsf_len, GFP_KERNEL); 487 if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
496 if (rc) 488 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
497 goto out_free_val;
498 489
499out: 490 if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
500 return rc; 491 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
492 release_sock(sk);
501 493
502out_free_val:
503 kfree(val); 494 kfree(val);
504 goto out; 495 return rc;
505} 496}
506 497
507static int do_dccp_setsockopt(struct sock *sk, int level, int optname, 498static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
@@ -510,7 +501,21 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
510 struct dccp_sock *dp = dccp_sk(sk); 501 struct dccp_sock *dp = dccp_sk(sk);
511 int val, err = 0; 502 int val, err = 0;
512 503
513 if (optlen < sizeof(int)) 504 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;
512 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);
516 }
517
518 if (optlen < (int)sizeof(int))
514 return -EINVAL; 519 return -EINVAL;
515 520
516 if (get_user(val, (int __user *)optval)) 521 if (get_user(val, (int __user *)optval))
@@ -521,53 +526,24 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
521 526
522 lock_sock(sk); 527 lock_sock(sk);
523 switch (optname) { 528 switch (optname) {
524 case DCCP_SOCKOPT_PACKET_SIZE:
525 DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
526 err = 0;
527 break;
528 case DCCP_SOCKOPT_CHANGE_L:
529 if (optlen != sizeof(struct dccp_so_feat))
530 err = -EINVAL;
531 else
532 err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
533 (struct dccp_so_feat __user *)
534 optval);
535 break;
536 case DCCP_SOCKOPT_CHANGE_R:
537 if (optlen != sizeof(struct dccp_so_feat))
538 err = -EINVAL;
539 else
540 err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
541 (struct dccp_so_feat __user *)
542 optval);
543 break;
544 case DCCP_SOCKOPT_SERVER_TIMEWAIT: 529 case DCCP_SOCKOPT_SERVER_TIMEWAIT:
545 if (dp->dccps_role != DCCP_ROLE_SERVER) 530 if (dp->dccps_role != DCCP_ROLE_SERVER)
546 err = -EOPNOTSUPP; 531 err = -EOPNOTSUPP;
547 else 532 else
548 dp->dccps_server_timewait = (val != 0); 533 dp->dccps_server_timewait = (val != 0);
549 break; 534 break;
550 case DCCP_SOCKOPT_SEND_CSCOV: /* sender side, RFC 4340, sec. 9.2 */ 535 case DCCP_SOCKOPT_SEND_CSCOV:
551 if (val < 0 || val > 15) 536 err = dccp_setsockopt_cscov(sk, val, false);
552 err = -EINVAL;
553 else
554 dp->dccps_pcslen = val;
555 break; 537 break;
556 case DCCP_SOCKOPT_RECV_CSCOV: /* receiver side, RFC 4340 sec. 9.2.1 */ 538 case DCCP_SOCKOPT_RECV_CSCOV:
557 if (val < 0 || val > 15) 539 err = dccp_setsockopt_cscov(sk, val, true);
558 err = -EINVAL;
559 else {
560 dp->dccps_pcrlen = val;
561 /* FIXME: add feature negotiation,
562 * ChangeL(MinimumChecksumCoverage, val) */
563 }
564 break; 540 break;
565 default: 541 default:
566 err = -ENOPROTOOPT; 542 err = -ENOPROTOOPT;
567 break; 543 break;
568 } 544 }
569
570 release_sock(sk); 545 release_sock(sk);
546
571 return err; 547 return err;
572} 548}
573 549
@@ -648,6 +624,18 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
648 case DCCP_SOCKOPT_GET_CUR_MPS: 624 case DCCP_SOCKOPT_GET_CUR_MPS:
649 val = dp->dccps_mss_cache; 625 val = dp->dccps_mss_cache;
650 break; 626 break;
627 case DCCP_SOCKOPT_AVAILABLE_CCIDS:
628 return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
629 case DCCP_SOCKOPT_TX_CCID:
630 val = ccid_get_current_tx_ccid(dp);
631 if (val < 0)
632 return -ENOPROTOOPT;
633 break;
634 case DCCP_SOCKOPT_RX_CCID:
635 val = ccid_get_current_rx_ccid(dp);
636 if (val < 0)
637 return -ENOPROTOOPT;
638 break;
651 case DCCP_SOCKOPT_SERVER_TIMEWAIT: 639 case DCCP_SOCKOPT_SERVER_TIMEWAIT:
652 val = dp->dccps_server_timewait; 640 val = dp->dccps_server_timewait;
653 break; 641 break;
@@ -976,7 +964,7 @@ adjudge_to_death:
976 state = sk->sk_state; 964 state = sk->sk_state;
977 sock_hold(sk); 965 sock_hold(sk);
978 sock_orphan(sk); 966 sock_orphan(sk);
979 atomic_inc(sk->sk_prot->orphan_count); 967 percpu_counter_inc(sk->sk_prot->orphan_count);
980 968
981 /* 969 /*
982 * It is the last release_sock in its life. It will remove backlog. 970 * It is the last release_sock in its life. It will remove backlog.
@@ -1040,17 +1028,21 @@ static int __init dccp_init(void)
1040{ 1028{
1041 unsigned long goal; 1029 unsigned long goal;
1042 int ehash_order, bhash_order, i; 1030 int ehash_order, bhash_order, i;
1043 int rc = -ENOBUFS; 1031 int rc;
1044 1032
1045 BUILD_BUG_ON(sizeof(struct dccp_skb_cb) > 1033 BUILD_BUG_ON(sizeof(struct dccp_skb_cb) >
1046 FIELD_SIZEOF(struct sk_buff, cb)); 1034 FIELD_SIZEOF(struct sk_buff, cb));
1047 1035 rc = percpu_counter_init(&dccp_orphan_count, 0);
1036 if (rc)
1037 goto out;
1038 rc = -ENOBUFS;
1039 inet_hashinfo_init(&dccp_hashinfo);
1048 dccp_hashinfo.bind_bucket_cachep = 1040 dccp_hashinfo.bind_bucket_cachep =
1049 kmem_cache_create("dccp_bind_bucket", 1041 kmem_cache_create("dccp_bind_bucket",
1050 sizeof(struct inet_bind_bucket), 0, 1042 sizeof(struct inet_bind_bucket), 0,
1051 SLAB_HWCACHE_ALIGN, NULL); 1043 SLAB_HWCACHE_ALIGN, NULL);
1052 if (!dccp_hashinfo.bind_bucket_cachep) 1044 if (!dccp_hashinfo.bind_bucket_cachep)
1053 goto out; 1045 goto out_free_percpu;
1054 1046
1055 /* 1047 /*
1056 * Size and allocate the main established and bind bucket 1048 * Size and allocate the main established and bind bucket
@@ -1084,8 +1076,8 @@ static int __init dccp_init(void)
1084 } 1076 }
1085 1077
1086 for (i = 0; i < dccp_hashinfo.ehash_size; i++) { 1078 for (i = 0; i < dccp_hashinfo.ehash_size; i++) {
1087 INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].chain); 1079 INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].chain, i);
1088 INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].twchain); 1080 INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].twchain, i);
1089 } 1081 }
1090 1082
1091 if (inet_ehash_locks_alloc(&dccp_hashinfo)) 1083 if (inet_ehash_locks_alloc(&dccp_hashinfo))
@@ -1143,6 +1135,8 @@ out_free_dccp_ehash:
1143out_free_bind_bucket_cachep: 1135out_free_bind_bucket_cachep:
1144 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); 1136 kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
1145 dccp_hashinfo.bind_bucket_cachep = NULL; 1137 dccp_hashinfo.bind_bucket_cachep = NULL;
1138out_free_percpu:
1139 percpu_counter_destroy(&dccp_orphan_count);
1146 goto out; 1140 goto out;
1147} 1141}
1148 1142