INET Framework for OMNeT++/OMNEST
Ieee80211MgmtSTA.cc
Go to the documentation of this file.
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