|
INET Framework for OMNeT++/OMNEST
|
00001 // 00002 // Copyright (C) 2006 Andras Varga 00003 // 00004 // This program is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public License 00006 // as published by the Free Software Foundation; either version 2 00007 // of the License, or (at your option) any later version. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU Lesser General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU Lesser General Public License 00015 // along with this program; if not, see <http://www.gnu.org/licenses/>. 00016 // 00017 00018 00019 #include "Ieee80211MgmtSTA.h" 00020 #include "Ieee802Ctrl_m.h" 00021 #include "NotifierConsts.h" 00022 #include "PhyControlInfo_m.h" 00023 #include "RadioState.h" 00024 #include "ChannelControl.h" 00025 00026 //TBD supportedRates! 00027 //TBD use command msg kinds? 00028 //TBD implement bitrate switching (Radio already supports it) 00029 //TBD where to put LCC header (SNAP)..? 00030 //TBD mac should be able to signal when msg got transmitted 00031 00032 Define_Module(Ieee80211MgmtSTA); 00033 00034 // message kind values for timers 00035 #define MK_AUTH_TIMEOUT 1 00036 #define MK_ASSOC_TIMEOUT 2 00037 #define MK_SCAN_SENDPROBE 3 00038 #define MK_SCAN_MINCHANNELTIME 4 00039 #define MK_SCAN_MAXCHANNELTIME 5 00040 #define MK_BEACON_TIMEOUT 6 00041 00042 #define MAX_BEACONS_MISSED 3.5 // beacon lost timeout, in beacon intervals (doesn't need to be integer) 00043 00044 00045 std::ostream& operator<<(std::ostream& os, const Ieee80211MgmtSTA::ScanningInfo& scanning) 00046 { 00047 os << "activeScan=" << scanning.activeScan 00048 << " probeDelay=" << scanning.probeDelay 00049 << " curChan="; 00050 if (scanning.channelList.empty()) 00051 os << "<none>"; 00052 else 00053 os << scanning.channelList[scanning.currentChannelIndex]; 00054 os << " minChanTime=" << scanning.minChannelTime 00055 << " maxChanTime=" << scanning.maxChannelTime; 00056 os << " chanList={"; 00057 for (int i=0; i<(int)scanning.channelList.size(); i++) 00058 os << (i==0 ? "" : " ") << scanning.channelList[i]; 00059 os << "}"; 00060 00061 return os; 00062 } 00063 00064 std::ostream& operator<<(std::ostream& os, const Ieee80211MgmtSTA::APInfo& ap) 00065 { 00066 os << "AP addr=" << ap.address 00067 << " chan=" << ap.channel 00068 << " ssid=" << ap.ssid 00069 //TBD supportedRates 00070 << " beaconIntvl=" << ap.beaconInterval 00071 << " rxPower=" << ap.rxPower 00072 << " authSeqExpected=" << ap.authSeqExpected 00073 << " isAuthenticated=" << ap.isAuthenticated; 00074 return os; 00075 } 00076 00077 std::ostream& operator<<(std::ostream& os, const Ieee80211MgmtSTA::AssociatedAPInfo& assocAP) 00078 { 00079 os << "AP addr=" << assocAP.address 00080 << " chan=" << assocAP.channel 00081 << " ssid=" << assocAP.ssid 00082 << " beaconIntvl=" << assocAP.beaconInterval 00083 << " receiveSeq=" << assocAP.receiveSequence 00084 << " rxPower=" << assocAP.rxPower; 00085 return os; 00086 } 00087 00088 void Ieee80211MgmtSTA::initialize(int stage) 00089 { 00090 Ieee80211MgmtBase::initialize(stage); 00091 if (stage==0) 00092 { 00093 isScanning = false; 00094 isAssociated = false; 00095 assocTimeoutMsg = NULL; 00096 00097 nb = NotificationBoardAccess().get(); 00098 00099 // determine numChannels (needed when we're told to scan "all" channels) 00100 //XXX find a better way than directly accessing channelControl 00101 cModule *cc = ChannelControl::get(); 00102 numChannels = cc->par("numChannels"); 00103 00104 WATCH(isScanning); 00105 WATCH(isAssociated); 00106 00107 WATCH(scanning); 00108 WATCH(assocAP); 00109 WATCH_LIST(apList); 00110 } 00111 } 00112 00113 void Ieee80211MgmtSTA::handleTimer(cMessage *msg) 00114 { 00115 if (msg->getKind()==MK_AUTH_TIMEOUT) 00116 { 00117 // authentication timed out 00118 APInfo *ap = (APInfo *)msg->getContextPointer(); 00119 EV << "Authentication timed out, AP address = " << ap->address << "\n"; 00120 00121 // send back failure report to agent 00122 sendAuthenticationConfirm(ap, PRC_TIMEOUT); 00123 } 00124 else if (msg->getKind()==MK_ASSOC_TIMEOUT) 00125 { 00126 // association timed out 00127 APInfo *ap = (APInfo *)msg->getContextPointer(); 00128 EV << "Association timed out, AP address = " << ap->address << "\n"; 00129 00130 // send back failure report to agent 00131 sendAssociationConfirm(ap, PRC_TIMEOUT); 00132 } 00133 else if (msg->getKind()==MK_SCAN_MAXCHANNELTIME) 00134 { 00135 // go to next channel during scanning 00136 bool done = scanNextChannel(); 00137 if (done) 00138 sendScanConfirm(); // send back response to agents' "scan" command 00139 delete msg; 00140 } 00141 else if (msg->getKind()==MK_SCAN_SENDPROBE) 00142 { 00143 // Active Scan: send a probe request, then wait for minChannelTime (11.1.3.2.2) 00144 delete msg; 00145 sendProbeRequest(); 00146 cMessage *timerMsg = new cMessage("minChannelTime", MK_SCAN_MINCHANNELTIME); 00147 scheduleAt(simTime()+scanning.minChannelTime, timerMsg); //XXX actually, we should start waiting after ProbeReq actually got transmitted 00148 } 00149 else if (msg->getKind()==MK_SCAN_MINCHANNELTIME) 00150 { 00151 // Active Scan: after minChannelTime, possibly listen for the remaining time until maxChannelTime 00152 delete msg; 00153 if (scanning.busyChannelDetected) 00154 { 00155 EV << "Busy channel detected during minChannelTime, continuing listening until maxChannelTime elapses\n"; 00156 cMessage *timerMsg = new cMessage("maxChannelTime", MK_SCAN_MAXCHANNELTIME); 00157 scheduleAt(simTime()+scanning.maxChannelTime - scanning.minChannelTime, timerMsg); 00158 } 00159 else 00160 { 00161 EV << "Channel was empty during minChannelTime, going to next channel\n"; 00162 bool done = scanNextChannel(); 00163 if (done) 00164 sendScanConfirm(); // send back response to agents' "scan" command 00165 } 00166 } 00167 else if (msg->getKind()==MK_BEACON_TIMEOUT) 00168 { 00169 // missed a few consecutive beacons 00170 beaconLost(); 00171 } 00172 else 00173 { 00174 error("internal error: unrecognized timer '%s'", msg->getName()); 00175 } 00176 } 00177 00178 void Ieee80211MgmtSTA::handleUpperMessage(cPacket *msg) 00179 { 00180 Ieee80211DataFrame *frame = encapsulate(msg); 00181 sendOrEnqueue(frame); 00182 } 00183 00184 void Ieee80211MgmtSTA::handleCommand(int msgkind, cPolymorphic *ctrl) 00185 { 00186 if (dynamic_cast<Ieee80211Prim_ScanRequest *>(ctrl)) 00187 processScanCommand((Ieee80211Prim_ScanRequest *)ctrl); 00188 else if (dynamic_cast<Ieee80211Prim_AuthenticateRequest *>(ctrl)) 00189 processAuthenticateCommand((Ieee80211Prim_AuthenticateRequest *)ctrl); 00190 else if (dynamic_cast<Ieee80211Prim_DeauthenticateRequest *>(ctrl)) 00191 processDeauthenticateCommand((Ieee80211Prim_DeauthenticateRequest *)ctrl); 00192 else if (dynamic_cast<Ieee80211Prim_AssociateRequest *>(ctrl)) 00193 processAssociateCommand((Ieee80211Prim_AssociateRequest *)ctrl); 00194 else if (dynamic_cast<Ieee80211Prim_ReassociateRequest *>(ctrl)) 00195 processReassociateCommand((Ieee80211Prim_ReassociateRequest *)ctrl); 00196 else if (dynamic_cast<Ieee80211Prim_DisassociateRequest *>(ctrl)) 00197 processDisassociateCommand((Ieee80211Prim_DisassociateRequest *)ctrl); 00198 else if (ctrl) 00199 error("handleCommand(): unrecognized control info class `%s'", ctrl->getClassName()); 00200 else 00201 error("handleCommand(): control info is NULL"); 00202 delete ctrl; 00203 } 00204 00205 Ieee80211DataFrame *Ieee80211MgmtSTA::encapsulate(cPacket *msg) 00206 { 00207 Ieee80211DataFrame *frame = new Ieee80211DataFrame(msg->getName()); 00208 00209 // frame goes to the AP 00210 frame->setToDS(true); 00211 00212 // receiver is the AP 00213 frame->setReceiverAddress(assocAP.address); 00214 00215 // destination address is in address3 00216 Ieee802Ctrl *ctrl = check_and_cast<Ieee802Ctrl *>(msg->removeControlInfo()); 00217 frame->setAddress3(ctrl->getDest()); 00218 delete ctrl; 00219 00220 frame->encapsulate(msg); 00221 return frame; 00222 } 00223 00224 Ieee80211MgmtSTA::APInfo *Ieee80211MgmtSTA::lookupAP(const MACAddress& address) 00225 { 00226 for (AccessPointList::iterator it=apList.begin(); it!=apList.end(); ++it) 00227 if (it->address == address) 00228 return &(*it); 00229 return NULL; 00230 } 00231 00232 void Ieee80211MgmtSTA::clearAPList() 00233 { 00234 for (AccessPointList::iterator it=apList.begin(); it!=apList.end(); ++it) 00235 if (it->authTimeoutMsg) 00236 delete cancelEvent(it->authTimeoutMsg); 00237 apList.clear(); 00238 } 00239 00240 void Ieee80211MgmtSTA::changeChannel(int channelNum) 00241 { 00242 EV << "Tuning to channel #" << channelNum << "\n"; 00243 00244 // sending PHY_C_CONFIGURERADIO command to MAC 00245 PhyControlInfo *phyCtrl = new PhyControlInfo(); 00246 phyCtrl->setChannelNumber(channelNum); 00247 cMessage *msg = new cMessage("changeChannel", PHY_C_CONFIGURERADIO); 00248 msg->setControlInfo(phyCtrl); 00249 send(msg, "macOut"); 00250 } 00251 00252 void Ieee80211MgmtSTA::beaconLost() 00253 { 00254 EV << "Missed a few consecutive beacons -- AP is considered lost\n"; 00255 nb->fireChangeNotification(NF_L2_BEACON_LOST, NULL); //XXX use InterfaceEntry as detail, etc... 00256 } 00257 00258 void Ieee80211MgmtSTA::sendManagementFrame(Ieee80211ManagementFrame *frame, const MACAddress& address) 00259 { 00260 // frame goes to the specified AP 00261 frame->setToDS(true); 00262 frame->setReceiverAddress(address); 00263 //XXX set sequenceNumber? 00264 00265 sendOrEnqueue(frame); 00266 } 00267 00268 void Ieee80211MgmtSTA::startAuthentication(APInfo *ap, simtime_t timeout) 00269 { 00270 if (ap->authTimeoutMsg) 00271 error("startAuthentication: authentication currently in progress with AP address=", ap->address.str().c_str()); 00272 if (ap->isAuthenticated) 00273 error("startAuthentication: already authenticated with AP address=", ap->address.str().c_str()); 00274 00275 changeChannel(ap->channel); 00276 00277 EV << "Sending initial Authentication frame with seqNum=1\n"; 00278 00279 // create and send first authentication frame 00280 Ieee80211AuthenticationFrame *frame = new Ieee80211AuthenticationFrame("Auth"); 00281 frame->getBody().setSequenceNumber(1); 00282 //XXX frame length could be increased to account for challenge text length etc. 00283 sendManagementFrame(frame, ap->address); 00284 00285 ap->authSeqExpected = 2; 00286 00287 // schedule timeout 00288 ASSERT(ap->authTimeoutMsg==NULL); 00289 ap->authTimeoutMsg = new cMessage("authTimeout", MK_AUTH_TIMEOUT); 00290 ap->authTimeoutMsg->setContextPointer(ap); 00291 scheduleAt(simTime()+timeout, ap->authTimeoutMsg); 00292 } 00293 00294 void Ieee80211MgmtSTA::startAssociation(APInfo *ap, simtime_t timeout) 00295 { 00296 if (isAssociated || assocTimeoutMsg) 00297 error("startAssociation: already associated or association currently in progress"); 00298 if (!ap->isAuthenticated) 00299 error("startAssociation: not yet authenticated with AP address=", ap->address.str().c_str()); 00300 00301 // switch to that channel 00302 changeChannel(ap->channel); 00303 00304 // create and send association request 00305 Ieee80211AssociationRequestFrame *frame = new Ieee80211AssociationRequestFrame("Assoc"); 00306 00307 //XXX set the following too? 00308 // string SSID 00309 // Ieee80211SupportedRatesElement supportedRates; 00310 00311 sendManagementFrame(frame, ap->address); 00312 00313 // schedule timeout 00314 ASSERT(assocTimeoutMsg==NULL); 00315 assocTimeoutMsg = new cMessage("assocTimeout", MK_ASSOC_TIMEOUT); 00316 assocTimeoutMsg->setContextPointer(ap); 00317 scheduleAt(simTime()+timeout, assocTimeoutMsg); 00318 } 00319 00320 void Ieee80211MgmtSTA::receiveChangeNotification(int category, const cPolymorphic *details) 00321 { 00322 Enter_Method_Silent(); 00323 printNotificationBanner(category, details); 00324 00325 // Note that we are only subscribed during scanning! 00326 if (category==NF_RADIOSTATE_CHANGED) 00327 { 00328 RadioState::State radioState = check_and_cast<RadioState *>(details)->getState(); 00329 if (radioState==RadioState::RECV) 00330 { 00331 EV << "busy radio channel detected during scanning\n"; 00332 scanning.busyChannelDetected = true; 00333 } 00334 } 00335 } 00336 00337 void Ieee80211MgmtSTA::processScanCommand(Ieee80211Prim_ScanRequest *ctrl) 00338 { 00339 EV << "Received Scan Request from agent, clearing AP list and starting scanning...\n"; 00340 00341 if (isScanning) 00342 error("processScanCommand: scanning already in progress"); 00343 if (isAssociated) 00344 { 00345 disassociate(); 00346 } 00347 else if (assocTimeoutMsg) 00348 { 00349 EV << "Cancelling ongoing association process\n"; 00350 delete cancelEvent(assocTimeoutMsg); 00351 assocTimeoutMsg = NULL; 00352 } 00353 00354 // clear existing AP list (and cancel any pending authentications) -- we want to start with a clean page 00355 clearAPList(); 00356 00357 // fill in scanning state 00358 ASSERT(ctrl->getBSSType()==BSSTYPE_INFRASTRUCTURE); 00359 scanning.bssid = ctrl->getBSSID().isUnspecified() ? MACAddress::BROADCAST_ADDRESS : ctrl->getBSSID(); 00360 scanning.ssid = ctrl->getSSID(); 00361 scanning.activeScan = ctrl->getActiveScan(); 00362 scanning.probeDelay = ctrl->getProbeDelay(); 00363 scanning.channelList.clear(); 00364 scanning.minChannelTime = ctrl->getMinChannelTime(); 00365 scanning.maxChannelTime = ctrl->getMaxChannelTime(); 00366 ASSERT(scanning.minChannelTime <= scanning.maxChannelTime); 00367 00368 // channel list to scan (default: all channels) 00369 for (int i=0; i<(int)ctrl->getChannelListArraySize(); i++) 00370 scanning.channelList.push_back(ctrl->getChannelList(i)); 00371 if (scanning.channelList.empty()) 00372 for (int i=0; i<numChannels; i++) 00373 scanning.channelList.push_back(i); 00374 00375 // start scanning 00376 if (scanning.activeScan) 00377 nb->subscribe(this, NF_RADIOSTATE_CHANGED); 00378 scanning.currentChannelIndex = -1; // so we'll start with index==0 00379 isScanning = true; 00380 scanNextChannel(); 00381 } 00382 00383 bool Ieee80211MgmtSTA::scanNextChannel() 00384 { 00385 // if we're already at the last channel, we're through 00386 if (scanning.currentChannelIndex==(int)scanning.channelList.size()-1) 00387 { 00388 EV << "Finished scanning last channel\n"; 00389 if (scanning.activeScan) 00390 nb->unsubscribe(this, NF_RADIOSTATE_CHANGED); 00391 isScanning = false; 00392 return true; // we're done 00393 } 00394 00395 // tune to next channel 00396 int newChannel = scanning.channelList[++scanning.currentChannelIndex]; 00397 changeChannel(newChannel); 00398 scanning.busyChannelDetected = false; 00399 00400 if (scanning.activeScan) 00401 { 00402 // Active Scan: first wait probeDelay, then send a probe. Listening 00403 // for minChannelTime or maxChannelTime takes place after that. (11.1.3.2) 00404 scheduleAt(simTime()+scanning.probeDelay, new cMessage("sendProbe", MK_SCAN_SENDPROBE)); 00405 } 00406 else 00407 { 00408 // Passive Scan: spend maxChannelTime on the channel (11.1.3.1) 00409 cMessage *timerMsg = new cMessage("maxChannelTime", MK_SCAN_MAXCHANNELTIME); 00410 scheduleAt(simTime()+scanning.maxChannelTime, timerMsg); 00411 } 00412 00413 return false; 00414 } 00415 00416 void Ieee80211MgmtSTA::sendProbeRequest() 00417 { 00418 EV << "Sending Probe Request, BSSID=" << scanning.bssid << ", SSID=\"" << scanning.ssid << "\"\n"; 00419 Ieee80211ProbeRequestFrame *frame = new Ieee80211ProbeRequestFrame("ProbeReq"); 00420 frame->getBody().setSSID(scanning.ssid.c_str()); 00421 sendManagementFrame(frame, scanning.bssid); 00422 } 00423 00424 void Ieee80211MgmtSTA::sendScanConfirm() 00425 { 00426 EV << "Scanning complete, found " << apList.size() << " APs, sending confirmation to agent\n"; 00427 00428 // copy apList contents into a ScanConfirm primitive and send it back 00429 int n = apList.size(); 00430 Ieee80211Prim_ScanConfirm *confirm = new Ieee80211Prim_ScanConfirm(); 00431 confirm->setBssListArraySize(n); 00432 AccessPointList::iterator it = apList.begin(); 00433 //XXX filter for req'd bssid and ssid 00434 for (int i=0; i<n; i++, it++) 00435 { 00436 APInfo *ap = &(*it); 00437 Ieee80211Prim_BSSDescription& bss = confirm->getBssList(i); 00438 bss.setChannelNumber(ap->channel); 00439 bss.setBSSID(ap->address); 00440 bss.setSSID(ap->ssid.c_str()); 00441 bss.setSupportedRates(ap->supportedRates); 00442 bss.setBeaconInterval(ap->beaconInterval); 00443 bss.setRxPower(ap->rxPower); 00444 } 00445 sendConfirm(confirm, PRC_SUCCESS); 00446 } 00447 00448 void Ieee80211MgmtSTA::processAuthenticateCommand(Ieee80211Prim_AuthenticateRequest *ctrl) 00449 { 00450 const MACAddress& address = ctrl->getAddress(); 00451 APInfo *ap = lookupAP(address); 00452 if (!ap) 00453 error("processAuthenticateCommand: AP not known: address = %s", address.str().c_str()); 00454 startAuthentication(ap, ctrl->getTimeout()); 00455 } 00456 00457 void Ieee80211MgmtSTA::processDeauthenticateCommand(Ieee80211Prim_DeauthenticateRequest *ctrl) 00458 { 00459 const MACAddress& address = ctrl->getAddress(); 00460 APInfo *ap = lookupAP(address); 00461 if (!ap) 00462 error("processDeauthenticateCommand: AP not known: address = %s", address.str().c_str()); 00463 00464 if (isAssociated && assocAP.address==address) 00465 disassociate(); 00466 00467 if (ap->isAuthenticated) 00468 ap->isAuthenticated = false; 00469 00470 // cancel possible pending authentication timer 00471 if (ap->authTimeoutMsg) 00472 { 00473 delete cancelEvent(ap->authTimeoutMsg); 00474 ap->authTimeoutMsg = NULL; 00475 } 00476 00477 // create and send deauthentication request 00478 Ieee80211DeauthenticationFrame *frame = new Ieee80211DeauthenticationFrame("Deauth"); 00479 frame->getBody().setReasonCode(ctrl->getReasonCode()); 00480 sendManagementFrame(frame, address); 00481 } 00482 00483 void Ieee80211MgmtSTA::processAssociateCommand(Ieee80211Prim_AssociateRequest *ctrl) 00484 { 00485 const MACAddress& address = ctrl->getAddress(); 00486 APInfo *ap = lookupAP(address); 00487 if (!ap) 00488 error("processAssociateCommand: AP not known: address = %s", address.str().c_str()); 00489 startAssociation(ap, ctrl->getTimeout()); 00490 } 00491 00492 void Ieee80211MgmtSTA::processReassociateCommand(Ieee80211Prim_ReassociateRequest *ctrl) 00493 { 00494 // treat the same way as association 00495 //XXX refine 00496 processAssociateCommand(ctrl); 00497 } 00498 00499 void Ieee80211MgmtSTA::processDisassociateCommand(Ieee80211Prim_DisassociateRequest *ctrl) 00500 { 00501 const MACAddress& address = ctrl->getAddress(); 00502 00503 if (isAssociated && address==assocAP.address) 00504 { 00505 disassociate(); 00506 } 00507 else if (assocTimeoutMsg) 00508 { 00509 // pending association 00510 delete cancelEvent(assocTimeoutMsg); 00511 assocTimeoutMsg = NULL; 00512 } 00513 00514 // create and send disassociation request 00515 Ieee80211DisassociationFrame *frame = new Ieee80211DisassociationFrame("Disass"); 00516 frame->getBody().setReasonCode(ctrl->getReasonCode()); 00517 sendManagementFrame(frame, address); 00518 } 00519 00520 void Ieee80211MgmtSTA::disassociate() 00521 { 00522 EV << "Disassociating from AP address=" << assocAP.address << "\n"; 00523 ASSERT(isAssociated); 00524 isAssociated = false; 00525 delete cancelEvent(assocAP.beaconTimeoutMsg); 00526 assocAP.beaconTimeoutMsg = NULL; 00527 assocAP = AssociatedAPInfo(); // clear it 00528 } 00529 00530 void Ieee80211MgmtSTA::sendAuthenticationConfirm(APInfo *ap, int resultCode) 00531 { 00532 Ieee80211Prim_AuthenticateConfirm *confirm = new Ieee80211Prim_AuthenticateConfirm(); 00533 confirm->setAddress(ap->address); 00534 sendConfirm(confirm, resultCode); 00535 } 00536 00537 void Ieee80211MgmtSTA::sendAssociationConfirm(APInfo *ap, int resultCode) 00538 { 00539 sendConfirm(new Ieee80211Prim_AssociateConfirm(), resultCode); 00540 } 00541 00542 void Ieee80211MgmtSTA::sendConfirm(Ieee80211PrimConfirm *confirm, int resultCode) 00543 { 00544 confirm->setResultCode(resultCode); 00545 cMessage *msg = new cMessage(confirm->getClassName()); 00546 msg->setControlInfo(confirm); 00547 send(msg, "agentOut"); 00548 } 00549 00550 int Ieee80211MgmtSTA::statusCodeToPrimResultCode(int statusCode) 00551 { 00552 return statusCode==SC_SUCCESSFUL ? PRC_SUCCESS : PRC_REFUSED; 00553 } 00554 00555 void Ieee80211MgmtSTA::handleDataFrame(Ieee80211DataFrame *frame) 00556 { 00557 sendUp(decapsulate(frame)); 00558 } 00559 00560 void Ieee80211MgmtSTA::handleAuthenticationFrame(Ieee80211AuthenticationFrame *frame) 00561 { 00562 MACAddress address = frame->getTransmitterAddress(); 00563 int frameAuthSeq = frame->getBody().getSequenceNumber(); 00564 EV << "Received Authentication frame from address=" << address << ", seqNum=" << frameAuthSeq << "\n"; 00565 00566 APInfo *ap = lookupAP(address); 00567 if (!ap) 00568 { 00569 EV << "AP not known, discarding authentication frame\n"; 00570 delete frame; 00571 return; 00572 } 00573 00574 // what if already authenticated with AP 00575 if (ap->isAuthenticated) 00576 { 00577 EV << "AP already authenticated, ignoring frame\n"; 00578 delete frame; 00579 return; 00580 } 00581 00582 // is authentication is in progress with this AP? 00583 if (!ap->authTimeoutMsg) 00584 { 00585 EV << "No authentication in progress with AP, ignoring frame\n"; 00586 delete frame; 00587 return; 00588 } 00589 00590 // check authentication sequence number is OK 00591 if (frameAuthSeq != ap->authSeqExpected) 00592 { 00593 // wrong sequence number: send error and return 00594 EV << "Wrong sequence number, " << ap->authSeqExpected << " expected\n"; 00595 Ieee80211AuthenticationFrame *resp = new Ieee80211AuthenticationFrame("Auth-ERROR"); 00596 resp->getBody().setStatusCode(SC_AUTH_OUT_OF_SEQ); 00597 sendManagementFrame(resp, frame->getTransmitterAddress()); 00598 delete frame; 00599 00600 // cancel timeout, send error to agent 00601 delete cancelEvent(ap->authTimeoutMsg); 00602 ap->authTimeoutMsg = NULL; 00603 sendAuthenticationConfirm(ap, PRC_REFUSED); //XXX or what resultCode? 00604 return; 00605 } 00606 00607 // check if more exchanges are needed for auth to be complete 00608 int statusCode = frame->getBody().getStatusCode(); 00609 00610 if (statusCode==SC_SUCCESSFUL && !frame->getBody().getIsLast()) 00611 { 00612 EV << "More steps required, sending another Authentication frame\n"; 00613 00614 // more steps required, send another Authentication frame 00615 Ieee80211AuthenticationFrame *resp = new Ieee80211AuthenticationFrame("Auth"); 00616 resp->getBody().setSequenceNumber(frameAuthSeq+1); 00617 resp->getBody().setStatusCode(SC_SUCCESSFUL); 00618 // XXX frame length could be increased to account for challenge text length etc. 00619 sendManagementFrame(resp, address); 00620 ap->authSeqExpected += 2; 00621 } 00622 else 00623 { 00624 if (statusCode==SC_SUCCESSFUL) 00625 EV << "Authentication successful\n"; 00626 else 00627 EV << "Authentication failed\n"; 00628 00629 // authentication completed 00630 ap->isAuthenticated = (statusCode==SC_SUCCESSFUL); 00631 delete cancelEvent(ap->authTimeoutMsg); 00632 ap->authTimeoutMsg = NULL; 00633 sendAuthenticationConfirm(ap, statusCodeToPrimResultCode(statusCode)); 00634 } 00635 00636 delete frame; 00637 } 00638 00639 void Ieee80211MgmtSTA::handleDeauthenticationFrame(Ieee80211DeauthenticationFrame *frame) 00640 { 00641 EV << "Received Deauthentication frame\n"; 00642 const MACAddress& address = frame->getAddress3(); // source address 00643 APInfo *ap = lookupAP(address); 00644 if (!ap || !ap->isAuthenticated) 00645 { 00646 EV << "Unknown AP, or not authenticated with that AP -- ignoring frame\n"; 00647 delete frame; 00648 return; 00649 } 00650 if (ap->authTimeoutMsg) 00651 { 00652 delete cancelEvent(ap->authTimeoutMsg); 00653 ap->authTimeoutMsg = NULL; 00654 EV << "Cancelling pending authentication\n"; 00655 delete frame; 00656 return; 00657 } 00658 00659 EV << "Setting isAuthenticated flag for that AP to false\n"; 00660 ap->isAuthenticated = false; 00661 } 00662 00663 void Ieee80211MgmtSTA::handleAssociationRequestFrame(Ieee80211AssociationRequestFrame *frame) 00664 { 00665 dropManagementFrame(frame); 00666 } 00667 00668 void Ieee80211MgmtSTA::handleAssociationResponseFrame(Ieee80211AssociationResponseFrame *frame) 00669 { 00670 EV << "Received Association Response frame\n"; 00671 00672 if (!assocTimeoutMsg) 00673 { 00674 EV << "No association in progress, ignoring frame\n"; 00675 delete frame; 00676 return; 00677 } 00678 00679 // extract frame contents 00680 MACAddress address = frame->getTransmitterAddress(); 00681 int statusCode = frame->getBody().getStatusCode(); 00682 //XXX short aid; 00683 //XXX Ieee80211SupportedRatesElement supportedRates; 00684 delete frame; 00685 00686 // look up AP data structure 00687 APInfo *ap = lookupAP(address); 00688 if (!ap) 00689 error("handleAssociationResponseFrame: AP not known: address=%s", address.str().c_str()); 00690 00691 if (isAssociated) 00692 { 00693 EV << "Breaking existing association with AP address=" << assocAP.address << "\n"; 00694 isAssociated = false; 00695 delete cancelEvent(assocAP.beaconTimeoutMsg); 00696 assocAP.beaconTimeoutMsg = NULL; 00697 assocAP = AssociatedAPInfo(); 00698 } 00699 00700 delete cancelEvent(assocTimeoutMsg); 00701 assocTimeoutMsg = NULL; 00702 00703 if (statusCode!=SC_SUCCESSFUL) 00704 { 00705 EV << "Association failed with AP address=" << ap->address << "\n"; 00706 } 00707 else 00708 { 00709 EV << "Association successful, AP address=" << ap->address << "\n"; 00710 00711 // change our state to "associated" 00712 isAssociated = true; 00713 (APInfo&)assocAP = (*ap); 00714 00715 nb->fireChangeNotification(NF_L2_ASSOCIATED, NULL); //XXX detail: InterfaceEntry? 00716 00717 assocAP.beaconTimeoutMsg = new cMessage("beaconTimeout", MK_BEACON_TIMEOUT); 00718 scheduleAt(simTime()+MAX_BEACONS_MISSED*assocAP.beaconInterval, assocAP.beaconTimeoutMsg); 00719 } 00720 00721 // report back to agent 00722 sendAssociationConfirm(ap, statusCodeToPrimResultCode(statusCode)); 00723 } 00724 00725 void Ieee80211MgmtSTA::handleReassociationRequestFrame(Ieee80211ReassociationRequestFrame *frame) 00726 { 00727 dropManagementFrame(frame); 00728 } 00729 00730 void Ieee80211MgmtSTA::handleReassociationResponseFrame(Ieee80211ReassociationResponseFrame *frame) 00731 { 00732 EV << "Received Reassociation Response frame\n"; 00733 //TBD handle with the same code as Association Response? 00734 } 00735 00736 void Ieee80211MgmtSTA::handleDisassociationFrame(Ieee80211DisassociationFrame *frame) 00737 { 00738 EV << "Received Disassociation frame\n"; 00739 const MACAddress& address = frame->getAddress3(); // source address 00740 00741 if (assocTimeoutMsg) 00742 { 00743 // pending association 00744 delete cancelEvent(assocTimeoutMsg); 00745 assocTimeoutMsg = NULL; 00746 } 00747 if (!isAssociated || address!=assocAP.address) 00748 { 00749 EV << "Not associated with that AP -- ignoring frame\n"; 00750 delete frame; 00751 return; 00752 } 00753 00754 EV << "Setting isAssociated flag to false\n"; 00755 isAssociated = false; 00756 delete cancelEvent(assocAP.beaconTimeoutMsg); 00757 assocAP.beaconTimeoutMsg = NULL; 00758 } 00759 00760 void Ieee80211MgmtSTA::handleBeaconFrame(Ieee80211BeaconFrame *frame) 00761 { 00762 EV << "Received Beacon frame\n"; 00763 storeAPInfo(frame->getTransmitterAddress(), frame->getBody()); 00764 00765 // if it is out associate AP, restart beacon timeout 00766 if (isAssociated && frame->getTransmitterAddress()==assocAP.address) 00767 { 00768 EV << "Beacon is from associated AP, restarting beacon timeout timer\n"; 00769 ASSERT(assocAP.beaconTimeoutMsg!=NULL); 00770 cancelEvent(assocAP.beaconTimeoutMsg); 00771 scheduleAt(simTime()+MAX_BEACONS_MISSED*assocAP.beaconInterval, assocAP.beaconTimeoutMsg); 00772 00773 //APInfo *ap = lookupAP(frame->getTransmitterAddress()); 00774 //ASSERT(ap!=NULL); 00775 } 00776 00777 delete frame; 00778 } 00779 00780 void Ieee80211MgmtSTA::handleProbeRequestFrame(Ieee80211ProbeRequestFrame *frame) 00781 { 00782 dropManagementFrame(frame); 00783 } 00784 00785 void Ieee80211MgmtSTA::handleProbeResponseFrame(Ieee80211ProbeResponseFrame *frame) 00786 { 00787 EV << "Received Probe Response frame\n"; 00788 storeAPInfo(frame->getTransmitterAddress(), frame->getBody()); 00789 delete frame; 00790 } 00791 00792 void Ieee80211MgmtSTA::storeAPInfo(const MACAddress& address, const Ieee80211BeaconFrameBody& body) 00793 { 00794 APInfo *ap = lookupAP(address); 00795 if (ap) 00796 { 00797 EV << "AP address=" << address << ", SSID=" << body.getSSID() << " already in our AP list, refreshing the info\n"; 00798 } 00799 else 00800 { 00801 EV << "Inserting AP address=" << address << ", SSID=" << body.getSSID() << " into our AP list\n"; 00802 apList.push_back(APInfo()); 00803 ap = &apList.back(); 00804 } 00805 00806 ap->channel = body.getChannelNumber(); 00807 ap->address = address; 00808 ap->ssid = body.getSSID(); 00809 ap->supportedRates = body.getSupportedRates(); 00810 ap->beaconInterval = body.getBeaconInterval(); 00811 00812 //XXX where to get this from? 00813 //ap->rxPower = ... 00814 } 00815