mac80211解析一

解析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_init(&local->mtx);

    mutex_init(&local->key_mtx);
    spin_lock_init(&local->filter_lock);
    spin_lock_init(&local->rx_path_lock);
    spin_lock_init(&local->queue_stop_reason_lock);

    INIT_LIST_HEAD(&local->chanctx_list);
    mutex_init(&local->chanctx_mtx);

    INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);

    INIT_WORK(&local->restart_work, ieee80211_restart_work);

    INIT_WORK(&local->radar_detected_work,
          ieee80211_dfs_radar_detected_work);

    INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
    local->smps_mode = IEEE80211_SMPS_OFF;

    INIT_WORK(&local->dynamic_ps_enable_work,
          ieee80211_dynamic_ps_enable_work);
    INIT_WORK(&local->dynamic_ps_disable_work,
          ieee80211_dynamic_ps_disable_work);
    setup_timer(&local->dynamic_ps_timer,
            ieee80211_dynamic_ps_timer, (unsigned long) local);

    INIT_WORK(&local->sched_scan_stopped_work,
          ieee80211_sched_scan_stopped_work);

    spin_lock_init(&local->ack_status_lock);
    idr_init(&local->ack_status_frames);

    sta_info_init(local);

    for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
        skb_queue_head_init(&local->pending[i]);
        atomic_set(&local->agg_queue_stop[i], 0);
    }
    tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
             (unsigned long)local);

    tasklet_init(&local->tasklet,
             ieee80211_tasklet_handler,
             (unsigned long) local);

    skb_queue_head_init(&local->skb_queue);
    skb_queue_head_init(&local->skb_queue_unreliable);

    ieee80211_led_names(local);

    ieee80211_roc_setup(local);

    return &local->hw;
}

ieee80211_register_hw中注册wiphy,初始化速率控制,并建立了无线网络的设备接口:

int ieee80211_register_hw(struct ieee80211_hw *hw)
{
    struct ieee80211_local *local = hw_to_local(hw);
    int result, i;
    enum ieee80211_band band;
    int channels, max_bitrates;
    bool supp_ht, supp_vht;
    netdev_features_t feature_whitelist;
    struct cfg80211_chan_def dflt_chandef = {};

    if (hw->flags & IEEE80211_HW_QUEUE_CONTROL &&
        (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE ||
         local->hw.offchannel_tx_hw_queue >= local->hw.queues))
        return -EINVAL;

#ifdef CONFIG_PM
    if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume))
        return -EINVAL;
#endif

    if (!local->use_chanctx) {
        for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
            const struct ieee80211_iface_combination *comb;

            comb = &local->hw.wiphy->iface_combinations[i];

            if (comb->num_different_channels > 1)
                return -EINVAL;
        }
    } else {
        /*
         * WDS is currently prohibited when channel contexts are used
         * because there's no clear definition of which channel WDS
         * type interfaces use
         */
        if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))
            return -EINVAL;

        /* DFS currently not supported with channel context drivers */
        for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
            const struct ieee80211_iface_combination *comb;

            comb = &local->hw.wiphy->iface_combinations[i];

            if (comb->radar_detect_widths)
                return -EINVAL;
        }
    }

    /* Only HW csum features are currently compatible with mac80211 */
    feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                NETIF_F_HW_CSUM;
    if (WARN_ON(hw->netdev_features & ~feature_whitelist))
        return -EINVAL;

    if (hw->max_report_rates == 0)
        hw->max_report_rates = hw->max_rates;

    local->rx_chains = 1;

    /*
     * generic code guarantees at least one band,
     * set this very early because much code assumes
     * that hw.conf.channel is assigned
     */
    channels = 0;
    max_bitrates = 0;
    supp_ht = false;
    supp_vht = false;
    for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
        struct ieee80211_supported_band *sband;

        sband = local->hw.wiphy->bands[band];
        if (!sband)
            continue;

        if (!dflt_chandef.chan) {
            cfg80211_chandef_create(&dflt_chandef,
                        &sband->channels[0],
                        NL80211_CHAN_NO_HT);
            /* init channel we're on */
            if (!local->use_chanctx && !local->_oper_chandef.chan) {
                local->hw.conf.chandef = dflt_chandef;
                local->_oper_chandef = dflt_chandef;
            }
            local->monitor_chandef = dflt_chandef;
        }

        channels += sband->n_channels;

        if (max_bitrates < sband->n_bitrates)
            max_bitrates = sband->n_bitrates;
        supp_ht = supp_ht || sband->ht_cap.ht_supported;
        supp_vht = supp_vht || sband->vht_cap.vht_supported;

        if (sband->ht_cap.ht_supported)
            local->rx_chains =
                max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs),
                    local->rx_chains);

        /* TODO: consider VHT for RX chains, hopefully it's the same */
    }

    /* if low-level driver supports AP, we also support VLAN */
    if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
        hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
        hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
    }

    /* mac80211 always supports monitor */
    hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
    hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);

    /* mac80211 doesn't support more than one IBSS interface right now */
    for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
        const struct ieee80211_iface_combination *c;
        int j;

        c = &hw->wiphy->iface_combinations[i];

        for (j = 0; j < c->n_limits; j++)
            if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
                c->limits[j].max > 1)
                return -EINVAL;
    }

    local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
                      sizeof(void *) * channels, GFP_KERNEL);
    if (!local->int_scan_req)
        return -ENOMEM;

    for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
        if (!local->hw.wiphy->bands[band])
            continue;
        local->int_scan_req->rates[band] = (u32) -1;
    }

