diff options
author | Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com> | 2011-10-25 10:04:23 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2011-11-11 05:58:52 -0500 |
commit | 55055976fe15f450aded0a6f2ed2996411bd3e2e (patch) | |
tree | 743d1c5def29c9081c4abfa1862c01d21bf1af7f /drivers/net/wireless/ath/ath6kl/cfg80211.c | |
parent | 7b85832dfbfaf09e793755041302d9e6d67cd39e (diff) |
ath6kl: Implement add_virtual_intf() and del_virtual_intf()
Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/cfg80211.c')
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 123 |
1 files changed, 121 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 893bd2c30720..87ede6265788 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -293,6 +293,57 @@ static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies, | |||
293 | return ret; | 293 | return ret; |
294 | } | 294 | } |
295 | 295 | ||
296 | static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type) | ||
297 | { | ||
298 | switch (type) { | ||
299 | case NL80211_IFTYPE_STATION: | ||
300 | *nw_type = INFRA_NETWORK; | ||
301 | break; | ||
302 | case NL80211_IFTYPE_ADHOC: | ||
303 | *nw_type = ADHOC_NETWORK; | ||
304 | break; | ||
305 | case NL80211_IFTYPE_AP: | ||
306 | *nw_type = AP_NETWORK; | ||
307 | break; | ||
308 | case NL80211_IFTYPE_P2P_CLIENT: | ||
309 | *nw_type = INFRA_NETWORK; | ||
310 | break; | ||
311 | case NL80211_IFTYPE_P2P_GO: | ||
312 | *nw_type = AP_NETWORK; | ||
313 | break; | ||
314 | default: | ||
315 | ath6kl_err("invalid interface type %u\n", type); | ||
316 | return -ENOTSUPP; | ||
317 | } | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, | ||
323 | u8 *if_idx, u8 *nw_type) | ||
324 | { | ||
325 | int i; | ||
326 | |||
327 | if (ath6kl_nliftype_to_drv_iftype(type, nw_type)) | ||
328 | return false; | ||
329 | |||
330 | if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) && | ||
331 | ar->num_vif)) | ||
332 | return false; | ||
333 | |||
334 | if (type == NL80211_IFTYPE_STATION || | ||
335 | type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) { | ||
336 | for (i = 0; i < MAX_NUM_VIF; i++) { | ||
337 | if ((ar->avail_idx_map >> i) & BIT(0)) { | ||
338 | *if_idx = i; | ||
339 | return true; | ||
340 | } | ||
341 | } | ||
342 | } | ||
343 | |||
344 | return false; | ||
345 | } | ||
346 | |||
296 | static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | 347 | static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, |
297 | struct cfg80211_connect_params *sme) | 348 | struct cfg80211_connect_params *sme) |
298 | { | 349 | { |
@@ -1206,6 +1257,52 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, | |||
1206 | return 0; | 1257 | return 0; |
1207 | } | 1258 | } |
1208 | 1259 | ||
1260 | static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, | ||
1261 | char *name, | ||
1262 | enum nl80211_iftype type, | ||
1263 | u32 *flags, | ||
1264 | struct vif_params *params) | ||
1265 | { | ||
1266 | struct ath6kl *ar = wiphy_priv(wiphy); | ||
1267 | struct net_device *ndev; | ||
1268 | u8 if_idx, nw_type; | ||
1269 | |||
1270 | if (ar->num_vif == MAX_NUM_VIF) { | ||
1271 | ath6kl_err("Reached maximum number of supported vif\n"); | ||
1272 | return ERR_PTR(-EINVAL); | ||
1273 | } | ||
1274 | |||
1275 | if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) { | ||
1276 | ath6kl_err("Not a supported interface type\n"); | ||
1277 | return ERR_PTR(-EINVAL); | ||
1278 | } | ||
1279 | |||
1280 | ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type); | ||
1281 | if (!ndev) | ||
1282 | return ERR_PTR(-ENOMEM); | ||
1283 | |||
1284 | ar->num_vif++; | ||
1285 | |||
1286 | return ndev; | ||
1287 | } | ||
1288 | |||
1289 | static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, | ||
1290 | struct net_device *ndev) | ||
1291 | { | ||
1292 | struct ath6kl *ar = wiphy_priv(wiphy); | ||
1293 | struct ath6kl_vif *vif = netdev_priv(ndev); | ||
1294 | |||
1295 | spin_lock(&ar->list_lock); | ||
1296 | list_del(&vif->list); | ||
1297 | spin_unlock(&ar->list_lock); | ||
1298 | |||
1299 | ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); | ||
1300 | |||
1301 | ath6kl_deinit_if_data(vif); | ||
1302 | |||
1303 | return 0; | ||
1304 | } | ||
1305 | |||
1209 | static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, | 1306 | static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, |
1210 | struct net_device *ndev, | 1307 | struct net_device *ndev, |
1211 | enum nl80211_iftype type, u32 *flags, | 1308 | enum nl80211_iftype type, u32 *flags, |
@@ -1947,6 +2044,8 @@ ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { | |||
1947 | }; | 2044 | }; |
1948 | 2045 | ||
1949 | static struct cfg80211_ops ath6kl_cfg80211_ops = { | 2046 | static struct cfg80211_ops ath6kl_cfg80211_ops = { |
2047 | .add_virtual_intf = ath6kl_cfg80211_add_iface, | ||
2048 | .del_virtual_intf = ath6kl_cfg80211_del_iface, | ||
1950 | .change_virtual_intf = ath6kl_cfg80211_change_iface, | 2049 | .change_virtual_intf = ath6kl_cfg80211_change_iface, |
1951 | .scan = ath6kl_cfg80211_scan, | 2050 | .scan = ath6kl_cfg80211_scan, |
1952 | .connect = ath6kl_cfg80211_connect, | 2051 | .connect = ath6kl_cfg80211_connect, |
@@ -2097,18 +2196,28 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif) | |||
2097 | 2196 | ||
2098 | void ath6kl_deinit_if_data(struct ath6kl_vif *vif) | 2197 | void ath6kl_deinit_if_data(struct ath6kl_vif *vif) |
2099 | { | 2198 | { |
2199 | struct ath6kl *ar = vif->ar; | ||
2200 | |||
2100 | aggr_module_destroy(vif->aggr_cntxt); | 2201 | aggr_module_destroy(vif->aggr_cntxt); |
2101 | 2202 | ||
2203 | ar->avail_idx_map |= BIT(vif->fw_vif_idx); | ||
2204 | |||
2205 | if (vif->nw_type == ADHOC_NETWORK) | ||
2206 | ar->ibss_if_active = false; | ||
2207 | |||
2102 | unregister_netdevice(vif->ndev); | 2208 | unregister_netdevice(vif->ndev); |
2209 | |||
2210 | ar->num_vif--; | ||
2103 | } | 2211 | } |
2104 | 2212 | ||
2105 | struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, | 2213 | struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, |
2106 | enum nl80211_iftype type, u8 fw_vif_idx) | 2214 | enum nl80211_iftype type, u8 fw_vif_idx, |
2215 | u8 nw_type) | ||
2107 | { | 2216 | { |
2108 | struct net_device *ndev; | 2217 | struct net_device *ndev; |
2109 | struct ath6kl_vif *vif; | 2218 | struct ath6kl_vif *vif; |
2110 | 2219 | ||
2111 | ndev = alloc_netdev(sizeof(*vif), "wlan%d", ether_setup); | 2220 | ndev = alloc_netdev(sizeof(*vif), name, ether_setup); |
2112 | if (!ndev) | 2221 | if (!ndev) |
2113 | return NULL; | 2222 | return NULL; |
2114 | 2223 | ||
@@ -2121,8 +2230,14 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, | |||
2121 | vif->wdev.netdev = ndev; | 2230 | vif->wdev.netdev = ndev; |
2122 | vif->wdev.iftype = type; | 2231 | vif->wdev.iftype = type; |
2123 | vif->fw_vif_idx = fw_vif_idx; | 2232 | vif->fw_vif_idx = fw_vif_idx; |
2233 | vif->nw_type = vif->next_mode = nw_type; | ||
2124 | ar->wdev = &vif->wdev; | 2234 | ar->wdev = &vif->wdev; |
2125 | 2235 | ||
2236 | memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); | ||
2237 | if (fw_vif_idx != 0) | ||
2238 | ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) | | ||
2239 | 0x2; | ||
2240 | |||
2126 | init_netdev(ndev); | 2241 | init_netdev(ndev); |
2127 | 2242 | ||
2128 | ath6kl_init_control_info(vif); | 2243 | ath6kl_init_control_info(vif); |
@@ -2134,11 +2249,15 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, | |||
2134 | if (register_netdevice(ndev)) | 2249 | if (register_netdevice(ndev)) |
2135 | goto err; | 2250 | goto err; |
2136 | 2251 | ||
2252 | ar->avail_idx_map &= ~BIT(fw_vif_idx); | ||
2137 | vif->sme_state = SME_DISCONNECTED; | 2253 | vif->sme_state = SME_DISCONNECTED; |
2138 | set_bit(WLAN_ENABLED, &vif->flags); | 2254 | set_bit(WLAN_ENABLED, &vif->flags); |
2139 | ar->wlan_pwr_state = WLAN_POWER_STATE_ON; | 2255 | ar->wlan_pwr_state = WLAN_POWER_STATE_ON; |
2140 | set_bit(NETDEV_REGISTERED, &vif->flags); | 2256 | set_bit(NETDEV_REGISTERED, &vif->flags); |
2141 | 2257 | ||
2258 | if (type == NL80211_IFTYPE_ADHOC) | ||
2259 | ar->ibss_if_active = true; | ||
2260 | |||
2142 | spin_lock(&ar->list_lock); | 2261 | spin_lock(&ar->list_lock); |
2143 | list_add_tail(&vif->list, &ar->vif_list); | 2262 | list_add_tail(&vif->list, &ar->vif_list); |
2144 | spin_unlock(&ar->list_lock); | 2263 | spin_unlock(&ar->list_lock); |