]> err.no Git - linux-2.6/blobdiff - net/dccp/proto.c
Manual merge with Linus.
[linux-2.6] / net / dccp / proto.c
index ef94b0c8a0c097e9e631aa8b6fcdf936d24a38bc..1ff7328b0e170bf137819ab03a76b3a4acdd9572 100644 (file)
@@ -53,6 +53,58 @@ struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
 
 EXPORT_SYMBOL_GPL(dccp_hashinfo);
 
+void dccp_set_state(struct sock *sk, const int state)
+{
+       const int oldstate = sk->sk_state;
+
+       dccp_pr_debug("%s(%p) %-10.10s -> %s\n",
+                     dccp_role(sk), sk,
+                     dccp_state_name(oldstate), dccp_state_name(state));
+       WARN_ON(state == oldstate);
+
+       switch (state) {
+       case DCCP_OPEN:
+               if (oldstate != DCCP_OPEN)
+                       DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
+               break;
+
+       case DCCP_CLOSED:
+               if (oldstate == DCCP_CLOSING || oldstate == DCCP_OPEN)
+                       DCCP_INC_STATS(DCCP_MIB_ESTABRESETS);
+
+               sk->sk_prot->unhash(sk);
+               if (inet_csk(sk)->icsk_bind_hash != NULL &&
+                   !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
+                       inet_put_port(&dccp_hashinfo, sk);
+               /* fall through */
+       default:
+               if (oldstate == DCCP_OPEN)
+                       DCCP_DEC_STATS(DCCP_MIB_CURRESTAB);
+       }
+
+       /* Change state AFTER socket is unhashed to avoid closed
+        * socket sitting in hash tables.
+        */
+       sk->sk_state = state;
+}
+
+EXPORT_SYMBOL_GPL(dccp_set_state);
+
+void dccp_done(struct sock *sk)
+{
+       dccp_set_state(sk, DCCP_CLOSED);
+       dccp_clear_xmit_timers(sk);
+
+       sk->sk_shutdown = SHUTDOWN_MASK;
+
+       if (!sock_flag(sk, SOCK_DEAD))
+               sk->sk_state_change(sk);
+       else
+               inet_csk_destroy_sock(sk);
+}
+
+EXPORT_SYMBOL_GPL(dccp_done);
+
 const char *dccp_packet_name(const int type)
 {
        static const char *dccp_packet_names[] = {
@@ -111,13 +163,13 @@ void dccp_unhash(struct sock *sk)
 
 EXPORT_SYMBOL_GPL(dccp_unhash);
 
-int dccp_init_sock(struct sock *sk)
+int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 {
        struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
-       static int dccp_ctl_socket_init = 1;
 
-       dccp_options_init(&dp->dccps_options);
+       dccp_minisock_init(&dp->dccps_minisock);
        do_gettimeofday(&dp->dccps_epoch);
 
        /*
@@ -127,28 +179,26 @@ int dccp_init_sock(struct sock *sk)
         * lets leave it here, later the real solution is to do this in a
         * setsockopt(CCIDs-I-want/accept). -acme
         */
-       if (likely(!dccp_ctl_socket_init)) {
-               int rc = dccp_feat_init(sk);
+       if (likely(ctl_sock_initialized)) {
+               int rc = dccp_feat_init(dmsk);
 
                if (rc)
                        return rc;
 
-               if (dp->dccps_options.dccpo_send_ack_vector) {
+               if (dmsk->dccpms_send_ack_vector) {
                        dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
                        if (dp->dccps_hc_rx_ackvec == NULL)
                                return -ENOMEM;
                }
-               dp->dccps_hc_rx_ccid =
-                               ccid_hc_rx_new(dp->dccps_options.dccpo_rx_ccid,
-                                              sk, GFP_KERNEL);
-               dp->dccps_hc_tx_ccid =
-                               ccid_hc_tx_new(dp->dccps_options.dccpo_tx_ccid,
-                                              sk, GFP_KERNEL);
+               dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid,
+                                                     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 ||
                             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);
-                       if (dp->dccps_options.dccpo_send_ack_vector) {
+                       if (dmsk->dccpms_send_ack_vector) {
                                dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
                                dp->dccps_hc_rx_ackvec = NULL;
                        }
@@ -157,9 +207,8 @@ int dccp_init_sock(struct sock *sk)
                }
        } else {
                /* control socket doesn't need feat nego */
-               INIT_LIST_HEAD(&dp->dccps_options.dccpo_pending);
-               INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
-               dccp_ctl_socket_init = 0;
+               INIT_LIST_HEAD(&dmsk->dccpms_pending);
+               INIT_LIST_HEAD(&dmsk->dccpms_conf);
        }
 
        dccp_init_xmit_timers(sk);
@@ -180,6 +229,7 @@ EXPORT_SYMBOL_GPL(dccp_init_sock);
 int dccp_destroy_sock(struct sock *sk)
 {
        struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
 
        /*
         * DCCP doesn't use sk_write_queue, just sk_send_head
@@ -197,7 +247,7 @@ int dccp_destroy_sock(struct sock *sk)
        kfree(dp->dccps_service_list);
        dp->dccps_service_list = NULL;
 
-       if (dp->dccps_options.dccpo_send_ack_vector) {
+       if (dmsk->dccpms_send_ack_vector) {
                dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
                dp->dccps_hc_rx_ackvec = NULL;
        }
@@ -206,7 +256,7 @@ int dccp_destroy_sock(struct sock *sk)
        dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
        /* clean up feature negotiation state */
-       dccp_feat_clean(sk);
+       dccp_feat_clean(dmsk);
 
        return 0;
 }
@@ -300,7 +350,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
        if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
                mask |= POLLHUP;
        if (sk->sk_shutdown & RCV_SHUTDOWN)
-               mask |= POLLIN | POLLRDNORM;
+               mask |= POLLIN | POLLRDNORM | POLLRDHUP;
 
        /* Connected? */
        if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
@@ -392,8 +442,8 @@ static int dccp_setsockopt_change(struct sock *sk, int type,
                goto out_free_val;
        }
 
-       rc = dccp_feat_change(sk, type, opt.dccpsf_feat, val, opt.dccpsf_len,
-                             GFP_KERNEL);
+       rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat,
+                             val, opt.dccpsf_len, GFP_KERNEL);
        if (rc)
                goto out_free_val;
 
@@ -405,18 +455,13 @@ out_free_val:
        goto out;
 }
 
-int dccp_setsockopt(struct sock *sk, int level, int optname,
-                   char __user *optval, int optlen)
+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;
 
-       if (level != SOL_DCCP)
-               return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
-                                                            optname, optval,
-                                                            optlen);
-
        if (optlen < sizeof(int))
                return -EINVAL;
 
@@ -462,8 +507,31 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
        return err;
 }
 
+int dccp_setsockopt(struct sock *sk, int level, int optname,
+                   char __user *optval, int optlen)
+{
+       if (level != SOL_DCCP)
+               return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
+                                                            optname, optval,
+                                                            optlen);
+       return do_dccp_setsockopt(sk, level, optname, optval, optlen);
+}
+
 EXPORT_SYMBOL_GPL(dccp_setsockopt);
 
