File Index
Files and directories
Sign in
FILE

pktid.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ovpn/pktid.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*  OpenVPN data channel offload
  3 *
  4 *  Copyright (C) 2020-2025 OpenVPN, Inc.
  5 *
  6 *  Author:	Antonio Quartulli <antonio@openvpn.net>
  7 *		James Yonan <james@openvpn.net>
  8 */
  9
 10#include <linux/atomic.h>
 11#include <linux/jiffies.h>
 12#include <linux/net.h>
 13#include <linux/netdevice.h>
 14#include <linux/types.h>
 15
 16#include "ovpnpriv.h"
 17#include "main.h"
 18#include "pktid.h"
 19
 20void ovpn_pktid_xmit_init(struct ovpn_pktid_xmit *pid)
 21{
 22	atomic_set(&pid->seq_num, 1);
 23}
 24
 25void ovpn_pktid_recv_init(struct ovpn_pktid_recv *pr)
 26{
 27	memset(pr, 0, sizeof(*pr));
 28	spin_lock_init(&pr->lock);
 29}
 30
 31/* Packet replay detection.
 32 * Allows ID backtrack of up to REPLAY_WINDOW_SIZE - 1.
 33 */
 34int ovpn_pktid_recv(struct ovpn_pktid_recv *pr, u32 pkt_id, u32 pkt_time)
 35{
 36	const unsigned long now = jiffies;
 37	int ret;
 38
 39	/* ID must not be zero */
 40	if (unlikely(pkt_id == 0))
 41		return -EINVAL;
 42
 43	spin_lock_bh(&pr->lock);
 44
 45	/* expire backtracks at or below pr->id after PKTID_RECV_EXPIRE time */
 46	if (unlikely(time_after_eq(now, pr->expire)))
 47		pr->id_floor = pr->id;
 48
 49	/* time changed? */
 50	if (unlikely(pkt_time != pr->time)) {
 51		if (pkt_time > pr->time) {
 52			/* time moved forward, accept */
 53			pr->base = 0;
 54			pr->extent = 0;
 55			pr->id = 0;
 56			pr->time = pkt_time;
 57			pr->id_floor = 0;
 58		} else {
 59			/* time moved backward, reject */
 60			ret = -ETIME;
 61			goto out;
 62		}
 63	}
 64
 65	if (likely(pkt_id == pr->id + 1)) {
 66		/* well-formed ID sequence (incremented by 1) */
 67		pr->base = REPLAY_INDEX(pr->base, -1);
 68		pr->history[pr->base / 8] |= (1 << (pr->base % 8));
 69		if (pr->extent < REPLAY_WINDOW_SIZE)
 70			++pr->extent;
 71		pr->id = pkt_id;
 72	} else if (pkt_id > pr->id) {
 73		/* ID jumped forward by more than one */
 74		const unsigned int delta = pkt_id - pr->id;
 75
 76		if (delta < REPLAY_WINDOW_SIZE) {
 77			unsigned int i;
 78
 79			pr->base = REPLAY_INDEX(pr->base, -delta);
 80			pr->history[pr->base / 8] |= (1 << (pr->base % 8));
 81			pr->extent += delta;
 82			if (pr->extent > REPLAY_WINDOW_SIZE)
 83				pr->extent = REPLAY_WINDOW_SIZE;
 84			for (i = 1; i < delta; ++i) {
 85				unsigned int newb = REPLAY_INDEX(pr->base, i);
 86
 87				pr->history[newb / 8] &= ~BIT(newb % 8);
 88			}
 89		} else {
 90			pr->base = 0;
 91			pr->extent = REPLAY_WINDOW_SIZE;
 92			memset(pr->history, 0, sizeof(pr->history));
 93			pr->history[0] = 1;
 94		}
 95		pr->id = pkt_id;
 96	} else {
 97		/* ID backtrack */
 98		const unsigned int delta = pr->id - pkt_id;
 99
100		if (delta > pr->max_backtrack)
101			pr->max_backtrack = delta;
102		if (delta < pr->extent) {
103			if (pkt_id > pr->id_floor) {
104				const unsigned int ri = REPLAY_INDEX(pr->base,
105								     delta);
106				u8 *p = &pr->history[ri / 8];
107				const u8 mask = (1 << (ri % 8));
108
109				if (*p & mask) {
110					ret = -EINVAL;
111					goto out;
112				}
113				*p |= mask;
114			} else {
115				ret = -EINVAL;
116				goto out;
117			}
118		} else {
119			ret = -EINVAL;
120			goto out;
121		}
122	}
123
124	pr->expire = now + PKTID_RECV_EXPIRE;
125	ret = 0;
126out:
127	spin_unlock_bh(&pr->lock);
128	return ret;
129}
~/ Read-only file preview.