0001
0002 #ifndef _IPV6_FRAG_H
0003 #define _IPV6_FRAG_H
0004 #include <linux/icmpv6.h>
0005 #include <linux/kernel.h>
0006 #include <net/addrconf.h>
0007 #include <net/ipv6.h>
0008 #include <net/inet_frag.h>
0009
0010 enum ip6_defrag_users {
0011 IP6_DEFRAG_LOCAL_DELIVER,
0012 IP6_DEFRAG_CONNTRACK_IN,
0013 __IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHRT_MAX,
0014 IP6_DEFRAG_CONNTRACK_OUT,
0015 __IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHRT_MAX,
0016 IP6_DEFRAG_CONNTRACK_BRIDGE_IN,
0017 __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX,
0018 };
0019
0020
0021
0022
0023 struct frag_queue {
0024 struct inet_frag_queue q;
0025
0026 int iif;
0027 __u16 nhoffset;
0028 u8 ecn;
0029 };
0030
0031 #if IS_ENABLED(CONFIG_IPV6)
0032 static inline void ip6frag_init(struct inet_frag_queue *q, const void *a)
0033 {
0034 struct frag_queue *fq = container_of(q, struct frag_queue, q);
0035 const struct frag_v6_compare_key *key = a;
0036
0037 q->key.v6 = *key;
0038 fq->ecn = 0;
0039 }
0040
0041 static inline u32 ip6frag_key_hashfn(const void *data, u32 len, u32 seed)
0042 {
0043 return jhash2(data,
0044 sizeof(struct frag_v6_compare_key) / sizeof(u32), seed);
0045 }
0046
0047 static inline u32 ip6frag_obj_hashfn(const void *data, u32 len, u32 seed)
0048 {
0049 const struct inet_frag_queue *fq = data;
0050
0051 return jhash2((const u32 *)&fq->key.v6,
0052 sizeof(struct frag_v6_compare_key) / sizeof(u32), seed);
0053 }
0054
0055 static inline int
0056 ip6frag_obj_cmpfn(struct rhashtable_compare_arg *arg, const void *ptr)
0057 {
0058 const struct frag_v6_compare_key *key = arg->key;
0059 const struct inet_frag_queue *fq = ptr;
0060
0061 return !!memcmp(&fq->key, key, sizeof(*key));
0062 }
0063
0064 static inline void
0065 ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq)
0066 {
0067 struct net_device *dev = NULL;
0068 struct sk_buff *head;
0069
0070 rcu_read_lock();
0071
0072 if (READ_ONCE(fq->q.fqdir->dead))
0073 goto out_rcu_unlock;
0074 spin_lock(&fq->q.lock);
0075
0076 if (fq->q.flags & INET_FRAG_COMPLETE)
0077 goto out;
0078
0079 inet_frag_kill(&fq->q);
0080
0081 dev = dev_get_by_index_rcu(net, fq->iif);
0082 if (!dev)
0083 goto out;
0084
0085 __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
0086 __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);
0087
0088
0089 if (!(fq->q.flags & INET_FRAG_FIRST_IN))
0090 goto out;
0091
0092
0093
0094
0095
0096 head = inet_frag_pull_head(&fq->q);
0097 if (!head)
0098 goto out;
0099
0100 head->dev = dev;
0101 spin_unlock(&fq->q.lock);
0102
0103 icmpv6_send(head, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0);
0104 kfree_skb(head);
0105 goto out_rcu_unlock;
0106
0107 out:
0108 spin_unlock(&fq->q.lock);
0109 out_rcu_unlock:
0110 rcu_read_unlock();
0111 inet_frag_put(&fq->q);
0112 }
0113
0114
0115 static inline bool
0116 ipv6frag_thdr_truncated(struct sk_buff *skb, int start, u8 *nexthdrp)
0117 {
0118 u8 nexthdr = *nexthdrp;
0119 __be16 frag_off;
0120 int offset;
0121
0122 offset = ipv6_skip_exthdr(skb, start, &nexthdr, &frag_off);
0123 if (offset < 0 || (frag_off & htons(IP6_OFFSET)))
0124 return false;
0125 switch (nexthdr) {
0126 case NEXTHDR_TCP:
0127 offset += sizeof(struct tcphdr);
0128 break;
0129 case NEXTHDR_UDP:
0130 offset += sizeof(struct udphdr);
0131 break;
0132 case NEXTHDR_ICMP:
0133 offset += sizeof(struct icmp6hdr);
0134 break;
0135 default:
0136 offset += 1;
0137 }
0138 if (offset > skb->len)
0139 return true;
0140 return false;
0141 }
0142
0143 #endif
0144 #endif