Fix bugs in the structure for rx_frame by making gap length one byte and

a packed array so sizeof work.  This broke RFMON mode and passing
up 802.11 packets.

The Linux emulation code was derived from the open source Linux driver to
maintain compatibility.

LEAP support is added, hints from Richard Johnson.  I've verified this
locally with PC350v42510.img firmware.  More bug fixing from Marco to
fix long passwords.

Change DELAYs in flash part of driver to FLASH_DELAY which uses tsleep
so it doesn't look like your system died during a flash update.

Install header files in /usr/include/dev/an

Cleanup some ifmedia bugs add "Home" key mode to ifmedia and ancontrol.
This way you can manage 2 keys a little easier.  Map the home mode into
key 5.  Enhance ifconfig to dump the various configured SSIDs.  I use
a bunch of different ones and roam between them.  Use the syntax similar
to the WEP keys to deal with setting difference SSIDs.

Bump up up the Card capabilities RID since they added 2 bytes to it
in the latest firmware.  Thankfully we changed it from a terminal
failure so the card still worked but the driver whined.

Some cleanup patches from Marco Molteni.

Submitted by:	Richard Johnson <raj@cisco.com>
		Marco Molteni <molter@tin.it>
		and myself
Various checks: David Wolfskill <david@catwhisker.org>
Reviewed by:	Brooks Davis <brooks@freebsd.org>
		Warner Losh <imp@freebsd.org>
Approved by:	Brooks Davis <brooks@freebsd.org>
		Warner Losh <imp@freebsd.org>
Obtained from:	Linux emulation API's from Aironet driver.
This commit is contained in:
ambrisko 2001-12-31 22:01:44 +00:00
parent c773675908
commit 71e0b3af6a
9 changed files with 915 additions and 54 deletions

View File

@ -12,6 +12,8 @@
..
..
dev
an
..
ic
..
ppbus

View File

@ -45,7 +45,7 @@ LDIRS= cam net netatalk netatm netgraph netinet netinet6 \
LNOHEADERDIRS= fs isofs ufs dev
LSUBDIRS= cam/scsi dev/ic dev/ppbus dev/usb dev/wi fs/devfs \
LSUBDIRS= cam/scsi dev/ic dev/ppbus dev/usb dev/wi dev/an fs/devfs \
fs/fdescfs fs/fifofs fs/msdosfs fs/ntfs fs/nullfs fs/nwfs fs/portalfs \
fs/procfs fs/smbfs fs/umapfs fs/unionfs isofs/cd9660 \
ufs/ffs ufs/ufs

View File

@ -99,6 +99,11 @@ set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
u_int8_t data[33];
ssid = 0;
len = sizeof(val);
if (len > 2 && isdigit(val[0]) && val[1] == ':') {
ssid = atoi(val)-1;
val += 2;
}
bzero(data, sizeof(data));
len = sizeof(data);
@ -296,6 +301,18 @@ ieee80211_status (s, info)
}
printf("\tssid ");
print_string(data, ireq.i_len);
num = 0;
ireq.i_type = IEEE80211_IOC_NUMSSIDS;
if (ioctl(s, SIOCG80211, &ireq) >= 0) {
num = ireq.i_val;
}
ireq.i_type = IEEE80211_IOC_SSID;
for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
printf(" %d:", ireq.i_val + 1);
print_string(data, ireq.i_len);
}
}
printf("\n");
ireq.i_type = IEEE80211_IOC_STATIONNAME;

View File

