文章目录

  • 数据结构
    • 通用管理帧首部: struct ieee80211_mgmt
    • 三地址帧首部: struct ieee80211_hdr_3addr
    • 支持速率定义: struct ieee80211_rate
    • 支持的band定义: struct ieee80211_supported_band
    • 支持的channel定义: struct ieee80211_channel
  • ieee80211_scan_state_send_probe()
  • 组装帧: ieee80211_build_probe_req()
    • 组装IE: ieee80211_build_preq_ies()
    • 组装skb: ieee80211_probereq_get()

当扫描状态机切换到SCAN_SEND_PROBE状态后,mac80211将调用ieee80211_scan_state_send_probe()组装Probe Request帧,然后将其发送出去。这篇笔记来看这部分代码的实现。

数据结构

通用管理帧首部: struct ieee80211_mgmt

struct ieee80211_mgmt {__le16 frame_control;__le16 duration;u8 da[6];u8 sa[6];u8 bssid[6];__le16 seq_ctrl;union {struct {__le16 auth_alg;__le16 auth_transaction;__le16 status_code;/* possibly followed by Challenge text */u8 variable[0];} __attribute__ ((packed)) auth;struct {__le16 reason_code;} __attribute__ ((packed)) deauth;struct {__le16 capab_info;__le16 listen_interval;/* followed by SSID and Supported rates */u8 variable[0];} __attribute__ ((packed)) assoc_req;struct {__le16 capab_info;__le16 status_code;__le16 aid;/* followed by Supported rates */u8 variable[0];} __attribute__ ((packed)) assoc_resp, reassoc_resp;struct {__le16 capab_info;__le16 listen_interval;u8 current_ap[6];/* followed by SSID and Supported rates */u8 variable[0];} __attribute__ ((packed)) reassoc_req;struct {__le16 reason_code;} __attribute__ ((packed)) disassoc;struct {__le64 timestamp;__le16 beacon_int;__le16 capab_info;/* followed by some of SSID, Supported rates,* FH Params, DS Params, CF Params, IBSS Params, TIM */u8 variable[0];} __attribute__ ((packed)) beacon;struct {/* only variable items: SSID, Supported rates */u8 variable[0];} __attribute__ ((packed)) probe_req;struct {__le64 timestamp;__le16 beacon_int;__le16 capab_info;/* followed by some of SSID, Supported rates,* FH Params, DS Params, CF Params, IBSS Params */u8 variable[0];} __attribute__ ((packed)) probe_resp;struct {u8 category;union {struct {u8 action_code;u8 dialog_token;u8 status_code;u8 variable[0];} __attribute__ ((packed)) wme_action;struct{u8 action_code;u8 element_id;u8 length;struct ieee80211_channel_sw_ie sw_elem;} __attribute__((packed)) chan_switch;struct{u8 action_code;u8 dialog_token;u8 element_id;u8 length;struct ieee80211_msrment_ie msr_elem;} __attribute__((packed)) measurement;struct{u8 action_code;u8 dialog_token;__le16 capab;__le16 timeout;__le16 start_seq_num;} __attribute__((packed)) addba_req;struct{u8 action_code;u8 dialog_token;__le16 status;__le16 capab;__le16 timeout;} __attribute__((packed)) addba_resp;struct{u8 action_code;__le16 params;__le16 reason_code;} __attribute__((packed)) delba;struct{u8 action_code;/* capab_info for open and confirm,* reason for close*/__le16 aux;/* Followed in plink_confirm by status* code, AID and supported rates,* and directly by supported rates in* plink_open and plink_close*/u8 variable[0];} __attribute__((packed)) plink_action;struct{u8 action_code;u8 variable[0];} __attribute__((packed)) mesh_action;struct {u8 action;u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];} __attribute__ ((packed)) sa_query;struct {u8 action;u8 smps_control;} __attribute__ ((packed)) ht_smps;} u;} __attribute__ ((packed)) action;} u;
} __attribute__ ((packed));

