drivers/net/ppp/pppoe.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ppp/pppoe.c
Extension
.c
Size
31272 bytes
Lines
1312
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 proto_ops pppoe_ops;
static const struct ppp_channel_ops pppoe_chan_ops;

/* per-net private data for this module */
static unsigned int pppoe_net_id __read_mostly;
struct pppoe_net {
	/*
	 * we could use _single_ hash table for all
	 * nets by injecting net id into the hash but
	 * it would increase hash chains and add
	 * a few additional math comparisons messy
	 * as well, moreover in case of SMP less locking
	 * controversy here
	 */
	struct pppox_sock __rcu *hash_table[PPPOE_HASH_SIZE];
	spinlock_t hash_lock;
};

/*
 * PPPoE could be in the following stages:
 * 1) Discovery stage (to obtain remote MAC and Session ID)
 * 2) Session stage (MAC and SID are known)
 *
 * Ethernet frames have a special tag for this but
 * we use simpler approach based on session id
 */
static inline bool stage_session(__be16 sid)
{
	return sid != 0;
}

static inline struct pppoe_net *pppoe_pernet(struct net *net)
{
	return net_generic(net, pppoe_net_id);
}

static inline int cmp_2_addr(struct pppoe_addr *a, struct pppoe_addr *b)
{
	return a->sid == b->sid && ether_addr_equal(a->remote, b->remote);
}

static inline int cmp_addr(struct pppoe_addr *a, __be16 sid, char *addr)
{
	return a->sid == sid && ether_addr_equal(a->remote, addr);
}

#if 8 % PPPOE_HASH_BITS
#error 8 must be a multiple of PPPOE_HASH_BITS
#endif

static u8 hash_item(__be16 sid, const u8 addr[ETH_ALEN])
{
	const u16 *addr16 = (const u16 *)addr;
	unsigned int i;
	u16 hash16;
	u8 hash;

	hash16 = addr16[0] ^ addr16[1] ^ addr16[2] ^ (__force u16)sid;
	hash = (hash16 >> 8) ^ hash16;
	for (i = 8; (i >>= 1) >= PPPOE_HASH_BITS;)
		hash ^= hash >> i;

	return hash & PPPOE_HASH_MASK;
}

/**********************************************************************
 *
 *  Set/get/delete/rehash items  (internal versions)
 *
 **********************************************************************/
static struct pppox_sock *__get_item(struct pppoe_net *pn, __be16 sid,
				unsigned char *addr, int ifindex)
{
	int hash = hash_item(sid, addr);
	struct pppox_sock *ret;

	ret = rcu_dereference(pn->hash_table[hash]);
	while (ret) {
		if (cmp_addr(&ret->pppoe_pa, sid, addr) &&
		    ret->pppoe_ifindex == ifindex)
			return ret;

		ret = rcu_dereference(ret->next);
	}

	return NULL;
}

static int __set_item(struct pppoe_net *pn, struct pppox_sock *po)
{

Annotation

Implementation Notes