ip_fragment.c 16.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6
/*
 * INET		An implementation of the TCP/IP protocol suite for the LINUX
 *		operating system.  INET is implemented using the  BSD Socket
 *		interface as the means of communication with the user level.
 *
 *		The IP fragmentation functionality.
7
 *
L
Linus Torvalds 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * Version:	$Id: ip_fragment.c,v 1.59 2002/01/12 07:54:56 davem Exp $
 *
 * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
 *		Alan Cox <Alan.Cox@linux.org>
 *
 * Fixes:
 *		Alan Cox	:	Split from ip.c , see ip_input.c for history.
 *		David S. Miller :	Begin massive cleanup...
 *		Andi Kleen	:	Add sysctls.
 *		xxxx		:	Overlapfrag bug.
 *		Ultima          :       ip_expire() kernel panic.
 *		Bill Hawes	:	Frag accounting and evictor fixes.
 *		John McDonald	:	0 length frag bug.
 *		Alexey Kuznetsov:	SMP races, threading, cleanup.
 *		Patrick McHardy :	LRU queue of frag heads for evictor.
 */

H
Herbert Xu 已提交
25
#include <linux/compiler.h>
L
Linus Torvalds 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
#include <linux/module.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/jiffies.h>
#include <linux/skbuff.h>
#include <linux/list.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/netdevice.h>
#include <linux/jhash.h>
#include <linux/random.h>
#include <net/sock.h>
#include <net/ip.h>
#include <net/icmp.h>
#include <net/checksum.h>
H
Herbert Xu 已提交
41
#include <net/inetpeer.h>
42
#include <net/inet_frag.h>
L
Linus Torvalds 已提交
43 44 45 46 47 48 49 50 51 52
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/inet.h>
#include <linux/netfilter_ipv4.h>

/* NOTE. Logic of IP defragmentation is parallel to corresponding IPv6
 * code now. If you change something here, _PLEASE_ update ipv6/reassembly.c
 * as well. Or notify me, at least. --ANK
 */

53
static int sysctl_ipfrag_max_dist __read_mostly = 64;
H
Herbert Xu 已提交
54

L
Linus Torvalds 已提交
55 56 57 58 59 60 61 62 63 64
struct ipfrag_skb_cb
{
	struct inet_skb_parm	h;
	int			offset;
};

#define FRAG_CB(skb)	((struct ipfrag_skb_cb*)((skb)->cb))

/* Describe an entry in the "incomplete datagrams" queue. */
struct ipq {
65 66
	struct inet_frag_queue q;

L
Linus Torvalds 已提交
67
	u32		user;
68 69 70
	__be32		saddr;
	__be32		daddr;
	__be16		id;
L
Linus Torvalds 已提交
71
	u8		protocol;
H
Herbert Xu 已提交
72 73 74
	int             iif;
	unsigned int    rid;
	struct inet_peer *peer;
L
Linus Torvalds 已提交
75 76
};

77
static struct inet_frags_ctl ip4_frags_ctl __read_mostly = {
78 79 80 81 82 83 84 85 86 87 88
	/*
	 * Fragment cache limits. We will commit 256K at one time. Should we
	 * cross that limit we will prune down to 192K. This should cope with
	 * even the most extreme cases without allowing an attacker to
	 * measurably harm machine performance.
	 */
	.high_thresh	 = 256 * 1024,
	.low_thresh	 = 192 * 1024,
	.secret_interval = 10 * 60 * HZ,
};

89
static struct inet_frags ip4_frags;
L
Linus Torvalds 已提交
90

91
int ip_frag_nqueues(struct net *net)
92
{
93
	return net->ipv4.frags.nqueues;
94
}
L
Linus Torvalds 已提交
95

96
int ip_frag_mem(struct net *net)
97
{
98
	return atomic_read(&net->ipv4.frags.mem);
99
}
L
Linus Torvalds 已提交
100

101 102 103
static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
			 struct net_device *dev);