三地址帧首部: struct ieee80211_hdr_3addr

struct ieee80211_hdr_3addr {__le16 frame_control;__le16 duration_id;u8 addr1[6];u8 addr2[6];u8 addr3[6];__le16 seq_ctrl;
} __attribute__ ((packed));

支持速率定义: struct ieee80211_rate

芯片驱动程序应该用该结构定义自己支持的速率信息。

struct ieee80211_rate {u32 flags;u16 bitrate;u16 hw_value, hw_value_short;
};// mac80211_hwsim支持的速率,2.4G全支持;5G支持hwsim_rates[4]开始的速率
static const struct ieee80211_rate hwsim_rates[] = {{ .bitrate = 10 },{ .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },{ .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },{ .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },{ .bitrate = 60 },{ .bitrate = 90 },{ .bitrate = 120 },{ .bitrate = 180 },{ .bitrate = 240 },{ .bitrate = 360 },{ .bitrate = 480 },{ .bitrate = 540 }
};

支持的band定义: struct ieee80211_supported_band

struct ieee80211_supported_band {struct ieee80211_channel *channels; // 支持的channel列表struct ieee80211_rate *bitrates; // 支持的速率enum ieee80211_band band; // 2.4G or 5Gint n_channels; // 支持的channel个数int n_bitrates; // 支持的速率个数struct ieee80211_sta_ht_cap ht_cap; // HT能力描述
};

支持的channel定义: struct ieee80211_channel

struct ieee80211_channel {enum ieee80211_band band; // 2.4G or 5Gu16 center_freq; // channel的中心频率u16 hw_value;u32 flags;int max_antenna_gain;int max_power; // 最大发射功率bool beacon_found;u32 orig_flags;int orig_mag, orig_mpwr;
};// mac80211_hwsim支持2.4G和5G所有的channel
#define CHAN2G(_freq)  { \.band = IEEE80211_BAND_2GHZ, \.center_freq = (_freq), \.hw_value = (_freq), \.max_power = 20, \
}#define CHAN5G(_freq) { \.band = IEEE80211_BAND_5GHZ, \.center_freq = (_freq), \.hw_value = (_freq), \.max_power = 20, \
}static const struct ieee80211_channel hwsim_channels_2ghz[] = {CHAN2G(2412), /* Channel 1 */CHAN2G(2417), /* Channel 2 */CHAN2G(2422), /* Channel 3 */CHAN2G(2427), /* Channel 4 */CHAN2G(2432), /* Channel 5 */CHAN2G(2437), /* Channel 6 */CHAN2G(2442), /* Channel 7 */CHAN2G(2447), /* Channel 8 */CHAN2G(2452), /* Channel 9 */CHAN2G(2457), /* Channel 10 */CHAN2G(2462), /* Channel 11 */CHAN2G(2467), /* Channel 12 */CHAN2G(2472), /* Channel 13 */CHAN2G(2484), /* Channel 14 */
};static const struct ieee80211_channel hwsim_channels_5ghz[] = {CHAN5G(5180), /* Channel 36 */CHAN5G(5200), /* Channel 40 */CHAN5G(5220), /* Channel 44 */CHAN5G(5240), /* Channel 48 */CHAN5G(5260), /* Channel 52 */CHAN5G(5280), /* Channel 56 */CHAN5G(5300), /* Channel 60 */CHAN5G(5320), /* Channel 64 */CHAN5G(5500), /* Channel 100 */CHAN5G(5520), /* Channel 104 */CHAN5G(5540), /* Channel 108 */CHAN5G(5560), /* Channel 112 */CHAN5G(5580), /* Channel 116 */CHAN5G(5600), /* Channel 120 */CHAN5G(5620), /* Channel 124 */CHAN5G(5640), /* Channel 128 */CHAN5G(5660), /* Channel 132 */CHAN5G(5680), /* Channel 136 */CHAN5G(5700), /* Channel 140 */CHAN5G(5745), /* Channel 149 */CHAN5G(5765), /* Channel 153 */CHAN5G(5785), /* Channel 157 */CHAN5G(5805), /* Channel 161 */CHAN5G(5825), /* Channel 165 */
};