+#ifdef CONFIG_COMPAT
+int compat_dccp_setsockopt(struct sock *sk, int level, int optname,
+                          char __user *optval, int optlen)
+{
+       if (level != SOL_DCCP)
+               return inet_csk_compat_setsockopt(sk, level, optname,
+                                                 optval, optlen);
+       return do_dccp_setsockopt(sk, level, optname, optval, optlen);
+}
+
+EXPORT_SYMBOL_GPL(compat_dccp_setsockopt);
+#endif
+
 static int dccp_getsockopt_service(struct sock *sk, int len,
                                   __be32 __user *optval,
                                   int __user *optlen)
@@ -495,16 +563,12 @@ out:
        return err;
 }
 
-int dccp_getsockopt(struct sock *sk, int level, int optname,
+static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
                    char __user *optval, int __user *optlen)
 {
        struct dccp_sock *dp;
        int val, len;
 
-       if (level != SOL_DCCP)
-               return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
-                                                            optname, optval,
-                                                            optlen);
        if (get_user(len, optlen))
                return -EFAULT;
 
@@ -537,8 +601,31 @@ int dccp_getsockopt(struct sock *sk, int level, int optname,
        return 0;
 }
 
+int dccp_getsockopt(struct sock *sk, int level, int optname,
+                   char __user *optval, int __user *optlen)
+{
+       if (level != SOL_DCCP)
+               return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
+                                                            optname, optval,
+                                                            optlen);
+       return do_dccp_getsockopt(sk, level, optname, optval, optlen);
+}
+
 EXPORT_SYMBOL_GPL(dccp_getsockopt);
 
+#ifdef CONFIG_COMPAT
+int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
+                          char __user *optval, int __user *optlen)
+{
+       if (level != SOL_DCCP)
+               return inet_csk_compat_getsockopt(sk, level, optname,
+                                                 optval, optlen);
+       return do_dccp_getsockopt(sk, level, optname, optval, optlen);
+}
+
+EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
+#endif
+
 int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                 size_t len)
 {