|
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 |