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 51bc09869SIan McDonald * Copyright (c) 2005 Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> 61bc09869SIan McDonald * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@ghostprotocols.net> 71bc09869SIan McDonald * Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz> 87c657876SArnaldo Carvalho de Melo * 97c657876SArnaldo Carvalho de Melo * This program is free software; you can redistribute it and/or 107c657876SArnaldo Carvalho de Melo * modify it under the terms of the GNU General Public License 117c657876SArnaldo Carvalho de Melo * as published by the Free Software Foundation; either version 127c657876SArnaldo Carvalho de Melo * 2 of the License, or (at your option) any later version. 137c657876SArnaldo Carvalho de Melo */ 147c657876SArnaldo Carvalho de Melo #include <linux/config.h> 157c657876SArnaldo Carvalho de Melo #include <linux/dccp.h> 167c657876SArnaldo Carvalho de Melo #include <linux/module.h> 177c657876SArnaldo Carvalho de Melo #include <linux/types.h> 187c657876SArnaldo Carvalho de Melo #include <linux/kernel.h> 197c657876SArnaldo Carvalho de Melo #include <linux/skbuff.h> 207c657876SArnaldo Carvalho de Melo 217c657876SArnaldo Carvalho de Melo #include "ccid.h" 227c657876SArnaldo Carvalho de Melo #include "dccp.h" 237c657876SArnaldo Carvalho de Melo 247c657876SArnaldo Carvalho de Melo static void dccp_ackpkts_check_rcv_ackvector(struct dccp_ackpkts *ap, 257c657876SArnaldo Carvalho de Melo struct sock *sk, 267c657876SArnaldo Carvalho de Melo const u64 ackno, 277c657876SArnaldo Carvalho de Melo const unsigned char len, 287c657876SArnaldo Carvalho de Melo const unsigned char *vector); 297c657876SArnaldo Carvalho de Melo 307c657876SArnaldo Carvalho de Melo /* stores the default values for new connection. may be changed with sysctl */ 317c657876SArnaldo Carvalho de Melo static const struct dccp_options dccpo_default_values = { 327c657876SArnaldo Carvalho de Melo .dccpo_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW, 337c657876SArnaldo Carvalho de Melo .dccpo_ccid = DCCPF_INITIAL_CCID, 347c657876SArnaldo Carvalho de Melo .dccpo_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR, 357c657876SArnaldo Carvalho de Melo .dccpo_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT, 367c657876SArnaldo Carvalho de Melo }; 377c657876SArnaldo Carvalho de Melo 387c657876SArnaldo Carvalho de Melo void dccp_options_init(struct dccp_options *dccpo) 397c657876SArnaldo Carvalho de Melo { 407c657876SArnaldo Carvalho de Melo memcpy(dccpo, &dccpo_default_values, sizeof(*dccpo)); 417c657876SArnaldo Carvalho de Melo } 427c657876SArnaldo Carvalho de Melo 437c657876SArnaldo Carvalho de Melo static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) 447c657876SArnaldo Carvalho de Melo { 457c657876SArnaldo Carvalho de Melo u32 value = 0; 467c657876SArnaldo Carvalho de Melo 477c657876SArnaldo Carvalho de Melo if (len > 3) 487c657876SArnaldo Carvalho de Melo value += *bf++ << 24; 497c657876SArnaldo Carvalho de Melo if (len > 2) 507c657876SArnaldo Carvalho de Melo value += *bf++ << 16; 517c657876SArnaldo Carvalho de Melo if (len > 1) 527c657876SArnaldo Carvalho de Melo value += *bf++ << 8; 537c657876SArnaldo Carvalho de Melo if (len > 0) 547c657876SArnaldo Carvalho de Melo value += *bf; 557c657876SArnaldo Carvalho de Melo 567c657876SArnaldo Carvalho de Melo return value; 577c657876SArnaldo Carvalho de Melo } 587c657876SArnaldo Carvalho de Melo 597c657876SArnaldo Carvalho de Melo int dccp_parse_options(struct sock *sk, struct sk_buff *skb) 607c657876SArnaldo Carvalho de Melo { 617c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 62725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 637690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 647690af3fSArnaldo Carvalho de Melo "CLIENT rx opt: " : "server rx opt: "; 657c657876SArnaldo Carvalho de Melo #endif 667c657876SArnaldo Carvalho de Melo const struct dccp_hdr *dh = dccp_hdr(skb); 677c657876SArnaldo Carvalho de Melo const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type; 687c657876SArnaldo Carvalho de Melo unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); 697c657876SArnaldo Carvalho de Melo unsigned char *opt_ptr = options; 707690af3fSArnaldo Carvalho de Melo const unsigned char *opt_end = (unsigned char *)dh + 717690af3fSArnaldo Carvalho de Melo (dh->dccph_doff * 4); 727c657876SArnaldo Carvalho de Melo struct dccp_options_received *opt_recv = &dp->dccps_options_received; 737c657876SArnaldo Carvalho de Melo unsigned char opt, len; 747c657876SArnaldo Carvalho de Melo unsigned char *value; 757c657876SArnaldo Carvalho de Melo 767c657876SArnaldo Carvalho de Melo memset(opt_recv, 0, sizeof(*opt_recv)); 777c657876SArnaldo Carvalho de Melo 787c657876SArnaldo Carvalho de Melo while (opt_ptr != opt_end) { 797c657876SArnaldo Carvalho de Melo opt = *opt_ptr++; 807c657876SArnaldo Carvalho de Melo len = 0; 817c657876SArnaldo Carvalho de Melo value = NULL; 827c657876SArnaldo Carvalho de Melo 837c657876SArnaldo Carvalho de Melo /* Check if this isn't a single byte option */ 847c657876SArnaldo Carvalho de Melo if (opt > DCCPO_MAX_RESERVED) { 857c657876SArnaldo Carvalho de Melo if (opt_ptr == opt_end) 867c657876SArnaldo Carvalho de Melo goto out_invalid_option; 877c657876SArnaldo Carvalho de Melo 887c657876SArnaldo Carvalho de Melo len = *opt_ptr++; 897c657876SArnaldo Carvalho de Melo if (len < 3) 907c657876SArnaldo Carvalho de Melo goto out_invalid_option; 917c657876SArnaldo Carvalho de Melo /* 927c657876SArnaldo Carvalho de Melo * Remove the type and len fields, leaving 937c657876SArnaldo Carvalho de Melo * just the value size 947c657876SArnaldo Carvalho de Melo */ 957c657876SArnaldo Carvalho de Melo len -= 2; 967c657876SArnaldo Carvalho de Melo value = opt_ptr; 977c657876SArnaldo Carvalho de Melo opt_ptr += len; 987c657876SArnaldo Carvalho de Melo 997c657876SArnaldo Carvalho de Melo if (opt_ptr > opt_end) 1007c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1017c657876SArnaldo Carvalho de Melo } 1027c657876SArnaldo Carvalho de Melo 1037c657876SArnaldo Carvalho de Melo switch (opt) { 1047c657876SArnaldo Carvalho de Melo case DCCPO_PADDING: 1057c657876SArnaldo Carvalho de Melo break; 1067c657876SArnaldo Carvalho de Melo case DCCPO_NDP_COUNT: 1077c657876SArnaldo Carvalho de Melo if (len > 3) 1087c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1097c657876SArnaldo Carvalho de Melo 1107c657876SArnaldo Carvalho de Melo opt_recv->dccpor_ndp = dccp_decode_value_var(value, len); 1117690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sNDP count=%d\n", debug_prefix, 1127690af3fSArnaldo Carvalho de Melo opt_recv->dccpor_ndp); 1137c657876SArnaldo Carvalho de Melo break; 1147c657876SArnaldo Carvalho de Melo case DCCPO_ACK_VECTOR_0: 1157c657876SArnaldo Carvalho de Melo if (len > DCCP_MAX_ACK_VECTOR_LEN) 1167c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1177c657876SArnaldo Carvalho de Melo 1187c657876SArnaldo Carvalho de Melo if (pkt_type == DCCP_PKT_DATA) 1197c657876SArnaldo Carvalho de Melo continue; 1207c657876SArnaldo Carvalho de Melo 1217c657876SArnaldo Carvalho de Melo opt_recv->dccpor_ack_vector_len = len; 1227c657876SArnaldo Carvalho de Melo opt_recv->dccpor_ack_vector_idx = value - options; 1237c657876SArnaldo Carvalho de Melo 1247c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sACK vector 0, len=%d, ack_ackno=%llu\n", 125f6ccf554SDavid S. Miller debug_prefix, len, 126f6ccf554SDavid S. Miller (unsigned long long) 127f6ccf554SDavid S. Miller DCCP_SKB_CB(skb)->dccpd_ack_seq); 1287c657876SArnaldo Carvalho de Melo dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, 1297c657876SArnaldo Carvalho de Melo value, len); 1307690af3fSArnaldo Carvalho de Melo dccp_ackpkts_check_rcv_ackvector(dp->dccps_hc_rx_ackpkts, 1317690af3fSArnaldo Carvalho de Melo sk, 1327c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_ack_seq, 1337c657876SArnaldo Carvalho de Melo len, value); 1347c657876SArnaldo Carvalho de Melo break; 1357c657876SArnaldo Carvalho de Melo case DCCPO_TIMESTAMP: 1367c657876SArnaldo Carvalho de Melo if (len != 4) 1377c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1387c657876SArnaldo Carvalho de Melo 1397c657876SArnaldo Carvalho de Melo opt_recv->dccpor_timestamp = ntohl(*(u32 *)value); 1407c657876SArnaldo Carvalho de Melo 1417c657876SArnaldo Carvalho de Melo dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; 1421bc09869SIan McDonald do_gettimeofday(&dp->dccps_timestamp_time); 1437c657876SArnaldo Carvalho de Melo 1447c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sTIMESTAMP=%u, ackno=%llu\n", 1457c657876SArnaldo Carvalho de Melo debug_prefix, opt_recv->dccpor_timestamp, 146f6ccf554SDavid S. Miller (unsigned long long) 1477c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_ack_seq); 1487c657876SArnaldo Carvalho de Melo break; 1497c657876SArnaldo Carvalho de Melo case DCCPO_TIMESTAMP_ECHO: 1501bc09869SIan McDonald if (len != 4 && len != 6 && len != 8) 1517c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1527c657876SArnaldo Carvalho de Melo 1537c657876SArnaldo Carvalho de Melo opt_recv->dccpor_timestamp_echo = ntohl(*(u32 *)value); 1547c657876SArnaldo Carvalho de Melo 1551bc09869SIan McDonald dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ", 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) 1601bc09869SIan McDonald DCCP_SKB_CB(skb)->dccpd_ack_seq); 1617c657876SArnaldo Carvalho de Melo 1621bc09869SIan McDonald if (len > 4) { 1631bc09869SIan McDonald if (len == 6) 1647690af3fSArnaldo Carvalho de Melo opt_recv->dccpor_elapsed_time = 1651bc09869SIan McDonald ntohs(*(u16 *)(value + 4)); 1661bc09869SIan McDonald else 1671bc09869SIan McDonald opt_recv->dccpor_elapsed_time = 1681bc09869SIan McDonald ntohl(*(u32 *)(value + 4)); 1691bc09869SIan McDonald 1707690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sTIMESTAMP_ECHO ELAPSED_TIME=%d\n", 1717690af3fSArnaldo Carvalho de Melo debug_prefix, 1727c657876SArnaldo Carvalho de Melo opt_recv->dccpor_elapsed_time); 1731bc09869SIan McDonald } 1747c657876SArnaldo Carvalho de Melo break; 1757c657876SArnaldo Carvalho de Melo case DCCPO_ELAPSED_TIME: 1761bc09869SIan McDonald if (len != 2 && len != 4) 1777c657876SArnaldo Carvalho de Melo goto out_invalid_option; 1787c657876SArnaldo Carvalho de Melo 1797c657876SArnaldo Carvalho de Melo if (pkt_type == DCCP_PKT_DATA) 1807c657876SArnaldo Carvalho de Melo continue; 1811bc09869SIan McDonald 1821bc09869SIan McDonald if (len == 2) 1837690af3fSArnaldo Carvalho de Melo opt_recv->dccpor_elapsed_time = 1841bc09869SIan McDonald ntohs(*(u16 *)value); 1851bc09869SIan McDonald else 1861bc09869SIan McDonald opt_recv->dccpor_elapsed_time = 1871bc09869SIan McDonald ntohl(*(u32 *)value); 1881bc09869SIan McDonald 1897c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sELAPSED_TIME=%d\n", debug_prefix, 1907c657876SArnaldo Carvalho de Melo opt_recv->dccpor_elapsed_time); 1917c657876SArnaldo Carvalho de Melo break; 1927c657876SArnaldo Carvalho de Melo /* 1937c657876SArnaldo Carvalho de Melo * From draft-ietf-dccp-spec-11.txt: 1947c657876SArnaldo Carvalho de Melo * 1957690af3fSArnaldo Carvalho de Melo * Option numbers 128 through 191 are for 1967690af3fSArnaldo Carvalho de Melo * options sent from the HC-Sender to the 1977690af3fSArnaldo Carvalho de Melo * HC-Receiver; option numbers 192 through 255 1987690af3fSArnaldo Carvalho de Melo * are for options sent from the HC-Receiver to 1997690af3fSArnaldo Carvalho de Melo * the HC-Sender. 2007c657876SArnaldo Carvalho de Melo */ 2017c657876SArnaldo Carvalho de Melo case 128 ... 191: { 2027c657876SArnaldo Carvalho de Melo const u16 idx = value - options; 2037c657876SArnaldo Carvalho de Melo 2047690af3fSArnaldo Carvalho de Melo if (ccid_hc_rx_parse_options(dp->dccps_hc_rx_ccid, sk, 2057690af3fSArnaldo Carvalho de Melo opt, len, idx, 2067690af3fSArnaldo Carvalho de Melo value) != 0) 2077c657876SArnaldo Carvalho de Melo goto out_invalid_option; 2087c657876SArnaldo Carvalho de Melo } 2097c657876SArnaldo Carvalho de Melo break; 2107c657876SArnaldo Carvalho de Melo case 192 ... 255: { 2117c657876SArnaldo Carvalho de Melo const u16 idx = value - options; 2127c657876SArnaldo Carvalho de Melo 2137690af3fSArnaldo Carvalho de Melo if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, 2147690af3fSArnaldo Carvalho de Melo opt, len, idx, 2157690af3fSArnaldo Carvalho de Melo value) != 0) 2167c657876SArnaldo Carvalho de Melo goto out_invalid_option; 2177c657876SArnaldo Carvalho de Melo } 2187c657876SArnaldo Carvalho de Melo break; 2197c657876SArnaldo Carvalho de Melo default: 2207690af3fSArnaldo Carvalho de Melo pr_info("DCCP(%p): option %d(len=%d) not " 2217690af3fSArnaldo Carvalho de Melo "implemented, ignoring\n", 2227c657876SArnaldo Carvalho de Melo sk, opt, len); 2237c657876SArnaldo Carvalho de Melo break; 2247c657876SArnaldo Carvalho de Melo } 2257c657876SArnaldo Carvalho de Melo } 2267c657876SArnaldo Carvalho de Melo 2277c657876SArnaldo Carvalho de Melo return 0; 2287c657876SArnaldo Carvalho de Melo 2297c657876SArnaldo Carvalho de Melo out_invalid_option: 2307c657876SArnaldo Carvalho de Melo DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT); 2317c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR; 2327c657876SArnaldo Carvalho de Melo pr_info("DCCP(%p): invalid option %d, len=%d\n", sk, opt, len); 2337c657876SArnaldo Carvalho de Melo return -1; 2347c657876SArnaldo Carvalho de Melo } 2357c657876SArnaldo Carvalho de Melo 2367c657876SArnaldo Carvalho de Melo static void dccp_encode_value_var(const u32 value, unsigned char *to, 2377c657876SArnaldo Carvalho de Melo const unsigned int len) 2387c657876SArnaldo Carvalho de Melo { 2397c657876SArnaldo Carvalho de Melo if (len > 3) 2407c657876SArnaldo Carvalho de Melo *to++ = (value & 0xFF000000) >> 24; 2417c657876SArnaldo Carvalho de Melo if (len > 2) 2427c657876SArnaldo Carvalho de Melo *to++ = (value & 0xFF0000) >> 16; 2437c657876SArnaldo Carvalho de Melo if (len > 1) 2447c657876SArnaldo Carvalho de Melo *to++ = (value & 0xFF00) >> 8; 2457c657876SArnaldo Carvalho de Melo if (len > 0) 2467c657876SArnaldo Carvalho de Melo *to++ = (value & 0xFF); 2477c657876SArnaldo Carvalho de Melo } 2487c657876SArnaldo Carvalho de Melo 2497c657876SArnaldo Carvalho de Melo static inline int dccp_ndp_len(const int ndp) 2507c657876SArnaldo Carvalho de Melo { 2517c657876SArnaldo Carvalho de Melo return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3; 2527c657876SArnaldo Carvalho de Melo } 2537c657876SArnaldo Carvalho de Melo 2547c657876SArnaldo Carvalho de Melo void dccp_insert_option(struct sock *sk, struct sk_buff *skb, 2557c657876SArnaldo Carvalho de Melo const unsigned char option, 2567c657876SArnaldo Carvalho de Melo const void *value, const unsigned char len) 2577c657876SArnaldo Carvalho de Melo { 2587c657876SArnaldo Carvalho de Melo unsigned char *to; 2597c657876SArnaldo Carvalho de Melo 2607c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) { 2617690af3fSArnaldo Carvalho de Melo LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " 2627690af3fSArnaldo Carvalho de Melo "%d option!\n", option); 2637c657876SArnaldo Carvalho de Melo return; 2647c657876SArnaldo Carvalho de Melo } 2657c657876SArnaldo Carvalho de Melo 2667c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2; 2677c657876SArnaldo Carvalho de Melo 2687c657876SArnaldo Carvalho de Melo to = skb_push(skb, len + 2); 2697c657876SArnaldo Carvalho de Melo *to++ = option; 2707c657876SArnaldo Carvalho de Melo *to++ = len + 2; 2717c657876SArnaldo Carvalho de Melo 2727c657876SArnaldo Carvalho de Melo memcpy(to, value, len); 2737c657876SArnaldo Carvalho de Melo } 2747c657876SArnaldo Carvalho de Melo 2757c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_insert_option); 2767c657876SArnaldo Carvalho de Melo 2777c657876SArnaldo Carvalho de Melo static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) 2787c657876SArnaldo Carvalho de Melo { 2797c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 2807c657876SArnaldo Carvalho de Melo int ndp = dp->dccps_ndp_count; 2817c657876SArnaldo Carvalho de Melo 2827c657876SArnaldo Carvalho de Melo if (dccp_non_data_packet(skb)) 2837c657876SArnaldo Carvalho de Melo ++dp->dccps_ndp_count; 2847c657876SArnaldo Carvalho de Melo else 2857c657876SArnaldo Carvalho de Melo dp->dccps_ndp_count = 0; 2867c657876SArnaldo Carvalho de Melo 2877c657876SArnaldo Carvalho de Melo if (ndp > 0) { 2887c657876SArnaldo Carvalho de Melo unsigned char *ptr; 2897c657876SArnaldo Carvalho de Melo const int ndp_len = dccp_ndp_len(ndp); 2907c657876SArnaldo Carvalho de Melo const int len = ndp_len + 2; 2917c657876SArnaldo Carvalho de Melo 2927c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) 2937c657876SArnaldo Carvalho de Melo return; 2947c657876SArnaldo Carvalho de Melo 2957c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len; 2967c657876SArnaldo Carvalho de Melo 2977c657876SArnaldo Carvalho de Melo ptr = skb_push(skb, len); 2987c657876SArnaldo Carvalho de Melo *ptr++ = DCCPO_NDP_COUNT; 2997c657876SArnaldo Carvalho de Melo *ptr++ = len; 3007c657876SArnaldo Carvalho de Melo dccp_encode_value_var(ndp, ptr, ndp_len); 3017c657876SArnaldo Carvalho de Melo } 3027c657876SArnaldo Carvalho de Melo } 3037c657876SArnaldo Carvalho de Melo 3047c657876SArnaldo Carvalho de Melo static inline int dccp_elapsed_time_len(const u32 elapsed_time) 3057c657876SArnaldo Carvalho de Melo { 306b1c9fe7bSIan McDonald return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; 3077c657876SArnaldo Carvalho de Melo } 3087c657876SArnaldo Carvalho de Melo 3097c657876SArnaldo Carvalho de Melo void dccp_insert_option_elapsed_time(struct sock *sk, 3107c657876SArnaldo Carvalho de Melo struct sk_buff *skb, 3117c657876SArnaldo Carvalho de Melo u32 elapsed_time) 3127c657876SArnaldo Carvalho de Melo { 313725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 3147c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 3157690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 3167690af3fSArnaldo Carvalho de Melo "CLIENT TX opt: " : "server TX opt: "; 3177c657876SArnaldo Carvalho de Melo #endif 3187c657876SArnaldo Carvalho de Melo const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); 3197c657876SArnaldo Carvalho de Melo const int len = 2 + elapsed_time_len; 3207c657876SArnaldo Carvalho de Melo unsigned char *to; 3217c657876SArnaldo Carvalho de Melo 3221bc09869SIan McDonald if (elapsed_time_len == 0) 3237c657876SArnaldo Carvalho de Melo return; 3247c657876SArnaldo Carvalho de Melo 3257c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { 3267690af3fSArnaldo Carvalho de Melo LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to " 3277690af3fSArnaldo Carvalho de Melo "insert elapsed time!\n"); 3287c657876SArnaldo Carvalho de Melo return; 3297c657876SArnaldo Carvalho de Melo } 3307c657876SArnaldo Carvalho de Melo 3317c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len; 3327c657876SArnaldo Carvalho de Melo 3337c657876SArnaldo Carvalho de Melo to = skb_push(skb, len); 3347c657876SArnaldo Carvalho de Melo *to++ = DCCPO_ELAPSED_TIME; 3357c657876SArnaldo Carvalho de Melo *to++ = len; 3367c657876SArnaldo Carvalho de Melo 3371bc09869SIan McDonald if (elapsed_time_len == 2) { 3381bc09869SIan McDonald const u16 var16 = htons((u16)elapsed_time); 3391bc09869SIan McDonald memcpy(to, &var16, 2); 3401bc09869SIan McDonald } else { 3411bc09869SIan McDonald const u32 var32 = htonl(elapsed_time); 3421bc09869SIan McDonald memcpy(to, &var32, 4); 3431bc09869SIan McDonald } 3447c657876SArnaldo Carvalho de Melo 3457c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sELAPSED_TIME=%u, len=%d, seqno=%llu\n", 3467c657876SArnaldo Carvalho de Melo debug_prefix, elapsed_time, 347f6ccf554SDavid S. Miller len, 348f6ccf554SDavid S. Miller (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); 3497c657876SArnaldo Carvalho de Melo } 3507c657876SArnaldo Carvalho de Melo 351d4b81ff7SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time); 3527c657876SArnaldo Carvalho de Melo 3537c657876SArnaldo Carvalho de Melo static void dccp_insert_option_ack_vector(struct sock *sk, struct sk_buff *skb) 3547c657876SArnaldo Carvalho de Melo { 3557c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 356725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 3577690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 3587690af3fSArnaldo Carvalho de Melo "CLIENT TX opt: " : "server TX opt: "; 3597c657876SArnaldo Carvalho de Melo #endif 3607c657876SArnaldo Carvalho de Melo struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts; 3617c657876SArnaldo Carvalho de Melo int len = ap->dccpap_buf_vector_len + 2; 3621bc09869SIan McDonald const u32 elapsed_time = now_delta(ap->dccpap_time) / 10; 3637c657876SArnaldo Carvalho de Melo unsigned char *to, *from; 3647c657876SArnaldo Carvalho de Melo 3657c657876SArnaldo Carvalho de Melo if (elapsed_time != 0) 3667c657876SArnaldo Carvalho de Melo dccp_insert_option_elapsed_time(sk, skb, elapsed_time); 3677c657876SArnaldo Carvalho de Melo 3687c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { 3697690af3fSArnaldo Carvalho de Melo LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to " 3707690af3fSArnaldo Carvalho de Melo "insert ACK Vector!\n"); 3717c657876SArnaldo Carvalho de Melo return; 3727c657876SArnaldo Carvalho de Melo } 3737c657876SArnaldo Carvalho de Melo 3747c657876SArnaldo Carvalho de Melo /* 3757c657876SArnaldo Carvalho de Melo * XXX: now we have just one ack vector sent record, so 3767c657876SArnaldo Carvalho de Melo * we have to wait for it to be cleared. 3777c657876SArnaldo Carvalho de Melo * 3787c657876SArnaldo Carvalho de Melo * Of course this is not acceptable, but this is just for 3797c657876SArnaldo Carvalho de Melo * basic testing now. 3807c657876SArnaldo Carvalho de Melo */ 3817c657876SArnaldo Carvalho de Melo if (ap->dccpap_ack_seqno != DCCP_MAX_SEQNO + 1) 3827c657876SArnaldo Carvalho de Melo return; 3837c657876SArnaldo Carvalho de Melo 3847c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len; 3857c657876SArnaldo Carvalho de Melo 3867c657876SArnaldo Carvalho de Melo to = skb_push(skb, len); 3877c657876SArnaldo Carvalho de Melo *to++ = DCCPO_ACK_VECTOR_0; 3887c657876SArnaldo Carvalho de Melo *to++ = len; 3897c657876SArnaldo Carvalho de Melo 3907c657876SArnaldo Carvalho de Melo len = ap->dccpap_buf_vector_len; 3917c657876SArnaldo Carvalho de Melo from = ap->dccpap_buf + ap->dccpap_buf_head; 3927c657876SArnaldo Carvalho de Melo 3937c657876SArnaldo Carvalho de Melo /* Check if buf_head wraps */ 3947c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_head + len > ap->dccpap_buf_len) { 3957690af3fSArnaldo Carvalho de Melo const unsigned int tailsize = (ap->dccpap_buf_len - 3967690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_head); 3977c657876SArnaldo Carvalho de Melo 3987c657876SArnaldo Carvalho de Melo memcpy(to, from, tailsize); 3997c657876SArnaldo Carvalho de Melo to += tailsize; 4007c657876SArnaldo Carvalho de Melo len -= tailsize; 4017c657876SArnaldo Carvalho de Melo from = ap->dccpap_buf; 4027c657876SArnaldo Carvalho de Melo } 4037c657876SArnaldo Carvalho de Melo 4047c657876SArnaldo Carvalho de Melo memcpy(to, from, len); 4057c657876SArnaldo Carvalho de Melo /* 4067c657876SArnaldo Carvalho de Melo * From draft-ietf-dccp-spec-11.txt: 4077c657876SArnaldo Carvalho de Melo * 4087c657876SArnaldo Carvalho de Melo * For each acknowledgement it sends, the HC-Receiver will add an 4097c657876SArnaldo Carvalho de Melo * acknowledgement record. ack_seqno will equal the HC-Receiver 4107c657876SArnaldo Carvalho de Melo * sequence number it used for the ack packet; ack_ptr will equal 4117690af3fSArnaldo Carvalho de Melo * buf_head; ack_ackno will equal buf_ackno; and ack_nonce will 4127690af3fSArnaldo Carvalho de Melo * equal buf_nonce. 4137c657876SArnaldo Carvalho de Melo * 4147c657876SArnaldo Carvalho de Melo * This implemention uses just one ack record for now. 4157c657876SArnaldo Carvalho de Melo */ 4167c657876SArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq; 4177c657876SArnaldo Carvalho de Melo ap->dccpap_ack_ptr = ap->dccpap_buf_head; 4187c657876SArnaldo Carvalho de Melo ap->dccpap_ack_ackno = ap->dccpap_buf_ackno; 4197c657876SArnaldo Carvalho de Melo ap->dccpap_ack_nonce = ap->dccpap_buf_nonce; 4207c657876SArnaldo Carvalho de Melo ap->dccpap_ack_vector_len = ap->dccpap_buf_vector_len; 4217c657876SArnaldo Carvalho de Melo 4227690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, " 4237690af3fSArnaldo Carvalho de Melo "ack_ackno=%llu\n", 4247c657876SArnaldo Carvalho de Melo debug_prefix, ap->dccpap_ack_vector_len, 425f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_seqno, 426f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_ackno); 4277c657876SArnaldo Carvalho de Melo } 4287c657876SArnaldo Carvalho de Melo 429d4b81ff7SArnaldo Carvalho de Melo void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) 4307c657876SArnaldo Carvalho de Melo { 4311bc09869SIan McDonald struct timeval tv; 4321bc09869SIan McDonald u32 now; 4331bc09869SIan McDonald 4341bc09869SIan McDonald do_gettimeofday(&tv); 4351bc09869SIan McDonald now = (tv.tv_sec * USEC_PER_SEC + tv.tv_usec) / 10; 4361bc09869SIan McDonald /* yes this will overflow but that is the point as we want a 4371bc09869SIan McDonald * 10 usec 32 bit timer which mean it wraps every 11.9 hours */ 4381bc09869SIan McDonald 4391bc09869SIan McDonald now = htonl(now); 4407c657876SArnaldo Carvalho de Melo dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now)); 4417c657876SArnaldo Carvalho de Melo } 4427c657876SArnaldo Carvalho de Melo 443d4b81ff7SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp); 444d4b81ff7SArnaldo Carvalho de Melo 4457690af3fSArnaldo Carvalho de Melo static void dccp_insert_option_timestamp_echo(struct sock *sk, 4467690af3fSArnaldo Carvalho de Melo struct sk_buff *skb) 4477c657876SArnaldo Carvalho de Melo { 4487c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 449725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 4507690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 4517690af3fSArnaldo Carvalho de Melo "CLIENT TX opt: " : "server TX opt: "; 4527c657876SArnaldo Carvalho de Melo #endif 4537c657876SArnaldo Carvalho de Melo u32 tstamp_echo; 4541bc09869SIan McDonald const u32 elapsed_time = now_delta(dp->dccps_timestamp_time) / 10; 4557c657876SArnaldo Carvalho de Melo const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); 4567c657876SArnaldo Carvalho de Melo const int len = 6 + elapsed_time_len; 4577c657876SArnaldo Carvalho de Melo unsigned char *to; 4587c657876SArnaldo Carvalho de Melo 4597c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { 4607690af3fSArnaldo Carvalho de Melo LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " 4617690af3fSArnaldo Carvalho de Melo "timestamp echo!\n"); 4627c657876SArnaldo Carvalho de Melo return; 4637c657876SArnaldo Carvalho de Melo } 4647c657876SArnaldo Carvalho de Melo 4657c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += len; 4667c657876SArnaldo Carvalho de Melo 4677c657876SArnaldo Carvalho de Melo to = skb_push(skb, len); 4687c657876SArnaldo Carvalho de Melo *to++ = DCCPO_TIMESTAMP_ECHO; 4697c657876SArnaldo Carvalho de Melo *to++ = len; 4707c657876SArnaldo Carvalho de Melo 4717c657876SArnaldo Carvalho de Melo tstamp_echo = htonl(dp->dccps_timestamp_echo); 4727c657876SArnaldo Carvalho de Melo memcpy(to, &tstamp_echo, 4); 4737c657876SArnaldo Carvalho de Melo to += 4; 4741bc09869SIan McDonald 4751bc09869SIan McDonald if (elapsed_time_len == 2) { 4761bc09869SIan McDonald const u16 var16 = htons((u16)elapsed_time); 4771bc09869SIan McDonald memcpy(to, &var16, 2); 4781bc09869SIan McDonald } else if (elapsed_time_len == 4) { 4791bc09869SIan McDonald const u32 var32 = htonl(elapsed_time); 4801bc09869SIan McDonald memcpy(to, &var32, 4); 4811bc09869SIan McDonald } 4827c657876SArnaldo Carvalho de Melo 4837c657876SArnaldo Carvalho de Melo dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, seqno=%llu\n", 4847c657876SArnaldo Carvalho de Melo debug_prefix, dp->dccps_timestamp_echo, 485f6ccf554SDavid S. Miller len, 486f6ccf554SDavid S. Miller (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); 4877c657876SArnaldo Carvalho de Melo 4887c657876SArnaldo Carvalho de Melo dp->dccps_timestamp_echo = 0; 4891bc09869SIan McDonald dp->dccps_timestamp_time.tv_sec = 0; 4901bc09869SIan McDonald dp->dccps_timestamp_time.tv_usec = 0; 4917c657876SArnaldo Carvalho de Melo } 4927c657876SArnaldo Carvalho de Melo 4937c657876SArnaldo Carvalho de Melo void dccp_insert_options(struct sock *sk, struct sk_buff *skb) 4947c657876SArnaldo Carvalho de Melo { 4957c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 4967c657876SArnaldo Carvalho de Melo 4977c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len = 0; 4987c657876SArnaldo Carvalho de Melo 4997c657876SArnaldo Carvalho de Melo if (dp->dccps_options.dccpo_send_ndp_count) 5007c657876SArnaldo Carvalho de Melo dccp_insert_option_ndp(sk, skb); 5017c657876SArnaldo Carvalho de Melo 5027c657876SArnaldo Carvalho de Melo if (!dccp_packet_without_ack(skb)) { 5037c657876SArnaldo Carvalho de Melo if (dp->dccps_options.dccpo_send_ack_vector && 5047690af3fSArnaldo Carvalho de Melo (dp->dccps_hc_rx_ackpkts->dccpap_buf_ackno != 5057690af3fSArnaldo Carvalho de Melo DCCP_MAX_SEQNO + 1)) 5067c657876SArnaldo Carvalho de Melo dccp_insert_option_ack_vector(sk, skb); 5077c657876SArnaldo Carvalho de Melo 5087c657876SArnaldo Carvalho de Melo if (dp->dccps_timestamp_echo != 0) 5097c657876SArnaldo Carvalho de Melo dccp_insert_option_timestamp_echo(sk, skb); 5107c657876SArnaldo Carvalho de Melo } 5117c657876SArnaldo Carvalho de Melo 5127c657876SArnaldo Carvalho de Melo ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb); 5137c657876SArnaldo Carvalho de Melo ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb); 5147c657876SArnaldo Carvalho de Melo 5157c657876SArnaldo Carvalho de Melo /* XXX: insert other options when appropriate */ 5167c657876SArnaldo Carvalho de Melo 5177c657876SArnaldo Carvalho de Melo if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) { 5187c657876SArnaldo Carvalho de Melo /* The length of all options has to be a multiple of 4 */ 5197c657876SArnaldo Carvalho de Melo int padding = DCCP_SKB_CB(skb)->dccpd_opt_len % 4; 5207c657876SArnaldo Carvalho de Melo 5217c657876SArnaldo Carvalho de Melo if (padding != 0) { 5227c657876SArnaldo Carvalho de Melo padding = 4 - padding; 5237c657876SArnaldo Carvalho de Melo memset(skb_push(skb, padding), 0, padding); 5247c657876SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_opt_len += padding; 5257c657876SArnaldo Carvalho de Melo } 5267c657876SArnaldo Carvalho de Melo } 5277c657876SArnaldo Carvalho de Melo } 5287c657876SArnaldo Carvalho de Melo 529a1d3a355SArnaldo Carvalho de Melo struct dccp_ackpkts *dccp_ackpkts_alloc(const unsigned int len, 530a1d3a355SArnaldo Carvalho de Melo const unsigned int __nocast priority) 5317c657876SArnaldo Carvalho de Melo { 5327c657876SArnaldo Carvalho de Melo struct dccp_ackpkts *ap = kmalloc(sizeof(*ap) + len, priority); 5337c657876SArnaldo Carvalho de Melo 5347c657876SArnaldo Carvalho de Melo if (ap != NULL) { 535725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 5367c657876SArnaldo Carvalho de Melo memset(ap->dccpap_buf, 0xFF, len); 5377c657876SArnaldo Carvalho de Melo #endif 5387c657876SArnaldo Carvalho de Melo ap->dccpap_buf_len = len; 5397690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_head = 5407690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_tail = 5417690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_len - 1; 5427690af3fSArnaldo Carvalho de Melo ap->dccpap_buf_ackno = 5437690af3fSArnaldo Carvalho de Melo ap->dccpap_ack_ackno = 5447690af3fSArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; 5457c657876SArnaldo Carvalho de Melo ap->dccpap_buf_nonce = ap->dccpap_buf_nonce = 0; 5467c657876SArnaldo Carvalho de Melo ap->dccpap_ack_ptr = 0; 5471bc09869SIan McDonald ap->dccpap_time.tv_sec = 0; 5481bc09869SIan McDonald ap->dccpap_time.tv_usec = 0; 5497c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len = ap->dccpap_ack_vector_len = 0; 5507c657876SArnaldo Carvalho de Melo } 5517c657876SArnaldo Carvalho de Melo 5527c657876SArnaldo Carvalho de Melo return ap; 5537c657876SArnaldo Carvalho de Melo } 5547c657876SArnaldo Carvalho de Melo 5557c657876SArnaldo Carvalho de Melo void dccp_ackpkts_free(struct dccp_ackpkts *ap) 5567c657876SArnaldo Carvalho de Melo { 5577c657876SArnaldo Carvalho de Melo if (ap != NULL) { 558725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 5597c657876SArnaldo Carvalho de Melo memset(ap, 0xFF, sizeof(*ap) + ap->dccpap_buf_len); 5607c657876SArnaldo Carvalho de Melo #endif 5617c657876SArnaldo Carvalho de Melo kfree(ap); 5627c657876SArnaldo Carvalho de Melo } 5637c657876SArnaldo Carvalho de Melo } 5647c657876SArnaldo Carvalho de Melo 5657c657876SArnaldo Carvalho de Melo static inline u8 dccp_ackpkts_state(const struct dccp_ackpkts *ap, 5667c657876SArnaldo Carvalho de Melo const unsigned int index) 5677c657876SArnaldo Carvalho de Melo { 5687c657876SArnaldo Carvalho de Melo return ap->dccpap_buf[index] & DCCP_ACKPKTS_STATE_MASK; 5697c657876SArnaldo Carvalho de Melo } 5707c657876SArnaldo Carvalho de Melo 5717c657876SArnaldo Carvalho de Melo static inline u8 dccp_ackpkts_len(const struct dccp_ackpkts *ap, 5727c657876SArnaldo Carvalho de Melo const unsigned int index) 5737c657876SArnaldo Carvalho de Melo { 5747c657876SArnaldo Carvalho de Melo return ap->dccpap_buf[index] & DCCP_ACKPKTS_LEN_MASK; 5757c657876SArnaldo Carvalho de Melo } 5767c657876SArnaldo Carvalho de Melo 5777c657876SArnaldo Carvalho de Melo /* 5787c657876SArnaldo Carvalho de Melo * If several packets are missing, the HC-Receiver may prefer to enter multiple 5797c657876SArnaldo Carvalho de Melo * bytes with run length 0, rather than a single byte with a larger run length; 5807c657876SArnaldo Carvalho de Melo * this simplifies table updates if one of the missing packets arrives. 5817c657876SArnaldo Carvalho de Melo */ 5827c657876SArnaldo Carvalho de Melo static inline int dccp_ackpkts_set_buf_head_state(struct dccp_ackpkts *ap, 5837c657876SArnaldo Carvalho de Melo const unsigned int packets, 5847c657876SArnaldo Carvalho de Melo const unsigned char state) 5857c657876SArnaldo Carvalho de Melo { 5867c657876SArnaldo Carvalho de Melo unsigned int gap; 5877c657876SArnaldo Carvalho de Melo signed long new_head; 5887c657876SArnaldo Carvalho de Melo 5897c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_vector_len + packets > ap->dccpap_buf_len) 5907c657876SArnaldo Carvalho de Melo return -ENOBUFS; 5917c657876SArnaldo Carvalho de Melo 5927c657876SArnaldo Carvalho de Melo gap = packets - 1; 5937c657876SArnaldo Carvalho de Melo new_head = ap->dccpap_buf_head - packets; 5947c657876SArnaldo Carvalho de Melo 5957c657876SArnaldo Carvalho de Melo if (new_head < 0) { 5967c657876SArnaldo Carvalho de Melo if (gap > 0) { 5977c657876SArnaldo Carvalho de Melo memset(ap->dccpap_buf, DCCP_ACKPKTS_STATE_NOT_RECEIVED, 5987c657876SArnaldo Carvalho de Melo gap + new_head + 1); 5997c657876SArnaldo Carvalho de Melo gap = -new_head; 6007c657876SArnaldo Carvalho de Melo } 6017c657876SArnaldo Carvalho de Melo new_head += ap->dccpap_buf_len; 6027c657876SArnaldo Carvalho de Melo } 6037c657876SArnaldo Carvalho de Melo 6047c657876SArnaldo Carvalho de Melo ap->dccpap_buf_head = new_head; 6057c657876SArnaldo Carvalho de Melo 6067c657876SArnaldo Carvalho de Melo if (gap > 0) 6077c657876SArnaldo Carvalho de Melo memset(ap->dccpap_buf + ap->dccpap_buf_head + 1, 6087c657876SArnaldo Carvalho de Melo DCCP_ACKPKTS_STATE_NOT_RECEIVED, gap); 6097c657876SArnaldo Carvalho de Melo 6107c657876SArnaldo Carvalho de Melo ap->dccpap_buf[ap->dccpap_buf_head] = state; 6117c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len += packets; 6127c657876SArnaldo Carvalho de Melo return 0; 6137c657876SArnaldo Carvalho de Melo } 6147c657876SArnaldo Carvalho de Melo 6157c657876SArnaldo Carvalho de Melo /* 6167c657876SArnaldo Carvalho de Melo * Implements the draft-ietf-dccp-spec-11.txt Appendix A 6177c657876SArnaldo Carvalho de Melo */ 6187c657876SArnaldo Carvalho de Melo int dccp_ackpkts_add(struct dccp_ackpkts *ap, u64 ackno, u8 state) 6197c657876SArnaldo Carvalho de Melo { 6207c657876SArnaldo Carvalho de Melo /* 6217c657876SArnaldo Carvalho de Melo * Check at the right places if the buffer is full, if it is, tell the 6227c657876SArnaldo Carvalho de Melo * caller to start dropping packets till the HC-Sender acks our ACK 6237c657876SArnaldo Carvalho de Melo * vectors, when we will free up space in dccpap_buf. 6247c657876SArnaldo Carvalho de Melo * 6257c657876SArnaldo Carvalho de Melo * We may well decide to do buffer compression, etc, but for now lets 6267c657876SArnaldo Carvalho de Melo * just drop. 6277c657876SArnaldo Carvalho de Melo * 6287c657876SArnaldo Carvalho de Melo * From Appendix A: 6297c657876SArnaldo Carvalho de Melo * 6307690af3fSArnaldo Carvalho de Melo * Of course, the circular buffer may overflow, either when the 6317690af3fSArnaldo Carvalho de Melo * HC-Sender is sending data at a very high rate, when the 6327690af3fSArnaldo Carvalho de Melo * HC-Receiver's acknowledgements are not reaching the HC-Sender, 6337690af3fSArnaldo Carvalho de Melo * or when the HC-Sender is forgetting to acknowledge those acks 6347690af3fSArnaldo Carvalho de Melo * (so the HC-Receiver is unable to clean up old state). In this 6357690af3fSArnaldo Carvalho de Melo * case, the HC-Receiver should either compress the buffer (by 6367690af3fSArnaldo Carvalho de Melo * increasing run lengths when possible), transfer its state to 6377690af3fSArnaldo Carvalho de Melo * a larger buffer, or, as a last resort, drop all received 6387690af3fSArnaldo Carvalho de Melo * packets, without processing them whatsoever, until its buffer 6397690af3fSArnaldo Carvalho de Melo * shrinks again. 6407c657876SArnaldo Carvalho de Melo */ 6417c657876SArnaldo Carvalho de Melo 6427c657876SArnaldo Carvalho de Melo /* See if this is the first ackno being inserted */ 6437c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_vector_len == 0) { 6447c657876SArnaldo Carvalho de Melo ap->dccpap_buf[ap->dccpap_buf_head] = state; 6457c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len = 1; 6467c657876SArnaldo Carvalho de Melo } else if (after48(ackno, ap->dccpap_buf_ackno)) { 6477690af3fSArnaldo Carvalho de Melo const u64 delta = dccp_delta_seqno(ap->dccpap_buf_ackno, 6487690af3fSArnaldo Carvalho de Melo ackno); 6497c657876SArnaldo Carvalho de Melo 6507c657876SArnaldo Carvalho de Melo /* 6517690af3fSArnaldo Carvalho de Melo * Look if the state of this packet is the same as the 6527690af3fSArnaldo Carvalho de Melo * previous ackno and if so if we can bump the head len. 6537c657876SArnaldo Carvalho de Melo */ 6547c657876SArnaldo Carvalho de Melo if (delta == 1 && 6557c657876SArnaldo Carvalho de Melo dccp_ackpkts_state(ap, ap->dccpap_buf_head) == state && 6567690af3fSArnaldo Carvalho de Melo (dccp_ackpkts_len(ap, ap->dccpap_buf_head) < 6577690af3fSArnaldo Carvalho de Melo DCCP_ACKPKTS_LEN_MASK)) 6587c657876SArnaldo Carvalho de Melo ap->dccpap_buf[ap->dccpap_buf_head]++; 6597c657876SArnaldo Carvalho de Melo else if (dccp_ackpkts_set_buf_head_state(ap, delta, state)) 6607c657876SArnaldo Carvalho de Melo return -ENOBUFS; 6617c657876SArnaldo Carvalho de Melo } else { 6627c657876SArnaldo Carvalho de Melo /* 6637c657876SArnaldo Carvalho de Melo * A.1.2. Old Packets 6647c657876SArnaldo Carvalho de Melo * 6657690af3fSArnaldo Carvalho de Melo * When a packet with Sequence Number S arrives, and 6667690af3fSArnaldo Carvalho de Melo * S <= buf_ackno, the HC-Receiver will scan the table 6677690af3fSArnaldo Carvalho de Melo * for the byte corresponding to S. (Indexing structures 6687690af3fSArnaldo Carvalho de Melo * could reduce the complexity of this scan.) 6697c657876SArnaldo Carvalho de Melo */ 6707c657876SArnaldo Carvalho de Melo u64 delta = dccp_delta_seqno(ackno, ap->dccpap_buf_ackno); 6717c657876SArnaldo Carvalho de Melo unsigned int index = ap->dccpap_buf_head; 6727c657876SArnaldo Carvalho de Melo 6737c657876SArnaldo Carvalho de Melo while (1) { 6747c657876SArnaldo Carvalho de Melo const u8 len = dccp_ackpkts_len(ap, index); 6757c657876SArnaldo Carvalho de Melo const u8 state = dccp_ackpkts_state(ap, index); 6767c657876SArnaldo Carvalho de Melo /* 6777690af3fSArnaldo Carvalho de Melo * valid packets not yet in dccpap_buf have a reserved 6787690af3fSArnaldo Carvalho de Melo * entry, with a len equal to 0. 6797c657876SArnaldo Carvalho de Melo */ 6807c657876SArnaldo Carvalho de Melo if (state == DCCP_ACKPKTS_STATE_NOT_RECEIVED && 6817690af3fSArnaldo Carvalho de Melo len == 0 && delta == 0) { /* Found our 6827690af3fSArnaldo Carvalho de Melo reserved seat! */ 683f6ccf554SDavid S. Miller dccp_pr_debug("Found %llu reserved seat!\n", 684f6ccf554SDavid S. Miller (unsigned long long) ackno); 6857c657876SArnaldo Carvalho de Melo ap->dccpap_buf[index] = state; 6867c657876SArnaldo Carvalho de Melo goto out; 6877c657876SArnaldo Carvalho de Melo } 6887c657876SArnaldo Carvalho de Melo /* len == 0 means one packet */ 6897c657876SArnaldo Carvalho de Melo if (delta < len + 1) 6907c657876SArnaldo Carvalho de Melo goto out_duplicate; 6917c657876SArnaldo Carvalho de Melo 6927c657876SArnaldo Carvalho de Melo delta -= len + 1; 6937c657876SArnaldo Carvalho de Melo if (++index == ap->dccpap_buf_len) 6947c657876SArnaldo Carvalho de Melo index = 0; 6957c657876SArnaldo Carvalho de Melo } 6967c657876SArnaldo Carvalho de Melo } 6977c657876SArnaldo Carvalho de Melo 6987c657876SArnaldo Carvalho de Melo ap->dccpap_buf_ackno = ackno; 6991bc09869SIan McDonald do_gettimeofday(&ap->dccpap_time); 7007c657876SArnaldo Carvalho de Melo out: 7017c657876SArnaldo Carvalho de Melo dccp_pr_debug(""); 7027c657876SArnaldo Carvalho de Melo dccp_ackpkts_print(ap); 7037c657876SArnaldo Carvalho de Melo return 0; 7047c657876SArnaldo Carvalho de Melo 7057c657876SArnaldo Carvalho de Melo out_duplicate: 7067c657876SArnaldo Carvalho de Melo /* Duplicate packet */ 7077690af3fSArnaldo Carvalho de Melo dccp_pr_debug("Received a dup or already considered lost " 7087690af3fSArnaldo Carvalho de Melo "packet: %llu\n", (unsigned long long) ackno); 7097c657876SArnaldo Carvalho de Melo return -EILSEQ; 7107c657876SArnaldo Carvalho de Melo } 7117c657876SArnaldo Carvalho de Melo 712725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 7137690af3fSArnaldo Carvalho de Melo void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, 7147690af3fSArnaldo Carvalho de Melo int len) 7157c657876SArnaldo Carvalho de Melo { 7167c657876SArnaldo Carvalho de Melo if (!dccp_debug) 7177c657876SArnaldo Carvalho de Melo return; 7187c657876SArnaldo Carvalho de Melo 719f6ccf554SDavid S. Miller printk("ACK vector len=%d, ackno=%llu |", len, 720f6ccf554SDavid S. Miller (unsigned long long) ackno); 7217c657876SArnaldo Carvalho de Melo 7227c657876SArnaldo Carvalho de Melo while (len--) { 7237c657876SArnaldo Carvalho de Melo const u8 state = (*vector & DCCP_ACKPKTS_STATE_MASK) >> 6; 7247c657876SArnaldo Carvalho de Melo const u8 rl = (*vector & DCCP_ACKPKTS_LEN_MASK); 7257c657876SArnaldo Carvalho de Melo 7267c657876SArnaldo Carvalho de Melo printk("%d,%d|", state, rl); 7277c657876SArnaldo Carvalho de Melo ++vector; 7287c657876SArnaldo Carvalho de Melo } 7297c657876SArnaldo Carvalho de Melo 7307c657876SArnaldo Carvalho de Melo printk("\n"); 7317c657876SArnaldo Carvalho de Melo } 7327c657876SArnaldo Carvalho de Melo 7337c657876SArnaldo Carvalho de Melo void dccp_ackpkts_print(const struct dccp_ackpkts *ap) 7347c657876SArnaldo Carvalho de Melo { 7357c657876SArnaldo Carvalho de Melo dccp_ackvector_print(ap->dccpap_buf_ackno, 7367c657876SArnaldo Carvalho de Melo ap->dccpap_buf + ap->dccpap_buf_head, 7377c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len); 7387c657876SArnaldo Carvalho de Melo } 7397c657876SArnaldo Carvalho de Melo #endif 7407c657876SArnaldo Carvalho de Melo 7417c657876SArnaldo Carvalho de Melo static void dccp_ackpkts_trow_away_ack_record(struct dccp_ackpkts *ap) 7427c657876SArnaldo Carvalho de Melo { 7437c657876SArnaldo Carvalho de Melo /* 7447c657876SArnaldo Carvalho de Melo * As we're keeping track of the ack vector size 7457c657876SArnaldo Carvalho de Melo * (dccpap_buf_vector_len) and the sent ack vector size 7467c657876SArnaldo Carvalho de Melo * (dccpap_ack_vector_len) we don't need dccpap_buf_tail at all, but 7477690af3fSArnaldo Carvalho de Melo * keep this code here as in the future we'll implement a vector of 7487690af3fSArnaldo Carvalho de Melo * ack records, as suggested in draft-ietf-dccp-spec-11.txt 7497690af3fSArnaldo Carvalho de Melo * Appendix A. -acme 7507c657876SArnaldo Carvalho de Melo */ 7517c657876SArnaldo Carvalho de Melo #if 0 7527c657876SArnaldo Carvalho de Melo ap->dccpap_buf_tail = ap->dccpap_ack_ptr + 1; 7537c657876SArnaldo Carvalho de Melo if (ap->dccpap_buf_tail >= ap->dccpap_buf_len) 7547c657876SArnaldo Carvalho de Melo ap->dccpap_buf_tail -= ap->dccpap_buf_len; 7557c657876SArnaldo Carvalho de Melo #endif 7567c657876SArnaldo Carvalho de Melo ap->dccpap_buf_vector_len -= ap->dccpap_ack_vector_len; 7577c657876SArnaldo Carvalho de Melo } 7587c657876SArnaldo Carvalho de Melo 7597c657876SArnaldo Carvalho de Melo void dccp_ackpkts_check_rcv_ackno(struct dccp_ackpkts *ap, struct sock *sk, 7607c657876SArnaldo Carvalho de Melo u64 ackno) 7617c657876SArnaldo Carvalho de Melo { 7627c657876SArnaldo Carvalho de Melo /* Check if we actually sent an ACK vector */ 7637c657876SArnaldo Carvalho de Melo if (ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1) 7647c657876SArnaldo Carvalho de Melo return; 7657c657876SArnaldo Carvalho de Melo 7667c657876SArnaldo Carvalho de Melo if (ackno == ap->dccpap_ack_seqno) { 767725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 7687c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 7697690af3fSArnaldo Carvalho de Melo const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 7707690af3fSArnaldo Carvalho de Melo "CLIENT rx ack: " : "server rx ack: "; 7717c657876SArnaldo Carvalho de Melo #endif 7727690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, " 7737690af3fSArnaldo Carvalho de Melo "ack_ackno=%llu, ACKED!\n", 7747c657876SArnaldo Carvalho de Melo debug_prefix, 1, 775f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_seqno, 776f6ccf554SDavid S. Miller (unsigned long long) ap->dccpap_ack_ackno); 7777c657876SArnaldo Carvalho de Melo dccp_ackpkts_trow_away_ack_record(ap); 7787c657876SArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; 7797c657876SArnaldo Carvalho de Melo } 7807c657876SArnaldo Carvalho de Melo } 7817c657876SArnaldo Carvalho de Melo 7827c657876SArnaldo Carvalho de Melo static void dccp_ackpkts_check_rcv_ackvector(struct dccp_ackpkts *ap, 7837c657876SArnaldo Carvalho de Melo struct sock *sk, u64 ackno, 7847c657876SArnaldo Carvalho de Melo const unsigned char len, 7857c657876SArnaldo Carvalho de Melo const unsigned char *vector) 7867c657876SArnaldo Carvalho de Melo { 7877c657876SArnaldo Carvalho de Melo unsigned char i; 7887c657876SArnaldo Carvalho de Melo 7897c657876SArnaldo Carvalho de Melo /* Check if we actually sent an ACK vector */ 7907c657876SArnaldo Carvalho de Melo if (ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1) 7917c657876SArnaldo Carvalho de Melo return; 7927c657876SArnaldo Carvalho de Melo /* 7937690af3fSArnaldo Carvalho de Melo * We're in the receiver half connection, so if the received an ACK 7947690af3fSArnaldo Carvalho de Melo * vector ackno (e.g. 50) before dccpap_ack_seqno (e.g. 52), we're 7957690af3fSArnaldo Carvalho de Melo * not interested. 7967c657876SArnaldo Carvalho de Melo * 7977c657876SArnaldo Carvalho de Melo * Extra explanation with example: 7987c657876SArnaldo Carvalho de Melo * 7997c657876SArnaldo Carvalho de Melo * if we received an ACK vector with ackno 50, it can only be acking 8007c657876SArnaldo Carvalho de Melo * 50, 49, 48, etc, not 52 (the seqno for the ACK vector we sent). 8017c657876SArnaldo Carvalho de Melo */ 8027690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug("is %llu < %llu? ", ackno, ap->dccpap_ack_seqno); */ 8037c657876SArnaldo Carvalho de Melo if (before48(ackno, ap->dccpap_ack_seqno)) { 8047690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("yes\n"); */ 8057c657876SArnaldo Carvalho de Melo return; 8067c657876SArnaldo Carvalho de Melo } 8077690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("no\n"); */ 8087c657876SArnaldo Carvalho de Melo 8097c657876SArnaldo Carvalho de Melo i = len; 8107c657876SArnaldo Carvalho de Melo while (i--) { 8117c657876SArnaldo Carvalho de Melo const u8 rl = (*vector & DCCP_ACKPKTS_LEN_MASK); 8127c657876SArnaldo Carvalho de Melo u64 ackno_end_rl; 8137c657876SArnaldo Carvalho de Melo 8147c657876SArnaldo Carvalho de Melo dccp_set_seqno(&ackno_end_rl, ackno - rl); 8157c657876SArnaldo Carvalho de Melo 8167690af3fSArnaldo Carvalho de Melo /* 8177690af3fSArnaldo Carvalho de Melo * dccp_pr_debug("is %llu <= %llu <= %llu? ", ackno_end_rl, 8187690af3fSArnaldo Carvalho de Melo * ap->dccpap_ack_seqno, ackno); 8197690af3fSArnaldo Carvalho de Melo */ 8207c657876SArnaldo Carvalho de Melo if (between48(ap->dccpap_ack_seqno, ackno_end_rl, ackno)) { 8217690af3fSArnaldo Carvalho de Melo const u8 state = (*vector & 8227690af3fSArnaldo Carvalho de Melo DCCP_ACKPKTS_STATE_MASK) >> 6; 8237690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("yes\n"); */ 8247c657876SArnaldo Carvalho de Melo 8257c657876SArnaldo Carvalho de Melo if (state != DCCP_ACKPKTS_STATE_NOT_RECEIVED) { 826725ba8eeSArnaldo Carvalho de Melo #ifdef CONFIG_IP_DCCP_DEBUG 8277c657876SArnaldo Carvalho de Melo struct dccp_sock *dp = dccp_sk(sk); 8287690af3fSArnaldo Carvalho de Melo const char *debug_prefix = 8297690af3fSArnaldo Carvalho de Melo dp->dccps_role == DCCP_ROLE_CLIENT ? 8307690af3fSArnaldo Carvalho de Melo "CLIENT rx ack: " : "server rx ack: "; 8317c657876SArnaldo Carvalho de Melo #endif 8327690af3fSArnaldo Carvalho de Melo dccp_pr_debug("%sACK vector 0, len=%d, " 8337690af3fSArnaldo Carvalho de Melo "ack_seqno=%llu, ack_ackno=%llu, " 8347690af3fSArnaldo Carvalho de Melo "ACKED!\n", 8357c657876SArnaldo Carvalho de Melo debug_prefix, len, 836f6ccf554SDavid S. Miller (unsigned long long) 837f6ccf554SDavid S. Miller ap->dccpap_ack_seqno, 838f6ccf554SDavid S. Miller (unsigned long long) 839f6ccf554SDavid S. Miller ap->dccpap_ack_ackno); 8407c657876SArnaldo Carvalho de Melo dccp_ackpkts_trow_away_ack_record(ap); 8417c657876SArnaldo Carvalho de Melo } 8427c657876SArnaldo Carvalho de Melo /* 8437690af3fSArnaldo Carvalho de Melo * If dccpap_ack_seqno was not received, no problem 8447690af3fSArnaldo Carvalho de Melo * we'll send another ACK vector. 8457c657876SArnaldo Carvalho de Melo */ 8467c657876SArnaldo Carvalho de Melo ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; 8477c657876SArnaldo Carvalho de Melo break; 8487c657876SArnaldo Carvalho de Melo } 8497690af3fSArnaldo Carvalho de Melo /* dccp_pr_debug_cat("no\n"); */ 8507c657876SArnaldo Carvalho de Melo 8517c657876SArnaldo Carvalho de Melo dccp_set_seqno(&ackno, ackno_end_rl - 1); 8527c657876SArnaldo Carvalho de Melo ++vector; 8537c657876SArnaldo Carvalho de Melo } 8547c657876SArnaldo Carvalho de Melo } 855