Linux 無線法規文件¶
本文件簡要回顧了 Linux 無線法規基礎設施的工作原理。
更多最新資訊可以在該專案的網頁上獲取
https://wireless.wiki.kernel.org/en/developers/Regulatory
將法規域儲存在使用者空間中¶
由於法規域的動態特性,我們將其儲存在使用者空間中,並提供一個框架供使用者空間上傳一個法規域到核心,作為所有無線裝置應遵守的中央核心法規域。
如何將法規域傳遞到核心¶
首次設定法規域時,核心將請求一個包含所有法規規則的資料庫檔案 (regulatory.db)。當需要查詢給定國家/地區的規則時,它將使用該資料庫。
如何將法規域傳遞到核心 (舊 CRDA 解決方案)¶
使用者空間透過讓使用者空間代理構建並透過 nl80211 傳送法規域來將其傳遞到核心。核心只會尊重預期的法規域。
目前可用的使用者空間代理 CRDA - 中央法規域代理,可以完成此操作。它的文件在這裡
https://wireless.wiki.kernel.org/en/developers/Regulatory/CRDA
本質上,核心會在知道需要新的法規域時傳送一個 udev 事件。可以設定一個 udev 規則來觸發 crda 傳送特定 ISO/IEC 3166 alpha2 的相應法規域。
以下是可以使用的 udev 規則的示例
# 示例檔案,應放在 /etc/udev/rules.d/regulatory.rules KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="/sbin/crda"
alpha2 作為環境變數在變數 COUNTRY 下傳遞。
誰請求法規域?¶
使用者
使用者可以使用 iw
https://wireless.wiki.kernel.org/en/users/Documentation/iw
一個例子
# set regulatory domain to "Costa Rica"
iw reg set CR
這將請求核心將法規域設定為指定的 alpha2。反過來,核心將透過傳送 uevent 請求使用者空間為使用者指定的 alpha2 提供法規域。
用於國家/地區資訊元素的無線子系統
核心將傳送一個 uevent,以通知使用者空間需要一個新的法規域。更多關於此的資訊將在新增其整合時新增。
驅動程式
如果驅動程式確定它們需要設定特定的法規域,它們可以使用 regulatory_hint() 通知無線核心。它們有兩種選擇——它們可以提供一個 alpha2,以便 crda 可以返回該國家/地區的法規域,或者它們可以基於內部自定義知識構建自己的法規域,以便無線核心可以尊重它。
大多數 驅動程式將依賴於第一種機制,即使用 alpha2 提供法規提示。對於這些驅動程式,還有一個額外的檢查,可用於確保基於自定義 EEPROM 法規資料的合規性。驅動程式可以透過在其 struct wiphy 上註冊一個 reg_notifier() 回撥來使用此額外的檢查。當核心的法規域已更改時,將呼叫此通知程式。驅動程式可以使用它來檢視所做的更改,並檢視誰進行了更改(驅動程式、使用者、國家/地區 IE),並根據其內部 EEPROM 資料確定允許的內容。希望能夠進行全球漫遊的裝置驅動程式應使用此回撥。當啟用其支援時,將在本文件中新增有關全球漫遊的更多資訊。
提供自己構建的法規域的裝置驅動程式不需要回調,因為它們註冊的通道是唯一允許的通道,因此無法啟用 額外的 通道。
示例程式碼 - 驅動程式提示 alpha2:¶
此示例來自 zd1211rw 裝置驅動程式。您可以首先將裝置的 EEPROM 國家/地區/法規域值對映到特定的 alpha2,如下所示
static struct zd_reg_alpha2_map reg_alpha2_map[] = {
{ ZD_REGDOMAIN_FCC, "US" },
{ ZD_REGDOMAIN_IC, "CA" },
{ ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */
{ ZD_REGDOMAIN_JAPAN, "JP" },
{ ZD_REGDOMAIN_JAPAN_ADD, "JP" },
{ ZD_REGDOMAIN_SPAIN, "ES" },
{ ZD_REGDOMAIN_FRANCE, "FR" },
然後,您可以定義一個例程,將讀取的 EEPROM 值對映到 alpha2,如下所示
static int zd_reg2alpha2(u8 regdomain, char *alpha2)
{
unsigned int i;
struct zd_reg_alpha2_map *reg_map;
for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) {
reg_map = ®_alpha2_map[i];
if (regdomain == reg_map->reg) {
alpha2[0] = reg_map->alpha2[0];
alpha2[1] = reg_map->alpha2[1];
return 0;
}
}
return 1;
}
最後,如果找到匹配項,則可以向核心提示您發現的 alpha2。您需要在註冊 wiphy 後執行此操作。您應該在初始化期間執行此操作。
r = zd_reg2alpha2(mac->regdomain, alpha2);
if (!r)
regulatory_hint(hw->wiphy, alpha2);
示例程式碼 - 驅動程式提供內建法規域:¶
[注意:此 API 當前不可用,可以在需要時新增]
如果您有可以從驅動程式中獲取的法規資訊,並且您 需要 使用它,我們將允許您構建一個法規域結構並將其傳遞給無線核心。為此,您應該 kmalloc() 一個足夠大的結構來容納您的法規域結構,然後您應該用您的資料填充它。最後,您只需呼叫 regulatory_hint(),其中包含法規域結構。
以下是一個簡單的示例,其中法規域使用堆疊進行快取。您的實現可能會有所不同(例如,讀取 EEPROM 快取)。
一些法規域的示例快取
struct ieee80211_regdomain mydriver_jp_regdom = {
.n_reg_rules = 3,
.alpha2 = "JP",
//.alpha2 = "99", /* If I have no alpha2 to map it to */
.reg_rules = {
/* IEEE 802.11b/g, channels 1..14 */
REG_RULE(2412-10, 2484+10, 40, 6, 20, 0),
/* IEEE 802.11a, channels 34..48 */
REG_RULE(5170-10, 5240+10, 40, 6, 20,
NL80211_RRF_NO_IR),
/* IEEE 802.11a, channels 52..64 */
REG_RULE(5260-10, 5320+10, 40, 6, 20,
NL80211_RRF_NO_IR|
NL80211_RRF_DFS),
}
};
然後在註冊 wiphy 後代碼的某部分中
struct ieee80211_regdomain *rd;
int size_of_regd;
int num_rules = mydriver_jp_regdom.n_reg_rules;
unsigned int i;
size_of_regd = sizeof(struct ieee80211_regdomain) +
(num_rules * sizeof(struct ieee80211_reg_rule));
rd = kzalloc(size_of_regd, GFP_KERNEL);
if (!rd)
return -ENOMEM;
memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain));
for (i=0; i < num_rules; i++)
memcpy(&rd->reg_rules[i],
&mydriver_jp_regdom.reg_rules[i],
sizeof(struct ieee80211_reg_rule));
regulatory_struct_hint(rd);
靜態編譯的法規資料庫¶
當資料庫應該固定到核心中時,可以在構建時將其作為韌體檔案提供,然後連結到核心中。