2 * hostapd / WMM (Wi-Fi Multimedia)
3 * Copyright 2002-2003, Instant802 Networks, Inc.
4 * Copyright 2005-2006, Devicescape Software, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Alternatively, this software may be distributed under the terms of BSD
13 * See README and COPYING for more details.
19 #include "ieee802_11.h"
25 /* TODO: maintain separate sequence and fragment numbers for each AC
26 * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
27 * if only WME stations are receiving a certain group */
30 static u8 wme_oui
[3] = { 0x00, 0x50, 0xf2 };
33 /* Add WME Parameter Element to Beacon and Probe Response frames. */
34 u8
* hostapd_eid_wme(struct hostapd_data
*hapd
, u8
*eid
)
37 struct wme_parameter_element
*wme
=
38 (struct wme_parameter_element
*) (pos
+ 2);
41 if (!hapd
->conf
->wme_enabled
)
43 eid
[0] = WLAN_EID_VENDOR_SPECIFIC
;
47 wme
->oui_type
= WME_OUI_TYPE
;
48 wme
->oui_subtype
= WME_OUI_SUBTYPE_PARAMETER_ELEMENT
;
49 wme
->version
= WME_VERSION
;
50 wme
->acInfo
= hapd
->parameter_set_count
& 0xf;
52 /* fill in a parameter set record for each AC */
53 for (e
= 0; e
< 4; e
++) {
54 struct wme_ac_parameter
*ac
= &wme
->ac
[e
];
55 struct hostapd_wme_ac_params
*acp
=
56 &hapd
->iconf
->wme_ac_params
[e
];
58 ac
->aifsn
= acp
->aifs
;
59 ac
->acm
= acp
->admission_control_mandatory
;
62 ac
->eCWmin
= acp
->cwmin
;
63 ac
->eCWmax
= acp
->cwmax
;
64 ac
->txopLimit
= host_to_le16(acp
->txopLimit
);
67 pos
= (u8
*) (wme
+ 1);
68 eid
[1] = pos
- eid
- 2; /* element length */
74 /* This function is called when a station sends an association request with
75 * WME info element. The function returns zero on success or non-zero on any
76 * error in WME element. eid does not include Element ID and Length octets. */
77 int hostapd_eid_wme_valid(struct hostapd_data
*hapd
, u8
*eid
, size_t len
)
79 struct wme_information_element
*wme
;
81 wpa_hexdump(MSG_MSGDUMP
, "WME IE", eid
, len
);
83 if (len
< sizeof(struct wme_information_element
)) {
84 wpa_printf(MSG_DEBUG
, "Too short WME IE (len=%lu)",
89 wme
= (struct wme_information_element
*) eid
;
90 wpa_printf(MSG_DEBUG
, "Validating WME IE: OUI %02x:%02x:%02x "
91 "OUI type %d OUI sub-type %d version %d",
92 wme
->oui
[0], wme
->oui
[1], wme
->oui
[2], wme
->oui_type
,
93 wme
->oui_subtype
, wme
->version
);
94 if (os_memcmp(wme
->oui
, wme_oui
, sizeof(wme_oui
)) != 0 ||
95 wme
->oui_type
!= WME_OUI_TYPE
||
96 wme
->oui_subtype
!= WME_OUI_SUBTYPE_INFORMATION_ELEMENT
||
97 wme
->version
!= WME_VERSION
) {
98 wpa_printf(MSG_DEBUG
, "Unsupported WME IE OUI/Type/Subtype/"
107 /* This function is called when a station sends an ACK frame for an AssocResp
108 * frame (status=success) and the matching AssocReq contained a WME element.
110 int hostapd_wme_sta_config(struct hostapd_data
*hapd
, struct sta_info
*sta
)
112 /* update kernel STA data for WME related items (WLAN_STA_WPA flag) */
113 if (sta
->flags
& WLAN_STA_WME
)
114 hostapd_sta_set_flags(hapd
, sta
->addr
, sta
->flags
,
117 hostapd_sta_set_flags(hapd
, sta
->addr
, sta
->flags
,
124 static void wme_send_action(struct hostapd_data
*hapd
, const u8
*addr
,
125 const struct wme_tspec_info_element
*tspec
,
126 u8 action_code
, u8 dialogue_token
, u8 status_code
)
129 struct ieee80211_mgmt
*m
= (struct ieee80211_mgmt
*) buf
;
130 struct wme_tspec_info_element
*t
=
131 (struct wme_tspec_info_element
*)
132 m
->u
.action
.u
.wme_action
.variable
;
135 hostapd_logger(hapd
, addr
, HOSTAPD_MODULE_IEEE80211
,
137 "action response - reason %d", status_code
);
138 os_memset(buf
, 0, sizeof(buf
));
139 m
->frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
140 WLAN_FC_STYPE_ACTION
);
141 os_memcpy(m
->da
, addr
, ETH_ALEN
);
142 os_memcpy(m
->sa
, hapd
->own_addr
, ETH_ALEN
);
143 os_memcpy(m
->bssid
, hapd
->own_addr
, ETH_ALEN
);
144 m
->u
.action
.category
= WME_ACTION_CATEGORY
;
145 m
->u
.action
.u
.wme_action
.action_code
= action_code
;
146 m
->u
.action
.u
.wme_action
.dialog_token
= dialogue_token
;
147 m
->u
.action
.u
.wme_action
.status_code
= status_code
;
148 os_memcpy(t
, tspec
, sizeof(struct wme_tspec_info_element
));
149 len
= ((u8
*) (t
+ 1)) - buf
;
151 if (hostapd_send_mgmt_frame(hapd
, m
, len
, 0) < 0)
152 perror("wme_send_action: send");
156 /* given frame data payload size in bytes, and data_rate in bits per second
157 * returns time to complete frame exchange */
158 /* FIX: should not use floating point types */
159 static double wme_frame_exchange_time(int bytes
, int data_rate
, int encryption
,
162 /* TODO: account for MAC/PHY headers correctly */
163 /* TODO: account for encryption headers */
164 /* TODO: account for WDS headers */
165 /* TODO: account for CTS protection */
166 /* TODO: account for SIFS + ACK at minimum PHY rate */
167 return (bytes
+ 400) * 8.0 / data_rate
;
171 static void wme_setup_request(struct hostapd_data
*hapd
,
172 struct ieee80211_mgmt
*mgmt
,
173 struct wme_tspec_info_element
*tspec
, size_t len
)
175 /* FIX: should not use floating point types */
176 double medium_time
, pps
;
178 /* TODO: account for airtime and answer no to tspec setup requests
179 * when none left!! */
181 pps
= (tspec
->mean_data_rate
/ 8.0) / tspec
->nominal_msdu_size
;
182 medium_time
= (tspec
->surplus_bandwidth_allowance
/ 8) * pps
*
183 wme_frame_exchange_time(tspec
->nominal_msdu_size
,
184 tspec
->minimum_phy_rate
, 0, 0);
185 tspec
->medium_time
= medium_time
* 1000000.0 / 32.0;
187 wme_send_action(hapd
, mgmt
->sa
, tspec
, WME_ACTION_CODE_SETUP_RESPONSE
,
188 mgmt
->u
.action
.u
.wme_action
.dialog_token
,
189 WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED
);
193 void hostapd_wme_action(struct hostapd_data
*hapd
, struct ieee80211_mgmt
*mgmt
,
197 int left
= len
- IEEE80211_HDRLEN
- 4;
198 u8
*pos
= ((u8
*) mgmt
) + IEEE80211_HDRLEN
+ 4;
199 struct ieee802_11_elems elems
;
200 struct sta_info
*sta
= ap_get_sta(hapd
, mgmt
->sa
);
202 /* check that the request comes from a valid station */
204 (sta
->flags
& (WLAN_STA_ASSOC
| WLAN_STA_WME
)) !=
205 (WLAN_STA_ASSOC
| WLAN_STA_WME
)) {
206 hostapd_logger(hapd
, mgmt
->sa
, HOSTAPD_MODULE_IEEE80211
,
208 "wme action received is not from associated wme"
210 /* TODO: respond with action frame refused status code */
214 /* extract the tspec info element */
215 if (ieee802_11_parse_elems(hapd
, pos
, left
, &elems
, 1) == ParseFailed
)
217 hostapd_logger(hapd
, mgmt
->sa
, HOSTAPD_MODULE_IEEE80211
,
219 "hostapd_wme_action - could not parse wme "
221 /* TODO: respond with action frame invalid parameters status
226 if (!elems
.wme_tspec
||
227 elems
.wme_tspec_len
!= (sizeof(struct wme_tspec_info_element
) - 2))
229 hostapd_logger(hapd
, mgmt
->sa
, HOSTAPD_MODULE_IEEE80211
,
231 "hostapd_wme_action - missing or wrong length "
233 /* TODO: respond with action frame invalid parameters status
238 /* TODO: check the request is for an AC with ACM set, if not, refuse
241 action_code
= mgmt
->u
.action
.u
.wme_action
.action_code
;
242 switch (action_code
) {
243 case WME_ACTION_CODE_SETUP_REQUEST
:
244 wme_setup_request(hapd
, mgmt
, (struct wme_tspec_info_element
*)
245 elems
.wme_tspec
, len
);
248 /* TODO: needed for client implementation */
249 case WME_ACTION_CODE_SETUP_RESPONSE
:
250 wme_setup_request(hapd
, mgmt
, len
);
252 /* TODO: handle station teardown requests */
253 case WME_ACTION_CODE_TEARDOWN
:
254 wme_teardown(hapd
, mgmt
, len
);
259 hostapd_logger(hapd
, mgmt
->sa
, HOSTAPD_MODULE_IEEE80211
,
261 "hostapd_wme_action - unknown action code %d",