#ifndef CPTCFG_MAC80211_MESH
    /* mesh depends on Kconfig, but drivers should set it if they want */
    local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
#endif

    /* if the underlying driver supports mesh, mac80211 will (at least)
     * provide routing of mesh authentication frames to userspace */
    if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT))
        local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH;

    /* mac80211 supports control port protocol changing */
    local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;

    if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
        local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
    } else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
        local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
        if (hw->max_signal <= 0) {
            result = -EINVAL;
            goto fail_wiphy_register;
        }
    }

    WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
         && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK),
         "U-APSD not supported with HW_PS_NULLFUNC_STACK\n");

    /*
     * Calculate scan IE length -- we need this to alloc
     * memory and to subtract from the driver limit. It
     * includes the DS Params, (extended) supported rates, and HT
     * information -- SSID is the driver's responsibility.
     */
    local->scan_ies_len = 4 + max_bitrates /* (ext) supp rates */ +
        3 /* DS Params */;
    if (supp_ht)
        local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap);

    if (supp_vht)
        local->scan_ies_len +=
            2 + sizeof(struct ieee80211_vht_cap);

    if (!local->ops->hw_scan) {
        /* For hw_scan, driver needs to set these up. */
        local->hw.wiphy->max_scan_ssids = 4;
        local->hw.wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
    }

    /*
     * If the driver supports any scan IEs, then assume the
     * limit includes the IEs mac80211 will add, otherwise
     * leave it at zero and let the driver sort it out; we
     * still pass our IEs to the driver but userspace will
     * not be allowed to in that case.
     */
    if (local->hw.wiphy->max_scan_ie_len)
        local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;

    WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes,
                     local->hw.n_cipher_schemes));

    result = ieee80211_init_cipher_suites(local);
    if (result < 0)
        goto fail_wiphy_register;

    if (!local->ops->remain_on_channel)
        local->hw.wiphy->max_remain_on_channel_duration = 5000;

    /* mac80211 based drivers don't support internal TDLS setup */
    if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
        local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;

    local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;

    result = wiphy_register(local->hw.wiphy);//注册wiphy
    if (result < 0)
        goto fail_wiphy_register;

    /*
     * We use the number of queues for feature tests (QoS, HT) internally
     * so restrict them appropriately.
     */
    if (hw->queues > IEEE80211_MAX_QUEUES)
        hw->queues = IEEE80211_MAX_QUEUES;

    local->workqueue =
        alloc_ordered_workqueue("%s", 0, wiphy_name(local->hw.wiphy));
    if (!local->workqueue) {
        result = -ENOMEM;
        goto fail_workqueue;
    }

    /*
     * The hardware needs headroom for sending the frame,
     * and we need some headroom for passing the frame to monitor
     * interfaces, but never both at the same time.
     */
    local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom,
                   IEEE80211_TX_STATUS_HEADROOM);

    debugfs_hw_add(local);

    /*
     * if the driver doesn't specify a max listen interval we
     * use 5 which should be a safe default
     */
    if (local->hw.max_listen_interval == 0)
        local->hw.max_listen_interval = 5;

    local->hw.conf.listen_interval = local->hw.max_listen_interval;

    local->dynamic_ps_forced_timeout = -1;

    result = ieee80211_wep_init(local);//初始化wep
    if (result < 0)
        wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
                result);

    local->hw.conf.flags = IEEE80211_CONF_IDLE;

    ieee80211_led_init(local);

    rtnl_lock();

    result = ieee80211_init_rate_ctrl_alg(local,
                          hw->rate_control_algorithm);//初始化速率控制算法
    if (result < 0) {
        wiphy_debug(local->hw.wiphy,
                "Failed to initialize rate control algorithm\n");
        goto fail_rate;
    }

    /* add one default STA interface if supported */
    if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) {
        result = ieee80211_if_add(local, "wlan%d", NULL,
                      NL80211_IFTYPE_STATION, NULL);
        if (result)
            wiphy_warn(local->hw.wiphy,
                   "Failed to add default virtual iface\n");
    }

    rtnl_unlock();

    local->network_latency_notifier.notifier_call =
        ieee80211_max_network_latency;
    result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
                     &local->network_latency_notifier);
    if (result) {
        rtnl_lock();
        goto fail_pm_qos;
    }