ieee80211_scan_state_send_probe()

static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,unsigned long *next_delay)
{int i;struct ieee80211_sub_if_data *sdata = local->scan_sdata;// 对于要扫描的每个ssid,发送Probe Request帧for (i = 0; i < local->scan_req->n_ssids; i++)ieee80211_send_probe_req(sdata, NULL, local->scan_req->ssids[i].ssid,local->scan_req->ssids[i].ssid_len, local->scan_req->ie, local->scan_req->ie_len);// 发送Probe帧后,最多等待1/33秒响应,然后在下一个channel上执行扫描*next_delay = IEEE80211_CHANNEL_TIME;local->next_scan_state = SCAN_DECISION;
}

local->scan_req->n_ssids直接来自用户态的扫描请求参数,从该函数的实现可以看出,即使用户态想要执行全扫描,也应该指定一个通配的SSID下来,否则将无法发起扫描。

向指定的SSID发送Probe Request帧的实现如下:

void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len)
{struct sk_buff *skb;// 组装Probe Request帧skb = ieee80211_build_probe_req(sdata, dst, ssid, ssid_len, ie, ie_len);// 调用标准的tx接口将Probe Request帧发送出去if (skb)ieee80211_tx_skb(sdata, skb);
}

组装帧: ieee80211_build_probe_req()

struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,u8 *dst, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len)
{struct ieee80211_local *local = sdata->local;struct sk_buff *skb;struct ieee80211_mgmt *mgmt; // 通用得管理帧首部size_t buf_len;u8 *buf;u8 chan;// 分配一块临时内存buf = kmalloc(200 + ie_len, GFP_KERNEL);if (!buf) {return NULL;}// 根据频率计算出当前要扫描的channel索引chan = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);// 将IE信息填充到临时内存buf中buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, local->hw.conf.channel->band,sdata->rc_rateidx_mask[local->hw.conf.channel->band], chan);// 构造并填充SKBskb = ieee80211_probereq_get(&local->hw, &sdata->vif, ssid, ssid_len, buf, buf_len);// 如果指定了目的地址,那么将其拷贝到帧都不得bssid字段if (dst) {mgmt = (struct ieee80211_mgmt *) skb->data;memcpy(mgmt->da, dst, ETH_ALEN);memcpy(mgmt->bssid, dst, ETH_ALEN);}// Probe Reuqest帧不加密IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;kfree(buf);return skb;
}

组装IE: ieee80211_build_preq_ies()

该函数将Probe Request帧中除了SSID以外得其它信息元素都填充到buffer指定得内存块中。

