aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_fragment.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ip_fragment.c')
-rw-r--r--net/ipv4/ip_fragment.c159
1 files changed, 51 insertions, 108 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 443b3f89192f..2143bf30597a 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -108,6 +108,11 @@ int ip_frag_mem(void)
108static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, 108static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
109 struct net_device *dev); 109 struct net_device *dev);
110 110
111struct ip4_create_arg {
112 struct iphdr *iph;
113 u32 user;
114};
115
111static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot) 116static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot)
112{ 117{
113 return jhash_3words((__force u32)id << 16 | prot, 118 return jhash_3words((__force u32)id << 16 | prot,
@@ -123,6 +128,19 @@ static unsigned int ip4_hashfn(struct inet_frag_queue *q)
123 return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol); 128 return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol);
124} 129}
125 130
131static int ip4_frag_match(struct inet_frag_queue *q, void *a)
132{
133 struct ipq *qp;
134 struct ip4_create_arg *arg = a;
135
136 qp = container_of(q, struct ipq, q);
137 return (qp->id == arg->iph->id &&
138 qp->saddr == arg->iph->saddr &&
139 qp->daddr == arg->iph->daddr &&
140 qp->protocol == arg->iph->protocol &&
141 qp->user == arg->user);
142}
143
126/* Memory Tracking Functions. */ 144/* Memory Tracking Functions. */
127static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work) 145static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work)
128{ 146{
@@ -132,6 +150,20 @@ static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work)
132 kfree_skb(skb); 150 kfree_skb(skb);
133} 151}
134 152
153static void ip4_frag_init(struct inet_frag_queue *q, void *a)
154{
155 struct ipq *qp = container_of(q, struct ipq, q);
156 struct ip4_create_arg *arg = a;
157
158 qp->protocol = arg->iph->protocol;
159 qp->id = arg->iph->id;
160 qp->saddr = arg->iph->saddr;
161 qp->daddr = arg->iph->daddr;
162 qp->user = arg->user;
163 qp->peer = sysctl_ipfrag_max_dist ?
164 inet_getpeer(arg->iph->saddr, 1) : NULL;
165}
166
135static __inline__ void ip4_frag_free(struct inet_frag_queue *q) 167static __inline__ void ip4_frag_free(struct inet_frag_queue *q)
136{ 168{
137 struct ipq *qp; 169 struct ipq *qp;
@@ -139,17 +171,6 @@ static __inline__ void ip4_frag_free(struct inet_frag_queue *q)
139 qp = container_of(q, struct ipq, q); 171 qp = container_of(q, struct ipq, q);
140 if (qp->peer) 172 if (qp->peer)
141 inet_putpeer(qp->peer); 173 inet_putpeer(qp->peer);
142 kfree(qp);
143}
144
145static __inline__ struct ipq *frag_alloc_queue(void)
146{
147 struct ipq *qp = kzalloc(sizeof(struct ipq), GFP_ATOMIC);
148
149 if (!qp)
150 return NULL;
151 atomic_add(sizeof(struct ipq), &ip4_frags.mem);
152 return qp;
153} 174}
154 175
155 176
@@ -185,7 +206,9 @@ static void ip_evictor(void)
185 */ 206 */
186static void ip_expire(unsigned long arg) 207static void ip_expire(unsigned long arg)
187{ 208{
188 struct ipq *qp = (struct ipq *) arg; 209 struct ipq *qp;
210
211 qp = container_of((struct inet_frag_queue *) arg, struct ipq, q);
189 212
190 spin_lock(&qp->q.lock); 213 spin_lock(&qp->q.lock);
191 214
@@ -210,112 +233,30 @@ out:
210 ipq_put(qp); 233 ipq_put(qp);
211} 234}
212 235
213/* Creation primitives. */ 236/* Find the correct entry in the "incomplete datagrams" queue for
214 237 * this IP datagram, and create new one, if nothing is found.
215static struct ipq *ip_frag_intern(struct ipq *qp_in) 238 */
239static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
216{ 240{
217 struct ipq *qp; 241 struct inet_frag_queue *q;
218#ifdef CONFIG_SMP 242 struct ip4_create_arg arg;
219 struct hlist_node *n;
220#endif
221 unsigned int hash; 243 unsigned int hash;
222 244
223 write_lock(&ip4_frags.lock); 245 arg.iph = iph;
224 hash = ipqhashfn(qp_in->id, qp_in->saddr, qp_in->daddr, 246 arg.user = user;
225 qp_in->protocol); 247 hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
226#ifdef CONFIG_SMP
227 /* With SMP race we have to recheck hash table, because
228 * such entry could be created on other cpu, while we
229 * promoted read lock to write lock.
230 */
231 hlist_for_each_entry(qp, n, &ip4_frags.hash[hash], q.list) {
232 if (qp->id == qp_in->id &&
233 qp->saddr == qp_in->saddr &&
234 qp->daddr == qp_in->daddr &&
235 qp->protocol == qp_in->protocol &&
236 qp->user == qp_in->user) {
237 atomic_inc(&qp->q.refcnt);
238 write_unlock(&ip4_frags.lock);
239 qp_in->q.last_in |= COMPLETE;
240 ipq_put(qp_in);
241 return qp;
242 }
243 }
244#endif
245 qp = qp_in;
246
247 if (!mod_timer(&qp->q.timer, jiffies + ip4_frags_ctl.timeout))
248 atomic_inc(&qp->q.refcnt);
249 248
250 atomic_inc(&qp->q.refcnt); 249 q = inet_frag_find(&ip4_frags, &arg, hash);
251 hlist_add_head(&qp->q.list, &ip4_frags.hash[hash]); 250 if (q == NULL)
252 INIT_LIST_HEAD(&qp->q.lru_list);
253 list_add_tail(&qp->q.lru_list, &ip4_frags.lru_list);
254 ip4_frags.nqueues++;
255 write_unlock(&ip4_frags.lock);
256 return qp;
257}
258
259/* Add an entry to the 'ipq' queue for a newly received IP datagram. */
260static struct ipq *ip_frag_create(struct iphdr *iph, u32 user)
261{
262 struct ipq *qp;
263
264 if ((qp = frag_alloc_queue()) == NULL)
265 goto out_nomem; 251 goto out_nomem;
266 252
267 qp->protocol = iph->protocol; 253 return container_of(q, struct ipq, q);
268 qp->id = iph->id;
269 qp->saddr = iph->saddr;
270 qp->daddr = iph->daddr;
271 qp->user = user;
272 qp->peer = sysctl_ipfrag_max_dist ? inet_getpeer(iph->saddr, 1) : NULL;
273
274 /* Initialize a timer for this entry. */
275 init_timer(&qp->q.timer);
276 qp->q.timer.data = (unsigned long) qp; /* pointer to queue */
277 qp->q.timer.function = ip_expire; /* expire function */
278 spin_lock_init(&qp->q.lock);
279 atomic_set(&qp->q.refcnt, 1);
280
281 return ip_frag_intern(qp);
282 254
283out_nomem: 255out_nomem:
284 LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n"); 256 LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n");
285 return NULL; 257 return NULL;
286} 258}
287 259
288/* Find the correct entry in the "incomplete datagrams" queue for
289 * this IP datagram, and create new one, if nothing is found.
290 */
291static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
292{
293 __be16 id = iph->id;
294 __be32 saddr = iph->saddr;
295 __be32 daddr = iph->daddr;
296 __u8 protocol = iph->protocol;
297 unsigned int hash;
298 struct ipq *qp;
299 struct hlist_node *n;
300
301 read_lock(&ip4_frags.lock);
302 hash = ipqhashfn(id, saddr, daddr, protocol);
303 hlist_for_each_entry(qp, n, &ip4_frags.hash[hash], q.list) {
304 if (qp->id == id &&
305 qp->saddr == saddr &&
306 qp->daddr == daddr &&
307 qp->protocol == protocol &&
308 qp->user == user) {
309 atomic_inc(&qp->q.refcnt);
310 read_unlock(&ip4_frags.lock);
311 return qp;
312 }
313 }
314 read_unlock(&ip4_frags.lock);
315
316 return ip_frag_create(iph, user);
317}
318
319/* Is the fragment too far ahead to be part of ipq? */ 260/* Is the fragment too far ahead to be part of ipq? */
320static inline int ip_frag_too_far(struct ipq *qp) 261static inline int ip_frag_too_far(struct ipq *qp)
321{ 262{
@@ -545,7 +486,6 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
545 if (prev) { 486 if (prev) {
546 head = prev->next; 487 head = prev->next;
547 fp = skb_clone(head, GFP_ATOMIC); 488 fp = skb_clone(head, GFP_ATOMIC);
548
549 if (!fp) 489 if (!fp)
550 goto out_nomem; 490 goto out_nomem;
551 491
@@ -571,7 +511,6 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
571 goto out_oversize; 511 goto out_oversize;
572 512
573 /* Head of list must not be cloned. */ 513 /* Head of list must not be cloned. */
574 err = -ENOMEM;
575 if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) 514 if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
576 goto out_nomem; 515 goto out_nomem;
577 516
@@ -627,6 +566,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
627out_nomem: 566out_nomem:
628 LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing " 567 LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing "
629 "queue %p\n", qp); 568 "queue %p\n", qp);
569 err = -ENOMEM;
630 goto out_fail; 570 goto out_fail;
631out_oversize: 571out_oversize:
632 if (net_ratelimit()) 572 if (net_ratelimit())
@@ -671,9 +611,12 @@ void __init ipfrag_init(void)
671{ 611{
672 ip4_frags.ctl = &ip4_frags_ctl; 612 ip4_frags.ctl = &ip4_frags_ctl;
673 ip4_frags.hashfn = ip4_hashfn; 613 ip4_frags.hashfn = ip4_hashfn;
614 ip4_frags.constructor = ip4_frag_init;
674 ip4_frags.destructor = ip4_frag_free; 615 ip4_frags.destructor = ip4_frag_free;
675 ip4_frags.skb_free = NULL; 616 ip4_frags.skb_free = NULL;
676 ip4_frags.qsize = sizeof(struct ipq); 617 ip4_frags.qsize = sizeof(struct ipq);
618 ip4_frags.match = ip4_frag_match;
619 ip4_frags.frag_expire = ip_expire;
677 inet_frags_init(&ip4_frags); 620 inet_frags_init(&ip4_frags);
678} 621}
679 622