]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/dccp/proto.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / net / dccp / proto.c
index ef343d53fcea22edf7d7bb2be677f349ec63f547..152975d942d9a59a7c26756d0f22419b9e298425 100644 (file)
@@ -185,6 +185,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
        dp->dccps_role          = DCCP_ROLE_UNDEFINED;
        dp->dccps_service       = DCCP_SERVICE_CODE_IS_ABSENT;
        dp->dccps_l_ack_ratio   = dp->dccps_r_ack_ratio = 1;
+       dp->dccps_tx_qlen       = sysctl_dccp_tx_qlen;
 
        dccp_init_xmit_timers(sk);
 
@@ -532,6 +533,20 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
        case DCCP_SOCKOPT_RECV_CSCOV:
                err = dccp_setsockopt_cscov(sk, val, true);
                break;
+       case DCCP_SOCKOPT_QPOLICY_ID:
+               if (sk->sk_state != DCCP_CLOSED)
+                       err = -EISCONN;
+               else if (val < 0 || val >= DCCPQ_POLICY_MAX)
+                       err = -EINVAL;
+               else
+                       dp->dccps_qpolicy = val;
+               break;
+       case DCCP_SOCKOPT_QPOLICY_TXQLEN:
+               if (val < 0)
+                       err = -EINVAL;
+               else
+                       dp->dccps_tx_qlen = val;
+               break;
        default:
                err = -ENOPROTOOPT;
                break;
@@ -639,6 +654,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
        case DCCP_SOCKOPT_RECV_CSCOV:
                val = dp->dccps_pcrlen;
                break;
+       case DCCP_SOCKOPT_QPOLICY_ID:
+               val = dp->dccps_qpolicy;
+               break;
+       case DCCP_SOCKOPT_QPOLICY_TXQLEN:
+               val = dp->dccps_tx_qlen;
+               break;
        case 128 ... 191:
                return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
                                             len, (u32 __user *)optval, optlen);
@@ -681,6 +702,47 @@ int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
 EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
 #endif
 
+static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb)
+{
+       struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+
+       /*
+        * Assign an (opaque) qpolicy priority value to skb->priority.
+        *
+        * We are overloading this skb field for use with the qpolicy subystem.
+        * The skb->priority is normally used for the SO_PRIORITY option, which
+        * is initialised from sk_priority. Since the assignment of sk_priority
+        * to skb->priority happens later (on layer 3), we overload this field
+        * for use with queueing priorities as long as the skb is on layer 4.
+        * The default priority value (if nothing is set) is 0.
+        */
+       skb->priority = 0;
+
+       for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+
+               if (!CMSG_OK(msg, cmsg))
+                       return -EINVAL;
+
+               if (cmsg->cmsg_level != SOL_DCCP)
+                       continue;
+
+               if (cmsg->cmsg_type <= DCCP_SCM_QPOLICY_MAX &&
+                   !dccp_qpolicy_param_ok(skb->sk, cmsg->cmsg_type))
+                       return -EINVAL;
+
+               switch (cmsg->cmsg_type) {
+               case DCCP_SCM_PRIORITY:
+                       if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u32)))
+                               return -EINVAL;
+                       skb->priority = *(__u32 *)CMSG_DATA(cmsg);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
 int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                 size_t len)
 {
@@ -696,8 +758,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
        lock_sock(sk);
 
-       if (sysctl_dccp_tx_qlen &&
-           (sk->sk_write_queue.qlen >= sysctl_dccp_tx_qlen)) {
+       if (dccp_qpolicy_full(sk)) {
                rc = -EAGAIN;
                goto out_release;
        }
@@ -725,7 +786,11 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        if (rc != 0)
                goto out_discard;
 
-       skb_queue_tail(&sk->sk_write_queue, skb);
+       rc = dccp_msghdr_parse(msg, skb);
+       if (rc != 0)
+               goto out_discard;
+
+       dccp_qpolicy_push(sk, skb);
        /*
         * The xmit_timer is set if the TX CCID is rate-based and will expire
         * when congestion control permits to release further packets into the