WirelessNLController.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 "WirelessNLController.hh"
18 
19 // Custom includes
20 #include <algorithm>
21 #include <fstream>
22 #include <net/if.h>
23 #include <netlink/netlink.h>
24 #include <netlink/genl/genl.h>
25 #include <netlink/genl/ctrl.h>
26 #include <netlink/genl/family.h>
27 #include <boost/filesystem.hpp>
28 #include <boost/filesystem/fstream.hpp>
29 #include <senf/Utils/Cpp11Support/cast.hh>
30 #include <senf/Utils/Range.hh>
31 #include <senf/Utils/String.hh>
32 #include <senf/Utils/algorithm.hh>
33 #include <senf/Utils/membind.hh>
34 
35 #define prefix_
36 //-/////////////////////////////////////////////////////////////////////////////////////////////////
37 
38 #define FOREACH_ID(x) BOOST_PP_CAT(x, __LINE__)
39 #define FOREACH_NESTED_ATTR(attr, nla) \
40  if (nla) \
41  for (int FOREACH_ID(_remaining) = nla_len(nla), \
42  FOREACH_ID(_loop_done) = 0; \
43  FOREACH_ID(_loop_done)==0; ++FOREACH_ID(_loop_done)) \
44  for (nlattr * attr = nla_attr_data(nla); \
45  nla_ok(attr, FOREACH_ID(_remaining)); \
46  attr = nla_next(attr, &(FOREACH_ID(_remaining))))
47 
48 #undef NLA_PUT
49 
50 #define NLA_PUT(msg, attrtype, attrlen, data) \
51  do { \
52  int r; \
53  if ((r = nla_put(msg.get(), attrtype, attrlen, data)) < 0) \
54  throw NetlinkException(r, "Failed to build the netlink message"); \
55  } while(0)
56 
57 #define NLA_PUT_NESTED(msg, attrtype, nestedMsg) \
58  do { \
59  int r; \
60  if ((r = nla_put_nested(msg.get(), attrtype, nestedMsg.get())) < 0) \
61  throw NetlinkException(r, "Failed to build the netlink message"); \
62  } while(0)
63 
64 #define KHZ_TO_MHZ(freq) ((freq) / 1000)
65 #define MHZ_TO_KHZ(freq) ((freq) * 1000)
66 
67 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
68 
69 //-/////////////////////////////////////////////////////////////////////////////////////////////////
70 
71 namespace {
72 
73  template <class T>
74  T & get_optional_value(boost::optional<T> & opt)
75  {
76  if (not opt)
77  opt = T();
78  return opt.get();
79  }
80 
81  static int static_netlink_cb(nl_msg * msg, void * arg) {
82  auto * cb (reinterpret_cast<senf::emu::WirelessNLController::NetlinkMsgCallback *>(arg));
83  return (*cb)(msg);
84  }
85 
86  static nlattr * nla_attr_data(const nlattr * nla) {
87  return reinterpret_cast<nlattr *>(nla_data(nla));
88  }
89 
90  struct nl_nested_attr_ptr
91  {
92  typedef boost::shared_ptr<nl_msg> nl_msg_ptr;
93  nl_msg_ptr msg;
94  nlattr * attr;
95 
96  nl_nested_attr_ptr(nl_msg_ptr msg_, int attrtype)
97  : msg(msg_), attr(nla_nest_start(msg.get(), attrtype))
98  {
99  if (!attr) throw senf::SystemException( "Failed to build netlink message", ENOBUFS);
100  }
101  ~nl_nested_attr_ptr()
102  {
103  nla_nest_end(msg.get(), attr);
104  }
105 
106  };
107 
108  struct NLAttributePolicies
109  {
110  static nla_policy freqPolicy[NL80211_FREQUENCY_ATTR_MAX + 1];
111  static nla_policy ratePolicy[NL80211_BITRATE_ATTR_MAX + 1];
112  static nla_policy surveyPolicy[NL80211_SURVEY_INFO_MAX + 1];
113  static nla_policy regRulePolicy[NL80211_FREQUENCY_ATTR_MAX + 1];
114  static nla_policy bssPolicy[NL80211_BSS_MAX + 1];
115 
116  static bool init() {
117  memset( freqPolicy, 0, sizeof(freqPolicy));
118  freqPolicy[NL80211_FREQUENCY_ATTR_FREQ] .type = NLA_U32;
119  freqPolicy[NL80211_FREQUENCY_ATTR_DISABLED] .type = NLA_FLAG;
120  freqPolicy[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN].type = NLA_FLAG;
121  freqPolicy[NL80211_FREQUENCY_ATTR_NO_IBSS] .type = NLA_FLAG;
122  freqPolicy[NL80211_FREQUENCY_ATTR_RADAR] .type = NLA_FLAG;
123  freqPolicy[NL80211_FREQUENCY_ATTR_MAX_TX_POWER].type = NLA_U32;
124  freqPolicy[NL80211_FREQUENCY_ATTR_DFS_STATE] .type = NLA_U32;
125  freqPolicy[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME].type = NLA_U32;
126 
127  memset( ratePolicy, 0, sizeof(ratePolicy));
128  ratePolicy[NL80211_BITRATE_ATTR_RATE] .type = NLA_U32;
129  ratePolicy[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE].type = NLA_FLAG;
130 
131  memset( surveyPolicy, 0, sizeof(surveyPolicy));
132  surveyPolicy[NL80211_SURVEY_INFO_FREQUENCY].type = NLA_U32;
133  surveyPolicy[NL80211_SURVEY_INFO_NOISE] .type = NLA_U8;
134 
135  memset( regRulePolicy, 0, sizeof(regRulePolicy));
136  regRulePolicy[NL80211_ATTR_REG_RULE_FLAGS] .type = NLA_U32;
137  regRulePolicy[NL80211_ATTR_FREQ_RANGE_START] .type = NLA_U32;
138  regRulePolicy[NL80211_ATTR_FREQ_RANGE_END] .type = NLA_U32;
139  regRulePolicy[NL80211_ATTR_FREQ_RANGE_MAX_BW] .type = NLA_U32;
140  regRulePolicy[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN].type = NLA_U32;
141  regRulePolicy[NL80211_ATTR_POWER_RULE_MAX_EIRP] .type = NLA_U32;
142  regRulePolicy[NL80211_ATTR_DFS_CAC_TIME] .type = NLA_U32;
143 
144  memset( bssPolicy, 0, sizeof(bssPolicy));
145  bssPolicy[NL80211_BSS_TSF].type = NLA_U64;
146  bssPolicy[NL80211_BSS_FREQUENCY].type = NLA_U32;
147  //bssPolicy[NL80211_BSS_BSSID] = {};
148  bssPolicy[NL80211_BSS_BEACON_INTERVAL].type = NLA_U16;
149  bssPolicy[NL80211_BSS_CAPABILITY].type = NLA_U16;
150  //bssPolicy[NL80211_BSS_INFORMATION_ELEMENTS] = { };
151  bssPolicy[NL80211_BSS_SIGNAL_MBM].type = NLA_U32;
152  bssPolicy[NL80211_BSS_SIGNAL_UNSPEC].type = NLA_U8;
153  bssPolicy[NL80211_BSS_STATUS].type = NLA_U32;
154  bssPolicy[NL80211_BSS_SEEN_MS_AGO].type = NLA_U32;
155  //bssPolicy[NL80211_BSS_BEACON_IES] = { };
156 
157  return true;
158  }
159  };
160 
161  nla_policy NLAttributePolicies::freqPolicy[NL80211_FREQUENCY_ATTR_MAX + 1];
162  nla_policy NLAttributePolicies::ratePolicy[NL80211_BITRATE_ATTR_MAX + 1];
163  nla_policy NLAttributePolicies::surveyPolicy[NL80211_SURVEY_INFO_MAX + 1];
164  nla_policy NLAttributePolicies::regRulePolicy[NL80211_FREQUENCY_ATTR_MAX + 1];
165  nla_policy NLAttributePolicies::bssPolicy[NL80211_BSS_MAX + 1];
166 
167  bool __attribute__((unused))
168  _nlAttributePolicies_initialized (NLAttributePolicies::init());
169 }
170 
171 //-/////////////////////////////////////////////////////////////////////////////////////////////////
172 // senf::emu::WirelessNLController
173 
175  : radarEvent(*this), regulatoryDomainChangeEvent(*this), scanEvent(*this),
176  ifIndex_(0), phyIndex_(-1),
177  nl_sock_(nullptr, nl_socket_free), nl_cache_(nullptr, nl_cache_free), nl_cb_(nullptr, nl_cb_put),
178  nl_event_sock_(nullptr, nl_socket_free), nl_event_cb_(nullptr, nl_cb_put)
179 {
180  ifIndex_ = if_nametoindex(interface.c_str());
181  if (ifIndex_ != 0) {
182  phyIndex_ = if_nameto_phy_index( interface);
183  phyName_ = if_nameto_phy_name( interface);
184  } else {
185  phyIndex_ = phy_nametoindex( interface);
186  phyName_ = interface;
187  }
188  if (phyIndex_ == -1)
189  throw senf::SystemException( "Could not discover the index of " , EINVAL) << interface;
190 
191  init(true); // disable seqNoCheck
192 }
193 
195  : radarEvent(*this), regulatoryDomainChangeEvent(*this), scanEvent(*this),
196  ifIndex_(0), phyIndex_(-1),
197  nl_sock_(nullptr, nl_socket_free), nl_cache_(nullptr, nl_cache_free), nl_cb_(nullptr, nl_cb_put),
198  nl_event_sock_(nullptr, nl_socket_free), nl_event_cb_(nullptr, nl_cb_put)
199 {
200  init(disableSeqNoCheck);
201 }
202 
203 prefix_ void senf::emu::WirelessNLController::init(bool disableSeqNoCheck)
204 {
205  survey_.clear();
206  ifaceType_ = IfaceType::Unknown;
207  hasHTCapabilities_ = false;
208  hasVHTCapabilities_ = false;
209  callback_ = nullptr;
210  netlinkMsgCb_ = senf::membind(&WirelessNLController::netlink_cb, this);
211  netlinkEventCb_ = senf::membind(&WirelessNLController::netlink_event_cb, this);
212 
213  initNlSock(nl_sock_, disableSeqNoCheck);
214  initNlCb(nl_sock_, nl_cb_, netlinkMsgCb_);
215  initNlCache(nl_sock_, nl_cache_);
216 
217  nl80211Id_ = genl_ctrl_resolve(nl_sock_.get(), "nl80211");
218  if (nl80211Id_ < 0)
219  SENF_THROW_SYSTEM_EXCEPTION( "nl80211 not found");
220 }
221 
222 prefix_ void senf::emu::WirelessNLController::initNlSock(nl_sock_ptr & sock, bool disableSeqNoCheck)
223 {
224  sock.reset(nl_socket_alloc());
225  if (not sock)
226  SENF_THROW_SYSTEM_EXCEPTION( "Failed to allocate netlink socket");
227 
228  if (genl_connect(sock.get()))
229  SENF_THROW_SYSTEM_EXCEPTION( "Failed to connect generic netlink socket");
230 
231  if (disableSeqNoCheck)
232  nl_socket_disable_seq_check(sock.get());
233  nl_socket_disable_auto_ack(sock.get());
234 }
235 
236 prefix_ void senf::emu::WirelessNLController::initNlCache(nl_sock_ptr & sock, nl_cache_ptr & cache)
237 {
238  nl_cache * c;
239  if (genl_ctrl_alloc_cache(sock.get(), &c))
240  SENF_THROW_SYSTEM_EXCEPTION( "Failed to connect generic netlink cache");
241  cache.reset(c);
242 }
243 
244 prefix_ void senf::emu::WirelessNLController::initNlCb(nl_sock_ptr & sock, nl_cb_ptr & cb, NetlinkMsgCallback & msgcb)
245 {
246  cb.reset(nl_cb_alloc(NL_CB_DEFAULT));
247  if (not cb)
248  SENF_THROW_SYSTEM_EXCEPTION( "Failed to allocate netlink callbacks\n");
249  nl_cb_set(cb.get(), NL_CB_VALID, NL_CB_CUSTOM, static_netlink_cb, &msgcb);
250  nl_socket_set_cb(sock.get(), cb.get());
251 }
252 
254  const
255 {
256  return phyIndex_;
257 }
258 
260  const
261 {
262  return phyName_;
263 }
264 
265 prefix_ senf::emu::WirelessNLController::nl_msg_ptr senf::emu::WirelessNLController::nlMsg()
266 {
267  nl_msg_ptr msg (nlmsg_alloc(), &nlmsg_free);
268  if (!msg)
269  SENF_THROW_SYSTEM_EXCEPTION( "Failed to allocate netlink message");
270  return msg;
271 }
272 
273 prefix_ senf::emu::WirelessNLController::nl_msg_ptr
274 senf::emu::WirelessNLController::nlMsgHeader(uint8_t cmd, CmdIdBy idBy, int flags)
275  const
276 {
277  nl_msg_ptr msg (nlMsg());
278  genlmsg_put( msg.get(),
279  NL_AUTO_PID, // pid
280  NL_AUTO_SEQ, // sequence number of message
281  nl80211Id_, // netlink family of nl80211
282  0, // length of user specific header
283  flags, // message flags
284  cmd, // netlink command
285  0 ); // protocol version
286  switch (idBy) {
287  case CIB_PHY:
288  if (phyIndex_ == -1)
289  throw NetlinkException(NLE_INVAL, "Device index missing");
290  NLA_PUT_U32( msg, NL80211_ATTR_WIPHY, phyIndex_);
291  break;
292  case CIB_IF:
293  if (ifIndex_ == 0)
294  throw NetlinkException(NLE_INVAL, "Interface index missing");
295  NLA_PUT_U32( msg, NL80211_ATTR_IFINDEX, ifIndex_);
296  break;
297  case CIB_NONE:
298  break;
299  }
300 
301  return msg;
302 }
303 
304 prefix_ void senf::emu::WirelessNLController::send_and_wait4response(nl_msg_ptr const & msg, CallbackMemPtr cb)
305 {
306  callback_ = cb;
307  int r;
308  if ((r = nl_send_auto_complete(nl_sock_.get(), msg.get())) > 0) {
309  if ((r = nl_recvmsgs_default( nl_sock_.get())) != 0)
310  throw NetlinkException(r);
311  } else {
312  throw NetlinkException(r);
313  }
314  callback_ = nullptr;
315 }
316 
317 prefix_ void senf::emu::WirelessNLController::send(nl_msg_ptr const & msg)
318 {
319  int r;
320  if ((r = nl_send_auto_complete(nl_sock_.get(), msg.get())) > 0) {
321  if ((r = nl_wait_for_ack( nl_sock_.get())) != 0)
322  throw NetlinkException(r);
323  } else {
324  throw NetlinkException(r);
325  }
326 }
327 
328 prefix_ void senf::emu::WirelessNLController::nlPutChannelDef(nl_msg_ptr msg, frequency_type freq, ChannelMode::Enum channelMode)
329 {
330  NLA_PUT_U32 ( msg, NL80211_ATTR_WIPHY_FREQ, KHZ_TO_MHZ(freq));
331  if (channelType(channelMode) == NL80211_CHAN_NO_HT or channelType(channelMode) == NL80211_CHAN_HT20) {
332  NLA_PUT_U32 ( msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channelType(channelMode));
333  }
334  else {
335  NLA_PUT_U32 ( msg, NL80211_ATTR_CHANNEL_WIDTH, channelWidth(channelMode));
336  NLA_PUT_U32 ( msg, NL80211_ATTR_CENTER_FREQ1, KHZ_TO_MHZ(centerFreq(freq, channelMode)));
337  }
338 }
339 
340 prefix_ int senf::emu::WirelessNLController::netlink_cb(nl_msg * msg)
341 {
342  if (callback_)
343  return (this->*callback_)(msg);
344  return NL_SKIP;
345 }
346 
347 prefix_ std::pair<senf::emu::WirelessNLController::DFSState::Enum,std::uint32_t> senf::emu::WirelessNLController::dfsState(frequency_type freq)
348 {
349  getWiphy();
350  DFSStateMap::const_iterator state (dfsStates_.find(freq));
351  if (state != dfsStates_.end()) {
352  return state->second;
353  }
354  return std::make_pair(DFSState::NoDFS, 0);
355 }
356 
358 {
359  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_SET_WIPHY, CIB_PHY, NLM_F_ACK));
360 
361  nlPutChannelDef(msg, freq, channelMode);
362 
363  send_and_wait4response(msg);
364 }
365 
367 {
368  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_SET_WIPHY, CIB_PHY, NLM_F_ACK));
369 
370  NLA_PUT_U32( msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, setting);
371  if (setting != TxPowerSetting::Auto)
372  NLA_PUT_U32( msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mBm);
373 
374  send_and_wait4response(msg);
375 }
376 
377 prefix_ void senf::emu::WirelessNLController::set_retryLimit(boost::uint8_t shortLimit, boost::uint8_t longLimit)
378 {
379  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_SET_WIPHY, CIB_PHY, NLM_F_ACK));
380 
381  NLA_PUT_U8( msg, NL80211_ATTR_WIPHY_RETRY_LONG, longLimit);
382  NLA_PUT_U8( msg, NL80211_ATTR_WIPHY_RETRY_SHORT, shortLimit);
383 
384  send_and_wait4response(msg);
385 }
386 
388 {
389  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_RADAR_DETECT, CIB_IF, NLM_F_ACK));
390 
391  nlPutChannelDef(msg, freq, channelMode);
392 
393  send_and_wait4response(msg);
394 }
395 
397 {
398  if (alpha2Country.size() != 2)
399  throw InvalidArgumentException("invalid alpha2 country: ") << alpha2Country;
400 
401  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_REQ_SET_REG, CIB_NONE, NLM_F_ACK));
402 
403  NLA_PUT_STRING( msg, NL80211_ATTR_REG_ALPHA2, alpha2Country.c_str());
404 
405  send_and_wait4response(msg);
406 }
407 
409 {
410  if (regDomain.alpha2Country.size() != 2)
411  throw InvalidArgumentException("invalid alpha2 country: ") << regDomain.alpha2Country;
412 
413  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_SET_REG, CIB_NONE, NLM_F_ACK));
414 
415  NLA_PUT_STRING( msg, NL80211_ATTR_REG_ALPHA2, regDomain.alpha2Country.c_str());
416  NLA_PUT_U8 ( msg, NL80211_ATTR_DFS_REGION, underlying_type_cast(regDomain.dfsRegion));
417  {
418  nl_nested_attr_ptr msgAttr (msg, NL80211_ATTR_REG_RULES);
419  unsigned i = 0;
420  for (RegulatoryRule const & rule : regDomain.rules) {
421  nl_nested_attr_ptr params (msg, i); // crda-3.13 always passes i == 0 here, so let's do the same
422  NLA_PUT_U32( msg, NL80211_ATTR_REG_RULE_FLAGS, rule.flags());
423  NLA_PUT_U32( msg, NL80211_ATTR_FREQ_RANGE_START, rule.frequencyRangeBegin());
424  NLA_PUT_U32( msg, NL80211_ATTR_FREQ_RANGE_END, rule.frequencyRangeEnd());
425  NLA_PUT_U32( msg, NL80211_ATTR_FREQ_RANGE_MAX_BW, rule.maxBandwidth());
426  NLA_PUT_U32( msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, rule.maxAntennaGain());
427  NLA_PUT_U32( msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, rule.maxEIRP());
428  NLA_PUT_U32( msg, NL80211_ATTR_DFS_CAC_TIME, rule.cacTime());
429  }
430  }
431 
432  send_and_wait4response(msg);
433 }
434 
436 {
437  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_GET_REG, CIB_NONE, NLM_F_ACK));
438 
439  send_and_wait4response(msg, &WirelessNLController::getRegDomain_cb);
440 
441  return regDomain_;
442 }
443 
444 //
445 // should be called AFTER joinCell()
446 // queues: NL80211_TXQ_Q_VO, NL80211_TXQ_Q_VI, NL80211_TXQ_Q_BK, NL80211_TXQ_Q_BE;
447 //
449  boost::uint16_t cwMin, boost::uint16_t cwMax, boost::uint8_t aifs, boost::uint16_t txop)
450 {
451  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_SET_WIPHY, CIB_IF, NLM_F_ACK));
452 
453  {
454  nl_nested_attr_ptr msgAttr (msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
455  nl_nested_attr_ptr params (msg, 1);
456  NLA_PUT_U8 (msg, NL80211_TXQ_ATTR_QUEUE, queue);
457  NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cwMin);
458  NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cwMax);
459  NLA_PUT_U8 (msg, NL80211_TXQ_ATTR_AIFS, aifs);
460  NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, txop);
461  }
462 
463  send_and_wait4response(msg);
464 }
465 
466 namespace {
467  // WTF?!? NL80211_TXRATE_LEGACY requires "u8 values with 1 = 500 kbps", but
468  // NL80211_BITRATE_ATTR_RATE provides "units of 100 kbps". GRRR!
469  uint8_t transform_bitrate(uint32_t r) {
470  return r / 500;
471  }
472 }
473 
474 #define NLA_PUT_OPTIONAL_VECTOR(msg, attrtype, optvector) \
475  do { \
476  if (optvector) NLA_PUT( msg, attrtype, optvector->size(), \
477  optvector->empty() ? NULL : &(*optvector)[0]); \
478  } while (0);
479 
481 {
482  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_SET_TX_BITRATE_MASK, CIB_IF, NLM_F_ACK));
483 
484  // copy the sets to a vector to get continuous memory
485  typedef std::vector<uint8_t> LegacyBitrateVector;
486  boost::optional<LegacyBitrateVector> legacy_24, legacy_5;
487  typedef std::vector<BitrateParameters::MCSIndex> MCSIndexVector;
488  boost::optional<MCSIndexVector> mcs_24, mcs_5;
489  struct nl80211_txrate_vht txrate_vht_24, txrate_vht_5;
490 
491  if (p.legacy_24) {
492  legacy_24.reset( LegacyBitrateVector(p.legacy_24->size()));
493  std::transform(p.legacy_24->begin(), p.legacy_24->end(), legacy_24->begin(), transform_bitrate);
494  }
495  if (p.legacy_5) {
496  legacy_5.reset( LegacyBitrateVector(p.legacy_5->size()));
497  std::transform(p.legacy_5->begin(), p.legacy_5->end(), legacy_5->begin(), transform_bitrate);
498  }
499  if (p.mcs_24) {
500  mcs_24.reset(MCSIndexVector(p.mcs_24->size()));
501  std::copy(p.mcs_24->begin(), p.mcs_24->end(), mcs_24->begin());
502  }
503  if (p.mcs_5) {
504  mcs_5.reset(MCSIndexVector(p.mcs_5->size()));
505  std::copy(p.mcs_5->begin(), p.mcs_5->end(), mcs_5->begin());
506  }
507  if (p.vht_mcs_table_24) {
508  for (int nss = 0; nss < NL80211_VHT_NSS_MAX; nss++)
509  txrate_vht_24.mcs[nss] = p.vht_mcs_table_24->at(nss).to_ulong();
510  }
511  if (p.vht_mcs_table_5) {
512  for (int nss = 0; nss < NL80211_VHT_NSS_MAX; nss++)
513  txrate_vht_5.mcs[nss] = p.vht_mcs_table_5->at(nss).to_ulong();
514  }
515  {
516  nl_nested_attr_ptr msgAttr (msg, NL80211_ATTR_TX_RATES);
517  if (legacy_24 or mcs_24 or p.vht_mcs_table_24 or p.gi_24) {
518  nl_nested_attr_ptr bandAttr (msg, NL80211_BAND_2GHZ);
521  if (p.vht_mcs_table_24)
522  NLA_PUT ( msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_24), &txrate_vht_24);
523  if (p.gi_24)
524  NLA_PUT_U8 ( msg, NL80211_TXRATE_GI, p.gi_24.get());
525  }
526  if (legacy_5 or mcs_5 or p.vht_mcs_table_5 or p.gi_5) {
527  nl_nested_attr_ptr bandAttr (msg, NL80211_BAND_5GHZ);
530  if (p.vht_mcs_table_5)
531  NLA_PUT ( msg, NL80211_TXRATE_VHT, sizeof(txrate_vht_5), &txrate_vht_5);
532  if (p.gi_5)
533  NLA_PUT_U8 ( msg, NL80211_TXRATE_GI, p.gi_5.get());
534  }
535  }
536 
537  send_and_wait4response(msg);
538 }
539 
540 prefix_ std::set<senf::emu::WirelessNLController::Band_t> const & senf::emu::WirelessNLController::supportedBands()
541 {
542  getWiphy();
543  return supportedBands_;
544 }
545 
547 {
548  getWiphy();
549  return bitrates_;
550 }
551 
553 {
554  getWiphy();
555  return senf::make_transform_range(frequencies_,
556  ::__gnu_cxx::select2nd<Frequencies::value_type>());
557 }
558 
560 {
561  getWiphy();
562  return senf::make_transform_range(frequencies_.equal_range(band),
563  ::__gnu_cxx::select2nd<Frequencies::value_type>());
564 }
565 
566 namespace {
567 # define BIT(x) (1ULL<<(x))
568  using namespace senf::emu;
569 
570  HTCapabilitiesInfo parseHTCapabilities(uint16_t flags)
571  {
572  HTCapabilitiesInfo capInfo;
573  capInfo.rxLDPC = flags & BIT(0);
574  capInfo.channelWidth = HTCapabilitiesInfo::ChannelWidth( flags & BIT(1));
575  capInfo.smPowerSave = HTCapabilitiesInfo::SMPowerSave( (flags >> 2) & 0x3);
576  capInfo.rxGreenfield = flags & BIT(4);
577  capInfo.rxHT20SGI = flags & BIT(5);
578  capInfo.rxHT40SGI = flags & BIT(6);
579  capInfo.txSTBC = flags & BIT(7);
580  capInfo.rxSTBC = HTCapabilitiesInfo::RXSTBC( (flags >> 8) & 0x3);
581  capInfo.delayedBlockAck = flags & BIT(10);
582  capInfo.maxAMSDULength = HTCapabilitiesInfo::MaxAMSDULength( flags & BIT(11));
583  capInfo.ht40DSSS_CCK = flags & BIT(12);
584  // BIT(13) is reserved
585  capInfo.fortyMHzIntolerant = flags & BIT(14);
586  capInfo.lSIG_TXOP_Protection = flags & BIT(15);
587  return capInfo;
588  }
589 
590  VHTCapabilitiesInfo parseVHTCapabilities(uint32_t flags)
591  {
592  VHTCapabilitiesInfo capInfo;
595  capInfo.rxLDPC = flags & BIT(4);
596  capInfo.shortGIfor80MHz = flags & BIT(5);
597  capInfo.shortGIfor160_8080MHz = flags & BIT(6);
598  capInfo.txSTBC = flags & BIT(7);
599  capInfo.suBeamformer = flags & BIT(11);
600  capInfo.suBeamformee = flags & BIT(12);
601  capInfo.suBeamformer = flags & BIT(19);
602  capInfo.suBeamformee = flags & BIT(20);
603  capInfo.vhtTxOpPowerSave = flags & BIT(21);
604  capInfo.htc_vhtCapable = flags & BIT(22);
605  capInfo.rxAntennaPatternConsistency = flags & BIT(28);
606  capInfo.txAntennaPatternConsistency = flags & BIT(29);
607  return capInfo;
608  };
609 
610 # undef BIT
611 }
612 
613 #define GET_RULE_ATTR_OR_SKIP( var, attr ) \
614  std::uint32_t var; \
615  if (not ruleAttr[attr]) continue; \
616  var = nla_get_u32(ruleAttr[attr]);
617 
618 prefix_ int senf::emu::WirelessNLController::getRegDomain_cb(nl_msg * msg)
619 {
620  nlattr * ruleAttr[NL80211_FREQUENCY_ATTR_MAX + 1];
621  nlattr * msgAttr[NL80211_ATTR_MAX + 1];
622 
623  genlmsghdr * msgHdr = reinterpret_cast<genlmsghdr *>(nlmsg_data(nlmsg_hdr(msg)));
624  nla_parse(msgAttr, NL80211_ATTR_MAX, genlmsg_attrdata(msgHdr, 0), genlmsg_attrlen(msgHdr, 0), NULL);
625 
626  regDomain_ = RegulatoryDomain();
627 
628  if (not msgAttr[NL80211_ATTR_REG_ALPHA2] or not msgAttr[NL80211_ATTR_REG_RULES])
629  return NL_SKIP;
630 
631  char * alpha2 = reinterpret_cast<char *>(nla_data(msgAttr[NL80211_ATTR_REG_ALPHA2]));
632  regDomain_.alpha2Country = std::string(alpha2, 2);
633 
634  if (msgAttr[NL80211_ATTR_DFS_REGION])
635  regDomain_.dfsRegion = RegulatoryDomain::DFSRegion(nla_get_u8(msgAttr[NL80211_ATTR_DFS_REGION]));
636  else
637  regDomain_.dfsRegion = RegulatoryDomain::DFSRegion::Unset;
638 
639  FOREACH_NESTED_ATTR( rule, msgAttr[NL80211_ATTR_REG_RULES] ) {
640  nla_parse(ruleAttr, NL80211_FREQUENCY_ATTR_MAX, nla_attr_data(rule), nla_len(rule), NLAttributePolicies::regRulePolicy);
641 
649 
650  regDomain_.rules.insert( RegulatoryRule()
651  .frequencyRange(start_freq_khz, end_freq_khz)
652  .maxBandwidth(max_bw_khz)
653  .maxAntennaGain(max_ant_gain_mbi)
654  .maxEIRP(max_eirp_mbm)
655  .cacTime(cac_time_ms)
656  .flags(flags) );
657  }
658 
659  return NL_OK;
660 }
661 
662 prefix_ int senf::emu::WirelessNLController::getWiphy_cb(nl_msg * msg)
663 {
664 // std::cout << "getWiphy_cb " << int(firstMutlipartMsg_) << std::endl;
665 // nl_msg_dump(msg, stdout);
666  nlattr * msgAttr[NL80211_ATTR_MAX + 1];
667  nlattr * bandAttr[NL80211_BAND_ATTR_MAX + 1];
668  nlattr * freqAttr[NL80211_FREQUENCY_ATTR_MAX + 1];
669  nlattr * rateAttr[NL80211_BITRATE_ATTR_MAX + 1];
670  uint16_t htCapa = 0;
671  uint32_t vhtCapa = 0;
672 
673  genlmsghdr * msgHdr = reinterpret_cast<genlmsghdr *>(nlmsg_data(nlmsg_hdr(msg)));
674  nla_parse(msgAttr, NL80211_ATTR_MAX, genlmsg_attrdata(msgHdr, 0), genlmsg_attrlen(msgHdr, 0), NULL);
675 
676 // if (! msgAttr[NL80211_ATTR_WIPHY_BANDS])
677 // return NL_SKIP;
678 
679  if (firstMutlipartMsg_) {
680  firstMutlipartMsg_ = false;
681  bitrates_ = BitrateParameters();
682  frequencies_.clear();
683  supportedBands_.clear();
684  dfsStates_.clear();
685  bandtype_ = -1;
686  tmpMCSRates_.reset();
687  tmpLegacyRates_.reset();
688  coverageClass_ = 0;
689  }
690 
691  // detail::dumpMsgAttributes(msgAttr, std::cout);
692 
693  bool firstBand (true);
695  nla_parse(bandAttr, NL80211_BAND_ATTR_MAX, nla_attr_data(band), nla_len(band), NULL);
696 
697 // detail::dumpBandAttributes(bandAttr, std::cout);
698 
699  // iterate over frequencies
701  nla_parse(freqAttr, NL80211_FREQUENCY_ATTR_MAX, nla_attr_data(freq), nla_len(freq),
702  NLAttributePolicies::freqPolicy);
703  if (not freqAttr[NL80211_FREQUENCY_ATTR_FREQ])
704  continue;
705  uint32_t f (nla_get_u32(freqAttr[NL80211_FREQUENCY_ATTR_FREQ]));
706 // if (freqAttr[NL80211_FREQUENCY_ATTR_RADAR])
707 // std::cout << f << " RADAR\n";
708  bandtype_ = f < 3000 ? BAND_2GHZ : BAND_5GHZ;
709  if (freqAttr[NL80211_FREQUENCY_ATTR_DISABLED])
710  continue;
711  frequencies_.insert( std::make_pair( Band_t(bandtype_), MHZ_TO_KHZ(f)));
712 
713 // detail::dumpFreqAttributes(freqAttr, std::cout);
714 
715  if (freqAttr[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
716  uint32_t state = nla_get_u32(freqAttr[NL80211_FREQUENCY_ATTR_DFS_STATE]);
717  uint32_t time = nla_get_u32(freqAttr[NL80211_FREQUENCY_ATTR_DFS_TIME]);
718  dfsStates_[MHZ_TO_KHZ(f)] = std::make_pair(DFSState::Enum(state), time);
719  }
720  }
721 
722  if (bandtype_ != -1) {
723  supportedBands_.insert( Band_t(bandtype_));
724  switch (bandtype_) {
725  case BAND_2GHZ:
726  if (tmpLegacyRates_) bitrates_.legacy_24 = tmpLegacyRates_;
727  if (tmpMCSRates_) bitrates_.mcs_24 = tmpMCSRates_;
728  break;
729  case BAND_5GHZ:
730  if (tmpLegacyRates_) bitrates_.legacy_5 = tmpLegacyRates_;
731  if (tmpMCSRates_) bitrates_.mcs_5 = tmpMCSRates_;
732  break;
733  }
734  }
735 
736  // iterate over bitrates
737  FOREACH_NESTED_ATTR( rate, bandAttr[NL80211_BAND_ATTR_RATES] ) {
738  nla_parse(rateAttr, NL80211_BITRATE_ATTR_MAX, nla_attr_data(rate), nla_len(rate),
739  NLAttributePolicies::ratePolicy);
740  if (rateAttr[NL80211_BITRATE_ATTR_RATE]) {
741  uint32_t r (nla_get_u32(rateAttr[NL80211_BITRATE_ATTR_RATE]));
742  switch (bandtype_) {
743  case -1:
744  get_optional_value(tmpLegacyRates_).insert( r*100);
745  break;
746  case BAND_2GHZ:
747  get_optional_value(bitrates_.legacy_24).insert( r*100);
748  break;
749  case BAND_5GHZ:
750  get_optional_value(bitrates_.legacy_5).insert( r*100);
751  break;
752  }
753  }
754  }
755 
756  // to simplify the HT capabilities handling we assume that all bands have the same capabilities
757  // otherwise log an important message and use the first one
758  if (bandAttr[NL80211_BAND_ATTR_HT_CAPA]) {
759  uint16_t bandHTCapa (nla_get_u16( bandAttr[NL80211_BAND_ATTR_HT_CAPA]));
760  if (firstBand) {
761  htCapabilities_ = parseHTCapabilities(bandHTCapa);
762  hasHTCapabilities_ = true;
763  htCapa = bandHTCapa;
764  }
765  if (bandHTCapa != htCapa)
766  SENF_LOG((senf::log::IMPORTANT) ("not all bands have the same HT Capabilities; using only the first one!"));
767  }
768  if (bandAttr[NL80211_BAND_ATTR_VHT_CAPA]) {
769  uint32_t bandVHTCapa (nla_get_u32( bandAttr[NL80211_BAND_ATTR_VHT_CAPA]));
770  if (firstBand) {
771  vhtCapabilities_ = parseVHTCapabilities(bandVHTCapa);
772  hasVHTCapabilities_ = true;
773  vhtCapa = bandVHTCapa;
774  }
775  if (bandVHTCapa != vhtCapa)
776  SENF_LOG((senf::log::IMPORTANT) ("not all bands have the same VHT Capabilities; using only the first one!"));
777  }
778  if (bandAttr[NL80211_BAND_ATTR_VHT_MCS_SET]) {
779  unsigned char * mcs (reinterpret_cast<unsigned char*>(nla_data(bandAttr[NL80211_BAND_ATTR_VHT_MCS_SET])));
780  boost::uint16_t tmp = mcs[0] | (mcs[1] << 8);
781  BitrateParameters::VHT_MCSBitmapTable & mcsBitmapTable (get_optional_value(
782  bandtype_ == BAND_2GHZ ? bitrates_.vht_mcs_table_24 : bitrates_.vht_mcs_table_5));
783  for (int nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
784  switch ((tmp >> (nss * 2)) & 3) {
785  case 0:
786  mcsBitmapTable[nss] = 0xff; // MCS 0-7
787  break;
788  case 1:
789  mcsBitmapTable[nss] = 0x1ff; // MCS 0-8
790  break;
791  case 2:
792  mcsBitmapTable[nss] = 0x3ff; // MCS 0-9
793  break;
794  case 3:
795  break; /* not supported */
796  }
797  }
798  }
799  if (bandAttr[NL80211_BAND_ATTR_HT_MCS_SET] && nla_len(bandAttr[NL80211_BAND_ATTR_HT_MCS_SET]) == 16) {
800  unsigned char * mcs (reinterpret_cast<unsigned char*>(nla_data(bandAttr[NL80211_BAND_ATTR_HT_MCS_SET])));
801  if (!(mcs[12] & (1 << 0))) { // tx_mcs_set_defined=0
802  SENF_LOG((senf::log::IMPORTANT) ("HT RX *only* MCS rate indexes not supported"));
803  continue;
804  }
805  if (mcs[12] & (1 << 1)) { // tx_rx_mcs_set_not_equal=1
806  SENF_LOG((senf::log::IMPORTANT) ("unequal HT RX/TX MCS rate indexes not supported"));
807  continue;
808  }
809  for (unsigned mcs_bit = 0; mcs_bit <= 76; ++mcs_bit) {
810  if (!!(mcs[mcs_bit/8] & (1 << mcs_bit % 8))) {
811  switch (bandtype_) {
812  case -1:
813  get_optional_value(tmpMCSRates_).insert( mcs_bit);
814  break;
815  case BAND_2GHZ:
816  get_optional_value(bitrates_.mcs_24).insert( mcs_bit);
817  break;
818  case BAND_5GHZ:
819  get_optional_value(bitrates_.mcs_5).insert( mcs_bit);
820  break;
821  }
822  }
823  }
824  }
825 
826  firstBand = false;
827  }
828 
829  if (msgAttr[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
830  coverageClass_ = nla_get_u8(msgAttr[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
831  }
832 
833  return NL_OK;
834 }
835 
836 prefix_ void senf::emu::WirelessNLController::getWiphy()
837 {
838  firstMutlipartMsg_ = true;
839 
840  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_GET_WIPHY, CIB_PHY, NLM_F_DUMP));
841  NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
842 
843  send_and_wait4response(msg, &WirelessNLController::getWiphy_cb);
844 }
845 
846 prefix_ int senf::emu::WirelessNLController::getSurvey_cb(nl_msg * msg)
847 {
848  nlattr * msgAttr[NL80211_ATTR_MAX + 1];
849  nlattr * sinfo[NL80211_SURVEY_INFO_MAX + 1];
850 
851  genlmsghdr * msgHdr = reinterpret_cast<genlmsghdr *>(nlmsg_data(nlmsg_hdr(msg)));
852  nla_parse(msgAttr, NL80211_ATTR_MAX, genlmsg_attrdata(msgHdr, 0), genlmsg_attrlen(msgHdr, 0), NULL);
853 
854  if (not msgAttr[NL80211_ATTR_SURVEY_INFO])
855  return NL_SKIP;
856 
857  if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, msgAttr[NL80211_ATTR_SURVEY_INFO],
858  NLAttributePolicies::surveyPolicy) != 0)
859  return NL_SKIP;
860 
861  Survey survey (!!sinfo[NL80211_SURVEY_INFO_IN_USE]);
862 
864  survey.frequency = MHZ_TO_KHZ(nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]));
865  if (sinfo[NL80211_SURVEY_INFO_NOISE])
866  survey.noise = nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
868  survey.channelTime = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
870  survey.channelTimeBusy = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
872  survey.channelTimeExtBusy = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY]);
874  survey.channelTimeRx = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
876  survey.channelTimeTx = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
877 
878  survey_.insert(survey);
879 
880  return NL_SKIP;
881 }
882 
883 prefix_ std::set<senf::emu::WirelessNLController::Survey> const & senf::emu::WirelessNLController::survey()
884 {
885  survey_.clear();
886  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_GET_SURVEY, CIB_IF, NLM_F_DUMP));
887  send_and_wait4response(msg, &WirelessNLController::getSurvey_cb);
888  return survey_;
889 }
890 
892 {
893  for (auto const & s : survey()) {
894  if (s.inUse)
895  return s.frequency;
896  }
897 
898  return 0;
899 }
900 
902 {
903  switch (type) {
904  case Unspecified: return "unspecified";
905  case AdHoc: return "IBSS";
906  case Station: return "managed";
907  case AP: return "AP";
908  case APVLan: return "AP/VLAN";
909  case WDS: return "WDS";
910  case Monitor: return "monitor";
911  case MeshPoint: return "mesh point";
912  case Unknown: return "unknown mode";
913  }
914  return "Unknown mode (" + senf::str(type) + ")";
915 }
916 
918 {
919  switch (state) {
920  case NoDFS: return "NoDFS";
921  case Usable: return "Usable";
922  case Unavailable: return "Unavailable";
923  case Available: return "Available";
924  }
925  return "Unknown state (" + senf::str(state) + ")";
926 }
927 
928 prefix_ int senf::emu::WirelessNLController::getIface_cb(nl_msg * msg)
929 {
930  nlattr * msgAttr[NL80211_ATTR_MAX + 1];
931 
932  genlmsghdr * msgHdr = reinterpret_cast<genlmsghdr *>(nlmsg_data(nlmsg_hdr(msg)));
933  nla_parse(msgAttr, NL80211_ATTR_MAX, genlmsg_attrdata(msgHdr, 0), genlmsg_attrlen(msgHdr, 0), NULL);
934 
935  if (msgAttr[NL80211_ATTR_IFTYPE]) {
936  uint32_t type (nla_get_u32(msgAttr[NL80211_ATTR_IFTYPE]));
937  ifaceType_ = type < IfaceType::Unknown ? IfaceType::Enum(type) : IfaceType::Unknown;
938  }
939  return NL_OK;
940 }
941 
943 {
944  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_GET_INTERFACE, CIB_IF));
945  send_and_wait4response(msg, &WirelessNLController::getIface_cb);
946  return ifaceType_;
947 }
948 
950 {
951  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_SET_INTERFACE, CIB_IF, NLM_F_ACK));
952 
953  switch (type) {
954  case IfaceType::Enum::AdHoc:
955  NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_ADHOC);
956  break;
957  case IfaceType::Enum::Station:
958  NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION);
959  break;
960  case IfaceType::Enum::AP:
961  NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP);
962  break;
963  case IfaceType::Enum::APVLan:
964  NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP_VLAN);
965  break;
966  case IfaceType::Enum::WDS:
967  NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_WDS);
968  break;
969  case IfaceType::Enum::Monitor:
970  NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
971  break;
972  case IfaceType::Enum::MeshPoint:
974  break;
975  case IfaceType::Enum::Unspecified:
976  case IfaceType::Enum::Unknown:
977  default:
978  throw senf::SystemException( "Unknown interface type ", EINVAL) << unsigned(type);
979  break;
980  }
981 
982  send_and_wait4response(msg);
983 }
984 
985 
986 prefix_ void senf::emu::WirelessNLController::add_monInterface(std::string const & name, int flags)
987 {
988  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_NEW_INTERFACE, CIB_PHY, NLM_F_ACK));
989 
990  NLA_PUT_STRING( msg, NL80211_ATTR_IFNAME, name.c_str());
991  NLA_PUT_U32 ( msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
992  nl_msg_ptr flagMsg (nlMsg());
993  for (int flag = 0; flag <= NL80211_MNTR_FLAG_MAX; ++flag) {
994  if (flags & (1 << flag))
995  NLA_PUT_FLAG(flagMsg, flag);
996  }
997  NLA_PUT_NESTED( msg, NL80211_ATTR_MNTR_FLAGS, flagMsg);
998 
999  send_and_wait4response(msg);
1000 }
1001 
1003 {
1004  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_NEW_INTERFACE, CIB_PHY, NLM_F_ACK));
1005 
1006  NLA_PUT_STRING( msg, NL80211_ATTR_IFNAME, name.c_str());
1007  NLA_PUT_U32 ( msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_ADHOC);
1008 
1009  send_and_wait4response(msg);
1010 }
1011 
1013 {
1014  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_NEW_INTERFACE, CIB_PHY, NLM_F_ACK));
1015 
1016  NLA_PUT_STRING( msg, NL80211_ATTR_IFNAME, name.c_str());
1017  NLA_PUT_U32 ( msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP);
1018 
1019  send_and_wait4response(msg);
1020 }
1021 
1022 prefix_ void senf::emu::WirelessNLController::add_meshInterface(std::string const & name, std::string const & meshId)
1023 {
1024  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_NEW_INTERFACE, CIB_PHY, NLM_F_ACK));
1025 
1026  NLA_PUT_STRING( msg, NL80211_ATTR_IFNAME, name.c_str());
1027  NLA_PUT_U32 ( msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MESH_POINT);
1028  if (not meshId.empty())
1029  NLA_PUT( msg, NL80211_ATTR_MESH_ID, meshId.length(), meshId.c_str());
1030 
1031  send_and_wait4response(msg);
1032 }
1033 
1034 
1036 {
1037  int ifindex = if_nametoindex(name.c_str());
1038  if (!ifindex) {
1039  throw senf::SystemException( "Could not discover the index of interface ", EINVAL) << name;
1040  }
1041 
1042  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_DEL_INTERFACE, CIB_NONE, NLM_F_ACK));
1043  NLA_PUT_U32( msg, NL80211_ATTR_IFINDEX, ifindex);
1044 
1045  send_and_wait4response(msg);
1046 }
1047 
1049  const
1050 {
1051  IfaceNameSet ifaceNames;
1052  // search for all wireless interfaces with our phy index
1053  boost::filesystem::directory_iterator end_itr;
1054  for (boost::filesystem::directory_iterator itr ("/sys/class/net"); itr != end_itr; ++itr ) {
1055  // hmpf.
1056 # if BOOST_FILESYSTEM_VERSION == 3
1057  std::string ifname (itr->path().filename().string());
1058 # else
1059  std::string ifname (itr->path().filename());
1060 # endif
1061  if (if_nameto_phy_index(ifname) == phyIndex_)
1062  ifaceNames.insert( ifname);
1063  }
1064  return ifaceNames;
1065 }
1066 
1068 {
1069  return std::min( ((distance + 449) / 450), 255u);
1070 }
1071 
1073 {
1074  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_SET_WIPHY, CIB_PHY, NLM_F_ACK));
1075 
1076  NLA_PUT_U8( msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, std::min( coverage, 255u));
1077 
1078  send_and_wait4response(msg);
1079 }
1080 
1082 {
1083  getWiphy();
1084  return coverageClass_;
1085 }
1086 
1088 {
1089  getWiphy();
1090  return hasHTCapabilities_;
1091 }
1092 
1094 {
1095  getWiphy();
1096  return hasVHTCapabilities_;
1097 }
1098 
1100 {
1101  getWiphy();
1102  return htCapabilities_;
1103 }
1104 
1106 {
1107  getWiphy();
1108  return vhtCapabilities_;
1109 }
1110 
1111 namespace {
1112  template <typename T>
1113  T readTokenFromFile(boost::filesystem::path const & path)
1114  {
1115  boost::filesystem::ifstream file;
1116  file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
1117  file.open(path, std::ios::in);
1118  T token;
1119  file >> token;
1120  file.close();
1121  return token;
1122  }
1123 
1124  int readIntFromFile(boost::filesystem::path const & path)
1125  {
1126  try {
1127  return readTokenFromFile<int>(path);
1128  } catch (std::exception & e) {}
1129  return -1;
1130  }
1131 
1132  std::string readStringFromFile(boost::filesystem::path const & path)
1133  {
1134  try {
1135  return readTokenFromFile<std::string>(path);
1136  } catch (std::exception & e) {}
1137  return "";
1138  }
1139 
1140  namespace fs = ::boost::filesystem;
1141 
1142  senf::MACAddress readMACAddressFromFile(fs::path const & path)
1143  {
1144  fs::ifstream file;
1145  file.exceptions( std::ifstream::failbit | std::ifstream::badbit);
1146  file.open(path, std::ios::in);
1147  senf::MACAddress addr;
1148  file >> addr;
1149  file.close();
1150  return addr;
1151  }
1152 }
1153 
1155 {
1156  return readIntFromFile(
1157  boost::filesystem::path("/sys/class/net")/ifname/"phy80211/index");
1158 }
1159 
1161 {
1162  return readIntFromFile(
1163  boost::filesystem::path("/sys/class/ieee80211")/phyname/"index");
1164 }
1165 
1166 prefix_ std::string senf::emu::WirelessNLController::if_nameto_phy_name(std::string const & ifname)
1167 {
1168  return readStringFromFile(
1169  boost::filesystem::path("/sys/class/net")/ifname/"phy80211/name");
1170 }
1171 
1173 {
1174  fs::directory_iterator end_itr;
1175  for (fs::directory_iterator itr ("/sys/class/ieee80211/"); itr != end_itr; ++itr) {
1176  try {
1177  if (readMACAddressFromFile(itr->path()/"macaddress") == mac)
1178  return itr->path().filename().string();
1179  } catch (std::exception &) {}
1180  }
1181  return "unknown mac";
1182 }
1183 
1185 {
1186  switch (channelMode) {
1187  case ChannelMode::NoHT20:
1189  case ChannelMode::HT20:
1190  return NL80211_CHAN_WIDTH_20;
1192  case ChannelMode::HT40Plus:
1193  return NL80211_CHAN_WIDTH_40;
1194  case ChannelMode::VHT80:
1195  return NL80211_CHAN_WIDTH_80;
1196  }
1197  throw InvalidArgumentException("invalid channelMode ") << channelMode;
1198 }
1199 
1201 {
1202  switch (channelMode) {
1203  case ChannelMode::NoHT20:
1204  return NL80211_CHAN_NO_HT;
1205  case ChannelMode::HT20:
1206  return NL80211_CHAN_HT20;
1208  return NL80211_CHAN_HT40MINUS;
1209  case ChannelMode::HT40Plus:
1210  return NL80211_CHAN_HT40PLUS;
1211  case ChannelMode::VHT80:
1212  return -1;
1213  }
1214  throw InvalidArgumentException("invalid channelMode ") << channelMode;
1215 }
1216 
1218  frequency_type freq, ChannelMode::Enum channelMode)
1219 {
1220  unsigned int vht80[] = {
1221  MHZ_TO_KHZ(4920), MHZ_TO_KHZ(5180), MHZ_TO_KHZ(5260), MHZ_TO_KHZ(5500),
1222  MHZ_TO_KHZ(5580), MHZ_TO_KHZ(5660), MHZ_TO_KHZ(5745) };
1223  unsigned j;
1224 
1225  switch (channelMode) {
1226  case ChannelMode::NoHT20:
1227  case ChannelMode::HT20:
1228  return freq;
1230  return freq - MHZ_TO_KHZ(10);
1231  case ChannelMode::HT40Plus:
1232  return freq + MHZ_TO_KHZ(10);
1233  case ChannelMode::VHT80:
1234  for (j = 0; j < ARRAY_SIZE(vht80); j++) {
1235  if (freq >= vht80[j] && freq < vht80[j] + MHZ_TO_KHZ(80))
1236  break;
1237  }
1238  if (j == ARRAY_SIZE(vht80))
1239  throw InvalidArgumentException("invalid frequency ") << freq;
1240  return vht80[j] + MHZ_TO_KHZ(30);
1241  }
1242  throw InvalidArgumentException("invalid channelMode ") << channelMode;
1243 }
1244 
1245 
1247 {
1248  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_LEAVE_MESH, CIB_IF, NLM_F_ACK));
1249  send_and_wait4response(msg);
1250 }
1251 
1252 prefix_ senf::emu::WirelessNLController::MeshJoinParameters::ptr senf::emu::WirelessNLController::mesh_join(
1253  std::string const & meshId, frequency_type freq, ChannelMode::Enum channelMode, bool & success)
1254 {
1255  return JoinParameters::ptr(new MeshJoinParameters(
1256  membind(&WirelessNLController::do_mesh_join, this), meshId, freq, channelMode, success) );
1257 }
1258 
1259 prefix_ void senf::emu::WirelessNLController::do_mesh_join(JoinParameters const & jp)
1260 {
1261  MeshJoinParameters const & parameters (static_cast<MeshJoinParameters const &>(jp));
1262  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_JOIN_MESH, CIB_IF, NLM_F_ACK));
1263 
1264  NLA_PUT( msg, NL80211_ATTR_MESH_ID, parameters.meshId_.length(), parameters.meshId_.c_str());
1265 
1266  nlPutChannelDef(msg, parameters.freq_, parameters.channelMode_);
1267 
1268  if (parameters.beaconInterval_)
1269  NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, parameters.beaconInterval_.get());
1270 
1271  if (parameters.handleDFS_)
1272  NLA_PUT_FLAG(msg, NL80211_ATTR_HANDLE_DFS);
1273 
1274  if (parameters.htCapabilities_) {
1276  sizeof(parameters.htCapabilities_.get()),
1277  parameters.htCapabilities_.get_ptr());
1279  sizeof(parameters.htCapabilitiesMask_.get()),
1280  parameters.htCapabilitiesMask_.get_ptr());
1281  }
1282 
1283  {
1284  nl_nested_attr_ptr msgAttr (msg, NL80211_ATTR_MESH_SETUP);
1285  if (! boost::empty(parameters.ies_))
1286  NLA_PUT( msg, NL80211_MESH_SETUP_IE, boost::size(parameters.ies_), &(*boost::begin(parameters.ies_)));
1287  if (parameters.vendorMetric_)
1288  NLA_PUT_U8( msg, NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC, parameters.vendorMetric_.get());
1289  if (parameters.vendorPathSelection_)
1290  NLA_PUT_U8( msg, NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL, parameters.vendorPathSelection_.get());
1291  if (parameters.vendorSynchronization_)
1292  NLA_PUT_U8( msg, NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, parameters.vendorSynchronization_.get());
1293  }
1294 
1295  send_and_wait4response(msg);
1296 }
1297 
1299 {
1300  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_LEAVE_IBSS, CIB_IF, NLM_F_ACK));
1301  send_and_wait4response(msg);
1302 }
1303 
1304 prefix_ senf::emu::WirelessNLController::IbssJoinParameters::ptr senf::emu::WirelessNLController::ibss_join(
1305  std::string const & ssid, frequency_type freq, ChannelMode::Enum channelMode, bool & success)
1306 {
1307  return JoinParameters::ptr( new IbssJoinParameters(
1308  membind(&WirelessNLController::do_ibss_join, this), ssid, freq, channelMode, success) );
1309 }
1310 
1311 prefix_ void senf::emu::WirelessNLController::do_ibss_join(JoinParameters const & jp)
1312 {
1313  IbssJoinParameters const & parameters (static_cast<IbssJoinParameters const &>(jp));
1314  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_JOIN_IBSS, CIB_IF, NLM_F_ACK));
1315 
1316  NLA_PUT( msg, NL80211_ATTR_SSID, parameters.ssid_.length(), parameters.ssid_.c_str());
1317 
1318  nlPutChannelDef(msg, parameters.freq_, parameters.channelMode_);
1319 
1320  NLA_PUT_FLAG( msg, NL80211_ATTR_FREQ_FIXED);
1321 
1322  if (parameters.handleDFS_)
1323  NLA_PUT_FLAG(msg, NL80211_ATTR_HANDLE_DFS);
1324 
1325  if (! boost::empty(parameters.ies_))
1326  NLA_PUT( msg, NL80211_ATTR_IE, boost::size(parameters.ies_), &(*boost::begin(parameters.ies_)));
1327 
1328  if (parameters.bssid_)
1329  NLA_PUT( msg, NL80211_ATTR_MAC, 6, &parameters.bssid_);
1330 
1331  if (parameters.beaconInterval_)
1332  NLA_PUT_U32( msg, NL80211_ATTR_BEACON_INTERVAL, parameters.beaconInterval_.get());
1333 
1334  if (parameters.htCapabilities_) {
1336  sizeof(parameters.htCapabilities_.get()),
1337  parameters.htCapabilities_.get_ptr());
1339  sizeof(parameters.htCapabilitiesMask_.get()),
1340  parameters.htCapabilitiesMask_.get_ptr());
1341  }
1342 
1343  send_and_wait4response(msg);
1344 }
1345 
1346 prefix_ void senf::emu::WirelessNLController::do_trigger_scan(std::set<frequency_type> const & frequencies, std::set<std::string> const & ssids)
1347 {
1348  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_TRIGGER_SCAN, CIB_IF, NLM_F_ACK));
1349 
1350  if (not ssids.empty()) {
1351  nl_msg_ptr ms (nlMsg());
1352  for (auto const & s : ssids){
1353  NLA_PUT(ms, NL80211_SCHED_SCAN_MATCH_ATTR_SSID, strlen(s.c_str()), s.c_str());
1354  }
1356  }
1357 
1358  if (not frequencies.empty()) {
1359  nl_msg_ptr freqs (nlMsg());
1360  int i = 1;
1361  for (frequency_type const & f : frequencies)
1362  NLA_PUT_U32(freqs, i++, KHZ_TO_MHZ(f));
1364  }
1365 
1366  send(msg);
1367 }
1368 
1369 prefix_ std::multiset<senf::emu::WirelessNLController::ScanResults> const & senf::emu::WirelessNLController::getScan()
1370 {
1371  scanResults_.clear();
1372  nl_msg_ptr msg (nlMsgHeader( NL80211_CMD_GET_SCAN, CIB_IF, NLM_F_DUMP));
1373  send_and_wait4response(msg, &WirelessNLController::getScan_cb);
1374  return scanResults_;
1375 }
1376 
1377 prefix_ int senf::emu::WirelessNLController::getScan_cb(nl_msg * msg)
1378 {
1379  nlattr * msgAttr[NL80211_ATTR_MAX + 1];
1380  nlattr * bss[NL80211_BSS_MAX + 1];
1381 
1382  genlmsghdr * msgHdr = reinterpret_cast<genlmsghdr *>(nlmsg_data(nlmsg_hdr(msg)));
1383  nla_parse(msgAttr, NL80211_ATTR_MAX, genlmsg_attrdata(msgHdr, 0), genlmsg_attrlen(msgHdr, 0), NULL);
1384 
1385  if (not msgAttr[NL80211_ATTR_BSS])
1386  return NL_SKIP;
1387 
1388  if (nla_parse_nested(bss, NL80211_BSS_MAX, msgAttr[NL80211_ATTR_BSS],
1389  NLAttributePolicies::bssPolicy) != 0)
1390  return NL_SKIP;
1391 
1392  if (!bss[NL80211_BSS_BSSID])
1393  return NL_SKIP;
1394 
1395  ScanResults res(bss[NL80211_BSS_BSSID] ? senf::MACAddress::from_data((char*)nla_data(bss[NL80211_BSS_BSSID])) : senf::MACAddress::None);
1396  if (bss[NL80211_BSS_TSF])
1397  res.tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
1398  if (bss[NL80211_BSS_FREQUENCY])
1399  res.frequency = MHZ_TO_KHZ(nla_get_u32(bss[NL80211_BSS_FREQUENCY]));
1400  if (bss[NL80211_BSS_BEACON_INTERVAL])
1401  res.beaconInterval = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
1402  if (bss[NL80211_BSS_CAPABILITY])
1403  res.capability = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
1404  if (bss[NL80211_BSS_SIGNAL_MBM])
1405  res.signal = int(nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM])) / 100;
1406  if (bss[NL80211_BSS_SIGNAL_UNSPEC])
1407  res.signalUnspec = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
1408 
1410  res.informationElementsLength = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1411  memcpy(res.informationElements, nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), res.informationElementsLength);
1412  }
1413  if (bss[NL80211_BSS_BEACON_IES]) {
1414  res.beaconInformationElementsLength = nla_len(bss[NL80211_BSS_BEACON_IES]);
1415  memcpy(res.beaconInformationElements, nla_data(bss[NL80211_BSS_BEACON_IES]), res.beaconInformationElementsLength);
1416  }
1417 
1418  scanResults_.insert(res);
1419 
1420  return NL_SKIP;
1421 }
1422 
1423 prefix_ int senf::emu::WirelessNLController::processScanResponse(std::uint8_t cmd, nlattr ** msgAttr)
1424 {
1425  ScanEvent event;
1426  if (cmd == NL80211_CMD_SCAN_ABORTED) {
1427  event.type = ScanEvent::Type::ABORTED;
1428  }
1429  else if (cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
1430  event.type = ScanEvent::Type::COMPLETED;
1431  }
1432  else {
1433  return NL_SKIP;
1434  }
1435 
1436  scanEvent.signal(event);
1437 
1438  return NL_OK;
1439 }
1440 
1441 prefix_ void senf::emu::WirelessNLController::get_multicastGroups()
1442 {
1443  int ctrlid = genl_ctrl_resolve(nl_sock_.get(), "nlctrl");
1444  if (ctrlid < 0)
1445  SENF_THROW_SYSTEM_EXCEPTION( "nlctrl not found");
1446 
1447  nl_msg_ptr msg (nlMsg());
1448  genlmsg_put( msg.get(),
1449  NL_AUTO_PID, NL_AUTO_SEQ,
1450  ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
1451 
1452  NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, "nl80211");
1453 
1454  send_and_wait4response(msg, &WirelessNLController::getMCGroups_cb);
1455 }
1456 
1457 prefix_ int senf::emu::WirelessNLController::getMCGroups_cb(nl_msg * msg)
1458 {
1459  nlattr * msgAttr[CTRL_ATTR_MAX + 1];
1460 
1461  genlmsghdr * msgHdr = reinterpret_cast<genlmsghdr *>(nlmsg_data(nlmsg_hdr(msg)));
1462  nla_parse(msgAttr, CTRL_ATTR_MAX, genlmsg_attrdata(msgHdr, 0), genlmsg_attrlen(msgHdr, 0), NULL);
1463 
1464  if (not msgAttr[CTRL_ATTR_MCAST_GROUPS])
1465  return NL_SKIP;
1466 
1467  multicastGroups_.clear();
1468  FOREACH_NESTED_ATTR( mcgrp, msgAttr[CTRL_ATTR_MCAST_GROUPS] ) {
1469  nlattr * grpAttr[CTRL_ATTR_MCAST_GRP_MAX + 1];
1470  nla_parse(grpAttr, CTRL_ATTR_MCAST_GRP_MAX, nla_attr_data(mcgrp), nla_len(mcgrp), NULL);
1471 
1472  if (not grpAttr[CTRL_ATTR_MCAST_GRP_NAME] or not grpAttr[CTRL_ATTR_MCAST_GRP_ID])
1473  continue;
1474 
1475  std::string grpName (
1476  reinterpret_cast<const char*>(nla_data(grpAttr[CTRL_ATTR_MCAST_GRP_NAME])),
1477  nla_len(grpAttr[CTRL_ATTR_MCAST_GRP_NAME])-1);
1478  int grpId (nla_get_u32(grpAttr[CTRL_ATTR_MCAST_GRP_ID]));
1479  multicastGroups_[grpName] = grpId;
1480  }
1481 
1482  return NL_OK;
1483 }
1484 
1485 prefix_ void senf::emu::WirelessNLController::processReadEvent(int eventMask)
1486 {
1487  nl_recvmsgs(nl_event_sock_.get(), nl_event_cb_.get());
1488 }
1489 
1490 prefix_ int senf::emu::WirelessNLController::netlink_event_cb(nl_msg * msg)
1491 {
1492  nlattr * msgAttr[NL80211_ATTR_MAX + 1];
1493  genlmsghdr * msgHdr = reinterpret_cast<genlmsghdr *>(nlmsg_data(nlmsg_hdr(msg)));
1494  nla_parse(msgAttr, NL80211_ATTR_MAX, genlmsg_attrdata(msgHdr, 0), genlmsg_attrlen(msgHdr, 0), NULL);
1495 
1496  if (phyIndex_ != -1 and msgAttr[NL80211_ATTR_WIPHY]) {
1497  if (phyIndex_ != int(nla_get_u32(msgAttr[NL80211_ATTR_WIPHY])))
1498  return NL_SKIP;
1499  }
1500  if (ifIndex_ != 0 and msgAttr[NL80211_ATTR_IFINDEX]) {
1501  if (ifIndex_ != int(nla_get_u32(msgAttr[NL80211_ATTR_IFINDEX])))
1502  return NL_SKIP;
1503  }
1504 
1505  switch (msgHdr->cmd) {
1507  return processRadarEvent(msgAttr);
1509  return processRegDomainEvent(msgAttr);
1510  }
1511 
1512  return NL_OK;
1513 }
1514 
1515 prefix_ int senf::emu::WirelessNLController::processRadarEvent(nlattr ** msgAttr)
1516 {
1517  if (not msgAttr[NL80211_ATTR_RADAR_EVENT] or not msgAttr[NL80211_ATTR_WIPHY_FREQ])
1518  return NL_SKIP;
1519 
1520  RadarEvent event;
1521  event.type = RadarEvent::Type(nla_get_u32(msgAttr[NL80211_ATTR_RADAR_EVENT]));
1522  event.frequency = nla_get_u32(msgAttr[NL80211_ATTR_WIPHY_FREQ]);
1523 
1524  radarEvent.signal(event);
1525 
1526  return NL_OK;
1527 }
1528 
1529 prefix_ int senf::emu::WirelessNLController::processRegDomainEvent(nlattr ** msgAttr)
1530 {
1531  if (not msgAttr[NL80211_ATTR_REG_TYPE])
1532  return NL_SKIP;
1533 
1535  event.type = RegulatoryDomainChangeEvent::Type(nla_get_u8(msgAttr[NL80211_ATTR_REG_TYPE]));
1536 
1537  regulatoryDomainChangeEvent.signal(event);
1538 
1539  return NL_OK;
1540 }
1541 
1542 prefix_ void senf::emu::WirelessNLController::initEventHandling()
1543 {
1544  if (nl_event_sock_)
1545  return;
1546  initNlSock(nl_event_sock_);
1547  initNlCb(nl_event_sock_, nl_event_cb_, netlinkEventCb_);
1548  nlEvent_.reset( new scheduler::FdEvent(
1549  "WirelessNLControllerEvent", senf::membind(&WirelessNLController::processReadEvent, this),
1550  nl_socket_get_fd(nl_event_sock_.get()), senf::scheduler::FdEvent::EV_READ));
1551 }
1552 
1553 prefix_ void senf::emu::WirelessNLController::deinitEventHandling()
1554 {
1555  nlEvent_.reset();
1556  nl_event_cb_.release();
1557  nl_event_sock_.release();
1558 }
1559 
1560 prefix_ int senf::emu::WirelessNLController::multicastGroupId(NetlinkMulticastGroup::Enum group)
1561 {
1562  get_multicastGroups();
1563 
1564  std::string groupName;
1565  switch (group) {
1567  groupName = "config";
1568  break;
1570  groupName = "scan";
1571  break;
1573  groupName = "regulatory";
1574  break;
1576  groupName = "mlme";
1577  break;
1579  groupName = "vendor";
1580  break;
1581  }
1582  if (not senf::contains(multicastGroups_, groupName))
1583  throw InvalidArgumentException("invalid group ") << groupName;
1584  return multicastGroups_[groupName];
1585 }
1586 
1587 prefix_ void senf::emu::WirelessNLController::join_multicastGroup(NetlinkMulticastGroup::Enum group)
1588 {
1589  if (senf::contains(joinedMCGroups_, group))
1590  return;
1591 
1592  if (joinedMCGroups_.empty())
1593  initEventHandling();
1594 
1595  int r = nl_socket_add_membership(nl_event_sock_.get(), multicastGroupId(group));
1596  if (r) {
1597  if (joinedMCGroups_.empty())
1598  deinitEventHandling();
1599  throw NetlinkException(r);
1600  }
1601 
1602  joinedMCGroups_.insert(group);
1603 }
1604 
1605 prefix_ void senf::emu::WirelessNLController::leave_multicastGroup(NetlinkMulticastGroup::Enum group)
1606 {
1607  if (not senf::contains(joinedMCGroups_, group))
1608  return;
1609 
1610  int r = nl_socket_drop_memberships(nl_event_sock_.get(), multicastGroupId(group));
1611  if (r)
1612  throw NetlinkException(r);
1613 
1614  joinedMCGroups_.erase(group);
1615 
1616  if (joinedMCGroups_.empty())
1617  deinitEventHandling();
1618 }
1619 
1620 //-/////////////////////////////////////////////////////////////////////////////////////////////////
1621 // WirelessNLController::JoinParameters
1622 
1623 prefix_ senf::emu::WirelessNLController::JoinParameters::JoinParameters(
1624  Callback cb, frequency_type freq, ChannelMode::Enum channelMode, bool & success)
1625  : callback_(cb), handleDFS_(false), freq_(freq), channelMode_(channelMode), success_(success)
1626 {}
1627 
1628 prefix_ senf::emu::WirelessNLController::JoinParameters::~JoinParameters()
1629 {
1630  try {
1631  callback_(*this);
1632  success_ = true;
1633  } catch (...) {
1634  success_ = false;
1635  }
1636 }
1637 
1638 prefix_ senf::emu::WirelessNLController::JoinParameters::ptr senf::emu::WirelessNLController::JoinParameters::handleDFS(bool flag)
1639 {
1640  handleDFS_ = flag;
1641  return shared_from_this();
1642 }
1643 
1644 prefix_ senf::emu::WirelessNLController::JoinParameters::ptr senf::emu::WirelessNLController::JoinParameters::beaconInterval(boost::optional<boost::uint32_t> interval)
1645 {
1646  beaconInterval_ = interval;
1647  return shared_from_this();
1648 }
1649 
1650 prefix_ void senf::emu::WirelessNLController::JoinParameters::initHTCapabilities()
1651 {
1652  if (htCapabilities_)
1653  return;
1654  htCapabilities_ = ieee80211_ht_cap();
1655  htCapabilitiesMask_ = ieee80211_ht_cap();
1656  memset(htCapabilities_.get_ptr(), 0, sizeof(htCapabilities_.get()));
1657  memset(htCapabilitiesMask_.get_ptr(), 0, sizeof(htCapabilitiesMask_.get()));
1658 }
1659 
1660 prefix_ senf::emu::WirelessNLController::JoinParameters::ptr senf::emu::WirelessNLController::JoinParameters::ampduFactor(unsigned factor)
1661 {
1662  if (factor > 3)
1663  throw InvalidArgumentException("invalid ampdu-factor: ") << factor;
1664  initHTCapabilities();
1665  htCapabilities_->ampdu_params_info |= factor & 0x3;
1666  htCapabilitiesMask_->ampdu_params_info |= 0x3; /* 2 bits for factor */
1667  return shared_from_this();
1668 }
1669 
1670 //-/////////////////////////////////////////////////////////////////////////////////////////////////
1671 // WirelessNLController::IbssJoinParameters
1672 
1673 prefix_ senf::emu::WirelessNLController::IbssJoinParameters::IbssJoinParameters(
1674  Callback cb, std::string const & ssid, frequency_type freq, ChannelMode::Enum channelMode, bool & success)
1675  : JoinParameters(cb, freq, channelMode, success),
1676  ssid_(ssid)
1677 {}
1678 
1679 prefix_ senf::emu::WirelessNLController::IbssJoinParameters::ptrI senf::emu::WirelessNLController::IbssJoinParameters::bssid(senf::MACAddress const & mac)
1680 {
1681  bssid_ = mac;
1682  return IbssJoinParameters::ptrI(this);
1683 }
1684 
1685 
1686 //-/////////////////////////////////////////////////////////////////////////////////////////////////
1687 // WirelessNLController::MeshJoinParameters
1688 
1689 prefix_ senf::emu::WirelessNLController::MeshJoinParameters::MeshJoinParameters(
1690  Callback cb, std::string const & meshId, frequency_type freq, ChannelMode::Enum channelMode, bool & success)
1691  : JoinParameters(cb, freq, channelMode, success),
1692  meshId_(meshId)
1693 {}
1694 
1695 prefix_ senf::emu::WirelessNLController::MeshJoinParameters::ptrM senf::emu::WirelessNLController::MeshJoinParameters::vendorMetric(bool enable)
1696 {
1697  vendorMetric_ = enable ? 1 : 0;
1698  return MeshJoinParameters::ptrM(this);
1699 }
1700 
1701 prefix_ senf::emu::WirelessNLController::MeshJoinParameters::ptrM senf::emu::WirelessNLController::MeshJoinParameters::vendorPathSelection(bool enable)
1702 {
1703  vendorPathSelection_ = enable ? 1 : 0;
1704  return MeshJoinParameters::ptrM(this);
1705 }
1706 
1707 prefix_ senf::emu::WirelessNLController::MeshJoinParameters::ptrM senf::emu::WirelessNLController::MeshJoinParameters::vendorSynchronization(bool enable)
1708 {
1709  vendorSynchronization_ = enable ? 1 : 0;
1710  return MeshJoinParameters::ptrM(this);
1711 }
1712 
1713 
1714 //-/////////////////////////////////////////////////////////////////////////////////////////////////
1715 // NetlinkException
1716 
1717 prefix_ senf::emu::NetlinkException::NetlinkException(int code, std::string const & descr)
1718  : code_(code)
1719 {
1720  (*this) << "Netlink exception (" << senf::str(errorNumber()) << ") [" << errorString() << "] " << descr;
1721 }
1722 
1724  const
1725 {
1726  return code_;
1727 }
1728 
1730  const
1731 {
1732  return nl_geterror(code_);
1733 }
1734 
1735 //-/////////////////////////////////////////////////////////////////////////////////////////////////
1736 #undef prefix_
1737 
1738 // Local Variables:
1739 // mode: c++
1740 // fill-column: 100
1741 // comment-column: 40
1742 // c-file-style: "senf"
1743 // indent-tabs-mode: nil
1744 // ispell-local-dictionary: "american"
1745 // compile-command: "scons -u test"
1746 // End:
void set_regulatory(RegulatoryDomain const &regDomain)
#define prefix_
void add_apInterface(std::string const &name)
static MACAddress const None
#define NL80211_TXQ_ATTR_QUEUE
Definition: nl80211-new.h:3508
RegulatoryRule & maxEIRP(std::int32_t eirp)
Definition: Regulatory.cc:112
void init()
void add_meshInterface(std::string const &name, std::string const &meshId="")
#define FOREACH_NESTED_ATTR(attr, nla)
std::uint8_t mac[6]
#define SENF_THROW_SYSTEM_EXCEPTION(desc)
void set_bitrates(BitrateParameters parameters)
void add_adhocInterface(std::string const &name)
#define NL80211_FREQUENCY_ATTR_NO_IBSS
Definition: nl80211-new.h:2916
#define NLA_PUT_NESTED(msg, attrtype, nestedMsg)
static int phy_nametoindex(std::string const &phyname)
void del_interface(std::string const &name)
static unsigned distanceToCoverageClass(unsigned distance)
std::set< Band_t > const & supportedBands()
void do_trigger_scan(std::set< frequency_type > const &frequencies, std::set< std::string > const &ssids={})
#define ARRAY_SIZE(arr)
#define NL80211_SURVEY_INFO_CHANNEL_TIME_TX
Definition: nl80211-new.h:3200
boost::function< int(nl_msg *)> NetlinkMsgCallback
boost::function< R(Args)> membind(R(T::*fn)(Args), T *ob)
boost::optional< MCSIndexSet > mcs_24
char ssid[36]
#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN
Definition: nl80211-new.h:2915
std::int32_t min
__u8 band
Definition: nl80211-new.h:128
#define NL80211_SURVEY_INFO_CHANNEL_TIME_RX
Definition: nl80211-new.h:3199
std::pair< DFSState::Enum, std::uint32_t > dfsState(frequency_type freq)
BitrateParameters const & bitrates()
Return valid bitrates.
void add_monInterface(std::string const &name, int flags=MonitorFlags::None)
boost::optional< LegacyBitrateSet > legacy_5
std::set< RegulatoryRule > rules
Definition: Regulatory.hh:132
void set_regulatory_request(std::string const &alpha2Country)
std::uint32_t frequencyRangeEnd() const
Definition: Regulatory.cc:38
std::array< VHT_MCSBitmap, NL80211_VHT_NSS_MAX > VHT_MCSBitmapTable
RegulatoryRule & maxAntennaGain(std::int32_t gain)
Definition: Regulatory.cc:124
NetlinkEvent< ScanEvent > scanEvent
#define KHZ_TO_MHZ(freq)
boost::optional< VHT_MCSBitmapTable > vht_mcs_table_24
std::multiset< ScanResults > const & getScan()
NetlinkEvent< RadarEvent > radarEvent
void set_txpower(TxPowerSetting::Enum setting, unsigned int mBm)
#define NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY
Definition: nl80211-new.h:3197
static frequency_type centerFreq(frequency_type freq, ChannelMode::Enum channelMode)
static std::string macToPhy(senf::MACAddress const &mac)
boost::optional< MCSIndexSet > mcs_5
std::uint8_t bssid[6]
RegulatoryRule & cacTime(std::uint32_t cac)
Definition: Regulatory.cc:118
VHTCapabilitiesInfo const & vhtCapabilities()
#define BIT(x)
void set_txQueueParameters(boost::uint8_t queue, boost::uint16_t cwMin, boost::uint16_t cwMax, boost::uint8_t aifs, boost::uint16_t txop)
struct senf::emu::MonitorDataFilterStatistics __attribute__
enum SupportedChannelWidth supportedChannelWidth
std::uint32_t frequencyRangeBegin() const
Definition: Regulatory.cc:32
JoinParameters::ptr mesh_join(std::string const &meshId, frequency_type freq, ChannelMode::Enum channelMode, bool &success)
std::set< std::string > IfaceNameSet
#define NLA_PUT_OPTIONAL_VECTOR(msg, attrtype, optvector)
RegulatoryRule & flags(std::uint32_t f)
Definition: Regulatory.cc:130
WirelessNLController(bool disableSeqNoCheck=true)
#define NL80211_SURVEY_INFO_CHANNEL_TIME
Definition: nl80211-new.h:3196
static int channelType(ChannelMode::Enum channelMode)
RegulatoryRule & maxBandwidth(std::uint32_t bandwidth)
Definition: Regulatory.cc:106
JoinParameters::ptr ibss_join(std::string const &ssid, frequency_type freq, ChannelMode::Enum channelMode, bool &success)
boost::optional< VHT_MCSBitmapTable > vht_mcs_table_5
static int if_nameto_phy_index(std::string const &ifname)
static int channelWidth(ChannelMode::Enum channelMode)
boost::optional< GICfg > gi_5
NetlinkException(int code, std::string const &descr="")
WirelessNLController public header.
HTCapabilitiesInfo const & htCapabilities()
void set_retryLimit(boost::uint8_t shortLimit, boost::uint8_t longLimit)
std::set< Survey > const & survey()
#define MHZ_TO_KHZ(freq)
#define NLA_PUT(msg, attrtype, attrlen, data)
void set_frequency(frequency_type freq, ChannelMode::Enum=ChannelMode::NoHT20)
boost::optional< GICfg > gi_24
#define NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY
Definition: nl80211-new.h:3198
NetlinkEvent< RegulatoryDomainChangeEvent > regulatoryDomainChangeEvent
struct ieee80211_mcs_info mcs
Definition: ieee80211.h:216
void start_radarDetection(unsigned int freq, ChannelMode::Enum=ChannelMode::NoHT20)
std::string const & phyName() const
static MACAddress from_data(InputIterator i)
#define SENF_LOG(args)
boost::optional< LegacyBitrateSet > legacy_24
__u16 mcs[NL80211_VHT_NSS_MAX]
Definition: nl80211-new.h:3815
#define GET_RULE_ATTR_OR_SKIP(var, attr)
static std::string if_nameto_phy_name(std::string const &ifname)
__be16 freq
boost::iterator_range< Frequencies_iterator > FrequencyRange
#define NL80211_VHT_NSS_MAX
Definition: nl80211-new.h:3808