Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0 */ 2 : : #ifndef _IPV6_FRAG_H 3 : : #define _IPV6_FRAG_H 4 : : #include <linux/kernel.h> 5 : : #include <net/addrconf.h> 6 : : #include <net/ipv6.h> 7 : : #include <net/inet_frag.h> 8 : : 9 : : enum ip6_defrag_users { 10 : : IP6_DEFRAG_LOCAL_DELIVER, 11 : : IP6_DEFRAG_CONNTRACK_IN, 12 : : __IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHRT_MAX, 13 : : IP6_DEFRAG_CONNTRACK_OUT, 14 : : __IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHRT_MAX, 15 : : IP6_DEFRAG_CONNTRACK_BRIDGE_IN, 16 : : __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX, 17 : : }; 18 : : 19 : : /* 20 : : * Equivalent of ipv4 struct ip 21 : : */ 22 : : struct frag_queue { 23 : : struct inet_frag_queue q; 24 : : 25 : : int iif; 26 : : __u16 nhoffset; 27 : : u8 ecn; 28 : : }; 29 : : 30 : : #if IS_ENABLED(CONFIG_IPV6) 31 : 0 : static inline void ip6frag_init(struct inet_frag_queue *q, const void *a) 32 : : { 33 : : struct frag_queue *fq = container_of(q, struct frag_queue, q); 34 : : const struct frag_v6_compare_key *key = a; 35 : : 36 : 0 : q->key.v6 = *key; 37 : 0 : fq->ecn = 0; 38 : 0 : } 39 : : 40 : 0 : static inline u32 ip6frag_key_hashfn(const void *data, u32 len, u32 seed) 41 : : { 42 : 0 : return jhash2(data, 43 : : sizeof(struct frag_v6_compare_key) / sizeof(u32), seed); 44 : : } 45 : : 46 : 0 : static inline u32 ip6frag_obj_hashfn(const void *data, u32 len, u32 seed) 47 : : { 48 : : const struct inet_frag_queue *fq = data; 49 : : 50 : 0 : return jhash2((const u32 *)&fq->key.v6, 51 : : sizeof(struct frag_v6_compare_key) / sizeof(u32), seed); 52 : : } 53 : : 54 : : static inline int 55 : 0 : ip6frag_obj_cmpfn(struct rhashtable_compare_arg *arg, const void *ptr) 56 : : { 57 : 0 : const struct frag_v6_compare_key *key = arg->key; 58 : : const struct inet_frag_queue *fq = ptr; 59 : : 60 : 0 : return !!memcmp(&fq->key, key, sizeof(*key)); 61 : : } 62 : : 63 : : static inline void 64 : 0 : ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq) 65 : : { 66 : : struct net_device *dev = NULL; 67 : : struct sk_buff *head; 68 : : 69 : : rcu_read_lock(); 70 [ # # ]: 0 : if (fq->q.fqdir->dead) 71 : : goto out_rcu_unlock; 72 : : spin_lock(&fq->q.lock); 73 : : 74 [ # # ]: 0 : if (fq->q.flags & INET_FRAG_COMPLETE) 75 : : goto out; 76 : : 77 : 0 : inet_frag_kill(&fq->q); 78 : : 79 : 0 : dev = dev_get_by_index_rcu(net, fq->iif); 80 [ # # ]: 0 : if (!dev) 81 : : goto out; 82 : : 83 [ # # ]: 0 : __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); 84 [ # # ]: 0 : __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); 85 : : 86 : : /* Don't send error if the first segment did not arrive. */ 87 [ # # ]: 0 : if (!(fq->q.flags & INET_FRAG_FIRST_IN)) 88 : : goto out; 89 : : 90 : : /* sk_buff::dev and sk_buff::rbnode are unionized. So we 91 : : * pull the head out of the tree in order to be able to 92 : : * deal with head->dev. 93 : : */ 94 : 0 : head = inet_frag_pull_head(&fq->q); 95 [ # # ]: 0 : if (!head) 96 : : goto out; 97 : : 98 : 0 : head->dev = dev; 99 : : spin_unlock(&fq->q.lock); 100 : : 101 : 0 : icmpv6_send(head, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0); 102 : 0 : kfree_skb(head); 103 : 0 : goto out_rcu_unlock; 104 : : 105 : : out: 106 : : spin_unlock(&fq->q.lock); 107 : : out_rcu_unlock: 108 : : rcu_read_unlock(); 109 : 0 : inet_frag_put(&fq->q); 110 : 0 : } 111 : : #endif 112 : : #endif