diff --git a/README.md b/README.md
index e03a0e7..0d22192 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,14 @@ $ pip3 install numpy matplotlib
```
## Testing environment (non-virtio)
+To test the network environment effectively, we utilize **Linux network namespaces**. These namespaces isolate network environments from the host system, providing distinct instances of network stacks with independent routes, firewall rules, and network devices.
+
+Without network namespaces, virtual interfaces created within the same namespace use the loopback device for packet transmission between them, as the kernel recognizes them as residing on the same host.
+
+In our testing setup, all interfaces created by `vwifi` are placed within an isolated network namespace. This approach ensures that each virtual interface operates independently, facilitating comprehensive testing of networking functionalities without interference from the host's network configuration.
+
+Below, we will conduct two separate tests: Infrastructure BSS and Independent BSS.
+### Infrastructure BSS
The testing environment consists of **one AP and two STAs**.
@@ -48,15 +56,12 @@ The AP then performs the following actions based on the packet type:
2. Broadcast: The AP forwards the packet to all other STAs in the network, except for the source STA, and then passes it to the protocol stack.
3. Multicast: The AP treats multicast packets the same way as broadcast packets.
-To test the network environment, we can utilize the **Linux network namespace**.
-Linux network namespace allows us to isolate a network environment from the host system, providing its own routes, firewall rules, and network devices.
-Essentially, it creates a separate instance of the network stack.
+### Independent BSS
+
-Without network namespace, when virtual interfaces are created that share the same network namespace and start transmitting/receiving packets between them,
-the kernel will use the loopback device for packet transmission/reception. This behavior occurs because the kernel identifies that the sender and receiver are on the same host.
-
-In conclusion, all the interfaces created by `vwifi` in the testing environment will be added to an isolated network namespace.
+The testing environment consists of **two IBSS devices**.
+The testing environment operates in IEEE 802.11 independent BSS. IBSS devices can communicate with any device in the same IBSS network **without the need to establish a connection beforehand**. However, devices in different IBSS networks cannot communicate with each other.
## Build and Run (non-virtio)
To build the kernel module, execute the following command:
@@ -72,7 +77,7 @@ $ sudo modprobe cfg80211
Insert the `vwifi` driver.
This will create three interfaces (the "station" parameter can be modified according to preference):
```shell
-$ sudo insmod vwifi.ko station=3
+$ sudo insmod vwifi.ko station=5
```
Please note that interfaces can only be created in station mode during the initialization phase.
@@ -85,7 +90,7 @@ To check the network interfaces, run the following command:
$ ip link
```
-There should be entries starting with `vw0`, `vw1`, and `vw2`, which correspond to the interfaces created by `vwifi`.
+There should be entries starting with `vw0`, `vw1`, `vw2`, `vw3`, and `vw4`, which correspond to the interfaces created by `vwifi`.
To view the available wireless interfaces, execute the following command:
```shell
@@ -94,24 +99,41 @@ $ sudo iw dev
You should see something similar to the following output:
```
-phy#2
+phy#5
+ Interface vw4
+ ifindex 7
+ wdev 0x500000001
+ addr 00:76:77:34:00:00
+ type managed
+ txpower 0.00 dBm
+phy#4
+ Interface vw3
+ ifindex 6
+ wdev 0x400000001
+ addr 00:76:77:33:00:00
+ type managed
+ txpower 0.00 dBm
+phy#3
Interface vw2
ifindex 5
- wdev 0x200000001
- addr 00:6f:77:6c:32:00
+ wdev 0x300000001
+ addr 00:76:77:32:00:00
type managed
-phy#1
+ txpower 0.00 dBm
+phy#2
Interface vw1
ifindex 4
- wdev 0x100000001
- addr 00:6f:77:6c:31:00
+ wdev 0x200000001
+ addr 00:76:77:31:00:00
type managed
-phy#0
+ txpower 0.00 dBm
+phy#1
Interface vw0
ifindex 3
- wdev 0x1
- addr 00:6f:77:6c:30:00
+ wdev 0x100000001
+ addr 00:76:77:30:00:00
type managed
+ txpower 0.00 dBm
```
As observed, each interface has its own phy (`struct wiphy`), allowing them to be placed into separate network namespaces.
@@ -125,6 +147,10 @@ $ sudo iw list
Reference output:
```
+Wiphy vw_phy4
+(... omit)
+Wiphy vw_phy3
+(... omit)
Wiphy vw_phy2
(... omit)
Wiphy vw_phy1
@@ -366,6 +392,175 @@ PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
4 packets transmitted, 4 received, 0% packet loss, time 3058ms
rtt min/avg/max/mdev = 0.054/0.141/0.342/0.117 ms
```
+### IBSS mode
+
+#### Creating Network Namespaces
+Create three network namespaces using the following commands:
+```shell
+$ sudo ip netns add ns3
+$ sudo ip netns add ns4
+```
+Find the `wiphy` name for the two interfaces.
+The index number for the `wiphy` name postfix might be different each time.
+Please use the following command for the ease of memorizing different index number everytime.
+```shell
+$ vw3_phy=$(sudo iw dev vw3 info | grep wiphy | awk '{print $2}')
+$ vw3_phy=$(sudo iw list | grep "wiphy index: $vw3_phy" -B 1 | grep Wiphy | awk '{print $2}')
+$ vw4_phy=$(sudo iw dev vw4 info | grep wiphy | awk '{print $2}')
+$ vw4_phy=$(sudo iw list | grep "wiphy index: $vw4_phy" -B 1 | grep Wiphy | awk '{print $2}')
+```
+Check whether the name of each `wiphy` is the same as the name listing under the command `sudo iw list`
+```shell
+$ echo $vw3_phy
+vw_phy3
+$ echo $vw4_phy
+vw_phy4
+```
+Assign the two interfaces to separate network namespaces.
+Please note that the `wiphy` is placed within the network namespace, and the interface associated with that wiphy will be contained within it.
+```shell
+$ sudo iw phy vw_phy3 set netns name ns3
+$ sudo iw phy vw_phy4 set netns name ns4
+```
+#### Assigning IP Addresses to Each Interface
+
+Now, assign an IP address to both interfaces using the following commands:
+```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
+```
+There are two methods to configure an IBSS network: manual configuration or using WPA.
+#### Option1 : Manual configuration
+##### Switch to IBSS mode
+Switch device to IBSS mode using the following command :
+
+***iw dev [interface] set type ibss***
+
+The following commands switch `vw3` and `vw4` to IBSS mode.
+```shell
+$ sudo ip netns exec ns3 iw dev vw3 set type ibss
+$ sudo ip netns exec ns4 iw dev vw4 set type ibss
+```
+Check the information of `vw3`.
+```shell
+$ sudo ip netns exec ns3 iw dev vw3 info
+```
+You should see output similar to the following:
+```
+Interface vw3
+ ifindex 6
+ wdev 0x400000001
+ addr 00:76:77:33:00:00
+ type IBSS
+ wiphy 4
+ txpower 0.00 dBm
+```
+##### Join IBSS network
+```shell
+$ sudo ip netns exec ns3 ip link set vw3 up
+$ sudo ip netns exec ns4 ip link set vw4 up
+```
+Users can join a specific IBSS cell and configure additional settings using the command :
+
+***iw dev [interface] ibss join [SSID] [freq in MHz] [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [fixed-freq] [fixed-bssid] [beacon-interval ] [basic-rates ] [mcast-rate ] [key d:0:abcde]***
+
+If the IBSS cell does not already exist, it will be created.
+
+The following command makes `vw3` and `vw4` join the same IBSS cell with the SSID `ibss1` and specifies the frequency as 2412 MHz:
+```shell
+$ sudo ip netns exec ns3 iw dev vw3 ibss join ibss1 2412 NOHT fixed-freq 00:76:77:33:00:00 beacon-interval 200
+$ sudo ip netns exec ns4 iw dev vw4 ibss join ibss1 2412 NOHT fixed-freq 00:76:77:33:00:00 beacon-interval 200
+```
+Check the information of `vw3`.
+```shell
+$ sudo ip netns exec ns3 iw dev vw3 info
+```
+You should see output similar to the following:
+```
+Interface vw3
+ ifindex 6
+ wdev 0x400000001
+ addr 00:76:77:33:00:00
+ ssid ibss1
+ type IBSS
+ wiphy 4
+ txpower 0.00 dBm
+```
+#### Option2 : Using WPA
+```shell
+$ sudo ip netns exec ns3 ip link set vw3 up
+$ sudo ip netns exec ns4 ip link set vw4 up
+```
+Prepare the following script `wpa_supplicant_ibss.conf` (you can modify the script based on your needs):
+```shell
+network={
+ ssid="ibss1"
+ mode=1
+ frequency=2412
+ key_mgmt=WPA-PSK
+ proto=RSN
+ pairwise=CCMP
+ group=CCMP
+ psk="12345678"
+}
+```
+Using the command **wpa_supplicant**, configure `vw3` and `vw4` to join `ibss1`.
+```shell
+$ 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
+```
+Check the information of `vw3`.
+```shell
+$ sudo ip netns exec ns3 iw dev vw3 info
+```
+You should see output similar to the following:
+```
+Interface vw3
+ ifindex 6
+ wdev 0x400000001
+ addr 00:76:77:33:00:00
+ ssid ibss1
+ type IBSS
+ wiphy 4
+ txpower 0.00 dBm
+```
+#### Transmission/Receivement test
+To perform a ping test between two IBSS devices (`vw3` and `vw4`) in the same ibss cell (`ibss1`), use the following command:
+```shell
+$ sudo ip netns exec ns3 ping -c 1 10.0.0.5
+```
+You should see output similar to the following:
+```
+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.093 ms
+
+--- 10.0.0.5 ping statistics ---
+1 packets transmitted, 1 received, 0% packet loss, time 0ms
+rtt min/avg/max/mdev = 0.093/0.093/0.093/0.000 ms
+```
+#### Leave IBSS network
+To leave the current IBSS cell, use ***iw dev [interface] ibss leave***.
+
+The following command makes `vw3` and `vw4` leave `ibss1`:
+```shell
+$ sudo ip netns exec ns3 iw dev vw3 ibss leave
+$ sudo ip netns exec ns4 iw dev vw4 ibss leave
+```
+Check the information of `vw3`.
+```shell
+$ sudo ip netns exec ns3 iw dev vw3 info
+```
+You should see output similar to the following:
+```
+Interface vw3
+ ifindex 6
+ wdev 0x400000001
+ addr 00:76:77:33:00:00
+ type IBSS
+ wiphy 4
+ txpower 0.00 dBm
+```
+
### vwifi-tool
A userspace tool which supports more user-specific utilization for vwifi.
Aiming to provide more flexibility and customization for users of vwifi.
diff --git a/assets/ibss.drawio b/assets/ibss.drawio
new file mode 100644
index 0000000..f82d8aa
--- /dev/null
+++ b/assets/ibss.drawio
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/ibss.png b/assets/ibss.png
new file mode 100644
index 0000000..3e17e0b
Binary files /dev/null and b/assets/ibss.png differ
diff --git a/scripts/verify.sh b/scripts/verify.sh
index 6113f07..baaa815 100755
--- a/scripts/verify.sh
+++ b/scripts/verify.sh
@@ -10,7 +10,7 @@ if [ $? -ne 0 ]; then
final_ret=1
fi
-insert_kmod vwifi.ko station=3
+insert_kmod vwifi.ko station=6
if [ $? -ne 0 ]; then
final_ret=2
fi
@@ -28,22 +28,34 @@ if [ $final_ret -eq 0 ]; then
sudo iw dev vw0 set txpower auto
sudo iw dev vw1 set txpower fixed 1200
sudo iw dev vw2 set txpower fixed 1300
+ sudo iw dev vw3 set txpower auto
+ sudo iw dev vw4 set txpower auto
+ sudo iw dev vw5 set txpower auto
# get phy number of each interface
sudo iw dev > device.log
vw0_phy=$(get_wiphy_name vw0)
vw1_phy=$(get_wiphy_name vw1)
vw2_phy=$(get_wiphy_name vw2)
+ vw3_phy=$(get_wiphy_name vw3)
+ vw4_phy=$(get_wiphy_name vw4)
+ vw5_phy=$(get_wiphy_name vw5)
# create network namespaces for each phy (interface)
sudo ip netns add ns0
sudo ip netns add ns1
sudo ip netns add ns2
+ sudo ip netns add ns3
+ sudo ip netns add ns4
+ sudo ip netns add ns5
# add each phy (interface) to separate network namesapces
sudo iw phy $vw0_phy set netns name ns0
sudo iw phy $vw1_phy set netns name ns1
sudo iw phy $vw2_phy set netns name ns2
+ sudo iw phy $vw3_phy set netns name ns3
+ sudo iw phy $vw4_phy set netns name ns4
+ sudo iw phy $vw5_phy set netns name ns5
# running hostapd on vw0, so vw0 becomes AP
sudo ip netns exec ns0 ip link set vw0 up
@@ -56,10 +68,22 @@ if [ $final_ret -eq 0 ]; then
sudo ip netns exec ns2 ip link set vw2 up
sudo ip netns exec ns2 ip link set lo up
+ sudo ip netns exec ns3 ip link set vw3 up
+ sudo ip netns exec ns3 ip link set lo up
+
+ sudo ip netns exec ns4 ip link set vw4 up
+ sudo ip netns exec ns4 ip link set lo up
+
+ sudo ip netns exec ns5 ip link set vw5 up
+ sudo ip netns exec ns5 ip link set lo up
+
# assing IP address to each interface
sudo ip netns exec ns0 ip addr add 10.0.0.1/24 dev vw0
sudo ip netns exec ns1 ip addr add 10.0.0.2/24 dev vw1
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 ns5 ip addr add 10.0.0.6/24 dev vw5
# ping test: STA vw1 <--> STA vw2, should fail, because they
# haven't connected to AP
@@ -136,6 +160,64 @@ if [ $final_ret -eq 0 ]; then
final_ret=7
fi
+ # vw3 becomes an IBSS and then joins the "ibss1" network.
+ echo
+ echo "=============="
+ echo "vw3 join ibss1"
+ echo "=============="
+ sudo ip netns exec ns3 wpa_supplicant -i vw3 -B -c scripts/wpa_supplicant_ibss.conf
+
+ # vw4 becomes an IBSS and then joins the "ibss1" network.
+ echo
+ echo "=============="
+ echo "vw4 join ibss1"
+ echo "=============="
+ sudo ip netns exec ns4 wpa_supplicant -i vw4 -B -c scripts/wpa_supplicant_ibss.conf
+
+ # vw5 becomes an IBSS and then joins the "ibss2" network (BSSID: 00:76:77:35:00:00).
+ echo
+ echo "=================================="
+ echo "vw5 join ibss2 (00:76:77:35:00:00)"
+ echo "=================================="
+ 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
+
+ # ping test: IBSS vw3 <--> STA vw2, should fail
+ echo
+ echo "================================================================================"
+ echo "Ping Test: IBSS vw3 (10.0.0.4) (in ibss1) <--> STA vw2 (10.0.0.3)"
+ echo
+ echo "(should fail)"
+ echo "(be patient, it will take some time to route...)"
+ echo "================================================================================"
+ sudo ip netns exec ns3 ping -c 1 10.0.0.3
+
+ # ping test: IBSS vw3 <--> IBSS vw5, should fail
+ echo
+ echo "================================================================================"
+ echo "Ping Test: IBSS vw3 (10.0.0.4) (in ibss1) <--> IBSS vw5 (10.0.0.6) (in ibss2)"
+ echo
+ echo "(should fail)"
+ echo "(be patient, it will take some time to route...)"
+ echo "================================================================================"
+ sudo ip netns exec ns3 ping -c 1 10.0.0.6
+
+ # ping test: IBSS vw3 <--> IBSS vw4, should success
+ echo
+ echo "================================================================================"
+ echo "Ping Test: IBSS vw3 (10.0.0.4) (in ibss1) <--> IBSS vw4 (10.0.0.5) (in ibss1)"
+ echo
+ echo "(should success)"
+ echo "(be patient, it will take some time to route...)"
+ echo "================================================================================"
+ sudo ip netns exec ns3 ping -c 1 10.0.0.5
+
+ # sudo ip netns exec ns3 ping -c 1 10.0.0.5
+ ping_rc=$?
+ if [ $ping_rc -ne 0 ]; then
+ final_ret=8
+ fi
+
# verify TSF (in usec)
sudo ip netns exec ns1 iw dev vw1 scan > scan_result.log
tsf=$(cat scan_result.log | grep "TSF" | tail -n 1 | awk '{print $2}')
@@ -145,7 +227,7 @@ if [ $final_ret -eq 0 ]; then
# difference between tsf and uptime should less than 0.5 sec.
if [ "${diff#-}" -gt 500000 ]; then
- final_ret=8
+ final_ret=9
fi
# plot the distribution of RSSI of vw0
@@ -162,7 +244,7 @@ if [ $final_ret -eq 0 ]; then
python3 $ROOT/scripts/plot_rssi.py
plot_rc=$?
if [ $plot_rc -ne 0 ]; then
- final_ret=9
+ final_ret=10
fi
# TestAP performs station dump
@@ -172,7 +254,7 @@ if [ $final_ret -eq 0 ]; then
sudo ip netns exec "ns${num}" iw dev | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}' > station_ssid.log
DIFF=$(diff dump_ssid.log station_ssid.log)
if [ "$DIFF" != "" ]; then
- final_ret=10
+ final_ret=11
break
fi
done
@@ -184,6 +266,9 @@ if [ $final_ret -eq 0 ]; then
sudo ip netns del ns0
sudo ip netns del ns1
sudo ip netns del ns2
+ sudo ip netns del ns3
+ sudo ip netns del ns4
+ sudo ip netns del ns5
rm scan_result.log scan_bssid.log connected.log device.log rssi.txt station_dump_result.log dump_ssid.log station_ssid.log
echo "==== Test PASSED ===="
exit 0
diff --git a/scripts/wpa_supplicant_ibss.conf b/scripts/wpa_supplicant_ibss.conf
new file mode 100644
index 0000000..e2fe299
--- /dev/null
+++ b/scripts/wpa_supplicant_ibss.conf
@@ -0,0 +1,10 @@
+network={
+ ssid="ibss1"
+ mode=1
+ frequency=2412
+ key_mgmt=WPA-PSK
+ proto=RSN
+ pairwise=CCMP
+ group=CCMP
+ psk="12345678"
+}
\ No newline at end of file
diff --git a/vwifi.c b/vwifi.c
index 2e09827..318cdee 100644
--- a/vwifi.c
+++ b/vwifi.c
@@ -63,10 +63,11 @@ struct vwifi_context {
* 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 */
- char *denylist; /**< maintaining the denylist */
+ 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 */
};
static DEFINE_SPINLOCK(vif_list_lock);
@@ -81,7 +82,7 @@ static atomic_t vwifi_wiphy_counter = ATOMIC_INIT(0);
/* Virtual interface pointed to by netdev_priv(). Fields in the structure are
* interface-dependent. Every interface has its own vwifi_vif, regardless of the
- * interface mode (STA, AP, Ad-hoc...).
+ * interface mode (STA, AP, IBSS...).
*/
struct vwifi_vif {
struct wireless_dev wdev;
@@ -103,7 +104,7 @@ struct vwifi_vif {
struct mutex lock;
- /* Split logic for STA and AP mode */
+ /* Split logic for the interface mode */
union {
/* Structure for STA mode */
struct {
@@ -138,6 +139,47 @@ struct vwifi_vif {
struct ieee80211_channel *channel;
enum nl80211_chan_width bw;
};
+ /* Structure for IBSS(ad hoc) mode */
+ struct {
+ /* List node for storing ibss devices (vwifi->ibss_list is the
+ * head), this field is for interface in IBSS mode.
+ */
+ struct list_head ibss_list;
+ /* defines the channel to use if no other IBSS to join can be found
+ */
+ struct cfg80211_chan_def ibss_chandef;
+ u16 ibss_beacon_int;
+ /* bitmap of basic rates */
+ u32 ibss_basic_rates;
+ /* The channel should be fixed -- do not search for IBSSs to join on
+ * other channels. */
+ bool ibss_channel_fixed;
+ /* This is a protected network, keys will be configured after
+ * joining */
+ bool ibss_privacy;
+ /* whether user space controls IEEE 802.1X port, i.e.,
+ * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
+ * required to assume that the port is unauthorized until authorized
+ * by user space. Otherwise, port is marked authorized by default.
+ */
+ bool ibss_control_port;
+ /* TRUE if userspace expects to exchange control
+ * port frames over NL80211 instead of the network interface.
+ */
+ bool ibss_control_port_over_nl80211;
+ /* whether user space controls DFS operation */
+ bool ibss_userspace_handles_dfs;
+ /* per-band multicast rate index + 1 (0: disabled) */
+ int ibss_mcast_rate[NUM_NL80211_BANDS];
+ /* HT Capabilities over-rides. */
+ struct ieee80211_ht_cap ibss_ht_capa;
+ /* The bits of ht_capa which are to be used. */
+ struct ieee80211_ht_cap ibss_ht_capa_mask;
+ /* static WEP keys */
+ struct key_params *ibss_wep_keys;
+ /* key index (0..3) of the default TX static WEP key */
+ int ibss_wep_tx_key;
+ };
};
struct timer_list scan_complete;
@@ -506,6 +548,54 @@ static void inform_bss(struct vwifi_vif *vif)
}
}
+/* Helper function that prepares a structure with self-defined BSS information
+ * and "informs" the kernel about the "new" Independent BSS.
+ */
+static void ibss_inform_bss(struct vwifi_vif *vif)
+{
+ struct vwifi_vif *ibss;
+
+ list_for_each_entry (ibss, &vwifi->ibss_list, ibss_list) {
+ struct cfg80211_bss *bss = NULL;
+ struct cfg80211_inform_bss data = {
+ /* the only channel */
+ .chan = &ibss->wdev.wiphy->bands[NL80211_BAND_2GHZ]->channels[0],
+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)
+ .scan_width = NL80211_BSS_CHAN_WIDTH_20,
+#endif
+ .signal = DBM_TO_MBM(rand_int_smooth(-100, -30, jiffies)),
+ };
+ int capability = WLAN_CAPABILITY_IBSS;
+
+ if (ibss->ibss_privacy)
+ capability |= WLAN_CAPABILITY_PRIVACY;
+
+ pr_info("vwifi: %s performs scan, found %s (SSID: %s, BSSID: %pM)\n",
+ vif->ndev->name, ibss->ndev->name, ibss->ssid, ibss->bssid);
+ pr_info("cap = %d, beacon_ie_len = %d\n", capability,
+ ibss->beacon_ie_len);
+
+ /* Using the CLOCK_BOOTTIME clock, which remains unaffected by changes
+ * in the system time-of-day clock and includes any time that the
+ * system is suspended.
+ * This clock is suitable for synchronizing the machines in the BSS
+ * using tsf.
+ */
+ u64 tsf = div_u64(ktime_get_boottime_ns(), 1000);
+
+ /* It is possible to use cfg80211_inform_bss() instead. */
+ bss = cfg80211_inform_bss_data(
+ vif->wdev.wiphy, &data, CFG80211_BSS_FTYPE_UNKNOWN, ibss->bssid,
+ tsf, capability, ibss->ibss_beacon_int, ibss->beacon_ie,
+ ibss->beacon_ie_len, GFP_KERNEL);
+
+ /* cfg80211_inform_bss_data() returns cfg80211_bss structure reference
+ * counter of which should be decremented if it is unused.
+ */
+ cfg80211_put_bss(vif->wdev.wiphy, bss);
+ }
+}
+
static void vwifi_beacon_inform_bss(struct vwifi_vif *ap,
struct vwifi_vif *sta,
struct cfg80211_inform_bss *bss_meta,
@@ -734,6 +824,10 @@ static int __vwifi_ndo_start_xmit(struct vwifi_vif *vif,
pr_info("vwifi: AP %s (%pM) send packet to STA %s (%pM)\n",
vif->ndev->name, eth_hdr->h_source, dest_vif->ndev->name,
eth_hdr->h_dest);
+ } else if (vif->wdev.iftype == NL80211_IFTYPE_ADHOC) {
+ pr_info("vwifi: IBSS %s (%pM) send packet to IBSS %s (%pM)\n",
+ vif->ndev->name, eth_hdr->h_source, dest_vif->ndev->name,
+ eth_hdr->h_dest);
}
pkt = kmalloc(sizeof(struct vwifi_packet), GFP_KERNEL);
@@ -771,6 +865,10 @@ static int __vwifi_ndo_start_xmit(struct vwifi_vif *vif,
pr_info("vwifi: AP %s (%pM) receive packet from STA %s (%pM)\n",
dest_vif->ndev->name, eth_hdr->h_dest, vif->ndev->name,
eth_hdr->h_source);
+ } else if (dest_vif->wdev.iftype == NL80211_IFTYPE_ADHOC) {
+ pr_info("vwifi: IBSS %s (%pM) receive packet from IBSS %s (%pM)\n",
+ dest_vif->ndev->name, eth_hdr->h_dest, vif->ndev->name,
+ eth_hdr->h_source);
}
/* Directly send to rx_queue, simulate the rx interrupt */
@@ -859,6 +957,49 @@ static netdev_tx_t vwifi_ndo_start_xmit(struct sk_buff *skb,
}
}
}
+ /* 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++;
+ }
+ }
+ }
+ }
if (!count)
vif->stats.tx_dropped++;
@@ -895,6 +1036,7 @@ static void vwifi_scan_timeout_work(struct work_struct *w)
/* inform with dummy BSS */
inform_bss(vif);
+ ibss_inform_bss(vif);
if (mutex_lock_interruptible(&vif->lock))
return;
@@ -1440,6 +1582,10 @@ static int vwifi_change_iface(struct wiphy *wiphy,
case NL80211_IFTYPE_AP:
ndev->ieee80211_ptr->iftype = type;
break;
+ case NL80211_IFTYPE_ADHOC:
+ pr_info("vwifi: %s start acting in IBSS mode.\n", ndev->name);
+ ndev->ieee80211_ptr->iftype = type;
+ break;
default:
pr_info("vwifi: invalid interface type %u\n", type);
return -EINVAL;
@@ -1915,6 +2061,91 @@ static int vwifi_get_tx_power(struct wiphy *wiphy,
return 0;
}
+/* Make the device join a specific IBSS. */
+static int vwifi_join_ibss(struct wiphy *wiphy,
+ struct net_device *ndev,
+ struct cfg80211_ibss_params *params)
+{
+ struct vwifi_vif *vif = ndev_get_vwifi_vif(ndev);
+ /* Validate vif pointer */
+ if (!vif)
+ return -EINVAL;
+ if (mutex_lock_interruptible(&vif->lock))
+ return -ERESTARTSYS;
+ /* Retrieve IBSS configuration parameters */
+ memcpy(vif->ssid, params->ssid, params->ssid_len);
+ vif->ibss_chandef = params->chandef;
+ vif->ssid_len = params->ssid_len;
+ /* 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;
+ }
+ }
+ }
+ vif->beacon_ie_len = params->ie_len;
+ memcpy(vif->beacon_ie, params->ie, params->ie_len);
+ vif->ibss_beacon_int = params->beacon_interval;
+ vif->ibss_basic_rates = params->basic_rates;
+ vif->ibss_channel_fixed = params->channel_fixed;
+ vif->ibss_privacy = params->privacy;
+ vif->ibss_control_port = params->control_port;
+ vif->ibss_control_port_over_nl80211 = params->control_port_over_nl80211;
+ vif->ibss_userspace_handles_dfs = params->userspace_handles_dfs;
+ memcpy(vif->ibss_mcast_rate, params->mcast_rate,
+ sizeof(params->mcast_rate));
+ vif->ibss_ht_capa = params->ht_capa;
+ vif->ibss_ht_capa_mask = params->ht_capa_mask;
+ vif->ibss_wep_keys = params->wep_keys;
+ vif->ibss_wep_tx_key = params->wep_tx_key;
+
+ mutex_unlock(&vif->lock);
+
+ /* Insert ibss into global ibss_list */
+ if (mutex_lock_interruptible(&vwifi->lock))
+ return -ERESTARTSYS;
+
+ list_add_tail(&vif->ibss_list, &vwifi->ibss_list);
+
+ mutex_unlock(&vwifi->lock);
+
+ pr_info("vwifi : %s join %s.\n", vif->ndev->name, vif->ssid);
+
+ return 0;
+}
+
+/* Make the device leave the current IBSS. */
+static int vwifi_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
+{
+ struct vwifi_vif *vif = ndev_get_vwifi_vif(ndev);
+ /* Validate vif pointer */
+ if (!vif)
+ return -EINVAL;
+ /* Remove ibss from global ibss_list */
+ if (mutex_lock_interruptible(&vwifi->lock))
+ return -ERESTARTSYS;
+
+ list_del(&vif->ibss_list);
+
+ mutex_unlock(&vwifi->lock);
+
+ pr_info("vwifi : %s leave %s.\n", vif->ndev->name, vif->ssid);
+
+ return 0;
+}
+
/* Structure of functions for FullMAC 80211 drivers. Functions implemented
* along with fields/flags in the wiphy structure represent driver features.
* This module can only perform "scan" and "connect". Some functions cannot
@@ -1937,6 +2168,8 @@ static struct cfg80211_ops vwifi_cfg_ops = {
.change_station = vwifi_change_station,
.set_tx_power = vwifi_set_tx_power,
.get_tx_power = vwifi_get_tx_power,
+ .join_ibss = vwifi_join_ibss,
+ .leave_ibss = vwifi_leave_ibss,
};
/* Macro for defining 2GHZ channel array */
@@ -2075,8 +2308,8 @@ static struct wiphy *vwifi_cfg80211_add(void)
* add other required types like "BIT(NL80211_IFTYPE_STATION) |
* BIT(NL80211_IFTYPE_AP)" etc.
*/
- wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_ADHOC);
for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
/* FIXME: add other band capabilities if needed, such as 40 width */
@@ -3096,6 +3329,7 @@ static int __init vwifi_init(void)
mutex_init(&vwifi->lock);
INIT_LIST_HEAD(&vwifi->vif_list);
INIT_LIST_HEAD(&vwifi->ap_list);
+ INIT_LIST_HEAD(&vwifi->ibss_list);
vwifi->denylist = kmalloc(sizeof(char) * MAX_DENYLIST_SIZE, GFP_KERNEL);
for (int i = 0; i < station; i++) {