162306a36Sopenharmony_ci/* cfg80211 support 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * See copyright notice in main.c 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/ieee80211.h> 662306a36Sopenharmony_ci#include <net/cfg80211.h> 762306a36Sopenharmony_ci#include "hw.h" 862306a36Sopenharmony_ci#include "main.h" 962306a36Sopenharmony_ci#include "orinoco.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "cfg.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* Supported bitrates. Must agree with hw.c */ 1462306a36Sopenharmony_cistatic struct ieee80211_rate orinoco_rates[] = { 1562306a36Sopenharmony_ci { .bitrate = 10 }, 1662306a36Sopenharmony_ci { .bitrate = 20 }, 1762306a36Sopenharmony_ci { .bitrate = 55 }, 1862306a36Sopenharmony_ci { .bitrate = 110 }, 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* Called after orinoco_private is allocated. */ 2462306a36Sopenharmony_civoid orinoco_wiphy_init(struct wiphy *wiphy) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct orinoco_private *priv = wiphy_priv(wiphy); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci wiphy->privid = orinoco_wiphy_privid; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci set_wiphy_dev(wiphy, priv->dev); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* Called after firmware is initialised */ 3462306a36Sopenharmony_ciint orinoco_wiphy_register(struct wiphy *wiphy) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct orinoco_private *priv = wiphy_priv(wiphy); 3762306a36Sopenharmony_ci int i, channels = 0; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (priv->firmware_type == FIRMWARE_TYPE_AGERE) 4062306a36Sopenharmony_ci wiphy->max_scan_ssids = 1; 4162306a36Sopenharmony_ci else 4262306a36Sopenharmony_ci wiphy->max_scan_ssids = 0; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* TODO: should we set if we only have demo ad-hoc? 4762306a36Sopenharmony_ci * (priv->has_port3) 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci if (priv->has_ibss) 5062306a36Sopenharmony_ci wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (!priv->broken_monitor || force_monitor) 5362306a36Sopenharmony_ci wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci priv->band.bitrates = orinoco_rates; 5662306a36Sopenharmony_ci priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* Only support channels allowed by the card EEPROM */ 5962306a36Sopenharmony_ci for (i = 0; i < NUM_CHANNELS; i++) { 6062306a36Sopenharmony_ci if (priv->channel_mask & (1 << i)) { 6162306a36Sopenharmony_ci priv->channels[i].center_freq = 6262306a36Sopenharmony_ci ieee80211_channel_to_frequency(i + 1, 6362306a36Sopenharmony_ci NL80211_BAND_2GHZ); 6462306a36Sopenharmony_ci channels++; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci priv->band.channels = priv->channels; 6862306a36Sopenharmony_ci priv->band.n_channels = channels; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; 7162306a36Sopenharmony_ci wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci i = 0; 7462306a36Sopenharmony_ci if (priv->has_wep) { 7562306a36Sopenharmony_ci priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40; 7662306a36Sopenharmony_ci i++; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (priv->has_big_wep) { 7962306a36Sopenharmony_ci priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104; 8062306a36Sopenharmony_ci i++; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci if (priv->has_wpa) { 8462306a36Sopenharmony_ci priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP; 8562306a36Sopenharmony_ci i++; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci wiphy->cipher_suites = priv->cipher_suites; 8862306a36Sopenharmony_ci wiphy->n_cipher_suites = i; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci wiphy->rts_threshold = priv->rts_thresh; 9162306a36Sopenharmony_ci if (!priv->has_mwo) 9262306a36Sopenharmony_ci wiphy->frag_threshold = priv->frag_thresh + 1; 9362306a36Sopenharmony_ci wiphy->retry_short = priv->short_retry_limit; 9462306a36Sopenharmony_ci wiphy->retry_long = priv->long_retry_limit; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return wiphy_register(wiphy); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, 10062306a36Sopenharmony_ci enum nl80211_iftype type, 10162306a36Sopenharmony_ci struct vif_params *params) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct orinoco_private *priv = wiphy_priv(wiphy); 10462306a36Sopenharmony_ci int err = 0; 10562306a36Sopenharmony_ci unsigned long lock; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (orinoco_lock(priv, &lock) != 0) 10862306a36Sopenharmony_ci return -EBUSY; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci switch (type) { 11162306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 11262306a36Sopenharmony_ci if (!priv->has_ibss && !priv->has_port3) 11362306a36Sopenharmony_ci err = -EINVAL; 11462306a36Sopenharmony_ci break; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 12062306a36Sopenharmony_ci if (priv->broken_monitor && !force_monitor) { 12162306a36Sopenharmony_ci wiphy_warn(wiphy, 12262306a36Sopenharmony_ci "Monitor mode support is buggy in this firmware, not enabling\n"); 12362306a36Sopenharmony_ci err = -EINVAL; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci default: 12862306a36Sopenharmony_ci err = -EINVAL; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (!err) { 13262306a36Sopenharmony_ci priv->iw_mode = type; 13362306a36Sopenharmony_ci set_port_type(priv); 13462306a36Sopenharmony_ci err = orinoco_commit(priv); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci orinoco_unlock(priv, &lock); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return err; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int orinoco_scan(struct wiphy *wiphy, 14362306a36Sopenharmony_ci struct cfg80211_scan_request *request) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct orinoco_private *priv = wiphy_priv(wiphy); 14662306a36Sopenharmony_ci int err; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (!request) 14962306a36Sopenharmony_ci return -EINVAL; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (priv->scan_request && priv->scan_request != request) 15262306a36Sopenharmony_ci return -EBUSY; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci priv->scan_request = request; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci err = orinoco_hw_trigger_scan(priv, request->ssids); 15762306a36Sopenharmony_ci /* On error the we aren't processing the request */ 15862306a36Sopenharmony_ci if (err) 15962306a36Sopenharmony_ci priv->scan_request = NULL; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return err; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int orinoco_set_monitor_channel(struct wiphy *wiphy, 16562306a36Sopenharmony_ci struct cfg80211_chan_def *chandef) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct orinoco_private *priv = wiphy_priv(wiphy); 16862306a36Sopenharmony_ci int err = 0; 16962306a36Sopenharmony_ci unsigned long flags; 17062306a36Sopenharmony_ci int channel; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (!chandef->chan) 17362306a36Sopenharmony_ci return -EINVAL; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT) 17662306a36Sopenharmony_ci return -EINVAL; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (chandef->chan->band != NL80211_BAND_2GHZ) 17962306a36Sopenharmony_ci return -EINVAL; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci channel = ieee80211_frequency_to_channel(chandef->chan->center_freq); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if ((channel < 1) || (channel > NUM_CHANNELS) || 18462306a36Sopenharmony_ci !(priv->channel_mask & (1 << (channel - 1)))) 18562306a36Sopenharmony_ci return -EINVAL; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (orinoco_lock(priv, &flags) != 0) 18862306a36Sopenharmony_ci return -EBUSY; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci priv->channel = channel; 19162306a36Sopenharmony_ci if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { 19262306a36Sopenharmony_ci /* Fast channel change - no commit if successful */ 19362306a36Sopenharmony_ci struct hermes *hw = &priv->hw; 19462306a36Sopenharmony_ci err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | 19562306a36Sopenharmony_ci HERMES_TEST_SET_CHANNEL, 19662306a36Sopenharmony_ci channel, NULL); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci orinoco_unlock(priv, &flags); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return err; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct orinoco_private *priv = wiphy_priv(wiphy); 20662306a36Sopenharmony_ci int frag_value = -1; 20762306a36Sopenharmony_ci int rts_value = -1; 20862306a36Sopenharmony_ci int err = 0; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (changed & WIPHY_PARAM_RETRY_SHORT) { 21162306a36Sopenharmony_ci /* Setting short retry not supported */ 21262306a36Sopenharmony_ci err = -EINVAL; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (changed & WIPHY_PARAM_RETRY_LONG) { 21662306a36Sopenharmony_ci /* Setting long retry not supported */ 21762306a36Sopenharmony_ci err = -EINVAL; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { 22162306a36Sopenharmony_ci /* Set fragmentation */ 22262306a36Sopenharmony_ci if (priv->has_mwo) { 22362306a36Sopenharmony_ci if (wiphy->frag_threshold == -1) 22462306a36Sopenharmony_ci frag_value = 0; 22562306a36Sopenharmony_ci else { 22662306a36Sopenharmony_ci printk(KERN_WARNING "%s: Fixed fragmentation " 22762306a36Sopenharmony_ci "is not supported on this firmware. " 22862306a36Sopenharmony_ci "Using MWO robust instead.\n", 22962306a36Sopenharmony_ci priv->ndev->name); 23062306a36Sopenharmony_ci frag_value = 1; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci } else { 23362306a36Sopenharmony_ci if (wiphy->frag_threshold == -1) 23462306a36Sopenharmony_ci frag_value = 2346; 23562306a36Sopenharmony_ci else if ((wiphy->frag_threshold < 257) || 23662306a36Sopenharmony_ci (wiphy->frag_threshold > 2347)) 23762306a36Sopenharmony_ci err = -EINVAL; 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci /* cfg80211 value is 257-2347 (odd only) 24062306a36Sopenharmony_ci * orinoco rid has range 256-2346 (even only) */ 24162306a36Sopenharmony_ci frag_value = wiphy->frag_threshold & ~0x1; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (changed & WIPHY_PARAM_RTS_THRESHOLD) { 24662306a36Sopenharmony_ci /* Set RTS. 24762306a36Sopenharmony_ci * 24862306a36Sopenharmony_ci * Prism documentation suggests default of 2432, 24962306a36Sopenharmony_ci * and a range of 0-3000. 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci * Current implementation uses 2347 as the default and 25262306a36Sopenharmony_ci * the upper limit. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (wiphy->rts_threshold == -1) 25662306a36Sopenharmony_ci rts_value = 2347; 25762306a36Sopenharmony_ci else if (wiphy->rts_threshold > 2347) 25862306a36Sopenharmony_ci err = -EINVAL; 25962306a36Sopenharmony_ci else 26062306a36Sopenharmony_ci rts_value = wiphy->rts_threshold; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (!err) { 26462306a36Sopenharmony_ci unsigned long flags; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (orinoco_lock(priv, &flags) != 0) 26762306a36Sopenharmony_ci return -EBUSY; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (frag_value >= 0) { 27062306a36Sopenharmony_ci if (priv->has_mwo) 27162306a36Sopenharmony_ci priv->mwo_robust = frag_value; 27262306a36Sopenharmony_ci else 27362306a36Sopenharmony_ci priv->frag_thresh = frag_value; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci if (rts_value >= 0) 27662306a36Sopenharmony_ci priv->rts_thresh = rts_value; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci err = orinoco_commit(priv); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci orinoco_unlock(priv, &flags); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return err; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ciconst struct cfg80211_ops orinoco_cfg_ops = { 28762306a36Sopenharmony_ci .change_virtual_intf = orinoco_change_vif, 28862306a36Sopenharmony_ci .set_monitor_channel = orinoco_set_monitor_channel, 28962306a36Sopenharmony_ci .scan = orinoco_scan, 29062306a36Sopenharmony_ci .set_wiphy_params = orinoco_set_wiphy_params, 29162306a36Sopenharmony_ci}; 292