1. 驱动的主进口如下:

/** * This is the main entry point for the brcmsmac driver. * * This function is scheduled upon module initialization and * does the driver registration, which result in brcms_bcma_probe() * call resulting in the driver bringup. */ staticvoid brcms_driver_init(struct work_struct *work) {
int error; error = bcma_driver_register(&brcms_bcma_driver); if (error) pr_err("%s: register returned %d\n", __func__, error); }

可以看到brcms_bcma_driver作为参数传递给了bcma_driver_register(). brcms_bcma_driver的定义如下:

staticstruct bcma_driver brcms_bcma_driver = {
.name     = KBUILD_MODNAME, .probe    = brcms_bcma_probe, .suspend  = brcms_suspend, .resume   = brcms_resume, .remove   = brcms_remove, .id_table = brcms_coreid_table, };

重视此中的probe函数。

2. 按照上方的解析,紧接着brcms_bcma_probe将会被调用。

staticint brcms_bcma_probe(struct bcma_device *pdev) {
struct brcms_info *wl; struct ieee80211_hw *hw; dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n", pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class, pdev->irq); if ((pdev->id.manuf != BCMA_MANUF_BCM) || (pdev->id.id != BCMA_CORE_80211)) return -ENODEV; hw = ieee80211_alloc_hw(sizeof(struct brcms_info), &brcms_ops); if (!hw) {
pr_err("%s: ieee80211_alloc_hw failed\n", __func__); return -ENOMEM; } SET_IEEE80211_DEV(hw, &pdev->dev); bcma_set_drvdata(pdev, hw); memset(hw->priv, 0, sizeof(*wl)); wl = brcms_attach(pdev); if (!wl) {
pr_err("%s: brcms_attach failed!\n", __func__); return -ENODEV; } brcms_led_register(wl); return0; }

重视brcms_bcma_probe()函数体中的这行代码:

hw = ieee80211_alloc_hw(sizeof(struct brcms_info), &brcms_ops);

这里的参数是brcms_ops, 它的定义如下:

staticconststruct ieee80211_ops brcms_ops = {
.tx = brcms_ops_tx, .start = brcms_ops_start, .stop = brcms_ops_stop, .add_interface = brcms_ops_add_interface, .remove_interface = brcms_ops_remove_interface, .config = brcms_ops_config, .bss_info_changed = brcms_ops_bss_info_changed, .configure_filter = brcms_ops_configure_filter, .sw_scan_start = brcms_ops_sw_scan_start, .sw_scan_complete = brcms_ops_sw_scan_complete, .conf_tx = brcms_ops_conf_tx, .sta_add = brcms_ops_sta_add, .ampdu_action = brcms_ops_ampdu_action, .rfkill_poll = brcms_ops_rfkill_poll, .flush = brcms_ops_flush, };

以tx为例,在tx.c中将会用到该函数指针。

这里有须要跟一下ieee80211_alloc_hw(), 关于该函数,Johannes Berg在他的《The mac80211 subsystem for kernel developers》中的申明是:

ieee80211_alloc_hw— Allocate a new hardware device

This must be called once for each hardware device. The returned pointer must be used to refer to this

device when calling other functions. mac80211 allocates a private data area for the driver pointed to by
priv in struct ieee80211_hw, the size of this area is given as priv_data_len.

我们重视到brcms_ops作为参数被传递给了ieee80211_alloc_hw(). 并且在该函数体中有如许的代码:

local->ops = ops;

这很首要,我们在后面会说起到。之后就是要new一个struct wiphy - wireless hardware description出来

/* 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);

别的还有tasklet初始化的代码,是跟接管数据慎密相干的:

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

在后面一节谈数据接管的时辰会胪陈。

在brcms_bcma_probe()的函数体中,完成了ieee80211_alloc_hw()之后的另一行首要代码就是:

wl = brcms_attach(pdev);

3. 接着解析brcms_attach()

3.1 起首初始化Tasklet

/* setup the bottom half handler */ tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl);

这里可以看到中断处理惩罚函数是brcms_dpc().

 

3.2 Download firmware

