| .. | .. |
|---|
| 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 |
|---|