mac80211解析二

来源:互联网 发布:政务电子地图数据规范 编辑:程序博客网 时间:2024/06/09 17:08

在实现无线网络设备分配时,ieee80211_register_hw关联了ieee80211_ops结构体:

ieee80211_ops结构体是mac80211到设备驱动的回调操作函数集合,定义如下:

/** * struct ieee80211_ops - callbacks from mac80211 to the driver * * This structure contains various callbacks that the driver may * handle or, in some cases, must handle, for example to configure * the hardware to a new channel or to transmit a frame. */struct ieee80211_ops {    void (*tx)(struct ieee80211_hw *hw,           struct ieee80211_tx_control *control,           struct sk_buff *skb);    int (*start)(struct ieee80211_hw *hw);    void (*stop)(struct ieee80211_hw *hw);#ifdef CONFIG_PM    int (*suspend)(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);    int (*resume)(struct ieee80211_hw *hw);    void (*set_wakeup)(struct ieee80211_hw *hw, bool enabled);#endif    int (*add_interface)(struct ieee80211_hw *hw,                 struct ieee80211_vif *vif);    int (*change_interface)(struct ieee80211_hw *hw,                struct ieee80211_vif *vif,                enum nl80211_iftype new_type, bool p2p);    void (*remove_interface)(struct ieee80211_hw *hw,                 struct ieee80211_vif *vif);    int (*config)(struct ieee80211_hw *hw, u32 changed);    void (*bss_info_changed)(struct ieee80211_hw *hw,                 struct ieee80211_vif *vif,                 struct ieee80211_bss_conf *info,                 u32 changed);    int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);    void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);    u64 (*prepare_multicast)(struct ieee80211_hw *hw,                 struct netdev_hw_addr_list *mc_list);    void (*configure_filter)(struct ieee80211_hw *hw,                 unsigned int changed_flags,                 unsigned int *total_flags,                 u64 multicast);    int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,               bool set);    int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,               struct ieee80211_vif *vif, struct ieee80211_sta *sta,               struct ieee80211_key_conf *key);    void (*update_tkip_key)(struct ieee80211_hw *hw,                struct ieee80211_vif *vif,                struct ieee80211_key_conf *conf,                struct ieee80211_sta *sta,                u32 iv32, u16 *phase1key);    void (*set_rekey_data)(struct ieee80211_hw *hw,                   struct ieee80211_vif *vif,                   struct cfg80211_gtk_rekey_data *data);    void (*set_default_unicast_key)(struct ieee80211_hw *hw,                    struct ieee80211_vif *vif, int idx);    int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,               struct cfg80211_scan_request *req);    void (*cancel_hw_scan)(struct ieee80211_hw *hw,                   struct ieee80211_vif *vif);    int (*sched_scan_start)(struct ieee80211_hw *hw,                struct ieee80211_vif *vif,                struct cfg80211_sched_scan_request *req,                struct ieee80211_sched_scan_ies *ies);    int (*sched_scan_stop)(struct ieee80211_hw *hw,                   struct ieee80211_vif *vif);    void (*sw_scan_start)(struct ieee80211_hw *hw);    void (*sw_scan_complete)(struct ieee80211_hw *hw);    int (*get_stats)(struct ieee80211_hw *hw,             struct ieee80211_low_level_stats *stats);    void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,                 u32 *iv32, u16 *iv16);    int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);    int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);    int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,               struct ieee80211_sta *sta);    int (*sta_remove)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,              struct ieee80211_sta *sta);#ifdef CPTCFG_MAC80211_DEBUGFS    void (*sta_add_debugfs)(struct ieee80211_hw *hw,                struct ieee80211_vif *vif,                struct ieee80211_sta *sta,                struct dentry *dir);    void (*sta_remove_debugfs)(struct ieee80211_hw *hw,                   struct ieee80211_vif *vif,                   struct ieee80211_sta *sta,                   struct dentry *dir);#endif    void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,            enum sta_notify_cmd, struct ieee80211_sta *sta);    int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,             struct ieee80211_sta *sta,             enum ieee80211_sta_state old_state,             enum ieee80211_sta_state new_state);    void (*sta_pre_rcu_remove)(struct ieee80211_hw *hw,                   struct ieee80211_vif *vif,                   struct ieee80211_sta *sta);    void (*sta_rc_update)(struct ieee80211_hw *hw,                  struct ieee80211_vif *vif,                  struct ieee80211_sta *sta,                  u32 changed);    int (*conf_tx)(struct ieee80211_hw *hw,               struct ieee80211_vif *vif, u16 ac,               const struct ieee80211_tx_queue_params *params);    u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);    void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,            u64 tsf);    void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);    int (*tx_last_beacon)(struct ieee80211_hw *hw);    int (*ampdu_action)(struct ieee80211_hw *hw,                struct ieee80211_vif *vif,                enum ieee80211_ampdu_mlme_action action,                struct ieee80211_sta *sta, u16 tid, u16 *ssn,                u8 buf_size);    int (*get_survey)(struct ieee80211_hw *hw, int idx,        struct survey_info *survey);    void (*rfkill_poll)(struct ieee80211_hw *hw);    void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class);#ifdef CPTCFG_NL80211_TESTMODE    int (*testmode_cmd)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,                void *data, int len);    int (*testmode_dump)(struct ieee80211_hw *hw, struct sk_buff *skb,                 struct netlink_callback *cb,                 void *data, int len);#endif    void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,              u32 queues, bool drop);    void (*channel_switch)(struct ieee80211_hw *hw,                   struct ieee80211_channel_switch *ch_switch);    int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);    int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);    int (*remain_on_channel)(struct ieee80211_hw *hw,                 struct ieee80211_vif *vif,                 struct ieee80211_channel *chan,                 int duration,                 enum ieee80211_roc_type type);    int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);    int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);    void (*get_ringparam)(struct ieee80211_hw *hw,                  u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);    bool (*tx_frames_pending)(struct ieee80211_hw *hw);    int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,                const struct cfg80211_bitrate_mask *mask);    void (*rssi_callback)(struct ieee80211_hw *hw,                  struct ieee80211_vif *vif,                  enum ieee80211_rssi_event rssi_event);    void (*allow_buffered_frames)(struct ieee80211_hw *hw,                      struct ieee80211_sta *sta,                      u16 tids, int num_frames,                      enum ieee80211_frame_release_type reason,                      bool more_data);    void (*release_buffered_frames)(struct ieee80211_hw *hw,                    struct ieee80211_sta *sta,                    u16 tids, int num_frames,                    enum ieee80211_frame_release_type reason,                    bool more_data);    int (*get_et_sset_count)(struct ieee80211_hw *hw,                     struct ieee80211_vif *vif, int sset);    void    (*get_et_stats)(struct ieee80211_hw *hw,                struct ieee80211_vif *vif,                struct ethtool_stats *stats, u64 *data);    void    (*get_et_strings)(struct ieee80211_hw *hw,                  struct ieee80211_vif *vif,                  u32 sset, u8 *data);    int (*get_rssi)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,                struct ieee80211_sta *sta, s8 *rssi_dbm);    void    (*mgd_prepare_tx)(struct ieee80211_hw *hw,                  struct ieee80211_vif *vif);    int (*add_chanctx)(struct ieee80211_hw *hw,               struct ieee80211_chanctx_conf *ctx);    void (*remove_chanctx)(struct ieee80211_hw *hw,                   struct ieee80211_chanctx_conf *ctx);    void (*change_chanctx)(struct ieee80211_hw *hw,                   struct ieee80211_chanctx_conf *ctx,                   u32 changed);    int (*assign_vif_chanctx)(struct ieee80211_hw *hw,                  struct ieee80211_vif *vif,                  struct ieee80211_chanctx_conf *ctx);    void (*unassign_vif_chanctx)(struct ieee80211_hw *hw,                     struct ieee80211_vif *vif,                     struct ieee80211_chanctx_conf *ctx);    void (*restart_complete)(struct ieee80211_hw *hw);#if IS_ENABLED(CONFIG_IPV6)    void (*ipv6_addr_change)(struct ieee80211_hw *hw,                 struct ieee80211_vif *vif,                 struct inet6_dev *idev);#endif    void (*channel_switch_beacon)(struct ieee80211_hw *hw,                      struct ieee80211_vif *vif,                      struct cfg80211_chan_def *chandef);    int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);    void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);    u32 (*get_expected_throughput)(struct ieee80211_sta *sta);};

这里写图片描述

ieee80211_register_hw 中初始化了tasklet的响应中断,如下,

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

其中中断函数ieee80211_tasklet_handler 实现网络数据的中断接收。

static void ieee80211_tasklet_handler(unsigned long data){    struct ieee80211_local *local = (struct ieee80211_local *) data;    struct sk_buff *skb;    while ((skb = skb_dequeue(&local->skb_queue)) ||           (skb = skb_dequeue(&local->skb_queue_unreliable))) {        switch (skb->pkt_type) {        case IEEE80211_RX_MSG:            /* Clear skb->pkt_type in order to not confuse kernel             * netstack. */            skb->pkt_type = 0;            ieee80211_rx(&local->hw, skb);            break;        case IEEE80211_TX_STATUS_MSG:            skb->pkt_type = 0;            ieee80211_tx_status(&local->hw, skb);            break;        default:            WARN(1, "mac80211: Packet is of unknown type %d\n",                 skb->pkt_type);            dev_kfree_skb(skb);            break;        }    }}

经过数据包的类型判断后,调用ieee80211_rx 函数进行数据接收,

/* * This is the receive path handler. It is called by a low level driver when an * 802.11 MPDU is received from the hardware. */void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb){    struct ieee80211_local *local = hw_to_local(hw);    struct ieee80211_rate *rate = NULL;    struct ieee80211_supported_band *sband;    struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);    WARN_ON_ONCE(softirq_count() == 0);    if (WARN_ON(status->band >= IEEE80211_NUM_BANDS))        goto drop;    sband = local->hw.wiphy->bands[status->band];    if (WARN_ON(!sband))        goto drop;    /*     * If we're suspending, it is possible although not too likely     * that we'd be receiving frames after having already partially     * quiesced the stack. We can't process such frames then since     * that might, for example, cause stations to be added or other     * driver callbacks be invoked.     */    if (unlikely(local->quiescing || local->suspended))        goto drop;    /* We might be during a HW reconfig, prevent Rx for the same reason */    if (unlikely(local->in_reconfig))        goto drop;    /*     * The same happens when we're not even started,     * but that's worth a warning.     */    if (WARN_ON(!local->started))        goto drop;    if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) {        /*         * Validate the rate, unless a PLCP error means that         * we probably can't have a valid rate here anyway.         */        if (status->flag & RX_FLAG_HT) {            /*             * rate_idx is MCS index, which can be [0-76]             * as documented on:             *             * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n             *             * Anything else would be some sort of driver or             * hardware error. The driver should catch hardware             * errors.             */            if (WARN(status->rate_idx > 76,                 "Rate marked as an HT rate but passed "                 "status->rate_idx is not "                 "an MCS index [0-76]: %d (0x%02x)\n",                 status->rate_idx,                 status->rate_idx))                goto drop;        } else if (status->flag & RX_FLAG_VHT) {            if (WARN_ONCE(status->rate_idx > 9 ||                      !status->vht_nss ||                      status->vht_nss > 8,                      "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n",                      status->rate_idx, status->vht_nss))                goto drop;        } else {            if (WARN_ON(status->rate_idx >= sband->n_bitrates))                goto drop;            rate = &sband->bitrates[status->rate_idx];        }    }    status->rx_flags = 0;    /*     * key references and virtual interfaces are protected using RCU     * and this requires that we are in a read-side RCU section during     * receive processing     */    rcu_read_lock();    /*     * Frames with failed FCS/PLCP checksum are not returned,     * all other frames are returned without radiotap header     * if it was previously present.     * Also, frames with less than 16 bytes are dropped.     */    skb = ieee80211_rx_monitor(local, skb, rate);    if (!skb) {        rcu_read_unlock();        return;    }    ieee80211_tpt_led_trig_rx(local,            ((struct ieee80211_hdr *)skb->data)->frame_control,            skb->len);    __ieee80211_rx_handle_packet(hw, skb);    rcu_read_unlock();    return; drop:    kfree_skb(skb);}

ieee80211_rx()函数中调用ieee80211_rx_monitor()拷贝帧传递给所有监听接口

/* * This function copies a received frame to all monitor interfaces and * returns a cleaned-up SKB that no longer includes the FCS nor the * radiotap header the driver might have added. */static struct sk_buff *ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,             struct ieee80211_rate *rate){    struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);    struct ieee80211_sub_if_data *sdata;    int needed_headroom;    struct sk_buff *skb, *skb2;    struct net_device *prev_dev = NULL;    int present_fcs_len = 0;    /*     * First, we may need to make a copy of the skb because     *  (1) we need to modify it for radiotap (if not present), and     *  (2) the other RX handlers will modify the skb we got.     *     * We don't need to, of course, if we aren't going to return     * the SKB because it has a bad FCS/PLCP checksum.     */    if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)        present_fcs_len = FCS_LEN;    /* ensure hdr->frame_control is in skb head */    if (!pskb_may_pull(origskb, 2)) {        dev_kfree_skb(origskb);        return NULL;    }    if (!local->monitors) {        if (should_drop_frame(origskb, present_fcs_len)) {            dev_kfree_skb(origskb);            return NULL;        }        return remove_monitor_info(local, origskb);    }    /* room for the radiotap header based on driver features */    needed_headroom = ieee80211_rx_radiotap_space(local, status);    if (should_drop_frame(origskb, present_fcs_len)) {        /* only need to expand headroom if necessary */        skb = origskb;        origskb = NULL;        /*         * This shouldn't trigger often because most devices have an         * RX header they pull before we get here, and that should         * be big enough for our radiotap information. We should         * probably export the length to drivers so that we can have         * them allocate enough headroom to start with.         */        if (skb_headroom(skb) < needed_headroom &&            pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) {            dev_kfree_skb(skb);            return NULL;        }    } else {        /*         * Need to make a copy and possibly remove radiotap header         * and FCS from the original.         */        skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC);        origskb = remove_monitor_info(local, origskb);        if (!skb)            return origskb;    }    /* prepend radiotap information */    ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom,                     true);    skb_reset_mac_header(skb);    skb->ip_summed = CHECKSUM_UNNECESSARY;    skb->pkt_type = PACKET_OTHERHOST;    skb->protocol = htons(ETH_P_802_2);    list_for_each_entry_rcu(sdata, &local->interfaces, list) {        if (sdata->vif.type != NL80211_IFTYPE_MONITOR)            continue;        if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)            continue;        if (!ieee80211_sdata_running(sdata))            continue;        if (prev_dev) {            skb2 = skb_clone(skb, GFP_ATOMIC);            if (skb2) {                skb2->dev = prev_dev;                netif_receive_skb(skb2);            }        }        prev_dev = sdata->dev;        sdata->dev->stats.rx_packets++;        sdata->dev->stats.rx_bytes += skb->len;    }    if (prev_dev) {        skb->dev = prev_dev;        netif_receive_skb(skb);    } else        dev_kfree_skb(skb);    return origskb;}

