參考 ath6kl_set_ies
的實作,他會先把 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
裡
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);
}
}