/*
* net/dccp/input.c
- *
+ *
* An implementation of the DCCP protocol
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* Otherwise,
* Drop packet and return
*/
- if (dh->dccph_type == DCCP_PKT_SYNC ||
+ 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) &&
- !before48(DCCP_SKB_CB(skb)->dccpd_seq, dp->dccps_swl))
+ dccp_delta_seqno(dp->dccps_swl,
+ DCCP_SKB_CB(skb)->dccpd_seq) >= 0)
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
DCCP_PKT_WITHOUT_ACK_SEQ))
dp->dccps_gar = DCCP_SKB_CB(skb)->dccpd_ack_seq;
} else {
- 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_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;
}
dccp_rcv_close(sk, skb);
return 0;
case DCCP_PKT_REQUEST:
- /* Step 7
- * or (S.is_server and P.type == Response)
+ /* Step 7
+ * or (S.is_server and P.type == Response)
* or (S.is_client and P.type == Request)
* or (S.state >= OPEN and P.type == Request
* and P.seqno >= S.OSR)
if (dp->dccps_role != DCCP_ROLE_CLIENT)
goto send_sync;
check_seq:
- if (!before48(DCCP_SKB_CB(skb)->dccpd_seq, dp->dccps_osr)) {
+ if (dccp_delta_seqno(dp->dccps_osr,
+ DCCP_SKB_CB(skb)->dccpd_seq) >= 0) {
send_sync:
dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq,
DCCP_PKT_SYNC);
const struct dccp_hdr *dh,
const unsigned len)
{
- /*
+ /*
* Step 4: Prepare sequence numbers in REQUEST
* If S.state == REQUEST,
* If (P.type == Response or P.type == Reset)
if (dccp_parse_options(sk, skb))
goto out_invalid_packet;
- 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 */
+ /* Obtain RTT sample from SYN exchange (used by CCID 3) */
+ if (dp->dccps_options_received.dccpor_timestamp_echo) {
+ struct timeval now;
+
+ dccp_timestamp(sk, &now);
+ dp->dccps_syn_rtt = dccp_sample_rtt(sk, &now, NULL);
+ }
+
+ 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);
* from the Response * /
* S.state := PARTOPEN
* Set PARTOPEN timer
- * Continue with S.state == PARTOPEN
+ * Continue with S.state == PARTOPEN
* / * Step 12 will send the Ack completing the
* three-way handshake * /
*/
*/
__kfree_skb(skb);
return 0;
- }
+ }
dccp_send_ack(sk);
return -1;
}
out_invalid_packet:
/* dccp_v4_do_rcv will send a reset */
DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
- return 1;
+ return 1;
}
static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
dccp_event_ack_recv(sk, skb);
- if (dccp_msk(sk)->dccpms_send_ack_vector &&
+ 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;
+ 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);
}
}
- if (!queued) {
+ if (!queued) {
discard:
__kfree_skb(skb);
}
}
EXPORT_SYMBOL_GPL(dccp_rcv_state_process);
+
+/**
+ * dccp_sample_rtt - Sample RTT from packet exchange
+ *
+ * @sk: connected dccp_sock
+ * @t_recv: receive timestamp of packet with timestamp echo
+ * @t_hist: packet history timestamp or NULL
+ */
+u32 dccp_sample_rtt(struct sock *sk, struct timeval *t_recv,
+ struct timeval *t_hist)
+{
+ struct dccp_sock *dp = dccp_sk(sk);
+ struct dccp_options_received *or = &dp->dccps_options_received;
+ suseconds_t delta;
+
+ if (t_hist == NULL) {
+ if (!or->dccpor_timestamp_echo) {
+ DCCP_WARN("packet without timestamp echo\n");
+ return DCCP_SANE_RTT_MAX;
+ }
+ timeval_sub_usecs(t_recv, or->dccpor_timestamp_echo * 10);
+ delta = timeval_usecs(t_recv);
+ } else
+ delta = timeval_delta(t_recv, t_hist);
+
+ delta -= or->dccpor_elapsed_time * 10; /* either set or 0 */
+
+ if (unlikely(delta <= 0)) {
+ DCCP_WARN("unusable RTT sample %ld, using min\n", (long)delta);
+ return DCCP_SANE_RTT_MIN;
+ }
+ if (unlikely(delta - (suseconds_t)DCCP_SANE_RTT_MAX > 0)) {
+ DCCP_WARN("RTT sample %ld too large, using max\n", (long)delta);
+ return DCCP_SANE_RTT_MAX;
+ }
+
+ return delta;
+}
+
+EXPORT_SYMBOL_GPL(dccp_sample_rtt);