高通QSDK 应用层发送控制帧
实践
使用cfg80211tool工具发送probe req帧
cfg80211tool ath0 sendmgmt 000FFF01401100001800000040003c00000fff014011000fff010003000fff0140110000

参数解释说明:
000FFF0140110000:目的mac地址00:0F:FF:01:40:11 至于后面那0000 为4字节对齐操
18000000:0x18 数据长度24字节 写成这样是 4字节对齐 且大小端模式考虑,24字节内容是从18000000后面开始计数长度,
以上字节是cfg80211tool工具规定的,以便驱动解析,后面是802.11的头,这里发送24字节,我们直发送802.11 mac Header部分

4000:Frame Control 这里0x4000 对应 对应probe Requset,具体看下面的抓包
3c00:Duration
000fff014011:Address1 目的地址
000fff010003:Address2 源地址
000fff014011:Address3 目的地址
0000:seq 该字段无所谓
验证

使用cfg80211tool工具发送Disassociate帧
cfg80211tool ath0 sendmgmt 000FFF01401100001a000000a0003c00000fff014011000fff010003000fff01401130040800

参数解释:
000FFF0140110000:目的mac地址00:0F:FF:01:40:11 至于后面那0000 为4字节对齐操
1a000000:0x1a 数据长度26字节 写成这样是 4字节对齐 且大小端模式考虑,26字节内容是从1a000000后面开始计数长度,
以上字节是cfg80211tool工具规定的,以便驱动解析,后面是802.11的头,这里发送26字节,802.11 mac Header 24字节+ wireless Management 2字节,即下图中的Reason Code ,当然从抓包中也可以看到这两个字节

a000:Frame Control 这里0xa000 对应 对应Disassociate ,具体看下面的抓包
3c00:Duration
000fff014011:Address1 目的地址
000fff010003:Address2 源地址
000fff014011:Address3 目的地址
0000:seq 该字段无所谓
0800 :Reason code
抓包

代码解析
参见[高通QSDK nl80211框架](./50.高通QSDK nl80211框架.md#cfg80211tool)文章的cfg80211tool章节介绍,熟悉cfg80211tool工具原理
修改xml文件如下:新增sendmgmt节点

sendmgmt命令会发送nl消息调用驱动层的
const struct wiphy_vendor_command wlan_cfg80211_vendor_commands[] = {
{
.info.vendor_id = QCA_NL80211_VENDOR_ID,
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION, // 该值为74
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = wlan_cfg80211_set_wificonfiguration // 调用该函数
},
};
static int wlan_cfg80211_set_wificonfiguration(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data,
int data_len)
{
struct wlan_cfg8011_genric_params generic_params;
// 解析cfg80211tool 传递过来的参数,存放到generic_params里面
//以上面发送的probe req 为例说明
//cfg80211tool ath0 sendmgmt 000FFF0140110000 18000000 4000 3c00 000fff014011 000fff010003 000fff014011 0000
extract_generic_command_params(wiphy, data, data_len, &generic_params);
//generic_params->command = 248 存放xml中dparam0 值
//generic_params->data 指向sendmgmt后面的这段数据000FFF0140110000 18000000 4000 3c00 000fff014011 000fff010003 000fff014011 0000
//generic_params->data_len 是该数据段的长度
switch(generic_params.command) {
case QCA_NL80211_VENDORSUBCMD_SEND_MGMT:
return_value = wlan_cfg80211_send_mgmt(wiphy, wdev, &generic_params); // 下面分析该函数
break;
}
}
static int wlan_cfg80211_send_mgmt(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct wlan_cfg8011_genric_params *params)
{
int ret = 0;
struct ieee80211req_mgmtbuf *mgmt_frm;
struct cfg80211_context *cfg_ctx = NULL;
struct ieee80211com *ic = NULL;
wlan_if_t vap = NULL;
int cmd_type;
void *cmd;
uint32_t *data = (u_int32_t *) params->data;
int i;
cfg_ctx = (struct cfg80211_context *)wiphy_priv(wiphy);
ic = cfg_ctx->ic;
cmd = extract_command(ic, wdev, &cmd_type);
if (cmd_type == VAP_CMD) {
vap = (wlan_if_t)cmd;
} else {
qdf_err(" %s Command on invalid interface \n", __func__);
return -EINVAL;
}
// 把000FFF0140110000 18000000 4000 3c00 000fff014011 000fff010003 000fff014011 0000 数据转换为ieee80211req_mgmtbuf类型的数据
/*
* struct ieee80211req_mgmtbuf {
* u_int8_t macaddr[IEEE80211_ADDR_LEN]; // 目的地址,虽然这里定义6字节,但是考虑到字节对齐,我们传递进来还是4字节对齐的000FFF0140110000
* u_int32_t buflen; // buf长度,这里定义为4字节,故而可以解释上面 0x18 在传递的时候是18000000
* u_int8_t buf[]; // buf[] = 4000 3c00 000fff014011 000fff010003 000fff014011 0000
* };
*/
mgmt_frm = (struct ieee80211req_mgmtbuf *) params->data;
/*
WIM_LOG_DEBUG("SEND MGMT:start:mac:%s datalen:%d buflen:%d",ether_sprintf(mgmt_frm->macaddr),params->data_len,mgmt_frm->buflen);
for(i=0;i<params->data_len;i++){
printk("%02x ",((uint8_t*)params->data)[i]);
}
printk("\n");
*/
if(mgmt_frm->buflen >= 37 && mgmt_frm->buf[24] == 0xff) {
qdf_err(" %s unknown action frame\n", __func__);
return -EINVAL;
}
/* if the macaddr requested is for broadcast then search for
all connected sta and send the mgmt packet */
if(vap) {
// 如果是广播的话,就跑到这里,我们上面传递的不是广播
if(IEEE80211_IS_BROADCAST(mgmt_frm->macaddr)) {
ret = wlan_iterate_station_list(vap, wlan_cfg80211_sta_send_mgmt, mgmt_frm);
}
else {
//故而走该分支,从这里可以看出,驱动是如何把数据解析为结构体 用的
ret = wlan_send_mgmt(vap, mgmt_frm->macaddr, mgmt_frm->buf, mgmt_frm->buflen);
// 下面就是wlan_send_mgmt函数的问题了 ,这里不在分析
}
} else {
qdf_err("%s: Invalid vap \n", __func__);
return -EINVAL;
}
/* wlan_iterate_station_list returns the number of sta connected,
so return error only if the return value is less than zero */
if (ret < 0) {
return ret;
} else {
return 0;
}
}