drivers/net/wan/hdlc_fr.c

Source file repositories/reference/linux-study-clean/drivers/net/wan/hdlc_fr.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wan/hdlc_fr.c
Extension
.c
Size
30249 bytes
Lines
1301
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 pvc_ops = {
	.ndo_open       = pvc_open,
	.ndo_stop       = pvc_close,
	.ndo_start_xmit = pvc_xmit,
	.ndo_siocwandev = pvc_ioctl,
};

static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
{
	hdlc_device *hdlc = dev_to_hdlc(frad);
	struct pvc_device *pvc;
	struct net_device *dev;
	int used;

	pvc = add_pvc(frad, dlci);
	if (!pvc) {
		netdev_warn(frad, "Memory squeeze on fr_add_pvc()\n");
		return -ENOBUFS;
	}

	if (*get_dev_p(pvc, type))
		return -EEXIST;

	used = pvc_is_used(pvc);

	if (type == ARPHRD_ETHER)
		dev = alloc_netdev(0, "pvceth%d", NET_NAME_UNKNOWN,
				   ether_setup);
	else
		dev = alloc_netdev(0, "pvc%d", NET_NAME_UNKNOWN, pvc_setup);

	if (!dev) {
		netdev_warn(frad, "Memory squeeze on fr_pvc()\n");
		delete_unused_pvcs(hdlc);
		return -ENOBUFS;
	}

	if (type == ARPHRD_ETHER) {
		dev->priv_flags &= ~IFF_TX_SKB_SHARING;
		eth_hw_addr_random(dev);
	} else {
		__be16 addr = htons(dlci);

		dev_addr_set(dev, (u8 *)&addr);
		dlci_to_q922(dev->broadcast, dlci);
	}
	dev->netdev_ops = &pvc_ops;
	dev->mtu = HDLC_MAX_MTU;
	dev->min_mtu = 68;
	dev->max_mtu = HDLC_MAX_MTU;
	dev->needed_headroom = 10;
	dev->priv_flags |= IFF_NO_QUEUE;
	dev->ml_priv = pvc;

	if (register_netdevice(dev) != 0) {
		free_netdev(dev);
		delete_unused_pvcs(hdlc);
		return -EIO;
	}

	dev->needs_free_netdev = true;
	*get_dev_p(pvc, type) = dev;
	if (!used) {
		state(hdlc)->dce_changed = 1;
		state(hdlc)->dce_pvc_count++;
	}
	return 0;
}

static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
{
	struct pvc_device *pvc;
	struct net_device *dev;

	pvc = find_pvc(hdlc, dlci);
	if (!pvc)
		return -ENOENT;

	dev = *get_dev_p(pvc, type);
	if (!dev)
		return -ENOENT;

	if (dev->flags & IFF_UP)
		return -EBUSY;		/* PVC in use */

	unregister_netdevice(dev); /* the destructor will free_netdev(dev) */
	*get_dev_p(pvc, type) = NULL;

	if (!pvc_is_used(pvc)) {
		state(hdlc)->dce_pvc_count--;

Annotation

Implementation Notes