aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/proto.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-09-08 20:28:59 -0400
committerDavid S. Miller <davem@davemloft.net>2008-09-08 20:28:59 -0400
commit0a68a20cc3eafa73bb54097c28b921147d7d3685 (patch)
tree8e5f315226b618cb8e050a0c7653c8ec134501e3 /net/dccp/proto.c
parent17dce5dfe38ae2fb359b61e855f5d8a3a8b7892b (diff)
parenta3cbdde8e9c38b66b4f13ac5d6ff1939ded0ff20 (diff)
Merge branch 'dccp' of git://eden-feed.erg.abdn.ac.uk/dccp_exp
Conflicts: net/dccp/input.c net/dccp/options.c
Diffstat (limited to 'net/dccp/proto.c')
-rw-r--r--net/dccp/proto.c281
1 files changed, 175 insertions, 106 deletions
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index d0bd34819761..ecf3be961e11 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -67,6 +67,9 @@ void dccp_set_state(struct sock *sk, const int state)
67 case DCCP_OPEN: 67 case DCCP_OPEN:
68 if (oldstate != DCCP_OPEN) 68 if (oldstate != DCCP_OPEN)
69 DCCP_INC_STATS(DCCP_MIB_CURRESTAB); 69 DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
70 /* Client retransmits all Confirm options until entering OPEN */
71 if (oldstate == DCCP_PARTOPEN)
72 dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg);
70 break; 73 break;
71 74
72 case DCCP_CLOSED: 75 case DCCP_CLOSED:
@@ -175,63 +178,25 @@ EXPORT_SYMBOL_GPL(dccp_state_name);
175int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) 178int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
176{ 179{
177 struct dccp_sock *dp = dccp_sk(sk); 180 struct dccp_sock *dp = dccp_sk(sk);
178 struct dccp_minisock *dmsk = dccp_msk(sk);
179 struct inet_connection_sock *icsk = inet_csk(sk); 181 struct inet_connection_sock *icsk = inet_csk(sk);
180 182
181 dccp_minisock_init(&dp->dccps_minisock);
182
183 icsk->icsk_rto = DCCP_TIMEOUT_INIT; 183 icsk->icsk_rto = DCCP_TIMEOUT_INIT;
184 icsk->icsk_syn_retries = sysctl_dccp_request_retries; 184 icsk->icsk_syn_retries = sysctl_dccp_request_retries;
185 sk->sk_state = DCCP_CLOSED; 185 sk->sk_state = DCCP_CLOSED;
186 sk->sk_write_space = dccp_write_space; 186 sk->sk_write_space = dccp_write_space;
187 icsk->icsk_sync_mss = dccp_sync_mss; 187 icsk->icsk_sync_mss = dccp_sync_mss;
188 dp->dccps_mss_cache = 536; 188 dp->dccps_mss_cache = TCP_MIN_RCVMSS;
189 dp->dccps_rate_last = jiffies; 189 dp->dccps_rate_last = jiffies;
190 dp->dccps_role = DCCP_ROLE_UNDEFINED; 190 dp->dccps_role = DCCP_ROLE_UNDEFINED;
191 dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT; 191 dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
192 dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; 192 dp->dccps_tx_qlen = sysctl_dccp_tx_qlen;
193 193
194 dccp_init_xmit_timers(sk); 194 dccp_init_xmit_timers(sk);
195 195
196 /* 196 INIT_LIST_HEAD(&dp->dccps_featneg);
197 * FIXME: We're hardcoding the CCID, and doing this at this point makes 197 /* control socket doesn't need feat nego */
198 * the listening (master) sock get CCID control blocks, which is not 198 if (likely(ctl_sock_initialized))
199 * necessary, but for now, to not mess with the test userspace apps, 199 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; 200 return 0;
236} 201}
237 202
@@ -240,7 +205,6 @@ EXPORT_SYMBOL_GPL(dccp_init_sock);
240void dccp_destroy_sock(struct sock *sk) 205void dccp_destroy_sock(struct sock *sk)
241{ 206{
242 struct dccp_sock *dp = dccp_sk(sk); 207 struct dccp_sock *dp = dccp_sk(sk);
243 struct dccp_minisock *dmsk = dccp_msk(sk);
244 208
245 /* 209 /*
246 * DCCP doesn't use sk_write_queue, just sk_send_head 210 * DCCP doesn't use sk_write_queue, just sk_send_head
@@ -258,7 +222,7 @@ void dccp_destroy_sock(struct sock *sk)
258 kfree(dp->dccps_service_list); 222 kfree(dp->dccps_service_list);
259 dp->dccps_service_list = NULL; 223 dp->dccps_service_list = NULL;
260 224
261 if (dmsk->dccpms_send_ack_vector) { 225 if (dp->dccps_hc_rx_ackvec != NULL) {
262 dccp_ackvec_free(dp->dccps_hc_rx_ackvec); 226 dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
263 dp->dccps_hc_rx_ackvec = NULL; 227 dp->dccps_hc_rx_ackvec = NULL;
264 } 228 }
@@ -267,7 +231,7 @@ void dccp_destroy_sock(struct sock *sk)
267 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; 231 dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
268 232
269 /* clean up feature negotiation state */ 233 /* clean up feature negotiation state */
270 dccp_feat_clean(dmsk); 234 dccp_feat_list_purge(&dp->dccps_featneg);
271} 235}
272 236
273EXPORT_SYMBOL_GPL(dccp_destroy_sock); 237EXPORT_SYMBOL_GPL(dccp_destroy_sock);
@@ -277,6 +241,9 @@ static inline int dccp_listen_start(struct sock *sk, int backlog)
277 struct dccp_sock *dp = dccp_sk(sk); 241 struct dccp_sock *dp = dccp_sk(sk);
278 242
279 dp->dccps_role = DCCP_ROLE_LISTEN; 243 dp->dccps_role = DCCP_ROLE_LISTEN;
244 /* do not start to listen if feature negotiation setup fails */
245 if (dccp_feat_finalise_settings(dp))
246 return -EPROTO;
280 return inet_csk_listen_start(sk, backlog); 247 return inet_csk_listen_start(sk, backlog);
281} 248}
282 249
@@ -466,42 +433,70 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
466 return 0; 433 return 0;
467} 434}
468 435
469/* byte 1 is feature. the rest is the preference list */ 436static 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{ 437{
473 struct dccp_so_feat opt; 438 u8 *list, len;
474 u8 *val; 439 int i, rc;
475 int rc;
476 440
477 if (copy_from_user(&opt, optval, sizeof(opt))) 441 if (cscov < 0 || cscov > 15)
478 return -EFAULT; 442 return -EINVAL;
479 /* 443 /*
480 * rfc4340: 6.1. Change Options 444 * Populate a list of permissible values, in the range cscov...15. This
445 * is necessary since feature negotiation of single values only works if
446 * both sides incidentally choose the same value. Since the list starts
447 * lowest-value first, negotiation will pick the smallest shared value.
481 */ 448 */
482 if (opt.dccpsf_len < 1) 449 if (cscov == 0)
450 return 0;
451 len = 16 - cscov;
452
453 list = kmalloc(len, GFP_KERNEL);
454 if (list == NULL)
455 return -ENOBUFS;
456
457 for (i = 0; i < len; i++)
458 list[i] = cscov++;
459
460 rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
461
462 if (rc == 0) {
463 if (rx)
464 dccp_sk(sk)->dccps_pcrlen = cscov;
465 else
466 dccp_sk(sk)->dccps_pcslen = cscov;
467 }
468 kfree(list);
469 return rc;
470}
471
472static int dccp_setsockopt_ccid(struct sock *sk, int type,
473 char __user *optval, int optlen)
474{
475 u8 *val;
476 int rc = 0;
477
478 if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
483 return -EINVAL; 479 return -EINVAL;
484 480
485 val = kmalloc(opt.dccpsf_len, GFP_KERNEL); 481 val = kmalloc(optlen, GFP_KERNEL);
486 if (!val) 482 if (val == NULL)
487 return -ENOMEM; 483 return -ENOMEM;
488 484
489 if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) { 485 if (copy_from_user(val, optval, optlen)) {
490 rc = -EFAULT; 486 kfree(val);
491 goto out_free_val; 487 return -EFAULT;
492 } 488 }
493 489
494 rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat, 490 lock_sock(sk);
495 val, opt.dccpsf_len, GFP_KERNEL); 491 if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
496 if (rc) 492 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
497 goto out_free_val;
498 493
499out: 494 if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
500 return rc; 495 rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
496 release_sock(sk);
501 497
502out_free_val:
503 kfree(val); 498 kfree(val);
504 goto out; 499 return rc;
505} 500}
506 501
507static int do_dccp_setsockopt(struct sock *sk, int level, int optname, 502static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
@@ -510,7 +505,21 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
510 struct dccp_sock *dp = dccp_sk(sk); 505 struct dccp_sock *dp = dccp_sk(sk);
511 int val, err = 0; 506 int val, err = 0;
512 507
513 if (optlen < sizeof(int)) 508 switch (optname) {
509 case DCCP_SOCKOPT_PACKET_SIZE:
510 DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
511 return 0;
512 case DCCP_SOCKOPT_CHANGE_L:
513 case DCCP_SOCKOPT_CHANGE_R:
514 DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
515 return 0;
516 case DCCP_SOCKOPT_CCID:
517 case DCCP_SOCKOPT_RX_CCID:
518 case DCCP_SOCKOPT_TX_CCID:
519 return dccp_setsockopt_ccid(sk, optname, optval, optlen);
520 }
521
522 if (optlen < (int)sizeof(int))
514 return -EINVAL; 523 return -EINVAL;
515 524
516 if (get_user(val, (int __user *)optval)) 525 if (get_user(val, (int __user *)optval))
@@ -521,53 +530,38 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
521 530
522 lock_sock(sk); 531 lock_sock(sk);
523 switch (optname) { 532 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: 533 case DCCP_SOCKOPT_SERVER_TIMEWAIT:
545 if (dp->dccps_role != DCCP_ROLE_SERVER) 534 if (dp->dccps_role != DCCP_ROLE_SERVER)
546 err = -EOPNOTSUPP; 535 err = -EOPNOTSUPP;
547 else 536 else
548 dp->dccps_server_timewait = (val != 0); 537 dp->dccps_server_timewait = (val != 0);
549 break; 538 break;
550 case DCCP_SOCKOPT_SEND_CSCOV: /* sender side, RFC 4340, sec. 9.2 */ 539 case DCCP_SOCKOPT_SEND_CSCOV:
551 if (val < 0 || val > 15) 540 err = dccp_setsockopt_cscov(sk, val, false);
541 break;
542 case DCCP_SOCKOPT_RECV_CSCOV:
543 err = dccp_setsockopt_cscov(sk, val, true);
544 break;
545 case DCCP_SOCKOPT_QPOLICY_ID:
546 if (sk->sk_state != DCCP_CLOSED)
547 err = -EISCONN;
548 else if (val < 0 || val >= DCCPQ_POLICY_MAX)
552 err = -EINVAL; 549 err = -EINVAL;
553 else 550 else
554 dp->dccps_pcslen = val; 551 dp->dccps_qpolicy = val;
555 break; 552 break;
556 case DCCP_SOCKOPT_RECV_CSCOV: /* receiver side, RFC 4340 sec. 9.2.1 */ 553 case DCCP_SOCKOPT_QPOLICY_TXQLEN:
557 if (val < 0 || val > 15) 554 if (val < 0)
558 err = -EINVAL; 555 err = -EINVAL;
559 else { 556 else
560 dp->dccps_pcrlen = val; 557 dp->dccps_tx_qlen = val;
561 /* FIXME: add feature negotiation,
562 * ChangeL(MinimumChecksumCoverage, val) */
563 }
564 break; 558 break;
565 default: 559 default:
566 err = -ENOPROTOOPT; 560 err = -ENOPROTOOPT;
567 break; 561 break;
568 } 562 }
569
570 release_sock(sk); 563 release_sock(sk);
564
571 return err; 565 return err;
572} 566}
573 567
@@ -648,6 +642,18 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
648 case DCCP_SOCKOPT_GET_CUR_MPS: 642 case DCCP_SOCKOPT_GET_CUR_MPS:
649 val = dp->dccps_mss_cache; 643 val = dp->dccps_mss_cache;
650 break; 644 break;
645 case DCCP_SOCKOPT_AVAILABLE_CCIDS:
646 return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
647 case DCCP_SOCKOPT_TX_CCID:
648 val = ccid_get_current_tx_ccid(dp);
649 if (val < 0)
650 return -ENOPROTOOPT;
651 break;
652 case DCCP_SOCKOPT_RX_CCID:
653 val = ccid_get_current_rx_ccid(dp);
654 if (val < 0)
655 return -ENOPROTOOPT;
656 break;
651 case DCCP_SOCKOPT_SERVER_TIMEWAIT: 657 case DCCP_SOCKOPT_SERVER_TIMEWAIT:
652 val = dp->dccps_server_timewait; 658 val = dp->dccps_server_timewait;
653 break; 659 break;
@@ -657,6 +663,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
657 case DCCP_SOCKOPT_RECV_CSCOV: 663 case DCCP_SOCKOPT_RECV_CSCOV:
658 val = dp->dccps_pcrlen; 664 val = dp->dccps_pcrlen;
659 break; 665 break;
666 case DCCP_SOCKOPT_QPOLICY_ID:
667 val = dp->dccps_qpolicy;
668 break;
669 case DCCP_SOCKOPT_QPOLICY_TXQLEN:
670 val = dp->dccps_tx_qlen;
671 break;
660 case 128 ... 191: 672 case 128 ... 191:
661 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, 673 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
662 len, (u32 __user *)optval, optlen); 674 len, (u32 __user *)optval, optlen);
@@ -699,6 +711,47 @@ int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
699EXPORT_SYMBOL_GPL(compat_dccp_getsockopt); 711EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
700#endif 712#endif
701 713
714static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb)
715{
716 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
717
718 /*
719 * Assign an (opaque) qpolicy priority value to skb->priority.
720 *
721 * We are overloading this skb field for use with the qpolicy subystem.
722 * The skb->priority is normally used for the SO_PRIORITY option, which
723 * is initialised from sk_priority. Since the assignment of sk_priority
724 * to skb->priority happens later (on layer 3), we overload this field
725 * for use with queueing priorities as long as the skb is on layer 4.
726 * The default priority value (if nothing is set) is 0.
727 */
728 skb->priority = 0;
729
730 for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
731
732 if (!CMSG_OK(msg, cmsg))
733 return -EINVAL;
734
735 if (cmsg->cmsg_level != SOL_DCCP)
736 continue;
737
738 if (cmsg->cmsg_type <= DCCP_SCM_QPOLICY_MAX &&
739 !dccp_qpolicy_param_ok(skb->sk, cmsg->cmsg_type))
740 return -EINVAL;
741
742 switch (cmsg->cmsg_type) {
743 case DCCP_SCM_PRIORITY:
744 if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u32)))
745 return -EINVAL;
746 skb->priority = *(__u32 *)CMSG_DATA(cmsg);
747 break;
748 default:
749 return -EINVAL;
750 }
751 }
752 return 0;
753}
754
702int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 755int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
703 size_t len) 756 size_t len)
704{ 757{
@@ -714,8 +767,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
714 767
715 lock_sock(sk); 768 lock_sock(sk);
716 769
717 if (sysctl_dccp_tx_qlen && 770 if (dccp_qpolicy_full(sk)) {
718 (sk->sk_write_queue.qlen >= sysctl_dccp_tx_qlen)) {
719 rc = -EAGAIN; 771 rc = -EAGAIN;
720 goto out_release; 772 goto out_release;
721 } 773 }
@@ -743,8 +795,12 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
743 if (rc != 0) 795 if (rc != 0)
744 goto out_discard; 796 goto out_discard;
745 797
746 skb_queue_tail(&sk->sk_write_queue, skb); 798 rc = dccp_msghdr_parse(msg, skb);
747 dccp_write_xmit(sk,0); 799 if (rc != 0)
800 goto out_discard;
801
802 dccp_qpolicy_push(sk, skb);
803 dccp_write_xmit(sk);
748out_release: 804out_release:
749 release_sock(sk); 805 release_sock(sk);
750 return rc ? : len; 806 return rc ? : len;
@@ -967,9 +1023,22 @@ void dccp_close(struct sock *sk, long timeout)
967 /* Check zero linger _after_ checking for unread data. */ 1023 /* Check zero linger _after_ checking for unread data. */
968 sk->sk_prot->disconnect(sk, 0); 1024 sk->sk_prot->disconnect(sk, 0);
969 } else if (sk->sk_state != DCCP_CLOSED) { 1025 } else if (sk->sk_state != DCCP_CLOSED) {
1026 /*
1027 * Normal connection termination. May need to wait if there are
1028 * still packets in the TX queue that are delayed by the CCID.
1029 */
1030 dccp_flush_write_queue(sk, &timeout);
970 dccp_terminate_connection(sk); 1031 dccp_terminate_connection(sk);
971 } 1032 }
972 1033
1034 /*
1035 * Flush write queue. This may be necessary in several cases:
1036 * - we have been closed by the peer but still have application data;
1037 * - abortive termination (unread data or zero linger time),
1038 * - normal termination but queue could not be flushed within time limit
1039 */
1040 __skb_queue_purge(&sk->sk_write_queue);
1041
973 sk_stream_wait_close(sk, timeout); 1042 sk_stream_wait_close(sk, timeout);
974 1043
975adjudge_to_death: 1044adjudge_to_death: