src/devices/wifi/nqsta-wifi-mac.cc
changeset 2524 db72c0e7743e
parent 2350 0b54480c4fd1
child 2528 a527ec47b756
equal deleted inserted replaced
2523:58182a1561cc 2524:db72c0e7743e
       
     1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
       
     2 /*
       
     3  * Copyright (c) 2005,2006 INRIA
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License version 2 as 
       
     7  * published by the Free Software Foundation;
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    17  *
       
    18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
       
    19  */
       
    20 
       
    21 #include "ns3/packet.h"
       
    22 #include "ns3/simulator.h"
       
    23 #include "ns3/assert.h"
       
    24 #include "ns3/log.h"
       
    25 #include "ns3/node.h"
       
    26 #include "ns3/uinteger.h"
       
    27 
       
    28 #include "nqsta-wifi-mac.h"
       
    29 #include "wifi-mac-header.h"
       
    30 #include "mgt-headers.h"
       
    31 #include "wifi-phy.h"
       
    32 #include "dca-txop.h"
       
    33 #include "mac-low.h"
       
    34 #include "dcf-manager.h"
       
    35 #include "mac-rx-middle.h"
       
    36 
       
    37 NS_LOG_COMPONENT_DEFINE ("NqstaWifiMac");
       
    38 
       
    39 #define TRACE(x) \
       
    40   NS_LOG_DEBUG (Simulator::Now () << " " << GetAddress () << " " << x);
       
    41 
       
    42 /*
       
    43  * The state machine for this NQSTA is:
       
    44  --------------            -----------
       
    45  | Associated |   <--------------------      ------->    | Refused |
       
    46  --------------      \    /      -----------
       
    47     \           \  /
       
    48      \    -----------------     -----------------------------
       
    49       \-> | Beacon Missed | --> | Wait Association Response |
       
    50     -----------------     -----------------------------
       
    51     \           ^
       
    52      \          |
       
    53       \    -----------------------
       
    54        \-> | Wait Probe Response |
       
    55            -----------------------
       
    56  */
       
    57 
       
    58 namespace ns3 {
       
    59 
       
    60 NS_OBJECT_ENSURE_REGISTERED (NqstaWifiMac);
       
    61 
       
    62 TypeId 
       
    63 NqstaWifiMac::GetTypeId (void)
       
    64 {
       
    65   static TypeId tid = TypeId ("NqstaWifiMac")
       
    66     .SetParent<WifiMac> ()
       
    67     .AddConstructor<NqstaWifiMac> ()
       
    68     .AddAttribute ("ProbeRequestTimeout", "XXX",
       
    69                    Seconds (0.5),
       
    70                    MakeTimeAccessor (&NqstaWifiMac::m_probeRequestTimeout),
       
    71                    MakeTimeChecker ())
       
    72     .AddAttribute ("AssocRequestTimeout", "XXX",
       
    73                    Seconds (0.5),
       
    74                    MakeTimeAccessor (&NqstaWifiMac::m_assocRequestTimeout),
       
    75                    MakeTimeChecker ())
       
    76     .AddAttribute ("MaxMissedBeacons", 
       
    77                    "Number of beacons which much be consecutively missed before "
       
    78                    "we attempt to restart association.",
       
    79                    Uinteger (10),
       
    80                    MakeUintegerAccessor (&NqstaWifiMac::m_maxMissedBeacons),
       
    81                    MakeUintegerChecker<uint32_t> ())
       
    82     ;
       
    83   return tid;
       
    84 }
       
    85 
       
    86 
       
    87 NqstaWifiMac::NqstaWifiMac ()
       
    88   : m_state (BEACON_MISSED),
       
    89     m_probeRequestEvent (),
       
    90     m_assocRequestEvent (),
       
    91     m_beaconWatchdogEnd (Seconds (0.0))
       
    92 {
       
    93   m_dcfManager = new DcfManager ();
       
    94 
       
    95   m_rxMiddle = new MacRxMiddle ();
       
    96   m_rxMiddle->SetForwardCallback (MakeCallback (&NqstaWifiMac::Receive, this));
       
    97 
       
    98   m_low = new MacLow ();
       
    99   m_low->SetRxCallback (MakeCallback (&MacRxMiddle::Receive, m_rxMiddle));
       
   100 
       
   101   m_dca = CreateObject<DcaTxop> ();
       
   102   m_dca->SetLow (m_low);
       
   103   m_dca->SetManager (m_dcfManager);
       
   104 }
       
   105 
       
   106 NqstaWifiMac::~NqstaWifiMac ()
       
   107 {}
       
   108 
       
   109 void
       
   110 NqstaWifiMac::DoDispose (void)
       
   111 {
       
   112   delete m_rxMiddle;
       
   113   delete m_low;
       
   114   m_rxMiddle = 0;
       
   115   m_low = 0;
       
   116   m_phy = 0;
       
   117   m_dca = 0;
       
   118   WifiMac::DoDispose ();
       
   119 }
       
   120 
       
   121 void 
       
   122 NqstaWifiMac::SetWifiPhy (Ptr<WifiPhy> phy)
       
   123 {
       
   124   m_phy = phy;
       
   125 }
       
   126 void 
       
   127 NqstaWifiMac::SetWifiRemoteStationManager (Ptr<WifiRemoteStationManager> stationManager)
       
   128 {
       
   129   m_stationManager = stationManager;
       
   130 }
       
   131 void 
       
   132 NqstaWifiMac::SetForwardUpCallback (Callback<void,Ptr<Packet>, const Mac48Address &> upCallback)
       
   133 {
       
   134   m_forwardUp = upCallback;
       
   135 }
       
   136 void 
       
   137 NqstaWifiMac::SetLinkUpCallback (Callback<void> linkUp)
       
   138 {
       
   139   m_linkUp = linkUp;
       
   140 }
       
   141 void 
       
   142 NqstaWifiMac::SetLinkDownCallback (Callback<void> linkDown)
       
   143 {
       
   144   m_linkDown = linkDown;
       
   145 }
       
   146 Mac48Address 
       
   147 NqstaWifiMac::GetAddress (void) const
       
   148 {
       
   149   return m_address;
       
   150 }
       
   151 Ssid 
       
   152 NqstaWifiMac::GetSsid (void) const
       
   153 {
       
   154   return m_ssid;
       
   155 }
       
   156 Mac48Address 
       
   157 NqstaWifiMac::GetBssid (void) const
       
   158 {
       
   159   return m_bssid;
       
   160 }
       
   161 void 
       
   162 NqstaWifiMac::SetAddress (Mac48Address address)
       
   163 {
       
   164   m_address = address;
       
   165 }
       
   166 void 
       
   167 NqstaWifiMac::SetSsid (Ssid ssid)
       
   168 {
       
   169   m_ssid = ssid;
       
   170 }
       
   171 
       
   172 void 
       
   173 NqstaWifiMac::SetMaxMissedBeacons (uint32_t missed)
       
   174 {
       
   175   m_maxMissedBeacons = missed;
       
   176 }
       
   177 void 
       
   178 NqstaWifiMac::SetProbeRequestTimeout (Time timeout)
       
   179 {
       
   180   m_probeRequestTimeout = timeout;
       
   181 }
       
   182 void 
       
   183 NqstaWifiMac::SetAssocRequestTimeout (Time timeout)
       
   184 {
       
   185   m_assocRequestTimeout = timeout;
       
   186 }
       
   187 
       
   188 void 
       
   189 NqstaWifiMac::StartActiveAssociation (void)
       
   190 {
       
   191   TryToEnsureAssociated ();
       
   192 }
       
   193 
       
   194 Mac48Address
       
   195 NqstaWifiMac::GetBroadcastBssid (void)
       
   196 {
       
   197   return Mac48Address::GetBroadcast ();
       
   198 }
       
   199 
       
   200 void 
       
   201 NqstaWifiMac::SetBssid (Mac48Address bssid)
       
   202 {
       
   203   m_bssid = bssid;
       
   204 }
       
   205 void 
       
   206 NqstaWifiMac::ForwardUp (Ptr<Packet> packet, const Mac48Address &address)
       
   207 {
       
   208   m_forwardUp (packet, address);
       
   209 }
       
   210 void
       
   211 NqstaWifiMac::SendProbeRequest (void)
       
   212 {
       
   213   TRACE ("send probe request");
       
   214   WifiMacHeader hdr;
       
   215   hdr.SetProbeReq ();
       
   216   hdr.SetAddr1 (GetBroadcastBssid ());
       
   217   hdr.SetAddr2 (GetAddress ());
       
   218   hdr.SetAddr3 (GetBroadcastBssid ());
       
   219   hdr.SetDsNotFrom ();
       
   220   hdr.SetDsNotTo ();
       
   221   Ptr<Packet> packet = Create<Packet> ();
       
   222   MgtProbeRequestHeader probe;
       
   223   probe.SetSsid (GetSsid ());
       
   224   probe.SetSupportedRates (GetSupportedRates ());
       
   225   packet->AddHeader (probe);
       
   226   
       
   227   m_dca->Queue (packet, hdr);
       
   228 
       
   229   m_probeRequestEvent = Simulator::Schedule (m_probeRequestTimeout,
       
   230                                              &NqstaWifiMac::ProbeRequestTimeout, this);
       
   231 }
       
   232 
       
   233 void
       
   234 NqstaWifiMac::SendAssociationRequest (void)
       
   235 {
       
   236   TRACE ("send assoc request to=" << GetBssid ());
       
   237   WifiMacHeader hdr;
       
   238   hdr.SetAssocReq ();
       
   239   hdr.SetAddr1 (GetBssid ());
       
   240   hdr.SetAddr2 (GetAddress ());
       
   241   hdr.SetAddr3 (GetBssid ());
       
   242   hdr.SetDsNotFrom ();
       
   243   hdr.SetDsNotTo ();
       
   244   Ptr<Packet> packet = Create<Packet> ();
       
   245   MgtAssocRequestHeader assoc;
       
   246   assoc.SetSsid (GetSsid ());
       
   247   assoc.SetSupportedRates (GetSupportedRates ());
       
   248   packet->AddHeader (assoc);
       
   249   
       
   250   m_dca->Queue (packet, hdr);
       
   251 
       
   252   m_assocRequestEvent = Simulator::Schedule (m_assocRequestTimeout,
       
   253                                              &NqstaWifiMac::AssocRequestTimeout, this);
       
   254 }
       
   255 void
       
   256 NqstaWifiMac::TryToEnsureAssociated (void)
       
   257 {
       
   258   switch (m_state) {
       
   259   case ASSOCIATED:
       
   260     return;
       
   261     break;
       
   262   case WAIT_PROBE_RESP:
       
   263     /* we have sent a probe request earlier so we
       
   264        do not need to re-send a probe request immediately.
       
   265        We just need to wait until probe-request-timeout
       
   266        or until we get a probe response
       
   267      */
       
   268     break;
       
   269   case BEACON_MISSED:
       
   270     /* we were associated but we missed a bunch of beacons
       
   271      * so we should assume we are not associated anymore.
       
   272      * We try to initiate a probe request now.
       
   273      */
       
   274     m_linkDown ();
       
   275     m_state = WAIT_PROBE_RESP;
       
   276     SendProbeRequest ();
       
   277     break;
       
   278   case WAIT_ASSOC_RESP:
       
   279     /* we have sent an assoc request so we do not need to
       
   280        re-send an assoc request right now. We just need to
       
   281        wait until either assoc-request-timeout or until
       
   282        we get an assoc response.
       
   283      */
       
   284     break;
       
   285   case REFUSED:
       
   286     /* we have sent an assoc request and received a negative
       
   287        assoc resp. We wait until someone restarts an 
       
   288        association with a given ssid.
       
   289      */
       
   290     break;
       
   291   }
       
   292 }
       
   293 
       
   294 void
       
   295 NqstaWifiMac::AssocRequestTimeout (void)
       
   296 {
       
   297   TRACE ("assoc request timeout");
       
   298   m_state = WAIT_ASSOC_RESP;
       
   299   SendAssociationRequest ();
       
   300 }
       
   301 void
       
   302 NqstaWifiMac::ProbeRequestTimeout (void)
       
   303 {
       
   304   TRACE ("probe request timeout");
       
   305   m_state = WAIT_PROBE_RESP;
       
   306   SendProbeRequest ();
       
   307 }
       
   308 void 
       
   309 NqstaWifiMac::MissedBeacons (void)
       
   310 {
       
   311   if (m_beaconWatchdogEnd > Simulator::Now ())
       
   312     {
       
   313       m_beaconWatchdog = Simulator::Schedule (m_beaconWatchdogEnd - Simulator::Now (),
       
   314                                               &NqstaWifiMac::MissedBeacons, this);
       
   315       return;
       
   316     }
       
   317   TRACE ("beacon missed");
       
   318   m_state = BEACON_MISSED;
       
   319   TryToEnsureAssociated ();
       
   320 }
       
   321 void 
       
   322 NqstaWifiMac::RestartBeaconWatchdog (Time delay)
       
   323 {
       
   324   m_beaconWatchdogEnd = std::max (Simulator::Now () + delay, m_beaconWatchdogEnd);
       
   325   if (Simulator::GetDelayLeft (m_beaconWatchdog) < delay &&
       
   326       m_beaconWatchdog.IsExpired ())
       
   327     {
       
   328       m_beaconWatchdog = Simulator::Schedule (delay, &NqstaWifiMac::MissedBeacons, this);
       
   329     }
       
   330 }
       
   331 bool
       
   332 NqstaWifiMac::IsAssociated (void)
       
   333 {
       
   334   return (m_state == ASSOCIATED)?true:false;
       
   335 }
       
   336 
       
   337 void 
       
   338 NqstaWifiMac::Enqueue (Ptr<const Packet> packet, Mac48Address to)
       
   339 {
       
   340   if (!IsAssociated ()) 
       
   341     {
       
   342       TryToEnsureAssociated ();
       
   343       return;
       
   344     }
       
   345   //TRACE ("enqueue size="<<packet->GetSize ()<<", to="<<to);
       
   346   WifiMacHeader hdr;
       
   347   hdr.SetTypeData ();
       
   348   hdr.SetAddr1 (GetBssid ());
       
   349   hdr.SetAddr2 (GetAddress ());
       
   350   hdr.SetAddr3 (to);
       
   351   hdr.SetDsNotFrom ();
       
   352   hdr.SetDsTo ();
       
   353   m_dca->Queue (packet, hdr);
       
   354 }
       
   355 
       
   356 void 
       
   357 NqstaWifiMac::Receive (Ptr<Packet> packet, WifiMacHeader const *hdr)
       
   358 {
       
   359   NS_ASSERT (!hdr->IsCtl ());
       
   360   if (hdr->GetAddr1 () != GetAddress () &&
       
   361       !hdr->GetAddr1 ().IsBroadcast ()) 
       
   362     {
       
   363       // packet is not for us
       
   364     } 
       
   365   else if (hdr->IsData ()) 
       
   366     {
       
   367       ForwardUp (packet, hdr->GetAddr2 ());
       
   368     } 
       
   369   else if (hdr->IsProbeReq () ||
       
   370            hdr->IsAssocReq ()) 
       
   371     {
       
   372       /* this is a frame aimed at an AP.
       
   373        * so we can safely ignore it.
       
   374        */
       
   375     } 
       
   376   else if (hdr->IsBeacon ()) 
       
   377     {
       
   378       MgtBeaconHeader beacon;
       
   379       packet->RemoveHeader (beacon);
       
   380       bool goodBeacon = false;
       
   381       if (GetSsid ().IsBroadcast () ||
       
   382           beacon.GetSsid ().IsEqual (GetSsid ()))
       
   383         {
       
   384           Time delay = MicroSeconds (beacon.GetBeaconIntervalUs () * m_maxMissedBeacons);
       
   385           RestartBeaconWatchdog (delay);
       
   386           goodBeacon = true;
       
   387         }
       
   388       if (goodBeacon) 
       
   389         {
       
   390           SetBssid (hdr->GetAddr3 ());
       
   391         }
       
   392       if (goodBeacon && m_state == BEACON_MISSED) 
       
   393         {
       
   394           m_state = WAIT_ASSOC_RESP;
       
   395           SendAssociationRequest ();
       
   396         }
       
   397   } 
       
   398   else if (hdr->IsProbeResp ()) 
       
   399     {
       
   400       if (m_state == WAIT_PROBE_RESP) 
       
   401         {
       
   402           MgtProbeResponseHeader probeResp;
       
   403           packet->RemoveHeader (probeResp);
       
   404           if (!probeResp.GetSsid ().IsEqual (GetSsid ()))
       
   405             {
       
   406               //not a probe resp for our ssid.
       
   407               return;
       
   408             }
       
   409           SetBssid (hdr->GetAddr3 ());
       
   410           Time delay = MicroSeconds (probeResp.GetBeaconIntervalUs () * m_maxMissedBeacons);
       
   411           RestartBeaconWatchdog (delay);
       
   412           if (m_probeRequestEvent.IsRunning ()) 
       
   413             {
       
   414               m_probeRequestEvent.Cancel ();
       
   415             }
       
   416           m_state = WAIT_ASSOC_RESP;
       
   417           SendAssociationRequest ();
       
   418         }
       
   419     } 
       
   420   else if (hdr->IsAssocResp ()) 
       
   421     {
       
   422       if (m_state == WAIT_ASSOC_RESP) 
       
   423         {
       
   424           MgtAssocResponseHeader assocResp;
       
   425           packet->RemoveHeader (assocResp);
       
   426           if (m_assocRequestEvent.IsRunning ()) 
       
   427             {
       
   428               m_assocRequestEvent.Cancel ();
       
   429             }
       
   430           if (assocResp.GetStatusCode ().IsSuccess ()) 
       
   431             {
       
   432               m_state = ASSOCIATED;
       
   433               TRACE ("assoc completed"); 
       
   434               SupportedRates rates = assocResp.GetSupportedRates ();
       
   435               WifiRemoteStation *ap = m_stationManager->Lookup (hdr->GetAddr2 ());
       
   436               for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
       
   437                 {
       
   438                   WifiMode mode = m_phy->GetMode (i);
       
   439                   if (rates.IsSupportedRate (mode.GetDataRate ()))
       
   440                     {
       
   441                       ap->AddSupportedMode (mode);
       
   442                       if (rates.IsBasicRate (mode.GetDataRate ()))
       
   443                         {
       
   444                           m_stationManager->AddBasicMode (mode);
       
   445                         }
       
   446                     }
       
   447                 }
       
   448               m_linkUp ();
       
   449             } 
       
   450           else 
       
   451             {
       
   452               TRACE ("assoc refused");
       
   453               m_state = REFUSED;
       
   454             }
       
   455         }
       
   456     }
       
   457 }
       
   458 
       
   459 SupportedRates
       
   460 NqstaWifiMac::GetSupportedRates (void) const
       
   461 {
       
   462   SupportedRates rates;
       
   463   for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
       
   464     {
       
   465       WifiMode mode = m_phy->GetMode (i);
       
   466       rates.AddSupportedRate (mode.GetDataRate ());
       
   467     }
       
   468   return rates;
       
   469 }
       
   470 
       
   471 } // namespace ns3