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 | |
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')
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 123 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/core.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/init.c | 10 |
4 files changed, 133 insertions, 6 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); |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 66042f2e7adb..d1a0216d7cf9 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, | 20 | struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, |
21 | enum nl80211_iftype type, | 21 | enum nl80211_iftype type, |
22 | u8 fw_vif_idx); | 22 | u8 fw_vif_idx, u8 nw_type); |
23 | int ath6kl_register_ieee80211_hw(struct ath6kl *ar); | 23 | int ath6kl_register_ieee80211_hw(struct ath6kl *ar); |
24 | struct ath6kl *ath6kl_core_alloc(struct device *dev); | 24 | struct ath6kl *ath6kl_core_alloc(struct device *dev); |
25 | void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar); | 25 | void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar); |
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 29bb2357a5cc..6933fb62ac46 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
@@ -460,6 +460,8 @@ struct ath6kl { | |||
460 | struct list_head vif_list; | 460 | struct list_head vif_list; |
461 | /* Lock to avoid race in vif_list entries among add/del/traverse */ | 461 | /* Lock to avoid race in vif_list entries among add/del/traverse */ |
462 | spinlock_t list_lock; | 462 | spinlock_t list_lock; |
463 | u8 num_vif; | ||
464 | u8 avail_idx_map; | ||
463 | spinlock_t lock; | 465 | spinlock_t lock; |
464 | struct semaphore sem; | 466 | struct semaphore sem; |
465 | u16 listen_intvl_b; | 467 | u16 listen_intvl_b; |
@@ -470,6 +472,7 @@ struct ath6kl { | |||
470 | u8 tx_pwr; | 472 | u8 tx_pwr; |
471 | struct ath6kl_node_mapping node_map[MAX_NODE_NUM]; | 473 | struct ath6kl_node_mapping node_map[MAX_NODE_NUM]; |
472 | u8 ibss_ps_enable; | 474 | u8 ibss_ps_enable; |
475 | bool ibss_if_active; | ||
473 | u8 node_num; | 476 | u8 node_num; |
474 | u8 next_ep_id; | 477 | u8 next_ep_id; |
475 | struct ath6kl_cookie *cookie_list; | 478 | struct ath6kl_cookie *cookie_list; |
@@ -666,4 +669,5 @@ void ath6kl_init_control_info(struct ath6kl_vif *vif); | |||
666 | void ath6kl_deinit_if_data(struct ath6kl_vif *vif); | 669 | void ath6kl_deinit_if_data(struct ath6kl_vif *vif); |
667 | void ath6kl_core_free(struct ath6kl *ar); | 670 | void ath6kl_core_free(struct ath6kl *ar); |
668 | struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); | 671 | struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); |
672 | void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready); | ||
669 | #endif /* CORE_H */ | 673 | #endif /* CORE_H */ |
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 60dbf721eb87..ce34fff605ad 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c | |||
@@ -88,7 +88,6 @@ void ath6kl_init_profile_info(struct ath6kl_vif *vif) | |||
88 | memset(vif->req_bssid, 0, sizeof(vif->req_bssid)); | 88 | memset(vif->req_bssid, 0, sizeof(vif->req_bssid)); |
89 | memset(vif->bssid, 0, sizeof(vif->bssid)); | 89 | memset(vif->bssid, 0, sizeof(vif->bssid)); |
90 | vif->bss_ch = 0; | 90 | vif->bss_ch = 0; |
91 | vif->nw_type = vif->next_mode = INFRA_NETWORK; | ||
92 | } | 91 | } |
93 | 92 | ||
94 | static int ath6kl_set_host_app_area(struct ath6kl *ar) | 93 | static int ath6kl_set_host_app_area(struct ath6kl *ar) |
@@ -1414,6 +1413,7 @@ static int ath6kl_init(struct ath6kl *ar) | |||
1414 | int status = 0; | 1413 | int status = 0; |
1415 | s32 timeleft; | 1414 | s32 timeleft; |
1416 | struct net_device *ndev; | 1415 | struct net_device *ndev; |
1416 | int i; | ||
1417 | 1417 | ||
1418 | if (!ar) | 1418 | if (!ar) |
1419 | return -EIO; | 1419 | return -EIO; |
@@ -1445,10 +1445,14 @@ static int ath6kl_init(struct ath6kl *ar) | |||
1445 | goto err_node_cleanup; | 1445 | goto err_node_cleanup; |
1446 | } | 1446 | } |
1447 | 1447 | ||
1448 | for (i = 0; i < MAX_NUM_VIF; i++) | ||
1449 | ar->avail_idx_map |= BIT(i); | ||
1450 | |||
1448 | rtnl_lock(); | 1451 | rtnl_lock(); |
1449 | 1452 | ||
1450 | /* Add an initial station interface */ | 1453 | /* Add an initial station interface */ |
1451 | ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0); | 1454 | ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, |
1455 | INFRA_NETWORK); | ||
1452 | 1456 | ||
1453 | rtnl_unlock(); | 1457 | rtnl_unlock(); |
1454 | 1458 | ||
@@ -1632,7 +1636,7 @@ err_wq: | |||
1632 | return ret; | 1636 | return ret; |
1633 | } | 1637 | } |
1634 | 1638 | ||
1635 | static void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) | 1639 | void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) |
1636 | { | 1640 | { |
1637 | static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 1641 | static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
1638 | bool discon_issued; | 1642 | bool discon_issued; |