#ifdef CONFIG_INET
    local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
    result = register_inetaddr_notifier(&local->ifa_notifier);
    if (result)
        goto fail_ifa;
#endif

#if IS_ENABLED(CONFIG_IPV6)
    local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
    result = register_inet6addr_notifier(&local->ifa6_notifier);
    if (result)
        goto fail_ifa6;
#endif

    return 0;

#if IS_ENABLED(CONFIG_IPV6)
 fail_ifa6:
#ifdef CONFIG_INET
    unregister_inetaddr_notifier(&local->ifa_notifier);
#endif
#endif
#if defined(CONFIG_INET) || defined(CONFIG_IPV6)
 fail_ifa:
    pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
                   &local->network_latency_notifier);
    rtnl_lock();
#endif
 fail_pm_qos:
    ieee80211_led_exit(local);
    ieee80211_remove_interfaces(local);
 fail_rate:
    rtnl_unlock();
    ieee80211_wep_free(local);
    sta_info_stop(local);
    destroy_workqueue(local->workqueue);
 fail_workqueue:
    wiphy_unregister(local->hw.wiphy);
 fail_wiphy_register:
    if (local->wiphy_ciphers_allocated)
        kfree(local->hw.wiphy->cipher_suites);
    kfree(local->int_scan_req);
    return result;
}

其中主要结构体是 ieee80211 localieee80211 hw,这两个结构体定义如下:


/**
 * struct ieee80211_hw - hardware information and state
 *
 * This structure contains the configuration and hardware
 * information for an 802.11 PHY.
 */
struct ieee80211_hw {
    struct ieee80211_conf conf;
    struct wiphy *wiphy;//指向为802.11 PHY分配wiphy
    const char *rate_control_algorithm; //硬件的速率控制算法
    void *priv;//指向设备驱动分配的私有数据结构体
    u32 flags; //enum ieee80211_hw_flags
    unsigned int extra_tx_headroom;
    unsigned int extra_beacon_tailroom;
    int vif_data_size;
    int sta_data_size;
    int chanctx_data_size;
    u16 queues;
    u16 max_listen_interval;
    s8 max_signal;
    u8 max_rates;
    u8 max_report_rates;
    u8 max_rate_tries;
    u8 max_rx_aggregation_subframes;
    u8 max_tx_aggregation_subframes;
    u8 offchannel_tx_hw_queue;
    u8 radiotap_mcs_details;
    u16 radiotap_vht_details;
    netdev_features_t netdev_features;
    u8 uapsd_queues;
    u8 uapsd_max_sp_len;
    u8 n_cipher_schemes;
    const struct ieee80211_cipher_scheme *cipher_schemes;
};

