drivers/net/wwan/iosm/iosm_ipc_wwan.c

Source file repositories/reference/linux-study-clean/drivers/net/wwan/iosm/iosm_ipc_wwan.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wwan/iosm/iosm_ipc_wwan.c
Extension
.c
Size
7530 bytes
Lines
317
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 ipc_inm_ops = {
	.ndo_open = ipc_wwan_link_open,
	.ndo_stop = ipc_wwan_link_stop,
	.ndo_start_xmit = ipc_wwan_link_transmit,
};

/* Setup function for creating new net link */
static void ipc_wwan_setup(struct net_device *iosm_dev)
{
	iosm_dev->header_ops = NULL;
	iosm_dev->hard_header_len = 0;
	iosm_dev->tx_queue_len = DEFAULT_TX_QUEUE_LEN;

	iosm_dev->type = ARPHRD_NONE;
	iosm_dev->mtu = ETH_DATA_LEN;
	iosm_dev->min_mtu = ETH_MIN_MTU;
	iosm_dev->max_mtu = ETH_MAX_MTU;

	iosm_dev->flags = IFF_POINTOPOINT | IFF_NOARP;
	iosm_dev->needs_free_netdev = true;

	iosm_dev->netdev_ops = &ipc_inm_ops;
}

/* Create new wwan net link */
static int ipc_wwan_newlink(void *ctxt, struct net_device *dev,
			    u32 if_id, struct netlink_ext_ack *extack)
{
	struct iosm_wwan *ipc_wwan = ctxt;
	struct iosm_netdev_priv *priv;
	int err;

	if (if_id < IP_MUX_SESSION_START ||
	    if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist))
		return -EINVAL;

	priv = wwan_netdev_drvpriv(dev);
	priv->if_id = if_id;
	priv->netdev = dev;
	priv->ipc_wwan = ipc_wwan;

	if (rcu_access_pointer(ipc_wwan->sub_netlist[if_id]))
		return -EBUSY;

	err = register_netdevice(dev);
	if (err)
		return err;

	rcu_assign_pointer(ipc_wwan->sub_netlist[if_id], priv);
	netif_device_attach(dev);

	return 0;
}

static void ipc_wwan_dellink(void *ctxt, struct net_device *dev,
			     struct list_head *head)
{
	struct iosm_netdev_priv *priv = wwan_netdev_drvpriv(dev);
	struct iosm_wwan *ipc_wwan = ctxt;
	int if_id = priv->if_id;

	if (WARN_ON(if_id < IP_MUX_SESSION_START ||
		    if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist)))
		return;

	if (WARN_ON(rcu_access_pointer(ipc_wwan->sub_netlist[if_id]) != priv))
		return;

	RCU_INIT_POINTER(ipc_wwan->sub_netlist[if_id], NULL);
	/* unregistering includes synchronize_net() */
	unregister_netdevice_queue(dev, head);
}

static const struct wwan_ops iosm_wwan_ops = {
	.priv_size = sizeof(struct iosm_netdev_priv),
	.setup = ipc_wwan_setup,
	.newlink = ipc_wwan_newlink,
	.dellink = ipc_wwan_dellink,
};

int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg,
		     bool dss, int if_id)
{
	struct sk_buff *skb = skb_arg;
	struct net_device_stats *stats;
	struct iosm_netdev_priv *priv;
	int ret;

	if ((skb->data[0] & IOSM_IP_TYPE_MASK) == IOSM_IP_TYPE_IPV4)
		skb->protocol = htons(ETH_P_IP);

Annotation

Implementation Notes