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."
7 From: David S. Miller <davem@davemloft.net>
9 [ Upstream commit e29d4363174949a7a4e46f670993d7ff43342c1c ]
11 This reverts commit 38783e671399b5405f1fd177d602c400a9577ae6.
13 It causes kernel bugzilla #14594
15 Signed-off-by: David S. Miller <davem@davemloft.net>
16 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
18 drivers/isdn/i4l/isdn_ppp.c | 348 ++++++++++++++++++++------------------------
19 include/linux/isdn_ppp.h | 2
20 2 files changed, 162 insertions(+), 188 deletions(-)
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 )
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);
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)
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;
45 @@ -1583,29 +1581,28 @@ static int isdn_ppp_mp_init( isdn_net_lo
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,
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 );
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)
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;
72 + isdn_mppp_stats * stats;
73 + struct sk_buff * newfrag, * frag, * start, *nextf;
74 + u32 newseq, minseq, thisseq;
76 - isdn_net_local *lpq;
80 spin_lock_irqsave(&net_dev->pb->lock, flags);
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
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;
98 isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
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);
106 /* if this packet seq # is less than last already processed one,
107 * toss it right away, but check for sequence start case first
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);
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
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);
134 - if (MP_LT(newseq, MP_SEQ(frag))) {
135 - __skb_queue_before(&mp->frags, frag, 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;
149 - frag = skb_peek(&mp->frags);
150 - start = ((MP_FLAGS(frag) & MP_BEGIN_FRAG) &&
151 - (MP_SEQ(frag) == mp->seq)) ? frag : NULL;
153 - goto check_overflow;
154 + start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
155 + MP_SEQ(frag) == mp->seq ? frag : NULL;
157 - /* main fragment traversing loop
159 + * main fragment traversing loop
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
170 * loop completes when we accomplished the following tasks:
171 + * - new fragment is inserted in the proper sequence ('newfrag' is
173 * - we hit a gap in the sequence, so no reassembly/processing is
174 * possible ('start' would be set to NULL)
176 * algorithm for this code is derived from code in the book
177 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
179 - skb_queue_walk_safe(&mp->frags, frag, nextf) {
180 - thisseq = MP_SEQ(frag);
181 + while (start != NULL || newfrag != NULL) {
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);
188 - stats->frame_drops++;
189 - isdn_ppp_mp_discard(mp, 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;
196 + /* drop any duplicate fragments */
197 + if (newfrag != NULL && thisseq == newseq) {
198 + isdn_ppp_mp_free_skb(mp, newfrag);
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;
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);
216 + stats->frame_drops++;
217 + start = isdn_ppp_mp_discard(mp, start,frag);
218 + nextf = frag->next;
220 + } else if (MP_LE(thisseq, minseq)) {
221 + if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
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 )
231 isdn_ppp_mp_free_skb(mp, frag);
238 - /* if we have end fragment, then we have full reassembly
239 - * sequence -- reassemble and process packet now
241 + /* if start is non-null and we have end fragment, then
242 + * we have full reassembly sequence -- reassemble
243 + * and process packet now
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);
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
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.
275 - if (frag == NULL) {
276 + /* if we just reassembled and the next one is here,
277 + * then start another reassembly. */
279 + if (frag == NULL) {
280 if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
283 - printk(KERN_WARNING"isdn_mppp(seq %d):"
284 - " END flag with no following "
289 + printk(KERN_WARNING"isdn_mppp(seq %d):"
290 + " END flag with no following "
296 - if (nextf != (struct sk_buff *)&mp->frags &&
298 - MP_LT(thisseq, minseq)) {
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
309 stats->frame_drops++;
310 - isdn_ppp_mp_discard(mp, start, nextf);
311 + mp->frags = isdn_ppp_mp_discard(mp,start,nextf);
313 /* break in the sequence, no reassembly */
325 + } /* while -- main loop */
327 + if (mp->frags == NULL)
330 /* rather straighforward way to deal with (not very) possible
333 + * queue overflow */
334 if (mp->frames > MP_MAX_QUEUE_LEN) {
336 - skb_queue_walk_safe(&mp->frags, frag, nextf) {
337 - if (mp->frames <= MP_MAX_QUEUE_LEN)
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);
347 spin_unlock_irqrestore(&mp->lock, flags);
350 -static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
351 +static void isdn_ppp_mp_cleanup( isdn_net_local * lp )
353 - struct sk_buff *skb, *tmp;
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;
361 + nextfrag = frag->next;
362 + isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
365 + lp->netdev->pb->frags = NULL;
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
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 )
379 - struct sk_buff *skb, *tmp;
382 - skb_queue_walk_safe(&mp->frags, skb, tmp) {
389 - __skb_unlink(skb, &mp->frags);
390 - isdn_ppp_mp_free_skb(mp, skb);
392 + while (from != to) {
393 + struct sk_buff * next = from->next;
394 + isdn_ppp_mp_free_skb(mp, from);
401 -static unsigned int calc_tot_len(struct sk_buff_head *queue,
402 - struct sk_buff *from, struct sk_buff *to)
404 - unsigned int tot_len = 0;
405 - struct sk_buff *skb;
406 - int found_start = 0;
408 - skb_queue_walk(queue, skb) {
413 - tot_len += skb->len - MP_HEADER_LEN;
420 -/* Reassemble packet using fragments in the reassembly queue from
421 - * 'from' until 'to', inclusive.
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,
426 +void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
427 + struct sk_buff * from, struct sk_buff * to )
429 - ippp_bundle *mp = net_dev->pb;
430 - unsigned int tot_len;
431 - struct sk_buff *skb;
432 + ippp_bundle * mp = net_dev->pb;
434 + struct sk_buff * skb;
435 + unsigned int tot_len;
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);
443 - tot_len = calc_tot_len(&mp->frags, from, to);
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 );
453 skb_pull(skb, MP_HEADER_LEN);
454 - __skb_unlink(skb, &mp->frags);
457 - struct sk_buff *walk, *tmp;
458 - int found_start = 0;
459 + struct sk_buff * frag;
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,
466 + for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)
467 + tot_len += frag->len - MP_HEADER_LEN;
469 - skb = dev_alloc_skb(tot_len);
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);
480 - skb_queue_walk_safe(&mp->frags, walk, tmp) {
485 + "of size %d\n", tot_len);
486 + isdn_ppp_mp_discard(mp, from, to);
491 - unsigned int len = walk->len - MP_HEADER_LEN;
492 - skb_copy_from_linear_data_offset(walk, MP_HEADER_LEN,
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;
503 + skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
507 + isdn_ppp_mp_free_skb(mp, from);
514 proto = isdn_ppp_strip_proto(skb);
515 isdn_ppp_push_higher(net_dev, lp, skb, proto);
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)
523 --- a/include/linux/isdn_ppp.h
524 +++ b/include/linux/isdn_ppp.h
525 @@ -157,7 +157,7 @@ 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