ieee80211 local 结构体:


struct ieee80211_local {
    /* embed the driver visible part.
     * don't cast (use the static inlines below), but we keep
     * it first anyway so they become a no-op */
    struct ieee80211_hw hw;

    const struct ieee80211_ops *ops;

    /*
     * private workqueue to mac80211. mac80211 makes this accessible
     * via ieee80211_queue_work()
     */
    struct workqueue_struct *workqueue;

    unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
    /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
    spinlock_t queue_stop_reason_lock;

    int open_count;
    int monitors, cooked_mntrs;
    /* number of interfaces with corresponding FIF_ flags */
    int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
        fif_probe_req;
    int probe_req_reg;
    unsigned int filter_flags; /* FIF_* */

    bool wiphy_ciphers_allocated;

    bool use_chanctx;

    /* protects the aggregated multicast list and filter calls */
    spinlock_t filter_lock;

    /* used for uploading changed mc list */
    struct work_struct reconfig_filter;

    /* aggregated multicast list */
    struct netdev_hw_addr_list mc_list;

    bool tim_in_locked_section; /* see ieee80211_beacon_get() */

    /*
     * suspended is true if we finished all the suspend _and_ we have
     * not yet come up from resume. This is to be used by mac80211
     * to ensure driver sanity during suspend and mac80211's own
     * sanity. It can eventually be used for WoW as well.
     */
    bool suspended;

    /*
     * Resuming is true while suspended, but when we're reprogramming the
     * hardware -- at that time it's allowed to use ieee80211_queue_work()
     * again even though some other parts of the stack are still suspended
     * and we still drop received frames to avoid waking the stack.
     */
    bool resuming;

    /*
     * quiescing is true during the suspend process _only_ to
     * ease timer cancelling etc.
     */
    bool quiescing;

    /* device is started */
    bool started;

    /* device is during a HW reconfig */
    bool in_reconfig;

    /* wowlan is enabled -- don't reconfig on resume */
    bool wowlan;

    /* DFS/radar detection is enabled */
    bool radar_detect_enabled;
    struct work_struct radar_detected_work;

    /* number of RX chains the hardware has */
    u8 rx_chains;

    int tx_headroom; /* required headroom for hardware/radiotap */

    /* Tasklet and skb queue to process calls from IRQ mode. All frames
     * added to skb_queue will be processed, but frames in
     * skb_queue_unreliable may be dropped if the total length of these
     * queues increases over the limit. */
#define IEEE80211_IRQSAFE_QUEUE_LIMIT 128
    struct tasklet_struct tasklet;
    struct sk_buff_head skb_queue;
    struct sk_buff_head skb_queue_unreliable;

    spinlock_t rx_path_lock;

    /* Station data */
    /*
     * The mutex only protects the list, hash table and
     * counter, reads are done with RCU.
     */
    struct mutex sta_mtx;
    spinlock_t tim_lock;
    unsigned long num_sta;
    struct list_head sta_list;
    struct sta_info __rcu *sta_hash[STA_HASH_SIZE];
    struct timer_list sta_cleanup;
    int sta_generation;

    /*
     * Tx latency statistics parameters for all stations.
     * Can enable via debugfs (NULL when disabled).
     */
    struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency;

    struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
    struct tasklet_struct tx_pending_tasklet;

    atomic_t agg_queue_stop[IEEE80211_MAX_QUEUES];

    /* number of interfaces with corresponding IFF_ flags */
    atomic_t iff_allmultis, iff_promiscs;

    struct rate_control_ref *rate_ctrl;

    struct crypto_cipher *wep_tx_tfm;
    struct crypto_cipher *wep_rx_tfm;
    u32 wep_iv;

