2 * hostapd / IEEE 802.11 Management
3 * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
15 #include "utils/includes.h"
17 #include "utils/common.h"
18 #include "common/ieee802_11_defs.h"
21 #include "ap_config.h"
22 #include "ap_drv_ops.h"
25 #ifdef CONFIG_IEEE80211W
27 u8
* hostapd_eid_assoc_comeback_time(struct hostapd_data
*hapd
,
28 struct sta_info
*sta
, u8
*eid
)
32 struct os_time now
, passed
;
34 *pos
++ = WLAN_EID_TIMEOUT_INTERVAL
;
36 *pos
++ = WLAN_TIMEOUT_ASSOC_COMEBACK
;
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
;
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
);
53 /* MLME-SAQuery.request */
54 void ieee802_11_send_sa_query_req(struct hostapd_data
*hapd
,
55 const u8
*addr
, const u8
*trans_id
)
57 struct ieee80211_mgmt mgmt
;
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
);
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");
81 void ieee802_11_send_sa_query_resp(struct hostapd_data
*hapd
,
82 const u8
*sa
, const u8
*trans_id
)
85 struct ieee80211_mgmt resp
;
88 wpa_printf(MSG_DEBUG
, "IEEE 802.11: Received SA Query Request from "
90 wpa_hexdump(MSG_DEBUG
, "IEEE 802.11: SA Query Transaction ID",
91 trans_id
, WLAN_SA_QUERY_TR_ID_LEN
);
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
));
100 wpa_printf(MSG_DEBUG
, "IEEE 802.11: Sending SA Query Response to "
101 MACSTR
, MAC2STR(sa
));
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");
119 void ieee802_11_sa_query_action(struct hostapd_data
*hapd
, const u8
*sa
,
120 const u8 action_type
, const u8
*trans_id
)
122 struct sta_info
*sta
;
125 if (action_type
== WLAN_SA_QUERY_REQUEST
) {
126 ieee802_11_send_sa_query_resp(hapd
, sa
, trans_id
);
130 if (action_type
!= WLAN_SA_QUERY_RESPONSE
) {
131 wpa_printf(MSG_DEBUG
, "IEEE 802.11: Unexpected SA Query "
132 "Action %d", action_type
);
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
);
141 /* MLME-SAQuery.confirm */
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");
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)
157 if (i
>= sta
->sa_query_count
) {
158 wpa_printf(MSG_DEBUG
, "IEEE 802.11: No matching SA Query "
159 "transaction identifier found");
163 hostapd_logger(hapd
, sta
->addr
, HOSTAPD_MODULE_IEEE80211
,
165 "Reply to pending SA Query received");
166 ap_sta_stop_sa_query(hapd
, sta
);
169 #endif /* CONFIG_IEEE80211W */
172 u8
* hostapd_eid_ext_capab(struct hostapd_data
*hapd
, u8
*eid
)
177 if (hapd
->conf
->tdls
& (TDLS_PROHIBIT
| TDLS_PROHIBIT_CHAN_SWITCH
))
179 if (len
< 4 && hapd
->conf
->interworking
)
184 *pos
++ = WLAN_EID_EXT_CAPAB
;
191 if (hapd
->conf
->interworking
)
192 *pos
|= 0x80; /* Bit 31 - Interworking */
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 */
208 u8
* hostapd_eid_interworking(struct hostapd_data
*hapd
, u8
*eid
)
211 #ifdef CONFIG_INTERWORKING
214 if (!hapd
->conf
->interworking
)
217 *pos
++ = WLAN_EID_INTERWORKING
;
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
;
226 *pos
|= INTERWORKING_ANO_ESR
;
227 if (hapd
->conf
->uesa
)
228 *pos
|= INTERWORKING_ANO_UESA
;
231 if (hapd
->conf
->venue_info_set
) {
232 *pos
++ = hapd
->conf
->venue_group
;
233 *pos
++ = hapd
->conf
->venue_type
;
236 if (!is_zero_ether_addr(hapd
->conf
->hessid
)) {
237 os_memcpy(pos
, hapd
->conf
->hessid
, ETH_ALEN
);
241 *len
= pos
- len
- 1;
242 #endif /* CONFIG_INTERWORKING */