dccp: Set per-connection CCIDs via socket options
[safe/jmp/linux-2.6] / net / dccp / proto.c
index 8b63394..445884c 100644 (file)
@@ -501,6 +501,36 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
        return rc;
 }
 
+static int dccp_setsockopt_ccid(struct sock *sk, int type,
+                               char __user *optval, int optlen)
+{
+       u8 *val;
+       int rc = 0;
+
+       if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
+               return -EINVAL;
+
+       val = kmalloc(optlen, GFP_KERNEL);
+       if (val == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(val, optval, optlen)) {
+               kfree(val);
+               return -EFAULT;
+       }
+
+       lock_sock(sk);
+       if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
+               rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
+
+       if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
+               rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
+       release_sock(sk);
+
+       kfree(val);
+       return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
                char __user *optval, int optlen)
 {
@@ -515,6 +545,10 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
        case DCCP_SOCKOPT_CHANGE_R:
                DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
                return 0;
+       case DCCP_SOCKOPT_CCID:
+       case DCCP_SOCKOPT_RX_CCID:
+       case DCCP_SOCKOPT_TX_CCID:
+               return dccp_setsockopt_ccid(sk, optname, optval, optlen);
        }
 
        if (optlen < (int)sizeof(int))