diff -r a8ef6c075cdf -r 0fafd9716f44 src/devices/wifi/wifi-remote-station-manager.cc --- a/src/devices/wifi/wifi-remote-station-manager.cc Wed Jun 23 06:43:21 2010 +0200 +++ b/src/devices/wifi/wifi-remote-station-manager.cc Wed Jun 23 08:47:29 2010 +0100 @@ -205,6 +205,12 @@ void WifiRemoteStationManager::SetupPhy (Ptr phy) { + // We need to track our PHY because it is the object that knows the + // full set of transmit rates that are supported. We need to know + // this in order to find the relevant mandatory rates when chosing a + // transmit rate for automatic control responses like + // acknowledgements. + m_wifiPhy = phy; m_defaultTxMode = phy->GetMode (0); Reset (); } @@ -255,7 +261,7 @@ { NS_ASSERT (!address.IsGroup ()); WifiRemoteStationState *state = LookupState (address); - state->m_modes.clear (); + state->m_operationalRateSet.clear (); AddSupportedMode (address, GetDefaultMode ()); } void @@ -263,7 +269,7 @@ { NS_ASSERT (!address.IsGroup ()); WifiRemoteStationState *state = LookupState (address); - for (WifiRemoteStationState::SupportedModes::const_iterator i = state->m_modes.begin (); i != state->m_modes.end (); i++) + for (WifiModeListIterator i = state->m_operationalRateSet.begin (); i != state->m_operationalRateSet.end (); i++) { if ((*i) == mode) { @@ -271,7 +277,7 @@ return; } } - state->m_modes.push_back (mode); + state->m_operationalRateSet.push_back (mode); } bool WifiRemoteStationManager::IsBrandNew (Mac48Address address) const @@ -533,39 +539,105 @@ WifiRemoteStationManager::GetControlAnswerMode (Mac48Address address, WifiMode reqMode) { /** - * see ieee 802.11e, section 9.6: - * - * To allow the transmitting STA to calculate the contents of - * the Duration/ID field, a STA responding to a received frame - * shall transmit its Control Response frame (either CTS or ACK) - * frames, other than the Block-Ack control frame, at the highest - * rate in the BSSBasicRateSet parameter that is less than or equal - * to the rate of the immediately previous frame in the frame - * exchange sequence (as defined in 9.79.12) and that is of the - * same modulation type as the received frame. If no rate in the - * basic rate set meets these conditions, then the control frame - * sent in response to a received frame shall be transmitted at - * the highest mandatory rate of the PHY that is less than or equal - * to the rate of the received frame, and that is of the same - * modulation type as the received frame. In addition, the Control - * Response frame shall be sent using the same PHY options as the - * received frame, unless they conflict with the requirement to use - * the BSSBasicRateSet parameter. + * The standard has relatively unambiguous rules for selecting a + * control response rate (the below is quoted from IEEE 802.11-2007, + * Section 9.6): + * + * To allow the transmitting STA to calculate the contents of the + * Duration/ID field, a STA responding to a received frame shall + * transmit its Control Response frame (either CTS or ACK), other + * than the BlockAck control frame, at the highest rate in the + * BSSBasicRateSet parameter that is less than or equal to the + * rate of the immediately previous frame in the frame exchange + * sequence (as defined in 9.12) and that is of the same + * modulation class (see 9.6.1) as the received frame... */ WifiMode mode = GetDefaultMode (); + bool found = false; // First, search the BSS Basic Rate set - for (WifiRemoteStationManager::BasicModesIterator i = BeginBasicModes (); i != EndBasicModes (); i++) + for (WifiModeListIterator i = m_bssBasicRateSet.begin (); + i != m_bssBasicRateSet.end (); i++) { - if (i->GetPhyRate () > mode.GetPhyRate () && - i->GetPhyRate () <= reqMode.GetPhyRate () && - i->GetModulationClass () == reqMode.GetModulationClass ()) + if ((!found || i->GetPhyRate () > mode.GetPhyRate ()) + && i->GetPhyRate () <= reqMode.GetPhyRate () + && i->GetModulationClass () == reqMode.GetModulationClass ()) { mode = *i; + // We've found a potentially-suitable transmit rate, but we + // need to continue and consider all the basic rates before + // we can be sure we've got the right one. + found = true; } } - // no need to search Mandatory rate set because it is included - // within the Basic rate set. + + // If we found a suitable rate in the BSSBasicRateSet, then we are + // done and can return that mode. + if (found) + { + return mode; + } + + /** + * If no suitable basic rate was found, we search the mandatory + * rates. The standard (IEEE 802.11-2007, Section 9.6) says: + * + * ...If no rate contained in the BSSBasicRateSet parameter meets + * these conditions, then the control frame sent in response to a + * received frame shall be transmitted at the highest mandatory + * rate of the PHY that is less than or equal to the rate of the + * received frame, and that is of the same modulation class as the + * received frame. In addition, the Control Response frame shall + * be sent using the same PHY options as the received frame, + * unless they conflict with the requirement to use the + * BSSBasicRateSet parameter. + * + * TODO: Note that we're ignoring the last sentence for now, because + * there is not yet any manipulation here of PHY options. + */ + for (uint32_t idx = 0; idx < m_wifiPhy->GetNModes (); idx++) + { + WifiMode thismode = m_wifiPhy->GetMode (idx); + + /* If the rate: + * + * - is a mandatory rate for the PHY, and + * - is equal to or faster than our current best choice, and + * - is less than or equal to the rate of the received frame, and + * - is of the same modulation class as the received frame + * + * ...then it's our best choice so far. + */ + if (thismode.IsMandatory () + && (!found || thismode.GetPhyRate () > mode.GetPhyRate ()) + && thismode.GetPhyRate () <= reqMode.GetPhyRate () + && thismode.GetModulationClass () == reqMode.GetModulationClass ()) + { + mode = thismode; + // As above; we've found a potentially-suitable transmit + // rate, but we need to continue and consider all the + // mandatory rates before we can be sure we've got the right + // one. + found = true; + } + } + + /** + * If we still haven't found a suitable rate for the response then + * someone has messed up the simulation config. This probably means + * that the WifiPhyStandard is not set correctly, or that a rate that + * is not supported by the PHY has been explicitly requested in a + * WifiRemoteStationManager (or descendant) configuration. + * + * Either way, it is serious - we can either disobey the standard or + * fail, and I have chosen to do the latter... + */ + if (!found) + { + NS_FATAL_ERROR ("Can't find response rate for " << reqMode + << ". Check standard and selected rates match."); + } + return mode; } @@ -602,7 +674,7 @@ WifiRemoteStationState *state = new WifiRemoteStationState (); state->m_state = WifiRemoteStationState::BRAND_NEW; state->m_address = address; - state->m_modes.push_back (GetDefaultMode ()); + state->m_operationalRateSet.push_back (GetDefaultMode ()); const_cast (this)->m_states.push_back (state); return state; } @@ -657,8 +729,8 @@ delete (*i); } m_stations.clear (); - m_basicModes.clear (); - m_basicModes.push_back (m_defaultTxMode); + m_bssBasicRateSet.clear (); + m_bssBasicRateSet.push_back (m_defaultTxMode); NS_ASSERT (m_defaultTxMode.IsMandatory ()); } void @@ -671,30 +743,19 @@ return; } } - m_basicModes.push_back (mode); + m_bssBasicRateSet.push_back (mode); } uint32_t WifiRemoteStationManager::GetNBasicModes (void) const { - return m_basicModes.size (); + return m_bssBasicRateSet.size (); } WifiMode WifiRemoteStationManager::GetBasicMode (uint32_t i) const { - NS_ASSERT (i < m_basicModes.size ()); - return m_basicModes[i]; + NS_ASSERT (i < m_bssBasicRateSet.size ()); + return m_bssBasicRateSet[i]; } -WifiRemoteStationManager::BasicModesIterator -WifiRemoteStationManager::BeginBasicModes (void) const -{ - return m_basicModes.begin (); -} -WifiRemoteStationManager::BasicModesIterator -WifiRemoteStationManager::EndBasicModes (void) const -{ - return m_basicModes.end (); -} - WifiMode WifiRemoteStationManager::GetNonUnicastMode (void) const { @@ -737,12 +798,12 @@ WifiRemoteStationManager::GetSupported (const WifiRemoteStation *station, uint32_t i) const { NS_ASSERT (i < GetNSupported (station)); - return station->m_state->m_modes[i]; + return station->m_state->m_operationalRateSet[i]; } uint32_t WifiRemoteStationManager::GetNSupported (const WifiRemoteStation *station) const { - return station->m_state->m_modes.size (); + return station->m_state->m_operationalRateSet.size (); } //WifiRemoteStationInfo constructor