17c657876SArnaldo Carvalho de Melo /* 27c657876SArnaldo Carvalho de Melo * net/dccp/options.c 37c657876SArnaldo Carvalho de Melo * 47c657876SArnaldo Carvalho de Melo * An implementation of the DCCP protocol 57c657876SArnaldo Carvalho de Melo * Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> 67c657876SArnaldo Carvalho de Melo * Arnaldo Carvalho de Melo <acme@ghostprotocols.net> 77c657876SArnaldo Carvalho de Melo * 87c657876SArnaldo Carvalho de Melo * This program is free software; you can redistribute it and/or 97c657876SArnaldo Carvalho de Melo * modify it under the terms of the GNU General Public License 107c657876SArnaldo Carvalho de Melo * as published by the Free Software Foundation; either version 117c657876SArnaldo Carvalho de Melo * 2 of the License, or (at your option) any later version. 127c657876SArnaldo Carvalho de Melo */ 137c657876SArnaldo Carvalho de Melo #include <linux/config.h> 147c657876SArnaldo Carvalho de Melo #include <linux/dccp.h> 157c657876SArnaldo Carvalho de Melo #include <linux/module.h> 167c657876SArnaldo Carvalho de Melo #include <linux/types.h> 177c657876SArnaldo Carvalho de Melo #include <linux/kernel.h> 187c657876SArnaldo Carvalho de Melo #include <linux/skbuff.h> 197c657876SArnaldo Carvalho de Melo 207c657876SArnaldo Carvalho de Melo #include "ccid.h" 217c657876SArnaldo Carvalho de Melo #include "dccp.h" 227c657876SArnaldo Carvalho de Melo 237c657876SArnaldo Carvalho de Melo static void dccp_ackpkts_check_rcv_ackvector(struct dccp_ackpkts *ap, 247c657876SArnaldo Carvalho de Melo struct sock *sk, 257c657876SArnaldo Carvalho de Melo const u64 ackno, 267c657876SArnaldo Carvalho de Melo const unsigned char len, 277c657876SArnaldo Carvalho de Melo const unsigned char *vector); 287c657876SArnaldo Carvalho de Melo 297c657876SArnaldo Carvalho de Melo /* stores the default values for new connection. may be changed with sysctl */ 307c657876SArnaldo Carvalho de Melo static const struct dccp_options dccpo_default_values = { 317c657876SArnaldo Carvalho de Melo .dccpo_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW, 327c657876SArnaldo Carvalho de Melo .dccpo_ccid = DCCPF_INITIAL_CCID, 337c657876SArnaldo Carvalho de Melo .dccpo_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR, 347c657876SArnaldo Carvalho de Melo .dccpo_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT, 357c657876SArnaldo Carvalho de Melo }; 367c657876SArnaldo Carvalho de Melo 377c657876SArnaldo Carvalho de Melo void dccp_options_init(struct dccp_options *dccpo) 387c657876SArnaldo Carvalho de Melo { 397c657876SArnaldo Carvalho de Melo memcpy(dccpo, &dccpo_default_values, sizeof(*dccpo)); 407c657876SArnaldo Carvalho de Melo } 417c657876SArnaldo Carvalho de Melo 427c657876SArnaldo Carvalho de Melo static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) 437c657876SArnaldo Carvalho de Melo { 447c657876SArnaldo Carvalho de Melo u32 value = 0; 457c657876SArnaldo Carvalho de Melo 467c657876SArnaldo Carvalho de Melo if (len > 3) 477c657876SArnaldo Carvalho de Melo value += *bf++ << 24; 487c657876SArnaldo Carvalho de Melo if (len > 2) 497c657876SArnaldo Carvalho de Melo value += *bf++ << 16; 507c657876SArnaldo Carvalho de Melo if (len > 1) 517c657876SArnaldo Carvalho de Melo value += *bf++ << 8; 527c657876SArnaldo Carvalho de Melo if (len > 0) 537c657876SArnaldo Carvalho de Melo value += *bf; 547c657876SArnaldo Carvalho de Melo 557c657876SArnaldo Carvalho de Melo return value; 567c657876SArnaldo Carvalho de Melo } 577c657876SArnaldo Carvalho de Melo 587c657876SArnaldo Carvalho de Melo int dccp_parse_options(struct sock *sk, struct sk_buff *skb) 597c657876SArnaldo Carvalho de Melo { 607c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 61725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 627690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 637690af3fSArnaldo Carvalho de Melo "CLIENT rx opt: " : "server rx opt: "; 647c657876SArnaldo Carvalho de Melo #endif 657c657876SArnaldo Carvalho de Melo const struct dccp_hdr *dh = dccp_hdr(skb); 667c657876SArnaldo Carvalho de Melo const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type; 677c657876SArnaldo Carvalho de Melo unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); 687c657876SArnaldo Carvalho de Melo unsigned char *opt_ptr = options; 697690af3fSArnaldo Carvalho de Melo const unsigned char *opt_end = (unsigned char *)dh + 707690af3fSArnaldo Carvalho de Melo (dh->dccph_doff * 4); 717c657876SArnaldo Carvalho de Melo struct dccp_options_received *opt_recv = &dp->dccps_options_received; 727c657876SArnaldo Carvalho de Melo unsigned char opt, len; 737c657876SArnaldo Carvalho de Melo unsigned char *value; 747c657876SArnaldo Carvalho de Melo 757c657876SArnaldo Carvalho de Melo memset(opt_recv, 0, sizeof(*opt_recv)); 767c657876SArnaldo Carvalho de Melo 777c657876SArnaldo Carvalho de Melo while (opt_ptr != opt_end) { 787c657876SArnaldo Carvalho de Melo opt = *opt_ptr++; 797c657876SArnaldo Carvalho de Melo len = 0; 807c657876SArnaldo Carvalho de Melo value = NULL; 817c657876SArnaldo Carvalho de Melo 827c657876SArnaldo Carvalho de Melo /* Check if this isn't a single byte option */ 837c657876SArnaldo Carvalho de Melo if (opt > DCCPO_MAX_RESERVED) { 847c657876SArnaldo Carvalho de Melo if (opt_ptr == opt_end) 857c657876SArnaldo Carvalho de Melo goto out_invalid_option; 867c657876SArnaldo Carvalho de Melo 877c657876SArnaldo Carvalho de Melo len = *opt_ptr++; 887c657876SArnaldo Carvalho de Melo if (len < 3) 897c657876SArnaldo Carvalho de Melo goto out_invalid_option; 907c657876SArnaldo Carvalho de Melo /* 917c657876SArnaldo Carvalho de Melo * Remove the type and len fields, leaving 927c657876SArnaldo Carvalho de Melo * just the value size 937c657876SArnaldo Carvalho de Melo */ 947c657876SArnaldo Carvalho de Melo len -= 2; 957c657876SArnaldo Carvalho de Melo value = opt_ptr; 967c657876SArnaldo Carvalho de Melo opt_ptr += len; 977c657876SArnaldo Carvalho de Melo 987c657876SArnaldo Carvalho de Melo if (opt_ptr > opt_end) 997c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1007c657876SArnaldo Carvalho de Melo } 1017c657876SArnaldo Carvalho de Melo 1027c657876SArnaldo Carvalho de Melo switch (opt) { 1037c657876SArnaldo Carvalho de Melo case DCCPO_PADDING: 1047c657876SArnaldo Carvalho de Melo break; 1057c657876SArnaldo Carvalho de Melo case DCCPO_NDP_COUNT: 1067c657876SArnaldo Carvalho de Melo if (len > 3) 1077c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1087c657876SArnaldo Carvalho de Melo 1097c657876SArnaldo Carvalho de Melo opt_recv->dccpor_ndp = dccp_decode_value_var(value, len); 1107690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sNDP count=%d\n", debug_prefix, 1117690af3fSArnaldo Carvalho de Melo opt_recv->dccpor_ndp); 1127c657876SArnaldo Carvalho de Melo break; 1137c657876SArnaldo Carvalho de Melo case DCCPO_ACK_VECTOR_0: 1147c657876SArnaldo Carvalho de Melo if (len > DCCP_MAX_ACK_VECTOR_LEN) 1157c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1167c657876SArnaldo Carvalho de Melo 1177c657876SArnaldo Carvalho de Melo if (pkt_type == DCCP_PKT_DATA) 1187c657876SArnaldo Carvalho de Melo continue; 1197c657876SArnaldo Carvalho de Melo 1207c657876SArnaldo Carvalho de Melo opt_recv->dccpor_ack_vector_len = len; 1217c657876SArnaldo Carvalho de Melo opt_recv->dccpor_ack_vector_idx = value - options; 1227c657876SArnaldo Carvalho de Melo 1237c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sACK vector 0, len=%d, ack_ackno=%llu\n", 124f6ccf554SDavid S. Miller debug_prefix, len, 125f6ccf554SDavid S. Miller (unsigned long long) 126f6ccf554SDavid S. Miller DCCP_SKB_CB(skb)->dccpd_ack_seq); 1277c657876SArnaldo Carvalho de Melo dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, 1287c657876SArnaldo Carvalho de Melo value, len); 1297690af3fSArnaldo Carvalho de Melo dccp_ackpkts_check_rcv_ackvector(dp->dccps_hc_rx_ackpkts, 1307690af3fSArnaldo Carvalho de Melo sk, 1317c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_ack_seq, 1327c657876SArnaldo Carvalho de Melo len, value); 1337c657876SArnaldo Carvalho de Melo break; 1347c657876SArnaldo Carvalho de Melo case DCCPO_TIMESTAMP: 1357c657876SArnaldo Carvalho de Melo if (len != 4) 1367c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1377c657876SArnaldo Carvalho de Melo 1387c657876SArnaldo Carvalho de Melo opt_recv->dccpor_timestamp = ntohl(*(u32 *)value); 1397c657876SArnaldo Carvalho de Melo 1407c657876SArnaldo Carvalho de Melo dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; 1417c657876SArnaldo Carvalho de Melo dp->dccps_timestamp_time = jiffies; 1427c657876SArnaldo Carvalho de Melo 1437c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sTIMESTAMP=%u, ackno=%llu\n", 1447c657876SArnaldo Carvalho de Melo debug_prefix, opt_recv->dccpor_timestamp, 145f6ccf554SDavid S. Miller (unsigned long long) 1467c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_ack_seq); 1477c657876SArnaldo Carvalho de Melo break; 1487c657876SArnaldo Carvalho de Melo case DCCPO_TIMESTAMP_ECHO: 1497c657876SArnaldo Carvalho de Melo if (len < 4 || len > 8) 1507c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1517c657876SArnaldo Carvalho de Melo 1527c657876SArnaldo Carvalho de Melo opt_recv->dccpor_timestamp_echo = ntohl(*(u32 *)value); 1537c657876SArnaldo Carvalho de Melo 1547690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, " 1557690af3fSArnaldo Carvalho de Melo "diff=%u\n", 1567690af3fSArnaldo Carvalho de Melo debug_prefix, 1577690af3fSArnaldo Carvalho de Melo opt_recv->dccpor_timestamp_echo, 158f6ccf554SDavid S. Miller len + 2, 159f6ccf554SDavid S. Miller (unsigned long long) 160f6ccf554SDavid S. Miller DCCP_SKB_CB(skb)->dccpd_ack_seq, 1617690af3fSArnaldo Carvalho de Melo (tcp_time_stamp - 1627690af3fSArnaldo Carvalho de Melo opt_recv->dccpor_timestamp_echo)); 1637c657876SArnaldo Carvalho de Melo 1647690af3fSArnaldo Carvalho de Melo opt_recv->dccpor_elapsed_time = 1657690af3fSArnaldo Carvalho de Melo dccp_decode_value_var(value + 4, 1667690af3fSArnaldo Carvalho de Melo len - 4); 1677690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sTIMESTAMP_ECHO ELAPSED_TIME=%d\n", 1687690af3fSArnaldo Carvalho de Melo debug_prefix, 1697c657876SArnaldo Carvalho de Melo opt_recv->dccpor_elapsed_time); 1707c657876SArnaldo Carvalho de Melo break; 1717c657876SArnaldo Carvalho de Melo case DCCPO_ELAPSED_TIME: 1727c657876SArnaldo Carvalho de Melo if (len > 4) 1737c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1747c657876SArnaldo Carvalho de Melo 1757c657876SArnaldo Carvalho de Melo if (pkt_type == DCCP_PKT_DATA) 1767c657876SArnaldo Carvalho de Melo continue; 1777690af3fSArnaldo Carvalho de Melo opt_recv->dccpor_elapsed_time = 1787690af3fSArnaldo Carvalho de Melo dccp_decode_value_var(value, len); 1797c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sELAPSED_TIME=%d\n", debug_prefix, 1807c657876SArnaldo Carvalho de Melo opt_recv->dccpor_elapsed_time); 1817c657876SArnaldo Carvalho de Melo break; 1827c657876SArnaldo Carvalho de Melo /* 1837c657876SArnaldo Carvalho de Melo * From draft-ietf-dccp-spec-11.txt: 1847c657876SArnaldo Carvalho de Melo * 1857690af3fSArnaldo Carvalho de Melo * Option numbers 128 through 191 are for 1867690af3fSArnaldo Carvalho de Melo * options sent from the HC-Sender to the 1877690af3fSArnaldo Carvalho de Melo * HC-Receiver; option numbers 192 through 255 1887690af3fSArnaldo Carvalho de Melo * are for options sent from the HC-Receiver to 1897690af3fSArnaldo Carvalho de Melo * the HC-Sender. 1907c657876SArnaldo Carvalho de Melo */ 1917c657876SArnaldo Carvalho de Melo case 128 ... 191: { 1927c657876SArnaldo Carvalho de Melo const u16 idx = value - options; 1937c657876SArnaldo Carvalho de Melo 1947690af3fSArnaldo Carvalho de Melo if (ccid_hc_rx_parse_options(dp->dccps_hc_rx_ccid, sk, 1957690af3fSArnaldo Carvalho de Melo opt, len, idx, 1967690af3fSArnaldo Carvalho de Melo value) != 0) 1977c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1987c657876SArnaldo Carvalho de Melo } 1997c657876SArnaldo Carvalho de Melo break; 2007c657876SArnaldo Carvalho de Melo case 192 ... 255: { 2017c657876SArnaldo Carvalho de Melo const u16 idx = value - options; 2027c657876SArnaldo Carvalho de Melo 2037690af3fSArnaldo Carvalho de Melo if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, 2047690af3fSArnaldo Carvalho de Melo opt, len, idx, 2057690af3fSArnaldo Carvalho de Melo value) != 0) 2067c657876SArnaldo Carvalho de Melo goto out_invalid_option; 2077c657876SArnaldo Carvalho de Melo } 2087c657876SArnaldo Carvalho de Melo break; 2097c657876SArnaldo Carvalho de Melo default: 2107690af3fSArnaldo Carvalho de Melo pr_info("DCCP(%p): option %d(len=%d) not " 2117690af3fSArnaldo Carvalho de Melo "implemented, ignoring\n", 2127c657876SArnaldo Carvalho de Melo sk, opt, len); 2137c657876SArnaldo Carvalho de Melo break; 2147c657876SArnaldo Carvalho de Melo } 2157c657876SArnaldo Carvalho de Melo } 2167c657876SArnaldo Carvalho de Melo 2177c657876SArnaldo Carvalho de Melo return 0; 2187c657876SArnaldo Carvalho de Melo 2197c657876SArnaldo Carvalho de Melo out_invalid_option: 2207c657876SArnaldo Carvalho de Melo DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT); 2217c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR; 2227c657876SArnaldo Carvalho de Melo pr_info("DCCP(%p): invalid option %d, len=%d\n", sk, opt, len); 2237c657876SArnaldo Carvalho de Melo return -1; 2247c657876SArnaldo Carvalho de Melo } 2257c657876SArnaldo Carvalho de Melo 2267c657876SArnaldo Carvalho de Melo static void dccp_encode_value_var(const u32 value, unsigned char *to, 2277c657876SArnaldo Carvalho de Melo const unsigned int len) 2287c657876SArnaldo Carvalho de Melo { 2297c657876SArnaldo Carvalho de Melo if (len > 3) 2307c657876SArnaldo Carvalho de Melo *to++ = (value & 0xFF000000) >> 24; 2317c657876SArnaldo Carvalho de Melo if (len > 2) 2327c657876SArnaldo Carvalho de Melo *to++ = (value & 0xFF0000) >> 16; 2337c657876SArnaldo Carvalho de Melo if (len > 1) 2347c657876SArnaldo Carvalho de Melo *to++ = (value & 0xFF00) >> 8; 2357c657876SArnaldo Carvalho de Melo if (len > 0) 2367c657876SArnaldo Carvalho de Melo *to++ = (value & 0xFF); 2377c657876SArnaldo Carvalho de Melo } 2387c657876SArnaldo Carvalho de Melo 2397c657876SArnaldo Carvalho de Melo static inline int dccp_ndp_len(const int ndp) 2407c657876SArnaldo Carvalho de Melo { 2417c657876SArnaldo Carvalho de Melo return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3; 2427c657876SArnaldo Carvalho de Melo } 2437c657876SArnaldo Carvalho de Melo 2447c657876SArnaldo Carvalho de Melo void dccp_insert_option(struct sock *sk, struct sk_buff *skb, 2457c657876SArnaldo Carvalho de Melo const unsigned char option, 2467c657876SArnaldo Carvalho de Melo const void *value, const unsigned char len) 2477c657876SArnaldo Carvalho de Melo { 2487c657876SArnaldo Carvalho de Melo unsigned char *to; 2497c657876SArnaldo Carvalho de Melo 2507c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) { 2517690af3fSArnaldo Carvalho de Melo LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " 2527690af3fSArnaldo Carvalho de Melo "%d option!\n", option); 2537c657876SArnaldo Carvalho de Melo return; 2547c657876SArnaldo Carvalho de Melo } 2557c657876SArnaldo Carvalho de Melo 2567c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2; 2577c657876SArnaldo Carvalho de Melo 2587c657876SArnaldo Carvalho de Melo to = skb_push(skb, len + 2); 2597c657876SArnaldo Carvalho de Melo *to++ = option; 2607c657876SArnaldo Carvalho de Melo *to++ = len + 2; 2617c657876SArnaldo Carvalho de Melo 2627c657876SArnaldo Carvalho de Melo memcpy(to, value, len); 2637c657876SArnaldo Carvalho de Melo } 2647c657876SArnaldo Carvalho de Melo 2657c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_insert_option); 2667c657876SArnaldo Carvalho de Melo 2677c657876SArnaldo Carvalho de Melo static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) 2687c657876SArnaldo Carvalho de Melo { 2697c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 2707c657876SArnaldo Carvalho de Melo int ndp = dp->dccps_ndp_count; 2717c657876SArnaldo Carvalho de Melo 2727c657876SArnaldo Carvalho de Melo if (dccp_non_data_packet(skb)) 2737c657876SArnaldo Carvalho de Melo ++dp->dccps_ndp_count; 2747c657876SArnaldo Carvalho de Melo else 2757c657876SArnaldo Carvalho de Melo dp->dccps_ndp_count = 0; 2767c657876SArnaldo Carvalho de Melo 2777c657876SArnaldo Carvalho de Melo if (ndp > 0) { 2787c657876SArnaldo Carvalho de Melo unsigned char *ptr; 2797c657876SArnaldo Carvalho de Melo const int ndp_len = dccp_ndp_len(ndp); 2807c657876SArnaldo Carvalho de Melo const int len = ndp_len + 2; 2817c657876SArnaldo Carvalho de Melo 2827c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) 2837c657876SArnaldo Carvalho de Melo return; 2847c657876SArnaldo Carvalho de Melo 2857c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len; 2867c657876SArnaldo Carvalho de Melo 2877c657876SArnaldo Carvalho de Melo ptr = skb_push(skb, len); 2887c657876SArnaldo Carvalho de Melo *ptr++ = DCCPO_NDP_COUNT; 2897c657876SArnaldo Carvalho de Melo *ptr++ = len; 2907c657876SArnaldo Carvalho de Melo dccp_encode_value_var(ndp, ptr, ndp_len); 2917c657876SArnaldo Carvalho de Melo } 2927c657876SArnaldo Carvalho de Melo } 2937c657876SArnaldo Carvalho de Melo 2947c657876SArnaldo Carvalho de Melo static inline int dccp_elapsed_time_len(const u32 elapsed_time) 2957c657876SArnaldo Carvalho de Melo { 2967c657876SArnaldo Carvalho de Melo return elapsed_time == 0 ? 0 : 2977c657876SArnaldo Carvalho de Melo elapsed_time <= 0xFF ? 1 : 2987c657876SArnaldo Carvalho de Melo elapsed_time <= 0xFFFF ? 2 : 2997c657876SArnaldo Carvalho de Melo elapsed_time <= 0xFFFFFF ? 3 : 4; 3007c657876SArnaldo Carvalho de Melo } 3017c657876SArnaldo Carvalho de Melo 3027c657876SArnaldo Carvalho de Melo void dccp_insert_option_elapsed_time(struct sock *sk, 3037c657876SArnaldo Carvalho de Melo struct sk_buff *skb, 3047c657876SArnaldo Carvalho de Melo u32 elapsed_time) 3057c657876SArnaldo Carvalho de Melo { 306725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 3077c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 3087690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 3097690af3fSArnaldo Carvalho de Melo "CLIENT TX opt: " : "server TX opt: "; 3107c657876SArnaldo Carvalho de Melo #endif 3117c657876SArnaldo Carvalho de Melo const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); 3127c657876SArnaldo Carvalho de Melo const int len = 2 + elapsed_time_len; 3137c657876SArnaldo Carvalho de Melo unsigned char *to; 3147c657876SArnaldo Carvalho de Melo 3157c657876SArnaldo Carvalho de Melo /* If elapsed_time == 0... */ 3167c657876SArnaldo Carvalho de Melo if (elapsed_time_len == 2) 3177c657876SArnaldo Carvalho de Melo return; 3187c657876SArnaldo Carvalho de Melo 3197c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { 3207690af3fSArnaldo Carvalho de Melo LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to " 3217690af3fSArnaldo Carvalho de Melo "insert elapsed time!\n"); 3227c657876SArnaldo Carvalho de Melo return; 3237c657876SArnaldo Carvalho de Melo } 3247c657876SArnaldo Carvalho de Melo 3257c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len; 3267c657876SArnaldo Carvalho de Melo 3277c657876SArnaldo Carvalho de Melo to = skb_push(skb, len); 3287c657876SArnaldo Carvalho de Melo *to++ = DCCPO_ELAPSED_TIME; 3297c657876SArnaldo Carvalho de Melo *to++ = len; 3307c657876SArnaldo Carvalho de Melo 3317c657876SArnaldo Carvalho de Melo dccp_encode_value_var(elapsed_time, to, elapsed_time_len); 3327c657876SArnaldo Carvalho de Melo 3337c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sELAPSED_TIME=%u, len=%d, seqno=%llu\n", 3347c657876SArnaldo Carvalho de Melo debug_prefix, elapsed_time, 335f6ccf554SDavid S. Miller len, 336f6ccf554SDavid S. Miller (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); 3377c657876SArnaldo Carvalho de Melo } 3387c657876SArnaldo Carvalho de Melo 3397c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL(dccp_insert_option_elapsed_time); 3407c657876SArnaldo Carvalho de Melo 3417c657876SArnaldo Carvalho de Melo static void dccp_insert_option_ack_vector(struct sock *sk, struct sk_buff *skb) 3427c657876SArnaldo Carvalho de Melo { 3437c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 344725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 3457690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 3467690af3fSArnaldo Carvalho de Melo "CLIENT TX opt: " : "server TX opt: "; 3477c657876SArnaldo Carvalho de Melo #endif 3487c657876SArnaldo Carvalho de Melo struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts; 3497c657876SArnaldo Carvalho de Melo int len = ap->dccpap_buf_vector_len + 2; 3507c657876SArnaldo Carvalho de Melo const u32 elapsed_time = jiffies_to_usecs(jiffies - ap->dccpap_time) / 10; 3517c657876SArnaldo Carvalho de Melo unsigned char *to, *from; 3527c657876SArnaldo Carvalho de Melo 3537c657876SArnaldo Carvalho de Melo if (elapsed_time != 0) 3547c657876SArnaldo Carvalho de Melo dccp_insert_option_elapsed_time(sk, skb, elapsed_time); 3557c657876SArnaldo Carvalho de Melo 3567c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { 3577690af3fSArnaldo Carvalho de Melo LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to " 3587690af3fSArnaldo Carvalho de Melo "insert ACK Vector!\n"); 3597c657876SArnaldo Carvalho de Melo return; 3607c657876SArnaldo Carvalho de Melo } 3617c657876SArnaldo Carvalho de Melo 3627c657876SArnaldo Carvalho de Melo /* 3637c657876SArnaldo Carvalho de Melo * XXX: now we have just one ack vector sent record, so 3647c657876SArnaldo Carvalho de Melo * we have to wait for it to be cleared. 3657c657876SArnaldo Carvalho de Melo * 3667c657876SArnaldo Carvalho de Melo * Of course this is not acceptable, but this is just for 3677c657876SArnaldo Carvalho de Melo * basic testing now. 3687c657876SArnaldo Carvalho de Melo */ 3697c657876SArnaldo Carvalho de Melo if (ap->dccpap_ack_seqno != DCCP_MAX_SEQNO + 1) 3707c657876SArnaldo Carvalho de Melo return; 3717c657876SArnaldo Carvalho de Melo 3727c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len; 3737c657876SArnaldo Carvalho de Melo 3747c657876SArnaldo Carvalho de Melo to = skb_push(skb, len); 3757c657876SArnaldo Carvalho de Melo *to++ = DCCPO_ACK_VECTOR_0; 3767c657876SArnaldo Carvalho de Melo *to++ = len; 3777c657876SArnaldo Carvalho de Melo 3787c657876SArnaldo Carvalho de Melo len = ap->dccpap_buf_vector_len; 3797c657876SArnaldo Carvalho de Melo from = ap->dccpap_buf + ap->dccpap_buf_head; 3807c657876SArnaldo Carvalho de Melo 3817c657876SArnaldo Carvalho de Melo /* Check if buf_head wraps */ 3827c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_head + len > ap->dccpap_buf_len) { 3837690af3fSArnaldo Carvalho de Melo const unsigned int tailsize = (ap->dccpap_buf_len - 3847690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_head); 3857c657876SArnaldo Carvalho de Melo 3867c657876SArnaldo Carvalho de Melo memcpy(to, from, tailsize); 3877c657876SArnaldo Carvalho de Melo to += tailsize; 3887c657876SArnaldo Carvalho de Melo len -= tailsize; 3897c657876SArnaldo Carvalho de Melo from = ap->dccpap_buf; 3907c657876SArnaldo Carvalho de Melo } 3917c657876SArnaldo Carvalho de Melo 3927c657876SArnaldo Carvalho de Melo memcpy(to, from, len); 3937c657876SArnaldo Carvalho de Melo /* 3947c657876SArnaldo Carvalho de Melo * From draft-ietf-dccp-spec-11.txt: 3957c657876SArnaldo Carvalho de Melo * 3967c657876SArnaldo Carvalho de Melo * For each acknowledgement it sends, the HC-Receiver will add an 3977c657876SArnaldo Carvalho de Melo * acknowledgement record. ack_seqno will equal the HC-Receiver 3987c657876SArnaldo Carvalho de Melo * sequence number it used for the ack packet; ack_ptr will equal 3997690af3fSArnaldo Carvalho de Melo * buf_head; ack_ackno will equal buf_ackno; and ack_nonce will 4007690af3fSArnaldo Carvalho de Melo * equal buf_nonce. 4017c657876SArnaldo Carvalho de Melo * 4027c657876SArnaldo Carvalho de Melo * This implemention uses just one ack record for now. 4037c657876SArnaldo Carvalho de Melo */ 4047c657876SArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq; 4057c657876SArnaldo Carvalho de Melo ap->dccpap_ack_ptr = ap->dccpap_buf_head; 4067c657876SArnaldo Carvalho de Melo ap->dccpap_ack_ackno = ap->dccpap_buf_ackno; 4077c657876SArnaldo Carvalho de Melo ap->dccpap_ack_nonce = ap->dccpap_buf_nonce; 4087c657876SArnaldo Carvalho de Melo ap->dccpap_ack_vector_len = ap->dccpap_buf_vector_len; 4097c657876SArnaldo Carvalho de Melo 4107690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, " 4117690af3fSArnaldo Carvalho de Melo "ack_ackno=%llu\n", 4127c657876SArnaldo Carvalho de Melo debug_prefix, ap->dccpap_ack_vector_len, 413f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_seqno, 414f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_ackno); 4157c657876SArnaldo Carvalho de Melo } 4167c657876SArnaldo Carvalho de Melo 4177690af3fSArnaldo Carvalho de Melo static inline void dccp_insert_option_timestamp(struct sock *sk, 4187690af3fSArnaldo Carvalho de Melo struct sk_buff *skb) 4197c657876SArnaldo Carvalho de Melo { 4207c657876SArnaldo Carvalho de Melo const u32 now = htonl(tcp_time_stamp); 4217c657876SArnaldo Carvalho de Melo dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now)); 4227c657876SArnaldo Carvalho de Melo } 4237c657876SArnaldo Carvalho de Melo 4247690af3fSArnaldo Carvalho de Melo static void dccp_insert_option_timestamp_echo(struct sock *sk, 4257690af3fSArnaldo Carvalho de Melo struct sk_buff *skb) 4267c657876SArnaldo Carvalho de Melo { 4277c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 428725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 4297690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 4307690af3fSArnaldo Carvalho de Melo "CLIENT TX opt: " : "server TX opt: "; 4317c657876SArnaldo Carvalho de Melo #endif 4327c657876SArnaldo Carvalho de Melo u32 tstamp_echo; 4337690af3fSArnaldo Carvalho de Melo const u32 elapsed_time = jiffies_to_usecs(jiffies - 4347690af3fSArnaldo Carvalho de Melo dp->dccps_timestamp_time) / 10; 4357c657876SArnaldo Carvalho de Melo const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); 4367c657876SArnaldo Carvalho de Melo const int len = 6 + elapsed_time_len; 4377c657876SArnaldo Carvalho de Melo unsigned char *to; 4387c657876SArnaldo Carvalho de Melo 4397c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { 4407690af3fSArnaldo Carvalho de Melo LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " 4417690af3fSArnaldo Carvalho de Melo "timestamp echo!\n"); 4427c657876SArnaldo Carvalho de Melo return; 4437c657876SArnaldo Carvalho de Melo } 4447c657876SArnaldo Carvalho de Melo 4457c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len; 4467c657876SArnaldo Carvalho de Melo 4477c657876SArnaldo Carvalho de Melo to = skb_push(skb, len); 4487c657876SArnaldo Carvalho de Melo *to++ = DCCPO_TIMESTAMP_ECHO; 4497c657876SArnaldo Carvalho de Melo *to++ = len; 4507c657876SArnaldo Carvalho de Melo 4517c657876SArnaldo Carvalho de Melo tstamp_echo = htonl(dp->dccps_timestamp_echo); 4527c657876SArnaldo Carvalho de Melo memcpy(to, &tstamp_echo, 4); 4537c657876SArnaldo Carvalho de Melo to += 4; 4547c657876SArnaldo Carvalho de Melo dccp_encode_value_var(elapsed_time, to, elapsed_time_len); 4557c657876SArnaldo Carvalho de Melo 4567c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, seqno=%llu\n", 4577c657876SArnaldo Carvalho de Melo debug_prefix, dp->dccps_timestamp_echo, 458f6ccf554SDavid S. Miller len, 459f6ccf554SDavid S. Miller (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); 4607c657876SArnaldo Carvalho de Melo 4617c657876SArnaldo Carvalho de Melo dp->dccps_timestamp_echo = 0; 4627c657876SArnaldo Carvalho de Melo dp->dccps_timestamp_time = 0; 4637c657876SArnaldo Carvalho de Melo } 4647c657876SArnaldo Carvalho de Melo 4657c657876SArnaldo Carvalho de Melo void dccp_insert_options(struct sock *sk, struct sk_buff *skb) 4667c657876SArnaldo Carvalho de Melo { 4677c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 4687c657876SArnaldo Carvalho de Melo 4697c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len = 0; 4707c657876SArnaldo Carvalho de Melo 4717c657876SArnaldo Carvalho de Melo if (dp->dccps_options.dccpo_send_ndp_count) 4727c657876SArnaldo Carvalho de Melo dccp_insert_option_ndp(sk, skb); 4737c657876SArnaldo Carvalho de Melo 4747c657876SArnaldo Carvalho de Melo if (!dccp_packet_without_ack(skb)) { 4757c657876SArnaldo Carvalho de Melo if (dp->dccps_options.dccpo_send_ack_vector && 4767690af3fSArnaldo Carvalho de Melo (dp->dccps_hc_rx_ackpkts->dccpap_buf_ackno != 4777690af3fSArnaldo Carvalho de Melo DCCP_MAX_SEQNO + 1)) 4787c657876SArnaldo Carvalho de Melo dccp_insert_option_ack_vector(sk, skb); 4797c657876SArnaldo Carvalho de Melo 4807c657876SArnaldo Carvalho de Melo dccp_insert_option_timestamp(sk, skb); 4817c657876SArnaldo Carvalho de Melo if (dp->dccps_timestamp_echo != 0) 4827c657876SArnaldo Carvalho de Melo dccp_insert_option_timestamp_echo(sk, skb); 4837c657876SArnaldo Carvalho de Melo } 4847c657876SArnaldo Carvalho de Melo 4857c657876SArnaldo Carvalho de Melo ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb); 4867c657876SArnaldo Carvalho de Melo ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb); 4877c657876SArnaldo Carvalho de Melo 4887c657876SArnaldo Carvalho de Melo /* XXX: insert other options when appropriate */ 4897c657876SArnaldo Carvalho de Melo 4907c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) { 4917c657876SArnaldo Carvalho de Melo /* The length of all options has to be a multiple of 4 */ 4927c657876SArnaldo Carvalho de Melo int padding = DCCP_SKB_CB(skb)->dccpd_opt_len % 4; 4937c657876SArnaldo Carvalho de Melo 4947c657876SArnaldo Carvalho de Melo if (padding != 0) { 4957c657876SArnaldo Carvalho de Melo padding = 4 - padding; 4967c657876SArnaldo Carvalho de Melo memset(skb_push(skb, padding), 0, padding); 4977c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += padding; 4987c657876SArnaldo Carvalho de Melo } 4997c657876SArnaldo Carvalho de Melo } 5007c657876SArnaldo Carvalho de Melo } 5017c657876SArnaldo Carvalho de Melo 502a1d3a355SArnaldo Carvalho de Melo struct dccp_ackpkts *dccp_ackpkts_alloc(const unsigned int len, 503a1d3a355SArnaldo Carvalho de Melo const unsigned int __nocast priority) 5047c657876SArnaldo Carvalho de Melo { 5057c657876SArnaldo Carvalho de Melo struct dccp_ackpkts *ap = kmalloc(sizeof(*ap) + len, priority); 5067c657876SArnaldo Carvalho de Melo 5077c657876SArnaldo Carvalho de Melo if (ap != NULL) { 508725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 5097c657876SArnaldo Carvalho de Melo memset(ap->dccpap_buf, 0xFF, len); 5107c657876SArnaldo Carvalho de Melo #endif 5117c657876SArnaldo Carvalho de Melo ap->dccpap_buf_len = len; 5127690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_head = 5137690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_tail = 5147690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_len - 1; 5157690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_ackno = 5167690af3fSArnaldo Carvalho de Melo ap->dccpap_ack_ackno = 5177690af3fSArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; 5187c657876SArnaldo Carvalho de Melo ap->dccpap_buf_nonce = ap->dccpap_buf_nonce = 0; 5197c657876SArnaldo Carvalho de Melo ap->dccpap_ack_ptr = 0; 5207c657876SArnaldo Carvalho de Melo ap->dccpap_time = 0; 5217c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len = ap->dccpap_ack_vector_len = 0; 5227c657876SArnaldo Carvalho de Melo } 5237c657876SArnaldo Carvalho de Melo 5247c657876SArnaldo Carvalho de Melo return ap; 5257c657876SArnaldo Carvalho de Melo } 5267c657876SArnaldo Carvalho de Melo 5277c657876SArnaldo Carvalho de Melo void dccp_ackpkts_free(struct dccp_ackpkts *ap) 5287c657876SArnaldo Carvalho de Melo { 5297c657876SArnaldo Carvalho de Melo if (ap != NULL) { 530725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 5317c657876SArnaldo Carvalho de Melo memset(ap, 0xFF, sizeof(*ap) + ap->dccpap_buf_len); 5327c657876SArnaldo Carvalho de Melo #endif 5337c657876SArnaldo Carvalho de Melo kfree(ap); 5347c657876SArnaldo Carvalho de Melo } 5357c657876SArnaldo Carvalho de Melo } 5367c657876SArnaldo Carvalho de Melo 5377c657876SArnaldo Carvalho de Melo static inline u8 dccp_ackpkts_state(const struct dccp_ackpkts *ap, 5387c657876SArnaldo Carvalho de Melo const unsigned int index) 5397c657876SArnaldo Carvalho de Melo { 5407c657876SArnaldo Carvalho de Melo return ap->dccpap_buf[index] & DCCP_ACKPKTS_STATE_MASK; 5417c657876SArnaldo Carvalho de Melo } 5427c657876SArnaldo Carvalho de Melo 5437c657876SArnaldo Carvalho de Melo static inline u8 dccp_ackpkts_len(const struct dccp_ackpkts *ap, 5447c657876SArnaldo Carvalho de Melo const unsigned int index) 5457c657876SArnaldo Carvalho de Melo { 5467c657876SArnaldo Carvalho de Melo return ap->dccpap_buf[index] & DCCP_ACKPKTS_LEN_MASK; 5477c657876SArnaldo Carvalho de Melo } 5487c657876SArnaldo Carvalho de Melo 5497c657876SArnaldo Carvalho de Melo /* 5507c657876SArnaldo Carvalho de Melo * If several packets are missing, the HC-Receiver may prefer to enter multiple 5517c657876SArnaldo Carvalho de Melo * bytes with run length 0, rather than a single byte with a larger run length; 5527c657876SArnaldo Carvalho de Melo * this simplifies table updates if one of the missing packets arrives. 5537c657876SArnaldo Carvalho de Melo */ 5547c657876SArnaldo Carvalho de Melo static inline int dccp_ackpkts_set_buf_head_state(struct dccp_ackpkts *ap, 5557c657876SArnaldo Carvalho de Melo const unsigned int packets, 5567c657876SArnaldo Carvalho de Melo const unsigned char state) 5577c657876SArnaldo Carvalho de Melo { 5587c657876SArnaldo Carvalho de Melo unsigned int gap; 5597c657876SArnaldo Carvalho de Melo signed long new_head; 5607c657876SArnaldo Carvalho de Melo 5617c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_vector_len + packets > ap->dccpap_buf_len) 5627c657876SArnaldo Carvalho de Melo return -ENOBUFS; 5637c657876SArnaldo Carvalho de Melo 5647c657876SArnaldo Carvalho de Melo gap = packets - 1; 5657c657876SArnaldo Carvalho de Melo new_head = ap->dccpap_buf_head - packets; 5667c657876SArnaldo Carvalho de Melo 5677c657876SArnaldo Carvalho de Melo if (new_head < 0) { 5687c657876SArnaldo Carvalho de Melo if (gap > 0) { 5697c657876SArnaldo Carvalho de Melo memset(ap->dccpap_buf, DCCP_ACKPKTS_STATE_NOT_RECEIVED, 5707c657876SArnaldo Carvalho de Melo gap + new_head + 1); 5717c657876SArnaldo Carvalho de Melo gap = -new_head; 5727c657876SArnaldo Carvalho de Melo } 5737c657876SArnaldo Carvalho de Melo new_head += ap->dccpap_buf_len; 5747c657876SArnaldo Carvalho de Melo } 5757c657876SArnaldo Carvalho de Melo 5767c657876SArnaldo Carvalho de Melo ap->dccpap_buf_head = new_head; 5777c657876SArnaldo Carvalho de Melo 5787c657876SArnaldo Carvalho de Melo if (gap > 0) 5797c657876SArnaldo Carvalho de Melo memset(ap->dccpap_buf + ap->dccpap_buf_head + 1, 5807c657876SArnaldo Carvalho de Melo DCCP_ACKPKTS_STATE_NOT_RECEIVED, gap); 5817c657876SArnaldo Carvalho de Melo 5827c657876SArnaldo Carvalho de Melo ap->dccpap_buf[ap->dccpap_buf_head] = state; 5837c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len += packets; 5847c657876SArnaldo Carvalho de Melo return 0; 5857c657876SArnaldo Carvalho de Melo } 5867c657876SArnaldo Carvalho de Melo 5877c657876SArnaldo Carvalho de Melo /* 5887c657876SArnaldo Carvalho de Melo * Implements the draft-ietf-dccp-spec-11.txt Appendix A 5897c657876SArnaldo Carvalho de Melo */ 5907c657876SArnaldo Carvalho de Melo int dccp_ackpkts_add(struct dccp_ackpkts *ap, u64 ackno, u8 state) 5917c657876SArnaldo Carvalho de Melo { 5927c657876SArnaldo Carvalho de Melo /* 5937c657876SArnaldo Carvalho de Melo * Check at the right places if the buffer is full, if it is, tell the 5947c657876SArnaldo Carvalho de Melo * caller to start dropping packets till the HC-Sender acks our ACK 5957c657876SArnaldo Carvalho de Melo * vectors, when we will free up space in dccpap_buf. 5967c657876SArnaldo Carvalho de Melo * 5977c657876SArnaldo Carvalho de Melo * We may well decide to do buffer compression, etc, but for now lets 5987c657876SArnaldo Carvalho de Melo * just drop. 5997c657876SArnaldo Carvalho de Melo * 6007c657876SArnaldo Carvalho de Melo * From Appendix A: 6017c657876SArnaldo Carvalho de Melo * 6027690af3fSArnaldo Carvalho de Melo * Of course, the circular buffer may overflow, either when the 6037690af3fSArnaldo Carvalho de Melo * HC-Sender is sending data at a very high rate, when the 6047690af3fSArnaldo Carvalho de Melo * HC-Receiver's acknowledgements are not reaching the HC-Sender, 6057690af3fSArnaldo Carvalho de Melo * or when the HC-Sender is forgetting to acknowledge those acks 6067690af3fSArnaldo Carvalho de Melo * (so the HC-Receiver is unable to clean up old state). In this 6077690af3fSArnaldo Carvalho de Melo * case, the HC-Receiver should either compress the buffer (by 6087690af3fSArnaldo Carvalho de Melo * increasing run lengths when possible), transfer its state to 6097690af3fSArnaldo Carvalho de Melo * a larger buffer, or, as a last resort, drop all received 6107690af3fSArnaldo Carvalho de Melo * packets, without processing them whatsoever, until its buffer 6117690af3fSArnaldo Carvalho de Melo * shrinks again. 6127c657876SArnaldo Carvalho de Melo */ 6137c657876SArnaldo Carvalho de Melo 6147c657876SArnaldo Carvalho de Melo /* See if this is the first ackno being inserted */ 6157c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_vector_len == 0) { 6167c657876SArnaldo Carvalho de Melo ap->dccpap_buf[ap->dccpap_buf_head] = state; 6177c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len = 1; 6187c657876SArnaldo Carvalho de Melo } else if (after48(ackno, ap->dccpap_buf_ackno)) { 6197690af3fSArnaldo Carvalho de Melo const u64 delta = dccp_delta_seqno(ap->dccpap_buf_ackno, 6207690af3fSArnaldo Carvalho de Melo ackno); 6217c657876SArnaldo Carvalho de Melo 6227c657876SArnaldo Carvalho de Melo /* 6237690af3fSArnaldo Carvalho de Melo * Look if the state of this packet is the same as the 6247690af3fSArnaldo Carvalho de Melo * previous ackno and if so if we can bump the head len. 6257c657876SArnaldo Carvalho de Melo */ 6267c657876SArnaldo Carvalho de Melo if (delta == 1 && 6277c657876SArnaldo Carvalho de Melo dccp_ackpkts_state(ap, ap->dccpap_buf_head) == state && 6287690af3fSArnaldo Carvalho de Melo (dccp_ackpkts_len(ap, ap->dccpap_buf_head) < 6297690af3fSArnaldo Carvalho de Melo DCCP_ACKPKTS_LEN_MASK)) 6307c657876SArnaldo Carvalho de Melo ap->dccpap_buf[ap->dccpap_buf_head]++; 6317c657876SArnaldo Carvalho de Melo else if (dccp_ackpkts_set_buf_head_state(ap, delta, state)) 6327c657876SArnaldo Carvalho de Melo return -ENOBUFS; 6337c657876SArnaldo Carvalho de Melo } else { 6347c657876SArnaldo Carvalho de Melo /* 6357c657876SArnaldo Carvalho de Melo * A.1.2. Old Packets 6367c657876SArnaldo Carvalho de Melo * 6377690af3fSArnaldo Carvalho de Melo * When a packet with Sequence Number S arrives, and 6387690af3fSArnaldo Carvalho de Melo * S <= buf_ackno, the HC-Receiver will scan the table 6397690af3fSArnaldo Carvalho de Melo * for the byte corresponding to S. (Indexing structures 6407690af3fSArnaldo Carvalho de Melo * could reduce the complexity of this scan.) 6417c657876SArnaldo Carvalho de Melo */ 6427c657876SArnaldo Carvalho de Melo u64 delta = dccp_delta_seqno(ackno, ap->dccpap_buf_ackno); 6437c657876SArnaldo Carvalho de Melo unsigned int index = ap->dccpap_buf_head; 6447c657876SArnaldo Carvalho de Melo 6457c657876SArnaldo Carvalho de Melo while (1) { 6467c657876SArnaldo Carvalho de Melo const u8 len = dccp_ackpkts_len(ap, index); 6477c657876SArnaldo Carvalho de Melo const u8 state = dccp_ackpkts_state(ap, index); 6487c657876SArnaldo Carvalho de Melo /* 6497690af3fSArnaldo Carvalho de Melo * valid packets not yet in dccpap_buf have a reserved 6507690af3fSArnaldo Carvalho de Melo * entry, with a len equal to 0. 6517c657876SArnaldo Carvalho de Melo */ 6527c657876SArnaldo Carvalho de Melo if (state == DCCP_ACKPKTS_STATE_NOT_RECEIVED && 6537690af3fSArnaldo Carvalho de Melo len == 0 && delta == 0) { /* Found our 6547690af3fSArnaldo Carvalho de Melo reserved seat! */ 655f6ccf554SDavid S. Miller dccp_pr_debug("Found %llu reserved seat!\n", 656f6ccf554SDavid S. Miller (unsigned long long) ackno); 6577c657876SArnaldo Carvalho de Melo ap->dccpap_buf[index] = state; 6587c657876SArnaldo Carvalho de Melo goto out; 6597c657876SArnaldo Carvalho de Melo } 6607c657876SArnaldo Carvalho de Melo /* len == 0 means one packet */ 6617c657876SArnaldo Carvalho de Melo if (delta < len + 1) 6627c657876SArnaldo Carvalho de Melo goto out_duplicate; 6637c657876SArnaldo Carvalho de Melo 6647c657876SArnaldo Carvalho de Melo delta -= len + 1; 6657c657876SArnaldo Carvalho de Melo if (++index == ap->dccpap_buf_len) 6667c657876SArnaldo Carvalho de Melo index = 0; 6677c657876SArnaldo Carvalho de Melo } 6687c657876SArnaldo Carvalho de Melo } 6697c657876SArnaldo Carvalho de Melo 6707c657876SArnaldo Carvalho de Melo ap->dccpap_buf_ackno = ackno; 6717c657876SArnaldo Carvalho de Melo ap->dccpap_time = jiffies; 6727c657876SArnaldo Carvalho de Melo out: 6737c657876SArnaldo Carvalho de Melo dccp_pr_debug(""); 6747c657876SArnaldo Carvalho de Melo dccp_ackpkts_print(ap); 6757c657876SArnaldo Carvalho de Melo return 0; 6767c657876SArnaldo Carvalho de Melo 6777c657876SArnaldo Carvalho de Melo out_duplicate: 6787c657876SArnaldo Carvalho de Melo /* Duplicate packet */ 6797690af3fSArnaldo Carvalho de Melo dccp_pr_debug("Received a dup or already considered lost " 6807690af3fSArnaldo Carvalho de Melo "packet: %llu\n", (unsigned long long) ackno); 6817c657876SArnaldo Carvalho de Melo return -EILSEQ; 6827c657876SArnaldo Carvalho de Melo } 6837c657876SArnaldo Carvalho de Melo 684725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 6857690af3fSArnaldo Carvalho de Melo void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, 6867690af3fSArnaldo Carvalho de Melo int len) 6877c657876SArnaldo Carvalho de Melo { 6887c657876SArnaldo Carvalho de Melo if (!dccp_debug) 6897c657876SArnaldo Carvalho de Melo return; 6907c657876SArnaldo Carvalho de Melo 691f6ccf554SDavid S. Miller printk("ACK vector len=%d, ackno=%llu |", len, 692f6ccf554SDavid S. Miller (unsigned long long) ackno); 6937c657876SArnaldo Carvalho de Melo 6947c657876SArnaldo Carvalho de Melo while (len--) { 6957c657876SArnaldo Carvalho de Melo const u8 state = (*vector & DCCP_ACKPKTS_STATE_MASK) >> 6; 6967c657876SArnaldo Carvalho de Melo const u8 rl = (*vector & DCCP_ACKPKTS_LEN_MASK); 6977c657876SArnaldo Carvalho de Melo 6987c657876SArnaldo Carvalho de Melo printk("%d,%d|", state, rl); 6997c657876SArnaldo Carvalho de Melo ++vector; 7007c657876SArnaldo Carvalho de Melo } 7017c657876SArnaldo Carvalho de Melo 7027c657876SArnaldo Carvalho de Melo printk("\n"); 7037c657876SArnaldo Carvalho de Melo } 7047c657876SArnaldo Carvalho de Melo 7057c657876SArnaldo Carvalho de Melo void dccp_ackpkts_print(const struct dccp_ackpkts *ap) 7067c657876SArnaldo Carvalho de Melo { 7077c657876SArnaldo Carvalho de Melo dccp_ackvector_print(ap->dccpap_buf_ackno, 7087c657876SArnaldo Carvalho de Melo ap->dccpap_buf + ap->dccpap_buf_head, 7097c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len); 7107c657876SArnaldo Carvalho de Melo } 7117c657876SArnaldo Carvalho de Melo #endif 7127c657876SArnaldo Carvalho de Melo 7137c657876SArnaldo Carvalho de Melo static void dccp_ackpkts_trow_away_ack_record(struct dccp_ackpkts *ap) 7147c657876SArnaldo Carvalho de Melo { 7157c657876SArnaldo Carvalho de Melo /* 7167c657876SArnaldo Carvalho de Melo * As we're keeping track of the ack vector size 7177c657876SArnaldo Carvalho de Melo * (dccpap_buf_vector_len) and the sent ack vector size 7187c657876SArnaldo Carvalho de Melo * (dccpap_ack_vector_len) we don't need dccpap_buf_tail at all, but 7197690af3fSArnaldo Carvalho de Melo * keep this code here as in the future we'll implement a vector of 7207690af3fSArnaldo Carvalho de Melo * ack records, as suggested in draft-ietf-dccp-spec-11.txt 7217690af3fSArnaldo Carvalho de Melo * Appendix A. -acme 7227c657876SArnaldo Carvalho de Melo */ 7237c657876SArnaldo Carvalho de Melo #if 0 7247c657876SArnaldo Carvalho de Melo ap->dccpap_buf_tail = ap->dccpap_ack_ptr + 1; 7257c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_tail >= ap->dccpap_buf_len) 7267c657876SArnaldo Carvalho de Melo ap->dccpap_buf_tail -= ap->dccpap_buf_len; 7277c657876SArnaldo Carvalho de Melo #endif 7287c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len -= ap->dccpap_ack_vector_len; 7297c657876SArnaldo Carvalho de Melo } 7307c657876SArnaldo Carvalho de Melo 7317c657876SArnaldo Carvalho de Melo void dccp_ackpkts_check_rcv_ackno(struct dccp_ackpkts *ap, struct sock *sk, 7327c657876SArnaldo Carvalho de Melo u64 ackno) 7337c657876SArnaldo Carvalho de Melo { 7347c657876SArnaldo Carvalho de Melo /* Check if we actually sent an ACK vector */ 7357c657876SArnaldo Carvalho de Melo if (ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1) 7367c657876SArnaldo Carvalho de Melo return; 7377c657876SArnaldo Carvalho de Melo 7387c657876SArnaldo Carvalho de Melo if (ackno == ap->dccpap_ack_seqno) { 739725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 7407c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 7417690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 7427690af3fSArnaldo Carvalho de Melo "CLIENT rx ack: " : "server rx ack: "; 7437c657876SArnaldo Carvalho de Melo #endif 7447690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, " 7457690af3fSArnaldo Carvalho de Melo "ack_ackno=%llu, ACKED!\n", 7467c657876SArnaldo Carvalho de Melo debug_prefix, 1, 747f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_seqno, 748f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_ackno); 7497c657876SArnaldo Carvalho de Melo dccp_ackpkts_trow_away_ack_record(ap); 7507c657876SArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; 7517c657876SArnaldo Carvalho de Melo } 7527c657876SArnaldo Carvalho de Melo } 7537c657876SArnaldo Carvalho de Melo 7547c657876SArnaldo Carvalho de Melo static void dccp_ackpkts_check_rcv_ackvector(struct dccp_ackpkts *ap, 7557c657876SArnaldo Carvalho de Melo struct sock *sk, u64 ackno, 7567c657876SArnaldo Carvalho de Melo const unsigned char len, 7577c657876SArnaldo Carvalho de Melo const unsigned char *vector) 7587c657876SArnaldo Carvalho de Melo { 7597c657876SArnaldo Carvalho de Melo unsigned char i; 7607c657876SArnaldo Carvalho de Melo 7617c657876SArnaldo Carvalho de Melo /* Check if we actually sent an ACK vector */ 7627c657876SArnaldo Carvalho de Melo if (ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1) 7637c657876SArnaldo Carvalho de Melo return; 7647c657876SArnaldo Carvalho de Melo /* 7657690af3fSArnaldo Carvalho de Melo * We're in the receiver half connection, so if the received an ACK 7667690af3fSArnaldo Carvalho de Melo * vector ackno (e.g. 50) before dccpap_ack_seqno (e.g. 52), we're 7677690af3fSArnaldo Carvalho de Melo * not interested. 7687c657876SArnaldo Carvalho de Melo * 7697c657876SArnaldo Carvalho de Melo * Extra explanation with example: 7707c657876SArnaldo Carvalho de Melo * 7717c657876SArnaldo Carvalho de Melo * if we received an ACK vector with ackno 50, it can only be acking 7727c657876SArnaldo Carvalho de Melo * 50, 49, 48, etc, not 52 (the seqno for the ACK vector we sent). 7737c657876SArnaldo Carvalho de Melo */ 7747690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug("is %llu < %llu? ", ackno, ap->dccpap_ack_seqno); */ 7757c657876SArnaldo Carvalho de Melo if (before48(ackno, ap->dccpap_ack_seqno)) { 7767690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("yes\n"); */ 7777c657876SArnaldo Carvalho de Melo return; 7787c657876SArnaldo Carvalho de Melo } 7797690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("no\n"); */ 7807c657876SArnaldo Carvalho de Melo 7817c657876SArnaldo Carvalho de Melo i = len; 7827c657876SArnaldo Carvalho de Melo while (i--) { 7837c657876SArnaldo Carvalho de Melo const u8 rl = (*vector & DCCP_ACKPKTS_LEN_MASK); 7847c657876SArnaldo Carvalho de Melo u64 ackno_end_rl; 7857c657876SArnaldo Carvalho de Melo 7867c657876SArnaldo Carvalho de Melo dccp_set_seqno(&ackno_end_rl, ackno - rl); 7877c657876SArnaldo Carvalho de Melo 7887690af3fSArnaldo Carvalho de Melo /* 7897690af3fSArnaldo Carvalho de Melo * dccp_pr_debug("is %llu <= %llu <= %llu? ", ackno_end_rl, 7907690af3fSArnaldo Carvalho de Melo * ap->dccpap_ack_seqno, ackno); 7917690af3fSArnaldo Carvalho de Melo */ 7927c657876SArnaldo Carvalho de Melo if (between48(ap->dccpap_ack_seqno, ackno_end_rl, ackno)) { 7937690af3fSArnaldo Carvalho de Melo const u8 state = (*vector & 7947690af3fSArnaldo Carvalho de Melo DCCP_ACKPKTS_STATE_MASK) >> 6; 7957690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("yes\n"); */ 7967c657876SArnaldo Carvalho de Melo 7977c657876SArnaldo Carvalho de Melo if (state != DCCP_ACKPKTS_STATE_NOT_RECEIVED) { 798725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 7997c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 8007690af3fSArnaldo Carvalho de Melo const char *debug_prefix = 8017690af3fSArnaldo Carvalho de Melo dp->dccps_role == DCCP_ROLE_CLIENT ? 8027690af3fSArnaldo Carvalho de Melo "CLIENT rx ack: " : "server rx ack: "; 8037c657876SArnaldo Carvalho de Melo #endif 8047690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sACK vector 0, len=%d, " 8057690af3fSArnaldo Carvalho de Melo "ack_seqno=%llu, ack_ackno=%llu, " 8067690af3fSArnaldo Carvalho de Melo "ACKED!\n", 8077c657876SArnaldo Carvalho de Melo debug_prefix, len, 808f6ccf554SDavid S. Miller (unsigned long long) 809f6ccf554SDavid S. Miller ap->dccpap_ack_seqno, 810f6ccf554SDavid S. Miller (unsigned long long) 811f6ccf554SDavid S. Miller ap->dccpap_ack_ackno); 8127c657876SArnaldo Carvalho de Melo dccp_ackpkts_trow_away_ack_record(ap); 8137c657876SArnaldo Carvalho de Melo } 8147c657876SArnaldo Carvalho de Melo /* 8157690af3fSArnaldo Carvalho de Melo * If dccpap_ack_seqno was not received, no problem 8167690af3fSArnaldo Carvalho de Melo * we'll send another ACK vector. 8177c657876SArnaldo Carvalho de Melo */ 8187c657876SArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; 8197c657876SArnaldo Carvalho de Melo break; 8207c657876SArnaldo Carvalho de Melo } 8217690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("no\n"); */ 8227c657876SArnaldo Carvalho de Melo 8237c657876SArnaldo Carvalho de Melo dccp_set_seqno(&ackno, ackno_end_rl - 1); 8247c657876SArnaldo Carvalho de Melo ++vector; 8257c657876SArnaldo Carvalho de Melo } 8267c657876SArnaldo Carvalho de Melo } 827