Commit ebcbfcf4 authored by Luis R. Rodriguez's avatar Luis R. Rodriguez

crda: add a reglib iterator reglib_for_each_country()

To allow for a simple library on reglib.c we want to enable
an iterator over the regulatory database that does not have
to lock the file, or pass references to the file. We instead
add an iterator reglib_get_country_idx() which will use a
new reglib_get_country_idx(), that does an O(n) search for
each new regulatory domain it needs to read.

The trade off here is to allow for a simple reglib.c implementation
at the cost that upon each iteration reglib_get_country_idx()
we will will be opening the regdb, and verifying the db signature.
Given that the only user of this iterator is regdbdump though and
that this is used for debugging for now this is trade off I am
willing to live with.

Systems that want to use the regdb as a database for fine tuning
radio parameters dynamically and reading this file very *often*
(seconds, minutes, who knows what the future holds) may want to
consider a slight optimization of exporting the direct mmap()
through the library but we are I think light years away from that.
Signed-off-by: 's avatarLuis R. Rodriguez <mcgrof@qca.qualcomm.com>
parent 0d421c28
......@@ -105,7 +105,7 @@ keys-%.c: utils/key2pub.py $(wildcard $(PUBKEY_DIR)/*.pem)
$(NQ) ' Trusted pubkeys:' $(wildcard $(PUBKEY_DIR)/*.pem)
$(Q)./utils/key2pub.py --$* $(wildcard $(PUBKEY_DIR)/*.pem) $@
%.o: %.c regdb.h
%.o: %.c regdb.h reglib.h
$(NQ) ' CC ' $@
$(Q)$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
......
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h> /* ntohl */
#include "regdb.h"
#include "reglib.h"
int main(int argc, char **argv)
{
int fd;
struct stat stat;
uint8_t *db;
struct regdb_file_header *header;
struct regdb_file_reg_country *countries;
int dblen, siglen, num_countries, i, r = 0;
struct ieee80211_regdomain *rd = NULL;
unsigned int idx = 0;
if (argc != 2) {
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return 2;
}
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror("failed to open db file");
return 2;
}
if (fstat(fd, &stat)) {
perror("failed to fstat db file");
return 2;
}
dblen = stat.st_size;
db = mmap(NULL, dblen, PROT_READ, MAP_PRIVATE, fd, 0);
if (db == MAP_FAILED) {
perror("failed to mmap db file");
return 2;
}
header = crda_get_file_ptr(db, dblen, sizeof(*header), 0);
if (ntohl(header->magic) != REGDB_MAGIC) {
fprintf(stderr, "Invalid database magic\n");
return 2;
}
if (ntohl(header->version) != REGDB_VERSION) {
fprintf(stderr, "Invalid database version\n");
return 2;
}
siglen = ntohl(header->signature_length);
/* adjust dblen so later sanity checks don't run into the signature */
dblen -= siglen;
if (dblen <= (int)sizeof(*header)) {
fprintf(stderr, "Invalid signature length %d\n", siglen);
return 2;
}
/* verify signature */
if (!crda_verify_db_signature(db, dblen, siglen))
return -EINVAL;
num_countries = ntohl(header->reg_country_num);
countries = crda_get_file_ptr(db, dblen,
sizeof(struct regdb_file_reg_country) * num_countries,
header->reg_country_ptr);
for (i = 0; i < num_countries; i++) {
struct regdb_file_reg_country *country = countries + i;
rd = country2rd(db, dblen, country);
if (!rd) {
r = -ENOMEM;
fprintf(stderr, "Could not covert country "
"(%.2s) to rd\n", country->alpha2);
goto out;
}
reglib_for_each_country(rd, idx, argv[1]) {
print_regdom(rd);
free(rd);
rd = NULL;
}
out:
return r;
return 0;
}
......@@ -3,6 +3,13 @@
#include <arpa/inet.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <arpa/inet.h> /* ntohl */
#include "reglib.h"
#ifdef USE_OPENSSL
......@@ -212,3 +219,65 @@ struct ieee80211_regdomain *country2rd(uint8_t *db, int dblen,
return rd;
}
struct ieee80211_regdomain *
reglib_get_country_idx(unsigned int idx, const char *file)
{
int fd;
struct stat stat;
uint8_t *db;
struct regdb_file_header *header;
struct regdb_file_reg_country *countries;
int dblen, siglen, num_countries;
struct ieee80211_regdomain *rd = NULL;
struct regdb_file_reg_country *country;
fd = open(file, O_RDONLY);
if (fd < 0)
return NULL;
if (fstat(fd, &stat))
return NULL;
dblen = stat.st_size;
db = mmap(NULL, dblen, PROT_READ, MAP_PRIVATE, fd, 0);
if (db == MAP_FAILED)
return NULL;
header = crda_get_file_ptr(db, dblen, sizeof(*header), 0);
if (ntohl(header->magic) != REGDB_MAGIC)
return NULL;
if (ntohl(header->version) != REGDB_VERSION)
return NULL;
siglen = ntohl(header->signature_length);
/* adjust dblen so later sanity checks don't run into the signature */
dblen -= siglen;
if (dblen <= (int)sizeof(*header))
return NULL;
/* verify signature */
if (!crda_verify_db_signature(db, dblen, siglen))
return NULL;
num_countries = ntohl(header->reg_country_num);
countries = crda_get_file_ptr(db, dblen,
sizeof(struct regdb_file_reg_country) * num_countries,
header->reg_country_ptr);
if (idx >= num_countries)
return NULL;
country = countries + idx;
rd = country2rd(db, dblen, country);
if (!rd)
return NULL;
return rd;
}
......@@ -78,6 +78,15 @@ int crda_verify_db_signature(uint8_t *db, int dblen, int siglen);
struct ieee80211_regdomain *country2rd(uint8_t *db, int dblen,
struct regdb_file_reg_country *country);
struct ieee80211_regdomain *
reglib_get_country_idx(unsigned int idx, const char *file);
#define reglib_for_each_country(__rd, __idx, __file) \
for (__rd = reglib_get_country_idx(__idx, __file); \
__rd != NULL; \
__rd = reglib_get_country_idx(__idx, __file), \
__idx++)
/* reg helpers */
void print_regdom(struct ieee80211_regdomain *rd);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment