diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/cfg80211.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/cfg80211.c | 816 |
1 files changed, 609 insertions, 207 deletions
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 7be1e9b83fd0..41c8e25df954 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -590,77 +590,62 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
590 | struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); | 590 | struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); |
591 | struct mwifiex_private *priv; | 591 | struct mwifiex_private *priv; |
592 | struct mwifiex_uap_bss_param *bss_cfg; | 592 | struct mwifiex_uap_bss_param *bss_cfg; |
593 | int ret, bss_started, i; | 593 | int ret; |
594 | |||
595 | for (i = 0; i < adapter->priv_num; i++) { | ||
596 | priv = adapter->priv[i]; | ||
597 | |||
598 | switch (priv->bss_role) { | ||
599 | case MWIFIEX_BSS_ROLE_UAP: | ||
600 | bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), | ||
601 | GFP_KERNEL); | ||
602 | if (!bss_cfg) | ||
603 | return -ENOMEM; | ||
604 | |||
605 | mwifiex_set_sys_config_invalid_data(bss_cfg); | ||
606 | |||
607 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) | ||
608 | bss_cfg->rts_threshold = wiphy->rts_threshold; | ||
609 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) | ||
610 | bss_cfg->frag_threshold = wiphy->frag_threshold; | ||
611 | if (changed & WIPHY_PARAM_RETRY_LONG) | ||
612 | bss_cfg->retry_limit = wiphy->retry_long; | ||
613 | |||
614 | bss_started = priv->bss_started; | ||
615 | |||
616 | ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, | ||
617 | HostCmd_ACT_GEN_SET, 0, | ||
618 | NULL, true); | ||
619 | if (ret) { | ||
620 | wiphy_err(wiphy, "Failed to stop the BSS\n"); | ||
621 | kfree(bss_cfg); | ||
622 | return ret; | ||
623 | } | ||
624 | 594 | ||
625 | ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, | 595 | priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); |
626 | HostCmd_ACT_GEN_SET, | ||
627 | UAP_BSS_PARAMS_I, bss_cfg, | ||
628 | false); | ||
629 | 596 | ||
630 | kfree(bss_cfg); | 597 | switch (priv->bss_role) { |
598 | case MWIFIEX_BSS_ROLE_UAP: | ||
599 | if (priv->bss_started) { | ||
600 | dev_err(adapter->dev, | ||
601 | "cannot change wiphy params when bss started"); | ||
602 | return -EINVAL; | ||
603 | } | ||
631 | 604 | ||
632 | if (ret) { | 605 | bss_cfg = kzalloc(sizeof(*bss_cfg), GFP_KERNEL); |
633 | wiphy_err(wiphy, "Failed to set bss config\n"); | 606 | if (!bss_cfg) |
634 | return ret; | 607 | return -ENOMEM; |
635 | } | ||
636 | 608 | ||
637 | if (!bss_started) | 609 | mwifiex_set_sys_config_invalid_data(bss_cfg); |
638 | break; | ||
639 | 610 | ||
640 | ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, | 611 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) |
641 | HostCmd_ACT_GEN_SET, 0, | 612 | bss_cfg->rts_threshold = wiphy->rts_threshold; |
642 | NULL, false); | 613 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) |
643 | if (ret) { | 614 | bss_cfg->frag_threshold = wiphy->frag_threshold; |
644 | wiphy_err(wiphy, "Failed to start BSS\n"); | 615 | if (changed & WIPHY_PARAM_RETRY_LONG) |
645 | return ret; | 616 | bss_cfg->retry_limit = wiphy->retry_long; |
646 | } | 617 | |
618 | ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, | ||
619 | HostCmd_ACT_GEN_SET, | ||
620 | UAP_BSS_PARAMS_I, bss_cfg, | ||
621 | false); | ||
622 | |||
623 | kfree(bss_cfg); | ||
624 | if (ret) { | ||
625 | wiphy_err(wiphy, "Failed to set wiphy phy params\n"); | ||
626 | return ret; | ||
627 | } | ||
628 | break; | ||
647 | 629 | ||
648 | break; | ||
649 | case MWIFIEX_BSS_ROLE_STA: | 630 | case MWIFIEX_BSS_ROLE_STA: |
650 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | 631 | if (priv->media_connected) { |
651 | ret = mwifiex_set_rts(priv, | 632 | dev_err(adapter->dev, |
652 | wiphy->rts_threshold); | 633 | "cannot change wiphy params when connected"); |
653 | if (ret) | 634 | return -EINVAL; |
654 | return ret; | 635 | } |
655 | } | 636 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { |
656 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { | 637 | ret = mwifiex_set_rts(priv, |
657 | ret = mwifiex_set_frag(priv, | 638 | wiphy->rts_threshold); |
658 | wiphy->frag_threshold); | 639 | if (ret) |
659 | if (ret) | 640 | return ret; |
660 | return ret; | 641 | } |
661 | } | 642 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { |
662 | break; | 643 | ret = mwifiex_set_frag(priv, |
644 | wiphy->frag_threshold); | ||
645 | if (ret) | ||
646 | return ret; | ||
663 | } | 647 | } |
648 | break; | ||
664 | } | 649 | } |
665 | 650 | ||
666 | return 0; | 651 | return 0; |
@@ -671,9 +656,6 @@ mwifiex_cfg80211_deinit_p2p(struct mwifiex_private *priv) | |||
671 | { | 656 | { |
672 | u16 mode = P2P_MODE_DISABLE; | 657 | u16 mode = P2P_MODE_DISABLE; |
673 | 658 | ||
674 | if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) | ||
675 | mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA); | ||
676 | |||
677 | if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, | 659 | if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, |
678 | HostCmd_ACT_GEN_SET, 0, &mode, true)) | 660 | HostCmd_ACT_GEN_SET, 0, &mode, true)) |
679 | return -1; | 661 | return -1; |
@@ -730,12 +712,249 @@ mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv) | |||
730 | HostCmd_ACT_GEN_SET, 0, &mode, true)) | 712 | HostCmd_ACT_GEN_SET, 0, &mode, true)) |
731 | return -1; | 713 | return -1; |
732 | 714 | ||
733 | if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) | 715 | return 0; |
734 | mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_UAP); | 716 | } |
717 | |||
718 | static int mwifiex_deinit_priv_params(struct mwifiex_private *priv) | ||
719 | { | ||
720 | priv->mgmt_frame_mask = 0; | ||
721 | if (mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, | ||
722 | HostCmd_ACT_GEN_SET, 0, | ||
723 | &priv->mgmt_frame_mask, false)) { | ||
724 | dev_warn(priv->adapter->dev, | ||
725 | "could not unregister mgmt frame rx\n"); | ||
726 | return -1; | ||
727 | } | ||
728 | |||
729 | mwifiex_deauthenticate(priv, NULL); | ||
730 | mwifiex_free_priv(priv); | ||
731 | priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; | ||
732 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | ||
733 | priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
735 | 734 | ||
736 | return 0; | 735 | return 0; |
737 | } | 736 | } |
738 | 737 | ||
738 | static int | ||
739 | mwifiex_init_new_priv_params(struct mwifiex_private *priv, | ||
740 | struct net_device *dev, | ||
741 | enum nl80211_iftype type) | ||
742 | { | ||
743 | mwifiex_init_priv(priv); | ||
744 | |||
745 | priv->bss_mode = type; | ||
746 | priv->wdev.iftype = type; | ||
747 | |||
748 | mwifiex_init_priv_params(priv, priv->netdev); | ||
749 | priv->bss_started = 0; | ||
750 | |||
751 | switch (type) { | ||
752 | case NL80211_IFTYPE_STATION: | ||
753 | case NL80211_IFTYPE_ADHOC: | ||
754 | priv->bss_role = MWIFIEX_BSS_ROLE_STA; | ||
755 | priv->bss_type = MWIFIEX_BSS_TYPE_STA; | ||
756 | break; | ||
757 | case NL80211_IFTYPE_P2P_CLIENT: | ||
758 | case NL80211_IFTYPE_P2P_GO: | ||
759 | priv->bss_role = MWIFIEX_BSS_ROLE_STA; | ||
760 | priv->bss_type = MWIFIEX_BSS_TYPE_P2P; | ||
761 | break; | ||
762 | case NL80211_IFTYPE_AP: | ||
763 | priv->bss_type = MWIFIEX_BSS_TYPE_UAP; | ||
764 | priv->bss_role = MWIFIEX_BSS_ROLE_UAP; | ||
765 | break; | ||
766 | default: | ||
767 | dev_err(priv->adapter->dev, | ||
768 | "%s: changing to %d not supported\n", | ||
769 | dev->name, type); | ||
770 | return -EOPNOTSUPP; | ||
771 | } | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static int | ||
777 | mwifiex_change_vif_to_p2p(struct net_device *dev, | ||
778 | enum nl80211_iftype curr_iftype, | ||
779 | enum nl80211_iftype type, u32 *flags, | ||
780 | struct vif_params *params) | ||
781 | { | ||
782 | struct mwifiex_private *priv; | ||
783 | struct mwifiex_adapter *adapter; | ||
784 | |||
785 | priv = mwifiex_netdev_get_priv(dev); | ||
786 | |||
787 | if (!priv) | ||
788 | return -1; | ||
789 | |||
790 | adapter = priv->adapter; | ||
791 | |||
792 | if (adapter->curr_iface_comb.p2p_intf == | ||
793 | adapter->iface_limit.p2p_intf) { | ||
794 | dev_err(adapter->dev, | ||
795 | "cannot create multiple P2P ifaces\n"); | ||
796 | return -1; | ||
797 | } | ||
798 | |||
799 | dev_dbg(priv->adapter->dev, "%s: changing role to p2p\n", dev->name); | ||
800 | |||
801 | if (mwifiex_deinit_priv_params(priv)) | ||
802 | return -1; | ||
803 | if (mwifiex_init_new_priv_params(priv, dev, type)) | ||
804 | return -1; | ||
805 | |||
806 | switch (type) { | ||
807 | case NL80211_IFTYPE_P2P_CLIENT: | ||
808 | if (mwifiex_cfg80211_init_p2p_client(priv)) | ||
809 | return -EFAULT; | ||
810 | break; | ||
811 | case NL80211_IFTYPE_P2P_GO: | ||
812 | if (mwifiex_cfg80211_init_p2p_go(priv)) | ||
813 | return -EFAULT; | ||
814 | break; | ||
815 | default: | ||
816 | dev_err(priv->adapter->dev, | ||
817 | "%s: changing to %d not supported\n", | ||
818 | dev->name, type); | ||
819 | return -EOPNOTSUPP; | ||
820 | } | ||
821 | |||
822 | if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, | ||
823 | HostCmd_ACT_GEN_SET, 0, NULL, true)) | ||
824 | return -1; | ||
825 | |||
826 | if (mwifiex_sta_init_cmd(priv, false, false)) | ||
827 | return -1; | ||
828 | |||
829 | switch (curr_iftype) { | ||
830 | case NL80211_IFTYPE_STATION: | ||
831 | case NL80211_IFTYPE_ADHOC: | ||
832 | adapter->curr_iface_comb.sta_intf--; | ||
833 | break; | ||
834 | case NL80211_IFTYPE_AP: | ||
835 | adapter->curr_iface_comb.uap_intf--; | ||
836 | break; | ||
837 | default: | ||
838 | break; | ||
839 | } | ||
840 | |||
841 | adapter->curr_iface_comb.p2p_intf++; | ||
842 | dev->ieee80211_ptr->iftype = type; | ||
843 | |||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | static int | ||
848 | mwifiex_change_vif_to_sta_adhoc(struct net_device *dev, | ||
849 | enum nl80211_iftype curr_iftype, | ||
850 | enum nl80211_iftype type, u32 *flags, | ||
851 | struct vif_params *params) | ||
852 | { | ||
853 | struct mwifiex_private *priv; | ||
854 | struct mwifiex_adapter *adapter; | ||
855 | |||
856 | priv = mwifiex_netdev_get_priv(dev); | ||
857 | |||
858 | if (!priv) | ||
859 | return -1; | ||
860 | |||
861 | adapter = priv->adapter; | ||
862 | |||
863 | if ((curr_iftype != NL80211_IFTYPE_P2P_CLIENT && | ||
864 | curr_iftype != NL80211_IFTYPE_P2P_GO) && | ||
865 | (adapter->curr_iface_comb.sta_intf == | ||
866 | adapter->iface_limit.sta_intf)) { | ||
867 | dev_err(adapter->dev, | ||
868 | "cannot create multiple station/adhoc ifaces\n"); | ||
869 | return -1; | ||
870 | } | ||
871 | |||
872 | if (type == NL80211_IFTYPE_STATION) | ||
873 | dev_notice(adapter->dev, | ||
874 | "%s: changing role to station\n", dev->name); | ||
875 | else | ||
876 | dev_notice(adapter->dev, | ||
877 | "%s: changing role to adhoc\n", dev->name); | ||
878 | |||
879 | if (mwifiex_deinit_priv_params(priv)) | ||
880 | return -1; | ||
881 | if (mwifiex_init_new_priv_params(priv, dev, type)) | ||
882 | return -1; | ||
883 | if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, | ||
884 | HostCmd_ACT_GEN_SET, 0, NULL, true)) | ||
885 | return -1; | ||
886 | if (mwifiex_sta_init_cmd(priv, false, false)) | ||
887 | return -1; | ||
888 | |||
889 | switch (curr_iftype) { | ||
890 | case NL80211_IFTYPE_P2P_CLIENT: | ||
891 | case NL80211_IFTYPE_P2P_GO: | ||
892 | adapter->curr_iface_comb.p2p_intf--; | ||
893 | break; | ||
894 | case NL80211_IFTYPE_AP: | ||
895 | adapter->curr_iface_comb.uap_intf--; | ||
896 | break; | ||
897 | default: | ||
898 | break; | ||
899 | } | ||
900 | |||
901 | adapter->curr_iface_comb.sta_intf++; | ||
902 | dev->ieee80211_ptr->iftype = type; | ||
903 | return 0; | ||
904 | } | ||
905 | |||
906 | static int | ||
907 | mwifiex_change_vif_to_ap(struct net_device *dev, | ||
908 | enum nl80211_iftype curr_iftype, | ||
909 | enum nl80211_iftype type, u32 *flags, | ||
910 | struct vif_params *params) | ||
911 | { | ||
912 | struct mwifiex_private *priv; | ||
913 | struct mwifiex_adapter *adapter; | ||
914 | |||
915 | priv = mwifiex_netdev_get_priv(dev); | ||
916 | |||
917 | if (!priv) | ||
918 | return -1; | ||
919 | |||
920 | adapter = priv->adapter; | ||
921 | |||
922 | if (adapter->curr_iface_comb.uap_intf == | ||
923 | adapter->iface_limit.uap_intf) { | ||
924 | dev_err(adapter->dev, | ||
925 | "cannot create multiple AP ifaces\n"); | ||
926 | return -1; | ||
927 | } | ||
928 | |||
929 | dev_notice(adapter->dev, "%s: changing role to AP\n", dev->name); | ||
930 | |||
931 | if (mwifiex_deinit_priv_params(priv)) | ||
932 | return -1; | ||
933 | if (mwifiex_init_new_priv_params(priv, dev, type)) | ||
934 | return -1; | ||
935 | if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, | ||
936 | HostCmd_ACT_GEN_SET, 0, NULL, true)) | ||
937 | return -1; | ||
938 | if (mwifiex_sta_init_cmd(priv, false, false)) | ||
939 | return -1; | ||
940 | |||
941 | switch (curr_iftype) { | ||
942 | case NL80211_IFTYPE_P2P_CLIENT: | ||
943 | case NL80211_IFTYPE_P2P_GO: | ||
944 | adapter->curr_iface_comb.p2p_intf--; | ||
945 | break; | ||
946 | case NL80211_IFTYPE_STATION: | ||
947 | case NL80211_IFTYPE_ADHOC: | ||
948 | adapter->curr_iface_comb.sta_intf--; | ||
949 | break; | ||
950 | default: | ||
951 | break; | ||
952 | } | ||
953 | |||
954 | adapter->curr_iface_comb.uap_intf++; | ||
955 | dev->ieee80211_ptr->iftype = type; | ||
956 | return 0; | ||
957 | } | ||
739 | /* | 958 | /* |
740 | * CFG802.11 operation handler to change interface type. | 959 | * CFG802.11 operation handler to change interface type. |
741 | */ | 960 | */ |
@@ -745,19 +964,32 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, | |||
745 | enum nl80211_iftype type, u32 *flags, | 964 | enum nl80211_iftype type, u32 *flags, |
746 | struct vif_params *params) | 965 | struct vif_params *params) |
747 | { | 966 | { |
748 | int ret; | ||
749 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | 967 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); |
968 | enum nl80211_iftype curr_iftype = dev->ieee80211_ptr->iftype; | ||
750 | 969 | ||
751 | switch (dev->ieee80211_ptr->iftype) { | 970 | switch (curr_iftype) { |
752 | case NL80211_IFTYPE_ADHOC: | 971 | case NL80211_IFTYPE_ADHOC: |
753 | switch (type) { | 972 | switch (type) { |
754 | case NL80211_IFTYPE_STATION: | 973 | case NL80211_IFTYPE_STATION: |
755 | break; | 974 | priv->bss_mode = type; |
975 | priv->sec_info.authentication_mode = | ||
976 | NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
977 | dev->ieee80211_ptr->iftype = type; | ||
978 | mwifiex_deauthenticate(priv, NULL); | ||
979 | return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, | ||
980 | HostCmd_ACT_GEN_SET, 0, NULL, | ||
981 | true); | ||
982 | case NL80211_IFTYPE_P2P_CLIENT: | ||
983 | case NL80211_IFTYPE_P2P_GO: | ||
984 | return mwifiex_change_vif_to_p2p(dev, curr_iftype, | ||
985 | type, flags, params); | ||
986 | case NL80211_IFTYPE_AP: | ||
987 | return mwifiex_change_vif_to_ap(dev, curr_iftype, type, | ||
988 | flags, params); | ||
756 | case NL80211_IFTYPE_UNSPECIFIED: | 989 | case NL80211_IFTYPE_UNSPECIFIED: |
757 | wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name); | 990 | wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name); |
758 | case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */ | 991 | case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */ |
759 | return 0; | 992 | return 0; |
760 | case NL80211_IFTYPE_AP: | ||
761 | default: | 993 | default: |
762 | wiphy_err(wiphy, "%s: changing to %d not supported\n", | 994 | wiphy_err(wiphy, "%s: changing to %d not supported\n", |
763 | dev->name, type); | 995 | dev->name, type); |
@@ -767,22 +999,25 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, | |||
767 | case NL80211_IFTYPE_STATION: | 999 | case NL80211_IFTYPE_STATION: |
768 | switch (type) { | 1000 | switch (type) { |
769 | case NL80211_IFTYPE_ADHOC: | 1001 | case NL80211_IFTYPE_ADHOC: |
770 | break; | 1002 | priv->bss_mode = type; |
771 | case NL80211_IFTYPE_P2P_CLIENT: | 1003 | priv->sec_info.authentication_mode = |
772 | if (mwifiex_cfg80211_init_p2p_client(priv)) | 1004 | NL80211_AUTHTYPE_OPEN_SYSTEM; |
773 | return -EFAULT; | ||
774 | dev->ieee80211_ptr->iftype = type; | 1005 | dev->ieee80211_ptr->iftype = type; |
775 | return 0; | 1006 | mwifiex_deauthenticate(priv, NULL); |
1007 | return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, | ||
1008 | HostCmd_ACT_GEN_SET, 0, NULL, | ||
1009 | true); | ||
1010 | case NL80211_IFTYPE_P2P_CLIENT: | ||
776 | case NL80211_IFTYPE_P2P_GO: | 1011 | case NL80211_IFTYPE_P2P_GO: |
777 | if (mwifiex_cfg80211_init_p2p_go(priv)) | 1012 | return mwifiex_change_vif_to_p2p(dev, curr_iftype, |
778 | return -EFAULT; | 1013 | type, flags, params); |
779 | dev->ieee80211_ptr->iftype = type; | 1014 | case NL80211_IFTYPE_AP: |
780 | return 0; | 1015 | return mwifiex_change_vif_to_ap(dev, curr_iftype, type, |
1016 | flags, params); | ||
781 | case NL80211_IFTYPE_UNSPECIFIED: | 1017 | case NL80211_IFTYPE_UNSPECIFIED: |
782 | wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name); | 1018 | wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name); |
783 | case NL80211_IFTYPE_STATION: /* This shouldn't happen */ | 1019 | case NL80211_IFTYPE_STATION: /* This shouldn't happen */ |
784 | return 0; | 1020 | return 0; |
785 | case NL80211_IFTYPE_AP: | ||
786 | default: | 1021 | default: |
787 | wiphy_err(wiphy, "%s: changing to %d not supported\n", | 1022 | wiphy_err(wiphy, "%s: changing to %d not supported\n", |
788 | dev->name, type); | 1023 | dev->name, type); |
@@ -791,12 +1026,20 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, | |||
791 | break; | 1026 | break; |
792 | case NL80211_IFTYPE_AP: | 1027 | case NL80211_IFTYPE_AP: |
793 | switch (type) { | 1028 | switch (type) { |
1029 | case NL80211_IFTYPE_ADHOC: | ||
1030 | case NL80211_IFTYPE_STATION: | ||
1031 | return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, | ||
1032 | type, flags, | ||
1033 | params); | ||
1034 | break; | ||
1035 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1036 | case NL80211_IFTYPE_P2P_GO: | ||
1037 | return mwifiex_change_vif_to_p2p(dev, curr_iftype, | ||
1038 | type, flags, params); | ||
794 | case NL80211_IFTYPE_UNSPECIFIED: | 1039 | case NL80211_IFTYPE_UNSPECIFIED: |
795 | wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name); | 1040 | wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name); |
796 | case NL80211_IFTYPE_AP: /* This shouldn't happen */ | 1041 | case NL80211_IFTYPE_AP: /* This shouldn't happen */ |
797 | return 0; | 1042 | return 0; |
798 | case NL80211_IFTYPE_ADHOC: | ||
799 | case NL80211_IFTYPE_STATION: | ||
800 | default: | 1043 | default: |
801 | wiphy_err(wiphy, "%s: changing to %d not supported\n", | 1044 | wiphy_err(wiphy, "%s: changing to %d not supported\n", |
802 | dev->name, type); | 1045 | dev->name, type); |
@@ -807,11 +1050,30 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, | |||
807 | case NL80211_IFTYPE_P2P_GO: | 1050 | case NL80211_IFTYPE_P2P_GO: |
808 | switch (type) { | 1051 | switch (type) { |
809 | case NL80211_IFTYPE_STATION: | 1052 | case NL80211_IFTYPE_STATION: |
810 | if (mwifiex_cfg80211_deinit_p2p(priv)) | 1053 | if (mwifiex_cfg80211_init_p2p_client(priv)) |
811 | return -EFAULT; | 1054 | return -EFAULT; |
812 | dev->ieee80211_ptr->iftype = type; | 1055 | dev->ieee80211_ptr->iftype = type; |
1056 | break; | ||
1057 | case NL80211_IFTYPE_ADHOC: | ||
1058 | if (mwifiex_cfg80211_deinit_p2p(priv)) | ||
1059 | return -EFAULT; | ||
1060 | return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, | ||
1061 | type, flags, | ||
1062 | params); | ||
1063 | break; | ||
1064 | case NL80211_IFTYPE_AP: | ||
1065 | if (mwifiex_cfg80211_deinit_p2p(priv)) | ||
1066 | return -EFAULT; | ||
1067 | return mwifiex_change_vif_to_ap(dev, curr_iftype, type, | ||
1068 | flags, params); | ||
1069 | case NL80211_IFTYPE_UNSPECIFIED: | ||
1070 | wiphy_warn(wiphy, "%s: kept type as P2P\n", dev->name); | ||
1071 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1072 | case NL80211_IFTYPE_P2P_GO: | ||
813 | return 0; | 1073 | return 0; |
814 | default: | 1074 | default: |
1075 | wiphy_err(wiphy, "%s: changing to %d not supported\n", | ||
1076 | dev->name, type); | ||
815 | return -EOPNOTSUPP; | 1077 | return -EOPNOTSUPP; |
816 | } | 1078 | } |
817 | break; | 1079 | break; |
@@ -821,16 +1083,8 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, | |||
821 | return -EOPNOTSUPP; | 1083 | return -EOPNOTSUPP; |
822 | } | 1084 | } |
823 | 1085 | ||
824 | dev->ieee80211_ptr->iftype = type; | ||
825 | priv->bss_mode = type; | ||
826 | mwifiex_deauthenticate(priv, NULL); | ||
827 | |||
828 | priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
829 | 1086 | ||
830 | ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, | 1087 | return 0; |
831 | HostCmd_ACT_GEN_SET, 0, NULL, true); | ||
832 | |||
833 | return ret; | ||
834 | } | 1088 | } |
835 | 1089 | ||
836 | static void | 1090 | static void |
@@ -1397,10 +1651,13 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1397 | { | 1651 | { |
1398 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | 1652 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); |
1399 | 1653 | ||
1654 | mwifiex_abort_cac(priv); | ||
1655 | |||
1400 | if (mwifiex_del_mgmt_ies(priv)) | 1656 | if (mwifiex_del_mgmt_ies(priv)) |
1401 | wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); | 1657 | wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); |
1402 | 1658 | ||
1403 | priv->ap_11n_enabled = 0; | 1659 | priv->ap_11n_enabled = 0; |
1660 | memset(&priv->bss_cfg, 0, sizeof(priv->bss_cfg)); | ||
1404 | 1661 | ||
1405 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, | 1662 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, |
1406 | HostCmd_ACT_GEN_SET, 0, NULL, true)) { | 1663 | HostCmd_ACT_GEN_SET, 0, NULL, true)) { |
@@ -1422,12 +1679,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, | |||
1422 | { | 1679 | { |
1423 | struct mwifiex_uap_bss_param *bss_cfg; | 1680 | struct mwifiex_uap_bss_param *bss_cfg; |
1424 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | 1681 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); |
1425 | u8 config_bands = 0; | ||
1426 | 1682 | ||
1427 | if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) | 1683 | if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) |
1428 | return -1; | 1684 | return -1; |
1429 | if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) | ||
1430 | return -1; | ||
1431 | 1685 | ||
1432 | bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); | 1686 | bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); |
1433 | if (!bss_cfg) | 1687 | if (!bss_cfg) |
@@ -1444,6 +1698,11 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, | |||
1444 | memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len); | 1698 | memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len); |
1445 | bss_cfg->ssid.ssid_len = params->ssid_len; | 1699 | bss_cfg->ssid.ssid_len = params->ssid_len; |
1446 | } | 1700 | } |
1701 | if (params->inactivity_timeout > 0) { | ||
1702 | /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ | ||
1703 | bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout; | ||
1704 | bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout; | ||
1705 | } | ||
1447 | 1706 | ||
1448 | switch (params->hidden_ssid) { | 1707 | switch (params->hidden_ssid) { |
1449 | case NL80211_HIDDEN_SSID_NOT_IN_USE: | 1708 | case NL80211_HIDDEN_SSID_NOT_IN_USE: |
@@ -1459,33 +1718,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, | |||
1459 | return -EINVAL; | 1718 | return -EINVAL; |
1460 | } | 1719 | } |
1461 | 1720 | ||
1462 | bss_cfg->channel = ieee80211_frequency_to_channel( | 1721 | mwifiex_uap_set_channel(bss_cfg, params->chandef); |
1463 | params->chandef.chan->center_freq); | ||
1464 | |||
1465 | /* Set appropriate bands */ | ||
1466 | if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) { | ||
1467 | bss_cfg->band_cfg = BAND_CONFIG_BG; | ||
1468 | config_bands = BAND_B | BAND_G; | ||
1469 | |||
1470 | if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT) | ||
1471 | config_bands |= BAND_GN; | ||
1472 | } else { | ||
1473 | bss_cfg->band_cfg = BAND_CONFIG_A; | ||
1474 | config_bands = BAND_A; | ||
1475 | |||
1476 | if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT) | ||
1477 | config_bands |= BAND_AN; | ||
1478 | |||
1479 | if (params->chandef.width > NL80211_CHAN_WIDTH_40) | ||
1480 | config_bands |= BAND_AAC; | ||
1481 | } | ||
1482 | |||
1483 | if (!((config_bands | priv->adapter->fw_bands) & | ||
1484 | ~priv->adapter->fw_bands)) | ||
1485 | priv->adapter->config_bands = config_bands; | ||
1486 | |||
1487 | mwifiex_set_uap_rates(bss_cfg, params); | 1722 | mwifiex_set_uap_rates(bss_cfg, params); |
1488 | mwifiex_send_domain_info_cmd_fw(wiphy); | ||
1489 | 1723 | ||
1490 | if (mwifiex_set_secure_params(priv, bss_cfg, params)) { | 1724 | if (mwifiex_set_secure_params(priv, bss_cfg, params)) { |
1491 | kfree(bss_cfg); | 1725 | kfree(bss_cfg); |
@@ -1508,45 +1742,29 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, | |||
1508 | 1742 | ||
1509 | mwifiex_set_wmm_params(priv, bss_cfg, params); | 1743 | mwifiex_set_wmm_params(priv, bss_cfg, params); |
1510 | 1744 | ||
1511 | if (params->inactivity_timeout > 0) { | 1745 | if (mwifiex_is_11h_active(priv) && |
1512 | /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ | 1746 | !cfg80211_chandef_dfs_required(wiphy, ¶ms->chandef, |
1513 | bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout; | 1747 | priv->bss_mode)) { |
1514 | bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout; | 1748 | dev_dbg(priv->adapter->dev, "Disable 11h extensions in FW\n"); |
1749 | if (mwifiex_11h_activate(priv, false)) { | ||
1750 | dev_err(priv->adapter->dev, | ||
1751 | "Failed to disable 11h extensions!!"); | ||
1752 | return -1; | ||
1753 | } | ||
1754 | priv->state_11h.is_11h_active = true; | ||
1515 | } | 1755 | } |
1516 | 1756 | ||
1517 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, | 1757 | if (mwifiex_config_start_uap(priv, bss_cfg)) { |
1518 | HostCmd_ACT_GEN_SET, 0, NULL, true)) { | 1758 | wiphy_err(wiphy, "Failed to start AP\n"); |
1519 | wiphy_err(wiphy, "Failed to stop the BSS\n"); | ||
1520 | kfree(bss_cfg); | 1759 | kfree(bss_cfg); |
1521 | return -1; | 1760 | return -1; |
1522 | } | 1761 | } |
1523 | 1762 | ||
1524 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, | 1763 | if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) |
1525 | HostCmd_ACT_GEN_SET, | ||
1526 | UAP_BSS_PARAMS_I, bss_cfg, false)) { | ||
1527 | wiphy_err(wiphy, "Failed to set the SSID\n"); | ||
1528 | kfree(bss_cfg); | ||
1529 | return -1; | 1764 | return -1; |
1530 | } | ||
1531 | 1765 | ||
1766 | memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg)); | ||
1532 | kfree(bss_cfg); | 1767 | kfree(bss_cfg); |
1533 | |||
1534 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, | ||
1535 | HostCmd_ACT_GEN_SET, 0, NULL, false)) { | ||
1536 | wiphy_err(wiphy, "Failed to start the BSS\n"); | ||
1537 | return -1; | ||
1538 | } | ||
1539 | |||
1540 | if (priv->sec_info.wep_enabled) | ||
1541 | priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; | ||
1542 | else | ||
1543 | priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; | ||
1544 | |||
1545 | if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, | ||
1546 | HostCmd_ACT_GEN_SET, 0, | ||
1547 | &priv->curr_pkt_filter, true)) | ||
1548 | return -1; | ||
1549 | |||
1550 | return 0; | 1768 | return 0; |
1551 | } | 1769 | } |
1552 | 1770 | ||
@@ -1605,15 +1823,15 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) | |||
1605 | ie_len = ie_buf[1] + sizeof(struct ieee_types_header); | 1823 | ie_len = ie_buf[1] + sizeof(struct ieee_types_header); |
1606 | 1824 | ||
1607 | band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); | 1825 | band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); |
1608 | chan = __ieee80211_get_channel(priv->wdev->wiphy, | 1826 | chan = __ieee80211_get_channel(priv->wdev.wiphy, |
1609 | ieee80211_channel_to_frequency(bss_info.bss_chan, | 1827 | ieee80211_channel_to_frequency(bss_info.bss_chan, |
1610 | band)); | 1828 | band)); |
1611 | 1829 | ||
1612 | bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, | 1830 | bss = cfg80211_inform_bss(priv->wdev.wiphy, chan, |
1613 | CFG80211_BSS_FTYPE_UNKNOWN, | 1831 | CFG80211_BSS_FTYPE_UNKNOWN, |
1614 | bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, | 1832 | bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, |
1615 | 0, ie_buf, ie_len, 0, GFP_KERNEL); | 1833 | 0, ie_buf, ie_len, 0, GFP_KERNEL); |
1616 | cfg80211_put_bss(priv->wdev->wiphy, bss); | 1834 | cfg80211_put_bss(priv->wdev.wiphy, bss); |
1617 | memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); | 1835 | memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); |
1618 | 1836 | ||
1619 | return 0; | 1837 | return 0; |
@@ -1734,12 +1952,12 @@ done: | |||
1734 | 1952 | ||
1735 | /* Find the BSS we want using available scan results */ | 1953 | /* Find the BSS we want using available scan results */ |
1736 | if (mode == NL80211_IFTYPE_ADHOC) | 1954 | if (mode == NL80211_IFTYPE_ADHOC) |
1737 | bss = cfg80211_get_bss(priv->wdev->wiphy, channel, | 1955 | bss = cfg80211_get_bss(priv->wdev.wiphy, channel, |
1738 | bssid, ssid, ssid_len, | 1956 | bssid, ssid, ssid_len, |
1739 | WLAN_CAPABILITY_IBSS, | 1957 | WLAN_CAPABILITY_IBSS, |
1740 | WLAN_CAPABILITY_IBSS); | 1958 | WLAN_CAPABILITY_IBSS); |
1741 | else | 1959 | else |
1742 | bss = cfg80211_get_bss(priv->wdev->wiphy, channel, | 1960 | bss = cfg80211_get_bss(priv->wdev.wiphy, channel, |
1743 | bssid, ssid, ssid_len, | 1961 | bssid, ssid, ssid_len, |
1744 | WLAN_CAPABILITY_ESS, | 1962 | WLAN_CAPABILITY_ESS, |
1745 | WLAN_CAPABILITY_ESS); | 1963 | WLAN_CAPABILITY_ESS); |
@@ -1796,7 +2014,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
1796 | return -EINVAL; | 2014 | return -EINVAL; |
1797 | } | 2015 | } |
1798 | 2016 | ||
1799 | if (priv->wdev && priv->wdev->current_bss) { | 2017 | if (priv->wdev.current_bss) { |
1800 | wiphy_warn(wiphy, "%s: already connected\n", dev->name); | 2018 | wiphy_warn(wiphy, "%s: already connected\n", dev->name); |
1801 | return -EALREADY; | 2019 | return -EALREADY; |
1802 | } | 2020 | } |
@@ -1854,7 +2072,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
1854 | static int mwifiex_set_ibss_params(struct mwifiex_private *priv, | 2072 | static int mwifiex_set_ibss_params(struct mwifiex_private *priv, |
1855 | struct cfg80211_ibss_params *params) | 2073 | struct cfg80211_ibss_params *params) |
1856 | { | 2074 | { |
1857 | struct wiphy *wiphy = priv->wdev->wiphy; | 2075 | struct wiphy *wiphy = priv->wdev.wiphy; |
1858 | struct mwifiex_adapter *adapter = priv->adapter; | 2076 | struct mwifiex_adapter *adapter = priv->adapter; |
1859 | int index = 0, i; | 2077 | int index = 0, i; |
1860 | u8 config_bands = 0; | 2078 | u8 config_bands = 0; |
@@ -2179,6 +2397,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, | |||
2179 | ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | 2397 | ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; |
2180 | } | 2398 | } |
2181 | 2399 | ||
2400 | #define MWIFIEX_MAX_WQ_LEN 30 | ||
2182 | /* | 2401 | /* |
2183 | * create a new virtual interface with the given name | 2402 | * create a new virtual interface with the given name |
2184 | */ | 2403 | */ |
@@ -2192,7 +2411,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
2192 | struct mwifiex_private *priv; | 2411 | struct mwifiex_private *priv; |
2193 | struct net_device *dev; | 2412 | struct net_device *dev; |
2194 | void *mdev_priv; | 2413 | void *mdev_priv; |
2195 | struct wireless_dev *wdev; | 2414 | char dfs_cac_str[MWIFIEX_MAX_WQ_LEN], dfs_chsw_str[MWIFIEX_MAX_WQ_LEN]; |
2196 | 2415 | ||
2197 | if (!adapter) | 2416 | if (!adapter) |
2198 | return ERR_PTR(-EFAULT); | 2417 | return ERR_PTR(-EFAULT); |
@@ -2201,20 +2420,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
2201 | case NL80211_IFTYPE_UNSPECIFIED: | 2420 | case NL80211_IFTYPE_UNSPECIFIED: |
2202 | case NL80211_IFTYPE_STATION: | 2421 | case NL80211_IFTYPE_STATION: |
2203 | case NL80211_IFTYPE_ADHOC: | 2422 | case NL80211_IFTYPE_ADHOC: |
2204 | priv = adapter->priv[MWIFIEX_BSS_TYPE_STA]; | 2423 | if (adapter->curr_iface_comb.sta_intf == |
2205 | if (priv->bss_mode) { | 2424 | adapter->iface_limit.sta_intf) { |
2206 | wiphy_err(wiphy, | 2425 | wiphy_err(wiphy, |
2207 | "cannot create multiple sta/adhoc ifaces\n"); | 2426 | "cannot create multiple sta/adhoc ifaces\n"); |
2208 | return ERR_PTR(-EINVAL); | 2427 | return ERR_PTR(-EINVAL); |
2209 | } | 2428 | } |
2210 | 2429 | ||
2211 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | 2430 | priv = mwifiex_get_unused_priv(adapter); |
2212 | if (!wdev) | 2431 | if (!priv) { |
2213 | return ERR_PTR(-ENOMEM); | 2432 | wiphy_err(wiphy, |
2433 | "could not get free private struct\n"); | ||
2434 | return ERR_PTR(-EFAULT); | ||
2435 | } | ||
2214 | 2436 | ||
2215 | wdev->wiphy = wiphy; | 2437 | priv->wdev.wiphy = wiphy; |
2216 | priv->wdev = wdev; | 2438 | priv->wdev.iftype = NL80211_IFTYPE_STATION; |
2217 | wdev->iftype = NL80211_IFTYPE_STATION; | ||
2218 | 2439 | ||
2219 | if (type == NL80211_IFTYPE_UNSPECIFIED) | 2440 | if (type == NL80211_IFTYPE_UNSPECIFIED) |
2220 | priv->bss_mode = NL80211_IFTYPE_STATION; | 2441 | priv->bss_mode = NL80211_IFTYPE_STATION; |
@@ -2229,20 +2450,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
2229 | 2450 | ||
2230 | break; | 2451 | break; |
2231 | case NL80211_IFTYPE_AP: | 2452 | case NL80211_IFTYPE_AP: |
2232 | priv = adapter->priv[MWIFIEX_BSS_TYPE_UAP]; | 2453 | if (adapter->curr_iface_comb.uap_intf == |
2233 | 2454 | adapter->iface_limit.uap_intf) { | |
2234 | if (priv->bss_mode) { | 2455 | wiphy_err(wiphy, |
2235 | wiphy_err(wiphy, "Can't create multiple AP interfaces"); | 2456 | "cannot create multiple AP ifaces\n"); |
2236 | return ERR_PTR(-EINVAL); | 2457 | return ERR_PTR(-EINVAL); |
2237 | } | 2458 | } |
2238 | 2459 | ||
2239 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | 2460 | priv = mwifiex_get_unused_priv(adapter); |
2240 | if (!wdev) | 2461 | if (!priv) { |
2241 | return ERR_PTR(-ENOMEM); | 2462 | wiphy_err(wiphy, |
2463 | "could not get free private struct\n"); | ||
2464 | return ERR_PTR(-EFAULT); | ||
2465 | } | ||
2242 | 2466 | ||
2243 | priv->wdev = wdev; | 2467 | priv->wdev.wiphy = wiphy; |
2244 | wdev->wiphy = wiphy; | 2468 | priv->wdev.iftype = NL80211_IFTYPE_AP; |
2245 | wdev->iftype = NL80211_IFTYPE_AP; | ||
2246 | 2469 | ||
2247 | priv->bss_type = MWIFIEX_BSS_TYPE_UAP; | 2470 | priv->bss_type = MWIFIEX_BSS_TYPE_UAP; |
2248 | priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; | 2471 | priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; |
@@ -2254,24 +2477,25 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
2254 | 2477 | ||
2255 | break; | 2478 | break; |
2256 | case NL80211_IFTYPE_P2P_CLIENT: | 2479 | case NL80211_IFTYPE_P2P_CLIENT: |
2257 | priv = adapter->priv[MWIFIEX_BSS_TYPE_P2P]; | 2480 | if (adapter->curr_iface_comb.p2p_intf == |
2258 | 2481 | adapter->iface_limit.p2p_intf) { | |
2259 | if (priv->bss_mode) { | 2482 | wiphy_err(wiphy, |
2260 | wiphy_err(wiphy, "Can't create multiple P2P ifaces"); | 2483 | "cannot create multiple P2P ifaces\n"); |
2261 | return ERR_PTR(-EINVAL); | 2484 | return ERR_PTR(-EINVAL); |
2262 | } | 2485 | } |
2263 | 2486 | ||
2264 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | 2487 | priv = mwifiex_get_unused_priv(adapter); |
2265 | if (!wdev) | 2488 | if (!priv) { |
2266 | return ERR_PTR(-ENOMEM); | 2489 | wiphy_err(wiphy, |
2267 | 2490 | "could not get free private struct\n"); | |
2268 | priv->wdev = wdev; | 2491 | return ERR_PTR(-EFAULT); |
2269 | wdev->wiphy = wiphy; | 2492 | } |
2270 | 2493 | ||
2494 | priv->wdev.wiphy = wiphy; | ||
2271 | /* At start-up, wpa_supplicant tries to change the interface | 2495 | /* At start-up, wpa_supplicant tries to change the interface |
2272 | * to NL80211_IFTYPE_STATION if it is not managed mode. | 2496 | * to NL80211_IFTYPE_STATION if it is not managed mode. |
2273 | */ | 2497 | */ |
2274 | wdev->iftype = NL80211_IFTYPE_P2P_CLIENT; | 2498 | priv->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT; |
2275 | priv->bss_mode = NL80211_IFTYPE_P2P_CLIENT; | 2499 | priv->bss_mode = NL80211_IFTYPE_P2P_CLIENT; |
2276 | 2500 | ||
2277 | /* Setting bss_type to P2P tells firmware that this interface | 2501 | /* Setting bss_type to P2P tells firmware that this interface |
@@ -2287,8 +2511,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
2287 | priv->bss_num = 0; | 2511 | priv->bss_num = 0; |
2288 | 2512 | ||
2289 | if (mwifiex_cfg80211_init_p2p_client(priv)) { | 2513 | if (mwifiex_cfg80211_init_p2p_client(priv)) { |
2290 | wdev = ERR_PTR(-EFAULT); | 2514 | memset(&priv->wdev, 0, sizeof(priv->wdev)); |
2291 | goto done; | 2515 | priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; |
2516 | return ERR_PTR(-EFAULT); | ||
2292 | } | 2517 | } |
2293 | 2518 | ||
2294 | break; | 2519 | break; |
@@ -2302,9 +2527,10 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
2302 | IEEE80211_NUM_ACS, 1); | 2527 | IEEE80211_NUM_ACS, 1); |
2303 | if (!dev) { | 2528 | if (!dev) { |
2304 | wiphy_err(wiphy, "no memory available for netdevice\n"); | 2529 | wiphy_err(wiphy, "no memory available for netdevice\n"); |
2530 | memset(&priv->wdev, 0, sizeof(priv->wdev)); | ||
2531 | priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; | ||
2305 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | 2532 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; |
2306 | wdev = ERR_PTR(-ENOMEM); | 2533 | return ERR_PTR(-ENOMEM); |
2307 | goto done; | ||
2308 | } | 2534 | } |
2309 | 2535 | ||
2310 | mwifiex_init_priv_params(priv, dev); | 2536 | mwifiex_init_priv_params(priv, dev); |
@@ -2324,7 +2550,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
2324 | &wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv); | 2550 | &wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv); |
2325 | 2551 | ||
2326 | dev_net_set(dev, wiphy_net(wiphy)); | 2552 | dev_net_set(dev, wiphy_net(wiphy)); |
2327 | dev->ieee80211_ptr = priv->wdev; | 2553 | dev->ieee80211_ptr = &priv->wdev; |
2328 | dev->ieee80211_ptr->iftype = priv->bss_mode; | 2554 | dev->ieee80211_ptr->iftype = priv->bss_mode; |
2329 | memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); | 2555 | memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); |
2330 | SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); | 2556 | SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); |
@@ -2345,10 +2571,47 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
2345 | free_netdev(dev); | 2571 | free_netdev(dev); |
2346 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | 2572 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; |
2347 | priv->netdev = NULL; | 2573 | priv->netdev = NULL; |
2348 | wdev = ERR_PTR(-EFAULT); | 2574 | memset(&priv->wdev, 0, sizeof(priv->wdev)); |
2349 | goto done; | 2575 | priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; |
2576 | return ERR_PTR(-EFAULT); | ||
2577 | } | ||
2578 | |||
2579 | strcpy(dfs_cac_str, "MWIFIEX_DFS_CAC"); | ||
2580 | strcat(dfs_cac_str, name); | ||
2581 | priv->dfs_cac_workqueue = alloc_workqueue(dfs_cac_str, | ||
2582 | WQ_HIGHPRI | | ||
2583 | WQ_MEM_RECLAIM | | ||
2584 | WQ_UNBOUND, 1); | ||
2585 | if (!priv->dfs_cac_workqueue) { | ||
2586 | wiphy_err(wiphy, "cannot register virtual network device\n"); | ||
2587 | free_netdev(dev); | ||
2588 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | ||
2589 | priv->netdev = NULL; | ||
2590 | memset(&priv->wdev, 0, sizeof(priv->wdev)); | ||
2591 | priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; | ||
2592 | return ERR_PTR(-ENOMEM); | ||
2593 | } | ||
2594 | |||
2595 | INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue); | ||
2596 | |||
2597 | strcpy(dfs_chsw_str, "MWIFIEX_DFS_CHSW"); | ||
2598 | strcat(dfs_chsw_str, name); | ||
2599 | priv->dfs_chan_sw_workqueue = alloc_workqueue(dfs_chsw_str, | ||
2600 | WQ_HIGHPRI | WQ_UNBOUND | | ||
2601 | WQ_MEM_RECLAIM, 1); | ||
2602 | if (!priv->dfs_chan_sw_workqueue) { | ||
2603 | wiphy_err(wiphy, "cannot register virtual network device\n"); | ||
2604 | free_netdev(dev); | ||
2605 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | ||
2606 | priv->netdev = NULL; | ||
2607 | memset(&priv->wdev, 0, sizeof(priv->wdev)); | ||
2608 | priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; | ||
2609 | return ERR_PTR(-ENOMEM); | ||
2350 | } | 2610 | } |
2351 | 2611 | ||
2612 | INIT_DELAYED_WORK(&priv->dfs_chan_sw_work, | ||
2613 | mwifiex_dfs_chan_sw_work_queue); | ||
2614 | |||
2352 | sema_init(&priv->async_sem, 1); | 2615 | sema_init(&priv->async_sem, 1); |
2353 | 2616 | ||
2354 | dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); | 2617 | dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); |
@@ -2357,13 +2620,24 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
2357 | mwifiex_dev_debugfs_init(priv); | 2620 | mwifiex_dev_debugfs_init(priv); |
2358 | #endif | 2621 | #endif |
2359 | 2622 | ||
2360 | done: | 2623 | switch (type) { |
2361 | if (IS_ERR(wdev)) { | 2624 | case NL80211_IFTYPE_UNSPECIFIED: |
2362 | kfree(priv->wdev); | 2625 | case NL80211_IFTYPE_STATION: |
2363 | priv->wdev = NULL; | 2626 | case NL80211_IFTYPE_ADHOC: |
2627 | adapter->curr_iface_comb.sta_intf++; | ||
2628 | break; | ||
2629 | case NL80211_IFTYPE_AP: | ||
2630 | adapter->curr_iface_comb.uap_intf++; | ||
2631 | break; | ||
2632 | case NL80211_IFTYPE_P2P_CLIENT: | ||
2633 | adapter->curr_iface_comb.p2p_intf++; | ||
2634 | break; | ||
2635 | default: | ||
2636 | wiphy_err(wiphy, "type not supported\n"); | ||
2637 | return ERR_PTR(-EINVAL); | ||
2364 | } | 2638 | } |
2365 | 2639 | ||
2366 | return wdev; | 2640 | return &priv->wdev; |
2367 | } | 2641 | } |
2368 | EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); | 2642 | EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); |
2369 | 2643 | ||
@@ -2373,12 +2647,13 @@ EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); | |||
2373 | int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) | 2647 | int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) |
2374 | { | 2648 | { |
2375 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); | 2649 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); |
2650 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2376 | 2651 | ||
2377 | #ifdef CONFIG_DEBUG_FS | 2652 | #ifdef CONFIG_DEBUG_FS |
2378 | mwifiex_dev_debugfs_remove(priv); | 2653 | mwifiex_dev_debugfs_remove(priv); |
2379 | #endif | 2654 | #endif |
2380 | 2655 | ||
2381 | mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); | 2656 | mwifiex_stop_net_dev_queue(priv->netdev, adapter); |
2382 | 2657 | ||
2383 | if (netif_carrier_ok(priv->netdev)) | 2658 | if (netif_carrier_ok(priv->netdev)) |
2384 | netif_carrier_off(priv->netdev); | 2659 | netif_carrier_off(priv->netdev); |
@@ -2386,14 +2661,42 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) | |||
2386 | if (wdev->netdev->reg_state == NETREG_REGISTERED) | 2661 | if (wdev->netdev->reg_state == NETREG_REGISTERED) |
2387 | unregister_netdevice(wdev->netdev); | 2662 | unregister_netdevice(wdev->netdev); |
2388 | 2663 | ||
2664 | if (priv->dfs_cac_workqueue) { | ||
2665 | flush_workqueue(priv->dfs_cac_workqueue); | ||
2666 | destroy_workqueue(priv->dfs_cac_workqueue); | ||
2667 | priv->dfs_cac_workqueue = NULL; | ||
2668 | } | ||
2669 | |||
2670 | if (priv->dfs_chan_sw_workqueue) { | ||
2671 | flush_workqueue(priv->dfs_chan_sw_workqueue); | ||
2672 | destroy_workqueue(priv->dfs_chan_sw_workqueue); | ||
2673 | priv->dfs_chan_sw_workqueue = NULL; | ||
2674 | } | ||
2389 | /* Clear the priv in adapter */ | 2675 | /* Clear the priv in adapter */ |
2390 | priv->netdev->ieee80211_ptr = NULL; | 2676 | priv->netdev->ieee80211_ptr = NULL; |
2391 | priv->netdev = NULL; | 2677 | priv->netdev = NULL; |
2392 | kfree(wdev); | 2678 | priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; |
2393 | priv->wdev = NULL; | ||
2394 | 2679 | ||
2395 | priv->media_connected = false; | 2680 | priv->media_connected = false; |
2396 | 2681 | ||
2682 | switch (priv->bss_mode) { | ||
2683 | case NL80211_IFTYPE_UNSPECIFIED: | ||
2684 | case NL80211_IFTYPE_STATION: | ||
2685 | case NL80211_IFTYPE_ADHOC: | ||
2686 | adapter->curr_iface_comb.sta_intf++; | ||
2687 | break; | ||
2688 | case NL80211_IFTYPE_AP: | ||
2689 | adapter->curr_iface_comb.uap_intf++; | ||
2690 | break; | ||
2691 | case NL80211_IFTYPE_P2P_CLIENT: | ||
2692 | case NL80211_IFTYPE_P2P_GO: | ||
2693 | adapter->curr_iface_comb.p2p_intf++; | ||
2694 | break; | ||
2695 | default: | ||
2696 | dev_err(adapter->dev, "del_virtual_intf: type not supported\n"); | ||
2697 | break; | ||
2698 | } | ||
2699 | |||
2397 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | 2700 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; |
2398 | 2701 | ||
2399 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || | 2702 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || |
@@ -2848,6 +3151,102 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
2848 | } | 3151 | } |
2849 | 3152 | ||
2850 | static int | 3153 | static int |
3154 | mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | ||
3155 | struct cfg80211_csa_settings *params) | ||
3156 | { | ||
3157 | struct ieee_types_header *chsw_ie; | ||
3158 | struct ieee80211_channel_sw_ie *channel_sw; | ||
3159 | int chsw_msec; | ||
3160 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
3161 | |||
3162 | if (priv->adapter->scan_processing) { | ||
3163 | dev_err(priv->adapter->dev, | ||
3164 | "radar detection: scan in process...\n"); | ||
3165 | return -EBUSY; | ||
3166 | } | ||
3167 | |||
3168 | if (priv->wdev.cac_started) | ||
3169 | return -EBUSY; | ||
3170 | |||
3171 | if (cfg80211_chandef_identical(¶ms->chandef, | ||
3172 | &priv->dfs_chandef)) | ||
3173 | return -EINVAL; | ||
3174 | |||
3175 | chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH, | ||
3176 | params->beacon_csa.tail, | ||
3177 | params->beacon_csa.tail_len); | ||
3178 | if (!chsw_ie) { | ||
3179 | dev_err(priv->adapter->dev, | ||
3180 | "Could not parse channel switch announcement IE\n"); | ||
3181 | return -EINVAL; | ||
3182 | } | ||
3183 | |||
3184 | channel_sw = (void *)(chsw_ie + 1); | ||
3185 | if (channel_sw->mode) { | ||
3186 | if (netif_carrier_ok(priv->netdev)) | ||
3187 | netif_carrier_off(priv->netdev); | ||
3188 | mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); | ||
3189 | } | ||
3190 | |||
3191 | if (mwifiex_del_mgmt_ies(priv)) | ||
3192 | wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); | ||
3193 | |||
3194 | if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon_csa)) { | ||
3195 | wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__); | ||
3196 | return -EFAULT; | ||
3197 | } | ||
3198 | |||
3199 | memcpy(&priv->dfs_chandef, ¶ms->chandef, sizeof(priv->dfs_chandef)); | ||
3200 | memcpy(&priv->beacon_after, ¶ms->beacon_after, | ||
3201 | sizeof(priv->beacon_after)); | ||
3202 | |||
3203 | chsw_msec = max(channel_sw->count * priv->bss_cfg.beacon_period, 100); | ||
3204 | queue_delayed_work(priv->dfs_chan_sw_workqueue, &priv->dfs_chan_sw_work, | ||
3205 | msecs_to_jiffies(chsw_msec)); | ||
3206 | return 0; | ||
3207 | } | ||
3208 | |||
3209 | static int | ||
3210 | mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy, | ||
3211 | struct net_device *dev, | ||
3212 | struct cfg80211_chan_def *chandef, | ||
3213 | u32 cac_time_ms) | ||
3214 | { | ||
3215 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
3216 | struct mwifiex_radar_params radar_params; | ||
3217 | |||
3218 | if (priv->adapter->scan_processing) { | ||
3219 | dev_err(priv->adapter->dev, | ||
3220 | "radar detection: scan already in process...\n"); | ||
3221 | return -EBUSY; | ||
3222 | } | ||
3223 | |||
3224 | if (!mwifiex_is_11h_active(priv)) { | ||
3225 | dev_dbg(priv->adapter->dev, "Enable 11h extensions in FW\n"); | ||
3226 | if (mwifiex_11h_activate(priv, true)) { | ||
3227 | dev_err(priv->adapter->dev, | ||
3228 | "Failed to activate 11h extensions!!"); | ||
3229 | return -1; | ||
3230 | } | ||
3231 | priv->state_11h.is_11h_active = true; | ||
3232 | } | ||
3233 | |||
3234 | memset(&radar_params, 0, sizeof(struct mwifiex_radar_params)); | ||
3235 | radar_params.chandef = chandef; | ||
3236 | radar_params.cac_time_ms = cac_time_ms; | ||
3237 | |||
3238 | memcpy(&priv->dfs_chandef, chandef, sizeof(priv->dfs_chandef)); | ||
3239 | |||
3240 | if (mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST, | ||
3241 | HostCmd_ACT_GEN_SET, 0, &radar_params, true)) | ||
3242 | return -1; | ||
3243 | |||
3244 | queue_delayed_work(priv->dfs_cac_workqueue, &priv->dfs_cac_work, | ||
3245 | msecs_to_jiffies(cac_time_ms)); | ||
3246 | return 0; | ||
3247 | } | ||
3248 | |||
3249 | static int | ||
2851 | mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, | 3250 | mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, |
2852 | const u8 *mac, | 3251 | const u8 *mac, |
2853 | struct station_parameters *params) | 3252 | struct station_parameters *params) |
@@ -2911,6 +3310,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { | |||
2911 | .tdls_oper = mwifiex_cfg80211_tdls_oper, | 3310 | .tdls_oper = mwifiex_cfg80211_tdls_oper, |
2912 | .add_station = mwifiex_cfg80211_add_station, | 3311 | .add_station = mwifiex_cfg80211_add_station, |
2913 | .change_station = mwifiex_cfg80211_change_station, | 3312 | .change_station = mwifiex_cfg80211_change_station, |
3313 | .start_radar_detection = mwifiex_cfg80211_start_radar_detection, | ||
3314 | .channel_switch = mwifiex_cfg80211_channel_switch, | ||
2914 | }; | 3315 | }; |
2915 | 3316 | ||
2916 | #ifdef CONFIG_PM | 3317 | #ifdef CONFIG_PM |
@@ -3009,12 +3410,13 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) | |||
3009 | wiphy->cipher_suites = mwifiex_cipher_suites; | 3410 | wiphy->cipher_suites = mwifiex_cipher_suites; |
3010 | wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); | 3411 | wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); |
3011 | 3412 | ||
3012 | memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN); | 3413 | ether_addr_copy(wiphy->perm_addr, adapter->perm_addr); |
3013 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 3414 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
3014 | wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | | 3415 | wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | |
3015 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | | 3416 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | |
3016 | WIPHY_FLAG_AP_UAPSD | | 3417 | WIPHY_FLAG_AP_UAPSD | |
3017 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 3418 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | |
3419 | WIPHY_FLAG_HAS_CHANNEL_SWITCH; | ||
3018 | 3420 | ||
3019 | if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) | 3421 | if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) |
3020 | wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | | 3422 | wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | |