NOTE: this page is for archival only, see the note at the end of the page.

CRDA - Central Regulatory Domain Agent

CRDA is a FOSS project to solve the problem of lack of support by wireless vendors due to regulatory considerations by dealing with regulatory considerations directly through the wireless subsystem. This is achieved by working with the community on a thorough and flexible regulatory database which is maintained in userspace and providing a userspace agent which can be triggered to update the kernel's wireless core with one regulatory domain for a specific country. Keeping the database in userspace allows distributions to provide updates without kernel upgrades. The database is ultimately converted to binary form using a new binary file format designed for size efficiency, integrity checking and to allow upgrades without updates of the kernel. Integrity of the file is ensured by CRDA by verifying the RSA digital signature of the database. The userspace agent can then be triggered to upload to the kernel one regulatory domain for a specific ISO-3166 alpha2 country string. We use an alpha2 country code as that is the same string used by the 802.11d country information element for country localization. Once the kernel has this one regulatory domain the wireless subsystem can decide how it wants to use this information.

Although CRDA can be seen as a complete regulatory solution for some Linux drivers it actually is not the only component which will be relied upon to help with regulatory restrictions. Some drivers rely on some readings from the EEPROM for enforcement or calibration and this is done through different techniques. We ensure drivers can keep relying on these internal techniques by using a notifier chain to inform the drivers upon regulatory domain change so they themselves can review the regulatory information set by basing it on their EEPROM data. For these type of drivers CRDA provides an extra layer of regulatory compliance. For drivers without any regulatory information from the EEPROM it is the complete regulatory solution.

Review of 802.11d

The 8011.d amendment:

specifies the extensions to IEEE Std 802.11 for Wireless Local Area Networks providing specifications for conformant operation beyond the original six regulatory domains of that standard. These extensions provide a mechanism for an IEEE Std 802.11 access point to deliver the required radio transmitter parameters to an IEEE Std 802.11 mobile station, which allows that station to configure its radio to operate within the applicable regulations of a geographic or political subdivision. This mechanism is applicable to all IEEE Std 802.11 PHY types. A secondary benefit of the mechanism described in this amendment is the ability for an IEEE Std 802.11 moble station to roam between regulatory domains.

802.11d Information Elements

Country IE

The Country Information Element contains the information required to allow a station to identify the regulatory domain in which the station is located and to configure its PHY for operation in that regulatory domain. The 802.11d Country IE has the following format:

 -------------------------------------------------------------------------
|  Element ID (7))                  |          Length                     |
|-------------------------------------------------------------------------|
|                              Country ISO3166-alpha2                     |
|-------------------------------------------------------------------------|
|  Indoor/Outdoor/Both         |    First channel number                  | 
|-------------------------------------------------------------------------|
|     Number of channels       |   Max TX power (+/- dBm)                 |
|-------------------------------------------------------------------------|
|                                             .......                     |
|-------------------------------------------------------------------------|
|        First channel number  |  Number of channels                      |
|-------------------------------------------------------------------------|
| Max TX power (+/- dBm)   |             Pad (if needed)                  |
 --------------------------------------------------------------------------

The CRDA design

The diagram below best illustrates the current design of using CRDA:

http://wireless.kernel.org/crda.png

RSA Digital Signature

Integrity is ensured by relying on a digital signature by signing the regulatory data using a private key, and embedding the signature and public key as part of the binary file. The final binary regulatory file is parsed by the userspace agent and its integrity is verified by checking the signature of the binary regulatory data so far in the binary file using the public embedded key and signed checksum.

The private key must be an RSA key and can be generated with openssl. An example of how to generate a 1024-bit RSA key with openssl follows:

openssl genrsa -out key.priv.pem 1024

We support different key sizes.

ASCII file format

Below is an example of a country entry for the db.txt regulatory file for AR (Argentina).

country AR:
        (2402 - 2482 @ 40), (N/A, 20), NO-HT40
        (5270 - 5330 @ 40), (6, 17), NO-HT40
        (5735 - 5815 @ 40), (6, 30), NO-HT40

Binary file format

We define a new custom binary file format for use with CRDA. We use a binary file to be able to compact the data as much as possible, to be able to have an integrity check and to be able to redistribute changes to regulatory information without updating the kernel. The magic number used to identify the file type is 0x52474442. We start the file format version at 19 to help with the magic signature, it however is still considered version 1 of the file format. The data in the file is kept in big endian format. Below we specify the file format for the binary regulatory database.

regdb.h HEAD on crda.git

#include <linux/types.h>

