[DCCP] ccid3: Replace scaled division operations
[safe/jmp/linux-2.6] / net / dccp / input.c
index 76c3401..7371a2f 100644 (file)
  *     2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/dccp.h>
 #include <linux/skbuff.h>
 
 #include <net/sock.h>
 
+#include "ackvec.h"
 #include "ccid.h"
 #include "dccp.h"
 
@@ -31,14 +31,10 @@ static void dccp_fin(struct sock *sk, struct sk_buff *skb)
 
 static void dccp_rcv_close(struct sock *sk, struct sk_buff *skb)
 {
-       switch (sk->sk_state) {
-       case DCCP_PARTOPEN:
-       case DCCP_OPEN:
-               dccp_v4_send_reset(sk, DCCP_RESET_CODE_CLOSED);
-               dccp_fin(sk, skb);
-               dccp_set_state(sk, DCCP_CLOSED);
-               break;
-       }
+       dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
+       dccp_fin(sk, skb);
+       dccp_set_state(sk, DCCP_CLOSED);
+       sk_wake_async(sk, 1, POLL_HUP);
 }
 
 static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb)
@@ -50,34 +46,29 @@ static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb)
         *        Drop packet and return
         */
        if (dccp_sk(sk)->dccps_role != DCCP_ROLE_CLIENT) {
-               dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq);
+               dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq, DCCP_PKT_SYNC);
                return;
        }
 
-       switch (sk->sk_state) {
-       case DCCP_PARTOPEN:
-       case DCCP_OPEN:
+       if (sk->sk_state != DCCP_CLOSING)
                dccp_set_state(sk, DCCP_CLOSING);
-               dccp_send_close(sk);
-               break;
-       }
+       dccp_send_close(sk, 0);
 }
 
-static inline void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
+static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
 
-       if (dp->dccps_options.dccpo_send_ack_vector)
-               dccp_ackpkts_check_rcv_ackno(dp->dccps_hc_rx_ackpkts, sk,
-                                            DCCP_SKB_CB(skb)->dccpd_ack_seq);
+       if (dccp_msk(sk)->dccpms_send_ack_vector)
+               dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk,
+                                           DCCP_SKB_CB(skb)->dccpd_ack_seq);
 }
 
 static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
 {
        const struct dccp_hdr *dh = dccp_hdr(skb);
        struct dccp_sock *dp = dccp_sk(sk);
-       u64 lswl = dp->dccps_swl;
-       u64 lawl = dp->dccps_awl;
+       u64 lswl, lawl;
 
        /*
         *   Step 5: Prepare sequence numbers for Sync
@@ -93,11 +84,14 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
         */
        if (dh->dccph_type == DCCP_PKT_SYNC || 
            dh->dccph_type == DCCP_PKT_SYNCACK) {
-               if (between48(DCCP_SKB_CB(skb)->dccpd_ack_seq, dp->dccps_awl, dp->dccps_awh) &&
+               if (between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                             dp->dccps_awl, dp->dccps_awh) &&
                    !before48(DCCP_SKB_CB(skb)->dccpd_seq, dp->dccps_swl))
                        dccp_update_gsr(sk, DCCP_SKB_CB(skb)->dccpd_seq);
                else
                        return -1;
+       }
+       
        /*
         *   Step 6: Check sequence numbers
         *      Let LSWL = S.SWL and LAWL = S.AWL
@@ -112,9 +106,12 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
         *        Send Sync packet acknowledging P.seqno
         *        Drop packet and return
         */
-       } else if (dh->dccph_type == DCCP_PKT_CLOSEREQ ||
-                  dh->dccph_type == DCCP_PKT_CLOSE ||
-                  dh->dccph_type == DCCP_PKT_RESET) {
+       lswl = dp->dccps_swl;
+       lawl = dp->dccps_awl;
+
+       if (dh->dccph_type == DCCP_PKT_CLOSEREQ ||
+           dh->dccph_type == DCCP_PKT_CLOSE ||
+           dh->dccph_type == DCCP_PKT_RESET) {
                lswl = dp->dccps_gsr;
                dccp_inc_seqno(&lswl);
                lawl = dp->dccps_gar;
@@ -122,72 +119,45 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
 
        if (between48(DCCP_SKB_CB(skb)->dccpd_seq, lswl, dp->dccps_swh) &&
            (DCCP_SKB_CB(skb)->dccpd_ack_seq == DCCP_PKT_WITHOUT_ACK_SEQ ||
-            between48(DCCP_SKB_CB(skb)->dccpd_ack_seq, lawl, dp->dccps_awh))) {
+            between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                      lawl, dp->dccps_awh))) {
                dccp_update_gsr(sk, DCCP_SKB_CB(skb)->dccpd_seq);
 
                if (dh->dccph_type != DCCP_PKT_SYNC &&
-                   DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
+                   (DCCP_SKB_CB(skb)->dccpd_ack_seq !=
+                    DCCP_PKT_WITHOUT_ACK_SEQ))
                        dp->dccps_gar = DCCP_SKB_CB(skb)->dccpd_ack_seq;
        } else {
-               dccp_pr_debug("Step 6 failed, sending SYNC...\n");
-               dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq);
+               DCCP_WARN("DCCP: Step 6 failed for %s packet, "
+                         "(LSWL(%llu) <= P.seqno(%llu) <= S.SWH(%llu)) and "
+                         "(P.ackno %s or LAWL(%llu) <= P.ackno(%llu) <= S.AWH(%llu), "
+                         "sending SYNC...\n",  dccp_packet_name(dh->dccph_type),
+                         (unsigned long long) lswl,
+                         (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq,
+                         (unsigned long long) dp->dccps_swh,
+                         (DCCP_SKB_CB(skb)->dccpd_ack_seq ==
+                               DCCP_PKT_WITHOUT_ACK_SEQ) ? "doesn't exist" : "exists",
+                         (unsigned long long) lawl,
+                         (unsigned long long) DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                         (unsigned long long) dp->dccps_awh);
+               dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq, DCCP_PKT_SYNC);
                return -1;
        }
 
        return 0;
 }
 
