Branch data Line data Source code
1 : : /*
2 : : * P2P - generic helper functions
3 : : * Copyright (c) 2009, Atheros Communications
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 "p2p_i.h"
13 : :
14 : :
15 : : /**
16 : : * p2p_random - Generate random string for SSID and passphrase
17 : : * @buf: Buffer for returning the result
18 : : * @len: Number of octets to write to the buffer
19 : : * Returns: 0 on success, -1 on failure
20 : : *
21 : : * This function generates a random string using the following character set:
22 : : * 'A'-'Z', 'a'-'z', '0'-'9'.
23 : : */
24 : 94 : int p2p_random(char *buf, size_t len)
25 : : {
26 : : u8 val;
27 : : size_t i;
28 : 94 : u8 letters = 'Z' - 'A' + 1;
29 : 94 : u8 numbers = 10;
30 : :
31 [ - + ]: 94 : if (os_get_random((unsigned char *) buf, len))
32 : 0 : return -1;
33 : : /* Character set: 'A'-'Z', 'a'-'z', '0'-'9' */
34 [ + + ]: 564 : for (i = 0; i < len; i++) {
35 : 470 : val = buf[i];
36 : 470 : val %= 2 * letters + numbers;
37 [ + + ]: 470 : if (val < letters)
38 : 192 : buf[i] = 'A' + val;
39 [ + + ]: 278 : else if (val < 2 * letters)
40 : 194 : buf[i] = 'a' + (val - letters);
41 : : else
42 : 84 : buf[i] = '0' + (val - 2 * letters);
43 : : }
44 : :
45 : 94 : return 0;
46 : : }
47 : :
48 : :
49 : : /**
50 : : * p2p_channel_to_freq - Convert channel info to frequency
51 : : * @op_class: Operating class
52 : : * @channel: Channel number
53 : : * Returns: Frequency in MHz or -1 if the specified channel is unknown
54 : : */
55 : 2197 : int p2p_channel_to_freq(int op_class, int channel)
56 : : {
57 : : /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
58 : : /* TODO: more operating classes */
59 [ + - - - : 2197 : switch (op_class) {
- - - -
- ]
60 : : case 81:
61 : : /* channels 1..13 */
62 [ + - ][ - + ]: 2197 : if (channel < 1 || channel > 13)
63 : 0 : return -1;
64 : 2197 : return 2407 + 5 * channel;
65 : : case 82:
66 : : /* channel 14 */
67 [ # # ]: 0 : if (channel != 14)
68 : 0 : return -1;
69 : 0 : return 2414 + 5 * channel;
70 : : case 83: /* channels 1..9; 40 MHz */
71 : : case 84: /* channels 5..13; 40 MHz */
72 [ # # ][ # # ]: 0 : if (channel < 1 || channel > 13)
73 : 0 : return -1;
74 : 0 : return 2407 + 5 * channel;
75 : : case 115: /* channels 36,40,44,48; indoor only */
76 : : case 118: /* channels 52,56,60,64; dfs */
77 [ # # ][ # # ]: 0 : if (channel < 36 || channel > 64)
78 : 0 : return -1;
79 : 0 : return 5000 + 5 * channel;
80 : : case 124: /* channels 149,153,157,161 */
81 : : case 125: /* channels 149,153,157,161,165,169 */
82 [ # # ][ # # ]: 0 : if (channel < 149 || channel > 161)
83 : 0 : return -1;
84 : 0 : return 5000 + 5 * channel;
85 : : case 116: /* channels 36,44; 40 MHz; indoor only */
86 : : case 117: /* channels 40,48; 40 MHz; indoor only */
87 : : case 119: /* channels 52,60; 40 MHz; dfs */
88 : : case 120: /* channels 56,64; 40 MHz; dfs */
89 [ # # ][ # # ]: 0 : if (channel < 36 || channel > 64)
90 : 0 : return -1;
91 : 0 : return 5000 + 5 * channel;
92 : : case 126: /* channels 149,157; 40 MHz */
93 : : case 127: /* channels 153,161; 40 MHz */
94 [ # # ][ # # ]: 0 : if (channel < 149 || channel > 161)
95 : 0 : return -1;
96 : 0 : return 5000 + 5 * channel;
97 : : case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
98 [ # # ][ # # ]: 0 : if (channel < 36 || channel > 161)
99 : 0 : return -1;
100 : 0 : return 5000 + 5 * channel;
101 : : }
102 : 2197 : return -1;
103 : : }
104 : :
105 : :
106 : : /**
107 : : * p2p_freq_to_channel - Convert frequency into channel info
108 : : * @op_class: Buffer for returning operating class
109 : : * @channel: Buffer for returning channel number
110 : : * Returns: 0 on success, -1 if the specified frequency is unknown
111 : : */
112 : 72 : int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
113 : : {
114 : : /* TODO: more operating classes */
115 [ + - ][ + - ]: 72 : if (freq >= 2412 && freq <= 2472) {
116 [ - + ]: 72 : if ((freq - 2407) % 5)
117 : 0 : return -1;
118 : :
119 : 72 : *op_class = 81; /* 2.407 GHz, channels 1..13 */
120 : 72 : *channel = (freq - 2407) / 5;
121 : 72 : return 0;
122 : : }
123 : :
124 [ # # ]: 0 : if (freq == 2484) {
125 : 0 : *op_class = 82; /* channel 14 */
126 : 0 : *channel = 14;
127 : 0 : return 0;
128 : : }
129 : :
130 [ # # ][ # # ]: 0 : if (freq >= 5180 && freq <= 5240) {
131 [ # # ]: 0 : if ((freq - 5000) % 5)
132 : 0 : return -1;
133 : :
134 : 0 : *op_class = 115; /* 5 GHz, channels 36..48 */
135 : 0 : *channel = (freq - 5000) / 5;
136 : 0 : return 0;
137 : : }
138 : :
139 [ # # ][ # # ]: 0 : if (freq >= 5745 && freq <= 5805) {
140 [ # # ]: 0 : if ((freq - 5000) % 5)
141 : 0 : return -1;
142 : :
143 : 0 : *op_class = 124; /* 5 GHz, channels 149..161 */
144 : 0 : *channel = (freq - 5000) / 5;
145 : 0 : return 0;
146 : : }
147 : :
148 : 72 : return -1;
149 : : }
150 : :
151 : :
152 : 292 : static void p2p_reg_class_intersect(const struct p2p_reg_class *a,
153 : : const struct p2p_reg_class *b,
154 : : struct p2p_reg_class *res)
155 : : {
156 : : size_t i, j;
157 : :
158 : 292 : res->reg_class = a->reg_class;
159 : :
160 [ + + ]: 2994 : for (i = 0; i < a->channels; i++) {
161 [ + + ]: 28754 : for (j = 0; j < b->channels; j++) {
162 [ + + ]: 26052 : if (a->channel[i] != b->channel[j])
163 : 23691 : continue;
164 : 2361 : res->channel[res->channels] = a->channel[i];
165 : 2361 : res->channels++;
166 [ - + ]: 2361 : if (res->channels == P2P_MAX_REG_CLASS_CHANNELS)
167 : 292 : return;
168 : : }
169 : : }
170 : : }
171 : :
172 : :
173 : : /**
174 : : * p2p_channels_intersect - Intersection of supported channel lists
175 : : * @a: First set of supported channels
176 : : * @b: Second set of supported channels
177 : : * @res: Data structure for returning the intersection of support channels
178 : : *
179 : : * This function can be used to find a common set of supported channels. Both
180 : : * input channels sets are assumed to use the same country code. If different
181 : : * country codes are used, the regulatory class numbers may not be matched
182 : : * correctly and results are undefined.
183 : : */
184 : 294 : void p2p_channels_intersect(const struct p2p_channels *a,
185 : : const struct p2p_channels *b,
186 : : struct p2p_channels *res)
187 : : {
188 : : size_t i, j;
189 : :
190 : 294 : os_memset(res, 0, sizeof(*res));
191 : :
192 [ + + ]: 646 : for (i = 0; i < a->reg_classes; i++) {
193 : 352 : const struct p2p_reg_class *a_reg = &a->reg_class[i];
194 [ + + ]: 764 : for (j = 0; j < b->reg_classes; j++) {
195 : 412 : const struct p2p_reg_class *b_reg = &b->reg_class[j];
196 [ + + ]: 412 : if (a_reg->reg_class != b_reg->reg_class)
197 : 120 : continue;
198 : 292 : p2p_reg_class_intersect(
199 : : a_reg, b_reg,
200 : 292 : &res->reg_class[res->reg_classes]);
201 [ + + ]: 292 : if (res->reg_class[res->reg_classes].channels) {
202 : 291 : res->reg_classes++;
203 [ - + ]: 291 : if (res->reg_classes == P2P_MAX_REG_CLASSES)
204 : 294 : return;
205 : : }
206 : : }
207 : : }
208 : : }
209 : :
210 : :
211 : 5 : static void p2p_op_class_union(struct p2p_reg_class *cl,
212 : : const struct p2p_reg_class *b_cl)
213 : : {
214 : : size_t i, j;
215 : :
216 [ + + ]: 15 : for (i = 0; i < b_cl->channels; i++) {
217 [ + + ]: 125 : for (j = 0; j < cl->channels; j++) {
218 [ - + ]: 115 : if (b_cl->channel[i] == cl->channel[j])
219 : 0 : break;
220 : : }
221 [ + - ]: 10 : if (j == cl->channels) {
222 [ - + ]: 10 : if (cl->channels == P2P_MAX_REG_CLASS_CHANNELS)
223 : 5 : return;
224 : 10 : cl->channel[cl->channels++] = b_cl->channel[i];
225 : : }
226 : : }
227 : : }
228 : :
229 : :
230 : : /**
231 : : * p2p_channels_union - Union of channel lists
232 : : * @a: First set of channels
233 : : * @b: Second set of channels
234 : : * @res: Data structure for returning the union of channels
235 : : */
236 : 35 : void p2p_channels_union(const struct p2p_channels *a,
237 : : const struct p2p_channels *b,
238 : : struct p2p_channels *res)
239 : : {
240 : : size_t i, j;
241 : :
242 [ - + ]: 35 : if (a != res)
243 : 0 : os_memcpy(res, a, sizeof(*res));
244 : :
245 [ + + ]: 70 : for (i = 0; i < res->reg_classes; i++) {
246 : 35 : struct p2p_reg_class *cl = &res->reg_class[i];
247 [ + + ]: 70 : for (j = 0; j < b->reg_classes; j++) {
248 : 35 : const struct p2p_reg_class *b_cl = &b->reg_class[j];
249 [ + + ]: 35 : if (cl->reg_class != b_cl->reg_class)
250 : 30 : continue;
251 : 5 : p2p_op_class_union(cl, b_cl);
252 : : }
253 : : }
254 : :
255 [ + + ]: 70 : for (j = 0; j < b->reg_classes; j++) {
256 : 35 : const struct p2p_reg_class *b_cl = &b->reg_class[j];
257 : :
258 [ + + ]: 140 : for (i = 0; i < res->reg_classes; i++) {
259 : 110 : struct p2p_reg_class *cl = &res->reg_class[i];
260 [ + + ]: 110 : if (cl->reg_class == b_cl->reg_class)
261 : 5 : break;
262 : : }
263 : :
264 [ + + ]: 35 : if (i == res->reg_classes) {
265 [ - + ]: 30 : if (res->reg_classes == P2P_MAX_REG_CLASSES)
266 : 35 : return;
267 : 30 : os_memcpy(&res->reg_class[res->reg_classes++],
268 : : b_cl, sizeof(struct p2p_reg_class));
269 : : }
270 : : }
271 : : }
272 : :
273 : :
274 : 108 : void p2p_channels_remove_freqs(struct p2p_channels *chan,
275 : : const struct wpa_freq_range_list *list)
276 : : {
277 : : size_t o, c;
278 : :
279 [ - + ]: 108 : if (list == NULL)
280 : 108 : return;
281 : :
282 : 108 : o = 0;
283 [ + + ]: 216 : while (o < chan->reg_classes) {
284 : 108 : struct p2p_reg_class *op = &chan->reg_class[o];
285 : :
286 : 108 : c = 0;
287 [ + + ]: 1016 : while (c < op->channels) {
288 : 908 : int freq = p2p_channel_to_freq(op->reg_class,
289 : 908 : op->channel[c]);
290 [ + - ][ + + ]: 908 : if (freq > 0 && freq_range_list_includes(list, freq)) {
291 : 13 : op->channels--;
292 : 13 : os_memmove(&op->channel[c],
293 : : &op->channel[c + 1],
294 : : op->channels - c);
295 : : } else
296 : 895 : c++;
297 : : }
298 : :
299 [ + + ]: 108 : if (op->channels == 0) {
300 : 3 : chan->reg_classes--;
301 : 3 : os_memmove(&chan->reg_class[o], &chan->reg_class[o + 1],
302 : : (chan->reg_classes - o) *
303 : : sizeof(struct p2p_reg_class));
304 : : } else
305 : 105 : o++;
306 : : }
307 : : }
308 : :
309 : :
310 : : /**
311 : : * p2p_channels_includes - Check whether a channel is included in the list
312 : : * @channels: List of supported channels
313 : : * @reg_class: Regulatory class of the channel to search
314 : : * @channel: Channel number of the channel to search
315 : : * Returns: 1 if channel was found or 0 if not
316 : : */
317 : 167 : int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
318 : : u8 channel)
319 : : {
320 : : size_t i, j;
321 [ + + ]: 174 : for (i = 0; i < channels->reg_classes; i++) {
322 : 167 : const struct p2p_reg_class *reg = &channels->reg_class[i];
323 [ - + ]: 167 : if (reg->reg_class != reg_class)
324 : 0 : continue;
325 [ + + ]: 715 : for (j = 0; j < reg->channels; j++) {
326 [ + + ]: 708 : if (reg->channel[j] == channel)
327 : 160 : return 1;
328 : : }
329 : : }
330 : 167 : return 0;
331 : : }
332 : :
333 : :
334 : 6 : int p2p_channels_includes_freq(const struct p2p_channels *channels,
335 : : unsigned int freq)
336 : : {
337 : : size_t i, j;
338 [ + - ]: 6 : for (i = 0; i < channels->reg_classes; i++) {
339 : 6 : const struct p2p_reg_class *reg = &channels->reg_class[i];
340 [ + - ]: 26 : for (j = 0; j < reg->channels; j++) {
341 [ + + ]: 26 : if (p2p_channel_to_freq(reg->reg_class,
342 : 52 : reg->channel[j]) == (int) freq)
343 : 6 : return 1;
344 : : }
345 : : }
346 : 6 : return 0;
347 : : }
348 : :
349 : :
350 : 13 : int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
351 : : {
352 : : u8 op_reg_class, op_channel;
353 [ - + ]: 13 : if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
354 : 0 : return 0;
355 : 13 : return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
356 : : op_channel);
357 : : }
358 : :
359 : :
360 : 29 : int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq)
361 : : {
362 : : u8 op_reg_class, op_channel;
363 [ - + ]: 29 : if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
364 : 0 : return 0;
365 [ + - ]: 58 : return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
366 [ + - ]: 29 : op_channel) &&
367 : 29 : !freq_range_list_includes(&p2p->no_go_freq, freq);
368 : : }
369 : :
370 : :
371 : 9 : int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq)
372 : : {
373 : : u8 op_reg_class, op_channel;
374 [ - + ]: 9 : if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
375 : 0 : return 0;
376 [ - + ]: 9 : return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
377 [ # # ]: 0 : op_channel) ||
378 : 0 : p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class,
379 : : op_channel);
380 : : }
381 : :
382 : :
383 : 9 : unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
384 : : const struct p2p_channels *channels)
385 : : {
386 : : unsigned int i;
387 : 9 : int freq = 0;
388 : :
389 [ + - ]: 9 : if (channels == NULL) {
390 [ - + ]: 9 : if (p2p->cfg->num_pref_chan) {
391 : 0 : freq = p2p_channel_to_freq(
392 : 0 : p2p->cfg->pref_chan[0].op_class,
393 : 0 : p2p->cfg->pref_chan[0].chan);
394 [ # # ]: 0 : if (freq < 0)
395 : 0 : freq = 0;
396 : : }
397 : 9 : return freq;
398 : : }
399 : :
400 [ # # ][ # # ]: 0 : for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
401 : 0 : freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class,
402 : 0 : p2p->cfg->pref_chan[i].chan);
403 [ # # ]: 0 : if (p2p_channels_includes_freq(channels, freq))
404 : 0 : return freq;
405 : : }
406 : :
407 : 9 : return 0;
408 : : }
409 : :
410 : :
411 : 2076 : void p2p_channels_dump(struct p2p_data *p2p, const char *title,
412 : : const struct p2p_channels *chan)
413 : : {
414 : : char buf[500], *pos, *end;
415 : : size_t i, j;
416 : : int ret;
417 : :
418 : 2076 : pos = buf;
419 : 2076 : end = pos + sizeof(buf);
420 : :
421 [ + + ]: 3560 : for (i = 0; i < chan->reg_classes; i++) {
422 : : const struct p2p_reg_class *c;
423 : 1484 : c = &chan->reg_class[i];
424 : 1484 : ret = os_snprintf(pos, end - pos, " %u:", c->reg_class);
425 [ + - ][ + - ]: 1484 : if (ret < 0 || ret >= end - pos)
426 : : break;
427 : 1484 : pos += ret;
428 : :
429 [ + + ]: 15072 : for (j = 0; j < c->channels; j++) {
430 [ + + ]: 13588 : ret = os_snprintf(pos, end - pos, "%s%u",
431 : : j == 0 ? "" : ",",
432 : 13588 : c->channel[j]);
433 [ + - ][ + - ]: 13588 : if (ret < 0 || ret >= end - pos)
434 : : break;
435 : 13588 : pos += ret;
436 : : }
437 : : }
438 : 2076 : *pos = '\0';
439 : :
440 : 2076 : p2p_dbg(p2p, "%s:%s", title, buf);
441 : 2076 : }
442 : :
443 : :
444 : 297 : int p2p_channel_select(struct p2p_channels *chans, const int *classes,
445 : : u8 *op_class, u8 *op_channel)
446 : : {
447 : : unsigned int i, j, r;
448 : :
449 [ + + ]: 990 : for (j = 0; classes[j]; j++) {
450 [ + + ]: 1386 : for (i = 0; i < chans->reg_classes; i++) {
451 : 693 : struct p2p_reg_class *c = &chans->reg_class[i];
452 : :
453 [ - + ]: 693 : if (c->channels == 0)
454 : 0 : continue;
455 : :
456 [ - + ]: 693 : if (c->reg_class == classes[j]) {
457 : : /*
458 : : * Pick one of the available channels in the
459 : : * operating class at random.
460 : : */
461 : 0 : os_get_random((u8 *) &r, sizeof(r));
462 : 0 : r %= c->channels;
463 : 0 : *op_class = c->reg_class;
464 : 0 : *op_channel = c->channel[r];
465 : 0 : return 0;
466 : : }
467 : : }
468 : : }
469 : :
470 : 297 : return -1;
471 : : }
|