]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
7f0e162ead65982ca7d2f97ac7d65c43ea5dd52f
[thirdparty/kernel/stable-queue.git] /
1 From 8a4be359396891878b81c71c52e4d41c628b9df2 Mon Sep 17 00:00:00 2001
2 From: David S. Miller <davem@davemloft.net>
3 Date: Sun, 15 Nov 2009 22:23:47 -0800
4 Subject: Revert "isdn: isdn_ppp: Use SKB list facilities instead of home-grown implementation."
5
6
7 From: David S. Miller <davem@davemloft.net>
8
9 [ Upstream commit e29d4363174949a7a4e46f670993d7ff43342c1c ]
10
11 This reverts commit 38783e671399b5405f1fd177d602c400a9577ae6.
12
13 It causes kernel bugzilla #14594
14
15 Signed-off-by: David S. Miller <davem@davemloft.net>
16 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
17 ---
18 drivers/isdn/i4l/isdn_ppp.c | 348 ++++++++++++++++++++------------------------
19 include/linux/isdn_ppp.h | 2
20 2 files changed, 162 insertions(+), 188 deletions(-)
21
22 --- a/drivers/isdn/i4l/isdn_ppp.c
23 +++ b/drivers/isdn/i4l/isdn_ppp.c
24 @@ -1535,10 +1535,8 @@ static int isdn_ppp_mp_bundle_array_init
25 int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
26 if( (isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL )
27 return -ENOMEM;
28 - for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
29 + for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
30 spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
31 - skb_queue_head_init(&isdn_ppp_bundle_arr[i].frags);
32 - }
33 return 0;
34 }
35
36 @@ -1571,7 +1569,7 @@ static int isdn_ppp_mp_init( isdn_net_lo
37 if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
38 return -ENOMEM;
39 lp->next = lp->last = lp; /* nobody else in a queue */
40 - skb_queue_head_init(&lp->netdev->pb->frags);
41 + lp->netdev->pb->frags = NULL;
42 lp->netdev->pb->frames = 0;
43 lp->netdev->pb->seq = UINT_MAX;
44 }
45 @@ -1583,29 +1581,28 @@ static int isdn_ppp_mp_init( isdn_net_lo
46
47 static u32 isdn_ppp_mp_get_seq( int short_seq,
48 struct sk_buff * skb, u32 last_seq );
49 -static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from,
50 - struct sk_buff *to);
51 -static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
52 - struct sk_buff *from, struct sk_buff *to,
53 - u32 lastseq);
54 -static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);
55 +static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
56 + struct sk_buff * from, struct sk_buff * to );
57 +static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
58 + struct sk_buff * from, struct sk_buff * to );
59 +static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );
60 static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
61
62 static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
63 - struct sk_buff *skb)
64 + struct sk_buff *skb)
65 {
66 - struct sk_buff *newfrag, *frag, *start, *nextf;
67 - u32 newseq, minseq, thisseq;
68 - isdn_mppp_stats *stats;
69 struct ippp_struct *is;
70 + isdn_net_local * lpq;
71 + ippp_bundle * mp;
72 + isdn_mppp_stats * stats;
73 + struct sk_buff * newfrag, * frag, * start, *nextf;
74 + u32 newseq, minseq, thisseq;
75 unsigned long flags;
76 - isdn_net_local *lpq;
77 - ippp_bundle *mp;
78 int slot;
79
80 spin_lock_irqsave(&net_dev->pb->lock, flags);
81 - mp = net_dev->pb;
82 - stats = &mp->stats;
83 + mp = net_dev->pb;
84 + stats = &mp->stats;
85 slot = lp->ppp_slot;
86 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
87 printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
88 @@ -1616,19 +1613,20 @@ static void isdn_ppp_mp_receive(isdn_net
89 return;
90 }
91 is = ippp_table[slot];
92 - if (++mp->frames > stats->max_queue_len)
93 + if( ++mp->frames > stats->max_queue_len )
94 stats->max_queue_len = mp->frames;
95 -
96 +
97 if (is->debug & 0x8)
98 isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
99
100 - newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
101 - skb, is->last_link_seqno);
102 + newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
103 + skb, is->last_link_seqno);
104 +
105
106 /* if this packet seq # is less than last already processed one,
107 * toss it right away, but check for sequence start case first
108 */
109 - if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {
110 + if( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) {
111 mp->seq = newseq; /* the first packet: required for
112 * rfc1990 non-compliant clients --
113 * prevents constant packet toss */
114 @@ -1638,7 +1636,7 @@ static void isdn_ppp_mp_receive(isdn_net
115 spin_unlock_irqrestore(&mp->lock, flags);
116 return;
117 }
118 -
119 +
120 /* find the minimum received sequence number over all links */
121 is->last_link_seqno = minseq = newseq;
122 for (lpq = net_dev->queue;;) {
123 @@ -1659,31 +1657,22 @@ static void isdn_ppp_mp_receive(isdn_net
124 * packets */
125 newfrag = skb;
126
127 - /* Insert new fragment into the proper sequence slot. */
128 - skb_queue_walk(&mp->frags, frag) {
129 - if (MP_SEQ(frag) == newseq) {
130 - isdn_ppp_mp_free_skb(mp, newfrag);
131 - newfrag = NULL;
132 - break;
133 - }
134 - if (MP_LT(newseq, MP_SEQ(frag))) {
135 - __skb_queue_before(&mp->frags, frag, newfrag);
136 - newfrag = NULL;
137 - break;
138 - }
139 - }
140 - if (newfrag)
141 - __skb_queue_tail(&mp->frags, newfrag);
142 + /* if this new fragment is before the first one, then enqueue it now. */
143 + if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
144 + newfrag->next = frag;
145 + mp->frags = frag = newfrag;
146 + newfrag = NULL;
147 + }
148
149 - frag = skb_peek(&mp->frags);
150 - start = ((MP_FLAGS(frag) & MP_BEGIN_FRAG) &&
151 - (MP_SEQ(frag) == mp->seq)) ? frag : NULL;
152 - if (!start)
153 - goto check_overflow;
154 + start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
155 + MP_SEQ(frag) == mp->seq ? frag : NULL;
156
157 - /* main fragment traversing loop
158 + /*
159 + * main fragment traversing loop
160 *
161 * try to accomplish several tasks:
162 + * - insert new fragment into the proper sequence slot (once that's done
163 + * newfrag will be set to NULL)
164 * - reassemble any complete fragment sequence (non-null 'start'
165 * indicates there is a continguous sequence present)
166 * - discard any incomplete sequences that are below minseq -- due
167 @@ -1692,46 +1681,71 @@ static void isdn_ppp_mp_receive(isdn_net
168 * come to complete such sequence and it should be discarded
169 *
170 * loop completes when we accomplished the following tasks:
171 + * - new fragment is inserted in the proper sequence ('newfrag' is
172 + * set to NULL)
173 * - we hit a gap in the sequence, so no reassembly/processing is
174 * possible ('start' would be set to NULL)
175 *
176 * algorithm for this code is derived from code in the book
177 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
178 */
179 - skb_queue_walk_safe(&mp->frags, frag, nextf) {
180 - thisseq = MP_SEQ(frag);
181 + while (start != NULL || newfrag != NULL) {
182
183 - /* check for misplaced start */
184 - if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
185 - printk(KERN_WARNING"isdn_mppp(seq %d): new "
186 - "BEGIN flag with no prior END", thisseq);
187 - stats->seqerrs++;
188 - stats->frame_drops++;
189 - isdn_ppp_mp_discard(mp, start, frag);
190 - start = frag;
191 - } else if (MP_LE(thisseq, minseq)) {
192 - if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
193 + thisseq = MP_SEQ(frag);
194 + nextf = frag->next;
195 +
196 + /* drop any duplicate fragments */
197 + if (newfrag != NULL && thisseq == newseq) {
198 + isdn_ppp_mp_free_skb(mp, newfrag);
199 + newfrag = NULL;
200 + }
201 +
202 + /* insert new fragment before next element if possible. */
203 + if (newfrag != NULL && (nextf == NULL ||
204 + MP_LT(newseq, MP_SEQ(nextf)))) {
205 + newfrag->next = nextf;
206 + frag->next = nextf = newfrag;
207 + newfrag = NULL;
208 + }
209 +
210 + if (start != NULL) {
211 + /* check for misplaced start */
212 + if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
213 + printk(KERN_WARNING"isdn_mppp(seq %d): new "
214 + "BEGIN flag with no prior END", thisseq);
215 + stats->seqerrs++;
216 + stats->frame_drops++;
217 + start = isdn_ppp_mp_discard(mp, start,frag);
218 + nextf = frag->next;
219 + }
220 + } else if (MP_LE(thisseq, minseq)) {
221 + if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
222 start = frag;
223 - else {
224 + else {
225 if (MP_FLAGS(frag) & MP_END_FRAG)
226 - stats->frame_drops++;
227 - __skb_unlink(skb, &mp->frags);
228 + stats->frame_drops++;
229 + if( mp->frags == frag )
230 + mp->frags = nextf;
231 isdn_ppp_mp_free_skb(mp, frag);
232 + frag = nextf;
233 continue;
234 - }
235 + }
236 }
237 -
238 - /* if we have end fragment, then we have full reassembly
239 - * sequence -- reassemble and process packet now
240 +
241 + /* if start is non-null and we have end fragment, then
242 + * we have full reassembly sequence -- reassemble
243 + * and process packet now
244 */
245 - if (MP_FLAGS(frag) & MP_END_FRAG) {
246 - minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;
247 - /* Reassemble the packet then dispatch it */
248 - isdn_ppp_mp_reassembly(net_dev, lp, start, frag, thisseq);
249 + if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
250 + minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;
251 + /* Reassemble the packet then dispatch it */
252 + isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
253 +
254 + start = NULL;
255 + frag = NULL;
256
257 - start = NULL;
258 - frag = NULL;
259 - }
260 + mp->frags = nextf;
261 + }
262
263 /* check if need to update start pointer: if we just
264 * reassembled the packet and sequence is contiguous
265 @@ -1742,25 +1756,26 @@ static void isdn_ppp_mp_receive(isdn_net
266 * below low watermark and set start to the next frag or
267 * clear start ptr.
268 */
269 - if (nextf != (struct sk_buff *)&mp->frags &&
270 + if (nextf != NULL &&
271 ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
272 - /* if we just reassembled and the next one is here,
273 - * then start another reassembly.
274 - */
275 - if (frag == NULL) {
276 + /* if we just reassembled and the next one is here,
277 + * then start another reassembly. */
278 +
279 + if (frag == NULL) {
280 if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
281 - start = nextf;
282 - else {
283 - printk(KERN_WARNING"isdn_mppp(seq %d):"
284 - " END flag with no following "
285 - "BEGIN", thisseq);
286 + start = nextf;
287 + else
288 + {
289 + printk(KERN_WARNING"isdn_mppp(seq %d):"
290 + " END flag with no following "
291 + "BEGIN", thisseq);
292 stats->seqerrs++;
293 }
294 }
295 - } else {
296 - if (nextf != (struct sk_buff *)&mp->frags &&
297 - frag != NULL &&
298 - MP_LT(thisseq, minseq)) {
299 +
300 + } else {
301 + if ( nextf != NULL && frag != NULL &&
302 + MP_LT(thisseq, minseq)) {
303 /* we've got a break in the sequence
304 * and we not at the end yet
305 * and we did not just reassembled
306 @@ -1769,39 +1784,41 @@ static void isdn_ppp_mp_receive(isdn_net
307 * discard all the frames below low watermark
308 * and start over */
309 stats->frame_drops++;
310 - isdn_ppp_mp_discard(mp, start, nextf);
311 + mp->frags = isdn_ppp_mp_discard(mp,start,nextf);
312 }
313 /* break in the sequence, no reassembly */
314 - start = NULL;
315 - }
316 - if (!start)
317 - break;
318 - }
319 -
320 -check_overflow:
321 + start = NULL;
322 + }
323 +
324 + frag = nextf;
325 + } /* while -- main loop */
326 +
327 + if (mp->frags == NULL)
328 + mp->frags = frag;
329 +
330 /* rather straighforward way to deal with (not very) possible
331 - * queue overflow
332 - */
333 + * queue overflow */
334 if (mp->frames > MP_MAX_QUEUE_LEN) {
335 stats->overflows++;
336 - skb_queue_walk_safe(&mp->frags, frag, nextf) {
337 - if (mp->frames <= MP_MAX_QUEUE_LEN)
338 - break;
339 - __skb_unlink(frag, &mp->frags);
340 - isdn_ppp_mp_free_skb(mp, frag);
341 + while (mp->frames > MP_MAX_QUEUE_LEN) {
342 + frag = mp->frags->next;
343 + isdn_ppp_mp_free_skb(mp, mp->frags);
344 + mp->frags = frag;
345 }
346 }
347 spin_unlock_irqrestore(&mp->lock, flags);
348 }
349
350 -static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
351 +static void isdn_ppp_mp_cleanup( isdn_net_local * lp )
352 {
353 - struct sk_buff *skb, *tmp;
354 -
355 - skb_queue_walk_safe(&lp->netdev->pb->frags, skb, tmp) {
356 - __skb_unlink(skb, &lp->netdev->pb->frags);
357 - isdn_ppp_mp_free_skb(lp->netdev->pb, skb);
358 + struct sk_buff * frag = lp->netdev->pb->frags;
359 + struct sk_buff * nextfrag;
360 + while( frag ) {
361 + nextfrag = frag->next;
362 + isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
363 + frag = nextfrag;
364 }
365 + lp->netdev->pb->frags = NULL;
366 }
367
368 static u32 isdn_ppp_mp_get_seq( int short_seq,
369 @@ -1838,115 +1855,72 @@ static u32 isdn_ppp_mp_get_seq( int shor
370 return seq;
371 }
372
373 -static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from,
374 - struct sk_buff *to)
375 +struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
376 + struct sk_buff * from, struct sk_buff * to )
377 {
378 - if (from) {
379 - struct sk_buff *skb, *tmp;
380 - int freeing = 0;
381 -
382 - skb_queue_walk_safe(&mp->frags, skb, tmp) {
383 - if (skb == to)
384 - break;
385 - if (skb == from)
386 - freeing = 1;
387 - if (!freeing)
388 - continue;
389 - __skb_unlink(skb, &mp->frags);
390 - isdn_ppp_mp_free_skb(mp, skb);
391 + if( from )
392 + while (from != to) {
393 + struct sk_buff * next = from->next;
394 + isdn_ppp_mp_free_skb(mp, from);
395 + from = next;
396 }
397 - }
398 + return from;
399 }
400
401 -static unsigned int calc_tot_len(struct sk_buff_head *queue,
402 - struct sk_buff *from, struct sk_buff *to)
403 -{
404 - unsigned int tot_len = 0;
405 - struct sk_buff *skb;
406 - int found_start = 0;
407 -
408 - skb_queue_walk(queue, skb) {
409 - if (skb == from)
410 - found_start = 1;
411 - if (!found_start)
412 - continue;
413 - tot_len += skb->len - MP_HEADER_LEN;
414 - if (skb == to)
415 - break;
416 - }
417 - return tot_len;
418 -}
419 -
420 -/* Reassemble packet using fragments in the reassembly queue from
421 - * 'from' until 'to', inclusive.
422 - */
423 -static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
424 - struct sk_buff *from, struct sk_buff *to,
425 - u32 lastseq)
426 +void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
427 + struct sk_buff * from, struct sk_buff * to )
428 {
429 - ippp_bundle *mp = net_dev->pb;
430 - unsigned int tot_len;
431 - struct sk_buff *skb;
432 + ippp_bundle * mp = net_dev->pb;
433 int proto;
434 + struct sk_buff * skb;
435 + unsigned int tot_len;
436
437 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
438 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
439 __func__, lp->ppp_slot);
440 return;
441 }
442 -
443 - tot_len = calc_tot_len(&mp->frags, from, to);
444 -
445 - if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {
446 - if (ippp_table[lp->ppp_slot]->debug & 0x40)
447 + if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
448 + if( ippp_table[lp->ppp_slot]->debug & 0x40 )
449 printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
450 - "len %d\n", MP_SEQ(from), from->len);
451 + "len %d\n", MP_SEQ(from), from->len );
452 skb = from;
453 skb_pull(skb, MP_HEADER_LEN);
454 - __skb_unlink(skb, &mp->frags);
455 mp->frames--;
456 } else {
457 - struct sk_buff *walk, *tmp;
458 - int found_start = 0;
459 + struct sk_buff * frag;
460 + int n;
461
462 - if (ippp_table[lp->ppp_slot]->debug & 0x40)
463 - printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
464 - "to %d, len %d\n", MP_SEQ(from), lastseq,
465 - tot_len);
466 + for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)
467 + tot_len += frag->len - MP_HEADER_LEN;
468
469 - skb = dev_alloc_skb(tot_len);
470 - if (!skb)
471 + if( ippp_table[lp->ppp_slot]->debug & 0x40 )
472 + printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
473 + "to %d, len %d\n", MP_SEQ(from),
474 + (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );
475 + if( (skb = dev_alloc_skb(tot_len)) == NULL ) {
476 printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
477 - "of size %d\n", tot_len);
478 -
479 - found_start = 0;
480 - skb_queue_walk_safe(&mp->frags, walk, tmp) {
481 - if (walk == from)
482 - found_start = 1;
483 - if (!found_start)
484 - continue;
485 + "of size %d\n", tot_len);
486 + isdn_ppp_mp_discard(mp, from, to);
487 + return;
488 + }
489
490 - if (skb) {
491 - unsigned int len = walk->len - MP_HEADER_LEN;
492 - skb_copy_from_linear_data_offset(walk, MP_HEADER_LEN,
493 - skb_put(skb, len),
494 - len);
495 - }
496 - __skb_unlink(walk, &mp->frags);
497 - isdn_ppp_mp_free_skb(mp, walk);
498 + while( from != to ) {
499 + unsigned int len = from->len - MP_HEADER_LEN;
500
501 - if (walk == to)
502 - break;
503 + skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
504 + skb_put(skb,len),
505 + len);
506 + frag = from->next;
507 + isdn_ppp_mp_free_skb(mp, from);
508 + from = frag;
509 }
510 }
511 - if (!skb)
512 - return;
513 -
514 proto = isdn_ppp_strip_proto(skb);
515 isdn_ppp_push_higher(net_dev, lp, skb, proto);
516 }
517
518 -static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)
519 +static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb)
520 {
521 dev_kfree_skb(skb);
522 mp->frames--;
523 --- a/include/linux/isdn_ppp.h
524 +++ b/include/linux/isdn_ppp.h
525 @@ -157,7 +157,7 @@ typedef struct {
526
527 typedef struct {
528 int mp_mrru; /* unused */
529 - struct sk_buff_head frags; /* fragments sl list */
530 + struct sk_buff * frags; /* fragments sl list -- use skb->next */
531 long frames; /* number of frames in the frame list */
532 unsigned int seq; /* last processed packet seq #: any packets
533 * with smaller seq # will be dropped