-int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
-                        const struct dccp_hdr *dh, const unsigned len)
+static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
+                                 const struct dccp_hdr *dh, const unsigned len)
 {
        struct dccp_sock *dp = dccp_sk(sk);
 
-       if (dccp_check_seqno(sk, skb))
-               goto discard;
-
-       if (dccp_parse_options(sk, skb))
-               goto discard;
-
-       if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
-               dccp_event_ack_recv(sk, skb);
-
-       /*
-        * FIXME: check ECN to see if we should use
-        * DCCP_ACKPKTS_STATE_ECN_MARKED
-        */
-       if (dp->dccps_options.dccpo_send_ack_vector) {
-               struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts;
-
-               if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts,
-                                    DCCP_SKB_CB(skb)->dccpd_seq,
-                                    DCCP_ACKPKTS_STATE_RECEIVED)) {
-                       LIMIT_NETDEBUG(pr_info("DCCP: acknowledgeable packets buffer full!\n"));
-                       ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1;
-                       inet_csk_schedule_ack(sk);
-                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, TCP_DELACK_MIN, TCP_RTO_MAX);
-                       goto discard;
-               }
-
-               /*
-                * FIXME: this activation is probably wrong, have to study more
-                * TCP delack machinery and how it fits into DCCP draft, but
-                * for now it kinda "works" 8)
-                */
-               if (!inet_csk_ack_scheduled(sk)) {
-                       inet_csk_schedule_ack(sk);
-                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, 5 * HZ, TCP_RTO_MAX);
-               }
-       }
-
-       ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
-       ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
-
        switch (dccp_hdr(skb)->dccph_type) {
        case DCCP_PKT_DATAACK:
        case DCCP_PKT_DATA:
                /*
-                * FIXME: check if sk_receive_queue is full, schedule DATA_DROPPED option
-                * if it is.
+                * FIXME: check if sk_receive_queue is full, schedule DATA_DROPPED
+                * option if it is.
                 */
                __skb_pull(skb, dh->dccph_doff * 4);
                __skb_queue_tail(&sk->sk_receive_queue, skb);
@@ -235,9 +205,21 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
 check_seq:
                if (!before48(DCCP_SKB_CB(skb)->dccpd_seq, dp->dccps_osr)) {
 send_sync:
-                       dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq);
+                       dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq,
+                                      DCCP_PKT_SYNC);
                }
                break;
+       case DCCP_PKT_SYNC:
+               dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq,
+                              DCCP_PKT_SYNCACK);
+               /*
+                * From RFC 4340, sec. 5.7
+                *
+                * As with DCCP-Ack packets, DCCP-Sync and DCCP-SyncAck packets
+                * MAY have non-zero-length application data areas, whose
+                * contents receivers MUST ignore.
+                */
+               goto discard;
        }
 
        DCCP_INC_STATS_BH(DCCP_MIB_INERRS);
@@ -246,6 +228,37 @@ discard:
        return 0;
 }
 
