diff options
author | Amitkumar Karwar <akarwar@marvell.com> | 2014-02-07 19:23:35 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-02-12 15:36:12 -0500 |
commit | 3b4d5c644204476265083a554dad56868b93b9dd (patch) | |
tree | abce22bed52cd794d1b492f0cb96fee23357ded8 /drivers/net/wireless/mwifiex/scan.c | |
parent | b8b3ecec91f106e2f26ac2e24dcda21f63336286 (diff) |
mwifiex: separate out response buffer parsing code
This new function will be useful later for extended scan
feature.
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwifiex/scan.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/scan.c | 309 |
1 files changed, 163 insertions, 146 deletions
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index b0be830aa342..28f0a38ff2d9 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c | |||
@@ -1576,6 +1576,156 @@ done: | |||
1576 | return 0; | 1576 | return 0; |
1577 | } | 1577 | } |
1578 | 1578 | ||
1579 | static int | ||
1580 | mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info, | ||
1581 | u32 *bytes_left, u64 fw_tsf, u8 *radio_type, | ||
1582 | bool ext_scan) | ||
1583 | { | ||
1584 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1585 | struct mwifiex_chan_freq_power *cfp; | ||
1586 | struct cfg80211_bss *bss; | ||
1587 | u8 bssid[ETH_ALEN]; | ||
1588 | s32 rssi; | ||
1589 | const u8 *ie_buf; | ||
1590 | size_t ie_len; | ||
1591 | u16 channel = 0; | ||
1592 | u16 beacon_size = 0; | ||
1593 | u32 curr_bcn_bytes; | ||
1594 | u32 freq; | ||
1595 | u16 beacon_period; | ||
1596 | u16 cap_info_bitmap; | ||
1597 | u8 *current_ptr; | ||
1598 | u64 timestamp; | ||
1599 | struct mwifiex_fixed_bcn_param *bcn_param; | ||
1600 | struct mwifiex_bss_priv *bss_priv; | ||
1601 | |||
1602 | if (*bytes_left >= sizeof(beacon_size)) { | ||
1603 | /* Extract & convert beacon size from command buffer */ | ||
1604 | memcpy(&beacon_size, *bss_info, sizeof(beacon_size)); | ||
1605 | *bytes_left -= sizeof(beacon_size); | ||
1606 | *bss_info += sizeof(beacon_size); | ||
1607 | } | ||
1608 | |||
1609 | if (!beacon_size || beacon_size > *bytes_left) { | ||
1610 | *bss_info += *bytes_left; | ||
1611 | *bytes_left = 0; | ||
1612 | return -EFAULT; | ||
1613 | } | ||
1614 | |||
1615 | /* Initialize the current working beacon pointer for this BSS | ||
1616 | * iteration | ||
1617 | */ | ||
1618 | current_ptr = *bss_info; | ||
1619 | |||
1620 | /* Advance the return beacon pointer past the current beacon */ | ||
1621 | *bss_info += beacon_size; | ||
1622 | *bytes_left -= beacon_size; | ||
1623 | |||
1624 | curr_bcn_bytes = beacon_size; | ||
1625 | |||
1626 | /* First 5 fields are bssid, RSSI(for legacy scan only), | ||
1627 | * time stamp, beacon interval, and capability information | ||
1628 | */ | ||
1629 | if (curr_bcn_bytes < ETH_ALEN + sizeof(u8) + | ||
1630 | sizeof(struct mwifiex_fixed_bcn_param)) { | ||
1631 | dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); | ||
1632 | return -EFAULT; | ||
1633 | } | ||
1634 | |||
1635 | memcpy(bssid, current_ptr, ETH_ALEN); | ||
1636 | current_ptr += ETH_ALEN; | ||
1637 | curr_bcn_bytes -= ETH_ALEN; | ||
1638 | |||
1639 | if (!ext_scan) { | ||
1640 | rssi = (s32) *(u8 *)current_ptr; | ||
1641 | rssi = (-rssi) * 100; /* Convert dBm to mBm */ | ||
1642 | current_ptr += sizeof(u8); | ||
1643 | curr_bcn_bytes -= sizeof(u8); | ||
1644 | dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%d\n", rssi); | ||
1645 | } | ||
1646 | |||
1647 | bcn_param = (struct mwifiex_fixed_bcn_param *)current_ptr; | ||
1648 | current_ptr += sizeof(*bcn_param); | ||
1649 | curr_bcn_bytes -= sizeof(*bcn_param); | ||
1650 | |||
1651 | timestamp = le64_to_cpu(bcn_param->timestamp); | ||
1652 | beacon_period = le16_to_cpu(bcn_param->beacon_period); | ||
1653 | |||
1654 | cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap); | ||
1655 | dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", | ||
1656 | cap_info_bitmap); | ||
1657 | |||
1658 | /* Rest of the current buffer are IE's */ | ||
1659 | ie_buf = current_ptr; | ||
1660 | ie_len = curr_bcn_bytes; | ||
1661 | dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n", | ||
1662 | curr_bcn_bytes); | ||
1663 | |||
1664 | while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) { | ||
1665 | u8 element_id, element_len; | ||
1666 | |||
1667 | element_id = *current_ptr; | ||
1668 | element_len = *(current_ptr + 1); | ||
1669 | if (curr_bcn_bytes < element_len + | ||
1670 | sizeof(struct ieee_types_header)) { | ||
1671 | dev_err(adapter->dev, | ||
1672 | "%s: bytes left < IE length\n", __func__); | ||
1673 | return -EFAULT; | ||
1674 | } | ||
1675 | if (element_id == WLAN_EID_DS_PARAMS) { | ||
1676 | channel = *(current_ptr + | ||
1677 | sizeof(struct ieee_types_header)); | ||
1678 | break; | ||
1679 | } | ||
1680 | |||
1681 | current_ptr += element_len + sizeof(struct ieee_types_header); | ||
1682 | curr_bcn_bytes -= element_len + | ||
1683 | sizeof(struct ieee_types_header); | ||
1684 | } | ||
1685 | |||
1686 | if (channel) { | ||
1687 | struct ieee80211_channel *chan; | ||
1688 | u8 band; | ||
1689 | |||
1690 | /* Skip entry if on csa closed channel */ | ||
1691 | if (channel == priv->csa_chan) { | ||
1692 | dev_dbg(adapter->dev, | ||
1693 | "Dropping entry on csa closed channel\n"); | ||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1697 | band = BAND_G; | ||
1698 | if (radio_type) | ||
1699 | band = mwifiex_radio_type_to_band(*radio_type & | ||
1700 | (BIT(0) | BIT(1))); | ||
1701 | |||
1702 | cfp = mwifiex_get_cfp(priv, band, channel, 0); | ||
1703 | |||
1704 | freq = cfp ? cfp->freq : 0; | ||
1705 | |||
1706 | chan = ieee80211_get_channel(priv->wdev->wiphy, freq); | ||
1707 | |||
1708 | if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { | ||
1709 | bss = cfg80211_inform_bss(priv->wdev->wiphy, | ||
1710 | chan, bssid, timestamp, | ||
1711 | cap_info_bitmap, beacon_period, | ||
1712 | ie_buf, ie_len, rssi, GFP_KERNEL); | ||
1713 | bss_priv = (struct mwifiex_bss_priv *)bss->priv; | ||
1714 | bss_priv->band = band; | ||
1715 | bss_priv->fw_tsf = fw_tsf; | ||
1716 | if (priv->media_connected && | ||
1717 | !memcmp(bssid, priv->curr_bss_params.bss_descriptor | ||
1718 | .mac_address, ETH_ALEN)) | ||
1719 | mwifiex_update_curr_bss_params(priv, bss); | ||
1720 | cfg80211_put_bss(priv->wdev->wiphy, bss); | ||
1721 | } | ||
1722 | } else { | ||
1723 | dev_dbg(adapter->dev, "missing BSS channel IE\n"); | ||
1724 | } | ||
1725 | |||
1726 | return 0; | ||
1727 | } | ||
1728 | |||
1579 | /* | 1729 | /* |
1580 | * This function handles the command response of scan. | 1730 | * This function handles the command response of scan. |
1581 | * | 1731 | * |
@@ -1609,12 +1759,12 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | |||
1609 | u32 bytes_left; | 1759 | u32 bytes_left; |
1610 | u32 idx; | 1760 | u32 idx; |
1611 | u32 tlv_buf_size; | 1761 | u32 tlv_buf_size; |
1612 | struct mwifiex_chan_freq_power *cfp; | ||
1613 | struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; | 1762 | struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; |
1614 | struct chan_band_param_set *chan_band; | 1763 | struct chan_band_param_set *chan_band; |
1615 | u8 is_bgscan_resp; | 1764 | u8 is_bgscan_resp; |
1616 | unsigned long flags; | 1765 | unsigned long flags; |
1617 | struct cfg80211_bss *bss; | 1766 | __le64 fw_tsf = 0; |
1767 | u8 *radio_type; | ||
1618 | 1768 | ||
1619 | is_bgscan_resp = (le16_to_cpu(resp->command) | 1769 | is_bgscan_resp = (le16_to_cpu(resp->command) |
1620 | == HostCmd_CMD_802_11_BG_SCAN_QUERY); | 1770 | == HostCmd_CMD_802_11_BG_SCAN_QUERY); |
@@ -1676,107 +1826,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | |||
1676 | &chan_band_tlv); | 1826 | &chan_band_tlv); |
1677 | 1827 | ||
1678 | for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { | 1828 | for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { |
1679 | u8 bssid[ETH_ALEN]; | ||
1680 | s32 rssi; | ||
1681 | const u8 *ie_buf; | ||
1682 | size_t ie_len; | ||
1683 | u16 channel = 0; | ||
1684 | __le64 fw_tsf = 0; | ||
1685 | u16 beacon_size = 0; | ||
1686 | u32 curr_bcn_bytes; | ||
1687 | u32 freq; | ||
1688 | u16 beacon_period; | ||
1689 | u16 cap_info_bitmap; | ||
1690 | u8 *current_ptr; | ||
1691 | u64 timestamp; | ||
1692 | struct mwifiex_fixed_bcn_param *bcn_param; | ||
1693 | struct mwifiex_bss_priv *bss_priv; | ||
1694 | |||
1695 | if (bytes_left >= sizeof(beacon_size)) { | ||
1696 | /* Extract & convert beacon size from command buffer */ | ||
1697 | memcpy(&beacon_size, bss_info, sizeof(beacon_size)); | ||
1698 | bytes_left -= sizeof(beacon_size); | ||
1699 | bss_info += sizeof(beacon_size); | ||
1700 | } | ||
1701 | |||
1702 | if (!beacon_size || beacon_size > bytes_left) { | ||
1703 | bss_info += bytes_left; | ||
1704 | bytes_left = 0; | ||
1705 | ret = -1; | ||
1706 | goto check_next_scan; | ||
1707 | } | ||
1708 | |||
1709 | /* Initialize the current working beacon pointer for this BSS | ||
1710 | * iteration */ | ||
1711 | current_ptr = bss_info; | ||
1712 | |||
1713 | /* Advance the return beacon pointer past the current beacon */ | ||
1714 | bss_info += beacon_size; | ||
1715 | bytes_left -= beacon_size; | ||
1716 | |||
1717 | curr_bcn_bytes = beacon_size; | ||
1718 | |||
1719 | /* First 5 fields are bssid, RSSI(for legacy scan only), | ||
1720 | * time stamp, beacon interval, and capability information | ||
1721 | */ | ||
1722 | if (curr_bcn_bytes < ETH_ALEN + sizeof(u8) + | ||
1723 | sizeof(struct mwifiex_fixed_bcn_param)) { | ||
1724 | dev_err(adapter->dev, | ||
1725 | "InterpretIE: not enough bytes left\n"); | ||
1726 | continue; | ||
1727 | } | ||
1728 | |||
1729 | memcpy(bssid, current_ptr, ETH_ALEN); | ||
1730 | current_ptr += ETH_ALEN; | ||
1731 | curr_bcn_bytes -= ETH_ALEN; | ||
1732 | |||
1733 | rssi = (s32) *(u8 *)current_ptr; | ||
1734 | rssi = (-rssi) * 100; /* Convert dBm to mBm */ | ||
1735 | current_ptr += sizeof(u8); | ||
1736 | curr_bcn_bytes -= sizeof(u8); | ||
1737 | dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%d\n", rssi); | ||
1738 | |||
1739 | bcn_param = (struct mwifiex_fixed_bcn_param *)current_ptr; | ||
1740 | current_ptr += sizeof(*bcn_param); | ||
1741 | curr_bcn_bytes -= sizeof(*bcn_param); | ||
1742 | |||
1743 | timestamp = le64_to_cpu(bcn_param->timestamp); | ||
1744 | beacon_period = le16_to_cpu(bcn_param->beacon_period); | ||
1745 | |||
1746 | cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap); | ||
1747 | dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", | ||
1748 | cap_info_bitmap); | ||
1749 | |||
1750 | /* Rest of the current buffer are IE's */ | ||
1751 | ie_buf = current_ptr; | ||
1752 | ie_len = curr_bcn_bytes; | ||
1753 | dev_dbg(adapter->dev, | ||
1754 | "info: InterpretIE: IELength for this AP = %d\n", | ||
1755 | curr_bcn_bytes); | ||
1756 | |||
1757 | while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) { | ||
1758 | u8 element_id, element_len; | ||
1759 | |||
1760 | element_id = *current_ptr; | ||
1761 | element_len = *(current_ptr + 1); | ||
1762 | if (curr_bcn_bytes < element_len + | ||
1763 | sizeof(struct ieee_types_header)) { | ||
1764 | dev_err(priv->adapter->dev, | ||
1765 | "%s: bytes left < IE length\n", | ||
1766 | __func__); | ||
1767 | goto check_next_scan; | ||
1768 | } | ||
1769 | if (element_id == WLAN_EID_DS_PARAMS) { | ||
1770 | channel = *(current_ptr + sizeof(struct ieee_types_header)); | ||
1771 | break; | ||
1772 | } | ||
1773 | |||
1774 | current_ptr += element_len + | ||
1775 | sizeof(struct ieee_types_header); | ||
1776 | curr_bcn_bytes -= element_len + | ||
1777 | sizeof(struct ieee_types_header); | ||
1778 | } | ||
1779 | |||
1780 | /* | 1829 | /* |
1781 | * If the TSF TLV was appended to the scan results, save this | 1830 | * If the TSF TLV was appended to the scan results, save this |
1782 | * entry's TSF value in the fw_tsf field. It is the firmware's | 1831 | * entry's TSF value in the fw_tsf field. It is the firmware's |
@@ -1787,51 +1836,19 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | |||
1787 | memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE], | 1836 | memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE], |
1788 | sizeof(fw_tsf)); | 1837 | sizeof(fw_tsf)); |
1789 | 1838 | ||
1790 | if (channel) { | 1839 | if (chan_band_tlv) { |
1791 | struct ieee80211_channel *chan; | 1840 | chan_band = &chan_band_tlv->chan_band_param[idx]; |
1792 | u8 band; | 1841 | radio_type = &chan_band->radio_type; |
1793 | |||
1794 | /* Skip entry if on csa closed channel */ | ||
1795 | if (channel == priv->csa_chan) { | ||
1796 | dev_dbg(adapter->dev, | ||
1797 | "Dropping entry on csa closed channel\n"); | ||
1798 | continue; | ||
1799 | } | ||
1800 | |||
1801 | band = BAND_G; | ||
1802 | if (chan_band_tlv) { | ||
1803 | chan_band = | ||
1804 | &chan_band_tlv->chan_band_param[idx]; | ||
1805 | band = mwifiex_radio_type_to_band( | ||
1806 | chan_band->radio_type | ||
1807 | & (BIT(0) | BIT(1))); | ||
1808 | } | ||
1809 | |||
1810 | cfp = mwifiex_get_cfp(priv, band, channel, 0); | ||
1811 | |||
1812 | freq = cfp ? cfp->freq : 0; | ||
1813 | |||
1814 | chan = ieee80211_get_channel(priv->wdev->wiphy, freq); | ||
1815 | |||
1816 | if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { | ||
1817 | bss = cfg80211_inform_bss(priv->wdev->wiphy, | ||
1818 | chan, bssid, timestamp, | ||
1819 | cap_info_bitmap, beacon_period, | ||
1820 | ie_buf, ie_len, rssi, GFP_KERNEL); | ||
1821 | bss_priv = (struct mwifiex_bss_priv *)bss->priv; | ||
1822 | bss_priv->band = band; | ||
1823 | bss_priv->fw_tsf = le64_to_cpu(fw_tsf); | ||
1824 | if (priv->media_connected && | ||
1825 | !memcmp(bssid, | ||
1826 | priv->curr_bss_params.bss_descriptor | ||
1827 | .mac_address, ETH_ALEN)) | ||
1828 | mwifiex_update_curr_bss_params(priv, | ||
1829 | bss); | ||
1830 | cfg80211_put_bss(priv->wdev->wiphy, bss); | ||
1831 | } | ||
1832 | } else { | 1842 | } else { |
1833 | dev_dbg(adapter->dev, "missing BSS channel IE\n"); | 1843 | radio_type = NULL; |
1834 | } | 1844 | } |
1845 | |||
1846 | ret = mwifiex_parse_single_response_buf(priv, &bss_info, | ||
1847 | &bytes_left, | ||
1848 | le64_to_cpu(fw_tsf), | ||
1849 | radio_type, false); | ||
1850 | if (ret) | ||
1851 | goto check_next_scan; | ||
1835 | } | 1852 | } |
1836 | 1853 | ||
1837 | check_next_scan: | 1854 | check_next_scan: |