/* prepare ucode */ if (brcms_request_fw(wl, pdev) < 0) {
wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in " "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm"); brcms_release_fw(wl); brcms_remove(pdev); return NULL; }

3.3 初始化硬件

/*

 * low level attach steps(all hw accesses go
 * inside, no more in rest of the attach)
*/
err = brcms_b_attach(wlc, core, unit, piomode);

3.4 申请中断

/* register our interrupt handler */ if (request_irq(pdev->irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit); goto fail; }
那么傍边断产生时比如稀有据过来须要接管时,brcms_isr()就会被触发。

3.5 注册设备

err = ieee80211_register_hw(hw); if (err) wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status" "%d\n", __func__, err);

ieee80211_register_hw()将会调用到ieee80211_if_add()来注册网卡设备

经由过程ieee80211_if_add()的代码可以看到这里终于调用了熟悉的register_netdevice()

int ieee80211_if_add(struct ieee80211_local *local, constchar *name, struct wireless_dev **new_wdev, enum nl80211_iftype type, struct vif_params *params){
... if (ndev) {
if (params) {
ndev->ieee80211_ptr->use_4addr = params->use_4addr; if (type == NL80211_IFTYPE_STATION) sdata->u.mgd.use_4addr = params->use_4addr; } ndev->features |= local->hw.netdev_features; ret = register_netdevice(ndev); if (ret) {
free_netdev(ndev); return ret; } } ... }

如今我们来看看driver是如何从WLAN chipset那边接管数据的

在上一篇文章中提到,数据过来时会产生中断,而在brcms_attach()函数体中,注册的interrupt handler是brcms_isr(),所以数据过来触发的第一个函数就是brcms_isr()。

1. 触发brcms_isr()

static irqreturn_t brcms_isr(int irq, void *dev_id) {
struct brcms_info *wl; irqreturn_t ret = IRQ_NONE; wl = (struct brcms_info *) dev_id; spin_lock(&wl->isr_lock); /* call common first level interrupt handler */ if (brcms_c_isr(wl->wlc)) {
/* schedule second level handler */ tasklet_schedule(&wl->tasklet); ret = IRQ_HANDLED; } spin_unlock(&wl->isr_lock); return ret; }

这里经由过程tasklet_schedule()来运行tasklet。在brcms_attach()中,已经用tasklet_init()指定了底半部的handler是brcms_dpc.

2. 触发brcms_dpc()

void brcms_dpc(unsigned long data) {
  .../* call the common second level interrupt handler */ if (wl->pub->up) {
if (wl->resched) {
unsigned long flags; spin_lock_irqsave(&wl->isr_lock, flags); brcms_c_intrsupd(wl->wlc); spin_unlock_irqrestore(&wl->isr_lock, flags); } wl->resched = brcms_c_dpc(wl->wlc, true); }   ... }

3. 调用brcms_c_dpc()

/* second-level interrupt processing *   Return true if another dpc needs to be re-scheduled. false otherwise. *   Param ""bounded"" indicates if applicable loops should be bounded. */ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) {
... /* * received data or control frame, MI_DMAINT is * indication of RX_FIFO interrupt */ if (macintstatus & MI_DMAINT) if (brcms_b_recv(wlc_hw, RX_FIFO, bounded)) wlc->macintstatus |= MI_DMAINT; ... }

4. 调用brcms_b_recv()

brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) {
... skb_queue_head_init(&recv_frames); /* gather received frames */ do {
/* !give others some time to run! */ if (n >= bound_limit) break; morepending = dma_rx(wlc_hw->di[fifo], &recv_frames); n++; } while (morepending); /* post more rbufs */ dma_rxfill(wlc_hw->di[fifo]); /* process each frame */ skb_queue_walk_safe(&recv_frames, p, next) {
struct d11rxhdr_le *rxh_le; struct d11rxhdr *rxh; skb_unlink(p, &recv_frames); rxh_le = (struct d11rxhdr_le *)p->data; rxh = (struct d11rxhdr *)p->data; ... brcms_c_recv(wlc_hw->wlc, p); } return morepending; }