104 105 106 107 108
struct ip4_create_arg {
	struct iphdr *iph;
	u32 user;
};

109
static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot)
L
Linus Torvalds 已提交
110
{
111 112
	return jhash_3words((__force u32)id << 16 | prot,
			    (__force u32)saddr, (__force u32)daddr,
113
			    ip4_frags.rnd) & (INETFRAGS_HASHSZ - 1);
L
Linus Torvalds 已提交
114 115
}

116
static unsigned int ip4_hashfn(struct inet_frag_queue *q)
L
Linus Torvalds 已提交
117
{
118
	struct ipq *ipq;
L
Linus Torvalds 已提交
119

120 121
	ipq = container_of(q, struct ipq, q);
	return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol);
L
Linus Torvalds 已提交
122 123
}

124 125 126 127 128 129 130 131 132 133 134 135 136
static int ip4_frag_match(struct inet_frag_queue *q, void *a)
{
	struct ipq *qp;
	struct ip4_create_arg *arg = a;

	qp = container_of(q, struct ipq, q);
	return (qp->id == arg->iph->id &&
			qp->saddr == arg->iph->saddr &&
			qp->daddr == arg->iph->daddr &&
			qp->protocol == arg->iph->protocol &&
			qp->user == arg->user);
}

L
Linus Torvalds 已提交
137
/* Memory Tracking Functions. */
138 139
static __inline__ void frag_kfree_skb(struct netns_frags *nf,
		struct sk_buff *skb, int *work)
L
Linus Torvalds 已提交
140 141 142
{
	if (work)
		*work -= skb->truesize;
143
	atomic_sub(skb->truesize, &nf->mem);
L
Linus Torvalds 已提交
144 145 146
	kfree_skb(skb);
}

147 148 149 150 151 152 153 154 155 156 157 158 159 160
static void ip4_frag_init(struct inet_frag_queue *q, void *a)
{
	struct ipq *qp = container_of(q, struct ipq, q);
	struct ip4_create_arg *arg = a;

	qp->protocol = arg->iph->protocol;
	qp->id = arg->iph->id;
	qp->saddr = arg->iph->saddr;
	qp->daddr = arg->iph->daddr;
	qp->user = arg->user;
	qp->peer = sysctl_ipfrag_max_dist ?
		inet_getpeer(arg->iph->saddr, 1) : NULL;
}

161
static __inline__ void ip4_frag_free(struct inet_frag_queue *q)
L
Linus Torvalds 已提交
162
{
163 164 165 166 167
	struct ipq *qp;

	qp = container_of(q, struct ipq, q);
	if (qp->peer)
		inet_putpeer(qp->peer);
L
Linus Torvalds 已提交
168 169 170 171 172
}


/* Destruction primitives. */

173
static __inline__ void ipq_put(struct ipq *ipq)
L
Linus Torvalds 已提交
174
{
P
Pavel Emelyanov 已提交
175
	inet_frag_put(&ipq->q, &ip4_frags);
L
Linus Torvalds 已提交
176 177 178 179 180 181 182
}

/* Kill ipq entry. It is not destroyed immediately,
 * because caller (and someone more) holds reference count.
 */
static void ipq_kill(struct ipq *ipq)
{
183
	inet_frag_kill(&ipq->q, &ip4_frags);
L
Linus Torvalds 已提交
184 185
}

186
/* Memory limiting on fragments.  Evictor trashes the oldest
L
Linus Torvalds 已提交
187 188
 * fragment queue until we are back under the threshold.
 */
189
static void ip_evictor(struct net *net)
L
Linus Torvalds 已提交
190
{
191 192
	int evicted;

193
	evicted = inet_frag_evictor(&net->ipv4.frags, &ip4_frags);
194 195
	if (evicted)
		IP_ADD_STATS_BH(IPSTATS_MIB_REASMFAILS, evicted);
L
Linus Torvalds 已提交
196 197 198 199 200 201 202
}

/*
 * Oops, a fragment queue timed out.  Kill it and send an ICMP reply.
 */
static void ip_expire(unsigned long arg)
{
203 204 205
	struct ipq *qp;

	qp = container_of((struct inet_frag_queue *) arg, struct ipq, q);
L
Linus Torvalds 已提交
206

207
	spin_lock(&qp->q.lock);
L
Linus Torvalds 已提交
208

209
	if (qp->q.last_in & COMPLETE)
L
Linus Torvalds 已提交
210 211 212 213 214 215 216
		goto out;

	ipq_kill(qp);

	IP_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT);
	IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);

217 218
	if ((qp->q.last_in&FIRST_IN) && qp->q.fragments != NULL) {
		struct sk_buff *head = qp->q.fragments;
L
Linus Torvalds 已提交
219
		/* Send an ICMP "Fragment Reassembly Timeout" message. */
220
		if ((head->dev = dev_get_by_index(&init_net, qp->iif)) != NULL) {
L
Linus Torvalds 已提交
221 222 223 224 225
			icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
			dev_put(head->dev);
		}
	}
out:
226
	spin_unlock(&qp->q.lock);
227
	ipq_put(qp);
L
Linus Torvalds 已提交
228 229
}

230 231 232
/* Find the correct entry in the "incomplete datagrams" queue for
 * this IP datagram, and create new one, if nothing is found.
 */
233
static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user)
L
Linus Torvalds 已提交
234
{
235 236
	struct inet_frag_queue *q;
	struct ip4_create_arg arg;
237
	unsigned int hash;
L
Linus Torvalds 已提交
238

239 240
	arg.iph = iph;
	arg.user = user;
241
	hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
L
Linus Torvalds 已提交
242

243
	q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash);
244 245
	if (q == NULL)
		goto out_nomem;
L
Linus Torvalds 已提交
246

247
	return container_of(q, struct ipq, q);
L
Linus Torvalds 已提交
248 249

out_nomem:
250
	LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n");
L
Linus Torvalds 已提交
251 252 253
	return NULL;
}

H
Herbert Xu 已提交
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
/* Is the fragment too far ahead to be part of ipq? */
static inline int ip_frag_too_far(struct ipq *qp)
{
	struct inet_peer *peer = qp->peer;
	unsigned int max = sysctl_ipfrag_max_dist;
	unsigned int start, end;

	int rc;

	if (!peer || !max)
		return 0;

	start = qp->rid;
	end = atomic_inc_return(&peer->rid);
	qp->rid = end;

270
	rc = qp->q.fragments && (end - start) > max;
H
Herbert Xu 已提交
271 272 273 274 275 276 277 278 279 280 281 282

	if (rc) {
		IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
	}

	return rc;
}

static int ip_frag_reinit(struct ipq *qp)
{
	struct sk_buff *fp;

283
	if (!mod_timer(&qp->q.timer, jiffies + qp->q.net->timeout)) {
284
		atomic_inc(&qp->q.refcnt);
H
Herbert Xu 已提交
285 286 287
		return -ETIMEDOUT;
	}

288
	fp = qp->q.fragments;
H
Herbert Xu 已提交
289 290
	do {
		struct sk_buff *xp = fp->next;
291
		frag_kfree_skb(qp->q.net, fp, NULL);
H
Herbert Xu 已提交
292 293 294
		fp = xp;
	} while (fp);

295 296 297 298
	qp->q.last_in = 0;
	qp->q.len = 0;
	qp->q.meat = 0;
	qp->q.fragments = NULL;
H
Herbert Xu 已提交
299 300 301 302 303
	qp->iif = 0;

	return 0;
}

L
Linus Torvalds 已提交
304
/* Add new segment to existing queue. */
305
static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
L
Linus Torvalds 已提交
306 307
{
	struct sk_buff *prev, *next;
308
	struct net_device *dev;
L
Linus Torvalds 已提交
309 310
	int flags, offset;
	int ihl, end;
311
	int err = -ENOENT;
L
Linus Torvalds 已提交
312

313
	if (qp->q.last_in & COMPLETE)
L
Linus Torvalds 已提交
314 315
		goto err;

H
Herbert Xu 已提交
316
	if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) &&
317 318
	    unlikely(ip_frag_too_far(qp)) &&
	    unlikely(err = ip_frag_reinit(qp))) {
H
Herbert Xu 已提交
319 320 321 322
		ipq_kill(qp);
		goto err;
	}

323
	offset = ntohs(ip_hdr(skb)->frag_off);
L
Linus Torvalds 已提交
324 325 326
	flags = offset & ~IP_OFFSET;
	offset &= IP_OFFSET;
	offset <<= 3;		/* offset is in 8-byte chunks */
327
	ihl = ip_hdrlen(skb);
L
Linus Torvalds 已提交
328 329

	/* Determine the position of this fragment. */
330
	end = offset + skb->len - ihl;
331
	err = -EINVAL;
L
Linus Torvalds 已提交
332 333 334 335 336 337

	/* Is this the final fragment? */
	if ((flags & IP_MF) == 0) {
		/* If we already have some bits beyond end
		 * or have different end, the segment is corrrupted.
		 */
338 339
		if (end < qp->q.len ||
		    ((qp->q.last_in & LAST_IN) && end != qp->q.len))
L
Linus Torvalds 已提交
340
			goto err;
341 342
		qp->q.last_in |= LAST_IN;
		qp->q.len = end;
L
Linus Torvalds 已提交
343 344 345 346 347 348
	} else {
		if (end&7) {
			end &= ~7;
			if (skb->ip_summed != CHECKSUM_UNNECESSARY)
				skb->ip_summed = CHECKSUM_NONE;
		}
349
		if (end > qp->q.len) {
L
Linus Torvalds 已提交
350
			/* Some bits beyond end -> corruption. */
351
			if (qp->q.last_in & LAST_IN)
L
Linus Torvalds 已提交
352
				goto err;
353
			qp->q.len = end;
L
Linus Torvalds 已提交
354 355 356 357 358
		}
	}
	if (end == offset)
		goto err;

359
	err = -ENOMEM;
L
Linus Torvalds 已提交
360 361
	if (pskb_pull(skb, ihl) == NULL)
		goto err;
362 363 364

	err = pskb_trim_rcsum(skb, end - offset);
	if (err)
L
Linus Torvalds 已提交
365 366 367 368 369 370 371
		goto err;

	/* Find out which fragments are in front and at the back of us
	 * in the chain of fragments so far.  We must know where to put
	 * this fragment, right?
	 */
	prev = NULL;
372
	for (next = qp->q.fragments; next != NULL; next = next->next) {
L
Linus Torvalds 已提交
373 374 375 376 377 378 379 380 381 382 383 384 385 386
		if (FRAG_CB(next)->offset >= offset)
			break;	/* bingo! */
		prev = next;
	}

	/* We found where to put this one.  Check for overlap with
	 * preceding fragment, and, if needed, align things so that
	 * any overlaps are eliminated.
	 */
	if (prev) {
		int i = (FRAG_CB(prev)->offset + prev->len) - offset;

		if (i > 0) {
			offset += i;
387
			err = -EINVAL;
L
Linus Torvalds 已提交
388 389
			if (end <= offset)
				goto err;
390
			err = -ENOMEM;
L
Linus Torvalds 已提交
391 392 393 394 395 396 397
			if (!pskb_pull(skb, i))
				goto err;
			if (skb->ip_summed != CHECKSUM_UNNECESSARY)
				skb->ip_summed = CHECKSUM_NONE;
		}
	}

398 399
	err = -ENOMEM;

L
Linus Torvalds 已提交
400 401 402 403 404 405 406 407 408 409
	while (next && FRAG_CB(next)->offset < end) {
		int i = end - FRAG_CB(next)->offset; /* overlap is 'i' bytes */

		if (i < next->len) {
			/* Eat head of the next overlapped fragment
			 * and leave the loop. The next ones cannot overlap.
			 */
			if (!pskb_pull(next, i))
				goto err;
			FRAG_CB(next)->offset += i;
410
			qp->q.meat -= i;
L
Linus Torvalds 已提交
411 412 413 414 415 416
			if (next->ip_summed != CHECKSUM_UNNECESSARY)
				next->ip_summed = CHECKSUM_NONE;
			break;
		} else {
			struct sk_buff *free_it = next;

417
			/* Old fragment is completely overridden with
L
Linus Torvalds 已提交
418 419 420 421 422 423 424
			 * new one drop it.
			 */
			next = next->next;

			if (prev)
				prev->next = next;
			else
425
				qp->q.fragments = next;
L
Linus Torvalds 已提交
426

427
			qp->q.meat -= free_it->len;
428
			frag_kfree_skb(qp->q.net, free_it, NULL);
L
Linus Torvalds 已提交
429 430 431 432 433 434 435 436 437 438
		}
	}

	FRAG_CB(skb)->offset = offset;

	/* Insert this fragment in the chain of fragments. */
	skb->next = next;
	if (prev)
		prev->next = skb;
	else
439
		qp->q.fragments = skb;
L
Linus Torvalds 已提交
440

441 442 443 444 445
	dev = skb->dev;
	if (dev) {
		qp->iif = dev->ifindex;
		skb->dev = NULL;
	}
446 447
	qp->q.stamp = skb->tstamp;
	qp->q.meat += skb->len;
448
	atomic_add(skb->truesize, &qp->q.net->mem);
L
Linus Torvalds 已提交
449
	if (offset == 0)
450
		qp->q.last_in |= FIRST_IN;
L
Linus Torvalds 已提交
451

452
	if (qp->q.last_in == (FIRST_IN | LAST_IN) && qp->q.meat == qp->q.len)
453 454
		return ip_frag_reasm(qp, prev, dev);

455 456 457
	write_lock(&ip4_frags.lock);
	list_move_tail(&qp->q.lru_list, &ip4_frags.lru_list);
	write_unlock(&ip4_frags.lock);
458
	return -EINPROGRESS;
L
Linus Torvalds 已提交
459 460 461

err:
	kfree_skb(skb);
462
	return err;
L
Linus Torvalds 已提交
463 464 465 466 467
}


/* Build a new IP datagram from all its fragments. */

468 469
static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
			 struct net_device *dev)
L
Linus Torvalds 已提交
470 471
{
	struct iphdr *iph;
472
	struct sk_buff *fp, *head = qp->q.fragments;
L
Linus Torvalds 已提交
473 474
	int len;
	int ihlen;
475
	int err;
L
Linus Torvalds 已提交
476 477 478

	ipq_kill(qp);

479 480 481 482 483 484 485 486 487 488
	/* Make the one we just received the head. */
	if (prev) {
		head = prev->next;
		fp = skb_clone(head, GFP_ATOMIC);
		if (!fp)
			goto out_nomem;

		fp->next = head->next;
		prev->next = fp;

489 490
		skb_morph(head, qp->q.fragments);
		head->next = qp->q.fragments->next;
491

492 493
		kfree_skb(qp->q.fragments);
		qp->q.fragments = head;
494 495
	}

L
Linus Torvalds 已提交
496 497 498 499
	BUG_TRAP(head != NULL);
	BUG_TRAP(FRAG_CB(head)->offset == 0);

	/* Allocate a new buffer for the datagram. */
500
	ihlen = ip_hdrlen(head);
501
	len = ihlen + qp->q.len;
L
Linus Torvalds 已提交
502

503
	err = -E2BIG;
S
Stephen Hemminger 已提交
504
	if (len > 65535)
L
Linus Torvalds 已提交
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
		goto out_oversize;

	/* Head of list must not be cloned. */
	if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
		goto out_nomem;

	/* If the first fragment is fragmented itself, we split
	 * it to two chunks: the first with data and paged part
	 * and the second, holding only fragments. */
	if (skb_shinfo(head)->frag_list) {
		struct sk_buff *clone;
		int i, plen = 0;

		if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)
			goto out_nomem;
		clone->next = head->next;
		head->next = clone;
		skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
		skb_shinfo(head)->frag_list = NULL;
		for (i=0; i<skb_shinfo(head)->nr_frags; i++)
			plen += skb_shinfo(head)->frags[i].size;
		clone->len = clone->data_len = head->data_len - plen;
		head->data_len -= clone->len;
		head->len -= clone->len;
		clone->csum = 0;
		clone->ip_summed = head->ip_summed;
531
		atomic_add(clone->truesize, &qp->q.net->mem);
L
Linus Torvalds 已提交
532 533 534
	}

	skb_shinfo(head)->frag_list = head->next;