    /* see iface.c */
    struct list_head interfaces;
    struct mutex iflist_mtx;

    /*
     * Key mutex, protects sdata's key_list and sta_info's
     * key pointers (write access, they're RCU.)
     */
    struct mutex key_mtx;

    /* mutex for scan and work locking */
    struct mutex mtx;

    /* Scanning and BSS list */
    unsigned long scanning;
    struct cfg80211_ssid scan_ssid;
    struct cfg80211_scan_request *int_scan_req;
    struct cfg80211_scan_request *scan_req, *hw_scan_req;
    struct cfg80211_chan_def scan_chandef;
    enum ieee80211_band hw_scan_band;
    int scan_channel_idx;
    int scan_ies_len;
    int hw_scan_ies_bufsize;

    struct work_struct sched_scan_stopped_work;
    struct ieee80211_sub_if_data __rcu *sched_scan_sdata;
    struct cfg80211_sched_scan_request *sched_scan_req;

    unsigned long leave_oper_channel_time;
    enum mac80211_scan_state next_scan_state;
    struct delayed_work scan_work;
    struct ieee80211_sub_if_data __rcu *scan_sdata;
    /* For backward compatibility only -- do not use */
    struct cfg80211_chan_def _oper_chandef;

    /* Temporary remain-on-channel for off-channel operations */
    struct ieee80211_channel *tmp_channel;

    /* channel contexts */
    struct list_head chanctx_list;
    struct mutex chanctx_mtx;

    /* SNMP counters */
    /* dot11CountersTable */
    u32 dot11TransmittedFragmentCount;
    u32 dot11MulticastTransmittedFrameCount;
    u32 dot11FailedCount;
    u32 dot11RetryCount;
    u32 dot11MultipleRetryCount;
    u32 dot11FrameDuplicateCount;
    u32 dot11ReceivedFragmentCount;
    u32 dot11MulticastReceivedFrameCount;
    u32 dot11TransmittedFrameCount;

#ifdef CPTCFG_MAC80211_LEDS
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
    int tx_led_counter, rx_led_counter;
#endif
    struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led;
    struct tpt_led_trigger *tpt_led_trigger;
    char tx_led_name[32], rx_led_name[32],
         assoc_led_name[32], radio_led_name[32];
#endif

#ifdef CPTCFG_MAC80211_DEBUG_COUNTERS
    /* TX/RX handler statistics */
    unsigned int tx_handlers_drop;
    unsigned int tx_handlers_queued;
    unsigned int tx_handlers_drop_unencrypted;
    unsigned int tx_handlers_drop_fragment;
    unsigned int tx_handlers_drop_wep;
    unsigned int tx_handlers_drop_not_assoc;
    unsigned int tx_handlers_drop_unauth_port;
    unsigned int rx_handlers_drop;
    unsigned int rx_handlers_queued;
    unsigned int rx_handlers_drop_nullfunc;
    unsigned int rx_handlers_drop_defrag;
    unsigned int rx_handlers_drop_short;
    unsigned int tx_expand_skb_head;
    unsigned int tx_expand_skb_head_cloned;
    unsigned int rx_expand_skb_head;
    unsigned int rx_expand_skb_head2;
    unsigned int rx_handlers_fragments;
    unsigned int tx_status_drop;
#define I802_DEBUG_INC(c) (c)++
#else /* CPTCFG_MAC80211_DEBUG_COUNTERS */
#define I802_DEBUG_INC(c) do { } while (0)
#endif /* CPTCFG_MAC80211_DEBUG_COUNTERS */


    int total_ps_buffered; /* total number of all buffered unicast and
                * multicast packets for power saving stations
                */

    bool pspolling;
    bool offchannel_ps_enabled;
    /*
     * PS can only be enabled when we have exactly one managed
     * interface (and monitors) in PS, this then points there.
     */
    struct ieee80211_sub_if_data *ps_sdata;
    struct work_struct dynamic_ps_enable_work;
    struct work_struct dynamic_ps_disable_work;
    struct timer_list dynamic_ps_timer;
    struct notifier_block network_latency_notifier;
    struct notifier_block ifa_notifier;
    struct notifier_block ifa6_notifier;

