Loading drivers/isdn/i4l/isdn_ppp.c +163 −189 Original line number Diff line number Diff line Loading @@ -1535,10 +1535,8 @@ static int isdn_ppp_mp_bundle_array_init(void) int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle); if( (isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL ) return -ENOMEM; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { for( i = 0; i < ISDN_MAX_CHANNELS; i++ ) spin_lock_init(&isdn_ppp_bundle_arr[i].lock); skb_queue_head_init(&isdn_ppp_bundle_arr[i].frags); } return 0; } Loading Loading @@ -1571,7 +1569,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL) return -ENOMEM; lp->next = lp->last = lp; /* nobody else in a queue */ skb_queue_head_init(&lp->netdev->pb->frags); lp->netdev->pb->frags = NULL; lp->netdev->pb->frames = 0; lp->netdev->pb->seq = UINT_MAX; } Loading @@ -1583,24 +1581,23 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) static u32 isdn_ppp_mp_get_seq( int short_seq, struct sk_buff * skb, u32 last_seq ); static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from, struct sk_buff *to); static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, struct sk_buff * from, struct sk_buff * to ); static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *from, struct sk_buff *to, u32 lastseq); struct sk_buff * from, struct sk_buff * to ); static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb ); static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ); static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb) { struct sk_buff *newfrag, *frag, *start, *nextf; u32 newseq, minseq, thisseq; isdn_mppp_stats *stats; struct ippp_struct *is; unsigned long flags; isdn_net_local * lpq; ippp_bundle * mp; isdn_mppp_stats * stats; struct sk_buff * newfrag, * frag, * start, *nextf; u32 newseq, minseq, thisseq; unsigned long flags; int slot; spin_lock_irqsave(&net_dev->pb->lock, flags); Loading @@ -1625,6 +1622,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, skb, is->last_link_seqno); /* if this packet seq # is less than last already processed one, * toss it right away, but check for sequence start case first */ Loading Loading @@ -1659,31 +1657,22 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * packets */ newfrag = skb; /* Insert new fragment into the proper sequence slot. */ skb_queue_walk(&mp->frags, frag) { if (MP_SEQ(frag) == newseq) { isdn_ppp_mp_free_skb(mp, newfrag); /* if this new fragment is before the first one, then enqueue it now. */ if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) { newfrag->next = frag; mp->frags = frag = newfrag; newfrag = NULL; break; } if (MP_LT(newseq, MP_SEQ(frag))) { __skb_queue_before(&mp->frags, frag, newfrag); newfrag = NULL; break; } } if (newfrag) __skb_queue_tail(&mp->frags, newfrag); frag = skb_peek(&mp->frags); start = ((MP_FLAGS(frag) & MP_BEGIN_FRAG) && (MP_SEQ(frag) == mp->seq)) ? frag : NULL; if (!start) goto check_overflow; start = MP_FLAGS(frag) & MP_BEGIN_FRAG && MP_SEQ(frag) == mp->seq ? frag : NULL; /* main fragment traversing loop /* * main fragment traversing loop * * try to accomplish several tasks: * - insert new fragment into the proper sequence slot (once that's done * newfrag will be set to NULL) * - reassemble any complete fragment sequence (non-null 'start' * indicates there is a continguous sequence present) * - discard any incomplete sequences that are below minseq -- due Loading @@ -1692,45 +1681,70 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * come to complete such sequence and it should be discarded * * loop completes when we accomplished the following tasks: * - new fragment is inserted in the proper sequence ('newfrag' is * set to NULL) * - we hit a gap in the sequence, so no reassembly/processing is * possible ('start' would be set to NULL) * * algorithm for this code is derived from code in the book * 'PPP Design And Debugging' by James Carlson (Addison-Wesley) */ skb_queue_walk_safe(&mp->frags, frag, nextf) { while (start != NULL || newfrag != NULL) { thisseq = MP_SEQ(frag); nextf = frag->next; /* drop any duplicate fragments */ if (newfrag != NULL && thisseq == newseq) { isdn_ppp_mp_free_skb(mp, newfrag); newfrag = NULL; } /* insert new fragment before next element if possible. */ if (newfrag != NULL && (nextf == NULL || MP_LT(newseq, MP_SEQ(nextf)))) { newfrag->next = nextf; frag->next = nextf = newfrag; newfrag = NULL; } if (start != NULL) { /* check for misplaced start */ if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) { printk(KERN_WARNING"isdn_mppp(seq %d): new " "BEGIN flag with no prior END", thisseq); stats->seqerrs++; stats->frame_drops++; isdn_ppp_mp_discard(mp, start, frag); start = frag; start = isdn_ppp_mp_discard(mp, start,frag); nextf = frag->next; } } else if (MP_LE(thisseq, minseq)) { if (MP_FLAGS(frag) & MP_BEGIN_FRAG) start = frag; else { if (MP_FLAGS(frag) & MP_END_FRAG) stats->frame_drops++; __skb_unlink(skb, &mp->frags); if( mp->frags == frag ) mp->frags = nextf; isdn_ppp_mp_free_skb(mp, frag); frag = nextf; continue; } } /* if we have end fragment, then we have full reassembly * sequence -- reassemble and process packet now /* if start is non-null and we have end fragment, then * we have full reassembly sequence -- reassemble * and process packet now */ if (MP_FLAGS(frag) & MP_END_FRAG) { if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) { minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK; /* Reassemble the packet then dispatch it */ isdn_ppp_mp_reassembly(net_dev, lp, start, frag, thisseq); isdn_ppp_mp_reassembly(net_dev, lp, start, nextf); start = NULL; frag = NULL; mp->frags = nextf; } /* check if need to update start pointer: if we just Loading @@ -1742,24 +1756,25 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * below low watermark and set start to the next frag or * clear start ptr. */ if (nextf != (struct sk_buff *)&mp->frags && if (nextf != NULL && ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) { /* if we just reassembled and the next one is here, * then start another reassembly. */ * then start another reassembly. */ if (frag == NULL) { if (MP_FLAGS(nextf) & MP_BEGIN_FRAG) start = nextf; else { else { printk(KERN_WARNING"isdn_mppp(seq %d):" " END flag with no following " "BEGIN", thisseq); stats->seqerrs++; } } } else { if (nextf != (struct sk_buff *)&mp->frags && frag != NULL && if ( nextf != NULL && frag != NULL && MP_LT(thisseq, minseq)) { /* we've got a break in the sequence * and we not at the end yet Loading @@ -1769,26 +1784,26 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * discard all the frames below low watermark * and start over */ stats->frame_drops++; isdn_ppp_mp_discard(mp, start, nextf); mp->frags = isdn_ppp_mp_discard(mp,start,nextf); } /* break in the sequence, no reassembly */ start = NULL; } if (!start) break; } check_overflow: frag = nextf; } /* while -- main loop */ if (mp->frags == NULL) mp->frags = frag; /* rather straighforward way to deal with (not very) possible * queue overflow */ * queue overflow */ if (mp->frames > MP_MAX_QUEUE_LEN) { stats->overflows++; skb_queue_walk_safe(&mp->frags, frag, nextf) { if (mp->frames <= MP_MAX_QUEUE_LEN) break; __skb_unlink(frag, &mp->frags); isdn_ppp_mp_free_skb(mp, frag); while (mp->frames > MP_MAX_QUEUE_LEN) { frag = mp->frags->next; isdn_ppp_mp_free_skb(mp, mp->frags); mp->frags = frag; } } spin_unlock_irqrestore(&mp->lock, flags); Loading @@ -1796,12 +1811,14 @@ check_overflow: static void isdn_ppp_mp_cleanup( isdn_net_local * lp ) { struct sk_buff *skb, *tmp; skb_queue_walk_safe(&lp->netdev->pb->frags, skb, tmp) { __skb_unlink(skb, &lp->netdev->pb->frags); isdn_ppp_mp_free_skb(lp->netdev->pb, skb); struct sk_buff * frag = lp->netdev->pb->frags; struct sk_buff * nextfrag; while( frag ) { nextfrag = frag->next; isdn_ppp_mp_free_skb(lp->netdev->pb, frag); frag = nextfrag; } lp->netdev->pb->frags = NULL; } static u32 isdn_ppp_mp_get_seq( int short_seq, Loading Loading @@ -1838,110 +1855,67 @@ static u32 isdn_ppp_mp_get_seq( int short_seq, return seq; } static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from, struct sk_buff *to) { if (from) { struct sk_buff *skb, *tmp; int freeing = 0; skb_queue_walk_safe(&mp->frags, skb, tmp) { if (skb == to) break; if (skb == from) freeing = 1; if (!freeing) continue; __skb_unlink(skb, &mp->frags); isdn_ppp_mp_free_skb(mp, skb); } } } static unsigned int calc_tot_len(struct sk_buff_head *queue, struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, struct sk_buff * from, struct sk_buff * to ) { unsigned int tot_len = 0; struct sk_buff *skb; int found_start = 0; skb_queue_walk(queue, skb) { if (skb == from) found_start = 1; if (!found_start) continue; tot_len += skb->len - MP_HEADER_LEN; if (skb == to) break; if( from ) while (from != to) { struct sk_buff * next = from->next; isdn_ppp_mp_free_skb(mp, from); from = next; } return tot_len; return from; } /* Reassemble packet using fragments in the reassembly queue from * 'from' until 'to', inclusive. */ static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *from, struct sk_buff *to, u32 lastseq) void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff * from, struct sk_buff * to ) { ippp_bundle * mp = net_dev->pb; unsigned int tot_len; struct sk_buff *skb; int proto; struct sk_buff * skb; unsigned int tot_len; if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", __func__, lp->ppp_slot); return; } tot_len = calc_tot_len(&mp->frags, from, to); if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) { if( ippp_table[lp->ppp_slot]->debug & 0x40 ) printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, " "len %d\n", MP_SEQ(from), from->len ); skb = from; skb_pull(skb, MP_HEADER_LEN); __skb_unlink(skb, &mp->frags); mp->frames--; } else { struct sk_buff *walk, *tmp; int found_start = 0; struct sk_buff * frag; int n; for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++) tot_len += frag->len - MP_HEADER_LEN; if( ippp_table[lp->ppp_slot]->debug & 0x40 ) printk(KERN_DEBUG"isdn_mppp: reassembling frames %d " "to %d, len %d\n", MP_SEQ(from), lastseq, tot_len); skb = dev_alloc_skb(tot_len); if (!skb) "to %d, len %d\n", MP_SEQ(from), (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len ); if( (skb = dev_alloc_skb(tot_len)) == NULL ) { printk(KERN_ERR "isdn_mppp: cannot allocate sk buff " "of size %d\n", tot_len); isdn_ppp_mp_discard(mp, from, to); return; } found_start = 0; skb_queue_walk_safe(&mp->frags, walk, tmp) { if (walk == from) found_start = 1; if (!found_start) continue; while( from != to ) { unsigned int len = from->len - MP_HEADER_LEN; if (skb) { unsigned int len = walk->len - MP_HEADER_LEN; skb_copy_from_linear_data_offset(walk, MP_HEADER_LEN, skb_copy_from_linear_data_offset(from, MP_HEADER_LEN, skb_put(skb,len), len); } __skb_unlink(walk, &mp->frags); isdn_ppp_mp_free_skb(mp, walk); if (walk == to) break; frag = from->next; isdn_ppp_mp_free_skb(mp, from); from = frag; } } if (!skb) return; proto = isdn_ppp_strip_proto(skb); isdn_ppp_push_higher(net_dev, lp, skb, proto); } Loading include/linux/isdn_ppp.h +1 −1 Original line number Diff line number Diff line Loading @@ -157,7 +157,7 @@ typedef struct { typedef struct { int mp_mrru; /* unused */ struct sk_buff_head frags; /* fragments sl list */ struct sk_buff * frags; /* fragments sl list -- use skb->next */ long frames; /* number of frames in the frame list */ unsigned int seq; /* last processed packet seq #: any packets * with smaller seq # will be dropped Loading Loading
drivers/isdn/i4l/isdn_ppp.c +163 −189 Original line number Diff line number Diff line Loading @@ -1535,10 +1535,8 @@ static int isdn_ppp_mp_bundle_array_init(void) int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle); if( (isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL ) return -ENOMEM; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { for( i = 0; i < ISDN_MAX_CHANNELS; i++ ) spin_lock_init(&isdn_ppp_bundle_arr[i].lock); skb_queue_head_init(&isdn_ppp_bundle_arr[i].frags); } return 0; } Loading Loading @@ -1571,7 +1569,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL) return -ENOMEM; lp->next = lp->last = lp; /* nobody else in a queue */ skb_queue_head_init(&lp->netdev->pb->frags); lp->netdev->pb->frags = NULL; lp->netdev->pb->frames = 0; lp->netdev->pb->seq = UINT_MAX; } Loading @@ -1583,24 +1581,23 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) static u32 isdn_ppp_mp_get_seq( int short_seq, struct sk_buff * skb, u32 last_seq ); static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from, struct sk_buff *to); static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, struct sk_buff * from, struct sk_buff * to ); static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *from, struct sk_buff *to, u32 lastseq); struct sk_buff * from, struct sk_buff * to ); static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb ); static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ); static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb) { struct sk_buff *newfrag, *frag, *start, *nextf; u32 newseq, minseq, thisseq; isdn_mppp_stats *stats; struct ippp_struct *is; unsigned long flags; isdn_net_local * lpq; ippp_bundle * mp; isdn_mppp_stats * stats; struct sk_buff * newfrag, * frag, * start, *nextf; u32 newseq, minseq, thisseq; unsigned long flags; int slot; spin_lock_irqsave(&net_dev->pb->lock, flags); Loading @@ -1625,6 +1622,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, skb, is->last_link_seqno); /* if this packet seq # is less than last already processed one, * toss it right away, but check for sequence start case first */ Loading Loading @@ -1659,31 +1657,22 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * packets */ newfrag = skb; /* Insert new fragment into the proper sequence slot. */ skb_queue_walk(&mp->frags, frag) { if (MP_SEQ(frag) == newseq) { isdn_ppp_mp_free_skb(mp, newfrag); /* if this new fragment is before the first one, then enqueue it now. */ if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) { newfrag->next = frag; mp->frags = frag = newfrag; newfrag = NULL; break; } if (MP_LT(newseq, MP_SEQ(frag))) { __skb_queue_before(&mp->frags, frag, newfrag); newfrag = NULL; break; } } if (newfrag) __skb_queue_tail(&mp->frags, newfrag); frag = skb_peek(&mp->frags); start = ((MP_FLAGS(frag) & MP_BEGIN_FRAG) && (MP_SEQ(frag) == mp->seq)) ? frag : NULL; if (!start) goto check_overflow; start = MP_FLAGS(frag) & MP_BEGIN_FRAG && MP_SEQ(frag) == mp->seq ? frag : NULL; /* main fragment traversing loop /* * main fragment traversing loop * * try to accomplish several tasks: * - insert new fragment into the proper sequence slot (once that's done * newfrag will be set to NULL) * - reassemble any complete fragment sequence (non-null 'start' * indicates there is a continguous sequence present) * - discard any incomplete sequences that are below minseq -- due Loading @@ -1692,45 +1681,70 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * come to complete such sequence and it should be discarded * * loop completes when we accomplished the following tasks: * - new fragment is inserted in the proper sequence ('newfrag' is * set to NULL) * - we hit a gap in the sequence, so no reassembly/processing is * possible ('start' would be set to NULL) * * algorithm for this code is derived from code in the book * 'PPP Design And Debugging' by James Carlson (Addison-Wesley) */ skb_queue_walk_safe(&mp->frags, frag, nextf) { while (start != NULL || newfrag != NULL) { thisseq = MP_SEQ(frag); nextf = frag->next; /* drop any duplicate fragments */ if (newfrag != NULL && thisseq == newseq) { isdn_ppp_mp_free_skb(mp, newfrag); newfrag = NULL; } /* insert new fragment before next element if possible. */ if (newfrag != NULL && (nextf == NULL || MP_LT(newseq, MP_SEQ(nextf)))) { newfrag->next = nextf; frag->next = nextf = newfrag; newfrag = NULL; } if (start != NULL) { /* check for misplaced start */ if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) { printk(KERN_WARNING"isdn_mppp(seq %d): new " "BEGIN flag with no prior END", thisseq); stats->seqerrs++; stats->frame_drops++; isdn_ppp_mp_discard(mp, start, frag); start = frag; start = isdn_ppp_mp_discard(mp, start,frag); nextf = frag->next; } } else if (MP_LE(thisseq, minseq)) { if (MP_FLAGS(frag) & MP_BEGIN_FRAG) start = frag; else { if (MP_FLAGS(frag) & MP_END_FRAG) stats->frame_drops++; __skb_unlink(skb, &mp->frags); if( mp->frags == frag ) mp->frags = nextf; isdn_ppp_mp_free_skb(mp, frag); frag = nextf; continue; } } /* if we have end fragment, then we have full reassembly * sequence -- reassemble and process packet now /* if start is non-null and we have end fragment, then * we have full reassembly sequence -- reassemble * and process packet now */ if (MP_FLAGS(frag) & MP_END_FRAG) { if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) { minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK; /* Reassemble the packet then dispatch it */ isdn_ppp_mp_reassembly(net_dev, lp, start, frag, thisseq); isdn_ppp_mp_reassembly(net_dev, lp, start, nextf); start = NULL; frag = NULL; mp->frags = nextf; } /* check if need to update start pointer: if we just Loading @@ -1742,24 +1756,25 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * below low watermark and set start to the next frag or * clear start ptr. */ if (nextf != (struct sk_buff *)&mp->frags && if (nextf != NULL && ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) { /* if we just reassembled and the next one is here, * then start another reassembly. */ * then start another reassembly. */ if (frag == NULL) { if (MP_FLAGS(nextf) & MP_BEGIN_FRAG) start = nextf; else { else { printk(KERN_WARNING"isdn_mppp(seq %d):" " END flag with no following " "BEGIN", thisseq); stats->seqerrs++; } } } else { if (nextf != (struct sk_buff *)&mp->frags && frag != NULL && if ( nextf != NULL && frag != NULL && MP_LT(thisseq, minseq)) { /* we've got a break in the sequence * and we not at the end yet Loading @@ -1769,26 +1784,26 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * discard all the frames below low watermark * and start over */ stats->frame_drops++; isdn_ppp_mp_discard(mp, start, nextf); mp->frags = isdn_ppp_mp_discard(mp,start,nextf); } /* break in the sequence, no reassembly */ start = NULL; } if (!start) break; } check_overflow: frag = nextf; } /* while -- main loop */ if (mp->frags == NULL) mp->frags = frag; /* rather straighforward way to deal with (not very) possible * queue overflow */ * queue overflow */ if (mp->frames > MP_MAX_QUEUE_LEN) { stats->overflows++; skb_queue_walk_safe(&mp->frags, frag, nextf) { if (mp->frames <= MP_MAX_QUEUE_LEN) break; __skb_unlink(frag, &mp->frags); isdn_ppp_mp_free_skb(mp, frag); while (mp->frames > MP_MAX_QUEUE_LEN) { frag = mp->frags->next; isdn_ppp_mp_free_skb(mp, mp->frags); mp->frags = frag; } } spin_unlock_irqrestore(&mp->lock, flags); Loading @@ -1796,12 +1811,14 @@ check_overflow: static void isdn_ppp_mp_cleanup( isdn_net_local * lp ) { struct sk_buff *skb, *tmp; skb_queue_walk_safe(&lp->netdev->pb->frags, skb, tmp) { __skb_unlink(skb, &lp->netdev->pb->frags); isdn_ppp_mp_free_skb(lp->netdev->pb, skb); struct sk_buff * frag = lp->netdev->pb->frags; struct sk_buff * nextfrag; while( frag ) { nextfrag = frag->next; isdn_ppp_mp_free_skb(lp->netdev->pb, frag); frag = nextfrag; } lp->netdev->pb->frags = NULL; } static u32 isdn_ppp_mp_get_seq( int short_seq, Loading Loading @@ -1838,110 +1855,67 @@ static u32 isdn_ppp_mp_get_seq( int short_seq, return seq; } static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from, struct sk_buff *to) { if (from) { struct sk_buff *skb, *tmp; int freeing = 0; skb_queue_walk_safe(&mp->frags, skb, tmp) { if (skb == to) break; if (skb == from) freeing = 1; if (!freeing) continue; __skb_unlink(skb, &mp->frags); isdn_ppp_mp_free_skb(mp, skb); } } } static unsigned int calc_tot_len(struct sk_buff_head *queue, struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, struct sk_buff * from, struct sk_buff * to ) { unsigned int tot_len = 0; struct sk_buff *skb; int found_start = 0; skb_queue_walk(queue, skb) { if (skb == from) found_start = 1; if (!found_start) continue; tot_len += skb->len - MP_HEADER_LEN; if (skb == to) break; if( from ) while (from != to) { struct sk_buff * next = from->next; isdn_ppp_mp_free_skb(mp, from); from = next; } return tot_len; return from; } /* Reassemble packet using fragments in the reassembly queue from * 'from' until 'to', inclusive. */ static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *from, struct sk_buff *to, u32 lastseq) void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff * from, struct sk_buff * to ) { ippp_bundle * mp = net_dev->pb; unsigned int tot_len; struct sk_buff *skb; int proto; struct sk_buff * skb; unsigned int tot_len; if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", __func__, lp->ppp_slot); return; } tot_len = calc_tot_len(&mp->frags, from, to); if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) { if( ippp_table[lp->ppp_slot]->debug & 0x40 ) printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, " "len %d\n", MP_SEQ(from), from->len ); skb = from; skb_pull(skb, MP_HEADER_LEN); __skb_unlink(skb, &mp->frags); mp->frames--; } else { struct sk_buff *walk, *tmp; int found_start = 0; struct sk_buff * frag; int n; for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++) tot_len += frag->len - MP_HEADER_LEN; if( ippp_table[lp->ppp_slot]->debug & 0x40 ) printk(KERN_DEBUG"isdn_mppp: reassembling frames %d " "to %d, len %d\n", MP_SEQ(from), lastseq, tot_len); skb = dev_alloc_skb(tot_len); if (!skb) "to %d, len %d\n", MP_SEQ(from), (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len ); if( (skb = dev_alloc_skb(tot_len)) == NULL ) { printk(KERN_ERR "isdn_mppp: cannot allocate sk buff " "of size %d\n", tot_len); isdn_ppp_mp_discard(mp, from, to); return; } found_start = 0; skb_queue_walk_safe(&mp->frags, walk, tmp) { if (walk == from) found_start = 1; if (!found_start) continue; while( from != to ) { unsigned int len = from->len - MP_HEADER_LEN; if (skb) { unsigned int len = walk->len - MP_HEADER_LEN; skb_copy_from_linear_data_offset(walk, MP_HEADER_LEN, skb_copy_from_linear_data_offset(from, MP_HEADER_LEN, skb_put(skb,len), len); } __skb_unlink(walk, &mp->frags); isdn_ppp_mp_free_skb(mp, walk); if (walk == to) break; frag = from->next; isdn_ppp_mp_free_skb(mp, from); from = frag; } } if (!skb) return; proto = isdn_ppp_strip_proto(skb); isdn_ppp_push_higher(net_dev, lp, skb, proto); } Loading
include/linux/isdn_ppp.h +1 −1 Original line number Diff line number Diff line Loading @@ -157,7 +157,7 @@ typedef struct { typedef struct { int mp_mrru; /* unused */ struct sk_buff_head frags; /* fragments sl list */ struct sk_buff * frags; /* fragments sl list -- use skb->next */ long frames; /* number of frames in the frame list */ unsigned int seq; /* last processed packet seq #: any packets * with smaller seq # will be dropped Loading