+int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
+                        const struct dccp_hdr *dh, const unsigned len)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+
+       if (dccp_check_seqno(sk, skb))
+               goto discard;
+
+       if (dccp_parse_options(sk, skb))
+               goto discard;
+
+       if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
+               dccp_event_ack_recv(sk, skb);
+
+       if (dccp_msk(sk)->dccpms_send_ack_vector &&
+           dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
+                           DCCP_SKB_CB(skb)->dccpd_seq,
+                           DCCP_ACKVEC_STATE_RECEIVED))
+               goto discard;
+
+       ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
+       ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
+
+       return __dccp_rcv_established(sk, skb, dh, len);
+discard:
+       __kfree_skb(skb);
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(dccp_rcv_established);
+
 static int dccp_rcv_request_sent_state_process(struct sock *sk,
                                               struct sk_buff *skb,
                                               const struct dccp_hdr *dh,
@@ -272,45 +285,61 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
                __kfree_skb(sk->sk_send_head);
                sk->sk_send_head = NULL;
 
-               if (!between48(DCCP_SKB_CB(skb)->dccpd_ack_seq, dp->dccps_awl, dp->dccps_awh)) {
-                       dccp_pr_debug("invalid ackno: S.AWL=%llu, P.ackno=%llu, S.AWH=%llu \n",
-                                     (unsigned long long) dp->dccps_awl,
-                                     (unsigned long long) DCCP_SKB_CB(skb)->dccpd_ack_seq,
-                                     (unsigned long long) dp->dccps_awh);
+               if (!between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                              dp->dccps_awl, dp->dccps_awh)) {
+                       dccp_pr_debug("invalid ackno: S.AWL=%llu, "
+                                     "P.ackno=%llu, S.AWH=%llu \n",
+                                     (unsigned long long)dp->dccps_awl,
+                          (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                                     (unsigned long long)dp->dccps_awh);
                        goto out_invalid_packet;
                }
 
-               dp->dccps_isr = DCCP_SKB_CB(skb)->dccpd_seq;
-               dccp_update_gsr(sk, DCCP_SKB_CB(skb)->dccpd_seq);
-
-               if (ccid_hc_rx_init(dp->dccps_hc_rx_ccid, sk) != 0 ||
-                   ccid_hc_tx_init(dp->dccps_hc_tx_ccid, sk) != 0) {
-                       ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
-                       ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
-                       /* FIXME: send appropriate RESET code */
+               if (dccp_parse_options(sk, skb))
                        goto out_invalid_packet;
-               }
 
-               dccp_sync_mss(sk, dp->dccps_pmtu_cookie);
+                if (dccp_msk(sk)->dccpms_send_ack_vector &&
+                    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
+                                    DCCP_SKB_CB(skb)->dccpd_seq,
+                                    DCCP_ACKVEC_STATE_RECEIVED))
+                        goto out_invalid_packet; /* FIXME: change error code */
+
+               dp->dccps_isr = DCCP_SKB_CB(skb)->dccpd_seq;
+               dccp_update_gsr(sk, dp->dccps_isr);
+               /*
+                * SWL and AWL are initially adjusted so that they are not less than
+                * the initial Sequence Numbers received and sent, respectively:
+                *      SWL := max(GSR + 1 - floor(W/4), ISR),
+                *      AWL := max(GSS - W' + 1, ISS).
+                * These adjustments MUST be applied only at the beginning of the
+                * connection.
+                *
+                * AWL was adjusted in dccp_v4_connect -acme
+                */
+               dccp_set_seqno(&dp->dccps_swl,
+                              max48(dp->dccps_swl, dp->dccps_isr));
+
+               dccp_sync_mss(sk, icsk->icsk_pmtu_cookie);
 
                /*
                 *    Step 10: Process REQUEST state (second part)
                 *       If S.state == REQUEST,
-                *        / * If we get here, P is a valid Response from the server (see
-                *           Step 4), and we should move to PARTOPEN state.  PARTOPEN
-                *           means send an Ack, don't send Data packets, retransmit
-                *           Acks periodically, and always include any Init Cookie from
-                *           the Response * /
+                *        / * If we get here, P is a valid Response from the
+                *            server (see Step 4), and we should move to
+                *            PARTOPEN state. PARTOPEN means send an Ack,
+                *            don't send Data packets, retransmit Acks
+                *            periodically, and always include any Init Cookie
+                *            from the Response * /
                 *        S.state := PARTOPEN
                 *        Set PARTOPEN timer
                 *        Continue with S.state == PARTOPEN
-                *        / * Step 12 will send the Ack completing the three-way
-                *           handshake * /
+                *        / * Step 12 will send the Ack completing the
+                *            three-way handshake * /
                 */
                dccp_set_state(sk, DCCP_PARTOPEN);
 
                /* Make sure socket is routed, for correct metrics. */
-               inet_sk_rebuild_header(sk);
+               icsk->icsk_af_ops->rebuild_header(sk);
 
                if (!sock_flag(sk, SOCK_DEAD)) {
                        sk->sk_state_change(sk);
@@ -340,8 +369,9 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
        }
 
 out_invalid_packet:
-       return 1; /* dccp_v4_do_rcv will send a reset, but...
-                    FIXME: the reset code should be DCCP_RESET_CODE_PACKET_ERROR  */
+       /* dccp_v4_do_rcv will send a reset */
+       DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
+       return 1; 
 }
 
 static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
