INET Framework for OMNeT++/OMNEST
Ieee80211AgentSTA.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 "Ieee80211AgentSTA.h"
00020 #include "Ieee80211Primitives_m.h"
00021 #include "NotifierConsts.h"
00022 
00023 
00024 
00025 Define_Module(Ieee80211AgentSTA);
00026 
00027 #define MK_STARTUP  1
00028 
00029 void Ieee80211AgentSTA::initialize(int stage)
00030 {
00031     if (stage==0)
00032     {
00033         // read parameters
00034         activeScan = par("activeScan");
00035         probeDelay = par("probeDelay");
00036         minChannelTime = par("minChannelTime");
00037         maxChannelTime = par("maxChannelTime");
00038         authenticationTimeout = par("authenticationTimeout");
00039         associationTimeout = par("associationTimeout");
00040         cStringTokenizer tokenizer(par("channelsToScan"));
00041         const char *token;
00042         while ((token = tokenizer.nextToken())!=NULL)
00043             channelsToScan.push_back(atoi(token));
00044 
00045         NotificationBoard *nb = NotificationBoardAccess().get();
00046         nb->subscribe(this, NF_L2_BEACON_LOST);
00047 
00048         // start up: send scan request
00049         scheduleAt(simTime()+uniform(0,maxChannelTime), new cMessage("startUp", MK_STARTUP));
00050     }
00051 }
00052 
00053 void Ieee80211AgentSTA::handleMessage(cMessage *msg)
00054 {
00055     if (msg->isSelfMessage())
00056         handleTimer(msg);
00057     else
00058         handleResponse(msg);
00059 }
00060 
00061 void Ieee80211AgentSTA::handleTimer(cMessage *msg)
00062 {
00063     if (msg->getKind()==MK_STARTUP)
00064     {
00065         EV << "Starting up\n";
00066         sendScanRequest();
00067         delete msg;
00068     }
00069     else
00070     {
00071         error("internal error: unrecognized timer '%s'", msg->getName());
00072     }
00073 }
00074 
00075 void Ieee80211AgentSTA::handleResponse(cMessage *msg)
00076 {
00077     cPolymorphic *ctrl = msg->removeControlInfo();
00078     delete msg;
00079 
00080     EV << "Processing confirmation from mgmt: " << ctrl->getClassName() << "\n";
00081 
00082     if (dynamic_cast<Ieee80211Prim_ScanConfirm *>(ctrl))
00083         processScanConfirm((Ieee80211Prim_ScanConfirm *)ctrl);
00084     else if (dynamic_cast<Ieee80211Prim_AuthenticateConfirm *>(ctrl))
00085         processAuthenticateConfirm((Ieee80211Prim_AuthenticateConfirm *)ctrl);
00086     else if (dynamic_cast<Ieee80211Prim_AssociateConfirm *>(ctrl))
00087         processAssociateConfirm((Ieee80211Prim_AssociateConfirm *)ctrl);
00088     else if (dynamic_cast<Ieee80211Prim_ReassociateConfirm *>(ctrl))
00089         processReassociateConfirm((Ieee80211Prim_ReassociateConfirm *)ctrl);
00090     else if (ctrl)
00091         error("handleResponse(): unrecognized control info class `%s'", ctrl->getClassName());
00092     else
00093         error("handleResponse(): control info is NULL");
00094     delete ctrl;
00095 }
00096 
00097 void Ieee80211AgentSTA::receiveChangeNotification(int category, const cPolymorphic *details)
00098 {
00099     Enter_Method_Silent();
00100     printNotificationBanner(category, details);
00101 
00102     if (category == NF_L2_BEACON_LOST)
00103     {
00104         //XXX should check details if it's about this NIC
00105         EV << "beacon lost, starting scanning again\n";
00106         getParentModule()->getParentModule()->bubble("Beacon lost!");
00107         //sendDisassociateRequest();
00108         sendScanRequest();
00109     }
00110 }
00111 
00112 void Ieee80211AgentSTA::sendRequest(Ieee80211PrimRequest *req)
00113 {
00114     cMessage *msg = new cMessage(req->getClassName());
00115     msg->setControlInfo(req);
00116     send(msg, "mgmtOut");
00117 }
00118 
00119 
00120 void Ieee80211AgentSTA::sendScanRequest()
00121 {
00122     EV << "Sending ScanRequest primitive to mgmt\n";
00123     Ieee80211Prim_ScanRequest *req = new Ieee80211Prim_ScanRequest();
00124     req->setBSSType(BSSTYPE_INFRASTRUCTURE);
00125     req->setActiveScan(activeScan);
00126     req->setProbeDelay(probeDelay);
00127     req->setMinChannelTime(minChannelTime);
00128     req->setMaxChannelTime(maxChannelTime);
00129     req->setChannelListArraySize(channelsToScan.size());
00130     for (int i=0; i<(int)channelsToScan.size(); i++)
00131         req->setChannelList(i, channelsToScan[i]);
00132     //XXX BSSID, SSID are left at default ("any")
00133 
00134     sendRequest(req);
00135 }
00136 
00137 void Ieee80211AgentSTA::sendAuthenticateRequest(const MACAddress& address)
00138 {
00139     EV << "Sending AuthenticateRequest primitive to mgmt\n";
00140     Ieee80211Prim_AuthenticateRequest *req = new Ieee80211Prim_AuthenticateRequest();
00141     req->setAddress(address);
00142     req->setTimeout(authenticationTimeout);
00143     sendRequest(req);
00144 }
00145 
00146 void Ieee80211AgentSTA::sendDeauthenticateRequest(const MACAddress& address, int reasonCode)
00147 {
00148     EV << "Sending DeauthenticateRequest primitive to mgmt\n";
00149     Ieee80211Prim_DeauthenticateRequest *req = new Ieee80211Prim_DeauthenticateRequest();
00150     req->setAddress(address);
00151     req->setReasonCode(reasonCode);
00152     sendRequest(req);
00153 }
00154 
00155 void Ieee80211AgentSTA::sendAssociateRequest(const MACAddress& address)
00156 {
00157     EV << "Sending AssociateRequest primitive to mgmt\n";
00158     Ieee80211Prim_AssociateRequest *req = new Ieee80211Prim_AssociateRequest();
00159     req->setAddress(address);
00160     req->setTimeout(associationTimeout);
00161     sendRequest(req);
00162 }
00163 
00164 void Ieee80211AgentSTA::sendReassociateRequest(const MACAddress& address)
00165 {
00166     EV << "Sending ReassociateRequest primitive to mgmt\n";
00167     Ieee80211Prim_ReassociateRequest *req = new Ieee80211Prim_ReassociateRequest();
00168     req->setAddress(address);
00169     req->setTimeout(associationTimeout);
00170     sendRequest(req);
00171 }
00172 
00173 void Ieee80211AgentSTA::sendDisassociateRequest(const MACAddress& address, int reasonCode)
00174 {
00175     EV << "Sending DisassociateRequest primitive to mgmt\n";
00176     Ieee80211Prim_DisassociateRequest *req = new Ieee80211Prim_DisassociateRequest();
00177     req->setAddress(address);
00178     req->setReasonCode(reasonCode);
00179     sendRequest(req);
00180 }
00181 
00182 void Ieee80211AgentSTA::processScanConfirm(Ieee80211Prim_ScanConfirm *resp)
00183 {
00184     // choose best AP
00185     int bssIndex = chooseBSS(resp);
00186     if (bssIndex==-1)
00187     {
00188         EV << "No (suitable) AP found, continue scanning\n";
00189         sendScanRequest();
00190         return;
00191     }
00192 
00193     dumpAPList(resp);
00194 
00195     Ieee80211Prim_BSSDescription& bssDesc = resp->getBssList(bssIndex);
00196     EV << "Chosen AP address=" << bssDesc.getBSSID() << " from list, starting authentication\n";
00197     sendAuthenticateRequest(bssDesc.getBSSID());
00198 }
00199 
00200 void Ieee80211AgentSTA::dumpAPList(Ieee80211Prim_ScanConfirm *resp)
00201 {
00202     EV << "Received AP list:\n";
00203     for (int i=0; i<(int)resp->getBssListArraySize(); i++)
00204     {
00205         Ieee80211Prim_BSSDescription& bssDesc = resp->getBssList(i);
00206         EV << "    " << i << ". "
00207            << " address=" << bssDesc.getBSSID()
00208            << " channel=" << bssDesc.getChannelNumber()
00209            << " SSID=" << bssDesc.getSSID()
00210            << " beaconIntvl=" << bssDesc.getBeaconInterval()
00211            << " rxPower=" << bssDesc.getRxPower()
00212            << endl;
00213         // later: supportedRates
00214     }
00215 }
00216 
00217 int Ieee80211AgentSTA::chooseBSS(Ieee80211Prim_ScanConfirm *resp)
00218 {
00219     if (resp->getBssListArraySize()==0)
00220         return -1;
00221 
00222     // here, just choose the one with the greatest receive power
00223     // TODO and which supports a good data rate we support
00224     int bestIndex = 0;
00225     for (int i=0; i<(int)resp->getBssListArraySize(); i++)
00226         if (resp->getBssList(i).getRxPower() > resp->getBssList(bestIndex).getRxPower())
00227             bestIndex = i;
00228     return bestIndex;
00229 }
00230 
00231 void Ieee80211AgentSTA::processAuthenticateConfirm(Ieee80211Prim_AuthenticateConfirm *resp)
00232 {
00233     if (resp->getResultCode()!=PRC_SUCCESS)
00234     {
00235         EV << "Authentication error\n";
00236 
00237         // try scanning again, maybe we'll have better luck next time, possibly with a different AP
00238         EV << "Going back to scanning\n";
00239         sendScanRequest();
00240     }
00241     else
00242     {
00243         EV << "Authentication successful, let's try to associate\n";
00244         sendAssociateRequest(resp->getAddress());
00245     }
00246 }
00247 
00248 void Ieee80211AgentSTA::processAssociateConfirm(Ieee80211Prim_AssociateConfirm *resp)
00249 {
00250     if (resp->getResultCode()!=PRC_SUCCESS)
00251     {
00252         EV << "Association error\n";
00253 
00254         // try scanning again, maybe we'll have better luck next time, possibly with a different AP
00255         EV << "Going back to scanning\n";
00256         sendScanRequest();
00257     }
00258     else
00259     {
00260         EV << "Association successful\n";
00261         // we are happy!
00262         getParentModule()->getParentModule()->bubble("Associated with AP");
00263     }
00264 }
00265 
00266 void Ieee80211AgentSTA::processReassociateConfirm(Ieee80211Prim_ReassociateConfirm *resp)
00267 {
00268     // treat the same way as AssociateConfirm
00269     if (resp->getResultCode()!=PRC_SUCCESS)
00270     {
00271         EV << "Reassociation error\n";
00272         EV << "Going back to scanning\n";
00273         sendScanRequest();
00274     }
00275     else
00276     {
00277         EV << "Reassociation successful\n";
00278         // we are happy!
00279     }
00280 }
00281