.. | .. |
---|
67 | 67 | struct sk_buff *head; |
---|
68 | 68 | |
---|
69 | 69 | rcu_read_lock(); |
---|
| 70 | + /* Paired with the WRITE_ONCE() in fqdir_pre_exit(). */ |
---|
| 71 | + if (READ_ONCE(fq->q.fqdir->dead)) |
---|
| 72 | + goto out_rcu_unlock; |
---|
70 | 73 | spin_lock(&fq->q.lock); |
---|
71 | 74 | |
---|
72 | 75 | if (fq->q.flags & INET_FRAG_COMPLETE) |
---|
.. | .. |
---|
106 | 109 | rcu_read_unlock(); |
---|
107 | 110 | inet_frag_put(&fq->q); |
---|
108 | 111 | } |
---|
| 112 | + |
---|
| 113 | +/* Check if the upper layer header is truncated in the first fragment. */ |
---|
| 114 | +static inline bool |
---|
| 115 | +ipv6frag_thdr_truncated(struct sk_buff *skb, int start, u8 *nexthdrp) |
---|
| 116 | +{ |
---|
| 117 | + u8 nexthdr = *nexthdrp; |
---|
| 118 | + __be16 frag_off; |
---|
| 119 | + int offset; |
---|
| 120 | + |
---|
| 121 | + offset = ipv6_skip_exthdr(skb, start, &nexthdr, &frag_off); |
---|
| 122 | + if (offset < 0 || (frag_off & htons(IP6_OFFSET))) |
---|
| 123 | + return false; |
---|
| 124 | + switch (nexthdr) { |
---|
| 125 | + case NEXTHDR_TCP: |
---|
| 126 | + offset += sizeof(struct tcphdr); |
---|
| 127 | + break; |
---|
| 128 | + case NEXTHDR_UDP: |
---|
| 129 | + offset += sizeof(struct udphdr); |
---|
| 130 | + break; |
---|
| 131 | + case NEXTHDR_ICMP: |
---|
| 132 | + offset += sizeof(struct icmp6hdr); |
---|
| 133 | + break; |
---|
| 134 | + default: |
---|
| 135 | + offset += 1; |
---|
| 136 | + } |
---|
| 137 | + if (offset > skb->len) |
---|
| 138 | + return true; |
---|
| 139 | + return false; |
---|
| 140 | +} |
---|
| 141 | + |
---|
109 | 142 | #endif |
---|
110 | 143 | #endif |
---|