Merge branch 'vendor/BMAKE'
[dragonfly.git] / contrib / hostapd / src / p2p / p2p_utils.c
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 int p2p_random(char *buf, size_t len)
25 {
26         u8 val;
27         size_t i;
28         u8 letters = 'Z' - 'A' + 1;
29         u8 numbers = 10;
30
31         if (os_get_random((unsigned char *) buf, len))
32                 return -1;
33         /* Character set: 'A'-'Z', 'a'-'z', '0'-'9' */
34         for (i = 0; i < len; i++) {
35                 val = buf[i];
36                 val %= 2 * letters + numbers;
37                 if (val < letters)
38                         buf[i] = 'A' + val;
39                 else if (val < 2 * letters)
40                         buf[i] = 'a' + (val - letters);
41                 else
42                         buf[i] = '0' + (val - 2 * letters);
43         }
44
45         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 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         switch (op_class) {
60         case 81:
61                 /* channels 1..13 */
62                 if (channel < 1 || channel > 13)
63                         return -1;
64                 return 2407 + 5 * channel;
65         case 82:
66                 /* channel 14 */
67                 if (channel != 14)
68                         return -1;
69                 return 2414 + 5 * channel;
70         case 83: /* channels 1..9; 40 MHz */
71         case 84: /* channels 5..13; 40 MHz */
72                 if (channel < 1 || channel > 13)
73                         return -1;
74                 return 2407 + 5 * channel;
75         case 115: /* channels 36,40,44,48; indoor only */
76         case 118: /* channels 52,56,60,64; dfs */
77                 if (channel < 36 || channel > 64)
78                         return -1;
79                 return 5000 + 5 * channel;
80         case 124: /* channels 149,153,157,161 */
81         case 125: /* channels 149,153,157,161,165,169 */
82                 if (channel < 149 || channel > 161)
83                         return -1;
84                 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                 if (channel < 36 || channel > 64)
90                         return -1;
91                 return 5000 + 5 * channel;
92         case 126: /* channels 149,157; 40 MHz */
93         case 127: /* channels 153,161; 40 MHz */
94                 if (channel < 149 || channel > 161)
95                         return -1;
96                 return 5000 + 5 * channel;
97         case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
98                 if (channel < 36 || channel > 161)
99                         return -1;
100                 return 5000 + 5 * channel;
101         }
102         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 int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
113 {
114         /* TODO: more operating classes */
115         if (freq >= 2412 && freq <= 2472) {
116                 if ((freq - 2407) % 5)
117                         return -1;
118
119                 *op_class = 81; /* 2.407 GHz, channels 1..13 */
120                 *channel = (freq - 2407) / 5;
121                 return 0;
122         }
123
124         if (freq == 2484) {
125                 *op_class = 82; /* channel 14 */
126                 *channel = 14;
127                 return 0;
128         }
129
130         if (freq >= 5180 && freq <= 5240) {
131                 if ((freq - 5000) % 5)
132                         return -1;
133
134                 *op_class = 115; /* 5 GHz, channels 36..48 */
135                 *channel = (freq - 5000) / 5;
136                 return 0;
137         }
138
139         if (freq >= 5745 && freq <= 5805) {
140                 if ((freq - 5000) % 5)
141                         return -1;
142
143                 *op_class = 124; /* 5 GHz, channels 149..161 */
144                 *channel = (freq - 5000) / 5;
145                 return 0;
146         }
147
148         return -1;
149 }
150
151
152 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         res->reg_class = a->reg_class;
159
160         for (i = 0; i < a->channels; i++) {
161                 for (j = 0; j < b->channels; j++) {
162                         if (a->channel[i] != b->channel[j])
163                                 continue;
164                         res->channel[res->channels] = a->channel[i];
165                         res->channels++;
166                         if (res->channels == P2P_MAX_REG_CLASS_CHANNELS)
167                                 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 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         os_memset(res, 0, sizeof(*res));
191
192         for (i = 0; i < a->reg_classes; i++) {
193                 const struct p2p_reg_class *a_reg = &a->reg_class[i];
194                 for (j = 0; j < b->reg_classes; j++) {
195                         const struct p2p_reg_class *b_reg = &b->reg_class[j];
196                         if (a_reg->reg_class != b_reg->reg_class)
197                                 continue;
198                         p2p_reg_class_intersect(
199                                 a_reg, b_reg,
200                                 &res->reg_class[res->reg_classes]);
201                         if (res->reg_class[res->reg_classes].channels) {
202                                 res->reg_classes++;
203                                 if (res->reg_classes == P2P_MAX_REG_CLASSES)
204                                         return;
205                         }
206                 }
207         }
208 }
209
210
211 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         for (i = 0; i < b_cl->channels; i++) {
217                 for (j = 0; j < cl->channels; j++) {
218                         if (b_cl->channel[i] == cl->channel[j])
219                                 break;
220                 }
221                 if (j == cl->channels) {
222                         if (cl->channels == P2P_MAX_REG_CLASS_CHANNELS)
223                                 return;
224                         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 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         if (a != res)
243                 os_memcpy(res, a, sizeof(*res));
244
245         for (i = 0; i < res->reg_classes; i++) {
246                 struct p2p_reg_class *cl = &res->reg_class[i];
247                 for (j = 0; j < b->reg_classes; j++) {
248                         const struct p2p_reg_class *b_cl = &b->reg_class[j];
249                         if (cl->reg_class != b_cl->reg_class)
250                                 continue;
251                         p2p_op_class_union(cl, b_cl);
252                 }
253         }
254
255         for (j = 0; j < b->reg_classes; j++) {
256                 const struct p2p_reg_class *b_cl = &b->reg_class[j];
257
258                 for (i = 0; i < res->reg_classes; i++) {
259                         struct p2p_reg_class *cl = &res->reg_class[i];
260                         if (cl->reg_class == b_cl->reg_class)
261                                 break;
262                 }
263
264                 if (i == res->reg_classes) {
265                         if (res->reg_classes == P2P_MAX_REG_CLASSES)
266                                 return;
267                         os_memcpy(&res->reg_class[res->reg_classes++],
268                                   b_cl, sizeof(struct p2p_reg_class));
269                 }
270         }
271 }
272
273
274 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         if (list == NULL)
280                 return;
281
282         o = 0;
283         while (o < chan->reg_classes) {
284                 struct p2p_reg_class *op = &chan->reg_class[o];
285
286                 c = 0;
287                 while (c < op->channels) {
288                         int freq = p2p_channel_to_freq(op->reg_class,
289                                                        op->channel[c]);
290                         if (freq > 0 && freq_range_list_includes(list, freq)) {
291                                 op->channels--;
292                                 os_memmove(&op->channel[c],
293                                            &op->channel[c + 1],
294                                            op->channels - c);
295                         } else
296                                 c++;
297                 }
298
299                 if (op->channels == 0) {
300                         chan->reg_classes--;
301                         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                         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 int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
318                           u8 channel)
319 {
320         size_t i, j;
321         for (i = 0; i < channels->reg_classes; i++) {
322                 const struct p2p_reg_class *reg = &channels->reg_class[i];
323                 if (reg->reg_class != reg_class)
324                         continue;
325                 for (j = 0; j < reg->channels; j++) {
326                         if (reg->channel[j] == channel)
327                                 return 1;
328                 }
329         }
330         return 0;
331 }
332
333
334 int p2p_channels_includes_freq(const struct p2p_channels *channels,
335                                unsigned int freq)
336 {
337         size_t i, j;
338         for (i = 0; i < channels->reg_classes; i++) {
339                 const struct p2p_reg_class *reg = &channels->reg_class[i];
340                 for (j = 0; j < reg->channels; j++) {
341                         if (p2p_channel_to_freq(reg->reg_class,
342                                                 reg->channel[j]) == (int) freq)
343                                 return 1;
344                 }
345         }
346         return 0;
347 }
348
349
350 int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
351 {
352         u8 op_reg_class, op_channel;
353         if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
354                 return 0;
355         return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
356                                      op_channel);
357 }
358
359
360 int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq)
361 {
362         u8 op_reg_class, op_channel;
363         if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
364                 return 0;
365         return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
366                                      op_channel) &&
367                 !freq_range_list_includes(&p2p->no_go_freq, freq);
368 }
369
370
371 int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq)
372 {
373         u8 op_reg_class, op_channel;
374         if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
375                 return 0;
376         return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
377                                      op_channel) ||
378                 p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class,
379                                       op_channel);
380 }
381
382
383 unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
384                                const struct p2p_channels *channels)
385 {
386         unsigned int i;
387         int freq = 0;
388
389         if (channels == NULL) {
390                 if (p2p->cfg->num_pref_chan) {
391                         freq = p2p_channel_to_freq(
392                                 p2p->cfg->pref_chan[0].op_class,
393                                 p2p->cfg->pref_chan[0].chan);
394                         if (freq < 0)
395                                 freq = 0;
396                 }
397                 return freq;
398         }
399
400         for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
401                 freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class,
402                                            p2p->cfg->pref_chan[i].chan);
403                 if (p2p_channels_includes_freq(channels, freq))
404                         return freq;
405         }
406
407         return 0;
408 }
409
410
411 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         pos = buf;
419         end = pos + sizeof(buf);
420
421         for (i = 0; i < chan->reg_classes; i++) {
422                 const struct p2p_reg_class *c;
423                 c = &chan->reg_class[i];
424                 ret = os_snprintf(pos, end - pos, " %u:", c->reg_class);
425                 if (ret < 0 || ret >= end - pos)
426                         break;
427                 pos += ret;
428
429                 for (j = 0; j < c->channels; j++) {
430                         ret = os_snprintf(pos, end - pos, "%s%u",
431                                           j == 0 ? "" : ",",
432                                           c->channel[j]);
433                         if (ret < 0 || ret >= end - pos)
434                                 break;
435                         pos += ret;
436                 }
437         }
438         *pos = '\0';
439
440         p2p_dbg(p2p, "%s:%s", title, buf);
441 }
442
443
444 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         for (j = 0; classes[j]; j++) {
450                 for (i = 0; i < chans->reg_classes; i++) {
451                         struct p2p_reg_class *c = &chans->reg_class[i];
452
453                         if (c->channels == 0)
454                                 continue;
455
456                         if (c->reg_class == classes[j]) {
457                                 /*
458                                  * Pick one of the available channels in the
459                                  * operating class at random.
460                                  */
461                                 os_get_random((u8 *) &r, sizeof(r));
462                                 r %= c->channels;
463                                 *op_class = c->reg_class;
464                                 *op_channel = c->channel[r];
465                                 return 0;
466                         }
467                 }
468         }
469
470         return -1;
471 }