diff options
Diffstat (limited to 'net/dccp/proto.c')
-rw-r--r-- | net/dccp/proto.c | 67 |
1 files changed, 64 insertions, 3 deletions
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index ef343d53fcea..d6a224982bb5 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -185,6 +185,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) | |||
185 | dp->dccps_role = DCCP_ROLE_UNDEFINED; | 185 | dp->dccps_role = DCCP_ROLE_UNDEFINED; |
186 | dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT; | 186 | dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT; |
187 | dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; | 187 | dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; |
188 | dp->dccps_tx_qlen = sysctl_dccp_tx_qlen; | ||
188 | 189 | ||
189 | dccp_init_xmit_timers(sk); | 190 | dccp_init_xmit_timers(sk); |
190 | 191 | ||
@@ -532,6 +533,20 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, | |||
532 | case DCCP_SOCKOPT_RECV_CSCOV: | 533 | case DCCP_SOCKOPT_RECV_CSCOV: |
533 | err = dccp_setsockopt_cscov(sk, val, true); | 534 | err = dccp_setsockopt_cscov(sk, val, true); |
534 | break; | 535 | break; |
536 | case DCCP_SOCKOPT_QPOLICY_ID: | ||
537 | if (sk->sk_state != DCCP_CLOSED) | ||
538 | err = -EISCONN; | ||
539 | else if (val < 0 || val >= DCCPQ_POLICY_MAX) | ||
540 | err = -EINVAL; | ||
541 | else | ||
542 | dp->dccps_qpolicy = val; | ||
543 | break; | ||
544 | case DCCP_SOCKOPT_QPOLICY_TXQLEN: | ||
545 | if (val < 0) | ||
546 | err = -EINVAL; | ||
547 | else | ||
548 | dp->dccps_tx_qlen = val; | ||
549 | break; | ||
535 | default: | 550 | default: |
536 | err = -ENOPROTOOPT; | 551 | err = -ENOPROTOOPT; |
537 | break; | 552 | break; |
@@ -639,6 +654,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname, | |||
639 | case DCCP_SOCKOPT_RECV_CSCOV: | 654 | case DCCP_SOCKOPT_RECV_CSCOV: |
640 | val = dp->dccps_pcrlen; | 655 | val = dp->dccps_pcrlen; |
641 | break; | 656 | break; |
657 | case DCCP_SOCKOPT_QPOLICY_ID: | ||
658 | val = dp->dccps_qpolicy; | ||
659 | break; | ||
660 | case DCCP_SOCKOPT_QPOLICY_TXQLEN: | ||
661 | val = dp->dccps_tx_qlen; | ||
662 | break; | ||
642 | case 128 ... 191: | 663 | case 128 ... 191: |
643 | return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, | 664 | return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, |
644 | len, (u32 __user *)optval, optlen); | 665 | len, (u32 __user *)optval, optlen); |
@@ -681,6 +702,43 @@ int compat_dccp_getsockopt(struct sock *sk, int level, int optname, | |||
681 | EXPORT_SYMBOL_GPL(compat_dccp_getsockopt); | 702 | EXPORT_SYMBOL_GPL(compat_dccp_getsockopt); |
682 | #endif | 703 | #endif |
683 | 704 | ||
705 | static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb) | ||
706 | { | ||
707 | struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); | ||
708 | |||
709 | /* | ||
710 | * Assign an (opaque) qpolicy priority value to skb->priority. | ||
711 | * | ||
712 | * We are overloading this skb field for use with the qpolicy subystem. | ||
713 | * The skb->priority is normally used for the SO_PRIORITY option, which | ||
714 | * is initialised from sk_priority. Since the assignment of sk_priority | ||
715 | * to skb->priority happens later (on layer 3), we overload this field | ||
716 | * for use with queueing priorities as long as the skb is on layer 4. | ||
717 | * The default priority value (if nothing is set) is 0. | ||
718 | */ | ||
719 | skb->priority = 0; | ||
720 | |||
721 | for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { | ||
722 | |||
723 | if (!CMSG_OK(msg, cmsg)) | ||
724 | return -EINVAL; | ||
725 | |||
726 | if (cmsg->cmsg_level != SOL_DCCP) | ||
727 | continue; | ||
728 | |||
729 | switch (cmsg->cmsg_type) { | ||
730 | case DCCP_SCM_PRIORITY: | ||
731 | if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u32))) | ||
732 | return -EINVAL; | ||
733 | skb->priority = *(__u32 *)CMSG_DATA(cmsg); | ||
734 | break; | ||
735 | default: | ||
736 | return -EINVAL; | ||
737 | } | ||
738 | } | ||
739 | return 0; | ||
740 | } | ||
741 | |||
684 | int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 742 | int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
685 | size_t len) | 743 | size_t len) |
686 | { | 744 | { |
@@ -696,8 +754,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
696 | 754 | ||
697 | lock_sock(sk); | 755 | lock_sock(sk); |
698 | 756 | ||
699 | if (sysctl_dccp_tx_qlen && | 757 | if (dccp_qpolicy_full(sk)) { |
700 | (sk->sk_write_queue.qlen >= sysctl_dccp_tx_qlen)) { | ||
701 | rc = -EAGAIN; | 758 | rc = -EAGAIN; |
702 | goto out_release; | 759 | goto out_release; |
703 | } | 760 | } |
@@ -725,7 +782,11 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
725 | if (rc != 0) | 782 | if (rc != 0) |
726 | goto out_discard; | 783 | goto out_discard; |
727 | 784 | ||
728 | skb_queue_tail(&sk->sk_write_queue, skb); | 785 | rc = dccp_msghdr_parse(msg, skb); |
786 | if (rc != 0) | ||
787 | goto out_discard; | ||
788 | |||
789 | dccp_qpolicy_push(sk, skb); | ||
729 | /* | 790 | /* |
730 | * The xmit_timer is set if the TX CCID is rate-based and will expire | 791 | * The xmit_timer is set if the TX CCID is rate-based and will expire |
731 | * when congestion control permits to release further packets into the | 792 | * when congestion control permits to release further packets into the |