]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/ap/ieee802_11_shared.c
Move Ext Capab and Interworking element construction into shared file
[thirdparty/hostap.git] / src / ap / ieee802_11_shared.c
1 /*
2 * hostapd / IEEE 802.11 Management
3 * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15 #include "utils/includes.h"
16
17 #include "utils/common.h"
18 #include "common/ieee802_11_defs.h"
19 #include "hostapd.h"
20 #include "sta_info.h"
21 #include "ap_config.h"
22 #include "ap_drv_ops.h"
23
24
25 #ifdef CONFIG_IEEE80211W
26
27 u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
28 struct sta_info *sta, u8 *eid)
29 {
30 u8 *pos = eid;
31 u32 timeout, tu;
32 struct os_time now, passed;
33
34 *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
35 *pos++ = 5;
36 *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
37 os_get_time(&now);
38 os_time_sub(&now, &sta->sa_query_start, &passed);
39 tu = (passed.sec * 1000000 + passed.usec) / 1024;
40 if (hapd->conf->assoc_sa_query_max_timeout > tu)
41 timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
42 else
43 timeout = 0;
44 if (timeout < hapd->conf->assoc_sa_query_max_timeout)
45 timeout++; /* add some extra time for local timers */
46 WPA_PUT_LE32(pos, timeout);
47 pos += 4;
48
49 return pos;
50 }
51
52
53 /* MLME-SAQuery.request */
54 void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
55 const u8 *addr, const u8 *trans_id)
56 {
57 struct ieee80211_mgmt mgmt;
58 u8 *end;
59
60 wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
61 MACSTR, MAC2STR(addr));
62 wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
63 trans_id, WLAN_SA_QUERY_TR_ID_LEN);
64
65 os_memset(&mgmt, 0, sizeof(mgmt));
66 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
67 WLAN_FC_STYPE_ACTION);
68 os_memcpy(mgmt.da, addr, ETH_ALEN);
69 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
70 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
71 mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
72 mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
73 os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
74 WLAN_SA_QUERY_TR_ID_LEN);
75 end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
76 if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt) < 0)
77 perror("ieee802_11_send_sa_query_req: send");
78 }
79
80
81 void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
82 const u8 *sa, const u8 *trans_id)
83 {
84 struct sta_info *sta;
85 struct ieee80211_mgmt resp;
86 u8 *end;
87
88 wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
89 MACSTR, MAC2STR(sa));
90 wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
91 trans_id, WLAN_SA_QUERY_TR_ID_LEN);
92
93 sta = ap_get_sta(hapd, sa);
94 if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
95 wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
96 "from unassociated STA " MACSTR, MAC2STR(sa));
97 return;
98 }
99
100 wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
101 MACSTR, MAC2STR(sa));
102
103 os_memset(&resp, 0, sizeof(resp));
104 resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
105 WLAN_FC_STYPE_ACTION);
106 os_memcpy(resp.da, sa, ETH_ALEN);
107 os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
108 os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
109 resp.u.action.category = WLAN_ACTION_SA_QUERY;
110 resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
111 os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
112 WLAN_SA_QUERY_TR_ID_LEN);
113 end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
114 if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp) < 0)
115 perror("ieee80211_mgmt_sa_query_request: send");
116 }
117
118
119 void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
120 const u8 action_type, const u8 *trans_id)
121 {
122 struct sta_info *sta;
123 int i;
124
125 if (action_type == WLAN_SA_QUERY_REQUEST) {
126 ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
127 return;
128 }
129
130 if (action_type != WLAN_SA_QUERY_RESPONSE) {
131 wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
132 "Action %d", action_type);
133 return;
134 }
135
136 wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
137 MACSTR, MAC2STR(sa));
138 wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
139 trans_id, WLAN_SA_QUERY_TR_ID_LEN);
140
141 /* MLME-SAQuery.confirm */
142
143 sta = ap_get_sta(hapd, sa);
144 if (sta == NULL || sta->sa_query_trans_id == NULL) {
145 wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
146 "pending SA Query request found");
147 return;
148 }
149
150 for (i = 0; i < sta->sa_query_count; i++) {
151 if (os_memcmp(sta->sa_query_trans_id +
152 i * WLAN_SA_QUERY_TR_ID_LEN,
153 trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0)
154 break;
155 }
156
157 if (i >= sta->sa_query_count) {
158 wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
159 "transaction identifier found");
160 return;
161 }
162
163 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
164 HOSTAPD_LEVEL_DEBUG,
165 "Reply to pending SA Query received");
166 ap_sta_stop_sa_query(hapd, sta);
167 }
168
169 #endif /* CONFIG_IEEE80211W */
170
171
172 u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
173 {
174 u8 *pos = eid;
175 u8 len = 0;
176
177 if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
178 len = 5;
179 if (len < 4 && hapd->conf->interworking)
180 len = 4;
181 if (len == 0)
182 return eid;
183
184 *pos++ = WLAN_EID_EXT_CAPAB;
185 *pos++ = len;
186 *pos++ = 0x00;
187 *pos++ = 0x00;
188 *pos++ = 0x00;
189
190 *pos = 0x00;
191 if (hapd->conf->interworking)
192 *pos |= 0x80; /* Bit 31 - Interworking */
193 pos++;
194
195 if (len < 5)
196 return pos;
197 *pos = 0x00;
198 if (hapd->conf->tdls & TDLS_PROHIBIT)
199 *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
200 if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
201 *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
202 pos++;
203
204 return pos;
205 }
206
207
208 u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
209 {
210 u8 *pos = eid;
211 #ifdef CONFIG_INTERWORKING
212 u8 *len;
213
214 if (!hapd->conf->interworking)
215 return eid;
216
217 *pos++ = WLAN_EID_INTERWORKING;
218 len = pos++;
219
220 *pos = hapd->conf->access_network_type;
221 if (hapd->conf->internet)
222 *pos |= INTERWORKING_ANO_INTERNET;
223 if (hapd->conf->asra)
224 *pos |= INTERWORKING_ANO_ASRA;
225 if (hapd->conf->esr)
226 *pos |= INTERWORKING_ANO_ESR;
227 if (hapd->conf->uesa)
228 *pos |= INTERWORKING_ANO_UESA;
229 pos++;
230
231 if (hapd->conf->venue_info_set) {
232 *pos++ = hapd->conf->venue_group;
233 *pos++ = hapd->conf->venue_type;
234 }
235
236 if (!is_zero_ether_addr(hapd->conf->hessid)) {
237 os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
238 pos += ETH_ALEN;
239 }
240
241 *len = pos - len - 1;
242 #endif /* CONFIG_INTERWORKING */
243
244 return pos;
245 }