hostapd: Update vendor branch to 0.6.10
[dragonfly.git] / contrib / hostapd / src / common / ieee802_11_common.c
1 /*
2  * IEEE 802.11 Common routines
3  * Copyright (c) 2002-2008, 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 "includes.h"
16
17 #include "common.h"
18 #include "ieee802_11_defs.h"
19 #include "ieee802_11_common.h"
20
21
22 static int ieee802_11_parse_vendor_specific(u8 *pos, size_t elen,
23                                             struct ieee802_11_elems *elems,
24                                             int show_errors)
25 {
26         unsigned int oui;
27
28         /* first 3 bytes in vendor specific information element are the IEEE
29          * OUI of the vendor. The following byte is used a vendor specific
30          * sub-type. */
31         if (elen < 4) {
32                 if (show_errors) {
33                         wpa_printf(MSG_MSGDUMP, "short vendor specific "
34                                    "information element ignored (len=%lu)",
35                                    (unsigned long) elen);
36                 }
37                 return -1;
38         }
39
40         oui = WPA_GET_BE24(pos);
41         switch (oui) {
42         case OUI_MICROSOFT:
43                 /* Microsoft/Wi-Fi information elements are further typed and
44                  * subtyped */
45                 switch (pos[3]) {
46                 case 1:
47                         /* Microsoft OUI (00:50:F2) with OUI Type 1:
48                          * real WPA information element */
49                         elems->wpa_ie = pos;
50                         elems->wpa_ie_len = elen;
51                         break;
52                 case WMM_OUI_TYPE:
53                         /* WMM information element */
54                         if (elen < 5) {
55                                 wpa_printf(MSG_MSGDUMP, "short WMM "
56                                            "information element ignored "
57                                            "(len=%lu)",
58                                            (unsigned long) elen);
59                                 return -1;
60                         }
61                         switch (pos[4]) {
62                         case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
63                         case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
64                                 /*
65                                  * Share same pointer since only one of these
66                                  * is used and they start with same data.
67                                  * Length field can be used to distinguish the
68                                  * IEs.
69                                  */
70                                 elems->wmm = pos;
71                                 elems->wmm_len = elen;
72                                 break;
73                         case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
74                                 elems->wmm_tspec = pos;
75                                 elems->wmm_tspec_len = elen;
76                                 break;
77                         default:
78                                 wpa_printf(MSG_MSGDUMP, "unknown WMM "
79                                            "information element ignored "
80                                            "(subtype=%d len=%lu)",
81                                            pos[4], (unsigned long) elen);
82                                 return -1;
83                         }
84                         break;
85                 case 4:
86                         /* Wi-Fi Protected Setup (WPS) IE */
87                         elems->wps_ie = pos;
88                         elems->wps_ie_len = elen;
89                         break;
90                 default:
91                         wpa_printf(MSG_MSGDUMP, "Unknown Microsoft "
92                                    "information element ignored "
93                                    "(type=%d len=%lu)\n",
94                                    pos[3], (unsigned long) elen);
95                         return -1;
96                 }
97                 break;
98
99         case OUI_BROADCOM:
100                 switch (pos[3]) {
101                 case VENDOR_HT_CAPAB_OUI_TYPE:
102                         elems->vendor_ht_cap = pos;
103                         elems->vendor_ht_cap_len = elen;
104                         break;
105                 default:
106                         wpa_printf(MSG_MSGDUMP, "Unknown Broadcom "
107                                    "information element ignored "
108                                    "(type=%d len=%lu)\n",
109                                    pos[3], (unsigned long) elen);
110                         return -1;
111                 }
112                 break;
113
114         default:
115                 wpa_printf(MSG_MSGDUMP, "unknown vendor specific information "
116                            "element ignored (vendor OUI %02x:%02x:%02x "
117                            "len=%lu)",
118                            pos[0], pos[1], pos[2], (unsigned long) elen);
119                 return -1;
120         }
121
122         return 0;
123 }
124
125
126 /**
127  * ieee802_11_parse_elems - Parse information elements in management frames
128  * @start: Pointer to the start of IEs
129  * @len: Length of IE buffer in octets
130  * @elems: Data structure for parsed elements
131  * @show_errors: Whether to show parsing errors in debug log
132  * Returns: Parsing result
133  */
134 ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
135                                 struct ieee802_11_elems *elems,
136                                 int show_errors)
137 {
138         size_t left = len;
139         u8 *pos = start;
140         int unknown = 0;
141
142         os_memset(elems, 0, sizeof(*elems));
143
144         while (left >= 2) {
145                 u8 id, elen;
146
147                 id = *pos++;
148                 elen = *pos++;
149                 left -= 2;
150
151                 if (elen > left) {
152                         if (show_errors) {
153                                 wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
154                                            "parse failed (id=%d elen=%d "
155                                            "left=%lu)",
156                                            id, elen, (unsigned long) left);
157                                 wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
158                         }
159                         return ParseFailed;
160                 }
161
162                 switch (id) {
163                 case WLAN_EID_SSID:
164                         elems->ssid = pos;
165                         elems->ssid_len = elen;
166                         break;
167                 case WLAN_EID_SUPP_RATES:
168                         elems->supp_rates = pos;
169                         elems->supp_rates_len = elen;
170                         break;
171                 case WLAN_EID_FH_PARAMS:
172                         elems->fh_params = pos;
173                         elems->fh_params_len = elen;
174                         break;
175                 case WLAN_EID_DS_PARAMS:
176                         elems->ds_params = pos;
177                         elems->ds_params_len = elen;
178                         break;
179                 case WLAN_EID_CF_PARAMS:
180                         elems->cf_params = pos;
181                         elems->cf_params_len = elen;
182                         break;
183                 case WLAN_EID_TIM:
184                         elems->tim = pos;
185                         elems->tim_len = elen;
186                         break;
187                 case WLAN_EID_IBSS_PARAMS:
188                         elems->ibss_params = pos;
189                         elems->ibss_params_len = elen;
190                         break;
191                 case WLAN_EID_CHALLENGE:
192                         elems->challenge = pos;
193                         elems->challenge_len = elen;
194                         break;
195                 case WLAN_EID_ERP_INFO:
196                         elems->erp_info = pos;
197                         elems->erp_info_len = elen;
198                         break;
199                 case WLAN_EID_EXT_SUPP_RATES:
200                         elems->ext_supp_rates = pos;
201                         elems->ext_supp_rates_len = elen;
202                         break;
203                 case WLAN_EID_VENDOR_SPECIFIC:
204                         if (ieee802_11_parse_vendor_specific(pos, elen,
205                                                              elems,
206                                                              show_errors))
207                                 unknown++;
208                         break;
209                 case WLAN_EID_RSN:
210                         elems->rsn_ie = pos;
211                         elems->rsn_ie_len = elen;
212                         break;
213                 case WLAN_EID_PWR_CAPABILITY:
214                         elems->power_cap = pos;
215                         elems->power_cap_len = elen;
216                         break;
217                 case WLAN_EID_SUPPORTED_CHANNELS:
218                         elems->supp_channels = pos;
219                         elems->supp_channels_len = elen;
220                         break;
221                 case WLAN_EID_MOBILITY_DOMAIN:
222                         elems->mdie = pos;
223                         elems->mdie_len = elen;
224                         break;
225                 case WLAN_EID_FAST_BSS_TRANSITION:
226                         elems->ftie = pos;
227                         elems->ftie_len = elen;
228                         break;
229                 case WLAN_EID_TIMEOUT_INTERVAL:
230                         elems->timeout_int = pos;
231                         elems->timeout_int_len = elen;
232                         break;
233                 case WLAN_EID_HT_CAP:
234                         elems->ht_capabilities = pos;
235                         elems->ht_capabilities_len = elen;
236                         break;
237                 case WLAN_EID_HT_OPERATION:
238                         elems->ht_operation = pos;
239                         elems->ht_operation_len = elen;
240                         break;
241                 default:
242                         unknown++;
243                         if (!show_errors)
244                                 break;
245                         wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
246                                    "ignored unknown element (id=%d elen=%d)",
247                                    id, elen);
248                         break;
249                 }
250
251                 left -= elen;
252                 pos += elen;
253         }
254
255         if (left)
256                 return ParseFailed;
257
258         return unknown ? ParseUnknown : ParseOK;
259 }