xref: /linux/include/net/psp/functions.h (revision da630d1da2b19442c337bcbe3bb3fa66fda1f5bb)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #ifndef __NET_PSP_HELPERS_H
4 #define __NET_PSP_HELPERS_H
5 
6 #include <linux/skbuff.h>
7 #include <linux/rcupdate.h>
8 #include <linux/udp.h>
9 #include <net/sock.h>
10 #include <net/tcp.h>
11 #include <net/psp/types.h>
12 
13 struct inet_timewait_sock;
14 
15 /* Driver-facing API */
16 struct psp_dev *
17 psp_dev_create(struct net_device *netdev, struct psp_dev_ops *psd_ops,
18 	       struct psp_dev_caps *psd_caps, void *priv_ptr);
19 void psp_dev_unregister(struct psp_dev *psd);
20 bool psp_dev_encapsulate(struct net *net, struct sk_buff *skb, __be32 spi,
21 			 u8 ver, __be16 sport);
22 int psp_dev_rcv(struct sk_buff *skb, u16 dev_id, u8 generation, bool strip_icv);
23 
24 /* Kernel-facing API */
25 void psp_assoc_put(struct psp_assoc *pas);
26 
27 #if IS_ENABLED(CONFIG_INET_PSP)
28 unsigned int psp_key_size(u32 version);
29 void psp_sk_assoc_free(struct sock *sk);
30 void psp_twsk_init(struct inet_timewait_sock *tw, const struct sock *sk);
31 void psp_twsk_assoc_free(struct inet_timewait_sock *tw);
32 void psp_reply_set_decrypted(const struct sock *sk, struct sk_buff *skb);
33 
34 static inline struct psp_assoc *psp_sk_assoc(const struct sock *sk)
35 {
36 	return rcu_dereference_check(sk->psp_assoc, lockdep_sock_is_held(sk));
37 }
38 
39 static inline void
40 psp_enqueue_set_decrypted(struct sock *sk, struct sk_buff *skb)
41 {
42 	struct psp_assoc *pas;
43 
44 	pas = psp_sk_assoc(sk);
45 	if (pas && pas->tx.spi)
46 		skb->decrypted = 1;
47 }
48 
49 static inline unsigned long
50 __psp_skb_coalesce_diff(const struct sk_buff *one, const struct sk_buff *two,
51 			unsigned long diffs)
52 {
53 	struct psp_skb_ext *a, *b;
54 
55 	a = skb_ext_find(one, SKB_EXT_PSP);
56 	b = skb_ext_find(two, SKB_EXT_PSP);
57 
58 	diffs |= (!!a) ^ (!!b);
59 	if (!diffs && unlikely(a))
60 		diffs |= memcmp(a, b, sizeof(*a));
61 	return diffs;
62 }
63 
64 static inline bool
65 psp_is_allowed_nondata(struct sk_buff *skb, struct psp_assoc *pas)
66 {
67 	bool fin = !!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN);
68 	u32 end_seq = TCP_SKB_CB(skb)->end_seq;
69 	u32 seq = TCP_SKB_CB(skb)->seq;
70 	bool pure_fin;
71 
72 	pure_fin = fin && end_seq - seq == 1;
73 
74 	return seq == end_seq || (pure_fin && seq == pas->upgrade_seq);
75 }
76 
77 static inline bool
78 psp_pse_matches_pas(struct psp_skb_ext *pse, struct psp_assoc *pas)
79 {
80 	return pse && pas->rx.spi == pse->spi &&
81 	       pas->generation == pse->generation &&
82 	       pas->version == pse->version &&
83 	       pas->dev_id == pse->dev_id;
84 }
85 
86 static inline enum skb_drop_reason
87 __psp_sk_rx_policy_check(struct sk_buff *skb, struct psp_assoc *pas)
88 {
89 	struct psp_skb_ext *pse = skb_ext_find(skb, SKB_EXT_PSP);
90 
91 	if (!pas)
92 		return pse ? SKB_DROP_REASON_PSP_INPUT : 0;
93 
94 	if (likely(psp_pse_matches_pas(pse, pas))) {
95 		if (unlikely(!pas->peer_tx))
96 			pas->peer_tx = 1;
97 
98 		return 0;
99 	}
100 
101 	if (!pse) {
102 		if (!pas->tx.spi ||
103 		    (!pas->peer_tx && psp_is_allowed_nondata(skb, pas)))
104 			return 0;
105 	}
106 
107 	return SKB_DROP_REASON_PSP_INPUT;
108 }
109 
110 static inline enum skb_drop_reason
111 psp_sk_rx_policy_check(struct sock *sk, struct sk_buff *skb)
112 {
113 	return __psp_sk_rx_policy_check(skb, psp_sk_assoc(sk));
114 }
115 
116 static inline enum skb_drop_reason
117 psp_twsk_rx_policy_check(struct inet_timewait_sock *tw, struct sk_buff *skb)
118 {
119 	return __psp_sk_rx_policy_check(skb, rcu_dereference(tw->psp_assoc));
120 }
121 
122 static inline struct psp_assoc *psp_sk_get_assoc_rcu(const struct sock *sk)
123 {
124 	struct psp_assoc *pas;
125 	int state;
126 
127 	state = READ_ONCE(sk->sk_state);
128 	if (!sk_is_inet(sk) || state == TCP_NEW_SYN_RECV)
129 		return NULL;
130 
131 	pas = state == TCP_TIME_WAIT ?
132 		      rcu_dereference(inet_twsk(sk)->psp_assoc) :
133 		      rcu_dereference(sk->psp_assoc);
134 	return pas;
135 }
136 
137 static inline struct psp_assoc *psp_skb_get_assoc_rcu(struct sk_buff *skb)
138 {
139 	if (!skb->decrypted || !skb->sk)
140 		return NULL;
141 
142 	return psp_sk_get_assoc_rcu(skb->sk);
143 }
144 
145 static inline unsigned int psp_sk_overhead(const struct sock *sk)
146 {
147 	int psp_encap = sizeof(struct udphdr) + PSP_HDR_SIZE + PSP_TRL_SIZE;
148 	bool has_psp = rcu_access_pointer(sk->psp_assoc);
149 
150 	return has_psp ? psp_encap : 0;
151 }
152 #else
153 static inline void psp_sk_assoc_free(struct sock *sk) { }
154 static inline void
155 psp_twsk_init(struct inet_timewait_sock *tw, const struct sock *sk) { }
156 static inline void psp_twsk_assoc_free(struct inet_timewait_sock *tw) { }
157 static inline void
158 psp_reply_set_decrypted(const struct sock *sk, struct sk_buff *skb) { }
159 
160 static inline struct psp_assoc *psp_sk_assoc(const struct sock *sk)
161 {
162 	return NULL;
163 }
164 
165 static inline void
166 psp_enqueue_set_decrypted(struct sock *sk, struct sk_buff *skb) { }
167 
168 static inline unsigned long
169 __psp_skb_coalesce_diff(const struct sk_buff *one, const struct sk_buff *two,
170 			unsigned long diffs)
171 {
172 	return diffs;
173 }
174 
175 static inline enum skb_drop_reason
176 psp_sk_rx_policy_check(struct sock *sk, struct sk_buff *skb)
177 {
178 	return 0;
179 }
180 
181 static inline enum skb_drop_reason
182 psp_twsk_rx_policy_check(struct inet_timewait_sock *tw, struct sk_buff *skb)
183 {
184 	return 0;
185 }
186 
187 static inline struct psp_assoc *psp_skb_get_assoc_rcu(struct sk_buff *skb)
188 {
189 	return NULL;
190 }
191 
192 static inline unsigned int psp_sk_overhead(const struct sock *sk)
193 {
194 	return 0;
195 }
196 #endif
197 
198 static inline unsigned long
199 psp_skb_coalesce_diff(const struct sk_buff *one, const struct sk_buff *two)
200 {
201 	return __psp_skb_coalesce_diff(one, two, 0);
202 }
203 
204 #endif /* __NET_PSP_HELPERS_H */
205