# Linux 核心專題: 虛擬無線網路裝置驅動程式
> 執行人: jychen0611
> [專題解說錄影](https://youtu.be/7iWKQkFi5hs)
> [投影片](https://docs.google.com/presentation/d/1mfPmcycuIvSVjwkX7R_eJEKTBklaW1c2/edit?usp=drive_link)
### Reviewed by `marsh-fish`
是否可以提供 Ad-hoc (IBSS) mode 的實作程式碼?
> 有關 Ad-hoc (IBSS) mode 相關程式碼的更新可見 [Support ad hoc network #70](https://github.com/sysprog21/vwifi/pull/70)
>[name=jychen0611]
### Reviewed by `dcciou`
請問是否知道封包的傳遞錯誤率
> 據我所知,目前 [iw](https://wireless.wiki.kernel.org/en/users/documentation/iw) 相關命令無法提供 BER (bit error rate) 的相關底層傳輸資訊,但能透過 **iw dev vw_i link** 得知封包傳遞接收的數量及 byte 數統計。若想用模擬的方式推得 BER ,則須考量SNR (signal-to-noise ratio)、編碼模式、距離、阻擋等因素。可見 [What is the relation between Bit Error Rate (BER), distance d and SNR(dB)?](https://in.mathworks.com/matlabcentral/answers/2068346-what-is-the-relation-between-bit-error-rate-ber-distance-d-and-snr-db)
>[name=jychen0611]
## 任務簡介
[vwifi](https://github.com/sysprog21/vwifi) 是個程式碼約~三千行,具體而微的 WiFi 裝置驅動程式,採用 cfg80211 框架。目前 vwifi 支援 scan, connect, disconnect 等 cfg80211 的介面操作,並得以正確處理 Tx/Rx 封包。
## TODO: 支援 Linux v6.8+
> [commit 35ca058](https://github.com/sysprog21/vwifi/commit/35ca058e767d87a7c809091ae910b2bf02687870) / [Align with recent cfg80211 header (#63)](https://github.com/sysprog21/vwifi/pull/63)
- [ ] The scan_width field is no longer present in the cfg80211_inform_bss structure.
> [commit 5add321](https://github.com/torvalds/linux/commit/5add321c329b1746589b51359259666ca3dbe219) "wifi: cfg80211: remove scan_width support"
kernel version : *v6.9-rc6 ~ v6.7-rc1*
date : Sep 13, 2023
> There really isn't any support for scanning at different channel widths than 20 MHz since there's no way to set it.
Remove this support for now, if somebody wants to maintain this whole thing later we can revisit how it should work.
```diff
- bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20;
```
- [ ] The parameters in the change_beacon function have been updated to cfg80211_ap_update.
:::info
[**beacon**](https://www.dictionary.com/browse/beacon) [bee-kuhn]
>*a guiding or warning signal, as a light or fire, especially one in an elevated position.*
在此指用來傳遞 BSS (Basic Service Set) 的相關訊息的 management frame,使其他無線裝置能得知該 BSS 的存在。
>A beacon frame is a type of management frame in IEEE 802.11 WLANs. It contains information about the network. Beacon frames are transmitted periodically; they serve to announce the presence of a wireless LAN and to provide a timing signal to synchronise communications with the devices using the network (the members of a service set).
* >In an infrastructure basic service set (BSS), beacon frames are transmitted by the access point (AP).
* >In ad hoc (IBSS) networks, beacon generation is distributed among the stations.
:::
> [commit bb55441](https://github.com/torvalds/linux/commit/bb55441c57ccc5cc2eab44e1a97698b9d708871d) "wifi: cfg80211: split struct cfg80211_ap_settings"
kernel version : *v6.9-rc6 ~ v6.7-rc1*
date : Sep 25, 2023
> Using the full struct cfg80211_ap_settings for an update is misleading, since most settings cannot be updated. Split the update case off into a new struct cfg80211_ap_update.
```diff
/**
* struct cfg80211_ap_update - AP configuration update
*
* Subset of &struct cfg80211_ap_settings, for updating a running AP.
*
* @beacon: beacon data
* @fils_discovery: FILS discovery transmission parameters
* @unsol_bcast_probe_resp: Unsolicited broadcast probe response parameters
*/
+struct cfg80211_ap_update {
+ struct cfg80211_beacon_data beacon;
+ struct cfg80211_fils_discovery fils_discovery;
+ struct cfg80211_unsol_bcast_probe_resp unsol_bcast_probe_resp;
+};
int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_ap_settings *info);
+ struct cfg80211_ap_update *info);
```
> [commit 66f85d5](https://github.com/torvalds/linux/commit/66f85d57b7109baf8a7d5ee04049ac9412611d35) "wifi: cfg80211: modify prototype for change_beacon"
kernel version : *v6.9-rc6 ~ v6.7-rc1*
date : Sep 13, 2023
> Modify the prototype for change_beacon() in struct cfg80211_op to accept cfg80211_ap_settings instead of cfg80211_beacon_data so that it can process data in addition to beacons.
Modify the prototypes of ieee80211_change_beacon() and driver specific functions accordingly.
```diff
int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_beacon_data *info);
+ struct cfg80211_ap_settings *info);
```
Simply put, the change_beacon function now includes two additional parameters, fils_discovery and unsol_bcast_probe_resp, which are part of the cfg80211_ap_update structure.
* fils_discovery : FILS discovery transmission parameters
* unsol_bcast_probe_resp : Unsolicited broadcast probe response parameters
## TODO: 建立背景知識
閱讀《[802.11 Wireless Networks: The Definitive Guide, 2/e](https://www.oreilly.com/library/view/80211-wireless-networks/0596100523/)》建立基礎概念
> [筆記](https://hackmd.io/@jychen0611/IEEE_802_11)
〈[Lightweight and Fast WiFi Access in Virtual Machines](https://osseu2023.sched.com/event/1OGgh)〉, Open Source Summit Europe 2023
## TODO: Emulate rate and mcs
> [commit a8bdf8a](https://github.com/sysprog21/vwifi/commit/a8bdf8a4405cbc5e25beb29bb1956bfac82ca303) / [Support data rate and MCS (#67)](https://github.com/sysprog21/vwifi/pull/67)
ref :
[WI-FI 7 MCS TABLE](https://semfionetworks.com/blog/wi-fi-7-mcs-table/)
[MCS Table](https://mcsindex.net/)
* QPSK (4-QAM)
* 利用 $0^\circ, 90^\circ, 180^\circ, 270^\circ$ 四個相位表示00 01 10 11,因此可表達 2 bits
* QAM
* $2^n$ QAM 表一個 symbol 可表達 n bits
![image](https://hackmd.io/_uploads/BJPswz8NC.png)
![image](https://hackmd.io/_uploads/SkKsBzUV0.png)
採用 802.11n (HT) 做為 PHY,設置如下 :
Modulation : 64-QAM
Data Bandwidth : 20MHz
Number of Spatial Streams : 4
參照 802.11n (HT) 調變對照表可得
Number of Data Subcarriers : 52
Number of Coded Bits per Subcarrier per Stream : 6
Coding : 5/6
OFDM Symbol Duration : 3.2 us
Guard Interval Duration : 0.8 us
即
$N_{SD} =52$
$N_{BPSCS} =6$
$R = \frac{5}{6}$
$N_{SS} = 4$
$T_{DFT} = 3.2\ us$
$T_{GI} = 0.8\ µs$
經公式推算後可得 data rate = 260 Mbps 與顯示結果相符
```diff
sinfo->filled = BIT_ULL(NL80211_STA_INFO_TX_PACKETS) |
...
+ BIT_ULL(NL80211_STA_INFO_RX_BITRATE)|
+ BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
/* Support 64-QAM modulation with 20MHz data bandwidth*/
+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS;
+ sinfo->rxrate.mcs = 31;
+ sinfo->rxrate.bw = RATE_INFO_BW_20;
+ sinfo->rxrate.n_bonded_ch = 1;
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+ sinfo->txrate.mcs = 31;
+ sinfo->txrate.bw = RATE_INFO_BW_20;
+ sinfo->txrate.n_bonded_ch = 1;
```
```shell
tx bitrate: 260.0 MBit/s MCS 31
rx bitrate: 260.0 MBit/s MCS 31
```
## TODO: 實作 vwifi_{set,get}_tx_power
>[commit f63872b](https://github.com/sysprog21/vwifi/commit/f63872b273f223b963c807c5e39b5f3299a818f5) / [Support transmit power (#68)](https://github.com/sysprog21/vwifi/pull/68)
在結構體 `vwifi_vif` 上新增 `tx_power` 以描述裝置的傳輸功率。
```diff
struct vwifi_vif {
+ /* Transmission power */
+ s32 tx_power;
};
```
在 `cfg80211_ops` 的架構上新增 `vwifi_set_tx_power` 及 `vwifi_get_tx_power` 用以設定和取得裝置的功率。
```diff
static struct cfg80211_ops vwifi_cfg_ops = {
+ .set_tx_power = vwifi_set_tx_power,
+ .get_tx_power = vwifi_get_tx_power,
};
```
使用者可透過 **iwconfig [interface] txpower [transmit power (dBm)]** 設定裝置傳輸功率。
以下命令將 `vw0` 的傳輸功率設為 11 dBm
```shell
$ sudo iwconfig vw0 txpower 11
$ iw dev
phy#10
Interface vw0
ifindex 12
wdev 0xa00000001
addr 00:76:77:30:00:00
type managed
txpower 11.00 dBm
```
為了維持命令一致性,必須支援 iw 命令設置 transmit power。
由於使用 iw 命令會導致 `set_tx_power` 的輸入參數 `wdev` 為 NULL,詳見
[cfg80211: allow per interface TX power setting](https://github.com/torvalds/linux/commit/c8442118ad9cd05cfe3b993f058e70ab25b1009a)
> The TX power setting is currently per wiphy (hardware
device) but with multi-channel capabilities that doesn't
make much sense any more.
>
> Allow drivers (and mac80211) to advertise support for
per-interface TX power configuration. **When the TX power is configured for the wiphy, the wdev will be NULL** and the driver can still handle that, but when a wdev is given the TX power can be set only for that wdev now.
>Signed-off-by: Johannes Berg <johannes.berg@intel.com>
因此新增函式 `wiphy_get_vwifi_vif` 以利用參數 `wiphy` 取得裝置的 virtual interface。
此外,亦利用參數 `type` 以區別命令為 auto/limit/fixed。
* auto : 使用預設傳輸功率
* limit : 限制功率上下限於特定值
* fixed : 可隨意設置功率
使用者可使用 **iw dev [interface] set txpower [auto/limit/fixed] [transmit power (mBm)]** 來設定。
* *注意這邊的功率單位為 mBm (1dBm = 100mBm)*
以下命令將 `vw0` 的傳輸功率設為 1100 mBm (即 11 dBm)
```shell
$ sudo iw dev vw0 set txpower fixed 1100
$ iw dev
phy#45
Interface vw0
ifindex 48
wdev 0x2d00000001
addr 00:76:77:30:00:00
type managed
txpower 11.00 dBm
```
## TODO: 實作 Ad-hoc (IBSS) mode
>[commit a5fc5f0](https://github.com/sysprog21/vwifi/commit/a5fc5f0734073a1f51dd75ebdfc9052c29848c5c) / [Support ad hoc network (#70)](https://github.com/sysprog21/vwifi/pull/70)
![ibss](https://hackmd.io/_uploads/ry3blTvP0.png)
### 新增 AD-HOC interface type
在 `wiphy` 上新增 `NL80211_IFTYPE_ADHOC` interface type,使其能透過 `vwifi_change_iface` 的 operation 切換成 Ad-hoc (IBSS) 模式。
```diff
static int vwifi_change_iface(...)
{
switch (type) {
...
+ case NL80211_IFTYPE_ADHOC:
+ ndev->ieee80211_ptr->iftype = type;
+ break;
...
}
wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_ADHOC);
```
使用者可透過命令 **iw dev [interface] set type ibss** 將裝置切換成 IBSS 模式。
```shell
$ sudo iw dev vw3 set type ibss
$ iw dev vw3 info
Interface vw3
ifindex 61
wdev 0x3a00000001
addr 00:76:77:33:00:00
type IBSS
wiphy 58
txpower 0.00 dBm
```
### 實作 IBSS join 與 leave 機制
在 `cfg80211_ops` 的架構上新增 `vwifi_join_ibss` 及 `vwifi_leave_ibss` 使 IBSS 裝置能加入特定 IBSS cell 及頻段。
```diff
static struct cfg80211_ops vwifi_cfg_ops = {
...
+ .join_ibss = vwifi_join_ibss,
+ .leave_ibss = vwifi_leave_ibss,
};
```
使用者可透過命令 **iw dev [interface] ibss join [SSID] [freq in MHz] [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [fixed-freq] [<fixed bssid>] [beacon-interval <TU>] [basic-rates <rate in Mbps,rate2,...>] [mcast-rate <rate in Mbps>] [key d:0:abcde]** 加入特定 IBSS cell 並同時建置其它設定。若此 IBSS cell 原先不存在則創建之。
以下命令使 `vw3` 加入 SSID 為 `ibss1` 的 IBSS cell,且指定頻段為 2412 MHz。
```shell
$ sudo iw dev vw3 ibss join ibss1 2412 NOHT fixed-freq 02:11:22:33:44:55 beacon-interval 100 basic-rates 6,12 mcast-rate 6 key d:0:abcde
$ iw dev vw3 info
Interface vw3
ifindex 51
wdev 0x3000000001
addr 00:76:77:33:00:00
ssid ibss1
type IBSS
wiphy 48
txpower 14.00 dBm
```
若要離開目前的 IBSS cell,則可使用 **iw dev [interface] ibss leave**
```
$ sudo iw dev vw3 ibss leave
$ iw dev vw3 info
Interface vw3
ifindex 51
wdev 0x3000000001
addr 00:76:77:33:00:00
type IBSS
wiphy 48
txpower 14.00 dBm
```
在 `vwifi_join_ibss` 中應紀錄 AD-HOC 之相關設定。
紀錄 AD-HOC 相關資訊的結構體定義在 virtual interface 中。
```c
/* Structure for AD-HOC mode */
struct {
/* List node for storing ibss (vwifi->ibss_list is the head),
* this field is for interface in AD-HOC mode.
*/
struct list_head ibss_list;
struct cfg80211_chan_def ah_chandef;
u16 ah_beacon_int;
u32 ah_basic_rates;
bool ah_channel_fixed;
bool ah_privacy;
bool ah_control_port;
bool ah_control_port_over_nl80211;
bool ah_userspace_handles_dfs;
int ah_mcast_rate[NUM_NL80211_BANDS];
struct ieee80211_ht_cap ah_ht_capa;
struct ieee80211_ht_cap ah_ht_capa_mask;
struct key_params *ah_wep_keys;
int ah_wep_tx_key;
};
```
在全域結構體 `vwifi_context` 中新增 `ibss_list` 以便尋找 ibss 裝置,當裝置 join 後便會被加入 `ibss_list`,若裝置 leave 則會被移出。
```diff
INIT_LIST_HEAD(&vwifi->vif_list);
INIT_LIST_HEAD(&vwifi->ap_list);
+INIT_LIST_HEAD(&vwifi->ibss_list);
```
```diff
/* Context for the whole program, so there's only single vwifi_context
* regardless of the number of virtual interfaces. Fields in the structure
* are interface-independent.
*/
struct vwifi_context {
/* We may not need this lock because vif_list would not change during
* the whole lifetime.
*/
struct mutex lock;
enum vwifi_state state; /**< indicate the program state */
struct list_head vif_list; /**< maintaining all interfaces */
struct list_head ap_list; /**< maintaining multiple AP */
+ struct list_head ibss_list;/**< maintaining all ibss devices */
char *denylist; /**< maintaining the denylist */
};
```
### 實作 AD-HOC 封包傳遞機制
在轉送前要確認 source 和 destination 是否處於相同 IBSS cell,以及確認是否在該 IBSS cell 的同個 BSS 中。
```c
/* TX by interface of IBSS(ad-hoc) mode */
else if (vif->wdev.iftype == NL80211_IFTYPE_ADHOC) {
/* Check if the packet is broadcasting */
if (is_broadcast_ether_addr(eth_hdr->h_dest)) {
list_for_each_entry (dest_vif, &vwifi->ibss_list, ibss_list) {
/* Don't send broadcast packet back to the source interface.
*/
if (ether_addr_equal(eth_hdr->h_source,
dest_vif->ndev->dev_addr))
continue;
/* Don't send packet from dest_vif's denylist */
if (denylist_check(dest_vif->ndev->name, vif->ndev->name))
continue;
/* Don't send packet to device with different SSID. */
if (strcmp(vif->ssid, dest_vif->ssid))
continue;
/* Don't send packet to device with different BSSID. */
if (!ether_addr_equal(vif->bssid, dest_vif->bssid))
continue;
if (__vwifi_ndo_start_xmit(vif, dest_vif, skb))
count++;
}
}
/* The packet is unicasting */
else {
list_for_each_entry (dest_vif, &vwifi->ibss_list, ibss_list) {
if (ether_addr_equal(eth_hdr->h_dest,
dest_vif->ndev->dev_addr)) {
/* Don't send packet from dest_vif's denylist */
if (denylist_check(dest_vif->ndev->name, vif->ndev->name))
continue;
/* Don't send packet to device with different SSID. */
if (strcmp(vif->ssid, dest_vif->ssid))
continue;
/* Don't send packet to device with different BSSID. */
if (!ether_addr_equal(vif->bssid, dest_vif->bssid))
continue;
if (__vwifi_ndo_start_xmit(vif, dest_vif, skb))
count++;
}
}
}
}
```
### Ping Test
#### 測試一 : 同 IBSS cell 中 ping 特定裝置
`vw3`, `vw4`, `vw5` 皆在同 IBSS cell 中,讓 `vw3` ping `vw4`,可發現封包正常傳遞。
```shell
$ sudo ip netns exec ns3 ip addr add 10.0.0.4/24 dev vw3
$ sudo ip netns exec ns4 ip addr add 10.0.0.5/24 dev vw4
$ sudo ip netns exec ns5 ip addr add 10.0.0.6/24 dev vw5
$ sudo ip netns exec ns3 ping -c 1 10.0.0.5
================================================================================
Ping Test: IBSS vw3 (10.0.0.4) (in ibss1) <--> IBSS vw4 (10.0.0.5) (in ibss1)
(should success)
(be patient, it will take some time to route...)
================================================================================
PING 10.0.0.5 (10.0.0.5) 56(84) bytes of data.
64 bytes from 10.0.0.5: icmp_seq=1 ttl=64 time=0.098 ms
--- 10.0.0.5 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.098/0.098/0.098/0.000 ms
```
觀察核心訊息可發現在 `vw3` 的 ARP cache 中原先無 `10.0.0.5` 對應的 mac address。
因此流程如下:
1. `vw3` 會先發送 **ARP Request** 封包 (broadcast) 請求 `10.0.0.5` 對應的 mac address。
2. `vw4` 會回傳 **ARP Reply** (內含 vw4 的 mac address),vw5 則無視之。
3. 當 `vw3` 收到 `vw4` 回傳的 ARP Reply 後,再進行 ICMP 封包傳遞 (**Ping Request**)。
4. `vw4` 收到 `vw3` 的 Ping Request 後,回傳 **Ping Reply**。
```sequence
vw3--vw4: ARP Request
vw3--vw5: ARP Request
vw4-vw3: ARP Reply
vw3-vw4: Ping Request
vw4-vw3: Ping Reply
```
```shell
[ 717.657196] broadcasting
[ 717.657204] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (ff:ff:ff:ff:ff:ff)
[ 717.657208] vwifi: IBSS vw4 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
[ 717.657212] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw5 (ff:ff:ff:ff:ff:ff)
[ 717.657214] vwifi: IBSS vw5 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
[ 717.657236] unicasting
[ 717.657237] vwifi: IBSS vw4 (00:76:77:34:00:00) send packet to IBSS vw3 (00:76:77:33:00:00)
[ 717.657238] vwifi: IBSS vw3 (00:76:77:33:00:00) receive packet from IBSS vw4 (00:76:77:34:00:00)
[ 717.657247] unicasting
[ 717.657248] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (00:76:77:34:00:00)
[ 717.657249] vwifi: IBSS vw4 (00:76:77:34:00:00) receive packet from IBSS vw3 (00:76:77:33:00:00)
[ 717.657263] unicasting
[ 717.657264] vwifi: IBSS vw4 (00:76:77:34:00:00) send packet to IBSS vw3 (00:76:77:33:00:00)
[ 717.657265] vwifi: IBSS vw3 (00:76:77:33:00:00) receive packet from IBSS vw4 (00:76:77:34:00:00)
```
#### 測試二 : ping 處於不同 IBSS cell 的裝置
`vw3` 和 `vw5` 處於不同 IBSS cell,讓 `vw3` ping `vw5`,如預期般失敗,原因在於兩者處於不同 IBSS,無法通訊。
```shell
$ sudo ip netns exec ns3 ip addr add 10.0.0.4/24 dev vw3
$ sudo ip netns exec ns4 ip addr add 10.0.0.5/24 dev vw4
$ sudo ip netns exec ns5 ip addr add 10.0.0.6/24 dev vw5
$ sudo ip netns exec ns3 ping -c 1 10.0.0.6
================================================================================
Ping Test: IBSS vw3 (10.0.0.4) (in ibss1) <--> IBSS vw5 (10.0.0.6) (in ibss2)
(should fail)
(be patient, it will take some time to route...)
================================================================================
PING 10.0.0.6 (10.0.0.6) 56(84) bytes of data.
From 10.0.0.4 icmp_seq=1 Destination Host Unreachable
--- 10.0.0.6 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
```
觀察核心訊息可發現, `vw3` 三度嘗試用 **ARP Request** 請求 mac address,但沒有裝置回應。
```shell
[ 3272.467235] broadcasting
[ 3272.467244] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (ff:ff:ff:ff:ff:ff)
[ 3272.467249] vwifi: IBSS vw4 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
[ 3273.492554] broadcasting
[ 3273.492598] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (ff:ff:ff:ff:ff:ff)
[ 3273.492613] vwifi: IBSS vw4 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
[ 3274.518330] broadcasting
[ 3274.518372] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (ff:ff:ff:ff:ff:ff)
[ 3274.518385] vwifi: IBSS vw4 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
```
#### 測試三 : ping 處於 STA mode 的裝置
`vw3` 為 IBSS mode, `vw2` 則為 STA mode,讓 `vw3` ping `vw2`,如預期般失敗。
```shell
$ sudo ip netns exec ns2 ip addr add 10.0.0.3/24 dev vw2
$ sudo ip netns exec ns3 ip addr add 10.0.0.4/24 dev vw3
$ sudo ip netns exec ns4 ip addr add 10.0.0.5/24 dev vw4
$ sudo ip netns exec ns3 ping -c 1 10.0.0.3
================================================================================
Ping Test: IBSS vw3 (10.0.0.4) (in ibss1) <--> STA vw2 (10.0.0.3)
(should fail)
(be patient, it will take some time to route...)
================================================================================
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
From 10.0.0.4 icmp_seq=1 Destination Host Unreachable
--- 10.0.0.3 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
```
如同測試二,`vw3` 三度嘗試用 **ARP Request** 請求 mac address,但沒有裝置回應。
```shell
[ 4208.333391] broadcasting
[ 4208.333399] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (ff:ff:ff:ff:ff:ff)
[ 4208.333403] vwifi: IBSS vw4 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
[ 4209.349666] broadcasting
[ 4209.349709] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (ff:ff:ff:ff:ff:ff)
[ 4209.349748] vwifi: IBSS vw4 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
[ 4210.375102] broadcasting
[ 4210.375162] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (ff:ff:ff:ff:ff:ff)
[ 4210.375190] vwifi: IBSS vw4 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
```
### 使 IBSS 支援掃描
```diff
/* inform with dummy BSS */
inform_bss(vif);
+ ah_inform_bss(vif);
```
執行 scan 可發現該 bss 資訊
```
BSS 00:76:77:30:00:00(on vw1)
TSF: 4320753904 usec (0d, 01:12:00)
freq: 2437
beacon interval: 100 TUs
capability: ESS Privacy (0x0011)
signal: -43.00 dBm
last seen: 0 ms ago
SSID: test
Supported rates: 1.0* 2.0* 5.5 11.0
DS Parameter set: channel 6
RSN: * Version: 1
* Group cipher: CCMP
* Pairwise ciphers: CCMP
* Authentication suites: PSK
* Capabilities: 1-PTKSA-RC 1-GTKSA-RC (0x0000)
Extended capabilities:
* SSID List
BSS 00:76:77:33:00:00(on vw1)
TSF: 4320753917 usec (0d, 01:12:00)
freq: 2412
beacon interval: 300 TUs
capability: IBSS (0x0002)
signal: -45.00 dBm
last seen: 0 ms ago
BSS 00:76:77:35:00:00(on vw1)
TSF: 4320753921 usec (0d, 01:12:00)
freq: 2412
beacon interval: 200 TUs
capability: IBSS (0x0002)
signal: -45.00 dBm
last seen: 0 ms ago
```
```shell
[ 4320.753585] vwifi: vw1 performs scan, found vw0 (SSID: test, BSSID: 00:76:77:30:00:00)
[ 4320.753594] cap = 17, beacon_ie_len = 43
[ 4320.753601] vwifi: vw1 performs scan, found vw3 (SSID: ibss1, BSSID: 00:76:77:33:00:00)
[ 4320.753604] cap = 2, beacon_ie_len = 0
[ 4320.753607] vwifi: vw1 performs scan, found vw4 (SSID: ibss1, BSSID: 00:76:77:33:00:00)
[ 4320.753609] cap = 2, beacon_ie_len = 0
[ 4320.753611] vwifi: vw1 performs scan, found vw5 (SSID: ibss2, BSSID: 00:76:77:35:00:00)
[ 4320.753612] cap = 2, beacon_ie_len = 0
```
### WPA support in IBSS mode
建立設定檔 `wpa_supplicant_ibss.conf`
```
network={
ssid="ibss1"
mode=1
frequency=2412
key_mgmt=WPA-PSK
proto=RSN
pairwise=CCMP
group=CCMP
psk="12345678"
}
```
#### 測試情境 1
使用命令 **wpa_supplicant** 設定 `vw3` 和 `vw4` 加入 `ibss1`
```shell
$ wpa_supplicant -i vw3 -B -c scripts/wpa_supplicant_ibss.conf
Successfully initialized wpa_supplicant
$ wpa_supplicant -i vw4 -B -c scripts/wpa_supplicant_ibss.conf
Successfully initialized wpa_supplicant
```
觀察 interface 資訊可發現兩者皆成功加入 `ibss1`
```
Interface vw3
ifindex 12
wdev 0x900000001
addr 00:76:77:33:00:00
ssid ibss1
type IBSS
wiphy 9
txpower 14.00 dBm
Interface vw4
ifindex 13
wdev 0xa00000001
addr 00:76:77:34:00:00
ssid ibss1
type IBSS
wiphy 10
txpower 15.00 dBm
```
仔細觀察核心訊息可發現一開始 `ibss1` 不存在,於是 `vw3` 創建之。而 `vw4` 透過掃描得知 `ibss1` 的存在,並加入之。
```
[ 205.578356] vwifi : vw3 start acting in IBSS mode.
[ 205.578720] vwifi : vw3 join ibss1.
[ 205.639498] vwifi: vw4 performs scan, found vw3 (SSID: ibss1, BSSID: 00:00:00:00:00:00)
[ 205.639506] cap = 18, beacon_ie_len = 35
[ 205.640141] vwifi : vw4 start acting in IBSS mode.
[ 205.640475] vwifi : vw4 join ibss1.
```
值得注意的一點是,使用 WPA 創建 ibss 網路,**其 BSSID 應由系統自動生成** (這樣可確保了每個 IBSS 網路的唯一性),因此並不會出現在 `join` 函式的輸入參數中。
因此當 `join` 參數的 BSSID 為 NULL 時,應比對當前存在的 ibss 網路。若有符合其 WPA 設定則沿用 BSSID ,否則以當前裝置的 MAC address 作為新網路的 BSSID。
```c
/* When the BSSID is automatically generated by the system, it will not be
* passed as a parameter to the join function. */
if (params->bssid)
memcpy(vif->bssid, params->bssid, ETH_ALEN);
else {
/* Search for IBSS networks with WPA settings in the IBSS list. If a
* matching network exists, join it. Otherwise, create one. */
memcpy(vif->bssid, ndev->dev_addr, ETH_ALEN);
struct vwifi_vif *ibss_vif = NULL;
list_for_each_entry (ibss_vif, &vwifi->ibss_list, ibss_list) {
if (ibss_vif->ssid_len == vif->ssid_len &&
!memcmp(ibss_vif->ssid, vif->ssid, vif->ssid_len) &&
ibss_vif->ibss_chandef.center_freq1 ==
vif->ibss_chandef.center_freq1) {
memcpy(vif->bssid, ibss_vif->bssid, ETH_ALEN);
break;
}
}
}
```
嘗試讓 `vw3` ping `vw4` ,封包傳遞成功。
```
$ sudo ip netns exec ns3 ping -c 1 10.0.0.5
================================================================================
Ping Test: IBSS vw3 (10.0.0.4) (in ibss1) <--> IBSS vw4 (10.0.0.5) (in ibss1)
(should success)
(be patient, it will take some time to route...)
================================================================================
PING 10.0.0.5 (10.0.0.5) 56(84) bytes of data.
64 bytes from 10.0.0.5: icmp_seq=1 ttl=64 time=1031 ms
--- 10.0.0.5 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1031.052/1031.052/1031.052/0.000 ms
```
```
[ 206.559641] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (ff:ff:ff:ff:ff:ff)
[ 206.559650] vwifi: IBSS vw4 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
[ 206.559699] vwifi: IBSS vw4 (00:76:77:34:00:00) send packet to IBSS vw3 (00:76:77:33:00:00)
[ 206.559701] vwifi: IBSS vw3 (00:76:77:33:00:00) receive packet from IBSS vw4 (00:76:77:34:00:00)
[ 206.559706] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (00:76:77:34:00:00)
[ 206.559708] vwifi: IBSS vw4 (00:76:77:34:00:00) receive packet from IBSS vw3 (00:76:77:33:00:00)
[ 206.559727] vwifi: IBSS vw4 (00:76:77:34:00:00) send packet to IBSS vw3 (00:76:77:33:00:00)
[ 206.559728] vwifi: IBSS vw3 (00:76:77:33:00:00) receive packet from IBSS vw4 (00:76:77:34:00:00)
```
#### 測試情境 2
`vw5` 以手動方式創建並加入 `ibss2` , `vw3` 和 `vw4` 則以 WPA 設定加入 `ibss1`。
```shell
$ sudo ip netns exec ns5 iw dev vw5 set type ibss
$ sudo ip netns exec ns5 iw dev vw5 ibss join ibss2 2412 NOHT fixed-freq 00:76:77:35:00:00 beacon-interval 300
$ sudo ip netns exec ns3 ip addr add 10.0.0.4/24 dev vw3
$ sudo ip netns exec ns4 ip addr add 10.0.0.5/24 dev vw4
$ sudo ip netns exec ns5 ip addr add 10.0.0.6/24 dev vw5
$ sudo ip netns exec ns3 wpa_supplicant -i vw3 -B -c scripts/wpa_supplicant_ibss.conf
$ sudo ip netns exec ns4 wpa_supplicant -i vw4 -B -c scripts/wpa_supplicant_ibss.conf
```
觀察核心訊息可發現,由於 `vw5` 先創建 `ibss2` ,所以 `vw3` 一開始設定時會掃描到 `ibss2` ,然而這並不符合 `vw3` 的 WPA 設定。於是 `vw3` 會自己創建一個 `ibss1` 。隨後 `vw4` 也會進行掃描,並同時發現 `ibss1` 和 `ibss2` ,選擇 `ibss1` 加入之。
```
[ 961.600176] vwifi : vw5 start acting in IBSS mode.
[ 961.613599] vwifi : vw5 join ibss2.
[ 962.020891] vwifi: vw3 performs scan, found vw5 (SSID: ibss2, BSSID: 00:76:77:35:00:00)
[ 962.020897] cap = 2, beacon_ie_len = 0
[ 962.021099] vwifi : vw3 start acting in IBSS mode.
[ 962.021256] vwifi : vw3 join ibss1.
[ 962.159989] vwifi: vw4 performs scan, found vw5 (SSID: ibss2, BSSID: 00:76:77:35:00:00)
[ 962.159998] cap = 2, beacon_ie_len = 0
[ 962.160004] vwifi: vw4 performs scan, found vw3 (SSID: ibss1, BSSID: 00:00:00:00:00:00)
[ 962.160006] cap = 18, beacon_ie_len = 35
[ 962.160645] vwifi : vw4 start acting in IBSS mode.
```
讓 `vw3` ping `vw5` ,很明顯無法傳遞封包。
```
$ sudo ip netns exec ns3 ping -c 1 10.0.0.6
================================================================================
Ping Test: IBSS vw3 (10.0.0.4) (in ibss1) <--> IBSS vw5 (10.0.0.6) (in ibss2)
(should fail)
(be patient, it will take some time to route...)
================================================================================
PING 10.0.0.6 (10.0.0.6) 56(84) bytes of data.
From 10.0.0.4 icmp_seq=1 Destination Host Unreachable
--- 10.0.0.6 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
```
```
[ 963.141034] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (ff:ff:ff:ff:ff:ff)
[ 963.141039] vwifi: IBSS vw4 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
[ 964.156816] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (ff:ff:ff:ff:ff:ff)
[ 964.156873] vwifi: IBSS vw4 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
[ 965.193847] vwifi: IBSS vw3 (00:76:77:33:00:00) send packet to IBSS vw4 (ff:ff:ff:ff:ff:ff)
[ 965.193908] vwifi: IBSS vw4 (ff:ff:ff:ff:ff:ff) receive packet from IBSS vw3 (00:76:77:33:00:00)
```
### Demo video
{%youtube 1IaLgEtjNUU %}
## Reference
[2022q1 vwifi](https://hackmd.io/@rickywu0421/FinalProject)
[Linux 核心專題: vwifi](https://hackmd.io/@sysprog/rJD2joOSh)
[Lightweight and Fast WiFi Access in Virtual Machines](https://osseu2023.sched.com/event/1OGgh)
[802.11 Wireless Networks: The Definitive Guide, 2/e](https://www.oreilly.com/library/view/80211-wireless-networks/0596100523/)
[LKMPG](https://sysprog21.github.io/lkmpg/)
[cfg80211_ops](https://elixir.bootlin.com/linux/latest/source/include/net/cfg80211.h#L4574)
[WI-FI 7 MCS TABLE](https://semfionetworks.com/blog/wi-fi-7-mcs-table/)
[MCS Table](https://mcsindex.net/)
[iw commands](https://wireless.wiki.kernel.org/en/users/documentation/iw)