-
Notifications
You must be signed in to change notification settings - Fork 74
/
Copy pathieee80211_duration.c
172 lines (152 loc) · 4.9 KB
/
ieee80211_duration.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/* copied from linux wireless-2.6/net/mac80211/util.c */
/*
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <[email protected]>
* Copyright 2007 Johannes Berg <[email protected]>
* Copyright 2014-2016 Bruno Randolf ([email protected])
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* utilities for mac80211
*/
#include <stdbool.h>
#include <math.h>
#include <uwifi/platform.h>
#include <uwifi/wlan80211.h>
#include <uwifi/util.h>
#include <uwifi/log.h>
#include "main.h"
#include "ieee80211_duration.h"
/* from mac80211/ieee80211_i.c, slightly modified */
/**
* ieee80211_is_erp_rate - Check if a rate is an ERP rate
* @phymode: The PHY-mode for this rate (MODE_IEEE80211...)
* @rate: Transmission rate to check, in 100 kbps
*
* Check if a given rate is an Extended Rate PHY (ERP) rate.
*/
static inline bool ieee80211_is_erp_rate(int phymode, int rate)
{
if (phymode & PHY_FLAG_G) {
if (rate != 10 && rate != 20 &&
rate != 55 && rate != 110) {
LOG_DBG("erp");
return true;
}
}
LOG_DBG("no erp");
return false;
}
static int get_cw_time(int cw_min, int cw_max, int retries, int slottime)
{
int cw = pow(2, (cw_min + retries)) - 1;
cw_max = pow(2, cw_max) - 1;
if(cw > cw_max)
cw = cw_max;
LOG_DBG("CW min %d max %d ret %d = %d", cw_min, cw_max, retries, cw);
return (cw * slottime) / 2;
}
static const unsigned char ieee802_1d_to_ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 };
/* BE BK VI VO */
static const unsigned char ac_to_aifs[4] = { 3, 7, 2, 2};
static const unsigned char ac_to_cwmin[4] = { 4, 4, 3, 2};
static const unsigned int ac_to_cwmax[4] = { 10, 10, 4, 3};
/* from mac80211/util.c, modified */
int ieee80211_frame_duration(int phymode, size_t len, int rate, int short_preamble,
int shortslot, int type, char qos_class, int retries)
{
int dur;
bool erp;
int sifs, slottime;
static int last_was_cts;
if (rate == 0) {
LOG_ERR("*** RATE *");
exit(12);
}
erp = ieee80211_is_erp_rate(phymode, rate);
/* calculate duration (in microseconds, rounded up to next higher
* integer if it includes a fractional microsecond) to send frame of
* len bytes (does not include FCS) at the given rate. Duration will
* also include SIFS.
*
* rate is in 100 kbps, so divident is multiplied by 10 in the
* DIV_ROUND_UP() operations.
*/
LOG_DBG("DUR mode %d, len %d, rate %d, shortpre %d shortslot %d type %x UP %d", phymode, (int)len, rate, short_preamble, shortslot, type, qos_class);
if (phymode == PHY_FLAG_A || erp) {
LOG_DBG("OFDM");
/*
* OFDM:
*
* N_DBPS = DATARATE x 4
* N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
* (16 = SIGNAL time, 6 = tail bits)
* TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
*
* T_SYM = 4 usec
* 802.11a - 17.5.2: aSIFSTime = 16 usec
* 802.11g - 19.8.4: aSIFSTime = 10 usec +
* signal ext = 6 usec
*/
sifs = 16; /* SIFS + signal ext */
slottime = 9;
dur = 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
4 * rate); /* T_SYM x N_SYM */
} else {
LOG_DBG("CCK");
/*
* 802.11b or 802.11g with 802.11b compatibility:
* 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
* Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
*
* 802.11 (DS): 15.3.3, 802.11b: 18.3.4
* aSIFSTime = 10 usec
* aPreambleLength = 144 usec or 72 usec with short preamble
* aPLCPHeaderLength = 48 usec or 24 usec with short preamble
*/
sifs = 10; /* aSIFSTime = 10 usec */
slottime = shortslot ? 9 : 20;
dur = short_preamble ? (72 + 24) : (144 + 48);
dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
}
if (type == WLAN_FRAME_CTS ||
type == WLAN_FRAME_ACK) {
//TODO: also fragments
LOG_DBG("DUR SIFS");
dur += sifs;
}
else if (type == WLAN_FRAME_BEACON) {
/* TODO: which AIFS and CW should be used for beacons? */
dur += sifs + (2 * slottime); /* AIFS */
dur += (slottime * 1) / 2; /* contention */
}
else if (WLAN_FRAME_IS_DATA(type) && last_was_cts) {
LOG_DBG("DUR LAST CTS");
dur += sifs;
}
else if (type == WLAN_FRAME_QDATA) {
unsigned char ac = ieee802_1d_to_ac[(unsigned char)qos_class];
dur += sifs + (ac_to_aifs[ac] * slottime); /* AIFS */
dur += get_cw_time(ac_to_cwmin[ac], ac_to_cwmax[ac], retries, slottime);
LOG_DBG("DUR AIFS %d CWMIN %d AC %d, UP %d", ac_to_aifs[ac], ac_to_cwmin[ac], ac, qos_class);
}
else {
LOG_DBG("DUR DIFS");
dur += sifs + (2 * slottime); /* DIFS */
dur += get_cw_time(4, 10, retries, slottime);
}
if (type == WLAN_FRAME_CTS) {
LOG_DBG("SET CTS");
last_was_cts = 1;
}
else
last_was_cts = 0;
/* TODO: Add EIFS (SIFS + ACKTXTIME) to frames with CRC errors, if we can get them */
LOG_DBG("DUR %d", dur);
return dur;
}