aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-09-22 04:15:02 -0400
committerDavid S. Miller <davem@davemloft.net>2008-09-22 04:15:02 -0400
commit38783e671399b5405f1fd177d602c400a9577ae6 (patch)
tree850a7bf098d8f9801e2cf045d1d1a34d0a152430
parent8fc5387cb837f9e44a0be2d7e297bbbcab36a292 (diff)
isdn: isdn_ppp: Use SKB list facilities instead of home-grown implementation.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c352
-rw-r--r--include/linux/isdn_ppp.h2
2 files changed, 190 insertions, 164 deletions
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 127cfdad68e7..77c280ef2eb6 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -1533,8 +1533,10 @@ static int isdn_ppp_mp_bundle_array_init(void)
1533 int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle); 1533 int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
1534 if( (isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL ) 1534 if( (isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL )
1535 return -ENOMEM; 1535 return -ENOMEM;
1536 for( i = 0; i < ISDN_MAX_CHANNELS; i++ ) 1536 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1537 spin_lock_init(&isdn_ppp_bundle_arr[i].lock); 1537 spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
1538 skb_queue_head_init(&isdn_ppp_bundle_arr[i].frags);
1539 }
1538 return 0; 1540 return 0;
1539} 1541}
1540 1542
@@ -1567,7 +1569,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
1567 if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL) 1569 if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
1568 return -ENOMEM; 1570 return -ENOMEM;
1569 lp->next = lp->last = lp; /* nobody else in a queue */ 1571 lp->next = lp->last = lp; /* nobody else in a queue */
1570 lp->netdev->pb->frags = NULL; 1572 skb_queue_head_init(&lp->netdev->pb->frags);
1571 lp->netdev->pb->frames = 0; 1573 lp->netdev->pb->frames = 0;
1572 lp->netdev->pb->seq = UINT_MAX; 1574 lp->netdev->pb->seq = UINT_MAX;
1573 } 1575 }
@@ -1579,28 +1581,29 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
1579 1581
1580static u32 isdn_ppp_mp_get_seq( int short_seq, 1582static u32 isdn_ppp_mp_get_seq( int short_seq,
1581 struct sk_buff * skb, u32 last_seq ); 1583 struct sk_buff * skb, u32 last_seq );
1582static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, 1584static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from,
1583 struct sk_buff * from, struct sk_buff * to ); 1585 struct sk_buff *to);
1584static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, 1586static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
1585 struct sk_buff * from, struct sk_buff * to ); 1587 struct sk_buff *from, struct sk_buff *to,
1586static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb ); 1588 u32 lastseq);
1589static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);
1587static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ); 1590static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
1588 1591
1589static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, 1592static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
1590 struct sk_buff *skb) 1593 struct sk_buff *skb)
1591{ 1594{
1592 struct ippp_struct *is; 1595 struct sk_buff *newfrag, *frag, *start, *nextf;
1593 isdn_net_local * lpq;
1594 ippp_bundle * mp;
1595 isdn_mppp_stats * stats;
1596 struct sk_buff * newfrag, * frag, * start, *nextf;
1597 u32 newseq, minseq, thisseq; 1596 u32 newseq, minseq, thisseq;
1597 isdn_mppp_stats *stats;
1598 struct ippp_struct *is;
1598 unsigned long flags; 1599 unsigned long flags;
1600 isdn_net_local *lpq;
1601 ippp_bundle *mp;
1599 int slot; 1602 int slot;
1600 1603
1601 spin_lock_irqsave(&net_dev->pb->lock, flags); 1604 spin_lock_irqsave(&net_dev->pb->lock, flags);
1602 mp = net_dev->pb; 1605 mp = net_dev->pb;
1603 stats = &mp->stats; 1606 stats = &mp->stats;
1604 slot = lp->ppp_slot; 1607 slot = lp->ppp_slot;
1605 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { 1608 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1606 printk(KERN_ERR "%s: lp->ppp_slot(%d)\n", 1609 printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
@@ -1611,20 +1614,19 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
1611 return; 1614 return;
1612 } 1615 }
1613 is = ippp_table[slot]; 1616 is = ippp_table[slot];
1614 if( ++mp->frames > stats->max_queue_len ) 1617 if (++mp->frames > stats->max_queue_len)
1615 stats->max_queue_len = mp->frames; 1618 stats->max_queue_len = mp->frames;
1616 1619
1617 if (is->debug & 0x8) 1620 if (is->debug & 0x8)
1618 isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb); 1621 isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
1619 1622
1620 newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, 1623 newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
1621 skb, is->last_link_seqno); 1624 skb, is->last_link_seqno);
1622
1623 1625
1624 /* if this packet seq # is less than last already processed one, 1626 /* if this packet seq # is less than last already processed one,
1625 * toss it right away, but check for sequence start case first 1627 * toss it right away, but check for sequence start case first
1626 */ 1628 */
1627 if( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) { 1629 if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {
1628 mp->seq = newseq; /* the first packet: required for 1630 mp->seq = newseq; /* the first packet: required for
1629 * rfc1990 non-compliant clients -- 1631 * rfc1990 non-compliant clients --
1630 * prevents constant packet toss */ 1632 * prevents constant packet toss */
@@ -1634,7 +1636,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
1634 spin_unlock_irqrestore(&mp->lock, flags); 1636 spin_unlock_irqrestore(&mp->lock, flags);
1635 return; 1637 return;
1636 } 1638 }
1637 1639
1638 /* find the minimum received sequence number over all links */ 1640 /* find the minimum received sequence number over all links */
1639 is->last_link_seqno = minseq = newseq; 1641 is->last_link_seqno = minseq = newseq;
1640 for (lpq = net_dev->queue;;) { 1642 for (lpq = net_dev->queue;;) {
@@ -1655,22 +1657,31 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
1655 * packets */ 1657 * packets */
1656 newfrag = skb; 1658 newfrag = skb;
1657 1659
1658 /* if this new fragment is before the first one, then enqueue it now. */ 1660 /* Insert new fragment into the proper sequence slot. */
1659 if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) { 1661 skb_queue_walk(&mp->frags, frag) {
1660 newfrag->next = frag; 1662 if (MP_SEQ(frag) == newseq) {
1661 mp->frags = frag = newfrag; 1663 isdn_ppp_mp_free_skb(mp, newfrag);
1662 newfrag = NULL; 1664 newfrag = NULL;
1663 } 1665 break;
1666 }
1667 if (MP_LT(newseq, MP_SEQ(frag))) {
1668 __skb_queue_before(&mp->frags, frag, newfrag);
1669 newfrag = NULL;
1670 break;
1671 }
1672 }
1673 if (newfrag)
1674 __skb_queue_tail(&mp->frags, newfrag);
1664 1675
1665 start = MP_FLAGS(frag) & MP_BEGIN_FRAG && 1676 frag = skb_peek(&mp->frags);
1666 MP_SEQ(frag) == mp->seq ? frag : NULL; 1677 start = ((MP_FLAGS(frag) & MP_BEGIN_FRAG) &&
1678 (MP_SEQ(frag) == mp->seq)) ? frag : NULL;
1679 if (!start)
1680 goto check_overflow;
1667 1681
1668 /* 1682 /* main fragment traversing loop
1669 * main fragment traversing loop
1670 * 1683 *
1671 * try to accomplish several tasks: 1684 * try to accomplish several tasks:
1672 * - insert new fragment into the proper sequence slot (once that's done
1673 * newfrag will be set to NULL)
1674 * - reassemble any complete fragment sequence (non-null 'start' 1685 * - reassemble any complete fragment sequence (non-null 'start'
1675 * indicates there is a continguous sequence present) 1686 * indicates there is a continguous sequence present)
1676 * - discard any incomplete sequences that are below minseq -- due 1687 * - discard any incomplete sequences that are below minseq -- due
@@ -1679,71 +1690,46 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
1679 * come to complete such sequence and it should be discarded 1690 * come to complete such sequence and it should be discarded
1680 * 1691 *
1681 * loop completes when we accomplished the following tasks: 1692 * loop completes when we accomplished the following tasks:
1682 * - new fragment is inserted in the proper sequence ('newfrag' is
1683 * set to NULL)
1684 * - we hit a gap in the sequence, so no reassembly/processing is 1693 * - we hit a gap in the sequence, so no reassembly/processing is
1685 * possible ('start' would be set to NULL) 1694 * possible ('start' would be set to NULL)
1686 * 1695 *
1687 * algorithm for this code is derived from code in the book 1696 * algorithm for this code is derived from code in the book
1688 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley) 1697 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
1689 */ 1698 */
1690 while (start != NULL || newfrag != NULL) { 1699 skb_queue_walk_safe(&mp->frags, frag, nextf) {
1691 1700 thisseq = MP_SEQ(frag);
1692 thisseq = MP_SEQ(frag); 1701
1693 nextf = frag->next; 1702 /* check for misplaced start */
1694 1703 if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
1695 /* drop any duplicate fragments */ 1704 printk(KERN_WARNING"isdn_mppp(seq %d): new "
1696 if (newfrag != NULL && thisseq == newseq) { 1705 "BEGIN flag with no prior END", thisseq);
1697 isdn_ppp_mp_free_skb(mp, newfrag); 1706 stats->seqerrs++;
1698 newfrag = NULL; 1707 stats->frame_drops++;
1699 } 1708 isdn_ppp_mp_discard(mp, start, frag);
1700 1709 start = frag;
1701 /* insert new fragment before next element if possible. */ 1710 } else if (MP_LE(thisseq, minseq)) {
1702 if (newfrag != NULL && (nextf == NULL || 1711 if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
1703 MP_LT(newseq, MP_SEQ(nextf)))) {
1704 newfrag->next = nextf;
1705 frag->next = nextf = newfrag;
1706 newfrag = NULL;
1707 }
1708
1709 if (start != NULL) {
1710 /* check for misplaced start */
1711 if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
1712 printk(KERN_WARNING"isdn_mppp(seq %d): new "
1713 "BEGIN flag with no prior END", thisseq);
1714 stats->seqerrs++;
1715 stats->frame_drops++;
1716 start = isdn_ppp_mp_discard(mp, start,frag);
1717 nextf = frag->next;
1718 }
1719 } else if (MP_LE(thisseq, minseq)) {
1720 if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
1721 start = frag; 1712 start = frag;
1722 else { 1713 else {
1723 if (MP_FLAGS(frag) & MP_END_FRAG) 1714 if (MP_FLAGS(frag) & MP_END_FRAG)
1724 stats->frame_drops++; 1715 stats->frame_drops++;
1725 if( mp->frags == frag ) 1716 __skb_unlink(skb, &mp->frags);
1726 mp->frags = nextf;
1727 isdn_ppp_mp_free_skb(mp, frag); 1717 isdn_ppp_mp_free_skb(mp, frag);
1728 frag = nextf;
1729 continue; 1718 continue;
1730 } 1719 }
1731 } 1720 }
1732 1721
1733 /* if start is non-null and we have end fragment, then 1722 /* if we have end fragment, then we have full reassembly
1734 * we have full reassembly sequence -- reassemble 1723 * sequence -- reassemble and process packet now
1735 * and process packet now
1736 */ 1724 */
1737 if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) { 1725 if (MP_FLAGS(frag) & MP_END_FRAG) {
1738 minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK; 1726 minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;
1739 /* Reassemble the packet then dispatch it */ 1727 /* Reassemble the packet then dispatch it */
1740 isdn_ppp_mp_reassembly(net_dev, lp, start, nextf); 1728 isdn_ppp_mp_reassembly(net_dev, lp, start, frag, thisseq);
1741
1742 start = NULL;
1743 frag = NULL;
1744 1729
1745 mp->frags = nextf; 1730 start = NULL;
1746 } 1731 frag = NULL;
1732 }
1747 1733
1748 /* check if need to update start pointer: if we just 1734 /* check if need to update start pointer: if we just
1749 * reassembled the packet and sequence is contiguous 1735 * reassembled the packet and sequence is contiguous
@@ -1754,26 +1740,25 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
1754 * below low watermark and set start to the next frag or 1740 * below low watermark and set start to the next frag or
1755 * clear start ptr. 1741 * clear start ptr.
1756 */ 1742 */
1757 if (nextf != NULL && 1743 if (nextf != (struct sk_buff *)&mp->frags &&
1758 ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) { 1744 ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
1759 /* if we just reassembled and the next one is here, 1745 /* if we just reassembled and the next one is here,
1760 * then start another reassembly. */ 1746 * then start another reassembly.
1761 1747 */
1762 if (frag == NULL) { 1748 if (frag == NULL) {
1763 if (MP_FLAGS(nextf) & MP_BEGIN_FRAG) 1749 if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
1764 start = nextf; 1750 start = nextf;
1765 else 1751 else {
1766 { 1752 printk(KERN_WARNING"isdn_mppp(seq %d):"
1767 printk(KERN_WARNING"isdn_mppp(seq %d):" 1753 " END flag with no following "
1768 " END flag with no following " 1754 "BEGIN", thisseq);
1769 "BEGIN", thisseq);
1770 stats->seqerrs++; 1755 stats->seqerrs++;
1771 } 1756 }
1772 } 1757 }
1773 1758 } else {
1774 } else { 1759 if (nextf != (struct sk_buff *)&mp->frags &&
1775 if ( nextf != NULL && frag != NULL && 1760 frag != NULL &&
1776 MP_LT(thisseq, minseq)) { 1761 MP_LT(thisseq, minseq)) {
1777 /* we've got a break in the sequence 1762 /* we've got a break in the sequence
1778 * and we not at the end yet 1763 * and we not at the end yet
1779 * and we did not just reassembled 1764 * and we did not just reassembled
@@ -1782,41 +1767,39 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
1782 * discard all the frames below low watermark 1767 * discard all the frames below low watermark
1783 * and start over */ 1768 * and start over */
1784 stats->frame_drops++; 1769 stats->frame_drops++;
1785 mp->frags = isdn_ppp_mp_discard(mp,start,nextf); 1770 isdn_ppp_mp_discard(mp, start, nextf);
1786 } 1771 }
1787 /* break in the sequence, no reassembly */ 1772 /* break in the sequence, no reassembly */
1788 start = NULL; 1773 start = NULL;
1789 } 1774 }
1790 1775 if (!start)
1791 frag = nextf; 1776 break;
1792 } /* while -- main loop */ 1777 }
1793 1778
1794 if (mp->frags == NULL) 1779check_overflow:
1795 mp->frags = frag;
1796
1797 /* rather straighforward way to deal with (not very) possible 1780 /* rather straighforward way to deal with (not very) possible
1798 * queue overflow */ 1781 * queue overflow
1782 */
1799 if (mp->frames > MP_MAX_QUEUE_LEN) { 1783 if (mp->frames > MP_MAX_QUEUE_LEN) {
1800 stats->overflows++; 1784 stats->overflows++;
1801 while (mp->frames > MP_MAX_QUEUE_LEN) { 1785 skb_queue_walk_safe(&mp->frags, frag, nextf) {
1802 frag = mp->frags->next; 1786 if (mp->frames <= MP_MAX_QUEUE_LEN)
1803 isdn_ppp_mp_free_skb(mp, mp->frags); 1787 break;
1804 mp->frags = frag; 1788 __skb_unlink(frag, &mp->frags);
1789 isdn_ppp_mp_free_skb(mp, frag);
1805 } 1790 }
1806 } 1791 }
1807 spin_unlock_irqrestore(&mp->lock, flags); 1792 spin_unlock_irqrestore(&mp->lock, flags);
1808} 1793}
1809 1794
1810static void isdn_ppp_mp_cleanup( isdn_net_local * lp ) 1795static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
1811{ 1796{
1812 struct sk_buff * frag = lp->netdev->pb->frags; 1797 struct sk_buff *skb, *tmp;
1813 struct sk_buff * nextfrag; 1798
1814 while( frag ) { 1799 skb_queue_walk_safe(&lp->netdev->pb->frags, skb, tmp) {
1815 nextfrag = frag->next; 1800 __skb_unlink(skb, &lp->netdev->pb->frags);
1816 isdn_ppp_mp_free_skb(lp->netdev->pb, frag); 1801 isdn_ppp_mp_free_skb(lp->netdev->pb, skb);
1817 frag = nextfrag; 1802 }
1818 }
1819 lp->netdev->pb->frags = NULL;
1820} 1803}
1821 1804
1822static u32 isdn_ppp_mp_get_seq( int short_seq, 1805static u32 isdn_ppp_mp_get_seq( int short_seq,
@@ -1853,72 +1836,115 @@ static u32 isdn_ppp_mp_get_seq( int short_seq,
1853 return seq; 1836 return seq;
1854} 1837}
1855 1838
1856struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, 1839static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from,
1857 struct sk_buff * from, struct sk_buff * to ) 1840 struct sk_buff *to)
1858{ 1841{
1859 if( from ) 1842 if (from) {
1860 while (from != to) { 1843 struct sk_buff *skb, *tmp;
1861 struct sk_buff * next = from->next; 1844 int freeing = 0;
1862 isdn_ppp_mp_free_skb(mp, from); 1845
1863 from = next; 1846 skb_queue_walk_safe(&mp->frags, skb, tmp) {
1847 if (skb == to)
1848 break;
1849 if (skb == from)
1850 freeing = 1;
1851 if (!freeing)
1852 continue;
1853 __skb_unlink(skb, &mp->frags);
1854 isdn_ppp_mp_free_skb(mp, skb);
1864 } 1855 }
1865 return from; 1856 }
1866} 1857}
1867 1858
1868void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, 1859static unsigned int calc_tot_len(struct sk_buff_head *queue,
1869 struct sk_buff * from, struct sk_buff * to ) 1860 struct sk_buff *from, struct sk_buff *to)
1870{ 1861{
1871 ippp_bundle * mp = net_dev->pb; 1862 unsigned int tot_len = 0;
1872 int proto; 1863 struct sk_buff *skb;
1873 struct sk_buff * skb; 1864 int found_start = 0;
1865
1866 skb_queue_walk(queue, skb) {
1867 if (skb == from)
1868 found_start = 1;
1869 if (!found_start)
1870 continue;
1871 tot_len += skb->len - MP_HEADER_LEN;
1872 if (skb == to)
1873 break;
1874 }
1875 return tot_len;
1876}
1877
1878/* Reassemble packet using fragments in the reassembly queue from
1879 * 'from' until 'to', inclusive.
1880 */
1881static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
1882 struct sk_buff *from, struct sk_buff *to,
1883 u32 lastseq)
1884{
1885 ippp_bundle *mp = net_dev->pb;
1874 unsigned int tot_len; 1886 unsigned int tot_len;
1887 struct sk_buff *skb;
1888 int proto;
1875 1889
1876 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { 1890 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
1877 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", 1891 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
1878 __func__, lp->ppp_slot); 1892 __func__, lp->ppp_slot);
1879 return; 1893 return;
1880 } 1894 }
1881 if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) { 1895
1882 if( ippp_table[lp->ppp_slot]->debug & 0x40 ) 1896 tot_len = calc_tot_len(&mp->frags, from, to);
1897
1898 if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {
1899 if (ippp_table[lp->ppp_slot]->debug & 0x40)
1883 printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, " 1900 printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
1884 "len %d\n", MP_SEQ(from), from->len ); 1901 "len %d\n", MP_SEQ(from), from->len);
1885 skb = from; 1902 skb = from;
1886 skb_pull(skb, MP_HEADER_LEN); 1903 skb_pull(skb, MP_HEADER_LEN);
1904 __skb_unlink(skb, &mp->frags);
1887 mp->frames--; 1905 mp->frames--;
1888 } else { 1906 } else {
1889 struct sk_buff * frag; 1907 struct sk_buff *walk, *tmp;
1890 int n; 1908 int found_start = 0;
1891 1909
1892 for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++) 1910 if (ippp_table[lp->ppp_slot]->debug & 0x40)
1893 tot_len += frag->len - MP_HEADER_LEN;
1894
1895 if( ippp_table[lp->ppp_slot]->debug & 0x40 )
1896 printk(KERN_DEBUG"isdn_mppp: reassembling frames %d " 1911 printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
1897 "to %d, len %d\n", MP_SEQ(from), 1912 "to %d, len %d\n", MP_SEQ(from), lastseq,
1898 (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len ); 1913 tot_len);
1899 if( (skb = dev_alloc_skb(tot_len)) == NULL ) { 1914
1915 skb = dev_alloc_skb(tot_len);
1916 if (!skb)
1900 printk(KERN_ERR "isdn_mppp: cannot allocate sk buff " 1917 printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
1901 "of size %d\n", tot_len); 1918 "of size %d\n", tot_len);
1902 isdn_ppp_mp_discard(mp, from, to); 1919
1903 return; 1920 found_start = 0;
1904 } 1921 skb_queue_walk_safe(&mp->frags, walk, tmp) {
1922 if (walk == from)
1923 found_start = 1;
1924 if (!found_start)
1925 continue;
1905 1926
1906 while( from != to ) { 1927 if (skb) {
1907 unsigned int len = from->len - MP_HEADER_LEN; 1928 unsigned int len = walk->len - MP_HEADER_LEN;
1929 skb_copy_from_linear_data_offset(walk, MP_HEADER_LEN,
1930 skb_put(skb, len),
1931 len);
1932 }
1933 __skb_unlink(walk, &mp->frags);
1934 isdn_ppp_mp_free_skb(mp, walk);
1908 1935
1909 skb_copy_from_linear_data_offset(from, MP_HEADER_LEN, 1936 if (walk == to)
1910 skb_put(skb,len), 1937 break;
1911 len);
1912 frag = from->next;
1913 isdn_ppp_mp_free_skb(mp, from);
1914 from = frag;
1915 } 1938 }
1916 } 1939 }
1940 if (!skb)
1941 return;
1942
1917 proto = isdn_ppp_strip_proto(skb); 1943 proto = isdn_ppp_strip_proto(skb);
1918 isdn_ppp_push_higher(net_dev, lp, skb, proto); 1944 isdn_ppp_push_higher(net_dev, lp, skb, proto);
1919} 1945}
1920 1946
1921static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb) 1947static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)
1922{ 1948{
1923 dev_kfree_skb(skb); 1949 dev_kfree_skb(skb);
1924 mp->frames--; 1950 mp->frames--;
diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h
index 8687a7dc0632..4c218ee7587a 100644
--- a/include/linux/isdn_ppp.h
+++ b/include/linux/isdn_ppp.h
@@ -157,7 +157,7 @@ typedef struct {
157 157
158typedef struct { 158typedef struct {
159 int mp_mrru; /* unused */ 159 int mp_mrru; /* unused */
160 struct sk_buff * frags; /* fragments sl list -- use skb->next */ 160 struct sk_buff_head frags; /* fragments sl list */
161 long frames; /* number of frames in the frame list */ 161 long frames; /* number of frames in the frame list */
162 unsigned int seq; /* last processed packet seq #: any packets 162 unsigned int seq; /* last processed packet seq #: any packets
163 * with smaller seq # will be dropped 163 * with smaller seq # will be dropped