drivers/net/ovpn/peer.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ovpn/peer.c
Extension
.c
Size
36408 bytes
Lines
1385
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source 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

if (ss->ss_family == AF_INET) {
			ip_len = sizeof(struct in_addr);
		} else if (ss->ss_family == AF_INET6) {
			ip_len = sizeof(struct in6_addr);
		} else {
			net_dbg_ratelimited("%s: invalid family %u for remote endpoint for peer %u\n",
					    netdev_name(peer->ovpn->dev),
					    ss->ss_family, peer->id);
			kfree(bind);
			return -EINVAL;
		}

		memcpy(&bind->local, local_ip, ip_len);
	}

	/* set binding */
	ovpn_bind_reset(peer, bind);

	return 0;
}

/* variable name __tbl2 needs to be different from __tbl1
 * in the macro below to avoid confusing clang
 */
#define ovpn_get_hash_slot(_tbl, _key, _key_len) ({	\
	typeof(_tbl) *__tbl2 = &(_tbl);			\
	jhash(_key, _key_len, 0) % HASH_SIZE(*__tbl2);	\
})

#define ovpn_get_hash_head(_tbl, _key, _key_len) ({		\
	typeof(_tbl) *__tbl1 = &(_tbl);				\
	&(*__tbl1)[ovpn_get_hash_slot(*__tbl1, _key, _key_len)];\
})

/**
 * ovpn_peer_endpoints_update - update remote or local endpoint for peer
 * @peer: peer to update the remote endpoint for
 * @skb: incoming packet to retrieve the source/destination address from
 */
void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb)
{
	struct hlist_nulls_head *nhead;
	struct sockaddr_storage ss;
	struct sockaddr_in6 *sa6;
	bool reset_cache = false;
	struct sockaddr_in *sa;
	struct ovpn_bind *bind;
	const void *local_ip;
	size_t salen = 0;

	spin_lock_bh(&peer->lock);
	bind = rcu_dereference_protected(peer->bind,
					 lockdep_is_held(&peer->lock));
	if (unlikely(!bind))
		goto unlock;

	switch (skb->protocol) {
	case htons(ETH_P_IP):
		/* float check */
		if (unlikely(!ovpn_bind_skb_src_match(bind, skb))) {
			/* unconditionally save local endpoint in case
			 * of float, as it may have changed as well
			 */
			local_ip = &ip_hdr(skb)->daddr;
			sa = (struct sockaddr_in *)&ss;
			sa->sin_family = AF_INET;
			sa->sin_addr.s_addr = ip_hdr(skb)->saddr;
			sa->sin_port = udp_hdr(skb)->source;
			salen = sizeof(*sa);
			reset_cache = true;
			break;
		}

		/* if no float happened, let's double check if the local endpoint
		 * has changed
		 */
		if (unlikely(bind->local.ipv4.s_addr != ip_hdr(skb)->daddr)) {
			net_dbg_ratelimited("%s: learning local IPv4 for peer %d (%pI4 -> %pI4)\n",
					    netdev_name(peer->ovpn->dev),
					    peer->id, &bind->local.ipv4.s_addr,
					    &ip_hdr(skb)->daddr);
			bind->local.ipv4.s_addr = ip_hdr(skb)->daddr;
			reset_cache = true;
		}
		break;
	case htons(ETH_P_IPV6):
		/* float check */
		if (unlikely(!ovpn_bind_skb_src_match(bind, skb))) {
			/* unconditionally save local endpoint in case
			 * of float, as it may have changed as well

Annotation

Implementation Notes