EmulatedWLANInterface.cc
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020 Fraunhofer Institute for Applied Information Technology (FIT)
3 // Network Research Group (NET)
4 // Schloss Birlinghoven, 53754 Sankt Augustin, GERMANY
5 // Contact: support@wiback.org
6 //
7 // This file is part of the SENF code tree.
8 // It is licensed under the 3-clause BSD License (aka New BSD License).
9 // See LICENSE.txt in the top level directory for details or visit
10 // https://opensource.org/licenses/BSD-3-Clause
11 //
12 
13 
17 #include "EmulatedWLANInterface.hh"
18 
19 // Custom includes
20 #include <boost/algorithm/string/predicate.hpp>
25 
26 #define prefix_
27 //-/////////////////////////////////////////////////////////////////////////////////////////////////
28 
29 //-/////////////////////////////////////////////////////////////////////////////////////////////////
30 // senf::emu::detail::EmulatedWLANInterfaceNet
31 
32 prefix_ senf::emu::detail::EmulatedWLANInterfaceNet::EmulatedWLANInterfaceNet()
33  : receiveFilter_(self()), transmitFilter_(self()),
34  beaconGenerator_(self()),
35  receiveInput(receiveFilter_.input),
36  receiveOutput(receiveFilter_.output), transmitInput (transmitFilter_.input),
37  transmitOutput(transmitFilter_.output)
38 {}
39 
40 //-/////////////////////////////////////////////////////////////////////////////////////////////////
41 // senf::emu::EmulatedWLANInterface
42 
43 namespace {
44  // Arbitrary magic number used to identify the emulation header for WLAN packets
45  // Defined to be the 32bit integer representation of the string 'WLAN' in network byte order
46  boost::uint32_t const wlanMagic (0x574c414eu);
47 }
48 
50  : Base(receiveOutput, transmitInput), modulationId_(0),
51  power_(0), mode_(ADHOC), dev_("NetEMU-WLAN")
52 {
53  ppi::connect(receiverJack, receiveInput);
54  ppi::connect(transmitOutput, transmitterJack);
55  ppi::connect(beaconGenerator_, transmitFilter_.beaconInput);
56 
57  disable();
58  id( uniqueMAC(wlanMagic));
59  mtu(1500u);
60 
63  init();
64 }
65 
66 namespace senf { namespace emu {
67 
70 }}
71 
73 {
74  Base::init();
75 
76  namespace kw = console::kw;
77  namespace fty = console::factory;
78  consoleDir().add("beaconInterval", fty::Command(
80  .arg("interval", "Beacon interval for emulated interfaces",
81  kw::parser=senf::parseClockServiceInterval)
82  .doc("Get/set the Beacon interval.\n"
83  "An interval of 0 disables the sending of beacons") );
84  consoleDir().add("beaconInterval", fty::Command(
86  .formatter(senf::formatClockServiceInterval) );
87  consoleDir().add("mode", fty::Command(
89  .arg("mode", "ADHOC, STA or AP")
90  .doc("Get/set the mode of a WLAN interface") );
91  consoleDir().add("mode", fty::Command(
93  consoleDir().add("registerModulation", fty::Command(
95  .arg("type", "'mcs' or 'legacy'")
96  .arg("args", "if type is mcs, args can be \n 'all' for all mcs indexes,\n"
97  " a range like '1-10' for all indexes in that range, or\n"
98  " a list of indexes like '(1 4 6 10)'\n"
99  "if type is legacy, args can be \n 'all' for all legacy rates, or\n"
100  " a list of rates like '(360, 540)")
101  .doc("register modulations") );
102 }
103 
104 prefix_ void senf::emu::EmulatedWLANInterface::v_id(MACAddress const & eui)
105 {
106  id_ = eui;
107 }
108 
109 prefix_ senf::MACAddress senf::emu::EmulatedWLANInterface::v_id()
110  const
111 {
112  return id_;
113 }
114 
115 prefix_ senf::emu::ModulationParameter::id_t senf::emu::EmulatedWLANInterface::v_modulationId()
116  const
117 {
118  return modulationId_;
119 }
120 
121 prefix_ std::string const & senf::emu::EmulatedWLANInterface::v_device()
122  const
123 {
124  return dev_;
125 }
126 
127 prefix_ void senf::emu::EmulatedWLANInterface::v_modulationId(ModulationParameter::id_t id)
128 {
130  modulationId_ = id;
131 }
132 
133 prefix_ int senf::emu::EmulatedWLANInterface::v_txPower()
134  const
135 {
136  return power_;
137 }
138 
139 prefix_ void senf::emu::EmulatedWLANInterface::v_txPower(int power)
140 {
141  power_ = power;
142 }
143 
145 {
147  if (modulationId_ == 0)
148  modulationId_ = id;
149 }
150 
151 
152 prefix_ void senf::emu::EmulatedWLANInterface::registerVHTModulation(unsigned vhtMcsIndex, unsigned streams, unsigned bandwidth, bool shortGI)
153 {
155  registerModulation(registry.parameterIdByMCS_VHT(vhtMcsIndex, streams, bandwidth, shortGI));
156 }
157 
158 prefix_ void senf::emu::EmulatedWLANInterface::registerHTModulation(unsigned mcsIndex)
159 {
161  registerModulation(registry.parameterIdByMCS_HT(mcsIndex, false, false));
162  registerModulation(registry.parameterIdByMCS_HT(mcsIndex, true, false));
163  registerModulation(registry.parameterIdByMCS_HT(mcsIndex, false, true ));
164  registerModulation(registry.parameterIdByMCS_HT(mcsIndex, true, true ));
165 }
166 
167 prefix_ void senf::emu::EmulatedWLANInterface::registerLegacyModulation(unsigned rate)
168 {
169  registerModulation( WLANModulationParameterRegistry::instance().parameterIdByLegacyRate(rate));
170 }
171 
173 {
174 #define catch_bad_lexical_cast(arg) \
175  catch (boost::bad_lexical_cast &) { \
176  throw console::SyntaxErrorException("argument syntax error: ") << arg; \
177  }
178 
179  switch (type) {
181  if (args.size() != 1 or not boost::algorithm::iequals(args[0], "all"))
182  throw console::SyntaxErrorException("vht argument must be 'all'");
183  for (senf::WLAN_MCSInfo::Info const & mcsInfo : senf::WLAN_MCSInfo::getInfos()) {
184  if (mcsInfo.index >= WLAN_MCSInfo::NUM_VHT_INDEX)
185  continue;
186  for (unsigned i=0; i<8; ++i) {
187  if (mcsInfo.rate[i] == 0)
188  continue;
189  registerVHTModulation(mcsInfo.index, mcsInfo.streams, WLAN_MCSInfo::fromBandwidthIndex(i), (i%2==1));
190  }
191  }
192  return;
194  if (args.size() == 1) {
195  if (boost::algorithm::iequals(args[0], "all")) { // register all HT modulations
196  for (senf::WLAN_MCSInfo::Info const & mcsInfo : senf::WLAN_MCSInfo::getInfos()) {
197  if (mcsInfo.index >= WLAN_MCSInfo::NUM_HT_INDEX)
198  continue;
199  registerHTModulation(WLAN_MCSInfo::toHTIndex(mcsInfo.index, mcsInfo.streams));
200  }
201  return;
202  }
203  std::string::size_type p = args[0].find('-');
204  if (p != std::string::npos) {
205  try { // register all modulations in range
206  unsigned start (boost::lexical_cast<unsigned>(args[0].substr(0, p)));
207  unsigned end (boost::lexical_cast<unsigned>(args[0].substr(p+1)));
208  for (unsigned i=start; i<=end; ++i)
209  registerHTModulation(i);
210  } catch_bad_lexical_cast(args[0]);
211  return;
212  }
213  try { // register one modulation index
214  registerHTModulation(boost::lexical_cast<unsigned>(args[0]));
215  } catch_bad_lexical_cast(args[0]);
216  return;
217  }
218  for (std::string index : args) {
219  try { // register all given modulation indexes
220  registerHTModulation(boost::lexical_cast<unsigned>(index));
221  } catch_bad_lexical_cast(index);
222  }
223  return;
224  }
226  if (args.size() == 1 && boost::algorithm::iequals(args[0], "all")) { // register all legacy modulations
229  registerLegacyModulation( info.rate);
230  }
233  registerLegacyModulation( info.rate);
234  }
235  return;
236  }
237  for (std::string rate : args) {
238  try { // register all given rates
239  registerLegacyModulation( boost::lexical_cast<unsigned>(rate));
240  } catch_bad_lexical_cast(rate);
241  }
242  return;
243  }
246  break;
247  }
248  throw console::SyntaxErrorException("argument syntax error: first argument must be 'ht' or 'legacy': ") << type;
249 
250 #undef catch_bad_lexical_cast
251 }
252 
253 
254 //-/////////////////////////////////////////////////////////////////////////////////////////////////
255 // senf::emu::detail::EmulatedWLANReceiveFilter
256 
257 prefix_ senf::emu::detail::EmulatedWLANReceiveFilter::
258 EmulatedWLANReceiveFilter(EmulatedWLANInterface & iface)
259  : iface_ (iface)
260 {
261  route(input, output);
262  input.onRequest(&EmulatedWLANReceiveFilter::request);
263 }
264 
265 prefix_ void senf::emu::detail::EmulatedWLANReceiveFilter::request()
266 {
267 
269  try {
270  // in case DVB Sender is tuned on the same frequency this
271  // will cause an exception
272  p = input();
273  }
275  SENF_LOG( (senf::log::CRITICAL) ("ignoring non-emulated WLAN frame"));
276  return;
277  }
278 
280  if (e) {
281  if (iface_.annotationMode())
282  output(prependAnnotationsPacket(e));
283  else
284  output(e);
285  return;
286  }
288  if (wmp) {
289  output(prependAnnotationsPacket(wmp));
290  }
291 }
292 
293 //-/////////////////////////////////////////////////////////////////////////////////////////////////
294 // senf::emu::detail::EmulatedWLANTransmitFilter
295 
296 prefix_ senf::emu::detail::EmulatedWLANTransmitFilter::
297 EmulatedWLANTransmitFilter(EmulatedWLANInterface & iface)
298  : iface_ (iface)
299 {
300  route(input, output);
301  route(beaconInput,output);
302  input.onRequest(&EmulatedWLANTransmitFilter::request);
303  beaconInput.onRequest(&EmulatedWLANTransmitFilter::beaconRequest);
304 }
305 
306 prefix_ void senf::emu::detail::EmulatedWLANTransmitFilter::request()
307 {
308  EthernetPacket e (input());
309  e->source() = iface_.id();
311  wph.finalizeThis();
312  output(wph);
313 }
314 
315 prefix_ void senf::emu::detail::EmulatedWLANTransmitFilter::beaconRequest()
316 {
317  WLANPacket_MgtFrame wmp (beaconInput());
319  wph->mgt() = true;
320  wph.finalizeThis();
321  output(wph);
322 }
323 
324 //-/////////////////////////////////////////////////////////////////////////////////////////////////
325 // senf::emu::detail::EmulatedWLANBeaconGenerator
326 prefix_ senf::emu::detail::EmulatedWLANBeaconGenerator::
327 EmulatedWLANBeaconGenerator(EmulatedWLANInterface & iface)
328 #ifdef SENF_DEBUG
329  : timer_(ClockService::seconds(2)),
330 #else
331  : timer_(ClockService::milliseconds(250)),
332 #endif
333  iface_(iface)
334 {
335  route(timer_,output);
336  init();
337 }
338 
339 prefix_ void senf::emu::detail::EmulatedWLANBeaconGenerator::init()
340 {
341  registerEvent( timer_, &EmulatedWLANBeaconGenerator::tick );
342 
343  //create beacon packet
344  WLANBeaconPacket p (WLANBeaconPacket::create());
345  p->beaconInterval() = ClockService::in_milliseconds(timer_.interval().first);
346  p->ssidIE().value() << "NetEMU";
347 
348  beacon_ = WLANPacket_MgtFrame::createBefore(p);
349  beacon_->destinationAddress() = MACAddress::Broadcast;
350  beacon_->sequenceNumber(0u);
351  beacon_->bssid() = senf::MACAddress::from_string("00:11:23:32:11:00");
352 }
353 
354 prefix_ void senf::emu::detail::EmulatedWLANBeaconGenerator::beaconInterval(ClockService::clock_type interval)
355 {
356  if (ClockService::in_nanoseconds(interval) == 0) {
357  timer_.enabled(false);
358  return;
359  }
360  WLANBeaconPacket wbp (beacon_.find<WLANBeaconPacket>(senf::nothrow));
361  wbp->beaconInterval() = ClockService::in_milliseconds(timer_.interval().first);
362  timer_.interval(interval);
363 }
364 
366 senf::emu::detail::EmulatedWLANBeaconGenerator::beaconInterval()
367 {
368  return timer_.interval().first;
369 }
370 
371 prefix_ void senf::emu::detail::EmulatedWLANBeaconGenerator::tick()
372 {
373  if (iface_.mode() == EmulatedWLANInterface::STA)
374  return;
375 
376  beacon_->sourceAddress() = iface_.id(); // iface not known during init
377  beacon_->sequenceNumber(beacon_->sequenceNumber()+1);
378 
379  beacon_.finalizeAll();
380  output(beacon_.clone());
381 }
382 
383 //-/////////////////////////////////////////////////////////////////////////////////////////////////
384 #undef prefix_
385 
386 
387 // Local Variables:
388 // mode: c++
389 // fill-column: 100
390 // comment-column: 40
391 // c-file-style: "senf"
392 // indent-tabs-mode: nil
393 // ispell-local-dictionary: "american"
394 // compile-command: "scons -u test"
395 // End:
config::time_type clock_type
#define SENF_MEMBINDFNP(ret, cls, fn, args)
static SENF_CLOCKSERVICE_CONSTEXPR int64_type in_milliseconds(clock_type const &v)
static ConcretePacket createBefore(Packet const &packet)
ModulationParameter::id_t parameterIdByMCS_HT(unsigned htMcsIndex, unsigned bandwidth, bool shortGI) const
u8 type
void registerModulation(ModulationParameter::id_t id)
static constexpr unsigned NUM_HT_INDEX
static SENF_CLOCKSERVICE_CONSTEXPR clock_type seconds(int64_type const &v)
static MACAddress from_string(std::string const &s)
OtherPacket find() const
ConcretePacket< WLANBeaconPacketType > WLANBeaconPacket
SENF_CONSOLE_REGISTER_ENUM_MEMBER(DVBModulationParameter, fec_rate_t,(FEC_NONE)(FEC_1_2)(FEC_2_3)(FEC_3_4)(FEC_4_5)(FEC_5_6)(FEC_6_7)(FEC_7_8)(FEC_8_9)(FEC_AUTO)(FEC_3_5)(FEC_9_10))
EthernetPacket prependAnnotationsPacket(Packet const &pkt, MACAddress const &src_=senf::MACAddress::None, MACAddress const &dst_=senf::MACAddress::Broadcast)
WLANPacket_MgtFrameType::packet WLANPacket_MgtFrame
static std::vector< LegacyModulationInfo > getLegacyModulationInfosOFDM()
ModulationParameter::id_t parameterIdByMCS_VHT(unsigned vhtMcsIndex, unsigned streams, unsigned bandwidth, bool shortGI) const
static SENF_CLOCKSERVICE_CONSTEXPR clock_type milliseconds(int64_type const &v)
static SENF_CLOCKSERVICE_CONSTEXPR int64_type in_nanoseconds(clock_type const &v)
console::ScopedDirectory & consoleDir()
static std::vector< LegacyModulationInfo > getLegacyModulationInfos11b()
#define prefix_
nothrow
static std::uint8_t toHTIndex(std::uint8_t index, std::uint8_t streams)
EmulatedWLANInterface public header.
WLANModulationParameter const & findModulationById(ModulationParameter::id_t id) const
static std::vector< Info > getInfos()
static constexpr unsigned NUM_VHT_INDEX
static WLANModulationParameterRegistry & instance()
MACAddress uniqueMAC(boost::uint32_t magic)
Get pseudo-random but unique MACAddress.
void finalizeThis()
#define catch_bad_lexical_cast(arg)
ConcretePacket< EthernetPacketType > EthernetPacket
#define SENF_LOG(args)
AnnotationsPacket public header.
static MACAddress const Broadcast
static unsigned fromBandwidthIndex(std::uint8_t bandwidthIndex)
void registerModulation(ModulationParameter::id_t id)
register modulation configuration