aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2010-12-15 17:52:40 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-12-16 15:22:30 -0500
commitcf4e594ea7e55555e81647b74a3a8e8b2826a529 (patch)
tree794013429d9613ef253111fb50f993600ab14a55
parent5928b91acae97622a6f2e679eb7a9f19bed68e3e (diff)
nl80211: Add notification for dropped Deauth/Disassoc
Add a new notification to indicate that a received, unprotected Deauthentication or Disassociation frame was dropped due to management frame protection being in use. This notification is needed to allow user space (e.g., wpa_supplicant) to implement SA Query procedure to recover from association state mismatch between an AP and STA. This is needed to avoid getting stuck in non-working state when MFP (IEEE 802.11w) is used and a protected Deauthentication or Disassociation frame is dropped for any reason. After that, the station would silently discard any unprotected Deauthentication or Disassociation frame that could be indicating that the AP does not have association for the STA (when the Reason Code would be 6 or 7). IEEE Std 802.11w-2009, 11.13 describes this recovery mechanism. Signed-off-by: Jouni Malinen <j@w1.fi> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/linux/nl80211.h10
-rw-r--r--include/net/cfg80211.h26
-rw-r--r--net/mac80211/rx.c22
-rw-r--r--net/wireless/mlme.c22
-rw-r--r--net/wireless/nl80211.c16
-rw-r--r--net/wireless/nl80211.h6
6 files changed, 100 insertions, 2 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 1cee56b3a79a..7483a89cee8f 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -399,6 +399,13 @@
399 * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the 399 * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
400 * network is determined by the network interface. 400 * network is determined by the network interface.
401 * 401 *
402 * @NL80211_CMD_UNPROT_DEAUTHENTICATE: Unprotected deauthentication frame
403 * notification. This event is used to indicate that an unprotected
404 * deauthentication frame was dropped when MFP is in use.
405 * @NL80211_CMD_UNPROT_DISASSOCIATE: Unprotected disassociation frame
406 * notification. This event is used to indicate that an unprotected
407 * disassociation frame was dropped when MFP is in use.
408 *
402 * @NL80211_CMD_MAX: highest used command number 409 * @NL80211_CMD_MAX: highest used command number
403 * @__NL80211_CMD_AFTER_LAST: internal use 410 * @__NL80211_CMD_AFTER_LAST: internal use
404 */ 411 */
@@ -508,6 +515,9 @@ enum nl80211_commands {
508 NL80211_CMD_JOIN_MESH, 515 NL80211_CMD_JOIN_MESH,
509 NL80211_CMD_LEAVE_MESH, 516 NL80211_CMD_LEAVE_MESH,
510 517
518 NL80211_CMD_UNPROT_DEAUTHENTICATE,
519 NL80211_CMD_UNPROT_DISASSOCIATE,
520
511 /* add new commands above here */ 521 /* add new commands above here */
512 522
513 /* used to define NL80211_CMD_MAX below */ 523 /* used to define NL80211_CMD_MAX below */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f45e15f12446..3d1c09b777e8 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2360,6 +2360,32 @@ void __cfg80211_send_disassoc(struct net_device *dev, const u8 *buf,
2360 size_t len); 2360 size_t len);
2361 2361
2362/** 2362/**
2363 * cfg80211_send_unprot_deauth - notification of unprotected deauthentication
2364 * @dev: network device
2365 * @buf: deauthentication frame (header + body)
2366 * @len: length of the frame data
2367 *
2368 * This function is called whenever a received Deauthentication frame has been
2369 * dropped in station mode because of MFP being used but the Deauthentication
2370 * frame was not protected. This function may sleep.
2371 */
2372void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
2373 size_t len);
2374
2375/**
2376 * cfg80211_send_unprot_disassoc - notification of unprotected disassociation
2377 * @dev: network device
2378 * @buf: disassociation frame (header + body)
2379 * @len: length of the frame data
2380 *
2381 * This function is called whenever a received Disassociation frame has been
2382 * dropped in station mode because of MFP being used but the Disassociation
2383 * frame was not protected. This function may sleep.
2384 */
2385void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
2386 size_t len);
2387
2388/**
2363 * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP) 2389 * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP)
2364 * @dev: network device 2390 * @dev: network device
2365 * @addr: The source MAC address of the frame 2391 * @addr: The source MAC address of the frame
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 052789ef4745..4573ce1e1d15 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1540,12 +1540,30 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
1540 if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { 1540 if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
1541 if (unlikely(!ieee80211_has_protected(fc) && 1541 if (unlikely(!ieee80211_has_protected(fc) &&
1542 ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && 1542 ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
1543 rx->key)) 1543 rx->key)) {
1544 if (ieee80211_is_deauth(fc))
1545 cfg80211_send_unprot_deauth(rx->sdata->dev,
1546 rx->skb->data,
1547 rx->skb->len);
1548 else if (ieee80211_is_disassoc(fc))
1549 cfg80211_send_unprot_disassoc(rx->sdata->dev,
1550 rx->skb->data,
1551 rx->skb->len);
1544 return -EACCES; 1552 return -EACCES;
1553 }
1545 /* BIP does not use Protected field, so need to check MMIE */ 1554 /* BIP does not use Protected field, so need to check MMIE */
1546 if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && 1555 if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
1547 ieee80211_get_mmie_keyidx(rx->skb) < 0)) 1556 ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
1557 if (ieee80211_is_deauth(fc))
1558 cfg80211_send_unprot_deauth(rx->sdata->dev,
1559 rx->skb->data,
1560 rx->skb->len);
1561 else if (ieee80211_is_disassoc(fc))
1562 cfg80211_send_unprot_disassoc(rx->sdata->dev,
1563 rx->skb->data,
1564 rx->skb->len);
1548 return -EACCES; 1565 return -EACCES;
1566 }
1549 /* 1567 /*
1550 * When using MFP, Action frames are not allowed prior to 1568 * When using MFP, Action frames are not allowed prior to
1551 * having configured keys. 1569 * having configured keys.
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index d7680f2a4c5b..aa5df8865ff7 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -263,6 +263,28 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
263} 263}
264EXPORT_SYMBOL(cfg80211_send_disassoc); 264EXPORT_SYMBOL(cfg80211_send_disassoc);
265 265
266void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
267 size_t len)
268{
269 struct wireless_dev *wdev = dev->ieee80211_ptr;
270 struct wiphy *wiphy = wdev->wiphy;
271 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
272
273 nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC);
274}
275EXPORT_SYMBOL(cfg80211_send_unprot_deauth);
276
277void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
278 size_t len)
279{
280 struct wireless_dev *wdev = dev->ieee80211_ptr;
281 struct wiphy *wiphy = wdev->wiphy;
282 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
283
284 nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC);
285}
286EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
287
266static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr) 288static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr)
267{ 289{
268 int i; 290 int i;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 594a6ac8b9d2..aefce54d47e2 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5473,6 +5473,22 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
5473 NL80211_CMD_DISASSOCIATE, gfp); 5473 NL80211_CMD_DISASSOCIATE, gfp);
5474} 5474}
5475 5475
5476void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev,
5477 struct net_device *netdev, const u8 *buf,
5478 size_t len, gfp_t gfp)
5479{
5480 nl80211_send_mlme_event(rdev, netdev, buf, len,
5481 NL80211_CMD_UNPROT_DEAUTHENTICATE, gfp);
5482}
5483
5484void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev,
5485 struct net_device *netdev, const u8 *buf,
5486 size_t len, gfp_t gfp)
5487{
5488 nl80211_send_mlme_event(rdev, netdev, buf, len,
5489 NL80211_CMD_UNPROT_DISASSOCIATE, gfp);
5490}
5491
5476static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, 5492static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
5477 struct net_device *netdev, int cmd, 5493 struct net_device *netdev, int cmd,
5478 const u8 *addr, gfp_t gfp) 5494 const u8 *addr, gfp_t gfp)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 16c2f7190768..e3f7fa886966 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -25,6 +25,12 @@ void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
25void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, 25void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
26 struct net_device *netdev, 26 struct net_device *netdev,
27 const u8 *buf, size_t len, gfp_t gfp); 27 const u8 *buf, size_t len, gfp_t gfp);
28void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev,
29 struct net_device *netdev,
30 const u8 *buf, size_t len, gfp_t gfp);
31void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev,
32 struct net_device *netdev,
33 const u8 *buf, size_t len, gfp_t gfp);
28void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, 34void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
29 struct net_device *netdev, 35 struct net_device *netdev,
30 const u8 *addr, gfp_t gfp); 36 const u8 *addr, gfp_t gfp);