18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef __NET_FRAG_H__ 38c2ecf20Sopenharmony_ci#define __NET_FRAG_H__ 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/rhashtable-types.h> 68c2ecf20Sopenharmony_ci#include <linux/completion.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* Per netns frag queues directory */ 98c2ecf20Sopenharmony_cistruct fqdir { 108c2ecf20Sopenharmony_ci /* sysctls */ 118c2ecf20Sopenharmony_ci long high_thresh; 128c2ecf20Sopenharmony_ci long low_thresh; 138c2ecf20Sopenharmony_ci int timeout; 148c2ecf20Sopenharmony_ci int max_dist; 158c2ecf20Sopenharmony_ci struct inet_frags *f; 168c2ecf20Sopenharmony_ci struct net *net; 178c2ecf20Sopenharmony_ci bool dead; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci struct rhashtable rhashtable ____cacheline_aligned_in_smp; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci /* Keep atomic mem on separate cachelines in structs that include it */ 228c2ecf20Sopenharmony_ci atomic_long_t mem ____cacheline_aligned_in_smp; 238c2ecf20Sopenharmony_ci struct work_struct destroy_work; 248c2ecf20Sopenharmony_ci}; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/** 278c2ecf20Sopenharmony_ci * fragment queue flags 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * @INET_FRAG_FIRST_IN: first fragment has arrived 308c2ecf20Sopenharmony_ci * @INET_FRAG_LAST_IN: final fragment has arrived 318c2ecf20Sopenharmony_ci * @INET_FRAG_COMPLETE: frag queue has been processed and is due for destruction 328c2ecf20Sopenharmony_ci * @INET_FRAG_HASH_DEAD: inet_frag_kill() has not removed fq from rhashtable 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cienum { 358c2ecf20Sopenharmony_ci INET_FRAG_FIRST_IN = BIT(0), 368c2ecf20Sopenharmony_ci INET_FRAG_LAST_IN = BIT(1), 378c2ecf20Sopenharmony_ci INET_FRAG_COMPLETE = BIT(2), 388c2ecf20Sopenharmony_ci INET_FRAG_HASH_DEAD = BIT(3), 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistruct frag_v4_compare_key { 428c2ecf20Sopenharmony_ci __be32 saddr; 438c2ecf20Sopenharmony_ci __be32 daddr; 448c2ecf20Sopenharmony_ci u32 user; 458c2ecf20Sopenharmony_ci u32 vif; 468c2ecf20Sopenharmony_ci __be16 id; 478c2ecf20Sopenharmony_ci u16 protocol; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct frag_v6_compare_key { 518c2ecf20Sopenharmony_ci struct in6_addr saddr; 528c2ecf20Sopenharmony_ci struct in6_addr daddr; 538c2ecf20Sopenharmony_ci u32 user; 548c2ecf20Sopenharmony_ci __be32 id; 558c2ecf20Sopenharmony_ci u32 iif; 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/** 598c2ecf20Sopenharmony_ci * struct inet_frag_queue - fragment queue 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * @node: rhash node 628c2ecf20Sopenharmony_ci * @key: keys identifying this frag. 638c2ecf20Sopenharmony_ci * @timer: queue expiration timer 648c2ecf20Sopenharmony_ci * @lock: spinlock protecting this frag 658c2ecf20Sopenharmony_ci * @refcnt: reference count of the queue 668c2ecf20Sopenharmony_ci * @rb_fragments: received fragments rb-tree root 678c2ecf20Sopenharmony_ci * @fragments_tail: received fragments tail 688c2ecf20Sopenharmony_ci * @last_run_head: the head of the last "run". see ip_fragment.c 698c2ecf20Sopenharmony_ci * @stamp: timestamp of the last received fragment 708c2ecf20Sopenharmony_ci * @len: total length of the original datagram 718c2ecf20Sopenharmony_ci * @meat: length of received fragments so far 728c2ecf20Sopenharmony_ci * @flags: fragment queue flags 738c2ecf20Sopenharmony_ci * @max_size: maximum received fragment size 748c2ecf20Sopenharmony_ci * @fqdir: pointer to struct fqdir 758c2ecf20Sopenharmony_ci * @rcu: rcu head for freeing deferall 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_cistruct inet_frag_queue { 788c2ecf20Sopenharmony_ci struct rhash_head node; 798c2ecf20Sopenharmony_ci union { 808c2ecf20Sopenharmony_ci struct frag_v4_compare_key v4; 818c2ecf20Sopenharmony_ci struct frag_v6_compare_key v6; 828c2ecf20Sopenharmony_ci } key; 838c2ecf20Sopenharmony_ci struct timer_list timer; 848c2ecf20Sopenharmony_ci spinlock_t lock; 858c2ecf20Sopenharmony_ci refcount_t refcnt; 868c2ecf20Sopenharmony_ci struct rb_root rb_fragments; 878c2ecf20Sopenharmony_ci struct sk_buff *fragments_tail; 888c2ecf20Sopenharmony_ci struct sk_buff *last_run_head; 898c2ecf20Sopenharmony_ci ktime_t stamp; 908c2ecf20Sopenharmony_ci int len; 918c2ecf20Sopenharmony_ci int meat; 928c2ecf20Sopenharmony_ci __u8 flags; 938c2ecf20Sopenharmony_ci u16 max_size; 948c2ecf20Sopenharmony_ci struct fqdir *fqdir; 958c2ecf20Sopenharmony_ci struct rcu_head rcu; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistruct inet_frags { 998c2ecf20Sopenharmony_ci unsigned int qsize; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci void (*constructor)(struct inet_frag_queue *q, 1028c2ecf20Sopenharmony_ci const void *arg); 1038c2ecf20Sopenharmony_ci void (*destructor)(struct inet_frag_queue *); 1048c2ecf20Sopenharmony_ci void (*frag_expire)(struct timer_list *t); 1058c2ecf20Sopenharmony_ci struct kmem_cache *frags_cachep; 1068c2ecf20Sopenharmony_ci const char *frags_cache_name; 1078c2ecf20Sopenharmony_ci struct rhashtable_params rhash_params; 1088c2ecf20Sopenharmony_ci refcount_t refcnt; 1098c2ecf20Sopenharmony_ci struct completion completion; 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciint inet_frags_init(struct inet_frags *); 1138c2ecf20Sopenharmony_civoid inet_frags_fini(struct inet_frags *); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciint fqdir_init(struct fqdir **fqdirp, struct inet_frags *f, struct net *net); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic inline void fqdir_pre_exit(struct fqdir *fqdir) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci /* Prevent creation of new frags. 1208c2ecf20Sopenharmony_ci * Pairs with READ_ONCE() in inet_frag_find(). 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci WRITE_ONCE(fqdir->high_thresh, 0); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* Pairs with READ_ONCE() in inet_frag_kill(), ip_expire() 1258c2ecf20Sopenharmony_ci * and ip6frag_expire_frag_queue(). 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci WRITE_ONCE(fqdir->dead, true); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_civoid fqdir_exit(struct fqdir *fqdir); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_civoid inet_frag_kill(struct inet_frag_queue *q); 1328c2ecf20Sopenharmony_civoid inet_frag_destroy(struct inet_frag_queue *q); 1338c2ecf20Sopenharmony_cistruct inet_frag_queue *inet_frag_find(struct fqdir *fqdir, void *key); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* Free all skbs in the queue; return the sum of their truesizes. */ 1368c2ecf20Sopenharmony_ciunsigned int inet_frag_rbtree_purge(struct rb_root *root); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic inline void inet_frag_put(struct inet_frag_queue *q) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&q->refcnt)) 1418c2ecf20Sopenharmony_ci inet_frag_destroy(q); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* Memory Tracking Functions. */ 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic inline long frag_mem_limit(const struct fqdir *fqdir) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci return atomic_long_read(&fqdir->mem); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic inline void sub_frag_mem_limit(struct fqdir *fqdir, long val) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci atomic_long_sub(val, &fqdir->mem); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic inline void add_frag_mem_limit(struct fqdir *fqdir, long val) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci atomic_long_add(val, &fqdir->mem); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* RFC 3168 support : 1628c2ecf20Sopenharmony_ci * We want to check ECN values of all fragments, do detect invalid combinations. 1638c2ecf20Sopenharmony_ci * In ipq->ecn, we store the OR value of each ip4_frag_ecn() fragment value. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci#define IPFRAG_ECN_NOT_ECT 0x01 /* one frag had ECN_NOT_ECT */ 1668c2ecf20Sopenharmony_ci#define IPFRAG_ECN_ECT_1 0x02 /* one frag had ECN_ECT_1 */ 1678c2ecf20Sopenharmony_ci#define IPFRAG_ECN_ECT_0 0x04 /* one frag had ECN_ECT_0 */ 1688c2ecf20Sopenharmony_ci#define IPFRAG_ECN_CE 0x08 /* one frag had ECN_CE */ 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciextern const u8 ip_frag_ecn_table[16]; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* Return values of inet_frag_queue_insert() */ 1738c2ecf20Sopenharmony_ci#define IPFRAG_OK 0 1748c2ecf20Sopenharmony_ci#define IPFRAG_DUP 1 1758c2ecf20Sopenharmony_ci#define IPFRAG_OVERLAP 2 1768c2ecf20Sopenharmony_ciint inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb, 1778c2ecf20Sopenharmony_ci int offset, int end); 1788c2ecf20Sopenharmony_civoid *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb, 1798c2ecf20Sopenharmony_ci struct sk_buff *parent); 1808c2ecf20Sopenharmony_civoid inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head, 1818c2ecf20Sopenharmony_ci void *reasm_data, bool try_coalesce); 1828c2ecf20Sopenharmony_cistruct sk_buff *inet_frag_pull_head(struct inet_frag_queue *q); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#endif 185