Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: fix timing for 5 MHz and 10 MHz channels

according to IEEE 802.11-2012 section 18, various timings change
when using 5 MHz and 10 MHz. Reflect this by using a "shift" when
calculating durations.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

authored by

Simon Wunderlich and committed by
Johannes Berg
438b61b7 3de805cf

+90 -25
+30 -1
net/mac80211/ieee80211_i.h
··· 812 812 return band; 813 813 } 814 814 815 + static inline int 816 + ieee80211_chandef_get_shift(struct cfg80211_chan_def *chandef) 817 + { 818 + switch (chandef->width) { 819 + case NL80211_CHAN_WIDTH_5: 820 + return 2; 821 + case NL80211_CHAN_WIDTH_10: 822 + return 1; 823 + default: 824 + return 0; 825 + } 826 + } 827 + 828 + static inline int 829 + ieee80211_vif_get_shift(struct ieee80211_vif *vif) 830 + { 831 + struct ieee80211_chanctx_conf *chanctx_conf; 832 + int shift = 0; 833 + 834 + rcu_read_lock(); 835 + chanctx_conf = rcu_dereference(vif->chanctx_conf); 836 + if (chanctx_conf) 837 + shift = ieee80211_chandef_get_shift(&chanctx_conf->def); 838 + rcu_read_unlock(); 839 + 840 + return shift; 841 + } 842 + 815 843 enum sdata_queue_type { 816 844 IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, 817 845 IEEE80211_SDATA_QUEUE_AGG_START = 1, ··· 1496 1468 u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, 1497 1469 enum nl80211_iftype type); 1498 1470 int ieee80211_frame_duration(enum ieee80211_band band, size_t len, 1499 - int rate, int erp, int short_preamble); 1471 + int rate, int erp, int short_preamble, 1472 + int shift); 1500 1473 void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, 1501 1474 struct ieee80211_hdr *hdr, const u8 *tsc, 1502 1475 gfp_t gfp);
+24 -6
net/mac80211/rc80211_minstrel.c
··· 382 382 static void 383 383 calc_rate_durations(enum ieee80211_band band, 384 384 struct minstrel_rate *d, 385 - struct ieee80211_rate *rate) 385 + struct ieee80211_rate *rate, 386 + struct cfg80211_chan_def *chandef) 386 387 { 387 388 int erp = !!(rate->flags & IEEE80211_RATE_ERP_G); 389 + int shift = ieee80211_chandef_get_shift(chandef); 388 390 389 391 d->perfect_tx_time = ieee80211_frame_duration(band, 1200, 390 - rate->bitrate, erp, 1); 392 + DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1, 393 + shift); 391 394 d->ack_time = ieee80211_frame_duration(band, 10, 392 - rate->bitrate, erp, 1); 395 + DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1, 396 + shift); 393 397 } 394 398 395 399 static void ··· 429 425 struct ieee80211_rate *ctl_rate; 430 426 unsigned int i, n = 0; 431 427 unsigned int t_slot = 9; /* FIXME: get real slot time */ 428 + u32 rate_flags; 432 429 433 430 mi->sta = sta; 434 431 mi->lowest_rix = rate_lowest_index(sband, sta); 435 432 ctl_rate = &sband->bitrates[mi->lowest_rix]; 436 433 mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10, 437 434 ctl_rate->bitrate, 438 - !!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1); 435 + !!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1, 436 + ieee80211_chandef_get_shift(chandef)); 439 437 438 + rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); 440 439 memset(mi->max_tp_rate, 0, sizeof(mi->max_tp_rate)); 441 440 mi->max_prob_rate = 0; 442 441 ··· 448 441 unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0; 449 442 unsigned int tx_time_single; 450 443 unsigned int cw = mp->cw_min; 444 + int shift; 451 445 452 446 if (!rate_supported(sta, sband->band, i)) 453 447 continue; 448 + if ((rate_flags & sband->bitrates[i].flags) != rate_flags) 449 + continue; 450 + 454 451 n++; 455 452 memset(mr, 0, sizeof(*mr)); 456 453 457 454 mr->rix = i; 458 - mr->bitrate = sband->bitrates[i].bitrate / 5; 459 - calc_rate_durations(sband->band, mr, &sband->bitrates[i]); 455 + shift = ieee80211_chandef_get_shift(chandef); 456 + mr->bitrate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 457 + (1 << shift) * 5); 458 + calc_rate_durations(sband->band, mr, &sband->bitrates[i], 459 + chandef); 460 460 461 461 /* calculate maximum number of retransmissions before 462 462 * fallback (based on maximum segment size) */ ··· 561 547 { 562 548 static const int bitrates[4] = { 10, 20, 55, 110 }; 563 549 struct ieee80211_supported_band *sband; 550 + u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); 564 551 int i, j; 565 552 566 553 sband = mp->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; ··· 572 557 struct ieee80211_rate *rate = &sband->bitrates[i]; 573 558 574 559 if (rate->flags & IEEE80211_RATE_ERP_G) 560 + continue; 561 + 562 + if ((rate_flags & sband->bitrates[i].flags) != rate_flags) 575 563 continue; 576 564 577 565 for (j = 0; j < ARRAY_SIZE(bitrates); j++) {
+3 -2
net/mac80211/rc80211_minstrel_ht.c
··· 862 862 mi->sta = sta; 863 863 mi->stats_update = jiffies; 864 864 865 - ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1); 866 - mi->overhead = ieee80211_frame_duration(sband->band, 0, 60, 1, 1) + ack_dur; 865 + ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1, 0); 866 + mi->overhead = ieee80211_frame_duration(sband->band, 0, 60, 1, 1, 0); 867 + mi->overhead += ack_dur; 867 868 mi->overhead_rtscts = mi->overhead + 2 * ack_dur; 868 869 869 870 mi->avg_ampdu_len = MINSTREL_FRAC(1, 1);
+7 -3
net/mac80211/tx.c
··· 40 40 struct sk_buff *skb, int group_addr, 41 41 int next_frag_len) 42 42 { 43 - int rate, mrate, erp, dur, i; 43 + int rate, mrate, erp, dur, i, shift; 44 44 struct ieee80211_rate *txrate; 45 45 struct ieee80211_local *local = tx->local; 46 46 struct ieee80211_supported_band *sband; ··· 153 153 rate = mrate; 154 154 } 155 155 156 + shift = ieee80211_vif_get_shift(&tx->sdata->vif); 157 + 156 158 /* Don't calculate ACKs for QoS Frames with NoAck Policy set */ 157 159 if (ieee80211_is_data_qos(hdr->frame_control) && 158 160 *(ieee80211_get_qos_ctl(hdr)) & IEEE80211_QOS_CTL_ACK_POLICY_NOACK) ··· 164 162 * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up 165 163 * to closest integer */ 166 164 dur = ieee80211_frame_duration(sband->band, 10, rate, erp, 167 - tx->sdata->vif.bss_conf.use_short_preamble); 165 + tx->sdata->vif.bss_conf.use_short_preamble, 166 + shift); 168 167 169 168 if (next_frag_len) { 170 169 /* Frame is fragmented: duration increases with time needed to ··· 174 171 /* next fragment */ 175 172 dur += ieee80211_frame_duration(sband->band, next_frag_len, 176 173 txrate->bitrate, erp, 177 - tx->sdata->vif.bss_conf.use_short_preamble); 174 + tx->sdata->vif.bss_conf.use_short_preamble, 175 + shift); 178 176 } 179 177 180 178 return cpu_to_le16(dur);
+26 -13
net/mac80211/util.c
··· 107 107 } 108 108 109 109 int ieee80211_frame_duration(enum ieee80211_band band, size_t len, 110 - int rate, int erp, int short_preamble) 110 + int rate, int erp, int short_preamble, 111 + int shift) 111 112 { 112 113 int dur; 113 114 ··· 119 118 * 120 119 * rate is in 100 kbps, so divident is multiplied by 10 in the 121 120 * DIV_ROUND_UP() operations. 121 + * 122 + * shift may be 2 for 5 MHz channels or 1 for 10 MHz channels, and 123 + * is assumed to be 0 otherwise. 122 124 */ 123 125 124 126 if (band == IEEE80211_BAND_5GHZ || erp) { ··· 134 130 * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext 135 131 * 136 132 * T_SYM = 4 usec 137 - * 802.11a - 17.5.2: aSIFSTime = 16 usec 133 + * 802.11a - 18.5.2: aSIFSTime = 16 usec 138 134 * 802.11g - 19.8.4: aSIFSTime = 10 usec + 139 135 * signal ext = 6 usec 140 136 */ 141 137 dur = 16; /* SIFS + signal ext */ 142 - dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ 143 - dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ 138 + dur += 16; /* IEEE 802.11-2012 18.3.2.4: T_PREAMBLE = 16 usec */ 139 + dur += 4; /* IEEE 802.11-2012 18.3.2.4: T_SIGNAL = 4 usec */ 144 140 dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, 145 141 4 * rate); /* T_SYM x N_SYM */ 142 + 143 + /* IEEE 802.11-2012 18.3.2.4: all values above are: 144 + * * times 4 for 5 MHz 145 + * * times 2 for 10 MHz 146 + */ 147 + dur *= 1 << shift; 146 148 } else { 147 149 /* 148 150 * 802.11b or 802.11g with 802.11b compatibility: ··· 178 168 { 179 169 struct ieee80211_sub_if_data *sdata; 180 170 u16 dur; 181 - int erp; 171 + int erp, shift = 0; 182 172 bool short_preamble = false; 183 173 184 174 erp = 0; ··· 187 177 short_preamble = sdata->vif.bss_conf.use_short_preamble; 188 178 if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 189 179 erp = rate->flags & IEEE80211_RATE_ERP_G; 180 + shift = ieee80211_vif_get_shift(vif); 190 181 } 191 182 192 183 dur = ieee80211_frame_duration(band, frame_len, rate->bitrate, erp, 193 - short_preamble); 184 + short_preamble, shift); 194 185 195 186 return cpu_to_le16(dur); 196 187 } ··· 205 194 struct ieee80211_rate *rate; 206 195 struct ieee80211_sub_if_data *sdata; 207 196 bool short_preamble; 208 - int erp; 197 + int erp, shift = 0; 209 198 u16 dur; 210 199 struct ieee80211_supported_band *sband; 211 200 ··· 221 210 short_preamble = sdata->vif.bss_conf.use_short_preamble; 222 211 if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 223 212 erp = rate->flags & IEEE80211_RATE_ERP_G; 213 + shift = ieee80211_vif_get_shift(vif); 224 214 } 225 215 226 216 /* CTS duration */ 227 217 dur = ieee80211_frame_duration(sband->band, 10, rate->bitrate, 228 - erp, short_preamble); 218 + erp, short_preamble, shift); 229 219 /* Data frame duration */ 230 220 dur += ieee80211_frame_duration(sband->band, frame_len, rate->bitrate, 231 - erp, short_preamble); 221 + erp, short_preamble, shift); 232 222 /* ACK duration */ 233 223 dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate, 234 - erp, short_preamble); 224 + erp, short_preamble, shift); 235 225 236 226 return cpu_to_le16(dur); 237 227 } ··· 247 235 struct ieee80211_rate *rate; 248 236 struct ieee80211_sub_if_data *sdata; 249 237 bool short_preamble; 250 - int erp; 238 + int erp, shift = 0; 251 239 u16 dur; 252 240 struct ieee80211_supported_band *sband; 253 241 ··· 262 250 short_preamble = sdata->vif.bss_conf.use_short_preamble; 263 251 if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) 264 252 erp = rate->flags & IEEE80211_RATE_ERP_G; 253 + shift = ieee80211_vif_get_shift(vif); 265 254 } 266 255 267 256 /* Data frame duration */ 268 257 dur = ieee80211_frame_duration(sband->band, frame_len, rate->bitrate, 269 - erp, short_preamble); 258 + erp, short_preamble, shift); 270 259 if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { 271 260 /* ACK duration */ 272 261 dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate, 273 - erp, short_preamble); 262 + erp, short_preamble, shift); 274 263 } 275 264 276 265 return cpu_to_le16(dur);