void ieee80211_prepare_rates(struct ieee80211_local *local, struct ieee80211_hw_mode *mode) { int i; for (i = 0; i < mode->num_rates; i++) { struct ieee80211_rate *rate = &mode->rates[i]; rate->flags &= ~(IEEE80211_RATE_SUPPORTED | IEEE80211_RATE_BASIC); if (local->supp_rates[mode->mode]) { if (!rate_list_match(local->supp_rates[mode->mode], rate->rate)) continue; } rate->flags |= IEEE80211_RATE_SUPPORTED; /* Use configured basic rate set if it is available. If not, * use defaults that are sane for most cases. */ if (local->basic_rates[mode->mode]) { if (rate_list_match(local->basic_rates[mode->mode], rate->rate)) rate->flags |= IEEE80211_RATE_BASIC; } else switch (mode->mode) { case MODE_IEEE80211A: if (rate->rate == 60 || rate->rate == 120 || rate->rate == 240) rate->flags |= IEEE80211_RATE_BASIC; break; case MODE_IEEE80211B: if (rate->rate == 10 || rate->rate == 20) rate->flags |= IEEE80211_RATE_BASIC; break; case MODE_ATHEROS_TURBO: if (rate->rate == 120 || rate->rate == 240 || rate->rate == 480) rate->flags |= IEEE80211_RATE_BASIC; break; case MODE_IEEE80211G: if (rate->rate == 10 || rate->rate == 20 || rate->rate == 55 || rate->rate == 110) rate->flags |= IEEE80211_RATE_BASIC; break; } /* Set ERP and MANDATORY flags based on phymode */ switch (mode->mode) { case MODE_IEEE80211A: if (rate->rate == 60 || rate->rate == 120 || rate->rate == 240) rate->flags |= IEEE80211_RATE_MANDATORY; break; case MODE_IEEE80211B: if (rate->rate == 10) rate->flags |= IEEE80211_RATE_MANDATORY; break; case MODE_ATHEROS_TURBO: break; case MODE_IEEE80211G: if (rate->rate == 10 || rate->rate == 20 || rate->rate == 55 || rate->rate == 110 || rate->rate == 60 || rate->rate == 120 || rate->rate == 240) rate->flags |= IEEE80211_RATE_MANDATORY; break; } if (ieee80211_is_erp_rate(mode->mode, rate->rate)) rate->flags |= IEEE80211_RATE_ERP; } }
/* 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; 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. */ DBG_PRINT("DUR mode %d, len %d, rate %d, shortpre %d shortslot %d type %x UP %d\n", phymode, (int)len, rate, short_preamble, shortslot, type, qos_class); if (phymode == PHY_FLAG_A || erp) { DBG_PRINT("OFDM\n"); /* * 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 { DBG_PRINT("CCK\n"); /* * 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 DBG_PRINT("DUR SIFS\n"); 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) { DBG_PRINT("DUR LAST CTS\n"); 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); DBG_PRINT("DUR AIFS %d CWMIN %d AC %d, UP %d\n", ac_to_aifs[ac], ac_to_cwmin[ac], ac, qos_class); } else { DBG_PRINT("DUR DIFS\n"); dur += sifs + (2 * slottime); /* DIFS */ dur += get_cw_time(4, 10, retries, slottime); } if (type == WLAN_FRAME_CTS) { DBG_PRINT("SET CTS\n"); last_was_cts = 1; } else last_was_cts = 0; /* TODO: Add EIFS (SIFS + ACKTXTIME) to frames with CRC errors, if we can get them */ DBG_PRINT("DUR %d\n", dur); return dur; }