kernel-fxtec-pro1x/net/dccp/ccids/ccid3.c

2156 lines
56 KiB
C
Raw Normal View History

/*
* net/dccp/ccids/ccid3.c
*
* Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
* Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz>
*
* 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 "../packet_history.h"
#include "ccid3.h"
/*
* Reason for maths with 10 here is to avoid 32 bit overflow when a is big.
*/
static inline u32 usecs_div(const u32 a, const u32 b)
{
const u32 tmp = a * (USEC_PER_SEC / 10);
return b > 20 ? tmp / (b / 10) : tmp;
}
#ifdef CCID3_DEBUG
extern int 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...)
#endif
#define TFRC_MIN_PACKET_SIZE 16
#define TFRC_STD_PACKET_SIZE 256
#define TFRC_MAX_PACKET_SIZE 65535
#define TFRC_INITIAL_TIMEOUT (2 * USEC_PER_SEC)
/* two seconds as per CCID3 spec 11 */
#define TFRC_OPSYS_HALF_TIME_GRAN (USEC_PER_SEC / (2 * HZ))
/* above is in usecs - half the scheduling granularity as per RFC3448 4.6 */
#define TFRC_WIN_COUNT_PER_RTT 4
#define TFRC_WIN_COUNT_LIMIT 16
#define TFRC_MAX_BACK_OFF_TIME 64
/* above is in seconds */
#define TFRC_SMALLEST_P 40
#define TFRC_RECV_IVAL_F_LENGTH 8 /* length(w[]) */
/* Number of later packets received before one is considered lost */
#define TFRC_RECV_NUM_LATE_LOSS 3
enum ccid3_options {
TFRC_OPT_LOSS_EVENT_RATE = 192,
TFRC_OPT_LOSS_INTERVALS = 193,
TFRC_OPT_RECEIVE_RATE = 194,
};
static int ccid3_debug;
static struct dccp_tx_hist *ccid3_tx_hist;
static struct dccp_rx_hist *ccid3_rx_hist;
static kmem_cache_t *ccid3_loss_interval_hist_slab __read_mostly;
static inline struct ccid3_loss_interval_hist_entry *
ccid3_loss_interval_hist_entry_new(const unsigned int __nocast prio)
{
return kmem_cache_alloc(ccid3_loss_interval_hist_slab, prio);
}
static inline void ccid3_loss_interval_hist_entry_delete(struct ccid3_loss_interval_hist_entry *entry)
{
if (entry != NULL)
kmem_cache_free(ccid3_loss_interval_hist_slab, entry);
}
static void ccid3_loss_interval_history_delete(struct list_head *hist)
{
struct ccid3_loss_interval_hist_entry *entry, *next;
list_for_each_entry_safe(entry, next, hist, ccid3lih_node) {
list_del_init(&entry->ccid3lih_node);
kmem_cache_free(ccid3_loss_interval_hist_slab, entry);
}
}
static int ccid3_init(struct sock *sk)
{
ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
return 0;
}
static void ccid3_exit(struct sock *sk)
{
ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), 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_DEBUG
static 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];
}
#endif
static inline void ccid3_hc_tx_set_state(struct sock *sk,
enum ccid3_hc_tx_states state)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
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;
}
#define CALCX_ARRSIZE 500
#define CALCX_SPLIT 50000
/* equivalent to 0.05 */
static const u32 calcx_lookup[CALCX_ARRSIZE][2] = {
{ 37172 , 8172 },
{ 53499 , 11567 },
{ 66664 , 14180 },
{ 78298 , 16388 },
{ 89021 , 18339 },
{ 99147 , 20108 },
{ 108858 , 21738 },
{ 118273 , 23260 },
{ 127474 , 24693 },
{ 136520 , 26052 },
{ 145456 , 27348 },
{ 154316 , 28589 },
{ 163130 , 29783 },
{ 171919 , 30935 },
{ 180704 , 32049 },
{ 189502 , 33130 },
{ 198328 , 34180 },
{ 207194 , 35202 },
{ 216114 , 36198 },
{ 225097 , 37172 },
{ 234153 , 38123 },
{ 243294 , 39055 },
{ 252527 , 39968 },
{ 261861 , 40864 },
{ 271305 , 41743 },
{ 280866 , 42607 },
{ 290553 , 43457 },
{ 300372 , 44293 },
{ 310333 , 45117 },
{ 320441 , 45929 },
{ 330705 , 46729 },
{ 341131 , 47518 },
{ 351728 , 48297 },
{ 362501 , 49066 },
{ 373460 , 49826 },
{ 384609 , 50577 },
{ 395958 , 51320 },
{ 407513 , 52054 },
{ 419281 , 52780 },
{ 431270 , 53499 },
{ 443487 , 54211 },
{ 455940 , 54916 },
{ 468635 , 55614 },
{ 481581 , 56306 },
{ 494785 , 56991 },
{ 508254 , 57671 },
{ 521996 , 58345 },
{ 536019 , 59014 },
{ 550331 , 59677 },
{ 564939 , 60335 },
{ 579851 , 60988 },
{ 595075 , 61636 },
{ 610619 , 62279 },
{ 626491 , 62918 },
{ 642700 , 63553 },
{ 659253 , 64183 },
{ 676158 , 64809 },
{ 693424 , 65431 },
{ 711060 , 66050 },
{ 729073 , 66664 },
{ 747472 , 67275 },
{ 766266 , 67882 },
{ 785464 , 68486 },
{ 805073 , 69087 },
{ 825103 , 69684 },
{ 845562 , 70278 },
{ 866460 , 70868 },
{ 887805 , 71456 },
{ 909606 , 72041 },
{ 931873 , 72623 },
{ 954614 , 73202 },
{ 977839 , 73778 },
{ 1001557 , 74352 },
{ 1025777 , 74923 },
{ 1050508 , 75492 },
{ 1075761 , 76058 },
{ 1101544 , 76621 },
{ 1127867 , 77183 },
{ 1154739 , 77741 },
{ 1182172 , 78298 },
{ 1210173 , 78852 },
{ 1238753 , 79405 },
{ 1267922 , 79955 },
{ 1297689 , 80503 },
{ 1328066 , 81049 },
{ 1359060 , 81593 },
{ 1390684 , 82135 },
{ 1422947 , 82675 },
{ 1455859 , 83213 },
{ 1489430 , 83750 },
{ 1523671 , 84284 },
{ 1558593 , 84817 },
{ 1594205 , 85348 },
{ 1630518 , 85878 },
{ 1667543 , 86406 },
{ 1705290 , 86932 },
{ 1743770 , 87457 },
{ 1782994 , 87980 },
{ 1822973 , 88501 },
{ 1863717 , 89021 },
{ 1905237 , 89540 },
{ 1947545 , 90057 },
{ 1990650 , 90573 },
{ 2034566 , 91087 },
{ 2079301 , 91600 },
{ 2124869 , 92111 },
{ 2171279 , 92622 },
{ 2218543 , 93131 },
{ 2266673 , 93639 },
{ 2315680 , 94145 },
{ 2365575 , 94650 },
{ 2416371 , 95154 },
{ 2468077 , 95657 },
{ 2520707 , 96159 },
{ 2574271 , 96660 },
{ 2628782 , 97159 },
{ 2684250 , 97658 },
{ 2740689 , 98155 },
{ 2798110 , 98651 },
{ 2856524 , 99147 },
{ 2915944 , 99641 },
{ 2976382 , 100134 },
{ 3037850 , 100626 },
{ 3100360 , 101117 },
{ 3163924 , 101608 },
{ 3228554 , 102097 },
{ 3294263 , 102586 },
{ 3361063 , 103073 },
{ 3428966 , 103560 },
{ 3497984 , 104045 },
{ 3568131 , 104530 },
{ 3639419 , 105014 },
{ 3711860 , 105498 },
{ 3785467 , 105980 },
{ 3860253 , 106462 },
{ 3936229 , 106942 },
{ 4013410 , 107422 },
{ 4091808 , 107902 },
{ 4171435 , 108380 },
{ 4252306 , 108858 },
{ 4334431 , 109335 },
{ 4417825 , 109811 },
{ 4502501 , 110287 },
{ 4588472 , 110762 },
{ 4675750 , 111236 },
{ 4764349 , 111709 },
{ 4854283 , 112182 },
{ 4945564 , 112654 },
{ 5038206 , 113126 },
{ 5132223 , 113597 },
{ 5227627 , 114067 },
{ 5324432 , 114537 },
{ 5422652 , 115006 },
{ 5522299 , 115474 },
{ 5623389 , 115942 },
{ 5725934 , 116409 },
{ 5829948 , 116876 },
{ 5935446 , 117342 },
{ 6042439 , 117808 },
{ 6150943 , 118273 },
{ 6260972 , 118738 },
{ 6372538 , 119202 },
{ 6485657 , 119665 },
{ 6600342 , 120128 },
{ 6716607 , 120591 },
{ 6834467 , 121053 },
{ 6953935 , 121514 },
{ 7075025 , 121976 },
{ 7197752 , 122436 },
{ 7322131 , 122896 },
{ 7448175 , 123356 },
{ 7575898 , 123815 },
{ 7705316 , 124274 },
{ 7836442 , 124733 },
{ 7969291 , 125191 },
{ 8103877 , 125648 },
{ 8240216 , 126105 },
{ 8378321 , 126562 },
{ 8518208 , 127018 },
{ 8659890 , 127474 },
{ 8803384 , 127930 },
{ 8948702 , 128385 },
{ 9095861 , 128840 },
{ 9244875 , 129294 },
{ 9395760 , 129748 },
{ 9548529 , 130202 },
{ 9703198 , 130655 },
{ 9859782 , 131108 },
{ 10018296 , 131561 },
{ 10178755 , 132014 },
{ 10341174 , 132466 },
{ 10505569 , 132917 },
{ 10671954 , 133369 },
{ 10840345 , 133820 },
{ 11010757 , 134271 },
{ 11183206 , 134721 },
{ 11357706 , 135171 },
{ 11534274 , 135621 },
{ 11712924 , 136071 },
{ 11893673 , 136520 },
{ 12076536 , 136969 },
{ 12261527 , 137418 },
{ 12448664 , 137867 },
{ 12637961 , 138315 },
{ 12829435 , 138763 },
{ 13023101 , 139211 },
{ 13218974 , 139658 },
{ 13417071 , 140106 },
{ 13617407 , 140553 },
{ 13819999 , 140999 },
{ 14024862 , 141446 },
{ 14232012 , 141892 },
{ 14441465 , 142339 },
{ 14653238 , 142785 },
{ 14867346 , 143230 },
{ 15083805 , 143676 },
{ 15302632 , 144121 },
{ 15523842 , 144566 },
{ 15747453 , 145011 },
{ 15973479 , 145456 },
{ 16201939 , 145900 },
{ 16432847 , 146345 },
{ 16666221 , 146789 },
{ 16902076 , 147233 },
{ 17140429 , 147677 },
{ 17381297 , 148121 },
{ 17624696 , 148564 },
{ 17870643 , 149007 },
{ 18119154 , 149451 },
{ 18370247 , 149894 },
{ 18623936 , 150336 },
{ 18880241 , 150779 },
{ 19139176 , 151222 },
{ 19400759 , 151664 },
{ 19665007 , 152107 },
{ 19931936 , 152549 },
{ 20201564 , 152991 },
{ 20473907 , 153433 },
{ 20748982 , 153875 },
{ 21026807 , 154316 },
{ 21307399 , 154758 },
{ 21590773 , 155199 },
{ 21876949 , 155641 },
{ 22165941 , 156082 },
{ 22457769 , 156523 },
{ 22752449 , 156964 },
{ 23049999 , 157405 },
{ 23350435 , 157846 },
{ 23653774 , 158287 },
{ 23960036 , 158727 },
{ 24269236 , 159168 },
{ 24581392 , 159608 },
{ 24896521 , 160049 },
{ 25214642 , 160489 },
{ 25535772 , 160929 },
{ 25859927 , 161370 },
{ 26187127 , 161810 },
{ 26517388 , 162250 },
{ 26850728 , 162690 },
{ 27187165 , 163130 },
{ 27526716 , 163569 },
{ 27869400 , 164009 },
{ 28215234 , 164449 },
{ 28564236 , 164889 },
{ 28916423 , 165328 },
{ 29271815 , 165768 },
{ 29630428 , 166208 },
{ 29992281 , 166647 },
{ 30357392 , 167087 },
{ 30725779 , 167526 },
{ 31097459 , 167965 },
{ 31472452 , 168405 },
{ 31850774 , 168844 },
{ 32232445 , 169283 },
{ 32617482 , 169723 },
{ 33005904 , 170162 },
{ 33397730 , 170601 },
{ 33792976 , 171041 },
{ 34191663 , 171480 },
{ 34593807 , 171919 },
{ 34999428 , 172358 },
{ 35408544 , 172797 },
{ 35821174 , 173237 },
{ 36237335 , 173676 },
{ 36657047 , 174115 },
{ 37080329 , 174554 },
{ 37507197 , 174993 },
{ 37937673 , 175433 },
{ 38371773 , 175872 },
{ 38809517 , 176311 },
{ 39250924 , 176750 },
{ 39696012 , 177190 },
{ 40144800 , 177629 },
{ 40597308 , 178068 },
{ 41053553 , 178507 },
{ 41513554 , 178947 },
{ 41977332 , 179386 },
{ 42444904 , 179825 },
{ 42916290 , 180265 },
{ 43391509 , 180704 },
{ 43870579 , 181144 },
{ 44353520 , 181583 },
{ 44840352 , 182023 },
{ 45331092 , 182462 },
{ 45825761 , 182902 },
{ 46324378 , 183342 },
{ 46826961 , 183781 },
{ 47333531 , 184221 },
{ 47844106 , 184661 },
{ 48358706 , 185101 },
{ 48877350 , 185541 },
{ 49400058 , 185981 },
{ 49926849 , 186421 },
{ 50457743 , 186861 },
{ 50992759 , 187301 },
{ 51531916 , 187741 },
{ 52075235 , 188181 },
{ 52622735 , 188622 },
{ 53174435 , 189062 },
{ 53730355 , 189502 },
{ 54290515 , 189943 },
{ 54854935 , 190383 },
{ 55423634 , 190824 },
{ 55996633 , 191265 },
{ 56573950 , 191706 },
{ 57155606 , 192146 },
{ 57741621 , 192587 },
{ 58332014 , 193028 },
{ 58926806 , 193470 },
{ 59526017 , 193911 },
{ 60129666 , 194352 },
{ 60737774 , 194793 },
{ 61350361 , 195235 },
{ 61967446 , 195677 },
{ 62589050 , 196118 },
{ 63215194 , 196560 },
{ 63845897 , 197002 },
{ 64481179 , 197444 },
{ 65121061 , 197886 },
{ 65765563 , 198328 },
{ 66414705 , 198770 },
{ 67068508 , 199213 },
{ 67726992 , 199655 },
{ 68390177 , 200098 },
{ 69058085 , 200540 },
{ 69730735 , 200983 },
{ 70408147 , 201426 },
{ 71090343 , 201869 },
{ 71777343 , 202312 },
{ 72469168 , 202755 },
{ 73165837 , 203199 },
{ 73867373 , 203642 },
{ 74573795 , 204086 },
{ 75285124 , 204529 },
{ 76001380 , 204973 },
{ 76722586 , 205417 },
{ 77448761 , 205861 },
{ 78179926 , 206306 },
{ 78916102 , 206750 },
{ 79657310 , 207194 },
{ 80403571 , 207639 },
{ 81154906 , 208084 },
{ 81911335 , 208529 },
{ 82672880 , 208974 },
{ 83439562 , 209419 },
{ 84211402 , 209864 },
{ 84988421 , 210309 },
{ 85770640 , 210755 },
{ 86558080 , 211201 },
{ 87350762 , 211647 },
{ 88148708 , 212093 },
{ 88951938 , 212539 },
{ 89760475 , 212985 },
{ 90574339 , 213432 },
{ 91393551 , 213878 },
{ 92218133 , 214325 },
{ 93048107 , 214772 },
{ 93883493 , 215219 },
{ 94724314 , 215666 },
{ 95570590 , 216114 },
{ 96422343 , 216561 },
{ 97279594 , 217009 },
{ 98142366 , 217457 },
{ 99010679 , 217905 },
{ 99884556 , 218353 },
{ 100764018 , 218801 },
{ 101649086 , 219250 },
{ 102539782 , 219698 },
{ 103436128 , 220147 },
{ 104338146 , 220596 },
{ 105245857 , 221046 },
{ 106159284 , 221495 },
{ 107078448 , 221945 },
{ 108003370 , 222394 },
{ 108934074 , 222844 },
{ 109870580 , 223294 },
{ 110812910 , 223745 },
{ 111761087 , 224195 },
{ 112715133 , 224646 },
{ 113675069 , 225097 },
{ 114640918 , 225548 },
{ 115612702 , 225999 },
{ 116590442 , 226450 },
{ 117574162 , 226902 },
{ 118563882 , 227353 },
{ 119559626 , 227805 },
{ 120561415 , 228258 },
{ 121569272 , 228710 },
{ 122583219 , 229162 },
{ 123603278 , 229615 },
{ 124629471 , 230068 },
{ 125661822 , 230521 },
{ 126700352 , 230974 },
{ 127745083 , 231428 },
{ 128796039 , 231882 },
{ 129853241 , 232336 },
{ 130916713 , 232790 },
{ 131986475 , 233244 },
{ 133062553 , 233699 },
{ 134144966 , 234153 },
{ 135233739 , 234608 },
{ 136328894 , 235064 },
{ 137430453 , 235519 },
{ 138538440 , 235975 },
{ 139652876 , 236430 },
{ 140773786 , 236886 },
{ 141901190 , 237343 },
{ 143035113 , 237799 },
{ 144175576 , 238256 },
{ 145322604 , 238713 },
{ 146476218 , 239170 },
{ 147636442 , 239627 },
{ 148803298 , 240085 },
{ 149976809 , 240542 },
{ 151156999 , 241000 },
{ 152343890 , 241459 },
{ 153537506 , 241917 },
{ 154737869 , 242376 },
{ 155945002 , 242835 },
{ 157158929 , 243294 },
{ 158379673 , 243753 },
{ 159607257 , 244213 },
{ 160841704 , 244673 },
{ 162083037 , 245133 },
{ 163331279 , 245593 },
{ 164586455 , 246054 },
{ 165848586 , 246514 },
{ 167117696 , 246975 },
{ 168393810 , 247437 },
{ 169676949 , 247898 },
{ 170967138 , 248360 },
{ 172264399 , 248822 },
{ 173568757 , 249284 },
{ 174880235 , 249747 },
{ 176198856 , 250209 },
{ 177524643 , 250672 },
{ 178857621 , 251136 },
{ 180197813 , 251599 },
{ 181545242 , 252063 },
{ 182899933 , 252527 },
{ 184261908 , 252991 },
{ 185631191 , 253456 },
{ 187007807 , 253920 },
{ 188391778 , 254385 },
{ 189783129 , 254851 },
{ 191181884 , 255316 },
{ 192588065 , 255782 },
{ 194001698 , 256248 },
{ 195422805 , 256714 },
{ 196851411 , 257181 },
{ 198287540 , 257648 },
{ 199731215 , 258115 },
{ 201182461 , 258582 },
{ 202641302 , 259050 },
{ 204107760 , 259518 },
{ 205581862 , 259986 },
{ 207063630 , 260454 },
{ 208553088 , 260923 },
{ 210050262 , 261392 },
{ 211555174 , 261861 },
{ 213067849 , 262331 },
{ 214588312 , 262800 },
{ 216116586 , 263270 },
{ 217652696 , 263741 },
{ 219196666 , 264211 },
{ 220748520 , 264682 },
{ 222308282 , 265153 },
{ 223875978 , 265625 },
{ 225451630 , 266097 },
{ 227035265 , 266569 },
{ 228626905 , 267041 },
{ 230226576 , 267514 },
{ 231834302 , 267986 },
{ 233450107 , 268460 },
{ 235074016 , 268933 },
{ 236706054 , 269407 },
{ 238346244 , 269881 },
{ 239994613 , 270355 },
{ 241651183 , 270830 },
{ 243315981 , 271305 }
};
/* Calculate the send rate as per section 3.1 of RFC3448
Returns send rate in bytes per second
Integer maths and lookups are used as not allowed floating point in kernel
The function for Xcalc as per section 3.1 of RFC3448 is:
X = s
-------------------------------------------------------------
R*sqrt(2*b*p/3) + (t_RTO * (3*sqrt(3*b*p/8) * p * (1+32*p^2)))
where
X is the trasmit rate in bytes/second
s is the packet size in bytes
R is the round trip time in seconds
p is the loss event rate, between 0 and 1.0, of the number of loss events
as a fraction of the number of packets transmitted
t_RTO is the TCP retransmission timeout value in seconds
b is the number of packets acknowledged by a single TCP acknowledgement
we can assume that b = 1 and t_RTO is 4 * R. With this the equation becomes:
X = s
-----------------------------------------------------------------------
R * sqrt(2 * p / 3) + (12 * R * (sqrt(3 * p / 8) * p * (1 + 32 * p^2)))
which we can break down into:
X = s
--------
R * f(p)
where f(p) = sqrt(2 * p / 3) + (12 * sqrt(3 * p / 8) * p * (1 + 32 * p * p))
Function parameters:
s - bytes
R - RTT in usecs
p - loss rate (decimal fraction multiplied by 1,000,000)
Returns Xcalc in bytes per second
DON'T alter this code unless you run test cases against it as the code
has been manipulated to stop underflow/overlow.
*/
static u32 ccid3_calc_x(u16 s, u32 R, u32 p)
{
int index;
u32 f;
u64 tmp1, tmp2;
if (p < CALCX_SPLIT)
index = (p / (CALCX_SPLIT / CALCX_ARRSIZE)) - 1;
else
index = (p / (1000000 / CALCX_ARRSIZE)) - 1;
if (index < 0)
/* p should be 0 unless there is a bug in my code */
index = 0;
if (R == 0)
R = 1; /* RTT can't be zero or else divide by zero */
BUG_ON(index >= CALCX_ARRSIZE);
if (p >= CALCX_SPLIT)
f = calcx_lookup[index][0];
else
f = calcx_lookup[index][1];
tmp1 = ((u64)s * 100000000);
tmp2 = ((u64)R * (u64)f);
do_div(tmp2,10000);
do_div(tmp1,tmp2);
/* don't alter above math unless you test due to overflow on 32 bit */
return (u32)tmp1;
}
/* 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 dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
/* To avoid large error in calcX */
if (hctx->ccid3hctx_p >= TFRC_SMALLEST_P) {
hctx->ccid3hctx_x_calc = ccid3_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;
do_gettimeofday(&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;
struct dccp_sock *dp = dccp_sk(sk);
unsigned long next_tmout = 0;
struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
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 = dp->dccps_hc_tx_ccid_private;
struct dccp_tx_hist_entry *new_packet;
struct timeval now;
long delay;
int rc = -ENOTCONN;
/* 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 (hctx == NULL || len == 0 ||
hctx->ccid3hctx_state == TFRC_SSTATE_TERM)
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 (new_packet == NULL) {
ccid3_pr_debug("%s, sk=%p, not enough mem to add "
"to history, send refused\n",
dccp_role(sk), sk);
goto out;
}
dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, new_packet);
}
do_gettimeofday(&now);
switch (hctx->ccid3hctx_state) {
case TFRC_SSTATE_NO_SENT:
ccid3_pr_debug("%s, sk=%p, first packet(%llu)\n",
dccp_role(sk), sk, dp->dccps_gss);
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_TIMEOUT;
/* 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);
ccid3_pr_debug("send_packet delay=%ld\n", delay);
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)
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)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
struct timeval now;
BUG_ON(hctx == NULL);
if (hctx->ccid3hctx_state == TFRC_SSTATE_TERM) {
ccid3_pr_debug("%s, sk=%p, while state is TFRC_SSTATE_TERM!\n",
dccp_role(sk), sk);
return;
}
do_gettimeofday(&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 (packet == NULL) {
printk(KERN_CRIT "%s: packet doesn't exists in "
"history!\n", __FUNCTION__);
return;
}
if (packet->dccphtx_sent) {
printk(KERN_CRIT "%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:
case TFRC_SSTATE_FBACK:
if (len > 0) {
hctx->ccid3hctx_t_nom = now;
ccid3_calc_new_t_ipi(hctx);
ccid3_calc_new_delta(hctx);
timeval_add_usecs(&hctx->ccid3hctx_t_nom,
hctx->ccid3hctx_t_ipi);
}
break;
default:
printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
__FUNCTION__, dccp_role(sk), sk, hctx->ccid3hctx_state);
dump_stack();
break;
}
}
static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
struct ccid3_options_received *opt_recv;
struct dccp_tx_hist_entry *packet;
unsigned long next_tmout;
u32 t_elapsed;
u32 pinv;
u32 x_recv;
u32 r_sample;
if (hctx == NULL)
return;
if (hctx->ccid3hctx_state == TFRC_SSTATE_TERM) {
ccid3_pr_debug("%s, sk=%p, received a packet when "
"terminating!\n", dccp_role(sk), sk);
return;
}
/* we are only interested in ACKs */
if (!(DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK ||
DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_DATAACK))
return;
opt_recv = &hctx->ccid3hctx_options_received;
t_elapsed = dp->dccps_options_received.dccpor_elapsed_time;
x_recv = opt_recv->ccid3or_receive_rate;
pinv = opt_recv->ccid3or_loss_event_rate;
switch (hctx->ccid3hctx_state) {
case TFRC_SSTATE_NO_SENT:
/* FIXME: what to do here? */
return;
case TFRC_SSTATE_NO_FBACK:
case TFRC_SSTATE_FBACK:
/* Calculate new round trip sample by
* R_sample = (now - t_recvdata) - t_delay */
/* get t_recvdata from history */
packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist,
DCCP_SKB_CB(skb)->dccpd_ack_seq);
if (packet == NULL) {
ccid3_pr_debug("%s, sk=%p, seqno %llu(%s) does't "
"exist in history!\n",
dccp_role(sk), sk,
DCCP_SKB_CB(skb)->dccpd_ack_seq,
dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
return;
}
/* Update RTT */
r_sample = timeval_now_delta(&packet->dccphtx_tstamp);
/* FIXME: */
// r_sample -= usecs_to_jiffies(t_elapsed * 10);
/* Update RTT estimate by
* If (No feedback recv)
* R = R_sample;
* Else
* R = q * R + (1 - q) * R_sample;
*
* q is a constant, RFC 3448 recomments 0.9
*/
if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) {
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK);
hctx->ccid3hctx_rtt = r_sample;
} else
hctx->ccid3hctx_rtt = (hctx->ccid3hctx_rtt * 9) / 10 +
r_sample / 10;
ccid3_pr_debug("%s, sk=%p, New RTT estimate=%uus, "
"r_sample=%us\n", dccp_role(sk), sk,
hctx->ccid3hctx_rtt, r_sample);
/* Update timeout interval */
hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt,
USEC_PER_SEC);
/* Update receive rate */
hctx->ccid3hctx_x_recv = x_recv;/* X_recv in bytes per sec */
/* Update loss event rate */
if (pinv == ~0 || pinv == 0)
hctx->ccid3hctx_p = 0;
else {
hctx->ccid3hctx_p = 1000000 / pinv;
if (hctx->ccid3hctx_p < TFRC_SMALLEST_P) {
hctx->ccid3hctx_p = TFRC_SMALLEST_P;
ccid3_pr_debug("%s, sk=%p, Smallest p used!\n",
dccp_role(sk), sk);
}
}
/* unschedule no feedback timer */
sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
/* Update sending rate */
ccid3_hc_tx_update_x(sk);
/* Update next send time */
timeval_sub_usecs(&hctx->ccid3hctx_t_nom,
hctx->ccid3hctx_t_ipi);
ccid3_calc_new_t_ipi(hctx);
timeval_add_usecs(&hctx->ccid3hctx_t_nom,
hctx->ccid3hctx_t_ipi);
ccid3_calc_new_delta(hctx);
/* remove all packets older than the one acked from history */
dccp_tx_hist_purge_older(ccid3_tx_hist,
&hctx->ccid3hctx_hist, packet);
/*
* Schedule no feedback timer to expire in
* max(4 * R, 2 * s / X)
*/
next_tmout = max(hctx->ccid3hctx_t_rto,
2 * usecs_div(hctx->ccid3hctx_s,
hctx->ccid3hctx_x));
ccid3_pr_debug("%s, sk=%p, Scheduled no feedback timer to "
"expire in %lu jiffies (%luus)\n",
dccp_role(sk), sk,
usecs_to_jiffies(next_tmout), next_tmout);
sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
jiffies + max_t(u32, 1, usecs_to_jiffies(next_tmout)));
/* set idle flag */
hctx->ccid3hctx_idle = 1;
break;
default:
printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
__FUNCTION__, dccp_role(sk), sk, hctx->ccid3hctx_state);
dump_stack();
break;
}
}
static void ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
{
const struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
if (hctx == NULL || !(sk->sk_state == DCCP_OPEN ||
sk->sk_state == DCCP_PARTOPEN))
return;
DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
}
static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
unsigned char len, u16 idx,
unsigned char *value)
{
int rc = 0;
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
struct ccid3_options_received *opt_recv;
if (hctx == NULL)
return 0;
opt_recv = &hctx->ccid3hctx_options_received;
if (opt_recv->ccid3or_seqno != dp->dccps_gsr) {
opt_recv->ccid3or_seqno = dp->dccps_gsr;
opt_recv->ccid3or_loss_event_rate = ~0;
opt_recv->ccid3or_loss_intervals_idx = 0;
opt_recv->ccid3or_loss_intervals_len = 0;
opt_recv->ccid3or_receive_rate = 0;
}
switch (option) {
case TFRC_OPT_LOSS_EVENT_RATE:
if (len != 4) {
ccid3_pr_debug("%s, sk=%p, invalid len for "
"TFRC_OPT_LOSS_EVENT_RATE\n",
dccp_role(sk), sk);
rc = -EINVAL;
} else {
opt_recv->ccid3or_loss_event_rate = ntohl(*(u32 *)value);
ccid3_pr_debug("%s, sk=%p, LOSS_EVENT_RATE=%u\n",
dccp_role(sk), sk,
opt_recv->ccid3or_loss_event_rate);
}
break;
case TFRC_OPT_LOSS_INTERVALS:
opt_recv->ccid3or_loss_intervals_idx = idx;
opt_recv->ccid3or_loss_intervals_len = len;
ccid3_pr_debug("%s, sk=%p, LOSS_INTERVALS=(%u, %u)\n",
dccp_role(sk), sk,
opt_recv->ccid3or_loss_intervals_idx,
opt_recv->ccid3or_loss_intervals_len);
break;
case TFRC_OPT_RECEIVE_RATE:
if (len != 4) {
ccid3_pr_debug("%s, sk=%p, invalid len for "
"TFRC_OPT_RECEIVE_RATE\n",
dccp_role(sk), sk);
rc = -EINVAL;
} else {
opt_recv->ccid3or_receive_rate = ntohl(*(u32 *)value);
ccid3_pr_debug("%s, sk=%p, RECEIVE_RATE=%u\n",
dccp_role(sk), sk,
opt_recv->ccid3or_receive_rate);
}
break;
}
return rc;
}
static int ccid3_hc_tx_init(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx;
ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
hctx = dp->dccps_hc_tx_ccid_private = kmalloc(sizeof(*hctx),
gfp_any());
if (hctx == NULL)
return -ENOMEM;
memset(hctx, 0, sizeof(*hctx));
if (dp->dccps_avg_packet_size >= TFRC_MIN_PACKET_SIZE &&
dp->dccps_avg_packet_size <= TFRC_MAX_PACKET_SIZE)
hctx->ccid3hctx_s = (u16)dp->dccps_avg_packet_size;
else
hctx->ccid3hctx_s = TFRC_STD_PACKET_SIZE;
/* Set transmission rate to 1 packet per second */
hctx->ccid3hctx_x = hctx->ccid3hctx_s;
hctx->ccid3hctx_t_rto = USEC_PER_SEC;
hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
INIT_LIST_HEAD(&hctx->ccid3hctx_hist);
init_timer(&hctx->ccid3hctx_no_feedback_timer);
return 0;
}
static void ccid3_hc_tx_exit(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
BUG_ON(hctx == NULL);
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_TERM);
sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
/* Empty packet history */
dccp_tx_hist_purge(ccid3_tx_hist, &hctx->ccid3hctx_hist);
kfree(dp->dccps_hc_tx_ccid_private);
dp->dccps_hc_tx_ccid_private = NULL;
}
/*
* RX Half Connection methods
*/
/* TFRC receiver states */
enum ccid3_hc_rx_states {
TFRC_RSTATE_NO_DATA = 1,
TFRC_RSTATE_DATA,
TFRC_RSTATE_TERM = 127,
};
#ifdef CCID3_DEBUG
static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
{
static char *ccid3_rx_state_names[] = {
[TFRC_RSTATE_NO_DATA] = "NO_DATA",
[TFRC_RSTATE_DATA] = "DATA",
[TFRC_RSTATE_TERM] = "TERM",
};
return ccid3_rx_state_names[state];
}
#endif
static inline void ccid3_hc_rx_set_state(struct sock *sk,
enum ccid3_hc_rx_states state)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
enum ccid3_hc_rx_states oldstate = hcrx->ccid3hcrx_state;
ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",
dccp_role(sk), sk, ccid3_rx_state_name(oldstate),
ccid3_rx_state_name(state));
WARN_ON(state == oldstate);
hcrx->ccid3hcrx_state = state;
}
static int ccid3_hc_rx_add_hist(struct sock *sk,
struct dccp_rx_hist_entry *packet)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
struct dccp_rx_hist_entry *entry, *next, *iter;
u8 num_later = 0;
iter = dccp_rx_hist_head(&hcrx->ccid3hcrx_hist);
if (iter == NULL)
dccp_rx_hist_add_entry(&hcrx->ccid3hcrx_hist, packet);
else {
const u64 seqno = packet->dccphrx_seqno;
if (after48(seqno, iter->dccphrx_seqno))
dccp_rx_hist_add_entry(&hcrx->ccid3hcrx_hist, packet);
else {
if (dccp_rx_hist_entry_data_packet(iter))
num_later = 1;
list_for_each_entry_continue(iter,
&hcrx->ccid3hcrx_hist,
dccphrx_node) {
if (after48(seqno, iter->dccphrx_seqno)) {
dccp_rx_hist_add_entry(&iter->dccphrx_node,
packet);
goto trim_history;
}
if (dccp_rx_hist_entry_data_packet(iter))
num_later++;
if (num_later == TFRC_RECV_NUM_LATE_LOSS) {
dccp_rx_hist_entry_delete(ccid3_rx_hist,
packet);
ccid3_pr_debug("%s, sk=%p, packet"
"(%llu) already lost!\n",
dccp_role(sk), sk,
seqno);
return 1;
}
}
if (num_later < TFRC_RECV_NUM_LATE_LOSS)
dccp_rx_hist_add_entry(&hcrx->ccid3hcrx_hist,
packet);
/*
* FIXME: else what? should we destroy the packet
* like above?
*/
}
}
trim_history:
/*
* Trim history (remove all packets after the NUM_LATE_LOSS + 1
* data packets)
*/
num_later = TFRC_RECV_NUM_LATE_LOSS + 1;
if (!list_empty(&hcrx->ccid3hcrx_loss_interval_hist)) {
list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
dccphrx_node) {
if (num_later == 0) {
list_del_init(&entry->dccphrx_node);
dccp_rx_hist_entry_delete(ccid3_rx_hist, entry);
} else if (dccp_rx_hist_entry_data_packet(entry))
--num_later;
}
} else {
int step = 0;
u8 win_count = 0; /* Not needed, but lets shut up gcc */
int tmp;
/*
* We have no loss interval history so we need at least one
* rtt:s of data packets to approximate rtt.
*/
list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
dccphrx_node) {
if (num_later == 0) {
switch (step) {
case 0:
step = 1;
/* OK, find next data packet */
num_later = 1;
break;
case 1:
step = 2;
/* OK, find next data packet */
num_later = 1;
win_count = entry->dccphrx_ccval;
break;
case 2:
tmp = win_count - entry->dccphrx_ccval;
if (tmp < 0)
tmp += TFRC_WIN_COUNT_LIMIT;
if (tmp > TFRC_WIN_COUNT_PER_RTT + 1) {
/*
* We have found a packet older
* than one rtt remove the rest
*/
step = 3;
} else /* OK, find next data packet */
num_later = 1;
break;
case 3:
list_del_init(&entry->dccphrx_node);
dccp_rx_hist_entry_delete(ccid3_rx_hist,
entry);
break;
}
} else if (dccp_rx_hist_entry_data_packet(entry))
--num_later;
}
}
return 0;
}
static void ccid3_hc_rx_send_feedback(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
struct dccp_rx_hist_entry *packet;
struct timeval now;
ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
do_gettimeofday(&now);
switch (hcrx->ccid3hcrx_state) {
case TFRC_RSTATE_NO_DATA:
hcrx->ccid3hcrx_x_recv = 0;
break;
case TFRC_RSTATE_DATA: {
const u32 delta = timeval_delta(&now,
&hcrx->ccid3hcrx_tstamp_last_feedback);
hcrx->ccid3hcrx_x_recv = (hcrx->ccid3hcrx_bytes_recv *
USEC_PER_SEC);
if (likely(delta > 1))
hcrx->ccid3hcrx_x_recv /= delta;
}
break;
default:
printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
__FUNCTION__, dccp_role(sk), sk, hcrx->ccid3hcrx_state);
dump_stack();
return;
}
packet = dccp_rx_hist_find_data_packet(&hcrx->ccid3hcrx_hist);
if (packet == NULL) {
printk(KERN_CRIT "%s: %s, sk=%p, no data packet in history!\n",
__FUNCTION__, dccp_role(sk), sk);
dump_stack();
return;
}
hcrx->ccid3hcrx_tstamp_last_feedback = now;
hcrx->ccid3hcrx_last_counter = packet->dccphrx_ccval;
hcrx->ccid3hcrx_seqno_last_counter = packet->dccphrx_seqno;
hcrx->ccid3hcrx_bytes_recv = 0;
/* Convert to multiples of 10us */
hcrx->ccid3hcrx_elapsed_time =
timeval_delta(&now, &packet->dccphrx_tstamp) / 10;
if (hcrx->ccid3hcrx_p == 0)
hcrx->ccid3hcrx_pinv = ~0;
else
hcrx->ccid3hcrx_pinv = 1000000 / hcrx->ccid3hcrx_p;
dccp_send_ack(sk);
}
static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
{
const struct dccp_sock *dp = dccp_sk(sk);
u32 x_recv, pinv;
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
if (hcrx == NULL || !(sk->sk_state == DCCP_OPEN ||
sk->sk_state == DCCP_PARTOPEN))
return;
DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_last_counter;
if (dccp_packet_without_ack(skb))
return;
if (hcrx->ccid3hcrx_elapsed_time != 0)
dccp_insert_option_elapsed_time(sk, skb,
hcrx->ccid3hcrx_elapsed_time);
dccp_insert_option_timestamp(sk, skb);
x_recv = htonl(hcrx->ccid3hcrx_x_recv);
pinv = htonl(hcrx->ccid3hcrx_pinv);
dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
&pinv, sizeof(pinv));
dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
&x_recv, sizeof(x_recv));
}
/* Weights used to calculate loss event rate */
/*
* These are integers as per section 8 of RFC3448. We can then divide by 4 *
* when we use it.
*/
static const int ccid3_hc_rx_w[TFRC_RECV_IVAL_F_LENGTH] = {
4, 4, 4, 4, 3, 2, 1, 1,
};
/*
* args: fvalue - function value to match
* returns: p closest to that value
*
* both fvalue and p are multiplied by 1,000,000 to use ints
*/
static u32 calcx_reverse_lookup(u32 fvalue) {
int ctr = 0;
int small;
if (fvalue < calcx_lookup[0][1])
return 0;
if (fvalue <= calcx_lookup[CALCX_ARRSIZE-1][1])
small = 1;
else if (fvalue > calcx_lookup[CALCX_ARRSIZE-1][0])
return 1000000;
else
small = 0;
while (fvalue > calcx_lookup[ctr][small])
ctr++;
if (small)
return (CALCX_SPLIT * ctr / CALCX_ARRSIZE);
else
return (1000000 * ctr / CALCX_ARRSIZE) ;
}
/* calculate first loss interval
*
* returns estimated loss interval in usecs */
static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
struct dccp_rx_hist_entry *entry, *next, *tail = NULL;
u32 rtt, delta, x_recv, fval, p, tmp2;
struct timeval tstamp = { 0, };
int interval = 0;
int win_count = 0;
int step = 0;
u64 tmp1;
list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
dccphrx_node) {
if (dccp_rx_hist_entry_data_packet(entry)) {
tail = entry;
switch (step) {
case 0:
tstamp = entry->dccphrx_tstamp;
win_count = entry->dccphrx_ccval;
step = 1;
break;
case 1:
interval = win_count - entry->dccphrx_ccval;
if (interval < 0)
interval += TFRC_WIN_COUNT_LIMIT;
if (interval > 4)
goto found;
break;
}
}
}
if (step == 0) {
printk(KERN_CRIT "%s: %s, sk=%p, packet history contains no "
"data packets!\n",
__FUNCTION__, dccp_role(sk), sk);
return ~0;
}
if (interval == 0) {
ccid3_pr_debug("%s, sk=%p, Could not find a win_count "
"interval > 0. Defaulting to 1\n",
dccp_role(sk), sk);
interval = 1;
}
found:
rtt = timeval_delta(&tstamp, &tail->dccphrx_tstamp) * 4 / interval;
ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n",
dccp_role(sk), sk, rtt);
if (rtt == 0)
rtt = 1;
delta = timeval_now_delta(&hcrx->ccid3hcrx_tstamp_last_feedback);
x_recv = hcrx->ccid3hcrx_bytes_recv * USEC_PER_SEC;
if (likely(delta > 1))
x_recv /= delta;
tmp1 = (u64)x_recv * (u64)rtt;
do_div(tmp1,10000000);
tmp2 = (u32)tmp1;
fval = (hcrx->ccid3hcrx_s * 100000) / tmp2;
/* do not alter order above or you will get overflow on 32 bit */
p = calcx_reverse_lookup(fval);
ccid3_pr_debug("%s, sk=%p, receive rate=%u bytes/s, implied "
"loss rate=%u\n", dccp_role(sk), sk, x_recv, p);
if (p == 0)
return ~0;
else
return 1000000 / p;
}
static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
struct ccid3_loss_interval_hist_entry *li_entry;
if (seq_loss != DCCP_MAX_SEQNO + 1) {
ccid3_pr_debug("%s, sk=%p, seq_loss=%llu, win_loss=%u, "
"packet loss detected\n",
dccp_role(sk), sk, seq_loss, win_loss);
if (list_empty(&hcrx->ccid3hcrx_loss_interval_hist)) {
struct ccid3_loss_interval_hist_entry *li_tail = NULL;
int i;
ccid3_pr_debug("%s, sk=%p, first loss event detected, "
"creating history\n",
dccp_role(sk), sk);
for (i = 0; i <= TFRC_RECV_IVAL_F_LENGTH; ++i) {
li_entry = ccid3_loss_interval_hist_entry_new(SLAB_ATOMIC);
if (li_entry == NULL) {
ccid3_loss_interval_history_delete(&hcrx->ccid3hcrx_loss_interval_hist);
ccid3_pr_debug("%s, sk=%p, not enough "
"mem for creating "
"history\n",
dccp_role(sk), sk);
return;
}
if (li_tail == NULL)
li_tail = li_entry;
list_add(&li_entry->ccid3lih_node,
&hcrx->ccid3hcrx_loss_interval_hist);
}
li_entry->ccid3lih_seqno = seq_loss;
li_entry->ccid3lih_win_count = win_loss;
li_tail->ccid3lih_interval = ccid3_hc_rx_calc_first_li(sk);
}
}
/* FIXME: find end of interval */
}
static void ccid3_hc_rx_detect_loss(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
struct dccp_rx_hist_entry *entry, *next, *packet;
struct dccp_rx_hist_entry *a_loss = NULL;
struct dccp_rx_hist_entry *b_loss = NULL;
u64 seq_loss = DCCP_MAX_SEQNO + 1;
u8 win_loss = 0;
u8 num_later = TFRC_RECV_NUM_LATE_LOSS;
list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
dccphrx_node) {
if (num_later == 0) {
b_loss = entry;
break;
} else if (dccp_rx_hist_entry_data_packet(entry))
--num_later;
}
if (b_loss == NULL)
goto out_update_li;
num_later = 1;
list_for_each_entry_safe_continue(entry, next, &hcrx->ccid3hcrx_hist,
dccphrx_node) {
if (num_later == 0) {
a_loss = entry;
break;
} else if (dccp_rx_hist_entry_data_packet(entry))
--num_later;
}
if (a_loss == NULL) {
if (list_empty(&hcrx->ccid3hcrx_loss_interval_hist)) {
/* no loss event have occured yet */
ccid3_pr_debug("%s, sk=%p, TODO: find a lost data "
"packet by comparing to initial "
"seqno\n",
dccp_role(sk), sk);
goto out_update_li;
} else {
pr_info("%s: %s, sk=%p, ERROR! Less than 4 data "
"packets in history",
__FUNCTION__, dccp_role(sk), sk);
return;
}
}
/* Locate a lost data packet */
entry = packet = b_loss;
list_for_each_entry_safe_continue(entry, next, &hcrx->ccid3hcrx_hist,
dccphrx_node) {
u64 delta = dccp_delta_seqno(entry->dccphrx_seqno,
packet->dccphrx_seqno);
if (delta != 0) {
if (dccp_rx_hist_entry_data_packet(packet))
--delta;
/*
* FIXME: check this, probably this % usage is because
* in earlier drafts the ndp count was just 8 bits
* long, but now it cam be up to 24 bits long.
*/
#if 0
if (delta % DCCP_NDP_LIMIT !=
(packet->dccphrx_ndp -
entry->dccphrx_ndp) % DCCP_NDP_LIMIT)
#endif
if (delta !=
packet->dccphrx_ndp - entry->dccphrx_ndp) {
seq_loss = entry->dccphrx_seqno;
dccp_inc_seqno(&seq_loss);
}
}
packet = entry;
if (packet == a_loss)
break;
}
if (seq_loss != DCCP_MAX_SEQNO + 1)
win_loss = a_loss->dccphrx_ccval;
out_update_li:
ccid3_hc_rx_update_li(sk, seq_loss, win_loss);
}
static u32 ccid3_hc_rx_calc_i_mean(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
struct ccid3_loss_interval_hist_entry *li_entry, *li_next;
int i = 0;
u32 i_tot;
u32 i_tot0 = 0;
u32 i_tot1 = 0;
u32 w_tot = 0;
list_for_each_entry_safe(li_entry, li_next,
&hcrx->ccid3hcrx_loss_interval_hist,
ccid3lih_node) {
if (i < TFRC_RECV_IVAL_F_LENGTH) {
i_tot0 += li_entry->ccid3lih_interval * ccid3_hc_rx_w[i];
w_tot += ccid3_hc_rx_w[i];
}
if (i != 0)
i_tot1 += li_entry->ccid3lih_interval * ccid3_hc_rx_w[i - 1];
if (++i > TFRC_RECV_IVAL_F_LENGTH)
break;
}
if (i != TFRC_RECV_IVAL_F_LENGTH) {
pr_info("%s: %s, sk=%p, ERROR! Missing entry in "
"interval history!\n",
__FUNCTION__, dccp_role(sk), sk);
return 0;
}
i_tot = max(i_tot0, i_tot1);
/* FIXME: Why do we do this? -Ian McDonald */
if (i_tot * 4 < w_tot)
i_tot = w_tot * 4;
return i_tot * 4 / w_tot;
}
static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
const struct dccp_options_received *opt_recv;
struct dccp_rx_hist_entry *packet;
struct timeval now;
u8 win_count;
u32 p_prev;
int ins;
if (hcrx == NULL)
return;
BUG_ON(!(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA ||
hcrx->ccid3hcrx_state == TFRC_RSTATE_DATA));
opt_recv = &dp->dccps_options_received;
switch (DCCP_SKB_CB(skb)->dccpd_type) {
case DCCP_PKT_ACK:
if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)
return;
case DCCP_PKT_DATAACK:
if (opt_recv->dccpor_timestamp_echo == 0)
break;
p_prev = hcrx->ccid3hcrx_rtt;
do_gettimeofday(&now);
hcrx->ccid3hcrx_rtt = timeval_usecs(&now) -
(opt_recv->dccpor_timestamp_echo -
opt_recv->dccpor_elapsed_time) * 10;
if (p_prev != hcrx->ccid3hcrx_rtt)
ccid3_pr_debug("%s, New RTT=%luus, elapsed time=%u\n",
dccp_role(sk), hcrx->ccid3hcrx_rtt,
opt_recv->dccpor_elapsed_time);
break;
case DCCP_PKT_DATA:
break;
default:
ccid3_pr_debug("%s, sk=%p, not DATA/DATAACK/ACK packet(%s)\n",
dccp_role(sk), sk,
dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
return;
}
packet = dccp_rx_hist_entry_new(ccid3_rx_hist, opt_recv->dccpor_ndp,
skb, SLAB_ATOMIC);
if (packet == NULL) {
ccid3_pr_debug("%s, sk=%p, Not enough mem to add rx packet "
"to history (consider it lost)!",
dccp_role(sk), sk);
return;
}
win_count = packet->dccphrx_ccval;
ins = ccid3_hc_rx_add_hist(sk, packet);
if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK)
return;
switch (hcrx->ccid3hcrx_state) {
case TFRC_RSTATE_NO_DATA:
ccid3_pr_debug("%s, sk=%p(%s), skb=%p, sending initial "
"feedback\n",
dccp_role(sk), sk,
dccp_state_name(sk->sk_state), skb);
ccid3_hc_rx_send_feedback(sk);
ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA);
return;
case TFRC_RSTATE_DATA:
hcrx->ccid3hcrx_bytes_recv += skb->len -
dccp_hdr(skb)->dccph_doff * 4;
if (ins != 0)
break;
do_gettimeofday(&now);
if (timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) >=
hcrx->ccid3hcrx_rtt) {
hcrx->ccid3hcrx_tstamp_last_ack = now;
ccid3_hc_rx_send_feedback(sk);
}
return;
default:
printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
__FUNCTION__, dccp_role(sk), sk, hcrx->ccid3hcrx_state);
dump_stack();
return;
}
/* Dealing with packet loss */
ccid3_pr_debug("%s, sk=%p(%s), data loss! Reacting...\n",
dccp_role(sk), sk, dccp_state_name(sk->sk_state));
ccid3_hc_rx_detect_loss(sk);
p_prev = hcrx->ccid3hcrx_p;
/* Calculate loss event rate */
if (!list_empty(&hcrx->ccid3hcrx_loss_interval_hist))
/* Scaling up by 1000000 as fixed decimal */
hcrx->ccid3hcrx_p = 1000000 / ccid3_hc_rx_calc_i_mean(sk);
if (hcrx->ccid3hcrx_p > p_prev) {
ccid3_hc_rx_send_feedback(sk);
return;
}
}
static int ccid3_hc_rx_init(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx;
ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
hcrx = dp->dccps_hc_rx_ccid_private = kmalloc(sizeof(*hcrx),
gfp_any());
if (hcrx == NULL)
return -ENOMEM;
memset(hcrx, 0, sizeof(*hcrx));
if (dp->dccps_avg_packet_size >= TFRC_MIN_PACKET_SIZE &&
dp->dccps_avg_packet_size <= TFRC_MAX_PACKET_SIZE)
hcrx->ccid3hcrx_s = (u16)dp->dccps_avg_packet_size;
else
hcrx->ccid3hcrx_s = TFRC_STD_PACKET_SIZE;
hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA;
INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist);
INIT_LIST_HEAD(&hcrx->ccid3hcrx_loss_interval_hist);
/*
* XXX this seems to be paranoid, need to think more about this, for
* now start with something different than zero. -acme
*/
hcrx->ccid3hcrx_rtt = USEC_PER_SEC / 5;
return 0;
}
static void ccid3_hc_rx_exit(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
if (hcrx == NULL)
return;
ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM);
/* Empty packet history */
dccp_rx_hist_purge(ccid3_rx_hist, &hcrx->ccid3hcrx_hist);
/* Empty loss interval history */
ccid3_loss_interval_history_delete(&hcrx->ccid3hcrx_loss_interval_hist);
kfree(dp->dccps_hc_rx_ccid_private);
dp->dccps_hc_rx_ccid_private = NULL;
}
static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
{
const struct dccp_sock *dp = dccp_sk(sk);
const struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
if (hcrx == NULL)
return;
info->tcpi_ca_state = hcrx->ccid3hcrx_state;
info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt;
}
static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
{
const struct dccp_sock *dp = dccp_sk(sk);
const struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
if (hctx == NULL)
return;
info->tcpi_rto = hctx->ccid3hctx_t_rto;
info->tcpi_rtt = hctx->ccid3hctx_rtt;
}
static struct ccid ccid3 = {
.ccid_id = 3,
.ccid_name = "ccid3",
.ccid_owner = THIS_MODULE,
.ccid_init = ccid3_init,
.ccid_exit = ccid3_exit,
.ccid_hc_tx_init = ccid3_hc_tx_init,
.ccid_hc_tx_exit = ccid3_hc_tx_exit,
.ccid_hc_tx_send_packet = ccid3_hc_tx_send_packet,
.ccid_hc_tx_packet_sent = ccid3_hc_tx_packet_sent,
.ccid_hc_tx_packet_recv = ccid3_hc_tx_packet_recv,
.ccid_hc_tx_insert_options = ccid3_hc_tx_insert_options,
.ccid_hc_tx_parse_options = ccid3_hc_tx_parse_options,
.ccid_hc_rx_init = ccid3_hc_rx_init,
.ccid_hc_rx_exit = ccid3_hc_rx_exit,
.ccid_hc_rx_insert_options = ccid3_hc_rx_insert_options,
.ccid_hc_rx_packet_recv = ccid3_hc_rx_packet_recv,
.ccid_hc_rx_get_info = ccid3_hc_rx_get_info,
.ccid_hc_tx_get_info = ccid3_hc_tx_get_info,
};
module_param(ccid3_debug, int, 0444);
MODULE_PARM_DESC(ccid3_debug, "Enable debug messages");
static __init int ccid3_module_init(void)
{
int rc = -ENOBUFS;
ccid3_rx_hist = dccp_rx_hist_new("ccid3");
if (ccid3_rx_hist == NULL)
goto out;
ccid3_tx_hist = dccp_tx_hist_new("ccid3");
if (ccid3_tx_hist == NULL)
goto out_free_rx;
ccid3_loss_interval_hist_slab = kmem_cache_create("li_hist_ccid3",
sizeof(struct ccid3_loss_interval_hist_entry),
0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
if (ccid3_loss_interval_hist_slab == NULL)
goto out_free_tx;
rc = ccid_register(&ccid3);
if (rc != 0)
goto out_free_loss_interval_history;
out:
return rc;
out_free_loss_interval_history:
kmem_cache_destroy(ccid3_loss_interval_hist_slab);
ccid3_loss_interval_hist_slab = NULL;
out_free_tx:
dccp_tx_hist_delete(ccid3_tx_hist);
ccid3_tx_hist = NULL;
out_free_rx:
dccp_rx_hist_delete(ccid3_rx_hist);
ccid3_rx_hist = NULL;
goto out;
}
module_init(ccid3_module_init);
static __exit void ccid3_module_exit(void)
{
#ifdef CONFIG_IP_DCCP_UNLOAD_HACK
/*
* Hack to use while developing, so that we get rid of the control
* sock, that is what keeps a refcount on dccp.ko -acme
*/
extern void dccp_ctl_sock_exit(void);
dccp_ctl_sock_exit();
#endif
ccid_unregister(&ccid3);
if (ccid3_tx_hist != NULL) {
dccp_tx_hist_delete(ccid3_tx_hist);
ccid3_tx_hist = NULL;
}
if (ccid3_rx_hist != NULL) {
dccp_rx_hist_delete(ccid3_rx_hist);
ccid3_rx_hist = NULL;
}
if (ccid3_loss_interval_hist_slab != NULL) {
kmem_cache_destroy(ccid3_loss_interval_hist_slab);
ccid3_loss_interval_hist_slab = NULL;
}
}
module_exit(ccid3_module_exit);
MODULE_AUTHOR("Ian McDonald <iam4@cs.waikato.ac.nz>, "
"Arnaldo Carvalho de Melo <acme@ghostprotocols.net>");
MODULE_DESCRIPTION("DCCP TFRC CCID3 CCID");
MODULE_LICENSE("GPL");
MODULE_ALIAS("net-dccp-ccid-3");