/* key must be 32 bytes, including the tx and rx MIC keys. * rsc must be 8 bytes * tsc must be 8 bytes or NULL */ int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, u8 *key, u8 *rsc, u8 *tsc) { struct { __le16 idx; u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; u8 key[TKIP_KEYLEN]; u8 tx_mic[MIC_KEYLEN]; u8 rx_mic[MIC_KEYLEN]; u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; } __attribute__ ((packed)) buf; int ret; int err; int k; u16 xmitting; key_idx &= 0x3; if (set_tx) key_idx |= 0x8000; buf.idx = cpu_to_le16(key_idx); memcpy(buf.key, key, sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); if (rsc == NULL) memset(buf.rsc, 0, sizeof(buf.rsc)); else memcpy(buf.rsc, rsc, sizeof(buf.rsc)); if (tsc == NULL) { memset(buf.tsc, 0, sizeof(buf.tsc)); buf.tsc[4] = 0x10; } else { memcpy(buf.tsc, tsc, sizeof(buf.tsc)); } /* Wait upto 100ms for tx queue to empty */ for (k = 100; k > 0; k--) { udelay(1000); ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, &xmitting); if (ret || !xmitting) break; } if (k == 0) ret = -ETIMEDOUT; err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, &buf); return ret ? ret : err; }
static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_request_info *info, struct iw_param *frq, char *extra) { struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int err; u16 val; unsigned long flags; if (orinoco_lock(priv, &flags) != 0) return -EBUSY; if (priv->has_mwo) { err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMWOROBUST_AGERE, &val); if (err) val = 0; frq->value = val ? 2347 : 0; frq->disabled = !val; frq->fixed = 0; } else { err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, &val); if (err) val = 0; frq->value = val; frq->disabled = (val >= 2346); frq->fixed = 1; } orinoco_unlock(priv, &flags); return err; }
int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate) { struct hermes *hw = &priv->hw; int i; int err = 0; u16 val; err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTTXRATE, &val); if (err) return err; switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ /* Note : in Lucent firmware, the return value of * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, * and therefore is totally different from the * encoding of HERMES_RID_CNFTXRATECONTROL. * Don't forget that 6Mb/s is really 5.5Mb/s */ if (val == 6) *bitrate = 5500000; else *bitrate = val * 1000000; break; case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ for (i = 0; i < BITRATE_TABLE_SIZE; i++) if (bitrate_table[i].intersil_txratectrl == val) { *bitrate = bitrate_table[i].bitrate * 100000; break; } if (i >= BITRATE_TABLE_SIZE) { printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", priv->ndev->name, val); err = -EIO; } break; default: BUG(); } return err; }
int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate) { struct hermes *hw = &priv->hw; int i; int err = 0; u16 val; err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTTXRATE, &val); if (err) return err; switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: /* */ /* */ if (val == 6) *bitrate = 5500000; else *bitrate = val * 1000000; break; case FIRMWARE_TYPE_INTERSIL: /* */ case FIRMWARE_TYPE_SYMBOL: /* */ for (i = 0; i < BITRATE_TABLE_SIZE; i++) if (bitrate_table[i].intersil_txratectrl == val) { *bitrate = bitrate_table[i].bitrate * 100000; break; } if (i >= BITRATE_TABLE_SIZE) { printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", priv->ndev->name, val); err = -EIO; } break; default: BUG(); } return err; }
int orinoco_hw_get_freq(struct orinoco_private *priv) { struct hermes *hw = &priv->hw; int err = 0; u16 channel; int freq = 0; unsigned long flags; if (orinoco_lock(priv, &flags) != 0) return -EBUSY; err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); if (err) goto out; /* Intersil firmware 1.3.5 returns 0 when the interface is down */ if (channel == 0) { err = -EBUSY; goto out; } if ((channel < 1) || (channel > NUM_CHANNELS)) { printk(KERN_WARNING "%s: Channel out of range (%d)!\n", priv->ndev->name, channel); err = -EBUSY; goto out; } freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); out: orinoco_unlock(priv, &flags); if (err > 0) err = -EBUSY; return err ? err : freq; }
/* key must be 32 bytes, including the tx and rx MIC keys. * rsc must be NULL or up to 8 bytes * tsc must be NULL or up to 8 bytes */ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, int set_tx, const u8 *key, const u8 *rsc, size_t rsc_len, const u8 *tsc, size_t tsc_len) { struct { __le16 idx; u8 rsc[ORINOCO_SEQ_LEN]; u8 key[TKIP_KEYLEN]; u8 tx_mic[MIC_KEYLEN]; u8 rx_mic[MIC_KEYLEN]; u8 tsc[ORINOCO_SEQ_LEN]; } __packed buf; struct hermes *hw = &priv->hw; int ret; int err; int k; u16 xmitting; key_idx &= 0x3; if (set_tx) key_idx |= 0x8000; buf.idx = cpu_to_le16(key_idx); memcpy(buf.key, key, sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); if (rsc_len > sizeof(buf.rsc)) rsc_len = sizeof(buf.rsc); if (tsc_len > sizeof(buf.tsc)) tsc_len = sizeof(buf.tsc); memset(buf.rsc, 0, sizeof(buf.rsc)); memset(buf.tsc, 0, sizeof(buf.tsc)); if (rsc != NULL) memcpy(buf.rsc, rsc, rsc_len); if (tsc != NULL) memcpy(buf.tsc, tsc, tsc_len); else buf.tsc[4] = 0x10; /* Wait up to 100ms for tx queue to empty */ for (k = 100; k > 0; k--) { udelay(1000); ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, &xmitting); if (ret || !xmitting) break; } if (k == 0) ret = -ETIMEDOUT; err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, &buf); return ret ? ret : err; }
/* Read settings from EEPROM into our private structure. * MAC address gets dropped into callers buffer * Can be called before netdev registration. */ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) { struct device *dev = priv->dev; struct hermes_idstring nickbuf; struct hermes *hw = &priv->hw; int len; int err; u16 reclen; /* Get the MAC address */ err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, ETH_ALEN, NULL, dev_addr); if (err) { dev_warn(dev, "Failed to read MAC address!\n"); goto out; } dev_dbg(dev, "MAC address %pM\n", dev_addr); /* Get the station name */ err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, sizeof(nickbuf), &reclen, &nickbuf); if (err) { dev_err(dev, "failed to read station name\n"); goto out; } if (nickbuf.len) len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); else len = min(IW_ESSID_MAX_SIZE, 2 * reclen); memcpy(priv->nick, &nickbuf.val, len); priv->nick[len] = '\0'; dev_dbg(dev, "Station name \"%s\"\n", priv->nick); /* Get allowed channels */ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, &priv->channel_mask); if (err) { dev_err(dev, "Failed to read channel list!\n"); goto out; } /* Get initial AP density */ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, &priv->ap_density); if (err || priv->ap_density < 1 || priv->ap_density > 3) priv->has_sensitivity = 0; /* Get initial RTS threshold */ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, &priv->rts_thresh); if (err) { dev_err(dev, "Failed to read RTS threshold!\n"); goto out; } /* Get initial fragmentation settings */ if (priv->has_mwo) err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMWOROBUST_AGERE, &priv->mwo_robust); else err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, &priv->frag_thresh); if (err) { dev_err(dev, "Failed to read fragmentation settings!\n"); goto out; } /* Power management setup */ if (priv->has_pm) { priv->pm_on = 0; priv->pm_mcast = 1; err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMAXSLEEPDURATION, &priv->pm_period); if (err) { dev_err(dev, "Failed to read power management " "period!\n"); goto out; } err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &priv->pm_timeout); if (err) { dev_err(dev, "Failed to read power management " "timeout!\n"); goto out; } } /* Preamble setup */ if (priv->has_preamble) { err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPREAMBLE_SYMBOL, &priv->preamble); if (err) { dev_err(dev, "Failed to read preamble setup\n"); goto out; } } /* Retry settings */ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, &priv->short_retry_limit); if (err) { dev_err(dev, "Failed to read short retry limit\n"); goto out; } err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, &priv->long_retry_limit); if (err) { dev_err(dev, "Failed to read long retry limit\n"); goto out; } err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, &priv->retry_lifetime); if (err) { dev_err(dev, "Failed to read max retry lifetime\n"); goto out; } out: return err; }