535
	skb_push(head, head->data - skb_network_header(head));
536
	atomic_sub(head->truesize, &qp->q.net->mem);
L
Linus Torvalds 已提交
537 538 539 540 541 542

	for (fp=head->next; fp; fp = fp->next) {
		head->data_len += fp->len;
		head->len += fp->len;
		if (head->ip_summed != fp->ip_summed)
			head->ip_summed = CHECKSUM_NONE;
543
		else if (head->ip_summed == CHECKSUM_COMPLETE)
L
Linus Torvalds 已提交
544 545
			head->csum = csum_add(head->csum, fp->csum);
		head->truesize += fp->truesize;
546
		atomic_sub(fp->truesize, &qp->q.net->mem);
L
Linus Torvalds 已提交
547 548 549 550
	}

	head->next = NULL;
	head->dev = dev;
551
	head->tstamp = qp->q.stamp;
L
Linus Torvalds 已提交
552

553
	iph = ip_hdr(head);
L
Linus Torvalds 已提交
554 555 556
	iph->frag_off = 0;
	iph->tot_len = htons(len);
	IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
557
	qp->q.fragments = NULL;
558
	return 0;
L
Linus Torvalds 已提交
559 560

out_nomem:
561
	LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing "
562
			      "queue %p\n", qp);
563
	err = -ENOMEM;
L
Linus Torvalds 已提交
564 565 566 567 568 569 570 571
	goto out_fail;
out_oversize:
	if (net_ratelimit())
		printk(KERN_INFO
			"Oversized IP packet from %d.%d.%d.%d.\n",
			NIPQUAD(qp->saddr));
out_fail:
	IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
572
	return err;
L
Linus Torvalds 已提交
573 574 575
}

/* Process an incoming IP datagram fragment. */
576
int ip_defrag(struct sk_buff *skb, u32 user)
L
Linus Torvalds 已提交
577 578
{
	struct ipq *qp;
579
	struct net *net;
580

L
Linus Torvalds 已提交
581 582
	IP_INC_STATS_BH(IPSTATS_MIB_REASMREQDS);

583
	net = skb->dev->nd_net;
L
Linus Torvalds 已提交
584
	/* Start by cleaning up the memory. */
585 586
	if (atomic_read(&net->ipv4.frags.mem) > ip4_frags_ctl.high_thresh)
		ip_evictor(net);
L
Linus Torvalds 已提交
587 588

	/* Lookup (or create) queue header */
589
	if ((qp = ip_find(net, ip_hdr(skb), user)) != NULL) {
590
		int ret;
L
Linus Torvalds 已提交
591

592
		spin_lock(&qp->q.lock);
L
Linus Torvalds 已提交
593

594
		ret = ip_frag_queue(qp, skb);
L
Linus Torvalds 已提交
595

596
		spin_unlock(&qp->q.lock);
597
		ipq_put(qp);
598
		return ret;
L
Linus Torvalds 已提交
599 600 601 602
	}

	IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
	kfree_skb(skb);
603
	return -ENOMEM;
L
Linus Torvalds 已提交
604 605
}

606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
#ifdef CONFIG_SYSCTL
static int zero;

