static unsigned int ip4_hashfn(struct inet_frag_queue *q) { struct ipq *ipq; ipq = container_of(q, struct ipq, q); return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol); }
/* Add an entry to the 'ipq' queue for a newly received IP datagram. * We will (hopefully :-) receive all other fragments of this datagram * in time, so we just create a queue for this datagram, in which we * will insert the received fragments at their respective positions. */ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph) { struct ipq *qp; unsigned int hash; int ihlen; qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC); if (qp == NULL) goto out_nomem; /* Allocate memory for the IP header (plus 8 octets for ICMP). */ ihlen = iph->ihl * 4; qp->iph = (struct iphdr *) frag_kmalloc(64 + 8, GFP_ATOMIC); if (qp->iph == NULL) goto out_free; memcpy(qp->iph, iph, ihlen + 8); qp->len = 0; qp->ihlen = ihlen; qp->fragments = NULL; qp->dev = skb->dev; /* Initialize a timer for this entry. */ init_timer(&qp->timer); qp->timer.expires = 0; /* (to be set later) */ qp->timer.data = (unsigned long) qp; /* pointer to queue */ qp->timer.function = ip_expire; /* expire function */ /* Add this entry to the queue. */ hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol); /* We are in a BH context, no locking necessary. -DaveM */ if((qp->next = ipq_hash[hash]) != NULL) qp->next->pprev = &qp->next; ipq_hash[hash] = qp; qp->pprev = &ipq_hash[hash]; return qp; out_free: frag_kfree_s(qp, sizeof(struct ipq)); out_nomem: NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n")); return(NULL); }
/* Find the correct entry in the "incomplete datagrams" queue for * this IP datagram, and create new one, if nothing is found. */ static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user) { struct inet_frag_queue *q; struct ip4_create_arg arg; unsigned int hash; arg.iph = iph; arg.user = user; hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol); q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash); if (IS_ERR_OR_NULL(q)) { inet_frag_maybe_warn_overflow(q, pr_fmt()); return NULL; } return container_of(q, struct ipq, q); }
/* Find the correct entry in the "incomplete datagrams" queue for * this IP datagram, and create new one, if nothing is found. */ static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user) { struct inet_frag_queue *q; struct ip4_create_arg arg; unsigned int hash; arg.iph = iph; arg.user = user; hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol); q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash); if (q == NULL) goto out_nomem; return container_of(q, struct ipq, q); out_nomem: LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n"); return NULL; }
/* Find the correct entry in the "incomplete datagrams" queue for * this IP datagram, and return the queue entry address if found. */ static inline struct ipq *ip_find(struct iphdr *iph, struct dst_entry *dst) { __u16 id = iph->id; __u32 saddr = iph->saddr; __u32 daddr = iph->daddr; __u8 protocol = iph->protocol; unsigned int hash = ipqhashfn(id, saddr, daddr, protocol); struct ipq *qp; /* Always, we are in a BH context, so no locking. -DaveM */ for(qp = ipq_hash[hash]; qp; qp = qp->next) { if(qp->iph->id == id && qp->iph->saddr == saddr && qp->iph->daddr == daddr && qp->iph->protocol == protocol) { del_timer(&qp->timer); break; } } return qp; }