    /*
     * The dynamic ps timeout configured from user space via WEXT -
     * this will override whatever chosen by mac80211 internally.
     */
    int dynamic_ps_forced_timeout;

    int user_power_level; /* in dBm, for all interfaces */

    enum ieee80211_smps_mode smps_mode;

    struct work_struct restart_work;

#ifdef CPTCFG_MAC80211_DEBUGFS
    struct local_debugfsdentries {
        struct dentry *rcdir;
        struct dentry *keys;
    } debugfs;
#endif

    /*
     * Remain-on-channel support
     */
    struct list_head roc_list;
    struct work_struct hw_roc_start, hw_roc_done;
    unsigned long hw_roc_start_time;
    u64 roc_cookie_counter;

    struct idr ack_status_frames;
    spinlock_t ack_status_lock;

    struct ieee80211_sub_if_data __rcu *p2p_sdata;

    struct napi_struct *napi;

    /* virtual monitor interface */
    struct ieee80211_sub_if_data __rcu *monitor_sdata;
    struct cfg80211_chan_def monitor_chandef;
};

mac80211是kernel的一个模块,则该模块也要进行模块初始化和卸载,初始化mac80211模块如下:


static int __init ieee80211_init(void)
{
    struct sk_buff *skb;
    int ret;

    BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb));
    BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
             IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));

    ret = rc80211_minstrel_init(); //初始化minstrel速率调整算法
    if (ret)
        return ret;

    ret = rc80211_minstrel_ht_init();
    if (ret)
        goto err_minstrel;

    ret = rc80211_pid_init();  //pid速率调整算法
    if (ret)
        goto err_pid;

    ret = ieee80211_iface_init(); //初始化网络接口,这里只实现了网络设备通知链的注册
    if (ret)
        goto err_netdev;

    return 0;
 err_netdev:
    rc80211_pid_exit();
 err_pid:
    rc80211_minstrel_ht_exit();
 err_minstrel:
    rc80211_minstrel_exit();

    return ret;
}

在三种算法中进行选择,这里探查minstrel_ht 算法,即rc80211_minstrel_ht_init

int __init
rc80211_minstrel_ht_init(void)
{
    init_sample_table();
    return ieee80211_rate_control_register(&mac80211_minstrel_ht);
}

init_sample_table 初始化探测速率表,minstrel对速率的管理是通过速率组来管理,sample_table是随机生成的一个速率表:

static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;  

ieee80211_rate_control_register 实现速率控制注册

int ieee80211_rate_control_register(const struct rate_control_ops *ops)
{
    struct rate_control_alg *alg;

    if (!ops->name)
        return -EINVAL;

    mutex_lock(&rate_ctrl_mutex);
    list_for_each_entry(alg, &rate_ctrl_algs, list) {
        if (!strcmp(alg->ops->name, ops->name)) {
            /* don't register an algorithm twice */
            WARN_ON(1);
            mutex_unlock(&rate_ctrl_mutex);
            return -EALREADY;
        }
    }

    alg = kzalloc(sizeof(*alg), GFP_KERNEL);
    if (alg == NULL) {
        mutex_unlock(&rate_ctrl_mutex);
        return -ENOMEM;
    }
    alg->ops = ops;

    list_add_tail(&alg->list, &rate_ctrl_algs);
    mutex_unlock(&rate_ctrl_mutex);

    return 0;
}

mac80211_minstrel_ht 结构体定义了速率控制操作结构体rate_control_ops ,实现了速率控制操作:


static const struct rate_control_ops mac80211_minstrel_ht = {
    .name = "minstrel_ht",
    .tx_status = 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,
    .remove_sta_debugfs = minstrel_ht_remove_sta_debugfs,
#endif
    .get_expected_throughput = minstrel_ht_get_expected_throughput,
};

你可能感兴趣的:(Linux,kernel,无线网络,linux网络,linux设备驱动,mac80211解析)