LCOV - code coverage report
Current view: top level - src/p2p - p2p_utils.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 199 214 93.0 %
Date: 2015-09-27 Functions: 20 20 100.0 %

          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 "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             :  */
      26         596 : int p2p_random(char *buf, size_t len)
      27             : {
      28             :         u8 val;
      29             :         size_t i;
      30         596 :         u8 letters = 'Z' - 'A' + 1;
      31         596 :         u8 numbers = 10;
      32             : 
      33         596 :         if (os_get_random((unsigned char *) buf, len))
      34           0 :                 return -1;
      35             :         /* Character set: 'A'-'Z', 'a'-'z', '0'-'9' */
      36        3515 :         for (i = 0; i < len; i++) {
      37        2919 :                 val = buf[i];
      38        2919 :                 val %= 2 * letters + numbers;
      39        2919 :                 if (val < letters)
      40        1276 :                         buf[i] = 'A' + val;
      41        1643 :                 else if (val < 2 * letters)
      42        1209 :                         buf[i] = 'a' + (val - letters);
      43             :                 else
      44         434 :                         buf[i] = '0' + (val - 2 * letters);
      45             :         }
      46             : 
      47         596 :         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             :  */
      57       97062 : int p2p_channel_to_freq(int op_class, int channel)
      58             : {
      59       97062 :         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             :  */
      69       10427 : int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
      70             : {
      71       10427 :         if (ieee80211_freq_to_channel_ext(freq, 0, 0, op_class, channel) ==
      72             :             NUM_HOSTAPD_MODES)
      73           1 :                 return -1;
      74             : 
      75       10426 :         return 0;
      76             : }
      77             : 
      78             : 
      79        1290 : static 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        1290 :         res->reg_class = a->reg_class;
      86             : 
      87       11976 :         for (i = 0; i < a->channels; i++) {
      88      111853 :                 for (j = 0; j < b->channels; j++) {
      89      101167 :                         if (a->channel[i] != b->channel[j])
      90       91415 :                                 continue;
      91        9752 :                         res->channel[res->channels] = a->channel[i];
      92        9752 :                         res->channels++;
      93        9752 :                         if (res->channels == P2P_MAX_REG_CLASS_CHANNELS)
      94        1290 :                                 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             :  */
     111        1168 : void 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        1168 :         os_memset(res, 0, sizeof(*res));
     118             : 
     119        2670 :         for (i = 0; i < a->reg_classes; i++) {
     120        1502 :                 const struct p2p_reg_class *a_reg = &a->reg_class[i];
     121        5333 :                 for (j = 0; j < b->reg_classes; j++) {
     122        3831 :                         const struct p2p_reg_class *b_reg = &b->reg_class[j];
     123        3831 :                         if (a_reg->reg_class != b_reg->reg_class)
     124        2541 :                                 continue;
     125        1290 :                         p2p_reg_class_intersect(
     126             :                                 a_reg, b_reg,
     127        1290 :                                 &res->reg_class[res->reg_classes]);
     128        1290 :                         if (res->reg_class[res->reg_classes].channels) {
     129        1287 :                                 res->reg_classes++;
     130        1287 :                                 if (res->reg_classes == P2P_MAX_REG_CLASSES)
     131        1168 :                                         return;
     132             :                         }
     133             :                 }
     134             :         }
     135             : }
     136             : 
     137             : 
     138           7 : static 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          21 :         for (i = 0; i < b_cl->channels; i++) {
     144         175 :                 for (j = 0; j < cl->channels; j++) {
     145         161 :                         if (b_cl->channel[i] == cl->channel[j])
     146           0 :                                 break;
     147             :                 }
     148          14 :                 if (j == cl->channels) {
     149          14 :                         if (cl->channels == P2P_MAX_REG_CLASS_CHANNELS)
     150           7 :                                 return;
     151          14 :                         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             :  */
     162        8223 : void p2p_channels_union_inplace(struct p2p_channels *res,
     163             :                                 const struct p2p_channels *b)
     164             : {
     165             :         size_t i, j;
     166             : 
     167        8498 :         for (i = 0; i < res->reg_classes; i++) {
     168         275 :                 struct p2p_reg_class *cl = &res->reg_class[i];
     169         338 :                 for (j = 0; j < b->reg_classes; j++) {
     170          63 :                         const struct p2p_reg_class *b_cl = &b->reg_class[j];
     171          63 :                         if (cl->reg_class != b_cl->reg_class)
     172          56 :                                 continue;
     173           7 :                         p2p_op_class_union(cl, b_cl);
     174             :                 }
     175             :         }
     176             : 
     177       16399 :         for (j = 0; j < b->reg_classes; j++) {
     178        8176 :                 const struct p2p_reg_class *b_cl = &b->reg_class[j];
     179             : 
     180        8907 :                 for (i = 0; i < res->reg_classes; i++) {
     181         738 :                         struct p2p_reg_class *cl = &res->reg_class[i];
     182         738 :                         if (cl->reg_class == b_cl->reg_class)
     183           7 :                                 break;
     184             :                 }
     185             : 
     186        8176 :                 if (i == res->reg_classes) {
     187        8169 :                         if (res->reg_classes == P2P_MAX_REG_CLASSES)
     188        8223 :                                 return;
     189        8169 :                         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             :  */
     202        8056 : void p2p_channels_union(const struct p2p_channels *a,
     203             :                         const struct p2p_channels *b,
     204             :                         struct p2p_channels *res)
     205             : {
     206        8056 :         os_memcpy(res, a, sizeof(*res));
     207        8056 :         p2p_channels_union_inplace(res, b);
     208        8056 : }
     209             : 
     210             : 
     211         381 : void p2p_channels_remove_freqs(struct p2p_channels *chan,
     212             :                                const struct wpa_freq_range_list *list)
     213             : {
     214             :         size_t o, c;
     215             : 
     216         381 :         if (list == NULL)
     217         381 :                 return;
     218             : 
     219         381 :         o = 0;
     220        1162 :         while (o < chan->reg_classes) {
     221         400 :                 struct p2p_reg_class *op = &chan->reg_class[o];
     222             : 
     223         400 :                 c = 0;
     224        3964 :                 while (c < op->channels) {
     225        3164 :                         int freq = p2p_channel_to_freq(op->reg_class,
     226        3164 :                                                        op->channel[c]);
     227        3164 :                         if (freq > 0 && freq_range_list_includes(list, freq)) {
     228          13 :                                 op->channels--;
     229          13 :                                 os_memmove(&op->channel[c],
     230             :                                            &op->channel[c + 1],
     231             :                                            op->channels - c);
     232             :                         } else
     233        3151 :                                 c++;
     234             :                 }
     235             : 
     236         400 :                 if (op->channels == 0) {
     237           3 :                         chan->reg_classes--;
     238           3 :                         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         397 :                         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             :  */
     254       12112 : int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
     255             :                           u8 channel)
     256             : {
     257             :         size_t i, j;
     258       15911 :         for (i = 0; i < channels->reg_classes; i++) {
     259       14515 :                 const struct p2p_reg_class *reg = &channels->reg_class[i];
     260       14515 :                 if (reg->reg_class != reg_class)
     261        3774 :                         continue;
     262       21545 :                 for (j = 0; j < reg->channels; j++) {
     263       21520 :                         if (reg->channel[j] == channel)
     264       10716 :                                 return 1;
     265             :                 }
     266             :         }
     267        1396 :         return 0;
     268             : }
     269             : 
     270             : 
     271          92 : int p2p_channels_includes_freq(const struct p2p_channels *channels,
     272             :                                unsigned int freq)
     273             : {
     274             :         size_t i, j;
     275         124 :         for (i = 0; i < channels->reg_classes; i++) {
     276          98 :                 const struct p2p_reg_class *reg = &channels->reg_class[i];
     277         567 :                 for (j = 0; j < reg->channels; j++) {
     278        1070 :                         if (p2p_channel_to_freq(reg->reg_class,
     279        1070 :                                                 reg->channel[j]) == (int) freq)
     280          66 :                                 return 1;
     281             :                 }
     282             :         }
     283          26 :         return 0;
     284             : }
     285             : 
     286             : 
     287        1037 : int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
     288             : {
     289             :         u8 op_reg_class, op_channel;
     290        1037 :         if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
     291           0 :                 return 0;
     292        1037 :         return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
     293             :                                      op_channel);
     294             : }
     295             : 
     296             : 
     297        8544 : int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq)
     298             : {
     299             :         u8 op_reg_class, op_channel;
     300        8544 :         if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
     301           0 :                 return 0;
     302       17088 :         return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
     303       17082 :                                      op_channel) &&
     304        8538 :                 !freq_range_list_includes(&p2p->no_go_freq, freq);
     305             : }
     306             : 
     307             : 
     308          32 : int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq)
     309             : {
     310             :         u8 op_reg_class, op_channel;
     311          32 :         if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
     312           1 :                 return 0;
     313          62 :         return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
     314          32 :                                      op_channel) ||
     315           1 :                 p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class,
     316             :                                       op_channel);
     317             : }
     318             : 
     319             : 
     320          53 : unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
     321             :                                const struct p2p_channels *channels)
     322             : {
     323             :         unsigned int i;
     324          53 :         int freq = 0;
     325          53 :         const struct p2p_channels *tmpc = channels ?
     326          53 :                 channels : &p2p->cfg->channels;
     327             : 
     328          53 :         if (tmpc == NULL)
     329           0 :                 return 0;
     330             : 
     331          79 :         for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
     332          28 :                 freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class,
     333          28 :                                            p2p->cfg->pref_chan[i].chan);
     334          28 :                 if (p2p_channels_includes_freq(tmpc, freq))
     335           2 :                         return freq;
     336             :         }
     337          51 :         return 0;
     338             : }
     339             : 
     340             : 
     341       87017 : void 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       87017 :         pos = buf;
     349       87017 :         end = pos + sizeof(buf);
     350             : 
     351      170749 :         for (i = 0; i < chan->reg_classes; i++) {
     352             :                 const struct p2p_reg_class *c;
     353       83732 :                 c = &chan->reg_class[i];
     354       83732 :                 ret = os_snprintf(pos, end - pos, " %u:", c->reg_class);
     355       83732 :                 if (os_snprintf_error(end - pos, ret))
     356           0 :                         break;
     357       83732 :                 pos += ret;
     358             : 
     359      754949 :                 for (j = 0; j < c->channels; j++) {
     360      671217 :                         ret = os_snprintf(pos, end - pos, "%s%u",
     361             :                                           j == 0 ? "" : ",",
     362      671217 :                                           c->channel[j]);
     363      671217 :                         if (os_snprintf_error(end - pos, ret))
     364           0 :                                 break;
     365      671217 :                         pos += ret;
     366             :                 }
     367             :         }
     368       87017 :         *pos = '\0';
     369             : 
     370       87017 :         p2p_dbg(p2p, "%s:%s", title, buf);
     371       87017 : }
     372             : 
     373             : 
     374         496 : static u8 p2p_channel_pick_random(const u8 *channels, unsigned int num_channels)
     375             : {
     376             :         unsigned int r;
     377         496 :         if (os_get_random((u8 *) &r, sizeof(r)) < 0)
     378           0 :                 r = 0;
     379         496 :         r %= num_channels;
     380         496 :         return channels[r];
     381             : }
     382             : 
     383             : 
     384        1037 : int 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        3759 :         for (j = 0; classes == NULL || classes[j]; j++) {
     390        5561 :                 for (i = 0; i < chans->reg_classes; i++) {
     391        2839 :                         struct p2p_reg_class *c = &chans->reg_class[i];
     392             : 
     393        2839 :                         if (c->channels == 0)
     394           0 :                                 continue;
     395             : 
     396        2839 :                         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          15 :                                 *op_class = c->reg_class;
     402          30 :                                 *op_channel = p2p_channel_pick_random(
     403          30 :                                         c->channel, c->channels);
     404          15 :                                 return 0;
     405             :                         }
     406             :                 }
     407        2722 :                 if (classes == NULL)
     408           0 :                         break;
     409             :         }
     410             : 
     411        1022 :         return -1;
     412             : }
     413             : 
     414             : 
     415         483 : int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
     416             :                               u8 *op_channel)
     417             : {
     418             :         u8 chan[4];
     419         483 :         unsigned int num_channels = 0;
     420             : 
     421             :         /* Try to find available social channels from 2.4 GHz */
     422         483 :         if (p2p_channels_includes(chans, 81, 1))
     423         481 :                 chan[num_channels++] = 1;
     424         483 :         if (p2p_channels_includes(chans, 81, 6))
     425         481 :                 chan[num_channels++] = 6;
     426         483 :         if (p2p_channels_includes(chans, 81, 11))
     427         481 :                 chan[num_channels++] = 11;
     428             : 
     429             :         /* Try to find available social channels from 60 GHz */
     430         483 :         if (p2p_channels_includes(chans, 180, 2))
     431           0 :                 chan[num_channels++] = 2;
     432             : 
     433         483 :         if (num_channels == 0)
     434           2 :                 return -1;
     435             : 
     436         481 :         *op_channel = p2p_channel_pick_random(chan, num_channels);
     437         481 :         if (*op_channel == 2)
     438           0 :                 *op_class = 180;
     439             :         else
     440         481 :                 *op_class = 81;
     441             : 
     442         481 :         return 0;
     443             : }
     444             : 
     445             : 
     446        8260 : int 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        8260 :         if (!channels || max_len == 0)
     452          20 :                 return 0;
     453             : 
     454       16605 :         for (i = 0, idx = 0; i < channels->reg_classes; i++) {
     455        8365 :                 const struct p2p_reg_class *c = &channels->reg_class[i];
     456             :                 unsigned int j;
     457             : 
     458        8365 :                 if (idx + 1 == max_len)
     459           0 :                         break;
     460       98610 :                 for (j = 0; j < c->channels; j++) {
     461             :                         int freq;
     462             :                         unsigned int k;
     463             : 
     464       90245 :                         if (idx + 1 == max_len)
     465           0 :                                 break;
     466       90245 :                         freq = p2p_channel_to_freq(c->reg_class,
     467       90245 :                                                    c->channel[j]);
     468       90245 :                         if (freq < 0)
     469           0 :                                 continue;
     470             : 
     471      545379 :                         for (k = 0; k < idx; k++) {
     472      455430 :                                 if (freq_list[k] == freq)
     473         296 :                                         break;
     474             :                         }
     475             : 
     476       90245 :                         if (k < idx)
     477         296 :                                 continue;
     478       89949 :                         freq_list[idx++] = freq;
     479             :                 }
     480             :         }
     481             : 
     482        8240 :         freq_list[idx] = 0;
     483             : 
     484        8240 :         return idx;
     485             : }

Generated by: LCOV version 1.10