@@ -355,14 +385,18 @@ static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
        case DCCP_PKT_RESET:
                inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
                break;
+       case DCCP_PKT_DATA:
+               if (sk->sk_state == DCCP_RESPOND)
+                       break;
        case DCCP_PKT_DATAACK:
        case DCCP_PKT_ACK:
                /*
-                * FIXME: we should be reseting the PARTOPEN (DELACK) timer here,
-                * but only if we haven't used the DELACK timer for something else,
-                * like sending a delayed ack for a TIMESTAMP echo, etc, for now
-                * were not clearing it, sending an extra ACK when there is nothing
-                * else to do in DELACK is not a big deal after all.
+                * FIXME: we should be reseting the PARTOPEN (DELACK) timer
+                * here but only if we haven't used the DELACK timer for
+                * something else, like sending a delayed ack for a TIMESTAMP
+                * echo, etc, for now were not clearing it, sending an extra
+                * ACK when there is nothing else to do in DELACK is not a big
+                * deal after all.
                 */
 
                /* Stop the PARTOPEN timer */
@@ -372,9 +406,11 @@ static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
                dccp_sk(sk)->dccps_osr = DCCP_SKB_CB(skb)->dccpd_seq;
                dccp_set_state(sk, DCCP_OPEN);
 
-               if (dh->dccph_type == DCCP_PKT_DATAACK) {
-                       dccp_rcv_established(sk, skb, dh, len);
-                       queued = 1; /* packet was queued (by dccp_rcv_established) */
+               if (dh->dccph_type == DCCP_PKT_DATAACK ||
+                   dh->dccph_type == DCCP_PKT_DATA) {
+                       __dccp_rcv_established(sk, skb, dh, len);
+                       queued = 1; /* packet was queued
+                                      (by __dccp_rcv_established) */
                }
                break;
        }
@@ -386,10 +422,50 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                           struct dccp_hdr *dh, unsigned len)
 {
        struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
        const int old_state = sk->sk_state;
        int queued = 0;
 
-       if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING) {
+       /*
+        *  Step 3: Process LISTEN state
+        *
+        *     If S.state == LISTEN,
+        *       If P.type == Request or P contains a valid Init Cookie option,
+        *            (* Must scan the packet's options to check for Init
+        *               Cookies.  Only Init Cookies are processed here,
+        *               however; other options are processed in Step 8.  This
+        *               scan need only be performed if the endpoint uses Init
+        *               Cookies *)
+        *            (* Generate a new socket and switch to that socket *)
+        *            Set S := new socket for this port pair
+        *            S.state = RESPOND
+        *            Choose S.ISS (initial seqno) or set from Init Cookies
+        *            Initialize S.GAR := S.ISS
+        *            Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init
+        *            Cookies Continue with S.state == RESPOND
+        *            (* A Response packet will be generated in Step 11 *)
+        *       Otherwise,
+        *            Generate Reset(No Connection) unless P.type == Reset
+        *            Drop packet and return
+        */
+       if (sk->sk_state == DCCP_LISTEN) {
+               if (dh->dccph_type == DCCP_PKT_REQUEST) {
+                       if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
+                                                                   skb) < 0)
+                               return 1;
+
+                       /* FIXME: do congestion control initialization */
+                       goto discard;
+               }
+               if (dh->dccph_type == DCCP_PKT_RESET)
+                       goto discard;
+
+               /* Caller (dccp_v4_do_rcv) will send Reset */
+               dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
+               return 1;
+       }
+
+       if (sk->sk_state != DCCP_REQUESTING) {
                if (dccp_check_seqno(sk, skb))
                        goto discard;
 
@@ -399,32 +475,17 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                if (dccp_parse_options(sk, skb))
                        goto discard;
 
-               if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
+               if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
                        dccp_event_ack_recv(sk, skb);
 
+               if (dccp_msk(sk)->dccpms_send_ack_vector &&
+                   dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
+                                   DCCP_SKB_CB(skb)->dccpd_seq,
+                                   DCCP_ACKVEC_STATE_RECEIVED))
+                       goto discard;
+
                ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
                ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
