NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
Minstrel.c
1/************************************************************************************
2* Copyright (C) 2023 *
3* TETCOS, Bangalore. India *
4* *
5* Tetcos owns the intellectual property rights in the Product and its content. *
6* The copying, redistribution, reselling or publication of any or all of the *
7* Product or its content without express prior written consent of Tetcos is *
8* prohibited. Ownership and / or any other right relating to the software and all *
9* intellectual property rights therein shall remain at all times with Tetcos. *
10* *
11* This source code is licensed per the NetSim license agreement. *
12* *
13* No portion of this source code may be used as the basis for a derivative work, *
14* or used, for any purpose other than its intended use per the NetSim license *
15* agreement. *
16* *
17* This source code and the algorithms contained within it are confidential trade *
18* secrets of TETCOS and may not be used as the basis for any other software, *
19* hardware, product or service. *
20* *
21* Author: Shashi Kant Suman *
22* *
23* ----------------------------------------------------------------------------------*/
24#include "main.h"
25
26#include "Minstrel.h"
27
28static int show=0; //variable for showing Minstrel Table
29
30
31#define SEED_r &NETWORK->ppstruDeviceList[0]->ulSeed[0],&NETWORK->ppstruDeviceList[0]->ulSeed[1]
32#define rand01() (fn_NetSim_Utilities_GenerateRandomNo(SEED_r)/NETSIM_RAND_MAX)
33#define ackTime(phy) (phy->plmeCharacteristics.aSIFSTime + get_preamble_time(phy) + (getAckSize(phy) * 8)/phy->dControlFrameDataRate)
34#define tSlot(phy) (phy->plmeCharacteristics.aSlotTime)
35#define transmissionTime(phy,byte,rate) (phy->plmeCharacteristics.aSIFSTime + get_preamble_time(phy)+ byte*8/rate)
36
37static Ptr_MinstrelPerRemoteStation getMinstrelInfo(NETSIM_ID dev,NETSIM_ID ifid,NETSIM_ID recv)
38{
39 switch (IEEE802_11_PHY(dev, ifid)->PhyProtocol)
40 {
41 case IEEE_802_11a:
42 case IEEE_802_11b:
43 case IEEE_802_11g:
44 case IEEE_802_11p:
45 {
46 Ptr_MinstrelWifiStation station = IEEE802_11_PHY(dev, ifid)->rateAdaptationData;
47 return station->minstrelInfo[recv];
48 }
49 break;
50 case IEEE_802_11ac:
51 case IEEE_802_11n:
52 case IEEE_802_11ax:
53 break;
54 default:
55 fnNetSimError("Unknown phy protocol in %s\n", __FUNCTION__);
56 }
57 return NULL;
58}
59
60void get_data_rate(NETSIM_ID devid,NETSIM_ID ifid,double* rate,unsigned int* len)
61{
62 PIEEE802_11_PHY_VAR phy = IEEE802_11_PHY(devid,ifid);
63 switch(phy->PhyProtocol)
64 {
65 case IEEE_802_11a:
66 case IEEE_802_11g:
67 case IEEE_802_11p:
68 get_ofdm_phy_all_rate((int)phy->dChannelBandwidth, rate, len);
69 break;
70 case IEEE_802_11b:
71 get_dsss_phy_all_rate(rate, len);
72 break;
73 case IEEE_802_11n:
74 case IEEE_802_11ac:
75 default:
76 fnNetSimError("Unknown phy protocol %d in %s.\n",phy->PhyProtocol,__FUNCTION__);
77 return;
78 }
79}
80
81void Minstrel_Init(NETSIM_ID nDevId,NETSIM_ID nifid)
82{
83 switch(IEEE802_11_PHY(nDevId,nifid)->PhyProtocol)
84 {
85 case IEEE_802_11a:
86 case IEEE_802_11b:
87 case IEEE_802_11g:
88 case IEEE_802_11p:
89 InitMinstrel(nDevId,nifid);
90 break;
91 case IEEE_802_11ac:
92 case IEEE_802_11n:
93 Ht_InitMinstrel(nDevId,nifid);
94 break;
95 case IEEE_802_11ax:
96 He_InitMinstrel(nDevId, nifid);
97 break;
98 default:
99 fnNetSimError("Unknown phy protocol in %s\n",__FUNCTION__);
100 }
101}
102
103BOOL Minstrel_DoNeedDataSend(NETSIM_ID nDevId,NETSIM_ID nifid,NETSIM_ID recvid)
104{
105 switch(IEEE802_11_PHY(nDevId,nifid)->PhyProtocol)
106 {
107 case IEEE_802_11a:
108 case IEEE_802_11b:
109 case IEEE_802_11g:
110 case IEEE_802_11p:
111 return DoNeedDataRetransmission(nDevId,nifid,recvid);
112 break;
113 case IEEE_802_11ac:
114 case IEEE_802_11n:
115 return Ht_DoNeedDataRetransmission(nDevId,nifid,recvid);
116 break;
117 case IEEE_802_11ax:
118 return He_DoNeedDataRetransmission(nDevId, nifid, recvid);
119 break;
120 default:
121 fnNetSimError("Unknown phy protocol in %s\n",__FUNCTION__);
122 }
123 return false;
124}
125
126void Minstrel_ReportDataFailed(NETSIM_ID nDevId,NETSIM_ID nifid,NETSIM_ID recvid)
127{
128 switch(IEEE802_11_PHY(nDevId,nifid)->PhyProtocol)
129 {
130 case IEEE_802_11a:
131 case IEEE_802_11b:
132 case IEEE_802_11g:
133 case IEEE_802_11p:
134 DoReportDataFailed(nDevId,nifid,recvid);
135 break;
136 case IEEE_802_11ac:
137 case IEEE_802_11n:
138 {
139 UINT c = 0;
140 NetSim_PACKET* p = IEEE802_11_MAC(nDevId,nifid)->currentProcessingPacket;
141 while(p)
142 {
143 c++;
144 p=p->pstruNextPacket;
145 }
146 DoReportAmpduStatus(nDevId,nifid,recvid,0,c);
147 }
148 break;
149 case IEEE_802_11ax:
150 {
151 UINT c = 0;
152 NetSim_PACKET* p = IEEE802_11_MAC(nDevId, nifid)->currentProcessingPacket;
153 while (p)
154 {
155 c++;
156 p = p->pstruNextPacket;
157 }
158 He_DoReportAmpduStatus(nDevId, nifid, recvid, 0, c);
159 }
160 break;
161 default:
162 fnNetSimError("Unknown phy protocol in %s\n",__FUNCTION__);
163 }
164}
165
166void Minstrel_ReportFinalDataFailed(NETSIM_ID nDevId,NETSIM_ID nifid,NETSIM_ID recvid)
167{
168 switch(IEEE802_11_PHY(nDevId,nifid)->PhyProtocol)
169 {
170 case IEEE_802_11a:
171 case IEEE_802_11b:
172 case IEEE_802_11g:
173 case IEEE_802_11p:
174 DoReportFinalDataFailed(nDevId,nifid,recvid);
175 break;
176 case IEEE_802_11ac:
177 case IEEE_802_11n:
178 {
179 UINT c = 0;
180 NetSim_PACKET* p = IEEE802_11_MAC(nDevId,nifid)->currentProcessingPacket;
181 while(p)
182 {
183 c++;
184 p=p->pstruNextPacket;
185 }
186 DoReportAmpduStatus(nDevId,nifid,recvid,0,c);
187 }
188 break;
189 case IEEE_802_11ax:
190 {
191 UINT c = 0;
192 NetSim_PACKET* p = IEEE802_11_MAC(nDevId, nifid)->currentProcessingPacket;
193 while (p)
194 {
195 c++;
196 p = p->pstruNextPacket;
197 }
198 He_DoReportAmpduStatus(nDevId, nifid, recvid, 0, c);
199 }
200 break;
201 default:
202 fnNetSimError("Unknown phy protocol in %s\n",__FUNCTION__);
203 }
204}
205
206void InitMinstrel(NETSIM_ID nDevId,NETSIM_ID nifid){
207 NETSIM_ID i;
208 NETSIM_ID nPort, nNumOfPorts;
209 Ptr_MinstrelWifiStation wifiStation;
210 //initialize the Minstrel global variables
211 show=1;
212 updateStatsTime = 100*1000; //100 ms
213 lookAroundRate= 10;
214 sampleCol = 10;
215 ewmaWeight = 25;
216
217 wifiStation = (Ptr_MinstrelWifiStation)calloc(1,sizeof(MinstrelWifiStation));
218 wifiStation->minstrelInfo = (Ptr_MinstrelPerRemoteStation*)calloc(NETWORK->nDeviceCount+1,sizeof(Ptr_MinstrelPerRemoteStation));
219
220 for(i=1;i<=NETWORK->nDeviceCount;i++)
221 {
222 nNumOfPorts = NETWORK->ppstruDeviceList[i - 1]->nNumOfInterface;
223 for (nPort = 1; nPort <= nNumOfPorts; nPort++)
224 {
225 if (isIEEE802_11_Configure(i, nPort))
226 {
227 wifiStation->minstrelInfo[i] = (Ptr_MinstrelPerRemoteStation)calloc(1,sizeof(MinstrelPerRemoteStation));
228 CheckInit(wifiStation->minstrelInfo[i],nDevId,nifid);
229 }
230 }
231 }
232 IEEE802_11_PHY(nDevId,nifid)->rateAdaptationData = wifiStation;
233}
234
235static void CheckInit(Ptr_MinstrelPerRemoteStation station,NETSIM_ID nDevId,NETSIM_ID nifid){
236 if(!station->isInitialized){
237 UINT i,get_nrate;
238 double get_rate[10];
239 //function to get the available rates for the device
240 get_data_rate(nDevId,nifid,get_rate,&get_nrate);
241
242 station->nextStatsUpdate = ldEventTime + updateStatsTime; //fill
243 station->maxTpRate= 0;
244 station->maxTp2Rate= 0;
245 station->maxProbRate= 0;
246 station->phy = IEEE802_11_PHY(nDevId,nifid);
247
248 station->nRate = get_nrate; //fill
249 station->baseRate = 0;
250 for(i=0;i<station->nRate;i++)
251 if(get_rate[i] < get_rate[station->baseRate]) //fill
252 station->baseRate = i;
253
254 station->sampleRate= 0;
255 station->trRate= 0;
256
257 station->isSampling= false;
258 station->samplePacketCount= 0;
259 station->totalPacketCount= 0;
260 station->shortRetry= 0;
261 station->longRetry= 0;
262 station->totalRetry= 0;
263
264 station->col= 0;
265 station->row= 0;
266 InitSampleTable(station);
267 InitMinstrelTable(station,get_rate);
268 station->isInitialized = true;
269 }
270}
271
272static void InitSampleTable(Ptr_MinstrelPerRemoteStation station){
273 UINT i,j;
274 //Memory allocation for Sample Table
275 station->sampleTable = calloc(station->nRate, sizeof(UINT*));
276 for(i=0;i<station->nRate;i++){
277 station->sampleTable[i] = calloc(sampleCol,sizeof(UINT));
278 for(j=0;j<sampleCol;j++)
279 station->sampleTable[i][j] = 10000;
280 //memset(station->sampleTable[i],10000,sampleCol*sizeof(UINT));
281 }
282
283 //set indices for traversing in Sample Table
284 station->col = 0;
285 station->row = 0;
286 //Randomly filling table with values [0,nRate-1]
287 for(j=0;j<sampleCol;j++){
288 for(i=0;i<station->nRate;i++){
289 //generate the random number
290 int random_var = station->nRate*(int)rand01();
291 random_var = (i+random_var)%station->nRate;
292
293 while(station->sampleTable[random_var][j] != 10000){
294 random_var = (random_var + 1)%station->nRate;
295 }
296 station->sampleTable[random_var][j] = i;
297 }
298 }
299}
300
301static void InitMinstrelTable(Ptr_MinstrelPerRemoteStation station,double *rate_arr){
302 UINT i,cw;
303 double trTime;
304 station->minstrelTable = (RateInfo*)calloc(station->nRate,sizeof(RateInfo));
305 for(i=0;i<station->nRate;i++){
306 station->minstrelTable[i].currNumAttempt= 0;
307 station->minstrelTable[i].currNumSuccess= 0;
308 station->minstrelTable[i].prevNumAttempt = 0;
309 station->minstrelTable[i].prevNumSuccess = 0;
310 station->minstrelTable[i].totalNumAttempt= 0;
311 station->minstrelTable[i].totalNumSuccess= 0;
312 station->minstrelTable[i].prob= 0;
313 station->minstrelTable[i].ewmaProb= 0;
314 station->minstrelTable[i].throughput= 0;
315 station->minstrelTable[i].numSampleSkipped= 0;
316 station->minstrelTable[i].rate= rate_arr[i]; //fill
317 station->minstrelTable[i].sampleLimit= -1; //no limit
318 station->minstrelTable[i].retryCount= 1; //atleast 1 retry count for each rate
319 station->minstrelTable[i].adjustedRetryCount= 1;
320 station->minstrelTable[i].perfectTrTime= transmissionTime(station->phy,1500,rate_arr[i]); //fill
321
322 cw = 15; //minimum contention window
323 trTime= station->minstrelTable[i].perfectTrTime + ackTime(station->phy); //fill
324
325 while(1){
326 //add retransmission time
327 trTime += station->minstrelTable[i].perfectTrTime + ackTime(station->phy); //fill
328
329 //contention window and average backoff
330 trTime+= (tSlot(station->phy)*cw)>>1; //fill
331 cw = min((cw<<1)|1,1023); //max contention window = 1023
332
333 //retry count is limited by 6 millisecond
334 if(trTime < 6000){
335 station->minstrelTable[i].retryCount++;
336 station->minstrelTable[i].adjustedRetryCount++;
337 }
338 else{
339 break;
340 }
341 }
342 }
343 UpdateStats(station);
344}
345
346void DoReportDataOk(NETSIM_ID dev,NETSIM_ID ifid,NETSIM_ID recv){
347 Ptr_MinstrelPerRemoteStation station = getMinstrelInfo(dev,ifid,recv);
348 if(!station->isInitialized)
349 return;
350
351 station->minstrelTable[station->trRate].currNumAttempt++;
352 station->minstrelTable[station->trRate].currNumSuccess++;
353
354 UpdatePacketCounter(station);
355 UpdateRetry(station);
356 UpdateStats(station);
357
358 if(station->nRate >=1)
359 station->trRate = FindRate(station);
360}
361
362void DoReportDataFailed(NETSIM_ID dev,NETSIM_ID ifid,NETSIM_ID recv){
363 Ptr_MinstrelPerRemoteStation station = getMinstrelInfo(dev,ifid,recv);
364 if(!station->isInitialized)
365 return;
366 UpdateRate(station);
367}
368
369static void UpdateRate(Ptr_MinstrelPerRemoteStation station){
370 //Retry Chain Table is Implemented here.
371 //Only called when data fails
372
373 station->longRetry++;
374 station->totalPacketCount++;
375 station->minstrelTable[station->trRate].currNumAttempt++;
376 //if sample rate is used
377 if(station->isSampling && station->trRate == station->sampleRate)
378 station->samplePacketCount++;
379
380 //for normal rate, we aren't sampling rates
381 if(!station->isSampling){
382
383 //first try with best throughput
384 if(station->longRetry < station->minstrelTable[station->maxTpRate].adjustedRetryCount){
385 station->trRate = station->maxTpRate;
386 }
387 //use 2nd best throughput rate
388 else if(station->longRetry <= station->minstrelTable[station->maxTpRate].adjustedRetryCount +
389 station->minstrelTable[station->maxTp2Rate].adjustedRetryCount){
390 station->trRate = station->maxTp2Rate;
391 }
392 //use best probability rate
393 else if(station->longRetry <= station->minstrelTable[station->maxTpRate].adjustedRetryCount +
394 station->minstrelTable[station->maxTp2Rate].adjustedRetryCount +
395 station->minstrelTable[station->maxProbRate].adjustedRetryCount){
396 station->trRate = station->maxProbRate;
397 }
398 //use lowest base rate
399 else if(station->longRetry > station->minstrelTable[station->maxTpRate].adjustedRetryCount +
400 station->minstrelTable[station->maxTp2Rate].adjustedRetryCount +
401 station->minstrelTable[station->maxProbRate].adjustedRetryCount){
402 station->trRate = station->baseRate;
403 }
404 else{
405 fnNetSimError("Failed to Update Rate");
406 }
407 }
408 //for lookaround rate, currently sampling
409 else{
410 //current sampling is slower than current best rate
411 if(station->isDeferredSample){
412 //use best throughput rate
413 if(station->longRetry < station->minstrelTable[station->maxTpRate].adjustedRetryCount){
414 station->trRate = station->maxTpRate;
415 }
416 //use random rate
417 else if(station->longRetry <= station->minstrelTable[station->maxTpRate].adjustedRetryCount +
418 station->minstrelTable[station->sampleRate].adjustedRetryCount){
419 station->trRate = station->sampleRate;
420 }
421 //use best probability rate
422 else if(station->longRetry <= station->minstrelTable[station->maxTpRate].adjustedRetryCount +
423 station->minstrelTable[station->sampleRate].adjustedRetryCount +
424 station->minstrelTable[station->maxProbRate].adjustedRetryCount){
425 station->trRate = station->maxProbRate;
426 }
427 //use lowest base rate
428 else if(station->longRetry > station->minstrelTable[station->maxTpRate].adjustedRetryCount +
429 station->minstrelTable[station->sampleRate].adjustedRetryCount +
430 station->minstrelTable[station->maxProbRate].adjustedRetryCount){
431 station->trRate = station->baseRate;
432 }
433 else{
434 fnNetSimError("Failed to Update Rate");
435 }
436 }
437 //current sampling rate is better than current best rate
438 else{
439 //use random rate
440 if(station->longRetry < station->minstrelTable[station->sampleRate].adjustedRetryCount){
441 station->trRate = station->sampleRate;
442 }
443 //use best throughput rate
444 else if(station->longRetry < station->minstrelTable[station->sampleRate].adjustedRetryCount +
445 station->minstrelTable[station->maxTpRate].adjustedRetryCount){
446 station->trRate = station->maxTpRate;
447 }
448 //use best probability rate
449 else if(station->longRetry <= station->minstrelTable[station->maxTpRate].adjustedRetryCount +
450 station->minstrelTable[station->sampleRate].adjustedRetryCount +
451 station->minstrelTable[station->maxProbRate].adjustedRetryCount){
452 station->trRate = station->maxProbRate;
453 }
454 //use lowest base rate
455 else if(station->longRetry > station->minstrelTable[station->maxTpRate].adjustedRetryCount +
456 station->minstrelTable[station->sampleRate].adjustedRetryCount +
457 station->minstrelTable[station->maxProbRate].adjustedRetryCount){
458 station->trRate = station->baseRate;
459 }
460 else{
461 fnNetSimError("Failed to Update Rate");
462 }
463 }
464 }
465}
466
467static void UpdatePacketCounter(Ptr_MinstrelPerRemoteStation station){
468 //Updates the packet counter of station
469 station->totalPacketCount++;
470
471 //If it is sampling and sampling rate is used
472 if(station->isSampling && station->trRate == station->sampleRate){
473 station->samplePacketCount++;
474 }
475
476 if(station->numSampleDeferred >0){
477 station->numSampleDeferred--;
478 }
479
480 //wrap around
481 if(station->totalPacketCount < 0){
482 station->numSampleDeferred = 0;
483 station->samplePacketCount = 0;
484 station->totalPacketCount = 0;
485 }
486
487 //whether sampling/deferred sample or not will be decided by "FindRate"
488 station->isSampling = false;
489 station->isDeferredSample = false;
490}
491
492static void UpdateRetry(Ptr_MinstrelPerRemoteStation station){
493 station->totalRetry += station->longRetry + station->shortRetry;
494 station->longRetry = 0;
495 station->shortRetry = 0;
496}
497
498static void UpdateStats(Ptr_MinstrelPerRemoteStation station){
499 UINT i,index_max_tp, index_max_tp2, index_max_prob;
500 double tempProb, max_prob, max_tp;
501 //Update time has not come
502 if(ldEventTime < station->nextStatsUpdate){
503 return;
504 }
505 if(!station->isInitialized){
506 return;
507 }
508 station->nextStatsUpdate = ldEventTime + updateStatsTime;
509 //update for each rate in minstrel table
510 for(i=0;i<station->nRate;i++){
511 double trTime;
512 trTime = station->minstrelTable[i].perfectTrTime;
513
514 //just for initialization
515 if(trTime == 0){
516 trTime = 1000*1000; //1 second
517 }
518
519 //if attempted something
520 if(station->minstrelTable[i].currNumAttempt){
521 station->minstrelTable[i].numSampleSkipped = 0;
522 //calculate probability of success
523 tempProb = (station->minstrelTable[i].currNumSuccess*18000) / station->minstrelTable[i].currNumAttempt;
524 tempProb = tempProb/18000.0;
525 station->minstrelTable[i].prob = tempProb;
526
527 //Updating this rate for the first time
528 if(station->minstrelTable[i].totalNumAttempt == 0){
529 station->minstrelTable[i].ewmaProb = tempProb;
530 }
531 else{
532 //ewma probability
533 tempProb = (tempProb*ewmaWeight + station->minstrelTable[i].ewmaProb*(100-ewmaWeight))/100;
534 station->minstrelTable[i].ewmaProb = tempProb;
535 }
536
537 //calculate Throughput(using ewmaProb)
538 //linux implementation
539 if(tempProb < 0.1)
540 station->minstrelTable[i].throughput = 0;
541 else
542 station->minstrelTable[i].throughput = (tempProb*8*1500)/(trTime); //fill
543
544 }
545 //if not attempted at this rate
546 else{
547 station->minstrelTable[i].numSampleSkipped++;
548 }
549
550 //bookkeeping
551 station->minstrelTable[i].totalNumAttempt += station->minstrelTable[i].currNumAttempt;
552 station->minstrelTable[i].totalNumSuccess += station->minstrelTable[i].currNumSuccess;
553 station->minstrelTable[i].prevNumAttempt = station->minstrelTable[i].currNumAttempt;
554 station->minstrelTable[i].prevNumSuccess = station->minstrelTable[i].currNumSuccess;
555 station->minstrelTable[i].currNumAttempt = 0;
556 station->minstrelTable[i].currNumSuccess = 0;
557
558 //sample less often below 10% and above 95% success
559 if(station->minstrelTable[i].ewmaProb < 0.1 || station->minstrelTable[i].ewmaProb > 0.95){
560 /**
561 * See: http://wireless.kernel.org/en/developers/Documentation/mac80211/RateControl/minstrel/
562 *
563 * Analysis of information showed that the system was sampling too hard at some rates.
564 * For those rates that never work (54mb, 500m range) there is no point in retrying 10 sample packets (< 6 ms time).
565 * Consequently, for the very low probability rates, we try at most twice when fails and not sample more than 4 times.
566 */
567 if(station->minstrelTable[i].retryCount > 2){
568 station->minstrelTable[i].adjustedRetryCount = 2;
569 }
570 station->minstrelTable[i].sampleLimit = 4;
571 }
572 else{
573 //no sampling limit
574 station->minstrelTable[i].sampleLimit = -1;
575 station->minstrelTable[i].adjustedRetryCount = station->minstrelTable[i].retryCount;
576 }
577
578 //if its 0,allow two retries (generally wont happen)
579 if(station->minstrelTable[i].adjustedRetryCount == 0)
580 station->minstrelTable[i].adjustedRetryCount = 2;
581 }
582
583 max_tp=0;
584 index_max_tp= 0;
585 index_max_tp2= 0;
586 index_max_prob=0;
587 max_prob=0;
588 //find the max throughput
589 for(i=0;i<station->nRate;i++){
590 if(max_tp < station->minstrelTable[i].throughput){
591 index_max_tp = i;
592 max_tp = station->minstrelTable[i].throughput;
593 }
594 }
595 //find the 2nd max throughput and high probability succ
596 max_tp=0;
597 for(i=0;i<station->nRate;i++){
598 if(i != index_max_tp && max_tp < station->minstrelTable[i].throughput){
599 index_max_tp2 = i;
600 max_tp = station->minstrelTable[i].throughput;
601 }
602 }
603 //find high probability success rate
604 for(i=0;i<station->nRate;i++){
605 //above 95% choose with highest throughput
606 if(station->minstrelTable[i].ewmaProb >= 0.95 && station->minstrelTable[i].throughput >= station->minstrelTable[index_max_prob].throughput){
607 index_max_prob = i;
608 max_prob = station->minstrelTable[i].ewmaProb;
609 }
610 else if(station->minstrelTable[i].ewmaProb >= max_prob){
611 index_max_prob = i;
612 max_prob = station->minstrelTable[i].ewmaProb;
613 }
614 }
615 station->maxTpRate = index_max_tp;
616 station->maxTp2Rate = index_max_tp2;
617 station->maxProbRate = index_max_prob;
618}
619
620static UINT FindRate(Ptr_MinstrelPerRemoteStation station){
621 UINT idx;
622 int delta;
623 if(station->totalPacketCount == 0)
624 return 0;
625
626 delta = (int)(((station->totalPacketCount*lookAroundRate)/100) - (station->samplePacketCount + station->numSampleDeferred/2 ));
627 //if delta < 0: no sampling required
628 //if delta > 0: insufficient sampling
629 if(delta >=0)
630 {
631 UINT n_rates = station->nRate;
632 if(delta > (int)(2* n_rates)){
633 /* From Linux implementation:
634 * With multi-rate retry, not every planned sample
635 * attempt actually gets used, due to the way the retry
636 * chain is set up - [max_tp,sample,prob,lowest] for
637 * sample_rate < max_tp.
638 *
639 * If there's too much sampling backlog and the link
640 * starts getting worse, minstrel would start bursting
641 * out lots of sampling frames, which would result
642 * in a large throughput loss. */
643 station->samplePacketCount += delta - 2*n_rates;
644 }
645
646 idx = GetNextSample(station); //fill
647 if(idx >= n_rates)
648 fnNetSimError("Unknown rate...!");
649
650 station->sampleRate = idx;
651
652 /* From Linux implementation:
653 * Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage)
654 * rate sampling method should be used.
655 * Respect such rates that are not sampled for 20 iterations.
656 */
657
658 if((station->minstrelTable[idx].perfectTrTime > station->minstrelTable[station->maxTpRate].perfectTrTime)
659 && station->minstrelTable[idx].numSampleSkipped < 20){
660 //if rate is slower defer to 2nd stage
661 station->isDeferredSample = true;
662 station->numSampleDeferred++;
663
664 //set flag for currently sampling
665 station->isSampling = true;
666 }
667 else{
668 //if sample limit is zero then dont sample this rate
669 if(station->minstrelTable[idx].sampleLimit == 0){
670 idx = station->maxTpRate;
671 station->isSampling = false;
672 }
673 else{
674 //set flag for currently sampling
675 station->isSampling = true;
676 if(station->minstrelTable[idx].sampleLimit > 0)
677 station->minstrelTable[idx].sampleLimit--;
678 }
679 }
680
681 //sample rate is slower
682 if(station->isDeferredSample){
683 idx = station->maxTpRate;
684 }
685 }
686 //delta < 0: no sampling required, continue using best rate
687 else
688 {
689 idx = station->maxTpRate;
690 }
691
692 return idx;
693}
694
695static UINT GetNextSample(Ptr_MinstrelPerRemoteStation station){
696 UINT sample_rate = station->sampleTable[station->row][station->col];
697
698 //bookkeeping for next sample index
699 station->row++;
700 if(station->row >= station->nRate){
701 station->row = 0;
702 station->col++;
703 if(station->col >= sampleCol)
704 station->col = 0;
705 }
706 return sample_rate;
707}
708
709//void DoReportFinalDataFailed(Ptr_MinstrelPerRemoteStation station){
710void DoReportFinalDataFailed(NETSIM_ID dev,NETSIM_ID ifid,NETSIM_ID recv){
711 Ptr_MinstrelPerRemoteStation station = getMinstrelInfo(dev,ifid,recv);
712 if(!station->isInitialized)
713 return;
714
715 UpdatePacketCounter(station);
716 UpdateRetry(station);
717 UpdateStats(station);
718
719 if(station->nRate >= 1)
720 station->trRate=FindRate(station);
721}
722
723//BOOL DoNeedDataRetransmission(Ptr_MinstrelPerRemoteStation station){
724BOOL DoNeedDataRetransmission(NETSIM_ID dev,NETSIM_ID ifid,NETSIM_ID recv){
725 Ptr_MinstrelPerRemoteStation station = getMinstrelInfo(dev,ifid,recv);
726 //check if we can do retransmission
727 if(!station->isInitialized)
728 return false;
729 if(station->longRetry > CountRetry(station))
730 return false;
731 else
732 return true;
733}
734
735static UINT CountRetry(Ptr_MinstrelPerRemoteStation station){
736 //if not sampling
737 if(!station->isSampling){
738 return station->minstrelTable[station->maxTpRate].adjustedRetryCount +
739 station->minstrelTable[station->maxTp2Rate].adjustedRetryCount +
740 station->minstrelTable[station->maxProbRate].adjustedRetryCount +
741 station->minstrelTable[station->baseRate].adjustedRetryCount;
742 }
743 else{
744 return station->minstrelTable[station->maxTpRate].adjustedRetryCount +
745 station->minstrelTable[station->sampleRate].adjustedRetryCount +
746 station->minstrelTable[station->maxProbRate].adjustedRetryCount +
747 station->minstrelTable[station->baseRate].adjustedRetryCount;
748 }
749}
750
751static void DoReportRtsFailed(Ptr_MinstrelPerRemoteStation station){
752 station->shortRetry++;
753}
754
755static void DoReportFinalRtsFailed(Ptr_MinstrelPerRemoteStation station){
756 UpdateRetry(station);
757}
758void Minstrel_Free(NETSIM_ID nDevId, NETSIM_ID nifid)
759{
760 NETSIM_ID i;
761 Ptr_MinstrelWifiStation wifistation= IEEE802_11_PHY(nDevId,nifid)->rateAdaptationData;
762 for(i=0;i<=NETWORK->nDeviceCount;i++){
763 if(wifistation->minstrelInfo[i])
764 {
765 FreeTables(wifistation->minstrelInfo[i]);
766 free(wifistation->minstrelInfo[i]);
767 }
768 }
769 free(wifistation->minstrelInfo);
770 free(wifistation);
771 IEEE802_11_PHY(nDevId,nifid)->rateAdaptationData = NULL;
772}
773
774void FreeMinstrel(NETSIM_ID nDevId, NETSIM_ID nifid)
775{
776 PIEEE802_11_PHY_VAR phy = IEEE802_11_PHY(nDevId, nifid);
777 switch(phy->PhyProtocol)
778 {
779 case IEEE_802_11a:
780 case IEEE_802_11b:
781 case IEEE_802_11g:
782 case IEEE_802_11p:
783 Minstrel_Free(nDevId,nifid);
784 break;
785 case IEEE_802_11ac:
786 case IEEE_802_11n:
787 HT_Minstrel_Free(nDevId,nifid);
788 break;
789 case IEEE_802_11ax:
790 HE_Minstrel_Free(nDevId, nifid);
791 break;
792 default:
793 fnNetSimError("Unknown phy protocol %d for device %d interface %d in %s\n", phy->PhyProtocol,
794 nDevId, nifid, __FUNCTION__);
795 }
796}
797
798void FreeTables(Ptr_MinstrelPerRemoteStation station){
799 UINT i;
800 for(i=0;i<station->nRate;i++){
801 free(station->sampleTable[i]);
802 }
803 free(station->sampleTable);
804 free(station->minstrelTable);
805}
806
807UINT get_minstrel_rate_index(NETSIM_ID dev,NETSIM_ID ifid,NETSIM_ID recv){
808 Ptr_MinstrelPerRemoteStation station = getMinstrelInfo(dev,ifid,recv);
809 if(!station || !station->isInitialized)
810 return 0;
811 return station->trRate;
812}
813
814void print_minstrel_table(PMETRICSWRITER metricsWriter)
815{
816 NETSIM_ID i, j;
817 UINT k;
818 Ptr_MinstrelPerRemoteStation station;
819 if(!show)
820 return;
821
822 PMETRICSNODE menu = init_metrics_node(MetricsNode_Menu, "Minstrel Data", NULL);
823 PMETRICSNODE table = init_metrics_node(MetricsNode_Table, "Minstrel table", NULL);
824 add_node_to_menu(menu, table);
825
826 add_table_heading_special(table,"SourceId#1,DestinationId#1,Rate#1,RetryCount#0,Throughput#1,EwmaProb#0,CurrentSuccess#0,CurrentAttempt#0,TotalSuccess#0,TotalAttempt#0,StationSample#0,StationTotal#0,StationRetry#0,");
827 for(i=1;i<=NETWORK->nDeviceCount;i++)
828 {
829 if(isIEEE802_11_Configure(i,1))
830 {
831 if(IEEE802_11_MAC(i,1)->rate_adaptationAlgo!= RATEADAPTATION_MINSTREL)
832 continue;
833 for(j=1;j<=NETWORK->nDeviceCount;j++)
834 {
835 station= getMinstrelInfo(i,1,j); //ifid is believed to be 1..Change if necessary
836 if(!station)
837 continue;
838 if(station && station->totalPacketCount > 0){ //print only if there is transmission
839
840 for(k=0;k<station->nRate;k++){
841 add_table_row_formatted(false,table, "%d,%d,%lf,", DEVICE_CONFIGID(i), DEVICE_CONFIGID(j),station->minstrelTable[k].rate);
842 add_table_row_formatted(true, table, "%u,%lf,%lf,",station->minstrelTable[k].retryCount,station->minstrelTable[k].throughput,station->minstrelTable[k].ewmaProb);
843 add_table_row_formatted(true, table, "%u,%u,%llu,",station->minstrelTable[k].currNumSuccess,station->minstrelTable[k].currNumAttempt,station->minstrelTable[k].totalNumSuccess);
844 add_table_row_formatted(true, table, "%llu,",station->minstrelTable[k].totalNumAttempt);
845 if(k==0)
846 add_table_row_formatted(true, table, "%llu,%llu,%llu,",station->samplePacketCount, station->totalPacketCount,station->totalRetry);
847 else
848 add_table_row_formatted(true, table, ",,,");
849
850 }
851 }
852 }
853 }
854 }
855 write_metrics_node(metricsWriter, WriterPosition_Current, NULL, menu);
856 delete_metrics_node(menu);
857}