int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, const u8 *ie,size_t ie_len, enum ieee80211_band band, u32 rate_mask, u8 channel)
{struct ieee80211_supported_band *sband;u8 *pos;size_t offset = 0, noffset;int supp_rates_len, i;u8 rates[32];int num_rates;int ext_rates_len;sband = local->hw.wiphy->bands[band];// pos指向起始位置pos = buffer;// 组装支持的速率IEnum_rates = 0;for (i = 0; i < sband->n_bitrates; i++) {if ((BIT(i) & rate_mask) == 0)continue; /* skip rate */rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5);}supp_rates_len = min_t(int, num_rates, 8);*pos++ = WLAN_EID_SUPP_RATES;*pos++ = supp_rates_len;memcpy(pos, rates, supp_rates_len);pos += supp_rates_len;/* insert "request information" if in custom IEs */if (ie && ie_len) {static const u8 before_extrates[] = {WLAN_EID_SSID,WLAN_EID_SUPP_RATES,WLAN_EID_REQUEST,};noffset = ieee80211_ie_split(ie, ie_len, before_extrates, ARRAY_SIZE(before_extrates), offset);memcpy(pos, ie + offset, noffset - offset);pos += noffset - offset;offset = noffset;}// 组装扩展速率IEext_rates_len = num_rates - supp_rates_len;if (ext_rates_len > 0) {*pos++ = WLAN_EID_EXT_SUPP_RATES;*pos++ = ext_rates_len;memcpy(pos, rates + supp_rates_len, ext_rates_len);pos += ext_rates_len;}// 2.4G需要填充DS IE信息if (channel && sband->band == IEEE80211_BAND_2GHZ) {*pos++ = WLAN_EID_DS_PARAMS;*pos++ = 1;*pos++ = channel;}/* insert custom IEs that go before HT */if (ie && ie_len) {static const u8 before_ht[] = {WLAN_EID_SSID,WLAN_EID_SUPP_RATES,WLAN_EID_REQUEST,WLAN_EID_EXT_SUPP_RATES,WLAN_EID_DS_PARAMS,WLAN_EID_SUPPORTED_REGULATORY_CLASSES,};noffset = ieee80211_ie_split(ie, ie_len, before_ht, ARRAY_SIZE(before_ht), offset);memcpy(pos, ie + offset, noffset - offset);pos += noffset - offset;offset = noffset;}if (sband->ht_cap.ht_supported) {u16 cap = sband->ht_cap.cap;__le16 tmp;*pos++ = WLAN_EID_HT_CAPABILITY;*pos++ = sizeof(struct ieee80211_ht_cap);memset(pos, 0, sizeof(struct ieee80211_ht_cap));tmp = cpu_to_le16(cap);memcpy(pos, &tmp, sizeof(u16));pos += sizeof(u16);*pos++ = sband->ht_cap.ampdu_factor |(sband->ht_cap.ampdu_density << IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));pos += sizeof(sband->ht_cap.mcs);pos += 2 + 4 + 1; /* ext info, BF cap, antsel */}/** If adding more here, adjust code in main.c* that calculates local->scan_ies_len.*//* add any remaining custom IEs */if (ie && ie_len) {noffset = ie_len;memcpy(pos, ie + offset, noffset - offset);pos += noffset - offset;}return pos - buffer;
}

组装skb: ieee80211_probereq_get()

struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len)
{struct ieee80211_sub_if_data *sdata;struct ieee80211_local *local;struct ieee80211_hdr_3addr *hdr;struct sk_buff *skb;size_t ie_ssid_len;u8 *pos;sdata = vif_to_sdata(vif);local = sdata->local;ie_ssid_len = 2 + ssid_len; // 为何要加2,IE中得length字段并不包含ID和length// 分配skb,并保留芯片驱动指定得预留空间skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + ie_ssid_len + ie_len);if (!skb) {return NULL;}skb_reserve(skb, local->hw.extra_tx_headroom);// 填充mac帧首部hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));memset(hdr, 0, sizeof(*hdr));hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ);memset(hdr->addr1, 0xff, ETH_ALEN);memcpy(hdr->addr2, vif->addr, ETH_ALEN);memset(hdr->addr3, 0xff, ETH_ALEN);// 填充SSID IEpos = skb_put(skb, ie_ssid_len);*pos++ = WLAN_EID_SSID;*pos++ = ssid_len;if (ssid)memcpy(pos, ssid, ssid_len);pos += ssid_len;// 填充其它IE信息if (ie) {pos = skb_put(skb, ie_len);memcpy(pos, ie, ie_len);}return skb;
}