-
-               /*
-                * FIXME: check ECN to see if we should use
-                * DCCP_ACKPKTS_STATE_ECN_MARKED
-                */
-               if (dp->dccps_options.dccpo_send_ack_vector) {
-                       if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts,
-                                            DCCP_SKB_CB(skb)->dccpd_seq,
-                                            DCCP_ACKPKTS_STATE_RECEIVED))
-                               goto discard;
-                       /*
-                        * FIXME: this activation is probably wrong, have to study more
-                        * TCP delack machinery and how it fits into DCCP draft, but
-                        * for now it kinda "works" 8)
-                        */
-                       if (dp->dccps_hc_rx_ackpkts->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1 &&
-                           !inet_csk_ack_scheduled(sk)) {
-                               inet_csk_schedule_ack(sk);
-                               inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, TCP_DELACK_MIN, TCP_RTO_MAX);
-                       }
-               }
        }
 
        /*
@@ -436,7 +497,10 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
         *              Drop packet and return
        */
        if (dh->dccph_type == DCCP_PKT_RESET) {
-               /* Queue the equivalent of TCP fin so that dccp_recvmsg exits the loop */
+               /*
+                * Queue the equivalent of TCP fin so that dccp_recvmsg
+                * exits the loop
+                */
                dccp_fin(sk, skb);
                dccp_time_wait(sk, DCCP_TIME_WAIT, 0);
                return 0;
@@ -450,35 +514,32 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                 *        Drop packet and return
                 */
        } else if ((dp->dccps_role != DCCP_ROLE_CLIENT &&
-                   (dh->dccph_type == DCCP_PKT_RESPONSE || dh->dccph_type == DCCP_PKT_CLOSEREQ)) ||
+                   (dh->dccph_type == DCCP_PKT_RESPONSE ||
+                    dh->dccph_type == DCCP_PKT_CLOSEREQ)) ||
                    (dp->dccps_role == DCCP_ROLE_CLIENT &&
                     dh->dccph_type == DCCP_PKT_REQUEST) ||
-                   (sk->sk_state == DCCP_RESPOND && dh->dccph_type == DCCP_PKT_DATA)) {
-               dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq);
+                   (sk->sk_state == DCCP_RESPOND &&
+                    dh->dccph_type == DCCP_PKT_DATA)) {
+               dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNC);
+               goto discard;
+       } else if (dh->dccph_type == DCCP_PKT_CLOSEREQ) {
+               dccp_rcv_closereq(sk, skb);
+               goto discard;
+       } else if (dh->dccph_type == DCCP_PKT_CLOSE) {
+               dccp_rcv_close(sk, skb);
+               return 0;
+       }
+
+       if (unlikely(dh->dccph_type == DCCP_PKT_SYNC)) {
+               dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNCACK);
                goto discard;
        }
 
        switch (sk->sk_state) {
        case DCCP_CLOSED:
+               dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
                return 1;
 
-       case DCCP_LISTEN:
-               if (dh->dccph_type == DCCP_PKT_ACK ||
-                   dh->dccph_type == DCCP_PKT_DATAACK)
-                       return 1;
-
-               if (dh->dccph_type == DCCP_PKT_RESET)
-                       goto discard;
-
-               if (dh->dccph_type == DCCP_PKT_REQUEST) {
-                       if (dccp_v4_conn_request(sk, skb) < 0)
-                               return 1;
-
-                       /* FIXME: do congestion control initialization */
-                       goto discard;
-               }
-               goto discard;
-
        case DCCP_REQUESTING:
                /* FIXME: do congestion control initialization */
 
@@ -491,11 +552,13 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 
        case DCCP_RESPOND:
        case DCCP_PARTOPEN:
-               queued = dccp_rcv_respond_partopen_state_process(sk, skb, dh, len);
+               queued = dccp_rcv_respond_partopen_state_process(sk, skb,
+                                                                dh, len);
                break;
        }
 
-       if (dh->dccph_type == DCCP_PKT_ACK || dh->dccph_type == DCCP_PKT_DATAACK) {
+       if (dh->dccph_type == DCCP_PKT_ACK ||
+           dh->dccph_type == DCCP_PKT_DATAACK) {
                switch (old_state) {
                case DCCP_PARTOPEN:
                        sk->sk_state_change(sk);
@@ -510,3 +573,5 @@ discard:
        }
        return 0;
 }
+
+EXPORT_SYMBOL_GPL(dccp_rcv_state_process);