Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[linux-2.6] / net / wireless / util.c
1 /*
2  * Wireless utility functions
3  *
4  * Copyright 2007-2009  Johannes Berg <johannes@sipsolutions.net>
5  */
6 #include <linux/bitops.h>
7 #include <net/cfg80211.h>
8 #include "core.h"
9
10 struct ieee80211_rate *
11 ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
12                             u32 basic_rates, int bitrate)
13 {
14         struct ieee80211_rate *result = &sband->bitrates[0];
15         int i;
16
17         for (i = 0; i < sband->n_bitrates; i++) {
18                 if (!(basic_rates & BIT(i)))
19                         continue;
20                 if (sband->bitrates[i].bitrate > bitrate)
21                         continue;
22                 result = &sband->bitrates[i];
23         }
24
25         return result;
26 }
27 EXPORT_SYMBOL(ieee80211_get_response_rate);
28
29 int ieee80211_channel_to_frequency(int chan)
30 {
31         if (chan < 14)
32                 return 2407 + chan * 5;
33
34         if (chan == 14)
35                 return 2484;
36
37         /* FIXME: 802.11j 17.3.8.3.2 */
38         return (chan + 1000) * 5;
39 }
40 EXPORT_SYMBOL(ieee80211_channel_to_frequency);
41
42 int ieee80211_frequency_to_channel(int freq)
43 {
44         if (freq == 2484)
45                 return 14;
46
47         if (freq < 2484)
48                 return (freq - 2407) / 5;
49
50         /* FIXME: 802.11j 17.3.8.3.2 */
51         return freq/5 - 1000;
52 }
53 EXPORT_SYMBOL(ieee80211_frequency_to_channel);
54
55 struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
56                                                   int freq)
57 {
58         enum ieee80211_band band;
59         struct ieee80211_supported_band *sband;
60         int i;
61
62         for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
63                 sband = wiphy->bands[band];
64
65                 if (!sband)
66                         continue;
67
68                 for (i = 0; i < sband->n_channels; i++) {
69                         if (sband->channels[i].center_freq == freq)
70                                 return &sband->channels[i];
71                 }
72         }
73
74         return NULL;
75 }
76 EXPORT_SYMBOL(__ieee80211_get_channel);
77
78 static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
79                                      enum ieee80211_band band)
80 {
81         int i, want;
82
83         switch (band) {
84         case IEEE80211_BAND_5GHZ:
85                 want = 3;
86                 for (i = 0; i < sband->n_bitrates; i++) {
87                         if (sband->bitrates[i].bitrate == 60 ||
88                             sband->bitrates[i].bitrate == 120 ||
89                             sband->bitrates[i].bitrate == 240) {
90                                 sband->bitrates[i].flags |=
91                                         IEEE80211_RATE_MANDATORY_A;
92                                 want--;
93                         }
94                 }
95                 WARN_ON(want);
96                 break;
97         case IEEE80211_BAND_2GHZ:
98                 want = 7;
99                 for (i = 0; i < sband->n_bitrates; i++) {
100                         if (sband->bitrates[i].bitrate == 10) {
101                                 sband->bitrates[i].flags |=
102                                         IEEE80211_RATE_MANDATORY_B |
103                                         IEEE80211_RATE_MANDATORY_G;
104                                 want--;
105                         }
106
107                         if (sband->bitrates[i].bitrate == 20 ||
108                             sband->bitrates[i].bitrate == 55 ||
109                             sband->bitrates[i].bitrate == 110 ||
110                             sband->bitrates[i].bitrate == 60 ||
111                             sband->bitrates[i].bitrate == 120 ||
112                             sband->bitrates[i].bitrate == 240) {
113                                 sband->bitrates[i].flags |=
114                                         IEEE80211_RATE_MANDATORY_G;
115                                 want--;
116                         }
117
118                         if (sband->bitrates[i].bitrate != 10 &&
119                             sband->bitrates[i].bitrate != 20 &&
120                             sband->bitrates[i].bitrate != 55 &&
121                             sband->bitrates[i].bitrate != 110)
122                                 sband->bitrates[i].flags |=
123                                         IEEE80211_RATE_ERP_G;
124                 }
125                 WARN_ON(want != 0 && want != 3 && want != 6);
126                 break;
127         case IEEE80211_NUM_BANDS:
128                 WARN_ON(1);
129                 break;
130         }
131 }
132
133 void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
134 {
135         enum ieee80211_band band;
136
137         for (band = 0; band < IEEE80211_NUM_BANDS; band++)
138                 if (wiphy->bands[band])
139                         set_mandatory_flags_band(wiphy->bands[band], band);
140 }
141
142 int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
143                                    const u8 *mac_addr)
144 {
145         if (key_idx > 5)
146                 return -EINVAL;
147
148         /*
149          * Disallow pairwise keys with non-zero index unless it's WEP
150          * (because current deployments use pairwise WEP keys with
151          * non-zero indizes but 802.11i clearly specifies to use zero)
152          */
153         if (mac_addr && key_idx &&
154             params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
155             params->cipher != WLAN_CIPHER_SUITE_WEP104)
156                 return -EINVAL;
157
158         /* TODO: add definitions for the lengths to linux/ieee80211.h */
159         switch (params->cipher) {
160         case WLAN_CIPHER_SUITE_WEP40:
161                 if (params->key_len != 5)
162                         return -EINVAL;
163                 break;
164         case WLAN_CIPHER_SUITE_TKIP:
165                 if (params->key_len != 32)
166                         return -EINVAL;
167                 break;
168         case WLAN_CIPHER_SUITE_CCMP:
169                 if (params->key_len != 16)
170                         return -EINVAL;
171                 break;
172         case WLAN_CIPHER_SUITE_WEP104:
173                 if (params->key_len != 13)
174                         return -EINVAL;
175                 break;
176         case WLAN_CIPHER_SUITE_AES_CMAC:
177                 if (params->key_len != 16)
178                         return -EINVAL;
179                 break;
180         default:
181                 return -EINVAL;
182         }
183
184         return 0;
185 }