aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath6kl
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>2011-10-25 10:04:23 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2011-11-11 05:58:52 -0500
commit55055976fe15f450aded0a6f2ed2996411bd3e2e (patch)
tree743d1c5def29c9081c4abfa1862c01d21bf1af7f /drivers/net/wireless/ath/ath6kl
parent7b85832dfbfaf09e793755041302d9e6d67cd39e (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.c123
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.h2
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h4
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c10
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
296static 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
322static 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
296static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, 347static 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
1260static 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
1289static 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
1209static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, 1306static 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
1949static struct cfg80211_ops ath6kl_cfg80211_ops = { 2046static 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
2098void ath6kl_deinit_if_data(struct ath6kl_vif *vif) 2197void 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
2105struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, 2213struct 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
20struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, 20struct 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);
23int ath6kl_register_ieee80211_hw(struct ath6kl *ar); 23int ath6kl_register_ieee80211_hw(struct ath6kl *ar);
24struct ath6kl *ath6kl_core_alloc(struct device *dev); 24struct ath6kl *ath6kl_core_alloc(struct device *dev);
25void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar); 25void 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);
666void ath6kl_deinit_if_data(struct ath6kl_vif *vif); 669void ath6kl_deinit_if_data(struct ath6kl_vif *vif);
667void ath6kl_core_free(struct ath6kl *ar); 670void ath6kl_core_free(struct ath6kl *ar);
668struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); 671struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar);
672void 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
94static int ath6kl_set_host_app_area(struct ath6kl *ar) 93static 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
1635static void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) 1639void 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;