17 #include <sys/types.h> 22 #define __O_TMPFILE 020000000 26 #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) 27 #define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT) 36 #define WORLD_REG_ALPHA "00" 37 #define INITIAL_REG_ALPHA "AA" 41 static CRDA instance_;
54 return dfsRegionFlag_;
60 logTag_(
"[senf::emu::CRDA " + senf::str(getpid()) +
"] ")
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));
73 fs.open(
"/sys/module/ath/parameters/dfsRegion", std::fstream::in);
82 logTag_ =
"[senf::emu::CRDA_DEBUG " + senf::str(getpid()) +
"] ";
92 .frequencyRange(700000, 800000)
96 .frequencyRange(2402000, 2494000)
100 .frequencyRange(3000000, 4000000)
104 .frequencyRange(4900000, 5925000)
108 .frequencyRange(57240000, 63720000)
109 .maxBandwidth(2160000)
116 .frequencyRange(700000, 800000)
120 .frequencyRange(2402000, 2494000)
124 .frequencyRange(3000000, 4000000)
128 .frequencyRange(4900000, 5250000)
132 .frequencyRange(5250000, 5350000)
136 .dfsRequired(
true) );
138 .frequencyRange(5470000, 5730000)
142 .dfsRequired(
true) );
144 .frequencyRange(5735000, 5925000)
148 .frequencyRange(57240000, 63720000)
149 .maxBandwidth(2160000)
156 if (filename.empty())
158 syncFilename_ = filename;
163 fs.open(syncFilename_, std::fstream::out | std::fstream::trunc);
178 SENF_LOG( (
senf::log::IMPORTANT) (logTag_ <<
"currentRegDomain initialized from kernel to " << currentRegDomain_ <<
". 'DummyCountry' initialized to " << dummyCountry_ <<
".") );
180 cachedRegDomains_.insert(currentRegDomain_);
182 currentRegDomain_ = worldRegDomain_;
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_) );
193 prefix_ void senf::emu::CRDA::cachedRegDomains(std::ostream & os)
196 os <<
"Number of cached regDomains: " << cachedRegDomains_.size() << std::endl;
198 for (
auto const & rd : cachedRegDomains_){
199 os << rd << std::endl;
206 return currentRegDomain_;
212 return worldRegDomain_;
226 SENF_LOG( (
senf::log::IMPORTANT) (logTag_ <<
"No Wireless Subsystem found. This node might be a non-wireless box. Hence equalsKernel() is always true") );
235 regDomain = worldRegDomain_;
240 auto const it (cachedRegDomains_.find(regDomain));
241 if (it != cachedRegDomains_.end()) {
247 if (dummyCountry_[1]++ ==
'Z') {
248 dummyCountry_[1] =
'A';
249 if (dummyCountry_[0]++ ==
'Z') {
250 dummyCountry_[0] =
'A';
254 if( dummyCountry_.compare(
"US") == 0)
255 dummyCountry_ =
"UT";
262 auto res (cachedRegDomains_.insert(regDomain));
264 SENF_LOG( (
senf::log::IMPORTANT) (logTag_ <<
"Not adding regDomain " << regDomain <<
" to cache, as entry " << *(res.first) <<
" is already present.") );
277 currentRegDomain_ = old;
281 prefix_ bool senf::emu::CRDA::setRegCountry(std::string alpha2Country)
283 if (alpha2Country.empty()) {
284 char *a2 = getenv(
"COUNTRY");
285 if (!a2 or strlen(a2) == 0) {
289 alpha2Country = std::string(a2);
295 fs.open(syncFilename_, std::fstream::out | std::fstream::trunc);
296 fs <<
"regDomain " << currentRegDomain_ <<
";" << std::endl;
300 SENF_LOG( (
senf::log::IMPORTANT) (logTag_ <<
"Error creating regDomain tmpfile at " << syncFilename_ <<
". Reason given: " << strerror(errno)) );
318 prefix_ void senf::emu::CRDA::kernelRegDomain(std::ostream & os)
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;
334 prefix_ void senf::emu::CRDA::setRegulatory()
336 std::string a2 (getenv(
"COUNTRY") ? getenv(
"COUNTRY") :
"");
343 if (a2 ==
"US" and !currentRegDomain_.
alpha2Country.empty()) {
348 auto regDomain ((currentRegDomain_ && a2.compare(
"00") != 0 && a2.compare(
"US") != 0) ? currentRegDomain_ : worldRegDomain_);
363 prefix_ void senf::emu::CRDA::help(
int exit_status)
365 std::cout <<
"Usage: crda [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" 377 prefix_ void senf::emu::CRDA::debugEnable()
388 char *a2 = getenv(
"COUNTRY");
389 char *action = getenv(
"ACTION");
391 if (!a2 and strcmp(action,
"change") == 0)
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) );
409 if ((strlen(a2) != 2) or ((strcmp(a2,
"00") != 0) and (!isalpha(a2[0]) or !isalpha(a2[1])))) {
415 if (strcmp(action,
"change") == 0) {
421 regDb.
parse(senf::console::root());
422 ::unlink(syncFilename_.c_str());
440 std::vector<std::string> nonOptions;
444 cmdlineOptions.
parse();
446 std::cerr << e.message() << std::endl;
449 if (not nonOptions.empty())
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> 477 state->
nl_sock = nl_socket_alloc();
479 fprintf(stderr,
"Failed to allocate netlink sock.\n");
483 if (genl_connect(state->
nl_sock)) {
484 fprintf(stderr,
"Failed to connect to generic netlink.\n");
486 goto out_sock_destroy;
490 fprintf(stderr,
"Failed to allocate generic netlink cache.\n");
492 goto out_sock_destroy;
497 fprintf(stderr,
"nl80211 not found.\n");
507 nl_socket_free(state->
nl_sock);
513 genl_family_put(state->
nl80211);
515 nl_socket_free(state->
nl_sock);
518 static int reg_handler(
struct nl_msg
__attribute__((unused)) *msg,
524 static int wait_handler(
struct nl_msg
__attribute__((unused)) *msg,
void *arg)
526 int *finished = (
int*) arg;
531 static int error_handler(
struct sockaddr_nl
__attribute__((unused)) *nla,
532 struct nlmsgerr *err,
535 fprintf(stderr,
"nl80211 error %d\n", err->error);
556 prefix_ int senf::emu::CRDA::setRegulatoryDirect()
558 std::string a2 (getenv(
"COUNTRY") ? getenv(
"COUNTRY") :
"");
565 if (a2 ==
"US" and !currentRegDomain_.alpha2Country.empty()) {
570 auto regDomain ((currentRegDomain_ && a2.compare(
"00") != 0 && a2.compare(
"US") != 0) ? currentRegDomain_ : worldRegDomain_);
582 struct nl_cb *cb = NULL;
585 struct nlattr *nl_reg_rules;
588 r = nl80211_init(&nlstate);
599 genlmsg_put(msg, 0, 0, genl_family_get_id(nlstate.
nl80211), 0,
607 goto nla_put_failure;
611 struct nlattr *nl_reg_rule;
612 nl_reg_rule = nla_nest_start(msg, i);
614 goto nla_put_failure;
616 r = put_reg_rule(rule, msg);
618 goto nla_put_failure;
620 nla_nest_end(msg, nl_reg_rule);
623 nla_nest_end(msg, nl_reg_rules);
625 cb = nl_cb_alloc(NL_CB_CUSTOM);
629 r = nl_send_auto_complete(nlstate.
nl_sock, msg);
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);
640 r = nl_wait_for_ack(nlstate.
nl_sock);
651 nl80211_cleanup(&nlstate);
void set_regulatory(RegulatoryDomain const ®Domain)
bool isEqualKernel(RegulatoryDomain const &other) const
RegulatoryRule & maxEIRP(std::int32_t eirp)
ProgramOptions & nonOptions(Container &container)
std::set< RegulatoryRule > rules
void set_regulatory_request(std::string const &alpha2Country)
std::uint32_t frequencyRangeEnd() const
senf::emu::RegulatoryDomain const & regDomain() const
RegulatoryRule & maxAntennaGain(std::int32_t gain)
int run(int argc, char const **argv)
#define INITIAL_REG_ALPHA
RegulatoryRule & cacTime(std::uint32_t cac)
std::string slaveName() const
struct nl_cache * nl_cache
struct senf::emu::MonitorDataFilterStatistics __attribute__
std::uint32_t frequencyRangeBegin() const
struct genl_family * nl80211
std::string alpha2Country
RegulatoryRule & flags(std::uint32_t f)
RegulatoryRule & maxBandwidth(std::uint32_t bandwidth)
bool init(bool MasterMode=false, std::string const &filename=DEFAULT_CRDA_SYNC_FILE)
std::string message() const
void route(action_t action=ACCEPT, int index=-1)
senf::console::ScopedDirectory dir
RegulatoryDomain get_regulatory()
senf::emu::RegulatoryDomain const & worldRegDomain() const
NodeType & add(std::string const &name, boost::shared_ptr< NodeType > node)
unsigned dfsRegionFlag() const