p2p_utils.c 11 KB

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