Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 1 | /* |
| 2 | * cfg80211 MLME SAP interface |
| 3 | * |
| 4 | * Copyright (c) 2009, Jouni Malinen <j@w1.fi> |
| 5 | */ |
| 6 | |
| 7 | #include <linux/kernel.h> |
| 8 | #include <linux/module.h> |
| 9 | #include <linux/netdevice.h> |
| 10 | #include <linux/nl80211.h> |
| 11 | #include <net/cfg80211.h> |
| 12 | #include "core.h" |
| 13 | #include "nl80211.h" |
| 14 | |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 15 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 16 | { |
| 17 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; |
| 18 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 19 | |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 20 | nl80211_send_rx_auth(rdev, dev, buf, len, gfp); |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 21 | cfg80211_sme_rx_auth(dev, buf, len); |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 22 | } |
| 23 | EXPORT_SYMBOL(cfg80211_send_rx_auth); |
| 24 | |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 25 | void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 26 | { |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 27 | u16 status_code; |
| 28 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 29 | struct wiphy *wiphy = wdev->wiphy; |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 30 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 31 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
| 32 | u8 *ie = mgmt->u.assoc_resp.variable; |
| 33 | int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); |
| 34 | |
| 35 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
| 36 | |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 37 | nl80211_send_rx_assoc(rdev, dev, buf, len, gfp); |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 38 | |
| 39 | cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, |
| 40 | status_code, gfp); |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 41 | } |
| 42 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); |
| 43 | |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 44 | void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 45 | { |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 46 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 47 | struct wiphy *wiphy = wdev->wiphy; |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 48 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 49 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
| 50 | |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 51 | nl80211_send_deauth(rdev, dev, buf, len, gfp); |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 52 | |
| 53 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { |
| 54 | u16 reason_code; |
| 55 | bool from_ap; |
| 56 | |
| 57 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
| 58 | |
| 59 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; |
| 60 | __cfg80211_disconnected(dev, gfp, NULL, 0, |
| 61 | reason_code, from_ap); |
| 62 | |
| 63 | wdev->sme_state = CFG80211_SME_IDLE; |
| 64 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { |
| 65 | cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, |
| 66 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); |
| 67 | } |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 68 | } |
Jouni Malinen | 53b46b8 | 2009-03-27 20:53:56 +0200 | [diff] [blame] | 69 | EXPORT_SYMBOL(cfg80211_send_deauth); |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 70 | |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 71 | void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 72 | { |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 73 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 74 | struct wiphy *wiphy = wdev->wiphy; |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 75 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 76 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
| 77 | |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 78 | nl80211_send_disassoc(rdev, dev, buf, len, gfp); |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 79 | |
| 80 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { |
| 81 | u16 reason_code; |
| 82 | bool from_ap; |
| 83 | |
| 84 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
| 85 | |
| 86 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; |
| 87 | __cfg80211_disconnected(dev, gfp, NULL, 0, |
| 88 | reason_code, from_ap); |
| 89 | |
| 90 | wdev->sme_state = CFG80211_SME_IDLE; |
| 91 | } |
Jouni Malinen | 6039f6d | 2009-03-19 13:39:21 +0200 | [diff] [blame] | 92 | } |
Jouni Malinen | 53b46b8 | 2009-03-27 20:53:56 +0200 | [diff] [blame] | 93 | EXPORT_SYMBOL(cfg80211_send_disassoc); |
Jouni Malinen | a3b8b05 | 2009-03-27 21:59:49 +0200 | [diff] [blame] | 94 | |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 95 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) |
Jouni Malinen | 1965c85 | 2009-04-22 21:38:25 +0300 | [diff] [blame] | 96 | { |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 97 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 98 | struct wiphy *wiphy = wdev->wiphy; |
Jouni Malinen | 1965c85 | 2009-04-22 21:38:25 +0300 | [diff] [blame] | 99 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 100 | nl80211_send_auth_timeout(rdev, dev, addr, gfp); |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 101 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
| 102 | cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
| 103 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); |
| 104 | wdev->sme_state = CFG80211_SME_IDLE; |
Jouni Malinen | 1965c85 | 2009-04-22 21:38:25 +0300 | [diff] [blame] | 105 | } |
| 106 | EXPORT_SYMBOL(cfg80211_send_auth_timeout); |
| 107 | |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 108 | void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) |
Jouni Malinen | 1965c85 | 2009-04-22 21:38:25 +0300 | [diff] [blame] | 109 | { |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 110 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 111 | struct wiphy *wiphy = wdev->wiphy; |
Jouni Malinen | 1965c85 | 2009-04-22 21:38:25 +0300 | [diff] [blame] | 112 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 113 | nl80211_send_assoc_timeout(rdev, dev, addr, gfp); |
Johannes Berg | 6829c878 | 2009-07-02 09:13:27 +0200 | [diff] [blame] | 114 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
| 115 | cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
| 116 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); |
| 117 | wdev->sme_state = CFG80211_SME_IDLE; |
Jouni Malinen | 1965c85 | 2009-04-22 21:38:25 +0300 | [diff] [blame] | 118 | } |
| 119 | EXPORT_SYMBOL(cfg80211_send_assoc_timeout); |
| 120 | |
Jouni Malinen | a3b8b05 | 2009-03-27 21:59:49 +0200 | [diff] [blame] | 121 | void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, |
| 122 | enum nl80211_key_type key_type, int key_id, |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 123 | const u8 *tsc, gfp_t gfp) |
Jouni Malinen | a3b8b05 | 2009-03-27 21:59:49 +0200 | [diff] [blame] | 124 | { |
| 125 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; |
| 126 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
Johannes Berg | f58d4ed | 2009-06-19 02:45:21 +0200 | [diff] [blame] | 127 | #ifdef CONFIG_WIRELESS_EXT |
| 128 | union iwreq_data wrqu; |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 129 | char *buf = kmalloc(128, gfp); |
Johannes Berg | f58d4ed | 2009-06-19 02:45:21 +0200 | [diff] [blame] | 130 | |
| 131 | if (buf) { |
| 132 | sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" |
| 133 | "keyid=%d %scast addr=%pM)", key_id, |
| 134 | key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni", |
| 135 | addr); |
| 136 | memset(&wrqu, 0, sizeof(wrqu)); |
| 137 | wrqu.data.length = strlen(buf); |
| 138 | wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); |
| 139 | kfree(buf); |
| 140 | } |
| 141 | #endif |
| 142 | |
Johannes Berg | e6d6e34 | 2009-07-01 21:26:47 +0200 | [diff] [blame] | 143 | nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp); |
Jouni Malinen | a3b8b05 | 2009-03-27 21:59:49 +0200 | [diff] [blame] | 144 | } |
| 145 | EXPORT_SYMBOL(cfg80211_michael_mic_failure); |