]> err.no Git - linux-2.6/blobdiff - net/dccp/input.c
[TCP]: Fix TCP_OFF() bug check introduced by previous change.
[linux-2.6] / net / dccp / input.c
index 76c3401e93a53ce984c972f4b7802b9c19b95c5c..ef29cef1dafe238196224bd8aed79cc139a2c329 100644 (file)
@@ -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_v4_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,17 +46,12 @@ 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:
-               dccp_set_state(sk, DCCP_CLOSING);
-               dccp_send_close(sk);
-               break;
-       }
+       dccp_set_state(sk, DCCP_CLOSING);
+       dccp_send_close(sk, 0);
 }
 
 static inline void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
@@ -76,8 +67,7 @@ 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 +83,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 +105,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,15 +118,31 @@ 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);
+               LIMIT_NETDEBUG(KERN_WARNING "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;
        }
 
@@ -161,10 +173,13 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
                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"));
+                       LIMIT_NETDEBUG(KERN_WARNING "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);
+                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+                                                 TCP_DELACK_MIN,
+                                                 DCCP_RTO_MAX);
                        goto discard;
                }
 
@@ -175,7 +190,8 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
                 */
                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);
+                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, 5 * HZ,
+                                                 DCCP_RTO_MAX);
                }
        }
 
@@ -186,8 +202,8 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
        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 +251,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 the draft:
+                *
+                * 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);
@@ -272,16 +300,30 @@ 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);
+               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));
 
                if (ccid_hc_rx_init(dp->dccps_hc_rx_ccid, sk) != 0 ||
                    ccid_hc_tx_init(dp->dccps_hc_tx_ccid, sk) != 0) {
@@ -296,16 +338,17 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
                /*
                 *    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);
 
@@ -341,7 +384,8 @@ 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  */
+                    FIXME: the reset code should be
+                           DCCP_RESET_CODE_PACKET_ERROR */
 }
 
 static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
@@ -358,11 +402,12 @@ static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
        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 */
@@ -374,7 +419,8 @@ static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
 
                if (dh->dccph_type == DCCP_PKT_DATAACK) {
                        dccp_rcv_established(sk, skb, dh, len);
-                       queued = 1; /* packet was queued (by dccp_rcv_established) */
+                       queued = 1; /* packet was queued
+                                      (by dccp_rcv_established) */
                }
                break;
        }
@@ -389,7 +435,48 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *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
+        *      (Continuing from dccp_v4_do_rcv and dccp_v6_do_rcv)
+        *
+        *     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 an Init
+        *              Cookie.  Only the Init Cookie is 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 Cookie
+        *           Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
+        *           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
+        *
+        * NOTE: the check for the packet types is done in
+        *       dccp_rcv_state_process
+        */
+       if (sk->sk_state == DCCP_LISTEN) {
+               if (dh->dccph_type == DCCP_PKT_REQUEST) {
+                       if (dccp_v4_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(No Connection)*/
+               return 1;
+       }
+
+       if (sk->sk_state != DCCP_REQUESTING) {
                if (dccp_check_seqno(sk, skb))
                        goto discard;
 
@@ -399,7 +486,8 @@ 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 (DCCP_SKB_CB(skb)->dccpd_ack_seq !=
+                   DCCP_PKT_WITHOUT_ACK_SEQ)
                        dccp_event_ack_recv(sk, skb);
 
                ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
@@ -415,14 +503,17 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                             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)
+                        * 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 &&
+                       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);
+                               inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+                                                         TCP_DELACK_MIN,
+                                                         DCCP_RTO_MAX);
                        }
                }
        }
@@ -436,7 +527,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 +544,27 @@ 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, DCCP_SKB_CB(skb)->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;
        }
 
        switch (sk->sk_state) {
        case DCCP_CLOSED:
                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 +577,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);