]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/wpa/src/common/ieee802_11_common.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / wpa / src / common / ieee802_11_common.c
1 /*
2  * IEEE 802.11 Common routines
3  * Copyright (c) 2002-2012, 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 "includes.h"
10
11 #include "common.h"
12 #include "ieee802_11_defs.h"
13 #include "ieee802_11_common.h"
14
15
16 static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
17                                             struct ieee802_11_elems *elems,
18                                             int show_errors)
19 {
20         unsigned int oui;
21
22         /* first 3 bytes in vendor specific information element are the IEEE
23          * OUI of the vendor. The following byte is used a vendor specific
24          * sub-type. */
25         if (elen < 4) {
26                 if (show_errors) {
27                         wpa_printf(MSG_MSGDUMP, "short vendor specific "
28                                    "information element ignored (len=%lu)",
29                                    (unsigned long) elen);
30                 }
31                 return -1;
32         }
33
34         oui = WPA_GET_BE24(pos);
35         switch (oui) {
36         case OUI_MICROSOFT:
37                 /* Microsoft/Wi-Fi information elements are further typed and
38                  * subtyped */
39                 switch (pos[3]) {
40                 case 1:
41                         /* Microsoft OUI (00:50:F2) with OUI Type 1:
42                          * real WPA information element */
43                         elems->wpa_ie = pos;
44                         elems->wpa_ie_len = elen;
45                         break;
46                 case WMM_OUI_TYPE:
47                         /* WMM information element */
48                         if (elen < 5) {
49                                 wpa_printf(MSG_MSGDUMP, "short WMM "
50                                            "information element ignored "
51                                            "(len=%lu)",
52                                            (unsigned long) elen);
53                                 return -1;
54                         }
55                         switch (pos[4]) {
56                         case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
57                         case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
58                                 /*
59                                  * Share same pointer since only one of these
60                                  * is used and they start with same data.
61                                  * Length field can be used to distinguish the
62                                  * IEs.
63                                  */
64                                 elems->wmm = pos;
65                                 elems->wmm_len = elen;
66                                 break;
67                         case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
68                                 elems->wmm_tspec = pos;
69                                 elems->wmm_tspec_len = elen;
70                                 break;
71                         default:
72                                 wpa_printf(MSG_EXCESSIVE, "unknown WMM "
73                                            "information element ignored "
74                                            "(subtype=%d len=%lu)",
75                                            pos[4], (unsigned long) elen);
76                                 return -1;
77                         }
78                         break;
79                 case 4:
80                         /* Wi-Fi Protected Setup (WPS) IE */
81                         elems->wps_ie = pos;
82                         elems->wps_ie_len = elen;
83                         break;
84                 default:
85                         wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
86                                    "information element ignored "
87                                    "(type=%d len=%lu)",
88                                    pos[3], (unsigned long) elen);
89                         return -1;
90                 }
91                 break;
92
93         case OUI_WFA:
94                 switch (pos[3]) {
95                 case P2P_OUI_TYPE:
96                         /* Wi-Fi Alliance - P2P IE */
97                         elems->p2p = pos;
98                         elems->p2p_len = elen;
99                         break;
100                 case WFD_OUI_TYPE:
101                         /* Wi-Fi Alliance - WFD IE */
102                         elems->wfd = pos;
103                         elems->wfd_len = elen;
104                         break;
105                 case HS20_INDICATION_OUI_TYPE:
106                         /* Hotspot 2.0 */
107                         elems->hs20 = pos;
108                         elems->hs20_len = elen;
109                         break;
110                 default:
111                         wpa_printf(MSG_MSGDUMP, "Unknown WFA "
112                                    "information element ignored "
113                                    "(type=%d len=%lu)\n",
114                                    pos[3], (unsigned long) elen);
115                         return -1;
116                 }
117                 break;
118
119         case OUI_BROADCOM:
120                 switch (pos[3]) {
121                 case VENDOR_HT_CAPAB_OUI_TYPE:
122                         elems->vendor_ht_cap = pos;
123                         elems->vendor_ht_cap_len = elen;
124                         break;
125                 default:
126                         wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
127                                    "information element ignored "
128                                    "(type=%d len=%lu)",
129                                    pos[3], (unsigned long) elen);
130                         return -1;
131                 }
132                 break;
133
134         default:
135                 wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
136                            "information element ignored (vendor OUI "
137                            "%02x:%02x:%02x len=%lu)",
138                            pos[0], pos[1], pos[2], (unsigned long) elen);
139                 return -1;
140         }
141
142         return 0;
143 }
144
145
146 /**
147  * ieee802_11_parse_elems - Parse information elements in management frames
148  * @start: Pointer to the start of IEs
149  * @len: Length of IE buffer in octets
150  * @elems: Data structure for parsed elements
151  * @show_errors: Whether to show parsing errors in debug log
152  * Returns: Parsing result
153  */
154 ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
155                                 struct ieee802_11_elems *elems,
156                                 int show_errors)
157 {
158         size_t left = len;
159         const u8 *pos = start;
160         int unknown = 0;
161
162         os_memset(elems, 0, sizeof(*elems));
163
164         while (left >= 2) {
165                 u8 id, elen;
166
167                 id = *pos++;
168                 elen = *pos++;
169                 left -= 2;
170
171                 if (elen > left) {
172                         if (show_errors) {
173                                 wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
174                                            "parse failed (id=%d elen=%d "
175                                            "left=%lu)",
176                                            id, elen, (unsigned long) left);
177                                 wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
178                         }
179                         return ParseFailed;
180                 }
181
182                 switch (id) {
183                 case WLAN_EID_SSID:
184                         elems->ssid = pos;
185                         elems->ssid_len = elen;
186                         break;
187                 case WLAN_EID_SUPP_RATES:
188                         elems->supp_rates = pos;
189                         elems->supp_rates_len = elen;
190                         break;
191                 case WLAN_EID_FH_PARAMS:
192                         elems->fh_params = pos;
193                         elems->fh_params_len = elen;
194                         break;
195                 case WLAN_EID_DS_PARAMS:
196                         elems->ds_params = pos;
197                         elems->ds_params_len = elen;
198                         break;
199                 case WLAN_EID_CF_PARAMS:
200                         elems->cf_params = pos;
201                         elems->cf_params_len = elen;
202                         break;
203                 case WLAN_EID_TIM:
204                         elems->tim = pos;
205                         elems->tim_len = elen;
206                         break;
207                 case WLAN_EID_IBSS_PARAMS:
208                         elems->ibss_params = pos;
209                         elems->ibss_params_len = elen;
210                         break;
211                 case WLAN_EID_CHALLENGE:
212                         elems->challenge = pos;
213                         elems->challenge_len = elen;
214                         break;
215                 case WLAN_EID_ERP_INFO:
216                         elems->erp_info = pos;
217                         elems->erp_info_len = elen;
218                         break;
219                 case WLAN_EID_EXT_SUPP_RATES:
220                         elems->ext_supp_rates = pos;
221                         elems->ext_supp_rates_len = elen;
222                         break;
223                 case WLAN_EID_VENDOR_SPECIFIC:
224                         if (ieee802_11_parse_vendor_specific(pos, elen,
225                                                              elems,
226                                                              show_errors))
227                                 unknown++;
228                         break;
229                 case WLAN_EID_RSN:
230                         elems->rsn_ie = pos;
231                         elems->rsn_ie_len = elen;
232                         break;
233                 case WLAN_EID_PWR_CAPABILITY:
234                         elems->power_cap = pos;
235                         elems->power_cap_len = elen;
236                         break;
237                 case WLAN_EID_SUPPORTED_CHANNELS:
238                         elems->supp_channels = pos;
239                         elems->supp_channels_len = elen;
240                         break;
241                 case WLAN_EID_MOBILITY_DOMAIN:
242                         elems->mdie = pos;
243                         elems->mdie_len = elen;
244                         break;
245                 case WLAN_EID_FAST_BSS_TRANSITION:
246                         elems->ftie = pos;
247                         elems->ftie_len = elen;
248                         break;
249                 case WLAN_EID_TIMEOUT_INTERVAL:
250                         elems->timeout_int = pos;
251                         elems->timeout_int_len = elen;
252                         break;
253                 case WLAN_EID_HT_CAP:
254                         elems->ht_capabilities = pos;
255                         elems->ht_capabilities_len = elen;
256                         break;
257                 case WLAN_EID_HT_OPERATION:
258                         elems->ht_operation = pos;
259                         elems->ht_operation_len = elen;
260                         break;
261                 case WLAN_EID_VHT_CAP:
262                         elems->vht_capabilities = pos;
263                         elems->vht_capabilities_len = elen;
264                         break;
265                 case WLAN_EID_VHT_OPERATION:
266                         elems->vht_operation = pos;
267                         elems->vht_operation_len = elen;
268                         break;
269                 case WLAN_EID_LINK_ID:
270                         if (elen < 18)
271                                 break;
272                         elems->link_id = pos;
273                         break;
274                 case WLAN_EID_INTERWORKING:
275                         elems->interworking = pos;
276                         elems->interworking_len = elen;
277                         break;
278                 case WLAN_EID_EXT_CAPAB:
279                         elems->ext_capab = pos;
280                         elems->ext_capab_len = elen;
281                         break;
282                 case WLAN_EID_BSS_MAX_IDLE_PERIOD:
283                         if (elen < 3)
284                                 break;
285                         elems->bss_max_idle_period = pos;
286                         break;
287                 case WLAN_EID_SSID_LIST:
288                         elems->ssid_list = pos;
289                         elems->ssid_list_len = elen;
290                         break;
291                 default:
292                         unknown++;
293                         if (!show_errors)
294                                 break;
295                         wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
296                                    "ignored unknown element (id=%d elen=%d)",
297                                    id, elen);
298                         break;
299                 }
300
301                 left -= elen;
302                 pos += elen;
303         }
304
305         if (left)
306                 return ParseFailed;
307
308         return unknown ? ParseUnknown : ParseOK;
309 }
310
311
312 int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
313 {
314         int count = 0;
315         const u8 *pos, *end;
316
317         if (ies == NULL)
318                 return 0;
319
320         pos = ies;
321         end = ies + ies_len;
322
323         while (pos + 2 <= end) {
324                 if (pos + 2 + pos[1] > end)
325                         break;
326                 count++;
327                 pos += 2 + pos[1];
328         }
329
330         return count;
331 }
332
333
334 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
335                                             u32 oui_type)
336 {
337         struct wpabuf *buf;
338         const u8 *end, *pos, *ie;
339
340         pos = ies;
341         end = ies + ies_len;
342         ie = NULL;
343
344         while (pos + 1 < end) {
345                 if (pos + 2 + pos[1] > end)
346                         return NULL;
347                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
348                     WPA_GET_BE32(&pos[2]) == oui_type) {
349                         ie = pos;
350                         break;
351                 }
352                 pos += 2 + pos[1];
353         }
354
355         if (ie == NULL)
356                 return NULL; /* No specified vendor IE found */
357
358         buf = wpabuf_alloc(ies_len);
359         if (buf == NULL)
360                 return NULL;
361
362         /*
363          * There may be multiple vendor IEs in the message, so need to
364          * concatenate their data fields.
365          */
366         while (pos + 1 < end) {
367                 if (pos + 2 + pos[1] > end)
368                         break;
369                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
370                     WPA_GET_BE32(&pos[2]) == oui_type)
371                         wpabuf_put_data(buf, pos + 6, pos[1] - 4);
372                 pos += 2 + pos[1];
373         }
374
375         return buf;
376 }
377
378
379 const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
380 {
381         u16 fc, type, stype;
382
383         /*
384          * PS-Poll frames are 16 bytes. All other frames are
385          * 24 bytes or longer.
386          */
387         if (len < 16)
388                 return NULL;
389
390         fc = le_to_host16(hdr->frame_control);
391         type = WLAN_FC_GET_TYPE(fc);
392         stype = WLAN_FC_GET_STYPE(fc);
393
394         switch (type) {
395         case WLAN_FC_TYPE_DATA:
396                 if (len < 24)
397                         return NULL;
398                 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
399                 case WLAN_FC_FROMDS | WLAN_FC_TODS:
400                 case WLAN_FC_TODS:
401                         return hdr->addr1;
402                 case WLAN_FC_FROMDS:
403                         return hdr->addr2;
404                 default:
405                         return NULL;
406                 }
407         case WLAN_FC_TYPE_CTRL:
408                 if (stype != WLAN_FC_STYPE_PSPOLL)
409                         return NULL;
410                 return hdr->addr1;
411         case WLAN_FC_TYPE_MGMT:
412                 return hdr->addr3;
413         default:
414                 return NULL;
415         }
416 }
417
418
419 int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
420                           const char *name, const char *val)
421 {
422         int num, v;
423         const char *pos;
424         struct hostapd_wmm_ac_params *ac;
425
426         /* skip 'wme_ac_' or 'wmm_ac_' prefix */
427         pos = name + 7;
428         if (os_strncmp(pos, "be_", 3) == 0) {
429                 num = 0;
430                 pos += 3;
431         } else if (os_strncmp(pos, "bk_", 3) == 0) {
432                 num = 1;
433                 pos += 3;
434         } else if (os_strncmp(pos, "vi_", 3) == 0) {
435                 num = 2;
436                 pos += 3;
437         } else if (os_strncmp(pos, "vo_", 3) == 0) {
438                 num = 3;
439                 pos += 3;
440         } else {
441                 wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
442                 return -1;
443         }
444
445         ac = &wmm_ac_params[num];
446
447         if (os_strcmp(pos, "aifs") == 0) {
448                 v = atoi(val);
449                 if (v < 1 || v > 255) {
450                         wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
451                         return -1;
452                 }
453                 ac->aifs = v;
454         } else if (os_strcmp(pos, "cwmin") == 0) {
455                 v = atoi(val);
456                 if (v < 0 || v > 12) {
457                         wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
458                         return -1;
459                 }
460                 ac->cwmin = v;
461         } else if (os_strcmp(pos, "cwmax") == 0) {
462                 v = atoi(val);
463                 if (v < 0 || v > 12) {
464                         wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
465                         return -1;
466                 }
467                 ac->cwmax = v;
468         } else if (os_strcmp(pos, "txop_limit") == 0) {
469                 v = atoi(val);
470                 if (v < 0 || v > 0xffff) {
471                         wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
472                         return -1;
473                 }
474                 ac->txop_limit = v;
475         } else if (os_strcmp(pos, "acm") == 0) {
476                 v = atoi(val);
477                 if (v < 0 || v > 1) {
478                         wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
479                         return -1;
480                 }
481                 ac->admission_control_mandatory = v;
482         } else {
483                 wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
484                 return -1;
485         }
486
487         return 0;
488 }