blob: 3427fe73d3c3b165b9ed832e52d9f0f9dcc596d9 [file] [log] [blame]
Jouni Malinen6039f6d2009-03-19 13:39:21 +02001/*
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 Berge6d6e342009-07-01 21:26:47 +020015void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020016{
17 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
18 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Berg6829c872009-07-02 09:13:27 +020019
Johannes Berge6d6e342009-07-01 21:26:47 +020020 nl80211_send_rx_auth(rdev, dev, buf, len, gfp);
Johannes Berg6829c872009-07-02 09:13:27 +020021 cfg80211_sme_rx_auth(dev, buf, len);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020022}
23EXPORT_SYMBOL(cfg80211_send_rx_auth);
24
Johannes Berge6d6e342009-07-01 21:26:47 +020025void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020026{
Johannes Berg6829c872009-07-02 09:13:27 +020027 u16 status_code;
28 struct wireless_dev *wdev = dev->ieee80211_ptr;
29 struct wiphy *wiphy = wdev->wiphy;
Jouni Malinen6039f6d2009-03-19 13:39:21 +020030 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Berg6829c872009-07-02 09:13:27 +020031 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 Berge6d6e342009-07-01 21:26:47 +020037 nl80211_send_rx_assoc(rdev, dev, buf, len, gfp);
Johannes Berg6829c872009-07-02 09:13:27 +020038
39 cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
40 status_code, gfp);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020041}
42EXPORT_SYMBOL(cfg80211_send_rx_assoc);
43
Johannes Berge6d6e342009-07-01 21:26:47 +020044void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020045{
Johannes Berg6829c872009-07-02 09:13:27 +020046 struct wireless_dev *wdev = dev->ieee80211_ptr;
47 struct wiphy *wiphy = wdev->wiphy;
Jouni Malinen6039f6d2009-03-19 13:39:21 +020048 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Berg6829c872009-07-02 09:13:27 +020049 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
50
Johannes Berge6d6e342009-07-01 21:26:47 +020051 nl80211_send_deauth(rdev, dev, buf, len, gfp);
Johannes Berg6829c872009-07-02 09:13:27 +020052
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 Malinen6039f6d2009-03-19 13:39:21 +020068}
Jouni Malinen53b46b82009-03-27 20:53:56 +020069EXPORT_SYMBOL(cfg80211_send_deauth);
Jouni Malinen6039f6d2009-03-19 13:39:21 +020070
Johannes Berge6d6e342009-07-01 21:26:47 +020071void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
Jouni Malinen6039f6d2009-03-19 13:39:21 +020072{
Johannes Berg6829c872009-07-02 09:13:27 +020073 struct wireless_dev *wdev = dev->ieee80211_ptr;
74 struct wiphy *wiphy = wdev->wiphy;
Jouni Malinen6039f6d2009-03-19 13:39:21 +020075 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Berg6829c872009-07-02 09:13:27 +020076 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
77
Johannes Berge6d6e342009-07-01 21:26:47 +020078 nl80211_send_disassoc(rdev, dev, buf, len, gfp);
Johannes Berg6829c872009-07-02 09:13:27 +020079
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 Malinen6039f6d2009-03-19 13:39:21 +020092}
Jouni Malinen53b46b82009-03-27 20:53:56 +020093EXPORT_SYMBOL(cfg80211_send_disassoc);
Jouni Malinena3b8b052009-03-27 21:59:49 +020094
Johannes Berge6d6e342009-07-01 21:26:47 +020095void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +030096{
Johannes Berg6829c872009-07-02 09:13:27 +020097 struct wireless_dev *wdev = dev->ieee80211_ptr;
98 struct wiphy *wiphy = wdev->wiphy;
Jouni Malinen1965c852009-04-22 21:38:25 +030099 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Berge6d6e342009-07-01 21:26:47 +0200100 nl80211_send_auth_timeout(rdev, dev, addr, gfp);
Johannes Berg6829c872009-07-02 09:13:27 +0200101 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 Malinen1965c852009-04-22 21:38:25 +0300105}
106EXPORT_SYMBOL(cfg80211_send_auth_timeout);
107
Johannes Berge6d6e342009-07-01 21:26:47 +0200108void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp)
Jouni Malinen1965c852009-04-22 21:38:25 +0300109{
Johannes Berg6829c872009-07-02 09:13:27 +0200110 struct wireless_dev *wdev = dev->ieee80211_ptr;
111 struct wiphy *wiphy = wdev->wiphy;
Jouni Malinen1965c852009-04-22 21:38:25 +0300112 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Berge6d6e342009-07-01 21:26:47 +0200113 nl80211_send_assoc_timeout(rdev, dev, addr, gfp);
Johannes Berg6829c872009-07-02 09:13:27 +0200114 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 Malinen1965c852009-04-22 21:38:25 +0300118}
119EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
120
Jouni Malinena3b8b052009-03-27 21:59:49 +0200121void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
122 enum nl80211_key_type key_type, int key_id,
Johannes Berge6d6e342009-07-01 21:26:47 +0200123 const u8 *tsc, gfp_t gfp)
Jouni Malinena3b8b052009-03-27 21:59:49 +0200124{
125 struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
126 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
Johannes Bergf58d4ed2009-06-19 02:45:21 +0200127#ifdef CONFIG_WIRELESS_EXT
128 union iwreq_data wrqu;
Johannes Berge6d6e342009-07-01 21:26:47 +0200129 char *buf = kmalloc(128, gfp);
Johannes Bergf58d4ed2009-06-19 02:45:21 +0200130
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 Berge6d6e342009-07-01 21:26:47 +0200143 nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
Jouni Malinena3b8b052009-03-27 21:59:49 +0200144}
145EXPORT_SYMBOL(cfg80211_michael_mic_failure);