Broadcom softmac WLAN 驱动解析(3)
Linux kernel发送数据的接口函数是packet_sendmsg,本质上对应了users pace的sendmsg实现。
比如在wpa_supplicant中,wpa_driver_nl80211_send_frame()就是用sendmsg发送数据的:
static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv, const void *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; } return 0; }
1. 首先来看packet_sendmsg()的实现
static int 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()
static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) { ... // 首先把数据从user space拷贝到kernel space err = memcpy_fromiovec((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 from 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_update_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); goto out; } ... }
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; } else if ((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_update(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_update(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()
static void 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()的定义如下:
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, };
显然,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()
static bool 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()
static bool __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()
static bool 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); } return true; }
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()
static void 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)) return true; /* packet discarded */ dev_kfree_skb_any(sdu); return false; }