drivers/net/gtp.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/gtp.c
Extension
.c
Size
60356 bytes
Lines
2547
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 gtp_netdev_ops = {
	.ndo_uninit		= gtp_dev_uninit,
	.ndo_start_xmit		= gtp_dev_xmit,
};

static const struct device_type gtp_type = {
	.name = "gtp",
};

#define GTP_TH_MAXLEN	(sizeof(struct udphdr) + sizeof(struct gtp0_header))
#define GTP_IPV4_MAXLEN	(sizeof(struct iphdr) + GTP_TH_MAXLEN)

static void gtp_link_setup(struct net_device *dev)
{
	struct gtp_dev *gtp = netdev_priv(dev);

	dev->netdev_ops		= &gtp_netdev_ops;
	dev->needs_free_netdev	= true;
	SET_NETDEV_DEVTYPE(dev, &gtp_type);

	dev->hard_header_len = 0;
	dev->addr_len = 0;
	dev->mtu = ETH_DATA_LEN - GTP_IPV4_MAXLEN;

	/* Zero header length. */
	dev->type = ARPHRD_NONE;
	dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;

	dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
	dev->priv_flags	|= IFF_NO_QUEUE;
	dev->lltx = true;
	netif_keep_dst(dev);

	dev->needed_headroom	= LL_MAX_HEADER + GTP_IPV4_MAXLEN;
	gtp->dev = dev;
}

static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]);

static void gtp_destructor(struct net_device *dev)
{
	struct gtp_dev *gtp = netdev_priv(dev);

	kfree(gtp->addr_hash);
	kfree(gtp->tid_hash);
}

static int gtp_sock_udp_config(struct udp_port_cfg *udp_conf,
			       const struct nlattr *nla, int family)
{
	udp_conf->family = family;

	switch (udp_conf->family) {
	case AF_INET:
		udp_conf->local_ip.s_addr = nla_get_be32(nla);
		break;
#if IS_ENABLED(CONFIG_IPV6)
	case AF_INET6:
		udp_conf->local_ip6 = nla_get_in6_addr(nla);
		break;
#endif
	default:
		return -EOPNOTSUPP;
	}

	return 0;
}

static struct sock *gtp_create_sock(int type, struct gtp_dev *gtp,
				    const struct nlattr *nla, int family)
{
	struct udp_tunnel_sock_cfg tuncfg = {};
	struct udp_port_cfg udp_conf = {};
	struct net *net = gtp->net;
	struct socket *sock;
	int err;

	if (nla) {
		err = gtp_sock_udp_config(&udp_conf, nla, family);
		if (err < 0)
			return ERR_PTR(err);
	} else {
		udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
		udp_conf.family = AF_INET;
	}

	if (type == UDP_ENCAP_GTP0)
		udp_conf.local_udp_port = htons(GTP0_PORT);
	else if (type == UDP_ENCAP_GTP1U)

Annotation

Implementation Notes