@@ -66,6 +66,7 @@ Ieee80211MgmtAp::AssociationResponseDisposition Ieee80211MgmtAp::getAssociationR
6666Ieee80211MgmtAp::~Ieee80211MgmtAp ()
6767{
6868 cancelAndDelete (beaconTimer);
69+ cancelAndDelete (associationResponseTimeoutTimer);
6970}
7071
7172void Ieee80211MgmtAp::initialize (int stage)
@@ -76,13 +77,17 @@ void Ieee80211MgmtAp::initialize(int stage)
7677 // read params and init vars
7778 ssid = par (" ssid" ).stdstringValue ();
7879 beaconInterval = par (" beaconInterval" );
80+ associationResponseTimeout = par (" associationResponseTimeout" );
81+ if (associationResponseTimeout < SIMTIME_ZERO )
82+ throw cRuntimeError (" parameter 'associationResponseTimeout' must not be negative" );
7983 numAuthSteps = par (" numAuthSteps" );
8084 if (numAuthSteps != 2 && numAuthSteps != 4 )
8185 throw cRuntimeError (" parameter 'numAuthSteps' (number of frames exchanged during authentication) must be 2 or 4, not %d" , numAuthSteps);
8286 channelNumber = -1 ; // value will arrive from physical layer in receiveChangeNotification()
8387 WATCH (ssid);
8488 WATCH (channelNumber);
8589 WATCH (beaconInterval);
90+ WATCH (associationResponseTimeout);
8691 WATCH (numAuthSteps);
8792 WATCH (staList);
8893
@@ -95,6 +100,7 @@ void Ieee80211MgmtAp::initialize(int stage)
95100
96101 // start beacon timer (randomize startup time)
97102 beaconTimer = new cMessage (" beaconTimer" );
103+ associationResponseTimeoutTimer = new cMessage (" associationResponseTimeoutTimer" );
98104 }
99105}
100106
@@ -104,6 +110,14 @@ void Ieee80211MgmtAp::handleTimer(cMessage *msg)
104110 sendBeacon ();
105111 scheduleAfter (beaconInterval, beaconTimer);
106112 }
113+ else if (msg == associationResponseTimeoutTimer) {
114+ auto sta = staList.find (scheduledAssociationResponseTimeoutAddress);
115+ if (sta != staList.end () && isAssociationResponseTimeoutDue (sta->second ,
116+ scheduledAssociationResponseTimeoutTransactionId, scheduledAssociationResponseTimeoutDeadline, simTime ()))
117+ clearPendingAssociation (&sta->second );
118+ else
119+ scheduleAssociationResponseTimeout ();
120+ }
107121 else {
108122 throw cRuntimeError (" internal error: unrecognized timer '%s'" , msg->getName ());
109123 }
@@ -210,13 +224,46 @@ uint64_t Ieee80211MgmtAp::createAssociationTransactionId()
210224 return nextAssociationTransactionId;
211225}
212226
227+ bool Ieee80211MgmtAp::isAssociationResponseTimeoutDue (const StaInfo& sta, uint64_t transactionId, simtime_t deadline, simtime_t currentTime)
228+ {
229+ return transactionId != 0 && sta.pendingAssociationTransactionId == transactionId &&
230+ sta.pendingAssociationDeadline == deadline && deadline <= currentTime;
231+ }
232+
213233void Ieee80211MgmtAp::clearPendingAssociation (StaInfo *sta)
214234{
215235 mib->cancelAssociationIdReservation (sta->address );
216236 sta->pendingAssociationSuccessful = false ;
217237 sta->pendingAssociationTransactionId = 0 ;
238+ sta->pendingAssociationDeadline = SIMTIME_MAX ;
218239 sta->pendingHtStateAvailable = false ;
219240 sta->pendingHtCapabilitiesValid = false ;
241+ sta->pendingHtCapabilities = Ieee80211HtCapabilities ();
242+ scheduleAssociationResponseTimeout ();
243+ }
244+
245+ void Ieee80211MgmtAp::scheduleAssociationResponseTimeout ()
246+ {
247+ cancelEvent (associationResponseTimeoutTimer);
248+ scheduledAssociationResponseTimeoutTransactionId = 0 ;
249+ scheduledAssociationResponseTimeoutDeadline = SIMTIME_MAX ;
250+ for (const auto & entry : staList) {
251+ const auto & sta = entry.second ;
252+ if (sta.pendingAssociationTransactionId != 0 && sta.pendingAssociationDeadline < scheduledAssociationResponseTimeoutDeadline) {
253+ scheduledAssociationResponseTimeoutAddress = entry.first ;
254+ scheduledAssociationResponseTimeoutTransactionId = sta.pendingAssociationTransactionId ;
255+ scheduledAssociationResponseTimeoutDeadline = sta.pendingAssociationDeadline ;
256+ }
257+ }
258+ if (scheduledAssociationResponseTimeoutTransactionId != 0 )
259+ scheduleAt (scheduledAssociationResponseTimeoutDeadline, associationResponseTimeoutTimer);
260+ }
261+
262+ void Ieee80211MgmtAp::startAssociationResponseTimeout (StaInfo *sta)
263+ {
264+ ASSERT (sta->pendingAssociationTransactionId != 0 );
265+ sta->pendingAssociationDeadline = simTime () + associationResponseTimeout;
266+ scheduleAssociationResponseTimeout ();
220267}
221268
222269void Ieee80211MgmtAp::sendBeacon ()
@@ -247,8 +294,8 @@ void Ieee80211MgmtAp::handleAuthenticationFrame(Packet *packet, const Ptr<const
247294 sta->address = staAddress;
248295 mib->bssAccessPointData .stations [staAddress] = Ieee80211Mib::NOT_AUTHENTICATED ;
249296 sta->authSeqExpected = 1 ;
250- clearPendingAssociation (sta);
251297 }
298+ clearPendingAssociation (sta);
252299
253300 // reset authentication status, when starting a new auth sequence
254301 // The statements below are added because the L2 handover time was greater than before when
@@ -263,7 +310,6 @@ void Ieee80211MgmtAp::handleAuthenticationFrame(Packet *packet, const Ptr<const
263310 mib->releaseAssociationId (sta->address );
264311 }
265312 mib->bssAccessPointData .stations [sta->address ] = Ieee80211Mib::NOT_AUTHENTICATED ;
266- clearPendingAssociation (sta);
267313 mib->removePeerHtCapabilities (sta->address );
268314 sta->authSeqExpected = 1 ;
269315 }
@@ -336,6 +382,8 @@ void Ieee80211MgmtAp::handleAssociationRequestFrame(Packet *packet, const Ptr<co
336382
337383 // "11.3.2 AP association procedures"
338384 StaInfo *sta = lookupSenderSTA (header);
385+ if (sta != nullptr )
386+ clearPendingAssociation (sta);
339387 if (!sta || mib->bssAccessPointData .stations [sta->address ] == Ieee80211Mib::NOT_AUTHENTICATED ) {
340388 // STA not authenticated: send error and return
341389 const auto & body = makeShared<Ieee80211DeauthenticationFrame>();
@@ -346,7 +394,6 @@ void Ieee80211MgmtAp::handleAssociationRequestFrame(Packet *packet, const Ptr<co
346394 }
347395
348396 const auto & requestBody = packet->peekData <Ieee80211AssociationRequestFrame>();
349- clearPendingAssociation (sta);
350397 sta->pendingAssociationSuccessful = false ;
351398 sta->pendingHtStateAvailable = true ;
352399 sta->pendingHtCapabilitiesValid = mib->isHtOperationSupported () && requestBody->getHtCapabilitiesPresent ();
@@ -367,6 +414,7 @@ void Ieee80211MgmtAp::handleAssociationRequestFrame(Packet *packet, const Ptr<co
367414 addHtCapabilities (body);
368415 addHtOperation (body);
369416 body->setChunkLength (B (2 + 2 + 2 + body->getSupportedRates ().numRates + 2 ) + getHtMgmtElementsLength (body));
417+ startAssociationResponseTimeout (sta);
370418 sendManagementFrame (basicHtMcsSupported ? " AssocResp-OK" : " AssocResp-UnsupportedHtMcs" , body, ST_ASSOCIATIONRESPONSE , sta->address , sta->pendingAssociationTransactionId );
371419}
372420
@@ -381,6 +429,8 @@ void Ieee80211MgmtAp::handleReassociationRequestFrame(Packet *packet, const Ptr<
381429
382430 // "11.3.4 AP reassociation procedures" -- almost the same as AssociationRequest processing
383431 StaInfo *sta = lookupSenderSTA (header);
432+ if (sta != nullptr )
433+ clearPendingAssociation (sta);
384434 if (!sta || mib->bssAccessPointData .stations [sta->address ] == Ieee80211Mib::NOT_AUTHENTICATED ) {
385435 // STA not authenticated: send error and return
386436 const auto & body = makeShared<Ieee80211DeauthenticationFrame>();
@@ -391,7 +441,6 @@ void Ieee80211MgmtAp::handleReassociationRequestFrame(Packet *packet, const Ptr<
391441 }
392442
393443 const auto & requestBody = packet->peekData <Ieee80211ReassociationRequestFrame>();
394- clearPendingAssociation (sta);
395444 sta->pendingAssociationSuccessful = false ;
396445 sta->pendingHtStateAvailable = true ;
397446 sta->pendingHtCapabilitiesValid = mib->isHtOperationSupported () && requestBody->getHtCapabilitiesPresent ();
@@ -412,6 +461,7 @@ void Ieee80211MgmtAp::handleReassociationRequestFrame(Packet *packet, const Ptr<
412461 addHtCapabilities (body);
413462 addHtOperation (body);
414463 body->setChunkLength (B (2 + 2 + 2 + (2 + supportedRates.numRates )) + getHtMgmtElementsLength (body));
464+ startAssociationResponseTimeout (sta);
415465 sendManagementFrame (basicHtMcsSupported ? " ReassocResp-OK" : " ReassocResp-UnsupportedHtMcs" , body, ST_REASSOCIATIONRESPONSE , sta->address , sta->pendingAssociationTransactionId );
416466}
417467
@@ -497,6 +547,7 @@ void Ieee80211MgmtAp::start()
497547void Ieee80211MgmtAp::stop ()
498548{
499549 cancelEvent (beaconTimer);
550+ cancelEvent (associationResponseTimeoutTimer);
500551 staList.clear ();
501552 mib->clearAssociationIds ();
502553 Ieee80211MgmtApBase::stop ();
0 commit comments