afb034bdd89ba256e9792491c16a53d689500cdf
[feed/packages.git] / net / dcwapd / patches / 01_add_uci_config_provider.patch
1 --- a/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 --- a/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 + }