|
@@ -156,6 +156,12 @@ MODULE_PARM_DESC(workaround_interval,
|
|
|
#define RNDIS_STATUS_ADAPTER_NOT_OPEN cpu_to_le32(0xc0010012)
|
|
|
|
|
|
|
|
|
+/* Known device types */
|
|
|
+#define RNDIS_UNKNOWN 0
|
|
|
+#define RNDIS_BCM4320A 1
|
|
|
+#define RNDIS_BCM4320B 2
|
|
|
+
|
|
|
+
|
|
|
/* NDIS data structures. Taken from wpa_supplicant driver_ndis.c
|
|
|
* slightly modified for datatype endianess, etc
|
|
|
*/
|
|
@@ -478,6 +484,7 @@ struct rndis_wlan_private {
|
|
|
struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)];
|
|
|
u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)];
|
|
|
|
|
|
+ int device_type;
|
|
|
int caps;
|
|
|
int multicast_size;
|
|
|
|
|
@@ -997,6 +1004,16 @@ static void restore_keys(struct usbnet *usbdev);
|
|
|
static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid,
|
|
|
bool *matched);
|
|
|
|
|
|
+static int rndis_start_bssid_list_scan(struct usbnet *usbdev)
|
|
|
+{
|
|
|
+ __le32 tmp;
|
|
|
+
|
|
|
+ /* Note: OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */
|
|
|
+ tmp = cpu_to_le32(1);
|
|
|
+ return rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
|
|
|
+ sizeof(tmp));
|
|
|
+}
|
|
|
+
|
|
|
static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
|
|
|
{
|
|
|
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
|
|
@@ -1905,7 +1922,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
|
|
|
struct usbnet *usbdev = netdev_priv(dev);
|
|
|
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
|
|
|
int ret;
|
|
|
- __le32 tmp;
|
|
|
+ int delay = SCAN_DELAY_JIFFIES;
|
|
|
|
|
|
netdev_dbg(usbdev->net, "cfg80211.scan\n");
|
|
|
|
|
@@ -1922,13 +1939,13 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
|
|
|
|
|
|
priv->scan_request = request;
|
|
|
|
|
|
- tmp = cpu_to_le32(1);
|
|
|
- ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
|
|
|
- sizeof(tmp));
|
|
|
+ ret = rndis_start_bssid_list_scan(usbdev);
|
|
|
if (ret == 0) {
|
|
|
+ if (priv->device_type == RNDIS_BCM4320A)
|
|
|
+ delay = HZ;
|
|
|
+
|
|
|
/* Wait before retrieving scan results from device */
|
|
|
- queue_delayed_work(priv->workqueue, &priv->scan_work,
|
|
|
- SCAN_DELAY_JIFFIES);
|
|
|
+ queue_delayed_work(priv->workqueue, &priv->scan_work, delay);
|
|
|
}
|
|
|
|
|
|
return ret;
|
|
@@ -3046,8 +3063,21 @@ static void rndis_device_poller(struct work_struct *work)
|
|
|
* also polls device with rndis_command() and catches for media link
|
|
|
* indications.
|
|
|
*/
|
|
|
- if (!is_associated(usbdev))
|
|
|
+ if (!is_associated(usbdev)) {
|
|
|
+ /* Workaround bad scanning in BCM4320a devices with active
|
|
|
+ * background scanning when not associated.
|
|
|
+ */
|
|
|
+ if (priv->device_type == RNDIS_BCM4320A && priv->radio_on &&
|
|
|
+ !priv->scan_request) {
|
|
|
+ /* Get previous scan results */
|
|
|
+ rndis_check_bssid_list(usbdev, NULL, NULL);
|
|
|
+
|
|
|
+ /* Initiate new scan */
|
|
|
+ rndis_start_bssid_list_scan(usbdev);
|
|
|
+ }
|
|
|
+
|
|
|
goto end;
|
|
|
+ }
|
|
|
|
|
|
len = sizeof(rssi);
|
|
|
ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len);
|
|
@@ -3104,10 +3134,12 @@ end:
|
|
|
/*
|
|
|
* driver/device initialization
|
|
|
*/
|
|
|
-static void rndis_copy_module_params(struct usbnet *usbdev)
|
|
|
+static void rndis_copy_module_params(struct usbnet *usbdev, int device_type)
|
|
|
{
|
|
|
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
|
|
|
|
|
|
+ priv->device_type = device_type;
|
|
|
+
|
|
|
priv->param_country[0] = modparam_country[0];
|
|
|
priv->param_country[1] = modparam_country[1];
|
|
|
priv->param_country[2] = 0;
|
|
@@ -3150,12 +3182,25 @@ static void rndis_copy_module_params(struct usbnet *usbdev)
|
|
|
priv->param_workaround_interval = modparam_workaround_interval;
|
|
|
}
|
|
|
|
|
|
+static int unknown_early_init(struct usbnet *usbdev)
|
|
|
+{
|
|
|
+ /* copy module parameters for unknown so that iwconfig reports txpower
|
|
|
+ * and workaround parameter is copied to private structure correctly.
|
|
|
+ */
|
|
|
+ rndis_copy_module_params(usbdev, RNDIS_UNKNOWN);
|
|
|
+
|
|
|
+ /* This is unknown device, so do not try set configuration parameters.
|
|
|
+ */
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int bcm4320a_early_init(struct usbnet *usbdev)
|
|
|
{
|
|
|
/* copy module parameters for bcm4320a so that iwconfig reports txpower
|
|
|
* and workaround parameter is copied to private structure correctly.
|
|
|
*/
|
|
|
- rndis_copy_module_params(usbdev);
|
|
|
+ rndis_copy_module_params(usbdev, RNDIS_BCM4320A);
|
|
|
|
|
|
/* bcm4320a doesn't handle configuration parameters well. Try
|
|
|
* set any and you get partially zeroed mac and broken device.
|
|
@@ -3169,7 +3214,7 @@ static int bcm4320b_early_init(struct usbnet *usbdev)
|
|
|
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
|
|
|
char buf[8];
|
|
|
|
|
|
- rndis_copy_module_params(usbdev);
|
|
|
+ rndis_copy_module_params(usbdev, RNDIS_BCM4320B);
|
|
|
|
|
|
/* Early initialization settings, setting these won't have effect
|
|
|
* if called after generic_rndis_bind().
|
|
@@ -3432,7 +3477,7 @@ static const struct driver_info rndis_wlan_info = {
|
|
|
.tx_fixup = rndis_tx_fixup,
|
|
|
.reset = rndis_wlan_reset,
|
|
|
.stop = rndis_wlan_stop,
|
|
|
- .early_init = bcm4320a_early_init,
|
|
|
+ .early_init = unknown_early_init,
|
|
|
.indication = rndis_wlan_indication,
|
|
|
};
|
|
|
|