參考 ath6kl_set_ies
的實作,他會先把 struct cfg80211_beacon_data *infobeacon_iesbeacon_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

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

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 用就好

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);
    }
}