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, , 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);elsereturn packet_snd(sock, msg, len);}

2. 调用packet_snd()

static int packet_snd(struct socket *sock,struct msghdr *msg, size_t len){…// 首先把数据从user space拷贝到kernel spaceerr = memcpy_fromiovec((void *)&vnet_hdr, msg->msg_iov,vnet_hdr_len);…/** Now send iterr = 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_ACTskb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS);#endiftrace_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); (sch_direct_xmit(skb, q, dev, txq, root_lock)) {if (unlikely(contended)) {spin_unlock(&q->busylock);contended = false;}__qdisc_run(q);} elseqdisc_run_end(q);rc = NET_XMIT_SUCCESS;}…}

5. 调用sch_direct_xmit()

昨晚多几分钟的准备,今天少几小时的麻烦。

Broadcom softmac WLAN 驱动解析(3)

相关文章:

你感兴趣的文章:

标签云: