static __inline__ struct frag_queue * fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, struct inet6_dev *idev) { struct inet_frag_queue *q; struct ip6_create_arg arg; unsigned int hash; arg.id = id; arg.user = IP6_DEFRAG_LOCAL_DELIVER; arg.src = src; arg.dst = dst; read_lock(&ip6_frags.lock); hash = ip6qhashfn(id, src, dst); q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); if (q == NULL) goto oom; return container_of(q, struct frag_queue, q); oom: IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS); return NULL; }
static unsigned int ip6_hashfn(struct inet_frag_queue *q) { struct frag_queue *fq; fq = container_of(q, struct frag_queue, q); return ip6qhashfn(fq->id, &fq->saddr, &fq->daddr); }
static __inline__ struct nf_ct_frag6_queue * fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst) { struct nf_ct_frag6_queue *fq; unsigned int hash = ip6qhashfn(id, src, dst); read_lock(&nf_ct_frag6_lock); for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) { if (fq->id == id && !ipv6_addr_cmp(src, &fq->saddr) && !ipv6_addr_cmp(dst, &fq->daddr)) { atomic_inc(&fq->refcnt); read_unlock(&nf_ct_frag6_lock); return fq; } } read_unlock(&nf_ct_frag6_lock); return nf_ct_frag6_create(hash, id, src, dst); }
static void nf_ct_frag6_secret_rebuild(unsigned long dummy) { unsigned long now = jiffies; int i; write_lock(&nf_ct_frag6_lock); get_random_bytes(&nf_ct_frag6_hash_rnd, sizeof(u32)); for (i = 0; i < FRAG6Q_HASHSZ; i++) { struct nf_ct_frag6_queue *q; q = nf_ct_frag6_hash[i]; while (q) { struct nf_ct_frag6_queue *next = q->next; unsigned int hval = ip6qhashfn(q->id, &q->saddr, &q->daddr); if (hval != i) { /* Unlink. */ if (q->next) q->next->pprev = q->pprev; *q->pprev = q->next; /* Relink to new hash chain. */ if ((q->next = nf_ct_frag6_hash[hval]) != NULL) q->next->pprev = &q->next; nf_ct_frag6_hash[hval] = q; q->pprev = &nf_ct_frag6_hash[hval]; } q = next; } } write_unlock(&nf_ct_frag6_lock); mod_timer(&nf_ct_frag6_secret_timer, now + nf_ct_frag6_secret_interval); }