wifi底層學習之路:三,Linux內核子系統mac80211

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;
}

歡迎訂閱公衆號【從零開始學無線】,一起學習交流!

                                                                 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章