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 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;
}