X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Frndis_wlan.c;h=2d2890878deae2162abf5dea253821f09f55e461;hb=cc755896a4274f11283bca32d1d658203844057a;hp=351affe793c4958068b99d75d380b71bb5bfd000;hpb=d695df9049199bdeadd81c29104da8e2542062cf;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 351affe..2d28908 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -83,11 +84,11 @@ MODULE_PARM_DESC(roamdelta, "set roaming tendency: 0=aggressive, 1=moderate, " "2=conservative (default: moderate)"); -static int modparam_workaround_interval = 500; +static int modparam_workaround_interval; module_param_named(workaround_interval, modparam_workaround_interval, int, 0444); MODULE_PARM_DESC(workaround_interval, - "set stall workaround interval in msecs (default: 500)"); + "set stall workaround interval in msecs (0=disabled) (default: 0)"); /* various RNDIS OID defs */ @@ -117,6 +118,7 @@ MODULE_PARM_DESC(workaround_interval, #define OID_802_11_ADD_KEY cpu_to_le32(0x0d01011d) #define OID_802_11_REMOVE_KEY cpu_to_le32(0x0d01011e) #define OID_802_11_ASSOCIATION_INFORMATION cpu_to_le32(0x0d01011f) +#define OID_802_11_CAPABILITY cpu_to_le32(0x0d010122) #define OID_802_11_PMKID cpu_to_le32(0x0d010123) #define OID_802_11_NETWORK_TYPES_SUPPORTED cpu_to_le32(0x0d010203) #define OID_802_11_NETWORK_TYPE_IN_USE cpu_to_le32(0x0d010204) @@ -253,8 +255,8 @@ struct ndis_80211_pmkid_cand_list { struct ndis_80211_status_indication { __le32 status_type; union { - enum ndis_80211_media_stream_mode media_stream_mode; - enum ndis_80211_radio_status radio_status; + __le32 media_stream_mode; + __le32 radio_status; struct ndis_80211_auth_request auth_request[0]; struct ndis_80211_pmkid_cand_list cand_list; } u; @@ -358,6 +360,30 @@ struct ndis_80211_assoc_info { __le32 offset_resp_ies; } __attribute__((packed)); +struct ndis_80211_auth_encr_pair { + __le32 auth_mode; + __le32 encr_mode; +} __attribute__((packed)); + +struct ndis_80211_capability { + __le32 length; + __le32 version; + __le32 num_pmkids; + __le32 num_auth_encr_pair; + struct ndis_80211_auth_encr_pair auth_encr_pair[0]; +} __attribute__((packed)); + +struct ndis_80211_bssid_info { + u8 bssid[6]; + u8 pmkid[16]; +}; + +struct ndis_80211_pmkid { + __le32 length; + __le32 bssid_info_count; + struct ndis_80211_bssid_info bssid_info[0]; +}; + /* * private data */ @@ -440,7 +466,7 @@ struct rndis_wlan_private { struct cfg80211_scan_request *scan_request; struct workqueue_struct *workqueue; - struct delayed_work stats_work; + struct delayed_work dev_poller_work; struct delayed_work scan_work; struct work_struct work; struct mutex command_lock; @@ -466,7 +492,7 @@ struct rndis_wlan_private { u32 param_workaround_interval; /* hardware state */ - int radio_on; + bool radio_on; int infra_mode; bool connected; u8 bssid[ETH_ALEN]; @@ -476,13 +502,7 @@ struct rndis_wlan_private { /* encryption stuff */ int encr_tx_key_index; struct rndis_wlan_encr_key encr_keys[4]; - enum nl80211_auth_type wpa_auth_type; int wpa_version; - int wpa_keymgmt; - int wpa_ie_len; - u8 *wpa_ie; - int wpa_cipher_pair; - int wpa_cipher_group; u8 command_buffer[COMMAND_BUFFER_SIZE]; }; @@ -515,7 +535,7 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); -static int rndis_set_channel(struct wiphy *wiphy, +static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type); static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, @@ -534,6 +554,14 @@ static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo); +static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa); + +static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa); + +static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, @@ -550,6 +578,9 @@ static struct cfg80211_ops rndis_config_ops = { .set_default_key = rndis_set_default_key, .get_station = rndis_get_station, .dump_station = rndis_dump_station, + .set_pmksa = rndis_set_pmksa, + .del_pmksa = rndis_del_pmksa, + .flush_pmksa = rndis_flush_pmksa, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -560,7 +591,6 @@ static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) return (struct rndis_wlan_private *)dev->driver_priv; } - static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) { switch (priv->param_power_output) { @@ -576,7 +606,6 @@ static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) } } - static bool is_wpa_key(struct rndis_wlan_private *priv, int idx) { int cipher = priv->encr_keys[idx].cipher; @@ -585,7 +614,6 @@ static bool is_wpa_key(struct rndis_wlan_private *priv, int idx) cipher == WLAN_CIPHER_SUITE_TKIP); } - static int rndis_cipher_to_alg(u32 cipher) { switch (cipher) { @@ -613,7 +641,6 @@ static int rndis_akm_suite_to_key_mgmt(u32 akm_suite) } } - #ifdef DEBUG static const char *oid_to_string(__le32 oid) { @@ -675,7 +702,6 @@ static const char *oid_to_string(__le32 oid) } #endif - /* translate error code */ static int rndis_error_status(__le32 rndis_status) { @@ -699,7 +725,6 @@ static int rndis_error_status(__le32 rndis_status) return ret; } - static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); @@ -710,6 +735,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) struct rndis_query_c *get_c; } u; int ret, buflen; + int resplen, respoffs, copylen; buflen = *len + sizeof(*u.get); if (buflen < CONTROL_BUFFER_SIZE) @@ -734,23 +760,48 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) ret = rndis_command(dev, u.header, buflen); priv->current_command_oid = 0; if (ret < 0) - devdbg(dev, "rndis_query_oid(%s): rndis_command() failed, %d " - "(%08x)", oid_to_string(oid), ret, - le32_to_cpu(u.get_c->status)); + netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n", + __func__, oid_to_string(oid), ret, + le32_to_cpu(u.get_c->status)); if (ret == 0) { - ret = le32_to_cpu(u.get_c->len); - if (ret > *len) - *len = ret; - memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len); - ret = rndis_error_status(u.get_c->status); + resplen = le32_to_cpu(u.get_c->len); + respoffs = le32_to_cpu(u.get_c->offset) + 8; + + if (respoffs > buflen) { + /* Device returned data offset outside buffer, error. */ + netdev_dbg(dev->net, "%s(%s): received invalid " + "data offset: %d > %d\n", __func__, + oid_to_string(oid), respoffs, buflen); + + ret = -EINVAL; + goto exit_unlock; + } + if ((resplen + respoffs) > buflen) { + /* Device would have returned more data if buffer would + * have been big enough. Copy just the bits that we got. + */ + copylen = buflen - respoffs; + } else { + copylen = resplen; + } + + if (copylen > *len) + copylen = *len; + + memcpy(data, u.buf + respoffs, copylen); + + *len = resplen; + + ret = rndis_error_status(u.get_c->status); if (ret < 0) - devdbg(dev, "rndis_query_oid(%s): device returned " - "error, 0x%08x (%d)", oid_to_string(oid), - le32_to_cpu(u.get_c->status), ret); + netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n", + __func__, oid_to_string(oid), + le32_to_cpu(u.get_c->status), ret); } +exit_unlock: mutex_unlock(&priv->command_lock); if (u.buf != priv->command_buffer) @@ -758,7 +809,6 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) return ret; } - static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); @@ -797,17 +847,17 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) ret = rndis_command(dev, u.header, buflen); priv->current_command_oid = 0; if (ret < 0) - devdbg(dev, "rndis_set_oid(%s): rndis_command() failed, %d " - "(%08x)", oid_to_string(oid), ret, - le32_to_cpu(u.set_c->status)); + netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n", + __func__, oid_to_string(oid), ret, + le32_to_cpu(u.set_c->status)); if (ret == 0) { ret = rndis_error_status(u.set_c->status); if (ret < 0) - devdbg(dev, "rndis_set_oid(%s): device returned error, " - "0x%08x (%d)", oid_to_string(oid), - le32_to_cpu(u.set_c->status), ret); + netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n", + __func__, oid_to_string(oid), + le32_to_cpu(u.set_c->status), ret); } mutex_unlock(&priv->command_lock); @@ -817,7 +867,6 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) return ret; } - static int rndis_reset(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -840,7 +889,6 @@ static int rndis_reset(struct usbnet *usbdev) return 0; } - /* * Specs say that we can only set config parameters only soon after device * initialization. @@ -878,11 +926,11 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param, #endif if (value_type == 2) - devdbg(dev, "setting config parameter: %s, value: %s", - param, (u8 *)value); + netdev_dbg(dev->net, "setting config parameter: %s, value: %s\n", + param, (u8 *)value); else - devdbg(dev, "setting config parameter: %s, value: %d", - param, *(u32 *)value); + netdev_dbg(dev->net, "setting config parameter: %s, value: %d\n", + param, *(u32 *)value); infobuf->name_offs = cpu_to_le32(sizeof(*infobuf)); infobuf->name_length = cpu_to_le32(param_len); @@ -905,20 +953,21 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param, } #ifdef DEBUG - devdbg(dev, "info buffer (len: %d):", info_len); + netdev_dbg(dev->net, "info buffer (len: %d)\n", info_len); for (i = 0; i < info_len; i += 12) { u32 *tmp = (u32 *)((u8 *)infobuf + i); - devdbg(dev, "%08X:%08X:%08X", - cpu_to_be32(tmp[0]), - cpu_to_be32(tmp[1]), - cpu_to_be32(tmp[2])); + netdev_dbg(dev->net, "%08X:%08X:%08X\n", + cpu_to_be32(tmp[0]), + cpu_to_be32(tmp[1]), + cpu_to_be32(tmp[2])); } #endif ret = rndis_set_oid(dev, OID_GEN_RNDIS_CONFIG_PARAMETER, infobuf, info_len); if (ret != 0) - devdbg(dev, "setting rndis config parameter failed, %d.", ret); + netdev_dbg(dev->net, "setting rndis config parameter failed, %d\n", + ret); kfree(infobuf); return ret; @@ -927,16 +976,9 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param, static int rndis_set_config_parameter_str(struct usbnet *dev, char *param, char *value) { - return(rndis_set_config_parameter(dev, param, 2, value)); + return rndis_set_config_parameter(dev, param, 2, value); } -/*static int rndis_set_config_parameter_u32(struct usbnet *dev, - char *param, u32 value) -{ - return(rndis_set_config_parameter(dev, param, 0, &value)); -}*/ - - /* * data conversion functions */ @@ -946,7 +988,6 @@ static int level_to_qual(int level) return qual >= 0 ? (qual <= 100 ? qual : 100) : 0; } - /* * common functions */ @@ -961,13 +1002,13 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid)); if (ret < 0) { - devwarn(usbdev, "setting SSID failed (%08X)", ret); + netdev_warn(usbdev->net, "setting SSID failed (%08X)\n", ret); return ret; } if (ret == 0) { memcpy(&priv->essid, ssid, sizeof(priv->essid)); - priv->radio_on = 1; - devdbg(usbdev, "set_essid: radio_on = 1"); + priv->radio_on = true; + netdev_dbg(usbdev->net, "%s(): radio_on = true\n", __func__); } return ret; @@ -979,7 +1020,8 @@ static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN); if (ret < 0) { - devwarn(usbdev, "setting BSSID[%pM] failed (%08X)", bssid, ret); + netdev_warn(usbdev->net, "setting BSSID[%pM] failed (%08X)\n", + bssid, ret); return ret; } @@ -1027,8 +1069,7 @@ static bool is_associated(struct usbnet *usbdev) return (ret == 0 && !is_zero_ether_addr(bssid)); } - -static int disassociate(struct usbnet *usbdev, int reset_ssid) +static int disassociate(struct usbnet *usbdev, bool reset_ssid) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_ssid ssid; @@ -1037,8 +1078,9 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) if (priv->radio_on) { ret = rndis_set_oid(usbdev, OID_802_11_DISASSOCIATE, NULL, 0); if (ret == 0) { - priv->radio_on = 0; - devdbg(usbdev, "disassociate: radio_on = 0"); + priv->radio_on = false; + netdev_dbg(usbdev->net, "%s(): radio_on = false\n", + __func__); if (reset_ssid) msleep(100); @@ -1064,7 +1106,6 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) return ret; } - static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, enum nl80211_auth_type auth_type, int keymgmt) { @@ -1072,8 +1113,8 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, __le32 tmp; int auth_mode, ret; - devdbg(usbdev, "set_auth_mode: wpa_version=0x%x authalg=0x%x " - "keymgmt=0x%x", wpa_version, auth_type, keymgmt); + netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x authalg=0x%x keymgmt=0x%x\n", + __func__, wpa_version, auth_type, keymgmt); if (wpa_version & NL80211_WPA_VERSION_2) { if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) @@ -1091,6 +1132,8 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, auth_mode = NDIS_80211_AUTH_SHARED; else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) auth_mode = NDIS_80211_AUTH_OPEN; + else if (auth_type == NL80211_AUTHTYPE_AUTOMATIC) + auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; else return -ENOTSUPP; @@ -1098,24 +1141,23 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp, sizeof(tmp)); if (ret != 0) { - devwarn(usbdev, "setting auth mode failed (%08X)", ret); + netdev_warn(usbdev->net, "setting auth mode failed (%08X)\n", + ret); return ret; } priv->wpa_version = wpa_version; - priv->wpa_auth_type = auth_type; - priv->wpa_keymgmt = keymgmt; return 0; } - static int set_priv_filter(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; - devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version); + netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x\n", + __func__, priv->wpa_version); if (priv->wpa_version & NL80211_WPA_VERSION_2 || priv->wpa_version & NL80211_WPA_VERSION_1) @@ -1127,15 +1169,13 @@ static int set_priv_filter(struct usbnet *usbdev) sizeof(tmp)); } - static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) { - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int encr_mode, ret; - devdbg(usbdev, "set_encr_mode: cipher_pair=0x%x cipher_group=0x%x", - pairwise, groupwise); + netdev_dbg(usbdev->net, "%s(): cipher_pair=0x%x cipher_group=0x%x\n", + __func__, pairwise, groupwise); if (pairwise & RNDIS_WLAN_ALG_CCMP) encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; @@ -1154,29 +1194,29 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp, sizeof(tmp)); if (ret != 0) { - devwarn(usbdev, "setting encr mode failed (%08X)", ret); + netdev_warn(usbdev->net, "setting encr mode failed (%08X)\n", + ret); return ret; } - priv->wpa_cipher_pair = pairwise; - priv->wpa_cipher_group = groupwise; return 0; } - static int set_infra_mode(struct usbnet *usbdev, int mode) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int ret; - devdbg(usbdev, "set_infra_mode: infra_mode=0x%x", priv->infra_mode); + netdev_dbg(usbdev->net, "%s(): infra_mode=0x%x\n", + __func__, priv->infra_mode); tmp = cpu_to_le32(mode); ret = rndis_set_oid(usbdev, OID_802_11_INFRASTRUCTURE_MODE, &tmp, sizeof(tmp)); if (ret != 0) { - devwarn(usbdev, "setting infra mode failed (%08X)", ret); + netdev_warn(usbdev->net, "setting infra mode failed (%08X)\n", + ret); return ret; } @@ -1189,12 +1229,11 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) return 0; } - static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) { __le32 tmp; - devdbg(usbdev, "set_rts_threshold %i", rts_threshold); + netdev_dbg(usbdev->net, "%s(): %i\n", __func__, rts_threshold); if (rts_threshold < 0 || rts_threshold > 2347) rts_threshold = 2347; @@ -1204,12 +1243,11 @@ static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) sizeof(tmp)); } - static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) { __le32 tmp; - devdbg(usbdev, "set_frag_threshold %i", frag_threshold); + netdev_dbg(usbdev->net, "%s(): %i\n", __func__, frag_threshold); if (frag_threshold < 256 || frag_threshold > 2346) frag_threshold = 2346; @@ -1219,7 +1257,6 @@ static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) sizeof(tmp)); } - static void set_default_iw_params(struct usbnet *usbdev) { set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); @@ -1229,24 +1266,22 @@ static void set_default_iw_params(struct usbnet *usbdev) set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); } - static int deauthenticate(struct usbnet *usbdev) { int ret; - ret = disassociate(usbdev, 1); + ret = disassociate(usbdev, true); set_default_iw_params(usbdev); return ret; } - static int set_channel(struct usbnet *usbdev, int channel) { struct ndis_80211_conf config; unsigned int dsconfig; int len, ret; - devdbg(usbdev, "set_channel(%d)", channel); + netdev_dbg(usbdev->net, "%s(%d)\n", __func__, channel); /* this OID is valid only when not associated */ if (is_associated(usbdev)) @@ -1257,7 +1292,8 @@ static int set_channel(struct usbnet *usbdev, int channel) len = sizeof(config); ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); if (ret < 0) { - devdbg(usbdev, "set_channel: querying configuration failed"); + netdev_dbg(usbdev->net, "%s(): querying configuration failed\n", + __func__); return ret; } @@ -1265,12 +1301,11 @@ static int set_channel(struct usbnet *usbdev, int channel) ret = rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config, sizeof(config)); - devdbg(usbdev, "set_channel: %d -> %d", channel, ret); + netdev_dbg(usbdev->net, "%s(): %d -> %d\n", __func__, channel, ret); return ret; } - /* index must be 0 - N, as per NDIS */ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, int index) @@ -1280,7 +1315,8 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, u32 cipher; int ret; - devdbg(usbdev, "add_wep_key(idx: %d, len: %d)", index, key_len); + netdev_dbg(usbdev->net, "%s(idx: %d, len: %d)\n", + __func__, index, key_len); if ((key_len != 5 && key_len != 13) || index < 0 || index > 3) return -EINVAL; @@ -1302,15 +1338,15 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, ret = set_encr_mode(usbdev, RNDIS_WLAN_ALG_WEP, RNDIS_WLAN_ALG_NONE); if (ret) - devwarn(usbdev, "encryption couldn't be enabled (%08X)", - ret); + netdev_warn(usbdev->net, "encryption couldn't be enabled (%08X)\n", + ret); } ret = rndis_set_oid(usbdev, OID_802_11_ADD_WEP, &ndis_key, sizeof(ndis_key)); if (ret != 0) { - devwarn(usbdev, "adding encryption key %d failed (%08X)", - index+1, ret); + netdev_warn(usbdev->net, "adding encryption key %d failed (%08X)\n", + index + 1, ret); return ret; } @@ -1322,10 +1358,9 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, return 0; } - static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, int index, const u8 *addr, const u8 *rx_seq, - int seq_len, u32 cipher, int flags) + int seq_len, u32 cipher, __le32 flags) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_key ndis_key; @@ -1333,22 +1368,23 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, int ret; if (index < 0 || index >= 4) { - devdbg(usbdev, "add_wpa_key: index out of range (%i)", index); + netdev_dbg(usbdev->net, "%s(): index out of range (%i)\n", + __func__, index); return -EINVAL; } if (key_len > sizeof(ndis_key.material) || key_len < 0) { - devdbg(usbdev, "add_wpa_key: key length out of range (%i)", - key_len); + netdev_dbg(usbdev->net, "%s(): key length out of range (%i)\n", + __func__, key_len); return -EINVAL; } if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) { if (!rx_seq || seq_len <= 0) { - devdbg(usbdev, "add_wpa_key: recv seq flag without" - "buffer"); + netdev_dbg(usbdev->net, "%s(): recv seq flag without buffer\n", + __func__); return -EINVAL; } if (rx_seq && seq_len > sizeof(ndis_key.rsc)) { - devdbg(usbdev, "add_wpa_key: too big recv seq buffer"); + netdev_dbg(usbdev->net, "%s(): too big recv seq buffer\n", __func__); return -EINVAL; } } @@ -1356,15 +1392,16 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, is_addr_ok = addr && !is_zero_ether_addr(addr) && !is_broadcast_ether_addr(addr); if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) { - devdbg(usbdev, "add_wpa_key: pairwise but bssid invalid (%pM)", - addr); + netdev_dbg(usbdev->net, "%s(): pairwise but bssid invalid (%pM)\n", + __func__, addr); return -EINVAL; } - devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index, - !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY), - !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY), - !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)); + netdev_dbg(usbdev->net, "%s(%i): flags:%i%i%i\n", + __func__, index, + !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY), + !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY), + !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)); memset(&ndis_key, 0, sizeof(ndis_key)); @@ -1398,7 +1435,8 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key, le32_to_cpu(ndis_key.size)); - devdbg(usbdev, "add_wpa_key: OID_802_11_ADD_KEY -> %08X", ret); + netdev_dbg(usbdev->net, "%s(): OID_802_11_ADD_KEY -> %08X\n", + __func__, ret); if (ret != 0) return ret; @@ -1417,7 +1455,6 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, return 0; } - static int restore_key(struct usbnet *usbdev, int key_idx) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1428,7 +1465,7 @@ static int restore_key(struct usbnet *usbdev, int key_idx) key = priv->encr_keys[key_idx]; - devdbg(usbdev, "restore_key: %i:%i", key_idx, key.len); + netdev_dbg(usbdev->net, "%s(): %i:%i\n", __func__, key_idx, key.len); if (key.len == 0) return 0; @@ -1436,7 +1473,6 @@ static int restore_key(struct usbnet *usbdev, int key_idx) return add_wep_key(usbdev, key.material, key.len, key_idx); } - static void restore_keys(struct usbnet *usbdev) { int i; @@ -1445,13 +1481,11 @@ static void restore_keys(struct usbnet *usbdev) restore_key(usbdev, i); } - static void clear_key(struct rndis_wlan_private *priv, int idx) { memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx])); } - /* remove_key is for both wep and wpa */ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid) { @@ -1466,8 +1500,9 @@ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid) is_wpa = is_wpa_key(priv, index); - devdbg(usbdev, "remove_key: %i:%s:%i", index, is_wpa ? "wpa" : "wep", - priv->encr_keys[index].len); + netdev_dbg(usbdev->net, "%s(): %i:%s:%i\n", + __func__, index, is_wpa ? "wpa" : "wep", + priv->encr_keys[index].len); clear_key(priv, index); @@ -1494,9 +1529,9 @@ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid) ret = rndis_set_oid(usbdev, OID_802_11_REMOVE_WEP, &keyindex, sizeof(keyindex)); if (ret != 0) { - devwarn(usbdev, - "removing encryption key %d failed (%08X)", - index, ret); + netdev_warn(usbdev->net, + "removing encryption key %d failed (%08X)\n", + index, ret); return ret; } } @@ -1508,66 +1543,269 @@ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid) return 0; } - static void set_multicast_list(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct dev_mc_list *mclist; - __le32 filter; - int ret, i, size; - char *buf; + struct netdev_hw_addr *ha; + __le32 filter, basefilter; + int ret; + char *mc_addrs = NULL; + int mc_count; - filter = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST; + basefilter = filter = RNDIS_PACKET_TYPE_DIRECTED | + RNDIS_PACKET_TYPE_BROADCAST; if (usbdev->net->flags & IFF_PROMISC) { filter |= RNDIS_PACKET_TYPE_PROMISCUOUS | RNDIS_PACKET_TYPE_ALL_LOCAL; - } else if (usbdev->net->flags & IFF_ALLMULTI || - usbdev->net->mc_count > priv->multicast_size) { + } else if (usbdev->net->flags & IFF_ALLMULTI) { filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; - } else if (usbdev->net->mc_count > 0) { - size = min(priv->multicast_size, usbdev->net->mc_count); - buf = kmalloc(size * ETH_ALEN, GFP_KERNEL); - if (!buf) { - devwarn(usbdev, - "couldn't alloc %d bytes of memory", - size * ETH_ALEN); + } + + if (filter != basefilter) + goto set_filter; + + /* + * mc_list should be accessed holding the lock, so copy addresses to + * local buffer first. + */ + netif_addr_lock_bh(usbdev->net); + mc_count = netdev_mc_count(usbdev->net); + if (mc_count > priv->multicast_size) { + filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; + } else if (mc_count) { + int i = 0; + + mc_addrs = kmalloc(mc_count * ETH_ALEN, GFP_ATOMIC); + if (!mc_addrs) { + netdev_warn(usbdev->net, + "couldn't alloc %d bytes of memory\n", + mc_count * ETH_ALEN); + netif_addr_unlock_bh(usbdev->net); return; } - mclist = usbdev->net->mc_list; - for (i = 0; i < size && mclist; mclist = mclist->next) { - if (mclist->dmi_addrlen != ETH_ALEN) - continue; + netdev_for_each_mc_addr(ha, usbdev->net) + memcpy(mc_addrs + i++ * ETH_ALEN, + ha->addr, ETH_ALEN); + } + netif_addr_unlock_bh(usbdev->net); - memcpy(buf + i * ETH_ALEN, mclist->dmi_addr, ETH_ALEN); - i++; - } + if (filter != basefilter) + goto set_filter; - ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, buf, - i * ETH_ALEN); - if (ret == 0 && i > 0) + if (mc_count) { + ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, mc_addrs, + mc_count * ETH_ALEN); + kfree(mc_addrs); + if (ret == 0) filter |= RNDIS_PACKET_TYPE_MULTICAST; else filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; - devdbg(usbdev, "OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d", - i, priv->multicast_size, ret); - - kfree(buf); + netdev_dbg(usbdev->net, "OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n", + mc_count, priv->multicast_size, ret); } +set_filter: ret = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter, sizeof(filter)); if (ret < 0) { - devwarn(usbdev, "couldn't set packet filter: %08x", - le32_to_cpu(filter)); + netdev_warn(usbdev->net, "couldn't set packet filter: %08x\n", + le32_to_cpu(filter)); + } + + netdev_dbg(usbdev->net, "OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d\n", + le32_to_cpu(filter), ret); +} + +#ifdef DEBUG +static void debug_print_pmkids(struct usbnet *usbdev, + struct ndis_80211_pmkid *pmkids, + const char *func_str) +{ + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + int i, len, count, max_pmkids, entry_len; + + max_pmkids = priv->wdev.wiphy->max_num_pmkids; + len = le32_to_cpu(pmkids->length); + count = le32_to_cpu(pmkids->bssid_info_count); + + entry_len = (count > 0) ? (len - sizeof(*pmkids)) / count : -1; + + netdev_dbg(usbdev->net, "%s(): %d PMKIDs (data len: %d, entry len: " + "%d)\n", func_str, count, len, entry_len); + + if (count > max_pmkids) + count = max_pmkids; + + for (i = 0; i < count; i++) { + u32 *tmp = (u32 *)pmkids->bssid_info[i].pmkid; + + netdev_dbg(usbdev->net, "%s(): bssid: %pM, " + "pmkid: %08X:%08X:%08X:%08X\n", + func_str, pmkids->bssid_info[i].bssid, + cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), + cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); + } +} +#else +static void debug_print_pmkids(struct usbnet *usbdev, + struct ndis_80211_pmkid *pmkids, + const char *func_str) +{ + return; +} +#endif + +static struct ndis_80211_pmkid *get_device_pmkids(struct usbnet *usbdev) +{ + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct ndis_80211_pmkid *pmkids; + int len, ret, max_pmkids; + + max_pmkids = priv->wdev.wiphy->max_num_pmkids; + len = sizeof(*pmkids) + max_pmkids * sizeof(pmkids->bssid_info[0]); + + pmkids = kzalloc(len, GFP_KERNEL); + if (!pmkids) + return ERR_PTR(-ENOMEM); + + pmkids->length = cpu_to_le32(len); + pmkids->bssid_info_count = cpu_to_le32(max_pmkids); + + ret = rndis_query_oid(usbdev, OID_802_11_PMKID, pmkids, &len); + if (ret < 0) { + netdev_dbg(usbdev->net, "%s(): OID_802_11_PMKID(%d, %d)" + " -> %d\n", __func__, len, max_pmkids, ret); + + kfree(pmkids); + return ERR_PTR(ret); } - devdbg(usbdev, "OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d", - le32_to_cpu(filter), ret); + if (le32_to_cpu(pmkids->bssid_info_count) > max_pmkids) + pmkids->bssid_info_count = cpu_to_le32(max_pmkids); + + debug_print_pmkids(usbdev, pmkids, __func__); + + return pmkids; } +static int set_device_pmkids(struct usbnet *usbdev, + struct ndis_80211_pmkid *pmkids) +{ + int ret, len, num_pmkids; + + num_pmkids = le32_to_cpu(pmkids->bssid_info_count); + len = sizeof(*pmkids) + num_pmkids * sizeof(pmkids->bssid_info[0]); + pmkids->length = cpu_to_le32(len); + + debug_print_pmkids(usbdev, pmkids, __func__); + + ret = rndis_set_oid(usbdev, OID_802_11_PMKID, pmkids, + le32_to_cpu(pmkids->length)); + if (ret < 0) { + netdev_dbg(usbdev->net, "%s(): OID_802_11_PMKID(%d, %d) -> %d" + "\n", __func__, len, num_pmkids, ret); + } + + kfree(pmkids); + return ret; +} + +static struct ndis_80211_pmkid *remove_pmkid(struct usbnet *usbdev, + struct ndis_80211_pmkid *pmkids, + struct cfg80211_pmksa *pmksa, + int max_pmkids) +{ + int i, len, count, newlen, err; + + len = le32_to_cpu(pmkids->length); + count = le32_to_cpu(pmkids->bssid_info_count); + + if (count > max_pmkids) + count = max_pmkids; + + for (i = 0; i < count; i++) + if (!compare_ether_addr(pmkids->bssid_info[i].bssid, + pmksa->bssid)) + break; + + /* pmkid not found */ + if (i == count) { + netdev_dbg(usbdev->net, "%s(): bssid not found (%pM)\n", + __func__, pmksa->bssid); + err = -ENOENT; + goto error; + } + + for (; i + 1 < count; i++) + pmkids->bssid_info[i] = pmkids->bssid_info[i + 1]; + + count--; + newlen = sizeof(*pmkids) + count * sizeof(pmkids->bssid_info[0]); + + pmkids->length = cpu_to_le32(newlen); + pmkids->bssid_info_count = cpu_to_le32(count); + + return pmkids; +error: + kfree(pmkids); + return ERR_PTR(err); +} + +static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev, + struct ndis_80211_pmkid *pmkids, + struct cfg80211_pmksa *pmksa, + int max_pmkids) +{ + int i, err, len, count, newlen; + + len = le32_to_cpu(pmkids->length); + count = le32_to_cpu(pmkids->bssid_info_count); + + if (count > max_pmkids) + count = max_pmkids; + + /* update with new pmkid */ + for (i = 0; i < count; i++) { + if (compare_ether_addr(pmkids->bssid_info[i].bssid, + pmksa->bssid)) + continue; + + memcpy(pmkids->bssid_info[i].pmkid, pmksa->pmkid, + WLAN_PMKID_LEN); + + return pmkids; + } + + /* out of space, return error */ + if (i == max_pmkids) { + netdev_dbg(usbdev->net, "%s(): out of space\n", __func__); + err = -ENOSPC; + goto error; + } + + /* add new pmkid */ + newlen = sizeof(*pmkids) + (count + 1) * sizeof(pmkids->bssid_info[0]); + + pmkids = krealloc(pmkids, newlen, GFP_KERNEL); + if (!pmkids) { + err = -ENOMEM; + goto error; + } + + pmkids->length = cpu_to_le32(newlen); + pmkids->bssid_info_count = cpu_to_le32(count + 1); + + memcpy(pmkids->bssid_info[count].bssid, pmksa->bssid, ETH_ALEN); + memcpy(pmkids->bssid_info[count].pmkid, pmksa->pmkid, WLAN_PMKID_LEN); + + return pmkids; +error: + kfree(pmkids); + return ERR_PTR(err); +} /* * cfg80211 ops @@ -1597,7 +1835,6 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, return set_infra_mode(usbdev, mode); } - static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) { struct rndis_wlan_private *priv = wiphy_priv(wiphy); @@ -1619,14 +1856,14 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) return 0; } - static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, int dbm) { struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; - devdbg(usbdev, "rndis_set_tx_power type:0x%x dbm:%i", type, dbm); + netdev_dbg(usbdev->net, "%s(): type:0x%x dbm:%i\n", + __func__, type, dbm); /* Device doesn't support changing txpower after initialization, only * turn off/on radio. Support 'auto' mode and setting same dBm that is @@ -1634,7 +1871,7 @@ static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, */ if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) { if (!priv->radio_on) - disassociate(usbdev, 1); /* turn on radio */ + disassociate(usbdev, true); /* turn on radio */ return 0; } @@ -1642,7 +1879,6 @@ static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, return -ENOTSUPP; } - static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) { struct rndis_wlan_private *priv = wiphy_priv(wiphy); @@ -1650,12 +1886,11 @@ static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) *dbm = get_bcm4320_power_dbm(priv); - devdbg(usbdev, "rndis_get_tx_power dbm:%i", *dbm); + netdev_dbg(usbdev->net, "%s(): dbm:%i\n", __func__, *dbm); return 0; } - #define SCAN_DELAY_JIFFIES (6 * HZ) static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) @@ -1665,7 +1900,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, int ret; __le32 tmp; - devdbg(usbdev, "cfg80211.scan"); + netdev_dbg(usbdev->net, "cfg80211.scan\n"); /* Get current bssid list from device before new scan, as new scan * clears internal bssid list. @@ -1692,7 +1927,6 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, return ret; } - static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, struct ndis_80211_bssid_ex *bssid) { @@ -1706,8 +1940,8 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, int ie_len, bssid_len; u8 *ie; - devdbg(usbdev, " found bssid: '%.32s' [%pM]", bssid->ssid.essid, - bssid->mac); + netdev_dbg(usbdev->net, " found bssid: '%.32s' [%pM]\n", + bssid->ssid.essid, bssid->mac); /* parse bssid structure */ bssid_len = le32_to_cpu(bssid->length); @@ -1741,7 +1975,6 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, GFP_KERNEL); } - static int rndis_check_bssid_list(struct usbnet *usbdev) { void *buf = NULL; @@ -1750,7 +1983,7 @@ static int rndis_check_bssid_list(struct usbnet *usbdev) int ret = -EINVAL, len, count, bssid_len; bool resized = false; - devdbg(usbdev, "check_bssid_list"); + netdev_dbg(usbdev->net, "check_bssid_list\n"); len = CONTROL_BUFFER_SIZE; resize_buf: @@ -1774,8 +2007,8 @@ resize_buf: bssid = bssid_list->bssid; bssid_len = le32_to_cpu(bssid->length); count = le32_to_cpu(bssid_list->num_items); - devdbg(usbdev, "check_bssid_list: %d BSSIDs found (buflen: %d)", count, - len); + netdev_dbg(usbdev->net, "check_bssid_list: %d BSSIDs found (buflen: %d)\n", + count, len); while (count && ((void *)bssid + bssid_len) <= (buf + len)) { rndis_bss_info_update(usbdev, bssid); @@ -1790,7 +2023,6 @@ out: return ret; } - static void rndis_get_scan_results(struct work_struct *work) { struct rndis_wlan_private *priv = @@ -1798,7 +2030,7 @@ static void rndis_get_scan_results(struct work_struct *work) struct usbnet *usbdev = priv->usbdev; int ret; - devdbg(usbdev, "get_scan_results"); + netdev_dbg(usbdev->net, "get_scan_results\n"); if (!priv->scan_request) return; @@ -1832,7 +2064,7 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, if (sme->crypto.n_ciphers_pairwise > 0 && pairwise == RNDIS_WLAN_ALG_NONE) { - deverr(usbdev, "Unsupported pairwise cipher"); + netdev_err(usbdev->net, "Unsupported pairwise cipher\n"); return -ENOTSUPP; } @@ -1842,28 +2074,30 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, if (sme->crypto.n_akm_suites > 0 && keymgmt == RNDIS_WLAN_KEY_MGMT_NONE) { - deverr(usbdev, "Invalid keymgmt"); + netdev_err(usbdev->net, "Invalid keymgmt\n"); return -ENOTSUPP; } - devdbg(usbdev, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:" - "0x%x]:0x%x)", sme->ssid, sme->bssid, chan, - sme->privacy, sme->crypto.wpa_versions, sme->auth_type, - groupwise, pairwise, keymgmt); + netdev_dbg(usbdev->net, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:0x%x]:0x%x)\n", + sme->ssid, sme->bssid, chan, + sme->privacy, sme->crypto.wpa_versions, sme->auth_type, + groupwise, pairwise, keymgmt); if (is_associated(usbdev)) disassociate(usbdev, false); ret = set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); if (ret < 0) { - devdbg(usbdev, "connect: set_infra_mode failed, %d", ret); + netdev_dbg(usbdev->net, "connect: set_infra_mode failed, %d\n", + ret); goto err_turn_radio_on; } ret = set_auth_mode(usbdev, sme->crypto.wpa_versions, sme->auth_type, keymgmt); if (ret < 0) { - devdbg(usbdev, "connect: set_auth_mode failed, %d", ret); + netdev_dbg(usbdev->net, "connect: set_auth_mode failed, %d\n", + ret); goto err_turn_radio_on; } @@ -1871,14 +2105,16 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, ret = set_encr_mode(usbdev, pairwise, groupwise); if (ret < 0) { - devdbg(usbdev, "connect: set_encr_mode failed, %d", ret); + netdev_dbg(usbdev->net, "connect: set_encr_mode failed, %d\n", + ret); goto err_turn_radio_on; } if (channel) { ret = set_channel(usbdev, chan); if (ret < 0) { - devdbg(usbdev, "connect: set_channel failed, %d", ret); + netdev_dbg(usbdev->net, "connect: set_channel failed, %d\n", + ret); goto err_turn_radio_on; } } @@ -1887,8 +2123,8 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, priv->encr_tx_key_index = sme->key_idx; ret = add_wep_key(usbdev, sme->key, sme->key_len, sme->key_idx); if (ret < 0) { - devdbg(usbdev, "connect: add_wep_key failed, %d " - "(%d, %d)", ret, sme->key_len, sme->key_idx); + netdev_dbg(usbdev->net, "connect: add_wep_key failed, %d (%d, %d)\n", + ret, sme->key_len, sme->key_idx); goto err_turn_radio_on; } } @@ -1897,7 +2133,8 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, !is_broadcast_ether_addr(sme->bssid)) { ret = set_bssid(usbdev, sme->bssid); if (ret < 0) { - devdbg(usbdev, "connect: set_bssid failed, %d", ret); + netdev_dbg(usbdev->net, "connect: set_bssid failed, %d\n", + ret); goto err_turn_radio_on; } } else @@ -1919,11 +2156,11 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, ret = set_essid(usbdev, &ssid); if (ret < 0) - devdbg(usbdev, "connect: set_essid failed, %d", ret); + netdev_dbg(usbdev->net, "connect: set_essid failed, %d\n", ret); return ret; err_turn_radio_on: - disassociate(usbdev, 1); + disassociate(usbdev, true); return ret; } @@ -1934,7 +2171,7 @@ static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; - devdbg(usbdev, "cfg80211.disconnect(%d)", reason_code); + netdev_dbg(usbdev->net, "cfg80211.disconnect(%d)\n", reason_code); priv->connected = false; memset(priv->bssid, 0, ETH_ALEN); @@ -1968,21 +2205,23 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, alg = RNDIS_WLAN_ALG_NONE; } - devdbg(usbdev, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)", params->ssid, - params->bssid, chan, params->privacy); + netdev_dbg(usbdev->net, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)\n", + params->ssid, params->bssid, chan, params->privacy); if (is_associated(usbdev)) disassociate(usbdev, false); ret = set_infra_mode(usbdev, NDIS_80211_INFRA_ADHOC); if (ret < 0) { - devdbg(usbdev, "join_ibss: set_infra_mode failed, %d", ret); + netdev_dbg(usbdev->net, "join_ibss: set_infra_mode failed, %d\n", + ret); goto err_turn_radio_on; } ret = set_auth_mode(usbdev, 0, auth_type, RNDIS_WLAN_KEY_MGMT_NONE); if (ret < 0) { - devdbg(usbdev, "join_ibss: set_auth_mode failed, %d", ret); + netdev_dbg(usbdev->net, "join_ibss: set_auth_mode failed, %d\n", + ret); goto err_turn_radio_on; } @@ -1990,15 +2229,16 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, ret = set_encr_mode(usbdev, alg, RNDIS_WLAN_ALG_NONE); if (ret < 0) { - devdbg(usbdev, "join_ibss: set_encr_mode failed, %d", ret); + netdev_dbg(usbdev->net, "join_ibss: set_encr_mode failed, %d\n", + ret); goto err_turn_radio_on; } if (channel) { ret = set_channel(usbdev, chan); if (ret < 0) { - devdbg(usbdev, "join_ibss: set_channel failed, %d", - ret); + netdev_dbg(usbdev->net, "join_ibss: set_channel failed, %d\n", + ret); goto err_turn_radio_on; } } @@ -2007,7 +2247,8 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, !is_broadcast_ether_addr(params->bssid)) { ret = set_bssid(usbdev, params->bssid); if (ret < 0) { - devdbg(usbdev, "join_ibss: set_bssid failed, %d", ret); + netdev_dbg(usbdev->net, "join_ibss: set_bssid failed, %d\n", + ret); goto err_turn_radio_on; } } else @@ -2027,11 +2268,12 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, ret = set_essid(usbdev, &ssid); if (ret < 0) - devdbg(usbdev, "join_ibss: set_essid failed, %d", ret); + netdev_dbg(usbdev->net, "join_ibss: set_essid failed, %d\n", + ret); return ret; err_turn_radio_on: - disassociate(usbdev, 1); + disassociate(usbdev, true); return ret; } @@ -2041,7 +2283,7 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; - devdbg(usbdev, "cfg80211.leave_ibss()"); + netdev_dbg(usbdev->net, "cfg80211.leave_ibss()\n"); priv->connected = false; memset(priv->bssid, 0, ETH_ALEN); @@ -2049,7 +2291,7 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return deauthenticate(usbdev); } -static int rndis_set_channel(struct wiphy *wiphy, +static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { struct rndis_wlan_private *priv = wiphy_priv(wiphy); @@ -2065,10 +2307,10 @@ static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, { struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; - int flags; + __le32 flags; - devdbg(usbdev, "rndis_add_key(%i, %pM, %08x)", key_index, mac_addr, - params->cipher); + netdev_dbg(usbdev->net, "%s(%i, %pM, %08x)\n", + __func__, key_index, mac_addr, params->cipher); switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: @@ -2089,8 +2331,8 @@ static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, key_index, mac_addr, params->seq, params->seq_len, params->cipher, flags); default: - devdbg(usbdev, "rndis_add_key: unsupported cipher %08x", - params->cipher); + netdev_dbg(usbdev->net, "%s(): unsupported cipher %08x\n", + __func__, params->cipher); return -ENOTSUPP; } } @@ -2101,7 +2343,7 @@ static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; - devdbg(usbdev, "rndis_del_key(%i, %pM)", key_index, mac_addr); + netdev_dbg(usbdev->net, "%s(%i, %pM)\n", __func__, key_index, mac_addr); return remove_key(usbdev, key_index, mac_addr); } @@ -2113,7 +2355,7 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, struct usbnet *usbdev = priv->usbdev; struct rndis_wlan_encr_key key; - devdbg(usbdev, "rndis_set_default_key(%i)", key_index); + netdev_dbg(usbdev->net, "%s(%i)\n", __func__, key_index); priv->encr_tx_key_index = key_index; @@ -2175,435 +2417,81 @@ static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, return 0; } -/* - * wireless extension handlers - */ - -static int rndis_iw_commit(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - /* dummy op */ - return 0; -} - -#if 0 -/* Commented code out instead of removing to have more sane patch for review. - * Will be removed later in the set. - */ -static int rndis_iw_set_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct ndis_80211_ssid ssid; - int length = wrqu->essid.length; - struct usbnet *usbdev = netdev_priv(dev); - - devdbg(usbdev, "SIOCSIWESSID: [flags:%d,len:%d] '%.32s'", - wrqu->essid.flags, wrqu->essid.length, essid); - - if (length > NDIS_802_11_LENGTH_SSID) - length = NDIS_802_11_LENGTH_SSID; - - ssid.length = cpu_to_le32(length); - if (length > 0) - memcpy(ssid.essid, essid, length); - else - memset(ssid.essid, 0, NDIS_802_11_LENGTH_SSID); - - set_assoc_params(usbdev); - - if (!wrqu->essid.flags || length == 0) - return disassociate(usbdev, 1); - else { - /* Pause and purge rx queue, so we don't pass packets before - * 'media connect'-indication. - */ - usbnet_pause_rx(usbdev); - usbnet_purge_paused_rxq(usbdev); - - return set_essid(usbdev, &ssid); - } -} - - -static int rndis_iw_get_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct ndis_80211_ssid ssid; - struct usbnet *usbdev = netdev_priv(dev); - int ret; - - ret = get_essid(usbdev, &ssid); - - if (ret == 0 && le32_to_cpu(ssid.length) > 0) { - wrqu->essid.flags = 1; - wrqu->essid.length = le32_to_cpu(ssid.length); - memcpy(essid, ssid.essid, wrqu->essid.length); - essid[wrqu->essid.length] = 0; - } else { - memset(essid, 0, sizeof(NDIS_802_11_LENGTH_SSID)); - wrqu->essid.flags = 0; - wrqu->essid.length = 0; - } - devdbg(usbdev, "SIOCGIWESSID: %s", essid); - return ret; -} - - -static int rndis_iw_get_bssid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - unsigned char bssid[ETH_ALEN]; - int ret; - - ret = get_bssid(usbdev, bssid); - - if (ret == 0) - devdbg(usbdev, "SIOCGIWAP: %pM", bssid); - else - devdbg(usbdev, "SIOCGIWAP: "); - - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu->ap_addr.sa_data, bssid, ETH_ALEN); - - return ret; -} - - -static int rndis_iw_set_bssid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - u8 *bssid = (u8 *)wrqu->ap_addr.sa_data; - int ret; - - devdbg(usbdev, "SIOCSIWAP: %pM", bssid); - - ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN); - - /* user apps may set ap's mac address, which is not required; - * they may fail to work if this function fails, so return - * success */ - if (ret) - devwarn(usbdev, "setting AP mac address failed (%08X)", ret); - - return 0; -} - - -static int rndis_iw_set_auth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int ret = -ENOTSUPP; - - switch (p->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - devdbg(usbdev, "SIOCSIWAUTH: WPA_VERSION, %08x", p->value); - priv->wpa_version = p->value; - ret = 0; - break; - - case IW_AUTH_CIPHER_PAIRWISE: - devdbg(usbdev, "SIOCSIWAUTH: CIPHER_PAIRWISE, %08x", p->value); - priv->wpa_cipher_pair = p->value; - ret = 0; - break; - - case IW_AUTH_CIPHER_GROUP: - devdbg(usbdev, "SIOCSIWAUTH: CIPHER_GROUP, %08x", p->value); - priv->wpa_cipher_group = p->value; - ret = 0; - break; - - case IW_AUTH_KEY_MGMT: - devdbg(usbdev, "SIOCSIWAUTH: KEY_MGMT, %08x", p->value); - priv->wpa_keymgmt = p->value; - ret = 0; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - devdbg(usbdev, "SIOCSIWAUTH: TKIP_COUNTERMEASURES, %08x", - p->value); - ret = 0; - break; - - case IW_AUTH_DROP_UNENCRYPTED: - devdbg(usbdev, "SIOCSIWAUTH: DROP_UNENCRYPTED, %08x", p->value); - ret = 0; - break; - - case IW_AUTH_80211_AUTH_ALG: - devdbg(usbdev, "SIOCSIWAUTH: 80211_AUTH_ALG, %08x", p->value); - priv->wpa_authalg = p->value; - ret = 0; - break; - - case IW_AUTH_WPA_ENABLED: - devdbg(usbdev, "SIOCSIWAUTH: WPA_ENABLED, %08x", p->value); - if (wrqu->param.value) - deauthenticate(usbdev); - ret = 0; - break; - - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - devdbg(usbdev, "SIOCSIWAUTH: RX_UNENCRYPTED_EAPOL, %08x", - p->value); - ret = 0; - break; - - case IW_AUTH_ROAMING_CONTROL: - devdbg(usbdev, "SIOCSIWAUTH: ROAMING_CONTROL, %08x", p->value); - ret = 0; - break; - - case IW_AUTH_PRIVACY_INVOKED: - devdbg(usbdev, "SIOCSIWAUTH: invalid cmd %d", - wrqu->param.flags & IW_AUTH_INDEX); - return -EOPNOTSUPP; - - default: - devdbg(usbdev, "SIOCSIWAUTH: UNKNOWN %08x, %08x", - p->flags & IW_AUTH_INDEX, p->value); - } - return ret; -} - - -static int rndis_iw_get_auth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - switch (p->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - p->value = priv->wpa_version; - break; - case IW_AUTH_CIPHER_PAIRWISE: - p->value = priv->wpa_cipher_pair; - break; - case IW_AUTH_CIPHER_GROUP: - p->value = priv->wpa_cipher_group; - break; - case IW_AUTH_KEY_MGMT: - p->value = priv->wpa_keymgmt; - break; - case IW_AUTH_80211_AUTH_ALG: - p->value = priv->wpa_authalg; - break; - default: - devdbg(usbdev, "SIOCGIWAUTH: invalid cmd %d", - wrqu->param.flags & IW_AUTH_INDEX); - return -EOPNOTSUPP; - } - return 0; -} - - -static int rndis_iw_set_encode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) +static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) { - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_wlan_encr_key key; - int ret, index, key_len; - u8 *keybuf; - - index = (wrqu->encoding.flags & IW_ENCODE_INDEX); - - /* iwconfig gives index as 1 - N */ - if (index > 0) - index--; - else - index = priv->encr_tx_key_index; + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + struct ndis_80211_pmkid *pmkids; + u32 *tmp = (u32 *)pmksa->pmkid; - if (index < 0 || index >= 4) { - devwarn(usbdev, "encryption index out of range (%u)", index); - return -EINVAL; - } + netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__, + pmksa->bssid, + cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), + cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); - /* remove key if disabled */ - if (wrqu->data.flags & IW_ENCODE_DISABLED) { - if (remove_key(usbdev, index, NULL)) - return -EINVAL; - else - return 0; + pmkids = get_device_pmkids(usbdev); + if (IS_ERR(pmkids)) { + /* couldn't read PMKID cache from device */ + return PTR_ERR(pmkids); } - /* global encryption state (for all keys) */ - if (wrqu->data.flags & IW_ENCODE_OPEN) - ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, - RNDIS_WLAN_KEY_MGMT_NONE); - else /*if (wrqu->data.flags & IW_ENCODE_RESTRICTED)*/ - ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_SHARED_KEY, - RNDIS_WLAN_KEY_MGMT_NONE); - if (ret != 0) - return ret; - - if (wrqu->data.length > 0) { - key_len = wrqu->data.length; - keybuf = extra; - } else { - /* must be set as tx key */ - if (priv->encr_keys[index].len == 0) - return -EINVAL; - key = priv->encr_keys[index]; - key_len = key.len; - keybuf = key.material; - priv->encr_tx_key_index = index; + pmkids = update_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids); + if (IS_ERR(pmkids)) { + /* not found, list full, etc */ + return PTR_ERR(pmkids); } - if (add_wep_key(usbdev, keybuf, key_len, index) != 0) - return -EINVAL; - - if (index == priv->encr_tx_key_index) - /* ndis drivers want essid to be set after setting encr */ - set_essid(usbdev, &priv->essid); - - return 0; + return set_device_pmkids(usbdev, pmkids); } - -static int rndis_iw_set_encode_ext(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) +static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) { - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int keyidx, flags, cipher; + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + struct ndis_80211_pmkid *pmkids; + u32 *tmp = (u32 *)pmksa->pmkid; - keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; + netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__, + pmksa->bssid, + cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), + cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); - /* iwconfig gives index as 1 - N */ - if (keyidx) - keyidx--; - else - keyidx = priv->encr_tx_key_index; - - if (keyidx < 0 || keyidx >= 4) { - devwarn(usbdev, "encryption index out of range (%u)", keyidx); - return -EINVAL; + pmkids = get_device_pmkids(usbdev); + if (IS_ERR(pmkids)) { + /* Couldn't read PMKID cache from device */ + return PTR_ERR(pmkids); } - if (ext->alg == IW_ENCODE_ALG_WEP) { - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - priv->encr_tx_key_index = keyidx; - return add_wep_key(usbdev, ext->key, ext->key_len, keyidx); + pmkids = remove_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids); + if (IS_ERR(pmkids)) { + /* not found, etc */ + return PTR_ERR(pmkids); } - cipher = -1; - if (ext->alg == IW_ENCODE_ALG_TKIP) - cipher = WLAN_CIPHER_SUITE_TKIP; - else if (ext->alg == IW_ENCODE_ALG_CCMP) - cipher = WLAN_CIPHER_SUITE_CCMP; - - if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) || - ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) - return remove_key(usbdev, keyidx, NULL); - - if (cipher == -1) - return -EOPNOTSUPP; - - flags = 0; - if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; - if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) - flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY; - - return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, - (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher, - flags); + return set_device_pmkids(usbdev, pmkids); } - -static int rndis_iw_get_rate(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) +static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) { - struct usbnet *usbdev = netdev_priv(dev); - __le32 tmp; - int ret, len; - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &tmp, &len); - if (ret == 0) { - wrqu->bitrate.value = le32_to_cpu(tmp) * 100; - wrqu->bitrate.disabled = 0; - wrqu->bitrate.flags = 1; - } - return ret; -} + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + struct ndis_80211_pmkid pmkid; + netdev_dbg(usbdev->net, "%s()\n", __func__); -static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - unsigned long flags; + memset(&pmkid, 0, sizeof(pmkid)); - spin_lock_irqsave(&priv->stats_lock, flags); - memcpy(&priv->iwstats, &priv->privstats, sizeof(priv->iwstats)); - spin_unlock_irqrestore(&priv->stats_lock, flags); + pmkid.length = cpu_to_le32(sizeof(pmkid)); + pmkid.bssid_info_count = cpu_to_le32(0); - return &priv->iwstats; + return rndis_set_oid(usbdev, OID_802_11_PMKID, &pmkid, sizeof(pmkid)); } -#endif - - -#define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT] -static const iw_handler rndis_iw_handler[] = -{ - IW_IOCTL(SIOCSIWCOMMIT) = rndis_iw_commit, - IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, - IW_IOCTL(SIOCSIWFREQ) = (iw_handler) cfg80211_wext_siwfreq, - IW_IOCTL(SIOCGIWFREQ) = (iw_handler) cfg80211_wext_giwfreq, - IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, - IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, - IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, - IW_IOCTL(SIOCSIWAP) = (iw_handler) cfg80211_wext_siwap, - IW_IOCTL(SIOCGIWAP) = (iw_handler) cfg80211_wext_giwap, - IW_IOCTL(SIOCSIWSCAN) = (iw_handler) cfg80211_wext_siwscan, - IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, - IW_IOCTL(SIOCSIWESSID) = (iw_handler) cfg80211_wext_siwessid, - IW_IOCTL(SIOCGIWESSID) = (iw_handler) cfg80211_wext_giwessid, - IW_IOCTL(SIOCGIWRATE) = (iw_handler) cfg80211_wext_giwrate, - IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, - IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, - IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag, - IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag, - IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) cfg80211_wext_siwtxpower, - IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower, - IW_IOCTL(SIOCSIWENCODE) = (iw_handler) cfg80211_wext_siwencode, - IW_IOCTL(SIOCSIWENCODEEXT) = (iw_handler) cfg80211_wext_siwencodeext, - IW_IOCTL(SIOCSIWAUTH) = (iw_handler) cfg80211_wext_siwauth, - IW_IOCTL(SIOCGIWAUTH) = (iw_handler) cfg80211_wext_giwauth, - IW_IOCTL(SIOCSIWGENIE) = (iw_handler) cfg80211_wext_siwgenie, - IW_IOCTL(SIOCSIWMLME) = (iw_handler) cfg80211_wext_siwmlme, -}; - -static const iw_handler rndis_wlan_private_handler[] = { -}; - -static const struct iw_priv_args rndis_wlan_private_args[] = { -}; - - -static const struct iw_handler_def rndis_iw_handlers = { - .num_standard = ARRAY_SIZE(rndis_iw_handler), - .num_private = ARRAY_SIZE(rndis_wlan_private_handler), - .num_private_args = ARRAY_SIZE(rndis_wlan_private_args), - .standard = (iw_handler *)rndis_iw_handler, - .private = (iw_handler *)rndis_wlan_private_handler, - .private_args = (struct iw_priv_args *)rndis_wlan_private_args, - .get_wireless_stats = cfg80211_wireless_stats, -}; - +/* + * workers, indication handlers, device poller + */ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2653,7 +2541,8 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) if (ret < 0) memset(bssid, 0, sizeof(bssid)); - devdbg(usbdev, "link up work: [%pM] %s", bssid, roamed ? "roamed" : ""); + netdev_dbg(usbdev->net, "link up work: [%pM]%s\n", + bssid, roamed ? " roamed" : ""); /* Internal bss list in device always contains at least the currently * connected bss and we can get it to cfg80211 with @@ -2721,22 +2610,22 @@ static void rndis_wlan_set_multicast_list(struct net_device *dev) queue_work(priv->workqueue, &priv->work); } - static void rndis_wlan_auth_indication(struct usbnet *usbdev, struct ndis_80211_status_indication *indication, int len) { u8 *buf; const char *type; - int flags, buflen; + int flags, buflen, key_id; bool pairwise_error, group_error; struct ndis_80211_auth_request *auth_req; + enum nl80211_key_type key_type; /* must have at least one array entry */ if (len < offsetof(struct ndis_80211_status_indication, u) + sizeof(struct ndis_80211_auth_request)) { - devinfo(usbdev, "authentication indication: " - "too short message (%i)", len); + netdev_info(usbdev->net, "authentication indication: too short message (%i)\n", + len); return; } @@ -2763,26 +2652,27 @@ static void rndis_wlan_auth_indication(struct usbnet *usbdev, type = "group_error"; } - devinfo(usbdev, "authentication indication: %s (0x%08x)", type, - le32_to_cpu(auth_req->flags)); + netdev_info(usbdev->net, "authentication indication: %s (0x%08x)\n", + type, le32_to_cpu(auth_req->flags)); - if (pairwise_error || group_error) { - union iwreq_data wrqu; - struct iw_michaelmicfailure micfailure; + if (pairwise_error) { + key_type = NL80211_KEYTYPE_PAIRWISE; + key_id = -1; - memset(&micfailure, 0, sizeof(micfailure)); - if (pairwise_error) - micfailure.flags |= IW_MICFAILURE_PAIRWISE; - if (group_error) - micfailure.flags |= IW_MICFAILURE_GROUP; + cfg80211_michael_mic_failure(usbdev->net, + auth_req->bssid, + key_type, key_id, NULL, + GFP_KERNEL); + } - memcpy(micfailure.src_addr.sa_data, auth_req->bssid, - ETH_ALEN); + if (group_error) { + key_type = NL80211_KEYTYPE_GROUP; + key_id = -1; - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = sizeof(micfailure); - wireless_send_event(usbdev->net, IWEVMICHAELMICFAILURE, - &wrqu, (u8 *)&micfailure); + cfg80211_michael_mic_failure(usbdev->net, + auth_req->bssid, + key_type, key_id, NULL, + GFP_KERNEL); } buflen -= le32_to_cpu(auth_req->length); @@ -2799,8 +2689,8 @@ static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, if (len < offsetof(struct ndis_80211_status_indication, u) + sizeof(struct ndis_80211_pmkid_cand_list)) { - devinfo(usbdev, "pmkid candidate list indication: " - "too short message (%i)", len); + netdev_info(usbdev->net, "pmkid candidate list indication: too short message (%i)\n", + len); return; } @@ -2810,30 +2700,30 @@ static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, offsetof(struct ndis_80211_status_indication, u); if (len < expected_len) { - devinfo(usbdev, "pmkid candidate list indication: " - "list larger than buffer (%i < %i)", - len, expected_len); + netdev_info(usbdev->net, "pmkid candidate list indication: list larger than buffer (%i < %i)\n", + len, expected_len); return; } cand_list = &indication->u.cand_list; - devinfo(usbdev, "pmkid candidate list indication: " - "version %i, candidates %i", - le32_to_cpu(cand_list->version), - le32_to_cpu(cand_list->num_candidates)); + netdev_info(usbdev->net, "pmkid candidate list indication: version %i, candidates %i\n", + le32_to_cpu(cand_list->version), + le32_to_cpu(cand_list->num_candidates)); if (le32_to_cpu(cand_list->version) != 1) return; for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) { - struct iw_pmkid_cand pcand; - union iwreq_data wrqu; struct ndis_80211_pmkid_candidate *cand = &cand_list->candidate_list[i]; - devdbg(usbdev, "cand[%i]: flags: 0x%08x, bssid: %pM", - i, le32_to_cpu(cand->flags), cand->bssid); + netdev_dbg(usbdev->net, "cand[%i]: flags: 0x%08x, bssid: %pM\n", + i, le32_to_cpu(cand->flags), cand->bssid); + +#if 0 + struct iw_pmkid_cand pcand; + union iwreq_data wrqu; memset(&pcand, 0, sizeof(pcand)); if (le32_to_cpu(cand->flags) & 0x01) @@ -2845,6 +2735,7 @@ static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, wrqu.data.length = sizeof(pcand); wireless_send_event(usbdev->net, IWEVPMKIDCAND, &wrqu, (u8 *)&pcand); +#endif } } @@ -2859,15 +2750,14 @@ static void rndis_wlan_media_specific_indication(struct usbnet *usbdev, len = le32_to_cpu(msg->length); if (len < 8) { - devinfo(usbdev, "media specific indication, " - "ignore too short message (%i < 8)", len); + netdev_info(usbdev->net, "media specific indication, ignore too short message (%i < 8)\n", + len); return; } if (offset + len > buflen) { - devinfo(usbdev, "media specific indication, " - "too large to fit to buffer (%i > %i)", - offset + len, buflen); + netdev_info(usbdev->net, "media specific indication, too large to fit to buffer (%i > %i)\n", + offset + len, buflen); return; } @@ -2875,13 +2765,13 @@ static void rndis_wlan_media_specific_indication(struct usbnet *usbdev, switch (le32_to_cpu(indication->status_type)) { case NDIS_80211_STATUSTYPE_RADIOSTATE: - devinfo(usbdev, "radio state indication: %i", - le32_to_cpu(indication->u.radio_status)); + netdev_info(usbdev->net, "radio state indication: %i\n", + le32_to_cpu(indication->u.radio_status)); return; case NDIS_80211_STATUSTYPE_MEDIASTREAMMODE: - devinfo(usbdev, "media stream mode indication: %i", - le32_to_cpu(indication->u.media_stream_mode)); + netdev_info(usbdev->net, "media stream mode indication: %i\n", + le32_to_cpu(indication->u.media_stream_mode)); return; case NDIS_80211_STATUSTYPE_AUTHENTICATION: @@ -2893,13 +2783,11 @@ static void rndis_wlan_media_specific_indication(struct usbnet *usbdev, return; default: - devinfo(usbdev, "media specific indication: " - "unknown status type 0x%08x", - le32_to_cpu(indication->status_type)); + netdev_info(usbdev->net, "media specific indication: unknown status type 0x%08x\n", + le32_to_cpu(indication->status_type)); } } - static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2913,14 +2801,13 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) * and userspace to think that device is * roaming/reassociating when it isn't. */ - devdbg(usbdev, "ignored OID_802_11_ADD_KEY triggered " - "'media connect'"); + netdev_dbg(usbdev->net, "ignored OID_802_11_ADD_KEY triggered 'media connect'\n"); return; } usbnet_pause_rx(usbdev); - devinfo(usbdev, "media connect"); + netdev_info(usbdev->net, "media connect\n"); /* queue work to avoid recursive calls into rndis_command */ set_bit(WORK_LINK_UP, &priv->work_pending); @@ -2928,7 +2815,7 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) break; case RNDIS_STATUS_MEDIA_DISCONNECT: - devinfo(usbdev, "media disconnect"); + netdev_info(usbdev->net, "media disconnect\n"); /* queue work to avoid recursive calls into rndis_command */ set_bit(WORK_LINK_DOWN, &priv->work_pending); @@ -2940,19 +2827,20 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) break; default: - devinfo(usbdev, "indication: 0x%08x", - le32_to_cpu(msg->status)); + netdev_info(usbdev->net, "indication: 0x%08x\n", + le32_to_cpu(msg->status)); break; } } - -static int rndis_wlan_get_caps(struct usbnet *usbdev) +static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy) { struct { __le32 num_items; __le32 items[8]; } networks_supported; + struct ndis_80211_capability *caps; + u8 caps_buf[sizeof(*caps) + sizeof(caps->auth_encr_pair) * 16]; int len, retval, i, n; struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2980,19 +2868,34 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev) } } + /* get device 802.11 capabilities, number of PMKIDs */ + caps = (struct ndis_80211_capability *)caps_buf; + len = sizeof(caps_buf); + retval = rndis_query_oid(usbdev, OID_802_11_CAPABILITY, caps, &len); + if (retval >= 0) { + netdev_dbg(usbdev->net, "OID_802_11_CAPABILITY -> len %d, " + "ver %d, pmkids %d, auth-encr-pairs %d\n", + le32_to_cpu(caps->length), + le32_to_cpu(caps->version), + le32_to_cpu(caps->num_pmkids), + le32_to_cpu(caps->num_auth_encr_pair)); + wiphy->max_num_pmkids = le32_to_cpu(caps->num_pmkids); + } else + wiphy->max_num_pmkids = 0; + return retval; } - -#define STATS_UPDATE_JIFFIES (HZ) -static void rndis_update_wireless_stats(struct work_struct *work) +#define DEVICE_POLLER_JIFFIES (HZ) +static void rndis_device_poller(struct work_struct *work) { struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, stats_work.work); + container_of(work, struct rndis_wlan_private, + dev_poller_work.work); struct usbnet *usbdev = priv->usbdev; __le32 rssi, tmp; int len, ret, j; - int update_jiffies = STATS_UPDATE_JIFFIES; + int update_jiffies = DEVICE_POLLER_JIFFIES; void *buf; /* Only check/do workaround when connected. Calling is_associated() @@ -3007,20 +2910,20 @@ static void rndis_update_wireless_stats(struct work_struct *work) if (ret == 0) priv->last_qual = level_to_qual(le32_to_cpu(rssi)); - devdbg(usbdev, "stats: OID_802_11_RSSI -> %d, rssi:%d", ret, - le32_to_cpu(rssi)); + netdev_dbg(usbdev->net, "dev-poller: OID_802_11_RSSI -> %d, rssi:%d, qual: %d\n", + ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi))); /* Workaround transfer stalls on poor quality links. * TODO: find right way to fix these stalls (as stalls do not happen * with ndiswrapper/windows driver). */ - if (priv->last_qual <= 25) { + if (priv->param_workaround_interval > 0 && priv->last_qual <= 25) { /* Decrease stats worker interval to catch stalls. * faster. Faster than 400-500ms causes packet loss, * Slower doesn't catch stalls fast enough. */ j = msecs_to_jiffies(priv->param_workaround_interval); - if (j > STATS_UPDATE_JIFFIES) - j = STATS_UPDATE_JIFFIES; + if (j > DEVICE_POLLER_JIFFIES) + j = DEVICE_POLLER_JIFFIES; else if (j <= 0) j = 1; update_jiffies = j; @@ -3040,8 +2943,8 @@ static void rndis_update_wireless_stats(struct work_struct *work) rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len); kfree(buf); } -end: +end: if (update_jiffies >= HZ) update_jiffies = round_jiffies_relative(update_jiffies); else { @@ -3050,28 +2953,16 @@ end: update_jiffies = j; } - queue_delayed_work(priv->workqueue, &priv->stats_work, update_jiffies); + queue_delayed_work(priv->workqueue, &priv->dev_poller_work, + update_jiffies); } - -static int bcm4320a_early_init(struct usbnet *usbdev) -{ - /* bcm4320a doesn't handle configuration parameters well. Try - * set any and you get partially zeroed mac and broken device. - */ - - return 0; -} - - -static int bcm4320b_early_init(struct usbnet *usbdev) +/* + * driver/device initialization + */ +static void rndis_copy_module_params(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - char buf[8]; - - /* Early initialization settings, setting these won't have effect - * if called after generic_rndis_bind(). - */ priv->param_country[0] = modparam_country[0]; priv->param_country[1] = modparam_country[1]; @@ -3113,6 +3004,32 @@ static int bcm4320b_early_init(struct usbnet *usbdev) priv->param_workaround_interval = 500; else priv->param_workaround_interval = modparam_workaround_interval; +} + +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); + + /* bcm4320a doesn't handle configuration parameters well. Try + * set any and you get partially zeroed mac and broken device. + */ + + return 0; +} + +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); + + /* Early initialization settings, setting these won't have effect + * if called after generic_rndis_bind(). + */ rndis_set_config_parameter_str(usbdev, "Country", priv->param_country); rndis_set_config_parameter_str(usbdev, "FrameBursting", @@ -3142,7 +3059,6 @@ static const struct net_device_ops rndis_wlan_netdev_ops = { .ndo_set_multicast_list = rndis_wlan_set_multicast_list, }; - static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) { struct wiphy *wiphy; @@ -3167,7 +3083,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) * Otherwise we'll be in big trouble in rndis_wlan_early_init(). */ usbdev->driver_priv = priv; - usbdev->net->wireless_handlers = &rndis_iw_handlers; priv->usbdev = usbdev; mutex_init(&priv->command_lock); @@ -3175,7 +3090,7 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); INIT_WORK(&priv->work, rndis_wlan_worker); - INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats); + INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller); INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); /* try bind rndis_host */ @@ -3215,7 +3130,7 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) wiphy->max_scan_ssids = 1; /* TODO: fill-out band/encr information based on priv->caps */ - rndis_wlan_get_caps(usbdev); + rndis_wlan_get_caps(usbdev, wiphy); memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); @@ -3245,14 +3160,14 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD); /* turn radio on */ - priv->radio_on = 1; - disassociate(usbdev, 1); + priv->radio_on = true; + disassociate(usbdev, true); netif_carrier_off(usbdev->net); return 0; fail: - cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->dev_poller_work); cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); @@ -3262,64 +3177,58 @@ fail: return retval; } - static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* turn radio off */ - disassociate(usbdev, 0); + disassociate(usbdev, false); - cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->dev_poller_work); cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue); - if (priv && priv->wpa_ie_len) - kfree(priv->wpa_ie); - rndis_unbind(usbdev, intf); wiphy_unregister(priv->wdev.wiphy); wiphy_free(priv->wdev.wiphy); } - static int rndis_wlan_reset(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int retval; - devdbg(usbdev, "rndis_wlan_reset"); + netdev_dbg(usbdev->net, "%s()\n", __func__); retval = rndis_reset(usbdev); if (retval) - devwarn(usbdev, "rndis_reset() failed: %d", retval); + netdev_warn(usbdev->net, "rndis_reset failed: %d\n", retval); /* rndis_reset cleared multicast list, so restore here. (set_multicast_list() also turns on current packet filter) */ set_multicast_list(usbdev); - queue_delayed_work(priv->workqueue, &priv->stats_work, - round_jiffies_relative(STATS_UPDATE_JIFFIES)); + queue_delayed_work(priv->workqueue, &priv->dev_poller_work, + round_jiffies_relative(DEVICE_POLLER_JIFFIES)); return deauthenticate(usbdev); } - static int rndis_wlan_stop(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int retval; __le32 filter; - devdbg(usbdev, "rndis_wlan_stop"); + netdev_dbg(usbdev->net, "%s()\n", __func__); - retval = disassociate(usbdev, 0); + retval = disassociate(usbdev, false); priv->work_pending = 0; - cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->dev_poller_work); cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); @@ -3338,7 +3247,6 @@ static int rndis_wlan_stop(struct usbnet *usbdev) return retval; } - static const struct driver_info bcm4320b_info = { .description = "Wireless RNDIS device, BCM4320b based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |