# [VWIFI](https://github.com/sysprog21/vwifi) 2024
## [vwifi.c](https://github.com/sysprog21/vwifi/blob/main/vwifi.c)
:::info
[Introduce a userspace tool](https://github.com/sysprog21/vwifi/commit/7814d59e38cc4839c167a179742342ab4ef030bf) ([#53](https://github.com/sysprog21/vwifi/pull/53))
:::
### denylist_check
確認當前這組(dest, source)是否在 denylist 中
### denylist_load
將資料存入 denylist
### denylist_nl_recv
送 denylist 給 vwifi ,並回報結果給 process
* [sk_buff](https://elixir.bootlin.com/linux/latest/source/include/linux/skbuff.h#L855)
* [nlmsghdr](https://elixir.bootlin.com/linux/v5.15.75/source/include/uapi/linux/netlink.h#L44)
* [nlmsg_data](https://elixir.bootlin.com/linux/v6.9/source/include/net/netlink.h#L591)
* head of message payload
* [nlmsg_new](https://elixir.bootlin.com/linux/v6.9/source/include/net/netlink.h#L1008)
* Allocate a new netlink message (socket buffer)
* [nlmsg_put](https://elixir.bootlin.com/linux/v6.9/source/include/net/netlink.h#L950)
* Add a new netlink message to an skb
* [nlmsg_unicast](https://elixir.bootlin.com/linux/v6.9/source/include/net/netlink.h#L1140)
* unicast a netlink message
* [NLMSG_DONE](https://elixir.bootlin.com/linux/v6.9/source/include/uapi/linux/netlink.h#L114)
* End of a dump
* [NETLINK_CB](https://elixir.bootlin.com/linux/v6.9/source/include/linux/netlink.h#L35)
* 取得 [netlink_skb_parms](https://elixir.bootlin.com/linux/v6.9/source/include/linux/netlink.h#L25)
```c
static struct netlink_kernel_cfg nl_config = {
.input = denylist_nl_recv,
};
```
### [netlink_kernel_cfg](https://elixir.bootlin.com/linux/v6.9/source/include/linux/netlink.h#L46)
optional Netlink kernel configuration parameters
* .input : 指定 denylist_nl_recv 為 callback function,用於接收處理來自 userspace 之訊息
___
### ndev_get_vwifi_vif
取得 net_device 之 virtual interface
* [net_device](https://elixir.bootlin.com/linux/v6.9/source/include/linux/netdevice.h#L2031)
* The DEVICE structure.
* [netdev_priv](https://elixir.bootlin.com/linux/v6.9/source/include/linux/netdevice.h#L2588)
* access network device private data
### wdev_get_vwifi_vif
取得 wireless_dev 之 virtual interface
* [wireless_dev](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L6149)
* wireless device state
* [container_of](https://hackmd.io/@sysprog/linux-macro-containerof)
* Calculate address of object that contains address ptr
___
:::info
[Support virtio-net](https://github.com/sysprog21/vwifi/commit/038b13dcb486ff06c2ee0e9a61dc208c13727895) ([#45](https://github.com/sysprog21/vwifi/pull/45))
* virtio
* vwifi mangement frame
:::
### [vwifi_mac_to_32](https://github.com/sysprog21/vwifi/pull/45#discussion_r1311203160)
maps 48-bit MAC addresses into 32-bit integers
> rickywu0421 on Aug 31, 2023
We need a hash function that maps 48-bit MAC addresses into 32-bit integers, so that the integer can be treated as a key in hash_add() and hash_for_each_possible().
This hash function is from murmur hash and is once used in #PR11 as our hash function. I think there may be a better hash function but currently, this works fine.
___
### __sin_s3
A sine approximation via a third-order approx.
### rand_int_smooth
產生特定範圍的 sin 平滑函數
___
### inform_bss
告知 linux 核心子系統 cfg80211 有關新的 bss 的資訊
* [list_for_each_entry](https://elixir.bootlin.com/linux/v6.9/source/include/linux/list.h#L777)
* pos: the type * to use as a loop cursor.
* head: the head for your list.
* member: the name of the list_head within the struct.
* [cfg80211_bss](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L2949)
* BSS description
* [cfg80211_inform_bss](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L2877)
* the BSS metadata
* [NL80211_BAND_2GHZ](https://elixir.bootlin.com/linux/v6.9/source/include/uapi/linux/nl80211.h#L5434)
* 2.4 GHz ISM band
* [NL80211_BSS_CHAN_WIDTH_20](https://elixir.bootlin.com/linux/v6.9/source/include/uapi/linux/nl80211.h#L5085)
* control channel is 20 MHz wide or compatible
* [DBM_TO_MBM](https://elixir.bootlin.com/linux/v6.9/source/include/linux/ieee80211.h#L4612)
* 1 DBM = 100 MBM
* [WLAN_CAPABILITY_ESS](https://elixir.bootlin.com/linux/v6.9/source/include/linux/ieee80211.h#L3261)
* [WLAN_CAPABILITY_PRIVACY](https://elixir.bootlin.com/linux/v6.9/source/include/linux/ieee80211.h#L3274)
* [ktime_get_boottime_ns](https://elixir.bootlin.com/linux/v6.9/source/include/linux/timekeeping.h#L187)
* Get the monotonic time since boot in nanoseconds
* [cfg80211_inform_bss_data](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L7270)
* This informs cfg80211 that BSS information was found and the BSS should be updated/added.
* Return: A referenced struct, **must be released with cfg80211_put_bss()!** Or %NULL on error.
* [cfg80211_inform_single_bss_data](https://elixir.bootlin.com/linux/v6.9/source/net/wireless/scan.c#L2155)
* [cfg80211_parse_mbssid_data](https://elixir.bootlin.com/linux/v6.9/source/net/wireless/scan.c#L2368)
* [cfg80211_parse_ml_sta_data](https://elixir.bootlin.com/linux/v6.9/source/net/wireless/scan.c#L3023)
* [CFG80211_BSS_FTYPE_UNKNOWN](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L7215)
* frame type that the BSS data came from
* driver doesn't know whether the data is from a beacon or probe response
* [GFP_KERNEL](https://elixir.bootlin.com/linux/v6.9/source/include/linux/gfp_types.h#L363)
* context flag
* is typical for kernel-internal allocations.
* [cfg80211_put_bss](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L7363)
* unref BSS struct
* [jiffies](https://elixir.bootlin.com/linux/v6.9/source/include/linux/raid/pq.h#L164)
### vwifi_beacon_inform_bss
傳送 beacon frame 到 cfg80211 子系統,再轉送給 STA
* [CFG80211_BSS_FTYPE_BEACON](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L7216)
* frame type that the BSS data came from
* data comes from a beacon
### vwifi_beacon
設置 meta data 並傳送 beacon 給 STA
* [(virtual) interface types](https://elixir.bootlin.com/linux/v6.9/source/include/uapi/linux/nl80211.h#L3503)
* NL80211_IFTYPE_AP
* access point
* NL80211_IFTYPE_MESH_POINT
* mesh point
* NL80211_IFTYPE_ADHOC
* independent BSS member
* NL80211_IFTYPE_OCB
* Outside Context of a BSS
* This mode corresponds to the MIB variable dot11OCBActivated=true
* NL80211_IFTYPE_STATION
* managed BSS member
* [ktime_get_real](https://elixir.bootlin.com/linux/v6.9/source/include/linux/timekeeping.h#L80)
* get the real (wall-) time in ktime_t format
* [ktime_to_us](https://elixir.bootlin.com/linux/v6.9/source/include/linux/ktime.h#L157)
* [ns_to_ktime](https://elixir.bootlin.com/linux/v6.9/source/include/linux/ktime.h#L220)
* return ns
* [hrtimer_forward_now](https://elixir.bootlin.com/linux/v6.9/source/include/linux/hrtimer.h#L352)
* forward the timer expiry so it expires after now
* [Return values for the callback function](https://elixir.bootlin.com/linux/v6.9/source/include/linux/hrtimer_types.h#L13)
* HRTIMER_NORESTART
* Timer is not restarted
* HRTIMER_RESTART
* Timer must be restarted
___
### vwifi_ndo_open
啟動 network device
* [netif_start_queue](https://elixir.bootlin.com/linux/v6.9/source/include/linux/netdevice.h#L3312)
* allow device to transmit
* Allow upper layers to call the device hard_start_xmit routine.
### vwifi_ndo_stop
關閉 network device,並清空 rx_queue
* [netif_stop_queue](https://elixir.bootlin.com/linux/v6.9/source/include/linux/netdevice.h#L3364)
* stop transmitted packets
* Stop upper layers calling the device hard_start_xmit routine. Used for flow control when transmit resources are unavailable.
* [list_for_each_entry_safe](https://elixir.bootlin.com/linux/v6.9/source/include/linux/list.h#L864)
* [list_del](https://elixir.bootlin.com/linux/v6.9/source/include/linux/list.h#L227)
* [kfree](https://elixir.bootlin.com/linux/v6.9/source/tools/virtio/linux/kernel.h#L80)
### vwifi_ndo_get_stats
取得 network device 之 `stats`
* [net_device_stats](https://elixir.bootlin.com/linux/v6.9/source/include/linux/netdevice.h#L188)
### vwifi_rx
從 rx_queue 取得封包
* STA mode
* 單純利用 `skb` 傳送封包到上層 protocol
* AP mode
* multicast/broadcast
* 利用 `skb1` 傳給除了 source STA 的所有 STA,亦用 `skb` 傳給上層 protocol
* unicast
* 傳給 AP : 單純利用 `skb` 傳送封包到上層 protocol
* 利用 `skb1` 傳給其他 STA
### __vwifi_ndo_start_xmit
新增 `pkt` 到 `dest_vir` 的 `rx_queue` 中,並呼叫 `vwifi_rx(dest_vif->ndev)` 取得封包
### vwifi_ndo_start_xmit
利用 `__vwifi_ndo_start_xmit` 傳送封包
* STA mode
* 直接傳
* AP mode
* multicast/broadcast
* 不可傳給 source STA 和 deny STA
* unicast
* 不可傳給 deny STA
```c
static struct net_device_ops vwifi_ndev_ops = {
.ndo_open = vwifi_ndo_open,
.ndo_stop = vwifi_ndo_stop,
.ndo_start_xmit = vwifi_ndo_start_xmit,
.ndo_get_stats = vwifi_ndo_get_stats,
};
```
### [net_device_ops](https://elixir.bootlin.com/linux/v6.9/source/include/linux/netdevice.h#L1355)
___
### vwifi_scan_timeout_work
呼叫 `cfg80211_scan_done` 完成 scan
* [work_struct](https://elixir.bootlin.com/linux/v6.9/source/include/linux/workqueue_types.h#L16)
* [cfg80211_scan_done](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L7093)
* notify that scan finished
### vwifi_scan_timeout
### vwifi_scan_routine
僅設置 scan timer,等到 timeout 後就會呼叫 `vwifi_scan_timeout`
### vwifi_connect_routine
### vwifi_disconnect_routine
* STA : 呼叫 `cfg80211_disconnected`
* AP : 呼叫 `cfg80211_disconnected` 並清空 bss_list
### vwifi_scan
### vwifi_connect
### vwifi_disconnect
### vwifi_get_station
取得特定 STA 資訊
* [station_info](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L2111)
* filled:
* bitflag of flags using the bits of &enum nl80211_sta_info to indicate the relevant values in this struct for them
* rxrate
* [rate_info](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L1928)
* [rate_info_flags](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L1860)
* current unicast bitrate to this station
* txrate
* current unicast bitrate from this station
* [MCS Index Table, Modulation and Coding Scheme Index 11n, 11ac, and 11ax](https://mcsindex.com/)
* [WI-FI 7 MCS TABLE](https://semfionetworks.com/blog/wi-fi-7-mcs-table/)
* sme_state
* station 連線狀態
### vwifi_dump_station
### vwifi_interface_add
初始化 interface 為 STA mode
### vwifi_change_iface
將 STA mode 改為 AP mode
### vwifi_start_ap
將 net_device `ndev` 設為 AP,並設置 SSID
### vwifi_stop_ap
關閉 AP,刪除 `bss_list`
### vwifi_change_beacon
### vwifi_add_key
### vwifi_del_key
### vwifi_set_default_key
### vwifi_change_station
### vwifi_delete_interface
取消 virtual interface 註冊
```c
static struct cfg80211_ops vwifi_cfg_ops = {
.change_virtual_intf = vwifi_change_iface,
.scan = vwifi_scan,
.connect = vwifi_connect,
.disconnect = vwifi_disconnect,
.get_station = vwifi_get_station,
.dump_station = vwifi_dump_station,
.start_ap = vwifi_start_ap,
.stop_ap = vwifi_stop_ap,
.change_beacon = vwifi_change_beacon,
.add_key = vwifi_add_key,
.del_key = vwifi_del_key,
.set_default_key = vwifi_set_default_key,
.change_station = vwifi_change_station,
};
```
### [cfg80211_ops](https://elixir.bootlin.com/linux/v6.9/source/include/net/cfg80211.h#L4574)
___
### vwifi_free
Unregister 所有 virtual interface
### vwifi_cfg80211_add
對所有 virtual interface 註冊一個 wiphy
___
### vwifi_virtio_scan_complete
### vwifi_virtio_scan_request
### vwifi_virtio_connect_request
### vwifi_virtio_disconnect
### vwifi_virtio_disconnect_tx
### vwifi_virtio_sta_entry_request
### vwifi_virtio_sta_entry_response
### vwifi_virtio_mgmt_rx_sta_entry_response
### vwifi_virtio_mgmt_rx_sta_entry_request
### vwifi_virtio_mgmt_rx_disconnect
### vwifi_virtio_mgmt_rx_connect_response
### vwifi_virtio_mgmt_rx_connect_request
### vwifi_virtio_mgmt_rx_scan_response
### vwifi_virtio_mgmt_rx_scan_request
### vwifi_virtio_mgmt_rx
### vwifi_virtio_data_rx
### vwifi_virtio_rx_switch
### vwifi_virtio_rx_work
### vwifi_virtio_tx_done
* [virtqueue](https://elixir.bootlin.com/linux/v6.9/source/include/linux/virtio.h#L30)
* a queue to register buffers for sending or receiving.
### vwifi_virtio_rx_done
### vwifi_virtio_tx
### vwifi_virtio_init_vqs
### vwifi_virtio_fill_vq
### vwifi_virtio_remove_vqs
### vwifi_virtio_probe
### vwifi_virtio_remove
___
### vwifi_init
### vwifi_exit
___
## vwifi-tool.c
### vwifi_status_check
開啟 `/sys/module/vwifi/initstate` 查看 vwifi status
### opt_set
確認使用者是否有使用 -d -s -c 之選項
### denylist_pair_check
確認 source 和 destination interfaces 數量是否相同
### denylist_make
生成 denylist
### denylist_send
透過 netlink 傳送 denylist 給 vwifi 核心模組
### main
從 commandline 獲取訊息以生成 denylist
___
在編譯時會產生以下警告訊息:
```shell
vwifi-tool.c: In function ‘denylist_send’:
vwifi-tool.c:95:5: warning: ‘strncpy’ writing 1040 bytes into a region of size 1024 overflows the destination [-Wstringop-overflow=]
95 | strncpy(NLMSG_DATA(nlh), denylist, NLMSG_SPACE(MAX_PAYLOAD));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vwifi-tool.c:90:29: note: at offset 16 into destination object of size 1040 allocated by ‘calloc’
90 | (struct nlmsghdr *) calloc(1, NLMSG_SPACE(MAX_PAYLOAD));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
calloc 分配 NLMSG_SPACE(MAX_PAYLOAD)的空間給 nlh 使用,這包含了標頭的空間,實際可用來裝訊息的空間大小只有 MAX_PAYLOAD。
```diff
-strncpy(NLMSG_DATA(nlh), denylist, NLMSG_SPACE(MAX_PAYLOAD));
+strncpy(NLMSG_DATA(nlh), denylist, MAX_PAYLOAD);
```
:::success
***[commit 3626397](https://github.com/sysprog21/vwifi/commit/362639786d5611b855c47365e62bcaed615dc20a)***
Fix buffer overflow ([#63](https://github.com/sysprog21/vwifi/pull/65))
:::
___
```c
mod_timer(&vif->scan_timeout, jiffies + msecs_to_jiffies(SCAN_TIMEOUT_MS));
```
* mod_timer
* Timer 是一種 **Callback** 機制,提供使用者設定片段時間後觸發的方式
* Timer 有區分一次性或者週期性,Linux Kernel 提供的 mod_timer() 是屬於**一次性**
* Timer時間使用 `jiffies` 計算,
* jiffies 是全域變數,該變數用來紀錄時間的中斷次數(從開機後),可以搭配 `msecs_to_jiffies()` 計算出需要的時間間隔
```c
mutex_init(&vif->lock);
mutex_lock_interruptible(&vif->lock);
mutex_unlock(&vif->lock);
```
* mutex_lock_interruptible
* 互斥鎖,可睡眠**可中斷**
```c
spin_lock_irqsave(&vwifi_virtio_lock, flags);
spin_unlock_irqrestore(&vwifi_virtio_lock, flags);
```
* spin_lock_irqsave
* 保存 Local Processor 當前的 irq 狀態,然後在 Local Processor 上**禁止硬體中斷**產生,並獲取指定 Lock
```c
spin_lock_bh(&vif_list_lock);
spin_unlock_bh(&vif_list_lock);
```
* spin_lock_bh
* **禁止軟體中斷**產生,並獲取指定 Lock
___