···15331533 int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);15341534 if( (isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL )15351535 return -ENOMEM;15361536- for( i = 0; i < ISDN_MAX_CHANNELS; i++ )15361536+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {15371537 spin_lock_init(&isdn_ppp_bundle_arr[i].lock);15381538+ skb_queue_head_init(&isdn_ppp_bundle_arr[i].frags);15391539+ }15381540 return 0;15391541}15401542···15691567 if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)15701568 return -ENOMEM;15711569 lp->next = lp->last = lp; /* nobody else in a queue */15721572- lp->netdev->pb->frags = NULL;15701570+ skb_queue_head_init(&lp->netdev->pb->frags);15731571 lp->netdev->pb->frames = 0;15741572 lp->netdev->pb->seq = UINT_MAX;15751573 }···1581157915821580static u32 isdn_ppp_mp_get_seq( int short_seq, 15831581 struct sk_buff * skb, u32 last_seq );15841584-static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,15851585- struct sk_buff * from, struct sk_buff * to );15861586-static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,15871587- struct sk_buff * from, struct sk_buff * to );15881588-static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );15821582+static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from,15831583+ struct sk_buff *to);15841584+static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,15851585+ struct sk_buff *from, struct sk_buff *to,15861586+ u32 lastseq);15871587+static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);15891588static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );1590158915911590static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, 15921592- struct sk_buff *skb)15911591+ struct sk_buff *skb)15931592{15941594- struct ippp_struct *is;15951595- isdn_net_local * lpq;15961596- ippp_bundle * mp;15971597- isdn_mppp_stats * stats;15981598- struct sk_buff * newfrag, * frag, * start, *nextf;15931593+ struct sk_buff *newfrag, *frag, *start, *nextf;15991594 u32 newseq, minseq, thisseq;15951595+ isdn_mppp_stats *stats;15961596+ struct ippp_struct *is;16001597 unsigned long flags;15981598+ isdn_net_local *lpq;15991599+ ippp_bundle *mp;16011600 int slot;1602160116031602 spin_lock_irqsave(&net_dev->pb->lock, flags);16041604- mp = net_dev->pb;16051605- stats = &mp->stats;16031603+ mp = net_dev->pb;16041604+ stats = &mp->stats;16061605 slot = lp->ppp_slot;16071606 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {16081607 printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",···16141611 return;16151612 }16161613 is = ippp_table[slot];16171617- if( ++mp->frames > stats->max_queue_len )16141614+ if (++mp->frames > stats->max_queue_len)16181615 stats->max_queue_len = mp->frames;16191619-16161616+16201617 if (is->debug & 0x8)16211618 isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);1622161916231623- newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, 16241624- skb, is->last_link_seqno);16251625-16201620+ newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,16211621+ skb, is->last_link_seqno);1626162216271623 /* if this packet seq # is less than last already processed one,16281624 * toss it right away, but check for sequence start case first 16291625 */16301630- if( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) {16261626+ if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {16311627 mp->seq = newseq; /* the first packet: required for16321628 * rfc1990 non-compliant clients --16331629 * prevents constant packet toss */···16361634 spin_unlock_irqrestore(&mp->lock, flags);16371635 return;16381636 }16391639-16371637+16401638 /* find the minimum received sequence number over all links */16411639 is->last_link_seqno = minseq = newseq;16421640 for (lpq = net_dev->queue;;) {···16571655 * packets */16581656 newfrag = skb;1659165716601660- /* if this new fragment is before the first one, then enqueue it now. */16611661- if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {16621662- newfrag->next = frag;16631663- mp->frags = frag = newfrag;16641664- newfrag = NULL;16651665- }16581658+ /* Insert new fragment into the proper sequence slot. */16591659+ skb_queue_walk(&mp->frags, frag) {16601660+ if (MP_SEQ(frag) == newseq) {16611661+ isdn_ppp_mp_free_skb(mp, newfrag);16621662+ newfrag = NULL;16631663+ break;16641664+ }16651665+ if (MP_LT(newseq, MP_SEQ(frag))) {16661666+ __skb_queue_before(&mp->frags, frag, newfrag);16671667+ newfrag = NULL;16681668+ break;16691669+ }16701670+ }16711671+ if (newfrag)16721672+ __skb_queue_tail(&mp->frags, newfrag);1666167316671667- start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&16681668- MP_SEQ(frag) == mp->seq ? frag : NULL;16741674+ frag = skb_peek(&mp->frags);16751675+ start = ((MP_FLAGS(frag) & MP_BEGIN_FRAG) &&16761676+ (MP_SEQ(frag) == mp->seq)) ? frag : NULL;16771677+ if (!start)16781678+ goto check_overflow;1669167916701670- /* 16711671- * main fragment traversing loop16801680+ /* main fragment traversing loop16721681 *16731682 * try to accomplish several tasks:16741674- * - insert new fragment into the proper sequence slot (once that's done16751675- * newfrag will be set to NULL)16761683 * - reassemble any complete fragment sequence (non-null 'start'16771684 * indicates there is a continguous sequence present)16781685 * - discard any incomplete sequences that are below minseq -- due···16901679 * come to complete such sequence and it should be discarded16911680 *16921681 * loop completes when we accomplished the following tasks:16931693- * - new fragment is inserted in the proper sequence ('newfrag' is 16941694- * set to NULL)16951682 * - we hit a gap in the sequence, so no reassembly/processing is 16961683 * possible ('start' would be set to NULL)16971684 *16981685 * algorithm for this code is derived from code in the book16991686 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)17001687 */17011701- while (start != NULL || newfrag != NULL) {16881688+ skb_queue_walk_safe(&mp->frags, frag, nextf) {16891689+ thisseq = MP_SEQ(frag);1702169017031703- thisseq = MP_SEQ(frag);17041704- nextf = frag->next;17051705-17061706- /* drop any duplicate fragments */17071707- if (newfrag != NULL && thisseq == newseq) {17081708- isdn_ppp_mp_free_skb(mp, newfrag);17091709- newfrag = NULL;17101710- }17111711-17121712- /* insert new fragment before next element if possible. */17131713- if (newfrag != NULL && (nextf == NULL || 17141714- MP_LT(newseq, MP_SEQ(nextf)))) {17151715- newfrag->next = nextf;17161716- frag->next = nextf = newfrag;17171717- newfrag = NULL;17181718- }17191719-17201720- if (start != NULL) {17211721- /* check for misplaced start */17221722- if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {17231723- printk(KERN_WARNING"isdn_mppp(seq %d): new "17241724- "BEGIN flag with no prior END", thisseq);17251725- stats->seqerrs++;17261726- stats->frame_drops++;17271727- start = isdn_ppp_mp_discard(mp, start,frag);17281728- nextf = frag->next;17291729- }17301730- } else if (MP_LE(thisseq, minseq)) { 17311731- if (MP_FLAGS(frag) & MP_BEGIN_FRAG)16911691+ /* check for misplaced start */16921692+ if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {16931693+ printk(KERN_WARNING"isdn_mppp(seq %d): new "16941694+ "BEGIN flag with no prior END", thisseq);16951695+ stats->seqerrs++;16961696+ stats->frame_drops++;16971697+ isdn_ppp_mp_discard(mp, start, frag);16981698+ start = frag;16991699+ } else if (MP_LE(thisseq, minseq)) { 17001700+ if (MP_FLAGS(frag) & MP_BEGIN_FRAG)17321701 start = frag;17331733- else {17021702+ else {17341703 if (MP_FLAGS(frag) & MP_END_FRAG)17351735- stats->frame_drops++;17361736- if( mp->frags == frag )17371737- mp->frags = nextf; 17041704+ stats->frame_drops++;17051705+ __skb_unlink(skb, &mp->frags);17381706 isdn_ppp_mp_free_skb(mp, frag);17391739- frag = nextf;17401707 continue;17411741- }17081708+ }17421709 }17431743-17441744- /* if start is non-null and we have end fragment, then17451745- * we have full reassembly sequence -- reassemble 17461746- * and process packet now17471747- */17481748- if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {17491749- minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;17501750- /* Reassemble the packet then dispatch it */17511751- isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);17521752-17531753- start = NULL;17541754- frag = NULL;1755171017561756- mp->frags = nextf;17571757- }17111711+ /* if we have end fragment, then we have full reassembly17121712+ * sequence -- reassemble and process packet now17131713+ */17141714+ if (MP_FLAGS(frag) & MP_END_FRAG) {17151715+ minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;17161716+ /* Reassemble the packet then dispatch it */17171717+ isdn_ppp_mp_reassembly(net_dev, lp, start, frag, thisseq);17181718+17191719+ start = NULL;17201720+ frag = NULL;17211721+ }1758172217591723 /* check if need to update start pointer: if we just17601724 * reassembled the packet and sequence is contiguous···17401754 * below low watermark and set start to the next frag or17411755 * clear start ptr.17421756 */ 17431743- if (nextf != NULL && 17571757+ if (nextf != (struct sk_buff *)&mp->frags && 17441758 ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {17451745- /* if we just reassembled and the next one is here, 17461746- * then start another reassembly. */17471747-17481748- if (frag == NULL) {17591759+ /* if we just reassembled and the next one is here, 17601760+ * then start another reassembly.17611761+ */17621762+ if (frag == NULL) {17491763 if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)17501750- start = nextf;17511751- else17521752- {17531753- printk(KERN_WARNING"isdn_mppp(seq %d):"17541754- " END flag with no following "17551755- "BEGIN", thisseq);17641764+ start = nextf;17651765+ else {17661766+ printk(KERN_WARNING"isdn_mppp(seq %d):"17671767+ " END flag with no following "17681768+ "BEGIN", thisseq);17561769 stats->seqerrs++;17571770 }17581771 }17591759-17601760- } else {17611761- if ( nextf != NULL && frag != NULL &&17621762- MP_LT(thisseq, minseq)) {17721772+ } else {17731773+ if (nextf != (struct sk_buff *)&mp->frags &&17741774+ frag != NULL &&17751775+ MP_LT(thisseq, minseq)) {17631776 /* we've got a break in the sequence17641777 * and we not at the end yet17651778 * and we did not just reassembled···17671782 * discard all the frames below low watermark 17681783 * and start over */17691784 stats->frame_drops++;17701770- mp->frags = isdn_ppp_mp_discard(mp,start,nextf);17851785+ isdn_ppp_mp_discard(mp, start, nextf);17711786 }17721787 /* break in the sequence, no reassembly */17731773- start = NULL;17741774- }17751775-17761776- frag = nextf;17771777- } /* while -- main loop */17781778-17791779- if (mp->frags == NULL)17801780- mp->frags = frag;17811781-17881788+ start = NULL;17891789+ }17901790+ if (!start)17911791+ break;17921792+ }17931793+17941794+check_overflow:17821795 /* rather straighforward way to deal with (not very) possible 17831783- * queue overflow */17961796+ * queue overflow17971797+ */17841798 if (mp->frames > MP_MAX_QUEUE_LEN) {17851799 stats->overflows++;17861786- while (mp->frames > MP_MAX_QUEUE_LEN) {17871787- frag = mp->frags->next;17881788- isdn_ppp_mp_free_skb(mp, mp->frags);17891789- mp->frags = frag;18001800+ skb_queue_walk_safe(&mp->frags, frag, nextf) {18011801+ if (mp->frames <= MP_MAX_QUEUE_LEN)18021802+ break;18031803+ __skb_unlink(frag, &mp->frags);18041804+ isdn_ppp_mp_free_skb(mp, frag);17901805 }17911806 }17921807 spin_unlock_irqrestore(&mp->lock, flags);17931808}1794180917951795-static void isdn_ppp_mp_cleanup( isdn_net_local * lp )18101810+static void isdn_ppp_mp_cleanup(isdn_net_local *lp)17961811{17971797- struct sk_buff * frag = lp->netdev->pb->frags;17981798- struct sk_buff * nextfrag;17991799- while( frag ) {18001800- nextfrag = frag->next;18011801- isdn_ppp_mp_free_skb(lp->netdev->pb, frag);18021802- frag = nextfrag;18121812+ struct sk_buff *skb, *tmp;18131813+18141814+ skb_queue_walk_safe(&lp->netdev->pb->frags, skb, tmp) {18151815+ __skb_unlink(skb, &lp->netdev->pb->frags);18161816+ isdn_ppp_mp_free_skb(lp->netdev->pb, skb);18031817 }18041804- lp->netdev->pb->frags = NULL;18051818}1806181918071820static u32 isdn_ppp_mp_get_seq( int short_seq, ···18361853 return seq;18371854}1838185518391839-struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,18401840- struct sk_buff * from, struct sk_buff * to )18561856+static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from,18571857+ struct sk_buff *to)18411858{18421842- if( from )18431843- while (from != to) {18441844- struct sk_buff * next = from->next;18451845- isdn_ppp_mp_free_skb(mp, from);18461846- from = next;18591859+ if (from) {18601860+ struct sk_buff *skb, *tmp;18611861+ int freeing = 0;18621862+18631863+ skb_queue_walk_safe(&mp->frags, skb, tmp) {18641864+ if (skb == to)18651865+ break;18661866+ if (skb == from)18671867+ freeing = 1;18681868+ if (!freeing)18691869+ continue;18701870+ __skb_unlink(skb, &mp->frags);18711871+ isdn_ppp_mp_free_skb(mp, skb);18471872 }18481848- return from;18731873+ }18491874}1850187518511851-void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,18521852- struct sk_buff * from, struct sk_buff * to )18761876+static unsigned int calc_tot_len(struct sk_buff_head *queue,18771877+ struct sk_buff *from, struct sk_buff *to)18531878{18541854- ippp_bundle * mp = net_dev->pb;18551855- int proto;18561856- struct sk_buff * skb;18791879+ unsigned int tot_len = 0;18801880+ struct sk_buff *skb;18811881+ int found_start = 0;18821882+18831883+ skb_queue_walk(queue, skb) {18841884+ if (skb == from)18851885+ found_start = 1;18861886+ if (!found_start)18871887+ continue;18881888+ tot_len += skb->len - MP_HEADER_LEN;18891889+ if (skb == to)18901890+ break;18911891+ }18921892+ return tot_len;18931893+}18941894+18951895+/* Reassemble packet using fragments in the reassembly queue from18961896+ * 'from' until 'to', inclusive.18971897+ */18981898+static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,18991899+ struct sk_buff *from, struct sk_buff *to,19001900+ u32 lastseq)19011901+{19021902+ ippp_bundle *mp = net_dev->pb;18571903 unsigned int tot_len;19041904+ struct sk_buff *skb;19051905+ int proto;1858190618591907 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {18601908 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",18611909 __func__, lp->ppp_slot);18621910 return;18631911 }18641864- if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {18651865- if( ippp_table[lp->ppp_slot]->debug & 0x40 )19121912+19131913+ tot_len = calc_tot_len(&mp->frags, from, to);19141914+19151915+ if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {19161916+ if (ippp_table[lp->ppp_slot]->debug & 0x40)18661917 printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "18671867- "len %d\n", MP_SEQ(from), from->len );19181918+ "len %d\n", MP_SEQ(from), from->len);18681919 skb = from;18691920 skb_pull(skb, MP_HEADER_LEN);19211921+ __skb_unlink(skb, &mp->frags);18701922 mp->frames--; 18711923 } else {18721872- struct sk_buff * frag;18731873- int n;19241924+ struct sk_buff *walk, *tmp;19251925+ int found_start = 0;1874192618751875- for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)18761876- tot_len += frag->len - MP_HEADER_LEN;18771877-18781878- if( ippp_table[lp->ppp_slot]->debug & 0x40 )19271927+ if (ippp_table[lp->ppp_slot]->debug & 0x40)18791928 printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "18801880- "to %d, len %d\n", MP_SEQ(from), 18811881- (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );18821882- if( (skb = dev_alloc_skb(tot_len)) == NULL ) {19291929+ "to %d, len %d\n", MP_SEQ(from), lastseq,19301930+ tot_len);19311931+19321932+ skb = dev_alloc_skb(tot_len);19331933+ if (!skb)18831934 printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "18841884- "of size %d\n", tot_len);18851885- isdn_ppp_mp_discard(mp, from, to);18861886- return;18871887- }19351935+ "of size %d\n", tot_len);1888193618891889- while( from != to ) {18901890- unsigned int len = from->len - MP_HEADER_LEN;19371937+ found_start = 0;19381938+ skb_queue_walk_safe(&mp->frags, walk, tmp) {19391939+ if (walk == from)19401940+ found_start = 1;19411941+ if (!found_start)19421942+ continue;1891194318921892- skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,18931893- skb_put(skb,len),18941894- len);18951895- frag = from->next;18961896- isdn_ppp_mp_free_skb(mp, from);18971897- from = frag; 19441944+ if (skb) {19451945+ unsigned int len = walk->len - MP_HEADER_LEN;19461946+ skb_copy_from_linear_data_offset(walk, MP_HEADER_LEN,19471947+ skb_put(skb, len),19481948+ len);19491949+ }19501950+ __skb_unlink(walk, &mp->frags);19511951+ isdn_ppp_mp_free_skb(mp, walk);19521952+19531953+ if (walk == to)19541954+ break;18981955 }18991956 }19571957+ if (!skb)19581958+ return;19591959+19001960 proto = isdn_ppp_strip_proto(skb);19011961 isdn_ppp_push_higher(net_dev, lp, skb, proto);19021962}1903196319041904-static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb)19641964+static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)19051965{19061966 dev_kfree_skb(skb);19071967 mp->frames--;
+1-1
include/linux/isdn_ppp.h
···157157158158typedef struct {159159 int mp_mrru; /* unused */160160- struct sk_buff * frags; /* fragments sl list -- use skb->next */160160+ struct sk_buff_head frags; /* fragments sl list */161161 long frames; /* number of frames in the frame list */162162 unsigned int seq; /* last processed packet seq #: any packets163163 * with smaller seq # will be dropped