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