You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

475 lines
18 KiB

  1. --- /dev/null
  2. +++ b/dcwlinux/uci_configuration_provider.h
  3. @@ -0,0 +1,104 @@
  4. +#ifndef UCI_CONFIGURATION_PROVIDER_H_INCLUDED
  5. +#define UCI_CONFIGURATION_PROVIDER_H_INCLUDED
  6. +
  7. +#include "./ap_configuration.h"
  8. +
  9. +namespace dcwlinux {
  10. +
  11. +class UciConfigurationProvider : public APConfigurationProvider {
  12. +
  13. + static const char *SECTION_TYPE_GENERAL;
  14. + static const char *SECTION_TYPE_CHANNEL_SET;
  15. + static const char *SECTION_TYPE_DATA_CHANNEL;
  16. + static const char *SECTION_TYPE_FILTER_SET;
  17. + static const char *SECTION_TYPE_FILTER;
  18. + static const char *DEFAULT_FILTER_SET_NAME;
  19. +
  20. + static const char *OPTION_TMPDIR;
  21. + static const char *OPTION_ENABLED;
  22. + static const char *OPTION_SSID;
  23. + static const char *OPTION_BRIDGE;
  24. + static const char *OPTION_DATA_CHANNELS;
  25. + static const char *OPTION_INTERFACES;
  26. + static const char *OPTION_MAC_ADDRESS;
  27. + static const char *OPTION_FILTERS;
  28. + static const char *OPTION_PACKET_SIZE;
  29. + static const char *OPTION_SOURCE_IP;
  30. + static const char *OPTION_SOURCE_PORT;
  31. + static const char *OPTION_PROTOCOL;
  32. + static const char *OPTION_DEST_PORT;
  33. +
  34. + static const char *FILTER_FILE_EXTENSION;
  35. +
  36. + UciConfigurationProvider(const UciConfigurationProvider&); //no copy
  37. +
  38. + typedef std::map<std::string, std::string> DataChannelBridgeMap;
  39. + struct PrimaryChannel {
  40. + std::string bridgeName;
  41. + DataChannelBridgeMap dataChannels;
  42. + };
  43. + typedef std::map<std::string, PrimaryChannel> PrimaryChannelMap;
  44. + typedef std::map<dcw::MacAddress, std::string> StationFilterMap;
  45. +
  46. + struct uci_context *_uciContext;
  47. + struct uci_package *_uciPackage;
  48. + const char *_uciConfig;
  49. +
  50. + std::string _filterDirectory;
  51. + PrimaryChannelMap _primaryChannels;
  52. + StationFilterMap _stationFilters;
  53. +
  54. +public:
  55. + UciConfigurationProvider(const char * const uciConfig); // the "config" part of UCI commands
  56. + virtual ~UciConfigurationProvider();
  57. +
  58. + virtual void InstanciateCFileTrafficFilterProfiles(CFTFPList& output) const;
  59. + virtual void GetPrimarySsids(SsidSet& output) const;
  60. + virtual void GetDataSsids(SsidSet& output, const char * const primarySsid) const;
  61. + virtual const char *GetSsidIfname(const char * const ssid) const;
  62. + virtual void GetStationTrafficFilterProfiles(StationTFPMap& output) const;
  63. +};
  64. +
  65. +}; //namespace dcwlinux {
  66. +
  67. +#endif //#ifndef UCI_CONFIGURATION_PROVIDER_H_INCLUDED
  68. +#ifndef UCI_CONFIGURATION_PROVIDER_H_INCLUDED
  69. +#define UCI_CONFIGURATION_PROVIDER_H_INCLUDED
  70. +
  71. +#include "./ap_configuration.h"
  72. +
  73. +namespace dcwlinux {
  74. +
  75. +class UciConfigurationProvider : public APConfigurationProvider {
  76. + UciConfigurationProvider(const UciConfigurationProvider&); //no copy
  77. +
  78. + typedef std::map<std::string, std::string> DataChannelBridgeMap;
  79. + struct PrimaryChannel {
  80. + std::string bridgeName;
  81. + DataChannelBridgeMap dataChannels;
  82. + };
  83. + typedef std::map<std::string, PrimaryChannel> PrimaryChannelMap;
  84. + typedef std::map<dcw::MacAddress, std::string> StationFilterMap;
  85. +
  86. + struct uci_context *_uciContext;
  87. + struct uci_package *_uciPackage;
  88. + const char *_uciConfig;
  89. +
  90. + PrimaryChannelMap _primaryChannels;
  91. + StationFilterMap _stationFilters;
  92. + CFTFPList _defaultFilters;
  93. +
  94. +public:
  95. + UciConfigurationProvider(const char * const uciConfig); // the "config" part of UCI commands
  96. + virtual ~UciConfigurationProvider();
  97. +
  98. + virtual void InstanciateCFileTrafficFilterProfiles(CFTFPList& output) const;
  99. + virtual void GetPrimarySsids(SsidSet& output) const;
  100. + virtual void GetDataSsids(SsidSet& output, const char * const primarySsid) const;
  101. + virtual const char *GetSsidIfname(const char * const ssid) const;
  102. + virtual void GetStationTrafficFilterProfiles(StationTFPMap& output) const;
  103. +};
  104. +
  105. +}; //namespace dcwlinux {
  106. +
  107. +#endif //#ifndef UCI_CONFIGURATION_PROVIDER_H_INCLUDED
  108. --- /dev/null
  109. +++ b/dcwlinux/uci_configuration_provider.cxx
  110. @@ -0,0 +1,365 @@
  111. +
  112. +#include <uci.h>
  113. +#include <string.h>
  114. +
  115. +#include <stdlib.h>
  116. +#include <stdexcept>
  117. +#include <sys/stat.h>
  118. +#include <cerrno>
  119. +#include <iostream>
  120. +#include <fstream>
  121. +
  122. +#include "./uci_configuration_provider.h"
  123. +
  124. +#include "dcwposix/filterdirscanner.h"
  125. +#include "dcw/macaddress.h"
  126. +#include "dcw/dcwlog.h"
  127. +
  128. +using namespace dcwlinux;
  129. +
  130. + const char *UciConfigurationProvider::SECTION_TYPE_GENERAL = "general";
  131. + const char *UciConfigurationProvider::SECTION_TYPE_CHANNEL_SET = "channel-set";
  132. + const char *UciConfigurationProvider::SECTION_TYPE_DATA_CHANNEL = "datachannel";
  133. + const char *UciConfigurationProvider::SECTION_TYPE_FILTER_SET = "filter-set";
  134. + const char *UciConfigurationProvider::SECTION_TYPE_FILTER = "filter";
  135. + const char *UciConfigurationProvider::DEFAULT_FILTER_SET_NAME = "TFP_Default";
  136. +
  137. + const char *UciConfigurationProvider::OPTION_TMPDIR = "tmpdir";
  138. + const char *UciConfigurationProvider::OPTION_ENABLED = "enabled";
  139. + const char *UciConfigurationProvider::OPTION_SSID = "ssid";
  140. + const char *UciConfigurationProvider::OPTION_BRIDGE = "bridge";
  141. + const char *UciConfigurationProvider::OPTION_DATA_CHANNELS = "data_channels";
  142. + const char *UciConfigurationProvider::OPTION_INTERFACES = "interfaces";
  143. + const char *UciConfigurationProvider::OPTION_MAC_ADDRESS = "mac";
  144. + const char *UciConfigurationProvider::OPTION_FILTERS = "filters";
  145. + const char *UciConfigurationProvider::OPTION_PACKET_SIZE = "packet_size";
  146. + const char *UciConfigurationProvider::OPTION_SOURCE_IP = "source_ip";
  147. + const char *UciConfigurationProvider::OPTION_SOURCE_PORT = "source_port";
  148. + const char *UciConfigurationProvider::OPTION_PROTOCOL = "protocol";
  149. + const char *UciConfigurationProvider::OPTION_DEST_PORT = "dest_port";
  150. +
  151. + const char *UciConfigurationProvider::FILTER_FILE_EXTENSION = ".tfp";
  152. +
  153. + UciConfigurationProvider::UciConfigurationProvider(const char * const uciConfig) : _uciConfig(uciConfig) {
  154. +
  155. + //printf("*** Start UciConfigurationProvider(%s)\n", _uciConfig);
  156. + //printf("*** About to uci_alloc_context()\n");
  157. +
  158. + _uciContext = uci_alloc_context();
  159. +
  160. + //printf("*** uci_alloc_context() complete\n");
  161. + //printf("*** About to uci_load()\n");
  162. +
  163. + if (_uciContext == NULL)
  164. + {
  165. + std::string err = "Error creating UCI context ";
  166. + throw std::runtime_error(err);
  167. + }
  168. +
  169. + uci_load(_uciContext, _uciConfig, &_uciPackage);
  170. +
  171. + //printf("*** uci_load complete()\n");
  172. +
  173. + if (_uciPackage == NULL)
  174. + {
  175. + std::string err = "Error loading UCI package " + std::string(_uciConfig);
  176. + throw std::runtime_error(err);
  177. + }
  178. +
  179. + uci_section *generalSection = uci_lookup_section(_uciContext, _uciPackage, UciConfigurationProvider::SECTION_TYPE_GENERAL);
  180. + if (generalSection == NULL)
  181. + {
  182. + std::string err = "Error: A general section (" + std::string(UciConfigurationProvider::SECTION_TYPE_GENERAL) + ") must be specified!";
  183. + throw std::runtime_error(err);
  184. + }
  185. +
  186. + uci_option *opt_tmpdir = uci_lookup_option(_uciContext, generalSection, UciConfigurationProvider::OPTION_TMPDIR);
  187. + if (opt_tmpdir == NULL)
  188. + {
  189. + std::string err = "Error: A temporary directory (" + std::string(UciConfigurationProvider::OPTION_TMPDIR) + ") must be specified!";
  190. + throw std::runtime_error(err);
  191. + }
  192. + char *tmpdir = opt_tmpdir->v.string;
  193. + //printf(" *** Set tmpdir: %s\n", tmpdir);
  194. +
  195. + // make sure that tmpdir exists
  196. + int status = mkdir(tmpdir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  197. + if ((status != 0) && // failure
  198. + (errno != EEXIST)) // the failure was not that the directory already existed
  199. + {
  200. + std::string err = "Error: Unable to create the temporary directory (tmpdir), error # " + errno;
  201. + throw std::runtime_error(err);
  202. + }
  203. + _filterDirectory = std::string(tmpdir);
  204. +
  205. + if (uci_lookup_section(_uciContext, _uciPackage, UciConfigurationProvider::DEFAULT_FILTER_SET_NAME) == NULL)
  206. + {
  207. + std::string err = "Error: A default traffic filter profile named " + std::string(UciConfigurationProvider::DEFAULT_FILTER_SET_NAME) + " MUST exist!";
  208. + throw std::runtime_error(err);
  209. + }
  210. +
  211. + // iterate over all of the sections in the package
  212. + uci_element *elem;
  213. + uci_foreach_element(&_uciPackage->sections, elem)
  214. + {
  215. + //printf("--==-- element.type: %d\n", elem->type);
  216. + //printf("--==-- element.name: %s\n", elem->name);
  217. +
  218. + if (elem->type == UCI_TYPE_SECTION)
  219. + {
  220. + // look up the section and get it's type
  221. +
  222. + uci_section *section = NULL;
  223. + //printf("*** Looking up section: %s\n", elem->name);
  224. +
  225. + section = uci_lookup_section(_uciContext, _uciPackage, elem->name);
  226. +
  227. + if ((section != NULL) && (section->type != NULL))
  228. + {
  229. + //printf(" *** Section type: %s\n", section->type);
  230. + if (strcmp(elem->name, UciConfigurationProvider::SECTION_TYPE_GENERAL) == 0)
  231. + {
  232. + // we already processed the general section for the tmpdir
  233. + }
  234. + else if (strcmp(section->type, UciConfigurationProvider::SECTION_TYPE_CHANNEL_SET) == 0)
  235. + {
  236. + // the section is a channel set, populate it with the specified values
  237. +
  238. + uci_option *enabled = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_ENABLED);
  239. + if ((enabled == NULL) || (strcmp(enabled->v.string, "1") != 0))
  240. + {
  241. + // found a disabled channel set, ignore it
  242. + continue;
  243. + }
  244. +
  245. + uci_option *ssid = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_SSID);
  246. + uci_option *bridge = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_BRIDGE);
  247. + uci_option *dataChannels = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_DATA_CHANNELS);
  248. +
  249. + if ((ssid != NULL) && (bridge != NULL) && (dataChannels != NULL))
  250. + {
  251. + PrimaryChannel &pc = _primaryChannels[ssid->v.string];
  252. + pc.bridgeName = bridge->v.string;
  253. +
  254. + char dataChannels_list[255];
  255. + // The dataChannels option is not a list
  256. + //if (dataChannels->type == UCI_TYPE_LIST)
  257. + if (dataChannels->v.string != NULL)
  258. + {
  259. + strcpy(dataChannels_list, dataChannels->v.string);
  260. + std::string str_dataChannels = dataChannels->v.string;
  261. + size_t start_pos = 0;
  262. + size_t pos = 0;
  263. + while(start_pos != std::string::npos)
  264. + {
  265. + pos = str_dataChannels.find(" ", start_pos);
  266. + //printf("****** start_pos: %u, pos: %u\n", start_pos, pos);
  267. + std::string str_dataChannel = str_dataChannels.substr(start_pos,
  268. + pos == std::string::npos ? pos : pos-start_pos);
  269. + //printf("*** dataChannel: %s\n", str_dataChannel.c_str());
  270. +
  271. + // update the start position for next loop
  272. + start_pos = (pos == std::string::npos ? pos : pos+1);
  273. +
  274. + uci_section *dcSection = uci_lookup_section(_uciContext, _uciPackage, str_dataChannel.c_str());
  275. + if (dcSection != NULL)
  276. + {
  277. + uci_option *dcSsid = uci_lookup_option(_uciContext, dcSection, UciConfigurationProvider::OPTION_SSID);
  278. + uci_option *dcBridge = uci_lookup_option(_uciContext, dcSection, UciConfigurationProvider::OPTION_BRIDGE);
  279. +
  280. + // TODO: configure dcBridge and dcInterfaces
  281. + //uci_option *dcInterfaces = uci_lookup_option(_uciContext, dcSection, UciConfigurationProvider::OPTION_INTERFACES);
  282. +
  283. + if ((dcSsid != NULL) && (dcBridge != NULL))
  284. + {
  285. + pc.dataChannels[dcSsid->v.string];
  286. + pc.dataChannels[dcSsid->v.string] = dcBridge->v.string;
  287. + }
  288. + }
  289. + }
  290. + }
  291. +
  292. + //printf("Section: %s, SSID: %s, Bridge: %s, Data Channels: %s\n", section->e.name, ssid->v.string, bridge->v.string, dataChannels_list);
  293. + }
  294. + }
  295. + else if (strcmp(section->type, UciConfigurationProvider::SECTION_TYPE_DATA_CHANNEL) == 0)
  296. + {
  297. + // data channels are processed by the channel set
  298. + }
  299. + else if (strcmp(section->type, UciConfigurationProvider::SECTION_TYPE_FILTER_SET) == 0)
  300. + {
  301. + // the section is a filter set, populate it with the specified values
  302. + //printf("*** filter set: %s\n", elem->name);
  303. +
  304. + // create a tfp file for the sectionName
  305. + std::ofstream tfpFile;
  306. + std::string tfpFilePath =
  307. + tmpdir + std::string("/") +
  308. + std::string(elem->name) +
  309. + std::string(UciConfigurationProvider::FILTER_FILE_EXTENSION);
  310. + tfpFile.open(tfpFilePath.c_str(), std::ios::out | std::ios::trunc);
  311. + if (!tfpFile.is_open())
  312. + {
  313. + std::string err = "Error: Unable to open the filter file: " + tfpFilePath;
  314. + throw std::runtime_error(err);
  315. + }
  316. +
  317. + const char *filterDelimiter = "\n";
  318. + char sFilterContents[2048];
  319. + sFilterContents[0] = '\0';
  320. +
  321. + uci_option *filters = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_FILTERS);
  322. + // The filters option is not a list
  323. + //if ((filters != NULL) && (filters->type == UCI_TYPE_LIST))
  324. + if (filters != NULL)
  325. + {
  326. + //printf("*** %s.filters is a list.\n", elem->name);
  327. + //struct uci_element *e;
  328. + //uci_foreach_element(&filters->v.list, e)
  329. +
  330. + std::string str_filters = filters->v.string;
  331. + //printf("*** STR_FILTERS: %s\n", str_filters.c_str());
  332. + size_t start_pos = 0;
  333. + size_t pos = 0;
  334. + while(start_pos != std::string::npos)
  335. + {
  336. + pos = str_filters.find(" ", start_pos);
  337. + //printf("****** start_pos: %u, pos: %u\n", start_pos, pos);
  338. + std::string str_filter = str_filters.substr(start_pos,
  339. + pos == std::string::npos ? pos : pos-start_pos);
  340. + //printf("*** Looking for filter section named: %s ...\n", str_filter.c_str());
  341. +
  342. + // update the start position for next loop
  343. + start_pos = (pos == std::string::npos ? pos : pos+1);
  344. +
  345. + uci_section *fSection = uci_lookup_section(_uciContext, _uciPackage, str_filter.c_str());
  346. + if (fSection != NULL)
  347. + {
  348. + uci_option *fPacketSize = uci_lookup_option(_uciContext, fSection, UciConfigurationProvider::OPTION_PACKET_SIZE);
  349. + uci_option *fSourceIp = uci_lookup_option(_uciContext, fSection, UciConfigurationProvider::OPTION_SOURCE_IP);
  350. + uci_option *fSourcePort = uci_lookup_option(_uciContext, fSection, UciConfigurationProvider::OPTION_SOURCE_PORT);
  351. + uci_option *fProtocol = uci_lookup_option(_uciContext, fSection, UciConfigurationProvider::OPTION_PROTOCOL);
  352. + uci_option *fDestPort = uci_lookup_option(_uciContext, fSection, UciConfigurationProvider::OPTION_DEST_PORT);
  353. +
  354. + if ((fPacketSize != NULL) &&
  355. + (fSourceIp != NULL) &&
  356. + (fSourcePort != NULL) &&
  357. + (fProtocol != NULL) &&
  358. + (fDestPort != NULL))
  359. + {
  360. + //printf("*** filter: %s %s:%s:%s:%s:%s\n", e->name,
  361. + // fPacketSize->v.string, fSourceIp->v.string, fSourcePort->v.string,
  362. + // fProtocol->v.string, fDestPort->v.string);
  363. +
  364. + strcpy(sFilterContents, fPacketSize->v.string);
  365. + strcat(sFilterContents, ":");
  366. + strcat(sFilterContents, fSourceIp->v.string);
  367. + strcat(sFilterContents, ":");
  368. + strcat(sFilterContents, fSourcePort->v.string);
  369. + strcat(sFilterContents, ":");
  370. + strcat(sFilterContents, fProtocol->v.string);
  371. + strcat(sFilterContents, ":");
  372. + strcat(sFilterContents, fDestPort->v.string);
  373. + strcat(sFilterContents, filterDelimiter);
  374. +
  375. + //printf("*** Writing filter contents to file: %s\n", sFilterContents);
  376. + tfpFile << sFilterContents;
  377. + }
  378. + else
  379. + {
  380. + std::string err = "Error parsing filter: " + str_filter;
  381. + throw std::runtime_error(err);
  382. + }
  383. + }
  384. + }
  385. + }
  386. + tfpFile.close();
  387. +
  388. + // if there is a MAC address for the filter set, we need to add it to the station filters list
  389. + uci_option *mac = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_MAC_ADDRESS);
  390. + if (mac != NULL)
  391. + {
  392. + // ignore wildcard MAC address
  393. + if (strcmp(mac->v.string,"*") != 0)
  394. + {
  395. + //printf(" *** MAC Address: %s\n", mac->v.string);
  396. + _stationFilters[::dcw::MacAddress(mac->v.string)] = elem->name;
  397. + }
  398. + }
  399. + }
  400. + else if (strcmp(section->type, UciConfigurationProvider::SECTION_TYPE_FILTER) == 0)
  401. + {
  402. + // filters are processed by the filter set
  403. + }
  404. + else
  405. + {
  406. + //std::string err = "Error: Unknown UCI section type: " + std::string(section->type);
  407. + //throw std::runtime_error(err);
  408. +
  409. + // Don't throw an exception. It is fine for UCI to contain things that we do not know about
  410. + // that it may use for other purposes, like UI or internal state
  411. + dcwlogdbgf("Ignoring UCI section type: %s\n", section->type);
  412. + }
  413. + }
  414. + }
  415. + }
  416. + }
  417. +
  418. + UciConfigurationProvider::~UciConfigurationProvider() {
  419. + uci_free_context(_uciContext);
  420. + }
  421. +
  422. + void UciConfigurationProvider::InstanciateCFileTrafficFilterProfiles(CFTFPList& output) const {
  423. + ::dcwposix::FilterdirScanner::FileFilterProfileList ffpl;
  424. + ::dcwposix::FilterdirScanner dirScanner(_filterDirectory.c_str());
  425. + dirScanner.Scan(ffpl);
  426. +
  427. + for (::dcwposix::FilterdirScanner::FileFilterProfileList::const_iterator i = ffpl.begin(); i != ffpl.end(); i++) {
  428. + output.push_back(new ::dcw::FileTrafficFilterProfile(*i));
  429. + }
  430. + }
  431. +
  432. +
  433. + void UciConfigurationProvider::GetPrimarySsids(SsidSet& output) const {
  434. + for (PrimaryChannelMap::const_iterator i = _primaryChannels.begin(); i != _primaryChannels.end(); i++) {
  435. + output.insert(i->first);
  436. + }
  437. + }
  438. +
  439. + void UciConfigurationProvider::GetDataSsids(SsidSet& output, const char * const primarySsid) const {
  440. + const PrimaryChannelMap::const_iterator pssid = _primaryChannels.find(primarySsid);
  441. + if (pssid == _primaryChannels.end()) return;
  442. +
  443. + for (DataChannelBridgeMap::const_iterator i = pssid->second.dataChannels.begin(); i != pssid->second.dataChannels.end(); i++) {
  444. + output.insert(i->first);
  445. + }
  446. + }
  447. +
  448. + const char *UciConfigurationProvider::GetSsidIfname(const char * const ssid) const {
  449. + PrimaryChannelMap::const_iterator pssid = _primaryChannels.find(ssid);
  450. + if (pssid != _primaryChannels.end()) {
  451. + if (pssid->second.bridgeName.empty()) {
  452. + return NULL;
  453. + }
  454. + return pssid->second.bridgeName.c_str();
  455. + }
  456. +
  457. + for (pssid = _primaryChannels.begin(); pssid != _primaryChannels.end(); pssid++) {
  458. + const DataChannelBridgeMap& dataChannels = pssid->second.dataChannels;
  459. + const DataChannelBridgeMap::const_iterator dc = dataChannels.find(ssid);
  460. + if (dc == dataChannels.end()) continue;
  461. + if (dc->second.empty()) {
  462. + return NULL;
  463. + }
  464. + return dc->second.c_str();
  465. + }
  466. +
  467. + return NULL;
  468. + }
  469. +
  470. + void UciConfigurationProvider::GetStationTrafficFilterProfiles(StationTFPMap& output) const {
  471. + for (StationFilterMap::const_iterator i = _stationFilters.begin(); i != _stationFilters.end(); i++) {
  472. + output[i->first] = i->second;
  473. + }
  474. +
  475. + }