@ -355,6 +355,7 @@ struct an_ltv_genconfig {
#define AN_AUTHTYPE_ENABLE 0x0100
#define AN_AUTHTYPE_PRIVACY_IN_USE 0x0100
#define AN_AUTHTYPE_ALLOW_UNENCRYPTED 0x0200
#define AN_AUTHTYPE_LEAP 0x1000
#define AN_PSAVE_NONE 0x0000
#define AN_PSAVE_CAM 0x0001
@ -480,6 +481,7 @@ struct an_ltv_caps {
u_int16_t an_softcaps; /* 0x7C */
u_int16_t an_bootblockrev; /* 0x7E */
u_int16_t an_req_hw_support; /* 0x80 */
u_int16_t an_unknown; /* 0x82 */
};
/*
@ -553,6 +555,7 @@ struct an_ltv_status {
#define AN_STATUS_OPMODE_RX_ENABLED 0x0004
#define AN_STATUS_OPMODE_IN_SYNC 0x0010
#define AN_STATUS_OPMODE_ASSOCIATED 0x0020
#define AN_STATUS_OPMODE_LEAP 0x0040
#define AN_STATUS_OPMODE_ERROR 0x8000
/*
@ -567,6 +570,55 @@ struct an_ltv_wepkey {
u_int8_t an_key[13]; /* 0x0C */
};
/*
* Receive frame structure.
*/
struct an_rxframe {
u_int32_t an_rx_time; /* 0x00 */
u_int16_t an_rx_status; /* 0x04 */
u_int16_t an_rx_payload_len; /* 0x06 */
u_int8_t an_rsvd0; /* 0x08 */
u_int8_t an_rx_signal_strength; /* 0x09 */
u_int8_t an_rx_rate; /* 0x0A */
u_int8_t an_rx_chan; /* 0x0B */
u_int8_t an_rx_assoc_cnt; /* 0x0C */
u_int8_t an_rsvd1[3]; /* 0x0D */
u_int8_t an_plcp_hdr[4]; /* 0x10 */
u_int16_t an_frame_ctl; /* 0x14 */
u_int16_t an_duration; /* 0x16 */
u_int8_t an_addr1[6]; /* 0x18 */
u_int8_t an_addr2[6]; /* 0x1E */
u_int8_t an_addr3[6]; /* 0x24 */
u_int16_t an_seq_ctl; /* 0x2A */
u_int8_t an_addr4[6]; /* 0x2C */
u_int8_t an_gaplen; /* 0x32 */
} __attribute__((packed));
/* Do not modify this unless you are modifying LEAP itself */
#define LEAP_USERNAME_MAX 32
#define LEAP_PASSWORD_MAX 32
/*
* LEAP Username
*/
struct an_ltv_leap_username {
u_int16_t an_len; /* 0x00 */
u_int16_t an_type; /* 0xXX */
u_int16_t an_username_len; /* 0x02 */
u_int8_t an_username[LEAP_USERNAME_MAX]; /* 0x04 */
};
/*
* LEAP Password
*/
struct an_ltv_leap_password {
u_int16_t an_len; /* 0x00 */
u_int16_t an_type; /* 0xXX */
u_int16_t an_password_len; /* 0x02 */
u_int8_t an_password[LEAP_PASSWORD_MAX]; /* 0x04 */
};
/*
* These are all the LTV record types that we can read or write
* from the Aironet. Not all of them are temendously useful, but I
@ -624,12 +676,76 @@ struct an_ltv_wepkey {
/*
* FreeBSD fake RID
*/
#define AN_RID_MONITOR_MODE 0x0001 /* Set monitor mode for driver */
#define AN_MONITOR 1
#define AN_MONITOR_ANY_BSS 2
#define AN_MONITOR_INCLUDE_BEACON 4
#define AN_MONITOR_AIRONET_HEADER 8
#define DLT_AIRONET_HEADER 120 /* Just something for now */
#define DLT_AIRONET_HEADER 120 /* Has been allocated at tcpdump.org */
/*
* from the Linux driver from Cisco ... no copyright header.
* Removed duplicated information that already existed in the FreeBSD driver
* provides emulation of the Cisco extensions to the Linux Aironet driver.
*/
/*
* Ioctl constants to be used in airo_ioctl.command
*/
#define AIROGCAP 0 /* Capability rid */
#define AIROGCFG 1 /* USED A LOT */
#define AIROGSLIST 2 /* System ID list */
#define AIROGVLIST 3 /* List of specified AP's */
#define AIROGDRVNAM 4 /* NOTUSED */
#define AIROGEHTENC 5 /* NOTUSED */
#define AIROGWEPKTMP 6
#define AIROGWEPKNV 7
#define AIROGSTAT 8
#define AIROGSTATSC32 9
#define AIROGSTATSD32 10
/*
* Leave gap of 40 commands after AIROGSTATSD32
*/
#define AIROPCAP AIROGSTATSD32 + 40
#define AIROPVLIST AIROPCAP + 1
#define AIROPSLIST AIROPVLIST + 1
#define AIROPCFG AIROPSLIST + 1
#define AIROPSIDS AIROPCFG + 1
#define AIROPAPLIST AIROPSIDS + 1
#define AIROPMACON AIROPAPLIST + 1 /* Enable mac */
#define AIROPMACOFF AIROPMACON + 1 /* Disable mac */
#define AIROPSTCLR AIROPMACOFF + 1
#define AIROPWEPKEY AIROPSTCLR + 1
#define AIROPWEPKEYNV AIROPWEPKEY + 1
#define AIROPLEAPPWD AIROPWEPKEYNV + 1
#define AIROPLEAPUSR AIROPLEAPPWD + 1
/*
* Another gap of 40 commands before flash codes
*/
#define AIROFLSHRST AIROPWEPKEYNV + 40
#define AIROFLSHGCHR AIROFLSHRST + 1
#define AIROFLSHSTFL AIROFLSHGCHR + 1
#define AIROFLSHPCHR AIROFLSHSTFL + 1
#define AIROFLPUTBUF AIROFLSHPCHR + 1
#define AIRORESTART AIROFLPUTBUF + 1
/*
* Struct to enable up to 65535 ioctl's
*/
#define AIROMAGIC 0xa55a
typedef struct aironet_ioctl {
unsigned short command; /* What to do */
unsigned short len; /* Len of data */
unsigned char *data; /* d-data */
} airo_ioctl;
#endif

View File

