Brillo: cfg80211 regulatory domain & CRDA

虽然Brillo m10-dev系统已经可以在RPi 2B/3B上正常运行了,同时RPi 3B的无线网卡也可以正常工用在AP/STA模式,但是在kernel log还是会有如下的警告信息:

[   10.336324] cfg80211: Calling CRDA to update world regulatory domain
[   13.496321] cfg80211: Calling CRDA to update world regulatory domain
[   16.656316] cfg80211: Calling CRDA to update world regulatory domain
[   19.816311] cfg80211: Calling CRDA to update world regulatory domain
[   22.976321] cfg80211: Calling CRDA to update world regulatory domain
[   26.136317] cfg80211: Calling CRDA to update world regulatory domain
[   29.296426] cfg80211: Calling CRDA to update world regulatory domain
[   32.456312] cfg80211: Calling CRDA to update world regulatory domain
[   35.616304] cfg80211: Exceeded CRDA call max attempts. Not calling CRDA

看到了有80211字段, 很显然跟无线网卡有关,同时我们如果去查找代码的话,可以发现log出自于rpi-4.1.y/net/wireless/reg.c文件:

/*
 * This lets us keep regulatory code which is updated on a regulatory
 * basis in userspace.
 */
static int call_crda(const char *alpha2)
{
    char country[12];
    char *env[] = { country, NULL };

    snprintf(country, sizeof(country), "COUNTRY=%c%c",
         alpha2[0], alpha2[1]);

    /* query internal regulatory database (if it exists) */
    reg_regdb_query(alpha2);

    if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) {
        pr_info("Exceeded CRDA call max attempts. Not calling CRDA\n");
        return -EINVAL;
    }

    if (!is_world_regdom((char *) alpha2))
        pr_info("Calling CRDA for country: %c%c\n",
            alpha2[0], alpha2[1]);
    else
        pr_info("Calling CRDA to update world regulatory domain\n");

    return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
}

从这里的comments我们可以知道,我们需要在userspace中更新regulatory domain,也就意味着我们需要一个应用程序去更新regulator domain。

而CRDA又是什么东西呢?从https://wireless.wiki.kernel.org/en/developers/regulatory/crda我们知道它的全称为Central Regulator Domain Agent, 就是用来更新regulatory domain的,在kernel启动或者是系统运行时,kernel会发送相应的uevent通知userspace去更新regulator domain,相关的UEVENT如下:

change@/devices/platform/regulatory.0 ACTION=change DEVPATH=/devices/platform/regulatory.0 SUBSYSTEM=platform COUNTRY=00 MODALIAS=platform:regulatory SEQNUM=1095

NOTE:在执行iw reg set命令的时候,也会收到相关的UEVENT信息:

$ iw reg set US

对于userspace应用来说,在Raspbian或者Ubuntu等其他linux系统来说,udev就会接收到相关的UEVENT信息,然后执行相应的命令去更新,也让你会发现有这相样的udev rules:

KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="/sbin/crda"

通过/sbin/crda去更新regulatory domain。在Ubuntu 14.04系统下,可以通过如下命令下载crda的代码:

$ apt-get source crda
Reading package lists... Done
Building dependency tree       
Reading state information... Done
NOTICE: 'crda' packaging is maintained in the 'Git' version control system at:
git://git.debian.org/kernel/crda.git
Need to get 29.5 kB of source archives.
Get:1 http://ubuntu.cn99.com/ubuntu/ trusty/main crda 1.1.2-1ubuntu2 (dsc) [2,068 B]
Get:2 http://ubuntu.cn99.com/ubuntu/ trusty/main crda 1.1.2-1ubuntu2 (tar) [21.8 kB]
Get:3 http://ubuntu.cn99.com/ubuntu/ trusty/main crda 1.1.2-1ubuntu2 (diff) [5,703 B]
Fetched 29.5 kB in 1s (17.0 kB/s)
gpgv: Signature made Mon 01 Oct 2012 03:57:22 PM EDT using RSA key ID 7D86500B
gpgv: Can't check signature: public key not found
dpkg-source: warning: failed to verify signature on ./crda_1.1.2-1ubuntu2.dsc
dpkg-source: info: extracting crda in crda-1.1.2
dpkg-source: info: unpacking crda_1.1.2.orig.tar.bz2
dpkg-source: info: unpacking crda_1.1.2-1ubuntu2.debian.tar.gz
dpkg-source: info: applying do_not_embed_pubkeys.patch
dpkg-source: info: applying crda_add-nested-support-for-libnl-3.2.patch

通过查看crda的代码,我们知道除了需要/sbin/crda文件之外,我们还需要如下这几个文件:

  1. /lib/crda/regulatory.bin
  2. /lib/crda/pubkeys/benh@debian.org.key.pub.pem
  3. /lib/crda/pubkeys/linville.key.pub.pem

NOTE: pubkeys只是用来检查regulatory.bin是否合法。

当然crda还会去读取环境变量:COUNTRY,并根据当前的环境变量更新regulatory domain。

在Brillo系统中,没有crda,也没有regulatory.bin,为什么DragonBoard 410c的kernel log却没有这样的log呢?原因在于regulatory domain的信息除了可以由userspace提供外,还可以采用kernel built-in的形式,只要你在配置kernel的时候,enable CONFIG_CFG80211_INTERNAL_REGDB,同时你还需要更新一下kernel代码中的net/wireless/db.txt文件:

#
# This file is a placeholder to prevent accidental build breakage if someone
# enables CONFIG_CFG80211_INTERNAL_REGDB.  Almost no one actually needs to
# enable that build option.
#
# You should be using CRDA instead.  It is even better if you use the CRDA
# package provided by your distribution, since they will probably keep it
# up-to-date on your behalf.
#
# If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will
# need to replace this file with one containing appropriately formatted
# regulatory rules that cover the regulatory domains you will be using.  Your
# best option is to extract the db.txt file from the wireless-regdb git
# repository:
#
#   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
#

如果你去查看DragonBoard 410c kernel相关的代码的话,你可以发现这个文件已经包含了regulatory domain的相关信息,如果去再去查看提记录的话,你会发出这个文件已经被修改多次,这也说明,regulatory domain还是通过userspace来更新比较好。

在brillo-m10-dev-rpi3b中也实现类似这样的更新机制:

存在一个crdad service, 用于monitor UEVENT, 当收到regulatory domain更新的UEVENT, 设置COUNTERY环境变量后,执行/system/bin/crda读取/vendor/lib/crda/regulatory.bin去更新regulatory domain。

1. 相关文件结构

/local/brillo-m10-dev-rpi3b
+-- device
    `-- hzak
        `-- rpi3b
            +-- base_product
            |   `-- rpi3b.mk
            +-- bsp
            |   +-- crdad
            |   `-- sepolicy
            |       +-- crdad.te
            |       `-- file_contexts
            `-- fs_config
                `-- android_filesystem_config.h

NOTE:

a. crda的代码来自于git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/crda.git

b. regulatory.bin及相应的pubkeys来自于NOOBS_v1.9.0.zip文件

c. 需要定义crdad domain, 不然在start crdad service时,会有如下log:

# start crdad
[  109.723461] init: Service crdad does not have a SELinux domain defined.

d. 最终生成的文件system/bin/crda可能需要有NET_CAP_ADMIN与NET_CAP_RAW权限,不然在写入regulatory时会失败。需要修改device/hzak/rpi3b/fs_config/android_filesystem_config.h文件。

2. 最终生成的文件结构

/system
+-- bin
|   +-- crda
|   `-- crdad
+-- etc
|   `-- init
|       `-- crdad.rc
`-- vendor
    `-- lib
        `-- crda
            +-- pubkeys
            |   +-- benh@debian.org.key.pub.pem
            |   `-- linville.key.pub.pem
            `-- regulatory.bin

3. 由于在kernel中开启了CONFIG_CFG80211_REG_DEBUG, 所以在kernel中会出现如下log:

[    7.145061] cfg80211: Calling CRDA to update world regulatory domain
[    7.215262] cfg80211: World regulatory domain updated:
[    7.220425] cfg80211:  DFS Master region: unset
[    7.224779] cfg80211:   (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp), (dfs_cac_time)
[    7.234573] cfg80211:   (2402000 KHz - 2472000 KHz @ 40000 KHz), (N/A, 2000 mBm), (N/A)
[    7.242615] cfg80211:   (2457000 KHz - 2482000 KHz @ 40000 KHz), (N/A, 2000 mBm), (N/A)
[    7.250672] cfg80211:   (2474000 KHz - 2494000 KHz @ 20000 KHz), (N/A, 2000 mBm), (N/A)
[    7.258745] cfg80211:   (5170000 KHz - 5250000 KHz @ 80000 KHz, 160000 KHz AUTO), (N/A, 2000 mBm), (N/A)
[    7.268289] cfg80211:   (5250000 KHz - 5330000 KHz @ 80000 KHz, 160000 KHz AUTO), (N/A, 2000 mBm), (0 s)
[    7.277838] cfg80211:   (5490000 KHz - 5730000 KHz @ 160000 KHz), (N/A, 2000 mBm), (0 s)
[    7.285977] cfg80211:   (5735000 KHz - 5835000 KHz @ 80000 KHz), (N/A, 2000 mBm), (N/A)
[    7.293983] cfg80211:   (57240000 KHz - 63720000 KHz @ 2160000 KHz), (N/A, 0 mBm), (N/A)

而如果通过iw命令手动更新regulatory domain,  也会有相应的log:

# iw reg set CN
[ 1201.998057] cfg80211: Calling CRDA for country: CN
# [ 1202.044542] cfg80211: Regulatory domain changed to country: CN
[ 1202.050432] cfg80211:  DFS Master region: FCC
[ 1202.054612] cfg80211:   (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp), (dfs_cac_time)
[ 1202.064375] cfg80211:   (2402000 KHz - 2482000 KHz @ 40000 KHz), (N/A, 2000 mBm), (N/A)
[ 1202.072401] cfg80211:   (5170000 KHz - 5250000 KHz @ 80000 KHz, 160000 KHz AUTO), (N/A, 2300 mBm), (N/A)
[ 1202.081898] cfg80211:   (5250000 KHz - 5330000 KHz @ 80000 KHz, 160000 KHz AUTO), (N/A, 2300 mBm), (0 s)
[ 1202.091390] cfg80211:   (5735000 KHz - 5835000 KHz @ 80000 KHz), (N/A, 3000 mBm), (N/A)
[ 1202.099407] cfg80211:   (57240000 KHz - 59400000 KHz @ 2160000 KHz), (N/A, 2800 mBm), (N/A)
[ 1202.107772] cfg80211:   (59400000 KHz - 63720000 KHz @ 2160000 KHz), (N/A, 4400 mBm), (N/A)
[ 1202.116136] cfg80211:   (63720000 KHz - 65880000 KHz @ 2160000 KHz), (N/A, 2800 mBm), (N/A)

相关的代码可以从这里下载:2016_04_15_brillo-m10-dev-rpi3b-v1.1.tar.gz

  • 相关的参考文档
  1. https://wireless.wiki.kernel.org/en/developers/regulatory/crda

《Brillo: cfg80211 regulatory domain & CRDA》有2个想法

  1. 你好,请问怎么开启CONFIG_CFG80211_INTERNAL_REGDB,它是内核的一个模块么?如果是,那么在make menuconfig里面的位置是什么,谢谢

    1. 你可以参考这两篇文档:
      1. http://linuxwireless.org/en/developers/Regulatory/
      2. http://linuxwireless.org/en/developers/Regulatory/CRDA/#CONFIG_CFG80211_INTERNAL_REGDB
      在这个文件中:
      https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/net/wireless/Kconfig#n142

发表评论

电子邮件地址不会被公开。 必填项已用*标注