get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/1006/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1006,
    "url": "http://patchwork.ozlabs.org/api/patches/1006/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20080922.191243.177666844.davem@davemloft.net/",
    "project": {
        "id": 7,
        "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api",
        "name": "Linux network development",
        "link_name": "netdev",
        "list_id": "netdev.vger.kernel.org",
        "list_email": "netdev@vger.kernel.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20080922.191243.177666844.davem@davemloft.net>",
    "list_archive_url": null,
    "date": "2008-09-23T02:12:43",
    "name": "[6/7] : isdn: isdn_ppp: Use SKB list facilities instead of home-grown implementation.",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "6043fa6ebfad1d4044c6c278b8b9961dd6ab083a",
    "submitter": {
        "id": 15,
        "url": "http://patchwork.ozlabs.org/api/people/15/?format=api",
        "name": "David Miller",
        "email": "davem@davemloft.net"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/20080922.191243.177666844.davem@davemloft.net/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/1006/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/1006/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<netdev-owner@vger.kernel.org>",
        "X-Original-To": "patchwork-incoming@ozlabs.org",
        "Delivered-To": "patchwork-incoming@ozlabs.org",
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.176.167])\n\tby ozlabs.org (Postfix) with ESMTP id 8358ADDEE7\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 23 Sep 2008 12:13:09 +1000 (EST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1754158AbYIWCNA (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tMon, 22 Sep 2008 22:13:00 -0400",
            "(majordomo@vger.kernel.org) by vger.kernel.org id S1753802AbYIWCM6\n\t(ORCPT <rfc822; netdev-outgoing>); Mon, 22 Sep 2008 22:12:58 -0400",
            "from 74-93-104-97-Washington.hfc.comcastbusiness.net\n\t([74.93.104.97]:37181\n\t\"EHLO sunset.davemloft.net\" rhost-flags-OK-FAIL-OK-OK)\n\tby vger.kernel.org with ESMTP id S1754069AbYIWCMz (ORCPT\n\t<rfc822;netdev@vger.kernel.org>); Mon, 22 Sep 2008 22:12:55 -0400",
            "from localhost (localhost [127.0.0.1])\n\tby sunset.davemloft.net (Postfix) with ESMTP id AF5E2C8C181\n\tfor <netdev@vger.kernel.org>; Mon, 22 Sep 2008 19:12:43 -0700 (PDT)"
        ],
        "Date": "Mon, 22 Sep 2008 19:12:43 -0700 (PDT)",
        "Message-Id": "<20080922.191243.177666844.davem@davemloft.net>",
        "To": "netdev@vger.kernel.org",
        "Subject": "[PATCH 6/7]: isdn: isdn_ppp: Use SKB list facilities instead of\n\thome-grown implementation.",
        "From": "David Miller <davem@davemloft.net>",
        "X-Mailer": "Mew version 6.1 on Emacs 22.1 / Mule 5.0 (SAKAKI)",
        "Mime-Version": "1.0",
        "Content-Type": "Text/Plain; charset=us-ascii",
        "Content-Transfer-Encoding": "7bit",
        "Sender": "netdev-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<netdev.vger.kernel.org>",
        "X-Mailing-List": "netdev@vger.kernel.org"
    },
    "content": "isdn: isdn_ppp: Use SKB list facilities instead of home-grown implementation.\n\nSigned-off-by: David S. Miller <davem@davemloft.net>\n---\n drivers/isdn/i4l/isdn_ppp.c |  352 +++++++++++++++++++++++--------------------\n include/linux/isdn_ppp.h    |    2 +-\n 2 files changed, 190 insertions(+), 164 deletions(-)",
    "diff": "diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c\nindex 127cfda..77c280e 100644\n--- a/drivers/isdn/i4l/isdn_ppp.c\n+++ b/drivers/isdn/i4l/isdn_ppp.c\n@@ -1533,8 +1533,10 @@ static int isdn_ppp_mp_bundle_array_init(void)\n \tint sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);\n \tif( (isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL )\n \t\treturn -ENOMEM;\n-\tfor( i = 0; i < ISDN_MAX_CHANNELS; i++ )\n+\tfor (i = 0; i < ISDN_MAX_CHANNELS; i++) {\n \t\tspin_lock_init(&isdn_ppp_bundle_arr[i].lock);\n+\t\tskb_queue_head_init(&isdn_ppp_bundle_arr[i].frags);\n+\t}\n \treturn 0;\n }\n \n@@ -1567,7 +1569,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )\n \t\tif ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)\n \t\t\treturn -ENOMEM;\n \t\tlp->next = lp->last = lp;\t/* nobody else in a queue */\n-\t\tlp->netdev->pb->frags = NULL;\n+\t\tskb_queue_head_init(&lp->netdev->pb->frags);\n \t\tlp->netdev->pb->frames = 0;\n \t\tlp->netdev->pb->seq = UINT_MAX;\n \t}\n@@ -1579,28 +1581,29 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )\n \n static u32 isdn_ppp_mp_get_seq( int short_seq, \n \t\t\t\t\tstruct sk_buff * skb, u32 last_seq );\n-static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,\n-\t\t\tstruct sk_buff * from, struct sk_buff * to );\n-static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,\n-\t\t\t\tstruct sk_buff * from, struct sk_buff * to );\n-static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );\n+static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from,\n+\t\t\t\tstruct sk_buff *to);\n+static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,\n+\t\t\t\t   struct sk_buff *from, struct sk_buff *to,\n+\t\t\t\t   u32 lastseq);\n+static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);\n static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );\n \n static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, \n-\t\t\t\t\t\t\tstruct sk_buff *skb)\n+\t\t\t\tstruct sk_buff *skb)\n {\n-\tstruct ippp_struct *is;\n-\tisdn_net_local * lpq;\n-\tippp_bundle * mp;\n-\tisdn_mppp_stats * stats;\n-\tstruct sk_buff * newfrag, * frag, * start, *nextf;\n+\tstruct sk_buff *newfrag, *frag, *start, *nextf;\n \tu32 newseq, minseq, thisseq;\n+\tisdn_mppp_stats *stats;\n+\tstruct ippp_struct *is;\n \tunsigned long flags;\n+\tisdn_net_local *lpq;\n+\tippp_bundle *mp;\n \tint slot;\n \n \tspin_lock_irqsave(&net_dev->pb->lock, flags);\n-    \tmp = net_dev->pb;\n-        stats = &mp->stats;\n+\tmp = net_dev->pb;\n+\tstats = &mp->stats;\n \tslot = lp->ppp_slot;\n \tif (slot < 0 || slot >= ISDN_MAX_CHANNELS) {\n \t\tprintk(KERN_ERR \"%s: lp->ppp_slot(%d)\\n\",\n@@ -1611,20 +1614,19 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,\n \t\treturn;\n \t}\n \tis = ippp_table[slot];\n-    \tif( ++mp->frames > stats->max_queue_len )\n+\tif (++mp->frames > stats->max_queue_len)\n \t\tstats->max_queue_len = mp->frames;\n-\t\n+\n \tif (is->debug & 0x8)\n \t\tisdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);\n \n-\tnewseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, \n-\t\t\t\t\t\tskb, is->last_link_seqno);\n-\n+\tnewseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,\n+\t\t\t\t     skb, is->last_link_seqno);\n \n \t/* if this packet seq # is less than last already processed one,\n \t * toss it right away, but check for sequence start case first \n \t */\n-\tif( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) {\n+\tif (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {\n \t\tmp->seq = newseq;\t/* the first packet: required for\n \t\t\t\t\t * rfc1990 non-compliant clients --\n \t\t\t\t\t * prevents constant packet toss */\n@@ -1634,7 +1636,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,\n \t\tspin_unlock_irqrestore(&mp->lock, flags);\n \t\treturn;\n \t}\n-\t\n+\n \t/* find the minimum received sequence number over all links */\n \tis->last_link_seqno = minseq = newseq;\n \tfor (lpq = net_dev->queue;;) {\n@@ -1655,22 +1657,31 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,\n \t\t\t\t\t * packets */\n \tnewfrag = skb;\n \n-  \t/* if this new fragment is before the first one, then enqueue it now. */\n-  \tif ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {\n-\t\tnewfrag->next = frag;\n-    \t\tmp->frags = frag = newfrag;\n-    \t\tnewfrag = NULL;\n-  \t}\n+\t/* Insert new fragment into the proper sequence slot.  */\n+\tskb_queue_walk(&mp->frags, frag) {\n+\t\tif (MP_SEQ(frag) == newseq) {\n+\t\t\tisdn_ppp_mp_free_skb(mp, newfrag);\n+\t\t\tnewfrag = NULL;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (MP_LT(newseq, MP_SEQ(frag))) {\n+\t\t\t__skb_queue_before(&mp->frags, frag, newfrag);\n+\t\t\tnewfrag = NULL;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tif (newfrag)\n+\t\t__skb_queue_tail(&mp->frags, newfrag);\n \n-  \tstart = MP_FLAGS(frag) & MP_BEGIN_FRAG &&\n-\t\t\t\tMP_SEQ(frag) == mp->seq ? frag : NULL;\n+\tfrag = skb_peek(&mp->frags);\n+\tstart = ((MP_FLAGS(frag) & MP_BEGIN_FRAG) &&\n+\t\t (MP_SEQ(frag) == mp->seq)) ? frag : NULL;\n+\tif (!start)\n+\t\tgoto check_overflow;\n \n-\t/* \n-\t * main fragment traversing loop\n+\t/* main fragment traversing loop\n \t *\n \t * try to accomplish several tasks:\n-\t * - insert new fragment into the proper sequence slot (once that's done\n-\t *   newfrag will be set to NULL)\n \t * - reassemble any complete fragment sequence (non-null 'start'\n \t *   indicates there is a continguous sequence present)\n \t * - discard any incomplete sequences that are below minseq -- due\n@@ -1679,71 +1690,46 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,\n \t *   come to complete such sequence and it should be discarded\n \t *\n \t * loop completes when we accomplished the following tasks:\n-\t * - new fragment is inserted in the proper sequence ('newfrag' is \n-\t *   set to NULL)\n \t * - we hit a gap in the sequence, so no reassembly/processing is \n \t *   possible ('start' would be set to NULL)\n \t *\n \t * algorithm for this code is derived from code in the book\n \t * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)\n \t */\n-  \twhile (start != NULL || newfrag != NULL) {\n-\n-    \t\tthisseq = MP_SEQ(frag);\n-    \t\tnextf = frag->next;\n-\n-    \t\t/* drop any duplicate fragments */\n-    \t\tif (newfrag != NULL && thisseq == newseq) {\n-      \t\t\tisdn_ppp_mp_free_skb(mp, newfrag);\n-      \t\t\tnewfrag = NULL;\n-    \t\t}\n-\n-    \t\t/* insert new fragment before next element if possible. */\n-    \t\tif (newfrag != NULL && (nextf == NULL || \n-\t\t\t\t\t\tMP_LT(newseq, MP_SEQ(nextf)))) {\n-      \t\t\tnewfrag->next = nextf;\n-      \t\t\tfrag->next = nextf = newfrag;\n-      \t\t\tnewfrag = NULL;\n-    \t\t}\n-\n-    \t\tif (start != NULL) {\n-\t    \t\t/* check for misplaced start */\n-      \t\t\tif (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {\n-\t\t\t\tprintk(KERN_WARNING\"isdn_mppp(seq %d): new \"\n-\t\t\t\t      \"BEGIN flag with no prior END\", thisseq);\n-\t\t\t\tstats->seqerrs++;\n-\t\t\t\tstats->frame_drops++;\n-\t\t\t\tstart = isdn_ppp_mp_discard(mp, start,frag);\n-\t\t\t\tnextf = frag->next;\n-      \t\t\t}\n-    \t\t} else if (MP_LE(thisseq, minseq)) {\t\t\n-      \t\t\tif (MP_FLAGS(frag) & MP_BEGIN_FRAG)\n+\tskb_queue_walk_safe(&mp->frags, frag, nextf) {\n+\t\tthisseq = MP_SEQ(frag);\n+\n+\t\t/* check for misplaced start */\n+\t\tif (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {\n+\t\t\tprintk(KERN_WARNING\"isdn_mppp(seq %d): new \"\n+\t\t\t       \"BEGIN flag with no prior END\", thisseq);\n+\t\t\tstats->seqerrs++;\n+\t\t\tstats->frame_drops++;\n+\t\t\tisdn_ppp_mp_discard(mp, start, frag);\n+\t\t\tstart = frag;\n+\t\t} else if (MP_LE(thisseq, minseq)) {\t\t\n+\t\t\tif (MP_FLAGS(frag) & MP_BEGIN_FRAG)\n \t\t\t\tstart = frag;\n-      \t\t\telse {\n+\t\t\telse {\n \t\t\t\tif (MP_FLAGS(frag) & MP_END_FRAG)\n-\t  \t\t\t\tstats->frame_drops++;\n-\t\t\t\tif( mp->frags == frag )\n-\t\t\t\t\tmp->frags = nextf;\t\n+\t\t\t\t\tstats->frame_drops++;\n+\t\t\t\t__skb_unlink(skb, &mp->frags);\n \t\t\t\tisdn_ppp_mp_free_skb(mp, frag);\n-\t\t\t\tfrag = nextf;\n \t\t\t\tcontinue;\n-      \t\t\t}\n+\t\t\t}\n \t\t}\n-\t\t\n-\t\t/* if start is non-null and we have end fragment, then\n-\t\t * we have full reassembly sequence -- reassemble \n-\t\t * and process packet now\n+\n+\t\t/* if we have end fragment, then we have full reassembly\n+\t\t * sequence -- reassemble and process packet now\n \t\t */\n-    \t\tif (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {\n-      \t\t\tminseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;\n-      \t\t\t/* Reassemble the packet then dispatch it */\n-\t\t\tisdn_ppp_mp_reassembly(net_dev, lp, start, nextf);\n-      \n-      \t\t\tstart = NULL;\n-      \t\t\tfrag = NULL;\n+\t\tif (MP_FLAGS(frag) & MP_END_FRAG) {\n+\t\t\tminseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;\n+\t\t\t/* Reassemble the packet then dispatch it */\n+\t\t\tisdn_ppp_mp_reassembly(net_dev, lp, start, frag, thisseq);\n \n-      \t\t\tmp->frags = nextf;\n-    \t\t}\n+\t\t\tstart = NULL;\n+\t\t\tfrag = NULL;\n+\t\t}\n \n \t\t/* check if need to update start pointer: if we just\n \t\t * reassembled the packet and sequence is contiguous\n@@ -1754,26 +1740,25 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,\n \t\t * below low watermark and set start to the next frag or\n \t\t * clear start ptr.\n \t\t */ \n-    \t\tif (nextf != NULL && \n+\t\tif (nextf != (struct sk_buff *)&mp->frags && \n \t\t    ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {\n-      \t\t\t/* if we just reassembled and the next one is here, \n-\t\t\t * then start another reassembly. */\n-\n-      \t\t\tif (frag == NULL) {\n+\t\t\t/* if we just reassembled and the next one is here, \n+\t\t\t * then start another reassembly.\n+\t\t\t */\n+\t\t\tif (frag == NULL) {\n \t\t\t\tif (MP_FLAGS(nextf) & MP_BEGIN_FRAG)\n-\t  \t\t\t\tstart = nextf;\n-\t\t\t\telse\n-\t\t\t\t{\n-\t  \t\t\t\tprintk(KERN_WARNING\"isdn_mppp(seq %d):\"\n-\t\t\t\t\t\t\" END flag with no following \"\n-\t\t\t\t\t\t\"BEGIN\", thisseq);\n+\t\t\t\t\tstart = nextf;\n+\t\t\t\telse {\n+\t\t\t\t\tprintk(KERN_WARNING\"isdn_mppp(seq %d):\"\n+\t\t\t\t\t       \" END flag with no following \"\n+\t\t\t\t\t       \"BEGIN\", thisseq);\n \t\t\t\t\tstats->seqerrs++;\n \t\t\t\t}\n \t\t\t}\n-\n-    \t\t} else {\n-\t\t\tif ( nextf != NULL && frag != NULL &&\n-\t\t\t\t\t\tMP_LT(thisseq, minseq)) {\n+\t\t} else {\n+\t\t\tif (nextf != (struct sk_buff *)&mp->frags &&\n+\t\t\t    frag != NULL &&\n+\t\t\t    MP_LT(thisseq, minseq)) {\n \t\t\t\t/* we've got a break in the sequence\n \t\t\t\t * and we not at the end yet\n \t\t\t\t * and we did not just reassembled\n@@ -1782,41 +1767,39 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,\n \t\t\t \t * discard all the frames below low watermark \n \t\t\t\t * and start over */\n \t\t\t\tstats->frame_drops++;\n-\t\t\t\tmp->frags = isdn_ppp_mp_discard(mp,start,nextf);\n+\t\t\t\tisdn_ppp_mp_discard(mp, start, nextf);\n \t\t\t}\n \t\t\t/* break in the sequence, no reassembly */\n-      \t\t\tstart = NULL;\n-    \t\t}\n-\t  \t\t\t\n-    \t\tfrag = nextf;\n-  \t}\t/* while -- main loop */\n-\t\n-  \tif (mp->frags == NULL)\n-    \t\tmp->frags = frag;\n-\t\t\n+\t\t\tstart = NULL;\n+\t\t}\n+\t\tif (!start)\n+\t\t\tbreak;\n+\t}\n+\n+check_overflow:\n \t/* rather straighforward way to deal with (not very) possible \n-\t * queue overflow */\n+\t * queue overflow\n+\t */\n \tif (mp->frames > MP_MAX_QUEUE_LEN) {\n \t\tstats->overflows++;\n-\t\twhile (mp->frames > MP_MAX_QUEUE_LEN) {\n-\t\t\tfrag = mp->frags->next;\n-\t\t\tisdn_ppp_mp_free_skb(mp, mp->frags);\n-\t\t\tmp->frags = frag;\n+\t\tskb_queue_walk_safe(&mp->frags, frag, nextf) {\n+\t\t\tif (mp->frames <= MP_MAX_QUEUE_LEN)\n+\t\t\t\tbreak;\n+\t\t\t__skb_unlink(frag, &mp->frags);\n+\t\t\tisdn_ppp_mp_free_skb(mp, frag);\n \t\t}\n \t}\n \tspin_unlock_irqrestore(&mp->lock, flags);\n }\n \n-static void isdn_ppp_mp_cleanup( isdn_net_local * lp )\n+static void isdn_ppp_mp_cleanup(isdn_net_local *lp)\n {\n-\tstruct sk_buff * frag = lp->netdev->pb->frags;\n-\tstruct sk_buff * nextfrag;\n-    \twhile( frag ) {\n-\t\tnextfrag = frag->next;\n-\t\tisdn_ppp_mp_free_skb(lp->netdev->pb, frag);\n-\t\tfrag = nextfrag;\n-\t}\n-\tlp->netdev->pb->frags = NULL;\n+\tstruct sk_buff *skb, *tmp;\n+\n+\tskb_queue_walk_safe(&lp->netdev->pb->frags, skb, tmp) {\n+\t\t__skb_unlink(skb, &lp->netdev->pb->frags);\n+\t\tisdn_ppp_mp_free_skb(lp->netdev->pb, skb);\n+\t}\n }\n \n static u32 isdn_ppp_mp_get_seq( int short_seq, \n@@ -1853,72 +1836,115 @@ static u32 isdn_ppp_mp_get_seq( int short_seq,\n \treturn seq;\n }\n \n-struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,\n-\t\t\tstruct sk_buff * from, struct sk_buff * to )\n+static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from,\n+\t\t\t\tstruct sk_buff *to)\n {\n-\tif( from )\n-\t\twhile (from != to) {\n-\t  \t\tstruct sk_buff * next = from->next;\n-\t\t\tisdn_ppp_mp_free_skb(mp, from);\n-\t  \t\tfrom = next;\n+\tif (from) {\n+\t\tstruct sk_buff *skb, *tmp;\n+\t\tint freeing = 0;\n+\n+\t\tskb_queue_walk_safe(&mp->frags, skb, tmp) {\n+\t\t\tif (skb == to)\n+\t\t\t\tbreak;\n+\t\t\tif (skb == from)\n+\t\t\t\tfreeing = 1;\n+\t\t\tif (!freeing)\n+\t\t\t\tcontinue;\n+\t\t\t__skb_unlink(skb, &mp->frags);\n+\t\t\tisdn_ppp_mp_free_skb(mp, skb);\n \t\t}\n-\treturn from;\n+\t}\n }\n \n-void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,\n-\t\t\t\tstruct sk_buff * from, struct sk_buff * to )\n+static unsigned int calc_tot_len(struct sk_buff_head *queue,\n+\t\t\t\t struct sk_buff *from, struct sk_buff *to)\n {\n-\tippp_bundle * mp = net_dev->pb;\n-\tint proto;\n-\tstruct sk_buff * skb;\n+\tunsigned int tot_len = 0;\n+\tstruct sk_buff *skb;\n+\tint found_start = 0;\n+\n+\tskb_queue_walk(queue, skb) {\n+\t\tif (skb == from)\n+\t\t\tfound_start = 1;\n+\t\tif (!found_start)\n+\t\t\tcontinue;\n+\t\ttot_len += skb->len - MP_HEADER_LEN;\n+\t\tif (skb == to)\n+\t\t\tbreak;\n+\t}\n+\treturn tot_len;\n+}\n+\n+/* Reassemble packet using fragments in the reassembly queue from\n+ * 'from' until 'to', inclusive.\n+ */\n+static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,\n+\t\t\t\t   struct sk_buff *from, struct sk_buff *to,\n+\t\t\t\t   u32 lastseq)\n+{\n+\tippp_bundle *mp = net_dev->pb;\n \tunsigned int tot_len;\n+\tstruct sk_buff *skb;\n+\tint proto;\n \n \tif (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {\n \t\tprintk(KERN_ERR \"%s: lp->ppp_slot(%d) out of range\\n\",\n \t\t\t__func__, lp->ppp_slot);\n \t\treturn;\n \t}\n-\tif( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {\n-\t\tif( ippp_table[lp->ppp_slot]->debug & 0x40 )\n+\n+\ttot_len = calc_tot_len(&mp->frags, from, to);\n+\n+\tif (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {\n+\t\tif (ippp_table[lp->ppp_slot]->debug & 0x40)\n \t\t\tprintk(KERN_DEBUG \"isdn_mppp: reassembly: frame %d, \"\n-\t\t\t\t\t\"len %d\\n\", MP_SEQ(from), from->len );\n+\t\t\t       \"len %d\\n\", MP_SEQ(from), from->len);\n \t\tskb = from;\n \t\tskb_pull(skb, MP_HEADER_LEN);\n+\t\t__skb_unlink(skb, &mp->frags);\n \t\tmp->frames--;\t\n \t} else {\n-\t\tstruct sk_buff * frag;\n-\t\tint n;\n+\t\tstruct sk_buff *walk, *tmp;\n+\t\tint found_start = 0;\n \n-\t\tfor(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)\n-\t\t\ttot_len += frag->len - MP_HEADER_LEN;\n-\n-\t\tif( ippp_table[lp->ppp_slot]->debug & 0x40 )\n+\t\tif (ippp_table[lp->ppp_slot]->debug & 0x40)\n \t\t\tprintk(KERN_DEBUG\"isdn_mppp: reassembling frames %d \"\n-\t\t\t\t\"to %d, len %d\\n\", MP_SEQ(from), \n-\t\t\t\t(MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );\n-\t\tif( (skb = dev_alloc_skb(tot_len)) == NULL ) {\n+\t\t\t       \"to %d, len %d\\n\", MP_SEQ(from), lastseq,\n+\t\t\t       tot_len);\n+\n+\t\tskb = dev_alloc_skb(tot_len);\n+\t\tif (!skb)\n \t\t\tprintk(KERN_ERR \"isdn_mppp: cannot allocate sk buff \"\n-\t\t\t\t\t\"of size %d\\n\", tot_len);\n-\t\t\tisdn_ppp_mp_discard(mp, from, to);\n-\t\t\treturn;\n-\t\t}\n+\t\t\t       \"of size %d\\n\", tot_len);\n+\n+\t\tfound_start = 0;\n+\t\tskb_queue_walk_safe(&mp->frags, walk, tmp) {\n+\t\t\tif (walk == from)\n+\t\t\t\tfound_start = 1;\n+\t\t\tif (!found_start)\n+\t\t\t\tcontinue;\n \n-\t\twhile( from != to ) {\n-\t\t\tunsigned int len = from->len - MP_HEADER_LEN;\n+\t\t\tif (skb) {\n+\t\t\t\tunsigned int len = walk->len - MP_HEADER_LEN;\n+\t\t\t\tskb_copy_from_linear_data_offset(walk, MP_HEADER_LEN,\n+\t\t\t\t\t\t\t\t skb_put(skb, len),\n+\t\t\t\t\t\t\t\t len);\n+\t\t\t}\n+\t\t\t__skb_unlink(walk, &mp->frags);\n+\t\t\tisdn_ppp_mp_free_skb(mp, walk);\n \n-\t\t\tskb_copy_from_linear_data_offset(from, MP_HEADER_LEN,\n-\t\t\t\t\t\t\t skb_put(skb,len),\n-\t\t\t\t\t\t\t len);\n-\t\t\tfrag = from->next;\n-\t\t\tisdn_ppp_mp_free_skb(mp, from);\n-\t\t\tfrom = frag; \n+\t\t\tif (walk == to)\n+\t\t\t\tbreak;\n \t\t}\n \t}\n+\tif (!skb)\n+\t\treturn;\n+\n    \tproto = isdn_ppp_strip_proto(skb);\n \tisdn_ppp_push_higher(net_dev, lp, skb, proto);\n }\n \n-static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb)\n+static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)\n {\n \tdev_kfree_skb(skb);\n \tmp->frames--;\ndiff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h\nindex 8687a7d..4c218ee 100644\n--- a/include/linux/isdn_ppp.h\n+++ b/include/linux/isdn_ppp.h\n@@ -157,7 +157,7 @@ typedef struct {\n \n typedef struct {\n   int mp_mrru;                        /* unused                             */\n-  struct sk_buff * frags;\t/* fragments sl list -- use skb->next */\n+  struct sk_buff_head frags;\t/* fragments sl list */\n   long frames;\t\t\t/* number of frames in the frame list */\n   unsigned int seq;\t\t/* last processed packet seq #: any packets\n   \t\t\t\t * with smaller seq # will be dropped\n",
    "prefixes": [
        "6/7"
    ]
}