@ -162,6 +162,23 @@ static void an_cache_store __P((struct an_softc *, struct ether_header *,
struct mbuf *, unsigned short));
#endif
/* function definitions for use with the Cisco's Linux configuration
utilities
*/
static int readrids __P((struct ifnet*, struct aironet_ioctl*));
static int writerids __P((struct ifnet*, struct aironet_ioctl*));
static int flashcard __P((struct ifnet*, struct aironet_ioctl*));
static int cmdreset __P((struct ifnet *));
static int setflashmode __P((struct ifnet *));
static int flashgchar __P((struct ifnet *,int,int));
static int flashpchar __P((struct ifnet *,int,int));
static int flashputbuf __P((struct ifnet *));
static int flashrestart __P((struct ifnet *));
static int WaitBusy __P((struct ifnet *, int));
static int unstickbusy __P((struct ifnet *));
static void an_dump_record __P((struct an_softc *,struct an_ltv_gen *,
char *));
@ -169,6 +186,7 @@ static int an_media_change __P((struct ifnet *));
static void an_media_status __P((struct ifnet *, struct ifmediareq *));
static int an_dump = 0;
static char an_conf[256];
/* sysctl vars */
@ -592,7 +610,7 @@ an_rxeof(sc)
return;
}
m->m_pkthdr.rcvif = ifp;
/* Read Ethenet encapsulated packet */
/* Read Ethernet encapsulated packet */
#ifdef ANCACHE
/* Read NIC frame header */
@ -1171,6 +1189,8 @@ an_setdef(sc, areq)
break;
case AN_RID_WEP_TEMP:
case AN_RID_WEP_PERM:
case AN_RID_LEAPUSERNAME:
case AN_RID_LEAPPASSWORD:
/* Disable the MAC. */
an_cmd(sc, AN_CMD_DISABLE, 0);
@ -1257,6 +1277,8 @@ an_ioctl(ifp, command, data)
struct an_ltv_key *key;
struct an_ltv_status *status;
struct an_ltv_ssidlist *ssids;
int mode;
struct aironet_ioctl l_ioctl;
sc = ifp->if_softc;
AN_LOCK(sc);
@ -1341,8 +1363,34 @@ an_ioctl(ifp, command, data)
break;
an_setdef(sc, &areq);
break;
case SIOCGPRIVATE_0: /* used by Cisco client utility */
copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl));
mode = l_ioctl.command;
if (mode >= AIROGCAP && mode <= AIROGSTATSD32) {
error = readrids(ifp, &l_ioctl);
}else if (mode >= AIROPCAP && mode <= AIROPLEAPUSR) {
error = writerids(ifp, &l_ioctl);
}else if (mode >= AIROFLSHRST && mode <= AIRORESTART) {
error = flashcard(ifp, &l_ioctl);
}else{
error =-1;
}
/* copy out the updated command info */
copyout(&l_ioctl, ifr->ifr_data, sizeof(l_ioctl));
break;
case SIOCGPRIVATE_1: /* used by Cisco client utility */
copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl));
l_ioctl.command = 0;
error = AIROMAGIC;
copyout(&error, l_ioctl.data, sizeof(error));
error = 0;
break;
case SIOCG80211:
areq.an_len = sizeof(areq);
/* was that a good idea DJA we are doing a short-cut */
switch (ireq->i_type) {
case IEEE80211_IOC_SSID:
if (ireq->i_val == -1) {
@ -1366,8 +1414,8 @@ an_ioctl(ifp, command, data)
tmpptr = ssids->an_ssid1;
} else if (ireq->i_val == 1) {
len = ssids->an_ssid2_len;
tmpptr = ssids->an_ssid3;
} else if (ireq->i_val == 1) {
tmpptr = ssids->an_ssid2;
} else if (ireq->i_val == 2) {
len = ssids->an_ssid3_len;
tmpptr = ssids->an_ssid3;
} else {
@ -1415,12 +1463,12 @@ an_ioctl(ifp, command, data)
* ancontrol so it will have to do until we get
* access to actual Cisco code.
*/
if (ireq->i_val < 0 || ireq->i_val > 7) {
if (ireq->i_val < 0 || ireq->i_val > 8) {
error = EINVAL;
break;
}
len = 0;
if (ireq->i_val < 4) {
if (ireq->i_val < 5) {
areq.an_type = AN_RID_WEP_TEMP;
for (i = 0; i < 5; i++) {
if (an_read_record(sc,
@ -1448,7 +1496,7 @@ an_ioctl(ifp, command, data)
error = copyout(tmpstr, ireq->i_data, len);
break;
case IEEE80211_IOC_NUMWEPKEYS:
ireq->i_val = 8;
ireq->i_val = 9; /* include home key */
break;
case IEEE80211_IOC_WEPTXKEY:
/*
@ -1458,7 +1506,7 @@ an_ioctl(ifp, command, data)
areq.an_type = AN_RID_WEP_TEMP;
for (i = 0; i < 5; i++) {
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
(struct an_ltv_gen *) &areq)) {
error = EINVAL;
break;
}
@ -1478,6 +1526,20 @@ an_ioctl(ifp, command, data)
break;
}
ireq->i_val = key->mac[0];
/*
* Check for home mode. Map home mode into
* 5th key since that is how it is stored on
* the card
*/
areq.an_len = sizeof(struct an_ltv_genconfig);
areq.an_type = AN_RID_GENCONFIG;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
if (config->an_home_product & AN_HOME_NETWORK)
ireq->i_val = 4;
break;
case IEEE80211_IOC_AUTHMODE:
areq.an_type = AN_RID_ACTUALCFG;
@ -1646,10 +1708,33 @@ an_ioctl(ifp, command, data)
bcopy(tmpstr, key->key, key->klen);
break;
case IEEE80211_IOC_WEPTXKEY:
if (ireq->i_val < 0 || ireq->i_val > 3) {
/*
* Map the 5th key into the home mode
* since that is how it is stored on
* the card
*/
if (ireq->i_val < 0 || ireq->i_val > 4) {
error = EINVAL;
break;
}
areq.an_len = sizeof(struct an_ltv_genconfig);
areq.an_type = AN_RID_ACTUALCFG;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
if (ireq->i_val == 4) {
config->an_home_product |= AN_HOME_NETWORK;
ireq->i_val = 0;
} else {
config->an_home_product &= ~AN_HOME_NETWORK;
}
sc->an_config.an_home_product
= config->an_home_product;
an_write_record(sc, (struct an_ltv_gen *)&areq);
bzero(&areq, sizeof(struct an_ltv_key));
areq.an_len = sizeof(struct an_ltv_key);
areq.an_type = AN_RID_WEP_PERM;
@ -2034,7 +2119,7 @@ an_shutdown(dev)
* a small fixed cache. The cache wraps if > MAX slots
* used. The cache may be zeroed out to start over.
* Two simple filters exist to reduce computation:
* 1. ip only (literally 0x800) which may be used
* 1. ip only (literally 0x800, ETHERTYPE_IP) which may be used
* to ignore some packets. It defaults to ip only.
* it could be used to focus on broadcast, non-IP 802.11 beacons.
* 2. multicast/broadcast only. This may be used to
@ -2099,7 +2184,7 @@ an_cache_store (sc, eh, m, rx_quality)
int i;
static int cache_slot = 0; /* use this cache entry */
static int wrapindex = 0; /* next "free" cache entry */
int saanp = 0;
int type_ipv4 = 0;
/* filters:
* 1. ip only
@ -2107,13 +2192,13 @@ an_cache_store (sc, eh, m, rx_quality)
* keep multicast only.
*/
if ((ntohs(eh->ether_type) == 0x800)) {
saanp = 1;
if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) {
type_ipv4 = 1;
}
/* filter for ip packets only
*/
if ( an_cache_iponly && !saanp) {
if ( an_cache_iponly && !type_ipv4) {
return;
}
@ -2131,7 +2216,7 @@ an_cache_store (sc, eh, m, rx_quality)
/* find the ip header. we want to store the ip_src
* address.
*/
if (saanp) {
if (type_ipv4) {
ip = mtod(m, struct ip *);
}
@ -2197,7 +2282,7 @@ an_cache_store (sc, eh, m, rx_quality)
* .mac src
* .signal, etc.
*/
if (saanp) {
if (type_ipv4) {
sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr;
}
bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc, 6);
@ -2290,3 +2375,505 @@ an_media_status(ifp, imr)
else if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED)
imr->ifm_status |= IFM_ACTIVE;
}
/********************** Cisco utility support routines *************/
/*
* ReadRids & WriteRids derived from Cisco driver additions to Ben Reed's
* Linux driver
*/
static int
readrids(ifp, l_ioctl)
struct ifnet *ifp;
struct aironet_ioctl *l_ioctl;
{
unsigned short rid;
struct an_softc *sc;
struct an_req areq;
switch (l_ioctl->command) {
case AIROGCAP:
rid = AN_RID_CAPABILITIES;
break;
case AIROGCFG:
rid = AN_RID_GENCONFIG;
break;
case AIROGSLIST:
rid = AN_RID_SSIDLIST;
break;
case AIROGVLIST:
rid = AN_RID_APLIST;
break;
case AIROGDRVNAM:
rid = AN_RID_DRVNAME;
break;
case AIROGEHTENC:
rid = AN_RID_ENCAPPROTO;
break;
case AIROGWEPKTMP:
rid = AN_RID_WEP_TEMP;
break;
case AIROGWEPKNV:
rid = AN_RID_WEP_PERM;
break;
case AIROGSTAT:
rid = AN_RID_STATUS;
break;
case AIROGSTATSD32:
rid = AN_RID_32BITS_DELTA;
break;
case AIROGSTATSC32:
rid = AN_RID_32BITS_CUM;
break;
default:
rid = 999;
break;
}
if (rid == 999) /* Is bad command */
return -EINVAL;
sc = ifp->if_softc;
areq.an_len = AN_MAX_DATALEN;
areq.an_type = rid;
an_read_record(sc, (struct an_ltv_gen *)&areq);
l_ioctl->len = areq.an_len - 4; /* just data */
/* the data contains the length at first */
if (copyout(&(areq.an_len), l_ioctl->data,
sizeof(areq.an_len))) {
return -EFAULT;
}
/* Just copy the data back */
if (copyout(&(areq.an_val), l_ioctl->data + 2,
l_ioctl->len)) {
return -EFAULT;
}
return 0;
}
static int
writerids(ifp, l_ioctl)
struct ifnet *ifp;
struct aironet_ioctl *l_ioctl;
{
struct an_softc *sc;
struct an_req areq;
int rid, command;
sc = ifp->if_softc;
rid = 0;
command = l_ioctl->command;
switch (command) {
case AIROPSIDS:
rid = AN_RID_SSIDLIST;
break;
case AIROPCAP:
rid = AN_RID_CAPABILITIES;
break;
case AIROPAPLIST:
rid = AN_RID_APLIST;
break;
case AIROPCFG:
rid = AN_RID_GENCONFIG;
break;
case AIROPMACON:
an_cmd(sc, AN_CMD_ENABLE, 0);
return 0;
break;
case AIROPMACOFF:
an_cmd(sc, AN_CMD_DISABLE, 0);
return 0;
break;
case AIROPSTCLR:
/*
* This command merely clears the counts does not actually
* store any data only reads rid. But as it changes the cards
* state, I put it in the writerid routines.
*/
rid = AN_RID_32BITS_DELTACLR;
sc = ifp->if_softc;
areq.an_len = AN_MAX_DATALEN;
areq.an_type = rid;
an_read_record(sc, (struct an_ltv_gen *)&areq);
l_ioctl->len = areq.an_len - 4; /* just data */
/* the data contains the length at first */
if (copyout(&(areq.an_len), l_ioctl->data,
sizeof(areq.an_len))) {
return -EFAULT;
}
/* Just copy the data */
if (copyout(&(areq.an_val), l_ioctl->data + 2,
l_ioctl->len)) {
return -EFAULT;
}
return 0;
break;
case AIROPWEPKEY:
rid = AN_RID_WEP_TEMP;
break;
case AIROPWEPKEYNV:
rid = AN_RID_WEP_PERM;
break;
case AIROPLEAPUSR:
rid = AN_RID_LEAPUSERNAME;
break;
case AIROPLEAPPWD:
rid = AN_RID_LEAPPASSWORD;
break;
default:
return -EOPNOTSUPP;
}
if (rid) {
if (l_ioctl->len > sizeof(areq.an_val) + 4)
return -EINVAL;
areq.an_len = l_ioctl->len + 4; /* add type & length */
areq.an_type = rid;
/* Just copy the data back */
copyin((l_ioctl->data) + 2, &areq.an_val,
l_ioctl->len);
an_cmd(sc, AN_CMD_DISABLE, 0);
an_write_record(sc, (struct an_ltv_gen *)&areq);
an_cmd(sc, AN_CMD_ENABLE, 0);
return 0;
}
return -EOPNOTSUPP;
}
/*
* General Flash utilities derived from Cisco driver additions to Ben Reed's
* Linux driver
*/
#define FLASH_DELAY(x) tsleep(ifp, PZERO, "flash", ((x) / hz) + 1);
static int
unstickbusy(ifp)
struct ifnet *ifp;
{
struct an_softc *sc = ifp->if_softc;
if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) {
CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
return 1;
}
return 0;
}
/*
* Wait for busy completion from card wait for delay uSec's Return true for
* success meaning command reg is clear
*/
static int
WaitBusy(ifp, uSec)
struct ifnet *ifp;
int uSec;
{
int statword = 0xffff;
int delay = 0;
struct an_softc *sc = ifp->if_softc;
while ((statword & AN_CMD_BUSY) && delay <= (1000 * 100)) {
FLASH_DELAY(10);
delay += 10;
statword = CSR_READ_2(sc, AN_COMMAND);
if ((AN_CMD_BUSY & statword) && (delay % 200)) {
unstickbusy(ifp);
}
}
return 0 == (AN_CMD_BUSY & statword);
}
/*
* STEP 1) Disable MAC and do soft reset on card.
*/
static int
cmdreset(ifp)
struct ifnet *ifp;
{
int status;
struct an_softc *sc = ifp->if_softc;
an_stop(sc);
an_cmd(sc, AN_CMD_DISABLE, 0);
if (!(status = WaitBusy(ifp, 600))) {
printf("an%d: Waitbusy hang b4 RESET =%d\n",
sc->an_unit, status);
return -EBUSY;
}
CSR_WRITE_2(sc, AN_COMMAND, AN_CMD_FW_RESTART);
FLASH_DELAY(1000); /* WAS 600 12/7/00 */
if (!(status = WaitBusy(ifp, 100))) {
printf("an%d: Waitbusy hang AFTER RESET =%d\n",
sc->an_unit, status);
return -EBUSY;
}
return 0;
}
/*
* STEP 2) Put the card in legendary flash mode
*/
#define FLASH_COMMAND 0x7e7e
static int
setflashmode(ifp)
struct ifnet *ifp;
{
int status;
struct an_softc *sc = ifp->if_softc;
CSR_WRITE_2(sc, AN_SW0, FLASH_COMMAND);
CSR_WRITE_2(sc, AN_SW1, FLASH_COMMAND);
CSR_WRITE_2(sc, AN_SW0, FLASH_COMMAND);
CSR_WRITE_2(sc, AN_COMMAND, FLASH_COMMAND);
/*
* mdelay(500); // 500ms delay
*/
FLASH_DELAY(500);
if (!(status = WaitBusy(ifp, 600))) {
printf("Waitbusy hang after setflash mode\n");
return -EIO;
}
return 0;
}
/*
* Get a character from the card matching matchbyte Step 3)
*/
static int
flashgchar(ifp, matchbyte, dwelltime)
struct ifnet *ifp;
int matchbyte;
int dwelltime;
{
int rchar;
unsigned char rbyte = 0;
int success = -1;
struct an_softc *sc = ifp->if_softc;
do {
rchar = CSR_READ_2(sc, AN_SW1);
if (dwelltime && !(0x8000 & rchar)) {
dwelltime -= 10;
FLASH_DELAY(10);
continue;
}
rbyte = 0xff & rchar;
if ((rbyte == matchbyte) && (0x8000 & rchar)) {
CSR_WRITE_2(sc, AN_SW1, 0);
success = 1;
break;
}
if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
break;
CSR_WRITE_2(sc, AN_SW1, 0);
} while (dwelltime > 0);
return success;
}
/*
* Put character to SWS0 wait for dwelltime x 50us for echo .
*/
static int
flashpchar(ifp, byte, dwelltime)
struct ifnet *ifp;
int byte;
int dwelltime;
{
int echo;
int pollbusy, waittime;
struct an_softc *sc = ifp->if_softc;
byte |= 0x8000;
if (dwelltime == 0)
dwelltime = 200;
waittime = dwelltime;
/*
* Wait for busy bit d15 to go false indicating buffer empty
*/
do {
pollbusy = CSR_READ_2(sc, AN_SW0);
if (pollbusy & 0x8000) {
FLASH_DELAY(50);
waittime -= 50;
continue;
} else
break;
}
while (waittime >= 0);
/* timeout for busy clear wait */
if (waittime <= 0) {
printf("an%d: flash putchar busywait timeout! \n",
sc->an_unit);
return -1;
}
/*
* Port is clear now write byte and wait for it to echo back
*/
do {
CSR_WRITE_2(sc, AN_SW0, byte);
FLASH_DELAY(50);
dwelltime -= 50;
echo = CSR_READ_2(sc, AN_SW1);
} while (dwelltime >= 0 && echo != byte);
CSR_WRITE_2(sc, AN_SW1, 0);
return echo == byte;
}
/*
* Transfer 32k of firmware data from user buffer to our buffer and send to
* the card
*/
char flashbuffer[1024 * 38]; /* RAW Buffer for flash will be
* dynamic next */
static int
flashputbuf(ifp)
struct ifnet *ifp;
{
unsigned short *bufp;
int nwords;
struct an_softc *sc = ifp->if_softc;
/* Write stuff */
bufp = (unsigned short *)flashbuffer;
CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100);
CSR_WRITE_2(sc, AN_AUX_OFFSET, 0);
for (nwords = 0; nwords != 16384; nwords++) {
CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff);
}
CSR_WRITE_2(sc, AN_SW0, 0x8000);
return 0;
}
/*
* After flashing restart the card.
*/
static int
flashrestart(ifp)
struct ifnet *ifp;
{
int status = 0;
struct an_softc *sc = ifp->if_softc;
FLASH_DELAY(1024); /* Added 12/7/00 */
an_init(sc);
FLASH_DELAY(1024); /* Added 12/7/00 */
return status;
}
/*
* Entry point for flash ioclt.
*/
static int
flashcard(ifp, l_ioctl)
struct ifnet *ifp;
struct aironet_ioctl *l_ioctl;
{
struct an_softc *sc;
struct an_req areq;
int z = 0, status;
sc = ifp->if_softc;
status = l_ioctl->command;
switch (l_ioctl->command) {
case AIROFLSHRST:
return cmdreset(ifp);
break;
case AIROFLSHSTFL:
return setflashmode(ifp);
break;
case AIROFLSHGCHR: /* Get char from aux */
copyin(l_ioctl->data, &areq, l_ioctl->len);
z = *(int *)&areq;
if ((status = flashgchar(ifp, z, 8000)) == 1)
return 0;
else
return -1;
break;
case AIROFLSHPCHR: /* Send char to card. */
copyin(l_ioctl->data, &areq, l_ioctl->len);
z = *(int *)&areq;
if ((status = flashpchar(ifp, z, 8000)) == -1)
return -EIO;
else
return 0;
break;
case AIROFLPUTBUF: /* Send 32k to card */
if (l_ioctl->len > sizeof(flashbuffer)) {
printf("an%d: Buffer to big, %x %x\n", sc->an_unit,
l_ioctl->len, sizeof(flashbuffer));
return -EINVAL;
}
copyin(l_ioctl->data, &flashbuffer, l_ioctl->len);
if ((status = flashputbuf(ifp)) != 0)
return -EIO;
else
return 0;
break;
case AIRORESTART:
if ((status = flashrestart(ifp)) != 0) {
printf("an%d: FLASHRESTART returned %d\n",
sc->an_unit, status);
return -EIO;
} else
return 0;
break;
default:
return -EINVAL;
}
return -EINVAL;
}

View File

@ -217,30 +217,6 @@ struct an_ltv_gen {
#define AN_DEF_SSID_LEN 7
#define AN_DEF_SSID "tsunami"
/*
* Receive frame structure.
*/
struct an_rxframe {
u_int32_t an_rx_time; /* 0x00 */
u_int16_t an_rx_status; /* 0x04 */
u_int16_t an_rx_payload_len; /* 0x06 */
u_int8_t an_rsvd0; /* 0x08 */
u_int8_t an_rx_signal_strength; /* 0x09 */
u_int8_t an_rx_rate; /* 0x0A */
u_int8_t an_rx_chan; /* 0x0B */
u_int8_t an_rx_assoc_cnt; /* 0x0C */
u_int8_t an_rsvd1[3]; /* 0x0D */
u_int8_t an_plcp_hdr[4]; /* 0x10 */
u_int16_t an_frame_ctl; /* 0x14 */
u_int16_t an_duration; /* 0x16 */
u_int8_t an_addr1[6]; /* 0x18 */
u_int8_t an_addr2[6]; /* 0x1E */
u_int8_t an_addr3[6]; /* 0x24 */
u_int16_t an_seq_ctl; /* 0x2A */
u_int8_t an_addr4[6]; /* 0x2C */
u_int16_t an_gaplen; /* 0x32 */
};
#define AN_RXGAP_MAX 8
/*
@ -265,8 +241,8 @@ struct an_txframe {
u_int8_t an_addr3[6]; /* 0x24 */
u_int16_t an_seq_ctl; /* 0x2A */
u_int8_t an_addr4[6]; /* 0x2C */
u_int16_t an_gaplen; /* 0x32 */
};
u_int8_t an_gaplen; /* 0x32 */
} __attribute__((packed));
struct an_rxframe_802_3 {
u_int16_t an_rx_802_3_status; /* 0x34 */
@ -386,6 +362,7 @@ struct an_softc {
int an_monitor;
int an_was_monitor;
u_char buf_802_11[MCLBYTES];
struct an_req areq;
};
#define AN_LOCK(_sc) mtx_lock(&(_sc)->an_mtx)

View File

@ -4,6 +4,7 @@ PROG= ancontrol
MAN= ancontrol.8
CFLAGS+= -I${.CURDIR}/../../sys -DANCACHE
LDADD+= -lmd
WARNS?= 2

View File

@ -82,10 +82,14 @@
.Nm
.Fl i Ar iface Fl m Ar mac_address
.Nm
.Fl i Ar iface Fl m Ar mac address
.Nm
.Fl i Ar iface
.Op Fl v Cm 1 | 2 | 3
.Fl n Ar SSID
.Nm
.Fl i Ar iface Fl o Ar 0|1
.Nm
.Fl i Ar iface Fl o Cm 0 | 1
.Nm
.Fl i Ar iface Fl p Ar tx_power
@ -259,7 +263,7 @@ option: selection
sets the receive diversity and
.Cm 1
sets the transmit diversity.
.It Fl i Ar iface Fl e Cm 0 | 1 | 2 | 3
.It Fl i Ar iface Fl e Cm 0 | 1 | 2 | 3 | 4
Set the transmit WEP key to use.
Note that until this command is issued, the device will use the
last key programmed.
@ -267,8 +271,9 @@ The transmit key is stored in NVRAM.
Currently
set transmit key can be checked via
.Fl C
option.
.It Fl i Ar iface Oo Fl v Cm 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 Oc Fl k Ar key
option. The 4th key sets the card in "Home Network Mode" and uses the
home key.
.It Fl i Ar iface Oo Fl v Cm 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 Oc Fl k Ar key
Set a WEP key.
For 40 bit prefix 10 hex character with 0x.
For 128 bit prefix 26 hex character with 0x.
@ -289,7 +294,8 @@ Note that the device will use the most recently-programmed key by default.
Currently set keys can be checked via
.Fl C
option, only the sizes of the
keys are returned.
keys are returned. The 8th key is for the home key. Note that
the value for the home key can be read back from firmware.
.It Fl i Ar iface Fl K Cm 0 | 1 | 2
Set authorization type.
Use
@ -310,6 +316,9 @@ for no WEP,
to enable full WEP,
.Cm 2
for mixed cell.
.It Fl i Ar iface Fl L Ar user_name
Enable LEAP and query for password. It will check to see if it
has authenticated for up to 60s. To disable LEAP set WEP mode.
.It Fl i Ar iface Fl j Ar netjoin_timeout
Set the ad-hoc network join timeout.
When a station is first activated
@ -423,6 +432,22 @@ need to be retransmitted instead of the whole packet.
The fragmentation
threshold can be anything from 64 to 2312 bytes.
The default is 2312.
.It Fl i Ar iface Fl M Ar 0-15
Set monitor mode via bit mask, meaning:
.Bl -tag -offset indent -compact -width 0x000000
.Em "Bit Mask Meaning"
.It 0
to not dump 802.11 packet.
.It 1
to enable 802.11 monitor.
.It 2
to monitor any SSID.
.It 4
to not skip beacons, monitor beacons produces a high system load.
.It 8
to enable full Aironet header returned via BPF.
Note it appears that a SSID must be set.
.El
.It Fl i Ar iface Fl r Ar RTS_threshold
Set the RTS/CTS threshold for a given interface.
This controls the

View File

@ -56,6 +56,7 @@ static const char rcsid[] =
#include <unistd.h>
#include <errno.h>
#include <err.h>
#include <md4.h>
static void an_getval __P((const char *, struct an_req *));
static void an_setval __P((const char *, struct an_req *));
@ -83,6 +84,7 @@ static int an_hex2int __P((char));
static void an_str2key __P((char *, struct an_ltv_key *));
static void an_setkeys __P((const char *, char *, int));
static void an_enable_tx_key __P((const char *, char *));
static void an_enable_leap_mode __P((const char *, char *));
static void usage __P((char *));
int main __P((int, char **));
@ -126,6 +128,7 @@ int main __P((int, char **));
#define ACT_SET_KEYS 35
#define ACT_ENABLE_TX_KEY 36
#define ACT_SET_MONITOR_MODE 37
#define ACT_SET_LEAP_MODE 38
static void an_getval(iface, areq)
const char *iface;
@ -277,6 +280,8 @@ static void an_dumpstatus(iface)
printf("synced ");
if (sts->an_opmode & AN_STATUS_OPMODE_ASSOCIATED)
printf("associated ");
if (sts->an_opmode & AN_STATUS_OPMODE_LEAP)
printf("LEAP ");
if (sts->an_opmode & AN_STATUS_OPMODE_ERROR)
printf("error ");
printf("]\n");
@ -285,6 +290,7 @@ static void an_dumpstatus(iface)
printf("\nSignal quality:\t\t");
an_printhex((char *)&sts->an_cur_signal_quality, 1);
printf("\nSignal strength:\t[ %d%% ]",sts->an_normalized_rssi);
printf("\nMax Noise:\t\t[ %d%% ]",sts->an_avg_noise_prev_min);
/*
* XXX: This uses the old definition of the rate field (units of
* 500kbps). Technically the new definition is that this field
@ -707,7 +713,9 @@ static void an_dumpconfig(iface)
printf("\nWEP enabled:\t\t\t\t[ ");
if (cfg->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE)
{
if (cfg->an_authtype & AN_AUTHTYPE_ALLOW_UNENCRYPTED)
if (cfg->an_authtype & AN_AUTHTYPE_LEAP)
printf("LEAP");
else if (cfg->an_authtype & AN_AUTHTYPE_ALLOW_UNENCRYPTED)
printf("mixed cell");
else
printf("full");
@ -805,6 +813,12 @@ static void an_dumpconfig(iface)
an_printwords(&cfg->an_arl_decay, 1);
printf("\nARL delay:\t\t\t\t");
an_printwords(&cfg->an_arl_delay, 1);
printf("\nConfiguration:\t\t\t\t[ ");
if (cfg->an_home_product & AN_HOME_NETWORK)
printf("Home Configuration");
else
printf("Enterprise Configuration");
printf(" ]");
printf("\n");
printf("\n");
@ -842,6 +856,7 @@ static void usage(p)
fprintf(stderr, "\t%s -i iface -f val (set frag threshold)\n", p);
fprintf(stderr, "\t%s -i iface -r val (set RTS threshold)\n", p);
fprintf(stderr, "\t%s -i iface -M 0-15 (set monitor mode)\n", p);
fprintf(stderr, "\t%s -i iface -L user (enter LEAP authentication mode)\n", p);
#ifdef ANCACHE
fprintf(stderr, "\t%s -i iface -Q print signal quality cache\n", p);
fprintf(stderr, "\t%s -i iface -Z zero out signal cache\n", p);
@ -962,12 +977,14 @@ static void an_setconfig(iface, act, arg)
case 0:
/* no WEP */
cfg->an_authtype &= ~(AN_AUTHTYPE_PRIVACY_IN_USE
| AN_AUTHTYPE_ALLOW_UNENCRYPTED);
| AN_AUTHTYPE_ALLOW_UNENCRYPTED
| AN_AUTHTYPE_LEAP);
break;
case 1:
/* full WEP */
cfg->an_authtype |= AN_AUTHTYPE_PRIVACY_IN_USE;
cfg->an_authtype &= ~AN_AUTHTYPE_ALLOW_UNENCRYPTED;
cfg->an_authtype &= ~AN_AUTHTYPE_LEAP;
break;
case 2:
/* mixed cell */
@ -1261,7 +1278,7 @@ static void an_setkeys(iface, key, keytype)
k->mac[4]=0;
k->mac[5]=0;
switch(keytype & 1){
switch(keytype & 1) {
case 0:
areq.an_len = sizeof(struct an_ltv_key);
areq.an_type = AN_RID_WEP_PERM;
@ -1289,12 +1306,12 @@ static void an_readkeyinfo(iface)
printf("WEP Key status:\n");
areq.an_type = AN_RID_WEP_TEMP; /* read first key */
for(i=0; i<5; i++){
for(i=0; i<5; i++) {
areq.an_len = sizeof(struct an_ltv_key);
an_getval(iface, &areq);
if(k->kindex == 0xffff)
if (k->kindex == 0xffff)
break;
switch (k->klen){
switch (k->klen) {
case 0:
printf("\tKey %d is unset\n",k->kindex);
break;
@ -1325,8 +1342,24 @@ static void an_enable_tx_key(iface, arg)
{
struct an_req areq;
struct an_ltv_key *k;
struct an_ltv_genconfig *config;
bzero((char *)&areq, sizeof(areq));
/* set home or not home mode */
areq.an_len = sizeof(struct an_ltv_genconfig);
areq.an_type = AN_RID_GENCONFIG;
an_getval(iface, &areq);
config = (struct an_ltv_genconfig *)&areq;
if (atoi(arg) == 4) {
config->an_home_product |= AN_HOME_NETWORK;
}else{
config->an_home_product &= ~AN_HOME_NETWORK;
}
an_setval(iface, &areq);
bzero((char *)&areq, sizeof(areq));
k = (struct an_ltv_key *)&areq;
/* From a Cisco engineer write the transmit key to use in the
@ -1348,6 +1381,102 @@ static void an_enable_tx_key(iface, arg)
return;
}
static void an_enable_leap_mode(iface, username)
const char *iface;
char *username;
{
struct an_req areq;
struct an_ltv_status *sts;
struct an_ltv_genconfig *cfg;
struct an_ltv_caps *caps;
struct an_ltv_leap_username an_username;
struct an_ltv_leap_password an_password;
char *password;
MD4_CTX context;
int len;
int i;
char unicode_password[LEAP_PASSWORD_MAX * 2];
areq.an_len = sizeof(areq);
areq.an_type = AN_RID_CAPABILITIES;
an_getval(iface, &areq);
caps = (struct an_ltv_caps *)&areq;
if (!caps->an_softcaps & AN_AUTHTYPE_LEAP) {
fprintf(stderr, "Firmware does not support LEAP\n");
exit(1);
}
bzero(&an_username, sizeof(an_username));
bzero(&an_password, sizeof(an_password));
len = strlen(username);
if (len > LEAP_USERNAME_MAX) {
printf("Username too long (max %d)\n", LEAP_USERNAME_MAX);
exit(1);
}
strncpy(an_username.an_username, username, len);
an_username.an_username_len = len;
an_username.an_len = sizeof(an_username);
an_username.an_type = AN_RID_LEAPUSERNAME;
password = getpass("Enter LEAP password:");
len = strlen(password);
if (len > LEAP_PASSWORD_MAX) {
printf("Password too long (max %d)\n", LEAP_PASSWORD_MAX);
exit(1);
}
bzero(&unicode_password, sizeof(unicode_password));
for(i = 0; i < len; i++) {
unicode_password[i * 2] = *password++;
}
/* First half */
MD4Init(&context);
MD4Update(&context, unicode_password, len * 2);
MD4Final(&an_password.an_password[0], &context);
/* Second half */
MD4Init (&context);
MD4Update (&context, &an_password.an_password[0], 16);
MD4Final (&an_password.an_password[16], &context);
an_password.an_password_len = 32;
an_password.an_len = sizeof(an_password);
an_password.an_type = AN_RID_LEAPPASSWORD;
an_setval(iface, (struct an_req *)&an_username);
an_setval(iface, (struct an_req *)&an_password);
areq.an_len = sizeof(areq);
areq.an_type = AN_RID_GENCONFIG;
an_getval(iface, &areq);
cfg = (struct an_ltv_genconfig *)&areq;
cfg->an_authtype = (AN_AUTHTYPE_PRIVACY_IN_USE | AN_AUTHTYPE_LEAP);
an_setval(iface, &areq);
sts = (struct an_ltv_status *)&areq;
areq.an_type = AN_RID_STATUS;
for (i = 60; i > 0; i--) {
an_getval(iface, &areq);
if (sts->an_opmode & AN_STATUS_OPMODE_LEAP) {
printf("Authenticated\n");
break;
}
sleep(1);
}
if (i == 0) {
fprintf(stderr, "Failed LEAP authentication\n");
exit(1);
}
}
int main(argc, argv)
int argc;
char *argv[];
@ -1378,7 +1507,7 @@ int main(argc, argv)
opterr = 1;
while ((ch = getopt(argc, argv,
"ANISCTht:a:e:o:s:n:v:d:j:b:c:r:p:w:m:l:k:K:W:QZM:")) != -1) {
"ANISCTht:a:e:o:s:n:v:d:j:b:c:r:p:w:m:l:k:K:W:QZM:L:")) != -1) {
switch(ch) {
case 'Z':
#ifdef ANCACHE
@ -1545,6 +1674,10 @@ int main(argc, argv)
act = ACT_SET_MONITOR_MODE;
arg = optarg;
break;
case 'L':
act = ACT_SET_LEAP_MODE;
arg = optarg;
break;
case 'h':
default:
usage(p);
@ -1602,6 +1735,9 @@ int main(argc, argv)
case ACT_ENABLE_TX_KEY:
an_enable_tx_key(iface, arg);
break;
case ACT_SET_LEAP_MODE:
an_enable_leap_mode(iface, arg);
break;
default:
an_setconfig(iface, act, arg);
break;