mac80211解析一

来源:互联网 发布:淘宝网抓绒女式外套 编辑:程序博客网 时间:2024/06/05 03:04

解析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 __initrc80211_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,};
1 0
原创粉丝点击