參考 [ath6kl_set_ies](https://elixir.bootlin.com/linux/latest/source/drivers/net/wireless/ath/ath6kl/cfg80211.c#L2678) 的實作,他會先把 `struct cfg80211_beacon_data *info` 的 `beacon_ies` 和 `beacon_ies_len` 直接拿來用 繼續看到 ``` /* this also clears IE in fw if it's not set */ res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_BEACON, info->beacon_ies, info->beacon_ies_len); ``` 可以發現裡面負責複製 ie 的程式為 ``` struct wmi_set_appie_cmd *p; ... if (ie != NULL && ie_len > 0) memcpy(p->ie_info, ie, ie_len); ``` 然後 `wmi_set_appie_cmd` 這個結構體為 ``` struct wmi_set_appie_cmd { u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */ u8 ie_len; u8 ie_info[]; } __packed; ``` 所以我這邊在 vwifi 的實作用 ``` /** * struct vif_saved_ie - holds saved IEs for a virtual interface. */ struct vif_saved_ie { u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */ u8 ie_len; u8 ie_info[]; } __packed; ``` `mgmt_frm_type` 定義為 ``` enum owl_mgmt_frame_type { OWL_FRAME_BEACON = 0, OWL_FRAME_PROBE_REQ, OWL_FRAME_PROBE_RESP, OWL_FRAME_ASSOC_REQ, OWL_FRAME_ASSOC_RESP, OWL_NUM_MGMT_FRAME }; ``` 接下來是要把 `vif_saved_ie` 放進 `owl_vif` 裡 ```diff struct owl_vif { struct wireless_dev wdev; struct net_device *ndev; struct net_device_stats stats; size_t ssid_len; /* Currently connected BSS id */ u8 bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; struct list_head rx_queue; /**< Head of received packet queue */ /* Store all owl_vif which is in the same BSS (AP will be the head). */ struct list_head bss_list; /* List entry for maintaining all owl_vif, which can be accessed via * owl->vif_list. */ struct list_head list; struct mutex lock; /* Split logic for STA and AP mode */ union { /* Structure for STA mode */ struct { /* For the case the STA is going to roam to another BSS */ u8 req_ssid[IEEE80211_MAX_SSID_LEN]; struct cfg80211_scan_request *scan_request; enum sme_state sme_state; /* connection information */ /* last connection time to a AP (in jiffies) */ unsigned long conn_time; unsigned long active_time; /**< last tx/rx time (in jiffies) */ u16 disconnect_reason_code; struct timer_list scan_timeout; struct work_struct ws_connect, ws_disconnect; struct work_struct ws_scan, ws_scan_timeout; /* For quickly finding the AP */ struct owl_vif *ap; }; /* Structure for AP mode */ struct { bool ap_enabled; /* List node for storing AP (owl->ap_list is the head), * this field is for interface in AP mode. */ struct list_head ap_list; + struct vif_saved_ie saved_beacon_ie; }; }; }; ``` 接下來是初始化 `saved_beacon_ie` 的部分,在 `owl_start_ap` ```diff static int owl_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *settings) { struct owl_vif *vif = ndev_get_owl_vif(ndev); pr_info("owl: %s start acting in AP mode.\n", ndev->name); pr_info("ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,", settings->chandef.chan->hw_value, settings->chandef.center_freq1, settings->chandef.width, settings->beacon_interval, settings->dtim_period); pr_info("ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d", settings->ssid, settings->ssid_len, settings->auth_type, settings->inactivity_timeout); if (settings->ssid == NULL) return -EINVAL; + if (settings->beacon_ies && settings->beacon_ies_len > 0) + memcpy(&vif->saved_beacon_ie.ie_info, settings->beacon_ies, settings->beacon_ies_len); + vif->saved_beacon_ie.mgmt_frm_type = OWL_FRAME_BEACON; + vif->saved_beacon_ie.ie_len = settings->beacon_ies_len; /* Seting up AP SSID and BSSID */ vif->ssid_len = settings->ssid_len; memcpy(vif->ssid, settings->ssid, settings->ssid_len); memcpy(vif->bssid, vif->ndev->dev_addr, ETH_ALEN); /* AP is the head of vif->bss_list */ INIT_LIST_HEAD(&vif->bss_list); /* Add AP to global ap_list */ list_add_tail(&vif->ap_list, &owl->ap_list); vif->ap_enabled = true; return 0; } ``` 接下來在執行 `inform_bss()` 的時候就可以直接從 `ap_vif` 拿之前儲存的 `saved_beacon_ie` 用就好 ```diff static void inform_bss(struct owl_vif *vif) { struct owl_vif *ap; list_for_each_entry (ap, &owl->ap_list, ap_list) { struct cfg80211_bss *bss = NULL; struct cfg80211_inform_bss data = { /* the only channel */ .chan = &ap->wdev.wiphy->bands[NL80211_BAND_2GHZ]->channels[0], .scan_width = NL80211_BSS_CHAN_WIDTH_20, .signal = DBM_TO_MBM(rand_int_smooth(-100, -30, jiffies)), }; pr_info("owl: %s performs scan, found %s (SSID: %s, BSSID: %pM)\n", vif->ndev->name, ap->ndev->name, ap->ssid, ap->bssid); - u8 *ie = kmalloc(ap->ssid_len + 2, GFP_KERNEL); + u8 *ie; + u8 ie_len = ap->saved_beacon_ie.ie_len; - ie[0] = WLAN_EID_SSID; - ie[1] = ap->ssid_len; - memcpy(ie + 2, ap->ssid, ap->ssid_len); + memcpy(ie, &ap->saved_beacon_ie.ie_info, 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 posible to use cfg80211_inform_bss() instead. */ - bss = cfg80211_inform_bss_data( - vif->wdev.wiphy, &data, CFG80211_BSS_FTYPE_UNKNOWN, ap->bssid, tsf, - WLAN_CAPABILITY_ESS, 100, ie, ap->ssid_len + 2, GFP_KERNEL); + bss = cfg80211_inform_bss_data( + vif->wdev.wiphy, &data, CFG80211_BSS_FTYPE_UNKNOWN, ap->bssid, tsf, + WLAN_CAPABILITY_ESS, 100, ie, ie_len, GFP_KERNEL); /* cfg80211_inform_bss_data() returns cfg80211_bss structure referefence * counter of which should be decremented if it is unused. */ cfg80211_put_bss(vif->wdev.wiphy, bss); kfree(ie); } } ``` 最後是 `beaconing` 的部分, ... 但是想到這到這裡有點奇怪!!! 因為要做 `saved_ie` 是因為要判斷收到 `beacon` 有沒有相同 如果相同就不傳 但是要跟誰比 @@ ``` static void beaconing(struct owl_vif *ap) { struct owl_vif *vif; list_for_each_entry (vif, &owl->vif_list, list) { if (vif->wdev.iftype == NL80211_IFTYPE_AP) continue; struct cfg80211_bss *bss = NULL; /* TODO: Simulate space to represent signal strength */ struct cfg80211_inform_bss data = { /* the only channel */ .chan = &ap->wdev.wiphy->bands[NL80211_BAND_2GHZ]->channels[0], .scan_width = NL80211_BSS_CHAN_WIDTH_20, .signal = DBM_TO_MBM(rand_int_smooth(-100, -30, jiffies)), }; pr_info("owl: %s receive beacon from %s (SSID: %s, BSSID: %pM)\n", vif->ndev->name, ap->ndev->name, ap->ssid, ap->bssid); u8 *ie = kmalloc(ap->ssid_len + 2, GFP_KERNEL); ie[0] = WLAN_EID_SSID; ie[1] = ap->ssid_len; memcpy(ie + 2, ap->ssid, ap->ssid_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 posible to use cfg80211_inform_bss() instead. */ bss = cfg80211_inform_bss_data( vif->wdev.wiphy, &data, CFG80211_BSS_FTYPE_BEACON, ap->bssid, tsf, WLAN_CAPABILITY_ESS, 10000, ie, ap->ssid_len + 2, GFP_KERNEL); /* cfg80211_inform_bss_data() returns cfg80211_bss structure referefence * counter of which should be decremented if it is unused. */ cfg80211_put_bss(vif->wdev.wiphy, bss); kfree(ie); } } ```