Ejemplo n.º 1
0
Archivo: hw.c Proyecto: 020gzh/linux
/* Set fixed AP address */
int __orinoco_hw_set_wap(struct orinoco_private *priv)
{
	int roaming_flag;
	int err = 0;
	struct hermes *hw = &priv->hw;

	switch (priv->firmware_type) {
	case FIRMWARE_TYPE_AGERE:
		/* not supported */
		break;
	case FIRMWARE_TYPE_INTERSIL:
		if (priv->bssid_fixed)
			roaming_flag = 2;
		else
			roaming_flag = 1;

		err = hermes_write_wordrec(hw, USER_BAP,
					   HERMES_RID_CNFROAMINGMODE,
					   roaming_flag);
		break;
	case FIRMWARE_TYPE_SYMBOL:
		err = HERMES_WRITE_RECORD(hw, USER_BAP,
					  HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
					  &priv->desired_bssid);
		break;
	}
	return err;
}
Ejemplo n.º 2
0
/* Change the WEP keys and/or the current keys.  Can be called
 * either from __orinoco_hw_setup_enc() or directly from
 * orinoco_ioctl_setiwencode().  In the later case the association
 * with the AP is not broken (if the firmware can handle it),
 * which is needed for 802.1x implementations. */
int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
{
	hermes_t *hw = &priv->hw;
	int err = 0;

	switch (priv->firmware_type) {
	case FIRMWARE_TYPE_AGERE:
		err = HERMES_WRITE_RECORD(hw, USER_BAP,
					  HERMES_RID_CNFWEPKEYS_AGERE,
					  &priv->keys);
		if (err)
			return err;
		err = hermes_write_wordrec(hw, USER_BAP,
					   HERMES_RID_CNFTXKEY_AGERE,
					   priv->tx_key);
		if (err)
			return err;
		break;
	case FIRMWARE_TYPE_INTERSIL:
	case FIRMWARE_TYPE_SYMBOL:
		{
			int keylen;
			int i;

			/* Force uniform key length to work around
			 * firmware bugs */
			keylen = le16_to_cpu(priv->keys[priv->tx_key].len);

			if (keylen > LARGE_KEY_SIZE) {
				printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
				       priv->ndev->name, priv->tx_key, keylen);
				return -E2BIG;
			}

			/* Write all 4 keys */
			for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
				err = hermes_write_ltv(hw, USER_BAP,
						HERMES_RID_CNFDEFAULTKEY0 + i,
						HERMES_BYTES_TO_RECLEN(keylen),
						priv->keys[i].data);
				if (err)
					return err;
			}

			/* Write the index of the key used in transmission */
			err = hermes_write_wordrec(hw, USER_BAP,
						HERMES_RID_CNFWEPDEFAULTKEYID,
						priv->tx_key);
			if (err)
				return err;
		}
		break;
	}

	return 0;
}
Ejemplo n.º 3
0
/* 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;
}
Ejemplo n.º 4
0
Archivo: hw.c Proyecto: 020gzh/linux
/* Disassociate from node with BSSID addr */
int orinoco_hw_disassociate(struct orinoco_private *priv,
			    u8 *addr, u16 reason_code)
{
	struct hermes *hw = &priv->hw;
	int err;

	struct {
		u8 addr[ETH_ALEN];
		__le16 reason_code;
	} __packed buf;

	/* Currently only supported by WPA enabled Agere fw */
	if (!priv->has_wpa)
		return -EOPNOTSUPP;

	memcpy(buf.addr, addr, ETH_ALEN);
	buf.reason_code = cpu_to_le16(reason_code);
	err = HERMES_WRITE_RECORD(hw, USER_BAP,
				  HERMES_RID_CNFDISASSOCIATE,
				  &buf);
	return err;
}
Ejemplo n.º 5
0
Archivo: hw.c Proyecto: 020gzh/linux
/* 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;
}
Ejemplo n.º 6
0
Archivo: hw.c Proyecto: 020gzh/linux
/* Change the WEP keys and/or the current keys.  Can be called
 * either from __orinoco_hw_setup_enc() or directly from
 * orinoco_ioctl_setiwencode().  In the later case the association
 * with the AP is not broken (if the firmware can handle it),
 * which is needed for 802.1x implementations. */
