xref: /openbmc/linux/net/dccp/options.c (revision b1c9fe7b)
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