1,mac80211是什么?
mac80211是linux内核子系统,是驱动开发者可用于为softmac无线设备写驱动的框架。mac80211在内核空间实现STA模式。在用户空间实现AP模式。
2,mac80211提供什么功能?
mac向上提供2类接口:数据和管理。管理29种,发起认证,连接,信道扫描等管理功能。
3,mac80211工作流程?
mac80211模块注册流程:
//关键结构体
static const struct rate_control_ops mac80211_minstrel_ht = {
.name = "minstrel_ht",
.tx_status_ext = minstrel_ht_tx_status,
.get_rate = minstrel_ht_get_rate,
.rate_init = minstrel_ht_rate_init,
.rate_update = minstrel_ht_rate_update,
.alloc_sta = minstrel_ht_alloc_sta,
.free_sta = minstrel_ht_free_sta,
.alloc = minstrel_ht_alloc,
.free = minstrel_ht_free,
#ifdef CPTCFG_MAC80211_DEBUGFS
.add_sta_debugfs = minstrel_ht_add_sta_debugfs,
#endif
.get_expected_throughput = minstrel_ht_get_expected_throughput,
};
static struct notifier_block mac80211_netdev_notifier = {
.notifier_call = netdev_notify,
};
//模块注册
subsys_initcall(ieee80211_init);
static int __init ieee80211_init(void)
{
ret = rc80211_minstrel_init();
-->init_sample_table();
-->ieee80211_rate_control_register(&mac80211_minstrel_ht); //速率控制注册
ret = ieee80211_iface_init();
-->register_netdevice_notifier(&mac80211_netdev_notifier); //网络设备注册
}
//网络设备注册
static int netdev_notify(struct notifier_block *nb, unsigned long state, void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ieee80211_debugfs_rename_netdev(sdata);
return NOTIFY_OK;
}
mac80211向cfg80211注册的ops
//最为关键的ops结构体
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
.change_virtual_intf = ieee80211_change_iface,
.start_p2p_device = ieee80211_start_p2p_device,
.stop_p2p_device = ieee80211_stop_p2p_device,
.add_key = ieee80211_add_key,
.del_key = ieee80211_del_key,
.get_key = ieee80211_get_key,
.set_default_key = ieee80211_config_default_key,
.set_default_mgmt_key = ieee80211_config_default_mgmt_key,
.start_ap = ieee80211_start_ap,
.change_beacon = ieee80211_change_beacon,
.stop_ap = ieee80211_stop_ap,
.add_station = ieee80211_add_station,
.del_station = ieee80211_del_station,
.change_station = ieee80211_change_station,
.get_station = ieee80211_get_station,
.dump_station = ieee80211_dump_station,
.dump_survey = ieee80211_dump_survey,
#ifdef CPTCFG_MAC80211_MESH
.add_mpath = ieee80211_add_mpath,
.del_mpath = ieee80211_del_mpath,
.change_mpath = ieee80211_change_mpath,
.get_mpath = ieee80211_get_mpath,
.dump_mpath = ieee80211_dump_mpath,
.get_mpp = ieee80211_get_mpp,
.dump_mpp = ieee80211_dump_mpp,
.update_mesh_config = ieee80211_update_mesh_config,
.get_mesh_config = ieee80211_get_mesh_config,
.join_mesh = ieee80211_join_mesh,
.leave_mesh = ieee80211_leave_mesh,
#endif
.join_ocb = ieee80211_join_ocb,
.leave_ocb = ieee80211_leave_ocb,
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
.set_monitor_channel = ieee80211_set_monitor_channel,
.suspend = ieee80211_suspend,
.resume = ieee80211_resume,
.scan = ieee80211_scan,
.abort_scan = ieee80211_abort_scan,
.sched_scan_start = ieee80211_sched_scan_start,
.sched_scan_stop = ieee80211_sched_scan_stop,
.auth = ieee80211_auth,
.assoc = ieee80211_assoc,
.deauth = ieee80211_deauth,
.disassoc = ieee80211_disassoc,
.join_ibss = ieee80211_join_ibss,
.leave_ibss = ieee80211_leave_ibss,
.set_mcast_rate = ieee80211_set_mcast_rate,
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
.set_antenna_gain = ieee80211_set_antenna_gain,
.set_wds_peer = ieee80211_set_wds_peer,
.rfkill_poll = ieee80211_rfkill_poll,
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
.set_power_mgmt = ieee80211_set_power_mgmt,
.set_bitrate_mask = ieee80211_set_bitrate_mask,
.remain_on_channel = ieee80211_remain_on_channel,
.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
.mgmt_tx = ieee80211_mgmt_tx,
.mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
.set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config,
.mgmt_frame_register = ieee80211_mgmt_frame_register,
.set_antenna = ieee80211_set_antenna,
.get_antenna = ieee80211_get_antenna,
.set_rekey_data = ieee80211_set_rekey_data,
.tdls_oper = ieee80211_tdls_oper,
.tdls_mgmt = ieee80211_tdls_mgmt,
.tdls_channel_switch = ieee80211_tdls_channel_switch,
.tdls_cancel_channel_switch = ieee80211_tdls_cancel_channel_switch,
.probe_client = ieee80211_probe_client,
.set_noack_map = ieee80211_set_noack_map,
#ifdef CONFIG_PM
.set_wakeup = ieee80211_set_wakeup,
#endif
.get_channel = ieee80211_cfg_get_channel,
.start_radar_detection = ieee80211_start_radar_detection,
.channel_switch = ieee80211_channel_switch,
.set_qos_map = ieee80211_set_qos_map,
.set_ap_chanwidth = ieee80211_set_ap_chanwidth,
.add_tx_ts = ieee80211_add_tx_ts,
.del_tx_ts = ieee80211_del_tx_ts,
.start_nan = ieee80211_start_nan,
.stop_nan = ieee80211_stop_nan,
.nan_change_conf = ieee80211_nan_change_conf,
.add_nan_func = ieee80211_add_nan_func,
.del_nan_func = ieee80211_del_nan_func,
.set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
};
//通过EXPORT_SYMBOL宏定义提供给驱动调用
struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
const struct ieee80211_ops *ops,
const char *requested_name)
{
wiphy = wiphy_new_nm(&mac80211_config_ops, priv_size, requested_name);
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
##INIT_DELAYED_WORK和INIT_WORK定时器中断函数
##queue_delayed_work()一起使用
}
EXPORT_SYMBOL(ieee80211_alloc_hw_nm);
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
-------->container_of(hw, struct ieee80211_local, hw);
//container_of()作用,通过member的地址计算得到container_type的首地址
}
EXPORT_SYMBOL(ieee80211_register_hw);
//注:EXPORT_SYMBOL的作用,标签内定义的函数或者符号对全部内核代码公开,
//不用修改内核代码就可以在内核模块中直接调用。
分析ath9k驱动源码
//htc_drv_init.c
static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid, char *product, u32 drv_info)
{
/* Register with mac80211 */
error = ieee80211_register_hw(hw);
}
4,指令分析:scan命令
cfg.c定义的cfg80211_ops,
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
....
.scan = ieee80211_scan,
....
};
static int ieee80211_scan(struct wiphy *wiphy,struct cfg80211_scan_request *req)
{
ieee80211_request_scan(sdata, req);
}
对ieee80211_request_scan()函数进一步分析,所在文件scan.c
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req)
{
__ieee80211_start_scan(sdata, req);
if(支持硬件扫描)[
ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
]
else [
rc = ieee80211_start_sw_scan(local, sdata); //软件扫描方式
]
}
int ieee80211_start_sw_scan()
{
//调用驱动层scan函数
drv_sw_scan_start(local, sdata, local->scan_addr);
//延时调用local->scan_work函数
ieee80211_queue_delayed_work(&local->hw,&local->scan_work, 0);
}
void drv_sw_scan_start()
{
//注:调用了ath9k的.sw_scan_start()函数
local->ops->sw_scan_start(&local->hw, &sdata->vif, mac_addr);
}
//延时调用的函数local->scan_work()对应的ath9k驱动函数又是什么呢?
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()经过一段延时然后在执行某个函数。
}
EXPORT_SYMBOL(ieee80211_alloc_hw_nm);
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)
{
//注:调用了ath9k的.sw_scan_complete()函数
local->ops->sw_scan_complete(&local->hw, &sdata->vif);
}
ath9k驱动对应scan的实现
#opshtc_drv_main.c,注册ieee80211_ops
struct ieee80211_ops ath9k_htc_ops = {
.tx = ath9k_htc_tx,
.start = ath9k_htc_start,
.stop = ath9k_htc_stop,
.add_interface = ath9k_htc_add_interface,
.remove_interface = ath9k_htc_remove_interface,
.config = ath9k_htc_config,
.configure_filter = ath9k_htc_configure_filter,
.sta_add = ath9k_htc_sta_add,
.sta_remove = ath9k_htc_sta_remove,
.conf_tx = ath9k_htc_conf_tx,
.sta_rc_update = ath9k_htc_sta_rc_update,
.bss_info_changed = ath9k_htc_bss_info_changed,
.set_key = ath9k_htc_set_key,
.get_tsf = ath9k_htc_get_tsf,
.set_tsf = ath9k_htc_set_tsf,
.reset_tsf = ath9k_htc_reset_tsf,
.ampdu_action = ath9k_htc_ampdu_action,
.sw_scan_start = ath9k_htc_sw_scan_start,
.sw_scan_complete = ath9k_htc_sw_scan_complete,
.set_rts_threshold = ath9k_htc_set_rts_threshold,
.rfkill_poll = ath9k_htc_rfkill_poll_state,
.set_coverage_class = ath9k_htc_set_coverage_class,
.set_bitrate_mask = ath9k_htc_set_bitrate_mask,
.get_stats = ath9k_htc_get_stats,
.get_antenna = ath9k_htc_get_antenna,
.channel_switch_beacon = ath9k_htc_channel_switch_beacon,
#ifdef CPTCFG_ATH9K_HTC_DEBUGFS
.get_et_sset_count = ath9k_htc_get_et_sset_count,
.get_et_stats = ath9k_htc_get_et_stats,
.get_et_strings = ath9k_htc_get_et_strings,
#endif
};
int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
u16 devid, char *product, u32 drv_info)
{
hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops);
}
int ath9k_htc_hw_init(struct htc_target *target, struct device *dev, u16 devid,
char *product, u32 drv_info)
{
if (ath9k_htc_probe_device(target, dev, devid, product, drv_info)) {
pr_err("Failed to initialize the device\n");
return -ENODEV;
}
return 0;
}
欢迎订阅公众号【从零开始学无线】,一起学习交流!