drivers/net/ovpn/tcp.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ovpn/tcp.c
Extension
.c
Size
16373 bytes
Lines
661
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 struct proto_ops ovpn_tcp_ops __ro_after_init;
static struct proto ovpn_tcp6_prot __ro_after_init;
static struct proto_ops ovpn_tcp6_ops __ro_after_init;

static int ovpn_tcp_parse(struct strparser *strp, struct sk_buff *skb)
{
	struct strp_msg *rxm = strp_msg(skb);
	__be16 blen;
	u16 len;
	int err;

	/* when packets are written to the TCP stream, they are prepended with
	 * two bytes indicating the actual packet size.
	 * Parse accordingly and return the actual size (including the size
	 * header)
	 */

	if (skb->len < rxm->offset + 2)
		return 0;

	err = skb_copy_bits(skb, rxm->offset, &blen, sizeof(blen));
	if (err < 0)
		return err;

	len = be16_to_cpu(blen);
	if (len < 2)
		return -EINVAL;

	return len + 2;
}

/* queue skb for sending to userspace via recvmsg on the socket */
static void ovpn_tcp_to_userspace(struct ovpn_peer *peer, struct sock *sk,
				  struct sk_buff *skb)
{
	skb_set_owner_r(skb, sk);
	memset(skb->cb, 0, sizeof(skb->cb));
	skb_queue_tail(&peer->tcp.user_queue, skb);
	peer->tcp.sk_cb.sk_data_ready(sk);
}

static struct sk_buff *ovpn_tcp_skb_packet(const struct ovpn_peer *peer,
					   struct sk_buff *orig_skb,
					   const int pkt_len, const int pkt_off)
{
	struct sk_buff *ovpn_skb;
	int err;

	/* create a new skb with only the content of the current packet */
	ovpn_skb = netdev_alloc_skb(peer->ovpn->dev, pkt_len);
	if (unlikely(!ovpn_skb))
		goto err;

	skb_copy_header(ovpn_skb, orig_skb);
	err = skb_copy_bits(orig_skb, pkt_off, skb_put(ovpn_skb, pkt_len),
			    pkt_len);
	if (unlikely(err)) {
		net_warn_ratelimited("%s: skb_copy_bits failed for peer %u\n",
				     netdev_name(peer->ovpn->dev), peer->id);
		kfree_skb(ovpn_skb);
		goto err;
	}

	consume_skb(orig_skb);
	return ovpn_skb;
err:
	kfree_skb(orig_skb);
	return NULL;
}

static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)
{
	struct ovpn_peer *peer = container_of(strp, struct ovpn_peer, tcp.strp);
	struct strp_msg *msg = strp_msg(skb);
	int pkt_len = msg->full_len - 2;
	u8 opcode;

	/* we need at least 4 bytes of data in the packet
	 * to extract the opcode and the key ID later on
	 */
	if (unlikely(pkt_len < OVPN_OPCODE_SIZE)) {
		net_warn_ratelimited("%s: packet too small to fetch opcode for peer %u\n",
				     netdev_name(peer->ovpn->dev), peer->id);
		goto err;
	}

	/* extract the packet into a new skb */
	skb = ovpn_tcp_skb_packet(peer, skb, pkt_len, msg->offset + 2);
	if (unlikely(!skb))
		goto err;

Annotation

Implementation Notes