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