解析mac80211从ieee80211_alloc_hw
函数分配 和ieee80211_register_hw
函数注册开始。
以pci无线网络设备为例,底层pci实现连接并注册pci设备之后,开始在ieee80211_alloc_hw
函数中实现无线网络设备的一些列初始化和设备分配,并关联ieee80211_ops
操作函数,实现mac层的操作。
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops)
{
struct ieee80211_local *local;
int priv_size, i;
struct wiphy *wiphy;
bool use_chanctx;
if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config ||
!ops->add_interface || !ops->remove_interface ||
!ops->configure_filter))
return NULL;
if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
return NULL;
/* check all or no channel context operations exist */
i = !!ops->add_chanctx + !!ops->remove_chanctx +
!!ops->change_chanctx + !!ops->assign_vif_chanctx +
!!ops->unassign_vif_chanctx;
if (WARN_ON(i != 0 && i != 5))
return NULL;
use_chanctx = i == 5;
/* Ensure 32-byte alignment of our private data and hw private data.
* We use the wiphy priv data for both our ieee80211_local and for
* the driver's private data
*
* In memory it'll be like this:
*
* +-------------------------+
* | struct wiphy |
* +-------------------------+
* | struct ieee80211_local |
* +-------------------------+
* | driver's private data |
* +-------------------------+
*
*/
priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
wiphy = wiphy_new(&mac80211_config_ops, priv_size);//分配一个新的wiphy
if (!wiphy)
return NULL;
wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes;
wiphy->privid = mac80211_wiphy_privid;
wiphy->flags |= WIPHY_FLAG_NETNS_OK |
WIPHY_FLAG_4ADDR_AP |
WIPHY_FLAG_4ADDR_STATION |
WIPHY_FLAG_REPORTS_OBSS |
WIPHY_FLAG_OFFCHAN_TX;
wiphy->extended_capabilities = extended_capabilities;
wiphy->extended_capabilities_mask = extended_capabilities;
wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities);
if (ops->remain_on_channel)
wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |
NL80211_FEATURE_SAE |
NL80211_FEATURE_HT_IBSS |
NL80211_FEATURE_VIF_TXPOWER |
NL80211_FEATURE_USERSPACE_MPM;
if (!ops->hw_scan)
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
NL80211_FEATURE_AP_SCAN;
if (!ops->set_key)
wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
wiphy->bss_priv_size = sizeof(struct ieee80211_bss);
local = wiphy_priv(wiphy);
local->hw.wiphy = wiphy;
local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
local->ops = ops;
local->use_chanctx = use_chanctx;
/* set up some defaults */
local->hw.queues = 1;
local->hw.max_rates = 1;
local->hw.max_report_rates = 0;
local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
local->hw.max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
local->hw.offchannel_tx_hw_queue = IEEE80211_INVAL_HW_QUEUE;
local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
IEEE80211_RADIOTAP_MCS_HAVE_GI |
IEEE80211_RADIOTAP_MCS_HAVE_BW;
local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI |
IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
local->hw.uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
local->hw.uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask;
INIT_LIST_HEAD(&local->interfaces);
__hw_addr_init(&local->mc_list);
mutex_init(&local->iflist_mtx);
mutex_in