aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2013-02-08 09:53:41 -0500
committerJohn W. Linville <linville@tuxdriver.com>2013-02-08 14:51:38 -0500
commit5f4f9f114eef4907b6077d19dd5ad7d0a27e0f80 (patch)
tree1984c32c530311db1eed82680220f5ced7701c11
parentde66efcadbb51935c8c668a38f2f1c187f349af9 (diff)
brcmfmac: implement support for deleting virtual interfaces
Deletion of the virtual interface was not fully supported so adding it now. Tested using p2p_connect command in wpa_supplicant. Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c64
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c199
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h4
4 files changed, 176 insertions, 92 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index 82724d371dd0..c4f30bd014dd 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -150,6 +150,7 @@
150#define BRCMF_E_REASON_MINTXRATE 9 150#define BRCMF_E_REASON_MINTXRATE 9
151#define BRCMF_E_REASON_TXFAIL 10 151#define BRCMF_E_REASON_TXFAIL 10
152 152
153#define BRCMF_E_REASON_LINK_BSSCFG_DIS 4
153#define BRCMF_E_REASON_FAST_ROAM_FAILED 5 154#define BRCMF_E_REASON_FAST_ROAM_FAILED 5
154#define BRCMF_E_REASON_DIRECTED_ROAM 6 155#define BRCMF_E_REASON_DIRECTED_ROAM 6
155#define BRCMF_E_REASON_TSPEC_REJECTED 7 156#define BRCMF_E_REASON_TSPEC_REJECTED 7
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index cec4116379ea..fff5722d4c0b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -827,6 +827,26 @@ static int brcmf_p2p_request_p2p_if(struct brcmf_if *ifp, u8 ea[ETH_ALEN],
827 return err; 827 return err;
828} 828}
829 829
830static int brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif *vif)
831{
832 struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
833 struct net_device *pri_ndev = cfg_to_ndev(cfg);
834 struct brcmf_if *ifp = netdev_priv(pri_ndev);
835 u8 *addr = vif->wdev.netdev->dev_addr;
836
837 return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN);
838}
839
840static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif)
841{
842 struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
843 struct net_device *pri_ndev = cfg_to_ndev(cfg);
844 struct brcmf_if *ifp = netdev_priv(pri_ndev);
845 u8 *addr = vif->wdev.netdev->dev_addr;
846
847 return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN);
848}
849
830/** 850/**
831 * brcmf_p2p_add_vif() - create a new P2P virtual interface. 851 * brcmf_p2p_add_vif() - create a new P2P virtual interface.
832 * 852 *
@@ -910,23 +930,43 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
910{ 930{
911 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); 931 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
912 struct brcmf_cfg80211_vif *vif; 932 struct brcmf_cfg80211_vif *vif;
933 unsigned long jiffie_timeout = msecs_to_jiffies(1500);
934 bool wait_for_disable = false;
913 int err; 935 int err;
914 936
937 brcmf_dbg(TRACE, "delete P2P vif\n");
915 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); 938 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
916 939
917 if (brcmf_cfg80211_vif_event_armed(cfg)) 940 switch (vif->wdev.iftype) {
918 return -EBUSY; 941 case NL80211_IFTYPE_P2P_CLIENT:
942 if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state))
943 wait_for_disable = true;
944 break;
945
946 case NL80211_IFTYPE_P2P_GO:
947 if (!brcmf_p2p_disable_p2p_if(vif))
948 wait_for_disable = true;
949 break;
950
951 case NL80211_IFTYPE_P2P_DEVICE:
952 default:
953 return -ENOTSUPP;
954 break;
955 }
956
957 if (wait_for_disable)
958 wait_for_completion_timeout(&cfg->vif_disabled, 500);
959
960 brcmf_vif_clear_mgmt_ies(vif);
919 961
920 brcmf_cfg80211_arm_vif_event(cfg, vif); 962 brcmf_cfg80211_arm_vif_event(cfg, vif);
921 /* wait for firmware event */ 963 err = brcmf_p2p_release_p2p_if(vif);
922 err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL, 964 if (!err)
923 msecs_to_jiffies(1500)); 965 /* wait for firmware event */
966 err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL,
967 jiffie_timeout);
924 brcmf_cfg80211_arm_vif_event(cfg, NULL); 968 brcmf_cfg80211_arm_vif_event(cfg, NULL);
925 if (wdev->netdev) 969 brcmf_free_vif(vif);
926 brcmf_dbg(INFO, "deleting vif \"%s\"\n", wdev->netdev->name); 970
927 else 971 return err;
928 brcmf_dbg(INFO, "deleting vif \"wdev-%u\"\n",
929 wdev->identifier);
930 brcmf_err("enter - not supported yet\n");
931 return -EOPNOTSUPP;
932} 972}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 6cd47e28b016..d792c3b2331a 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -445,9 +445,103 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
445 } 445 }
446} 446}
447 447
448static void brcmf_set_mpc(struct net_device *ndev, int mpc)
449{
450 struct brcmf_if *ifp = netdev_priv(ndev);
451 s32 err = 0;
452
453 if (check_vif_up(ifp->vif)) {
454 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
455 if (err) {
456 brcmf_err("fail to set mpc\n");
457 return;
458 }
459 brcmf_dbg(INFO, "MPC : %d\n", mpc);
460 }
461}
462
463static s32
464brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
465 struct net_device *ndev,
466 bool aborted, bool fw_abort)
467{
468 struct brcmf_scan_params_le params_le;
469 struct cfg80211_scan_request *scan_request;
470 s32 err = 0;
471
472 brcmf_dbg(SCAN, "Enter\n");
473
474 /* clear scan request, because the FW abort can cause a second call */
475 /* to this functon and might cause a double cfg80211_scan_done */
476 scan_request = cfg->scan_request;
477 cfg->scan_request = NULL;
478
479 if (timer_pending(&cfg->escan_timeout))
480 del_timer_sync(&cfg->escan_timeout);
481
482 if (fw_abort) {
483 /* Do a scan abort to stop the driver's scan engine */
484 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
485 memset(&params_le, 0, sizeof(params_le));
486 memset(params_le.bssid, 0xFF, ETH_ALEN);
487 params_le.bss_type = DOT11_BSSTYPE_ANY;
488 params_le.scan_type = 0;
489 params_le.channel_num = cpu_to_le32(1);
490 params_le.nprobes = cpu_to_le32(1);
491 params_le.active_time = cpu_to_le32(-1);
492 params_le.passive_time = cpu_to_le32(-1);
493 params_le.home_time = cpu_to_le32(-1);
494 /* Scan is aborted by setting channel_list[0] to -1 */
495 params_le.channel_list[0] = cpu_to_le16(-1);
496 /* E-Scan (or anyother type) can be aborted by SCAN */
497 err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
498 &params_le, sizeof(params_le));
499 if (err)
500 brcmf_err("Scan abort failed\n");
501 }
502 /*
503 * e-scan can be initiated by scheduled scan
504 * which takes precedence.
505 */
506 if (cfg->sched_escan) {
507 brcmf_dbg(SCAN, "scheduled scan completed\n");
508 cfg->sched_escan = false;
509 if (!aborted)
510 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
511 brcmf_set_mpc(ndev, 1);
512 } else if (scan_request) {
513 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
514 aborted ? "Aborted" : "Done");
515 cfg80211_scan_done(scan_request, aborted);
516 brcmf_set_mpc(ndev, 1);
517 }
518 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
519 brcmf_err("Scan complete while device not scanning\n");
520 return -EPERM;
521 }
522
523 return err;
524}
525
448static 526static
449int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) 527int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
450{ 528{
529 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
530 struct net_device *ndev = wdev->netdev;
531
532 /* vif event pending in firmware */
533 if (brcmf_cfg80211_vif_event_armed(cfg))
534 return -EBUSY;
535
536 if (ndev) {
537 if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
538 cfg->escan_info.ndev == ndev)
539 brcmf_notify_escan_complete(cfg, ndev, true,
540 true);
541
542 brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
543 }
544
451 switch (wdev->iftype) { 545 switch (wdev->iftype) {
452 case NL80211_IFTYPE_ADHOC: 546 case NL80211_IFTYPE_ADHOC:
453 case NL80211_IFTYPE_STATION: 547 case NL80211_IFTYPE_STATION:
@@ -525,21 +619,6 @@ done:
525 return err; 619 return err;
526} 620}
527 621
528static void brcmf_set_mpc(struct net_device *ndev, int mpc)
529{
530 struct brcmf_if *ifp = netdev_priv(ndev);
531 s32 err = 0;
532
533 if (check_vif_up(ifp->vif)) {
534 err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
535 if (err) {
536 brcmf_err("fail to set mpc\n");
537 return;
538 }
539 brcmf_dbg(INFO, "MPC : %d\n", mpc);
540 }
541}
542
543static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, 622static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
544 struct cfg80211_scan_request *request) 623 struct cfg80211_scan_request *request)
545{ 624{
@@ -620,69 +699,6 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
620} 699}
621 700
622static s32 701static s32
623brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
624 struct net_device *ndev,
625 bool aborted, bool fw_abort)
626{
627 struct brcmf_scan_params_le params_le;
628 struct cfg80211_scan_request *scan_request;
629 s32 err = 0;
630
631 brcmf_dbg(SCAN, "Enter\n");
632
633 /* clear scan request, because the FW abort can cause a second call */
634 /* to this functon and might cause a double cfg80211_scan_done */
635 scan_request = cfg->scan_request;
636 cfg->scan_request = NULL;
637
638 if (timer_pending(&cfg->escan_timeout))
639 del_timer_sync(&cfg->escan_timeout);
640
641 if (fw_abort) {
642 /* Do a scan abort to stop the driver's scan engine */
643 brcmf_dbg(SCAN, "ABORT scan in firmware\n");
644 memset(&params_le, 0, sizeof(params_le));
645 memset(params_le.bssid, 0xFF, ETH_ALEN);
646 params_le.bss_type = DOT11_BSSTYPE_ANY;
647 params_le.scan_type = 0;
648 params_le.channel_num = cpu_to_le32(1);
649 params_le.nprobes = cpu_to_le32(1);
650 params_le.active_time = cpu_to_le32(-1);
651 params_le.passive_time = cpu_to_le32(-1);
652 params_le.home_time = cpu_to_le32(-1);
653 /* Scan is aborted by setting channel_list[0] to -1 */
654 params_le.channel_list[0] = cpu_to_le16(-1);
655 /* E-Scan (or anyother type) can be aborted by SCAN */
656 err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
657 &params_le, sizeof(params_le));
658 if (err)
659 brcmf_err("Scan abort failed\n");
660 }
661 /*
662 * e-scan can be initiated by scheduled scan
663 * which takes precedence.
664 */
665 if (cfg->sched_escan) {
666 brcmf_dbg(SCAN, "scheduled scan completed\n");
667 cfg->sched_escan = false;
668 if (!aborted)
669 cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
670 brcmf_set_mpc(ndev, 1);
671 } else if (scan_request) {
672 brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
673 aborted ? "Aborted" : "Done");
674 cfg80211_scan_done(scan_request, aborted);
675 brcmf_set_mpc(ndev, 1);
676 }
677 if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
678 brcmf_err("Scan complete while device not scanning\n");
679 return -EPERM;
680 }
681
682 return err;
683}
684
685static s32
686brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, 702brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
687 struct cfg80211_scan_request *request, u16 action) 703 struct cfg80211_scan_request *request, u16 action)
688{ 704{
@@ -3474,6 +3490,22 @@ exit:
3474 return err; 3490 return err;
3475} 3491}
3476 3492
3493s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
3494{
3495 s32 pktflags[] = {
3496 BRCMF_VNDR_IE_PRBREQ_FLAG,
3497 BRCMF_VNDR_IE_PRBRSP_FLAG,
3498 BRCMF_VNDR_IE_BEACON_FLAG
3499 };
3500 int i;
3501
3502 for (i = 0; i < ARRAY_SIZE(pktflags); i++)
3503 brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
3504
3505 memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
3506 return 0;
3507}
3508
3477static s32 3509static s32
3478brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, 3510brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
3479 struct cfg80211_ap_settings *settings) 3511 struct cfg80211_ap_settings *settings)
@@ -4260,6 +4292,12 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
4260 struct station_info sinfo; 4292 struct station_info sinfo;
4261 4293
4262 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason); 4294 brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
4295 if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
4296 ndev != cfg_to_ndev(cfg)) {
4297 brcmf_dbg(CONN, "AP mode link down\n");
4298 complete(&cfg->vif_disabled);
4299 return 0;
4300 }
4263 4301
4264 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && 4302 if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
4265 (reason == BRCMF_E_STATUS_SUCCESS)) { 4303 (reason == BRCMF_E_STATUS_SUCCESS)) {
@@ -4316,6 +4354,8 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
4316 } 4354 }
4317 brcmf_link_down(ifp->vif); 4355 brcmf_link_down(ifp->vif);
4318 brcmf_init_prof(ndev_to_prof(ndev)); 4356 brcmf_init_prof(ndev_to_prof(ndev));
4357 if (ndev != cfg_to_ndev(cfg))
4358 complete(&cfg->vif_disabled);
4319 } else if (brcmf_is_nonetwork(cfg, e)) { 4359 } else if (brcmf_is_nonetwork(cfg, e)) {
4320 if (brcmf_is_ibssmode(ifp->vif)) 4360 if (brcmf_is_ibssmode(ifp->vif))
4321 clear_bit(BRCMF_VIF_STATUS_CONNECTING, 4361 clear_bit(BRCMF_VIF_STATUS_CONNECTING,
@@ -4401,7 +4441,6 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
4401 4441
4402 case BRCMF_E_IF_DEL: 4442 case BRCMF_E_IF_DEL:
4403 ifp->vif = NULL; 4443 ifp->vif = NULL;
4404 brcmf_free_vif(vif);
4405 mutex_unlock(&event->vif_event_lock); 4444 mutex_unlock(&event->vif_event_lock);
4406 /* event may not be upon user request */ 4445 /* event may not be upon user request */
4407 if (brcmf_cfg80211_vif_event_armed(cfg)) 4446 if (brcmf_cfg80211_vif_event_armed(cfg))
@@ -4507,7 +4546,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
4507 mutex_init(&cfg->usr_sync); 4546 mutex_init(&cfg->usr_sync);
4508 brcmf_init_escan(cfg); 4547 brcmf_init_escan(cfg);
4509 brcmf_init_conf(cfg->conf); 4548 brcmf_init_conf(cfg->conf);
4510 4549 init_completion(&cfg->vif_disabled);
4511 return err; 4550 return err;
4512} 4551}
4513 4552
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
index a996afa8df4d..506818844a74 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
@@ -148,6 +148,7 @@ struct brcmf_cfg80211_profile {
148 * @BRCMF_VIF_STATUS_READY: ready for operation. 148 * @BRCMF_VIF_STATUS_READY: ready for operation.
149 * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. 149 * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
150 * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. 150 * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
151 * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress.
151 * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation. 152 * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation.
152 * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. 153 * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
153 */ 154 */
@@ -155,6 +156,7 @@ enum brcmf_vif_status {
155 BRCMF_VIF_STATUS_READY, 156 BRCMF_VIF_STATUS_READY,
156 BRCMF_VIF_STATUS_CONNECTING, 157 BRCMF_VIF_STATUS_CONNECTING,
157 BRCMF_VIF_STATUS_CONNECTED, 158 BRCMF_VIF_STATUS_CONNECTED,
159 BRCMF_VIF_STATUS_DISCONNECTING,
158 BRCMF_VIF_STATUS_AP_CREATING, 160 BRCMF_VIF_STATUS_AP_CREATING,
159 BRCMF_VIF_STATUS_AP_CREATED 161 BRCMF_VIF_STATUS_AP_CREATED
160}; 162};
@@ -405,6 +407,7 @@ struct brcmf_cfg80211_info {
405 struct list_head vif_list; 407 struct list_head vif_list;
406 u8 vif_cnt; 408 u8 vif_cnt;
407 struct brcmf_cfg80211_vif_event vif_event; 409 struct brcmf_cfg80211_vif_event vif_event;
410 struct completion vif_disabled;
408}; 411};
409 412
410/** 413/**
@@ -479,6 +482,7 @@ void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
479 482
480s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, 483s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
481 const u8 *vndr_ie_buf, u32 vndr_ie_len); 484 const u8 *vndr_ie_buf, u32 vndr_ie_len);
485s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif);
482struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key); 486struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key);
483u16 channel_to_chanspec(struct ieee80211_channel *ch); 487u16 channel_to_chanspec(struct ieee80211_channel *ch);
484u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state); 488u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state);