5. 调用brcms_c_recv()

/* Process received frames */ /* * Return true if more frames need to be processed. false otherwise. * Param ""bound"" indicates max. # frames to process before break out. */ staticvoid brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p) {
... /* not supporting A-MSDU */ is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK; if (is_amsdu) goto toss; brcms_c_recvctl(wlc, rxh, p); return; toss: brcmu_pkt_buf_free_skb(p); }

6. 调用brcms_c_recvctl()

staticvoid brcms_c_recvctl(struct brcms_c_info *wlc, struct d11rxhdr *rxh, struct sk_buff *p) {
int len_mpdu; struct ieee80211_rx_status rx_status; struct ieee80211_hdr *hdr; memset(&rx_status, 0, sizeof(rx_status)); prep_mac80211_status(wlc, rxh, p, &rx_status); /* mac header+body length, exclude CRC and plcp header */ len_mpdu = p->len - D11_PHY_HDR_LEN - FCS_LEN; skb_pull(p, D11_PHY_HDR_LEN); __skb_trim(p, len_mpdu); /* unmute transmit */ if (wlc->hw->suspended_fifos) {
hdr = (struct ieee80211_hdr *)p->data; if (ieee80211_is_beacon(hdr->frame_control)) brcms_b_mute(wlc->hw, false); } memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p); }

这里我们临时只须要存眷最后一行,也就是ieee80211_rx_irqsafe()

7. 调用ieee80211_rx_irqsafe()

/* This is a version of the rx handler that can be called  hard irq * context. Post the skb on the queue and schedule the tasklet */ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb) {
struct ieee80211_local *local = hw_to_local(hw); BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb)); skb->pkt_type = IEEE80211_RX_MSG; skb_queue_tail(&local->skb_queue, skb); tasklet_schedule(&local->tasklet); }

关键的一行代码是tasklet_schedule(), 回想一下我们在解析ieee80211_alloc_hw()时提到的这句代码:

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

这里终于派上了用处,ieee80211_tasklet_handler被触发了。

8. 调用ieee80211_tasklet_handler()

staticvoid ieee80211_tasklet_handler(unsigned long data) {
struct ieee80211_local *local = (struct ieee80211_local *) data; struct sta_info *sta, *tmp; struct skb_eos p_msg_data *eos p_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; ... } } }

这里我们只关怀IEEE80211_RX_MSG类型的处理惩罚。

9. 调用ieee80211_rx(), 终于走到了rx.c

/* * This is the receive path handler. It is called by a low level driver when an * 802.11 MPDU is received  the hardware. */ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) {
... 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_handle_packet()

10. 调用__ieee80211_rx_handle_packet()

staticvoid __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb) {
... if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) || ieee80211_is_beacon(hdr->frame_control))) ieee80211_scan_rx(local, skb); if (ieee80211_is_data(fc)) {
prev_sta = NULL; for_each_sta_info(local, hdr->addr2, sta, tmp) {
if (!prev_sta) {
prev_sta = sta; continue; } rx.sta = prev_sta; rx.sdata = prev_sta->sdata; ieee80211_prepare_and_rx_handle(&rx, skb, false); prev_sta = sta; } if (prev_sta) {
rx.sta = prev_sta; rx.sdata = prev_sta->sdata; if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) return; gotoout; } } ... }

可以看到若是是probe response或者beacon如许的frame, 会有别的的处理惩罚。我们这里只解析是data的景象。

11. 调用ieee80211_prepare_and_rx_handle()

staticbool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,

struct sk_buff *skb, bool consume)
{
    ...
    ieee80211_invoke_rx_handlers(rx);
returntrue;
}

12. 调用ieee80211_invoke_rx_handlers()

staticvoid ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
{
    ...
    ieee80211_rx_handlers(rx, &reorder_release);
return;
    ...
}

13. 调用ieee80211_rx_handlers()

