Subject: Support of USB/WiFi D-Link DWL-G122 802.11g on NetBSD
To: None <tech-kern@netbsd.org>
From: Ian Zagorskih <ianzag@megasignal.com>
List: tech-kern
Date: 04/27/2005 18:54:09
--Boundary-00=_h13bC3MzttkCcJc
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
$ uname -a
NetBSD IANZAG 3.99.3 NetBSD 3.99.3 (DWL-G122) #38: Wed Apr 27 16:48:49 NOVST
2005 ianzag@IANZAG:/home/ianzag/NetBSD/kernel/DWL-G122 i386
Some time ago i got two D-Link DWL-G122 USB-WiFi adapters as described at:
http://www.dlink.com/products/?pid=334
Unfortunately, NetBSD-current does not have suport for this cards yet, but
looks like OpenBSD-current has. So i desided to port OpenBSD's code on
NetBSD. After some work looks like ported driver works quite fine [except
problems described below].
Changes relatively to NetBSD-current:
1. dev/usb/if_ral* - new files from OpenBSD with NetBSD specific changes. All
changes are wrapped with __OpenBSD__ /__NetBSD__ defines.
2. dev/usb/files.usb - added new device ural.
3. usbdevs - added new USB device codes.
4. net80211 - added ieee80211_beacon_alloc() from OpenBSD.
5. ral.4 - man page for *ral cards. I guess it should be fixed to include only
USB version. Well, or port PCI/CardBus cards code too :)
For testing i have two machines, A and B, with identical DSL-G122 cards. On
both machines USB 1.1 was used.
dmesg when card is inserted:
---cut---
ural0 at uhub4 port 5
ural0: ANI 802.11g W, rev 2.00/0.01, addr 6
ural0: MAC/BBP RT2570 (rev 0x03), RF RT2526, address 00:11:95:87:5d:88
ural0: 11b rates: 1Mbps 2Mbps 5.5Mbps 11Mbps
ural0: 11g rates: 1Mbps 2Mbps 5.5Mbps 11Mbps 6Mbps 9Mbps 12Mbps 18Mbps 24Mbps
36Mbps 48Mbps 54Mbps
---cut---
Configure machine A as Host AP with IP 10.0.0.1
# ifconfig ural0 ssid foo mediaopt hostap
# ifconfig ural0 inet 10.0.0.1
# ifconfig ural0
ural0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ssid foo
powersave off
bssid 00:11:95:87:5d:88 chan 1
address: 00:11:95:87:5d:88
media: IEEE802.11 autoselect hostap (autoselect mode 11b hostap)
status: active
inet 10.0.0.1 netmask 0xff000000 broadcast 10.255.255.255
Configure machine B as BSS with IP 10.0.0.2
# ifconfig ural0 ssid foo
# ifconfig ural0 inet 10.0.0.2
# ifconfig ural0
ural0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ssid foo
powersave off
bssid 00:11:95:87:5d:88 chan 1
address: 00:11:95:89:99:27
media: IEEE802.11 autoselect (DS11)
status: active
inet 10.0.0.2 netmask 0xff000000 broadcast 10.255.255.255
Check for online nodes around from machine A:
# wiconfig ural0 -D
scanning ...
AP Information
ap[0]:
netname (SSID): [ foo ]
BSSID: [ 00:11:95:89:99:27 ]
Channel: [ 1 ]
Quality/Signal/Noise [signal]: [ 0 / 20 / 0 ]
[dBm]: [ 0 / -129 / -149 ]
BSS Beacon Interval [msec]: [ 100 ]
Capinfo: [ ESS ]
DataRate [Mbps]: [ 2 ]
So looks like both A and B find eachother just fine. Great :)
The problem is that when i ping another machine, for example, B from A, i get
the following in my dmesg:
# ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1): 56 data bytes
^C
----10.0.0.1 PING Statistics----
8 packets transmitted, 0 packets received, 100.0% packet loss
arpresolve: can't allocate llinfo on ural0 for 10.0.0.1
arpresolve: can't allocate llinfo on ural0 for 10.0.0.1
arpresolve: can't allocate llinfo on ural0 for 10.0.0.1
arpresolve: can't allocate llinfo on ural0 for 10.0.0.1
arpresolve: can't allocate llinfo on ural0 for 10.0.0.1
arpresolve: can't allocate llinfo on ural0 for 10.0.0.1
arpresolve: can't allocate llinfo on ural0 for 10.0.0.1
arpresolve: can't allocate llinfo on ural0 for 10.0.0.1
Looks like ARP level + new driver are broken at some point.
Would be great if anybody with experience in NetBSD inet stack and WiFi would
review my patches and gave me some hints/comments/etc. I'm trying to discover
why ARP is broken but my current knowledge isn't enough for this.
But anyway, looks like OpenBSD D-Link & K driver almost works on NetBSD :)
// wbr
--Boundary-00=_h13bC3MzttkCcJc
Content-Type: text/x-chdr;
charset="us-ascii";
name="if_ralvar.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="if_ralvar.h"
/* $NetBSD$ */
/* $OpenBSD: if_ralvar.h,v 1.1 2005/03/16 20:17:10 damien Exp $ */
/*-
* Copyright (c) 2005
* Damien Bergamini <damien.bergamini@free.fr>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define RAL_RX_LIST_COUNT 1
#define RAL_TX_LIST_COUNT 1
struct ural_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
uint8_t wr_flags;
uint16_t wr_chan_freq;
uint16_t wr_chan_flags;
uint8_t wr_antenna;
uint8_t wr_antsignal;
} __packed;
#define RAL_RX_RADIOTAP_PRESENT \
((1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_CHANNEL) | \
(1 << IEEE80211_RADIOTAP_ANTENNA) | \
(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL))
struct ural_tx_radiotap_header {
struct ieee80211_radiotap_header wt_ihdr;
uint8_t wt_flags;
uint8_t wt_rate;
uint16_t wt_chan_freq;
uint16_t wt_chan_flags;
uint8_t wt_antenna;
} __packed;
#define RAL_TX_RADIOTAP_PRESENT \
((1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
(1 << IEEE80211_RADIOTAP_CHANNEL) | \
(1 << IEEE80211_RADIOTAP_ANTENNA))
struct ural_softc;
struct ural_tx_data {
struct ural_softc *sc;
usbd_xfer_handle xfer;
uint8_t *buf;
struct mbuf *m;
struct ieee80211_node *ni;
};
struct ural_rx_data {
struct ural_softc *sc;
usbd_xfer_handle xfer;
uint8_t *buf;
struct mbuf *m;
};
struct ural_softc {
USBBASEDEVICE sc_dev;
struct ieee80211com sc_ic;
int (*sc_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
usbd_device_handle sc_udev;
usbd_interface_handle sc_iface;
uint8_t sc_rx_no;
uint8_t sc_tx_no;
uint32_t asic_rev;
uint8_t rf_rev;
usbd_pipe_handle sc_rx_pipeh;
usbd_pipe_handle sc_tx_pipeh;
enum ieee80211_state sc_state;
struct usb_task sc_task;
struct ural_rx_data rx_data[RAL_RX_LIST_COUNT];
struct ural_tx_data tx_data[RAL_TX_LIST_COUNT];
int tx_queued;
#ifdef __OpenBSD__
struct timeout scan_ch;
#else
struct callout scan_ch;
#endif
int sc_tx_timer;
uint32_t rf_regs[4];
uint8_t txpow[14];
struct {
uint8_t val;
uint8_t reg;
} __packed bbp_prom[16];
int led_mode;
int hw_radio;
int rx_ant;
int tx_ant;
int nb_ant;
#if NBPFILTER > 0
caddr_t sc_drvbpf;
union {
struct ural_rx_radiotap_header th;
uint8_t pad[64];
} sc_rxtapu;
#define sc_rxtap sc_rxtapu.th
int sc_rxtap_len;
union {
struct ural_tx_radiotap_header th;
uint8_t pad[64];
} sc_txtapu;
#define sc_txtap sc_txtapu.th
int sc_txtap_len;
#endif
};
--Boundary-00=_h13bC3MzttkCcJc
Content-Type: text/x-chdr;
charset="us-ascii";
name="if_ralreg.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="if_ralreg.h"
/* $NetBSD$ */
/* $OpenBSD: if_ralreg.h,v 1.5 2005/04/01 13:13:43 damien Exp $ */
/*-
* Copyright (c) 2005
* Damien Bergamini <damien.bergamini@free.fr>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define RAL_RX_DESC_SIZE (sizeof (struct ural_rx_desc))
#define RAL_TX_DESC_SIZE (sizeof (struct ural_tx_desc))
#define RAL_CONFIG_NO 1
#define RAL_IFACE_INDEX 0
#define RAL_WRITE_MAC 0x02
#define RAL_READ_MAC 0x03
#define RAL_WRITE_MULTI_MAC 0x06
#define RAL_READ_MULTI_MAC 0x07
#define RAL_READ_EEPROM 0x09
/*
* MAC registers.
*/
#define RAL_MAC_CSR0 0x0400 /* ASIC Version */
#define RAL_MAC_CSR1 0x0402 /* System control */
#define RAL_MAC_CSR2 0x0404 /* MAC addr0 */
#define RAL_MAC_CSR3 0x0406 /* MAC addr1 */
#define RAL_MAC_CSR4 0x0408 /* MAC addr2 */
#define RAL_MAC_CSR5 0x040a /* BSSID0 */
#define RAL_MAC_CSR6 0x040c /* BSSID1 */
#define RAL_MAC_CSR7 0x040e /* BSSID2 */
#define RAL_MAC_CSR8 0x0410 /* Max frame length */
#define RAL_MAC_CSR9 0x0412 /* Timer control */
#define RAL_MAC_CSR11 0x0416 /* IFS */
#define RAL_MAC_CSR12 0x0418 /* EIFS */
#define RAL_MAC_CSR13 0x041a /* Power mode0 */
#define RAL_MAC_CSR14 0x041c /* Power mode1 */
#define RAL_MAC_CSR15 0x041e /* Power saving transition0 */
#define RAL_MAC_CSR16 0x0420 /* Power saving transition1 */
#define RAL_MAC_CSR17 0x0422 /* Power state control */
#define RAL_MAC_CSR18 0x0424 /* Auto wake-up control */
#define RAL_MAC_CSR19 0x0426 /* GPIO control */
#define RAL_MAC_CSR20 0x0428 /* LED control0 */
#define RAL_MAC_CSR22 0x042c /* XXX not documented */
/*
* Tx/Rx Registers.
*/
#define RAL_TXRX_CSR0 0x0440 /* Security control */
#define RAL_TXRX_CSR2 0x0444 /* Rx control */
#define RAL_TXRX_CSR5 0x044a /* CCK Tx BBP ID0 */
#define RAL_TXRX_CSR6 0x044c /* CCK Tx BBP ID1 */
#define RAL_TXRX_CSR7 0x044e /* OFDM Tx BBP ID0 */
#define RAL_TXRX_CSR8 0x0450 /* OFDM Tx BBP ID1 */
#define RAL_TXRX_CSR11 0x0456 /* Auto responder basic rate */
#define RAL_TXRX_CSR18 0x0464 /* Beacon interval */
#define RAL_TXRX_CSR19 0x0466 /* Beacon/sync control */
#define RAL_TXRX_CSR20 0x0468 /* Beacon alignment */
#define RAL_TXRX_CSR21 0x046a /* XXX not documented */
/*
* Security registers.
*/
#define RAL_SEC_CSR0 0x0480 /* Shared key 0, word 0 */
/*
* PHY registers.
*/
#define RAL_PHY_CSR2 0x04c4 /* Tx MAC configuration */
#define RAL_PHY_CSR4 0x04c8 /* Interface configuration */
#define RAL_PHY_CSR5 0x04ca /* BBP Pre-Tx CCK */
#define RAL_PHY_CSR6 0x04cc /* BBP Pre-Tx OFDM */
#define RAL_PHY_CSR7 0x04ce /* BBP serial control */
#define RAL_PHY_CSR8 0x04d0 /* BBP serial status */
#define RAL_PHY_CSR9 0x04d2 /* RF serial control0 */
#define RAL_PHY_CSR10 0x04d4 /* RF serial control1 */
/*
* Statistics registers.
*/
#define RAL_STA_CSR0 0x04e0 /* FCS error */
#define RAL_DISABLE_RX (1 << 0)
#define RAL_DROP_CRC_ERROR (1 << 1)
#define RAL_DROP_PHY_ERROR (1 << 2)
#define RAL_DROP_CTL (1 << 3)
#define RAL_DROP_NOT_TO_ME (1 << 4)
#define RAL_DROP_TODS (1 << 5)
#define RAL_DROP_VERSION_ERROR (1 << 6)
#define RAL_DROP_MULTICAST (1 << 9)
#define RAL_DROP_BROADCAST (1 << 10)
#define RAL_HOST_READY (1 << 2)
#define RAL_RESET_ASIC (1 << 0)
#define RAL_RESET_BBP (1 << 1)
#define RAL_ENABLE_TSF (1 << 0)
#define RAL_ENABLE_TSF_SYNC(x) (((x) & 0x3) << 1)
#define RAL_ENABLE_TBCN (1 << 3)
#define RAL_ENABLE_BEACON_GENERATOR (1 << 4)
#define RAL_RF_AWAKE (3 << 7)
#define RAL_BBP_AWAKE (3 << 5)
#define RAL_BBP_WRITE (1 << 15)
#define RAL_BBP_BUSY (1 << 0)
#define RAL_RF1_AUTOTUNE 0x08000
#define RAL_RF3_AUTOTUNE 0x00040
#define RAL_RF_2522 0x00
#define RAL_RF_2523 0x01
#define RAL_RF_2524 0x02
#define RAL_RF_2525 0x03
#define RAL_RF_2525E 0x04
#define RAL_RF_2526 0x05
/* dual-band RF */
#define RAL_RF_5222 0x10
#define RAL_BBP_VERSION 0
#define RAL_BBP_TX 2
#define RAL_BBP_RX 14
#define RAL_BBP_ANTA 0x00
#define RAL_BBP_DIVERSITY 0x01
#define RAL_BBP_ANTB 0x02
#define RAL_BBP_ANTMASK 0x03
#define RAL_BBP_FLIPIQ 0x04
#define RAL_JAPAN_FILTER 0x08
struct ural_tx_desc {
uint32_t flags;
#define RAL_TX_RETRY(x) ((x) << 4)
#define RAL_TX_MORE_FRAG (1 << 8)
#define RAL_TX_ACK (1 << 9)
#define RAL_TX_TIMESTAMP (1 << 10)
#define RAL_TX_OFDM (1 << 11)
#define RAL_TX_NEWSEQ (1 << 12)
#define RAL_TX_IFS_MASK 0x00006000
#define RAL_TX_IFS_BACKOFF (0 << 13)
#define RAL_TX_IFS_SIFS (1 << 13)
#define RAL_TX_IFS_NEWBACKOFF (2 << 13)
#define RAL_TX_IFS_NONE (3 << 13)
uint16_t wme;
#define RAL_LOGCWMAX(x) (((x) & 0xf) << 12)
#define RAL_LOGCWMIN(x) (((x) & 0xf) << 8)
#define RAL_AIFSN(x) (((x) & 0x3) << 6)
#define RAL_IVOFFSET(x) (((x) & 0x3f))
uint16_t reserved;
uint8_t plcp_signal;
uint8_t plcp_service;
#define RAL_PLCP_LENGEXT 0x80
uint16_t plcp_length;
uint32_t iv;
uint32_t eiv;
} __packed;
struct ural_rx_desc {
uint32_t flags;
#define RAL_RX_CRC_ERROR (1 << 5)
#define RAL_RX_PHY_ERROR (1 << 7)
uint8_t rate;
uint8_t rssi;
uint16_t reserved;
uint32_t iv;
uint32_t eiv;
} __packed;
#define RAL_RF_LOBUSY (1 << 15)
#define RAL_RF_BUSY (1 << 31)
#define RAL_RF_20BIT (20 << 24)
#define RAL_RF1 0
#define RAL_RF2 2
#define RAL_RF3 1
#define RAL_RF4 3
#define RAL_EEPROM_ADDRESS 0x0004
#define RAL_EEPROM_TXPOWER 0x003c
#define RAL_EEPROM_CONFIG0 0x0016
#define RAL_EEPROM_BBP_BASE 0x001c
--Boundary-00=_h13bC3MzttkCcJc
Content-Type: text/x-csrc;
charset="us-ascii";
name="if_ral.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="if_ral.c"
/* $NetBSD$ */
/* $OpenBSD: if_ral.c,v 1.28 2005/04/17 13:41:51 damien Exp $ */
/*-
* Copyright (c) 2005
* Damien Bergamini <damien.bergamini@free.fr>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*-
* Ralink Technology RT2500USB chipset driver
* http://www.ralinktech.com/
*
* Ported to NetBSD by Ian Zagorskih
*/
#ifdef __NetBSD__
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD$");
#endif
#include "bpfilter.h"
#include <sys/param.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#ifdef __OpenBSD__
#include <sys/timeout.h>
#else
#include <sys/callout.h>
#endif
#include <sys/conf.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <machine/endian.h>
#include <machine/intr.h>
#if NBPFILTER > 0
#include <net/bpf.h>
#endif
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <net/if_ether.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#ifdef __OpenBSD__
#include <netinet/if_ether.h>
#endif
#include <netinet/ip.h>
#endif
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_rssadapt.h>
#include <net80211/ieee80211_radiotap.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdevs.h>
#include <dev/usb/if_ralreg.h>
#include <dev/usb/if_ralvar.h>
#ifdef USB_DEBUG
#define URAL_DEBUG
#endif
#ifdef URAL_DEBUG
#define DPRINTF(x) do { if (ural_debug) printf x; } while (0)
#define DPRINTFN(n, x) do { if (ural_debug >= (n)) printf x; } while (0)
int ural_debug = 1;
#else
#define DPRINTF(x)
#define DPRINTFN(n, x)
#endif
#ifdef __NetBSD__
#define M_DUP_PKTHDR M_COPY_PKTHDR /* XXX */
#define IEEE80211_F_WEPON IEEE80211_F_PRIVACY
#define letoh32 htole32
#define letoh16 htole16
#endif
/* various supported device vendors/products */
static const struct usb_devno ural_devs[] = {
{ USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2570 },
{ USB_VENDOR_ASUS, USB_PRODUCT_RALINK_RT2570 },
{ USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54G },
{ USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54GP },
{ USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_C54RU },
{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_RT2570 },
{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KG54 },
{ USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2570 },
{ USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2570_2 },
{ USB_VENDOR_SMC, USB_PRODUCT_SMC_RT2570 }
};
Static int ural_alloc_tx_list(struct ural_softc *);
Static void ural_free_tx_list(struct ural_softc *);
Static int ural_alloc_rx_list(struct ural_softc *);
Static void ural_free_rx_list(struct ural_softc *);
Static int ural_media_change(struct ifnet *);
Static void ural_next_scan(void *);
Static void ural_task(void *);
Static int ural_newstate(struct ieee80211com *,
enum ieee80211_state, int);
Static void ural_txeof(usbd_xfer_handle, usbd_private_handle,
usbd_status);
Static void ural_rxeof(usbd_xfer_handle, usbd_private_handle,
usbd_status);
Static int ural_ack_rate(int);
Static uint16_t ural_txtime(int, int, uint32_t);
Static uint8_t ural_plcp_signal(int);
Static void ural_setup_tx_desc(struct ural_softc *,
struct ural_tx_desc *, uint32_t, int, int);
Static int ural_tx_bcn(struct ural_softc *, struct mbuf *,
struct ieee80211_node *);
Static int ural_tx_mgt(struct ural_softc *, struct mbuf *,
struct ieee80211_node *);
Static int ural_tx_data(struct ural_softc *, struct mbuf *,
struct ieee80211_node *);
Static void ural_start(struct ifnet *);
Static void ural_watchdog(struct ifnet *);
Static int ural_ioctl(struct ifnet *, u_long, caddr_t);
Static void ural_eeprom_read(struct ural_softc *, uint16_t, void *,
int);
Static uint16_t ural_read(struct ural_softc *, uint16_t);
Static void ural_read_multi(struct ural_softc *, uint16_t, void *,
int);
Static void ural_write(struct ural_softc *, uint16_t, uint16_t);
Static void ural_write_multi(struct ural_softc *, uint16_t, void *,
int);
Static void ural_bbp_write(struct ural_softc *, uint8_t, uint8_t);
Static uint8_t ural_bbp_read(struct ural_softc *, uint8_t);
Static void ural_rf_write(struct ural_softc *, uint8_t, uint32_t);
Static void ural_set_chan(struct ural_softc *,
struct ieee80211_channel *);
Static void ural_disable_rf_tune(struct ural_softc *);
Static void ural_enable_tsf_sync(struct ural_softc *);
Static void ural_set_bssid(struct ural_softc *, uint8_t *);
Static void ural_set_macaddr(struct ural_softc *, uint8_t *);
Static void ural_update_promisc(struct ural_softc *);
Static const char *ural_get_rf(int);
Static void ural_read_eeprom(struct ural_softc *);
Static int ural_bbp_init(struct ural_softc *);
Static void ural_set_txantenna(struct ural_softc *, int);
Static void ural_set_rxantenna(struct ural_softc *, int);
Static int ural_init(struct ifnet *);
Static void ural_stop(struct ifnet *, int);
/*
* Supported rates for 802.11a/b/g modes (in 500Kbps unit).
*/
static const struct ieee80211_rateset ural_rateset_11a =
{ 8, { 12, 18, 24, 36, 48, 72, 96, 108 } };
static const struct ieee80211_rateset ural_rateset_11b =
{ 4, { 2, 4, 11, 22 } };
static const struct ieee80211_rateset ural_rateset_11g =
{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
/*
* Default values for MAC registers; values taken from the reference driver.
*/
static const struct {
uint16_t reg;
uint16_t val;
} ural_def_mac[] = {
{ RAL_TXRX_CSR5, 0x8c8d },
{ RAL_TXRX_CSR6, 0x8b8a },
{ RAL_TXRX_CSR7, 0x8687 },
{ RAL_TXRX_CSR8, 0x0085 },
{ RAL_MAC_CSR13, 0x1111 },
{ RAL_MAC_CSR14, 0x1e11 },
{ RAL_TXRX_CSR21, 0xe78f },
{ RAL_MAC_CSR9, 0xff1d },
{ RAL_MAC_CSR11, 0x0002 },
{ RAL_MAC_CSR22, 0x0053 },
{ RAL_MAC_CSR15, 0x0000 },
{ RAL_MAC_CSR8, 0x0780 },
{ RAL_TXRX_CSR19, 0x0000 },
{ RAL_TXRX_CSR18, 0x005a },
{ RAL_PHY_CSR2, 0x0000 },
{ RAL_TXRX_CSR0, 0x1ec0 },
{ RAL_PHY_CSR4, 0x000f }
};
/*
* Default values for BBP registers; values taken from the reference driver.
*/
static const struct {
uint8_t reg;
uint8_t val;
} ural_def_bbp[] = {
{ 3, 0x02 },
{ 4, 0x19 },
{ 14, 0x1c },
{ 15, 0x30 },
{ 16, 0xac },
{ 17, 0x48 },
{ 18, 0x18 },
{ 19, 0xff },
{ 20, 0x1e },
{ 21, 0x08 },
{ 22, 0x08 },
{ 23, 0x08 },
{ 24, 0x80 },
{ 25, 0x50 },
{ 26, 0x08 },
{ 27, 0x23 },
{ 30, 0x10 },
{ 31, 0x2b },
{ 32, 0xb9 },
{ 34, 0x12 },
{ 35, 0x50 },
{ 39, 0xc4 },
{ 40, 0x02 },
{ 41, 0x60 },
{ 53, 0x10 },
{ 54, 0x18 },
{ 56, 0x08 },
{ 57, 0x10 },
{ 58, 0x08 },
{ 61, 0x60 },
{ 62, 0x10 },
{ 75, 0xff }
};
/*
* Default values for RF register R2 indexed by channel numbers.
*/
static const uint32_t ural_rf2522_r2[] = {
0x307f6, 0x307fb, 0x30800, 0x30805, 0x3080a, 0x3080f, 0x30814,
0x30819, 0x3081e, 0x30823, 0x30828, 0x3082d, 0x30832, 0x3083e
};
static const uint32_t ural_rf2523_r2[] = {
0x00327, 0x00328, 0x00329, 0x0032a, 0x0032b, 0x0032c, 0x0032d,
0x0032e, 0x0032f, 0x00340, 0x00341, 0x00342, 0x00343, 0x00346
};
static const uint32_t ural_rf2524_r2[] = {
0x00327, 0x00328, 0x00329, 0x0032a, 0x0032b, 0x0032c, 0x0032d,
0x0032e, 0x0032f, 0x00340, 0x00341, 0x00342, 0x00343, 0x00346
};
static const uint32_t ural_rf2525_r2[] = {
0x20327, 0x20328, 0x20329, 0x2032a, 0x2032b, 0x2032c, 0x2032d,
0x2032e, 0x2032f, 0x20340, 0x20341, 0x20342, 0x20343, 0x20346
};
static const uint32_t ural_rf2525_hi_r2[] = {
0x2032f, 0x20340, 0x20341, 0x20342, 0x20343, 0x20344, 0x20345,
0x20346, 0x20347, 0x20348, 0x20349, 0x2034a, 0x2034b, 0x2034e
};
static const uint32_t ural_rf2525e_r2[] = {
0x2044d, 0x2044e, 0x2044f, 0x20460, 0x20461, 0x20462, 0x20463,
0x20464, 0x20465, 0x20466, 0x20467, 0x20468, 0x20469, 0x2046b
};
static const uint32_t ural_rf2526_hi_r2[] = {
0x0022a, 0x0022b, 0x0022b, 0x0022c, 0x0022c, 0x0022d, 0x0022d,
0x0022e, 0x0022e, 0x0022f, 0x0022d, 0x00240, 0x00240, 0x00241
};
static const uint32_t ural_rf2526_r2[] = {
0x00226, 0x00227, 0x00227, 0x00228, 0x00228, 0x00229, 0x00229,
0x0022a, 0x0022a, 0x0022b, 0x0022b, 0x0022c, 0x0022c, 0x0022d
};
/*
* For dual-band RF, RF registers R1 and R4 also depend on channel number;
* values taken from the reference driver.
*/
static const struct {
uint8_t chan;
uint32_t r1;
uint32_t r2;
uint32_t r4;
} ural_rf5222[] = {
/* channels in the 2.4GHz band */
{ 1, 0x08808, 0x0044d, 0x00282 },
{ 2, 0x08808, 0x0044e, 0x00282 },
{ 3, 0x08808, 0x0044f, 0x00282 },
{ 4, 0x08808, 0x00460, 0x00282 },
{ 5, 0x08808, 0x00461, 0x00282 },
{ 6, 0x08808, 0x00462, 0x00282 },
{ 7, 0x08808, 0x00463, 0x00282 },
{ 8, 0x08808, 0x00464, 0x00282 },
{ 9, 0x08808, 0x00465, 0x00282 },
{ 10, 0x08808, 0x00466, 0x00282 },
{ 11, 0x08808, 0x00467, 0x00282 },
{ 12, 0x08808, 0x00468, 0x00282 },
{ 13, 0x08808, 0x00469, 0x00282 },
{ 14, 0x08808, 0x0046b, 0x00286 },
/* channels in the 5.2GHz band */
{ 36, 0x08804, 0x06225, 0x00287 },
{ 40, 0x08804, 0x06226, 0x00287 },
{ 44, 0x08804, 0x06227, 0x00287 },
{ 48, 0x08804, 0x06228, 0x00287 },
{ 52, 0x08804, 0x06229, 0x00287 },
{ 56, 0x08804, 0x0622a, 0x00287 },
{ 60, 0x08804, 0x0622b, 0x00287 },
{ 64, 0x08804, 0x0622c, 0x00287 },
{ 100, 0x08804, 0x02200, 0x00283 },
{ 104, 0x08804, 0x02201, 0x00283 },
{ 108, 0x08804, 0x02202, 0x00283 },
{ 112, 0x08804, 0x02203, 0x00283 },
{ 116, 0x08804, 0x02204, 0x00283 },
{ 120, 0x08804, 0x02205, 0x00283 },
{ 124, 0x08804, 0x02206, 0x00283 },
{ 128, 0x08804, 0x02207, 0x00283 },
{ 132, 0x08804, 0x02208, 0x00283 },
{ 136, 0x08804, 0x02209, 0x00283 },
{ 140, 0x08804, 0x0220a, 0x00283 },
{ 149, 0x08808, 0x02429, 0x00281 },
{ 153, 0x08808, 0x0242b, 0x00281 },
{ 157, 0x08808, 0x0242d, 0x00281 },
{ 161, 0x08808, 0x0242f, 0x00281 }
};
USB_DECLARE_DRIVER(ural);
USB_MATCH(ural)
{
USB_MATCH_START(ural, uaa);
if (uaa->iface != NULL)
return UMATCH_NONE;
return (usb_lookup(ural_devs, uaa->vendor, uaa->product) != NULL) ?
UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
}
USB_ATTACH(ural)
{
USB_ATTACH_START(ural, sc, uaa);
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
usb_interface_descriptor_t *id;
usb_endpoint_descriptor_t *ed;
usbd_status error;
char devinfo[1024];
int i;
sc->sc_udev = uaa->device;
usbd_devinfo(sc->sc_udev, 0, devinfo, sizeof devinfo);
USB_ATTACH_SETUP;
printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
if (usbd_set_config_no(sc->sc_udev, RAL_CONFIG_NO, 0) != 0) {
printf("%s: could not set configuration no\n",
USBDEVNAME(sc->sc_dev));
USB_ATTACH_ERROR_RETURN;
}
/* get the first interface handle */
error = usbd_device2interface_handle(sc->sc_udev, RAL_IFACE_INDEX,
&sc->sc_iface);
if (error != 0) {
printf("%s: could not get interface handle\n",
USBDEVNAME(sc->sc_dev));
USB_ATTACH_ERROR_RETURN;
}
/*
* Find endpoints.
*/
id = usbd_get_interface_descriptor(sc->sc_iface);
for (i = 0; i < id->bNumEndpoints; i++) {
ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
if (ed == NULL) {
printf("%s: no endpoint descriptor for %d\n",
USBDEVNAME(sc->sc_dev), i);
USB_ATTACH_ERROR_RETURN;
}
if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
sc->sc_rx_no = ed->bEndpointAddress;
else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
sc->sc_tx_no = ed->bEndpointAddress;
}
usb_init_task(&sc->sc_task, ural_task, sc);
#ifdef __OpenBSD__
timeout_set(&sc->scan_ch, ural_next_scan, sc);
#else
callout_init(&sc->scan_ch);
callout_setfunc(&sc->scan_ch, ural_next_scan, sc);
#endif
/* retrieve RT2570 rev. no */
sc->asic_rev = ural_read(sc, RAL_MAC_CSR0);
/* retrieve MAC address and various other things from EEPROM */
ural_read_eeprom(sc);
printf("%s: MAC/BBP RT2570 (rev 0x%02x), RF %s, address %s\n",
USBDEVNAME(sc->sc_dev), sc->asic_rev, ural_get_rf(sc->rf_rev),
ether_sprintf(ic->ic_myaddr));
ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
ic->ic_state = IEEE80211_S_INIT;
/* set device capabilities */
ic->ic_caps = IEEE80211_C_MONITOR | IEEE80211_C_IBSS |
IEEE80211_C_HOSTAP | IEEE80211_C_SHPREAMBLE | IEEE80211_C_PMGT |
IEEE80211_C_TXPMGT | IEEE80211_C_WEP;
if (sc->rf_rev == RAL_RF_5222) {
/* set supported .11a rates */
ic->ic_sup_rates[IEEE80211_MODE_11A] = ural_rateset_11a;
/* set supported .11a channels */
for (i = 36; i <= 64; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
for (i = 100; i <= 140; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
for (i = 149; i <= 161; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
}
/* set supported .11b and .11g rates */
ic->ic_sup_rates[IEEE80211_MODE_11B] = ural_rateset_11b;
ic->ic_sup_rates[IEEE80211_MODE_11G] = ural_rateset_11g;
/* set supported .11b and .11g channels (1 through 14) */
for (i = 1; i <= 14; i++) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
ic->ic_channels[i].ic_flags =
IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
}
ifp->if_softc = sc;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_init = ural_init;
ifp->if_stop = ural_stop;
ifp->if_start = ural_start;
ifp->if_ioctl = ural_ioctl;
ifp->if_watchdog = ural_watchdog;
IFQ_SET_READY(&ifp->if_snd);
memcpy(ifp->if_xname, USBDEVNAME(sc->sc_dev), IFNAMSIZ);
/* Call MI attach routine */
if_attach(ifp);
ieee80211_ifattach(ifp);
/* override state transition machine */
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = ural_newstate;
/* Setup ifmedia interface */
ieee80211_media_init(ifp, ural_media_change, ieee80211_media_status);
#if NBPFILTER > 0
#ifdef __OpenBSD__
bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
sizeof (struct ieee80211_frame) + 64);
#else
bpfattach(ifp, DLT_IEEE802_11_RADIO,
sizeof (struct ieee80211_frame) + 64);
#endif
#endif
sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
sc->sc_rxtap.wr_ihdr.it_present = htole32(RAL_RX_RADIOTAP_PRESENT);
sc->sc_txtap_len = sizeof sc->sc_txtapu;
sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
sc->sc_txtap.wt_ihdr.it_present = htole32(RAL_TX_RADIOTAP_PRESENT);
usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
USBDEV(sc->sc_dev));
USB_ATTACH_SUCCESS_RETURN;
}
USB_DETACH(ural)
{
USB_DETACH_START(ural, sc);
struct ifnet *ifp = &sc->sc_ic.ic_if;
int s;
s = splusb();
usb_rem_task(sc->sc_udev, &sc->sc_task);
#ifdef __OpenBSD__
timeout_del(&sc->scan_ch);
#else
callout_stop(&sc->scan_ch);
#endif
if (sc->sc_rx_pipeh != NULL) {
usbd_abort_pipe(sc->sc_rx_pipeh);
usbd_close_pipe(sc->sc_rx_pipeh);
}
if (sc->sc_tx_pipeh != NULL) {
usbd_abort_pipe(sc->sc_tx_pipeh);
usbd_close_pipe(sc->sc_tx_pipeh);
}
ural_free_rx_list(sc);
ural_free_tx_list(sc);
#if NBPFILTER > 0
bpfdetach(ifp);
#endif
ieee80211_ifdetach(ifp);
if_detach(ifp);
splx(s);
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
USBDEV(sc->sc_dev));
return 0;
}
Static int
ural_alloc_tx_list(struct ural_softc *sc)
{
struct ural_tx_data *data;
int i, error;
sc->tx_queued = 0;
for (i = 0; i < RAL_TX_LIST_COUNT; i++) {
data = &sc->tx_data[i];
data->sc = sc;
data->xfer = usbd_alloc_xfer(sc->sc_udev);
if (data->xfer == NULL) {
printf("%s: could not allocate tx xfer\n",
USBDEVNAME(sc->sc_dev));
error = ENOMEM;
goto fail;
}
data->buf = usbd_alloc_buffer(data->xfer,
RAL_TX_DESC_SIZE + MCLBYTES);
if (data->buf == NULL) {
printf("%s: could not allocate tx buffer\n",
USBDEVNAME(sc->sc_dev));
error = ENOMEM;
goto fail;
}
}
return 0;
fail: ural_free_tx_list(sc);
return error;
}
Static void
ural_free_tx_list(struct ural_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ural_tx_data *data;
int i;
for (i = 0; i < RAL_TX_LIST_COUNT; i++) {
data = &sc->tx_data[i];
if (data->xfer != NULL) {
usbd_free_xfer(data->xfer);
data->xfer = NULL;
}
if (data->ni != NULL) {
ieee80211_release_node(ic, data->ni);
data->ni = NULL;
}
}
}
Static int
ural_alloc_rx_list(struct ural_softc *sc)
{
struct ural_rx_data *data;
int i, error;
for (i = 0; i < RAL_RX_LIST_COUNT; i++) {
data = &sc->rx_data[i];
data->sc = sc;
data->xfer = usbd_alloc_xfer(sc->sc_udev);
if (data->xfer == NULL) {
printf("%s: could not allocate rx xfer\n",
USBDEVNAME(sc->sc_dev));
error = ENOMEM;
goto fail;
}
if (usbd_alloc_buffer(data->xfer, MCLBYTES) == NULL) {
printf("%s: could not allocate rx buffer\n",
USBDEVNAME(sc->sc_dev));
error = ENOMEM;
goto fail;
}
MGETHDR(data->m, M_DONTWAIT, MT_DATA);
if (data->m == NULL) {
printf("%s: could not allocate rx mbuf\n",
USBDEVNAME(sc->sc_dev));
error = ENOMEM;
goto fail;
}
MCLGET(data->m, M_DONTWAIT);
if (!(data->m->m_flags & M_EXT)) {
printf("%s: could not allocate rx mbuf cluster\n",
USBDEVNAME(sc->sc_dev));
error = ENOMEM;
goto fail;
}
data->buf = mtod(data->m, uint8_t *);
}
return 0;
fail: ural_free_tx_list(sc);
return error;
}
Static void
ural_free_rx_list(struct ural_softc *sc)
{
struct ural_rx_data *data;
int i;
for (i = 0; i < RAL_RX_LIST_COUNT; i++) {
data = &sc->rx_data[i];
if (data->xfer != NULL) {
usbd_free_xfer(data->xfer);
data->xfer = NULL;
}
if (data->m != NULL) {
m_freem(data->m);
data->m = NULL;
}
}
}
Static int
ural_media_change(struct ifnet *ifp)
{
int error;
error = ieee80211_media_change(ifp);
if (error != ENETRESET)
return error;
if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
ural_init(ifp);
return 0;
}
/*
* This function is called periodically (every 200ms) during scanning to
* switch from one channel to another.
*/
Static void
ural_next_scan(void *arg)
{
struct ural_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
if (ic->ic_state == IEEE80211_S_SCAN)
ieee80211_next_scan(ic);
}
Static void
ural_task(void *arg)
{
struct ural_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
enum ieee80211_state ostate;
struct mbuf *m;
ostate = ic->ic_state;
switch (sc->sc_state) {
case IEEE80211_S_INIT:
if (ostate == IEEE80211_S_RUN) {
/* abort TSF synchronization */
ural_write(sc, RAL_TXRX_CSR19, 0);
/* force tx led to stop blinking */
ural_write(sc, RAL_MAC_CSR20, 0);
}
break;
case IEEE80211_S_SCAN:
ural_set_chan(sc, ic->ic_bss->ni_chan);
#ifdef __OpenBSD__
timeout_add(&sc->scan_ch, hz / 5);
#else
callout_schedule(&sc->scan_ch, hz / 5);
#endif
break;
case IEEE80211_S_AUTH:
ural_set_chan(sc, ic->ic_bss->ni_chan);
break;
case IEEE80211_S_ASSOC:
ural_set_chan(sc, ic->ic_bss->ni_chan);
break;
case IEEE80211_S_RUN:
ural_set_chan(sc, ic->ic_bss->ni_chan);
if (ic->ic_opmode != IEEE80211_M_MONITOR)
ural_set_bssid(sc, ic->ic_bss->ni_bssid);
if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
ic->ic_opmode == IEEE80211_M_IBSS) {
m = ieee80211_beacon_alloc(ic, ic->ic_bss);
if (m == NULL) {
printf("%s: could not allocate beacon\n",
USBDEVNAME(sc->sc_dev));
return;
}
if (ural_tx_bcn(sc, m, ic->ic_bss) != 0) {
m_freem(m);
printf("%s: could not transmit beacon\n",
USBDEVNAME(sc->sc_dev));
return;
}
/* beacon is no longer needed */
m_freem(m);
}
/* make tx led blink on tx (controlled by ASIC) */
ural_write(sc, RAL_MAC_CSR20, 1);
if (ic->ic_opmode != IEEE80211_M_MONITOR)
ural_enable_tsf_sync(sc);
break;
}
sc->sc_newstate(ic, sc->sc_state, -1);
}
Static int
ural_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
struct ural_softc *sc = ic->ic_if.if_softc;
usb_rem_task(sc->sc_udev, &sc->sc_task);
#ifdef __OpenBSD__
timeout_del(&sc->scan_ch);
#else
callout_stop(&sc->scan_ch);
#endif
/* do it in a process context */
sc->sc_state = nstate;
usb_add_task(sc->sc_udev, &sc->sc_task);
return 0;
}
/* quickly determine if a given rate is CCK or OFDM */
#define RAL_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22)
#define RAL_ACK_SIZE 14 /* 10 + 4(FCS) */
#define RAL_CTS_SIZE 14 /* 10 + 4(FCS) */
#define RAL_SIFS 10
Static void
ural_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
struct ural_tx_data *data = priv;
struct ural_softc *sc = data->sc;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
int s;
if (status != USBD_NORMAL_COMPLETION) {
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
return;
printf("%s: could not transmit buffer: %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(status));
if (status == USBD_STALLED)
usbd_clear_endpoint_stall(sc->sc_tx_pipeh);
ifp->if_oerrors++;
return;
}
s = splnet();
m_freem(data->m);
data->m = NULL;
ieee80211_release_node(ic, data->ni);
data->ni = NULL;
sc->tx_queued--;
ifp->if_opackets++;
DPRINTFN(10, ("tx done\n"));
sc->sc_tx_timer = 0;
ifp->if_flags &= ~IFF_OACTIVE;
ural_start(ifp);
splx(s);
}
Static void
ural_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
struct ural_rx_data *data = priv;
struct ural_softc *sc = data->sc;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
struct ural_rx_desc *desc;
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
struct mbuf *m;
int s, len;
if (status != USBD_NORMAL_COMPLETION) {
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
return;
if (status == USBD_STALLED)
usbd_clear_endpoint_stall(sc->sc_rx_pipeh);
goto skip;
}
usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
if (len < RAL_RX_DESC_SIZE) {
printf("%s: xfer too short %d\n", USBDEVNAME(sc->sc_dev), len);
ifp->if_ierrors++;
goto skip;
}
/* rx descriptor is located at the end */
desc = (struct ural_rx_desc *)(data->buf + len - RAL_RX_DESC_SIZE);
if ((letoh32(desc->flags) & RAL_RX_PHY_ERROR) ||
(letoh32(desc->flags) & RAL_RX_CRC_ERROR)) {
/*
* This should not happen since we did not request to receive
* those frames when we filled RAL_TXRX_CSR2.
*/
DPRINTFN(5, ("PHY or CRC error\n"));
ifp->if_ierrors++;
goto skip;
}
/* finalize mbuf */
m = data->m;
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = m->m_len = (letoh32(desc->flags) >> 16) & 0xfff;
m->m_flags |= M_HASFCS; /* hardware appends FCS */
s = splnet();
#if NBPFILTER > 0
if (sc->sc_drvbpf != NULL) {
struct mbuf mb;
struct ural_rx_radiotap_header *tap = &sc->sc_rxtap;
tap->wr_flags = 0;
tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
tap->wr_antenna = sc->rx_ant;
tap->wr_antsignal = desc->rssi;
M_DUP_PKTHDR(&mb, m);
mb.m_data = (caddr_t)tap;
mb.m_len = sc->sc_txtap_len;
mb.m_next = m;
mb.m_pkthdr.len += mb.m_len;
bpf_mtap(sc->sc_drvbpf, &mb);
}
#endif
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic, wh);
/* send the frame to the 802.11 layer */
ieee80211_input(ifp, m, ni, desc->rssi, 0);
/* node is no longer needed */
ieee80211_release_node(ic, ni);
splx(s);
MGETHDR(data->m, M_DONTWAIT, MT_DATA);
if (data->m == NULL) {
printf("%s: could not allocate rx mbuf\n",
USBDEVNAME(sc->sc_dev));
return;
}
MCLGET(data->m, M_DONTWAIT);
if (!(data->m->m_flags & M_EXT)) {
printf("%s: could not allocate rx mbuf cluster\n",
USBDEVNAME(sc->sc_dev));
m_freem(data->m);
data->m = NULL;
return;
}
data->buf = mtod(data->m, uint8_t *);
DPRINTFN(15, ("rx done\n"));
skip: /* setup a new transfer */
usbd_setup_xfer(xfer, sc->sc_rx_pipeh, data, data->buf, MCLBYTES,
USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, ural_rxeof);
usbd_transfer(xfer);
}
/*
* Return the expected ack rate for a frame transmitted at rate `rate'.
* XXX: this should depend on the destination node basic rate set.
*/
Static int
ural_ack_rate(int rate)
{
switch (rate) {
/* CCK rates */
case 2:
return 2;
case 4:
case 11:
case 22:
return 4;
/* OFDM rates */
case 12:
case 18:
return 12;
case 24:
case 36:
return 24;
case 48:
case 72:
case 96:
case 108:
return 48;
}
/* default to 1Mbps */
return 2;
}
/*
* Compute the duration (in us) needed to transmit `len' bytes at rate `rate'.
* The function automatically determines the operating mode depending on the
* given rate. `flags' indicates whether short preamble is in use or not.
*/
Static uint16_t
ural_txtime(int len, int rate, uint32_t flags)
{
uint16_t txtime;
int ceil, dbps;
if (RAL_RATE_IS_OFDM(rate)) {
/*
* OFDM TXTIME calculation.
* From IEEE Std 802.11a-1999, pp. 37.
*/
dbps = rate * 2; /* data bits per OFDM symbol */
ceil = (16 + 8 * len + 6) / dbps;
if ((16 + 8 * len + 6) % dbps != 0)
ceil++;
txtime = 16 + 4 + 4 * ceil + 6;
} else {
/*
* High Rate TXTIME calculation.
* From IEEE Std 802.11b-1999, pp. 28.
*/
ceil = (8 * len * 2) / rate;
if ((8 * len * 2) % rate != 0)
ceil++;
if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE))
txtime = 72 + 24 + ceil;
else
txtime = 144 + 48 + ceil;
}
return txtime;
}
Static uint8_t
ural_plcp_signal(int rate)
{
switch (rate) {
/* CCK rates (returned values are device-dependent) */
case 2: return 0x0;
case 4: return 0x1;
case 11: return 0x2;
case 22: return 0x3;
/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
case 12: return 0xb;
case 18: return 0xf;
case 24: return 0xa;
case 36: return 0xe;
case 48: return 0x9;
case 72: return 0xd;
case 96: return 0x8;
case 108: return 0xc;
/* unsupported rates (should not get there) */
default: return 0xff;
}
}
Static void
ural_setup_tx_desc(struct ural_softc *sc, struct ural_tx_desc *desc,
uint32_t flags, int len, int rate)
{
struct ieee80211com *ic = &sc->sc_ic;
uint16_t plcp_length;
int remainder;
desc->flags = htole32(flags);
desc->flags |= htole32(RAL_TX_NEWSEQ);
desc->flags |= htole32(len << 16);
if (RAL_RATE_IS_OFDM(rate))
desc->flags |= htole32(RAL_TX_OFDM);
desc->wme = htole16(RAL_LOGCWMAX(5) | RAL_LOGCWMIN(3) | RAL_AIFSN(2));
/*
* Fill PLCP fields.
*/
desc->plcp_service = 4;
len += 4; /* account for FCS */
if (RAL_RATE_IS_OFDM(rate)) {
/*
* PLCP length field (LENGTH).
* From IEEE Std 802.11a-1999, pp. 14.
*/
plcp_length = len & 0xfff;
desc->plcp_length = htole16((plcp_length >> 6) << 8 |
(plcp_length & 0x3f));
} else {
/*
* Long PLCP LENGTH field.
* From IEEE Std 802.11b-1999, pp. 16.
*/
plcp_length = (8 * len * 2) / rate;
remainder = (8 * len * 2) % rate;
if (remainder != 0) {
if (rate == 22 && (rate - remainder) / 16 != 0)
desc->plcp_service |= RAL_PLCP_LENGEXT;
plcp_length++;
}
desc->plcp_length = htole16(plcp_length);
}
desc->plcp_signal = ural_plcp_signal(rate);
if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
desc->plcp_signal |= 0x08;
desc->iv = 0;
desc->eiv = 0;
}
#define RAL_TX_TIMEOUT 5000
Static int
ural_tx_bcn(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
{
struct ural_tx_desc *desc;
usbd_xfer_handle xfer;
usbd_status error;
uint8_t cmd = 0;
uint8_t *buf;
int xferlen, rate;
rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 4;
xfer = usbd_alloc_xfer(sc->sc_udev);
if (xfer == NULL)
return ENOMEM;
/* xfer length needs to be a multiple of two! */
xferlen = (RAL_TX_DESC_SIZE + m0->m_pkthdr.len + 1) & ~1;
buf = usbd_alloc_buffer(xfer, xferlen);
if (buf == NULL) {
usbd_free_xfer(xfer);
return ENOMEM;
}
usbd_setup_xfer(xfer, sc->sc_tx_pipeh, NULL, &cmd, sizeof cmd,
USBD_FORCE_SHORT_XFER, RAL_TX_TIMEOUT, NULL);
error = usbd_sync_transfer(xfer);
if (error != 0) {
usbd_free_xfer(xfer);
return error;
}
desc = (struct ural_tx_desc *)buf;
m_copydata(m0, 0, m0->m_pkthdr.len, buf + RAL_TX_DESC_SIZE);
ural_setup_tx_desc(sc, desc, RAL_TX_IFS_NEWBACKOFF | RAL_TX_TIMESTAMP,
m0->m_pkthdr.len, rate);
DPRINTFN(10, ("sending beacon frame len=%u rate=%u xfer len=%u\n",
m0->m_pkthdr.len, rate, xferlen));
usbd_setup_xfer(xfer, sc->sc_tx_pipeh, NULL, buf, xferlen,
USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RAL_TX_TIMEOUT, NULL);
error = usbd_sync_transfer(xfer);
usbd_free_xfer(xfer);
return error;
}
Static int
ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ural_tx_desc *desc;
struct ural_tx_data *data;
struct ieee80211_frame *wh;
uint32_t flags = 0;
uint16_t dur;
usbd_status error;
int xferlen, rate;
data = &sc->tx_data[0];
desc = (struct ural_tx_desc *)data->buf;
rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 4;
#if NBPFILTER > 0
if (sc->sc_drvbpf != NULL) {
struct mbuf mb;
struct ural_tx_radiotap_header *tap = &sc->sc_txtap;
tap->wt_flags = 0;
tap->wt_rate = rate;
tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
tap->wt_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
tap->wt_antenna = sc->tx_ant;
M_DUP_PKTHDR(&mb, m0);
mb.m_data = (caddr_t)tap;
mb.m_len = sc->sc_txtap_len;
mb.m_next = m0;
mb.m_pkthdr.len += mb.m_len;
bpf_mtap(sc->sc_drvbpf, &mb);
}
#endif
data->m = m0;
data->ni = ni;
wh = mtod(m0, struct ieee80211_frame *);
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
flags |= RAL_TX_ACK;
dur = ural_txtime(RAL_ACK_SIZE, rate, ic->ic_flags) + RAL_SIFS;
*(uint16_t *)wh->i_dur = htole16(dur);
/* tell hardware to add timestamp for probe responses */
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
IEEE80211_FC0_TYPE_MGT &&
(wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
IEEE80211_FC0_SUBTYPE_PROBE_RESP)
flags |= RAL_TX_TIMESTAMP;
}
m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RAL_TX_DESC_SIZE);
ural_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate);
/* xfer length needs to be a multiple of two! */
xferlen = (RAL_TX_DESC_SIZE + m0->m_pkthdr.len + 1) & ~1;
DPRINTFN(10, ("sending mgt frame len=%u rate=%u xfer len=%u\n",
m0->m_pkthdr.len, rate, xferlen));
usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, xferlen,
USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RAL_TX_TIMEOUT, ural_txeof);
error = usbd_transfer(data->xfer);
if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS) {
m_freem(m0);
return error;
}
sc->tx_queued++;
return 0;
}
Static int
ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
struct ieee80211_rateset *rs;
struct ural_tx_desc *desc;
struct ural_tx_data *data;
struct ieee80211_frame *wh;
uint32_t flags = 0;
uint16_t dur;
usbd_status error;
int xferlen, rate;
if (ic->ic_fixed_rate != -1) {
rs = &ic->ic_sup_rates[ic->ic_curmode];
rate = rs->rs_rates[ic->ic_fixed_rate];
} else {
rs = &ni->ni_rates;
rate = rs->rs_rates[ni->ni_txrate];
}
rate &= IEEE80211_RATE_VAL;
if (ic->ic_flags & IEEE80211_F_WEPON) {
m0 = ieee80211_wep_crypt(ifp, m0, 1);
if (m0 == NULL)
return ENOBUFS;
}
#if NBPFILTER > 0
if (sc->sc_drvbpf != NULL) {
struct mbuf mb;
struct ural_tx_radiotap_header *tap = &sc->sc_txtap;
tap->wt_flags = 0;
tap->wt_rate = rate;
tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
tap->wt_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
tap->wt_antenna = sc->tx_ant;
M_DUP_PKTHDR(&mb, m0);
mb.m_data = (caddr_t)tap;
mb.m_len = sc->sc_txtap_len;
mb.m_next = m0;
mb.m_pkthdr.len += mb.m_len;
bpf_mtap(sc->sc_drvbpf, &mb);
}
#endif
data = &sc->tx_data[0];
desc = (struct ural_tx_desc *)data->buf;
data->m = m0;
data->ni = ni;
wh = mtod(m0, struct ieee80211_frame *);
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
flags |= RAL_TX_ACK;
flags |= RAL_TX_RETRY(7);
dur = ural_txtime(RAL_ACK_SIZE, ural_ack_rate(rate),
ic->ic_flags) + RAL_SIFS;
*(uint16_t *)wh->i_dur = htole16(dur);
}
m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RAL_TX_DESC_SIZE);
ural_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate);
/* xfer length needs to be a multiple of two! */
xferlen = (RAL_TX_DESC_SIZE + m0->m_pkthdr.len + 1) & ~1;
DPRINTFN(10, ("sending data frame len=%u rate=%u xfer len=%u\n",
m0->m_pkthdr.len, rate, xferlen));
usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, xferlen,
USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RAL_TX_TIMEOUT, ural_txeof);
error = usbd_transfer(data->xfer);
if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS) {
m_freem(m0);
return error;
}
sc->tx_queued++;
return 0;
}
Static void
ural_start(struct ifnet *ifp)
{
struct ural_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni;
struct mbuf *m0;
for (;;) {
IF_POLL(&ic->ic_mgtq, m0);
if (m0 != NULL) {
if (sc->tx_queued >= RAL_TX_LIST_COUNT) {
ifp->if_flags |= IFF_OACTIVE;
break;
}
IF_DEQUEUE(&ic->ic_mgtq, m0);
ni = (struct ieee80211_node *)m0->m_pkthdr.rcvif;
m0->m_pkthdr.rcvif = NULL;
#if NBPFILTER > 0
if (ic->ic_rawbpf != NULL)
bpf_mtap(ic->ic_rawbpf, m0);
#endif
if (ural_tx_mgt(sc, m0, ni) != 0)
break;
} else {
if (ic->ic_state != IEEE80211_S_RUN)
break;
IFQ_DEQUEUE(&ifp->if_snd, m0);
if (m0 == NULL)
break;
if (sc->tx_queued >= RAL_TX_LIST_COUNT) {
IF_PREPEND(&ifp->if_snd, m0);
ifp->if_flags |= IFF_OACTIVE;
break;
}
#if NBPFILTER > 0
if (ifp->if_bpf != NULL)
bpf_mtap(ifp->if_bpf, m0);
#endif
m0 = ieee80211_encap(ifp, m0, &ni);
if (m0 == NULL)
continue;
#if NBPFILTER > 0
if (ic->ic_rawbpf != NULL)
bpf_mtap(ic->ic_rawbpf, m0);
#endif
if (ural_tx_data(sc, m0, ni) != 0) {
if (ni != NULL)
ieee80211_release_node(ic, ni);
ifp->if_oerrors++;
break;
}
}
sc->sc_tx_timer = 5;
ifp->if_timer = 1;
}
}
Static void
ural_watchdog(struct ifnet *ifp)
{
struct ural_softc *sc = ifp->if_softc;
ifp->if_timer = 0;
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
printf("%s: device timeout\n", USBDEVNAME(sc->sc_dev));
/*ural_init(ifp); XXX needs a process context! */
ifp->if_oerrors++;
return;
}
ifp->if_timer = 1;
}
ieee80211_watchdog(ifp);
}
Static int
ural_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct ural_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
struct ifaddr *ifa;
struct ifreq *ifr;
int s, error = 0;
s = splnet();
switch (cmd) {
case SIOCSIFADDR:
ifa = (struct ifaddr *)data;
ifp->if_flags |= IFF_UP;
#ifdef INET
if (ifa->ifa_addr->sa_family == AF_INET)
#ifdef __NetBSD__
arp_ifinit(ifp, ifa);
#else
arp_ifinit(&ic->ic_ac, ifa);
#endif
#endif
/* FALLTHROUGH */
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
if (ifp->if_flags & IFF_RUNNING)
ural_update_promisc(sc);
else
ural_init(ifp);
} else {
if (ifp->if_flags & IFF_RUNNING)
ural_stop(ifp, 1);
}
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
ifr = (struct ifreq *)data;
#ifdef __OpenBSD__
error = (cmd == SIOCADDMULTI) ?
ether_addmulti(ifr, &ic->ic_ac) :
ether_delmulti(ifr, &ic->ic_ac);
#else
error = (cmd == SIOCADDMULTI) ?
ether_addmulti(ifr, &ic->ic_ec) :
ether_delmulti(ifr, &ic->ic_ec);
#endif
if (error == ENETRESET)
error = 0;
break;
case SIOCS80211CHANNEL:
/*
* This allows for fast channel switching in monitor mode
* (used by kismet). In IBSS mode, we must explicitly reset
* the interface to generate a new beacon frame.
*/
error = ieee80211_ioctl(ifp, cmd, data);
if (error == ENETRESET &&
ic->ic_opmode == IEEE80211_M_MONITOR) {
ural_set_chan(sc, ic->ic_ibss_chan);
error = 0;
}
break;
default:
error = ieee80211_ioctl(ifp, cmd, data);
}
if (error == ENETRESET) {
if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
(IFF_UP | IFF_RUNNING))
ural_init(ifp);
error = 0;
}
splx(s);
return error;
}
Static void
ural_eeprom_read(struct ural_softc *sc, uint16_t addr, void *buf, int len)
{
usb_device_request_t req;
usbd_status error;
req.bmRequestType = UT_READ_VENDOR_DEVICE;
req.bRequest = RAL_READ_EEPROM;
USETW(req.wValue, 0);
USETW(req.wIndex, addr);
USETW(req.wLength, len);
error = usbd_do_request(sc->sc_udev, &req, buf);
if (error != 0) {
printf("%s: could not read EEPROM: %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(error));
}
}
Static uint16_t
ural_read(struct ural_softc *sc, uint16_t reg)
{
usb_device_request_t req;
usbd_status error;
uint16_t val;
req.bmRequestType = UT_READ_VENDOR_DEVICE;
req.bRequest = RAL_READ_MAC;
USETW(req.wValue, 0);
USETW(req.wIndex, reg);
USETW(req.wLength, sizeof (uint16_t));
error = usbd_do_request(sc->sc_udev, &req, &val);
if (error != 0) {
printf("%s: could not read MAC register: %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(error));
return 0;
}
return le16toh(val);
}
Static void
ural_read_multi(struct ural_softc *sc, uint16_t reg, void *buf, int len)
{
usb_device_request_t req;
usbd_status error;
req.bmRequestType = UT_READ_VENDOR_DEVICE;
req.bRequest = RAL_READ_MULTI_MAC;
USETW(req.wValue, 0);
USETW(req.wIndex, reg);
USETW(req.wLength, len);
error = usbd_do_request(sc->sc_udev, &req, buf);
if (error != 0) {
printf("%s: could not read MAC register: %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(error));
return;
}
}
Static void
ural_write(struct ural_softc *sc, uint16_t reg, uint16_t val)
{
usb_device_request_t req;
usbd_status error;
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = RAL_WRITE_MAC;
USETW(req.wValue, val);
USETW(req.wIndex, reg);
USETW(req.wLength, 0);
error = usbd_do_request(sc->sc_udev, &req, NULL);
if (error != 0) {
printf("%s: could not write MAC register: %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(error));
}
}
Static void
ural_write_multi(struct ural_softc *sc, uint16_t reg, void *buf, int len)
{
usb_device_request_t req;
usbd_status error;
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = RAL_WRITE_MULTI_MAC;
USETW(req.wValue, 0);
USETW(req.wIndex, reg);
USETW(req.wLength, len);
error = usbd_do_request(sc->sc_udev, &req, buf);
if (error != 0) {
printf("%s: could not write MAC register: %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(error));
}
}
Static void
ural_bbp_write(struct ural_softc *sc, uint8_t reg, uint8_t val)
{
uint16_t tmp;
int ntries;
for (ntries = 0; ntries < 5; ntries++) {
if (!(ural_read(sc, RAL_PHY_CSR8) & RAL_BBP_BUSY))
break;
}
if (ntries == 5) {
printf("%s: could not write to BBP\n", USBDEVNAME(sc->sc_dev));
return;
}
tmp = reg << 8 | val;
ural_write(sc, RAL_PHY_CSR7, tmp);
}
Static uint8_t
ural_bbp_read(struct ural_softc *sc, uint8_t reg)
{
uint16_t val;
int ntries;
val = RAL_BBP_WRITE | reg << 8;
ural_write(sc, RAL_PHY_CSR7, val);
for (ntries = 0; ntries < 5; ntries++) {
if (!(ural_read(sc, RAL_PHY_CSR8) & RAL_BBP_BUSY))
break;
}
if (ntries == 5) {
printf("%s: could not read BBP\n", USBDEVNAME(sc->sc_dev));
return 0;
}
return ural_read(sc, RAL_PHY_CSR7) & 0xff;
}
Static void
ural_rf_write(struct ural_softc *sc, uint8_t reg, uint32_t val)
{
uint32_t tmp;
int ntries;
for (ntries = 0; ntries < 5; ntries++) {
if (!(ural_read(sc, RAL_PHY_CSR10) & RAL_RF_LOBUSY))
break;
}
if (ntries == 5) {
printf("%s: could not write to RF\n", USBDEVNAME(sc->sc_dev));
return;
}
tmp = RAL_RF_BUSY | RAL_RF_20BIT | (val & 0xfffff) << 2 | (reg & 0x3);
ural_write(sc, RAL_PHY_CSR9, tmp & 0xffff);
ural_write(sc, RAL_PHY_CSR10, tmp >> 16);
/* remember last written value in sc */
sc->rf_regs[reg] = val;
DPRINTFN(15, ("RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff));
}
Static void
ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
{
#define N(a) (sizeof (a) / sizeof ((a)[0]))
struct ieee80211com *ic = &sc->sc_ic;
uint8_t power, tmp;
u_int i, chan;
chan = ieee80211_chan2ieee(ic, c);
if (chan == 0 || chan == IEEE80211_CHAN_ANY)
return;
if (IEEE80211_IS_CHAN_2GHZ(c))
power = min(sc->txpow[chan - 1], 31);
else
power = 31;
DPRINTFN(2, ("setting channel to %u, txpower to %u\n", chan, power));
switch (sc->rf_rev) {
case RAL_RF_2522:
ural_rf_write(sc, RAL_RF1, 0x00814);
ural_rf_write(sc, RAL_RF2, ural_rf2522_r2[chan - 1]);
ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
break;
case RAL_RF_2523:
ural_rf_write(sc, RAL_RF1, 0x08804);
ural_rf_write(sc, RAL_RF2, ural_rf2523_r2[chan - 1]);
ural_rf_write(sc, RAL_RF3, power << 7 | 0x38044);
ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
break;
case RAL_RF_2524:
ural_rf_write(sc, RAL_RF1, 0x0c808);
ural_rf_write(sc, RAL_RF2, ural_rf2524_r2[chan - 1]);
ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
break;
case RAL_RF_2525:
ural_rf_write(sc, RAL_RF1, 0x08808);
ural_rf_write(sc, RAL_RF2, ural_rf2525_hi_r2[chan - 1]);
ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
ural_rf_write(sc, RAL_RF1, 0x08808);
ural_rf_write(sc, RAL_RF2, ural_rf2525_r2[chan - 1]);
ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
break;
case RAL_RF_2525E:
ural_rf_write(sc, RAL_RF1, 0x08808);
ural_rf_write(sc, RAL_RF2, ural_rf2525e_r2[chan - 1]);
ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282);
break;
case RAL_RF_2526:
ural_rf_write(sc, RAL_RF2, ural_rf2526_hi_r2[chan - 1]);
ural_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381);
ural_rf_write(sc, RAL_RF1, 0x08804);
ural_rf_write(sc, RAL_RF2, ural_rf2526_r2[chan - 1]);
ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
ural_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381);
break;
/* dual-band RF */
case RAL_RF_5222:
for (i = 0; i < N(ural_rf5222); i++)
if (ural_rf5222[i].chan == chan)
break;
if (i < N(ural_rf5222)) {
ural_rf_write(sc, RAL_RF1, ural_rf5222[i].r1);
ural_rf_write(sc, RAL_RF2, ural_rf5222[i].r2);
ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
ural_rf_write(sc, RAL_RF4, ural_rf5222[i].r4);
}
break;
}
if (ic->ic_opmode != IEEE80211_M_MONITOR &&
ic->ic_state != IEEE80211_S_SCAN) {
/* set Japan filter bit for channel 14 */
tmp = ural_bbp_read(sc, 70);
tmp &= ~RAL_JAPAN_FILTER;
if (chan == 14)
tmp |= RAL_JAPAN_FILTER;
ural_bbp_write(sc, 70, tmp);
/* clear CRC errors */
ural_read(sc, RAL_STA_CSR0);
DELAY(1000); /* RF needs a 1ms delay here */
ural_disable_rf_tune(sc);
}
#undef N
}
/*
* Disable RF auto-tuning.
*/
Static void
ural_disable_rf_tune(struct ural_softc *sc)
{
uint32_t tmp;
if (sc->rf_rev != RAL_RF_2523) {
tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE;
ural_rf_write(sc, RAL_RF1, tmp);
}
tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE;
ural_rf_write(sc, RAL_RF3, tmp);
DPRINTFN(2, ("disabling RF autotune\n"));
}
/*
* Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF
* synchronization.
*/
Static void
ural_enable_tsf_sync(struct ural_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
uint16_t logcwmin, preload, tmp;
/* first, disable TSF synchronization */
ural_write(sc, RAL_TXRX_CSR19, 0);
tmp = (16 * ic->ic_bss->ni_intval) << 4;
ural_write(sc, RAL_TXRX_CSR18, tmp);
logcwmin = (ic->ic_opmode == IEEE80211_M_IBSS) ? 2 : 0;
preload = (ic->ic_opmode == IEEE80211_M_IBSS) ? 320 : 6;
tmp = logcwmin << 12 | preload;
ural_write(sc, RAL_TXRX_CSR20, tmp);
/* finally, enable TSF synchronization */
tmp = RAL_ENABLE_TSF | RAL_ENABLE_TBCN;
if (ic->ic_opmode == IEEE80211_M_STA)
tmp |= RAL_ENABLE_TSF_SYNC(1);
else
tmp |= RAL_ENABLE_TSF_SYNC(2) | RAL_ENABLE_BEACON_GENERATOR;
ural_write(sc, RAL_TXRX_CSR19, tmp);
DPRINTF(("enabling TSF synchronization\n"));
}
Static void
ural_set_bssid(struct ural_softc *sc, uint8_t *bssid)
{
uint16_t tmp;
tmp = bssid[0] | bssid[1] << 8;
ural_write(sc, RAL_MAC_CSR5, tmp);
tmp = bssid[2] | bssid[3] << 8;
ural_write(sc, RAL_MAC_CSR6, tmp);
tmp = bssid[4] | bssid[5] << 8;
ural_write(sc, RAL_MAC_CSR7, tmp);
#ifdef __OpenBSD__
DPRINTF(("setting BSSID to %6D\n", bssid, ":"));
#else
DPRINTF(("setting BSSID to %s\n", ether_sprintf(bssid)));
#endif
}
Static void
ural_set_macaddr(struct ural_softc *sc, uint8_t *addr)
{
uint16_t tmp;
tmp = addr[0] | addr[1] << 8;
ural_write(sc, RAL_MAC_CSR2, tmp);
tmp = addr[2] | addr[3] << 8;
ural_write(sc, RAL_MAC_CSR3, tmp);
tmp = addr[4] | addr[5] << 8;
ural_write(sc, RAL_MAC_CSR4, tmp);
#ifdef __OpenBSD__
DPRINTF(("setting MAC address to %6D\n", addr, ":"));
#else
DPRINTF(("setting MAC address to %s\n", ether_sprintf(addr)));
#endif
}
Static void
ural_update_promisc(struct ural_softc *sc)
{
struct ifnet *ifp = &sc->sc_ic.ic_if;
uint16_t tmp;
tmp = ural_read(sc, RAL_TXRX_CSR2);
tmp &= ~RAL_DROP_NOT_TO_ME;
if (!(ifp->if_flags & IFF_PROMISC))
tmp |= RAL_DROP_NOT_TO_ME;
ural_write(sc, RAL_TXRX_CSR2, tmp);
DPRINTF(("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
"entering" : "leaving"));
}
Static const char *
ural_get_rf(int rev)
{
switch (rev) {
case RAL_RF_2522: return "RT2522";
case RAL_RF_2523: return "RT2523";
case RAL_RF_2524: return "RT2524";
case RAL_RF_2525: return "RT2525";
case RAL_RF_2525E: return "RT2525e";
case RAL_RF_2526: return "RT2526";
case RAL_RF_5222: return "RT5222";
default: return "unknown";
}
}
Static void
ural_read_eeprom(struct ural_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
uint16_t val;
ural_eeprom_read(sc, RAL_EEPROM_CONFIG0, &val, 2);
val = letoh16(val);
sc->rf_rev = (val >> 11) & 0x7;
sc->hw_radio = (val >> 10) & 0x1;
sc->led_mode = (val >> 6) & 0x7;
sc->rx_ant = (val >> 4) & 0x3;
sc->tx_ant = (val >> 2) & 0x3;
sc->nb_ant = val & 0x3;
/* read MAC address */
ural_eeprom_read(sc, RAL_EEPROM_ADDRESS, ic->ic_myaddr, 6);
/* read default values for BBP registers */
ural_eeprom_read(sc, RAL_EEPROM_BBP_BASE, sc->bbp_prom, 2 * 16);
/* read Tx power for all b/g channels */
ural_eeprom_read(sc, RAL_EEPROM_TXPOWER, sc->txpow, 14);
}
Static int
ural_bbp_init(struct ural_softc *sc)
{
#define N(a) (sizeof (a) / sizeof ((a)[0]))
int i, ntries;
/* wait for BBP to be ready */
for (ntries = 0; ntries < 100; ntries++) {
if (ural_bbp_read(sc, RAL_BBP_VERSION) != 0)
break;
DELAY(1000);
}
if (ntries == 100) {
printf("%s: timeout waiting for BBP\n", USBDEVNAME(sc->sc_dev));
return EIO;
}
/* initialize BBP registers to default values */
for (i = 0; i < N(ural_def_bbp); i++)
ural_bbp_write(sc, ural_def_bbp[i].reg, ural_def_bbp[i].val);
#if 0
/* initialize BBP registers to values stored in EEPROM */
for (i = 0; i < 16; i++) {
if (sc->bbp_prom[i].reg == 0xff)
continue;
ural_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val);
}
#endif
return 0;
#undef N
}
Static void
ural_set_txantenna(struct ural_softc *sc, int antenna)
{
uint16_t tmp;
uint8_t tx;
tx = ural_bbp_read(sc, RAL_BBP_TX) & ~RAL_BBP_ANTMASK;
if (antenna == 1)
tx |= RAL_BBP_ANTA;
else if (antenna == 2)
tx |= RAL_BBP_ANTB;
else
tx |= RAL_BBP_DIVERSITY;
/* need to force I/Q flip for RF 2525e, 2526 and 5222 */
if (sc->rf_rev == RAL_RF_2525E || sc->rf_rev == RAL_RF_2526 ||
sc->rf_rev == RAL_RF_5222)
tx |= RAL_BBP_FLIPIQ;
ural_bbp_write(sc, RAL_BBP_TX, tx);
/* update flags in PHY_CSR5 and PHY_CSR6 too */
tmp = ural_read(sc, RAL_PHY_CSR5) & ~0x7;
ural_write(sc, RAL_PHY_CSR5, tmp | (tx & 0x7));
tmp = ural_read(sc, RAL_PHY_CSR6) & ~0x7;
ural_write(sc, RAL_PHY_CSR6, tmp | (tx & 0x7));
}
Static void
ural_set_rxantenna(struct ural_softc *sc, int antenna)
{
uint8_t rx;
rx = ural_bbp_read(sc, RAL_BBP_RX) & ~RAL_BBP_ANTMASK;
if (antenna == 1)
rx |= RAL_BBP_ANTA;
else if (antenna == 2)
rx |= RAL_BBP_ANTB;
else
rx |= RAL_BBP_DIVERSITY;
/* need to force no I/Q flip for RF 2525e and 2526 */
if (sc->rf_rev == RAL_RF_2525E || sc->rf_rev == RAL_RF_2526)
rx &= ~RAL_BBP_FLIPIQ;
ural_bbp_write(sc, RAL_BBP_RX, rx);
}
Static int
ural_init(struct ifnet *ifp)
{
#define N(a) (sizeof (a) / sizeof ((a)[0]))
struct ural_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_wepkey *wk;
struct ural_rx_data *data;
uint16_t sta[11], tmp;
usbd_status error;
int i, ntries;
ural_stop(ifp, 0);
/* initialize MAC registers to default values */
for (i = 0; i < N(ural_def_mac); i++)
ural_write(sc, ural_def_mac[i].reg, ural_def_mac[i].val);
/* wait for BBP and RF to wake up (this can take a long time!) */
for (ntries = 0; ntries < 100; ntries++) {
tmp = ural_read(sc, RAL_MAC_CSR17);
if ((tmp & (RAL_BBP_AWAKE | RAL_RF_AWAKE)) ==
(RAL_BBP_AWAKE | RAL_RF_AWAKE))
break;
DELAY(1000);
}
if (ntries == 100) {
printf("%s: timeout waiting for BBP/RF to wakeup\n",
USBDEVNAME(sc->sc_dev));
error = EIO;
goto fail;
}
/* we're ready! */
ural_write(sc, RAL_MAC_CSR1, RAL_HOST_READY);
/* set supported basic rates (1, 2, 6, 12, 24) */
ural_write(sc, RAL_TXRX_CSR11, 0x153);
error = ural_bbp_init(sc);
if (error != 0)
goto fail;
/* set default BSS channel */
ic->ic_bss->ni_chan = ic->ic_ibss_chan;
ural_set_chan(sc, ic->ic_bss->ni_chan);
/* clear statistic registers (STA_CSR0 to STA_CSR10) */
ural_read_multi(sc, RAL_STA_CSR0, sta, sizeof sta);
ural_set_txantenna(sc, 1);
ural_set_rxantenna(sc, 1);
IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
ural_set_macaddr(sc, ic->ic_myaddr);
/*
* Copy WEP keys into adapter's memory (SEC_CSR0 to SEC_CSR31).
*/
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
wk = &ic->ic_nw_keys[i];
ural_write_multi(sc, RAL_SEC_CSR0 + i * IEEE80211_KEYBUF_SIZE,
wk->wk_key, IEEE80211_KEYBUF_SIZE);
}
/*
* Open Tx and Rx USB bulk pipes.
*/
error = usbd_open_pipe(sc->sc_iface, sc->sc_tx_no, USBD_EXCLUSIVE_USE,
&sc->sc_tx_pipeh);
if (error != 0) {
printf("%s: could not open Tx pipe: %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(error));
goto fail;
}
error = usbd_open_pipe(sc->sc_iface, sc->sc_rx_no, USBD_EXCLUSIVE_USE,
&sc->sc_rx_pipeh);
if (error != 0) {
printf("%s: could not open Rx pipe: %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(error));
goto fail;
}
/*
* Allocate Tx and Rx xfer queues.
*/
error = ural_alloc_tx_list(sc);
if (error != 0) {
printf("%s: could not allocate Tx list\n",
USBDEVNAME(sc->sc_dev));
goto fail;
}
error = ural_alloc_rx_list(sc);
if (error != 0) {
printf("%s: could not allocate Rx list\n",
USBDEVNAME(sc->sc_dev));
goto fail;
}
/*
* Start up the receive pipe.
*/
for (i = 0; i < RAL_RX_LIST_COUNT; i++) {
data = &sc->rx_data[i];
usbd_setup_xfer(data->xfer, sc->sc_rx_pipeh, data, data->buf,
MCLBYTES, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, ural_rxeof);
usbd_transfer(data->xfer);
}
/* kick Rx */
tmp = RAL_DROP_PHY_ERROR | RAL_DROP_CRC_ERROR;
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
tmp |= RAL_DROP_CTL | RAL_DROP_VERSION_ERROR;
if (ic->ic_opmode != IEEE80211_M_HOSTAP)
tmp |= RAL_DROP_TODS;
if (!(ifp->if_flags & IFF_PROMISC))
tmp |= RAL_DROP_NOT_TO_ME;
}
ural_write(sc, RAL_TXRX_CSR2, tmp);
ifp->if_flags &= ~IFF_OACTIVE;
ifp->if_flags |= IFF_RUNNING;
if (ic->ic_opmode == IEEE80211_M_MONITOR)
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
else
ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
return 0;
fail: ural_stop(ifp, 1);
return error;
#undef N
}
Static void
ural_stop(struct ifnet *ifp, int disable)
{
struct ural_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
/* disable Rx */
ural_write(sc, RAL_TXRX_CSR2, RAL_DISABLE_RX);
/* reset ASIC and BBP (but won't reset MAC registers!) */
ural_write(sc, RAL_MAC_CSR1, RAL_RESET_ASIC | RAL_RESET_BBP);
ural_write(sc, RAL_MAC_CSR1, 0);
ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
sc->sc_tx_timer = 0;
ifp->if_timer = 0;
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
if (sc->sc_rx_pipeh != NULL) {
usbd_abort_pipe(sc->sc_rx_pipeh);
usbd_close_pipe(sc->sc_rx_pipeh);
sc->sc_rx_pipeh = NULL;
}
if (sc->sc_tx_pipeh != NULL) {
usbd_abort_pipe(sc->sc_tx_pipeh);
usbd_close_pipe(sc->sc_tx_pipeh);
sc->sc_tx_pipeh = NULL;
}
ural_free_rx_list(sc);
ural_free_tx_list(sc);
}
int
ural_activate(device_ptr_t self, enum devact act)
{
switch (act) {
case DVACT_ACTIVATE:
return EOPNOTSUPP;
case DVACT_DEACTIVATE:
/*if_deactivate(&sc->sc_ic.ic_if);*/
break;
}
return 0;
}
--Boundary-00=_h13bC3MzttkCcJc
Content-Type: text/x-diff;
charset="us-ascii";
name="net80211.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="net80211.patch"
Index: ieee80211_output.c
===================================================================
RCS file: /cvsroot/src/sys/net80211/ieee80211_output.c,v
retrieving revision 1.28
diff -u -r1.28 ieee80211_output.c
--- ieee80211_output.c 26 Feb 2005 22:45:09 -0000 1.28
+++ ieee80211_output.c 27 Apr 2005 10:04:57 -0000
@@ -90,6 +90,10 @@
#endif
#endif
+#ifdef __NetBSD__
+ #define IEEE80211_F_WEPON IEEE80211_F_PRIVACY
+#endif /* __NetBSD__ */
+
#ifdef IEEE80211_DEBUG
/*
* Decide if an outbound management frame should be
@@ -816,6 +820,97 @@
#undef senderr
}
+struct mbuf *
+ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
+ struct ieee80211_frame *wh;
+ struct mbuf *m;
+ int pktlen;
+ u_int8_t *frm;
+ u_int16_t capinfo;
+ struct ieee80211_rateset *rs;
+
+ rs = &ni->ni_rates;
+ pktlen = sizeof (struct ieee80211_frame)
+ + 8 + 2 + 2 + 2+ni->ni_esslen + 2+rs->rs_nrates + 3 + 6;
+ if (rs->rs_nrates > IEEE80211_RATE_SIZE)
+ pktlen += 2;
+ m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
+ 2 + ic->ic_des_esslen
+ + 2 + IEEE80211_RATE_SIZE
+ + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
+ if (m == NULL)
+ return NULL;
+
+ wh = mtod(m, struct ieee80211_frame *);
+ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
+ IEEE80211_FC0_SUBTYPE_BEACON;
+ wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
+ *(u_int16_t *)wh->i_dur = 0;
+ IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
+ IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
+ IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
+ *(u_int16_t *)wh->i_seq = 0;
+
+ /*
+ * beacon frame format
+ * [8] time stamp
+ * [2] beacon interval
+ * [2] cabability information
+ * [tlv] ssid
+ * [tlv] supported rates
+ * [tlv] parameter set (IBSS)
+ * [tlv] extended supported rates
+ */
+ frm = (u_int8_t *)&wh[1];
+ bzero(frm, 8); /* timestamp is set by hardware */
+ frm += 8;
+ *(u_int16_t *)frm = htole16(ni->ni_intval);
+ frm += 2;
+ if (ic->ic_opmode == IEEE80211_M_IBSS) {
+ capinfo = IEEE80211_CAPINFO_IBSS;
+ } else {
+ capinfo = IEEE80211_CAPINFO_ESS;
+ }
+ if (ic->ic_flags & IEEE80211_F_WEPON)
+ capinfo |= IEEE80211_CAPINFO_PRIVACY;
+ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
+ IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
+ capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
+ if (ic->ic_flags & IEEE80211_F_SHSLOT)
+ capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
+ *(u_int16_t *)frm = htole16(capinfo);
+ frm += 2;
+ *frm++ = IEEE80211_ELEMID_SSID;
+ *frm++ = ni->ni_esslen;
+ memcpy(frm, ni->ni_essid, ni->ni_esslen);
+ frm += ni->ni_esslen;
+ frm = ieee80211_add_rates(frm, rs);
+ *frm++ = IEEE80211_ELEMID_DSPARMS;
+ *frm++ = 1;
+ *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
+ if (ic->ic_opmode == IEEE80211_M_IBSS) {
+ *frm++ = IEEE80211_ELEMID_IBSSPARMS;
+ *frm++ = 2;
+ *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */
+ } else {
+ /* TODO: TIM */
+ *frm++ = IEEE80211_ELEMID_TIM;
+ *frm++ = 4; /* length */
+ *frm++ = 0; /* DTIM count */
+ *frm++ = 1; /* DTIM period */
+ *frm++ = 0; /* bitmap control */
+ *frm++ = 0; /* Partial Virtual Bitmap (variable length) */
+ }
+ frm = ieee80211_add_xrates(frm, rs);
+ m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
+ m->m_pkthdr.rcvif = (void *)ni;
+ IASSERT(m->m_pkthdr.len <= pktlen,
+ ("beacon bigger than expected, len %u calculated %u",
+ m->m_pkthdr.len, pktlen));
+ return m;
+}
+
void
ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni,
struct mbuf *m)
Index: ieee80211_proto.h
===================================================================
RCS file: /cvsroot/src/sys/net80211/ieee80211_proto.h,v
retrieving revision 1.9
diff -u -r1.9 ieee80211_proto.h
--- ieee80211_proto.h 26 Feb 2005 22:45:09 -0000 1.9
+++ ieee80211_proto.h 27 Apr 2005 10:04:57 -0000
@@ -65,6 +65,8 @@
int, int);
extern struct mbuf *ieee80211_encap(struct ifnet *, struct mbuf *,
struct ieee80211_node **);
+extern struct mbuf *ieee80211_beacon_alloc(struct ieee80211com *,
+ struct ieee80211_node *);
extern void ieee80211_pwrsave(struct ieee80211com *, struct ieee80211_node *,
struct mbuf *);
extern struct mbuf *ieee80211_decap(struct ifnet *, struct mbuf *);
--Boundary-00=_h13bC3MzttkCcJc
Content-Type: text/x-diff;
charset="us-ascii";
name="usb.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="usb.patch"
Index: files.usb
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/files.usb,v
retrieving revision 1.60
diff -u -r1.60 files.usb
--- files.usb 15 Apr 2005 17:18:18 -0000 1.60
+++ files.usb 27 Apr 2005 10:05:53 -0000
@@ -247,3 +247,8 @@
device atu: ether, ifnet, arp, wlan
attach atu at uhub
file dev/usb/if_atu.c atu
+
+# Ralink Technology RT2500USB
+device ural: ether, ifnet, arp, wlan
+attach ural at uhub
+file dev/usb/if_ral.c ural
Index: usbdevs
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usbdevs,v
retrieving revision 1.398
diff -u -r1.398 usbdevs
--- usbdevs 15 Mar 2005 17:52:18 -0000 1.398
+++ usbdevs 27 Apr 2005 10:05:55 -0000
@@ -359,6 +359,7 @@
vendor NEODIO 0x0aec Neodio
vendor VODAFONE 0x0af0 Vodafone
vendor TODOS 0x0b0c Todos Data System
+vendor ASUS 0x0b05 ASUS
vendor SIIG2 0x0b39 SIIG
vendor TEKRAM 0x0b3b Tekram Technology
vendor HAL 0x0b41 HAL Corporation
@@ -401,8 +402,11 @@
vendor BELKIN2 0x1293 Belkin Components
vendor AINCOMM 0x12fd Aincomm
vendor MOBILITY 0x1342 Mobility
+vendor CISCOLINKSYS 0x13b1 Cisco-Linksys
vendor SHARK 0x13d2 Shark
vendor SILICOM 0x1485 Silicom
+vendor RALINK 0x148f Ralink Technology
+vendor CONCEPTRONIC2 0x14b2 Conceptronic
vendor SILICONPORTALS 0x1527 Silicon Portals
vendor OQO 0x1557 OQO
vendor SOHOWARE 0x15e8 SOHOware
@@ -582,6 +586,9 @@
/* ASIX Electronics products */
product ASIX AX88172 0x1720 USB 2.0 10/100 ethernet controller
+/* ASUS products */
+product ASUS RT2570 0x1707 RT2570
+
/* ATen products */
product ATEN UC1284 0x2001 Parallel printer adapter
product ATEN UC10T 0x2002 10Mbps ethernet adapter
@@ -690,6 +697,10 @@
product CHPRODUCTS FIGHTERSTICK 0x00f3 Fighterstick
product CHPRODUCTS FLIGHTYOKE 0x00ff Flight Sim Yoke
+/* Cisco-Linksys products */
+product CISCOLINKSYS WUSB54G 0x000d RT2570
+product CISCOLINKSYS WUSB54GP 0x0011 RT2570
+
/* Compaq products */
product COMPAQ IPAQPOCKETPC 0x0003 iPAQ PocketPC
product COMPAQ A1500 0x0012 A1500
@@ -702,6 +713,9 @@
/* Composite Corp products looks the same as "TANGTOP" */
product COMPOSITE USBPS2 0x0001 USB to PS2 Adaptor
+/* Conceptronic products */
+product CONCEPTRONIC2 C54RU 0x3c02 C54RU WLAN
+
/* Concord Camera products */
product CONCORDCAMERA EYE_Q_3X 0x0100 Eye Q 3x
@@ -769,6 +783,7 @@
product DLINK DUBE100 0x1a00 10/100 ethernet adapter
product DLINK DSB650TX4 0x200c 10/100 ethernet adapter
product DLINK DWL122 0x3700 Wireless DWL122
+product DLINK RT2570 0x3c00 RT2570
product DLINK DSB650C 0x4000 10Mbps ethernet adapter
product DLINK DSB650TX1 0x4001 10/100 ethernet adapter
product DLINK DSB650TX 0x4002 10/100 ethernet adapter
@@ -1228,6 +1243,7 @@
product MELCO KS11G 0x0027 WLI-USB-KS11G USB-wlan
product MELCO LUAU2KTX 0x003d LUA-U2-KTX Ethernet
product MELCO KB11 0x0044 WLI-USB-KB11 WLAN
+product MELCO KG54 0x0066 WLI-U2-KG54 WLAN
/* Metricom products */
product METRICOM RICOCHET_GS 0x0001 Ricochet GS
@@ -1524,6 +1540,10 @@
/* Rainbow Technologies products */
product RAINBOW IKEY2000 0x1200 i-Key 2000
+/* Ralink Technology products */
+product RALINK RT2570 0x1706 RT2570
+product RALINK RT2570_2 0x2570 RT2570
+
/* RATOC Systems products */
product RATOC REXUSB60 0xb000 USB serial REX-USB60
@@ -1657,6 +1677,7 @@
product SMC 2206USB 0x0201 EZ Connect USB Ethernet Adapter
product SMC2 2020HUB 0x2020 USB Hub
product SMC3 2662WUSB 0xa002 2662W-AR Wireless Adapter
+product SMC RT2570 0xee13 RT2570
/* SOHOware products */
product SOHOWARE NUB100 0x9100 10/100 USB Ethernet
--Boundary-00=_h13bC3MzttkCcJc
Content-Type: application/x-troff;
name="ral.4"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="ral.4"
.\" $OpenBSD: ral.4,v 1.24 2005/03/18 20:28:27 damien Exp $
.\"
.\" Copyright (c) 2005
.\" Damien Bergamini <damien.bergamini@free.fr>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd February 15, 2005
.Os
.Dt RAL 4
.Sh NAME
.Nm ral
.Nd Ralink Technology RT25x0 IEEE 802.11a/b/g wireless network driver
.Sh SYNOPSIS
.Cd "ral* at cardbus?"
.Cd "ral* at pci?"
.Cd "ural* at uhub? port ?"
.Sh DESCRIPTION
The
.Nm
driver supports PCI/CardBus wireless adapters based on the Ralink RT2500
chipset
and the
.Nm ural
driver supports USB 2.0 wireless adapters based on the Ralink RT2500USB
chipset.
The two drivers are similar and will be merged into one in the future.
.Pp
The RT2500 chipset consists of two integrated chips, a RT2560 or RT2570 MAC/BBP
and a radio transceiver (the model of which depends on the card revision).
.Pp
The RT2522, RT2523, RT2524, RT2525, RT2526 and RT2525e radio transceivers
operate in the 2.4GHz band (802.11b/g) whereas the RT5222 is a dual-band radio
transceiver that can operate in the 2.4GHz and 5.2GHz bands (802.11a).
.Pp
The transmit speed is user-selectable or can be adapted automatically by the
driver depending on the received-signal strength.
See
.Xr rssadapt 9
for more information.
.Pp
These are the modes the
.Nm
driver can operate in:
.Bl -tag -width "IBSS-masterXX"
.It BSS mode
Also known as
.Em infrastructure
mode, this is used when associating with an access point, through
which all traffic passes.
This mode is the default.
.It IBSS mode
Also known as
.Em IEEE ad-hoc
mode or
.Em peer-to-peer
mode.
This is the standardized method of operating without an access point.
Stations associate with a service set.
However, actual connections between stations are peer-to-peer.
.It Host AP
In this mode the driver acts as an access point (base station)
for other cards.
.It monitor mode
In this mode the driver is able to receive packets without
associating with an access point.
This disables the internal receive filter and enables the card to
capture packets from networks which it wouldn't normally have access to,
or to scan for access points.
.El
.Pp
.Nm
supports software WEP.
Wired Equivalent Privacy (WEP) is the de facto encryption standard
for wireless networks.
It can be typically configured in one of three modes:
no encryption; 40-bit encryption; or 104-bit encryption.
Unfortunately, due to serious weaknesses in WEP protocol
it is strongly recommended that it not be used as the
sole mechanism to secure wireless communication.
WEP is not enabled by default.
.Sh CONFIGURATION
The
.Nm
driver can be configured at runtime with
.Xr ifconfig 8
or on boot with
.Xr hostname.if 5
using the following parameters:
.Bl -tag -width Ds
.It Cm bssid Ar bssid
Set the desired BSSID.
.It Fl bssid
Unset the desired BSSID.
The interface will automatically select a BSSID in this mode, which is
the default.
.It Cm chan Ar n
Set the channel (radio frequency) to be used by the driver based on
the given channel ID
.Ar n .
.It Fl chan
Unset the desired channel to be used by the driver.
The driver will automatically select a channel in this mode, which is
the default.
.It Cm media Ar media
The
.Nm
driver supports the following
.Ar media
types:
.Pp
.Bl -tag -width autoselect -compact
.It Cm autoselect
Enable autoselection of the media type and options.
.It Cm DS1
Set 802.11b DS 1Mbps operation.
.It Cm DS2
Set 802.11b DS 2Mbps operation.
.It Cm DS5
Set 802.11b DS 5.5Mbps operation.
.It Cm DS11
Set 802.11b DS 11Mbps operation.
.It Cm OFDM6
Set 802.11a/g OFDM 6Mbps operation.
.It Cm OFDM9
Set 802.11a/g OFDM 9Mbps operation.
.It Cm OFDM12
Set 802.11a/g OFDM 12Mbps operation.
.It Cm OFDM18
Set 802.11a/g OFDM 18Mbps operation.
.It Cm OFDM24
Set 802.11a/g OFDM 24Mbps operation.
.It Cm OFDM36
Set 802.11a/g OFDM 36Mbps operation.
.It Cm OFDM48
Set 802.11a/g OFDM 48Mbps operation.
.It Cm OFDM54
Set 802.11a/g OFDM 54Mbps operation.
.El
.It Cm mediaopt Ar opts
The
.Nm
driver supports the following media options:
.Pp
.Bl -tag -width monitor -compact
.It Cm hostap
Select Host AP operation.
.It Cm ibss
Select IBSS operation.
.It Cm monitor
Select monitor mode.
.El
.It Fl mediaopt Ar opts
Disable the specified media options on the driver and returns it to the
default mode of operation (BSS).
.It Cm mode Ar mode
The
.Nm
driver supports the following modes:
.Pp
.Bl -tag -width 11b -compact
.It Cm 11a
Force 802.11a operation (RT5222 only).
.It Cm 11b
Force 802.11b operation.
.It Cm 11g
Force 802.11g operation.
.El
.It Cm nwid Ar id
Set the network ID.
The
.Ar id
can either be any text string up to 32 characters in length,
or a series of hexadecimal digits up to 64 digits.
An empty
.Ar id
string allows the interface to connect to any available access points.
By default the
.Nm
driver uses an empty string.
.It Cm nwkey Ar key
Enable WEP encryption using the specified
.Ar key .
The
.Ar key
can either be a string, a series of hexadecimal digits (preceded by
.Sq 0x ) ,
or a set of keys of the form
.Dq n:k1,k2,k3,k4 ,
where
.Sq n
specifies which of the keys will be used for transmitted packets,
and the four keys,
.Dq k1
through
.Dq k4 ,
are configured as WEP keys.
If a set of keys is specified, a comma
.Pq Sq \&,
within the key must be escaped with a backslash.
Note that if multiple keys are used, their order must be the same within
the network.
.Nm
is capable of using both 40-bit (5 characters or 10 hexadecimal digits)
or 104-bit (13 characters or 26 hexadecimal digits) keys.
.It Fl nwkey
Disable WEP encryption.
This is the default mode of operation.
.El
.Sh HARDWARE
The following PCI adapters should work:
.Bd -filled
A-Link WL54H.
Amigo AWI-926W.
AMIT WL531P.
AOpen AOI-831.
ASUS WL-130g.
ASUS WIFI-G-AAY.
Atlantis Land A02-PCI-W54.
Belkin F5D7000 v3.
Canyon CN-WF511.
CNet CWP-854.
Compex WLP54G.
Conceptronic C54Ri.
Digitus DN-7006G-RA.
E-Tech WGPI02.
Edimax EW-7128g.
Eminent EM3037.
Encore ENLWI-G-RLAM.
Fiberline WL-400P.
Gigabyte GN-WPKG.
Hawking HWP54GR.
iNexQ CR054g-009 (R03).
JAHT WN-4054PCI.
LevelOne WNC-0301 v2.
Linksys WMP54G v4.
Micronet SP906GK.
Minitar MN54GPC-R.
MSI PC54G2.
OvisLink EVO-W54PCI.
PheeNet HWL-PCIG/RA.
Pro-Nets PC80211G.
Repotec RP-WP0854.
SATech SN-54P.
Sitecom WL-115.
Surecom EP-9321-g.
Surecom EP-9321-g1.
Sweex LC700030.
TekComm NE-9321-g.
Unex CR054g-R02.
Zinwell ZWX-G361.
Zonet ZEW1600.
.Ed
.Pp
The following CardBus adapters should work:
.Bd -filled
A-Link WL54PC.
Amigo AWI-914W.
AMIT WL531C.
ASUS WL-107G.
Atlantis Land A02-PCM-W54.
Belkin F5D7010 v2.
Canyon CN-WF513.
CC&C WL-2102.
CNet CWC-854.
Compex WL54G.
Conceptronic C54RC.
Digitus DN-7001G-RA.
E-Tech WGPC02.
Edimax EW-7108PCg.
Eminent EM3036.
Encore ENPWI-G-RLAM.
Fibreline WL-400X.
Gigabyte GN-WMKG.
Hawking HWC54GR.
JAHT WN-4054P.
LevelOne WPC-0301 v2.
Micronet SP908GK V3.
Minitar MN54GCB-R.
MSI CB54G2.
Pro-Nets CB80211G.
Repotec RP-WB7108.
SATech SN-54C.
Sitecom WL-112.
SparkLAN WL-685R.
Surecom EP-9428-g.
Sweex LC500050.
TekComm NE-9428-g.
Unex MR054g-R02.
Zinwell ZWX-G160.
Zonet ZEW1500.
.Ed
.Pp
The following Mini PCI adapters should work:
.Bd -filled
Amigo AWI-922W.
Billionton MIWLGRL.
Gigabyte GN-WIKG.
MSI MP54G2.
Zinwell ZWX-G360.
.Ed
.Pp
The following USB 2.0 adapters should work:
.Bd -filled
AMIT WL532U.
ASUS WL-167g.
Buffalo WLI-U2-KG54-AI.
CNet CWD-854.
Compex WLU54G.
Conceptronic C54RU.
D-Link DWL-G122 (b1).
E-Tech WGUS02.
Gigabyte GN-WBKG.
Linksys WUSB54G v4.
Linksys WUSB54GP v4.
MSI MS-6861.
MSI MS-6865.
MSI MS-6869.
Repotec RP-WU0402.
Surecom EP-9001-g.
Zinwell ZWX-G261.
.Ed
.Sh EXAMPLES
The following
.Xr hostname.if 5
example configures ral0 to join whatever network is available on boot,
using WEP key
.Dq 0x1deadbeef1 ,
channel 11, obtaining an IP address using DHCP:
.Bd -literal -offset indent
dhcp NONE NONE NONE nwkey 0x1deadbeef1 chan 11
.Ed
.Pp
Configure ral0 for WEP, using hex key
.Dq 0x1deadbeef1 :
.Bd -literal -offset indent
# ifconfig ral0 nwkey 0x1deadbeef1
.Ed
.Pp
Return ral0 to its default settings:
.Bd -literal -offset indent
# ifconfig ral0 -bssid -chan media autoselect -mediaopt \e
nwid "" -nwkey
.Ed
.Pp
Join an existing BSS network,
.Dq my_net :
.Bd -literal -offset indent
# ifconfig ral0 192.168.1.1 netmask 0xffffff00 nwid my_net
.Ed
.Sh DIAGNOSTICS
.Bl -diag
.It "ral%d: device timeout"
The driver will reset the hardware.
This should not happen.
.El
.Sh SEE ALSO
.Xr arp 4 ,
.Xr cardbus 4 ,
.Xr ifmedia 4 ,
.Xr intro 4 ,
.Xr netintro 4 ,
.Xr pci 4 ,
.Xr hostname.if 5 ,
.Xr ifconfig 8
.Rs
.%T Ralink Technology
.%O http://www.ralinktech.com
.Re
.Sh HISTORY
The
.Nm
driver first appeared in
.Ox 3.7 .
.Sh AUTHORS
The
.Nm
driver was written by
.An Damien Bergamini Aq damien@openbsd.org .
.Sh CAVEATS
PCI
.Nm
adapters seem to strictly require a system supporting PCI 2.2 or greater and
will likely not work in systems based on older revisions of the PCI
specification.
.Pp
The
.Nm ural
driver does not support automatic adaptation of the transmit speed.
--Boundary-00=_h13bC3MzttkCcJc--