Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

isdn: isdn_ppp: Use SKB list facilities instead of home-grown implementation.

Signed-off-by: David S. Miller <davem@davemloft.net>

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