staticvoid ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
struct sk_buff_head *frames)
{
    ieee80211_rx_result res = RX_DROP_MONITOR;
struct sk_buff *skb;
#define CALL_RXH(rxh)                do {                        res = rxh(rx);                if (res != RX_CONTINUE)                goto rxh_next;      } while (0);
    spin_lock_bh(&rx->local->rx_path_lock);
while ((skb = __skb_dequeue(frames))) {
/*
         * all the other fields are valid across frames
         * that belong to an aMPDU since they are on the
         * same TID  the same station
*/
        rx->skb = skb;
        CALL_RXH(ieee80211_rx_h_decrypt)
        CALL_RXH(ieee80211_rx_h_check_more_data)
        CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll)
        CALL_RXH(ieee80211_rx_h_sta_process)
        CALL_RXH(ieee80211_rx_h_defragment)
        CALL_RXH(ieee80211_rx_h_michael_mic_verify)
/* must be after MMIC verify so header is counted in MPDU mic */
#ifdef CONFIG_MAC80211_MESH
if (ieee80211_vif_is_mesh(&rx->sdata->vif))
            CALL_RXH(ieee80211_rx_h_mesh_fwding);
#endif
        CALL_RXH(ieee80211_rx_h_amsdu)
        CALL_RXH(ieee80211_rx_h_data)
/* special treatment -- needs the queue */
        res = ieee80211_rx_h_ctrl(rx, frames);
if (res != RX_CONTINUE)
goto rxh_next;
        CALL_RXH(ieee80211_rx_h_mgmt_check)
        CALL_RXH(ieee80211_rx_h_action)
        CALL_RXH(ieee80211_rx_h_userspace_mgmt)
        CALL_RXH(ieee80211_rx_h_action_return)
        CALL_RXH(ieee80211_rx_h_mgmt)
rxh_next:
        ieee80211_rx_handlers_result(rx, res);
#undef CALL_RXH
    }
    spin_unlock_bh(&rx->local->rx_path_lock);
}

还是只看是data的景象,会持续调用ieee80211_rx_h_data()

14. 调用ieee80211_rx_h_data()

static ieee80211_rx_result debug_noinline ieee80211_rx_h_data(struct ieee80211_rx_data *rx) {
... rx->skb->dev = dev; dev->stats.rx_packets++; dev->stats.rx_bytes += rx->skb->len; if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 && !is_multicast_ether_addr( ((struct ethhdr *)rx->skb->data)->h_dest) && (!local->scanning && !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))) {
mod_timer(&local->dynamic_ps_timer, jiffies + msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); } ieee80211_deliver_skb(rx); return RX_QUEUED; }

15. 调用ieee80211_deliver_skb()

/* * requires that rx->skb is a frame with ethernet header */ staticvoid ieee80211_deliver_skb(struct ieee80211_rx_data *rx) {
... skb = rx->skb; ... if (skb) {
int align __maybe_unused; #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS /* * ""align"" will only take the values 0 or 2 here * since all frames are required to be aligned * to 2-byte boundaries when being passed to * mac80211; the code here works just as well if * that isn""t true, but mac80211 assumes it can * access fields as 2-byte aligned (e.g. for * compare_ether_addr) */ align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3; if (align) {
if (WARN_ON(skb_headroom(skb) < 3)) {
dev_kfree_skb(skb); skb = NULL; } else {
u8 *data = skb->data; size_t len = skb_headlen(skb); skb->data -= align; memmove(skb->data, data, len); skb_set_tail_pointer(skb, len); } } #endif if (skb) {
/* deliver to local stack */ skb->protocol = eth_type_trans(skb, dev); memset(skb->cb, 0, sizeof(skb->cb)); netif_receive_skb(skb); } } ... } 这里最核心的代码就是netif_receive_skb(skb)了,至此,数据已经从WLAN chipset接管到并发送至内核的收集子体系去向理惩罚。

Linux kernel发送数据的接口函数是packet_sendmsg,本质上对应了users pace的sendmsg实现。

比如在wpa_supplicant中,wpa_driver_nl80211_send_frame()就是用sendmsg发送数据的:

staticint wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
constvoid *data, size_t len,
int encrypt)
{
...
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = iov,
.msg_iovlen = 2,
.msg_control = NULL,
.msg_controllen = 0,
.msg_flags = 0,
};
...
res = sendmsg(drv->monitor_sock, &msg, 0);
if (res < 0) {
wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
return -1;
}
return0;
}
1. 起首来看packet_sendmsg()的实现
staticint packet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) {
struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); if (po->tx_ring.pg_vec) return tpacket_snd(po, msg); else return packet_snd(sock, msg, len); }

2. 调用packet_snd()

staticint packet_snd(struct socket *sock, struct msghdr *msg, size_t len) {
... // 起首把数据从user space拷贝到kernel space err = memcpy_iovec((void *)&vnet_hdr, msg->msg_iov, vnet_hdr_len); ... /* *    Now send it */ // 然后用dev_queue_xmit()来发送skb. err = dev_queue_xmit(skb); if (err > 0 && (err = net_xmit_errno(err)) != 0) goto out_unlock; ... }

3. 调用dev_queue_xmit()

/** *    dev_queue_xmit - transmit a buffer *    @skb: buffer to transmit * *    Queue a buffer for transmission to a network device. The caller must *    have set the device and priority and built the buffer before calling *    this function. The function can be called  an interrupt. * *    A negative errno code is returned on a failure. A success does not *    guarantee the frame will be transmitted as it may be dropped due *    to congestion or traffic shaping. */ int dev_queue_xmit(struct sk_buff *skb) {
struct net_device *dev = skb->dev; struct netdev_queue *txq; struct Qdisc *q; int rc = -ENOMEM; skb_reset_mac_header(skb); /* Disable soft irqs for various locks below. Also * stops preemption for RCU. */ rcu_read_lock_bh(); skb__prio(skb); txq = netdev_pick_tx(dev, skb); q = rcu_dereference_bh(txq->qdisc); #ifdef CONFIG_NET_CLS_ACT skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS); #endif trace_net_dev_queue(skb); if (q->enqueue) {
rc = __dev_xmit_skb(skb, q, dev, txq); gotoout; } ... }

4. 调用__dev_xmit_skb()

static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, struct net_device *dev, struct netdev_queue *txq) {
... if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) {
kfree_skb(skb); rc = NET_XMIT_DROP; } elseif ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) && qdisc_run_begin(q)) {
/* * This is a work-conserving queue; there are no old skbs * waiting to be sent out; and the qdisc is not running - * xmit the skb directly. */ if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE)) skb_dst_force(skb); qdisc_bstats_(q, skb); // 重视这里 if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {
if (unlikely(contended)) {
spin_unlock(&q->busylock); contended = false; } __qdisc_run(q); } else qdisc_run_end(q); rc = NET_XMIT_SUCCESS; } ... }

5. 调用sch_direct_xmit()

/*

* Transmit one skb, and handle the return status as required. Holding the
* __QDISC_STATE_RUNNING bit guarantees that only one CPU can execute this
* function.
*
* Returns to the caller:
*                0  - queue is empty or throttled.
*                >0 - queue is not empty.
*/
int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
struct net_device *dev, struct netdev_queue *txq,
spinlock_t *root_lock)
{
...
if (!netif_xmit_frozen_or_stopped(txq))
ret = dev_hard_start_xmit(skb, dev, txq);
...
}

6. 调用dev_hard_start_xmit()

int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq) {
... do {
struct sk_buff *nskb = skb->next; skb->next = nskb->next; nskb->next = NULL; /* * If device doesn""t need nskb->dst, release it right now while * its hot in this cpu cache */ if (dev->priv_flags & IFF_XMIT_DST_RELEASE) skb_dst_drop(nskb); if (!list_empty(&ptype_all)) dev_queue_xmit_nit(nskb, dev); skb_len = nskb->len; // 调用了ndo_start_xmit rc = ops->ndo_start_xmit(nskb, dev); trace_net_dev_xmit(nskb, rc, dev, skb_len); if (unlikely(rc != NETDEV_TX_OK)) {
if (rc & ~NETDEV_TX_MASK) goto out_kfree_gso_skb; nskb->next = skb->next; skb->next = nskb; return rc; } txq_trans_(txq); if (unlikely(netif_xmit_stopped(txq) && skb->next)) return NETDEV_TX_BUSY; } while (skb->next); ... }