/*
 * WARNING: This file needs to be kept in sync with
 *  - the parser (dbparse.py)
 *  - the generator code (db2bin.py)
 */

/* spells "RGDB" */
#define REGDB_MAGIC     0x52474442

/*
 * Only supported version now, start at arbitrary number
 * to have some more magic. We still consider this to be
 * "Version 1" of the file.
 */
#define REGDB_VERSION   19

/*
 * The signature at the end of the file is an RSA-signed
 * SHA-1 hash of the file.
 */

struct regdb_file_header {
        /* must be REGDB_MAGIC */
        __be32  magic;
        /* must be REGDB_VERSION */
        __be32  version;
        /*
         * Pointer (offset) into file where country list starts
         * and number of countries. The country list is sorted
         * alphabetically to allow binary searching (should it
         * become really huge.)
         */
        __be32  reg_country_ptr;
        __be32  reg_country_num;
        /* length (in bytes) of the signature at the end of the file */
        __be32  signature_length;
};

struct regdb_file_freq_range {
        __be32  start_freq,
                end_freq,
                max_bandwidth;
};

/*
 * Values of zero mean "not applicable", i.e. the regulatory
 * does not limit a certain value.
 */
struct regdb_file_power_rule {
        /* antenna gain is in mBi (100 * dBi) */
        __be32  max_antenna_gain;
        /* this is in mBm (100 * dBm) */
        __be32  max_eirp;
};

#define EDGE_POWER_SHIFT        11

enum reg_rule_flags {
        RRF_NO_OFDM             = 1<<0,
        RRF_NO_CCK              = 1<<1,
        RRF_NO_INDOOR           = 1<<2,
        RRF_NO_OUTDOOR          = 1<<3,
        RRF_DFS                 = 1<<4,
        RRF_PTP_ONLY            = 1<<5,
        RRF_PTMP_ONLY           = 1<<6,
        RRF_PASSIVE_SCAN        = 1<<7,
        RRF_NO_IBSS             = 1<<8,
        /* hole at 9 */
        RRF_NO_HT40             = 1<<10,
};

struct regdb_file_reg_rule {
        /* pointers (offsets) into the file */
        __be32  freq_range_ptr,
                power_rule_ptr;
        /* rule flags */
        __be32 flags;
};

struct regdb_file_reg_rules_collection {
        __be32  reg_rule_num;
        /* pointers (offsets) into the file */
        __be32  reg_rule_ptrs[];
};

struct regdb_file_reg_country {
        __u8    alpha2[2];
        __u8    PAD[2];
        /* pointer (offset) into the file */
        __be32  reg_collection_ptr;
};


/*
 * Verify that no unexpected padding is added to structures
 * for some reason.
 */

#define ERROR_ON(cond) \
        ((void)sizeof(char[1 - 2*!!(cond)]))

#define CHECK_STRUCT(name, size) \
        ERROR_ON(sizeof(struct name) != size)

static inline void check_db_binary_structs(void)
{
        CHECK_STRUCT(regdb_file_header, 20);
        CHECK_STRUCT(regdb_file_freq_range, 12);
        CHECK_STRUCT(regdb_file_power_rule, 8);
        CHECK_STRUCT(regdb_file_reg_rule, 12);
        CHECK_STRUCT(regdb_file_reg_rules_collection, 4);
        CHECK_STRUCT(regdb_file_reg_country, 8);
}

Binary file magic pattern

The following magic(5) pattern can be used on systems with the file(1) program which recognizes the format of different binary file. To recognize CRDA binary regulatory database files add into your /etc/magic file:

# CRDA Regulatory database file
# http://git.kernel.org/?p=linux/kernel/git/mcgrof/crda.git;a=summary
# (see regdb.h)
0       belong          0x52474442      CRDA regulatory database file
>4      belong          19              (Version 1)

Status of CRDA

The userspace agent components of parsing a db.txt, implementing RSA digital signature support and defining a file format are all complete. A guide db.txt is also available. What is left:

  • Integration with the kernel
  • Write the userspace agent the kernel will communicate with

A first patch for RFC has been posted, follows are expected soon.

CRDA code

You can get the latest CRDA code from:

git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/crda.git

Usage design in Linux

In this section we cover how will be using CRDA on our wireless subsystem in Linux and how it will work for the different types of drivers we have.

Wireless core initialization

Upon the initialization of the wireless core (cfg80211) the world regulatory domain will be set as the central regulatory domain. The world regulatory domain can however be dynamically generated as the common denominator of all regulatory domains supported and every now and then updated statically in kernel. If CRDA is present the latest dynamic world regulatory domain can always be available by querying CRDA and having it provide the the latest dynamic common world regulatory domain. We however always leave a statically defined world regulatory domain in the kernel in case of the absence of CRDA.

