1 /*
2 * Control interface for shared AP commands
3 * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "utils/includes.h"
10
11 #include "utils/common.h"
12 #include "common/ieee802_11_defs.h"
13 #include "hostapd.h"
14 #include "ieee802_1x.h"
15 #include "wpa_auth.h"
16 #include "ieee802_11.h"
17 #include "sta_info.h"
18 #include "wps_hostapd.h"
19 #include "p2p_hostapd.h"
20 #include "ctrl_iface_ap.h"
21 #include "ap_drv_ops.h"
22
23
hostapd_ctrl_iface_sta_mib(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)24 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
25 struct sta_info *sta,
26 char *buf, size_t buflen)
27 {
28 int len, res, ret;
29
30 if (sta == NULL) {
31 ret = os_snprintf(buf, buflen, "FAIL\n");
32 if (ret < 0 || (size_t) ret >= buflen)
33 return 0;
34 return ret;
35 }
36
37 len = 0;
38 ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
39 MAC2STR(sta->addr));
40 if (ret < 0 || (size_t) ret >= buflen - len)
41 return len;
42 len += ret;
43
44 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
45 if (res >= 0)
46 len += res;
47 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
48 if (res >= 0)
49 len += res;
50 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
51 if (res >= 0)
52 len += res;
53 res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
54 buflen - len);
55 if (res >= 0)
56 len += res;
57 res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
58 if (res >= 0)
59 len += res;
60
61 return len;
62 }
63
64
hostapd_ctrl_iface_sta_first(struct hostapd_data * hapd,char * buf,size_t buflen)65 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
66 char *buf, size_t buflen)
67 {
68 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
69 }
70
71
hostapd_ctrl_iface_sta(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)72 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
73 char *buf, size_t buflen)
74 {
75 u8 addr[ETH_ALEN];
76 int ret;
77
78 if (hwaddr_aton(txtaddr, addr)) {
79 ret = os_snprintf(buf, buflen, "FAIL\n");
80 if (ret < 0 || (size_t) ret >= buflen)
81 return 0;
82 return ret;
83 }
84 return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
85 buf, buflen);
86 }
87
88
hostapd_ctrl_iface_sta_next(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)89 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
90 char *buf, size_t buflen)
91 {
92 u8 addr[ETH_ALEN];
93 struct sta_info *sta;
94 int ret;
95
96 if (hwaddr_aton(txtaddr, addr) ||
97 (sta = ap_get_sta(hapd, addr)) == NULL) {
98 ret = os_snprintf(buf, buflen, "FAIL\n");
99 if (ret < 0 || (size_t) ret >= buflen)
100 return 0;
101 return ret;
102 }
103 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
104 }
105
106
107 #ifdef CONFIG_P2P_MANAGER
p2p_manager_disconnect(struct hostapd_data * hapd,u16 stype,u8 minor_reason_code,const u8 * addr)108 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
109 u8 minor_reason_code, const u8 *addr)
110 {
111 struct ieee80211_mgmt *mgmt;
112 int ret;
113 u8 *pos;
114
115 if (hapd->driver->send_frame == NULL)
116 return -1;
117
118 mgmt = os_zalloc(sizeof(*mgmt) + 100);
119 if (mgmt == NULL)
120 return -1;
121
122 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
123 " with minor reason code %u (stype=%u)",
124 MAC2STR(addr), minor_reason_code, stype);
125
126 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
127 os_memcpy(mgmt->da, addr, ETH_ALEN);
128 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
129 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
130 if (stype == WLAN_FC_STYPE_DEAUTH) {
131 mgmt->u.deauth.reason_code =
132 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
133 pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
134 } else {
135 mgmt->u.disassoc.reason_code =
136 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
137 pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
138 }
139
140 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
141 *pos++ = 4 + 3 + 1;
142 WPA_PUT_BE24(pos, OUI_WFA);
143 pos += 3;
144 *pos++ = P2P_OUI_TYPE;
145
146 *pos++ = P2P_ATTR_MINOR_REASON_CODE;
147 WPA_PUT_LE16(pos, 1);
148 pos += 2;
149 *pos++ = minor_reason_code;
150
151 ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
152 pos - (u8 *) mgmt, 1);
153 os_free(mgmt);
154
155 return ret < 0 ? -1 : 0;
156 }
157 #endif /* CONFIG_P2P_MANAGER */
158
159
hostapd_ctrl_iface_deauthenticate(struct hostapd_data * hapd,const char * txtaddr)160 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
161 const char *txtaddr)
162 {
163 u8 addr[ETH_ALEN];
164 struct sta_info *sta;
165 const char *pos;
166
167 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
168 txtaddr);
169
170 if (hwaddr_aton(txtaddr, addr))
171 return -1;
172
173 pos = os_strstr(txtaddr, " test=");
174 if (pos) {
175 struct ieee80211_mgmt mgmt;
176 int encrypt;
177 if (hapd->driver->send_frame == NULL)
178 return -1;
179 pos += 6;
180 encrypt = atoi(pos);
181 os_memset(&mgmt, 0, sizeof(mgmt));
182 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
183 WLAN_FC_STYPE_DEAUTH);
184 os_memcpy(mgmt.da, addr, ETH_ALEN);
185 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
186 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
187 mgmt.u.deauth.reason_code =
188 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
189 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
190 IEEE80211_HDRLEN +
191 sizeof(mgmt.u.deauth),
192 encrypt) < 0)
193 return -1;
194 return 0;
195 }
196
197 #ifdef CONFIG_P2P_MANAGER
198 pos = os_strstr(txtaddr, " p2p=");
199 if (pos) {
200 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
201 atoi(pos + 5), addr);
202 }
203 #endif /* CONFIG_P2P_MANAGER */
204
205 hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
206 sta = ap_get_sta(hapd, addr);
207 if (sta)
208 ap_sta_deauthenticate(hapd, sta,
209 WLAN_REASON_PREV_AUTH_NOT_VALID);
210 else if (addr[0] == 0xff)
211 hostapd_free_stas(hapd);
212
213 return 0;
214 }
215
216
hostapd_ctrl_iface_disassociate(struct hostapd_data * hapd,const char * txtaddr)217 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
218 const char *txtaddr)
219 {
220 u8 addr[ETH_ALEN];
221 struct sta_info *sta;
222 const char *pos;
223
224 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
225 txtaddr);
226
227 if (hwaddr_aton(txtaddr, addr))
228 return -1;
229
230 pos = os_strstr(txtaddr, " test=");
231 if (pos) {
232 struct ieee80211_mgmt mgmt;
233 int encrypt;
234 if (hapd->driver->send_frame == NULL)
235 return -1;
236 pos += 6;
237 encrypt = atoi(pos);
238 os_memset(&mgmt, 0, sizeof(mgmt));
239 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
240 WLAN_FC_STYPE_DISASSOC);
241 os_memcpy(mgmt.da, addr, ETH_ALEN);
242 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
243 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
244 mgmt.u.disassoc.reason_code =
245 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
246 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
247 IEEE80211_HDRLEN +
248 sizeof(mgmt.u.deauth),
249 encrypt) < 0)
250 return -1;
251 return 0;
252 }
253
254 #ifdef CONFIG_P2P_MANAGER
255 pos = os_strstr(txtaddr, " p2p=");
256 if (pos) {
257 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
258 atoi(pos + 5), addr);
259 }
260 #endif /* CONFIG_P2P_MANAGER */
261
262 hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
263 sta = ap_get_sta(hapd, addr);
264 if (sta)
265 ap_sta_disassociate(hapd, sta,
266 WLAN_REASON_PREV_AUTH_NOT_VALID);
267 else if (addr[0] == 0xff)
268 hostapd_free_stas(hapd);
269
270 return 0;
271 }
272