CRDA.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 
14 #include "CRDA.hh"
15 
16 // Custom includes
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 
21 #ifndef __O_TMPFILE
22 #define __O_TMPFILE 020000000
23 #endif
24 /* a horrid kludge trying to make sure that this will fail on old kernels */
25 #ifndef O_TMPFILE
26 #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
27 #define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT)
28 #endif
29 
30 #include <senf/Utils/Console.hh>
31 
32 
33 #define prefix_
34 
36 #define WORLD_REG_ALPHA "00"
37 #define INITIAL_REG_ALPHA "AA"
38 
40 {
41  static CRDA instance_;
42  return instance_;
43 }
44 
46  const
47 {
48  return CRDA_SLAVE_NAME;
49 }
50 
52  const
53 {
54  return dfsRegionFlag_;
55 }
56 
57 prefix_ senf::emu::CRDA::CRDA()
58  : dummyCountry_(INITIAL_REG_ALPHA),
59  dfsRegionFlag_(unsigned(RegulatoryDomain::DFSRegion::Unset)),
60  logTag_("[senf::emu::CRDA " + senf::str(getpid()) + "] ")
61 {
62  namespace fty = senf::console::factory;
63  dir.add("kernelRegDomain", fty::Command(&CRDA::kernelRegDomain, this));
64  dir.add("worldRegDomain", fty::Variable(boost::cref(worldRegDomain_)));
65  dir.add("regDomain", fty::Variable(boost::cref(currentRegDomain_)));
66  dir.add("dfsRegionFlag", fty::Variable(boost::cref(dfsRegionFlag_)));
67  dir.add("syncFilename", fty::Variable(boost::cref(syncFilename_)));
68  dir.add("dummyCountry", fty::Variable(boost::cref(dummyCountry_)));
69  dir.add("cachedRegDomains", fty::Command(&CRDA::cachedRegDomains, this));
70 
71  try {
72  std::fstream fs;
73  fs.open("/sys/module/ath/parameters/dfsRegion", std::fstream::in);
74  if (fs.is_open()) {
75  fs >> dfsRegionFlag_;
76  fs.close();
77  }
78  }
79  catch (...) {};
80 
82  logTag_ = "[senf::emu::CRDA_DEBUG " + senf::str(getpid()) + "] ";
83 
84  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "DFS-Unset mode enabled.") );
85 
86  // see: https://en.wikipedia.org/wiki/U-NII
87 
88  // Regd debug world regulatory domain
89  worldRegDomain_.alpha2Country = ""; // leave this blank here !!!
91  worldRegDomain_.rules.insert(RegulatoryRule()
92  .frequencyRange(700000, 800000)
93  .maxBandwidth(20000)
94  .maxEIRP(3000) );
95  worldRegDomain_.rules.insert(RegulatoryRule()
96  .frequencyRange(2402000, 2494000)
97  .maxBandwidth(40000)
98  .maxEIRP(3000) );
99  worldRegDomain_.rules.insert(RegulatoryRule()
100  .frequencyRange(3000000, 4000000)
101  .maxBandwidth(40000)
102  .maxEIRP(3000) );
103  worldRegDomain_.rules.insert(RegulatoryRule()
104  .frequencyRange(4900000, 5925000)
105  .maxBandwidth(80000)
106  .maxEIRP(3000) );
107  worldRegDomain_.rules.insert(RegulatoryRule()
108  .frequencyRange(57240000, 63720000)
109  .maxBandwidth(2160000)
110  .maxEIRP(1000) );
111  } else {
112  // regular world regulatory domain
113  worldRegDomain_.alpha2Country = ""; // leave this blank here !!!
115  worldRegDomain_.rules.insert(RegulatoryRule()
116  .frequencyRange(700000, 800000)
117  .maxBandwidth(20000)
118  .maxEIRP(3000) );
119  worldRegDomain_.rules.insert(RegulatoryRule()
120  .frequencyRange(2402000, 2494000)
121  .maxBandwidth(40000)
122  .maxEIRP(3000) );
123  worldRegDomain_.rules.insert(RegulatoryRule()
124  .frequencyRange(3000000, 4000000)
125  .maxBandwidth(40000)
126  .maxEIRP(3000) );
127  worldRegDomain_.rules.insert(RegulatoryRule()
128  .frequencyRange(4900000, 5250000)
129  .maxBandwidth(80000)
130  .maxEIRP(3000) );
131  worldRegDomain_.rules.insert(RegulatoryRule()
132  .frequencyRange(5250000, 5350000)
133  .maxBandwidth(80000)
134  .maxEIRP(3000)
135  .cacTime(60000)
136  .dfsRequired(true) );
137  worldRegDomain_.rules.insert(RegulatoryRule()
138  .frequencyRange(5470000, 5730000)
139  .maxBandwidth(80000)
140  .maxEIRP(3000)
141  .cacTime(60000)
142  .dfsRequired(true) );
143  worldRegDomain_.rules.insert(RegulatoryRule()
144  .frequencyRange(5735000, 5925000)
145  .maxBandwidth(80000)
146  .maxEIRP(3000) );
147  worldRegDomain_.rules.insert(RegulatoryRule()
148  .frequencyRange(57240000, 63720000)
149  .maxBandwidth(2160000)
150  .maxEIRP(1000) );
151  }
152 }
153 
154 prefix_ bool senf::emu::CRDA::init(bool masterMode, std::string const & filename)
155 {
156  if (filename.empty())
157  return false;
158  syncFilename_ = filename;
159 
160  if (masterMode) {
161  try {
162  std::fstream fs;
163  fs.open(syncFilename_, std::fstream::out | std::fstream::trunc);
164  fs.close();
165  }
166  catch(...) {
167  return false;
168  }
169 
170  try {
172  currentRegDomain_ = wnlc.get_regulatory();
173  // initialize our country counter
174  if (currentRegDomain_.alpha2Country.compare(WORLD_REG_ALPHA) == 0 or currentRegDomain_.alpha2Country.compare("98") == 0)
175  dummyCountry_ = INITIAL_REG_ALPHA;
176  else
177  dummyCountry_ = currentRegDomain_.alpha2Country;
178  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "currentRegDomain initialized from kernel to " << currentRegDomain_ << ". 'DummyCountry' initialized to " << dummyCountry_ << ".") );
179  // store the new mapping (if the mapping already exists, this does nothing)
180  cachedRegDomains_.insert(currentRegDomain_);
181  } catch (...) {
182  currentRegDomain_ = worldRegDomain_;
183  currentRegDomain_.alpha2Country = WORLD_REG_ALPHA;
184  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "No Wireless Subsystem found. This node might be a non-wireless box. Defaulting to build-in worldRegDomain " << currentRegDomain_) );
185  }
186  } else {
187  logTag_ += "(SLV) ";
188  }
189 
190  return true;
191 }
192 
193 prefix_ void senf::emu::CRDA::cachedRegDomains(std::ostream & os)
194  const
195 {
196  os << "Number of cached regDomains: " << cachedRegDomains_.size() << std::endl;
197 
198  for (auto const & rd : cachedRegDomains_){
199  os << rd << std::endl;
200  }
201 }
202 
204  const
205 {
206  return currentRegDomain_;
207 }
208 
210  const
211 {
212  return worldRegDomain_;
213 }
214 
216 {
217  try {
219  if (!currentRegDomain_.isEqualKernel(wnlc.get_regulatory())) {
220  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Kernel regDomain " << wnlc.get_regulatory() << " does not match CRDA regDoamin " << currentRegDomain_) );
221  return false;
222  }
223  return true;
224  }
225  catch(...) {
226  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "No Wireless Subsystem found. This node might be a non-wireless box. Hence equalsKernel() is always true") );
227  }
228 
229  return true;
230 }
231 
233 {
234  if (!regDomain) {
235  regDomain = worldRegDomain_;
236  regDomain.alpha2Country = WORLD_REG_ALPHA;
237  } else {
238  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "regDomain cache (" << cachedRegDomains_.size() << ") lookup for " << regDomain) );
239  // check if we already have a mapping for this regDomain
240  auto const it (cachedRegDomains_.find(regDomain));
241  if (it != cachedRegDomains_.end()) {
242  // yes: re-use the alpha2Country
243  regDomain.alpha2Country = it->alpha2Country;
244  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Cached regDomain found as " << *it) );
245  } else {
246  // no: generate a new alpha2country
247  if (dummyCountry_[1]++ == 'Z') {
248  dummyCountry_[1] = 'A';
249  if (dummyCountry_[0]++ == 'Z') {
250  dummyCountry_[0] = 'A';
251  }
252  }
253  // 'US' seem to be a special country code, so we avoid using it
254  if( dummyCountry_.compare("US") == 0)
255  dummyCountry_ = "UT";
256  regDomain.alpha2Country = dummyCountry_;
257  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "regDomain not found in cache. Creating new regDomain as " << regDomain) );
258  }
259  }
260 
261  // store the new mapping (if the mapping already exists, this does nothing)
262  auto res (cachedRegDomains_.insert(regDomain));
263  if (!res.second) {
264  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Not adding regDomain " << regDomain << " to cache, as entry " << *(res.first) << " is already present.") );
265  }
266 
267  // we might need to revert, if the below fails
268  RegulatoryDomain old (currentRegDomain_);
269 
270  // set the new regDomain first, to avoid possible race conditions with the kernel CRDA upcall
271  currentRegDomain_ = regDomain;
272 
273  if (setRegCountry(currentRegDomain_.alpha2Country)) {
274  return true;
275  }
276 
277  currentRegDomain_ = old;
278  return false;
279 }
280 
281 prefix_ bool senf::emu::CRDA::setRegCountry(std::string alpha2Country)
282 {
283  if (alpha2Country.empty()) {
284  char *a2 = getenv("COUNTRY");
285  if (!a2 or strlen(a2) == 0) {
286  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "COUNTRY not set. Ignoring Request.") );
287  return false;
288  }
289  alpha2Country = std::string(a2);
290  }
291 
292  try {
293  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Writing regDomain tmpfile " << currentRegDomain_) );
294  std::fstream fs;
295  fs.open(syncFilename_, std::fstream::out | std::fstream::trunc);
296  fs << "regDomain " << currentRegDomain_ << ";" << std::endl;
297  fs.close();
298  }
299  catch(...) {
300  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Error creating regDomain tmpfile at " << syncFilename_ << ". Reason given: " << strerror(errno)) );
301  return false;
302  }
303 
304  currentRegDomain_.alpha2Country = alpha2Country;
305 
306  try {
308  wnlc.set_regulatory_request(alpha2Country);
309  } catch (senf::ExceptionMixin & e) {
310  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Setting Regulatory Country to " << alpha2Country << " failed: " << e.message()) );
311  return false;
312  }
313  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Requested Regulatory Country " << alpha2Country ) );
314 
315  return true;
316 }
317 
318 prefix_ void senf::emu::CRDA::kernelRegDomain(std::ostream & os)
319 {
320  try {
322  os << wnlc.get_regulatory() << std::endl;
323  std::cout << wnlc.get_regulatory() << std::endl;
324  } catch (...) {
325  os << "No Wireless Subsystem found. This node might be a non-wireless box." << std::endl;
326  std::cout << "No Wireless Subsystem found. This node might be a non-wireless box." << std::endl;
327  }
328 }
329 
330 //
332 //
333 
334 prefix_ void senf::emu::CRDA::setRegulatory()
335 {
336  std::string a2 (getenv("COUNTRY") ? getenv("COUNTRY") : "");
337 
338  if(a2.empty()) {
339  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "COUNTRY not set. Ignoring request.") );
340  return;
341  }
342 
343  if (a2 == "US" and !currentRegDomain_.alpha2Country.empty()) {
344  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "RegDomain US should not be requested from userspace. Ignoring request.") );
345  return;
346  }
347 
348  auto regDomain ((currentRegDomain_ && a2.compare("00") != 0 && a2.compare("US") != 0) ? currentRegDomain_ : worldRegDomain_);
349 
351 
352  try {
353  WirelessNLController wnlc (false); // do not disable seqNoChecks
355  } catch (senf::ExceptionMixin & e) {
356  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Setting regulatory domain failed: " << e.message() << ", " << regDomain) );
357  return;
358  }
359 
360  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Regulatory rules pushed to kernel as " << regDomain) );
361 }
362 
363 prefix_ void senf::emu::CRDA::help(int exit_status)
364 {
365  std::cout << "Usage: crda [options]"
366  "\n options:"
367  "\n --help show this help"
368  "\n --regDomain=\"<regDomain>\" specifies the regDomain to be pushed with setRegCountry."
369  "\n --setRegCountry=\"<alpha2>\" trigger the kernel to load the specified regulatory for the given dummy country."
370  "\n --setRegulatory push current/world regulatory rules to the kernel - called via udev"
371  "\n --getRegulatory dump current kernel regulatory domain."
372  "\n --debug log debug info into /tmp/crda.log"
373  "\n";
374  exit(exit_status);
375 }
376 
377 prefix_ void senf::emu::CRDA::debugEnable()
378 {
379  logDebugTarget_.reset( new senf::log::FileTarget( "/tmp/crda.log"));
380  logDebugTarget_->route<senf::log::NOTICE>();
381 }
382 
383 prefix_ int senf::emu::CRDA::run(int argc, char const ** argv)
384 {
385  if (argc == 1)
386  help(EXIT_SUCCESS);
387 
388  char *a2 = getenv("COUNTRY");
389  char *action = getenv("ACTION");
390 
391  if (!a2 and strcmp(action,"change") == 0)
392  return -EINVAL;
393 
394  CRDA & crda (instance());
395 
396  crda.logTarget_.route<senf::log::MESSAGE>();
397 
398  namespace fty = senf::console::factory;
399  senf::console::root().add("help", fty::Command( &CRDA::help, &crda).arg(senf::console::kw::default_value = EXIT_SUCCESS) );
400  senf::console::root().add("setRegCountry", fty::Command( &CRDA::setRegCountry, &crda).arg(senf::console::kw::default_value = "") );
401  senf::console::root().add("setRegulatory", fty::Command( &CRDA::setRegulatory, &crda) );
402  senf::console::root().add("getRegulatory", fty::Command( &CRDA::kernelRegDomain, &crda) );
403  senf::console::root().add("regDomain", fty::Variable(currentRegDomain_));
404  senf::console::root().add("debug", fty::Command( &CRDA::debugEnable, &crda) );
405 
406  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Action " << action << ", COUNTRY " << a2 << ", regDomain.alpha " << (currentRegDomain_ ? currentRegDomain_.alpha2Country : "(unset)")) );
407 
408  if (a2) {
409  if ((strlen(a2) != 2) or ((strcmp(a2, "00") != 0) and (!isalpha(a2[0]) or !isalpha(a2[1])))) {
410  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Illegal COUNTRY alpha: '" << a2 << "'. Ignoring request.") );
411  return -EINVAL;
412  }
413  }
414 
415  if (strcmp(action,"change") == 0) {
416  try {
417  // Try to read and parse the redDBFile written by the main process
418  // If present and valid, this will call setRegDomain
419  senf::console::ConfigFile regDb (syncFilename_);
420  regDb.ignoreMissing();
421  regDb.parse(senf::console::root());
422  ::unlink(syncFilename_.c_str());
423  }
424  catch(...) {};
425  }
426 
427  // udev rule file will add '--setRegulatory' arg to command line
428  // declare -x ACTION="change"
429  // declare -x COUNTRY="AA"
430  // declare -x DEVPATH="/devices/platform/regulatory.0"
431  // declare -x MODALIAS="platform:regulatory"
432  // declare -x OLDPWD
433  // declare -x PWD="/"
434  // declare -x SEQNUM="1699"
435  // declare -x SHLVL="1"
436  // declare -x SUBSYSTEM="platform"
437  // declare -x UDEV_LOG="3"
438  // declare -x USEC_INITIALIZED="62694593"
439 
440  std::vector<std::string> nonOptions;
441  senf::console::ProgramOptions cmdlineOptions (argc, argv, senf::console::root());
442  cmdlineOptions.nonOptions(nonOptions);
443  try {
444  cmdlineOptions.parse();
445  } catch (senf::console::SyntaxErrorException const & e) {
446  std::cerr << e.message() << std::endl;
447  help(EXIT_FAILURE);
448  }
449  if (not nonOptions.empty())
450  help(EXIT_FAILURE);
451 
452  return EXIT_SUCCESS;
453 }
454 
455 
456 //
457 // The below has been taken from crda-3.13
458 //
459 
460 #include <netlink/genl/genl.h>
461 #include <netlink/genl/family.h>
462 #include <netlink/genl/ctrl.h>
463 #include <netlink/msg.h>
464 #include <netlink/attr.h>
465 #include "nl80211-new.h"
466 
468  struct nl_sock *nl_sock;
469  struct nl_cache *nl_cache;
470  struct genl_family *nl80211;
471 };
472 
473 static int nl80211_init(struct nl80211_state *state)
474 {
475  int err;
476 
477  state->nl_sock = nl_socket_alloc();
478  if (!state->nl_sock) {
479  fprintf(stderr, "Failed to allocate netlink sock.\n");
480  return -ENOMEM;
481  }
482 
483  if (genl_connect(state->nl_sock)) {
484  fprintf(stderr, "Failed to connect to generic netlink.\n");
485  err = -ENOLINK;
486  goto out_sock_destroy;
487  }
488 
489  if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) {
490  fprintf(stderr, "Failed to allocate generic netlink cache.\n");
491  err = -ENOMEM;
492  goto out_sock_destroy;
493  }
494 
495  state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
496  if (!state->nl80211) {
497  fprintf(stderr, "nl80211 not found.\n");
498  err = -ENOENT;
499  goto out_cache_free;
500  }
501 
502  return 0;
503 
504  out_cache_free:
505  nl_cache_free(state->nl_cache);
506  out_sock_destroy:
507  nl_socket_free(state->nl_sock);
508  return err;
509 }
510 
511 static void nl80211_cleanup(struct nl80211_state *state)
512 {
513  genl_family_put(state->nl80211);
514  nl_cache_free(state->nl_cache);
515  nl_socket_free(state->nl_sock);
516 }
517 
518 static int reg_handler(struct nl_msg __attribute__((unused)) *msg,
519  void __attribute__((unused)) *arg)
520 {
521  return NL_SKIP;
522 }
523 
524 static int wait_handler(struct nl_msg __attribute__((unused)) *msg, void *arg)
525 {
526  int *finished = (int*) arg;
527  *finished = 1;
528  return NL_STOP;
529 }
530 
531 static int error_handler(struct sockaddr_nl __attribute__((unused)) *nla,
532  struct nlmsgerr *err,
533  void __attribute__((unused)) *arg)
534 {
535  fprintf(stderr, "nl80211 error %d\n", err->error);
536  exit(err->error);
537 }
538 
539 static int put_reg_rule(senf::emu::RegulatoryRule const & rule, struct nl_msg *msg)
540 {
541  NLA_PUT_U32( msg, NL80211_ATTR_REG_RULE_FLAGS, rule.flags());
542  NLA_PUT_U32( msg, NL80211_ATTR_FREQ_RANGE_START, rule.frequencyRangeBegin());
543  NLA_PUT_U32( msg, NL80211_ATTR_FREQ_RANGE_END, rule.frequencyRangeEnd());
544  NLA_PUT_U32( msg, NL80211_ATTR_FREQ_RANGE_MAX_BW, rule.maxBandwidth());
545  NLA_PUT_U32( msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, rule.maxAntennaGain());
546  NLA_PUT_U32( msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, rule.maxEIRP());
547  if (rule.cacTime() > 0)
548  NLA_PUT_U32(msg, NL80211_ATTR_DFS_CAC_TIME, rule.cacTime());
549 
550  return 0;
551 
552  nla_put_failure:
553  return -1;
554 }
555 
556 prefix_ int senf::emu::CRDA::setRegulatoryDirect()
557 {
558  std::string a2 (getenv("COUNTRY") ? getenv("COUNTRY") : "");
559 
560  if(a2.empty()) {
561  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "COUNTRY not set. Ignoring request.") );
562  exit(-EINVAL);
563  }
564 
565  if (a2 == "US" and !currentRegDomain_.alpha2Country.empty()) {
566  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "RegDomain US should not be requested from userspace. Ignoring request.") );
567  exit(-EINVAL);
568  }
569 
570  auto regDomain ((currentRegDomain_ && a2.compare("00") != 0 && a2.compare("US") != 0) ? currentRegDomain_ : worldRegDomain_);
571 
573 
574  //
575  // From here, we exec the original CRDA code using our regDomain
576  //
577 
578  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Executing CRDA code to setRegulatory for " << regDomain) );
579 
580  int i = 0, r;
581  struct nl80211_state nlstate;
582  struct nl_cb *cb = NULL;
583  struct nl_msg *msg;
584  int finished = 0;
585  struct nlattr *nl_reg_rules;
586 
587 
588  r = nl80211_init(&nlstate);
589  if (r) {
590  exit(-EIO);
591  }
592 
593  msg = nlmsg_alloc();
594  if (!msg) {
595  r = -1;
596  goto out;
597  }
598 
599  genlmsg_put(msg, 0, 0, genl_family_get_id(nlstate.nl80211), 0,
600  0, NL80211_CMD_SET_REG, 0);
601 
602  NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, regDomain.alpha2Country.c_str());
603  NLA_PUT_U8(msg, NL80211_ATTR_DFS_REGION, std::uint8_t(regDomain.dfsRegion));
604 
605  nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
606  if (!nl_reg_rules) {
607  goto nla_put_failure;
608  }
609 
610  for (RegulatoryRule const & rule : regDomain.rules) {
611  struct nlattr *nl_reg_rule;
612  nl_reg_rule = nla_nest_start(msg, i);
613  if (!nl_reg_rule)
614  goto nla_put_failure;
615 
616  r = put_reg_rule(rule, msg);
617  if (r)
618  goto nla_put_failure;
619 
620  nla_nest_end(msg, nl_reg_rule);
621  }
622 
623  nla_nest_end(msg, nl_reg_rules);
624 
625  cb = nl_cb_alloc(NL_CB_CUSTOM);
626  if (!cb)
627  goto cb_out;
628 
629  r = nl_send_auto_complete(nlstate.nl_sock, msg);
630 
631  if (r < 0) {
632  goto cb_out;
633  }
634 
635  nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, reg_handler, NULL);
636  nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
637  nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL);
638 
639  if (!finished) {
640  r = nl_wait_for_ack(nlstate.nl_sock);
641  if (r < 0) {
642  goto cb_out;
643  }
644  }
645 
646  cb_out:
647  nl_cb_put(cb);
648  nla_put_failure:
649  nlmsg_free(msg);
650  out:
651  nl80211_cleanup(&nlstate);
652 
653  if (r) {
654  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Error (" << r << ") pushing regDomain to kernel as " << regDomain) );
655  } else {
656  SENF_LOG( (senf::log::IMPORTANT) (logTag_ << "Regulatory rules pushed to kernel as " << regDomain) );
657  }
658 
659  exit(r);
660 }
661 
662 
663 
665 #undef prefix_
void set_regulatory(RegulatoryDomain const &regDomain)
bool isEqualKernel(RegulatoryDomain const &other) const
Definition: Regulatory.cc:241
RegulatoryRule & maxEIRP(std::int32_t eirp)
Definition: Regulatory.cc:112
bool equalsKernel()
Definition: CRDA.cc:215
#define WORLD_REG_ALPHA
Definition: CRDA.cc:36
#define CRDA_SLAVE_NAME
Definition: CRDA.hh:29
ProgramOptions & nonOptions(Container &container)
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
senf::emu::RegulatoryDomain const & regDomain() const
Definition: CRDA.cc:203
RegulatoryRule & maxAntennaGain(std::int32_t gain)
Definition: Regulatory.cc:124
static CRDA & instance()
Definition: CRDA.cc:39
int run(int argc, char const **argv)
Definition: CRDA.cc:383
#define INITIAL_REG_ALPHA
Definition: CRDA.cc:37
RegulatoryRule & cacTime(std::uint32_t cac)
Definition: Regulatory.cc:118
std::string slaveName() const
Definition: CRDA.cc:45
struct nl_cache * nl_cache
Definition: CRDA.cc:469
struct senf::emu::MonitorDataFilterStatistics __attribute__
std::uint32_t frequencyRangeBegin() const
Definition: Regulatory.cc:32
struct genl_family * nl80211
Definition: CRDA.cc:470
RegulatoryRule & flags(std::uint32_t f)
Definition: Regulatory.cc:130
RegulatoryRule & maxBandwidth(std::uint32_t bandwidth)
Definition: Regulatory.cc:106
bool init(bool MasterMode=false, std::string const &filename=DEFAULT_CRDA_SYNC_FILE)
Definition: CRDA.cc:154
std::string message() const
struct nl_sock * nl_sock
Definition: CRDA.cc:468
void route(action_t action=ACCEPT, int index=-1)
senf::console::ScopedDirectory dir
Definition: CRDA.hh:36
#define prefix_
Definition: CRDA.cc:33
senf::emu::RegulatoryDomain const & worldRegDomain() const
Definition: CRDA.cc:209
#define SENF_LOG(args)
NodeType & add(std::string const &name, boost::shared_ptr< NodeType > node)
unsigned dfsRegionFlag() const
Definition: CRDA.cc:51