blob: 7db801ec1ab9c231e28d8c9f6a9de911f885824c [file] [log] [blame]
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001/*
2 * net/dccp/ccids/ccid3.c
3 *
4 * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
Ian McDonalde6bccd32006-08-26 19:01:30 -07005 * Copyright (c) 2005-6 Ian McDonald <ian.mcdonald@jandi.co.nz>
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07006 *
7 * An implementation of the DCCP protocol
8 *
9 * This code has been developed by the University of Waikato WAND
10 * research group. For further information please see http://www.wand.net.nz/
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070011 *
12 * This code also uses code from Lulea University, rereleased as GPL by its
13 * authors:
14 * Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon
15 *
16 * Changes to meet Linux coding standards, to make it meet latest ccid3 draft
17 * and to make it work as a loadable module in the DCCP stack written by
18 * Arnaldo Carvalho de Melo <acme@conectiva.com.br>.
19 *
20 * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
21 *
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 */
36
37#include "../ccid.h"
38#include "../dccp.h"
Arnaldo Carvalho de Melo4524b252005-08-27 23:18:26 -030039#include "lib/packet_history.h"
Arnaldo Carvalho de Meloae6706f2005-08-27 23:03:09 -030040#include "lib/loss_interval.h"
Arnaldo Carvalho de Melo36729c12005-08-28 00:47:15 -030041#include "lib/tfrc.h"
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070042#include "ccid3.h"
43
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -030044/*
Arnaldo Carvalho de Melo0ba7a3b2005-09-09 02:28:47 -030045 * Reason for maths here is to avoid 32 bit overflow when a is big.
46 * With this we get close to the limit.
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -030047 */
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -080048static u32 usecs_div(const u32 a, const u32 b)
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -030049{
Arnaldo Carvalho de Melo0ba7a3b2005-09-09 02:28:47 -030050 const u32 div = a < (UINT_MAX / (USEC_PER_SEC / 10)) ? 10 :
51 a < (UINT_MAX / (USEC_PER_SEC / 50)) ? 50 :
52 a < (UINT_MAX / (USEC_PER_SEC / 100)) ? 100 :
53 a < (UINT_MAX / (USEC_PER_SEC / 500)) ? 500 :
54 a < (UINT_MAX / (USEC_PER_SEC / 1000)) ? 1000 :
55 a < (UINT_MAX / (USEC_PER_SEC / 5000)) ? 5000 :
56 a < (UINT_MAX / (USEC_PER_SEC / 10000)) ? 10000 :
57 a < (UINT_MAX / (USEC_PER_SEC / 50000)) ? 50000 :
58 100000;
59 const u32 tmp = a * (USEC_PER_SEC / div);
60 return (b >= 2 * div) ? tmp / (b / div) : tmp;
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -030061}
62
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070063
Gerrit Renker56724aa2006-11-20 18:28:09 -020064
65#ifdef CONFIG_IP_DCCP_CCID3_DEBUG
66static int ccid3_debug;
67#define ccid3_pr_debug(format, a...) DCCP_PR_DEBUG(ccid3_debug, format, ##a)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070068#else
69#define ccid3_pr_debug(format, a...)
70#endif
71
Arnaldo Carvalho de Meloa1d3a352005-08-13 22:42:25 -030072static struct dccp_tx_hist *ccid3_tx_hist;
73static struct dccp_rx_hist *ccid3_rx_hist;
Arnaldo Carvalho de Meloae6706f2005-08-27 23:03:09 -030074static struct dccp_li_hist *ccid3_li_hist;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070075
Gerrit Renker56724aa2006-11-20 18:28:09 -020076#ifdef CONFIG_IP_DCCP_CCID3_DEBUG
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070077static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state)
78{
79 static char *ccid3_state_names[] = {
80 [TFRC_SSTATE_NO_SENT] = "NO_SENT",
81 [TFRC_SSTATE_NO_FBACK] = "NO_FBACK",
82 [TFRC_SSTATE_FBACK] = "FBACK",
83 [TFRC_SSTATE_TERM] = "TERM",
84 };
85
86 return ccid3_state_names[state];
87}
88#endif
89
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -080090static void ccid3_hc_tx_set_state(struct sock *sk,
91 enum ccid3_hc_tx_states state)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070092{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -030093 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070094 enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state;
95
96 ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -030097 dccp_role(sk), sk, ccid3_tx_state_name(oldstate),
98 ccid3_tx_state_name(state));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -070099 WARN_ON(state == oldstate);
100 hctx->ccid3hctx_state = state;
101}
102
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700103/* Calculate new t_ipi (inter packet interval) by t_ipi = s / X_inst */
104static inline void ccid3_calc_new_t_ipi(struct ccid3_hc_tx_sock *hctx)
105{
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -0300106 /*
107 * If no feedback spec says t_ipi is 1 second (set elsewhere and then
108 * doubles after every no feedback timer (separate function)
109 */
110 if (hctx->ccid3hctx_state != TFRC_SSTATE_NO_FBACK)
111 hctx->ccid3hctx_t_ipi = usecs_div(hctx->ccid3hctx_s,
112 hctx->ccid3hctx_x);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700113}
114
115/* Calculate new delta by delta = min(t_ipi / 2, t_gran / 2) */
116static inline void ccid3_calc_new_delta(struct ccid3_hc_tx_sock *hctx)
117{
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300118 hctx->ccid3hctx_delta = min_t(u32, hctx->ccid3hctx_t_ipi / 2,
119 TFRC_OPSYS_HALF_TIME_GRAN);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700120}
121
122/*
123 * Update X by
124 * If (p > 0)
125 * x_calc = calcX(s, R, p);
126 * X = max(min(X_calc, 2 * X_recv), s / t_mbi);
127 * Else
128 * If (now - tld >= R)
129 * X = max(min(2 * X, 2 * X_recv), s / R);
130 * tld = now;
131 */
132static void ccid3_hc_tx_update_x(struct sock *sk)
133{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300134 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700135
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300136 /* To avoid large error in calcX */
137 if (hctx->ccid3hctx_p >= TFRC_SMALLEST_P) {
Arnaldo Carvalho de Melo36729c12005-08-28 00:47:15 -0300138 hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s,
139 hctx->ccid3hctx_rtt,
140 hctx->ccid3hctx_p);
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300141 hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_calc,
142 2 * hctx->ccid3hctx_x_recv),
143 (hctx->ccid3hctx_s /
144 TFRC_MAX_BACK_OFF_TIME));
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300145 } else {
146 struct timeval now;
147
Arnaldo Carvalho de Melob0e56782005-09-09 02:38:35 -0300148 dccp_timestamp(sk, &now);
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300149 if (timeval_delta(&now, &hctx->ccid3hctx_t_ld) >=
150 hctx->ccid3hctx_rtt) {
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -0300151 hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_recv,
152 hctx->ccid3hctx_x) * 2,
153 usecs_div(hctx->ccid3hctx_s,
154 hctx->ccid3hctx_rtt));
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300155 hctx->ccid3hctx_t_ld = now;
156 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700157 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700158}
159
160static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
161{
162 struct sock *sk = (struct sock *)data;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700163 unsigned long next_tmout = 0;
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300164 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700165
166 bh_lock_sock(sk);
167 if (sock_owned_by_user(sk)) {
168 /* Try again later. */
169 /* XXX: set some sensible MIB */
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300170 sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
171 jiffies + HZ / 5);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700172 goto out;
173 }
174
175 ccid3_pr_debug("%s, sk=%p, state=%s\n", dccp_role(sk), sk,
176 ccid3_tx_state_name(hctx->ccid3hctx_state));
177
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700178 switch (hctx->ccid3hctx_state) {
179 case TFRC_SSTATE_TERM:
180 goto out;
181 case TFRC_SSTATE_NO_FBACK:
182 /* Halve send rate */
183 hctx->ccid3hctx_x /= 2;
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -0300184 if (hctx->ccid3hctx_x < (hctx->ccid3hctx_s /
185 TFRC_MAX_BACK_OFF_TIME))
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300186 hctx->ccid3hctx_x = (hctx->ccid3hctx_s /
187 TFRC_MAX_BACK_OFF_TIME);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700188
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300189 ccid3_pr_debug("%s, sk=%p, state=%s, updated tx rate to %d "
190 "bytes/s\n",
191 dccp_role(sk), sk,
192 ccid3_tx_state_name(hctx->ccid3hctx_state),
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700193 hctx->ccid3hctx_x);
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -0300194 next_tmout = max_t(u32, 2 * usecs_div(hctx->ccid3hctx_s,
195 hctx->ccid3hctx_x),
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300196 TFRC_INITIAL_TIMEOUT);
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300197 /*
198 * FIXME - not sure above calculation is correct. See section
199 * 5 of CCID3 11 should adjust tx_t_ipi and double that to
200 * achieve it really
201 */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700202 break;
203 case TFRC_SSTATE_FBACK:
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300204 /*
205 * Check if IDLE since last timeout and recv rate is less than
206 * 4 packets per RTT
207 */
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300208 if (!hctx->ccid3hctx_idle ||
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -0300209 (hctx->ccid3hctx_x_recv >=
210 4 * usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt))) {
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300211 ccid3_pr_debug("%s, sk=%p, state=%s, not idle\n",
212 dccp_role(sk), sk,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700213 ccid3_tx_state_name(hctx->ccid3hctx_state));
214 /* Halve sending rate */
215
216 /* If (X_calc > 2 * X_recv)
217 * X_recv = max(X_recv / 2, s / (2 * t_mbi));
218 * Else
219 * X_recv = X_calc / 4;
220 */
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300221 BUG_ON(hctx->ccid3hctx_p >= TFRC_SMALLEST_P &&
222 hctx->ccid3hctx_x_calc == 0);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700223
224 /* check also if p is zero -> x_calc is infinity? */
225 if (hctx->ccid3hctx_p < TFRC_SMALLEST_P ||
226 hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv)
227 hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2,
228 hctx->ccid3hctx_s / (2 * TFRC_MAX_BACK_OFF_TIME));
229 else
230 hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc / 4;
231
232 /* Update sending rate */
233 ccid3_hc_tx_update_x(sk);
234 }
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -0300235 /*
236 * Schedule no feedback timer to expire in
237 * max(4 * R, 2 * s / X)
238 */
Arnaldo Carvalho de Meloc68e64c2005-08-21 05:07:37 -0300239 next_tmout = max_t(u32, hctx->ccid3hctx_t_rto,
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -0300240 2 * usecs_div(hctx->ccid3hctx_s,
241 hctx->ccid3hctx_x));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700242 break;
243 default:
Gerrit Renker3c695262006-11-15 21:27:47 -0200244 DCCP_BUG("%s, sk=%p, Illegal state (%d)!", dccp_role(sk), sk,
245 hctx->ccid3hctx_state);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700246 goto out;
247 }
248
249 sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300250 jiffies + max_t(u32, 1, usecs_to_jiffies(next_tmout)));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700251 hctx->ccid3hctx_idle = 1;
252out:
253 bh_unlock_sock(sk);
254 sock_put(sk);
255}
256
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700257static int ccid3_hc_tx_send_packet(struct sock *sk,
258 struct sk_buff *skb, int len)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700259{
260 struct dccp_sock *dp = dccp_sk(sk);
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300261 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300262 struct dccp_tx_hist_entry *new_packet;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700263 struct timeval now;
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700264 long delay;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700265 int rc = -ENOTCONN;
266
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300267 BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM);
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300268
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300269 /* Check if pure ACK or Terminating*/
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700270 /*
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300271 * XXX: We only call this function for DATA and DATAACK, on, these
272 * packets can have zero length, but why the comment about "pure ACK"?
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700273 */
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300274 if (unlikely(len == 0))
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700275 goto out;
276
277 /* See if last packet allocated was not sent */
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300278 new_packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);
279 if (new_packet == NULL || new_packet->dccphtx_sent) {
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300280 new_packet = dccp_tx_hist_entry_new(ccid3_tx_hist,
281 SLAB_ATOMIC);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700282
283 rc = -ENOBUFS;
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300284 if (unlikely(new_packet == NULL)) {
285 LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, not enough "
286 "mem to add to history, send refused\n",
287 __FUNCTION__, dccp_role(sk), sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700288 goto out;
289 }
290
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300291 dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, new_packet);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700292 }
293
Arnaldo Carvalho de Melob0e56782005-09-09 02:38:35 -0300294 dccp_timestamp(sk, &now);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700295
296 switch (hctx->ccid3hctx_state) {
297 case TFRC_SSTATE_NO_SENT:
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300298 sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
299 jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700300 hctx->ccid3hctx_last_win_count = 0;
301 hctx->ccid3hctx_t_last_win_count = now;
302 ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
Arnaldo Carvalho de Melod7e0fb92005-09-09 19:58:18 -0300303 hctx->ccid3hctx_t_ipi = TFRC_INITIAL_IPI;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700304
305 /* Set nominal send time for initial packet */
306 hctx->ccid3hctx_t_nom = now;
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300307 timeval_add_usecs(&hctx->ccid3hctx_t_nom,
308 hctx->ccid3hctx_t_ipi);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700309 ccid3_calc_new_delta(hctx);
310 rc = 0;
311 break;
312 case TFRC_SSTATE_NO_FBACK:
313 case TFRC_SSTATE_FBACK:
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300314 delay = (timeval_delta(&now, &hctx->ccid3hctx_t_nom) -
315 hctx->ccid3hctx_delta);
Arnaldo Carvalho de Melo27258ee2005-08-09 20:30:56 -0700316 delay /= -1000;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700317 /* divide by -1000 is to convert to ms and get sign right */
Arnaldo Carvalho de Melod6809c12005-08-27 03:06:35 -0300318 rc = delay > 0 ? delay : 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700319 break;
320 default:
Gerrit Renker3c695262006-11-15 21:27:47 -0200321 DCCP_BUG("%s, sk=%p, Illegal state (%d)!", dccp_role(sk), sk,
322 hctx->ccid3hctx_state);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700323 rc = -EINVAL;
324 break;
325 }
326
327 /* Can we send? if so add options and add to packet history */
Arnaldo Carvalho de Melo507d37c2005-09-09 02:30:07 -0300328 if (rc == 0) {
329 dp->dccps_hc_tx_insert_options = 1;
Arnaldo Carvalho de Meloc1734372005-08-13 20:34:23 -0300330 new_packet->dccphtx_ccval =
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300331 DCCP_SKB_CB(skb)->dccpd_ccval =
332 hctx->ccid3hctx_last_win_count;
Ian McDonald66a377c2006-08-26 23:40:50 -0700333 timeval_add_usecs(&hctx->ccid3hctx_t_nom,
334 hctx->ccid3hctx_t_ipi);
Arnaldo Carvalho de Melo507d37c2005-09-09 02:30:07 -0300335 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700336out:
337 return rc;
338}
339
340static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len)
341{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300342 const struct dccp_sock *dp = dccp_sk(sk);
343 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700344 struct timeval now;
345
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300346 BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700347
Arnaldo Carvalho de Melob0e56782005-09-09 02:38:35 -0300348 dccp_timestamp(sk, &now);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700349
350 /* check if we have sent a data packet */
351 if (len > 0) {
352 unsigned long quarter_rtt;
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300353 struct dccp_tx_hist_entry *packet;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700354
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300355 packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300356 if (unlikely(packet == NULL)) {
357 LIMIT_NETDEBUG(KERN_WARNING "%s: packet doesn't "
358 "exists in history!\n", __FUNCTION__);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700359 return;
360 }
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300361 if (unlikely(packet->dccphtx_sent)) {
362 LIMIT_NETDEBUG(KERN_WARNING "%s: no unsent packet in "
363 "history!\n", __FUNCTION__);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700364 return;
365 }
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300366 packet->dccphtx_tstamp = now;
367 packet->dccphtx_seqno = dp->dccps_gss;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700368 /*
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300369 * Check if win_count have changed
Gerrit Renker0e64e942006-10-24 16:17:51 -0700370 * Algorithm in "8.1. Window Counter Value" in RFC 4342.
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700371 */
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -0300372 quarter_rtt = timeval_delta(&now, &hctx->ccid3hctx_t_last_win_count);
373 if (likely(hctx->ccid3hctx_rtt > 8))
374 quarter_rtt /= hctx->ccid3hctx_rtt / 4;
375
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700376 if (quarter_rtt > 0) {
377 hctx->ccid3hctx_t_last_win_count = now;
378 hctx->ccid3hctx_last_win_count = (hctx->ccid3hctx_last_win_count +
379 min_t(unsigned long, quarter_rtt, 5)) % 16;
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300380 ccid3_pr_debug("%s, sk=%p, window changed from "
381 "%u to %u!\n",
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700382 dccp_role(sk), sk,
Arnaldo Carvalho de Meloc1734372005-08-13 20:34:23 -0300383 packet->dccphtx_ccval,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700384 hctx->ccid3hctx_last_win_count);
385 }
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300386
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700387 hctx->ccid3hctx_idle = 0;
Arnaldo Carvalho de Meloc1734372005-08-13 20:34:23 -0300388 packet->dccphtx_rtt = hctx->ccid3hctx_rtt;
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300389 packet->dccphtx_sent = 1;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700390 } else
391 ccid3_pr_debug("%s, sk=%p, seqno=%llu NOT inserted!\n",
392 dccp_role(sk), sk, dp->dccps_gss);
393
394 switch (hctx->ccid3hctx_state) {
395 case TFRC_SSTATE_NO_SENT:
396 /* if first wasn't pure ack */
397 if (len != 0)
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300398 printk(KERN_CRIT "%s: %s, First packet sent is noted "
399 "as a data packet\n",
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700400 __FUNCTION__, dccp_role(sk));
401 return;
402 case TFRC_SSTATE_NO_FBACK:
403 case TFRC_SSTATE_FBACK:
404 if (len > 0) {
Ian McDonald66a377c2006-08-26 23:40:50 -0700405 timeval_sub_usecs(&hctx->ccid3hctx_t_nom,
406 hctx->ccid3hctx_t_ipi);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700407 ccid3_calc_new_t_ipi(hctx);
408 ccid3_calc_new_delta(hctx);
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300409 timeval_add_usecs(&hctx->ccid3hctx_t_nom,
410 hctx->ccid3hctx_t_ipi);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700411 }
412 break;
413 default:
Gerrit Renker3c695262006-11-15 21:27:47 -0200414 DCCP_BUG("%s, sk=%p, Illegal state (%d)!", dccp_role(sk), sk,
415 hctx->ccid3hctx_state);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700416 break;
417 }
418}
419
420static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
421{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300422 const struct dccp_sock *dp = dccp_sk(sk);
423 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700424 struct ccid3_options_received *opt_recv;
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300425 struct dccp_tx_hist_entry *packet;
Arnaldo Carvalho de Melob0e56782005-09-09 02:38:35 -0300426 struct timeval now;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700427 unsigned long next_tmout;
Ian McDonald1bc09862005-08-20 00:23:43 -0300428 u32 t_elapsed;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700429 u32 pinv;
430 u32 x_recv;
431 u32 r_sample;
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300432
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300433 BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700434
435 /* we are only interested in ACKs */
436 if (!(DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK ||
437 DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_DATAACK))
438 return;
439
440 opt_recv = &hctx->ccid3hctx_options_received;
441
Arnaldo Carvalho de Melo1a285992005-09-09 02:32:56 -0300442 t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700443 x_recv = opt_recv->ccid3or_receive_rate;
444 pinv = opt_recv->ccid3or_loss_event_rate;
445
446 switch (hctx->ccid3hctx_state) {
447 case TFRC_SSTATE_NO_SENT:
448 /* FIXME: what to do here? */
449 return;
450 case TFRC_SSTATE_NO_FBACK:
451 case TFRC_SSTATE_FBACK:
452 /* Calculate new round trip sample by
453 * R_sample = (now - t_recvdata) - t_delay */
454 /* get t_recvdata from history */
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300455 packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist,
456 DCCP_SKB_CB(skb)->dccpd_ack_seq);
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300457 if (unlikely(packet == NULL)) {
458 LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, seqno "
459 "%llu(%s) does't exist in history!\n",
460 __FUNCTION__, dccp_role(sk), sk,
461 (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq,
462 dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700463 return;
464 }
465
466 /* Update RTT */
Arnaldo Carvalho de Melob0e56782005-09-09 02:38:35 -0300467 dccp_timestamp(sk, &now);
468 r_sample = timeval_delta(&now, &packet->dccphtx_tstamp);
Arnaldo Carvalho de Melo1a285992005-09-09 02:32:56 -0300469 if (unlikely(r_sample <= t_elapsed))
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300470 LIMIT_NETDEBUG(KERN_WARNING "%s: r_sample=%uus, "
471 "t_elapsed=%uus\n",
Arnaldo Carvalho de Melo1a285992005-09-09 02:32:56 -0300472 __FUNCTION__, r_sample, t_elapsed);
473 else
474 r_sample -= t_elapsed;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700475
476 /* Update RTT estimate by
477 * If (No feedback recv)
478 * R = R_sample;
479 * Else
480 * R = q * R + (1 - q) * R_sample;
481 *
482 * q is a constant, RFC 3448 recomments 0.9
483 */
484 if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) {
485 ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK);
486 hctx->ccid3hctx_rtt = r_sample;
487 } else
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300488 hctx->ccid3hctx_rtt = (hctx->ccid3hctx_rtt * 9) / 10 +
489 r_sample / 10;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700490
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300491 ccid3_pr_debug("%s, sk=%p, New RTT estimate=%uus, "
492 "r_sample=%us\n", dccp_role(sk), sk,
493 hctx->ccid3hctx_rtt, r_sample);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700494
495 /* Update timeout interval */
Arnaldo Carvalho de Meloc68e64c2005-08-21 05:07:37 -0300496 hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt,
497 USEC_PER_SEC);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700498
499 /* Update receive rate */
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300500 hctx->ccid3hctx_x_recv = x_recv;/* X_recv in bytes per sec */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700501
502 /* Update loss event rate */
503 if (pinv == ~0 || pinv == 0)
504 hctx->ccid3hctx_p = 0;
505 else {
506 hctx->ccid3hctx_p = 1000000 / pinv;
507
508 if (hctx->ccid3hctx_p < TFRC_SMALLEST_P) {
509 hctx->ccid3hctx_p = TFRC_SMALLEST_P;
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300510 ccid3_pr_debug("%s, sk=%p, Smallest p used!\n",
511 dccp_role(sk), sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700512 }
513 }
514
515 /* unschedule no feedback timer */
516 sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
517
518 /* Update sending rate */
519 ccid3_hc_tx_update_x(sk);
520
521 /* Update next send time */
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300522 timeval_sub_usecs(&hctx->ccid3hctx_t_nom,
523 hctx->ccid3hctx_t_ipi);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700524 ccid3_calc_new_t_ipi(hctx);
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300525 timeval_add_usecs(&hctx->ccid3hctx_t_nom,
526 hctx->ccid3hctx_t_ipi);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700527 ccid3_calc_new_delta(hctx);
528
529 /* remove all packets older than the one acked from history */
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300530 dccp_tx_hist_purge_older(ccid3_tx_hist,
531 &hctx->ccid3hctx_hist, packet);
Arnaldo Carvalho de Meloc530cfb2005-08-29 02:15:54 -0300532 /*
533 * As we have calculated new ipi, delta, t_nom it is possible that
534 * we now can send a packet, so wake up dccp_wait_for_ccids.
535 */
536 sk->sk_write_space(sk);
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300537
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300538 /*
539 * Schedule no feedback timer to expire in
540 * max(4 * R, 2 * s / X)
541 */
Arnaldo Carvalho de Meloc68e64c2005-08-21 05:07:37 -0300542 next_tmout = max(hctx->ccid3hctx_t_rto,
Arnaldo Carvalho de Melo6b5e6332005-08-27 20:11:28 -0300543 2 * usecs_div(hctx->ccid3hctx_s,
544 hctx->ccid3hctx_x));
545
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300546 ccid3_pr_debug("%s, sk=%p, Scheduled no feedback timer to "
547 "expire in %lu jiffies (%luus)\n",
548 dccp_role(sk), sk,
549 usecs_to_jiffies(next_tmout), next_tmout);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700550
551 sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300552 jiffies + max_t(u32, 1, usecs_to_jiffies(next_tmout)));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700553
554 /* set idle flag */
555 hctx->ccid3hctx_idle = 1;
556 break;
557 default:
Gerrit Renker3c695262006-11-15 21:27:47 -0200558 DCCP_BUG("%s, sk=%p, Illegal state (%d)!", dccp_role(sk), sk,
559 hctx->ccid3hctx_state);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700560 break;
561 }
562}
563
Arnaldo Carvalho de Melo2d0817d2006-03-20 22:32:06 -0800564static int ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700565{
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300566 const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700567
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300568 BUG_ON(hctx == NULL);
569
Arnaldo Carvalho de Melo2d0817d2006-03-20 22:32:06 -0800570 if (sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)
571 DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
572 return 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700573}
574
575static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300576 unsigned char len, u16 idx,
577 unsigned char *value)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700578{
579 int rc = 0;
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300580 const struct dccp_sock *dp = dccp_sk(sk);
581 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700582 struct ccid3_options_received *opt_recv;
583
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300584 BUG_ON(hctx == NULL);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700585
586 opt_recv = &hctx->ccid3hctx_options_received;
587
588 if (opt_recv->ccid3or_seqno != dp->dccps_gsr) {
589 opt_recv->ccid3or_seqno = dp->dccps_gsr;
590 opt_recv->ccid3or_loss_event_rate = ~0;
591 opt_recv->ccid3or_loss_intervals_idx = 0;
592 opt_recv->ccid3or_loss_intervals_len = 0;
593 opt_recv->ccid3or_receive_rate = 0;
594 }
595
596 switch (option) {
597 case TFRC_OPT_LOSS_EVENT_RATE:
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300598 if (unlikely(len != 4)) {
599 LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, invalid "
600 "len for TFRC_OPT_LOSS_EVENT_RATE\n",
601 __FUNCTION__, dccp_role(sk), sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700602 rc = -EINVAL;
603 } else {
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800604 opt_recv->ccid3or_loss_event_rate = ntohl(*(__be32 *)value);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700605 ccid3_pr_debug("%s, sk=%p, LOSS_EVENT_RATE=%u\n",
606 dccp_role(sk), sk,
607 opt_recv->ccid3or_loss_event_rate);
608 }
609 break;
610 case TFRC_OPT_LOSS_INTERVALS:
611 opt_recv->ccid3or_loss_intervals_idx = idx;
612 opt_recv->ccid3or_loss_intervals_len = len;
613 ccid3_pr_debug("%s, sk=%p, LOSS_INTERVALS=(%u, %u)\n",
614 dccp_role(sk), sk,
615 opt_recv->ccid3or_loss_intervals_idx,
616 opt_recv->ccid3or_loss_intervals_len);
617 break;
618 case TFRC_OPT_RECEIVE_RATE:
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300619 if (unlikely(len != 4)) {
620 LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, invalid "
621 "len for TFRC_OPT_RECEIVE_RATE\n",
622 __FUNCTION__, dccp_role(sk), sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700623 rc = -EINVAL;
624 } else {
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800625 opt_recv->ccid3or_receive_rate = ntohl(*(__be32 *)value);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700626 ccid3_pr_debug("%s, sk=%p, RECEIVE_RATE=%u\n",
627 dccp_role(sk), sk,
628 opt_recv->ccid3or_receive_rate);
629 }
630 break;
631 }
632
633 return rc;
634}
635
Arnaldo Carvalho de Melo91f0ebf2006-03-20 19:21:44 -0800636static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700637{
638 struct dccp_sock *dp = dccp_sk(sk);
Arnaldo Carvalho de Melo91f0ebf2006-03-20 19:21:44 -0800639 struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700640
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -0300641 if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE &&
642 dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE)
643 hctx->ccid3hctx_s = dp->dccps_packet_size;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700644 else
645 hctx->ccid3hctx_s = TFRC_STD_PACKET_SIZE;
646
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300647 /* Set transmission rate to 1 packet per second */
648 hctx->ccid3hctx_x = hctx->ccid3hctx_s;
Arnaldo Carvalho de Meloc68e64c2005-08-21 05:07:37 -0300649 hctx->ccid3hctx_t_rto = USEC_PER_SEC;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700650 hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
651 INIT_LIST_HEAD(&hctx->ccid3hctx_hist);
Arnaldo Carvalho de Meloaa5d7df2006-03-20 17:35:13 -0800652
653 hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer;
654 hctx->ccid3hctx_no_feedback_timer.data = (unsigned long)sk;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700655 init_timer(&hctx->ccid3hctx_no_feedback_timer);
656
657 return 0;
658}
659
660static void ccid3_hc_tx_exit(struct sock *sk)
661{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300662 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700663
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700664 BUG_ON(hctx == NULL);
665
666 ccid3_hc_tx_set_state(sk, TFRC_SSTATE_TERM);
667 sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
668
669 /* Empty packet history */
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300670 dccp_tx_hist_purge(ccid3_tx_hist, &hctx->ccid3hctx_hist);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700671}
672
673/*
674 * RX Half Connection methods
675 */
676
Gerrit Renker56724aa2006-11-20 18:28:09 -0200677#ifdef CONFIG_IP_DCCP_CCID3_DEBUG
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700678static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
679{
680 static char *ccid3_rx_state_names[] = {
681 [TFRC_RSTATE_NO_DATA] = "NO_DATA",
682 [TFRC_RSTATE_DATA] = "DATA",
683 [TFRC_RSTATE_TERM] = "TERM",
684 };
685
686 return ccid3_rx_state_names[state];
687}
688#endif
689
Arnaldo Carvalho de Meloc25a18b2006-03-20 21:58:56 -0800690static void ccid3_hc_rx_set_state(struct sock *sk,
691 enum ccid3_hc_rx_states state)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700692{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300693 struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700694 enum ccid3_hc_rx_states oldstate = hcrx->ccid3hcrx_state;
695
696 ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300697 dccp_role(sk), sk, ccid3_rx_state_name(oldstate),
698 ccid3_rx_state_name(state));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700699 WARN_ON(state == oldstate);
700 hcrx->ccid3hcrx_state = state;
701}
702
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700703static void ccid3_hc_rx_send_feedback(struct sock *sk)
704{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300705 struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700706 struct dccp_sock *dp = dccp_sk(sk);
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300707 struct dccp_rx_hist_entry *packet;
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300708 struct timeval now;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700709
710 ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
711
Arnaldo Carvalho de Melob0e56782005-09-09 02:38:35 -0300712 dccp_timestamp(sk, &now);
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300713
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700714 switch (hcrx->ccid3hcrx_state) {
715 case TFRC_RSTATE_NO_DATA:
716 hcrx->ccid3hcrx_x_recv = 0;
717 break;
718 case TFRC_RSTATE_DATA: {
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300719 const u32 delta = timeval_delta(&now,
720 &hcrx->ccid3hcrx_tstamp_last_feedback);
Arnaldo Carvalho de Melo27ae543e2005-09-09 02:31:07 -0300721 hcrx->ccid3hcrx_x_recv = usecs_div(hcrx->ccid3hcrx_bytes_recv,
722 delta);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700723 }
724 break;
725 default:
Gerrit Renker3c695262006-11-15 21:27:47 -0200726 DCCP_BUG("%s, sk=%p, Illegal state (%d)!", dccp_role(sk), sk,
727 hcrx->ccid3hcrx_state);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700728 return;
729 }
730
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300731 packet = dccp_rx_hist_find_data_packet(&hcrx->ccid3hcrx_hist);
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300732 if (unlikely(packet == NULL)) {
733 LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, no data packet "
734 "in history!\n",
735 __FUNCTION__, dccp_role(sk), sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700736 return;
737 }
738
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300739 hcrx->ccid3hcrx_tstamp_last_feedback = now;
Ian McDonald66a377c2006-08-26 23:40:50 -0700740 hcrx->ccid3hcrx_ccval_last_counter = packet->dccphrx_ccval;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700741 hcrx->ccid3hcrx_bytes_recv = 0;
742
743 /* Convert to multiples of 10us */
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300744 hcrx->ccid3hcrx_elapsed_time =
745 timeval_delta(&now, &packet->dccphrx_tstamp) / 10;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700746 if (hcrx->ccid3hcrx_p == 0)
747 hcrx->ccid3hcrx_pinv = ~0;
748 else
749 hcrx->ccid3hcrx_pinv = 1000000 / hcrx->ccid3hcrx_p;
Arnaldo Carvalho de Melo507d37c2005-09-09 02:30:07 -0300750 dp->dccps_hc_rx_insert_options = 1;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700751 dccp_send_ack(sk);
752}
753
Arnaldo Carvalho de Melo2d0817d2006-03-20 22:32:06 -0800754static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700755{
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300756 const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800757 __be32 x_recv, pinv;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700758
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300759 BUG_ON(hcrx == NULL);
760
761 if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
Arnaldo Carvalho de Melo2d0817d2006-03-20 22:32:06 -0800762 return 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700763
Ian McDonald66a377c2006-08-26 23:40:50 -0700764 DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_ccval_last_counter;
Arnaldo Carvalho de Melo4fded332005-08-23 21:51:59 -0700765
766 if (dccp_packet_without_ack(skb))
Arnaldo Carvalho de Melo2d0817d2006-03-20 22:32:06 -0800767 return 0;
768
Arnaldo Carvalho de Melo4fded332005-08-23 21:51:59 -0700769 x_recv = htonl(hcrx->ccid3hcrx_x_recv);
770 pinv = htonl(hcrx->ccid3hcrx_pinv);
Arnaldo Carvalho de Melo2d0817d2006-03-20 22:32:06 -0800771
772 if ((hcrx->ccid3hcrx_elapsed_time != 0 &&
773 dccp_insert_option_elapsed_time(sk, skb,
774 hcrx->ccid3hcrx_elapsed_time)) ||
775 dccp_insert_option_timestamp(sk, skb) ||
776 dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
777 &pinv, sizeof(pinv)) ||
778 dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
779 &x_recv, sizeof(x_recv)))
780 return -1;
781
782 return 0;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700783}
784
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700785/* calculate first loss interval
786 *
787 * returns estimated loss interval in usecs */
788
789static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
790{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300791 struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300792 struct dccp_rx_hist_entry *entry, *next, *tail = NULL;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700793 u32 rtt, delta, x_recv, fval, p, tmp2;
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300794 struct timeval tstamp = { 0, };
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700795 int interval = 0;
796 int win_count = 0;
797 int step = 0;
798 u64 tmp1;
799
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300800 list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
801 dccphrx_node) {
802 if (dccp_rx_hist_entry_data_packet(entry)) {
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700803 tail = entry;
804
805 switch (step) {
806 case 0:
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300807 tstamp = entry->dccphrx_tstamp;
Arnaldo Carvalho de Meloc1734372005-08-13 20:34:23 -0300808 win_count = entry->dccphrx_ccval;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700809 step = 1;
810 break;
811 case 1:
Arnaldo Carvalho de Meloc1734372005-08-13 20:34:23 -0300812 interval = win_count - entry->dccphrx_ccval;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700813 if (interval < 0)
814 interval += TFRC_WIN_COUNT_LIMIT;
815 if (interval > 4)
816 goto found;
817 break;
818 }
819 }
820 }
821
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300822 if (unlikely(step == 0)) {
823 LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, packet history "
824 "contains no data packets!\n",
825 __FUNCTION__, dccp_role(sk), sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700826 return ~0;
827 }
828
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300829 if (unlikely(interval == 0)) {
830 LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, Could not find a "
831 "win_count interval > 0. Defaulting to 1\n",
832 __FUNCTION__, dccp_role(sk), sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700833 interval = 1;
834 }
835found:
Ian McDonald66a377c2006-08-26 23:40:50 -0700836 if (!tail) {
837 LIMIT_NETDEBUG(KERN_WARNING "%s: tail is null\n",
838 __FUNCTION__);
839 return ~0;
840 }
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -0300841 rtt = timeval_delta(&tstamp, &tail->dccphrx_tstamp) * 4 / interval;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700842 ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n",
843 dccp_role(sk), sk, rtt);
844 if (rtt == 0)
845 rtt = 1;
846
Arnaldo Carvalho de Melob0e56782005-09-09 02:38:35 -0300847 dccp_timestamp(sk, &tstamp);
848 delta = timeval_delta(&tstamp, &hcrx->ccid3hcrx_tstamp_last_feedback);
849 x_recv = usecs_div(hcrx->ccid3hcrx_bytes_recv, delta);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700850
Ian McDonald66a377c2006-08-26 23:40:50 -0700851 if (x_recv == 0)
852 x_recv = hcrx->ccid3hcrx_x_recv;
853
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700854 tmp1 = (u64)x_recv * (u64)rtt;
855 do_div(tmp1,10000000);
856 tmp2 = (u32)tmp1;
Ian McDonald66a377c2006-08-26 23:40:50 -0700857
858 if (!tmp2) {
859 LIMIT_NETDEBUG(KERN_WARNING "tmp2 = 0 "
860 "%s: x_recv = %u, rtt =%u\n",
861 __FUNCTION__, x_recv, rtt);
862 return ~0;
863 }
864
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700865 fval = (hcrx->ccid3hcrx_s * 100000) / tmp2;
866 /* do not alter order above or you will get overflow on 32 bit */
Arnaldo Carvalho de Melo36729c12005-08-28 00:47:15 -0300867 p = tfrc_calc_x_reverse_lookup(fval);
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300868 ccid3_pr_debug("%s, sk=%p, receive rate=%u bytes/s, implied "
869 "loss rate=%u\n", dccp_role(sk), sk, x_recv, p);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700870
871 if (p == 0)
872 return ~0;
873 else
874 return 1000000 / p;
875}
876
877static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss)
878{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300879 struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
Ian McDonaldfc747e82006-08-29 17:50:19 -0700880 struct dccp_li_hist_entry *head;
Ian McDonald66a377c2006-08-26 23:40:50 -0700881 u64 seq_temp;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700882
Ian McDonald66a377c2006-08-26 23:40:50 -0700883 if (list_empty(&hcrx->ccid3hcrx_li_hist)) {
884 if (!dccp_li_hist_interval_new(ccid3_li_hist,
885 &hcrx->ccid3hcrx_li_hist, seq_loss, win_loss))
Arnaldo Carvalho de Meloae6706f2005-08-27 23:03:09 -0300886 return;
Ian McDonald66a377c2006-08-26 23:40:50 -0700887
Ian McDonaldfc747e82006-08-29 17:50:19 -0700888 head = list_entry(hcrx->ccid3hcrx_li_hist.next,
889 struct dccp_li_hist_entry, dccplih_node);
890 head->dccplih_interval = ccid3_hc_rx_calc_first_li(sk);
Ian McDonald66a377c2006-08-26 23:40:50 -0700891 } else {
892 struct dccp_li_hist_entry *entry;
893 struct list_head *tail;
894
Ian McDonaldfc747e82006-08-29 17:50:19 -0700895 head = list_entry(hcrx->ccid3hcrx_li_hist.next,
896 struct dccp_li_hist_entry, dccplih_node);
Ian McDonald66a377c2006-08-26 23:40:50 -0700897 /* FIXME win count check removed as was wrong */
898 /* should make this check with receive history */
899 /* and compare there as per section 10.2 of RFC4342 */
900
901 /* new loss event detected */
902 /* calculate last interval length */
903 seq_temp = dccp_delta_seqno(head->dccplih_seqno, seq_loss);
904 entry = dccp_li_hist_entry_new(ccid3_li_hist, SLAB_ATOMIC);
905
906 if (entry == NULL) {
907 printk(KERN_CRIT "%s: out of memory\n",__FUNCTION__);
908 dump_stack();
909 return;
910 }
911
912 list_add(&entry->dccplih_node, &hcrx->ccid3hcrx_li_hist);
913
914 tail = hcrx->ccid3hcrx_li_hist.prev;
915 list_del(tail);
916 kmem_cache_free(ccid3_li_hist->dccplih_slab, tail);
917
918 /* Create the newest interval */
919 entry->dccplih_seqno = seq_loss;
920 entry->dccplih_interval = seq_temp;
921 entry->dccplih_win_count = win_loss;
922 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700923}
924
Ian McDonald66a377c2006-08-26 23:40:50 -0700925static int ccid3_hc_rx_detect_loss(struct sock *sk,
926 struct dccp_rx_hist_entry *packet)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700927{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300928 struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
Ian McDonald66a377c2006-08-26 23:40:50 -0700929 struct dccp_rx_hist_entry *rx_hist = dccp_rx_hist_head(&hcrx->ccid3hcrx_hist);
930 u64 seqno = packet->dccphrx_seqno;
931 u64 tmp_seqno;
932 int loss = 0;
933 u8 ccval;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700934
Ian McDonald66a377c2006-08-26 23:40:50 -0700935
936 tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss;
937
938 if (!rx_hist ||
939 follows48(packet->dccphrx_seqno, hcrx->ccid3hcrx_seqno_nonloss)) {
940 hcrx->ccid3hcrx_seqno_nonloss = seqno;
941 hcrx->ccid3hcrx_ccval_nonloss = packet->dccphrx_ccval;
942 goto detect_out;
943 }
944
945
946 while (dccp_delta_seqno(hcrx->ccid3hcrx_seqno_nonloss, seqno)
947 > TFRC_RECV_NUM_LATE_LOSS) {
948 loss = 1;
949 ccid3_hc_rx_update_li(sk, hcrx->ccid3hcrx_seqno_nonloss,
950 hcrx->ccid3hcrx_ccval_nonloss);
951 tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss;
952 dccp_inc_seqno(&tmp_seqno);
953 hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno;
954 dccp_inc_seqno(&tmp_seqno);
955 while (dccp_rx_hist_find_entry(&hcrx->ccid3hcrx_hist,
956 tmp_seqno, &ccval)) {
957 hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno;
958 hcrx->ccid3hcrx_ccval_nonloss = ccval;
959 dccp_inc_seqno(&tmp_seqno);
960 }
961 }
962
963 /* FIXME - this code could be simplified with above while */
964 /* but works at moment */
965 if (follows48(packet->dccphrx_seqno, hcrx->ccid3hcrx_seqno_nonloss)) {
966 hcrx->ccid3hcrx_seqno_nonloss = seqno;
967 hcrx->ccid3hcrx_ccval_nonloss = packet->dccphrx_ccval;
968 }
969
970detect_out:
971 dccp_rx_hist_add_packet(ccid3_rx_hist, &hcrx->ccid3hcrx_hist,
972 &hcrx->ccid3hcrx_li_hist, packet,
973 hcrx->ccid3hcrx_seqno_nonloss);
974 return loss;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700975}
976
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700977static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
978{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300979 struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
Arnaldo Carvalho de Melo4fded332005-08-23 21:51:59 -0700980 const struct dccp_options_received *opt_recv;
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -0300981 struct dccp_rx_hist_entry *packet;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700982 struct timeval now;
983 u8 win_count;
Ian McDonald66a377c2006-08-26 23:40:50 -0700984 u32 p_prev, rtt_prev, r_sample, t_elapsed;
985 int loss;
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -0300986
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -0300987 BUG_ON(hcrx == NULL ||
988 !(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA ||
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700989 hcrx->ccid3hcrx_state == TFRC_RSTATE_DATA));
990
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -0300991 opt_recv = &dccp_sk(sk)->dccps_options_received;
Arnaldo Carvalho de Melo4fded332005-08-23 21:51:59 -0700992
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700993 switch (DCCP_SKB_CB(skb)->dccpd_type) {
994 case DCCP_PKT_ACK:
995 if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)
996 return;
997 case DCCP_PKT_DATAACK:
Arnaldo Carvalho de Melo4fded332005-08-23 21:51:59 -0700998 if (opt_recv->dccpor_timestamp_echo == 0)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -0700999 break;
Ian McDonald66a377c2006-08-26 23:40:50 -07001000 rtt_prev = hcrx->ccid3hcrx_rtt;
Arnaldo Carvalho de Melob0e56782005-09-09 02:38:35 -03001001 dccp_timestamp(sk, &now);
Arnaldo Carvalho de Melob3a30772005-09-09 02:34:10 -03001002 timeval_sub_usecs(&now, opt_recv->dccpor_timestamp_echo * 10);
1003 r_sample = timeval_usecs(&now);
1004 t_elapsed = opt_recv->dccpor_elapsed_time * 10;
1005
1006 if (unlikely(r_sample <= t_elapsed))
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -03001007 LIMIT_NETDEBUG(KERN_WARNING "%s: r_sample=%uus, "
1008 "t_elapsed=%uus\n",
Arnaldo Carvalho de Melob3a30772005-09-09 02:34:10 -03001009 __FUNCTION__, r_sample, t_elapsed);
1010 else
1011 r_sample -= t_elapsed;
1012
1013 if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)
1014 hcrx->ccid3hcrx_rtt = r_sample;
1015 else
1016 hcrx->ccid3hcrx_rtt = (hcrx->ccid3hcrx_rtt * 9) / 10 +
1017 r_sample / 10;
1018
Ian McDonald66a377c2006-08-26 23:40:50 -07001019 if (rtt_prev != hcrx->ccid3hcrx_rtt)
1020 ccid3_pr_debug("%s, New RTT=%uus, elapsed time=%u\n",
Arnaldo Carvalho de Melo4fded332005-08-23 21:51:59 -07001021 dccp_role(sk), hcrx->ccid3hcrx_rtt,
1022 opt_recv->dccpor_elapsed_time);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001023 break;
1024 case DCCP_PKT_DATA:
1025 break;
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -03001026 default: /* We're not interested in other packet types, move along */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001027 return;
1028 }
1029
Arnaldo Carvalho de Melob0e56782005-09-09 02:38:35 -03001030 packet = dccp_rx_hist_entry_new(ccid3_rx_hist, sk, opt_recv->dccpor_ndp,
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -03001031 skb, SLAB_ATOMIC);
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -03001032 if (unlikely(packet == NULL)) {
1033 LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, Not enough mem to "
1034 "add rx packet to history, consider it lost!\n",
1035 __FUNCTION__, dccp_role(sk), sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001036 return;
1037 }
1038
Arnaldo Carvalho de Meloc1734372005-08-13 20:34:23 -03001039 win_count = packet->dccphrx_ccval;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001040
Ian McDonald66a377c2006-08-26 23:40:50 -07001041 loss = ccid3_hc_rx_detect_loss(sk, packet);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001042
1043 if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK)
1044 return;
1045
1046 switch (hcrx->ccid3hcrx_state) {
1047 case TFRC_RSTATE_NO_DATA:
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -03001048 ccid3_pr_debug("%s, sk=%p(%s), skb=%p, sending initial "
1049 "feedback\n",
1050 dccp_role(sk), sk,
1051 dccp_state_name(sk->sk_state), skb);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001052 ccid3_hc_rx_send_feedback(sk);
1053 ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA);
1054 return;
1055 case TFRC_RSTATE_DATA:
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -03001056 hcrx->ccid3hcrx_bytes_recv += skb->len -
1057 dccp_hdr(skb)->dccph_doff * 4;
Ian McDonald66a377c2006-08-26 23:40:50 -07001058 if (loss)
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -03001059 break;
1060
Arnaldo Carvalho de Melob0e56782005-09-09 02:38:35 -03001061 dccp_timestamp(sk, &now);
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -03001062 if (timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) >=
1063 hcrx->ccid3hcrx_rtt) {
1064 hcrx->ccid3hcrx_tstamp_last_ack = now;
1065 ccid3_hc_rx_send_feedback(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001066 }
Arnaldo Carvalho de Melob6ee3d42005-08-27 18:18:18 -03001067 return;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001068 default:
Gerrit Renker3c695262006-11-15 21:27:47 -02001069 DCCP_BUG("%s, sk=%p, Illegal state (%d)!", dccp_role(sk), sk,
1070 hcrx->ccid3hcrx_state);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001071 return;
1072 }
1073
1074 /* Dealing with packet loss */
Arnaldo Carvalho de Melo4fded332005-08-23 21:51:59 -07001075 ccid3_pr_debug("%s, sk=%p(%s), data loss! Reacting...\n",
1076 dccp_role(sk), sk, dccp_state_name(sk->sk_state));
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001077
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001078 p_prev = hcrx->ccid3hcrx_p;
1079
1080 /* Calculate loss event rate */
Ian McDonaldc0996662006-03-03 17:54:46 -08001081 if (!list_empty(&hcrx->ccid3hcrx_li_hist)) {
1082 u32 i_mean = dccp_li_hist_calc_i_mean(&hcrx->ccid3hcrx_li_hist);
1083
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001084 /* Scaling up by 1000000 as fixed decimal */
Ian McDonaldc0996662006-03-03 17:54:46 -08001085 if (i_mean != 0)
1086 hcrx->ccid3hcrx_p = 1000000 / i_mean;
Ian McDonald66a377c2006-08-26 23:40:50 -07001087 } else {
1088 printk(KERN_CRIT "%s: empty loss hist\n",__FUNCTION__);
1089 dump_stack();
Ian McDonaldc0996662006-03-03 17:54:46 -08001090 }
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001091
1092 if (hcrx->ccid3hcrx_p > p_prev) {
1093 ccid3_hc_rx_send_feedback(sk);
1094 return;
1095 }
1096}
1097
Arnaldo Carvalho de Melo91f0ebf2006-03-20 19:21:44 -08001098static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001099{
1100 struct dccp_sock *dp = dccp_sk(sk);
Arnaldo Carvalho de Melo91f0ebf2006-03-20 19:21:44 -08001101 struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001102
1103 ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
1104
Arnaldo Carvalho de Meloa84ffe42005-08-28 04:51:32 -03001105 if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE &&
1106 dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE)
1107 hcrx->ccid3hcrx_s = dp->dccps_packet_size;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001108 else
1109 hcrx->ccid3hcrx_s = TFRC_STD_PACKET_SIZE;
1110
1111 hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA;
1112 INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist);
Arnaldo Carvalho de Meloae6706f2005-08-27 23:03:09 -03001113 INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist);
Arnaldo Carvalho de Melob0e56782005-09-09 02:38:35 -03001114 dccp_timestamp(sk, &hcrx->ccid3hcrx_tstamp_last_ack);
Arnaldo Carvalho de Melo954ee312005-09-09 02:37:05 -03001115 hcrx->ccid3hcrx_tstamp_last_feedback = hcrx->ccid3hcrx_tstamp_last_ack;
1116 hcrx->ccid3hcrx_rtt = 5000; /* XXX 5ms for now... */
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001117 return 0;
1118}
1119
1120static void ccid3_hc_rx_exit(struct sock *sk)
1121{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -03001122 struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001123
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -03001124 BUG_ON(hcrx == NULL);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001125
1126 ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM);
1127
1128 /* Empty packet history */
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -03001129 dccp_rx_hist_purge(ccid3_rx_hist, &hcrx->ccid3hcrx_hist);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001130
1131 /* Empty loss interval history */
Arnaldo Carvalho de Meloae6706f2005-08-27 23:03:09 -03001132 dccp_li_hist_purge(ccid3_li_hist, &hcrx->ccid3hcrx_li_hist);
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001133}
1134
Arnaldo Carvalho de Melo2babe1f2005-08-23 21:52:35 -07001135static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
1136{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -03001137 const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
Arnaldo Carvalho de Melo2babe1f2005-08-23 21:52:35 -07001138
Arnaldo Carvalho de Melo59c23532005-09-12 14:16:58 -07001139 /* Listen socks doesn't have a private CCID block */
1140 if (sk->sk_state == DCCP_LISTEN)
1141 return;
1142
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -03001143 BUG_ON(hcrx == NULL);
Arnaldo Carvalho de Melo2babe1f2005-08-23 21:52:35 -07001144
1145 info->tcpi_ca_state = hcrx->ccid3hcrx_state;
1146 info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
1147 info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt;
1148}
1149
1150static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
1151{
Arnaldo Carvalho de Melo59725dc2005-09-09 02:40:58 -03001152 const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
Arnaldo Carvalho de Melo2babe1f2005-08-23 21:52:35 -07001153
Arnaldo Carvalho de Melo59c23532005-09-12 14:16:58 -07001154 /* Listen socks doesn't have a private CCID block */
1155 if (sk->sk_state == DCCP_LISTEN)
1156 return;
1157
Arnaldo Carvalho de Melo59d203f2005-09-09 20:01:25 -03001158 BUG_ON(hctx == NULL);
Arnaldo Carvalho de Melo2babe1f2005-08-23 21:52:35 -07001159
1160 info->tcpi_rto = hctx->ccid3hctx_t_rto;
1161 info->tcpi_rtt = hctx->ccid3hctx_rtt;
1162}
1163
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -07001164static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
1165 u32 __user *optval, int __user *optlen)
1166{
1167 const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
1168 const void *val;
1169
1170 /* Listen socks doesn't have a private CCID block */
1171 if (sk->sk_state == DCCP_LISTEN)
1172 return -EINVAL;
1173
1174 switch (optname) {
1175 case DCCP_SOCKOPT_CCID_RX_INFO:
1176 if (len < sizeof(hcrx->ccid3hcrx_tfrc))
1177 return -EINVAL;
1178 len = sizeof(hcrx->ccid3hcrx_tfrc);
1179 val = &hcrx->ccid3hcrx_tfrc;
1180 break;
1181 default:
1182 return -ENOPROTOOPT;
1183 }
1184
1185 if (put_user(len, optlen) || copy_to_user(optval, val, len))
1186 return -EFAULT;
1187
1188 return 0;
1189}
1190
1191static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
1192 u32 __user *optval, int __user *optlen)
1193{
1194 const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
1195 const void *val;
1196
1197 /* Listen socks doesn't have a private CCID block */
1198 if (sk->sk_state == DCCP_LISTEN)
1199 return -EINVAL;
1200
1201 switch (optname) {
1202 case DCCP_SOCKOPT_CCID_TX_INFO:
1203 if (len < sizeof(hctx->ccid3hctx_tfrc))
1204 return -EINVAL;
1205 len = sizeof(hctx->ccid3hctx_tfrc);
1206 val = &hctx->ccid3hctx_tfrc;
1207 break;
1208 default:
1209 return -ENOPROTOOPT;
1210 }
1211
1212 if (put_user(len, optlen) || copy_to_user(optval, val, len))
1213 return -EFAULT;
1214
1215 return 0;
1216}
1217
Arnaldo Carvalho de Melo91f0ebf2006-03-20 19:21:44 -08001218static struct ccid_operations ccid3 = {
Ian McDonald3dd9a7c2006-09-22 14:26:44 +12001219 .ccid_id = DCCPC_CCID3,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001220 .ccid_name = "ccid3",
1221 .ccid_owner = THIS_MODULE,
Arnaldo Carvalho de Melo91f0ebf2006-03-20 19:21:44 -08001222 .ccid_hc_tx_obj_size = sizeof(struct ccid3_hc_tx_sock),
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001223 .ccid_hc_tx_init = ccid3_hc_tx_init,
1224 .ccid_hc_tx_exit = ccid3_hc_tx_exit,
1225 .ccid_hc_tx_send_packet = ccid3_hc_tx_send_packet,
1226 .ccid_hc_tx_packet_sent = ccid3_hc_tx_packet_sent,
1227 .ccid_hc_tx_packet_recv = ccid3_hc_tx_packet_recv,
1228 .ccid_hc_tx_insert_options = ccid3_hc_tx_insert_options,
1229 .ccid_hc_tx_parse_options = ccid3_hc_tx_parse_options,
Arnaldo Carvalho de Melo91f0ebf2006-03-20 19:21:44 -08001230 .ccid_hc_rx_obj_size = sizeof(struct ccid3_hc_rx_sock),
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001231 .ccid_hc_rx_init = ccid3_hc_rx_init,
1232 .ccid_hc_rx_exit = ccid3_hc_rx_exit,
1233 .ccid_hc_rx_insert_options = ccid3_hc_rx_insert_options,
1234 .ccid_hc_rx_packet_recv = ccid3_hc_rx_packet_recv,
Arnaldo Carvalho de Melo2babe1f2005-08-23 21:52:35 -07001235 .ccid_hc_rx_get_info = ccid3_hc_rx_get_info,
1236 .ccid_hc_tx_get_info = ccid3_hc_tx_get_info,
Arnaldo Carvalho de Melo88f964d2005-09-18 00:19:32 -07001237 .ccid_hc_rx_getsockopt = ccid3_hc_rx_getsockopt,
1238 .ccid_hc_tx_getsockopt = ccid3_hc_tx_getsockopt,
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001239};
1240
Gerrit Renker56724aa2006-11-20 18:28:09 -02001241#ifdef CONFIG_IP_DCCP_CCID3_DEBUG
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001242module_param(ccid3_debug, int, 0444);
1243MODULE_PARM_DESC(ccid3_debug, "Enable debug messages");
Gerrit Renker56724aa2006-11-20 18:28:09 -02001244#endif
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001245
1246static __init int ccid3_module_init(void)
1247{
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -03001248 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001249
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -03001250 ccid3_rx_hist = dccp_rx_hist_new("ccid3");
1251 if (ccid3_rx_hist == NULL)
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001252 goto out;
1253
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -03001254 ccid3_tx_hist = dccp_tx_hist_new("ccid3");
1255 if (ccid3_tx_hist == NULL)
1256 goto out_free_rx;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001257
Arnaldo Carvalho de Meloae6706f2005-08-27 23:03:09 -03001258 ccid3_li_hist = dccp_li_hist_new("ccid3");
1259 if (ccid3_li_hist == NULL)
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -03001260 goto out_free_tx;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001261
1262 rc = ccid_register(&ccid3);
1263 if (rc != 0)
1264 goto out_free_loss_interval_history;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001265out:
1266 return rc;
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -03001267
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001268out_free_loss_interval_history:
Arnaldo Carvalho de Meloae6706f2005-08-27 23:03:09 -03001269 dccp_li_hist_delete(ccid3_li_hist);
1270 ccid3_li_hist = NULL;
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -03001271out_free_tx:
1272 dccp_tx_hist_delete(ccid3_tx_hist);
1273 ccid3_tx_hist = NULL;
1274out_free_rx:
1275 dccp_rx_hist_delete(ccid3_rx_hist);
1276 ccid3_rx_hist = NULL;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001277 goto out;
1278}
1279module_init(ccid3_module_init);
1280
1281static __exit void ccid3_module_exit(void)
1282{
1283 ccid_unregister(&ccid3);
1284
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -03001285 if (ccid3_tx_hist != NULL) {
1286 dccp_tx_hist_delete(ccid3_tx_hist);
1287 ccid3_tx_hist = NULL;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001288 }
Arnaldo Carvalho de Melo8c60f3f2005-08-10 12:59:38 -03001289 if (ccid3_rx_hist != NULL) {
1290 dccp_rx_hist_delete(ccid3_rx_hist);
1291 ccid3_rx_hist = NULL;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001292 }
Arnaldo Carvalho de Meloae6706f2005-08-27 23:03:09 -03001293 if (ccid3_li_hist != NULL) {
1294 dccp_li_hist_delete(ccid3_li_hist);
1295 ccid3_li_hist = NULL;
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001296 }
1297}
1298module_exit(ccid3_module_exit);
1299
Ian McDonalde6bccd32006-08-26 19:01:30 -07001300MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>, "
Arnaldo Carvalho de Melo1f2333a2005-08-27 03:51:58 -03001301 "Arnaldo Carvalho de Melo <acme@ghostprotocols.net>");
Arnaldo Carvalho de Melo7c657872005-08-09 20:14:34 -07001302MODULE_DESCRIPTION("DCCP TFRC CCID3 CCID");
1303MODULE_LICENSE("GPL");
1304MODULE_ALIAS("net-dccp-ccid-3");