1 /*
2 * IEEE 802.11 Common routines
3 * Copyright (c) 2002-2019, 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 "utils/includes.h"
10
11 #include "utils/common.h"
12 #include "defs.h"
13 #include "ieee802_11_defs.h"
14 #include "ieee802_11_common.h"
15 #include "common/wpa_supplicant_i.h"
16
17 /**
18 * get_ie - Fetch a specified information element from IEs buffer
19 * @ies: Information elements buffer
20 * @len: Information elements buffer length
21 * @eid: Information element identifier (WLAN_EID_*)
22 * Returns: Pointer to the information element (id field) or %NULL if not found
23 *
24 * This function returns the first matching information element in the IEs
25 * buffer or %NULL in case the element is not found.
26 */
get_ie(const u8 * ies,size_t len,u8 eid)27 const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
28 {
29 const struct element *elem;
30
31 if (!ies)
32 return NULL;
33
34 for_each_element_id(elem, eid, ies, len)
35 return &elem->id;
36
37 return NULL;
38 }
39
get_vendor_ie(const u8 * ies,size_t len,u32 vendor_type)40 const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
41 {
42 const struct element *elem;
43
44 for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) {
45 if (elem->datalen >= 4 &&
46 vendor_type == WPA_GET_BE32(elem->data))
47 return &elem->id;
48 }
49
50 return NULL;
51 }
52
mbo_add_ie(u8 * buf,size_t len,const u8 * attr,size_t attr_len)53 size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
54 {
55 /*
56 * MBO IE requires 6 bytes without the attributes: EID (1), length (1),
57 * OUI (3), OUI type (1).
58 */
59 if (len < 6 + attr_len) {
60 wpa_printf(MSG_DEBUG,
61 "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu",
62 len, attr_len);
63 return 0;
64 }
65
66 *buf++ = WLAN_EID_VENDOR_SPECIFIC;
67 *buf++ = attr_len + 4;
68 WPA_PUT_BE24(buf, OUI_WFA);
69 buf += 3;
70 *buf++ = MBO_OUI_TYPE;
71 os_memcpy(buf, attr, attr_len);
72
73 return 6 + attr_len;
74 }
75
ieee802_11_parse_candidate_list(const char * pos,u8 * nei_rep,size_t nei_rep_len)76 int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
77 size_t nei_rep_len)
78 {
79 u8 *nei_pos = nei_rep;
80 const char *end;
81
82 /*
83 * BSS Transition Candidate List Entries - Neighbor Report elements
84 * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
85 * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
86 */
87 while (pos) {
88 u8 *nei_start;
89 long int val;
90 char *endptr, *tmp;
91
92 pos = os_strstr(pos, " neighbor=");
93 if (!pos)
94 break;
95 if (nei_pos + 15 > nei_rep + nei_rep_len) {
96 wpa_printf(MSG_DEBUG,
97 "Not enough room for additional neighbor");
98 return -1;
99 }
100 pos += 10;
101
102 nei_start = nei_pos;
103 *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
104 nei_pos++; /* length to be filled in */
105
106 if (hwaddr_aton2(pos, nei_pos) < 0) {
107 wpa_printf(MSG_DEBUG, "Invalid BSSID");
108 return -1;
109 }
110 nei_pos += ETH_ALEN;
111 pos += 17;
112 if (*pos != ',') {
113 wpa_printf(MSG_DEBUG, "Missing BSSID Information");
114 return -1;
115 }
116 pos++;
117
118 val = strtol(pos, &endptr, 0);
119 WPA_PUT_LE32(nei_pos, val);
120 nei_pos += 4;
121 if (*endptr != ',') {
122 wpa_printf(MSG_DEBUG, "Missing Operating Class");
123 return -1;
124 }
125 pos = endptr + 1;
126
127 *nei_pos++ = atoi(pos); /* Operating Class */
128 pos = os_strchr(pos, ',');
129 if (pos == NULL) {
130 wpa_printf(MSG_DEBUG, "Missing Channel Number");
131 return -1;
132 }
133 pos++;
134
135 *nei_pos++ = atoi(pos); /* Channel Number */
136 pos = os_strchr(pos, ',');
137 if (pos == NULL) {
138 wpa_printf(MSG_DEBUG, "Missing PHY Type");
139 return -1;
140 }
141 pos++;
142
143 *nei_pos++ = atoi(pos); /* PHY Type */
144 end = os_strchr(pos, ' ');
145 tmp = os_strchr(pos, ',');
146 if (tmp && (!end || tmp < end)) {
147 /* Optional Subelements (hexdump) */
148 size_t len;
149
150 pos = tmp + 1;
151 end = os_strchr(pos, ' ');
152 if (end)
153 len = end - pos;
154 else
155 len = os_strlen(pos);
156 if (nei_pos + len / 2 > nei_rep + nei_rep_len) {
157 wpa_printf(MSG_DEBUG,
158 "Not enough room for neighbor subelements");
159 return -1;
160 }
161 if (len & 0x01 ||
162 hexstr2bin(pos, nei_pos, len / 2) < 0) {
163 wpa_printf(MSG_DEBUG,
164 "Invalid neighbor subelement info");
165 return -1;
166 }
167 nei_pos += len / 2;
168 pos = end;
169 }
170
171 nei_start[1] = nei_pos - nei_start - 2;
172 }
173
174 return nei_pos - nei_rep;
175 }
176
177 /**
178 * ieee802_11_parse_elems - Parse information elements in management frames
179 * @start: Pointer to the start of IEs
180 * @len: Length of IE buffer in octets
181 * @elems: Data structure for parsed elements
182 * @show_errors: Whether to show parsing errors in debug log
183 * Returns: Parsing result
184 */
ieee802_11_parse_elems(struct wpa_supplicant * wpa_s,const u8 * start,size_t len)185 int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len)
186 {
187 const struct element *elem;
188
189 if (!start)
190 return 0;
191
192 for_each_element(elem, start, len) {
193 u8 id = elem->id;
194 const u8 *pos = elem->data;
195
196 switch (id) {
197 case WLAN_EID_RRM_ENABLED_CAPABILITIES:
198 os_memcpy(wpa_s->rrm_ie, pos, 5);
199 wpa_s->rrm.rrm_used = true;
200 break;
201 case WLAN_EID_EXT_CAPAB:
202 /* extended caps can go beyond 8 octacts but we aren't using them now */
203 os_memcpy(wpa_s->extend_caps, pos, 5);
204 break;
205 default:
206 break;
207
208 }
209 }
210 return 0;
211 }
212
ieee802_11_ext_capab(const u8 * ie,unsigned int capab)213 int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
214 {
215 if (!ie || ie[1] <= capab / 8)
216 return 0;
217 return !!(ie[2 + capab / 8] & BIT(capab % 8));
218 }
219
get_operating_class(u8 chan,int sec_channel)220 u8 get_operating_class(u8 chan, int sec_channel)
221 {
222 u8 op_class;
223
224 if (chan < 1 || chan > 14)
225 return 0;
226 if (sec_channel == 1)
227 op_class = 83;
228 else if (sec_channel == -1)
229 op_class = 84;
230 else
231 op_class = 81;
232
233 return op_class;
234 }
235