[DCCP]: Send Reset upon Sync in state REQUEST
[safe/jmp/linux-2.6] / net / dccp / proto.c
index 047d170..14ec1d2 100644 (file)
@@ -52,6 +52,9 @@ struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
 
 EXPORT_SYMBOL_GPL(dccp_hashinfo);
 
+/* the maximum queue length for tx in packets. 0 is no limit */
+int sysctl_dccp_tx_qlen __read_mostly = 5;
+
 void dccp_set_state(struct sock *sk, const int state)
 {
        const int oldstate = sk->sk_state;
@@ -169,7 +172,6 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
        struct inet_connection_sock *icsk = inet_csk(sk);
 
        dccp_minisock_init(&dp->dccps_minisock);
-       do_gettimeofday(&dp->dccps_epoch);
 
        /*
         * FIXME: We're hardcoding the CCID, and doing this at this point makes
@@ -193,7 +195,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
                                                      sk, GFP_KERNEL);
                dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
                                                      sk, GFP_KERNEL);
-               if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
+               if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
                             dp->dccps_hc_tx_ccid == NULL)) {
                        ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
                        ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
@@ -212,6 +214,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 
        dccp_init_xmit_timers(sk);
        icsk->icsk_rto          = DCCP_TIMEOUT_INIT;
+       icsk->icsk_syn_retries  = sysctl_dccp_request_retries;
        sk->sk_state            = DCCP_CLOSED;
        sk->sk_write_space      = dccp_write_space;
        icsk->icsk_sync_mss     = dccp_sync_mss;
@@ -386,7 +389,7 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
        struct dccp_sock *dp = dccp_sk(sk);
        struct dccp_service_list *sl = NULL;
 
-       if (service == DCCP_SERVICE_INVALID_VALUE || 
+       if (service == DCCP_SERVICE_INVALID_VALUE ||
            optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32))
                return -EINVAL;
 
@@ -451,9 +454,8 @@ out_free_val:
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
                char __user *optval, int optlen)
 {
-       struct dccp_sock *dp;
-       int err;
-       int val;
+       struct dccp_sock *dp = dccp_sk(sk);
+       int val, err = 0;
 
        if (optlen < sizeof(int))
                return -EINVAL;
@@ -465,23 +467,19 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
                return dccp_setsockopt_service(sk, val, optval, optlen);
 
        lock_sock(sk);
-       dp = dccp_sk(sk);
-       err = 0;
-
        switch (optname) {
        case DCCP_SOCKOPT_PACKET_SIZE:
-               dp->dccps_packet_size = val;
+               DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
+               err = 0;
                break;
-
        case DCCP_SOCKOPT_CHANGE_L:
                if (optlen != sizeof(struct dccp_so_feat))
                        err = -EINVAL;
                else
                        err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
-                                                    (struct dccp_so_feat __user *)
+                                                    (struct dccp_so_feat __user *)
                                                     optval);
                break;
-
        case DCCP_SOCKOPT_CHANGE_R:
                if (optlen != sizeof(struct dccp_so_feat))
                        err = -EINVAL;
@@ -490,12 +488,26 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
                                                     (struct dccp_so_feat __user *)
                                                     optval);
                break;
-
+       case DCCP_SOCKOPT_SEND_CSCOV:   /* sender side, RFC 4340, sec. 9.2 */
+               if (val < 0 || val > 15)
+                       err = -EINVAL;
+               else
+                       dp->dccps_pcslen = val;
+               break;
+       case DCCP_SOCKOPT_RECV_CSCOV:   /* receiver side, RFC 4340 sec. 9.2.1 */
+               if (val < 0 || val > 15)
+                       err = -EINVAL;
+               else {
+                       dp->dccps_pcrlen = val;
+                       /* FIXME: add feature negotiation,
+                        * ChangeL(MinimumChecksumCoverage, val) */
+               }
+               break;
        default:
                err = -ENOPROTOOPT;
                break;
        }
-       
+
        release_sock(sk);
        return err;
 }
@@ -562,19 +574,26 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
        if (get_user(len, optlen))
                return -EFAULT;
 