7. 那么ndo_start_xmit对应哪个函数?

在第一节的3.5中提到了ieee80211_register_hw()会调用ieee80211_if_add(),但当时我们只留心了register_netdevice()。

这里再解析一下别的一处斗劲首要的代码,也就是register_netdevice()之前的ieee80211_setup_sdata()

/* setup type-dependent data */ ieee80211_setup_sdata(sdata, type); if (ndev) {
if (params) {
ndev->ieee80211_ptr->use_4addr = params->use_4addr; if (type == NL80211_IFTYPE_STATION) sdata->u.mgd.use_4addr = params->use_4addr; } ndev->features |= local->hw.netdev_features; ret = register_netdevice(ndev); if (ret) {
free_netdev(ndev); return ret; } }

持续跟进ieee80211_setup_sdata()

staticvoid ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, enum nl80211_iftype type) {
... /* only monitor/p2p-device differ */ if (sdata->dev) {
sdata->dev->netdev_ops = &ieee80211_dataif_ops; sdata->dev->type = ARPHRD_ETHER; } skb_queue_head_init(&sdata->skb_queue); INIT_WORK(&sdata->work, ieee80211_iface_work); INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); ... }

ieee80211_dataif_ops()的定义如下:

staticconststruct 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__queue    = ieee80211_netdev__queue, };

显然,ndo_start_xmit对应的函数是ieee80211_subif_start_xmit()

8. 调用ieee80211_subif_start_xmit()

/** * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type * subinterfaces (wlan#, WDS, and VLAN interfaces) * @skb: packet to be sent * @dev: incoming interface * * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will * not be freed, and caller is responsible for either retrying later or freeing * skb). * * 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) {
... ieee80211_xmit(sdata, skb, band); rcu_read_unlock(); return NETDEV_TX_OK; }

9. 调用ieee80211_xmit()

void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, enum ieee80211_band band) {
... ieee80211_set_qos_hdr(sdata, skb); ieee80211_tx(sdata, skb, false, band); }

10. 调用ieee80211_tx()

staticbool ieee80211_tx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, bool txpending, enum ieee80211_band band) {
... if (!invoke_tx_handlers(&tx)) result = __ieee80211_tx(local, &tx.skbs, led_len, tx.sta, txpending); return result; }

11. 调用__ieee80211_tx()

staticbool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff_head *skbs, int led_len, struct sta_info *sta, bool txpending) {
... result = ieee80211_tx_frags(local, vif, pubsta, skbs, txpending); ieee80211_tpt_led_trig_tx(local, fc, led_len); ieee80211_led_tx(local, 1); ... return result; }

12. 调用ieee80211_tx_frags()

staticbool ieee80211_tx_frags(struct ieee80211_local *local, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct sk_buff_head *skbs, bool txpending) {
... skb_queue_walk_safe(skbs, skb, tmp) {
... drv_tx(local, &control, skb); } returntrue; }

13. 调用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_alloc_hw()函数体中有如许的代码:

local->ops = ops;

而这个ops又是从ieee80211_alloc_hw()的参数传进来的,也就是brcms_ops.

所以local->ops-tx()实际上就触发了brcms_ops_tx()

 

14. 调用brcms_ops_tx()

staticvoid brcms_ops_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) {
... if (brcms_c_sendpkt_mac80211(wl->wlc, skb, hw)) tx_info->rate_driver_data[0] = control->sta; done: spin_unlock_bh(&wl->lock); }

15. 调用brcms_c_sendpkt_mac80211()

bool brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, struct ieee80211_hw *hw) {
uint fifo; struct scb *scb = &wlc->pri_scb; fifo = brcms_ac_to_fifo(skb_get_queue_mapping(sdu)); brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0); // 这里是关键 if (!brcms_c_tx(wlc, sdu)) returntrue; /* packet discarded */ dev_kfree_skb_any(sdu); returnfalse; }