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