diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist index 95e12c1c4f01..a90d7ff7b8fb 100644 --- a/etc/mtree/BSD.include.dist +++ b/etc/mtree/BSD.include.dist @@ -12,6 +12,8 @@ .. .. dev + an + .. ic .. ppbus diff --git a/include/Makefile b/include/Makefile index f991f3f35722..3df3f2a82bc5 100644 --- a/include/Makefile +++ b/include/Makefile @@ -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 diff --git a/sbin/ifconfig/ifieee80211.c b/sbin/ifconfig/ifieee80211.c index ac8c8712d977..33b2d83f9d64 100644 --- a/sbin/ifconfig/ifieee80211.c +++ b/sbin/ifconfig/ifieee80211.c @@ -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; diff --git a/sys/dev/an/if_aironet_ieee.h b/sys/dev/an/if_aironet_ieee.h index 25343123467e..2e110f2907d5 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 /* @@ -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 diff --git a/sys/dev/an/if_an.c b/sys/dev/an/if_an.c index ce8d22475d61..f97aaad66dc7 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 0113d933d3d8..9d5631479080 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) diff --git a/usr.sbin/ancontrol/Makefile b/usr.sbin/ancontrol/Makefile index fe33ae171a40..696af713b323 100644 --- a/usr.sbin/ancontrol/Makefile +++ b/usr.sbin/ancontrol/Makefile @@ -4,6 +4,7 @@ PROG= ancontrol MAN= ancontrol.8 CFLAGS+= -I${.CURDIR}/../../sys -DANCACHE +LDADD+= -lmd WARNS?= 2 diff --git a/usr.sbin/ancontrol/ancontrol.8 b/usr.sbin/ancontrol/ancontrol.8 index 0b5f21d48188..90d87305ac9a 100644 --- a/usr.sbin/ancontrol/ancontrol.8 +++ b/usr.sbin/ancontrol/ancontrol.8 @@ -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 diff --git a/usr.sbin/ancontrol/ancontrol.c b/usr.sbin/ancontrol/ancontrol.c index 0a89c4fbdcad..eadc5e37583d 100644 --- a/usr.sbin/ancontrol/ancontrol.c +++ b/usr.sbin/ancontrol/ancontrol.c @@ -56,6 +56,7 @@ static const char rcsid[] = #include #include #include +#include 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;