目录
本章以指令:iw dev wlan0 scan为例,带你走进iw层,cfg80211层,mac80211cfg,驱动层细节流程。
一,iw应用层
1,其实是两条命令
分析scan.c文件,跟踪TOPLEVEL(scan, "[-u] xx", 0, 0, CIB_NETDEV, handle_scan_combined, "xxx");
从handle_scan_combined()函数可知,最终运行下面两条指令。
iw dev wlan0 scan trigger
对应的netlink消息:NL80211_CMD_TRIGGER_SCAN
iw dev wlan0 scan dump
对应的netlink消息:NL80211_CMD_GET_SCAN
二,cfg80211层
1,netlink接收到 NL80211_CMD_TRIGGER_SCAN,执行下面函数
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
//调用mac80211注册的cfg80211_ops对应的函数.scan
rdev_scan(rdev, request);
-->ret = rdev->ops->scan(&rdev->wiphy, request); //mac80211实现
//构造netlink消息,回复给iw
nl80211_send_scan_start(rdev, wdev);
-->nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-->nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,NL80211_CMD_TRIGGER_SCAN) < 0)
-->nl80211hdr_put(msg, portid, seq, flags, cmd);
-->nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
-->nl80211_add_scan_req(msg, rdev);
-->genlmsg_end(msg, hdr);
--genlmsg_multicast_netns()
}
2,netlink接收到 NL80211_CMD_GET_SCAN,执行下面函数
static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
{
nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
cfg80211_bss_expire(rdev);
list_for_each_entry(scan, &rdev->bss_list, list) {
nl80211_send_bss(skb, cb,cb->nlh->nlmsg_seq, NLM_F_MULTI,rdev, wdev, scan); //从bss段中取出数据
}
}
三,mac80211层
1,从cfg80211层中,可知调用的是.scan函数
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
....
.scan = ieee80211_scan,
.abort_scan = ieee80211_abort_scan,
....
};
static int ieee80211_scan(struct wiphy *wiphy,struct cfg80211_scan_request *req)
{
ieee80211_request_scan(sdata, req);
-->__ieee80211_start_scan(sdata, req);
//软件扫描方式
--->ieee80211_start_sw_scan(local, sdata);
---->drv_sw_scan_start(local, sdata, local->scan_addr);
------->local->ops->sw_scan_start(&local->hw, &sdata->vif, mac_addr); //ath9k实现
//延时调用ieee80211_scan_work,调用前需要初始化
---->ieee80211_queue_delayed_work(&local->hw,&local->scan_work, 0);
//local->scan_work()的实现如下
local->scan_work
-->ieee80211_scan_work()
--->__ieee80211_scan_completed()
---->drv_sw_scan_complete()
----->.sw_scan_complete//ath9k实现
}
2,延时调用ieee80211_scan_work()的初始化过程在ieee80211_alloc_hw_nm()函数
struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
const struct ieee80211_ops *ops,
const char *requested_name)
{
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
// 这里使用的是INIT_DELAYED_WORK()那么之后
// 我们就会调用schedule_delayed_work(),这两是一对
// 表示经过一段延时然后在执行某个函数。
}
EXPORT_SYMBOL(ieee80211_alloc_hw_nm);
//以下是ieee80211_scan_work()的实现细节
void ieee80211_scan_work(struct work_struct *work)
{
__ieee80211_scan_completed(&local->hw, aborted);
}
static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
{
drv_sw_scan_complete(local, scan_sdata);
}
static inline void drv_sw_scan_complete(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
local->ops->sw_scan_complete(&local->hw, &sdata->vif);
}
void ieee80211_scan_work(struct work_struct *work)
{
__ieee80211_scan_completed(&local->hw, aborted);
}
static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
{
drv_sw_scan_complete(local, scan_sdata);
}
static inline void drv_sw_scan_complete(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
local->ops->sw_scan_complete(&local->hw, &sdata->vif);
}
四,无线驱动层
1,从mac80211层可知,调用的是.sw_scan_start()和.sw_scan_complete()函数
struct ieee80211_ops ath9k_htc_ops = {
.tx = ath9k_htc_tx,
.start = ath9k_htc_start,
.stop = ath9k_htc_stop,
.add_interface = ath9k_htc_add_interface,
....
.sw_scan_start = ath9k_htc_sw_scan_start,
.sw_scan_complete = ath9k_htc_sw_scan_complete,
....
};
欢迎订阅公众号【从零开始学无线】,一起学习交流!