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 { 296b1c9fe7bSIan McDonald return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; 2977c657876SArnaldo Carvalho de Melo } 2987c657876SArnaldo Carvalho de Melo 2997c657876SArnaldo Carvalho de Melo void dccp_insert_option_elapsed_time(struct sock *sk, 3007c657876SArnaldo Carvalho de Melo struct sk_buff *skb, 3017c657876SArnaldo Carvalho de Melo u32 elapsed_time) 3027c657876SArnaldo Carvalho de Melo { 303725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 3047c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 3057690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 3067690af3fSArnaldo Carvalho de Melo "CLIENT TX opt: " : "server TX opt: "; 3077c657876SArnaldo Carvalho de Melo #endif 3087c657876SArnaldo Carvalho de Melo const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); 3097c657876SArnaldo Carvalho de Melo const int len = 2 + elapsed_time_len; 3107c657876SArnaldo Carvalho de Melo unsigned char *to; 3117c657876SArnaldo Carvalho de Melo 3127c657876SArnaldo Carvalho de Melo /* If elapsed_time == 0... */ 3137c657876SArnaldo Carvalho de Melo if (elapsed_time_len == 2) 3147c657876SArnaldo Carvalho de Melo return; 3157c657876SArnaldo Carvalho de Melo 3167c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { 3177690af3fSArnaldo Carvalho de Melo LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to " 3187690af3fSArnaldo Carvalho de Melo "insert elapsed time!\n"); 3197c657876SArnaldo Carvalho de Melo return; 3207c657876SArnaldo Carvalho de Melo } 3217c657876SArnaldo Carvalho de Melo 3227c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len; 3237c657876SArnaldo Carvalho de Melo 3247c657876SArnaldo Carvalho de Melo to = skb_push(skb, len); 3257c657876SArnaldo Carvalho de Melo *to++ = DCCPO_ELAPSED_TIME; 3267c657876SArnaldo Carvalho de Melo *to++ = len; 3277c657876SArnaldo Carvalho de Melo 3287c657876SArnaldo Carvalho de Melo dccp_encode_value_var(elapsed_time, to, elapsed_time_len); 3297c657876SArnaldo Carvalho de Melo 3307c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sELAPSED_TIME=%u, len=%d, seqno=%llu\n", 3317c657876SArnaldo Carvalho de Melo debug_prefix, elapsed_time, 332f6ccf554SDavid S. Miller len, 333f6ccf554SDavid S. Miller (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); 3347c657876SArnaldo Carvalho de Melo } 3357c657876SArnaldo Carvalho de Melo 3367c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL(dccp_insert_option_elapsed_time); 3377c657876SArnaldo Carvalho de Melo 3387c657876SArnaldo Carvalho de Melo static void dccp_insert_option_ack_vector(struct sock *sk, struct sk_buff *skb) 3397c657876SArnaldo Carvalho de Melo { 3407c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 341725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 3427690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 3437690af3fSArnaldo Carvalho de Melo "CLIENT TX opt: " : "server TX opt: "; 3447c657876SArnaldo Carvalho de Melo #endif 3457c657876SArnaldo Carvalho de Melo struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts; 3467c657876SArnaldo Carvalho de Melo int len = ap->dccpap_buf_vector_len + 2; 3477c657876SArnaldo Carvalho de Melo const u32 elapsed_time = jiffies_to_usecs(jiffies - ap->dccpap_time) / 10; 3487c657876SArnaldo Carvalho de Melo unsigned char *to, *from; 3497c657876SArnaldo Carvalho de Melo 3507c657876SArnaldo Carvalho de Melo if (elapsed_time != 0) 3517c657876SArnaldo Carvalho de Melo dccp_insert_option_elapsed_time(sk, skb, elapsed_time); 3527c657876SArnaldo Carvalho de Melo 3537c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { 3547690af3fSArnaldo Carvalho de Melo LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to " 3557690af3fSArnaldo Carvalho de Melo "insert ACK Vector!\n"); 3567c657876SArnaldo Carvalho de Melo return; 3577c657876SArnaldo Carvalho de Melo } 3587c657876SArnaldo Carvalho de Melo 3597c657876SArnaldo Carvalho de Melo /* 3607c657876SArnaldo Carvalho de Melo * XXX: now we have just one ack vector sent record, so 3617c657876SArnaldo Carvalho de Melo * we have to wait for it to be cleared. 3627c657876SArnaldo Carvalho de Melo * 3637c657876SArnaldo Carvalho de Melo * Of course this is not acceptable, but this is just for 3647c657876SArnaldo Carvalho de Melo * basic testing now. 3657c657876SArnaldo Carvalho de Melo */ 3667c657876SArnaldo Carvalho de Melo if (ap->dccpap_ack_seqno != DCCP_MAX_SEQNO + 1) 3677c657876SArnaldo Carvalho de Melo return; 3687c657876SArnaldo Carvalho de Melo 3697c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len; 3707c657876SArnaldo Carvalho de Melo 3717c657876SArnaldo Carvalho de Melo to = skb_push(skb, len); 3727c657876SArnaldo Carvalho de Melo *to++ = DCCPO_ACK_VECTOR_0; 3737c657876SArnaldo Carvalho de Melo *to++ = len; 3747c657876SArnaldo Carvalho de Melo 3757c657876SArnaldo Carvalho de Melo len = ap->dccpap_buf_vector_len; 3767c657876SArnaldo Carvalho de Melo from = ap->dccpap_buf + ap->dccpap_buf_head; 3777c657876SArnaldo Carvalho de Melo 3787c657876SArnaldo Carvalho de Melo /* Check if buf_head wraps */ 3797c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_head + len > ap->dccpap_buf_len) { 3807690af3fSArnaldo Carvalho de Melo const unsigned int tailsize = (ap->dccpap_buf_len - 3817690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_head); 3827c657876SArnaldo Carvalho de Melo 3837c657876SArnaldo Carvalho de Melo memcpy(to, from, tailsize); 3847c657876SArnaldo Carvalho de Melo to += tailsize; 3857c657876SArnaldo Carvalho de Melo len -= tailsize; 3867c657876SArnaldo Carvalho de Melo from = ap->dccpap_buf; 3877c657876SArnaldo Carvalho de Melo } 3887c657876SArnaldo Carvalho de Melo 3897c657876SArnaldo Carvalho de Melo memcpy(to, from, len); 3907c657876SArnaldo Carvalho de Melo /* 3917c657876SArnaldo Carvalho de Melo * From draft-ietf-dccp-spec-11.txt: 3927c657876SArnaldo Carvalho de Melo * 3937c657876SArnaldo Carvalho de Melo * For each acknowledgement it sends, the HC-Receiver will add an 3947c657876SArnaldo Carvalho de Melo * acknowledgement record. ack_seqno will equal the HC-Receiver 3957c657876SArnaldo Carvalho de Melo * sequence number it used for the ack packet; ack_ptr will equal 3967690af3fSArnaldo Carvalho de Melo * buf_head; ack_ackno will equal buf_ackno; and ack_nonce will 3977690af3fSArnaldo Carvalho de Melo * equal buf_nonce. 3987c657876SArnaldo Carvalho de Melo * 3997c657876SArnaldo Carvalho de Melo * This implemention uses just one ack record for now. 4007c657876SArnaldo Carvalho de Melo */ 4017c657876SArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq; 4027c657876SArnaldo Carvalho de Melo ap->dccpap_ack_ptr = ap->dccpap_buf_head; 4037c657876SArnaldo Carvalho de Melo ap->dccpap_ack_ackno = ap->dccpap_buf_ackno; 4047c657876SArnaldo Carvalho de Melo ap->dccpap_ack_nonce = ap->dccpap_buf_nonce; 4057c657876SArnaldo Carvalho de Melo ap->dccpap_ack_vector_len = ap->dccpap_buf_vector_len; 4067c657876SArnaldo Carvalho de Melo 4077690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, " 4087690af3fSArnaldo Carvalho de Melo "ack_ackno=%llu\n", 4097c657876SArnaldo Carvalho de Melo debug_prefix, ap->dccpap_ack_vector_len, 410f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_seqno, 411f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_ackno); 4127c657876SArnaldo Carvalho de Melo } 4137c657876SArnaldo Carvalho de Melo 4147690af3fSArnaldo Carvalho de Melo static inline void dccp_insert_option_timestamp(struct sock *sk, 4157690af3fSArnaldo Carvalho de Melo struct sk_buff *skb) 4167c657876SArnaldo Carvalho de Melo { 4177c657876SArnaldo Carvalho de Melo const u32 now = htonl(tcp_time_stamp); 4187c657876SArnaldo Carvalho de Melo dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now)); 4197c657876SArnaldo Carvalho de Melo } 4207c657876SArnaldo Carvalho de Melo 4217690af3fSArnaldo Carvalho de Melo static void dccp_insert_option_timestamp_echo(struct sock *sk, 4227690af3fSArnaldo Carvalho de Melo struct sk_buff *skb) 4237c657876SArnaldo Carvalho de Melo { 4247c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 425725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 4267690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 4277690af3fSArnaldo Carvalho de Melo "CLIENT TX opt: " : "server TX opt: "; 4287c657876SArnaldo Carvalho de Melo #endif 4297c657876SArnaldo Carvalho de Melo u32 tstamp_echo; 4307690af3fSArnaldo Carvalho de Melo const u32 elapsed_time = jiffies_to_usecs(jiffies - 4317690af3fSArnaldo Carvalho de Melo dp->dccps_timestamp_time) / 10; 4327c657876SArnaldo Carvalho de Melo const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); 4337c657876SArnaldo Carvalho de Melo const int len = 6 + elapsed_time_len; 4347c657876SArnaldo Carvalho de Melo unsigned char *to; 4357c657876SArnaldo Carvalho de Melo 4367c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { 4377690af3fSArnaldo Carvalho de Melo LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " 4387690af3fSArnaldo Carvalho de Melo "timestamp echo!\n"); 4397c657876SArnaldo Carvalho de Melo return; 4407c657876SArnaldo Carvalho de Melo } 4417c657876SArnaldo Carvalho de Melo 4427c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len; 4437c657876SArnaldo Carvalho de Melo 4447c657876SArnaldo Carvalho de Melo to = skb_push(skb, len); 4457c657876SArnaldo Carvalho de Melo *to++ = DCCPO_TIMESTAMP_ECHO; 4467c657876SArnaldo Carvalho de Melo *to++ = len; 4477c657876SArnaldo Carvalho de Melo 4487c657876SArnaldo Carvalho de Melo tstamp_echo = htonl(dp->dccps_timestamp_echo); 4497c657876SArnaldo Carvalho de Melo memcpy(to, &tstamp_echo, 4); 4507c657876SArnaldo Carvalho de Melo to += 4; 4517c657876SArnaldo Carvalho de Melo dccp_encode_value_var(elapsed_time, to, elapsed_time_len); 4527c657876SArnaldo Carvalho de Melo 4537c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, seqno=%llu\n", 4547c657876SArnaldo Carvalho de Melo debug_prefix, dp->dccps_timestamp_echo, 455f6ccf554SDavid S. Miller len, 456f6ccf554SDavid S. Miller (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); 4577c657876SArnaldo Carvalho de Melo 4587c657876SArnaldo Carvalho de Melo dp->dccps_timestamp_echo = 0; 4597c657876SArnaldo Carvalho de Melo dp->dccps_timestamp_time = 0; 4607c657876SArnaldo Carvalho de Melo } 4617c657876SArnaldo Carvalho de Melo 4627c657876SArnaldo Carvalho de Melo void dccp_insert_options(struct sock *sk, struct sk_buff *skb) 4637c657876SArnaldo Carvalho de Melo { 4647c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 4657c657876SArnaldo Carvalho de Melo 4667c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len = 0; 4677c657876SArnaldo Carvalho de Melo 4687c657876SArnaldo Carvalho de Melo if (dp->dccps_options.dccpo_send_ndp_count) 4697c657876SArnaldo Carvalho de Melo dccp_insert_option_ndp(sk, skb); 4707c657876SArnaldo Carvalho de Melo 4717c657876SArnaldo Carvalho de Melo if (!dccp_packet_without_ack(skb)) { 4727c657876SArnaldo Carvalho de Melo if (dp->dccps_options.dccpo_send_ack_vector && 4737690af3fSArnaldo Carvalho de Melo (dp->dccps_hc_rx_ackpkts->dccpap_buf_ackno != 4747690af3fSArnaldo Carvalho de Melo DCCP_MAX_SEQNO + 1)) 4757c657876SArnaldo Carvalho de Melo dccp_insert_option_ack_vector(sk, skb); 4767c657876SArnaldo Carvalho de Melo 4777c657876SArnaldo Carvalho de Melo dccp_insert_option_timestamp(sk, skb); 4787c657876SArnaldo Carvalho de Melo if (dp->dccps_timestamp_echo != 0) 4797c657876SArnaldo Carvalho de Melo dccp_insert_option_timestamp_echo(sk, skb); 4807c657876SArnaldo Carvalho de Melo } 4817c657876SArnaldo Carvalho de Melo 4827c657876SArnaldo Carvalho de Melo ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb); 4837c657876SArnaldo Carvalho de Melo ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb); 4847c657876SArnaldo Carvalho de Melo 4857c657876SArnaldo Carvalho de Melo /* XXX: insert other options when appropriate */ 4867c657876SArnaldo Carvalho de Melo 4877c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) { 4887c657876SArnaldo Carvalho de Melo /* The length of all options has to be a multiple of 4 */ 4897c657876SArnaldo Carvalho de Melo int padding = DCCP_SKB_CB(skb)->dccpd_opt_len % 4; 4907c657876SArnaldo Carvalho de Melo 4917c657876SArnaldo Carvalho de Melo if (padding != 0) { 4927c657876SArnaldo Carvalho de Melo padding = 4 - padding; 4937c657876SArnaldo Carvalho de Melo memset(skb_push(skb, padding), 0, padding); 4947c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += padding; 4957c657876SArnaldo Carvalho de Melo } 4967c657876SArnaldo Carvalho de Melo } 4977c657876SArnaldo Carvalho de Melo } 4987c657876SArnaldo Carvalho de Melo 499a1d3a355SArnaldo Carvalho de Melo struct dccp_ackpkts *dccp_ackpkts_alloc(const unsigned int len, 500a1d3a355SArnaldo Carvalho de Melo const unsigned int __nocast priority) 5017c657876SArnaldo Carvalho de Melo { 5027c657876SArnaldo Carvalho de Melo struct dccp_ackpkts *ap = kmalloc(sizeof(*ap) + len, priority); 5037c657876SArnaldo Carvalho de Melo 5047c657876SArnaldo Carvalho de Melo if (ap != NULL) { 505725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 5067c657876SArnaldo Carvalho de Melo memset(ap->dccpap_buf, 0xFF, len); 5077c657876SArnaldo Carvalho de Melo #endif 5087c657876SArnaldo Carvalho de Melo ap->dccpap_buf_len = len; 5097690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_head = 5107690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_tail = 5117690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_len - 1; 5127690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_ackno = 5137690af3fSArnaldo Carvalho de Melo ap->dccpap_ack_ackno = 5147690af3fSArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; 5157c657876SArnaldo Carvalho de Melo ap->dccpap_buf_nonce = ap->dccpap_buf_nonce = 0; 5167c657876SArnaldo Carvalho de Melo ap->dccpap_ack_ptr = 0; 5177c657876SArnaldo Carvalho de Melo ap->dccpap_time = 0; 5187c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len = ap->dccpap_ack_vector_len = 0; 5197c657876SArnaldo Carvalho de Melo } 5207c657876SArnaldo Carvalho de Melo 5217c657876SArnaldo Carvalho de Melo return ap; 5227c657876SArnaldo Carvalho de Melo } 5237c657876SArnaldo Carvalho de Melo 5247c657876SArnaldo Carvalho de Melo void dccp_ackpkts_free(struct dccp_ackpkts *ap) 5257c657876SArnaldo Carvalho de Melo { 5267c657876SArnaldo Carvalho de Melo if (ap != NULL) { 527725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 5287c657876SArnaldo Carvalho de Melo memset(ap, 0xFF, sizeof(*ap) + ap->dccpap_buf_len); 5297c657876SArnaldo Carvalho de Melo #endif 5307c657876SArnaldo Carvalho de Melo kfree(ap); 5317c657876SArnaldo Carvalho de Melo } 5327c657876SArnaldo Carvalho de Melo } 5337c657876SArnaldo Carvalho de Melo 5347c657876SArnaldo Carvalho de Melo static inline u8 dccp_ackpkts_state(const struct dccp_ackpkts *ap, 5357c657876SArnaldo Carvalho de Melo const unsigned int index) 5367c657876SArnaldo Carvalho de Melo { 5377c657876SArnaldo Carvalho de Melo return ap->dccpap_buf[index] & DCCP_ACKPKTS_STATE_MASK; 5387c657876SArnaldo Carvalho de Melo } 5397c657876SArnaldo Carvalho de Melo 5407c657876SArnaldo Carvalho de Melo static inline u8 dccp_ackpkts_len(const struct dccp_ackpkts *ap, 5417c657876SArnaldo Carvalho de Melo const unsigned int index) 5427c657876SArnaldo Carvalho de Melo { 5437c657876SArnaldo Carvalho de Melo return ap->dccpap_buf[index] & DCCP_ACKPKTS_LEN_MASK; 5447c657876SArnaldo Carvalho de Melo } 5457c657876SArnaldo Carvalho de Melo 5467c657876SArnaldo Carvalho de Melo /* 5477c657876SArnaldo Carvalho de Melo * If several packets are missing, the HC-Receiver may prefer to enter multiple 5487c657876SArnaldo Carvalho de Melo * bytes with run length 0, rather than a single byte with a larger run length; 5497c657876SArnaldo Carvalho de Melo * this simplifies table updates if one of the missing packets arrives. 5507c657876SArnaldo Carvalho de Melo */ 5517c657876SArnaldo Carvalho de Melo static inline int dccp_ackpkts_set_buf_head_state(struct dccp_ackpkts *ap, 5527c657876SArnaldo Carvalho de Melo const unsigned int packets, 5537c657876SArnaldo Carvalho de Melo const unsigned char state) 5547c657876SArnaldo Carvalho de Melo { 5557c657876SArnaldo Carvalho de Melo unsigned int gap; 5567c657876SArnaldo Carvalho de Melo signed long new_head; 5577c657876SArnaldo Carvalho de Melo 5587c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_vector_len + packets > ap->dccpap_buf_len) 5597c657876SArnaldo Carvalho de Melo return -ENOBUFS; 5607c657876SArnaldo Carvalho de Melo 5617c657876SArnaldo Carvalho de Melo gap = packets - 1; 5627c657876SArnaldo Carvalho de Melo new_head = ap->dccpap_buf_head - packets; 5637c657876SArnaldo Carvalho de Melo 5647c657876SArnaldo Carvalho de Melo if (new_head < 0) { 5657c657876SArnaldo Carvalho de Melo if (gap > 0) { 5667c657876SArnaldo Carvalho de Melo memset(ap->dccpap_buf, DCCP_ACKPKTS_STATE_NOT_RECEIVED, 5677c657876SArnaldo Carvalho de Melo gap + new_head + 1); 5687c657876SArnaldo Carvalho de Melo gap = -new_head; 5697c657876SArnaldo Carvalho de Melo } 5707c657876SArnaldo Carvalho de Melo new_head += ap->dccpap_buf_len; 5717c657876SArnaldo Carvalho de Melo } 5727c657876SArnaldo Carvalho de Melo 5737c657876SArnaldo Carvalho de Melo ap->dccpap_buf_head = new_head; 5747c657876SArnaldo Carvalho de Melo 5757c657876SArnaldo Carvalho de Melo if (gap > 0) 5767c657876SArnaldo Carvalho de Melo memset(ap->dccpap_buf + ap->dccpap_buf_head + 1, 5777c657876SArnaldo Carvalho de Melo DCCP_ACKPKTS_STATE_NOT_RECEIVED, gap); 5787c657876SArnaldo Carvalho de Melo 5797c657876SArnaldo Carvalho de Melo ap->dccpap_buf[ap->dccpap_buf_head] = state; 5807c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len += packets; 5817c657876SArnaldo Carvalho de Melo return 0; 5827c657876SArnaldo Carvalho de Melo } 5837c657876SArnaldo Carvalho de Melo 5847c657876SArnaldo Carvalho de Melo /* 5857c657876SArnaldo Carvalho de Melo * Implements the draft-ietf-dccp-spec-11.txt Appendix A 5867c657876SArnaldo Carvalho de Melo */ 5877c657876SArnaldo Carvalho de Melo int dccp_ackpkts_add(struct dccp_ackpkts *ap, u64 ackno, u8 state) 5887c657876SArnaldo Carvalho de Melo { 5897c657876SArnaldo Carvalho de Melo /* 5907c657876SArnaldo Carvalho de Melo * Check at the right places if the buffer is full, if it is, tell the 5917c657876SArnaldo Carvalho de Melo * caller to start dropping packets till the HC-Sender acks our ACK 5927c657876SArnaldo Carvalho de Melo * vectors, when we will free up space in dccpap_buf. 5937c657876SArnaldo Carvalho de Melo * 5947c657876SArnaldo Carvalho de Melo * We may well decide to do buffer compression, etc, but for now lets 5957c657876SArnaldo Carvalho de Melo * just drop. 5967c657876SArnaldo Carvalho de Melo * 5977c657876SArnaldo Carvalho de Melo * From Appendix A: 5987c657876SArnaldo Carvalho de Melo * 5997690af3fSArnaldo Carvalho de Melo * Of course, the circular buffer may overflow, either when the 6007690af3fSArnaldo Carvalho de Melo * HC-Sender is sending data at a very high rate, when the 6017690af3fSArnaldo Carvalho de Melo * HC-Receiver's acknowledgements are not reaching the HC-Sender, 6027690af3fSArnaldo Carvalho de Melo * or when the HC-Sender is forgetting to acknowledge those acks 6037690af3fSArnaldo Carvalho de Melo * (so the HC-Receiver is unable to clean up old state). In this 6047690af3fSArnaldo Carvalho de Melo * case, the HC-Receiver should either compress the buffer (by 6057690af3fSArnaldo Carvalho de Melo * increasing run lengths when possible), transfer its state to 6067690af3fSArnaldo Carvalho de Melo * a larger buffer, or, as a last resort, drop all received 6077690af3fSArnaldo Carvalho de Melo * packets, without processing them whatsoever, until its buffer 6087690af3fSArnaldo Carvalho de Melo * shrinks again. 6097c657876SArnaldo Carvalho de Melo */ 6107c657876SArnaldo Carvalho de Melo 6117c657876SArnaldo Carvalho de Melo /* See if this is the first ackno being inserted */ 6127c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_vector_len == 0) { 6137c657876SArnaldo Carvalho de Melo ap->dccpap_buf[ap->dccpap_buf_head] = state; 6147c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len = 1; 6157c657876SArnaldo Carvalho de Melo } else if (after48(ackno, ap->dccpap_buf_ackno)) { 6167690af3fSArnaldo Carvalho de Melo const u64 delta = dccp_delta_seqno(ap->dccpap_buf_ackno, 6177690af3fSArnaldo Carvalho de Melo ackno); 6187c657876SArnaldo Carvalho de Melo 6197c657876SArnaldo Carvalho de Melo /* 6207690af3fSArnaldo Carvalho de Melo * Look if the state of this packet is the same as the 6217690af3fSArnaldo Carvalho de Melo * previous ackno and if so if we can bump the head len. 6227c657876SArnaldo Carvalho de Melo */ 6237c657876SArnaldo Carvalho de Melo if (delta == 1 && 6247c657876SArnaldo Carvalho de Melo dccp_ackpkts_state(ap, ap->dccpap_buf_head) == state && 6257690af3fSArnaldo Carvalho de Melo (dccp_ackpkts_len(ap, ap->dccpap_buf_head) < 6267690af3fSArnaldo Carvalho de Melo DCCP_ACKPKTS_LEN_MASK)) 6277c657876SArnaldo Carvalho de Melo ap->dccpap_buf[ap->dccpap_buf_head]++; 6287c657876SArnaldo Carvalho de Melo else if (dccp_ackpkts_set_buf_head_state(ap, delta, state)) 6297c657876SArnaldo Carvalho de Melo return -ENOBUFS; 6307c657876SArnaldo Carvalho de Melo } else { 6317c657876SArnaldo Carvalho de Melo /* 6327c657876SArnaldo Carvalho de Melo * A.1.2. Old Packets 6337c657876SArnaldo Carvalho de Melo * 6347690af3fSArnaldo Carvalho de Melo * When a packet with Sequence Number S arrives, and 6357690af3fSArnaldo Carvalho de Melo * S <= buf_ackno, the HC-Receiver will scan the table 6367690af3fSArnaldo Carvalho de Melo * for the byte corresponding to S. (Indexing structures 6377690af3fSArnaldo Carvalho de Melo * could reduce the complexity of this scan.) 6387c657876SArnaldo Carvalho de Melo */ 6397c657876SArnaldo Carvalho de Melo u64 delta = dccp_delta_seqno(ackno, ap->dccpap_buf_ackno); 6407c657876SArnaldo Carvalho de Melo unsigned int index = ap->dccpap_buf_head; 6417c657876SArnaldo Carvalho de Melo 6427c657876SArnaldo Carvalho de Melo while (1) { 6437c657876SArnaldo Carvalho de Melo const u8 len = dccp_ackpkts_len(ap, index); 6447c657876SArnaldo Carvalho de Melo const u8 state = dccp_ackpkts_state(ap, index); 6457c657876SArnaldo Carvalho de Melo /* 6467690af3fSArnaldo Carvalho de Melo * valid packets not yet in dccpap_buf have a reserved 6477690af3fSArnaldo Carvalho de Melo * entry, with a len equal to 0. 6487c657876SArnaldo Carvalho de Melo */ 6497c657876SArnaldo Carvalho de Melo if (state == DCCP_ACKPKTS_STATE_NOT_RECEIVED && 6507690af3fSArnaldo Carvalho de Melo len == 0 && delta == 0) { /* Found our 6517690af3fSArnaldo Carvalho de Melo reserved seat! */ 652f6ccf554SDavid S. Miller dccp_pr_debug("Found %llu reserved seat!\n", 653f6ccf554SDavid S. Miller (unsigned long long) ackno); 6547c657876SArnaldo Carvalho de Melo ap->dccpap_buf[index] = state; 6557c657876SArnaldo Carvalho de Melo goto out; 6567c657876SArnaldo Carvalho de Melo } 6577c657876SArnaldo Carvalho de Melo /* len == 0 means one packet */ 6587c657876SArnaldo Carvalho de Melo if (delta < len + 1) 6597c657876SArnaldo Carvalho de Melo goto out_duplicate; 6607c657876SArnaldo Carvalho de Melo 6617c657876SArnaldo Carvalho de Melo delta -= len + 1; 6627c657876SArnaldo Carvalho de Melo if (++index == ap->dccpap_buf_len) 6637c657876SArnaldo Carvalho de Melo index = 0; 6647c657876SArnaldo Carvalho de Melo } 6657c657876SArnaldo Carvalho de Melo } 6667c657876SArnaldo Carvalho de Melo 6677c657876SArnaldo Carvalho de Melo ap->dccpap_buf_ackno = ackno; 6687c657876SArnaldo Carvalho de Melo ap->dccpap_time = jiffies; 6697c657876SArnaldo Carvalho de Melo out: 6707c657876SArnaldo Carvalho de Melo dccp_pr_debug(""); 6717c657876SArnaldo Carvalho de Melo dccp_ackpkts_print(ap); 6727c657876SArnaldo Carvalho de Melo return 0; 6737c657876SArnaldo Carvalho de Melo 6747c657876SArnaldo Carvalho de Melo out_duplicate: 6757c657876SArnaldo Carvalho de Melo /* Duplicate packet */ 6767690af3fSArnaldo Carvalho de Melo dccp_pr_debug("Received a dup or already considered lost " 6777690af3fSArnaldo Carvalho de Melo "packet: %llu\n", (unsigned long long) ackno); 6787c657876SArnaldo Carvalho de Melo return -EILSEQ; 6797c657876SArnaldo Carvalho de Melo } 6807c657876SArnaldo Carvalho de Melo 681725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 6827690af3fSArnaldo Carvalho de Melo void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, 6837690af3fSArnaldo Carvalho de Melo int len) 6847c657876SArnaldo Carvalho de Melo { 6857c657876SArnaldo Carvalho de Melo if (!dccp_debug) 6867c657876SArnaldo Carvalho de Melo return; 6877c657876SArnaldo Carvalho de Melo 688f6ccf554SDavid S. Miller printk("ACK vector len=%d, ackno=%llu |", len, 689f6ccf554SDavid S. Miller (unsigned long long) ackno); 6907c657876SArnaldo Carvalho de Melo 6917c657876SArnaldo Carvalho de Melo while (len--) { 6927c657876SArnaldo Carvalho de Melo const u8 state = (*vector & DCCP_ACKPKTS_STATE_MASK) >> 6; 6937c657876SArnaldo Carvalho de Melo const u8 rl = (*vector & DCCP_ACKPKTS_LEN_MASK); 6947c657876SArnaldo Carvalho de Melo 6957c657876SArnaldo Carvalho de Melo printk("%d,%d|", state, rl); 6967c657876SArnaldo Carvalho de Melo ++vector; 6977c657876SArnaldo Carvalho de Melo } 6987c657876SArnaldo Carvalho de Melo 6997c657876SArnaldo Carvalho de Melo printk("\n"); 7007c657876SArnaldo Carvalho de Melo } 7017c657876SArnaldo Carvalho de Melo 7027c657876SArnaldo Carvalho de Melo void dccp_ackpkts_print(const struct dccp_ackpkts *ap) 7037c657876SArnaldo Carvalho de Melo { 7047c657876SArnaldo Carvalho de Melo dccp_ackvector_print(ap->dccpap_buf_ackno, 7057c657876SArnaldo Carvalho de Melo ap->dccpap_buf + ap->dccpap_buf_head, 7067c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len); 7077c657876SArnaldo Carvalho de Melo } 7087c657876SArnaldo Carvalho de Melo #endif 7097c657876SArnaldo Carvalho de Melo 7107c657876SArnaldo Carvalho de Melo static void dccp_ackpkts_trow_away_ack_record(struct dccp_ackpkts *ap) 7117c657876SArnaldo Carvalho de Melo { 7127c657876SArnaldo Carvalho de Melo /* 7137c657876SArnaldo Carvalho de Melo * As we're keeping track of the ack vector size 7147c657876SArnaldo Carvalho de Melo * (dccpap_buf_vector_len) and the sent ack vector size 7157c657876SArnaldo Carvalho de Melo * (dccpap_ack_vector_len) we don't need dccpap_buf_tail at all, but 7167690af3fSArnaldo Carvalho de Melo * keep this code here as in the future we'll implement a vector of 7177690af3fSArnaldo Carvalho de Melo * ack records, as suggested in draft-ietf-dccp-spec-11.txt 7187690af3fSArnaldo Carvalho de Melo * Appendix A. -acme 7197c657876SArnaldo Carvalho de Melo */ 7207c657876SArnaldo Carvalho de Melo #if 0 7217c657876SArnaldo Carvalho de Melo ap->dccpap_buf_tail = ap->dccpap_ack_ptr + 1; 7227c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_tail >= ap->dccpap_buf_len) 7237c657876SArnaldo Carvalho de Melo ap->dccpap_buf_tail -= ap->dccpap_buf_len; 7247c657876SArnaldo Carvalho de Melo #endif 7257c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len -= ap->dccpap_ack_vector_len; 7267c657876SArnaldo Carvalho de Melo } 7277c657876SArnaldo Carvalho de Melo 7287c657876SArnaldo Carvalho de Melo void dccp_ackpkts_check_rcv_ackno(struct dccp_ackpkts *ap, struct sock *sk, 7297c657876SArnaldo Carvalho de Melo u64 ackno) 7307c657876SArnaldo Carvalho de Melo { 7317c657876SArnaldo Carvalho de Melo /* Check if we actually sent an ACK vector */ 7327c657876SArnaldo Carvalho de Melo if (ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1) 7337c657876SArnaldo Carvalho de Melo return; 7347c657876SArnaldo Carvalho de Melo 7357c657876SArnaldo Carvalho de Melo if (ackno == ap->dccpap_ack_seqno) { 736725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 7377c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 7387690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 7397690af3fSArnaldo Carvalho de Melo "CLIENT rx ack: " : "server rx ack: "; 7407c657876SArnaldo Carvalho de Melo #endif 7417690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, " 7427690af3fSArnaldo Carvalho de Melo "ack_ackno=%llu, ACKED!\n", 7437c657876SArnaldo Carvalho de Melo debug_prefix, 1, 744f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_seqno, 745f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_ackno); 7467c657876SArnaldo Carvalho de Melo dccp_ackpkts_trow_away_ack_record(ap); 7477c657876SArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; 7487c657876SArnaldo Carvalho de Melo } 7497c657876SArnaldo Carvalho de Melo } 7507c657876SArnaldo Carvalho de Melo 7517c657876SArnaldo Carvalho de Melo static void dccp_ackpkts_check_rcv_ackvector(struct dccp_ackpkts *ap, 7527c657876SArnaldo Carvalho de Melo struct sock *sk, u64 ackno, 7537c657876SArnaldo Carvalho de Melo const unsigned char len, 7547c657876SArnaldo Carvalho de Melo const unsigned char *vector) 7557c657876SArnaldo Carvalho de Melo { 7567c657876SArnaldo Carvalho de Melo unsigned char i; 7577c657876SArnaldo Carvalho de Melo 7587c657876SArnaldo Carvalho de Melo /* Check if we actually sent an ACK vector */ 7597c657876SArnaldo Carvalho de Melo if (ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1) 7607c657876SArnaldo Carvalho de Melo return; 7617c657876SArnaldo Carvalho de Melo /* 7627690af3fSArnaldo Carvalho de Melo * We're in the receiver half connection, so if the received an ACK 7637690af3fSArnaldo Carvalho de Melo * vector ackno (e.g. 50) before dccpap_ack_seqno (e.g. 52), we're 7647690af3fSArnaldo Carvalho de Melo * not interested. 7657c657876SArnaldo Carvalho de Melo * 7667c657876SArnaldo Carvalho de Melo * Extra explanation with example: 7677c657876SArnaldo Carvalho de Melo * 7687c657876SArnaldo Carvalho de Melo * if we received an ACK vector with ackno 50, it can only be acking 7697c657876SArnaldo Carvalho de Melo * 50, 49, 48, etc, not 52 (the seqno for the ACK vector we sent). 7707c657876SArnaldo Carvalho de Melo */ 7717690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug("is %llu < %llu? ", ackno, ap->dccpap_ack_seqno); */ 7727c657876SArnaldo Carvalho de Melo if (before48(ackno, ap->dccpap_ack_seqno)) { 7737690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("yes\n"); */ 7747c657876SArnaldo Carvalho de Melo return; 7757c657876SArnaldo Carvalho de Melo } 7767690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("no\n"); */ 7777c657876SArnaldo Carvalho de Melo 7787c657876SArnaldo Carvalho de Melo i = len; 7797c657876SArnaldo Carvalho de Melo while (i--) { 7807c657876SArnaldo Carvalho de Melo const u8 rl = (*vector & DCCP_ACKPKTS_LEN_MASK); 7817c657876SArnaldo Carvalho de Melo u64 ackno_end_rl; 7827c657876SArnaldo Carvalho de Melo 7837c657876SArnaldo Carvalho de Melo dccp_set_seqno(&ackno_end_rl, ackno - rl); 7847c657876SArnaldo Carvalho de Melo 7857690af3fSArnaldo Carvalho de Melo /* 7867690af3fSArnaldo Carvalho de Melo * dccp_pr_debug("is %llu <= %llu <= %llu? ", ackno_end_rl, 7877690af3fSArnaldo Carvalho de Melo * ap->dccpap_ack_seqno, ackno); 7887690af3fSArnaldo Carvalho de Melo */ 7897c657876SArnaldo Carvalho de Melo if (between48(ap->dccpap_ack_seqno, ackno_end_rl, ackno)) { 7907690af3fSArnaldo Carvalho de Melo const u8 state = (*vector & 7917690af3fSArnaldo Carvalho de Melo DCCP_ACKPKTS_STATE_MASK) >> 6; 7927690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("yes\n"); */ 7937c657876SArnaldo Carvalho de Melo 7947c657876SArnaldo Carvalho de Melo if (state != DCCP_ACKPKTS_STATE_NOT_RECEIVED) { 795725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 7967c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 7977690af3fSArnaldo Carvalho de Melo const char *debug_prefix = 7987690af3fSArnaldo Carvalho de Melo dp->dccps_role == DCCP_ROLE_CLIENT ? 7997690af3fSArnaldo Carvalho de Melo "CLIENT rx ack: " : "server rx ack: "; 8007c657876SArnaldo Carvalho de Melo #endif 8017690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sACK vector 0, len=%d, " 8027690af3fSArnaldo Carvalho de Melo "ack_seqno=%llu, ack_ackno=%llu, " 8037690af3fSArnaldo Carvalho de Melo "ACKED!\n", 8047c657876SArnaldo Carvalho de Melo debug_prefix, len, 805f6ccf554SDavid S. Miller (unsigned long long) 806f6ccf554SDavid S. Miller ap->dccpap_ack_seqno, 807f6ccf554SDavid S. Miller (unsigned long long) 808f6ccf554SDavid S. Miller ap->dccpap_ack_ackno); 8097c657876SArnaldo Carvalho de Melo dccp_ackpkts_trow_away_ack_record(ap); 8107c657876SArnaldo Carvalho de Melo } 8117c657876SArnaldo Carvalho de Melo /* 8127690af3fSArnaldo Carvalho de Melo * If dccpap_ack_seqno was not received, no problem 8137690af3fSArnaldo Carvalho de Melo * we'll send another ACK vector. 8147c657876SArnaldo Carvalho de Melo */ 8157c657876SArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; 8167c657876SArnaldo Carvalho de Melo break; 8177c657876SArnaldo Carvalho de Melo } 8187690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("no\n"); */ 8197c657876SArnaldo Carvalho de Melo 8207c657876SArnaldo Carvalho de Melo dccp_set_seqno(&ackno, ackno_end_rl - 1); 8217c657876SArnaldo Carvalho de Melo ++vector; 8227c657876SArnaldo Carvalho de Melo } 8237c657876SArnaldo Carvalho de Melo } 824