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 printf("Too short WME IE (len=%lu)\n", (unsigned long) len
);
88 wme
= (struct wme_information_element
*) eid
;
89 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
, "Validating WME IE: OUI "
90 "%02x:%02x:%02x OUI type %d OUI sub-type %d "
92 wme
->oui
[0], wme
->oui
[1], wme
->oui
[2], wme
->oui_type
,
93 wme
->oui_subtype
, wme
->version
);
94 if (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 printf("Unsupported WME IE OUI/Type/Subtype/Version\n");
106 /* This function is called when a station sends an ACK frame for an AssocResp
107 * frame (status=success) and the matching AssocReq contained a WME element.
109 int hostapd_wme_sta_config(struct hostapd_data
*hapd
, struct sta_info
*sta
)
111 /* update kernel STA data for WME related items (WLAN_STA_WPA flag) */
112 if (sta
->flags
& WLAN_STA_WME
)
113 hostapd_sta_set_flags(hapd
, sta
->addr
, WLAN_STA_WME
, ~0);
115 hostapd_sta_set_flags(hapd
, sta
->addr
, 0, ~WLAN_STA_WME
);
121 static void wme_send_action(struct hostapd_data
*hapd
, const u8
*addr
,
122 const struct wme_tspec_info_element
*tspec
,
123 u8 action_code
, u8 dialogue_token
, u8 status_code
)
126 struct ieee80211_mgmt
*m
= (struct ieee80211_mgmt
*) buf
;
127 struct wme_tspec_info_element
*t
=
128 (struct wme_tspec_info_element
*)
129 m
->u
.action
.u
.wme_action
.variable
;
132 hostapd_logger(hapd
, addr
, HOSTAPD_MODULE_IEEE80211
,
134 "action response - reason %d", status_code
);
135 memset(buf
, 0, sizeof(buf
));
136 m
->frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
137 WLAN_FC_STYPE_ACTION
);
138 memcpy(m
->da
, addr
, ETH_ALEN
);
139 memcpy(m
->sa
, hapd
->own_addr
, ETH_ALEN
);
140 memcpy(m
->bssid
, hapd
->own_addr
, ETH_ALEN
);
141 m
->u
.action
.category
= WME_ACTION_CATEGORY
;
142 m
->u
.action
.u
.wme_action
.action_code
= action_code
;
143 m
->u
.action
.u
.wme_action
.dialog_token
= dialogue_token
;
144 m
->u
.action
.u
.wme_action
.status_code
= status_code
;
145 memcpy(t
, tspec
, sizeof(struct wme_tspec_info_element
));
146 len
= ((u8
*) (t
+ 1)) - buf
;
148 if (hostapd_send_mgmt_frame(hapd
, m
, len
, 0) < 0)
149 perror("wme_send_action: send");
153 /* given frame data payload size in bytes, and data_rate in bits per second
154 * returns time to complete frame exchange */
155 /* FIX: should not use floating point types */
156 static double wme_frame_exchange_time(int bytes
, int data_rate
, int encryption
,
159 /* TODO: account for MAC/PHY headers correctly */
160 /* TODO: account for encryption headers */
161 /* TODO: account for WDS headers */
162 /* TODO: account for CTS protection */
163 /* TODO: account for SIFS + ACK at minimum PHY rate */
164 return (bytes
+ 400) * 8.0 / data_rate
;
168 static void wme_setup_request(struct hostapd_data
*hapd
,
169 struct ieee80211_mgmt
*mgmt
,
170 struct wme_tspec_info_element
*tspec
, size_t len
)
172 /* FIX: should not use floating point types */
173 double medium_time
, pps
;
175 /* TODO: account for airtime and answer no to tspec setup requests
176 * when none left!! */
178 pps
= (tspec
->mean_data_rate
/ 8.0) / tspec
->nominal_msdu_size
;
179 medium_time
= (tspec
->surplus_bandwidth_allowance
/ 8) * pps
*
180 wme_frame_exchange_time(tspec
->nominal_msdu_size
,
181 tspec
->minimum_phy_rate
, 0, 0);
182 tspec
->medium_time
= medium_time
* 1000000.0 / 32.0;
184 wme_send_action(hapd
, mgmt
->sa
, tspec
, WME_ACTION_CODE_SETUP_RESPONSE
,
185 mgmt
->u
.action
.u
.wme_action
.dialog_token
,
186 WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED
);
190 void hostapd_wme_action(struct hostapd_data
*hapd
, struct ieee80211_mgmt
*mgmt
,
194 int left
= len
- IEEE80211_HDRLEN
- 4;
195 u8
*pos
= ((u8
*) mgmt
) + IEEE80211_HDRLEN
+ 4;
196 struct ieee802_11_elems elems
;
197 struct sta_info
*sta
= ap_get_sta(hapd
, mgmt
->sa
);
199 /* check that the request comes from a valid station */
201 (sta
->flags
& (WLAN_STA_ASSOC
| WLAN_STA_WME
)) !=
202 (WLAN_STA_ASSOC
| WLAN_STA_WME
)) {
203 hostapd_logger(hapd
, mgmt
->sa
, HOSTAPD_MODULE_IEEE80211
,
205 "wme action received is not from associated wme"
207 /* TODO: respond with action frame refused status code */
211 /* extract the tspec info element */
212 if (ieee802_11_parse_elems(hapd
, pos
, left
, &elems
, 1) == ParseFailed
)
214 hostapd_logger(hapd
, mgmt
->sa
, HOSTAPD_MODULE_IEEE80211
,
216 "hostapd_wme_action - could not parse wme "
218 /* TODO: respond with action frame invalid parameters status
223 if (!elems
.wme_tspec
||
224 elems
.wme_tspec_len
!= (sizeof(struct wme_tspec_info_element
) - 2))
226 hostapd_logger(hapd
, mgmt
->sa
, HOSTAPD_MODULE_IEEE80211
,
228 "hostapd_wme_action - missing or wrong length "
230 /* TODO: respond with action frame invalid parameters status
235 /* TODO: check the request is for an AC with ACM set, if not, refuse
238 action_code
= mgmt
->u
.action
.u
.wme_action
.action_code
;
239 switch (action_code
) {
240 case WME_ACTION_CODE_SETUP_REQUEST
:
241 wme_setup_request(hapd
, mgmt
, (struct wme_tspec_info_element
*)
242 elems
.wme_tspec
, len
);
245 /* TODO: needed for client implementation */
246 case WME_ACTION_CODE_SETUP_RESPONSE
:
247 wme_setup_request(hapd
, mgmt
, len
);
249 /* TODO: handle station teardown requests */
250 case WME_ACTION_CODE_TEARDOWN
:
251 wme_teardown(hapd
, mgmt
, len
);
256 hostapd_logger(hapd
, mgmt
->sa
, HOSTAPD_MODULE_IEEE80211
,
258 "hostapd_wme_action - unknown action code %d",