diff options
author | Arend van Spriel <arend@broadcom.com> | 2012-10-22 16:55:30 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-10-29 15:28:43 -0400 |
commit | 3eacf866559c3d2062690bab8bf09f15f963fb16 (patch) | |
tree | 4ae1a95e5968fdce933fee891cefd20fbe9d84bf | |
parent | ec6de0ed3ecfab6acfa11c32f9acc9b3c6a5adc7 (diff) |
brcmfmac: introduce brcmf_cfg80211_vif structure
This patch introduces the brcmf_cfg80211_vif structure which is
used to keep track of multiple virtual interfaces in the driver.
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Franky Lin <frankyl@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 147 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | 39 |
3 files changed, 129 insertions, 62 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index bde5e253e0ed..8704daa2758f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h | |||
@@ -682,10 +682,14 @@ struct brcmf_if_event { | |||
682 | u8 bssidx; | 682 | u8 bssidx; |
683 | }; | 683 | }; |
684 | 684 | ||
685 | /* forward declaration */ | ||
686 | struct brcmf_cfg80211_vif; | ||
687 | |||
685 | /** | 688 | /** |
686 | * struct brcmf_if - interface control information. | 689 | * struct brcmf_if - interface control information. |
687 | * | 690 | * |
688 | * @drvr: points to device related information. | 691 | * @drvr: points to device related information. |
692 | * @vif: points to cfg80211 specific interface information. | ||
689 | * @ndev: associated network device. | 693 | * @ndev: associated network device. |
690 | * @stats: interface specific network statistics. | 694 | * @stats: interface specific network statistics. |
691 | * @idx: interface index in device firmware. | 695 | * @idx: interface index in device firmware. |
@@ -694,6 +698,7 @@ struct brcmf_if_event { | |||
694 | */ | 698 | */ |
695 | struct brcmf_if { | 699 | struct brcmf_if { |
696 | struct brcmf_pub *drvr; | 700 | struct brcmf_pub *drvr; |
701 | struct brcmf_cfg80211_vif *vif; | ||
697 | struct net_device *ndev; | 702 | struct net_device *ndev; |
698 | struct net_device_stats stats; | 703 | struct net_device_stats stats; |
699 | int idx; | 704 | int idx; |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 069a4e468120..21d6ab358c81 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | |||
@@ -49,6 +49,8 @@ | |||
49 | #define BRCMF_PNO_SCAN_COMPLETE 1 | 49 | #define BRCMF_PNO_SCAN_COMPLETE 1 |
50 | #define BRCMF_PNO_SCAN_INCOMPLETE 0 | 50 | #define BRCMF_PNO_SCAN_INCOMPLETE 0 |
51 | 51 | ||
52 | #define BRCMF_IFACE_MAX_CNT 2 | ||
53 | |||
52 | #define TLV_LEN_OFF 1 /* length offset */ | 54 | #define TLV_LEN_OFF 1 /* length offset */ |
53 | #define TLV_HDR_LEN 2 /* header length */ | 55 | #define TLV_HDR_LEN 2 /* header length */ |
54 | #define TLV_BODY_OFF 2 /* body offset */ | 56 | #define TLV_BODY_OFF 2 /* body offset */ |
@@ -3441,7 +3443,7 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, | |||
3441 | static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) | 3443 | static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) |
3442 | { | 3444 | { |
3443 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | 3445 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); |
3444 | struct net_device *ndev = cfg->wdev->netdev; | 3446 | struct net_device *ndev = cfg_to_ndev(cfg); |
3445 | struct brcmf_dcmd *dcmd = data; | 3447 | struct brcmf_dcmd *dcmd = data; |
3446 | struct sk_buff *reply; | 3448 | struct sk_buff *reply; |
3447 | int ret; | 3449 | int ret; |
@@ -4194,72 +4196,95 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy) | |||
4194 | #endif | 4196 | #endif |
4195 | } | 4197 | } |
4196 | 4198 | ||
4197 | static struct wireless_dev *brcmf_alloc_wdev(struct device *ndev) | 4199 | static struct wiphy *brcmf_setup_wiphy(struct device *phydev) |
4198 | { | 4200 | { |
4199 | struct wireless_dev *wdev; | 4201 | struct wiphy *wiphy; |
4200 | s32 err = 0; | 4202 | s32 err = 0; |
4201 | 4203 | ||
4202 | wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); | 4204 | wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info)); |
4203 | if (!wdev) | 4205 | if (!wiphy) { |
4204 | return ERR_PTR(-ENOMEM); | ||
4205 | |||
4206 | wdev->wiphy = wiphy_new(&wl_cfg80211_ops, | ||
4207 | sizeof(struct brcmf_cfg80211_info)); | ||
4208 | if (!wdev->wiphy) { | ||
4209 | WL_ERR("Could not allocate wiphy device\n"); | 4206 | WL_ERR("Could not allocate wiphy device\n"); |
4210 | err = -ENOMEM; | 4207 | return ERR_PTR(-ENOMEM); |
4211 | goto wiphy_new_out; | 4208 | } |
4212 | } | 4209 | set_wiphy_dev(wiphy, phydev); |
4213 | set_wiphy_dev(wdev->wiphy, ndev); | 4210 | wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; |
4214 | wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; | 4211 | wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; |
4215 | wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; | 4212 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
4216 | wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 4213 | BIT(NL80211_IFTYPE_ADHOC) | |
4217 | BIT(NL80211_IFTYPE_ADHOC) | | 4214 | BIT(NL80211_IFTYPE_AP); |
4218 | BIT(NL80211_IFTYPE_AP); | 4215 | wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; |
4219 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; | 4216 | wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set |
4220 | wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set | ||
4221 | * it as 11a by default. | 4217 | * it as 11a by default. |
4222 | * This will be updated with | 4218 | * This will be updated with |
4223 | * 11n phy tables in | 4219 | * 11n phy tables in |
4224 | * "ifconfig up" | 4220 | * "ifconfig up" |
4225 | * if phy has 11n capability | 4221 | * if phy has 11n capability |
4226 | */ | 4222 | */ |
4227 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 4223 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
4228 | wdev->wiphy->cipher_suites = __wl_cipher_suites; | 4224 | wiphy->cipher_suites = __wl_cipher_suites; |
4229 | wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); | 4225 | wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); |
4230 | wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power | 4226 | wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power |
4231 | * save mode | 4227 | * save mode |
4232 | * by default | 4228 | * by default |
4233 | */ | 4229 | */ |
4234 | brcmf_wiphy_pno_params(wdev->wiphy); | 4230 | brcmf_wiphy_pno_params(wiphy); |
4235 | err = wiphy_register(wdev->wiphy); | 4231 | err = wiphy_register(wiphy); |
4236 | if (err < 0) { | 4232 | if (err < 0) { |
4237 | WL_ERR("Could not register wiphy device (%d)\n", err); | 4233 | WL_ERR("Could not register wiphy device (%d)\n", err); |
4238 | goto wiphy_register_out; | 4234 | wiphy_free(wiphy); |
4235 | return ERR_PTR(err); | ||
4239 | } | 4236 | } |
4240 | return wdev; | 4237 | return wiphy; |
4238 | } | ||
4239 | |||
4240 | static | ||
4241 | struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | ||
4242 | struct net_device *netdev, | ||
4243 | s32 mode, bool pm_block) | ||
4244 | { | ||
4245 | struct brcmf_cfg80211_vif *vif; | ||
4246 | |||
4247 | if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT) | ||
4248 | return ERR_PTR(-ENOSPC); | ||
4249 | |||
4250 | vif = kzalloc(sizeof(*vif), GFP_KERNEL); | ||
4251 | if (!vif) | ||
4252 | return ERR_PTR(-ENOMEM); | ||
4241 | 4253 | ||
4242 | wiphy_register_out: | 4254 | vif->wdev.wiphy = cfg->wiphy; |
4243 | wiphy_free(wdev->wiphy); | 4255 | vif->wdev.netdev = netdev; |
4256 | vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode); | ||
4244 | 4257 | ||
4245 | wiphy_new_out: | 4258 | if (netdev) { |
4246 | kfree(wdev); | 4259 | vif->ifp = netdev_priv(netdev); |
4260 | netdev->ieee80211_ptr = &vif->wdev; | ||
4261 | SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy)); | ||
4262 | } | ||
4263 | |||
4264 | vif->mode = mode; | ||
4265 | vif->pm_block = pm_block; | ||
4266 | vif->roam_off = -1; | ||
4247 | 4267 | ||
4248 | return ERR_PTR(err); | 4268 | list_add_tail(&vif->list, &cfg->vif_list); |
4269 | cfg->vif_cnt++; | ||
4270 | return vif; | ||
4249 | } | 4271 | } |
4250 | 4272 | ||
4251 | static void brcmf_free_wdev(struct brcmf_cfg80211_info *cfg) | 4273 | static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) |
4252 | { | 4274 | { |
4253 | struct wireless_dev *wdev = cfg->wdev; | 4275 | struct brcmf_cfg80211_info *cfg; |
4276 | struct wiphy *wiphy; | ||
4254 | 4277 | ||
4255 | if (!wdev) { | 4278 | wiphy = vif->wdev.wiphy; |
4256 | WL_ERR("wdev is invalid\n"); | 4279 | cfg = wiphy_priv(wiphy); |
4257 | return; | 4280 | list_del(&vif->list); |
4281 | cfg->vif_cnt--; | ||
4282 | |||
4283 | kfree(vif); | ||
4284 | if (!cfg->vif_cnt) { | ||
4285 | wiphy_unregister(wiphy); | ||
4286 | wiphy_free(wiphy); | ||
4258 | } | 4287 | } |
4259 | wiphy_unregister(wdev->wiphy); | ||
4260 | wiphy_free(wdev->wiphy); | ||
4261 | kfree(wdev); | ||
4262 | cfg->wdev = NULL; | ||
4263 | } | 4288 | } |
4264 | 4289 | ||
4265 | static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg, | 4290 | static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg, |
@@ -4935,8 +4960,10 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr) | |||
4935 | { | 4960 | { |
4936 | struct net_device *ndev = drvr->iflist[0]->ndev; | 4961 | struct net_device *ndev = drvr->iflist[0]->ndev; |
4937 | struct device *busdev = drvr->dev; | 4962 | struct device *busdev = drvr->dev; |
4938 | struct wireless_dev *wdev; | ||
4939 | struct brcmf_cfg80211_info *cfg; | 4963 | struct brcmf_cfg80211_info *cfg; |
4964 | struct wiphy *wiphy; | ||
4965 | struct brcmf_cfg80211_vif *vif; | ||
4966 | struct brcmf_if *ifp; | ||
4940 | s32 err = 0; | 4967 | s32 err = 0; |
4941 | 4968 | ||
4942 | if (!ndev) { | 4969 | if (!ndev) { |
@@ -4944,35 +4971,45 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr) | |||
4944 | return NULL; | 4971 | return NULL; |
4945 | } | 4972 | } |
4946 | 4973 | ||
4947 | wdev = brcmf_alloc_wdev(busdev); | 4974 | ifp = netdev_priv(ndev); |
4948 | if (IS_ERR(wdev)) { | 4975 | wiphy = brcmf_setup_wiphy(busdev); |
4976 | if (IS_ERR(wiphy)) | ||
4949 | return NULL; | 4977 | return NULL; |
4950 | } | ||
4951 | 4978 | ||
4952 | wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); | 4979 | cfg = wiphy_priv(wiphy); |
4953 | cfg = wdev_to_cfg(wdev); | 4980 | cfg->wiphy = wiphy; |
4954 | cfg->wdev = wdev; | ||
4955 | cfg->pub = drvr; | 4981 | cfg->pub = drvr; |
4956 | ndev->ieee80211_ptr = wdev; | 4982 | INIT_LIST_HEAD(&cfg->vif_list); |
4957 | SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); | 4983 | |
4958 | wdev->netdev = ndev; | 4984 | vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false); |
4985 | if (IS_ERR(vif)) { | ||
4986 | wiphy_free(wiphy); | ||
4987 | return NULL; | ||
4988 | } | ||
4989 | |||
4959 | err = wl_init_priv(cfg); | 4990 | err = wl_init_priv(cfg); |
4960 | if (err) { | 4991 | if (err) { |
4961 | WL_ERR("Failed to init iwm_priv (%d)\n", err); | 4992 | WL_ERR("Failed to init iwm_priv (%d)\n", err); |
4962 | goto cfg80211_attach_out; | 4993 | goto cfg80211_attach_out; |
4963 | } | 4994 | } |
4964 | 4995 | ||
4996 | ifp->vif = vif; | ||
4965 | return cfg; | 4997 | return cfg; |
4966 | 4998 | ||
4967 | cfg80211_attach_out: | 4999 | cfg80211_attach_out: |
4968 | brcmf_free_wdev(cfg); | 5000 | brcmf_free_vif(vif); |
4969 | return NULL; | 5001 | return NULL; |
4970 | } | 5002 | } |
4971 | 5003 | ||
4972 | void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) | 5004 | void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) |
4973 | { | 5005 | { |
5006 | struct brcmf_cfg80211_vif *vif; | ||
5007 | struct brcmf_cfg80211_vif *tmp; | ||
5008 | |||
4974 | wl_deinit_priv(cfg); | 5009 | wl_deinit_priv(cfg); |
4975 | brcmf_free_wdev(cfg); | 5010 | list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) { |
5011 | brcmf_free_vif(vif); | ||
5012 | } | ||
4976 | } | 5013 | } |
4977 | 5014 | ||
4978 | void | 5015 | void |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 191262578e02..6644ea85f07f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | |||
@@ -235,6 +235,25 @@ struct brcmf_cfg80211_profile { | |||
235 | s32 band; | 235 | s32 band; |
236 | }; | 236 | }; |
237 | 237 | ||
238 | /** | ||
239 | * struct brcmf_cfg80211_vif - virtual interface specific information. | ||
240 | * | ||
241 | * @ifp: lower layer interface pointer | ||
242 | * @wdev: wireless device. | ||
243 | * @mode: operating mode. | ||
244 | * @roam_off: roaming state. | ||
245 | * @pm_block: power-management blocked. | ||
246 | * @list: linked list. | ||
247 | */ | ||
248 | struct brcmf_cfg80211_vif { | ||
249 | struct brcmf_if *ifp; | ||
250 | struct wireless_dev wdev; | ||
251 | s32 mode; | ||
252 | s32 roam_off; | ||
253 | bool pm_block; | ||
254 | struct list_head list; | ||
255 | }; | ||
256 | |||
238 | /* dongle iscan event loop */ | 257 | /* dongle iscan event loop */ |
239 | struct brcmf_cfg80211_iscan_eloop { | 258 | struct brcmf_cfg80211_iscan_eloop { |
240 | s32 (*handler[WL_SCAN_ERSULTS_LAST]) | 259 | s32 (*handler[WL_SCAN_ERSULTS_LAST]) |
@@ -383,7 +402,7 @@ struct brcmf_pno_scanresults_le { | |||
383 | /** | 402 | /** |
384 | * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface | 403 | * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface |
385 | * | 404 | * |
386 | * @wdev: representing wl cfg80211 device. | 405 | * @wiphy: wiphy object for cfg80211 interface. |
387 | * @conf: dongle configuration. | 406 | * @conf: dongle configuration. |
388 | * @scan_request: cfg80211 scan request object. | 407 | * @scan_request: cfg80211 scan request object. |
389 | * @el: main event loop. | 408 | * @el: main event loop. |
@@ -422,10 +441,11 @@ struct brcmf_pno_scanresults_le { | |||
422 | * @escan_timeout_work: scan timeout worker. | 441 | * @escan_timeout_work: scan timeout worker. |
423 | * @escan_ioctl_buf: dongle command buffer for escan commands. | 442 | * @escan_ioctl_buf: dongle command buffer for escan commands. |
424 | * @ap_info: host ap information. | 443 | * @ap_info: host ap information. |
425 | * @ci: used to link this structure to netdev private data. | 444 | * @vif_list: linked list of vif instances. |
445 | * @vif_cnt: number of vif instances. | ||
426 | */ | 446 | */ |
427 | struct brcmf_cfg80211_info { | 447 | struct brcmf_cfg80211_info { |
428 | struct wireless_dev *wdev; | 448 | struct wiphy *wiphy; |
429 | struct brcmf_cfg80211_conf *conf; | 449 | struct brcmf_cfg80211_conf *conf; |
430 | struct cfg80211_scan_request *scan_request; | 450 | struct cfg80211_scan_request *scan_request; |
431 | struct brcmf_cfg80211_event_loop el; | 451 | struct brcmf_cfg80211_event_loop el; |
@@ -464,11 +484,13 @@ struct brcmf_cfg80211_info { | |||
464 | struct work_struct escan_timeout_work; | 484 | struct work_struct escan_timeout_work; |
465 | u8 *escan_ioctl_buf; | 485 | u8 *escan_ioctl_buf; |
466 | struct ap_info *ap_info; | 486 | struct ap_info *ap_info; |
487 | struct list_head vif_list; | ||
488 | u8 vif_cnt; | ||
467 | }; | 489 | }; |
468 | 490 | ||
469 | static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *w) | 491 | static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg) |
470 | { | 492 | { |
471 | return w->wdev->wiphy; | 493 | return cfg->wiphy; |
472 | } | 494 | } |
473 | 495 | ||
474 | static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w) | 496 | static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w) |
@@ -481,9 +503,12 @@ static inline struct brcmf_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd) | |||
481 | return (struct brcmf_cfg80211_info *)(wdev_priv(wd)); | 503 | return (struct brcmf_cfg80211_info *)(wdev_priv(wd)); |
482 | } | 504 | } |
483 | 505 | ||
484 | static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg) | 506 | static inline |
507 | struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg) | ||
485 | { | 508 | { |
486 | return cfg->wdev->netdev; | 509 | struct brcmf_cfg80211_vif *vif; |
510 | vif = list_first_entry(&cfg->vif_list, struct brcmf_cfg80211_vif, list); | ||
511 | return vif->wdev.netdev; | ||
487 | } | 512 | } |
488 | 513 | ||
489 | static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev) | 514 | static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev) |