Beispiel #1
0
/* Converts a file regdomain to ieee80211_regdomain, easier to manage */
struct ieee80211_regdomain *country2rd(__u8 *db, int dblen, struct regdb_file_reg_country *country)
{
	struct regdb_file_reg_rules_collection *rcoll;
	struct ieee80211_regdomain *rd;
	int i, num_rules, size_of_rd;

	rcoll = crda_get_file_ptr(db, dblen, sizeof(*rcoll), country->reg_collection_ptr);
	num_rules = ntohl(rcoll->reg_rule_num);
	/* re-get pointer with sanity checking for num_rules */
	rcoll = crda_get_file_ptr(db, dblen, sizeof(*rcoll) + num_rules * sizeof(__be32), country->reg_collection_ptr);

	size_of_rd = sizeof(struct ieee80211_regdomain) + num_rules * sizeof(struct ieee80211_reg_rule);

	rd = malloc(size_of_rd);
	if (!rd)
		return NULL;

	memset(rd, 0, size_of_rd);

	rd->alpha2[0] = country->alpha2[0];
	rd->alpha2[1] = country->alpha2[1];
	rd->n_reg_rules = num_rules;

	for (i = 0; i < num_rules; i++) {
		reg_rule2rd(db, dblen, rcoll->reg_rule_ptrs[i], &rd->reg_rules[i]);
	}

	return rd;
}
Beispiel #2
0
static void reg_rule2rd(__u8 *db, int dblen, __be32 ruleptr, struct ieee80211_reg_rule *rd_reg_rule)
{
	struct regdb_file_reg_rule *rule;
	struct regdb_file_freq_range *freq;
	struct regdb_file_power_rule *power;

	struct ieee80211_freq_range *rd_freq_range = &rd_reg_rule->freq_range;
	struct ieee80211_power_rule *rd_power_rule = &rd_reg_rule->power_rule;

	rule = crda_get_file_ptr(db, dblen, sizeof(*rule), ruleptr);
	freq = crda_get_file_ptr(db, dblen, sizeof(*freq), rule->freq_range_ptr);
	power = crda_get_file_ptr(db, dblen, sizeof(*power), rule->power_rule_ptr);

	rd_freq_range->start_freq_khz = ntohl(freq->start_freq);
	rd_freq_range->end_freq_khz = ntohl(freq->end_freq);
	rd_freq_range->max_bandwidth_khz = ntohl(freq->max_bandwidth);

	rd_power_rule->max_antenna_gain = ntohl(power->max_antenna_gain);
	rd_power_rule->max_eirp = ntohl(power->max_eirp);

	rd_reg_rule->flags = ntohl(rule->flags);
}
Beispiel #3
0
struct ieee80211_regdomain *mac80211_get_regdomain(char *varcountry)
{
	int fd = -1;
	struct stat stat;
	__u8 *db;
	struct regdb_file_header *header;
	struct regdb_file_reg_country *countries;
	int dblen, siglen, num_countries, i, j;
	char alpha2[2];
	int found_country = 0;

	struct regdb_file_reg_rules_collection *rcoll;
	struct regdb_file_reg_country *country;
	int num_rules;
	struct ieee80211_regdomain *rd = NULL;

	const char *regdb_paths[] = {
		"/lib/crda/regulatory.bin",
		NULL
	};
	const char **regdb = regdb_paths;

	if (!varcountry) {
		fprintf(stderr, "COUNTRY environment variable not set.\n");
		return rd;
	}

	if (!is_valid_regdom(varcountry)) {
		fprintf(stderr, "COUNTRY environment variable must be an " "ISO ISO 3166-1-alpha-2 (uppercase) or 00\n");
		return rd;
	}

	memcpy(alpha2, varcountry, 2);

	while (*regdb != NULL) {
		fd = open(*regdb, O_RDONLY);
		if (fd >= 0)
			break;
		regdb++;
	}
	if (fd < 0) {
		perror("failed to open db file");
		return rd;
	}

	if (fstat(fd, &stat)) {
		perror("failed to fstat db file");
		return rd;
	}

	dblen = stat.st_size;

	db = mmap(NULL, dblen, PROT_READ, MAP_PRIVATE, fd, 0);
	if (db == MAP_FAILED) {
		perror("failed to mmap db file");
		if (fd)
			close(fd);
		return rd;
	}

	/* db file starts with a struct regdb_file_header */
	header = crda_get_file_ptr(db, dblen, sizeof(*header), 0);

	if (ntohl(header->magic) != REGDB_MAGIC) {
		fprintf(stderr, "Invalid database magic\n");
		goto out;
	}

	if (ntohl(header->version) != REGDB_VERSION) {
		fprintf(stderr, "Invalid database version\n");
		goto out;
	}

	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);
		goto out;
	}

	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++) {
		country = countries + i;
		if (memcmp(country->alpha2, alpha2, 2) == 0) {
			found_country = 1;
			break;
		}
	}

	if (!found_country) {
		fprintf(stderr, "No country match in regulatory database.\n");
		goto out;
	}
	rd = country2rd(db, dblen, country);
out:
	if (munmap(db, dblen + siglen) == -1) {
		fprintf(stderr, "mac80211regulatory failed to munmap crda database\n");
	}
	if (fd)
		close(fd);
	return rd;
}
int main(int argc, char **argv)
{
	int fd;
	struct stat stat;
	__u8 *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;

	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;
		}

		print_regdom(rd);
		free(rd);
		rd = NULL;

	}
out:
	return r;
}