Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
     5         kx #include <errno.h>
     5         kx #include <stdio.h>
     5         kx #include <arpa/inet.h>
     5         kx #include <sys/types.h>
     5         kx #include <dirent.h>
     5         kx #include <sys/stat.h>
     5         kx #include <stdlib.h>
     5         kx #include <sys/mman.h>
     5         kx #include <fcntl.h>
     5         kx #include <stdbool.h>
     5         kx #include <unistd.h>
     5         kx #include <string.h>
     5         kx #include <limits.h>
     5         kx 
     5         kx #include <arpa/inet.h> /* ntohl */
     5         kx 
     5         kx #include "reglib.h"
     5         kx #include "regdb.h"
     5         kx 
     5         kx #ifdef USE_OPENSSL
     5         kx #include <openssl/objects.h>
     5         kx #include <openssl/rsa.h>
     5         kx #include <openssl/sha.h>
     5         kx #include <openssl/pem.h>
     5         kx #include <openssl/bn.h>
     5         kx #endif
     5         kx 
     5         kx #ifdef USE_GCRYPT
     5         kx #include <gcrypt.h>
     5         kx #endif
     5         kx 
     5         kx #include "reglib.h"
     5         kx 
     5         kx #ifdef USE_OPENSSL
     5         kx #include "keys-ssl.c"
     5         kx #endif
     5         kx 
     5         kx #ifdef USE_GCRYPT
     5         kx #include "keys-gcrypt.c"
     5         kx #endif
     5         kx 
     5         kx int debug = 0;
     5         kx 
     5         kx void *
     5         kx reglib_get_file_ptr(uint8_t *db, size_t dblen, size_t structlen, uint32_t ptr)
     5         kx {
     5         kx 	uint32_t p = ntohl(ptr);
     5         kx 
     5         kx 	if (structlen > dblen) {
     5         kx 		fprintf(stderr, "Invalid database file, too short!\n");
     5         kx 		exit(3);
     5         kx 	}
     5         kx 
     5         kx 	if (p > dblen - structlen) {
     5         kx 		fprintf(stderr, "Invalid database file, bad pointer!\n");
     5         kx 		exit(3);
     5         kx 	}
     5         kx 
     5         kx 	return (void *)(db + p);
     5         kx }
     5         kx 
     5         kx static size_t
     5         kx reglib_array_len(size_t baselen, unsigned int elemcount, size_t elemlen)
     5         kx {
     5         kx 	if (elemcount > (SIZE_MAX - baselen) / elemlen) {
     5         kx 		fprintf(stderr, "Invalid database file, count too large!\n");
     5         kx 		exit(3);
     5         kx 	}
     5         kx 
     5         kx 	return baselen + elemcount * elemlen;
     5         kx }
     5         kx 
     5         kx /*
     5         kx  * reglib_verify_db_signature():
     5         kx  *
     5         kx  * Checks the validity of the signature found on the regulatory
     5         kx  * database against the array 'keys'. Returns 1 if there exists
     5         kx  * at least one key in the array such that the signature is valid
     5         kx  * against that key; 0 otherwise.
     5         kx  */
     5         kx 
     5         kx #ifdef USE_OPENSSL
     5         kx int reglib_verify_db_signature(uint8_t *db, size_t dblen, size_t siglen)
     5         kx {
     5         kx 	RSA *rsa = NULL;
     5         kx 	BIGNUM *rsa_e = NULL, *rsa_n = NULL;
     5         kx 	uint8_t hash[SHA_DIGEST_LENGTH];
     5         kx 	unsigned int i;
     5         kx 	int ok = 0;
     5         kx 	DIR *pubkey_dir;
     5         kx 	struct dirent *nextfile;
     5         kx 	FILE *keyfile;
     5         kx 	char filename[PATH_MAX];
     5         kx 
     5         kx 	if (SHA1(db, dblen, hash) != hash) {
     5         kx 		fprintf(stderr, "Failed to calculate SHA1 sum.\n");
     5         kx 		goto out;
     5         kx 	}
     5         kx 
     5         kx 	for (i = 0; (i < sizeof(keys)/sizeof(keys[0])) && (!ok); i++) {
     5         kx 		rsa = RSA_new();
     5         kx 		if (!rsa) {
     5         kx 			fprintf(stderr, "Failed to create RSA key.\n");
     5         kx 			goto out;
     5         kx 		}
     5         kx 
     5         kx 		rsa_e = BN_bin2bn(keys[i].e, keys[i].len_e, NULL);
     5         kx 		if (!rsa_e) {
     5         kx 			fprintf(stderr, "Failed to convert value for RSA e.\n");
     5         kx 			goto out;
     5         kx 		}
     5         kx 		rsa_n = BN_bin2bn(keys[i].n, keys[i].len_n, NULL);
     5         kx 		if (!rsa_n) {
     5         kx 			fprintf(stderr, "Failed to convert value for RSA n.\n");
     5         kx 			goto out;
     5         kx 		}
     5         kx 
     5         kx #if OPENSSL_VERSION_NUMBER < 0x10100000L
     5         kx 		rsa->e = rsa_e;
     5         kx 		rsa->n = rsa_n;
     5         kx #else
     5         kx 		if (RSA_set0_key(rsa, rsa_n, rsa_e, NULL) != 1) {
     5         kx 			fprintf(stderr, "Failed to set RSA key.\n");
     5         kx 			goto out;
     5         kx 		}
     5         kx #endif
     5         kx 		/* BIGNUMs now owned by the RSA object */
     5         kx 		rsa_e = NULL;
     5         kx 		rsa_n = NULL;
     5         kx 
     5         kx 		ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
     5         kx 				db + dblen, siglen, rsa) == 1;
     5         kx 
     5         kx 		RSA_free(rsa);
     5         kx 		rsa = NULL;
     5         kx 	}
     5         kx 	if (!ok && (pubkey_dir = opendir(PUBKEY_DIR))) {
     5         kx 		while (!ok && (nextfile = readdir(pubkey_dir))) {
     5         kx 			snprintf(filename, PATH_MAX, "%s/%s", PUBKEY_DIR,
     5         kx 				nextfile->d_name);
     5         kx 			if ((keyfile = fopen(filename, "rb"))) {
     5         kx 				rsa = PEM_read_RSA_PUBKEY(keyfile,
     5         kx 					NULL, NULL, NULL);
     5         kx 				if (rsa)
     5         kx 					ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
     5         kx 						db + dblen, siglen, rsa) == 1;
     5         kx 				RSA_free(rsa);
     5         kx 				rsa = NULL;
     5         kx 				fclose(keyfile);
     5         kx 			}
     5         kx 		}
     5         kx 		closedir(pubkey_dir);
     5         kx 	}
     5         kx 
     5         kx 	if (!ok)
     5         kx 		fprintf(stderr, "Database signature verification failed.\n");
     5         kx 
     5         kx out:
     5         kx 	RSA_free(rsa);
     5         kx 	BN_free(rsa_e);
     5         kx 	BN_free(rsa_n);
     5         kx 	return ok;
     5         kx }
     5         kx #endif /* USE_OPENSSL */
     5         kx 
     5         kx #ifdef USE_GCRYPT
     5         kx int reglib_verify_db_signature(uint8_t *db, size_t dblen, size_t siglen)
     5         kx {
     5         kx 	gcry_mpi_t mpi_e, mpi_n;
     5         kx 	gcry_sexp_t rsa, signature, data;
     5         kx 	uint8_t hash[20];
     5         kx 	unsigned int i;
     5         kx 	int ok = 0;
     5         kx 
     5         kx 	/* initialise */
     5         kx 	gcry_check_version(NULL);
     5         kx 
     5         kx 	/* hash the db */
     5         kx 	gcry_md_hash_buffer(GCRY_MD_SHA1, hash, db, dblen);
     5         kx 
     5         kx 	if (gcry_sexp_build(&data, NULL, "(data (flags pkcs1) (hash sha1 %b))",
     5         kx 			    20, hash)) {
     5         kx 		fprintf(stderr, "Failed to build data S-expression.\n");
     5         kx 		return ok;
     5         kx 	}
     5         kx 
     5         kx 	if (gcry_sexp_build(&signature, NULL, "(sig-val (rsa (s %b)))",
     5         kx 			    siglen, db + dblen)) {
     5         kx 		fprintf(stderr, "Failed to build signature S-expression.\n");
     5         kx 		gcry_sexp_release(data);
     5         kx 		return ok;
     5         kx 	}
     5         kx 
     5         kx 	for (i = 0; (i < sizeof(keys)/sizeof(keys[0])) && (!ok); i++) {
     5         kx 		if (gcry_mpi_scan(&mpi_e, GCRYMPI_FMT_USG,
     5         kx 				keys[i].e, keys[i].len_e, NULL) ||
     5         kx 		    gcry_mpi_scan(&mpi_n, GCRYMPI_FMT_USG,
     5         kx 				keys[i].n, keys[i].len_n, NULL)) {
     5         kx 			fprintf(stderr, "Failed to convert numbers.\n");
     5         kx 			goto out;
     5         kx 		}
     5         kx 
     5         kx 		if (gcry_sexp_build(&rsa, NULL,
     5         kx 				    "(public-key (rsa (n %m) (e %m)))",
     5         kx 				    mpi_n, mpi_e)) {
     5         kx 			fprintf(stderr, "Failed to build RSA S-expression.\n");
     5         kx 			gcry_mpi_release(mpi_e);
     5         kx 			gcry_mpi_release(mpi_n);
     5         kx 			goto out;
     5         kx 		}
     5         kx 
     5         kx 		ok = gcry_pk_verify(signature, data, rsa) == 0;
     5         kx 		gcry_mpi_release(mpi_e);
     5         kx 		gcry_mpi_release(mpi_n);
     5         kx 		gcry_sexp_release(rsa);
     5         kx 	}
     5         kx 
     5         kx 	if (!ok)
     5         kx 		fprintf(stderr, "Database signature verification failed.\n");
     5         kx 
     5         kx out:
     5         kx 	gcry_sexp_release(data);
     5         kx 	gcry_sexp_release(signature);
     5         kx 	return ok;
     5         kx }
     5         kx #endif /* USE_GCRYPT */
     5         kx 
     5         kx #if !defined(USE_OPENSSL) && !defined(USE_GCRYPT)
     5         kx int reglib_verify_db_signature(uint8_t *db, size_t dblen, size_t siglen)
     5         kx {
     5         kx 	return 1;
     5         kx }
     5         kx #endif
     5         kx 
     5         kx const struct reglib_regdb_ctx *reglib_malloc_regdb_ctx(const char *regdb_file)
     5         kx {
     5         kx 	struct regdb_file_header *header;
     5         kx 	struct reglib_regdb_ctx *ctx;
     5         kx 
     5         kx 	ctx = malloc(sizeof(struct reglib_regdb_ctx));
     5         kx 	if (!ctx)
     5         kx 		return NULL;
     5         kx 
     5         kx 	memset(ctx, 0, sizeof(struct reglib_regdb_ctx));
     5         kx 
     5         kx 	ctx->fd = open(regdb_file, O_RDONLY);
     5         kx 
     5         kx 	if (ctx->fd < 0) {
     5         kx 		free(ctx);
     5         kx 		return NULL;
     5         kx 	}
     5         kx 
     5         kx 	if (fstat(ctx->fd, &ctx->stat)) {
     5         kx 		close(ctx->fd);
     5         kx 		free(ctx);
     5         kx 		return NULL;
     5         kx 	}
     5         kx 
     5         kx 	ctx->real_dblen = ctx->stat.st_size;
     5         kx 
     5         kx 	ctx->db = mmap(NULL, ctx->real_dblen, PROT_READ,
     5         kx 		       MAP_PRIVATE, ctx->fd, 0);
     5         kx 	if (ctx->db == MAP_FAILED) {
     5         kx 		close(ctx->fd);
     5         kx 		free(ctx);
     5         kx 		return NULL;
     5         kx 	}
     5         kx 
     5         kx 	ctx->header = reglib_get_file_ptr(ctx->db, ctx->real_dblen,
     5         kx 					  sizeof(struct regdb_file_header),
     5         kx 					  0);
     5         kx 	header = ctx->header;
     5         kx 
     5         kx 	if (ntohl(header->magic) != REGDB_MAGIC)
     5         kx 		goto err_out;
     5         kx 
     5         kx 	if (ntohl(header->version) != REGDB_VERSION)
     5         kx 		goto err_out;
     5         kx 
     5         kx 	ctx->siglen = ntohl(header->signature_length);
     5         kx 
     5         kx 	if (ctx->siglen > ctx->real_dblen - sizeof(*header))
     5         kx 		goto err_out;
     5         kx 
     5         kx 	/* The actual dblen does not take into account the signature */
     5         kx 	ctx->dblen = ctx->real_dblen - ctx->siglen;
     5         kx 
     5         kx 	/* verify signature */
     5         kx 	if (!reglib_verify_db_signature(ctx->db, ctx->dblen, ctx->siglen))
     5         kx 		goto err_out;
     5         kx 
     5         kx 	ctx->verified = true;
     5         kx 	ctx->num_countries = ntohl(header->reg_country_num);
     5         kx 	ctx->countries = reglib_get_file_ptr(ctx->db,
     5         kx 					     ctx->dblen,
     5         kx 					     sizeof(struct regdb_file_reg_country) * ctx->num_countries,
     5         kx 					     header->reg_country_ptr);
     5         kx 	return ctx;
     5         kx 
     5         kx err_out:
     5         kx 	close(ctx->fd);
     5         kx 	munmap(ctx->db, ctx->real_dblen);
     5         kx 	free(ctx);
     5         kx 	return NULL;
     5         kx }
     5         kx 
     5         kx void reglib_free_regdb_ctx(const struct reglib_regdb_ctx *regdb_ctx)
     5         kx {
     5         kx 	struct reglib_regdb_ctx *ctx;
     5         kx 
     5         kx 	if (!regdb_ctx)
     5         kx 		return;
     5         kx 
     5         kx 	ctx = (struct reglib_regdb_ctx *) regdb_ctx;
     5         kx 
     5         kx 	memset(ctx, 0, sizeof(struct reglib_regdb_ctx));
     5         kx 	close(ctx->fd);
     5         kx 	munmap(ctx->db, ctx->real_dblen);
     5         kx 	free(ctx);
     5         kx }
     5         kx 
     5         kx static void reg_rule2rd(uint8_t *db, size_t dblen,
     5         kx 	uint32_t ruleptr, struct ieee80211_reg_rule *rd_reg_rule)
     5         kx {
     5         kx 	struct regdb_file_reg_rule *rule;
     5         kx 	struct regdb_file_freq_range *freq;
     5         kx 	struct regdb_file_power_rule *power;
     5         kx 
     5         kx 	struct ieee80211_freq_range *rd_freq_range = &rd_reg_rule->freq_range;
     5         kx 	struct ieee80211_power_rule *rd_power_rule = &rd_reg_rule->power_rule;
     5         kx 
     5         kx 	rule  = reglib_get_file_ptr(db, dblen, sizeof(*rule), ruleptr);
     5         kx 	freq  = reglib_get_file_ptr(db, dblen, sizeof(*freq), rule->freq_range_ptr);
     5         kx 	power = reglib_get_file_ptr(db, dblen, sizeof(*power), rule->power_rule_ptr);
     5         kx 
     5         kx 	rd_freq_range->start_freq_khz = ntohl(freq->start_freq);
     5         kx 	rd_freq_range->end_freq_khz = ntohl(freq->end_freq);
     5         kx 	rd_freq_range->max_bandwidth_khz = ntohl(freq->max_bandwidth);
     5         kx 
     5         kx 	rd_power_rule->max_antenna_gain = ntohl(power->max_antenna_gain);
     5         kx 	rd_power_rule->max_eirp = ntohl(power->max_eirp);
     5         kx 
     5         kx 	rd_reg_rule->flags = ntohl(rule->flags);
     5         kx 
     5         kx 	if (rd_reg_rule->flags & RRF_NO_IR_ALL)
     5         kx 		rd_reg_rule->flags |= RRF_NO_IR_ALL;
     5         kx }
     5         kx 
     5         kx /* Converts a file regdomain to ieee80211_regdomain, easier to manage */
     5         kx const static struct ieee80211_regdomain *
     5         kx country2rd(const struct reglib_regdb_ctx *ctx,
     5         kx 	   struct regdb_file_reg_country *country)
     5         kx {
     5         kx 	struct regdb_file_reg_rules_collection *rcoll;
     5         kx 	struct ieee80211_regdomain *rd;
     5         kx 	unsigned int i, num_rules;
     5         kx 	size_t size_of_rd;
     5         kx 
     5         kx 	rcoll = reglib_get_file_ptr(ctx->db, ctx->dblen, sizeof(*rcoll),
     5         kx 				    country->reg_collection_ptr);
     5         kx 	num_rules = ntohl(rcoll->reg_rule_num);
     5         kx 	/* re-get pointer with sanity checking for num_rules */
     5         kx 	rcoll = reglib_get_file_ptr(ctx->db, ctx->dblen,
     5         kx 				    reglib_array_len(sizeof(*rcoll), num_rules,
     5         kx 						     sizeof(uint32_t)),
     5         kx 				    country->reg_collection_ptr);
     5         kx 
     5         kx 	size_of_rd = reglib_array_len(sizeof(struct ieee80211_regdomain),
     5         kx 				      num_rules,
     5         kx 				      sizeof(struct ieee80211_reg_rule));
     5         kx 
     5         kx 	rd = malloc(size_of_rd);
     5         kx 	if (!rd)
     5         kx 		return NULL;
     5         kx 
     5         kx 	memset(rd, 0, size_of_rd);
     5         kx 
     5         kx 	rd->alpha2[0] = country->alpha2[0];
     5         kx 	rd->alpha2[1] = country->alpha2[1];
     5         kx 	rd->dfs_region = country->creqs & 0x3;
     5         kx 	rd->n_reg_rules = num_rules;
     5         kx 
     5         kx 	for (i = 0; i < num_rules; i++) {
     5         kx 		reg_rule2rd(ctx->db, ctx->dblen, rcoll->reg_rule_ptrs[i],
     5         kx 			&rd->reg_rules[i]);
     5         kx 	}
     5         kx 
     5         kx 	return rd;
     5         kx }
     5         kx 
     5         kx const struct ieee80211_regdomain *
     5         kx reglib_get_rd_idx(unsigned int idx, const struct reglib_regdb_ctx *ctx)
     5         kx {
     5         kx 	struct regdb_file_reg_country *country;
     5         kx 
     5         kx 	if (!ctx)
     5         kx 		return NULL;
     5         kx 
     5         kx 	if (idx >= ctx->num_countries)
     5         kx 		return NULL;
     5         kx 
     5         kx 	country = ctx->countries + idx;
     5         kx 
     5         kx 	return country2rd(ctx, country);
     5         kx }
     5         kx 
     5         kx const struct ieee80211_regdomain *
     5         kx reglib_get_rd_alpha2(const char *alpha2, const char *file)
     5         kx {
     5         kx 	const struct reglib_regdb_ctx *ctx;
     5         kx 	const struct ieee80211_regdomain *rd = NULL;
     5         kx 	struct regdb_file_reg_country *country;
     5         kx 	bool found_country = false;
     5         kx 	unsigned int i;
     5         kx 
     5         kx 	ctx = reglib_malloc_regdb_ctx(file);
     5         kx 	if (!ctx)
     5         kx 		return NULL;
     5         kx 
     5         kx 	for (i = 0; i < ctx->num_countries; i++) {
     5         kx 		country = ctx->countries + i;
     5         kx 		if (memcmp(country->alpha2, alpha2, 2) == 0) {
     5         kx 			found_country = 1;
     5         kx 			break;
     5         kx 		}
     5         kx 	}
     5         kx 
     5         kx 	if (!found_country)
     5         kx 		goto out;
     5         kx 
     5         kx 	rd = country2rd(ctx, country);
     5         kx 	if (!rd)
     5         kx 		goto out;
     5         kx 
     5         kx out:
     5         kx 	reglib_free_regdb_ctx(ctx);
     5         kx 	return rd;
     5         kx }
     5         kx 
     5         kx /* Sanity check on a regulatory rule */
     5         kx static int is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
     5         kx {
     5         kx 	const struct ieee80211_freq_range *freq_range = &rule->freq_range;
     5         kx 	uint32_t freq_diff;
     5         kx 
     5         kx 	if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0)
     5         kx 		return 0;
     5         kx 
     5         kx 	if (freq_range->start_freq_khz > freq_range->end_freq_khz)
     5         kx 		return 0;
     5         kx 
     5         kx 	freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
     5         kx 
     5         kx 	if (freq_range->end_freq_khz <= freq_range->start_freq_khz ||
     5         kx 	    freq_range->max_bandwidth_khz > freq_diff)
     5         kx 		return 0;
     5         kx 
     5         kx 	return 1;
     5         kx }
     5         kx 
     5         kx int reglib_is_valid_rd(const struct ieee80211_regdomain *rd)
     5         kx {
     5         kx 	const struct ieee80211_reg_rule *reg_rule = NULL;
     5         kx 	unsigned int i;
     5         kx 
     5         kx 	if (!rd->n_reg_rules)
     5         kx 		return 0;
     5         kx 
     5         kx 	for (i = 0; i < rd->n_reg_rules; i++) {
     5         kx 		reg_rule = &rd->reg_rules[i];
     5         kx 		if (!is_valid_reg_rule(reg_rule))
     5         kx 		return 0;
     5         kx 	}
     5         kx 	return 1;
     5         kx }
     5         kx 
     5         kx static int reg_rules_union(const struct ieee80211_reg_rule *rule1,
     5         kx 			   const struct ieee80211_reg_rule *rule2,
     5         kx 			   struct ieee80211_reg_rule *union_rule)
     5         kx {
     5         kx 	const struct ieee80211_freq_range *freq_range1, *freq_range2;
     5         kx 	struct ieee80211_freq_range *freq_range;
     5         kx 	const struct ieee80211_power_rule *power_rule1, *power_rule2;
     5         kx 	struct ieee80211_power_rule *power_rule;
     5         kx 
     5         kx 	freq_range1 = &rule1->freq_range;
     5         kx 	freq_range2 = &rule2->freq_range;
     5         kx 	freq_range = &union_rule->freq_range;
     5         kx 
     5         kx 	power_rule1 = &rule1->power_rule;
     5         kx 	power_rule2 = &rule2->power_rule;
     5         kx 	power_rule = &union_rule->power_rule;
     5         kx 
     5         kx 
     5         kx 	if (freq_range1->end_freq_khz < freq_range2->start_freq_khz)
     5         kx 		return -EINVAL;
     5         kx 	if (freq_range2->end_freq_khz < freq_range1->start_freq_khz)
     5         kx 		return -EINVAL;
     5         kx 
     5         kx 	freq_range->start_freq_khz = reglib_min(freq_range1->start_freq_khz,
     5         kx 					 freq_range2->start_freq_khz);
     5         kx 	freq_range->end_freq_khz = reglib_max(freq_range1->end_freq_khz,
     5         kx 				       freq_range2->end_freq_khz);
     5         kx 	freq_range->max_bandwidth_khz = reglib_max(freq_range1->max_bandwidth_khz,
     5         kx 					    freq_range2->max_bandwidth_khz);
     5         kx 
     5         kx 	power_rule->max_eirp = reglib_max(power_rule1->max_eirp,
     5         kx 		power_rule2->max_eirp);
     5         kx 	power_rule->max_antenna_gain = reglib_max(power_rule1->max_antenna_gain,
     5         kx 		power_rule2->max_antenna_gain);
     5         kx 
     5         kx 	union_rule->flags = rule1->flags | rule2->flags;
     5         kx 
     5         kx 	if (!is_valid_reg_rule(union_rule))
     5         kx 		return -EINVAL;
     5         kx 
     5         kx 	return 0;
     5         kx }
     5         kx 
     5         kx /*
     5         kx  * Helper for reglib_intersect_rds(), this does the real
     5         kx  * mathematical intersection fun
     5         kx  */
     5         kx static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
     5         kx 			       const struct ieee80211_reg_rule *rule2,
     5         kx 			       struct ieee80211_reg_rule *intersected_rule)
     5         kx {
     5         kx 	const struct ieee80211_freq_range *freq_range1, *freq_range2;
     5         kx 	struct ieee80211_freq_range *freq_range;
     5         kx 	const struct ieee80211_power_rule *power_rule1, *power_rule2;
     5         kx 	struct ieee80211_power_rule *power_rule;
     5         kx 	uint32_t freq_diff;
     5         kx 
     5         kx 	freq_range1 = &rule1->freq_range;
     5         kx 	freq_range2 = &rule2->freq_range;
     5         kx 	freq_range = &intersected_rule->freq_range;
     5         kx 
     5         kx 	power_rule1 = &rule1->power_rule;
     5         kx 	power_rule2 = &rule2->power_rule;
     5         kx 	power_rule = &intersected_rule->power_rule;
     5         kx 
     5         kx 	freq_range->start_freq_khz = reglib_max(freq_range1->start_freq_khz,
     5         kx 					 freq_range2->start_freq_khz);
     5         kx 	freq_range->end_freq_khz = reglib_min(freq_range1->end_freq_khz,
     5         kx 				       freq_range2->end_freq_khz);
     5         kx 	freq_range->max_bandwidth_khz = reglib_min(freq_range1->max_bandwidth_khz,
     5         kx 					    freq_range2->max_bandwidth_khz);
     5         kx 
     5         kx 	freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
     5         kx 	if (freq_range->max_bandwidth_khz > freq_diff)
     5         kx 		freq_range->max_bandwidth_khz = freq_diff;
     5         kx 
     5         kx 	power_rule->max_eirp = reglib_min(power_rule1->max_eirp,
     5         kx 		power_rule2->max_eirp);
     5         kx 	power_rule->max_antenna_gain = reglib_min(power_rule1->max_antenna_gain,
     5         kx 		power_rule2->max_antenna_gain);
     5         kx 
     5         kx 	intersected_rule->flags = rule1->flags | rule2->flags;
     5         kx 
     5         kx 	if (!is_valid_reg_rule(intersected_rule))
     5         kx 		return -EINVAL;
     5         kx 
     5         kx 	return 0;
     5         kx }
     5         kx 
     5         kx /**
     5         kx  * reglib_intersect_rds - do the intersection between two regulatory domains
     5         kx  * @rd1: first regulatory domain
     5         kx  * @rd2: second regulatory domain
     5         kx  *
     5         kx  * Use this function to get the intersection between two regulatory domains.
     5         kx  * Once completed we will mark the alpha2 for the rd as intersected, "98",
     5         kx  * as no one single alpha2 can represent this regulatory domain.
     5         kx  *
     5         kx  * Returns a pointer to the regulatory domain structure which will hold the
     5         kx  * resulting intersection of rules between rd1 and rd2. We will
     5         kx  * malloc() this structure for you.
     5         kx  */
     5         kx struct ieee80211_regdomain *
     5         kx reglib_intersect_rds(const struct ieee80211_regdomain *rd1,
     5         kx 		     const struct ieee80211_regdomain *rd2)
     5         kx {
     5         kx 	int r;
     5         kx 	size_t size_of_regd;
     5         kx 	unsigned int x, y;
     5         kx 	unsigned int num_rules = 0, rule_idx = 0;
     5         kx 	const struct ieee80211_reg_rule *rule1, *rule2;
     5         kx 	struct ieee80211_reg_rule *intersected_rule;
     5         kx 	struct ieee80211_regdomain *rd;
     5         kx 	/* This is just a dummy holder to help us count */
     5         kx 	struct ieee80211_reg_rule irule;
     5         kx 
     5         kx 	/* Uses the stack temporarily for counter arithmetic */
     5         kx 	intersected_rule = &irule;
     5         kx 
     5         kx 	memset(intersected_rule, 0, sizeof(struct ieee80211_reg_rule));
     5         kx 
     5         kx 	if (!rd1 || !rd2)
     5         kx 		return NULL;
     5         kx 
     5         kx 	/* First we get a count of the rules we'll need, then we actually
     5         kx 	 * build them. This is to so we can malloc() and free() a
     5         kx 	 * regdomain once. The reason we use reg_rules_intersect() here
     5         kx 	 * is it will return -EINVAL if the rule computed makes no sense.
     5         kx 	 * All rules that do check out OK are valid. */
     5         kx 
     5         kx 	for (x = 0; x < rd1->n_reg_rules; x++) {
     5         kx 		rule1 = &rd1->reg_rules[x];
     5         kx 		for (y = 0; y < rd2->n_reg_rules; y++) {
     5         kx 			rule2 = &rd2->reg_rules[y];
     5         kx 			if (!reg_rules_intersect(rule1, rule2,
     5         kx 					intersected_rule))
     5         kx 				num_rules++;
     5         kx 			memset(intersected_rule, 0,
     5         kx 					sizeof(struct ieee80211_reg_rule));
     5         kx 		}
     5         kx 	}
     5         kx 
     5         kx 	if (!num_rules)
     5         kx 		return NULL;
     5         kx 
     5         kx 	size_of_regd = reglib_array_len(sizeof(struct ieee80211_regdomain),
     5         kx 					num_rules + 1,
     5         kx 					sizeof(struct ieee80211_reg_rule));
     5         kx 
     5         kx 	rd = malloc(size_of_regd);
     5         kx 	if (!rd)
     5         kx 		return NULL;
     5         kx 
     5         kx 	memset(rd, 0, size_of_regd);
     5         kx 
     5         kx 	for (x = 0; x < rd1->n_reg_rules; x++) {
     5         kx 		rule1 = &rd1->reg_rules[x];
     5         kx 		for (y = 0; y < rd2->n_reg_rules; y++) {
     5         kx 			rule2 = &rd2->reg_rules[y];
     5         kx 			/* This time around instead of using the stack lets
     5         kx 			 * write to the target rule directly saving ourselves
     5         kx 			 * a memcpy() */
     5         kx 			intersected_rule = &rd->reg_rules[rule_idx];
     5         kx 			r = reg_rules_intersect(rule1, rule2,
     5         kx 				intersected_rule);
     5         kx 			if (r)
     5         kx 				continue;
     5         kx 			rule_idx++;
     5         kx 		}
     5         kx 	}
     5         kx 
     5         kx 	if (rule_idx != num_rules) {
     5         kx 		free(rd);
     5         kx 		return NULL;
     5         kx 	}
     5         kx 
     5         kx 	rd->n_reg_rules = num_rules;
     5         kx 	rd->alpha2[0] = '9';
     5         kx 	rd->alpha2[1] = '9';
     5         kx 
     5         kx 	return rd;
     5         kx }
     5         kx 
     5         kx const struct ieee80211_regdomain *
     5         kx reglib_intersect_regdb(const struct reglib_regdb_ctx *ctx)
     5         kx {
     5         kx 	const struct ieee80211_regdomain *rd;
     5         kx 	struct ieee80211_regdomain *prev_rd_intsct = NULL, *rd_intsct = NULL;
     5         kx 	int intersected = 0;
     5         kx 	unsigned int idx = 0;
     5         kx 
     5         kx 	if (!ctx)
     5         kx 		return NULL;
     5         kx 
     5         kx 	reglib_for_each_country(rd, idx, ctx) {
     5         kx 		if (reglib_is_world_regdom((const char *) rd->alpha2)) {
     5         kx 			free((struct ieee80211_regdomain *) rd);
     5         kx 			continue;
     5         kx 		}
     5         kx 
     5         kx 		if (!prev_rd_intsct) {
     5         kx 			prev_rd_intsct = (struct ieee80211_regdomain *) rd;
     5         kx 			continue;
     5         kx 		}
     5         kx 
     5         kx 		if (rd_intsct) {
     5         kx 			free(prev_rd_intsct);
     5         kx 			prev_rd_intsct = (struct ieee80211_regdomain *) rd_intsct;
     5         kx 		}
     5         kx 
     5         kx 		rd_intsct = reglib_intersect_rds(prev_rd_intsct, rd);
     5         kx 		if (!rd_intsct) {
     5         kx 			free(prev_rd_intsct);
     5         kx 			free((struct ieee80211_regdomain *) rd);
     5         kx 			return NULL;
     5         kx 		}
     5         kx 
     5         kx 		intersected++;
     5         kx 		free((struct ieee80211_regdomain *) rd);
     5         kx 	}
     5         kx 
     5         kx 	if (!idx)
     5         kx 		return NULL;
     5         kx 
     5         kx 	if (intersected <= 0) {
     5         kx 		rd_intsct = prev_rd_intsct;
     5         kx 		prev_rd_intsct = NULL;
     5         kx 		if (idx > 1) {
     5         kx 			free(rd_intsct);
     5         kx 			return NULL;
     5         kx 		}
     5         kx 	}
     5         kx 
     5         kx 	if (prev_rd_intsct)
     5         kx 		free(prev_rd_intsct);
     5         kx 
     5         kx 	return rd_intsct;
     5         kx }
     5         kx 
     5         kx static const char *dfs_domain_name(enum regdb_dfs_regions region)
     5         kx {
     5         kx 	switch (region) {
     5         kx 	case REGDB_DFS_UNSET:
     5         kx 		return "DFS-UNSET";
     5         kx 	case REGDB_DFS_FCC:
     5         kx 		return "DFS-FCC";
     5         kx 	case REGDB_DFS_ETSI:
     5         kx 		return "DFS-ETSI";
     5         kx 	case REGDB_DFS_JP:
     5         kx 		return "DFS-JP";
     5         kx 	default:
     5         kx 		return "DFS-invalid";
     5         kx 	}
     5         kx }
     5         kx 
     5         kx static void print_reg_rule(const struct ieee80211_reg_rule *rule)
     5         kx {
     5         kx 	const struct ieee80211_freq_range *freq;
     5         kx 	const struct ieee80211_power_rule *power;
     5         kx 
     5         kx 	freq  = &rule->freq_range;
     5         kx 	power = &rule->power_rule;
     5         kx 
     5         kx 	printf("\t(%.3f - %.3f @ %.3f), ",
     5         kx 	       ((float)(freq->start_freq_khz))/1000.0,
     5         kx 	       ((float)(freq->end_freq_khz))/1000.0,
     5         kx 	       ((float)(freq->max_bandwidth_khz))/1000.0);
     5         kx 
     5         kx 	printf("(");
     5         kx 
     5         kx 	if (power->max_eirp)
     5         kx 		printf("%.2f)", ((float)(power->max_eirp)/100.0));
     5         kx 	else
     5         kx 		printf("N/A)");
     5         kx 
     5         kx 	if (rule->dfs_cac_ms)
     5         kx 		printf(", (%u)", rule->dfs_cac_ms);
     5         kx 	else
     5         kx 		printf(", (N/A)");
     5         kx 
     5         kx 	if (rule->flags & RRF_NO_OFDM)
     5         kx 		printf(", NO-OFDM");
     5         kx 	if (rule->flags & RRF_NO_CCK)
     5         kx 		printf(", NO-CCK");
     5         kx 	if (rule->flags & RRF_NO_INDOOR)
     5         kx 		printf(", NO-INDOOR");
     5         kx 	if (rule->flags & RRF_NO_OUTDOOR)
     5         kx 		printf(", NO-OUTDOOR");
     5         kx 	if (rule->flags & RRF_DFS)
     5         kx 		printf(", DFS");
     5         kx 	if (rule->flags & RRF_PTP_ONLY)
     5         kx 		printf(", PTP-ONLY");
     5         kx 	if (rule->flags & RRF_PTMP_ONLY)
     5         kx 		printf(", PTMP-ONLY");
     5         kx 	if (rule->flags & RRF_NO_IR_ALL)
     5         kx 		printf(", NO-IR");
     5         kx 	if (rule->flags & RRF_AUTO_BW)
     5         kx 		printf(", AUTO-BW");
     5         kx 
     5         kx 	printf("\n");
     5         kx }
     5         kx 
     5         kx void reglib_print_regdom(const struct ieee80211_regdomain *rd)
     5         kx {
     5         kx 	unsigned int i;
     5         kx 	printf("country %.2s: %s\n", rd->alpha2,
     5         kx 	       dfs_domain_name(rd->dfs_region));
     5         kx 	for (i = 0; i < rd->n_reg_rules; i++)
     5         kx 		print_reg_rule(&rd->reg_rules[i]);
     5         kx 	printf("\n");
     5         kx }
     5         kx 
     5         kx static unsigned int reglib_parse_dfs_region(char *dfs_region)
     5         kx {
     5         kx 	if (!dfs_region)
     5         kx 		return REGDB_DFS_UNSET;
     5         kx 
     5         kx 	if (strstr(dfs_region, "DFS-FCC"))
     5         kx 		return REGDB_DFS_FCC;
     5         kx 	if (strstr(dfs_region, "DFS-ETSI"))
     5         kx 		return REGDB_DFS_ETSI;
     5         kx 	if (strstr(dfs_region, "DFS-JP"))
     5         kx 		return REGDB_DFS_JP;
     5         kx 	return REGDB_DFS_UNSET;
     5         kx }
     5         kx 
     5         kx static uint32_t reglib_parse_rule_flag(char *flag_s)
     5         kx {
     5         kx 	uint32_t flags = 0;
     5         kx 
     5         kx 	if (strstr(flag_s, "NO-OFDM"))
     5         kx 		flags |= RRF_NO_OFDM;
     5         kx 	if (strstr(flag_s, "NO-CCK"))
     5         kx 		flags |= RRF_NO_CCK;
     5         kx 	if (strstr(flag_s, "NO-INDOOR"))
     5         kx 		flags |= RRF_NO_INDOOR;
     5         kx 	if (strstr(flag_s, "NO-OUTDOOR"))
     5         kx 		flags |= RRF_NO_OUTDOOR;
     5         kx 	if (strstr(flag_s, "DFS"))
     5         kx 		flags |= RRF_DFS;
     5         kx 	if (strstr(flag_s, "PTP-ONLY"))
     5         kx 		flags |= RRF_PTP_ONLY;
     5         kx 	if (strstr(flag_s, "PTMP-ONLY"))
     5         kx 		flags |= RRF_PTMP_ONLY;
     5         kx 	if (strstr(flag_s, "NO-IR"))
     5         kx 		flags |= RRF_NO_IR;
     5         kx 	if (strstr(flag_s, "AUTO-BW"))
     5         kx 		flags |= RRF_AUTO_BW;
     5         kx 
     5         kx 	return flags;
     5         kx }
     5         kx 
     5         kx static int reglib_parse_rule(FILE *fp, struct ieee80211_reg_rule *reg_rule)
     5         kx {
     5         kx 	char line[1024];
     5         kx 	char *line_p;
     5         kx 	int hits, r = 0;
     5         kx 	float start_freq_khz, end_freq_khz, max_bandwidth_khz, max_eirp;
     5         kx 	unsigned int dfs_cac_ms = 0;
     5         kx 
     5         kx 	memset(line, 0, sizeof(line));
     5         kx 	line_p = fgets(line, sizeof(line), fp);
     5         kx 	if (line_p != line)
     5         kx 		return -EINVAL;
     5         kx 
     5         kx 	/* First get start, end and bandwidth */
     5         kx 	hits = sscanf(line_p, "\t(%f - %f @ %f),",
     5         kx 		      &start_freq_khz,
     5         kx 		      &end_freq_khz,
     5         kx 		      &max_bandwidth_khz);
     5         kx 
     5         kx 	if (hits != 3)
     5         kx 		return -EINVAL;
     5         kx 
     5         kx 	reg_rule->freq_range.start_freq_khz =
     5         kx 		REGLIB_MHZ_TO_KHZ(start_freq_khz);
     5         kx 	reg_rule->freq_range.end_freq_khz =
     5         kx 		REGLIB_MHZ_TO_KHZ(end_freq_khz);
     5         kx 	reg_rule->freq_range.max_bandwidth_khz =
     5         kx 		REGLIB_MHZ_TO_KHZ(max_bandwidth_khz);
     5         kx 
     5         kx 	/* Next get eirp */
     5         kx 	strsep(&line_p, ",");
     5         kx 	if (!line_p) {
     5         kx 		fprintf(stderr, "not found eirp in line: %s\n", line);
     5         kx 		return -EINVAL;
     5         kx 	}
     5         kx 
     5         kx 	if (strstr(line_p, "mW")) {
     5         kx 		hits = sscanf(line_p, " (%f mW)", &max_eirp);
     5         kx 		if (hits != 1)
     5         kx 			return -EINVAL;
     5         kx 		reg_rule->power_rule.max_eirp =
     5         kx 			REGLIB_MW_TO_MBM(max_eirp);
     5         kx 	} else {
     5         kx 		hits = sscanf(line_p, " (%f)", &max_eirp);
     5         kx 		if (hits != 1)
     5         kx 			return -EINVAL;
     5         kx 		reg_rule->power_rule.max_eirp =
     5         kx 			REGLIB_DBM_TO_MBM(max_eirp);
     5         kx 	}
     5         kx 
     5         kx 	/* Next get optional arguments (flags ...) */
     5         kx 	strsep(&line_p, ",");
     5         kx 	if (line_p) {
     5         kx 		/* Check DFS CAC time */
     5         kx 		hits = sscanf(line_p, " (%u)", &dfs_cac_ms);
     5         kx 		if (hits == 1)
     5         kx 			reg_rule->dfs_cac_ms = dfs_cac_ms;
     5         kx 
     5         kx 		/* Check flags */
     5         kx 		reg_rule->flags = reglib_parse_rule_flag(line_p);
     5         kx 	}
     5         kx 
     5         kx 	return r;
     5         kx }
     5         kx 
     5         kx static uint32_t
     5         kx reglib_get_n_rules(FILE *fp, struct ieee80211_reg_rule *reg_rule)
     5         kx {
     5         kx 	uint32_t n_rules = 0;
     5         kx 	int r;
     5         kx 	bool save_debug = false;
     5         kx 
     5         kx 	save_debug = debug;
     5         kx 	debug = false;
     5         kx 
     5         kx 	while (1) {
     5         kx 		r = reglib_parse_rule(fp, reg_rule);
     5         kx 		if (r != 0)
     5         kx 			break;
     5         kx 		n_rules++;
     5         kx 	}
     5         kx 
     5         kx 	debug = save_debug;
     5         kx 
     5         kx 	return n_rules;
     5         kx }
     5         kx 
     5         kx static int reglib_parse_reg_rule(FILE *fp, struct ieee80211_reg_rule *reg_rule)
     5         kx {
     5         kx 	int r;
     5         kx 
     5         kx 	while (1) {
     5         kx 		r = reglib_parse_rule(fp, reg_rule);
     5         kx 		if (r != 0)
     5         kx 			continue;
     5         kx 		return 0;
     5         kx 	}
     5         kx }
     5         kx 
     5         kx static struct ieee80211_regdomain *
     5         kx reglib_parse_rules(FILE *fp, struct ieee80211_regdomain *trd)
     5         kx {
     5         kx 	struct ieee80211_regdomain *rd;
     5         kx 	struct ieee80211_reg_rule rule;
     5         kx 	struct ieee80211_reg_rule *reg_rule;
     5         kx 	fpos_t pos;
     5         kx 	unsigned int i;
     5         kx 	uint32_t size_of_regd = 0, num_rules = 0;
     5         kx 	int r;
     5         kx 
     5         kx 	memset(&rule, 0, sizeof(rule));
     5         kx 	reg_rule = &rule;
     5         kx 
     5         kx 	r = fgetpos(fp, &pos);
     5         kx 	if (r != 0) {
     5         kx 		fprintf(stderr, "fgetpos() failed: %s\n",
     5         kx 			strerror(errno));
     5         kx 		return NULL;
     5         kx 	}
     5         kx 
     5         kx 	num_rules = reglib_get_n_rules(fp, reg_rule);
     5         kx 	if (!num_rules)
     5         kx 		return NULL;
     5         kx 
     5         kx 	size_of_regd = reglib_array_len(sizeof(struct ieee80211_regdomain),
     5         kx 					num_rules + 1,
     5         kx 					sizeof(struct ieee80211_reg_rule));
     5         kx 	rd = malloc(size_of_regd);
     5         kx 	if (!rd)
     5         kx 		return NULL;
     5         kx 
     5         kx 	memset(rd, 0, size_of_regd);
     5         kx 	memcpy(rd, trd, sizeof(*trd));
     5         kx 
     5         kx 	rd->n_reg_rules = num_rules;
     5         kx 
     5         kx 	r = fsetpos(fp, &pos);
     5         kx 	if (r != 0) {
     5         kx 		fprintf(stderr, "fsetpos() failed: %s\n",
     5         kx 			strerror(errno));
     5         kx 		free(rd);
     5         kx 		return NULL;
     5         kx 	}
     5         kx 	for (i = 0; i < num_rules; i++) {
     5         kx 		struct ieee80211_reg_rule *rrule = &rd->reg_rules[i];
     5         kx 
     5         kx 		if (reglib_parse_reg_rule(fp, rrule) != 0) {
     5         kx 			fprintf(stderr, "rule parse failed\n");
     5         kx 			free(rd);
     5         kx 			return NULL;
     5         kx 		}
     5         kx 	}
     5         kx 	return rd;
     5         kx }
     5         kx 
     5         kx static int reglib_parse_country_dfs(char *line, struct ieee80211_regdomain *rd)
     5         kx {
     5         kx 	char dfs_region_alpha[9];
     5         kx 	char alpha2[2];
     5         kx 	int hits;
     5         kx 
     5         kx 	memset(rd, 0, sizeof(*rd));
     5         kx 	memset(alpha2, 0, sizeof(alpha2));
     5         kx 	memset(dfs_region_alpha, 0, sizeof(dfs_region_alpha));
     5         kx 
     5         kx 	hits = sscanf(line, "country %2[a-zA-Z0-9]:%*[ ]%s\n",
     5         kx 		      alpha2,
     5         kx 		      dfs_region_alpha);
     5         kx 	if (hits <= 0)
     5         kx 		return -EINVAL;
     5         kx 
     5         kx 	rd->alpha2[0] = alpha2[0];
     5         kx 	rd->alpha2[1] = alpha2[1];
     5         kx 	rd->dfs_region = reglib_parse_dfs_region(dfs_region_alpha);
     5         kx 
     5         kx 	return 0;
     5         kx }
     5         kx 
     5         kx struct ieee80211_regdomain *__reglib_parse_country(FILE *fp)
     5         kx {
     5         kx 	struct ieee80211_regdomain *rd;
     5         kx 	struct ieee80211_regdomain tmp_rd;
     5         kx 	char line[1024];
     5         kx 	char *line_p;
     5         kx 	int r = 0;
     5         kx 
     5         kx 	memset(&tmp_rd, 0, sizeof(tmp_rd));
     5         kx 	memset(line, 0, sizeof(line));
     5         kx 
     5         kx 	line_p = fgets(line, sizeof(line), fp);
     5         kx 
     5         kx 	if (line_p != line) {
     5         kx 		return NULL;
     5         kx 	}
     5         kx 
     5         kx 	/* Country */
     5         kx 	r = reglib_parse_country_dfs(line_p, &tmp_rd);
     5         kx 	if (r != 0) {
     5         kx 		fprintf(stderr, "Invalid country line: %s", line);
     5         kx 		return NULL;
     5         kx 	}
     5         kx 
     5         kx 	/* Rules */
     5         kx 	rd = reglib_parse_rules(fp, &tmp_rd);
     5         kx 
     5         kx 	return rd;
     5         kx }
     5         kx 
     5         kx static int reglib_find_next_country_stream(FILE *fp)
     5         kx {
     5         kx 	fpos_t prev_pos;
     5         kx 	int r;
     5         kx 	unsigned int i = 0;
     5         kx 
     5         kx 	while(1) {
     5         kx 		char line[1024];
     5         kx 		char *line_p;
     5         kx 
     5         kx 		r = fgetpos(fp, &prev_pos);
     5         kx 		if (r != 0) {
     5         kx 			fprintf(stderr, "fgetpos() failed: %s\n",
     5         kx 				strerror(errno));
     5         kx 			return r;
     5         kx 		}
     5         kx 
     5         kx 		memset(line, 0, sizeof(line));
     5         kx 
     5         kx 		line_p = fgets(line, sizeof(line), fp);
     5         kx 		if (line_p == line) {
     5         kx 			if (strspn(line, "\n") == strlen(line)) {
     5         kx 				i++;
     5         kx 				continue;
     5         kx 			}
     5         kx 			if (strncmp(line, "country", 7) != 0)
     5         kx 				continue;
     5         kx 			r = fsetpos(fp, &prev_pos);
     5         kx 			if (r != 0) {
     5         kx 				fprintf(stderr, "fsetpos() failed: %s\n",
     5         kx 					strerror(errno));
     5         kx 				return r;
     5         kx 			}
     5         kx 			return 0;
     5         kx 		} else
     5         kx 			return EOF;
     5         kx 	}
     5         kx }
     5         kx 
     5         kx struct ieee80211_regdomain *reglib_parse_country(FILE *fp)
     5         kx {
     5         kx 	int r;
     5         kx 
     5         kx 	r = reglib_find_next_country_stream(fp);
     5         kx 	if (r != 0)
     5         kx 		return NULL;
     5         kx 	return __reglib_parse_country(fp);
     5         kx }
     5         kx 
     5         kx FILE *reglib_create_parse_stream(FILE *f)
     5         kx {
     5         kx 	unsigned int lines = 0;
     5         kx 	FILE *fp;
     5         kx 
     5         kx 	fp = tmpfile();
     5         kx 	if (errno) {
     5         kx 		fprintf(stderr, "%s\n", strerror(errno));
     5         kx 		return NULL;
     5         kx 	}
     5         kx 
     5         kx 	while(1) {
     5         kx 		char line[1024];
     5         kx 		char *line_p;
     5         kx 
     5         kx 		line_p = fgets(line, sizeof(line), f);
     5         kx 		if (line_p == line) {
     5         kx 			if (strchr(line, '#') == NULL) {
     5         kx 				fputs(line, fp);
     5         kx 				lines++;
     5         kx 			}
     5         kx 			continue;
     5         kx 		} else
     5         kx 			break;
     5         kx 	}
     5         kx 
     5         kx 	rewind(fp);
     5         kx 	fflush(fp);
     5         kx 
     5         kx 	return fp;
     5         kx }
     5         kx 
     5         kx /*
     5         kx  * Just whatever for now, nothing formal, but note that as bands
     5         kx  * grow we'll want to make this a bit more formal somehow.
     5         kx  */
     5         kx static uint32_t reglib_deduce_band(uint32_t start_freq_khz)
     5         kx {
     5         kx 	uint32_t freq_mhz = REGLIB_KHZ_TO_MHZ(start_freq_khz);
     5         kx 
     5         kx 	if (freq_mhz >= 4000)
     5         kx 		return 5;
     5         kx 	if (freq_mhz > 2000 && freq_mhz < 4000)
     5         kx 		return 2;
     5         kx 	if (freq_mhz > 50000)
     5         kx 		return 60;
     5         kx 	return 1234;
     5         kx }
     5         kx 
     5         kx /*
     5         kx  * The idea behind a rule key is that if two rule keys share the
     5         kx  * same key they can be merged together if their frequencies overlap.
     5         kx  */
     5         kx static uint64_t reglib_rule_key(struct ieee80211_reg_rule *reg_rule)
     5         kx {
     5         kx 	struct ieee80211_power_rule *power_rule;
     5         kx 	struct ieee80211_freq_range *freq_range;
     5         kx 	uint32_t band;
     5         kx 	uint32_t key;
     5         kx 
     5         kx 	freq_range = &reg_rule->freq_range;
     5         kx 	band = reglib_deduce_band(freq_range->start_freq_khz);
     5         kx 
     5         kx 	power_rule = &reg_rule->power_rule;
     5         kx 
     5         kx 	key = ((power_rule->max_eirp ^  0) <<  0) ^
     5         kx 	      ((reg_rule->flags      ^  8) <<  8) ^
     5         kx 	      ((band                 ^ 16) << 16);
     5         kx 
     5         kx 	return key;
     5         kx }
     5         kx 
     5         kx struct reglib_optimize_map {
     5         kx 	bool optimized;
     5         kx 	uint32_t key;
     5         kx };
     5         kx 
     5         kx /* Does the provided rule suffice both of the other two */
     5         kx static int reglib_opt_rule_fit(struct ieee80211_reg_rule *rule1,
     5         kx 			       struct ieee80211_reg_rule *rule2,
     5         kx 			       struct ieee80211_reg_rule *opt_rule)
     5         kx {
     5         kx 	struct ieee80211_reg_rule interesected_rule;
     5         kx 	struct ieee80211_reg_rule *int_rule;
     5         kx 	int r;
     5         kx 
     5         kx 	memset(&interesected_rule, 0, sizeof(struct ieee80211_reg_rule));
     5         kx 	int_rule = &interesected_rule;
     5         kx 
     5         kx 	r = reg_rules_intersect(rule1, opt_rule, int_rule);
     5         kx 	if (r != 0)
     5         kx 		return r;
     5         kx 	r = reg_rules_intersect(rule2, opt_rule, int_rule);
     5         kx 	if (r != 0)
     5         kx 		return r;
     5         kx 
     5         kx 	return 0;
     5         kx }
     5         kx 
     5         kx static int reg_rule_optimize(struct ieee80211_reg_rule *rule1,
     5         kx 			     struct ieee80211_reg_rule *rule2,
     5         kx 			     struct ieee80211_reg_rule *opt_rule)
     5         kx {
     5         kx 	int r;
     5         kx 
     5         kx 	r = reg_rules_union(rule1, rule2, opt_rule);
     5         kx 	if (r != 0)
     5         kx 		return r;
     5         kx 	r = reglib_opt_rule_fit(rule1, rule2, opt_rule);
     5         kx 	if (r != 0)
     5         kx 		return r;
     5         kx 
     5         kx 	return 0;
     5         kx }
     5         kx 
     5         kx /*
     5         kx  * Here's the math explanation:
     5         kx  *
     5         kx  * This takes each pivot frequency on the regulatory domain, computes
     5         kx  * the union between it each regulatory rule on the regulatory domain
     5         kx  * sequentially, and after that it tries to verify that the pivot frequency
     5         kx  * fits on it by computing an intersection between it and the union, if
     5         kx  * a rule exist as a possible intersection then we know the rule can be
     5         kx  * subset of the combination of the two frequency ranges (union) computed.
     5         kx  */
     5         kx static unsigned int reg_rule_optimize_rd(struct ieee80211_regdomain *rd,
     5         kx 					 unsigned int rule_idx,
     5         kx 					 struct ieee80211_reg_rule *opt_rule,
     5         kx 					 struct reglib_optimize_map *opt_map)
     5         kx {
     5         kx 	unsigned int i;
     5         kx 	struct ieee80211_reg_rule *rule1;
     5         kx 	struct ieee80211_reg_rule *rule2;
     5         kx 
     5         kx 	struct ieee80211_reg_rule tmp_optimized_rule;
     5         kx 	struct ieee80211_reg_rule *tmp_opt_rule;
     5         kx 
     5         kx 	struct ieee80211_reg_rule *target_rule;
     5         kx 
     5         kx 	unsigned int optimized = 0;
     5         kx 	int r;
     5         kx 
     5         kx 	if (rule_idx > rd->n_reg_rules)
     5         kx 		return 0;
     5         kx 
     5         kx 	rule1 = &rd->reg_rules[rule_idx];
     5         kx 
     5         kx 	memset(&tmp_optimized_rule, 0, sizeof(struct ieee80211_reg_rule));
     5         kx 	tmp_opt_rule = &tmp_optimized_rule;
     5         kx 
     5         kx 	memset(opt_rule, 0, sizeof(*opt_rule));
     5         kx 
     5         kx 	for (i = 0; i < rd->n_reg_rules; i++) {
     5         kx 		if (rule_idx == i)
     5         kx 			continue;
     5         kx 		rule2 = &rd->reg_rules[i];
     5         kx 		if (opt_map[rule_idx].key != opt_map[i].key)
     5         kx 			continue;
     5         kx 
     5         kx 		target_rule = optimized ? opt_rule : rule1;
     5         kx 		r = reg_rule_optimize(target_rule, rule2, tmp_opt_rule);
     5         kx 		if (r != 0)
     5         kx 			continue;
     5         kx 		memcpy(opt_rule, tmp_opt_rule, sizeof(*tmp_opt_rule));
     5         kx 
     5         kx 		if (!opt_map[i].optimized) {
     5         kx 			opt_map[i].optimized = true;
     5         kx 			optimized++;
     5         kx 		}
     5         kx 		if (!opt_map[rule_idx].optimized) {
     5         kx 			opt_map[rule_idx].optimized = true;
     5         kx 			optimized++;
     5         kx 		}
     5         kx 	}
     5         kx 	return optimized;
     5         kx }
     5         kx 
     5         kx struct ieee80211_regdomain *
     5         kx reglib_optimize_regdom(struct ieee80211_regdomain *rd)
     5         kx {
     5         kx 	struct ieee80211_regdomain *opt_rd = NULL;
     5         kx 	struct ieee80211_reg_rule *reg_rule;
     5         kx 	struct ieee80211_reg_rule *reg_rule_dst;
     5         kx 	struct ieee80211_reg_rule optimized_reg_rule;
     5         kx 	struct ieee80211_reg_rule *opt_reg_rule;
     5         kx 	struct reglib_optimize_map *opt_map;
     5         kx 	unsigned int i, idx = 0, non_opt = 0, opt = 0;
     5         kx 	size_t num_rules, size_of_regd, size_of_opt_map;
     5         kx 	unsigned int num_opts = 0;
     5         kx 
     5         kx 	size_of_opt_map = (rd->n_reg_rules + 2) *
     5         kx 		sizeof(struct reglib_optimize_map);
     5         kx 	opt_map = malloc(size_of_opt_map);
     5         kx 	if (!opt_map)
     5         kx 		return NULL;
     5         kx 
     5         kx 	memset(opt_map, 0, size_of_opt_map);
     5         kx 	memset(&optimized_reg_rule, 0, sizeof(struct ieee80211_reg_rule));
     5         kx 
     5         kx 	opt_reg_rule = &optimized_reg_rule;
     5         kx 
     5         kx 	for (i = 0; i < rd->n_reg_rules; i++) {
     5         kx 		reg_rule = &rd->reg_rules[i];
     5         kx 		opt_map[i].key = reglib_rule_key(reg_rule);
     5         kx 	}
     5         kx 	for (i = 0; i < rd->n_reg_rules; i++) {
     5         kx 		reg_rule = &rd->reg_rules[i];
     5         kx 		if (opt_map[i].optimized)
     5         kx 			continue;
     5         kx 		num_opts = reg_rule_optimize_rd(rd, i, opt_reg_rule, opt_map);
     5         kx 		if (!num_opts)
     5         kx 			non_opt++;
     5         kx 		else
     5         kx 			opt += (num_opts ? 1 : 0);
     5         kx 	}
     5         kx 
     5         kx 	num_rules = non_opt + opt;
     5         kx 
     5         kx 	if (num_rules > rd->n_reg_rules)
     5         kx 		goto fail_opt_map;
     5         kx 
     5         kx 	size_of_regd = reglib_array_len(sizeof(struct ieee80211_regdomain),
     5         kx 					num_rules + 1,
     5         kx 					sizeof(struct ieee80211_reg_rule));
     5         kx 
     5         kx 	opt_rd = malloc(size_of_regd);
     5         kx 	if (!opt_rd)
     5         kx 		goto fail_opt_map;
     5         kx 	memset(opt_rd, 0, size_of_regd);
     5         kx 
     5         kx 	opt_rd->n_reg_rules = num_rules;
     5         kx 	opt_rd->alpha2[0] = rd->alpha2[0];
     5         kx 	opt_rd->alpha2[1] = rd->alpha2[1];
     5         kx 	opt_rd->dfs_region = rd->dfs_region;
     5         kx 
     5         kx 	memset(opt_map, 0, size_of_opt_map);
     5         kx 	memset(&optimized_reg_rule, 0, sizeof(struct ieee80211_reg_rule));
     5         kx 
     5         kx 	opt_reg_rule = &optimized_reg_rule;
     5         kx 
     5         kx 	for (i = 0; i < rd->n_reg_rules; i++) {
     5         kx 		reg_rule = &rd->reg_rules[i];
     5         kx 		opt_map[i].key = reglib_rule_key(reg_rule);
     5         kx 	}
     5         kx 
     5         kx 	for (i = 0; i < rd->n_reg_rules; i++) {
     5         kx 		reg_rule = &rd->reg_rules[i];
     5         kx 		reg_rule_dst = &opt_rd->reg_rules[idx];
     5         kx 		if (opt_map[i].optimized)
     5         kx 			continue;
     5         kx 		num_opts = reg_rule_optimize_rd(rd, i, opt_reg_rule, opt_map);
     5         kx 		if (!num_opts)
     5         kx 			memcpy(reg_rule_dst, reg_rule, sizeof(struct ieee80211_reg_rule));
     5         kx 		else
     5         kx 			memcpy(reg_rule_dst, opt_reg_rule, sizeof(struct ieee80211_reg_rule));
     5         kx 		idx++;
     5         kx 	}
     5         kx 
     5         kx 	if (idx != num_rules)
     5         kx 		goto fail;
     5         kx 
     5         kx 	for (i = 0; i < opt_rd->n_reg_rules; i++) {
     5         kx 		reg_rule = &opt_rd->reg_rules[i];
     5         kx 		if (!is_valid_reg_rule(reg_rule))
     5         kx 			goto fail;
     5         kx 	}
     5         kx 
     5         kx 	free(opt_map);
     5         kx 	return opt_rd;
     5         kx fail:
     5         kx 	free(opt_rd);
     5         kx fail_opt_map:
     5         kx 	free(opt_map);
     5         kx 	return NULL;
     5         kx }