⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ccid3.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  net/dccp/ccids/ccid3.c * *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. *  Copyright (c) 2005-6 Ian McDonald <imcdnzl@gmail.com> * *  An implementation of the DCCP protocol * *  This code has been developed by the University of Waikato WAND *  research group. For further information please see http://www.wand.net.nz/ * *  This code also uses code from Lulea University, rereleased as GPL by its *  authors: *  Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon * *  Changes to meet Linux coding standards, to make it meet latest ccid3 draft *  and to make it work as a loadable module in the DCCP stack written by *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>. * *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/config.h>#include "../ccid.h"#include "../dccp.h"#include "lib/packet_history.h"#include "lib/loss_interval.h"#include "lib/tfrc.h"#include "ccid3.h"/* * Reason for maths here is to avoid 32 bit overflow when a is big. * With this we get close to the limit. */static inline u32 usecs_div(const u32 a, const u32 b){	const u32 div = a < (UINT_MAX / (USEC_PER_SEC /    10)) ?    10 :			a < (UINT_MAX / (USEC_PER_SEC /    50)) ?    50 :			a < (UINT_MAX / (USEC_PER_SEC /   100)) ?   100 :			a < (UINT_MAX / (USEC_PER_SEC /   500)) ?   500 :			a < (UINT_MAX / (USEC_PER_SEC /  1000)) ?  1000 :			a < (UINT_MAX / (USEC_PER_SEC /  5000)) ?  5000 :			a < (UINT_MAX / (USEC_PER_SEC / 10000)) ? 10000 :			a < (UINT_MAX / (USEC_PER_SEC / 50000)) ? 50000 :								 100000;	const u32 tmp = a * (USEC_PER_SEC / div);	return (b >= 2 * div) ? tmp / (b / div) : tmp;}static int ccid3_debug;#ifdef CCID3_DEBUG#define ccid3_pr_debug(format, a...) \	do { if (ccid3_debug) \		printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \	} while (0)#else#define ccid3_pr_debug(format, a...)#endifstatic struct dccp_tx_hist *ccid3_tx_hist;static struct dccp_rx_hist *ccid3_rx_hist;static struct dccp_li_hist *ccid3_li_hist;static int ccid3_init(struct sock *sk){	return 0;}static void ccid3_exit(struct sock *sk){}/* TFRC sender states */enum ccid3_hc_tx_states {       	TFRC_SSTATE_NO_SENT = 1,	TFRC_SSTATE_NO_FBACK,	TFRC_SSTATE_FBACK,	TFRC_SSTATE_TERM,};#ifdef CCID3_DEBUGstatic const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state){	static char *ccid3_state_names[] = {	[TFRC_SSTATE_NO_SENT]  = "NO_SENT",	[TFRC_SSTATE_NO_FBACK] = "NO_FBACK",	[TFRC_SSTATE_FBACK]    = "FBACK",	[TFRC_SSTATE_TERM]     = "TERM",	};	return ccid3_state_names[state];}#endifstatic inline void ccid3_hc_tx_set_state(struct sock *sk,					 enum ccid3_hc_tx_states state){	struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);	enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state;	ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",		       dccp_role(sk), sk, ccid3_tx_state_name(oldstate),		       ccid3_tx_state_name(state));	WARN_ON(state == oldstate);	hctx->ccid3hctx_state = state;}/* Calculate new t_ipi (inter packet interval) by t_ipi = s / X_inst */static inline void ccid3_calc_new_t_ipi(struct ccid3_hc_tx_sock *hctx){	/*	 * If no feedback spec says t_ipi is 1 second (set elsewhere and then	 * doubles after every no feedback timer (separate function)	 */	if (hctx->ccid3hctx_state != TFRC_SSTATE_NO_FBACK)		hctx->ccid3hctx_t_ipi = usecs_div(hctx->ccid3hctx_s,						  hctx->ccid3hctx_x);}/* Calculate new delta by delta = min(t_ipi / 2, t_gran / 2) */static inline void ccid3_calc_new_delta(struct ccid3_hc_tx_sock *hctx){	hctx->ccid3hctx_delta = min_t(u32, hctx->ccid3hctx_t_ipi / 2,					   TFRC_OPSYS_HALF_TIME_GRAN);}/* * Update X by *    If (p > 0) *       x_calc = calcX(s, R, p); *       X = max(min(X_calc, 2 * X_recv), s / t_mbi); *    Else *       If (now - tld >= R) *          X = max(min(2 * X, 2 * X_recv), s / R); *          tld = now; */ static void ccid3_hc_tx_update_x(struct sock *sk){	struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);	/* To avoid large error in calcX */	if (hctx->ccid3hctx_p >= TFRC_SMALLEST_P) {		hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s,						     hctx->ccid3hctx_rtt,						     hctx->ccid3hctx_p);		hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_calc,							  2 * hctx->ccid3hctx_x_recv),					       (hctx->ccid3hctx_s /					        TFRC_MAX_BACK_OFF_TIME));	} else {		struct timeval now;		dccp_timestamp(sk, &now);	       	if (timeval_delta(&now, &hctx->ccid3hctx_t_ld) >=		    hctx->ccid3hctx_rtt) {			hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_recv,								  hctx->ccid3hctx_x) * 2,						       usecs_div(hctx->ccid3hctx_s,							       	 hctx->ccid3hctx_rtt));			hctx->ccid3hctx_t_ld = now;		}	}}static void ccid3_hc_tx_no_feedback_timer(unsigned long data){	struct sock *sk = (struct sock *)data;	unsigned long next_tmout = 0;	struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);	bh_lock_sock(sk);	if (sock_owned_by_user(sk)) {		/* Try again later. */		/* XXX: set some sensible MIB */		sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,			       jiffies + HZ / 5);		goto out;	}	ccid3_pr_debug("%s, sk=%p, state=%s\n", dccp_role(sk), sk,		       ccid3_tx_state_name(hctx->ccid3hctx_state));		switch (hctx->ccid3hctx_state) {	case TFRC_SSTATE_TERM:		goto out;	case TFRC_SSTATE_NO_FBACK:		/* Halve send rate */		hctx->ccid3hctx_x /= 2;		if (hctx->ccid3hctx_x < (hctx->ccid3hctx_s /					 TFRC_MAX_BACK_OFF_TIME))			hctx->ccid3hctx_x = (hctx->ccid3hctx_s /					     TFRC_MAX_BACK_OFF_TIME);		ccid3_pr_debug("%s, sk=%p, state=%s, updated tx rate to %d "			       "bytes/s\n",			       dccp_role(sk), sk,			       ccid3_tx_state_name(hctx->ccid3hctx_state),			       hctx->ccid3hctx_x);		next_tmout = max_t(u32, 2 * usecs_div(hctx->ccid3hctx_s,						      hctx->ccid3hctx_x),					TFRC_INITIAL_TIMEOUT);		/*		 * FIXME - not sure above calculation is correct. See section		 * 5 of CCID3 11 should adjust tx_t_ipi and double that to		 * achieve it really		 */		break;	case TFRC_SSTATE_FBACK:		/*		 * Check if IDLE since last timeout and recv rate is less than		 * 4 packets per RTT		 */		if (!hctx->ccid3hctx_idle ||		    (hctx->ccid3hctx_x_recv >=		     4 * usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt))) {			ccid3_pr_debug("%s, sk=%p, state=%s, not idle\n",				       dccp_role(sk), sk,				       ccid3_tx_state_name(hctx->ccid3hctx_state));			/* Halve sending rate */			/*  If (X_calc > 2 * X_recv)			 *    X_recv = max(X_recv / 2, s / (2 * t_mbi));			 *  Else			 *    X_recv = X_calc / 4;			 */			BUG_ON(hctx->ccid3hctx_p >= TFRC_SMALLEST_P &&			       hctx->ccid3hctx_x_calc == 0);			/* check also if p is zero -> x_calc is infinity? */			if (hctx->ccid3hctx_p < TFRC_SMALLEST_P ||			    hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv)				hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2,								    hctx->ccid3hctx_s / (2 * TFRC_MAX_BACK_OFF_TIME));			else				hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc / 4;			/* Update sending rate */			ccid3_hc_tx_update_x(sk);		}		/*		 * Schedule no feedback timer to expire in		 * max(4 * R, 2 * s / X)		 */		next_tmout = max_t(u32, hctx->ccid3hctx_t_rto, 					2 * usecs_div(hctx->ccid3hctx_s,						      hctx->ccid3hctx_x));		break;	default:		printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",		       __FUNCTION__, dccp_role(sk), sk, hctx->ccid3hctx_state);		dump_stack();		goto out;	}	sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, 		      jiffies + max_t(u32, 1, usecs_to_jiffies(next_tmout)));	hctx->ccid3hctx_idle = 1;out:	bh_unlock_sock(sk);	sock_put(sk);}static int ccid3_hc_tx_send_packet(struct sock *sk,				   struct sk_buff *skb, int len){	struct dccp_sock *dp = dccp_sk(sk);	struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);	struct dccp_tx_hist_entry *new_packet;	struct timeval now;	long delay;	int rc = -ENOTCONN;	BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM);	/* Check if pure ACK or Terminating*/	/*	 * XXX: We only call this function for DATA and DATAACK, on, these	 * packets can have zero length, but why the comment about "pure ACK"?	 */	if (unlikely(len == 0))		goto out;	/* See if last packet allocated was not sent */	new_packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);	if (new_packet == NULL || new_packet->dccphtx_sent) {		new_packet = dccp_tx_hist_entry_new(ccid3_tx_hist,						    SLAB_ATOMIC);		rc = -ENOBUFS;		if (unlikely(new_packet == NULL)) {			LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, not enough "				       "mem to add to history, send refused\n",				       __FUNCTION__, dccp_role(sk), sk);			goto out;		}		dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, new_packet);	}	dccp_timestamp(sk, &now);	switch (hctx->ccid3hctx_state) {	case TFRC_SSTATE_NO_SENT:		hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer;		hctx->ccid3hctx_no_feedback_timer.data     = (unsigned long)sk;		sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,			       jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT));		hctx->ccid3hctx_last_win_count	 = 0;		hctx->ccid3hctx_t_last_win_count = now;		ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);		hctx->ccid3hctx_t_ipi = TFRC_INITIAL_IPI;		/* Set nominal send time for initial packet */		hctx->ccid3hctx_t_nom = now;		timeval_add_usecs(&hctx->ccid3hctx_t_nom,				  hctx->ccid3hctx_t_ipi);		ccid3_calc_new_delta(hctx);		rc = 0;		break;	case TFRC_SSTATE_NO_FBACK:	case TFRC_SSTATE_FBACK:		delay = (timeval_delta(&now, &hctx->ccid3hctx_t_nom) -		         hctx->ccid3hctx_delta);		delay /= -1000;		/* divide by -1000 is to convert to ms and get sign right */		rc = delay > 0 ? delay : 0;		break;	default:		printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",		       __FUNCTION__, dccp_role(sk), sk, hctx->ccid3hctx_state);		dump_stack();		rc = -EINVAL;		break;	}	/* Can we send? if so add options and add to packet history */	if (rc == 0) {		dp->dccps_hc_tx_insert_options = 1;		new_packet->dccphtx_ccval =			DCCP_SKB_CB(skb)->dccpd_ccval =				hctx->ccid3hctx_last_win_count;	}out:	return rc;}static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len){	const struct dccp_sock *dp = dccp_sk(sk);	struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);	struct timeval now;	BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM);	dccp_timestamp(sk, &now);	/* check if we have sent a data packet */	if (len > 0) {		unsigned long quarter_rtt;		struct dccp_tx_hist_entry *packet;		packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);		if (unlikely(packet == NULL)) {			LIMIT_NETDEBUG(KERN_WARNING "%s: packet doesn't "				       "exists in history!\n", __FUNCTION__);			return;		}		if (unlikely(packet->dccphtx_sent)) {			LIMIT_NETDEBUG(KERN_WARNING "%s: no unsent packet in "				       "history!\n", __FUNCTION__);			return;		}		packet->dccphtx_tstamp = now;		packet->dccphtx_seqno  = dp->dccps_gss;		/*		 * Check if win_count have changed		 * Algorithm in "8.1. Window Counter Valuer" in		 * draft-ietf-dccp-ccid3-11.txt		 */		quarter_rtt = timeval_delta(&now, &hctx->ccid3hctx_t_last_win_count);		if (likely(hctx->ccid3hctx_rtt > 8))			quarter_rtt /= hctx->ccid3hctx_rtt / 4;		if (quarter_rtt > 0) {			hctx->ccid3hctx_t_last_win_count = now;			hctx->ccid3hctx_last_win_count	 = (hctx->ccid3hctx_last_win_count +							    min_t(unsigned long, quarter_rtt, 5)) % 16;			ccid3_pr_debug("%s, sk=%p, window changed from "				       "%u to %u!\n",				       dccp_role(sk), sk,				       packet->dccphtx_ccval,				       hctx->ccid3hctx_last_win_count);		}		hctx->ccid3hctx_idle = 0;		packet->dccphtx_rtt  = hctx->ccid3hctx_rtt;		packet->dccphtx_sent = 1;	} else		ccid3_pr_debug("%s, sk=%p, seqno=%llu NOT inserted!\n",			       dccp_role(sk), sk, dp->dccps_gss);	switch (hctx->ccid3hctx_state) {	case TFRC_SSTATE_NO_SENT:		/* if first wasn't pure ack */		if (len != 0)			printk(KERN_CRIT "%s: %s, First packet sent is noted "					 "as a data packet\n",			       __FUNCTION__, dccp_role(sk));		return;	case TFRC_SSTATE_NO_FBACK:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -