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