1 /* SPDX-License-Identifier: GPL-2.0 */
4 #include <linux/kernel.h>
5 #include <net/addrconf.h>
7 #include <net/inet_frag.h>
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
,
20 * Equivalent of ipv4 struct ip
23 struct inet_frag_queue q
;
30 #if IS_ENABLED(CONFIG_IPV6)
31 static inline void ip6frag_init(struct inet_frag_queue
*q
, const void *a
)
33 struct frag_queue
*fq
= container_of(q
, struct frag_queue
, q
);
34 const struct frag_v6_compare_key
*key
= a
;
40 static inline u32
ip6frag_key_hashfn(const void *data
, u32 len
, u32 seed
)
43 sizeof(struct frag_v6_compare_key
) / sizeof(u32
), seed
);
46 static inline u32
ip6frag_obj_hashfn(const void *data
, u32 len
, u32 seed
)
48 const struct inet_frag_queue
*fq
= data
;
50 return jhash2((const u32
*)&fq
->key
.v6
,
51 sizeof(struct frag_v6_compare_key
) / sizeof(u32
), seed
);
55 ip6frag_obj_cmpfn(struct rhashtable_compare_arg
*arg
, const void *ptr
)
57 const struct frag_v6_compare_key
*key
= arg
->key
;
58 const struct inet_frag_queue
*fq
= ptr
;
60 return !!memcmp(&fq
->key
, key
, sizeof(*key
));
64 ip6frag_expire_frag_queue(struct net
*net
, struct frag_queue
*fq
)
66 struct net_device
*dev
= NULL
;
70 spin_lock(&fq
->q
.lock
);
72 if (fq
->q
.flags
& INET_FRAG_COMPLETE
)
75 inet_frag_kill(&fq
->q
);
77 dev
= dev_get_by_index_rcu(net
, fq
->iif
);
81 __IP6_INC_STATS(net
, __in6_dev_get(dev
), IPSTATS_MIB_REASMFAILS
);
82 __IP6_INC_STATS(net
, __in6_dev_get(dev
), IPSTATS_MIB_REASMTIMEOUT
);
84 /* Don't send error if the first segment did not arrive. */
85 if (!(fq
->q
.flags
& INET_FRAG_FIRST_IN
))
88 /* sk_buff::dev and sk_buff::rbnode are unionized. So we
89 * pull the head out of the tree in order to be able to
90 * deal with head->dev.
92 head
= inet_frag_pull_head(&fq
->q
);
98 spin_unlock(&fq
->q
.lock
);
100 icmpv6_send(head
, ICMPV6_TIME_EXCEED
, ICMPV6_EXC_FRAGTIME
, 0);
105 spin_unlock(&fq
->q
.lock
);
108 inet_frag_put(&fq
->q
);