drivers/net/wireless/virtual/virt_wifi.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/virtual/virt_wifi.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/virtual/virt_wifi.c
Extension
.c
Size
18824 bytes
Lines
717
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct net_device_ops virt_wifi_ops = {
	.ndo_start_xmit = virt_wifi_start_xmit,
	.ndo_open	= virt_wifi_net_device_open,
	.ndo_stop	= virt_wifi_net_device_stop,
	.ndo_get_iflink = virt_wifi_net_device_get_iflink,
};

/* Invoked as part of rtnl lock release. */
static void virt_wifi_net_device_destructor(struct net_device *dev)
{
	/* Delayed past dellink to allow nl80211 to react to the device being
	 * deleted.
	 */
	kfree(dev->ieee80211_ptr);
	dev->ieee80211_ptr = NULL;
}

/* No lock interaction. */
static void virt_wifi_setup(struct net_device *dev)
{
	ether_setup(dev);
	dev->netdev_ops = &virt_wifi_ops;
	dev->needs_free_netdev  = true;
}

/* Called in a RCU read critical section from netif_receive_skb */
static rx_handler_result_t virt_wifi_rx_handler(struct sk_buff **pskb)
{
	struct sk_buff *skb = *pskb;
	struct virt_wifi_netdev_priv *priv =
		rcu_dereference(skb->dev->rx_handler_data);

	if (!priv->is_connected)
		return RX_HANDLER_PASS;

	/* GFP_ATOMIC because this is a packet interrupt handler. */
	skb = skb_share_check(skb, GFP_ATOMIC);
	if (!skb) {
		dev_err(&priv->upperdev->dev, "can't skb_share_check\n");
		return RX_HANDLER_CONSUMED;
	}

	*pskb = skb;
	skb->dev = priv->upperdev;
	skb->pkt_type = PACKET_HOST;
	return RX_HANDLER_ANOTHER;
}

/* Called with rtnl lock held. */
static int virt_wifi_newlink(struct net_device *dev,
			     struct rtnl_newlink_params *params,
			     struct netlink_ext_ack *extack)
{
	struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
	struct net *link_net = rtnl_newlink_link_net(params);
	struct nlattr **tb = params->tb;
	int err;

	if (!tb[IFLA_LINK])
		return -EINVAL;

	netif_carrier_off(dev);

	priv->upperdev = dev;
	priv->lowerdev = __dev_get_by_index(link_net,
					    nla_get_u32(tb[IFLA_LINK]));

	if (!priv->lowerdev)
		return -ENODEV;
	if (!tb[IFLA_MTU])
		dev->mtu = priv->lowerdev->mtu;
	else if (dev->mtu > priv->lowerdev->mtu)
		return -EINVAL;

	err = netdev_rx_handler_register(priv->lowerdev, virt_wifi_rx_handler,
					 priv);
	if (err) {
		dev_err(&priv->lowerdev->dev,
			"can't netdev_rx_handler_register: %d\n", err);
		return err;
	}

	eth_hw_addr_inherit(dev, priv->lowerdev);
	netif_stacked_transfer_operstate(priv->lowerdev, dev);

	dev->ieee80211_ptr = kzalloc_obj(*dev->ieee80211_ptr);

	if (!dev->ieee80211_ptr) {
		err = -ENOMEM;
		goto remove_handler;

Annotation

Implementation Notes