aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-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
7 files changed, 261 insertions, 24 deletions
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__ */