[linux无线子系统]主动扫描之发送Probe Request帧相关推荐

  1. probe request帧结构_WIFI探针原理

    WIFI 探针原理:WIFI 是基于IEEE802.11a/b/g/n 协议,在标准协议中,定义了AP(无线接入点)和STA(站或客户端)的两种工作模式:协议中规定了BEACON.ACK.DATA.P ...

  2. probe request帧结构_WLAN 无线网络 09 - 管理帧

    0000,Association request:关联请求帧 认证成功后,STA就会进入关联阶段, 这个交互的目的是为了加入这个BSS 并获取一个AID.通过Association Request携带 ...

  3. probe request帧结构_WIFI基础知识(802.11)

    1. WEP,Wired Equivalent Privacy: 802.11中最早期的加密标准 2. CCMP(CTR with CBC-MAC Protocol): 基于AES的全新加密协议,在I ...

  4. Probe Request

    如果某AP的SSID是隐藏的 那么通常手机发送的普通的probe request包是无法获取到隐藏的SSID////////////////////////////////////无线客户端工作过程中 ...

  5. Android Wifi 主动扫描 被动扫描

    介绍主动扫描,被动扫描以及连接的wifi的扫描过程 参考文档 <802.11无线网络权威指南> <80_Y0513_1_QCA_WCN36X0_SOFTWARE_ARCHITECTU ...

  6. [转]Android Wifi 主动扫描 被动扫描

    介绍主动扫描,被动扫描以及连接的wifi的扫描过程 参考文档 <802.11无线网络权威指南> <80_Y0513_1_QCA_WCN36X0_SOFTWARE_ARCHITECTU ...

  7. 主动扫描和被动扫描的区别

    主动扫描和被动扫描知识 对于一个station来说,如果希望连接到AP,首先必须发现AP.发现的方式就两种被动扫描(passive scan)和主动扫描(active scan),记住两个关键字:被动 ...

  8. Linux内核网络数据包发送(四)——Linux netdevice 子系统

    Linux内核网络数据包发送(四)--Linux netdevice 子系统 1. 前言 2. `dev_queue_xmit` and `__dev_queue_xmit` 2.1 `netdev_ ...

  9. linux 无线 扫描不到网络,解决deepin扫描不到WiFi和蓝牙信号问题

    今天为我的联想拯救者Y7000笔记本安装了Windows10+deepin15.10.1双系统,但是启动deepin后发现无线网络无法扫描的WiFi信号,经过一番搜索后,找到了解决方案. 理论上联想系 ...

最新文章

  1. 筛选法求N以内的所有素数
  2. 完胜ReLU!斯坦福的神经网络采用这种激活函数,竟高保真还原各种图像视频
  3. 《effective java》类和对象
  4. PyQt - 维基百科,自由的百科全书
  5. upload-labs-master文件上传靶场第七关详解
  6. Qt编程'hello world
  7. 电脑连接电视方法详解_笔记本连接电视方法有哪些?分享两种笔记本连接电视方法...
  8. 从源码看ConcurrentHashMap
  9. wps如何保存最终状态_如何使得打开word文件显示最终的修改状态
  10. LeetCode 435 无重叠区间
  11. python重命名csv文件_Python根据文件中选定的字符复制和重命名许多小csv文件
  12. Linux Makefile自动生成--config.h
  13. document.execCommand() 命令详解 只支持IE
  14. sql 二进制文件的导入导出
  15. 计算机械效率的公式四种,物理计算公式;
  16. 数据结构导论 笔记整理
  17. 网页版Facebook第三方登陆
  18. 苹果电脑各型号支持的macOS版本列表
  19. 安卓设备数据转移到ios设备
  20. cellpadding ,cellspacing的意思

热门文章

  1. 【2022年对话机器人chatbot】SaleSmartly如何解决客服难题
  2. macd金叉公式成功率_MACD金叉kdj死叉和20日线可靠吗
  3. 接口测试之Postman使用全指南(原来使用 Postman测试API接口如此简单)
  4. 输出电容的ESR对DC_DC的影响——电感发烫排查思路
  5. NAT与NAT穿透(二)
  6. java基础-网络编程
  7. [VB.NET]VB的vbFromUnicode、vbUnicode在vb.net中怎么使用
  8. java 20008年月历输出 日期的个位与星期数相等 的日子
  9. C语言怎么消除最后的回车键,多样例输出,如何去掉最后一个回车
  10. Linux之日志系统