aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2009-12-18 17:59:01 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-21 18:56:10 -0500
commit3b377ea9d4efc94dc52fe41b4dfdb463635ab298 (patch)
tree76724e77913096c03f6b216573d4a24ce13fe7c3
parent59d9cb071d6209f2e8df2d16228cfdc7bab1f2d1 (diff)
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>
-rw-r--r--Documentation/networking/regulatory.txt24
-rw-r--r--net/wireless/.gitignore1
-rw-r--r--net/wireless/Kconfig16
-rw-r--r--net/wireless/Makefile6
-rw-r--r--net/wireless/db.txt17
-rw-r--r--net/wireless/genregdb.awk118
-rw-r--r--net/wireless/reg.c120
-rw-r--r--net/wireless/regdb.h7
8 files changed, 285 insertions, 24 deletions
diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt
index ee31369e9e5b..9551622d0a7b 100644
--- a/Documentation/networking/regulatory.txt
+++ b/Documentation/networking/regulatory.txt
@@ -188,3 +188,27 @@ Then in some part of your code after your wiphy has been registered:
188 &mydriver_jp_regdom.reg_rules[i], 188 &mydriver_jp_regdom.reg_rules[i],
189 sizeof(struct ieee80211_reg_rule)); 189 sizeof(struct ieee80211_reg_rule));
190 regulatory_struct_hint(rd); 190 regulatory_struct_hint(rd);
191
192Statically compiled regulatory database
193---------------------------------------
194
195In most situations the userland solution using CRDA as described
196above is the preferred solution. However in some cases a set of
197rules built into the kernel itself may be desirable. To account
198for this situation, a configuration option has been provided
199(i.e. CONFIG_CFG80211_INTERNAL_REGDB). With this option enabled,
200the wireless database information contained in net/wireless/db.txt is
201used to generate a data structure encoded in net/wireless/regdb.c.
202That option also enables code in net/wireless/reg.c which queries
203the data in regdb.c as an alternative to using CRDA.
204
205The file net/wireless/db.txt should be kept up-to-date with the db.txt
206file available in the git repository here:
207
208 git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
209
210Again, most users in most situations should be using the CRDA package
211provided with their distribution, and in most other situations users
212should be building and using CRDA on their own rather than using
213this option. If you are not absolutely sure that you should be using
214CONFIG_CFG80211_INTERNAL_REGDB then _DO_NOT_USE_IT_.
diff --git a/net/wireless/.gitignore b/net/wireless/.gitignore
new file mode 100644
index 000000000000..c33451b896d9
--- /dev/null
+++ b/net/wireless/.gitignore
@@ -0,0 +1 @@
regdb.c
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 90e93a5701aa..8419971f07c5 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -109,6 +109,22 @@ config WIRELESS_OLD_REGULATORY
109 109
110 Say N and if you say Y, please tell us why. The default is N. 110 Say N and if you say Y, please tell us why. The default is N.
111 111
112config 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
112config CFG80211_WEXT 128config CFG80211_WEXT
113 bool "cfg80211 wireless extensions compatibility" 129 bool "cfg80211 wireless extensions compatibility"
114 depends on CFG80211 130 depends on CFG80211
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index f07c8dc7aab2..e77e508126fa 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -13,5 +13,11 @@ cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
13cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o 13cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o
14cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o 14cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
15cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o 15cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
16cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
16 17
17ccflags-y += -D__CHECK_ENDIAN__ 18ccflags-y += -D__CHECK_ENDIAN__
19
20$(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk
21 @$(AWK) -f $(srctree)/$(src)/genregdb.awk < $< > $@
22
23clean-files := regdb.c
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
new file mode 100644
index 000000000000..a2fc3a09ccdc
--- /dev/null
+++ b/net/wireless/db.txt
@@ -0,0 +1,17 @@
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#
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk
new file mode 100644
index 000000000000..8316cf075ce9
--- /dev/null
+++ b/net/wireless/genregdb.awk
@@ -0,0 +1,118 @@
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
15BEGIN {
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
46active && /^[ \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
106active && /^[ \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
114END {
115 print regdb "};"
116 print ""
117 print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);"
118}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index c01470e7de15..65f86264f7bb 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -40,6 +40,7 @@
40#include <net/cfg80211.h> 40#include <net/cfg80211.h>
41#include "core.h" 41#include "core.h"
42#include "reg.h" 42#include "reg.h"
43#include "regdb.h"
43#include "nl80211.h" 44#include "nl80211.h"
44 45
45/* Receipt of information from last regulatory request */ 46/* Receipt of information from last regulatory request */
@@ -360,6 +361,98 @@ static bool country_ie_integrity_changes(u32 checksum)
360 return false; 361 return false;
361} 362}
362 363
364static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
365 const struct ieee80211_regdomain *src_regd)
366{
367 struct ieee80211_regdomain *regd;
368 int size_of_regd = 0;
369 unsigned int i;
370
371 size_of_regd = sizeof(struct ieee80211_regdomain) +
372 ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
373
374 regd = kzalloc(size_of_regd, GFP_KERNEL);
375 if (!regd)
376 return -ENOMEM;
377
378 memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
379
380 for (i = 0; i < src_regd->n_reg_rules; i++)
381 memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
382 sizeof(struct ieee80211_reg_rule));
383
384 *dst_regd = regd;
385 return 0;
386}
387
388#ifdef CONFIG_CFG80211_INTERNAL_REGDB
389struct reg_regdb_search_request {
390 char alpha2[2];
391 struct list_head list;
392};
393
394static LIST_HEAD(reg_regdb_search_list);
395static DEFINE_SPINLOCK(reg_regdb_search_lock);
396
397static void reg_regdb_search(struct work_struct *work)
398{
399 struct reg_regdb_search_request *request;
400 const struct ieee80211_regdomain *curdom, *regdom;
401 int i, r;
402
403 spin_lock(&reg_regdb_search_lock);
404 while (!list_empty(&reg_regdb_search_list)) {
405 request = list_first_entry(&reg_regdb_search_list,
406 struct reg_regdb_search_request,
407 list);
408 list_del(&request->list);
409
410 for (i=0; i<reg_regdb_size; i++) {
411 curdom = reg_regdb[i];
412
413 if (!memcmp(request->alpha2, curdom->alpha2, 2)) {
414 r = reg_copy_regd(&regdom, curdom);
415 if (r)
416 break;
417 spin_unlock(&reg_regdb_search_lock);
418 mutex_lock(&cfg80211_mutex);
419 set_regdom(regdom);
420 mutex_unlock(&cfg80211_mutex);
421 spin_lock(&reg_regdb_search_lock);
422 break;
423 }
424 }
425
426 kfree(request);
427 }
428 spin_unlock(&reg_regdb_search_lock);
429}
430
431static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
432
433static void reg_regdb_query(const char *alpha2)
434{
435 struct reg_regdb_search_request *request;
436
437 if (!alpha2)
438 return;
439
440 request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL);
441 if (!request)
442 return;
443
444 memcpy(request->alpha2, alpha2, 2);
445
446 spin_lock(&reg_regdb_search_lock);
447 list_add_tail(&request->list, &reg_regdb_search_list);
448 spin_unlock(&reg_regdb_search_lock);
449
450 schedule_work(&reg_regdb_work);
451}
452#else
453static inline void reg_regdb_query(const char *alpha2) {}
454#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
455
363/* 456/*
364 * This lets us keep regulatory code which is updated on a regulatory 457 * This lets us keep regulatory code which is updated on a regulatory
365 * basis in userspace. 458 * basis in userspace.
@@ -379,6 +472,9 @@ static int call_crda(const char *alpha2)
379 printk(KERN_INFO "cfg80211: Calling CRDA to update world " 472 printk(KERN_INFO "cfg80211: Calling CRDA to update world "
380 "regulatory domain\n"); 473 "regulatory domain\n");
381 474
475 /* query internal regulatory database (if it exists) */
476 reg_regdb_query(alpha2);
477
382 country_env[8] = alpha2[0]; 478 country_env[8] = alpha2[0];
383 country_env[9] = alpha2[1]; 479 country_env[9] = alpha2[1];
384 480
@@ -1367,30 +1463,6 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
1367} 1463}
1368EXPORT_SYMBOL(wiphy_apply_custom_regulatory); 1464EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
1369 1465
1370static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
1371 const struct ieee80211_regdomain *src_regd)
1372{
1373 struct ieee80211_regdomain *regd;
1374 int size_of_regd = 0;
1375 unsigned int i;
1376
1377 size_of_regd = sizeof(struct ieee80211_regdomain) +
1378 ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
1379
1380 regd = kzalloc(size_of_regd, GFP_KERNEL);
1381 if (!regd)
1382 return -ENOMEM;
1383
1384 memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
1385
1386 for (i = 0; i < src_regd->n_reg_rules; i++)
1387 memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
1388 sizeof(struct ieee80211_reg_rule));
1389
1390 *dst_regd = regd;
1391 return 0;
1392}
1393
1394/* 1466/*
1395 * Return value which can be used by ignore_request() to indicate 1467 * Return value which can be used by ignore_request() to indicate
1396 * it has been determined we should intersect two regulatory domains 1468 * it has been determined we should intersect two regulatory domains
diff --git a/net/wireless/regdb.h b/net/wireless/regdb.h
new file mode 100644
index 000000000000..818222c92513
--- /dev/null
+++ b/net/wireless/regdb.h
@@ -0,0 +1,7 @@
1#ifndef __REGDB_H__
2#define __REGDB_H__
3
4extern const struct ieee80211_regdomain *reg_regdb[];
5extern int reg_regdb_size;
6
7#endif /* __REGDB_H__ */