-       if (len < sizeof(int))
+       if (len < (int)sizeof(int))
                return -EINVAL;
 
        dp = dccp_sk(sk);
 
        switch (optname) {
        case DCCP_SOCKOPT_PACKET_SIZE:
-               val = dp->dccps_packet_size;
-               len = sizeof(dp->dccps_packet_size);
-               break;
+               DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
+               return 0;
        case DCCP_SOCKOPT_SERVICE:
                return dccp_getsockopt_service(sk, len,
                                               (__be32 __user *)optval, optlen);
+       case DCCP_SOCKOPT_SEND_CSCOV:
+               val = dp->dccps_pcslen;
+               len = sizeof(val);
+               break;
+       case DCCP_SOCKOPT_RECV_CSCOV:
+               val = dp->dccps_pcrlen;
+               len = sizeof(val);
+               break;
        case 128 ... 191:
                return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
                                             len, (u32 __user *)optval, optlen);
@@ -630,6 +649,13 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                return -EMSGSIZE;
 
        lock_sock(sk);
+
+       if (sysctl_dccp_tx_qlen &&
+           (sk->sk_write_queue.qlen >= sysctl_dccp_tx_qlen)) {
+               rc = -EAGAIN;
+               goto out_release;
+       }
+
        timeo = sock_sndtimeo(sk, noblock);
 
        /*
@@ -805,7 +831,7 @@ EXPORT_SYMBOL_GPL(inet_dccp_listen);
 static const unsigned char dccp_new_state[] = {
        /* current state:   new state:      action:     */
        [0]               = DCCP_CLOSED,
-       [DCCP_OPEN]       = DCCP_CLOSING | DCCP_ACTION_FIN,
+       [DCCP_OPEN]       = DCCP_CLOSING | DCCP_ACTION_FIN,
        [DCCP_REQUESTING] = DCCP_CLOSED,
        [DCCP_PARTOPEN]   = DCCP_CLOSING | DCCP_ACTION_FIN,
        [DCCP_LISTEN]     = DCCP_CLOSED,
@@ -976,7 +1002,7 @@ static int __init dccp_init(void)
        dccp_hashinfo.bind_bucket_cachep =
                kmem_cache_create("dccp_bind_bucket",
                                  sizeof(struct inet_bind_bucket), 0,
-                                 SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                 SLAB_HWCACHE_ALIGN, NULL);
        if (!dccp_hashinfo.bind_bucket_cachep)
                goto out;
 
@@ -999,7 +1025,6 @@ static int __init dccp_init(void)
        do {
                dccp_hashinfo.ehash_size = (1UL << ehash_order) * PAGE_SIZE /
                                        sizeof(struct inet_ehash_bucket);
-               dccp_hashinfo.ehash_size >>= 1;
                while (dccp_hashinfo.ehash_size &
                       (dccp_hashinfo.ehash_size - 1))
                        dccp_hashinfo.ehash_size--;
@@ -1008,14 +1033,14 @@ static int __init dccp_init(void)
        } while (!dccp_hashinfo.ehash && --ehash_order > 0);
 
        if (!dccp_hashinfo.ehash) {
-               printk(KERN_CRIT "Failed to allocate DCCP "
-                                "established hash table\n");
+               DCCP_CRIT("Failed to allocate DCCP established hash table");
                goto out_free_bind_bucket_cachep;
        }
 
-       for (i = 0; i < (dccp_hashinfo.ehash_size << 1); i++) {
+       for (i = 0; i < dccp_hashinfo.ehash_size; i++) {
                rwlock_init(&dccp_hashinfo.ehash[i].lock);
                INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].chain);
+               INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].twchain);
        }
 
        bhash_order = ehash_order;
@@ -1031,7 +1056,7 @@ static int __init dccp_init(void)
        } while (!dccp_hashinfo.bhash && --bhash_order >= 0);
 
        if (!dccp_hashinfo.bhash) {
-               printk(KERN_CRIT "Failed to allocate DCCP bind hash table\n");
+               DCCP_CRIT("Failed to allocate DCCP bind hash table");
                goto out_free_dccp_ehash;
        }
 
@@ -1051,6 +1076,8 @@ static int __init dccp_init(void)
        rc = dccp_sysctl_init();
        if (rc)
                goto out_ackvec_exit;
+
+       dccp_timestamping_init();
 out:
        return rc;
 out_ackvec_exit: