Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.13 290 lines 6.6 kB view raw
1/* cfg80211 support 2 * 3 * See copyright notice in main.c 4 */ 5#include <linux/ieee80211.h> 6#include <net/cfg80211.h> 7#include "hw.h" 8#include "main.h" 9#include "orinoco.h" 10 11#include "cfg.h" 12 13/* Supported bitrates. Must agree with hw.c */ 14static struct ieee80211_rate orinoco_rates[] = { 15 { .bitrate = 10 }, 16 { .bitrate = 20 }, 17 { .bitrate = 55 }, 18 { .bitrate = 110 }, 19}; 20 21static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid; 22 23/* Called after orinoco_private is allocated. */ 24void orinoco_wiphy_init(struct wiphy *wiphy) 25{ 26 struct orinoco_private *priv = wiphy_priv(wiphy); 27 28 wiphy->privid = orinoco_wiphy_privid; 29 30 set_wiphy_dev(wiphy, priv->dev); 31} 32 33/* Called after firmware is initialised */ 34int orinoco_wiphy_register(struct wiphy *wiphy) 35{ 36 struct orinoco_private *priv = wiphy_priv(wiphy); 37 int i, channels = 0; 38 39 if (priv->firmware_type == FIRMWARE_TYPE_AGERE) 40 wiphy->max_scan_ssids = 1; 41 else 42 wiphy->max_scan_ssids = 0; 43 44 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 45 46 /* TODO: should we set if we only have demo ad-hoc? 47 * (priv->has_port3) 48 */ 49 if (priv->has_ibss) 50 wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); 51 52 if (!priv->broken_monitor || force_monitor) 53 wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); 54 55 priv->band.bitrates = orinoco_rates; 56 priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates); 57 58 /* Only support channels allowed by the card EEPROM */ 59 for (i = 0; i < NUM_CHANNELS; i++) { 60 if (priv->channel_mask & (1 << i)) { 61 priv->channels[i].center_freq = 62 ieee80211_dsss_chan_to_freq(i + 1); 63 channels++; 64 } 65 } 66 priv->band.channels = priv->channels; 67 priv->band.n_channels = channels; 68 69 wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; 70 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; 71 72 i = 0; 73 if (priv->has_wep) { 74 priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40; 75 i++; 76 77 if (priv->has_big_wep) { 78 priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104; 79 i++; 80 } 81 } 82 if (priv->has_wpa) { 83 priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP; 84 i++; 85 } 86 wiphy->cipher_suites = priv->cipher_suites; 87 wiphy->n_cipher_suites = i; 88 89 wiphy->rts_threshold = priv->rts_thresh; 90 if (!priv->has_mwo) 91 wiphy->frag_threshold = priv->frag_thresh + 1; 92 wiphy->retry_short = priv->short_retry_limit; 93 wiphy->retry_long = priv->long_retry_limit; 94 95 return wiphy_register(wiphy); 96} 97 98static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, 99 enum nl80211_iftype type, u32 *flags, 100 struct vif_params *params) 101{ 102 struct orinoco_private *priv = wiphy_priv(wiphy); 103 int err = 0; 104 unsigned long lock; 105 106 if (orinoco_lock(priv, &lock) != 0) 107 return -EBUSY; 108 109 switch (type) { 110 case NL80211_IFTYPE_ADHOC: 111 if (!priv->has_ibss && !priv->has_port3) 112 err = -EINVAL; 113 break; 114 115 case NL80211_IFTYPE_STATION: 116 break; 117 118 case NL80211_IFTYPE_MONITOR: 119 if (priv->broken_monitor && !force_monitor) { 120 wiphy_warn(wiphy, 121 "Monitor mode support is buggy in this firmware, not enabling\n"); 122 err = -EINVAL; 123 } 124 break; 125 126 default: 127 err = -EINVAL; 128 } 129 130 if (!err) { 131 priv->iw_mode = type; 132 set_port_type(priv); 133 err = orinoco_commit(priv); 134 } 135 136 orinoco_unlock(priv, &lock); 137 138 return err; 139} 140 141static int orinoco_scan(struct wiphy *wiphy, 142 struct cfg80211_scan_request *request) 143{ 144 struct orinoco_private *priv = wiphy_priv(wiphy); 145 int err; 146 147 if (!request) 148 return -EINVAL; 149 150 if (priv->scan_request && priv->scan_request != request) 151 return -EBUSY; 152 153 priv->scan_request = request; 154 155 err = orinoco_hw_trigger_scan(priv, request->ssids); 156 /* On error the we aren't processing the request */ 157 if (err) 158 priv->scan_request = NULL; 159 160 return err; 161} 162 163static int orinoco_set_monitor_channel(struct wiphy *wiphy, 164 struct cfg80211_chan_def *chandef) 165{ 166 struct orinoco_private *priv = wiphy_priv(wiphy); 167 int err = 0; 168 unsigned long flags; 169 int channel; 170 171 if (!chandef->chan) 172 return -EINVAL; 173 174 if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT) 175 return -EINVAL; 176 177 if (chandef->chan->band != IEEE80211_BAND_2GHZ) 178 return -EINVAL; 179 180 channel = ieee80211_freq_to_dsss_chan(chandef->chan->center_freq); 181 182 if ((channel < 1) || (channel > NUM_CHANNELS) || 183 !(priv->channel_mask & (1 << (channel - 1)))) 184 return -EINVAL; 185 186 if (orinoco_lock(priv, &flags) != 0) 187 return -EBUSY; 188 189 priv->channel = channel; 190 if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { 191 /* Fast channel change - no commit if successful */ 192 struct hermes *hw = &priv->hw; 193 err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | 194 HERMES_TEST_SET_CHANNEL, 195 channel, NULL); 196 } 197 orinoco_unlock(priv, &flags); 198 199 return err; 200} 201 202static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed) 203{ 204 struct orinoco_private *priv = wiphy_priv(wiphy); 205 int frag_value = -1; 206 int rts_value = -1; 207 int err = 0; 208 209 if (changed & WIPHY_PARAM_RETRY_SHORT) { 210 /* Setting short retry not supported */ 211 err = -EINVAL; 212 } 213 214 if (changed & WIPHY_PARAM_RETRY_LONG) { 215 /* Setting long retry not supported */ 216 err = -EINVAL; 217 } 218 219 if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { 220 /* Set fragmentation */ 221 if (priv->has_mwo) { 222 if (wiphy->frag_threshold < 0) 223 frag_value = 0; 224 else { 225 printk(KERN_WARNING "%s: Fixed fragmentation " 226 "is not supported on this firmware. " 227 "Using MWO robust instead.\n", 228 priv->ndev->name); 229 frag_value = 1; 230 } 231 } else { 232 if (wiphy->frag_threshold < 0) 233 frag_value = 2346; 234 else if ((wiphy->frag_threshold < 257) || 235 (wiphy->frag_threshold > 2347)) 236 err = -EINVAL; 237 else 238 /* cfg80211 value is 257-2347 (odd only) 239 * orinoco rid has range 256-2346 (even only) */ 240 frag_value = wiphy->frag_threshold & ~0x1; 241 } 242 } 243 244 if (changed & WIPHY_PARAM_RTS_THRESHOLD) { 245 /* Set RTS. 246 * 247 * Prism documentation suggests default of 2432, 248 * and a range of 0-3000. 249 * 250 * Current implementation uses 2347 as the default and 251 * the upper limit. 252 */ 253 254 if (wiphy->rts_threshold < 0) 255 rts_value = 2347; 256 else if (wiphy->rts_threshold > 2347) 257 err = -EINVAL; 258 else 259 rts_value = wiphy->rts_threshold; 260 } 261 262 if (!err) { 263 unsigned long flags; 264 265 if (orinoco_lock(priv, &flags) != 0) 266 return -EBUSY; 267 268 if (frag_value >= 0) { 269 if (priv->has_mwo) 270 priv->mwo_robust = frag_value; 271 else 272 priv->frag_thresh = frag_value; 273 } 274 if (rts_value >= 0) 275 priv->rts_thresh = rts_value; 276 277 err = orinoco_commit(priv); 278 279 orinoco_unlock(priv, &flags); 280 } 281 282 return err; 283} 284 285const struct cfg80211_ops orinoco_cfg_ops = { 286 .change_virtual_intf = orinoco_change_vif, 287 .set_monitor_channel = orinoco_set_monitor_channel, 288 .scan = orinoco_scan, 289 .set_wiphy_params = orinoco_set_wiphy_params, 290};