ieee80211_rx 在调用__ieee80211_rx_handle_packet进行数据帧操作,

__ieee80211_rx_handle_packet     ---->ieee80211_prepare_and_rx_handle         ---->ieee80211_invoke_rx_handlers            ---->ieee80211_rx_handlers 

经过一些列数据帧的判别,最后在ieee80211_rx_handlers中实现接收处理。

ieee80211_register_hw注册函数中,使用了ieee80211_if_add 函数创建了网络接口,并提供了网络接口操作函数net_device_ops,定义如下:

static const struct net_device_ops ieee80211_dataif_ops = {    .ndo_open       = ieee80211_open,    .ndo_stop       = ieee80211_stop,    .ndo_uninit     = ieee80211_uninit,    .ndo_start_xmit     = ieee80211_subif_start_xmit,    .ndo_set_rx_mode    = ieee80211_set_multicast_list,    .ndo_change_mtu     = ieee80211_change_mtu,    .ndo_set_mac_address    = ieee80211_change_mac,    .ndo_select_queue   = ieee80211_netdev_select_queue,}; 

其中ieee80211_subif_start_xmit 实现了数据的发送,

/** * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type * subinterfaces (wlan#, WDS, and VLAN interfaces) * This function takes in an Ethernet header and encapsulates it with suitable * IEEE 802.11 header based on which interface the packet is coming in. The * encapsulated packet will then be passed to master interface, wlan#.11, for * transmission (through low-level driver). */netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,                    struct net_device *dev){    struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);    struct ieee80211_local *local = sdata->local;    struct ieee80211_tx_info *info;    int head_need;    u16 ethertype, hdrlen,  meshhdrlen = 0;    __le16 fc;    struct ieee80211_hdr hdr;    struct ieee80211s_hdr mesh_hdr __maybe_unused;    struct mesh_path __maybe_unused *mppath = NULL, *mpath = NULL;    const u8 *encaps_data;    int encaps_len, skip_header_bytes;    int nh_pos, h_pos;    struct sta_info *sta = NULL;    bool wme_sta = false, authorized = false, tdls_auth = false;    bool tdls_direct = false;    bool multicast;    u32 info_flags = 0;    u16 info_id = 0;    struct ieee80211_chanctx_conf *chanctx_conf;    struct ieee80211_sub_if_data *ap_sdata;    enum ieee80211_band band;    if (unlikely(skb->len < ETH_HLEN))        goto fail;    /* convert Ethernet header to proper 802.11 header (based on     * operation mode) */    ethertype = (skb->data[12] << 8) | skb->data[13];    fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);    rcu_read_lock();    /* Measure frame arrival for Tx latency statistics calculation */    ieee80211_tx_latency_start_msrmnt(local, skb);    switch (sdata->vif.type) {    case NL80211_IFTYPE_AP_VLAN:        sta = rcu_dereference(sdata->u.vlan.sta);        if (sta) {            fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);            /* RA TA DA SA */            memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN);            memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);            memcpy(hdr.addr3, skb->data, ETH_ALEN);            memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);            hdrlen = 30;            authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);            wme_sta = test_sta_flag(sta, WLAN_STA_WME);        }        ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,                    u.ap);        chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf);        if (!chanctx_conf)            goto fail_rcu;        band = chanctx_conf->def.chan->band;        if (sta)            break;        /* fall through */    case NL80211_IFTYPE_AP:        if (sdata->vif.type == NL80211_IFTYPE_AP)            chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);        if (!chanctx_conf)            goto fail_rcu;        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);        /* DA BSSID SA */        memcpy(hdr.addr1, skb->data, ETH_ALEN);        memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);        memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);        hdrlen = 24;        band = chanctx_conf->def.chan->band;        break;    case NL80211_IFTYPE_WDS:        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);        /* RA TA DA SA */        memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);        memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);        memcpy(hdr.addr3, skb->data, ETH_ALEN);        memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);        hdrlen = 30;        /*         * This is the exception! WDS style interfaces are prohibited         * when channel contexts are in used so this must be valid         */        band = local->hw.conf.chandef.chan->band;        break;#ifdef CPTCFG_MAC80211_MESH    case NL80211_IFTYPE_MESH_POINT:        if (!is_multicast_ether_addr(skb->data)) {            struct sta_info *next_hop;            bool mpp_lookup = true;            mpath = mesh_path_lookup(sdata, skb->data);            if (mpath) {                mpp_lookup = false;                next_hop = rcu_dereference(mpath->next_hop);                if (!next_hop ||                    !(mpath->flags & (MESH_PATH_ACTIVE |                              MESH_PATH_RESOLVING)))                    mpp_lookup = true;            }            if (mpp_lookup)                mppath = mpp_path_lookup(sdata, skb->data);            if (mppath && mpath)                mesh_path_del(mpath->sdata, mpath->dst);        }        /*         * Use address extension if it is a packet from         * another interface or if we know the destination         * is being proxied by a portal (i.e. portal address         * differs from proxied address)         */        if (ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN) &&            !(mppath && !ether_addr_equal(mppath->mpp, skb->data))) {            hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,                    skb->data, skb->data + ETH_ALEN);            meshhdrlen = ieee80211_new_mesh_header(sdata, &mesh_hdr,                                   NULL, NULL);        } else {            /* DS -> MBSS (802.11-2012 13.11.3.3).             * For unicast with unknown forwarding information,             * destination might be in the MBSS or if that fails             * forwarded to another mesh gate. In either case             * resolution will be handled in ieee80211_xmit(), so             * leave the original DA. This also works for mcast */            const u8 *mesh_da = skb->data;            if (mppath)                mesh_da = mppath->mpp;            else if (mpath)                mesh_da = mpath->dst;            hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,                    mesh_da, sdata->vif.addr);            if (is_multicast_ether_addr(mesh_da))                /* DA TA mSA AE:SA */                meshhdrlen = ieee80211_new_mesh_header(                        sdata, &mesh_hdr,                        skb->data + ETH_ALEN, NULL);            else                /* RA TA mDA mSA AE:DA SA */                meshhdrlen = ieee80211_new_mesh_header(                        sdata, &mesh_hdr, skb->data,                        skb->data + ETH_ALEN);        }        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);        if (!chanctx_conf)            goto fail_rcu;        band = chanctx_conf->def.chan->band;        break;#endif    case NL80211_IFTYPE_STATION:        if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {            bool tdls_peer = false;            sta = sta_info_get(sdata, skb->data);            if (sta) {                authorized = test_sta_flag(sta,                            WLAN_STA_AUTHORIZED);                wme_sta = test_sta_flag(sta, WLAN_STA_WME);                tdls_peer = test_sta_flag(sta,                             WLAN_STA_TDLS_PEER);                tdls_auth = test_sta_flag(sta,                        WLAN_STA_TDLS_PEER_AUTH);            }            /*             * If the TDLS link is enabled, send everything             * directly. Otherwise, allow TDLS setup frames             * to be transmitted indirectly.             */            tdls_direct = tdls_peer && (tdls_auth ||                 !(ethertype == ETH_P_TDLS && skb->len > 14 &&                   skb->data[14] == WLAN_TDLS_SNAP_RFTYPE));        }        if (tdls_direct) {            /* link during setup - throw out frames to peer */            if (!tdls_auth)                goto fail_rcu;            /* DA SA BSSID */            memcpy(hdr.addr1, skb->data, ETH_ALEN);            memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);            memcpy(hdr.addr3, sdata->u.mgd.bssid, ETH_ALEN);            hdrlen = 24;        }  else if (sdata->u.mgd.use_4addr &&                cpu_to_be16(ethertype) != sdata->control_port_protocol) {            fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |                      IEEE80211_FCTL_TODS);            /* RA TA DA SA */            memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);            memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);            memcpy(hdr.addr3, skb->data, ETH_ALEN);            memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);            hdrlen = 30;        } else {            fc |= cpu_to_le16(IEEE80211_FCTL_TODS);            /* BSSID SA DA */            memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);            memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);            memcpy(hdr.addr3, skb->data, ETH_ALEN);            hdrlen = 24;        }        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);        if (!chanctx_conf)            goto fail_rcu;        band = chanctx_conf->def.chan->band;        break;    case NL80211_IFTYPE_ADHOC:        /* DA SA BSSID */        memcpy(hdr.addr1, skb->data, ETH_ALEN);        memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);        memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN);        hdrlen = 24;        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);        if (!chanctx_conf)            goto fail_rcu;        band = chanctx_conf->def.chan->band;        break;    default:        goto fail_rcu;    }    /*     * There's no need to try to look up the destination     * if it is a multicast address (which can only happen     * in AP mode)     */    multicast = is_multicast_ether_addr(hdr.addr1);    if (!multicast) {        sta = sta_info_get(sdata, hdr.addr1);        if (sta) {            authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);            wme_sta = test_sta_flag(sta, WLAN_STA_WME);        }    }    /* For mesh, the use of the QoS header is mandatory */    if (ieee80211_vif_is_mesh(&sdata->vif))        wme_sta = true;    /* receiver and we are QoS enabled, use a QoS type frame */    if (wme_sta && local->hw.queues >= IEEE80211_NUM_ACS) {        fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);        hdrlen += 2;    }    /*     * Drop unicast frames to unauthorised stations unless they are     * EAPOL frames from the local station.     */    if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) &&             !multicast && !authorized &&             (cpu_to_be16(ethertype) != sdata->control_port_protocol ||              !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {#ifdef CPTCFG_MAC80211_VERBOSE_DEBUG        net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n",                    dev->name, hdr.addr1);#endif        I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);        goto fail_rcu;    }#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))    if (unlikely(!multicast && skb->sk &&             skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) {        struct sk_buff *orig_skb = skb;        skb = skb_clone(skb, GFP_ATOMIC);        if (skb) {            unsigned long flags;            int id;            spin_lock_irqsave(&local->ack_status_lock, flags);            id = idr_alloc(&local->ack_status_frames, orig_skb,                       1, 0x10000, GFP_ATOMIC);            spin_unlock_irqrestore(&local->ack_status_lock, flags);            if (id >= 0) {                info_id = id;                info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;            } else if (skb_shared(skb)) {                kfree_skb(orig_skb);            } else {                kfree_skb(skb);                skb = orig_skb;            }        } else {            /* couldn't clone -- lose tx status ... */            skb = orig_skb;        }    }#endif    /*     * If the skb is shared we need to obtain our own copy.     */    if (skb_shared(skb)) {        struct sk_buff *tmp_skb = skb;        /* can't happen -- skb is a clone if info_id != 0 */        WARN_ON(info_id);        skb = skb_clone(skb, GFP_ATOMIC);        kfree_skb(tmp_skb);        if (!skb)            goto fail_rcu;    }    hdr.frame_control = fc;    hdr.duration_id = 0;    hdr.seq_ctrl = 0;    skip_header_bytes = ETH_HLEN;    if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {        encaps_data = bridge_tunnel_header;        encaps_len = sizeof(bridge_tunnel_header);        skip_header_bytes -= 2;    } else if (ethertype >= ETH_P_802_3_MIN) {        encaps_data = rfc1042_header;        encaps_len = sizeof(rfc1042_header);        skip_header_bytes -= 2;    } else {        encaps_data = NULL;        encaps_len = 0;    }    nh_pos = skb_network_header(skb) - skb->data;    h_pos = skb_transport_header(skb) - skb->data;    skb_pull(skb, skip_header_bytes);    nh_pos -= skip_header_bytes;    h_pos -= skip_header_bytes;    head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);    /*     * So we need to modify the skb header and hence need a copy of     * that. The head_need variable above doesn't, so far, include     * the needed header space that we don't need right away. If we     * can, then we don't reallocate right now but only after the     * frame arrives at the master device (if it does...)     *     * If we cannot, however, then we will reallocate to include all     * the ever needed space. Also, if we need to reallocate it anyway,     * make it big enough for everything we may ever need.     */    if (head_need > 0 || skb_cloned(skb)) {        head_need += sdata->encrypt_headroom;        head_need += local->tx_headroom;        head_need = max_t(int, 0, head_need);        if (ieee80211_skb_resize(sdata, skb, head_need, true)) {            ieee80211_free_txskb(&local->hw, skb);            skb = NULL;            goto fail_rcu;        }    }    if (encaps_data) {        memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);        nh_pos += encaps_len;        h_pos += encaps_len;    }#ifdef CPTCFG_MAC80211_MESH    if (meshhdrlen > 0) {        memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);        nh_pos += meshhdrlen;        h_pos += meshhdrlen;    }#endif    if (ieee80211_is_data_qos(fc)) {        __le16 *qos_control;        qos_control = (__le16 *) skb_push(skb, 2);        memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);        /*         * Maybe we could actually set some fields here, for now just         * initialise to zero to indicate no special operation.         */        *qos_control = 0;    } else        memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);    nh_pos += hdrlen;    h_pos += hdrlen;    dev->stats.tx_packets++;    dev->stats.tx_bytes += skb->len;    /* Update skb pointers to various headers since this modified frame     * is going to go through Linux networking code that may potentially     * need things like pointer to IP header. */    skb_set_mac_header(skb, 0);    skb_set_network_header(skb, nh_pos);    skb_set_transport_header(skb, h_pos);    info = IEEE80211_SKB_CB(skb);    memset(info, 0, sizeof(*info));    dev->trans_start = jiffies;    info->flags = info_flags;    info->ack_frame_id = info_id;    ieee80211_xmit(sdata, skb, band);    rcu_read_unlock();    return NETDEV_TX_OK; fail_rcu:    rcu_read_unlock(); fail:    dev_kfree_skb(skb);    return NETDEV_TX_OK;}

调用ieee80211_tx 进行传输数据处理,

ieee80211_tx     ----->invoke_tx_handlers     ----->__ieee80211_tx         ----->ieee80211_tx_frags             ----->drv_tx

最后调用drv_tx(),把帧传递给底层驱动:

static inline void drv_tx(struct ieee80211_local *local,          struct ieee80211_tx_control *control,          struct sk_buff *skb){    local->ops->tx(&local->hw, control, skb);} 

可以看到,调用了ieee80211_ops中的tx() 实现数据的发送。

1 0