int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
{
	struct hermes *hw = &priv->hw;
	int err = 0;
	int i;

	switch (priv->firmware_type) {
	case FIRMWARE_TYPE_AGERE:
	{
		struct orinoco_key keys[ORINOCO_MAX_KEYS];

		memset(&keys, 0, sizeof(keys));
		for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
			int len = min(priv->keys[i].key_len,
				      ORINOCO_MAX_KEY_SIZE);
			memcpy(&keys[i].data, priv->keys[i].key, len);
			if (len > SMALL_KEY_SIZE)
				keys[i].len = cpu_to_le16(LARGE_KEY_SIZE);
			else if (len > 0)
				keys[i].len = cpu_to_le16(SMALL_KEY_SIZE);
			else
				keys[i].len = cpu_to_le16(0);
		}

		err = HERMES_WRITE_RECORD(hw, USER_BAP,
					  HERMES_RID_CNFWEPKEYS_AGERE,
					  &keys);
		if (err)
			return err;
		err = hermes_write_wordrec(hw, USER_BAP,
					   HERMES_RID_CNFTXKEY_AGERE,
					   priv->tx_key);
		if (err)
			return err;
		break;
	}
	case FIRMWARE_TYPE_INTERSIL:
	case FIRMWARE_TYPE_SYMBOL:
		{
			int keylen;

			/* Force uniform key length to work around
			 * firmware bugs */
			keylen = priv->keys[priv->tx_key].key_len;

			if (keylen > LARGE_KEY_SIZE) {
				printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
				       priv->ndev->name, priv->tx_key, keylen);
				return -E2BIG;
			} else if (keylen > SMALL_KEY_SIZE)
				keylen = LARGE_KEY_SIZE;
			else if (keylen > 0)
				keylen = SMALL_KEY_SIZE;
			else
				keylen = 0;

			/* Write all 4 keys */
			for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
				u8 key[LARGE_KEY_SIZE] = { 0 };

				memcpy(key, priv->keys[i].key,
				       priv->keys[i].key_len);

				err = hw->ops->write_ltv(hw, USER_BAP,
						HERMES_RID_CNFDEFAULTKEY0 + i,
						HERMES_BYTES_TO_RECLEN(keylen),
						key);
				if (err)
					return err;
			}

			/* Write the index of the key used in transmission */
			err = hermes_write_wordrec(hw, USER_BAP,
						HERMES_RID_CNFWEPDEFAULTKEYID,
						priv->tx_key);
			if (err)
				return err;
		}
		break;
	}

	return 0;
}
Ejemplo n.º 7
0
Archivo: hw.c Proyecto: 020gzh/linux
int orinoco_hw_trigger_scan(struct orinoco_private *priv,
			    const struct cfg80211_ssid *ssid)
{
	struct net_device *dev = priv->ndev;
	struct hermes *hw = &priv->hw;
	unsigned long flags;
	int err = 0;

	if (orinoco_lock(priv, &flags) != 0)
		return -EBUSY;

	/* Scanning with port 0 disabled would fail */
	if (!netif_running(dev)) {
		err = -ENETDOWN;
		goto out;
	}

	/* In monitor mode, the scan results are always empty.
	 * Probe responses are passed to the driver as received
	 * frames and could be processed in software. */
	if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
		err = -EOPNOTSUPP;
		goto out;
	}

	if (priv->has_hostscan) {
		switch (priv->firmware_type) {
		case FIRMWARE_TYPE_SYMBOL:
			err = hermes_write_wordrec(hw, USER_BAP,
						HERMES_RID_CNFHOSTSCAN_SYMBOL,
						HERMES_HOSTSCAN_SYMBOL_ONCE |
						HERMES_HOSTSCAN_SYMBOL_BCAST);
			break;
		case FIRMWARE_TYPE_INTERSIL: {
			__le16 req[3];

			req[0] = cpu_to_le16(0x3fff);	/* All channels */
			req[1] = cpu_to_le16(0x0001);	/* rate 1 Mbps */
			req[2] = 0;			/* Any ESSID */
			err = HERMES_WRITE_RECORD(hw, USER_BAP,
						  HERMES_RID_CNFHOSTSCAN, &req);
			break;
		}
		case FIRMWARE_TYPE_AGERE:
			if (ssid->ssid_len > 0) {
				struct hermes_idstring idbuf;
				size_t len = ssid->ssid_len;

				idbuf.len = cpu_to_le16(len);
				memcpy(idbuf.val, ssid->ssid, len);

				err = hw->ops->write_ltv(hw, USER_BAP,
					       HERMES_RID_CNFSCANSSID_AGERE,
					       HERMES_BYTES_TO_RECLEN(len + 2),
					       &idbuf);
			} else
				err = hermes_write_wordrec(hw, USER_BAP,
						   HERMES_RID_CNFSCANSSID_AGERE,
						   0);	/* Any ESSID */
			if (err)
				break;

			if (priv->has_ext_scan) {
				err = hermes_write_wordrec(hw, USER_BAP,
						HERMES_RID_CNFSCANCHANNELS2GHZ,
						0x7FFF);
				if (err)
					goto out;

				err = hermes_inquire(hw,
						     HERMES_INQ_CHANNELINFO);
			} else
				err = hermes_inquire(hw, HERMES_INQ_SCAN);

			break;
		}
	} else
		err = hermes_inquire(hw, HERMES_INQ_SCAN);

 out:
	orinoco_unlock(priv, &flags);

	return err;
}