static struct ctl_table ip4_frags_ctl_table[] = {
	{
		.ctl_name	= NET_IPV4_IPFRAG_HIGH_THRESH,
		.procname	= "ipfrag_high_thresh",
		.data		= &ip4_frags_ctl.high_thresh,
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= &proc_dointvec
	},
	{
		.ctl_name	= NET_IPV4_IPFRAG_LOW_THRESH,
		.procname	= "ipfrag_low_thresh",
		.data		= &ip4_frags_ctl.low_thresh,
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= &proc_dointvec
	},
	{
		.ctl_name	= NET_IPV4_IPFRAG_TIME,
		.procname	= "ipfrag_time",
629
		.data		= &init_net.ipv4.frags.timeout,
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= &proc_dointvec_jiffies,
		.strategy	= &sysctl_jiffies
	},
	{
		.ctl_name	= NET_IPV4_IPFRAG_SECRET_INTERVAL,
		.procname	= "ipfrag_secret_interval",
		.data		= &ip4_frags_ctl.secret_interval,
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= &proc_dointvec_jiffies,
		.strategy	= &sysctl_jiffies
	},
	{
		.procname	= "ipfrag_max_dist",
		.data		= &sysctl_ipfrag_max_dist,
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= &proc_dointvec_minmax,
		.extra1		= &zero
	},
	{ }
};

static int ip4_frags_ctl_register(struct net *net)
{
657
	struct ctl_table *table;
658 659
	struct ctl_table_header *hdr;

660 661 662 663 664 665 666 667
	table = ip4_frags_ctl_table;
	if (net != &init_net) {
		table = kmemdup(table, sizeof(ip4_frags_ctl_table), GFP_KERNEL);
		if (table == NULL)
			goto err_alloc;

		table[0].mode &= ~0222;
		table[1].mode &= ~0222;
668
		table[2].data = &net->ipv4.frags.timeout;
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
		table[3].mode &= ~0222;
		table[4].mode &= ~0222;
	}

	hdr = register_net_sysctl_table(net, net_ipv4_ctl_path, table);
	if (hdr == NULL)
		goto err_reg;

	net->ipv4.frags_hdr = hdr;
	return 0;

err_reg:
	if (net != &init_net)
		kfree(table);
err_alloc:
	return -ENOMEM;
}

static void ip4_frags_ctl_unregister(struct net *net)
{
	struct ctl_table *table;

	table = net->ipv4.frags_hdr->ctl_table_arg;
	unregister_net_sysctl_table(net->ipv4.frags_hdr);
	kfree(table);
694 695 696 697 698 699
}
#else
static inline int ip4_frags_ctl_register(struct net *net)
{
	return 0;
}
700 701 702 703

static inline void ip4_frags_ctl_unregister(struct net *net)
{
}
704 705 706 707
#endif

static int ipv4_frags_init_net(struct net *net)
{
708 709 710 711 712 713 714
	/*
	 * Important NOTE! Fragment queue must be destroyed before MSL expires.
	 * RFC791 is wrong proposing to prolongate timer each fragment arrival
	 * by TTL.
	 */
	net->ipv4.frags.timeout = IP_FRAG_TIME;

715 716
	inet_frags_init_net(&net->ipv4.frags);

717 718 719
	return ip4_frags_ctl_register(net);
}

720
void __init ipfrag_init(void)
L
Linus Torvalds 已提交
721
{
722
	ipv4_frags_init_net(&init_net);
723
	ip4_frags.ctl = &ip4_frags_ctl;
724
	ip4_frags.hashfn = ip4_hashfn;
725
	ip4_frags.constructor = ip4_frag_init;
726 727 728
	ip4_frags.destructor = ip4_frag_free;
	ip4_frags.skb_free = NULL;
	ip4_frags.qsize = sizeof(struct ipq);
729
	ip4_frags.match = ip4_frag_match;
730
	ip4_frags.frag_expire = ip_expire;
731
	inet_frags_init(&ip4_frags);
L
Linus Torvalds 已提交
732 733 734
}

EXPORT_SYMBOL(ip_defrag);