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 deviceThis 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 bypriv 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_MESHif (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; }