1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2009 IITP RAS
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: Kirill Andreev <andreev@iitp.ru>
19  */
20 
21 #include "ie-dot11s-configuration.h"
22 #include "ie-dot11s-peer-management.h"
23 #include "dot11s-mac-header.h"
24 #include "peer-management-protocol-mac.h"
25 #include "peer-management-protocol.h"
26 #include "peer-link-frame.h"
27 #include "ns3/mesh-wifi-interface-mac.h"
28 #include "ns3/simulator.h"
29 #include "ns3/mesh-information-element-vector.h"
30 #include "ns3/log.h"
31 
32 namespace ns3 {
33 
34 NS_LOG_COMPONENT_DEFINE ("PeerManagementProtocolMac");
35 
36 namespace dot11s {
PeerManagementProtocolMac(uint32_t interface,Ptr<PeerManagementProtocol> protocol)37 PeerManagementProtocolMac::PeerManagementProtocolMac (uint32_t interface,
38                                                       Ptr<PeerManagementProtocol> protocol)
39 {
40   m_ifIndex = interface;
41   m_protocol = protocol;
42 }
43 
~PeerManagementProtocolMac()44 PeerManagementProtocolMac::~PeerManagementProtocolMac ()
45 {
46 }
47 
48 void
SetParent(Ptr<MeshWifiInterfaceMac> parent)49 PeerManagementProtocolMac::SetParent (Ptr<MeshWifiInterfaceMac> parent)
50 {
51   m_parent = parent;
52   m_parent->TraceConnectWithoutContext ("DroppedMpdu", MakeCallback (&PeerManagementProtocolMac::TxError, this));
53   m_parent->TraceConnectWithoutContext ("AckedMpdu",   MakeCallback (&PeerManagementProtocolMac::TxOk,    this));
54 }
55 void
TxError(WifiMacDropReason reason,Ptr<const WifiMacQueueItem> mpdu)56 PeerManagementProtocolMac::TxError (WifiMacDropReason reason, Ptr<const WifiMacQueueItem> mpdu)
57 {
58   m_protocol->TransmissionFailure (m_ifIndex, mpdu->GetHeader ().GetAddr1 ());
59 }
60 void
TxOk(Ptr<const WifiMacQueueItem> mpdu)61 PeerManagementProtocolMac::TxOk (Ptr <const WifiMacQueueItem> mpdu)
62 {
63   m_protocol->TransmissionSuccess (m_ifIndex, mpdu->GetHeader ().GetAddr1 ());
64 }
65 bool
Receive(Ptr<Packet> const_packet,const WifiMacHeader & header)66 PeerManagementProtocolMac::Receive (Ptr<Packet> const_packet, const WifiMacHeader & header)
67 {
68   NS_LOG_FUNCTION (this << const_packet << header);
69   // First of all we copy a packet, because we need to remove some
70   //headers
71   Ptr<Packet> packet = const_packet->Copy ();
72   if (header.IsBeacon ())
73     {
74       NS_LOG_DEBUG ("Is Beacon from " << header.GetAddr2 ());
75       MgtBeaconHeader beacon_hdr;
76       packet->RemoveHeader (beacon_hdr);
77       MeshInformationElementVector elements;
78       // To determine header size here, we can rely on the knowledge that
79       // this is the last header to remove.
80       packet->RemoveHeader (elements, packet->GetSize ());
81       Ptr<IeBeaconTiming> beaconTiming = DynamicCast<IeBeaconTiming> (elements.FindFirst (IE_BEACON_TIMING));
82       Ptr<IeMeshId> meshId = DynamicCast<IeMeshId> (elements.FindFirst (IE_MESH_ID));
83 
84       if ((meshId != 0) && (m_protocol->GetMeshId ()->IsEqual (*meshId)))
85         {
86           m_protocol->ReceiveBeacon (m_ifIndex, header.GetAddr2 (), MicroSeconds (
87                                        beacon_hdr.GetBeaconIntervalUs ()), beaconTiming);
88         }
89       else
90         {
91           NS_LOG_DEBUG ("MeshId mismatch " << m_protocol->GetMeshId ()->PeekString () << " " << (*meshId) << "; ignoring");
92         }
93       // Beacon shall not be dropped. May be needed to another plugins
94       return true;
95     }
96   uint16_t aid = 0;  // applicable only in Confirm message
97   IeConfiguration config;
98   if (header.IsAction ())
99     {
100       NS_LOG_DEBUG ("Is action");
101       WifiActionHeader actionHdr;
102       packet->RemoveHeader (actionHdr);
103       WifiActionHeader::ActionValue actionValue = actionHdr.GetAction ();
104       // If can not handle - just return;
105       if (actionHdr.GetCategory () != WifiActionHeader::SELF_PROTECTED)
106         {
107           NS_LOG_DEBUG ("Cannot handle non SELF PROTECTED");
108           return m_protocol->IsActiveLink (m_ifIndex, header.GetAddr2 ());
109         }
110       m_stats.rxMgt++;
111       m_stats.rxMgtBytes += packet->GetSize ();
112       Mac48Address peerAddress = header.GetAddr2 ();
113       Mac48Address peerMpAddress = header.GetAddr3 ();
114       if (actionValue.selfProtectedAction == WifiActionHeader::PEER_LINK_OPEN)
115         {
116           NS_LOG_DEBUG ("Received PEER_LINK_OPEN");
117           PeerLinkOpenStart::PlinkOpenStartFields fields;
118           PeerLinkOpenStart peerFrame;
119           packet->RemoveHeader (peerFrame);
120           fields = peerFrame.GetFields ();
121           if (!fields.meshId.IsEqual ( *(m_protocol->GetMeshId ())))
122             {
123               NS_LOG_DEBUG ("PEER_LINK_OPEN:  MeshId mismatch");
124               m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
125               // Broken peer link frame - drop it
126               m_stats.brokenMgt++;
127               return false;
128             }
129           if (!(m_parent->CheckSupportedRates (fields.rates)))
130             {
131               NS_LOG_DEBUG ("PEER_LINK_OPEN:  configuration mismatch");
132               m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
133               // Broken peer link frame - drop it
134               m_stats.brokenMgt++;
135               return false;
136             }
137           config = fields.config;
138         }
139       else if (actionValue.selfProtectedAction == WifiActionHeader::PEER_LINK_CONFIRM)
140         {
141           NS_LOG_DEBUG ("Received PEER_LINK_CONFIRM");
142           PeerLinkConfirmStart::PlinkConfirmStartFields fields;
143           PeerLinkConfirmStart peerFrame;
144           packet->RemoveHeader (peerFrame);
145           fields = peerFrame.GetFields ();
146           if (!(m_parent->CheckSupportedRates (fields.rates)))
147             {
148               NS_LOG_DEBUG ("PEER_LINK_CONFIRM:  configuration mismatch");
149               m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
150               // Broken peer link frame - drop it
151               m_stats.brokenMgt++;
152               return false;
153             }
154           aid = fields.aid;
155           config = fields.config;
156         }
157       else if (actionValue.selfProtectedAction == WifiActionHeader::PEER_LINK_CLOSE)
158         {
159           NS_LOG_DEBUG ("Received PEER_LINK_CLOSE");
160           PeerLinkCloseStart::PlinkCloseStartFields fields;
161           PeerLinkCloseStart peerFrame;
162           packet->RemoveHeader (peerFrame);
163           fields = peerFrame.GetFields ();
164           if (!fields.meshId.IsEqual ( *(m_protocol->GetMeshId ())))
165             {
166               NS_LOG_DEBUG ("PEER_LINK_CLOSE:  configuration mismatch");
167               m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
168               // Broken peer link frame - drop it
169               m_stats.brokenMgt++;
170               return false;
171             }
172         }
173       else
174         {
175           NS_FATAL_ERROR ("Unknown Self-protected Action type: " << actionValue.selfProtectedAction);
176         }
177       Ptr<IePeerManagement> peerElement;
178       MeshInformationElementVector elements;
179       // To determine header size here, we can rely on the knowledge that
180       // this is the last header to remove.
181       packet->RemoveHeader (elements, packet->GetSize ());
182       peerElement = DynamicCast<IePeerManagement>(elements.FindFirst (IE_MESH_PEERING_MANAGEMENT));
183 
184       NS_ASSERT (peerElement != 0);
185       //Check that frame subtype corresponds to peer link subtype
186       if (peerElement->SubtypeIsOpen ())
187         {
188           m_stats.rxOpen++;
189           NS_ASSERT (actionValue.selfProtectedAction == WifiActionHeader::PEER_LINK_OPEN);
190         }
191       if (peerElement->SubtypeIsConfirm ())
192         {
193           m_stats.rxConfirm++;
194           NS_ASSERT (actionValue.selfProtectedAction == WifiActionHeader::PEER_LINK_CONFIRM);
195         }
196       if (peerElement->SubtypeIsClose ())
197         {
198           m_stats.rxClose++;
199           NS_ASSERT (actionValue.selfProtectedAction == WifiActionHeader::PEER_LINK_CLOSE);
200         }
201       //Deliver Peer link management frame to protocol:
202       m_protocol->ReceivePeerLinkFrame (m_ifIndex, peerAddress, peerMpAddress, aid, *peerElement, config);
203       // if we can handle a frame - drop it
204       return false;
205     }
206   return m_protocol->IsActiveLink (m_ifIndex, header.GetAddr2 ());
207 }
208 bool
UpdateOutcomingFrame(Ptr<Packet> packet,WifiMacHeader & header,Mac48Address from,Mac48Address to)209 PeerManagementProtocolMac::UpdateOutcomingFrame (Ptr<Packet> packet, WifiMacHeader & header,
210                                                  Mac48Address from, Mac48Address to)
211 {
212   NS_LOG_FUNCTION (this << packet << header << from << to);
213   if (header.IsAction ())
214     {
215       WifiActionHeader actionHdr;
216       packet->PeekHeader (actionHdr);
217       if (actionHdr.GetCategory () == WifiActionHeader::SELF_PROTECTED)
218         {
219           return true;
220         }
221     }
222   if (header.GetAddr1 ().IsGroup ())
223     {
224       return true;
225     }
226   else
227     {
228       if (m_protocol->IsActiveLink (m_ifIndex, header.GetAddr1 ()))
229         {
230           return true;
231         }
232       else
233         {
234           m_stats.dropped++;
235           return false;
236         }
237     }
238 }
239 void
UpdateBeacon(MeshWifiBeacon & beacon) const240 PeerManagementProtocolMac::UpdateBeacon (MeshWifiBeacon & beacon) const
241 {
242   if (m_protocol->GetBeaconCollisionAvoidance ())
243     {
244       Ptr<IeBeaconTiming> beaconTiming = m_protocol->GetBeaconTimingElement (m_ifIndex);
245       beacon.AddInformationElement (beaconTiming);
246     }
247   beacon.AddInformationElement (m_protocol->GetMeshId ());
248   m_protocol->NotifyBeaconSent (m_ifIndex, beacon.GetBeaconInterval ());
249 }
250 
251 void
SendPeerLinkManagementFrame(Mac48Address peerAddress,Mac48Address peerMpAddress,uint16_t aid,IePeerManagement peerElement,IeConfiguration meshConfig)252 PeerManagementProtocolMac::SendPeerLinkManagementFrame (Mac48Address peerAddress, Mac48Address peerMpAddress,
253                                                         uint16_t aid, IePeerManagement peerElement, IeConfiguration meshConfig)
254 {
255   NS_LOG_FUNCTION (this << peerAddress << peerMpAddress);
256   //Create a packet:
257   meshConfig.SetNeighborCount (m_protocol->GetNumberOfLinks ());
258   Ptr<Packet> packet = Create<Packet> ();
259   MeshInformationElementVector elements;
260   elements.AddInformationElement (Ptr<IePeerManagement> (&peerElement));
261   packet->AddHeader (elements);
262   //Create an 802.11 frame header:
263   //Send management frame to MAC:
264   if (peerElement.SubtypeIsOpen ())
265     {
266       PeerLinkOpenStart::PlinkOpenStartFields fields;
267       fields.rates = m_parent->GetSupportedRates ();
268       fields.capability = 0;
269       fields.meshId = *(m_protocol->GetMeshId ());
270       fields.config = meshConfig;
271       PeerLinkOpenStart plinkOpen;
272       WifiActionHeader actionHdr;
273       m_stats.txOpen++;
274       WifiActionHeader::ActionValue action;
275       action.selfProtectedAction = WifiActionHeader::PEER_LINK_OPEN;
276       actionHdr.SetAction (WifiActionHeader::SELF_PROTECTED, action);
277       plinkOpen.SetPlinkOpenStart (fields);
278       packet->AddHeader (plinkOpen);
279       packet->AddHeader (actionHdr);
280     }
281   if (peerElement.SubtypeIsConfirm ())
282     {
283       PeerLinkConfirmStart::PlinkConfirmStartFields fields;
284       fields.rates = m_parent->GetSupportedRates ();
285       fields.capability = 0;
286       fields.config = meshConfig;
287       PeerLinkConfirmStart plinkConfirm;
288       WifiActionHeader actionHdr;
289       m_stats.txConfirm++;
290       WifiActionHeader::ActionValue action;
291       action.selfProtectedAction = WifiActionHeader::PEER_LINK_CONFIRM;
292       fields.aid = aid;
293       actionHdr.SetAction (WifiActionHeader::SELF_PROTECTED, action);
294       plinkConfirm.SetPlinkConfirmStart (fields);
295       packet->AddHeader (plinkConfirm);
296       packet->AddHeader (actionHdr);
297     }
298   if (peerElement.SubtypeIsClose ())
299     {
300       PeerLinkCloseStart::PlinkCloseStartFields fields;
301       fields.meshId = *(m_protocol->GetMeshId ());
302       PeerLinkCloseStart plinkClose;
303       WifiActionHeader actionHdr;
304       m_stats.txClose++;
305       WifiActionHeader::ActionValue action;
306       action.selfProtectedAction = WifiActionHeader::PEER_LINK_CLOSE;
307       actionHdr.SetAction (WifiActionHeader::SELF_PROTECTED, action);
308       plinkClose.SetPlinkCloseStart (fields);
309       packet->AddHeader (plinkClose);
310       packet->AddHeader (actionHdr);
311     }
312   m_stats.txMgt++;
313   m_stats.txMgtBytes += packet->GetSize ();
314   // Wifi Mac header:
315   WifiMacHeader hdr;
316   hdr.SetType (WIFI_MAC_MGT_ACTION);
317   hdr.SetAddr1 (peerAddress);
318   hdr.SetAddr2 (m_parent->GetAddress ());
319   //Addr is not used here, we use it as our MP address
320   hdr.SetAddr3 (m_protocol->GetAddress ());
321   hdr.SetDsNotFrom ();
322   hdr.SetDsNotTo ();
323   m_parent->SendManagementFrame (packet, hdr);
324 }
325 
326 Mac48Address
GetAddress() const327 PeerManagementProtocolMac::GetAddress () const
328 {
329   if (m_parent != 0)
330     {
331       return m_parent->GetAddress ();
332     }
333   else
334     {
335       return Mac48Address ();
336     }
337 }
338 void
SetBeaconShift(Time shift)339 PeerManagementProtocolMac::SetBeaconShift (Time shift)
340 {
341   if (shift != Seconds (0))
342     {
343       m_stats.beaconShift++;
344     }
345   m_parent->ShiftTbtt (shift);
346 }
Statistics()347 PeerManagementProtocolMac::Statistics::Statistics () :
348   txOpen (0), txConfirm (0), txClose (0), rxOpen (0), rxConfirm (0), rxClose (0), dropped (0), brokenMgt (0),
349   txMgt (0), txMgtBytes (0), rxMgt (0), rxMgtBytes (0), beaconShift (0)
350 {
351 }
352 void
Print(std::ostream & os) const353 PeerManagementProtocolMac::Statistics::Print (std::ostream & os) const
354 {
355   os << "<Statistics "
356   "txOpen=\"" << txOpen << "\"" << std::endl <<
357   "txConfirm=\"" << txConfirm << "\"" << std::endl <<
358   "txClose=\"" << txClose << "\"" << std::endl <<
359   "rxOpen=\"" << rxOpen << "\"" << std::endl <<
360   "rxConfirm=\"" << rxConfirm << "\"" << std::endl <<
361   "rxClose=\"" << rxClose << "\"" << std::endl <<
362   "dropped=\"" << dropped << "\"" << std::endl <<
363   "brokenMgt=\"" << brokenMgt << "\"" << std::endl <<
364   "txMgt=\"" << txMgt << "\"" << std::endl <<
365   "txMgtBytes=\"" << txMgtBytes << "\"" << std::endl <<
366   "rxMgt=\"" << rxMgt << "\"" << std::endl <<
367   "rxMgtBytes=\"" << rxMgtBytes << "\"" << std::endl <<
368   "beaconShift=\"" << beaconShift << "\"/>" << std::endl;
369 }
370 void
Report(std::ostream & os) const371 PeerManagementProtocolMac::Report (std::ostream & os) const
372 {
373   os << "<PeerManagementProtocolMac "
374   "address=\"" << m_parent->GetAddress () << "\">" << std::endl;
375   m_stats.Print (os);
376   os << "</PeerManagementProtocolMac>" << std::endl;
377 }
378 void
ResetStats()379 PeerManagementProtocolMac::ResetStats ()
380 {
381   m_stats = Statistics ();
382 }
383 uint32_t
GetLinkMetric(Mac48Address peerAddress)384 PeerManagementProtocolMac::GetLinkMetric (Mac48Address peerAddress)
385 {
386   return m_parent->GetLinkMetric (peerAddress);
387 }
388 int64_t
AssignStreams(int64_t stream)389 PeerManagementProtocolMac::AssignStreams (int64_t stream)
390 {
391   return m_protocol->AssignStreams (stream);
392 }
393 
394 } // namespace dot11s
395 } // namespace ns3
396 
397