aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/mlme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/mlme.c')
-rw-r--r--net/wireless/mlme.c214
1 files changed, 212 insertions, 2 deletions
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 82e6002c8d67..62bc8855e123 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -148,22 +148,23 @@ void __cfg80211_send_deauth(struct net_device *dev,
148 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 148 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
149 const u8 *bssid = mgmt->bssid; 149 const u8 *bssid = mgmt->bssid;
150 int i; 150 int i;
151 bool found = false;
151 152
152 ASSERT_WDEV_LOCK(wdev); 153 ASSERT_WDEV_LOCK(wdev);
153 154
154 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
155
156 if (wdev->current_bss && 155 if (wdev->current_bss &&
157 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { 156 memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
158 cfg80211_unhold_bss(wdev->current_bss); 157 cfg80211_unhold_bss(wdev->current_bss);
159 cfg80211_put_bss(&wdev->current_bss->pub); 158 cfg80211_put_bss(&wdev->current_bss->pub);
160 wdev->current_bss = NULL; 159 wdev->current_bss = NULL;
160 found = true;
161 } else for (i = 0; i < MAX_AUTH_BSSES; i++) { 161 } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
162 if (wdev->auth_bsses[i] && 162 if (wdev->auth_bsses[i] &&
163 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { 163 memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
164 cfg80211_unhold_bss(wdev->auth_bsses[i]); 164 cfg80211_unhold_bss(wdev->auth_bsses[i]);
165 cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 165 cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
166 wdev->auth_bsses[i] = NULL; 166 wdev->auth_bsses[i] = NULL;
167 found = true;
167 break; 168 break;
168 } 169 }
169 if (wdev->authtry_bsses[i] && 170 if (wdev->authtry_bsses[i] &&
@@ -171,10 +172,16 @@ void __cfg80211_send_deauth(struct net_device *dev,
171 cfg80211_unhold_bss(wdev->authtry_bsses[i]); 172 cfg80211_unhold_bss(wdev->authtry_bsses[i]);
172 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 173 cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
173 wdev->authtry_bsses[i] = NULL; 174 wdev->authtry_bsses[i] = NULL;
175 found = true;
174 break; 176 break;
175 } 177 }
176 } 178 }
177 179
180 if (!found)
181 return;
182
183 nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
184
178 if (wdev->sme_state == CFG80211_SME_CONNECTED) { 185 if (wdev->sme_state == CFG80211_SME_CONNECTED) {
179 u16 reason_code; 186 u16 reason_code;
180 bool from_ap; 187 bool from_ap;
@@ -684,3 +691,206 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
684 } 691 }
685 } 692 }
686} 693}
694
695void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
696 struct ieee80211_channel *chan,
697 enum nl80211_channel_type channel_type,
698 unsigned int duration, gfp_t gfp)
699{
700 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
701 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
702
703 nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type,
704 duration, gfp);
705}
706EXPORT_SYMBOL(cfg80211_ready_on_channel);
707
708void cfg80211_remain_on_channel_expired(struct net_device *dev,
709 u64 cookie,
710 struct ieee80211_channel *chan,
711 enum nl80211_channel_type channel_type,
712 gfp_t gfp)
713{
714 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
715 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
716
717 nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan,
718 channel_type, gfp);
719}
720EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
721
722void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
723 struct station_info *sinfo, gfp_t gfp)
724{
725 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
726 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
727
728 nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
729}
730EXPORT_SYMBOL(cfg80211_new_sta);
731
732struct cfg80211_action_registration {
733 struct list_head list;
734
735 u32 nlpid;
736
737 int match_len;
738
739 u8 match[];
740};
741
742int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
743 const u8 *match_data, int match_len)
744{
745 struct cfg80211_action_registration *reg, *nreg;
746 int err = 0;
747
748 nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
749 if (!nreg)
750 return -ENOMEM;
751
752 spin_lock_bh(&wdev->action_registrations_lock);
753
754 list_for_each_entry(reg, &wdev->action_registrations, list) {
755 int mlen = min(match_len, reg->match_len);
756
757 if (memcmp(reg->match, match_data, mlen) == 0) {
758 err = -EALREADY;
759 break;
760 }
761 }
762
763 if (err) {
764 kfree(nreg);
765 goto out;
766 }
767
768 memcpy(nreg->match, match_data, match_len);
769 nreg->match_len = match_len;
770 nreg->nlpid = snd_pid;
771 list_add(&nreg->list, &wdev->action_registrations);
772
773 out:
774 spin_unlock_bh(&wdev->action_registrations_lock);
775 return err;
776}
777
778void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid)
779{
780 struct cfg80211_action_registration *reg, *tmp;
781
782 spin_lock_bh(&wdev->action_registrations_lock);
783
784 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
785 if (reg->nlpid == nlpid) {
786 list_del(&reg->list);
787 kfree(reg);
788 }
789 }
790
791 spin_unlock_bh(&wdev->action_registrations_lock);
792}
793
794void cfg80211_mlme_purge_actions(struct wireless_dev *wdev)
795{
796 struct cfg80211_action_registration *reg, *tmp;
797
798 spin_lock_bh(&wdev->action_registrations_lock);
799
800 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
801 list_del(&reg->list);
802 kfree(reg);
803 }
804
805 spin_unlock_bh(&wdev->action_registrations_lock);
806}
807
808int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
809 struct net_device *dev,
810 struct ieee80211_channel *chan,
811 enum nl80211_channel_type channel_type,
812 const u8 *buf, size_t len, u64 *cookie)
813{
814 struct wireless_dev *wdev = dev->ieee80211_ptr;
815 const struct ieee80211_mgmt *mgmt;
816
817 if (rdev->ops->action == NULL)
818 return -EOPNOTSUPP;
819 if (len < 24 + 1)
820 return -EINVAL;
821
822 mgmt = (const struct ieee80211_mgmt *) buf;
823 if (!ieee80211_is_action(mgmt->frame_control))
824 return -EINVAL;
825 if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
826 /* Verify that we are associated with the destination AP */
827 if (!wdev->current_bss ||
828 memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
829 ETH_ALEN) != 0 ||
830 memcmp(wdev->current_bss->pub.bssid, mgmt->da,
831 ETH_ALEN) != 0)
832 return -ENOTCONN;
833 }
834
835 if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
836 return -EINVAL;
837
838 /* Transmit the Action frame as requested by user space */
839 return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
840 buf, len, cookie);
841}
842
843bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
844 size_t len, gfp_t gfp)
845{
846 struct wireless_dev *wdev = dev->ieee80211_ptr;
847 struct wiphy *wiphy = wdev->wiphy;
848 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
849 struct cfg80211_action_registration *reg;
850 const u8 *action_data;
851 int action_data_len;
852 bool result = false;
853
854 /* frame length - min size excluding category */
855 action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1);
856
857 /* action data starts with category */
858 action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1;
859
860 spin_lock_bh(&wdev->action_registrations_lock);
861
862 list_for_each_entry(reg, &wdev->action_registrations, list) {
863 if (reg->match_len > action_data_len)
864 continue;
865
866 if (memcmp(reg->match, action_data, reg->match_len))
867 continue;
868
869 /* found match! */
870
871 /* Indicate the received Action frame to user space */
872 if (nl80211_send_action(rdev, dev, reg->nlpid, freq,
873 buf, len, gfp))
874 continue;
875
876 result = true;
877 break;
878 }
879
880 spin_unlock_bh(&wdev->action_registrations_lock);
881
882 return result;
883}
884EXPORT_SYMBOL(cfg80211_rx_action);
885
886void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
887 const u8 *buf, size_t len, bool ack, gfp_t gfp)
888{
889 struct wireless_dev *wdev = dev->ieee80211_ptr;
890 struct wiphy *wiphy = wdev->wiphy;
891 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
892
893 /* Indicate TX status of the Action frame to user space */
894 nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
895}
896EXPORT_SYMBOL(cfg80211_action_tx_status);