summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/an/if_aironet_ieee.h118
-rw-r--r--sys/dev/an/if_an.c617
-rw-r--r--sys/dev/an/if_anreg.h29
3 files changed, 722 insertions, 42 deletions
diff --git a/sys/dev/an/if_aironet_ieee.h b/sys/dev/an/if_aironet_ieee.h
index 2534312..2e110f2 100644
--- a/sys/dev/an/if_aironet_ieee.h
+++ b/sys/dev/an/if_aironet_ieee.h
@@ -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
/*
@@ -568,6 +571,55 @@ struct an_ltv_wepkey {
};
/*
+ * 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
* list as many as I know about here for completeness.
@@ -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
diff --git a/sys/dev/an/if_an.c b/sys/dev/an/if_an.c
index ce8d224..f97aaad 100644
--- a/sys/dev/an/if_an.c
+++ b/sys/dev/an/if_an.c
@@ -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;
+}
+
diff --git a/sys/dev/an/if_anreg.h b/sys/dev/an/if_anreg.h
index 0113d93..9d56314 100644
--- a/sys/dev/an/if_anreg.h
+++ b/sys/dev/an/if_anreg.h
@@ -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)
OpenPOWER on IntegriCloud