Commit 49fee692 authored by Daniel Drake's avatar Daniel Drake Committed by John W. Linville

libertas: link mesh device to wiphy

The mesh device is now exposed as an interface of the wiphy.
This exposes the mesh device to the cfg80211 interface, allowing
mesh channel selection to be reimplemented, and available to
NetworkManager as it was before.

Some header tweaking was needed in order to implement lbs_mesh_activated().
Signed-off-by: default avatarDaniel Drake <dsd@laptop.org>
Acked-by: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 04b0c5c6
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "decl.h" #include "decl.h"
#include "cfg.h" #include "cfg.h"
#include "cmd.h" #include "cmd.h"
#include "mesh.h"
#define CHAN2G(_channel, _freq, _flags) { \ #define CHAN2G(_channel, _freq, _flags) { \
...@@ -442,13 +443,16 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy, ...@@ -442,13 +443,16 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
struct lbs_private *priv = wiphy_priv(wiphy); struct lbs_private *priv = wiphy_priv(wiphy);
int ret = -ENOTSUPP; int ret = -ENOTSUPP;
lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
channel->center_freq, channel_type); netdev_name(netdev), channel->center_freq, channel_type);
if (channel_type != NL80211_CHAN_NO_HT) if (channel_type != NL80211_CHAN_NO_HT)
goto out; goto out;
ret = lbs_set_channel(priv, channel->hw_value); if (netdev == priv->mesh_dev)
ret = lbs_mesh_set_channel(priv, channel->hw_value);
else
ret = lbs_set_channel(priv, channel->hw_value);
out: out:
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
...@@ -1292,6 +1296,9 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, ...@@ -1292,6 +1296,9 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
int ret = 0; int ret = 0;
u8 preamble = RADIO_PREAMBLE_SHORT; u8 preamble = RADIO_PREAMBLE_SHORT;
if (dev == priv->mesh_dev)
return -EOPNOTSUPP;
lbs_deb_enter(LBS_DEB_CFG80211); lbs_deb_enter(LBS_DEB_CFG80211);
if (!sme->bssid) { if (!sme->bssid) {
...@@ -1408,6 +1415,9 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, ...@@ -1408,6 +1415,9 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
struct lbs_private *priv = wiphy_priv(wiphy); struct lbs_private *priv = wiphy_priv(wiphy);
struct cmd_ds_802_11_deauthenticate cmd; struct cmd_ds_802_11_deauthenticate cmd;
if (dev == priv->mesh_dev)
return -EOPNOTSUPP;
lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code); lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
/* store for lbs_cfg_ret_disconnect() */ /* store for lbs_cfg_ret_disconnect() */
...@@ -1439,6 +1449,9 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy, ...@@ -1439,6 +1449,9 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,
{ {
struct lbs_private *priv = wiphy_priv(wiphy); struct lbs_private *priv = wiphy_priv(wiphy);
if (netdev == priv->mesh_dev)
return -EOPNOTSUPP;
lbs_deb_enter(LBS_DEB_CFG80211); lbs_deb_enter(LBS_DEB_CFG80211);
if (key_index != priv->wep_tx_key) { if (key_index != priv->wep_tx_key) {
...@@ -1460,6 +1473,9 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, ...@@ -1460,6 +1473,9 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
u16 key_type; u16 key_type;
int ret = 0; int ret = 0;
if (netdev == priv->mesh_dev)
return -EOPNOTSUPP;
lbs_deb_enter(LBS_DEB_CFG80211); lbs_deb_enter(LBS_DEB_CFG80211);
lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n", lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
...@@ -1603,6 +1619,9 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev, ...@@ -1603,6 +1619,9 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
s8 signal, noise; s8 signal, noise;
int ret; int ret;
if (dev == priv->mesh_dev)
return -EOPNOTSUPP;
if (idx != 0) if (idx != 0)
ret = -ENOENT; ret = -ENOENT;
...@@ -1636,6 +1655,9 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, ...@@ -1636,6 +1655,9 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
struct lbs_private *priv = wiphy_priv(wiphy); struct lbs_private *priv = wiphy_priv(wiphy);
int ret = 0; int ret = 0;
if (dev == priv->mesh_dev)
return -EOPNOTSUPP;
lbs_deb_enter(LBS_DEB_CFG80211); lbs_deb_enter(LBS_DEB_CFG80211);
switch (type) { switch (type) {
...@@ -1959,6 +1981,9 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, ...@@ -1959,6 +1981,9 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_bss *bss; struct cfg80211_bss *bss;
DECLARE_SSID_BUF(ssid_buf); DECLARE_SSID_BUF(ssid_buf);
if (dev == priv->mesh_dev)
return -EOPNOTSUPP;
lbs_deb_enter(LBS_DEB_CFG80211); lbs_deb_enter(LBS_DEB_CFG80211);
if (!params->channel) { if (!params->channel) {
...@@ -1995,6 +2020,9 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) ...@@ -1995,6 +2020,9 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
struct cmd_ds_802_11_ad_hoc_stop cmd; struct cmd_ds_802_11_ad_hoc_stop cmd;
int ret = 0; int ret = 0;
if (dev == priv->mesh_dev)
return -EOPNOTSUPP;
lbs_deb_enter(LBS_DEB_CFG80211); lbs_deb_enter(LBS_DEB_CFG80211);
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
...@@ -2117,6 +2145,8 @@ int lbs_cfg_register(struct lbs_private *priv) ...@@ -2117,6 +2145,8 @@ int lbs_cfg_register(struct lbs_private *priv)
BIT(NL80211_IFTYPE_ADHOC); BIT(NL80211_IFTYPE_ADHOC);
if (lbs_rtap_supported(priv)) if (lbs_rtap_supported(priv))
wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
if (lbs_mesh_activated(priv))
wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT);
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz; wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#ifndef _LBS_DEV_H_ #ifndef _LBS_DEV_H_
#define _LBS_DEV_H_ #define _LBS_DEV_H_
#include "mesh.h"
#include "defs.h" #include "defs.h"
#include "host.h" #include "host.h"
...@@ -22,6 +21,17 @@ struct sleep_params { ...@@ -22,6 +21,17 @@ struct sleep_params {
uint16_t sp_reserved; uint16_t sp_reserved;
}; };
/* Mesh statistics */
struct lbs_mesh_stats {
u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
u32 fwd_drop_ttl; /* Fwd: TTL zero */
u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
u32 fwd_drop_noroute; /* Fwd: No route to Destination */
u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
u32 drop_blind; /* Rx: Dropped by blinding table */
u32 tx_failed_cnt; /* Tx: Failed transmissions */
};
/* Private structure for the MV device */ /* Private structure for the MV device */
struct lbs_private { struct lbs_private {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "decl.h" #include "decl.h"
#include "cmd.h" #include "cmd.h"
#include "mesh.h"
static void lbs_ethtool_get_drvinfo(struct net_device *dev, static void lbs_ethtool_get_drvinfo(struct net_device *dev,
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "cfg.h" #include "cfg.h"
#include "debugfs.h" #include "debugfs.h"
#include "cmd.h" #include "cmd.h"
#include "mesh.h"
#define DRIVER_RELEASE_VERSION "323.p0" #define DRIVER_RELEASE_VERSION "323.p0"
const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
...@@ -950,17 +951,20 @@ int lbs_start_card(struct lbs_private *priv) ...@@ -950,17 +951,20 @@ int lbs_start_card(struct lbs_private *priv)
if (ret) if (ret)
goto done; goto done;
if (!lbs_disablemesh)
lbs_init_mesh(priv);
else
pr_info("%s: mesh disabled\n", dev->name);
if (lbs_cfg_register(priv)) { if (lbs_cfg_register(priv)) {
pr_err("cannot register device\n"); pr_err("cannot register device\n");
goto done; goto done;
} }
lbs_update_channel(priv); if (lbs_mesh_activated(priv))
lbs_start_mesh(priv);
if (!lbs_disablemesh) lbs_update_channel(priv);
lbs_init_mesh(priv);
else
pr_info("%s: mesh disabled\n", dev->name);
lbs_debugfs_init_one(priv, dev); lbs_debugfs_init_one(priv, dev);
......
...@@ -129,6 +129,19 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action, ...@@ -129,6 +129,19 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
} }
int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
{
return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
}
static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
{
struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
if (mesh_wdev->channel)
return mesh_wdev->channel->hw_value;
else
return 1;
}
/*************************************************************************** /***************************************************************************
* Mesh sysfs support * Mesh sysfs support
...@@ -812,7 +825,6 @@ static void lbs_persist_config_remove(struct net_device *dev) ...@@ -812,7 +825,6 @@ static void lbs_persist_config_remove(struct net_device *dev)
*/ */
int lbs_init_mesh(struct lbs_private *priv) int lbs_init_mesh(struct lbs_private *priv)
{ {
struct net_device *dev = priv->dev;
int ret = 0; int ret = 0;
lbs_deb_enter(LBS_DEB_MESH); lbs_deb_enter(LBS_DEB_MESH);
...@@ -837,11 +849,9 @@ int lbs_init_mesh(struct lbs_private *priv) ...@@ -837,11 +849,9 @@ int lbs_init_mesh(struct lbs_private *priv)
useful */ useful */
priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
priv->channel)) {
priv->mesh_tlv = TLV_TYPE_MESH_ID; priv->mesh_tlv = TLV_TYPE_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
priv->channel))
priv->mesh_tlv = 0; priv->mesh_tlv = 0;
} }
} else } else
...@@ -851,23 +861,16 @@ int lbs_init_mesh(struct lbs_private *priv) ...@@ -851,23 +861,16 @@ int lbs_init_mesh(struct lbs_private *priv)
* 0x100+37; Do not invoke command with old TLV. * 0x100+37; Do not invoke command with old TLV.
*/ */
priv->mesh_tlv = TLV_TYPE_MESH_ID; priv->mesh_tlv = TLV_TYPE_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
priv->channel))
priv->mesh_tlv = 0; priv->mesh_tlv = 0;
} }
/* Stop meshing until interface is brought up */ /* Stop meshing until interface is brought up */
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel); lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
if (priv->mesh_tlv) { if (priv->mesh_tlv) {
sprintf(priv->mesh_ssid, "mesh"); sprintf(priv->mesh_ssid, "mesh");
priv->mesh_ssid_len = 4; priv->mesh_ssid_len = 4;
lbs_add_mesh(priv);
if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
netdev_err(dev, "cannot register lbs_mesh attribute\n");
ret = 1; ret = 1;
} }
...@@ -875,6 +878,13 @@ int lbs_init_mesh(struct lbs_private *priv) ...@@ -875,6 +878,13 @@ int lbs_init_mesh(struct lbs_private *priv)
return ret; return ret;
} }
void lbs_start_mesh(struct lbs_private *priv)
{
lbs_add_mesh(priv);
if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
}
int lbs_deinit_mesh(struct lbs_private *priv) int lbs_deinit_mesh(struct lbs_private *priv)
{ {
...@@ -904,7 +914,8 @@ static int lbs_mesh_stop(struct net_device *dev) ...@@ -904,7 +914,8 @@ static int lbs_mesh_stop(struct net_device *dev)
struct lbs_private *priv = dev->ml_priv; struct lbs_private *priv = dev->ml_priv;
lbs_deb_enter(LBS_DEB_MESH); lbs_deb_enter(LBS_DEB_MESH);
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel); lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
lbs_mesh_get_channel(priv));
spin_lock_irq(&priv->driver_lock); spin_lock_irq(&priv->driver_lock);
...@@ -947,7 +958,8 @@ static int lbs_mesh_dev_open(struct net_device *dev) ...@@ -947,7 +958,8 @@ static int lbs_mesh_dev_open(struct net_device *dev)
spin_unlock_irq(&priv->driver_lock); spin_unlock_irq(&priv->driver_lock);
ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel); ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
lbs_mesh_get_channel(priv));
out: out:
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
...@@ -971,18 +983,32 @@ static const struct net_device_ops mesh_netdev_ops = { ...@@ -971,18 +983,32 @@ static const struct net_device_ops mesh_netdev_ops = {
static int lbs_add_mesh(struct lbs_private *priv) static int lbs_add_mesh(struct lbs_private *priv)
{ {
struct net_device *mesh_dev = NULL; struct net_device *mesh_dev = NULL;
struct wireless_dev *mesh_wdev;
int ret = 0; int ret = 0;
lbs_deb_enter(LBS_DEB_MESH); lbs_deb_enter(LBS_DEB_MESH);
/* Allocate a virtual mesh device */ /* Allocate a virtual mesh device */
mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!mesh_wdev) {
lbs_deb_mesh("init mshX wireless device failed\n");
ret = -ENOMEM;
goto done;
}
mesh_dev = alloc_netdev(0, "msh%d", ether_setup); mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
if (!mesh_dev) { if (!mesh_dev) {
lbs_deb_mesh("init mshX device failed\n"); lbs_deb_mesh("init mshX device failed\n");
ret = -ENOMEM; ret = -ENOMEM;
goto done; goto err_free_wdev;
} }
mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
mesh_wdev->wiphy = priv->wdev->wiphy;
mesh_wdev->netdev = mesh_dev;
mesh_dev->ml_priv = priv; mesh_dev->ml_priv = priv;
mesh_dev->ieee80211_ptr = mesh_wdev;
priv->mesh_dev = mesh_dev; priv->mesh_dev = mesh_dev;
mesh_dev->netdev_ops = &mesh_netdev_ops; mesh_dev->netdev_ops = &mesh_netdev_ops;
...@@ -996,7 +1022,7 @@ static int lbs_add_mesh(struct lbs_private *priv) ...@@ -996,7 +1022,7 @@ static int lbs_add_mesh(struct lbs_private *priv)
ret = register_netdev(mesh_dev); ret = register_netdev(mesh_dev);
if (ret) { if (ret) {
pr_err("cannot register mshX virtual interface\n"); pr_err("cannot register mshX virtual interface\n");
goto err_free; goto err_free_netdev;
} }
ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
...@@ -1012,9 +1038,12 @@ static int lbs_add_mesh(struct lbs_private *priv) ...@@ -1012,9 +1038,12 @@ static int lbs_add_mesh(struct lbs_private *priv)
err_unregister: err_unregister:
unregister_netdev(mesh_dev); unregister_netdev(mesh_dev);
err_free: err_free_netdev:
free_netdev(mesh_dev); free_netdev(mesh_dev);
err_free_wdev:
kfree(mesh_wdev);
done: done:
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
return ret; return ret;
...@@ -1035,6 +1064,7 @@ void lbs_remove_mesh(struct lbs_private *priv) ...@@ -1035,6 +1064,7 @@ void lbs_remove_mesh(struct lbs_private *priv)
lbs_persist_config_remove(mesh_dev); lbs_persist_config_remove(mesh_dev);
unregister_netdev(mesh_dev); unregister_netdev(mesh_dev);
priv->mesh_dev = NULL; priv->mesh_dev = NULL;
kfree(mesh_dev->ieee80211_ptr);
free_netdev(mesh_dev); free_netdev(mesh_dev);
lbs_deb_leave(LBS_DEB_MESH); lbs_deb_leave(LBS_DEB_MESH);
} }
......
...@@ -9,30 +9,25 @@ ...@@ -9,30 +9,25 @@
#include <net/lib80211.h> #include <net/lib80211.h>
#include "host.h" #include "host.h"
#include "dev.h"
#ifdef CONFIG_LIBERTAS_MESH #ifdef CONFIG_LIBERTAS_MESH
/* Mesh statistics */
struct lbs_mesh_stats {
u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
u32 fwd_drop_ttl; /* Fwd: TTL zero */
u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
u32 fwd_drop_noroute; /* Fwd: No route to Destination */
u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
u32 drop_blind; /* Rx: Dropped by blinding table */
u32 tx_failed_cnt; /* Tx: Failed transmissions */
};
struct net_device; struct net_device;
struct lbs_private;
int lbs_init_mesh(struct lbs_private *priv); int lbs_init_mesh(struct lbs_private *priv);
void lbs_start_mesh(struct lbs_private *priv);
int lbs_deinit_mesh(struct lbs_private *priv); int lbs_deinit_mesh(struct lbs_private *priv);
void lbs_remove_mesh(struct lbs_private *priv); void lbs_remove_mesh(struct lbs_private *priv);
static inline bool lbs_mesh_activated(struct lbs_private *priv)
{
/* Mesh SSID is only programmed after successful init */
return priv->mesh_ssid_len != 0;
}
int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel);
/* Sending / Receiving */ /* Sending / Receiving */
...@@ -67,11 +62,13 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev, ...@@ -67,11 +62,13 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,
#define lbs_init_mesh(priv) #define lbs_init_mesh(priv)
#define lbs_deinit_mesh(priv) #define lbs_deinit_mesh(priv)
#define lbs_start_mesh(priv)
#define lbs_add_mesh(priv) #define lbs_add_mesh(priv)
#define lbs_remove_mesh(priv) #define lbs_remove_mesh(priv)
#define lbs_mesh_set_dev(priv, dev, rxpd) (dev) #define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
#define lbs_mesh_set_txpd(priv, dev, txpd) #define lbs_mesh_set_txpd(priv, dev, txpd)
#define lbs_mesh_config(priv, enable, chan) #define lbs_mesh_set_channel(priv, channel) (0)
#define lbs_mesh_activated(priv) (false)
#endif #endif
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "radiotap.h" #include "radiotap.h"
#include "decl.h" #include "decl.h"
#include "dev.h" #include "dev.h"
#include "mesh.h"
struct eth803hdr { struct eth803hdr {
u8 dest_addr[6]; u8 dest_addr[6];
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "decl.h" #include "decl.h"
#include "defs.h" #include "defs.h"
#include "dev.h" #include "dev.h"
#include "mesh.h"
/** /**
* convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment