100c94ca2SJakub Kicinski /* SPDX-License-Identifier: GPL-2.0-only */ 200c94ca2SJakub Kicinski 300c94ca2SJakub Kicinski #ifndef __NET_PSP_HELPERS_H 400c94ca2SJakub Kicinski #define __NET_PSP_HELPERS_H 500c94ca2SJakub Kicinski 6659a2899SJakub Kicinski #include <linux/skbuff.h> 76b46ca26SJakub Kicinski #include <linux/rcupdate.h> 8e9726925SJakub Kicinski #include <linux/udp.h> 9659a2899SJakub Kicinski #include <net/sock.h> 106b46ca26SJakub Kicinski #include <net/tcp.h> 1100c94ca2SJakub Kicinski #include <net/psp/types.h> 1200c94ca2SJakub Kicinski 13ed8a507bSJakub Kicinski struct inet_timewait_sock; 14ed8a507bSJakub Kicinski 1500c94ca2SJakub Kicinski /* Driver-facing API */ 1600c94ca2SJakub Kicinski struct psp_dev * 1700c94ca2SJakub Kicinski psp_dev_create(struct net_device *netdev, struct psp_dev_ops *psd_ops, 1800c94ca2SJakub Kicinski struct psp_dev_caps *psd_caps, void *priv_ptr); 1900c94ca2SJakub Kicinski void psp_dev_unregister(struct psp_dev *psd); 20*fc724515SRaed Salem bool psp_dev_encapsulate(struct net *net, struct sk_buff *skb, __be32 spi, 21*fc724515SRaed Salem u8 ver, __be16 sport); 2200c94ca2SJakub Kicinski 23ed8a507bSJakub Kicinski /* Kernel-facing API */ 246b46ca26SJakub Kicinski void psp_assoc_put(struct psp_assoc *pas); 256b46ca26SJakub Kicinski 266b46ca26SJakub Kicinski static inline void *psp_assoc_drv_data(struct psp_assoc *pas) 276b46ca26SJakub Kicinski { 286b46ca26SJakub Kicinski return pas->drv_data; 296b46ca26SJakub Kicinski } 306b46ca26SJakub Kicinski 31659a2899SJakub Kicinski #if IS_ENABLED(CONFIG_INET_PSP) 326b46ca26SJakub Kicinski unsigned int psp_key_size(u32 version); 336b46ca26SJakub Kicinski void psp_sk_assoc_free(struct sock *sk); 346b46ca26SJakub Kicinski void psp_twsk_init(struct inet_timewait_sock *tw, const struct sock *sk); 356b46ca26SJakub Kicinski void psp_twsk_assoc_free(struct inet_timewait_sock *tw); 366b46ca26SJakub Kicinski void psp_reply_set_decrypted(struct sk_buff *skb); 376b46ca26SJakub Kicinski 386b46ca26SJakub Kicinski static inline struct psp_assoc *psp_sk_assoc(const struct sock *sk) 396b46ca26SJakub Kicinski { 406b46ca26SJakub Kicinski return rcu_dereference_check(sk->psp_assoc, lockdep_sock_is_held(sk)); 416b46ca26SJakub Kicinski } 42659a2899SJakub Kicinski 43659a2899SJakub Kicinski static inline void 44659a2899SJakub Kicinski psp_enqueue_set_decrypted(struct sock *sk, struct sk_buff *skb) 45659a2899SJakub Kicinski { 466b46ca26SJakub Kicinski struct psp_assoc *pas; 476b46ca26SJakub Kicinski 486b46ca26SJakub Kicinski pas = psp_sk_assoc(sk); 496b46ca26SJakub Kicinski if (pas && pas->tx.spi) 506b46ca26SJakub Kicinski skb->decrypted = 1; 51659a2899SJakub Kicinski } 52659a2899SJakub Kicinski 53659a2899SJakub Kicinski static inline unsigned long 54659a2899SJakub Kicinski __psp_skb_coalesce_diff(const struct sk_buff *one, const struct sk_buff *two, 55659a2899SJakub Kicinski unsigned long diffs) 56659a2899SJakub Kicinski { 576b46ca26SJakub Kicinski struct psp_skb_ext *a, *b; 586b46ca26SJakub Kicinski 596b46ca26SJakub Kicinski a = skb_ext_find(one, SKB_EXT_PSP); 606b46ca26SJakub Kicinski b = skb_ext_find(two, SKB_EXT_PSP); 616b46ca26SJakub Kicinski 626b46ca26SJakub Kicinski diffs |= (!!a) ^ (!!b); 636b46ca26SJakub Kicinski if (!diffs && unlikely(a)) 646b46ca26SJakub Kicinski diffs |= memcmp(a, b, sizeof(*a)); 65659a2899SJakub Kicinski return diffs; 66659a2899SJakub Kicinski } 67659a2899SJakub Kicinski 686b46ca26SJakub Kicinski static inline bool 696b46ca26SJakub Kicinski psp_is_allowed_nondata(struct sk_buff *skb, struct psp_assoc *pas) 706b46ca26SJakub Kicinski { 716b46ca26SJakub Kicinski bool fin = !!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN); 726b46ca26SJakub Kicinski u32 end_seq = TCP_SKB_CB(skb)->end_seq; 736b46ca26SJakub Kicinski u32 seq = TCP_SKB_CB(skb)->seq; 746b46ca26SJakub Kicinski bool pure_fin; 756b46ca26SJakub Kicinski 766b46ca26SJakub Kicinski pure_fin = fin && end_seq - seq == 1; 776b46ca26SJakub Kicinski 786b46ca26SJakub Kicinski return seq == end_seq || (pure_fin && seq == pas->upgrade_seq); 796b46ca26SJakub Kicinski } 806b46ca26SJakub Kicinski 816b46ca26SJakub Kicinski static inline bool 826b46ca26SJakub Kicinski psp_pse_matches_pas(struct psp_skb_ext *pse, struct psp_assoc *pas) 836b46ca26SJakub Kicinski { 846b46ca26SJakub Kicinski return pse && pas->rx.spi == pse->spi && 856b46ca26SJakub Kicinski pas->generation == pse->generation && 866b46ca26SJakub Kicinski pas->version == pse->version && 876b46ca26SJakub Kicinski pas->dev_id == pse->dev_id; 886b46ca26SJakub Kicinski } 896b46ca26SJakub Kicinski 906b46ca26SJakub Kicinski static inline enum skb_drop_reason 916b46ca26SJakub Kicinski __psp_sk_rx_policy_check(struct sk_buff *skb, struct psp_assoc *pas) 926b46ca26SJakub Kicinski { 936b46ca26SJakub Kicinski struct psp_skb_ext *pse = skb_ext_find(skb, SKB_EXT_PSP); 946b46ca26SJakub Kicinski 956b46ca26SJakub Kicinski if (!pas) 966b46ca26SJakub Kicinski return pse ? SKB_DROP_REASON_PSP_INPUT : 0; 976b46ca26SJakub Kicinski 986b46ca26SJakub Kicinski if (likely(psp_pse_matches_pas(pse, pas))) { 996b46ca26SJakub Kicinski if (unlikely(!pas->peer_tx)) 1006b46ca26SJakub Kicinski pas->peer_tx = 1; 1016b46ca26SJakub Kicinski 1026b46ca26SJakub Kicinski return 0; 1036b46ca26SJakub Kicinski } 1046b46ca26SJakub Kicinski 1056b46ca26SJakub Kicinski if (!pse) { 1066b46ca26SJakub Kicinski if (!pas->tx.spi || 1076b46ca26SJakub Kicinski (!pas->peer_tx && psp_is_allowed_nondata(skb, pas))) 1086b46ca26SJakub Kicinski return 0; 1096b46ca26SJakub Kicinski } 1106b46ca26SJakub Kicinski 1116b46ca26SJakub Kicinski return SKB_DROP_REASON_PSP_INPUT; 1126b46ca26SJakub Kicinski } 1136b46ca26SJakub Kicinski 114659a2899SJakub Kicinski static inline enum skb_drop_reason 115659a2899SJakub Kicinski psp_sk_rx_policy_check(struct sock *sk, struct sk_buff *skb) 116659a2899SJakub Kicinski { 1176b46ca26SJakub Kicinski return __psp_sk_rx_policy_check(skb, psp_sk_assoc(sk)); 118659a2899SJakub Kicinski } 119659a2899SJakub Kicinski 120659a2899SJakub Kicinski static inline enum skb_drop_reason 121659a2899SJakub Kicinski psp_twsk_rx_policy_check(struct inet_timewait_sock *tw, struct sk_buff *skb) 122659a2899SJakub Kicinski { 1236b46ca26SJakub Kicinski return __psp_sk_rx_policy_check(skb, rcu_dereference(tw->psp_assoc)); 1246b46ca26SJakub Kicinski } 1256b46ca26SJakub Kicinski 1266b46ca26SJakub Kicinski static inline struct psp_assoc *psp_sk_get_assoc_rcu(struct sock *sk) 1276b46ca26SJakub Kicinski { 1286b46ca26SJakub Kicinski struct inet_timewait_sock *tw; 1296b46ca26SJakub Kicinski struct psp_assoc *pas; 1306b46ca26SJakub Kicinski int state; 1316b46ca26SJakub Kicinski 1326b46ca26SJakub Kicinski state = 1 << READ_ONCE(sk->sk_state); 1336b46ca26SJakub Kicinski if (!sk_is_inet(sk) || state & TCPF_NEW_SYN_RECV) 1346b46ca26SJakub Kicinski return NULL; 1356b46ca26SJakub Kicinski 1366b46ca26SJakub Kicinski tw = inet_twsk(sk); 1376b46ca26SJakub Kicinski pas = state & TCPF_TIME_WAIT ? rcu_dereference(tw->psp_assoc) : 1386b46ca26SJakub Kicinski rcu_dereference(sk->psp_assoc); 1396b46ca26SJakub Kicinski return pas; 140659a2899SJakub Kicinski } 141659a2899SJakub Kicinski 142659a2899SJakub Kicinski static inline struct psp_assoc *psp_skb_get_assoc_rcu(struct sk_buff *skb) 143659a2899SJakub Kicinski { 1446b46ca26SJakub Kicinski if (!skb->decrypted || !skb->sk) 145659a2899SJakub Kicinski return NULL; 1466b46ca26SJakub Kicinski 1476b46ca26SJakub Kicinski return psp_sk_get_assoc_rcu(skb->sk); 148659a2899SJakub Kicinski } 149e9726925SJakub Kicinski 150e9726925SJakub Kicinski static inline unsigned int psp_sk_overhead(const struct sock *sk) 151e9726925SJakub Kicinski { 152e9726925SJakub Kicinski int psp_encap = sizeof(struct udphdr) + PSP_HDR_SIZE + PSP_TRL_SIZE; 153e9726925SJakub Kicinski bool has_psp = rcu_access_pointer(sk->psp_assoc); 154e9726925SJakub Kicinski 155e9726925SJakub Kicinski return has_psp ? psp_encap : 0; 156e9726925SJakub Kicinski } 157659a2899SJakub Kicinski #else 158659a2899SJakub Kicinski static inline void psp_sk_assoc_free(struct sock *sk) { } 159659a2899SJakub Kicinski static inline void 160659a2899SJakub Kicinski psp_twsk_init(struct inet_timewait_sock *tw, const struct sock *sk) { } 161659a2899SJakub Kicinski static inline void psp_twsk_assoc_free(struct inet_timewait_sock *tw) { } 162659a2899SJakub Kicinski static inline void 163659a2899SJakub Kicinski psp_reply_set_decrypted(struct sk_buff *skb) { } 164659a2899SJakub Kicinski 1656b46ca26SJakub Kicinski static inline struct psp_assoc *psp_sk_assoc(const struct sock *sk) 1666b46ca26SJakub Kicinski { 1676b46ca26SJakub Kicinski return NULL; 1686b46ca26SJakub Kicinski } 1696b46ca26SJakub Kicinski 170659a2899SJakub Kicinski static inline void 171659a2899SJakub Kicinski psp_enqueue_set_decrypted(struct sock *sk, struct sk_buff *skb) { } 172659a2899SJakub Kicinski 173659a2899SJakub Kicinski static inline unsigned long 174659a2899SJakub Kicinski __psp_skb_coalesce_diff(const struct sk_buff *one, const struct sk_buff *two, 175659a2899SJakub Kicinski unsigned long diffs) 176659a2899SJakub Kicinski { 177659a2899SJakub Kicinski return diffs; 178659a2899SJakub Kicinski } 179659a2899SJakub Kicinski 180659a2899SJakub Kicinski static inline enum skb_drop_reason 181659a2899SJakub Kicinski psp_sk_rx_policy_check(struct sock *sk, struct sk_buff *skb) 182659a2899SJakub Kicinski { 183659a2899SJakub Kicinski return 0; 184659a2899SJakub Kicinski } 185659a2899SJakub Kicinski 186659a2899SJakub Kicinski static inline enum skb_drop_reason 187659a2899SJakub Kicinski psp_twsk_rx_policy_check(struct inet_timewait_sock *tw, struct sk_buff *skb) 188659a2899SJakub Kicinski { 189659a2899SJakub Kicinski return 0; 190659a2899SJakub Kicinski } 191659a2899SJakub Kicinski 192659a2899SJakub Kicinski static inline struct psp_assoc *psp_skb_get_assoc_rcu(struct sk_buff *skb) 193659a2899SJakub Kicinski { 194659a2899SJakub Kicinski return NULL; 195659a2899SJakub Kicinski } 196e9726925SJakub Kicinski 197e9726925SJakub Kicinski static inline unsigned int psp_sk_overhead(const struct sock *sk) 198e9726925SJakub Kicinski { 199e9726925SJakub Kicinski return 0; 200e9726925SJakub Kicinski } 201659a2899SJakub Kicinski #endif 202659a2899SJakub Kicinski 203659a2899SJakub Kicinski static inline unsigned long 204659a2899SJakub Kicinski psp_skb_coalesce_diff(const struct sk_buff *one, const struct sk_buff *two) 205659a2899SJakub Kicinski { 206659a2899SJakub Kicinski return __psp_skb_coalesce_diff(one, two, 0); 207659a2899SJakub Kicinski } 208ed8a507bSJakub Kicinski 20900c94ca2SJakub Kicinski #endif /* __NET_PSP_HELPERS_H */ 210