Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

wireless: support internal statically compiled regulatory database

This patch provides infrastructure for machine translation of the
regulatory rules database used by CRDA into a C data structure.
It includes code for searching that database as an alternative
to dynamic regulatory rules updates via CRDA. Most people should
use CRDA instead of this infrastructure, but it provides a better
alternative than the WIRELESS_OLD_REGULATORY infrastructure (which
can now be removed).

Signed-off-by: John W. Linville <linville@tuxdriver.com>

+285 -24
+24
Documentation/networking/regulatory.txt
··· 188 188 &mydriver_jp_regdom.reg_rules[i], 189 189 sizeof(struct ieee80211_reg_rule)); 190 190 regulatory_struct_hint(rd); 191 + 192 + Statically compiled regulatory database 193 + --------------------------------------- 194 + 195 + In most situations the userland solution using CRDA as described 196 + above is the preferred solution. However in some cases a set of 197 + rules built into the kernel itself may be desirable. To account 198 + for this situation, a configuration option has been provided 199 + (i.e. CONFIG_CFG80211_INTERNAL_REGDB). With this option enabled, 200 + the wireless database information contained in net/wireless/db.txt is 201 + used to generate a data structure encoded in net/wireless/regdb.c. 202 + That option also enables code in net/wireless/reg.c which queries 203 + the data in regdb.c as an alternative to using CRDA. 204 + 205 + The file net/wireless/db.txt should be kept up-to-date with the db.txt 206 + file available in the git repository here: 207 + 208 + git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git 209 + 210 + Again, most users in most situations should be using the CRDA package 211 + provided with their distribution, and in most other situations users 212 + should be building and using CRDA on their own rather than using 213 + this option. If you are not absolutely sure that you should be using 214 + CONFIG_CFG80211_INTERNAL_REGDB then _DO_NOT_USE_IT_.
+1
net/wireless/.gitignore
··· 1 + regdb.c
+16
net/wireless/Kconfig
··· 109 109 110 110 Say N and if you say Y, please tell us why. The default is N. 111 111 112 + config CFG80211_INTERNAL_REGDB 113 + bool "use statically compiled regulatory rules database" if EMBEDDED 114 + default n 115 + depends on CFG80211 116 + ---help--- 117 + This option generates an internal data structure representing 118 + the wireless regulatory rules described in net/wireless/db.txt 119 + and includes code to query that database. This is an alternative 120 + to using CRDA for defining regulatory rules for the kernel. 121 + 122 + For details see: 123 + 124 + http://wireless.kernel.org/en/developers/Regulatory 125 + 126 + Most distributions have a CRDA package. So if unsure, say N. 127 + 112 128 config CFG80211_WEXT 113 129 bool "cfg80211 wireless extensions compatibility" 114 130 depends on CFG80211
+6
net/wireless/Makefile
··· 13 13 cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o 14 14 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o 15 15 cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o 16 + cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o 16 17 17 18 ccflags-y += -D__CHECK_ENDIAN__ 19 + 20 + $(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk 21 + @$(AWK) -f $(srctree)/$(src)/genregdb.awk < $< > $@ 22 + 23 + clean-files := regdb.c
+17
net/wireless/db.txt
··· 1 + # 2 + # This file is a placeholder to prevent accidental build breakage if someone 3 + # enables CONFIG_CFG80211_INTERNAL_REGDB. Almost no one actually needs to 4 + # enable that build option. 5 + # 6 + # You should be using CRDA instead. It is even better if you use the CRDA 7 + # package provided by your distribution, since they will probably keep it 8 + # up-to-date on your behalf. 9 + # 10 + # If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will 11 + # need to replace this file with one containing appropriately formatted 12 + # regulatory rules that cover the regulatory domains you will be using. Your 13 + # best option is to extract the db.txt file from the wireless-regdb git 14 + # repository: 15 + # 16 + # git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git 17 + #
+118
net/wireless/genregdb.awk
··· 1 + #!/usr/bin/awk -f 2 + # 3 + # genregdb.awk -- generate regdb.c from db.txt 4 + # 5 + # Actually, it reads from stdin (presumed to be db.txt) and writes 6 + # to stdout (presumed to be regdb.c), but close enough... 7 + # 8 + # Copyright 2009 John W. Linville <linville@tuxdriver.com> 9 + # 10 + # This program is free software; you can redistribute it and/or modify 11 + # it under the terms of the GNU General Public License version 2 as 12 + # published by the Free Software Foundation. 13 + # 14 + 15 + BEGIN { 16 + active = 0 17 + rules = 0; 18 + print "/*" 19 + print " * DO NOT EDIT -- file generated from data in db.txt" 20 + print " */" 21 + print "" 22 + print "#include <linux/nl80211.h>" 23 + print "#include <net/cfg80211.h>" 24 + print "" 25 + regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n" 26 + } 27 + 28 + /^[ \t]*#/ { 29 + /* Ignore */ 30 + } 31 + 32 + !active && /^[ \t]*$/ { 33 + /* Ignore */ 34 + } 35 + 36 + !active && /country/ { 37 + country=$2 38 + sub(/:/, "", country) 39 + printf "static const struct ieee80211_regdomain regdom_%s = {\n", country 40 + printf "\t.alpha2 = \"%s\",\n", country 41 + printf "\t.reg_rules = {\n" 42 + active = 1 43 + regdb = regdb "\t&regdom_" country ",\n" 44 + } 45 + 46 + active && /^[ \t]*\(/ { 47 + start = $1 48 + sub(/\(/, "", start) 49 + end = $3 50 + bw = $5 51 + sub(/\),/, "", bw) 52 + gain = $6 53 + sub(/\(/, "", gain) 54 + sub(/,/, "", gain) 55 + power = $7 56 + sub(/\)/, "", power) 57 + sub(/,/, "", power) 58 + # power might be in mW... 59 + units = $8 60 + sub(/\)/, "", units) 61 + sub(/,/, "", units) 62 + if (units == "mW") { 63 + if (power == 100) { 64 + power = 20 65 + } else if (power == 200) { 66 + power = 23 67 + } else if (power == 500) { 68 + power = 27 69 + } else if (power == 1000) { 70 + power = 30 71 + } else { 72 + print "Unknown power value in database!" 73 + } 74 + } 75 + flagstr = "" 76 + for (i=8; i<=NF; i++) 77 + flagstr = flagstr $i 78 + split(flagstr, flagarray, ",") 79 + flags = "" 80 + for (arg in flagarray) { 81 + if (flagarray[arg] == "NO-OFDM") { 82 + flags = flags "\n\t\t\tNL80211_RRF_NO_OFDM | " 83 + } else if (flagarray[arg] == "NO-CCK") { 84 + flags = flags "\n\t\t\tNL80211_RRF_NO_CCK | " 85 + } else if (flagarray[arg] == "NO-INDOOR") { 86 + flags = flags "\n\t\t\tNL80211_RRF_NO_INDOOR | " 87 + } else if (flagarray[arg] == "NO-OUTDOOR") { 88 + flags = flags "\n\t\t\tNL80211_RRF_NO_OUTDOOR | " 89 + } else if (flagarray[arg] == "DFS") { 90 + flags = flags "\n\t\t\tNL80211_RRF_DFS | " 91 + } else if (flagarray[arg] == "PTP-ONLY") { 92 + flags = flags "\n\t\t\tNL80211_RRF_PTP_ONLY | " 93 + } else if (flagarray[arg] == "PTMP-ONLY") { 94 + flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | " 95 + } else if (flagarray[arg] == "PASSIVE-SCAN") { 96 + flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | " 97 + } else if (flagarray[arg] == "NO-IBSS") { 98 + flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | " 99 + } 100 + } 101 + flags = flags "0" 102 + printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags 103 + rules++ 104 + } 105 + 106 + active && /^[ \t]*$/ { 107 + active = 0 108 + printf "\t},\n" 109 + printf "\t.n_reg_rules = %d\n", rules 110 + printf "};\n\n" 111 + rules = 0; 112 + } 113 + 114 + END { 115 + print regdb "};" 116 + print "" 117 + print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);" 118 + }
+96 -24
net/wireless/reg.c
··· 40 40 #include <net/cfg80211.h> 41 41 #include "core.h" 42 42 #include "reg.h" 43 + #include "regdb.h" 43 44 #include "nl80211.h" 44 45 45 46 /* Receipt of information from last regulatory request */ ··· 361 360 return false; 362 361 } 363 362 363 + static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, 364 + const struct ieee80211_regdomain *src_regd) 365 + { 366 + struct ieee80211_regdomain *regd; 367 + int size_of_regd = 0; 368 + unsigned int i; 369 + 370 + size_of_regd = sizeof(struct ieee80211_regdomain) + 371 + ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule)); 372 + 373 + regd = kzalloc(size_of_regd, GFP_KERNEL); 374 + if (!regd) 375 + return -ENOMEM; 376 + 377 + memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain)); 378 + 379 + for (i = 0; i < src_regd->n_reg_rules; i++) 380 + memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i], 381 + sizeof(struct ieee80211_reg_rule)); 382 + 383 + *dst_regd = regd; 384 + return 0; 385 + } 386 + 387 + #ifdef CONFIG_CFG80211_INTERNAL_REGDB 388 + struct reg_regdb_search_request { 389 + char alpha2[2]; 390 + struct list_head list; 391 + }; 392 + 393 + static LIST_HEAD(reg_regdb_search_list); 394 + static DEFINE_SPINLOCK(reg_regdb_search_lock); 395 + 396 + static void reg_regdb_search(struct work_struct *work) 397 + { 398 + struct reg_regdb_search_request *request; 399 + const struct ieee80211_regdomain *curdom, *regdom; 400 + int i, r; 401 + 402 + spin_lock(&reg_regdb_search_lock); 403 + while (!list_empty(&reg_regdb_search_list)) { 404 + request = list_first_entry(&reg_regdb_search_list, 405 + struct reg_regdb_search_request, 406 + list); 407 + list_del(&request->list); 408 + 409 + for (i=0; i<reg_regdb_size; i++) { 410 + curdom = reg_regdb[i]; 411 + 412 + if (!memcmp(request->alpha2, curdom->alpha2, 2)) { 413 + r = reg_copy_regd(&regdom, curdom); 414 + if (r) 415 + break; 416 + spin_unlock(&reg_regdb_search_lock); 417 + mutex_lock(&cfg80211_mutex); 418 + set_regdom(regdom); 419 + mutex_unlock(&cfg80211_mutex); 420 + spin_lock(&reg_regdb_search_lock); 421 + break; 422 + } 423 + } 424 + 425 + kfree(request); 426 + } 427 + spin_unlock(&reg_regdb_search_lock); 428 + } 429 + 430 + static DECLARE_WORK(reg_regdb_work, reg_regdb_search); 431 + 432 + static void reg_regdb_query(const char *alpha2) 433 + { 434 + struct reg_regdb_search_request *request; 435 + 436 + if (!alpha2) 437 + return; 438 + 439 + request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL); 440 + if (!request) 441 + return; 442 + 443 + memcpy(request->alpha2, alpha2, 2); 444 + 445 + spin_lock(&reg_regdb_search_lock); 446 + list_add_tail(&request->list, &reg_regdb_search_list); 447 + spin_unlock(&reg_regdb_search_lock); 448 + 449 + schedule_work(&reg_regdb_work); 450 + } 451 + #else 452 + static inline void reg_regdb_query(const char *alpha2) {} 453 + #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ 454 + 364 455 /* 365 456 * This lets us keep regulatory code which is updated on a regulatory 366 457 * basis in userspace. ··· 471 378 else 472 379 printk(KERN_INFO "cfg80211: Calling CRDA to update world " 473 380 "regulatory domain\n"); 381 + 382 + /* query internal regulatory database (if it exists) */ 383 + reg_regdb_query(alpha2); 474 384 475 385 country_env[8] = alpha2[0]; 476 386 country_env[9] = alpha2[1]; ··· 1462 1366 WARN_ON(!bands_set); 1463 1367 } 1464 1368 EXPORT_SYMBOL(wiphy_apply_custom_regulatory); 1465 - 1466 - static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, 1467 - const struct ieee80211_regdomain *src_regd) 1468 - { 1469 - struct ieee80211_regdomain *regd; 1470 - int size_of_regd = 0; 1471 - unsigned int i; 1472 - 1473 - size_of_regd = sizeof(struct ieee80211_regdomain) + 1474 - ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule)); 1475 - 1476 - regd = kzalloc(size_of_regd, GFP_KERNEL); 1477 - if (!regd) 1478 - return -ENOMEM; 1479 - 1480 - memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain)); 1481 - 1482 - for (i = 0; i < src_regd->n_reg_rules; i++) 1483 - memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i], 1484 - sizeof(struct ieee80211_reg_rule)); 1485 - 1486 - *dst_regd = regd; 1487 - return 0; 1488 - } 1489 1369 1490 1370 /* 1491 1371 * Return value which can be used by ignore_request() to indicate
+7
net/wireless/regdb.h
··· 1 + #ifndef __REGDB_H__ 2 + #define __REGDB_H__ 3 + 4 + extern const struct ieee80211_regdomain *reg_regdb[]; 5 + extern int reg_regdb_size; 6 + 7 + #endif /* __REGDB_H__ */