Once each driver or mac80211 (when ieee80211_hw_register() is called) calls wiphy_register() wiphy_update_regulatory() is called to update the device's supported bands and channels based on the world regulatory domain as this was just set upon initialization. So each driver will *initially* only support the world regulatory domain.

Setting the current regulatory domain

As per 802.11d devices are able to roam if they have dot11MultiDomainCapabilityEnabled set. Most modern devices are capable of this. For devices that do not have this capability enabled they would simply rely on their static hardware capabilities. For those devices that are capable or roaming we support different ways in which they can set the regulatory domain.

Driver settings

Each driver can hint to the wireless core (cfg80211) which regulatory domain to set by providing an ISO-3166 alpha2 country code. In the end only one regulatory domain is possible for the entire wireless core because you can only be present in one place at the same time. CRDA was designed to support differentiating rules for PtP and PtMP so differnt rules for these are possible within one regulatory domain, however the wireless subsystem must first be enhanced to help distinguish between these two type of link options for each interface.

Conflicts can arise when you have multiple wireless devices present on a system which claim different regulatory domains. For now we will be trusting the regulatory domain selected by the first wireless card on a system which claims to know the current regulatory domain. Eventual support for dealing with conflicts will be dealt with, in these cases it seems reasonable to let the user select the alpha2 themselves. Remember each driver still is capable of being informed about this to adjust its own channel enable/disable flags after that through the notification chain.

Once an alpha2 is suggested to the wireless core it will query CRDA for a regulatory domain for that alpha2. The wireless core will then iterate overall all registered wireless devices and update the device's list of enabled channels, max power, max bandwidth and max antenna gain for each of them.

After a regulatory domain has been set the notification chain is called and each registered callback informed of the event. Drivers have the option to register their callback for this notification chain. They can review the current regulatory settings and update them based on further requirements.

802.11d settings

As per 802.11d APs can provide an ISO-3166-alpha alpha2 country string and a channel list with an associated max tx power setting. In practice though vendors do not always trust APs country information element regulatory information due to considerations for outdated data or rogue APs. To help with these considerations and to also help follow the standard we can determine the regulatory domain set based on the common denominator of elements and data present between the APs country information element and what CRDA provides for the given alpha2. Additionally if drivers want further checks they simply implement the notification chain callback to be informed when a new regulatory domain is set.

Manual setting of the regulatory domain

Manual setting for a regulatory domain only makes sense if you have no 802.11d capable AP or if your card has no embedded EEPROM regulatory information. To help these type of devices we can allow setting of the regulatory domain to help the user comply to regulatory rules. This can happen, for example, when you travel with a card with no world roaming capabilities, for example. For devices with their own EEPROM regulatory information the callback routine registered to the regulatory callback chain for the driver can ensure the EEPROM data is respected if a user changes the regulatory information manually. This ensures only the supported channel list by the EEPROM or a subset of it is used, never more.

Driver initialization

As mentioned above in the wireless core initializationafter the driver has registered to the wireless core (cfg80211) the world regulatory domain settings will have been set by default as no beacons with 802.11d country information elements could have been received yet. The channels it should register to the wireless core should be *all* supported hardware channels.

Drivers with no EEPROM regulatory information

Drivers with no EEPROM regulatory information can simply rely on the world regulatory domain, wait for an 802.11d country information element or by setting the regulatory domain manually.

Drivers with EEPROM regulatory information

If the EEPROM regulatory information indicates some channels for a specific regulatory domain should not be enabled they can simply be disabled by the driver callback routine registered to the regulatory chain notification, this will be called following the setting of a regulatory domain in the wireless core. If the driver can map its EEPROM regulatory domain to a specific ISO-3166 alpha2 country code it can inform the wireless core of this. The wireless core will then query CRDA for a regulatory domain for this country,then iterate over all present wireless devices and update the driver's information based on these new regulatory rules. At the end of this iteration over all wireless devices the regulatory notification chain is called and each driver which has a registered callback can run. This allows drivers to review the changes made on its channel list based on its own EEPROM data.


This is a static dump of the wiki, taken after locking it in January 2015. The new wiki is at https://wireless.wiki.kernel.org/.
versions of this page: last, v53, v52, v51, v50, v49, v48, v47, v46, v45, v44, v43, v42, v41, v40, v39, v38, v37, v36, v35, v34, v33, v32, v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16, v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5, v4, v3, v2, v1