diff options
-rw-r--r-- | drivers/isdn/i4l/isdn_ppp.c | 352 | ||||
-rw-r--r-- | include/linux/isdn_ppp.h | 2 |
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 | ||
1580 | static u32 isdn_ppp_mp_get_seq( int short_seq, | 1582 | static 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 ); |
1582 | static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, | 1584 | static 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); |
1584 | 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, |
1585 | struct sk_buff * from, struct sk_buff * to ); | 1587 | struct sk_buff *from, struct sk_buff *to, |
1586 | static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb ); | 1588 | u32 lastseq); |
1589 | static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb); | ||
1587 | static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ); | 1590 | static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ); |
1588 | 1591 | ||
1589 | static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, | 1592 | static 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) | 1779 | check_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 | ||
1810 | static void isdn_ppp_mp_cleanup( isdn_net_local * lp ) | 1795 | static 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 | ||
1822 | static u32 isdn_ppp_mp_get_seq( int short_seq, | 1805 | static 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 | ||
1856 | struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, | 1839 | static 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 | ||
1868 | void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, | 1859 | static 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 | */ | ||
1881 | static 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 | ||
1921 | static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb) | 1947 | static 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 | ||
158 | typedef struct { | 158 | typedef 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 |