diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/cfg80211.c')
| -rw-r--r-- | drivers/net/wireless/mwifiex/cfg80211.c | 852 |
1 files changed, 632 insertions, 220 deletions
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 93ab36fc9f93..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; | ||
| 734 | |||
| 735 | return 0; | ||
| 736 | } | ||
| 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 | } | ||
| 735 | 900 | ||
| 901 | adapter->curr_iface_comb.sta_intf++; | ||
| 902 | dev->ieee80211_ptr->iftype = type; | ||
| 736 | return 0; | 903 | return 0; |
| 737 | } | 904 | } |
| 738 | 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 | |||
| 830 | ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, | ||
| 831 | HostCmd_ACT_GEN_SET, 0, NULL, true); | ||
| 832 | 1086 | ||
| 833 | return ret; | 1087 | return 0; |
| 834 | } | 1088 | } |
| 835 | 1089 | ||
| 836 | static void | 1090 | static void |
| @@ -856,16 +1110,16 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo, | |||
| 856 | /* HT or VHT */ | 1110 | /* HT or VHT */ |
| 857 | switch (tx_htinfo & (BIT(3) | BIT(2))) { | 1111 | switch (tx_htinfo & (BIT(3) | BIT(2))) { |
| 858 | case 0: | 1112 | case 0: |
| 859 | /* This will be 20MHz */ | 1113 | rate->bw = RATE_INFO_BW_20; |
| 860 | break; | 1114 | break; |
| 861 | case (BIT(2)): | 1115 | case (BIT(2)): |
| 862 | rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 1116 | rate->bw = RATE_INFO_BW_40; |
| 863 | break; | 1117 | break; |
| 864 | case (BIT(3)): | 1118 | case (BIT(3)): |
| 865 | rate->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | 1119 | rate->bw = RATE_INFO_BW_80; |
| 866 | break; | 1120 | break; |
| 867 | case (BIT(3) | BIT(2)): | 1121 | case (BIT(3) | BIT(2)): |
| 868 | rate->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | 1122 | rate->bw = RATE_INFO_BW_160; |
| 869 | break; | 1123 | break; |
| 870 | } | 1124 | } |
| 871 | 1125 | ||
| @@ -885,8 +1139,9 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo, | |||
| 885 | if ((tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) { | 1139 | if ((tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) { |
| 886 | rate->mcs = priv->tx_rate; | 1140 | rate->mcs = priv->tx_rate; |
| 887 | rate->flags |= RATE_INFO_FLAGS_MCS; | 1141 | rate->flags |= RATE_INFO_FLAGS_MCS; |
| 1142 | rate->bw = RATE_INFO_BW_20; | ||
| 888 | if (tx_htinfo & BIT(1)) | 1143 | if (tx_htinfo & BIT(1)) |
| 889 | rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 1144 | rate->bw = RATE_INFO_BW_40; |
| 890 | if (tx_htinfo & BIT(2)) | 1145 | if (tx_htinfo & BIT(2)) |
| 891 | rate->flags |= RATE_INFO_FLAGS_SHORT_GI; | 1146 | rate->flags |= RATE_INFO_FLAGS_SHORT_GI; |
| 892 | } | 1147 | } |
| @@ -910,10 +1165,10 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, | |||
| 910 | { | 1165 | { |
| 911 | u32 rate; | 1166 | u32 rate; |
| 912 | 1167 | ||
| 913 | sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | | 1168 | sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) | BIT(NL80211_STA_INFO_TX_BYTES) | |
| 914 | STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS | | 1169 | BIT(NL80211_STA_INFO_RX_PACKETS) | BIT(NL80211_STA_INFO_TX_PACKETS) | |
| 915 | STATION_INFO_TX_BITRATE | | 1170 | BIT(NL80211_STA_INFO_TX_BITRATE) | |
| 916 | STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; | 1171 | BIT(NL80211_STA_INFO_SIGNAL) | BIT(NL80211_STA_INFO_SIGNAL_AVG); |
| 917 | 1172 | ||
| 918 | /* Get signal information from the firmware */ | 1173 | /* Get signal information from the firmware */ |
| 919 | if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO, | 1174 | if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO, |
| @@ -944,7 +1199,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, | |||
| 944 | sinfo->txrate.legacy = rate * 5; | 1199 | sinfo->txrate.legacy = rate * 5; |
| 945 | 1200 | ||
| 946 | if (priv->bss_mode == NL80211_IFTYPE_STATION) { | 1201 | if (priv->bss_mode == NL80211_IFTYPE_STATION) { |
| 947 | sinfo->filled |= STATION_INFO_BSS_PARAM; | 1202 | sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); |
| 948 | sinfo->bss_param.flags = 0; | 1203 | sinfo->bss_param.flags = 0; |
| 949 | if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap & | 1204 | if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap & |
| 950 | WLAN_CAPABILITY_SHORT_PREAMBLE) | 1205 | WLAN_CAPABILITY_SHORT_PREAMBLE) |
| @@ -1037,10 +1292,11 @@ mwifiex_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev, | |||
| 1037 | survey->channel = ieee80211_get_channel(wiphy, | 1292 | survey->channel = ieee80211_get_channel(wiphy, |
| 1038 | ieee80211_channel_to_frequency(pchan_stats[idx].chan_num, band)); | 1293 | ieee80211_channel_to_frequency(pchan_stats[idx].chan_num, band)); |
| 1039 | survey->filled = SURVEY_INFO_NOISE_DBM | | 1294 | survey->filled = SURVEY_INFO_NOISE_DBM | |
| 1040 | SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY; | 1295 | SURVEY_INFO_TIME | |
| 1296 | SURVEY_INFO_TIME_BUSY; | ||
| 1041 | survey->noise = pchan_stats[idx].noise; | 1297 | survey->noise = pchan_stats[idx].noise; |
| 1042 | survey->channel_time = pchan_stats[idx].cca_scan_dur; | 1298 | survey->time = pchan_stats[idx].cca_scan_dur; |
| 1043 | survey->channel_time_busy = pchan_stats[idx].cca_busy_dur; | 1299 | survey->time_busy = pchan_stats[idx].cca_busy_dur; |
| 1044 | 1300 | ||
| 1045 | return 0; | 1301 | return 0; |
| 1046 | } | 1302 | } |
| @@ -1395,10 +1651,13 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
| 1395 | { | 1651 | { |
| 1396 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | 1652 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); |
| 1397 | 1653 | ||
| 1654 | mwifiex_abort_cac(priv); | ||
| 1655 | |||
| 1398 | if (mwifiex_del_mgmt_ies(priv)) | 1656 | if (mwifiex_del_mgmt_ies(priv)) |
| 1399 | wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); | 1657 | wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); |
| 1400 | 1658 | ||
| 1401 | priv->ap_11n_enabled = 0; | 1659 | priv->ap_11n_enabled = 0; |
| 1660 | memset(&priv->bss_cfg, 0, sizeof(priv->bss_cfg)); | ||
| 1402 | 1661 | ||
| 1403 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, | 1662 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, |
| 1404 | HostCmd_ACT_GEN_SET, 0, NULL, true)) { | 1663 | HostCmd_ACT_GEN_SET, 0, NULL, true)) { |
| @@ -1420,12 +1679,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, | |||
| 1420 | { | 1679 | { |
| 1421 | struct mwifiex_uap_bss_param *bss_cfg; | 1680 | struct mwifiex_uap_bss_param *bss_cfg; |
| 1422 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | 1681 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); |
| 1423 | u8 config_bands = 0; | ||
| 1424 | 1682 | ||
| 1425 | if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) | 1683 | if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) |
| 1426 | return -1; | 1684 | return -1; |
| 1427 | if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) | ||
| 1428 | return -1; | ||
| 1429 | 1685 | ||
| 1430 | bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); | 1686 | bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); |
| 1431 | if (!bss_cfg) | 1687 | if (!bss_cfg) |
| @@ -1442,6 +1698,11 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, | |||
| 1442 | memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len); | 1698 | memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len); |
| 1443 | bss_cfg->ssid.ssid_len = params->ssid_len; | 1699 | bss_cfg->ssid.ssid_len = params->ssid_len; |
| 1444 | } | 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 | } | ||
| 1445 | 1706 | ||
| 1446 | switch (params->hidden_ssid) { | 1707 | switch (params->hidden_ssid) { |
| 1447 | case NL80211_HIDDEN_SSID_NOT_IN_USE: | 1708 | case NL80211_HIDDEN_SSID_NOT_IN_USE: |
| @@ -1457,33 +1718,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, | |||
| 1457 | return -EINVAL; | 1718 | return -EINVAL; |
| 1458 | } | 1719 | } |
| 1459 | 1720 | ||
| 1460 | bss_cfg->channel = ieee80211_frequency_to_channel( | 1721 | mwifiex_uap_set_channel(bss_cfg, params->chandef); |
| 1461 | params->chandef.chan->center_freq); | ||
| 1462 | |||
| 1463 | /* Set appropriate bands */ | ||
| 1464 | if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) { | ||
| 1465 | bss_cfg->band_cfg = BAND_CONFIG_BG; | ||
| 1466 | config_bands = BAND_B | BAND_G; | ||
| 1467 | |||
| 1468 | if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT) | ||
| 1469 | config_bands |= BAND_GN; | ||
| 1470 | } else { | ||
| 1471 | bss_cfg->band_cfg = BAND_CONFIG_A; | ||
| 1472 | config_bands = BAND_A; | ||
| 1473 | |||
| 1474 | if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT) | ||
| 1475 | config_bands |= BAND_AN; | ||
| 1476 | |||
| 1477 | if (params->chandef.width > NL80211_CHAN_WIDTH_40) | ||
| 1478 | config_bands |= BAND_AAC; | ||
| 1479 | } | ||
| 1480 | |||
| 1481 | if (!((config_bands | priv->adapter->fw_bands) & | ||
| 1482 | ~priv->adapter->fw_bands)) | ||
| 1483 | priv->adapter->config_bands = config_bands; | ||
| 1484 | |||
| 1485 | mwifiex_set_uap_rates(bss_cfg, params); | 1722 | mwifiex_set_uap_rates(bss_cfg, params); |
| 1486 | mwifiex_send_domain_info_cmd_fw(wiphy); | ||
| 1487 | 1723 | ||
| 1488 | if (mwifiex_set_secure_params(priv, bss_cfg, params)) { | 1724 | if (mwifiex_set_secure_params(priv, bss_cfg, params)) { |
| 1489 | kfree(bss_cfg); | 1725 | kfree(bss_cfg); |
| @@ -1506,45 +1742,29 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, | |||
| 1506 | 1742 | ||
| 1507 | mwifiex_set_wmm_params(priv, bss_cfg, params); | 1743 | mwifiex_set_wmm_params(priv, bss_cfg, params); |
| 1508 | 1744 | ||
| 1509 | if (params->inactivity_timeout > 0) { | 1745 | if (mwifiex_is_11h_active(priv) && |
| 1510 | /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ | 1746 | !cfg80211_chandef_dfs_required(wiphy, ¶ms->chandef, |
| 1511 | bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout; | 1747 | priv->bss_mode)) { |
| 1512 | 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; | ||
| 1513 | } | 1755 | } |
| 1514 | 1756 | ||
| 1515 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, | 1757 | if (mwifiex_config_start_uap(priv, bss_cfg)) { |
| 1516 | HostCmd_ACT_GEN_SET, 0, NULL, true)) { | 1758 | wiphy_err(wiphy, "Failed to start AP\n"); |
| 1517 | wiphy_err(wiphy, "Failed to stop the BSS\n"); | ||
| 1518 | kfree(bss_cfg); | 1759 | kfree(bss_cfg); |
| 1519 | return -1; | 1760 | return -1; |
| 1520 | } | 1761 | } |
| 1521 | 1762 | ||
| 1522 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, | 1763 | if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) |
| 1523 | HostCmd_ACT_GEN_SET, | ||
| 1524 | UAP_BSS_PARAMS_I, bss_cfg, false)) { | ||
| 1525 | wiphy_err(wiphy, "Failed to set the SSID\n"); | ||
| 1526 | kfree(bss_cfg); | ||
| 1527 | return -1; | 1764 | return -1; |
| 1528 | } | ||
| 1529 | 1765 | ||
| 1766 | memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg)); | ||
| 1530 | kfree(bss_cfg); | 1767 | kfree(bss_cfg); |
| 1531 | |||
| 1532 | if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, | ||
| 1533 | HostCmd_ACT_GEN_SET, 0, NULL, false)) { | ||
| 1534 | wiphy_err(wiphy, "Failed to start the BSS\n"); | ||
| 1535 | return -1; | ||
| 1536 | } | ||
| 1537 | |||
| 1538 | if (priv->sec_info.wep_enabled) | ||
| 1539 | priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; | ||
| 1540 | else | ||
| 1541 | priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; | ||
| 1542 | |||
| 1543 | if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, | ||
| 1544 | HostCmd_ACT_GEN_SET, 0, | ||
| 1545 | &priv->curr_pkt_filter, true)) | ||
| 1546 | return -1; | ||
| 1547 | |||
| 1548 | return 0; | 1768 | return 0; |
| 1549 | } | 1769 | } |
| 1550 | 1770 | ||
| @@ -1603,15 +1823,15 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) | |||
| 1603 | ie_len = ie_buf[1] + sizeof(struct ieee_types_header); | 1823 | ie_len = ie_buf[1] + sizeof(struct ieee_types_header); |
| 1604 | 1824 | ||
| 1605 | band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); | 1825 | band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); |
| 1606 | chan = __ieee80211_get_channel(priv->wdev->wiphy, | 1826 | chan = __ieee80211_get_channel(priv->wdev.wiphy, |
| 1607 | ieee80211_channel_to_frequency(bss_info.bss_chan, | 1827 | ieee80211_channel_to_frequency(bss_info.bss_chan, |
| 1608 | band)); | 1828 | band)); |
| 1609 | 1829 | ||
| 1610 | bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, | 1830 | bss = cfg80211_inform_bss(priv->wdev.wiphy, chan, |
| 1611 | CFG80211_BSS_FTYPE_UNKNOWN, | 1831 | CFG80211_BSS_FTYPE_UNKNOWN, |
| 1612 | bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, | 1832 | bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, |
| 1613 | 0, ie_buf, ie_len, 0, GFP_KERNEL); | 1833 | 0, ie_buf, ie_len, 0, GFP_KERNEL); |
| 1614 | cfg80211_put_bss(priv->wdev->wiphy, bss); | 1834 | cfg80211_put_bss(priv->wdev.wiphy, bss); |
| 1615 | memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); | 1835 | memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); |
| 1616 | 1836 | ||
| 1617 | return 0; | 1837 | return 0; |
| @@ -1732,12 +1952,12 @@ done: | |||
| 1732 | 1952 | ||
| 1733 | /* Find the BSS we want using available scan results */ | 1953 | /* Find the BSS we want using available scan results */ |
| 1734 | if (mode == NL80211_IFTYPE_ADHOC) | 1954 | if (mode == NL80211_IFTYPE_ADHOC) |
| 1735 | bss = cfg80211_get_bss(priv->wdev->wiphy, channel, | 1955 | bss = cfg80211_get_bss(priv->wdev.wiphy, channel, |
| 1736 | bssid, ssid, ssid_len, | 1956 | bssid, ssid, ssid_len, |
| 1737 | WLAN_CAPABILITY_IBSS, | 1957 | WLAN_CAPABILITY_IBSS, |
| 1738 | WLAN_CAPABILITY_IBSS); | 1958 | WLAN_CAPABILITY_IBSS); |
| 1739 | else | 1959 | else |
| 1740 | bss = cfg80211_get_bss(priv->wdev->wiphy, channel, | 1960 | bss = cfg80211_get_bss(priv->wdev.wiphy, channel, |
| 1741 | bssid, ssid, ssid_len, | 1961 | bssid, ssid, ssid_len, |
| 1742 | WLAN_CAPABILITY_ESS, | 1962 | WLAN_CAPABILITY_ESS, |
| 1743 | WLAN_CAPABILITY_ESS); | 1963 | WLAN_CAPABILITY_ESS); |
| @@ -1784,6 +2004,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
| 1784 | struct cfg80211_connect_params *sme) | 2004 | struct cfg80211_connect_params *sme) |
| 1785 | { | 2005 | { |
| 1786 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | 2006 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); |
| 2007 | struct mwifiex_adapter *adapter = priv->adapter; | ||
| 1787 | int ret; | 2008 | int ret; |
| 1788 | 2009 | ||
| 1789 | if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) { | 2010 | if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) { |
| @@ -1793,11 +2014,18 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
| 1793 | return -EINVAL; | 2014 | return -EINVAL; |
| 1794 | } | 2015 | } |
| 1795 | 2016 | ||
| 1796 | if (priv->wdev && priv->wdev->current_bss) { | 2017 | if (priv->wdev.current_bss) { |
| 1797 | wiphy_warn(wiphy, "%s: already connected\n", dev->name); | 2018 | wiphy_warn(wiphy, "%s: already connected\n", dev->name); |
| 1798 | return -EALREADY; | 2019 | return -EALREADY; |
| 1799 | } | 2020 | } |
| 1800 | 2021 | ||
| 2022 | if (adapter->surprise_removed || adapter->is_cmd_timedout) { | ||
| 2023 | wiphy_err(wiphy, | ||
| 2024 | "%s: Ignore connection. Card removed or FW in bad state\n", | ||
| 2025 | dev->name); | ||
| 2026 | return -EFAULT; | ||
| 2027 | } | ||
| 2028 | |||
| 1801 | wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", | 2029 | wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", |
| 1802 | (char *) sme->ssid, sme->bssid); | 2030 | (char *) sme->ssid, sme->bssid); |
| 1803 | 2031 | ||
| @@ -1844,7 +2072,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
| 1844 | static int mwifiex_set_ibss_params(struct mwifiex_private *priv, | 2072 | static int mwifiex_set_ibss_params(struct mwifiex_private *priv, |
| 1845 | struct cfg80211_ibss_params *params) | 2073 | struct cfg80211_ibss_params *params) |
| 1846 | { | 2074 | { |
| 1847 | struct wiphy *wiphy = priv->wdev->wiphy; | 2075 | struct wiphy *wiphy = priv->wdev.wiphy; |
| 1848 | struct mwifiex_adapter *adapter = priv->adapter; | 2076 | struct mwifiex_adapter *adapter = priv->adapter; |
| 1849 | int index = 0, i; | 2077 | int index = 0, i; |
| 1850 | u8 config_bands = 0; | 2078 | u8 config_bands = 0; |
| @@ -2169,6 +2397,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, | |||
| 2169 | ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | 2397 | ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; |
| 2170 | } | 2398 | } |
| 2171 | 2399 | ||
| 2400 | #define MWIFIEX_MAX_WQ_LEN 30 | ||
| 2172 | /* | 2401 | /* |
| 2173 | * create a new virtual interface with the given name | 2402 | * create a new virtual interface with the given name |
| 2174 | */ | 2403 | */ |
| @@ -2182,7 +2411,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
| 2182 | struct mwifiex_private *priv; | 2411 | struct mwifiex_private *priv; |
| 2183 | struct net_device *dev; | 2412 | struct net_device *dev; |
| 2184 | void *mdev_priv; | 2413 | void *mdev_priv; |
| 2185 | struct wireless_dev *wdev; | 2414 | char dfs_cac_str[MWIFIEX_MAX_WQ_LEN], dfs_chsw_str[MWIFIEX_MAX_WQ_LEN]; |
| 2186 | 2415 | ||
| 2187 | if (!adapter) | 2416 | if (!adapter) |
| 2188 | return ERR_PTR(-EFAULT); | 2417 | return ERR_PTR(-EFAULT); |
| @@ -2191,20 +2420,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
| 2191 | case NL80211_IFTYPE_UNSPECIFIED: | 2420 | case NL80211_IFTYPE_UNSPECIFIED: |
| 2192 | case NL80211_IFTYPE_STATION: | 2421 | case NL80211_IFTYPE_STATION: |
| 2193 | case NL80211_IFTYPE_ADHOC: | 2422 | case NL80211_IFTYPE_ADHOC: |
| 2194 | priv = adapter->priv[MWIFIEX_BSS_TYPE_STA]; | 2423 | if (adapter->curr_iface_comb.sta_intf == |
| 2195 | if (priv->bss_mode) { | 2424 | adapter->iface_limit.sta_intf) { |
| 2196 | wiphy_err(wiphy, | 2425 | wiphy_err(wiphy, |
| 2197 | "cannot create multiple sta/adhoc ifaces\n"); | 2426 | "cannot create multiple sta/adhoc ifaces\n"); |
| 2198 | return ERR_PTR(-EINVAL); | 2427 | return ERR_PTR(-EINVAL); |
| 2199 | } | 2428 | } |
| 2200 | 2429 | ||
| 2201 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | 2430 | priv = mwifiex_get_unused_priv(adapter); |
| 2202 | if (!wdev) | 2431 | if (!priv) { |
| 2203 | return ERR_PTR(-ENOMEM); | 2432 | wiphy_err(wiphy, |
| 2433 | "could not get free private struct\n"); | ||
| 2434 | return ERR_PTR(-EFAULT); | ||
| 2435 | } | ||
| 2204 | 2436 | ||
| 2205 | wdev->wiphy = wiphy; | 2437 | priv->wdev.wiphy = wiphy; |
| 2206 | priv->wdev = wdev; | 2438 | priv->wdev.iftype = NL80211_IFTYPE_STATION; |
| 2207 | wdev->iftype = NL80211_IFTYPE_STATION; | ||
| 2208 | 2439 | ||
| 2209 | if (type == NL80211_IFTYPE_UNSPECIFIED) | 2440 | if (type == NL80211_IFTYPE_UNSPECIFIED) |
| 2210 | priv->bss_mode = NL80211_IFTYPE_STATION; | 2441 | priv->bss_mode = NL80211_IFTYPE_STATION; |
| @@ -2219,20 +2450,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
| 2219 | 2450 | ||
| 2220 | break; | 2451 | break; |
| 2221 | case NL80211_IFTYPE_AP: | 2452 | case NL80211_IFTYPE_AP: |
| 2222 | priv = adapter->priv[MWIFIEX_BSS_TYPE_UAP]; | 2453 | if (adapter->curr_iface_comb.uap_intf == |
| 2223 | 2454 | adapter->iface_limit.uap_intf) { | |
| 2224 | if (priv->bss_mode) { | 2455 | wiphy_err(wiphy, |
| 2225 | wiphy_err(wiphy, "Can't create multiple AP interfaces"); | 2456 | "cannot create multiple AP ifaces\n"); |
| 2226 | return ERR_PTR(-EINVAL); | 2457 | return ERR_PTR(-EINVAL); |
| 2227 | } | 2458 | } |
| 2228 | 2459 | ||
| 2229 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | 2460 | priv = mwifiex_get_unused_priv(adapter); |
| 2230 | if (!wdev) | 2461 | if (!priv) { |
| 2231 | return ERR_PTR(-ENOMEM); | 2462 | wiphy_err(wiphy, |
| 2463 | "could not get free private struct\n"); | ||
| 2464 | return ERR_PTR(-EFAULT); | ||
| 2465 | } | ||
| 2232 | 2466 | ||
| 2233 | priv->wdev = wdev; | 2467 | priv->wdev.wiphy = wiphy; |
| 2234 | wdev->wiphy = wiphy; | 2468 | priv->wdev.iftype = NL80211_IFTYPE_AP; |
| 2235 | wdev->iftype = NL80211_IFTYPE_AP; | ||
| 2236 | 2469 | ||
| 2237 | priv->bss_type = MWIFIEX_BSS_TYPE_UAP; | 2470 | priv->bss_type = MWIFIEX_BSS_TYPE_UAP; |
| 2238 | priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; | 2471 | priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; |
| @@ -2244,24 +2477,25 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
| 2244 | 2477 | ||
| 2245 | break; | 2478 | break; |
| 2246 | case NL80211_IFTYPE_P2P_CLIENT: | 2479 | case NL80211_IFTYPE_P2P_CLIENT: |
| 2247 | priv = adapter->priv[MWIFIEX_BSS_TYPE_P2P]; | 2480 | if (adapter->curr_iface_comb.p2p_intf == |
| 2248 | 2481 | adapter->iface_limit.p2p_intf) { | |
| 2249 | if (priv->bss_mode) { | 2482 | wiphy_err(wiphy, |
| 2250 | wiphy_err(wiphy, "Can't create multiple P2P ifaces"); | 2483 | "cannot create multiple P2P ifaces\n"); |
| 2251 | return ERR_PTR(-EINVAL); | 2484 | return ERR_PTR(-EINVAL); |
| 2252 | } | 2485 | } |
| 2253 | 2486 | ||
| 2254 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | 2487 | priv = mwifiex_get_unused_priv(adapter); |
| 2255 | if (!wdev) | 2488 | if (!priv) { |
| 2256 | return ERR_PTR(-ENOMEM); | 2489 | wiphy_err(wiphy, |
| 2257 | 2490 | "could not get free private struct\n"); | |
| 2258 | priv->wdev = wdev; | 2491 | return ERR_PTR(-EFAULT); |
| 2259 | wdev->wiphy = wiphy; | 2492 | } |
| 2260 | 2493 | ||
| 2494 | priv->wdev.wiphy = wiphy; | ||
| 2261 | /* At start-up, wpa_supplicant tries to change the interface | 2495 | /* At start-up, wpa_supplicant tries to change the interface |
| 2262 | * to NL80211_IFTYPE_STATION if it is not managed mode. | 2496 | * to NL80211_IFTYPE_STATION if it is not managed mode. |
| 2263 | */ | 2497 | */ |
| 2264 | wdev->iftype = NL80211_IFTYPE_P2P_CLIENT; | 2498 | priv->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT; |
| 2265 | priv->bss_mode = NL80211_IFTYPE_P2P_CLIENT; | 2499 | priv->bss_mode = NL80211_IFTYPE_P2P_CLIENT; |
| 2266 | 2500 | ||
| 2267 | /* Setting bss_type to P2P tells firmware that this interface | 2501 | /* Setting bss_type to P2P tells firmware that this interface |
| @@ -2277,8 +2511,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
| 2277 | priv->bss_num = 0; | 2511 | priv->bss_num = 0; |
| 2278 | 2512 | ||
| 2279 | if (mwifiex_cfg80211_init_p2p_client(priv)) { | 2513 | if (mwifiex_cfg80211_init_p2p_client(priv)) { |
| 2280 | wdev = ERR_PTR(-EFAULT); | 2514 | memset(&priv->wdev, 0, sizeof(priv->wdev)); |
| 2281 | goto done; | 2515 | priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; |
| 2516 | return ERR_PTR(-EFAULT); | ||
| 2282 | } | 2517 | } |
| 2283 | 2518 | ||
| 2284 | break; | 2519 | break; |
| @@ -2292,9 +2527,10 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
| 2292 | IEEE80211_NUM_ACS, 1); | 2527 | IEEE80211_NUM_ACS, 1); |
| 2293 | if (!dev) { | 2528 | if (!dev) { |
| 2294 | 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; | ||
| 2295 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | 2532 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; |
| 2296 | wdev = ERR_PTR(-ENOMEM); | 2533 | return ERR_PTR(-ENOMEM); |
| 2297 | goto done; | ||
| 2298 | } | 2534 | } |
| 2299 | 2535 | ||
| 2300 | mwifiex_init_priv_params(priv, dev); | 2536 | mwifiex_init_priv_params(priv, dev); |
| @@ -2314,7 +2550,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
| 2314 | &wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv); | 2550 | &wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv); |
| 2315 | 2551 | ||
| 2316 | dev_net_set(dev, wiphy_net(wiphy)); | 2552 | dev_net_set(dev, wiphy_net(wiphy)); |
| 2317 | dev->ieee80211_ptr = priv->wdev; | 2553 | dev->ieee80211_ptr = &priv->wdev; |
| 2318 | dev->ieee80211_ptr->iftype = priv->bss_mode; | 2554 | dev->ieee80211_ptr->iftype = priv->bss_mode; |
| 2319 | memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); | 2555 | memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); |
| 2320 | SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); | 2556 | SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); |
| @@ -2335,10 +2571,47 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
| 2335 | free_netdev(dev); | 2571 | free_netdev(dev); |
| 2336 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | 2572 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; |
| 2337 | priv->netdev = NULL; | 2573 | priv->netdev = NULL; |
| 2338 | wdev = ERR_PTR(-EFAULT); | 2574 | memset(&priv->wdev, 0, sizeof(priv->wdev)); |
| 2339 | 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); | ||
| 2340 | } | 2610 | } |
| 2341 | 2611 | ||
| 2612 | INIT_DELAYED_WORK(&priv->dfs_chan_sw_work, | ||
| 2613 | mwifiex_dfs_chan_sw_work_queue); | ||
| 2614 | |||
| 2342 | sema_init(&priv->async_sem, 1); | 2615 | sema_init(&priv->async_sem, 1); |
| 2343 | 2616 | ||
| 2344 | 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); |
| @@ -2347,13 +2620,24 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | |||
| 2347 | mwifiex_dev_debugfs_init(priv); | 2620 | mwifiex_dev_debugfs_init(priv); |
| 2348 | #endif | 2621 | #endif |
| 2349 | 2622 | ||
| 2350 | done: | 2623 | switch (type) { |
| 2351 | if (IS_ERR(wdev)) { | 2624 | case NL80211_IFTYPE_UNSPECIFIED: |
| 2352 | kfree(priv->wdev); | 2625 | case NL80211_IFTYPE_STATION: |
| 2353 | 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); | ||
| 2354 | } | 2638 | } |
| 2355 | 2639 | ||
| 2356 | return wdev; | 2640 | return &priv->wdev; |
| 2357 | } | 2641 | } |
| 2358 | EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); | 2642 | EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); |
| 2359 | 2643 | ||
| @@ -2363,12 +2647,13 @@ EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); | |||
| 2363 | 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) |
| 2364 | { | 2648 | { |
| 2365 | 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; | ||
| 2366 | 2651 | ||
| 2367 | #ifdef CONFIG_DEBUG_FS | 2652 | #ifdef CONFIG_DEBUG_FS |
| 2368 | mwifiex_dev_debugfs_remove(priv); | 2653 | mwifiex_dev_debugfs_remove(priv); |
| 2369 | #endif | 2654 | #endif |
| 2370 | 2655 | ||
| 2371 | mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); | 2656 | mwifiex_stop_net_dev_queue(priv->netdev, adapter); |
| 2372 | 2657 | ||
| 2373 | if (netif_carrier_ok(priv->netdev)) | 2658 | if (netif_carrier_ok(priv->netdev)) |
| 2374 | netif_carrier_off(priv->netdev); | 2659 | netif_carrier_off(priv->netdev); |
| @@ -2376,14 +2661,42 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) | |||
| 2376 | if (wdev->netdev->reg_state == NETREG_REGISTERED) | 2661 | if (wdev->netdev->reg_state == NETREG_REGISTERED) |
| 2377 | unregister_netdevice(wdev->netdev); | 2662 | unregister_netdevice(wdev->netdev); |
| 2378 | 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 | } | ||
| 2379 | /* Clear the priv in adapter */ | 2675 | /* Clear the priv in adapter */ |
| 2380 | priv->netdev->ieee80211_ptr = NULL; | 2676 | priv->netdev->ieee80211_ptr = NULL; |
| 2381 | priv->netdev = NULL; | 2677 | priv->netdev = NULL; |
| 2382 | kfree(wdev); | 2678 | priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; |
| 2383 | priv->wdev = NULL; | ||
| 2384 | 2679 | ||
| 2385 | priv->media_connected = false; | 2680 | priv->media_connected = false; |
| 2386 | 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 | |||
| 2387 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | 2700 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; |
| 2388 | 2701 | ||
| 2389 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || | 2702 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || |
| @@ -2838,6 +3151,102 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
| 2838 | } | 3151 | } |
| 2839 | 3152 | ||
| 2840 | 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 | ||
| 2841 | mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, | 3250 | mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, |
| 2842 | const u8 *mac, | 3251 | const u8 *mac, |
| 2843 | struct station_parameters *params) | 3252 | struct station_parameters *params) |
| @@ -2901,6 +3310,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { | |||
| 2901 | .tdls_oper = mwifiex_cfg80211_tdls_oper, | 3310 | .tdls_oper = mwifiex_cfg80211_tdls_oper, |
| 2902 | .add_station = mwifiex_cfg80211_add_station, | 3311 | .add_station = mwifiex_cfg80211_add_station, |
| 2903 | .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, | ||
| 2904 | }; | 3315 | }; |
| 2905 | 3316 | ||
| 2906 | #ifdef CONFIG_PM | 3317 | #ifdef CONFIG_PM |
| @@ -2999,12 +3410,13 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) | |||
| 2999 | wiphy->cipher_suites = mwifiex_cipher_suites; | 3410 | wiphy->cipher_suites = mwifiex_cipher_suites; |
| 3000 | wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); | 3411 | wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); |
| 3001 | 3412 | ||
| 3002 | memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN); | 3413 | ether_addr_copy(wiphy->perm_addr, adapter->perm_addr); |
| 3003 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 3414 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
| 3004 | wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | | 3415 | wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | |
| 3005 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | | 3416 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | |
| 3006 | WIPHY_FLAG_AP_UAPSD | | 3417 | WIPHY_FLAG_AP_UAPSD | |
| 3007 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 3418 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | |
| 3419 | WIPHY_FLAG_HAS_CHANNEL_SWITCH; | ||
| 3008 | 3420 | ||
| 3009 | if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) | 3421 | if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) |
| 3010 | wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | | 3422 | wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | |
