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