INET Framework for OMNeT++/OMNEST
Ieee80211MgmtAP.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 "Ieee80211MgmtAP.h"
00020 #include "Ieee802Ctrl_m.h"
00021 #include "EtherFrame_m.h"
00022 #include "NotifierConsts.h"
00023 #include "RadioState.h"
00024 
00025 
00026 Define_Module(Ieee80211MgmtAP);
00027 
00028 static std::ostream& operator<< (std::ostream& os, const Ieee80211MgmtAP::STAInfo& sta)
00029 {
00030     os << "state:" << sta.status;
00031     return os;
00032 }
00033 
00034 void Ieee80211MgmtAP::initialize(int stage)
00035 {
00036     Ieee80211MgmtAPBase::initialize(stage);
00037 
00038     if (stage==0)
00039     {
00040         // read params and init vars
00041         ssid = par("ssid").stringValue();
00042         beaconInterval = par("beaconInterval");
00043         numAuthSteps = par("numAuthSteps");
00044         if (numAuthSteps!=2 && numAuthSteps!=4)
00045             error("parameter 'numAuthSteps' (number of frames exchanged during authentication) must be 2 or 4, not %d", numAuthSteps);
00046         channelNumber = -1;  // value will arrive from physical layer in receiveChangeNotification()
00047         WATCH(ssid);
00048         WATCH(channelNumber);
00049         WATCH(beaconInterval);
00050         WATCH(numAuthSteps);
00051         WATCH_MAP(staList);
00052 
00053         //TBD fill in supportedRates
00054 
00055         // subscribe for notifications
00056         NotificationBoard *nb = NotificationBoardAccess().get();
00057         nb->subscribe(this, NF_RADIO_CHANNEL_CHANGED);
00058 
00059         // start beacon timer (randomize startup time)
00060         beaconTimer = new cMessage("beaconTimer");
00061         scheduleAt(simTime()+uniform(0,beaconInterval), beaconTimer);
00062     }
00063 }
00064 
00065 void Ieee80211MgmtAP::handleTimer(cMessage *msg)
00066 {
00067     if (msg==beaconTimer)
00068     {
00069         sendBeacon();
00070         scheduleAt(simTime()+beaconInterval, beaconTimer);
00071     }
00072     else
00073     {
00074         error("internal error: unrecognized timer '%s'", msg->getName());
00075     }
00076 }
00077 
00078 void Ieee80211MgmtAP::handleUpperMessage(cPacket *msg)
00079 {
00080     // must be an EtherFrame frame arriving from MACRelayUnit, that is,
00081     // bridged from another interface of the AP (probably Ethernet).
00082     EtherFrame *etherframe = check_and_cast<EtherFrame *>(msg);
00083 
00084     // check we really have a STA with that dest address
00085     STAList::iterator it = staList.find(etherframe->getDest());
00086     if (it==staList.end() || it->second.status!=ASSOCIATED)
00087     {
00088         EV << "STA with MAC address " << etherframe->getDest() << " not associated with this AP, dropping frame\n";
00089         delete etherframe; // XXX count drops?
00090         return;
00091     }
00092 
00093     // convert Ethernet frame
00094     Ieee80211DataFrame *frame = convertFromEtherFrame(etherframe);
00095     sendOrEnqueue(frame);
00096 }
00097 
00098 void Ieee80211MgmtAP::handleCommand(int msgkind, cPolymorphic *ctrl)
00099 {
00100     error("handleCommand(): no commands supported");
00101 }
00102 
00103 void Ieee80211MgmtAP::receiveChangeNotification(int category, const cPolymorphic *details)
00104 {
00105     Enter_Method_Silent();
00106     printNotificationBanner(category, details);
00107 
00108     if (category == NF_RADIO_CHANNEL_CHANGED)
00109     {
00110         EV << "updating channel number\n";
00111         channelNumber = check_and_cast<RadioState *>(details)->getChannelNumber();
00112     }
00113 }
00114 
00115 Ieee80211MgmtAP::STAInfo *Ieee80211MgmtAP::lookupSenderSTA(Ieee80211ManagementFrame *frame)
00116 {
00117     STAList::iterator it = staList.find(frame->getTransmitterAddress());
00118     return it==staList.end() ? NULL : &(it->second);
00119 }
00120 
00121 void Ieee80211MgmtAP::sendManagementFrame(Ieee80211ManagementFrame *frame, const MACAddress& destAddr)
00122 {
00123     frame->setFromDS(true);
00124     frame->setReceiverAddress(destAddr);
00125     frame->setAddress3(myAddress);
00126     sendOrEnqueue(frame);
00127 }
00128 
00129 void Ieee80211MgmtAP::sendBeacon()
00130 {
00131     EV << "Sending beacon\n";
00132     Ieee80211BeaconFrame *frame = new Ieee80211BeaconFrame("Beacon");
00133     Ieee80211BeaconFrameBody& body = frame->getBody();
00134     body.setSSID(ssid.c_str());
00135     body.setSupportedRates(supportedRates);
00136     body.setBeaconInterval(beaconInterval);
00137     body.setChannelNumber(channelNumber);
00138 
00139     frame->setReceiverAddress(MACAddress::BROADCAST_ADDRESS);
00140     frame->setFromDS(true);
00141 
00142     sendOrEnqueue(frame);
00143 }
00144 
00145 void Ieee80211MgmtAP::handleDataFrame(Ieee80211DataFrame *frame)
00146 {
00147     // check toDS bit
00148     if (!frame->getToDS())
00149     {
00150         // looks like this is not for us - discard
00151         EV << "Frame is not for us (toDS=false) -- discarding\n";
00152         delete frame;
00153         return;
00154     }
00155 
00156     // handle broadcast frames
00157     if (frame->getAddress3().isBroadcast())
00158     {
00159         EV << "Handling broadcast frame\n";
00160         if (hasRelayUnit)
00161             send(convertToEtherFrame((Ieee80211DataFrame *)frame->dup()), "uppergateOut");
00162         distributeReceivedDataFrame(frame);
00163         return;
00164     }
00165 
00166     // look up destination address in our STA list
00167     STAList::iterator it = staList.find(frame->getAddress3());
00168     if (it==staList.end())
00169     {
00170         // not our STA -- pass up frame to relayUnit for LAN bridging if we have one
00171         if (hasRelayUnit)
00172             send(convertToEtherFrame(frame), "uppergateOut");
00173         else {
00174             EV << "Frame's destination address is not in our STA list -- dropping frame\n";
00175             delete frame;
00176         }
00177     }
00178     else
00179     {
00180         // dest address is our STA, but is it already associated?
00181         if (it->second.status == ASSOCIATED)
00182             distributeReceivedDataFrame(frame); // send it out to the destination STA
00183         else {
00184             EV << "Frame's destination STA is not in associated state -- dropping frame\n";
00185             delete frame;
00186         }
00187     }
00188 }
00189 
00190 void Ieee80211MgmtAP::handleAuthenticationFrame(Ieee80211AuthenticationFrame *frame)
00191 {
00192     int frameAuthSeq = frame->getBody().getSequenceNumber();
00193     EV << "Processing Authentication frame, seqNum=" << frameAuthSeq << "\n";
00194 
00195     // create STA entry if needed
00196     STAInfo *sta = lookupSenderSTA(frame);
00197     if (!sta)
00198     {
00199         MACAddress staAddress = frame->getTransmitterAddress();
00200         sta = &staList[staAddress]; // this implicitly creates a new entry
00201         sta->address = staAddress;
00202         sta->status = NOT_AUTHENTICATED;
00203         sta->authSeqExpected = 1;
00204     }
00205 
00206     // check authentication sequence number is OK
00207     if (frameAuthSeq != sta->authSeqExpected)
00208     {
00209         // wrong sequence number: send error and return
00210         EV << "Wrong sequence number, " << sta->authSeqExpected << " expected\n";
00211         Ieee80211AuthenticationFrame *resp = new Ieee80211AuthenticationFrame("Auth-ERROR");
00212         resp->getBody().setStatusCode(SC_AUTH_OUT_OF_SEQ);
00213         sendManagementFrame(resp, frame->getTransmitterAddress());
00214         delete frame;
00215         sta->authSeqExpected = 1; // go back to start square
00216         return;
00217     }
00218 
00219     // station is authenticated if it made it through the required number of steps
00220     bool isLast = (frameAuthSeq+1 == numAuthSteps);
00221 
00222     // send OK response (we don't model the cryptography part, just assume
00223     // successful authentication every time)
00224     EV << "Sending Authentication frame, seqNum=" << (frameAuthSeq+1) << "\n";
00225     Ieee80211AuthenticationFrame *resp = new Ieee80211AuthenticationFrame(isLast ? "Auth-OK" : "Auth");
00226     resp->getBody().setSequenceNumber(frameAuthSeq+1);
00227     resp->getBody().setStatusCode(SC_SUCCESSFUL);
00228     resp->getBody().setIsLast(isLast);
00229     // XXX frame length could be increased to account for challenge text length etc.
00230     sendManagementFrame(resp, frame->getTransmitterAddress());
00231 
00232     delete frame;
00233 
00234     // update status
00235     if (isLast)
00236     {
00237         sta->status = AUTHENTICATED; // XXX only when ACK of this frame arrives
00238         EV << "STA authenticated\n";
00239     }
00240     else
00241     {
00242         sta->authSeqExpected += 2;
00243         EV << "Expecting Authentication frame " << sta->authSeqExpected << "\n";
00244     }
00245 }
00246 
00247 void Ieee80211MgmtAP::handleDeauthenticationFrame(Ieee80211DeauthenticationFrame *frame)
00248 {
00249     EV << "Processing Deauthentication frame\n";
00250 
00251     STAInfo *sta = lookupSenderSTA(frame);
00252     delete frame;
00253 
00254     if (sta)
00255     {
00256         // mark STA as not authenticated; alternatively, it could also be removed from staList
00257         sta->status = NOT_AUTHENTICATED;
00258         sta->authSeqExpected = 1;
00259     }
00260 }
00261 
00262 void Ieee80211MgmtAP::handleAssociationRequestFrame(Ieee80211AssociationRequestFrame *frame)
00263 {
00264     EV << "Processing AssociationRequest frame\n";
00265 
00266     // "11.3.2 AP association procedures"
00267     STAInfo *sta = lookupSenderSTA(frame);
00268     if (!sta || sta->status==NOT_AUTHENTICATED)
00269     {
00270         // STA not authenticated: send error and return
00271         Ieee80211DeauthenticationFrame *resp = new Ieee80211DeauthenticationFrame("Deauth");
00272         resp->getBody().setReasonCode(RC_NONAUTH_ASS_REQUEST);
00273         sendManagementFrame(resp, frame->getTransmitterAddress());
00274         delete frame;
00275         return;
00276     }
00277 
00278     delete frame;
00279 
00280     // mark STA as associated
00281     sta->status = ASSOCIATED; // XXX this should only take place when MAC receives the ACK for the response
00282 
00283     // send OK response
00284     Ieee80211AssociationResponseFrame *resp = new Ieee80211AssociationResponseFrame("AssocResp-OK");
00285     Ieee80211AssociationResponseFrameBody& body = resp->getBody();
00286     body.setStatusCode(SC_SUCCESSFUL);
00287     body.setAid(0); //XXX
00288     body.setSupportedRates(supportedRates);
00289     sendManagementFrame(resp, sta->address);
00290 }
00291 
00292 void Ieee80211MgmtAP::handleAssociationResponseFrame(Ieee80211AssociationResponseFrame *frame)
00293 {
00294     dropManagementFrame(frame);
00295 }
00296 
00297 void Ieee80211MgmtAP::handleReassociationRequestFrame(Ieee80211ReassociationRequestFrame *frame)
00298 {
00299     EV << "Processing ReassociationRequest frame\n";
00300 
00301     // "11.3.4 AP reassociation procedures" -- almost the same as AssociationRequest processing
00302     STAInfo *sta = lookupSenderSTA(frame);
00303     if (!sta || sta->status==NOT_AUTHENTICATED)
00304     {
00305         // STA not authenticated: send error and return
00306         Ieee80211DeauthenticationFrame *resp = new Ieee80211DeauthenticationFrame("Deauth");
00307         resp->getBody().setReasonCode(RC_NONAUTH_ASS_REQUEST);
00308         sendManagementFrame(resp, frame->getTransmitterAddress());
00309         delete frame;
00310         return;
00311     }
00312 
00313     delete frame;
00314 
00315     // mark STA as associated
00316     sta->status = ASSOCIATED; // XXX this should only take place when MAC receives the ACK for the response
00317 
00318     // send OK response
00319     Ieee80211ReassociationResponseFrame *resp = new Ieee80211ReassociationResponseFrame("ReassocResp-OK");
00320     Ieee80211ReassociationResponseFrameBody& body = resp->getBody();
00321     body.setStatusCode(SC_SUCCESSFUL);
00322     body.setAid(0); //XXX
00323     body.setSupportedRates(supportedRates);
00324     sendManagementFrame(resp, sta->address);
00325 }
00326 
00327 void Ieee80211MgmtAP::handleReassociationResponseFrame(Ieee80211ReassociationResponseFrame *frame)
00328 {
00329     dropManagementFrame(frame);
00330 }
00331 
00332 void Ieee80211MgmtAP::handleDisassociationFrame(Ieee80211DisassociationFrame *frame)
00333 {
00334     STAInfo *sta = lookupSenderSTA(frame);
00335     delete frame;
00336 
00337     if (sta)
00338     {
00339         sta->status = AUTHENTICATED;
00340     }
00341 }
00342 
00343 void Ieee80211MgmtAP::handleBeaconFrame(Ieee80211BeaconFrame *frame)
00344 {
00345     dropManagementFrame(frame);
00346 }
00347 
00348 void Ieee80211MgmtAP::handleProbeRequestFrame(Ieee80211ProbeRequestFrame *frame)
00349 {
00350     EV << "Processing ProbeRequest frame\n";
00351 
00352     if (strcmp(frame->getBody().getSSID(),"")!=0 && strcmp(frame->getBody().getSSID(), ssid.c_str())!=0)
00353     {
00354         EV << "SSID `" << frame->getBody().getSSID() << "' does not match, ignoring frame\n";
00355         dropManagementFrame(frame);
00356         return;
00357     }
00358 
00359     MACAddress staAddress = frame->getTransmitterAddress();
00360     delete frame;
00361 
00362     EV << "Sending ProbeResponse frame\n";
00363     Ieee80211ProbeResponseFrame *resp = new Ieee80211ProbeResponseFrame("ProbeResp");
00364     Ieee80211ProbeResponseFrameBody& body = resp->getBody();
00365     body.setSSID(ssid.c_str());
00366     body.setSupportedRates(supportedRates);
00367     body.setBeaconInterval(beaconInterval);
00368     body.setChannelNumber(channelNumber);
00369     sendManagementFrame(resp, staAddress);
00370 }
00371 
00372 void Ieee80211MgmtAP::handleProbeResponseFrame(Ieee80211ProbeResponseFrame *frame)
00373 {
00374     dropManagementFrame(frame);
00375 }
00376 
00377