diff options
author | John W. Linville <linville@tuxdriver.com> | 2008-11-17 15:41:34 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-11-17 15:41:34 -0500 |
commit | 87b95b336ffb91acc9dfabc0c0ffc0aa1c09b29d (patch) | |
tree | c2eb49c84f4aed6b84d096091605608f1e1b6551 | |
download | external_wireless-regdb-87b95b336ffb91acc9dfabc0c0ffc0aa1c09b29d.tar.gz external_wireless-regdb-87b95b336ffb91acc9dfabc0c0ffc0aa1c09b29d.tar.bz2 external_wireless-regdb-87b95b336ffb91acc9dfabc0c0ffc0aa1c09b29d.zip |
Initial project creation/import...
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | LICENSE | 16 | ||||
-rw-r--r-- | Makefile | 15 | ||||
-rw-r--r-- | README | 29 | ||||
-rw-r--r-- | db.txt | 576 | ||||
-rwxr-xr-x | db2bin.py | 145 | ||||
-rwxr-xr-x | dbparse.py | 357 | ||||
-rw-r--r-- | key.pub.pem | 6 | ||||
-rw-r--r-- | regulatory.bin | bin | 0 -> 2812 bytes | |||
-rw-r--r-- | web/Regulatory.py | 166 |
9 files changed, 1310 insertions, 0 deletions
@@ -0,0 +1,16 @@ +Copyright (c) 2008, Luis R. Rodriguez <mcgrof@gmail.com> +Copyright (c) 2008, Johannes Berg <johannes@sipsolutions.net> +Copyright (c) 2008, Michael Green <Michael.Green@Atheros.com> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1d8ff2a --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +.PHONY: all clean + +all: regulatory.bin key.pub.pem + +clean: + rm -f regulatory.bin key.pub.pem + +regulatory.bin: db.txt key.priv.pem + ./db2bin.py regulatory.bin db.txt key.priv.pem + +key.pub.pem: key.priv.pem + openssl rsa -in key.priv.pem -out key.pub.pem -pubout -outform PEM + +key.priv.pem: + openssl genrsa -out key.priv.pem 2048 @@ -0,0 +1,29 @@ +This repository contains the plain text version of the regulatory +database file I maintain for use with Central Regulatory Database +Agent daemon. Also included is the compiled binary version of this +file signed with my RSA key. This represents a good faith attempt +to capture regulatory information that is correct at the time of its last +modification. This information is provided to you with no warranty +either expressed or implied. + +Also included are the tools used to compile and sign the regulatory.bin +file as well as a MoinMoin macro used for viewing the database. + + TECHNICAL INFORMATION +======================= + +The regulatory information in `db.txt' is stored in a human-readable +format which can be read using the `dbparse.py' python module. This +python module is used by the web viewer (Regulatory.py) which is +implemented as a MoinMoin macro (and used on http://wireless.kernel.org) +to allow viewing the database for verification. + +The dbparse module is also used by db2bin.py, the `compiler', which +compiles and signs the binary database. + +For more information, please see the CRDA git repository: + + git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/crda.git + +John W. Linville +17 November 2008 @@ -0,0 +1,576 @@ +country 00: + (2402 - 2472 @ 40), (6, 20) + +country AE: + (2402 - 2482 @ 40), (N/A, 20) + +country AL: + (2402 - 2482 @ 20), (N/A, 20) + +country AM: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 18) + (5250 - 5330 @ 20), (N/A, 18), DFS + +country AN: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country AR: + (2402 - 2482 @ 20), (N/A, 20) + (5270 - 5330 @ 20), (6, 17), DFS + (5735 - 5815 @ 20), (6, 30) + +country AT: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country AU: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (6, 23) + (5250 - 5330 @ 40), (6, 23), DFS + (5735 - 5835 @ 40), (6, 30) + +country AZ: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 18) + (5250 - 5330 @ 40), (N/A, 18), DFS + +country BA: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + (5490 - 5710 @ 20), (N/A, 27), DFS + +country BE: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country BG: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 23) + (5250 - 5290 @ 40), (N/A, 23), DFS + (5490 - 5710 @ 40), (N/A, 30), DFS + +country BH: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + (5735 - 5835 @ 20), (N/A, 20) + +country BL: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 18) + (5250 - 5330 @ 40), (N/A, 18), DFS + +country BN: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country BO: + (2402 - 2482 @ 40), (N/A, 30) + (5735 - 5835 @ 40), (N/A, 30) + +country BR: + (2402 - 2482 @ 20), (N/A, 20) + (5170 - 5250 @ 20), (6, 17) + (5250 - 5330 @ 20), (6, 20), DFS + (5490 - 5710 @ 20), (6, 20), DFS + (5735 - 5835 @ 20), (6, 30) + +country BY: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country BZ: + (2402 - 2482 @ 40), (N/A, 30) + (5735 - 5835 @ 40), (N/A, 30) + +country CA: + (2402 - 2472 @ 40), (6, 27) + (5170 - 5250 @ 40), (6, 17) + (5250 - 5330 @ 40), (6, 20), DFS + (5490 - 5710 @ 40), (6, 20), DFS + (5735 - 5835 @ 40), (6, 30) + +country CH: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country CL: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5735 - 5835 @ 40), (N/A, 20) + +country CN: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country CO: + (2402 - 2472 @ 40), (6, 27) + (5170 - 5250 @ 20), (6, 17) + (5250 - 5330 @ 20), (6, 23), DFS + (5735 - 5835 @ 20), (6, 30) + +country CR: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (6, 17) + (5250 - 5330 @ 20), (6, 23), DFS + (5735 - 5835 @ 20), (6, 30) + +country CS: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country CY: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country CZ: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + +# Data from "Frequenznutzungsplan" (as published in April 2008), +# downloaded from http://www.bundesnetzagentur.de/media/archive/13358.pdf +country DE: + # entries 279004 and 280006 + (2400 - 2483.5 @ 40), (N/A, 100 mW) + # entries 303005 and 304002 + (5150 - 5255 @ 40), (N/A, 200 mW), NO-OUTDOOR, DFS + # entries 308002 and 309001 + (5470 - 5650 @ 40), (N/A, 1000 mW), DFS + +country DK: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country DO: + (2402 - 2472 @ 40), (6, 27) + (5170 - 5250 @ 40), (6, 17) + (5250 - 5330 @ 40), (6, 23), DFS + (5735 - 5835 @ 40), (6, 30) + +country DZ: + (2402 - 2482 @ 20), (N/A, 20) + +country EC: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (6, 17) + (5250 - 5330 @ 20), (6, 23), DFS + (5735 - 5835 @ 20), (6, 30) + +country EE: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country EG: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + +country ES: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country FI: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country FR: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country GE: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 18) + (5250 - 5330 @ 40), (N/A, 18), DFS + +country GB: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country GR: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country GT: + (2402 - 2472 @ 40), (6, 27) + (5170 - 5250 @ 40), (6, 17) + (5250 - 5330 @ 40), (6, 23), DFS + (5735 - 5835 @ 40), (6, 30) + +country HN: + (2402 - 2482 @ 40), (N/A, 20) + +country HK: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (6, 23) + (5250 - 5330 @ 40), (6, 23), DFS + (5735 - 5835 @ 40), (6, 30) + +country HR: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + +country HU: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country ID: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 20), (N/A, 30) + +country IE: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country IL: + (2402 - 2482 @ 40), (N/A, 20) + +country IN: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + (5735 - 5835 @ 20), (N/A, 20) + +country IS: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country IR: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country IT: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country JM: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country JP: + (2402 - 2472 @ 40), (N/A, 20) + (2457 - 2482 @ 40), (N/A, 20) + (2474 - 2494 @ 40), (N/A, 20) + (4910 - 4930 @ 10), (N/A, 23) + (4910 - 4990 @ 40), (N/A, 23) + (4930 - 4950 @ 10), (N/A, 23) + (5030 - 5045 @ 10), (N/A, 23) + (5030 - 5090 @ 40), (N/A, 23) + (5050 - 5060 @ 10), (N/A, 23) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 23), DFS + +country JO: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 18) + +country KP: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5330 @ 40), (6, 20) + (5160 - 5250 @ 40), (6, 20), DFS + (5490 - 5630 @ 40), (6, 30), DFS + (5735 - 5815 @ 40), (6, 30) + +country KR: + (2402 - 2482 @ 20), (N/A, 20) + (5170 - 5250 @ 20), (6, 20) + (5260 - 5330 @ 20), (6, 20), DFS + (5490 - 5710 @ 20), (6, 30), DFS + (5735 - 5815 @ 20), (6, 30) + +country KW: + (2402 - 2482 @ 40), (N/A, 20) + +country KZ: + (2402 - 2482 @ 40), (N/A, 20) + +country LB: + (2402 - 2482 @ 40), (N/A, 20) + +country LI: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country LK: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (6, 17) + (5250 - 5330 @ 20), (6, 20), DFS + (5490 - 5710 @ 20), (6, 20), DFS + (5735 - 5835 @ 20), (6, 30) + +country LT: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country LU: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country LV: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country MC: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 18) + (5250 - 5330 @ 40), (N/A, 18), DFS + +country MA: + (2402 - 2482 @ 40), (N/A, 20) + +country MO: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (6, 23) + (5250 - 5330 @ 40), (6, 23), DFS + (5735 - 5835 @ 40), (6, 30) + +country MK: + (2402 - 2482 @ 40), (N/A, 20) + +country MT: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country MY: + (2402 - 2482 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 30), DFS + (5735 - 5835 @ 20), (N/A, 30) + +country MX: + (2402 - 2472 @ 40), (6, 27) + (5170 - 5250 @ 40), (6, 17) + (5250 - 5330 @ 40), (6, 23), DFS + (5735 - 5835 @ 40), (6, 30) + +country NL: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country NO: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country NP: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country NZ: + (2402 - 2482 @ 40), (N/A, 30) + (5170 - 5250 @ 20), (6, 23) + (5250 - 5330 @ 20), (6, 23), DFS + (5735 - 5835 @ 20), (6, 30) + +country OM: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + (5735 - 5835 @ 20), (N/A, 20) + +country PA: + (2402 - 2472 @ 40), (6, 27) + (5170 - 5250 @ 40), (6, 17) + (5250 - 5330 @ 40), (6, 23), DFS + (5735 - 5835 @ 40), (6, 30) + +country PE: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 20), (N/A, 30) + +country PG: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (6, 17) + (5250 - 5330 @ 40), (6, 23), DFS + (5735 - 5835 @ 40), (6, 30) + +country PH: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country PK: + (2402 - 2482 @ 40), (N/A, 20) + +country PL: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country PT: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country PR: + (2402 - 2472 @ 40), (6, 27) + (5170 - 5250 @ 40), (6, 17) + (5250 - 5330 @ 40), (6, 23), DFS + (5735 - 5835 @ 40), (6, 30) + +country QA: + (2402 - 2482 @ 40), (N/A, 20) + +country RO: + (2402 - 2482 @ 40), (N/A, 20) + +country RU: + (2402 - 2482 @ 40), (N/A, 20) + +country SA: + (2402 - 2482 @ 40), (N/A, 20) + +country SE: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country SG: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5735 - 5835 @ 40), (N/A, 20) + +country SI: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country SK: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country SV: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (6, 17) + (5250 - 5330 @ 20), (6, 23), DFS + (5735 - 5835 @ 20), (6, 30) + +country SY: + (2402 - 2482 @ 40), (N/A, 20) + +country TW: + (2402 - 2472 @ 40), (6, 27) + (5270 - 5330 @ 40), (6, 17), DFS + (5735 - 5815 @ 40), (6, 30) + +country TH: + (2402 - 2482 @ 40), (N/A, 20) + +country TT: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 18) + (5250 - 5330 @ 20), (N/A, 18), DFS + +country TN: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + +country TR: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + +country UA: + (2402 - 2482 @ 40), (N/A, 20) + +country US: + (2402 - 2472 @ 40), (6, 27) + (5170 - 5250 @ 40), (6, 17) + (5250 - 5330 @ 40), (6, 20), DFS + (5490 - 5710 @ 40), (6, 20), DFS + (5735 - 5835 @ 40), (6, 30) + +country UY: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5815 @ 20), (N/A, 23) + +country UZ: + (2402 - 2472 @ 40), (6, 27) + (5170 - 5250 @ 40), (6, 17) + (5250 - 5330 @ 40), (6, 20), DFS + (5490 - 5710 @ 40), (6, 20), DFS + (5735 - 5835 @ 40), (6, 30) + +country VE: + (2402 - 2482 @ 40), (N/A, 30) + (5735 - 5815 @ 20), (N/A, 23) + +country VN: + (2402 - 2482 @ 40), (N/A, 20) + +country YE: + (2402 - 2482 @ 40), (N/A, 20) + +country ZA: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (6, 17) + (5250 - 5330 @ 20), (6, 20), DFS + (5490 - 5710 @ 20), (6, 20), DFS + (5735 - 5835 @ 20), (6, 30) + +country ZW: + (2402 - 2482 @ 40), (N/A, 20) + diff --git a/db2bin.py b/db2bin.py new file mode 100755 index 0000000..e783b3a --- /dev/null +++ b/db2bin.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python + +from cStringIO import StringIO +import struct +import sha +from dbparse import DBParser +import sys + +MAGIC = 0x52474442 +VERSION = 19 + +if len(sys.argv) < 3: + print 'Usage: %s output-file input-file [key-file]' % sys.argv[0] + sys.exit(2) + +def create_rules(countries): + result = {} + for c in countries.itervalues(): + for rule in c.permissions: + result[rule] = 1 + return result.keys() + +def create_collections(countries): + result = {} + for c in countries.itervalues(): + result[c.permissions] = 1 + return result.keys() + + +def be32(output, val): + output.write(struct.pack('>I', val)) + +class PTR(object): + def __init__(self, output): + self._output = output + self._pos = output.tell() + be32(output, 0xFFFFFFFF) + + def set(self, val=None): + if val is None: + val = self._output.tell() + self._offset = val + pos = self._output.tell() + self._output.seek(self._pos) + be32(self._output, val) + self._output.seek(pos) + + def get(self): + return self._offset + +p = DBParser() +countries = p.parse(file(sys.argv[2])) +power = [] +bands = [] +for c in countries.itervalues(): + for perm in c.permissions: + if not perm.freqband in bands: + bands.append(perm.freqband) + if not perm.power in power: + power.append(perm.power) +rules = create_rules(countries) +rules.sort(cmp=lambda x, y: cmp(x.freqband, y.freqband)) +collections = create_collections(countries) +collections.sort(cmp=lambda x, y: cmp(x[0].freqband, y[0].freqband)) + +output = StringIO() + +# struct regdb_file_header +be32(output, MAGIC) +be32(output, VERSION) +reg_country_ptr = PTR(output) +# add number of countries +be32(output, len(countries)) +siglen = PTR(output) + +power_rules = {} +for pr in power: + power_rules[pr] = output.tell() + pr = [int(v * 100.0) for v in (pr.max_ant_gain, pr.max_eirp)] + # struct regdb_file_power_rule + output.write(struct.pack('>II', *pr)) + +freq_ranges = {} +for fr in bands: + freq_ranges[fr] = output.tell() + fr = [int(f * 1000.0) for f in (fr.start, fr.end, fr.maxbw)] + # struct regdb_file_freq_range + output.write(struct.pack('>III', *fr)) + + +reg_rules = {} +for reg_rule in rules: + freq_range, power_rule = reg_rule.freqband, reg_rule.power + reg_rules[reg_rule] = output.tell() + # struct regdb_file_reg_rule + output.write(struct.pack('>III', freq_ranges[freq_range], power_rules[power_rule], + reg_rule.flags)) + + +reg_rules_collections = {} + +for coll in collections: + reg_rules_collections[coll] = output.tell() + # struct regdb_file_reg_rules_collection + coll = list(coll) + be32(output, len(coll)) + coll.sort(cmp=lambda x, y: cmp(x.freqband, y.freqband)) + for regrule in coll: + be32(output, reg_rules[regrule]) + +# update country pointer now! +reg_country_ptr.set() + +countrynames = countries.keys() +countrynames.sort() +for alpha2 in countrynames: + coll = countries[alpha2] + # struct regdb_file_reg_country + output.write(struct.pack('>ccxxI', str(alpha2[0]), str(alpha2[1]), reg_rules_collections[coll.permissions])) + + +if len(sys.argv) > 3: + # Load RSA only now so people can use this script + # without having those libraries installed to verify + # their SQL changes + from M2Crypto import RSA + + # determine signature length + key = RSA.load_key(sys.argv[3]) + hash = sha.new() + hash.update(output.getvalue()) + sig = key.sign(hash.digest()) + # write it to file + siglen.set(len(sig)) + # sign again + hash = sha.new() + hash.update(output.getvalue()) + sig = key.sign(hash.digest()) + + output.write(sig) +else: + siglen.set(0) + +outfile = open(sys.argv[1], 'w') +outfile.write(output.getvalue()) diff --git a/dbparse.py b/dbparse.py new file mode 100755 index 0000000..55615bd --- /dev/null +++ b/dbparse.py @@ -0,0 +1,357 @@ +#!/usr/bin/env python + +import sys, math + +# must match <linux/nl80211.h> enum nl80211_reg_rule_flags + +flag_definitions = { + 'NO-OFDM': 1<<0, + 'NO-CCK': 1<<1, + 'NO-INDOOR': 1<<2, + 'NO-OUTDOOR': 1<<3, + 'DFS': 1<<4, + 'PTP-ONLY': 1<<5, + 'PTMP-ONLY': 1<<6, + 'PASSIVE-SCAN': 1<<7, + 'NO-IBSS': 1<<8, + # hole at bit 9. FIXME: Where is NO-HT40 defined? + 'NO-HT40': 1<<10, +} + +class FreqBand(object): + def __init__(self, start, end, bw, comments=None): + self.start = start + self.end = end + self.maxbw = bw + self.comments = comments or [] + + def __cmp__(self, other): + s = self + o = other + if not isinstance(o, FreqBand): + return False + return cmp((s.start, s.end, s.maxbw), (o.start, o.end, o.maxbw)) + + def __hash__(self): + s = self + return hash((s.start, s.end, s.maxbw)) + + def __str__(self): + return '<FreqBand %.3f - %.3f @ %.3f>' % ( + self.start, self.end, self.maxbw) + +class PowerRestriction(object): + def __init__(self, max_ant_gain, max_eirp, comments = None): + self.max_ant_gain = max_ant_gain + self.max_eirp = max_eirp + self.comments = comments or [] + + def __cmp__(self, other): + s = self + o = other + if not isinstance(o, PowerRestriction): + return False + return cmp((s.max_ant_gain, s.max_eirp), + (o.max_ant_gain, o.max_eirp)) + + def __str__(self): + return '<PowerRestriction ...>' + + def __hash__(self): + s = self + return hash((s.max_ant_gain, s.max_eirp)) + +class FlagError(Exception): + def __init__(self, flag): + self.flag = flag + +class Permission(object): + def __init__(self, freqband, power, flags): + assert isinstance(freqband, FreqBand) + assert isinstance(power, PowerRestriction) + self.freqband = freqband + self.power = power + self.flags = 0 + for flag in flags: + if not flag in flag_definitions: + raise FlagError(flag) + self.flags |= flag_definitions[flag] + self.textflags = flags + + def _as_tuple(self): + return (self.freqband, self.power, self.flags) + + def __cmp__(self, other): + if not isinstance(other, Permission): + return False + return cmp(self._as_tuple(), other._as_tuple()) + + def __hash__(self): + return hash(self._as_tuple()) + +class Country(object): + def __init__(self, permissions=None, comments=None): + self._permissions = permissions or [] + self.comments = comments or [] + + def add(self, perm): + assert isinstance(perm, Permission) + self._permissions.append(perm) + self._permissions.sort() + + def __contains__(self, perm): + assert isinstance(perm, Permission) + return perm in self._permissions + + def __str__(self): + r = ['(%s, %s)' % (str(b), str(p)) for b, p in self._permissions] + return '<Country (%s)>' % (', '.join(r)) + + def _get_permissions_tuple(self): + return tuple(self._permissions) + permissions = property(_get_permissions_tuple) + +class SyntaxError(Exception): + pass + +class DBParser(object): + def __init__(self, warn=None): + self._warn_callout = warn or sys.stderr.write + + def _syntax_error(self, txt=None): + txt = txt and ' (%s)' % txt or '' + raise SyntaxError("Syntax error in line %d%s" % (self._lineno, txt)) + + def _warn(self, txt): + self._warn_callout("Warning (line %d): %s\n" % (self._lineno, txt)) + + def _parse_band_def(self, bname, banddef, dupwarn=True): + try: + freqs, bw = banddef.split('@') + bw = float(bw) + except ValueError: + bw = 20.0 + + try: + start, end = freqs.split('-') + start = float(start) + end = float(end) + except ValueError: + self._syntax_error("band must have frequency range") + + b = FreqBand(start, end, bw, comments=self._comments) + self._comments = [] + self._banddup[bname] = bname + if b in self._bandrev: + if dupwarn: + self._warn('Duplicate band definition ("%s" and "%s")' % ( + bname, self._bandrev[b])) + self._banddup[bname] = self._bandrev[b] + self._bands[bname] = b + self._bandrev[b] = bname + self._bandline[bname] = self._lineno + + def _parse_band(self, line): + try: + bname, line = line.split(':', 1) + if not bname: + self._syntax_error("'band' keyword must be followed by name") + except ValueError: + self._syntax_error("band name must be followed by colon") + + if bname in flag_definitions: + self._syntax_error("Invalid band name") + + self._parse_band_def(bname, line) + + def _parse_power(self, line): + try: + pname, line = line.split(':', 1) + if not pname: + self._syntax_error("'power' keyword must be followed by name") + except ValueError: + self._syntax_error("power name must be followed by colon") + + if pname in flag_definitions: + self._syntax_error("Invalid power name") + + self._parse_power_def(pname, line) + + def _parse_power_def(self, pname, line, dupwarn=True): + try: + (max_ant_gain, + max_eirp) = line.split(',') + if max_ant_gain == 'N/A': + max_ant_gain = '0' + if max_eirp == 'N/A': + max_eirp = '0' + max_ant_gain = float(max_ant_gain) + def conv_pwr(pwr): + if pwr.endswith('mW'): + pwr = float(pwr[:-2]) + return 10.0 * math.log10(pwr) + else: + return float(pwr) + max_eirp = conv_pwr(max_eirp) + except ValueError: + self._syntax_error("invalid power data") + + p = PowerRestriction(max_ant_gain, max_eirp, + comments=self._comments) + self._comments = [] + self._powerdup[pname] = pname + if p in self._powerrev: + if dupwarn: + self._warn('Duplicate power definition ("%s" and "%s")' % ( + pname, self._powerrev[p])) + self._powerdup[pname] = self._powerrev[p] + self._power[pname] = p + self._powerrev[p] = pname + self._powerline[pname] = self._lineno + + def _parse_country(self, line): + try: + cname, line = line.split(':', 1) + if not cname: + self._syntax_error("'country' keyword must be followed by name") + if line: + self._syntax_error("extra data at end of country line") + except ValueError: + self._syntax_error("country name must be followed by colon") + + cnames = cname.split(',') + + self._current_countries = {} + for cname in cnames: + if len(cname) != 2: + self._warn("country '%s' not alpha2" % cname) + if not cname in self._countries: + self._countries[cname] = Country(comments=self._comments) + self._current_countries[cname] = self._countries[cname] + self._comments = [] + + def _parse_country_item(self, line): + if line[0] == '(': + try: + band, line = line[1:].split('),', 1) + bname = 'UNNAMED %d' % self._lineno + self._parse_band_def(bname, band, dupwarn=False) + except: + self._syntax_error("Badly parenthesised band definition") + else: + try: + bname, line = line.split(',', 1) + if not bname: + self._syntax_error("country definition must have band") + if not line: + self._syntax_error("country definition must have power") + except ValueError: + self._syntax_error("country definition must have band and power") + + if line[0] == '(': + items = line.split('),', 1) + if len(items) == 1: + pname = items[0] + line = '' + if not pname[-1] == ')': + self._syntax_error("Badly parenthesised power definition") + pname = pname[:-1] + flags = [] + else: + pname = items[0] + flags = items[1].split(',') + power = pname[1:] + pname = 'UNNAMED %d' % self._lineno + self._parse_power_def(pname, power, dupwarn=False) + else: + line = line.split(',') + pname = line[0] + flags = line[1:] + + if not bname in self._bands: + self._syntax_error("band does not exist") + if not pname in self._power: + self._syntax_error("power does not exist") + self._bands_used[bname] = True + self._power_used[pname] = True + # de-duplicate so binary database is more compact + bname = self._banddup[bname] + pname = self._powerdup[pname] + b = self._bands[bname] + p = self._power[pname] + try: + perm = Permission(b, p, flags) + except FlagError, e: + self._syntax_error("Invalid flag '%s'" % e.flag) + for cname, c in self._current_countries.iteritems(): + if perm in c: + self._warn('Rule "%s, %s" added to "%s" twice' % ( + bname, pname, cname)) + else: + c.add(perm) + + def parse(self, f): + self._current_countries = None + self._bands = {} + self._power = {} + self._countries = {} + self._bands_used = {} + self._power_used = {} + self._bandrev = {} + self._powerrev = {} + self._banddup = {} + self._powerdup = {} + self._bandline = {} + self._powerline = {} + + self._comments = [] + + self._lineno = 0 + for line in f: + self._lineno += 1 + line = line.strip() + if line[0:1] == '#': + self._comments.append(line[1:].strip()) + line = line.replace(' ', '').replace('\t', '') + if not line: + self._comments = [] + line = line.split('#')[0] + if not line: + continue + if line[0:4] == 'band': + self._parse_band(line[4:]) + self._current_countries = None + self._comments = [] + elif line[0:5] == 'power': + self._parse_power(line[5:]) + self._current_countries = None + self._comments = [] + elif line[0:7] == 'country': + self._parse_country(line[7:]) + self._comments = [] + elif self._current_countries is not None: + self._parse_country_item(line) + self._comments = [] + else: + self._syntax_error("Expected band, power or country definition") + + countries = self._countries + bands = {} + for k, v in self._bands.iteritems(): + if k in self._bands_used: + bands[self._banddup[k]] = v + continue + # we de-duplicated, but don't warn again about the dupes + if self._banddup[k] == k: + self._lineno = self._bandline[k] + self._warn('Unused band definition "%s"' % k) + power = {} + for k, v in self._power.iteritems(): + if k in self._power_used: + power[self._powerdup[k]] = v + continue + # we de-duplicated, but don't warn again about the dupes + if self._powerdup[k] == k: + self._lineno = self._powerline[k] + self._warn('Unused power definition "%s"' % k) + return countries diff --git a/key.pub.pem b/key.pub.pem new file mode 100644 index 0000000..924cb61 --- /dev/null +++ b/key.pub.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNw+8TztaTHSjM0i4qROwPltR0 +OVVb5rRX6Kh8AnpUINXDZr5djP0Z63w33t1SDXpLTgtlKrL98c33kaC9CIM8pK0u +9uVxJkM5iF+VcBHrJUBefKn1xlQ8KiqIsobl+c9Jjd70TrGCJ+iG9KuYcJ3UAshV +OfT/UvKfXFzyR4UbSQIDAQAB +-----END PUBLIC KEY----- diff --git a/regulatory.bin b/regulatory.bin Binary files differnew file mode 100644 index 0000000..2de18a9 --- /dev/null +++ b/regulatory.bin diff --git a/web/Regulatory.py b/web/Regulatory.py new file mode 100644 index 0000000..f56fddd --- /dev/null +++ b/web/Regulatory.py @@ -0,0 +1,166 @@ +# -*- coding: iso-8859-1 -*- +""" + Regulatory Database + + @copyright: 2008 Johannes Berg + @license: GNU GPL, see COPYING for details. +""" + +import codecs, math +from dbparse import DBParser, flag_definitions + +Dependencies = ["time"] + +def _country(macro, countries, code): + result = [] + + f = macro.formatter + + result.extend([ + f.heading(1, 1), + f.text('Regulatory definition for %s' % _get_iso_code(code)), + f.heading(0, 1), + ]) + + try: + country = countries[code] + except: + result.append(f.text('No information available')) + return ''.join(result) + + + if country.comments: + result.extend([ + f.preformatted(1), + f.text('\n'.join(country.comments)), + f.preformatted(0), + ]) + + result.append(f.table(1)) + result.extend([ + f.table_row(1), + f.table_cell(1), f.strong(1), + f.text('Band [MHz]'), + f.strong(0), f.table_cell(0), + f.table_cell(1), f.strong(1), + f.text('Max BW [MHz]'), + f.strong(0), f.table_cell(0), + f.table_cell(1), f.strong(1), + f.text('Flags'), + f.strong(0), f.table_cell(0), + f.table_cell(1), f.strong(1), + f.text('Max antenna gain [dBi]'), + f.strong(0), f.table_cell(0), + f.table_cell(1), f.strong(1), + f.text('Max EIRP [dBm'), + f.hardspace, + f.text('(mW)]'), + f.strong(0), f.table_cell(0), + f.table_row(0), + ]) + + for perm in country.permissions: + def str_or_na(val, dBm=False): + if val and not dBm: + return '%.2f' % val + elif val: + return '%.2f (%.2f)' % (val, math.pow(10, val/10.0)) + return 'N/A' + result.extend([ + f.table_row(1), + f.table_cell(1), + f.text('%.3f - %.3f' % (perm.freqband.start, perm.freqband.end)), + f.table_cell(0), + f.table_cell(1), + f.text('%.3f' % (perm.freqband.maxbw,)), + f.table_cell(0), + f.table_cell(1), + f.text(', '.join(perm.textflags)), + f.table_cell(0), + f.table_cell(1), + f.text(str_or_na(perm.power.max_ant_gain)), + f.table_cell(0), + f.table_cell(1), + f.text(str_or_na(perm.power.max_eirp, dBm=True)), + f.table_cell(0), + f.table_row(0), + ]) + + result.append(f.table(0)) + + result.append(f.linebreak(0)) + result.append(f.linebreak(0)) + result.append(macro.request.page.link_to(macro.request, 'return to country list')) + return ''.join(result) + +_iso_list = {} + +def _get_iso_code(code): + if not _iso_list: + for line in codecs.open('/usr/share/iso-codes/iso_3166.tab', encoding='utf-8'): + line = line.strip() + c, name = line.split('\t') + _iso_list[c] = name + return _iso_list.get(code, 'Unknown (%s)' % code) + +def macro_Regulatory(macro): + _ = macro.request.getText + request = macro.request + f = macro.formatter + + country = request.form.get('alpha2', [None])[0] + + dbpath = '/tmp/db.txt' + if hasattr(request.cfg, 'regdb_path'): + dbpath = request.cfg.regdb_path + + result = [] + + if request.form.get('raw', [None])[0]: + result.append(f.code_area(1, 'db-raw', show=1, start=1, step=1)) + for line in open(dbpath): + result.extend([ + f.code_line(1), + f.text(line.rstrip()), + f.code_line(0), + ]) + result.append(f.code_area(0, 'db-raw')) + result.append(macro.request.page.link_to(macro.request, 'return to country list')) + return ''.join(result) + + warnings = [] + countries = DBParser(warn=lambda x: warnings.append(x)).parse(open(dbpath)) + + if country: + return _country(macro, countries, country) + + countries = countries.keys() + countries = [(_get_iso_code(code), code) for code in countries] + countries.sort() + + result.extend([ + f.heading(1, 1), + f.text('Countries'), + f.heading(0, 1), + ]) + + result.append(f.bullet_list(1)) + for name, code in countries: + result.extend([ + f.listitem(1), + request.page.link_to(request, name, querystr={'alpha2': code}), + f.listitem(0), + ]) + result.append(f.bullet_list(0)) + + if warnings: + result.append(f.heading(1, 2)) + result.append(f.text("Warnings")) + result.append(f.heading(0, 2)) + result.append(f.preformatted(1)) + result.extend(warnings) + result.append(f.preformatted(0)) + + result.append(request.page.link_to(request, 'view raw database', querystr={'raw': 1})) + + return ''.join(result) |