1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-14 10:09:48 +00:00

Integrate the hostap stuff that Thomas Skibo <skibo@packbell.net>

wrote.  This code was for 4.5-release, so I've ported it to -current
and made a few minor tweaks.  The biggest non-style tweak was to not
make access point the default.

More changes will be needed to get this actually working, but I wanted
to get a relatively pure baseline.  This doesn't seem to break what
works now.
This commit is contained in:
Warner Losh 2002-04-11 07:21:16 +00:00
parent 5ed43a1e8e
commit 1bd2b5b4cd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=94405
8 changed files with 1768 additions and 52 deletions

View File

@ -50,6 +50,7 @@
#ifndef SIOCGWAVELAN
#define SIOCGWAVELAN SIOCGIFGENERIC
#endif
#define WI_RID_MONITOR_MODE 0x0500
/*
* Technically I don't think there's a limit to a record
@ -113,6 +114,13 @@ struct wi_80211_hdr {
#define WI_STYPE_MGMT_AUTH 0x00B0 /* authentication */
#define WI_STYPE_MGMT_DEAUTH 0x00C0 /* deauthentication */
#define WI_STYPE_CTL_PSPOLL 0x00A0
#define WI_STYPE_CTL_RTS 0x00B0
#define WI_STYPE_CTL_CTS 0x00C0
#define WI_STYPE_CTL_ACK 0x00D0
#define WI_STYPE_CTL_CFEND 0x00E0
#define WI_STYPE_CTL_CFENDACK 0x00F0
struct wi_mgmt_hdr {
u_int16_t frame_ctl;
u_int16_t duration;
@ -209,7 +217,7 @@ struct wi_counters {
#define IV_EVERY100_FRAME 0x60 /* every 100 frame IV reuse */
#define HOST_DECRYPT 0x80
#define WI_RID_WEP_MAPTABLE 0xFC29
#define WI_RID_AUTH_CNTL 0xFC2A
#define WI_RID_CNFAUTHMODE 0xFC2A
#define WI_RID_ROAMING_MODE 0xFC2D
#define WI_RID_BASIC_RATE 0xFCB3
#define WI_RID_SUPPORT_RATE 0xFCB4
@ -221,7 +229,11 @@ struct wi_counters {
#define WI_RID_CREATE_IBSS 0xFC81 /* create IBSS */
#define WI_RID_FRAG_THRESH 0xFC82 /* frag len, unicast msg xmit */
#define WI_RID_RTS_THRESH 0xFC83 /* frame len for RTS/CTS handshake */
#define WI_RID_TX_RATE 0xFC84 /* data rate for message xmit */
#define WI_RID_TX_RATE 0xFC84 /* data rate for message xmit
* 0 == Fixed 1mbps
* 1 == Fixed 2mbps
* 2 == auto fallback
*/
#define WI_RID_PROMISC 0xFC85 /* enable promisc mode */
#define WI_RID_FRAG_THRESH0 0xFC90
#define WI_RID_FRAG_THRESH1 0xFC91

View File

@ -95,6 +95,10 @@
#include <net/bpf.h>
#include <dev/wi/if_wavelan_ieee.h>
#ifdef WI_HOSTAP
#include <dev/wi/wi_hostap.h>
#include <sys/random.h>
#endif
#include <dev/wi/if_wivar.h>
#include <dev/wi/if_wireg.h>
@ -124,7 +128,6 @@ static int wi_seek(struct wi_softc *, int, int, int);
static int wi_alloc_nicmem(struct wi_softc *, int, int *);
static void wi_inquire(void *);
static void wi_setdef(struct wi_softc *, struct wi_req *);
static int wi_mgmt_xmit(struct wi_softc *, caddr_t, int);
#ifdef WICACHE
static
@ -214,6 +217,7 @@ wi_generic_attach(device_t dev)
struct ifnet *ifp;
int error;
/* XXX maybe we need the splimp stuff here XXX */
sc = device_get_softc(dev);
ifp = &sc->arpcom.ac_if;
@ -290,6 +294,7 @@ wi_generic_attach(device_t dev)
sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
sc->wi_roaming = WI_DEFAULT_ROAMING;
sc->wi_authtype = WI_DEFAULT_AUTHTYPE;
sc->wi_authmode = IEEE80211_AUTH_OPEN;
/*
* Read the default channel from the NIC. This may vary
@ -311,11 +316,18 @@ wi_generic_attach(device_t dev)
sc->wi_has_wep = gen.wi_val;
if (bootverbose) {
device_printf(sc->dev,
"%s:wi_has_wep = %d\n",
__func__, sc->wi_has_wep);
device_printf(sc->dev, "%s:wi_has_wep = %d\n",
__func__, sc->wi_has_wep);
}
/*
* Find supported rates.
*/
gen.wi_type = WI_RID_TX_RATE;
gen.wi_len = 2;
wi_read_record(sc, &gen);
sc->wi_supprates = gen.wi_val;
bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats));
wi_init(sc);
@ -339,6 +351,20 @@ wi_generic_attach(device_t dev)
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
IFM_IEEE80211_ADHOC, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
#ifdef IFM_IEEE80211_HOSTAP
if (sc->sc_firmware_type == WI_INTERSIL) {
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
IFM_IEEE80211_HOSTAP, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
IFM_IEEE80211_HOSTAP, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
IFM_IEEE80211_HOSTAP, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
IFM_IEEE80211_HOSTAP, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
IFM_IEEE80211_HOSTAP, 0), 0);
}
#endif
#undef ADD
ifmedia_set(&sc->ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
0, 0));
@ -587,6 +613,38 @@ wi_rxeof(sc)
eh = mtod(m, struct ether_header *);
m->m_pkthdr.rcvif = ifp;
#ifdef WI_HOSTAP
if (rx_frame.wi_status == WI_STAT_MGMT &&
sc->wi_ptype == WI_PORTTYPE_AP) {
if ((WI_802_11_OFFSET_RAW + rx_frame.wi_dat_len + 2) >
MCLBYTES) {
device_printf(sc->dev, "oversized mgmt packet "
"received in hostap mode "
"(wi_dat_len=%d, wi_status=0x%x)\n",
rx_frame.wi_dat_len, rx_frame.wi_status);
m_freem(m);
ifp->if_ierrors++;
return;
}
/* Put the whole header in there. */
bcopy(&rx_frame, mtod(m, void *),
sizeof(struct wi_frame));
if (wi_read_data(sc, id, WI_802_11_OFFSET_RAW,
mtod(m, caddr_t) + WI_802_11_OFFSET_RAW,
rx_frame.wi_dat_len + 2)) {
m_freem(m);
ifp->if_ierrors++;
return;
}
m->m_pkthdr.len = m->m_len =
WI_802_11_OFFSET_RAW + rx_frame.wi_dat_len;
/* XXX: consider giving packet to bhp? */
wihap_mgmt_input(sc, &rx_frame, m);
return;
}
#endif /* WI_HOSTAP */
if (rx_frame.wi_status == WI_STAT_1042 ||
rx_frame.wi_status == WI_STAT_TUNNEL ||
rx_frame.wi_status == WI_STAT_WMP_MSG) {
@ -653,6 +711,18 @@ wi_rxeof(sc)
ifp->if_ipackets++;
#ifdef WI_HOSTAP
if (sc->wi_ptype == WI_PORTTYPE_AP) {
/*
* Give host AP code first crack at data
* packets. If it decides to handle it (or
* drop it), it will return a non-zero.
* Otherwise, it is destined for this host.
*/
if (wihap_data_input(sc, &rx_frame, m))
return;
}
#endif
/* Receive packet. */
m_adj(m, sizeof(struct ether_header));
#ifdef WICACHE
@ -688,6 +758,7 @@ wi_inquire(xsc)
{
struct wi_softc *sc;
struct ifnet *ifp;
int s;
sc = xsc;
ifp = &sc->arpcom.ac_if;
@ -698,7 +769,9 @@ wi_inquire(xsc)
if (ifp->if_flags & IFF_OACTIVE)
return;
s = splimp();
wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0);
splx(s);
return;
}
@ -1002,7 +1075,7 @@ wi_read_record(sc, ltv)
oltv->wi_len = 2;
oltv->wi_val = ltv->wi_val;
break;
case WI_RID_AUTH_CNTL:
case WI_RID_CNFAUTHMODE:
oltv->wi_len = 2;
if (le16toh(ltv->wi_val) & 0x01)
oltv->wi_val = htole16(1);
@ -1047,10 +1120,18 @@ wi_write_record(sc, ltv)
case WI_RID_ENCRYPTION:
p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
p2ltv.wi_len = 2;
if (le16toh(ltv->wi_val))
if (le16toh(ltv->wi_val)) {
p2ltv.wi_val =htole16(PRIVACY_INVOKED |
EXCLUDE_UNENCRYPTED);
else
#ifdef WI_HOSTAP
if (sc->wi_ptype == WI_PORTTYPE_AP)
/*
* Disable tx encryption...
* it's broken.
*/
p2ltv.wi_val |= htole16(HOST_ENCRYPT);
#endif
} else
p2ltv.wi_val =
htole16(HOST_ENCRYPT | HOST_DECRYPT);
ltv = &p2ltv;
@ -1084,8 +1165,8 @@ wi_write_record(sc, ltv)
}
return 0;
}
case WI_RID_AUTH_CNTL:
p2ltv.wi_type = WI_RID_AUTH_CNTL;
case WI_RID_CNFAUTHMODE:
p2ltv.wi_type = WI_RID_CNFAUTHMODE;
p2ltv.wi_len = 2;
if (le16toh(ltv->wi_val) == 1)
p2ltv.wi_val = htole16(0x01);
@ -1372,7 +1453,7 @@ wi_setdef(sc, wreq)
case WI_RID_MAX_SLEEP:
sc->wi_max_sleep = le16toh(wreq->wi_val[0]);
break;
case WI_RID_AUTH_CNTL:
case WI_RID_CNFAUTHMODE:
sc->wi_authtype = le16toh(wreq->wi_val[0]);
break;
case WI_RID_ROAMING_MODE:
@ -1632,7 +1713,7 @@ wi_ioctl(ifp, command, data)
ireq->i_val = sc->wi_tx_key;
break;
case IEEE80211_IOC_AUTHMODE:
ireq->i_val = IEEE80211_AUTH_NONE;
ireq->i_val = sc->wi_authmode;
break;
case IEEE80211_IOC_STATIONNAME:
error = copyout(sc->wi_node_name,
@ -1712,7 +1793,7 @@ wi_ioctl(ifp, command, data)
sc->wi_tx_key = ireq->i_val;
break;
case IEEE80211_IOC_AUTHMODE:
error = EINVAL;
sc->wi_authmode = ireq->i_val;
break;
case IEEE80211_IOC_STATIONNAME:
if (ireq->i_len > 32) {
@ -1763,7 +1844,18 @@ wi_ioctl(ifp, command, data)
/* Reinitialize WaveLAN. */
wi_init(sc);
break;
#ifdef WI_HOSTAP
case SIOCHOSTAP_ADD:
case SIOCHOSTAP_DEL:
case SIOCHOSTAP_GET:
case SIOCHOSTAP_GETALL:
case SIOCHOSTAP_GFLAGS:
case SIOCHOSTAP_SFLAGS:
/* Send all Host AP specific ioctl's to Host AP code. */
error = wihap_ioctl(sc, command, data);
break;
#endif
default:
error = EINVAL;
break;
@ -1834,6 +1926,9 @@ wi_init(xsc)
/* Program the nodename. */
WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name);
/* Specify the authentication mode. */
WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authmode);
/* Set our MAC address. */
mac.wi_len = 4;
mac.wi_type = WI_RID_MAC_NODE;
@ -1863,7 +1958,7 @@ wi_init(xsc)
/* firm ver < 0.8 variant 2 */
WI_SETVAL(WI_RID_PROMISC, 1);
}
WI_SETVAL(WI_RID_AUTH_CNTL, sc->wi_authtype);
WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype);
}
}
@ -1891,6 +1986,15 @@ wi_init(xsc)
/* enable interrupts */
CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
#ifdef WI_HOSTAP
wihap_init(sc);
/*
* Initialize ICV to something random. XXX: this doesn't work
* if init happens in early boot-up. Fix later.
*/
read_random(&sc->wi_icv, sizeof(sc->wi_icv));
#endif
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
@ -1900,6 +2004,159 @@ wi_init(xsc)
return;
}
#ifdef WI_HOSTAP
/*
* Host encryption code: Transmits are broken in Host AP mode when WEP is
* enabled. So, we disable TX encryption and manually encrypt it here.
*/
static u_int32_t
wi_next_crc32(u_int32_t crc32, u_int8_t byte)
{
/* Thanks again, RFC 1662. */
static u_int32_t fcstab_32[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
return (crc32>>8) ^ fcstab_32[(u_int8_t)(byte ^ crc32)];
}
static __inline void
SWAP(u_int8_t *pa, u_int8_t *pb)
{
u_int8_t c;
c = *pa;
*pa = *pb;
*pb = c;
}
static void
wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len)
{
int i;
u_int32_t crc32;
u_int8_t k[16];
u_int8_t state[256];
u_int8_t x, y;
int keylen;
keylen = (sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen>5) ? 16:8;
/* Create ICV/key concatenation. */
k[0] = sc->wi_icv >> 16;
k[1] = sc->wi_icv >> 8;
k[2] = sc->wi_icv;
for (i=3; i<keylen; i++)
k[i] = sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat[i-3];
/* Insert ICV in packet. */
buf[0] = k[0];
buf[1] = k[1];
buf[2] = k[2];
buf[3] = (sc->wi_tx_key<<6);
++sc->wi_icv;
/* Initialize key. */
for (i=0; i<256; i++)
state[i]=i;
x=0;
y=0;
for (i=0; i<256; i++) {
y = (k[x]+state[i]+y);
SWAP(&state[i], &state[y]);
x = (x+1) & (keylen-1);
}
/* Start encrypting. */
x=0;
y=0;
crc32=0xffffffff;
for (i=0; i<len; i++) {
x++;
y = state[x]+y;
SWAP(&state[x], &state[y]);
crc32 = wi_next_crc32(crc32, buf[i+4]);
buf[i+4] ^= state[ (u_int8_t)(state[x] + state[y]) ];
}
/* Append CRC-32, encrypt it too. */
crc32 ^= 0xffffffff;
for (i=0; i<4; i++) {
x++;
y = state[x]+y;
SWAP(&state[x], &state[y]);
buf[i+len+4] = crc32;
crc32 >>= 8;
buf[i+len+4] ^= state[ (u_int8_t)(state[x] + state[y]) ];
}
}
#endif /* WI_HOSTAP */
static void
wi_start(ifp)
struct ifnet *ifp;
@ -1923,6 +2180,9 @@ wi_start(ifp)
return;
}
#ifdef WI_HOSTAP
nextpkt:
#endif
IF_DEQUEUE(&ifp->if_snd, m0);
if (m0 == NULL) {
WI_UNLOCK(sc);
@ -1930,9 +2190,22 @@ wi_start(ifp)
}
bzero((char *)&tx_frame, sizeof(tx_frame));
tx_frame.wi_frame_ctl = htole16(WI_FTYPE_DATA);
id = sc->wi_tx_data_id;
eh = mtod(m0, struct ether_header *);
#ifdef WI_HOSTAP
if (sc->wi_ptype == WI_PORTTYPE_AP) {
if (!wihap_check_tx(&sc->wi_hostap_info,
eh->ether_dhost, &tx_frame.wi_tx_rate)) {
if (ifp->if_flags & IFF_DEBUG)
printf("wi_start: dropping unassoc "
"dst %6D\n", eh->ether_dhost, ":");
m_freem(m0);
goto nextpkt;
}
}
#endif
/*
* Use RFC1042 encoding for IP and ARP datagrams,
* 802.3 for anything else.
@ -1940,38 +2213,81 @@ wi_start(ifp)
if (ntohs(eh->ether_type) > ETHER_MAX_LEN) {
bcopy((char *)&eh->ether_dhost,
(char *)&tx_frame.wi_addr1, ETHER_ADDR_LEN);
bcopy((char *)&eh->ether_shost,
(char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN);
#ifdef WI_HOSTAP
if (sc->wi_ptype == WI_PORTTYPE_AP) {
tx_frame.wi_tx_ctl = WI_ENC_TX_MGMT; /* XXX */
tx_frame.wi_frame_ctl |= WI_FCTL_FROMDS;
if (sc->wi_use_wep)
tx_frame.wi_frame_ctl |= WI_FCTL_WEP;
bcopy((char *)&sc->arpcom.ac_enaddr,
(char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN);
bcopy((char *)&eh->ether_shost,
(char *)&tx_frame.wi_addr3, ETHER_ADDR_LEN);
}
else
#endif
bcopy((char *)&eh->ether_shost,
(char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN);
bcopy((char *)&eh->ether_dhost,
(char *)&tx_frame.wi_dst_addr, ETHER_ADDR_LEN);
bcopy((char *)&eh->ether_shost,
(char *)&tx_frame.wi_src_addr, ETHER_ADDR_LEN);
tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN;
tx_frame.wi_frame_ctl = WI_FTYPE_DATA;
tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0);
tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1);
tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
tx_frame.wi_type = eh->ether_type;
m_copydata(m0, sizeof(struct ether_header),
m0->m_pkthdr.len - sizeof(struct ether_header),
(caddr_t)&sc->wi_txbuf);
wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
sizeof(struct wi_frame));
wi_write_data(sc, id, WI_802_11_OFFSET, (caddr_t)&sc->wi_txbuf,
(m0->m_pkthdr.len - sizeof(struct ether_header)) + 2);
#ifdef WI_HOSTAP
if (sc->wi_ptype == WI_PORTTYPE_AP && sc->wi_use_wep) {
/* Do host encryption. */
bcopy(&tx_frame.wi_dat[0], &sc->wi_txbuf[4], 8);
m_copydata(m0, sizeof(struct ether_header),
m0->m_pkthdr.len - sizeof(struct ether_header),
(caddr_t)&sc->wi_txbuf[12]);
wi_do_hostencrypt(sc, &sc->wi_txbuf[0],
tx_frame.wi_dat_len);
tx_frame.wi_dat_len += 8;
wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
sizeof(struct wi_frame));
wi_write_data(sc, id, WI_802_11_OFFSET_RAW,
(caddr_t)&sc->wi_txbuf, (m0->m_pkthdr.len -
sizeof(struct ether_header)) + 18);
}
else
#endif
{
m_copydata(m0, sizeof(struct ether_header),
m0->m_pkthdr.len - sizeof(struct ether_header),
(caddr_t)&sc->wi_txbuf);
wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
sizeof(struct wi_frame));
wi_write_data(sc, id, WI_802_11_OFFSET,
(caddr_t)&sc->wi_txbuf, (m0->m_pkthdr.len -
sizeof(struct ether_header)) + 2);
}
} else {
tx_frame.wi_dat_len = m0->m_pkthdr.len;
eh->ether_type = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&sc->wi_txbuf);
#ifdef WI_HOSTAP
if (sc->wi_ptype == WI_PORTTYPE_AP && sc->wi_use_wep) {
/* Do host encryption. */
printf( "XXX: host encrypt not implemented for 802.3\n" );
}
else
#endif
{
eh->ether_type = htons(m0->m_pkthdr.len -
WI_SNAPHDR_LEN);
m_copydata(m0, 0, m0->m_pkthdr.len,
(caddr_t)&sc->wi_txbuf);
wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
sizeof(struct wi_frame));
wi_write_data(sc, id, WI_802_3_OFFSET, (caddr_t)&sc->wi_txbuf,
m0->m_pkthdr.len + 2);
wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
sizeof(struct wi_frame));
wi_write_data(sc, id, WI_802_3_OFFSET,
(caddr_t)&sc->wi_txbuf, m0->m_pkthdr.len + 2);
}
}
/*
@ -1998,7 +2314,7 @@ wi_start(ifp)
return;
}
static int
int
wi_mgmt_xmit(sc, data, len)
struct wi_softc *sc;
caddr_t data;
@ -2021,12 +2337,13 @@ wi_mgmt_xmit(sc, data, len)
bcopy((char *)hdr, (char *)&tx_frame.wi_frame_ctl,
sizeof(struct wi_80211_hdr));
tx_frame.wi_dat_len = len - WI_SNAPHDR_LEN;
tx_frame.wi_len = htons(len - WI_SNAPHDR_LEN);
tx_frame.wi_tx_ctl = WI_ENC_TX_MGMT;
tx_frame.wi_dat_len = len - sizeof(struct wi_80211_hdr);
tx_frame.wi_len = htons(tx_frame.wi_dat_len);
wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame));
wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr,
(len - sizeof(struct wi_80211_hdr)) + 2);
len - sizeof(struct wi_80211_hdr) + 2);
if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) {
device_printf(sc->dev, "xmit failed\n");
@ -2049,6 +2366,10 @@ wi_stop(sc)
return;
}
#ifdef WI_HOSTAP
wihap_shutdown(sc);
#endif
ifp = &sc->arpcom.ac_if;
/*
@ -2268,7 +2589,8 @@ wi_cache_store(struct wi_softc *sc, struct ether_header *eh,
int sig, noise;
int sawip=0;
/* filters:
/*
* filters:
* 1. ip only
* 2. configurable filter to throw out unicast packets,
* keep multicast only.
@ -2278,13 +2600,15 @@ wi_cache_store(struct wi_softc *sc, struct ether_header *eh,
sawip = 1;
}
/* filter for ip packets only
/*
* filter for ip packets only
*/
if (wi_cache_iponly && !sawip) {
return;
}
/* filter for broadcast/multicast only
/*
* filter for broadcast/multicast only
*/
if (wi_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
return;
@ -2295,21 +2619,23 @@ wi_cache_store(struct wi_softc *sc, struct ether_header *eh,
rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff);
#endif
/* find the ip header. we want to store the ip_src
/*
* find the ip header. we want to store the ip_src
* address.
*/
if (sawip) {
if (sawip)
ip = mtod(m, struct ip *);
}
/* do a linear search for a matching MAC address
/*
* do a linear search for a matching MAC address
* in the cache table
* . MAC address is 6 bytes,
* . var w_nextitem holds total number of entries already cached
*/
for(i = 0; i < sc->wi_nextitem; i++) {
if (! bcmp(eh->ether_shost , sc->wi_sigcache[i].macsrc, 6 )) {
/* Match!,
/*
* Match!,
* so we already have this entry,
* update the data
*/
@ -2317,19 +2643,22 @@ wi_cache_store(struct wi_softc *sc, struct ether_header *eh,
}
}
/* did we find a matching mac address?
/*
* did we find a matching mac address?
* if yes, then overwrite a previously existing cache entry
*/
if (i < sc->wi_nextitem ) {
cache_slot = i;
}
/* else, have a new address entry,so
/*
* else, have a new address entry,so
* add this new entry,
* if table full, then we need to replace LRU entry
*/
else {
/* check for space in cache table
/*
* check for space in cache table
* note: wi_nextitem also holds number of entries
* added in the cache table
*/
@ -2349,7 +2678,8 @@ wi_cache_store(struct wi_softc *sc, struct ether_header *eh,
}
}
/* invariant: cache_slot now points at some slot
/*
* invariant: cache_slot now points at some slot
* in cache.
*/
if (cache_slot < 0 || cache_slot >= MAXWICACHE) {
@ -2359,14 +2689,14 @@ wi_cache_store(struct wi_softc *sc, struct ether_header *eh,
return;
}
/* store items in cache
/*
* store items in cache
* .ip source address
* .mac src
* .signal, etc.
*/
if (sawip) {
if (sawip)
sc->wi_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr;
}
bcopy( eh->ether_shost, sc->wi_sigcache[cache_slot].macsrc, 6);
sig = (rx_quality >> 8) & 0xFF;
@ -2390,6 +2720,12 @@ wi_get_cur_ssid(sc, ssid, len)
wreq.wi_len = WI_MAX_DATALEN;
switch (sc->wi_ptype) {
#ifdef WI_HOSTAP
case WI_PORTTYPE_AP:
*len = IEEE80211_NWID_LEN;
bcopy(sc->wi_net_name, ssid, IEEE80211_NWID_LEN);
break;
#endif
case WI_PORTTYPE_ADHOC:
wreq.wi_type = WI_RID_CURRENT_SSID;
error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq);
@ -2442,6 +2778,10 @@ wi_media_change(ifp)
if ((sc->ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
sc->wi_ptype = WI_PORTTYPE_ADHOC;
#if defined(WI_HOSTAP) && defined(IFM_IEEE80211_HOSTAP)
else if ((sc->ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_HOSTAP) != 0)
sc->wi_ptype = WI_PORTTYPE_AP;
#endif
else
sc->wi_ptype = WI_PORTTYPE_BSS;
@ -2482,6 +2822,10 @@ wi_media_status(ifp, imr)
imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
if (sc->wi_ptype == WI_PORTTYPE_ADHOC)
imr->ifm_active |= IFM_IEEE80211_ADHOC;
#if defined(WI_HOSTAP) && defined(IFM_IEEE80211_HOSTAP)
else if (sc->wi_ptype == WI_PORTTYPE_AP)
imr->ifm_active |= IFM_IEEE80211_HOSTAP;
#endif
wreq.wi_type = WI_RID_CUR_TX_RATE;
wreq.wi_len = WI_MAX_DATALEN;
if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) {
@ -2512,6 +2856,10 @@ wi_media_status(ifp, imr)
* created one ourselves.
*/
imr->ifm_status |= IFM_ACTIVE;
#ifdef WI_HOSTAP
else if (sc->wi_ptype == WI_PORTTYPE_AP)
imr->ifm_status |= IFM_ACTIVE;
#endif
else {
wreq.wi_type = WI_RID_COMMQUAL;
wreq.wi_len = WI_MAX_DATALEN;

View File

@ -60,6 +60,9 @@
#include <dev/pccard/pccarddevs.h>
#include <dev/wi/if_wavelan_ieee.h>
#ifdef WI_HOSTAP
#include <dev/wi/wi_hostap.h>
#endif
#include <dev/wi/if_wivar.h>
#include <dev/wi/if_wireg.h>

View File

@ -59,6 +59,9 @@
#include <net/if_ieee80211.h>
#include <dev/wi/if_wavelan_ieee.h>
#ifdef WI_HOSTAP
#include <dev/wi/wi_hostap.h>
#endif
#include <dev/wi/if_wivar.h>
#include <dev/wi/if_wireg.h>

View File

@ -497,9 +497,11 @@ struct wi_ltv_pcf {
* (Only PRISM2; not 802.11 compliant mode, testing use only)
* 6 == HOST AP (Only PRISM2)
*/
#define WI_PORTTYPE_IBSS 0x0
#define WI_PORTTYPE_BSS 0x1
#define WI_PORTTYPE_WDS 0x2
#define WI_PORTTYPE_ADHOC 0x3
#define WI_PORTTYPE_AP 0x6
/*
* Mac addresses. (0xFC01, 0xFC08)
@ -538,6 +540,14 @@ struct wi_ltv_mcast {
struct ether_addr wi_mcast[16];
};
/*
* supported rates. (0xFCB4)
*/
#define WI_SUPPRATES_1M 0x0001
#define WI_SUPPRATES_2M 0x0002
#define WI_SUPPRATES_5M 0x0004
#define WI_SUPPRATES_11M 0x0008
/*
* Information frame types.
*/
@ -556,7 +566,8 @@ struct wi_frame {
u_int16_t wi_rsvd1; /* 0x04 */
u_int16_t wi_q_info; /* 0x06 */
u_int16_t wi_rsvd2; /* 0x08 */
u_int16_t wi_rsvd3; /* 0x0A */
u_int8_t wi_tx_rtry; /* 0x0A */
u_int8_t wi_tx_rate; /* 0x0B */
u_int16_t wi_tx_ctl; /* 0x0C */
u_int16_t wi_frame_ctl; /* 0x0E */
u_int16_t wi_id; /* 0x10 */
@ -576,6 +587,7 @@ struct wi_frame {
#define WI_802_3_OFFSET 0x2E
#define WI_802_11_OFFSET 0x44
#define WI_802_11_OFFSET_RAW 0x3C
#define WI_802_11_OFFSET_HDR 0x0E
#define WI_STAT_BADCRC 0x0001
#define WI_STAT_UNDECRYPTABLE 0x0002
@ -584,10 +596,12 @@ struct wi_frame {
#define WI_STAT_1042 0x2000 /* RFC1042 encoded */
#define WI_STAT_TUNNEL 0x4000 /* Bridge-tunnel encoded */
#define WI_STAT_WMP_MSG 0x6000 /* WaveLAN-II management protocol */
#define WI_STAT_MGMT 0x8000 /* 802.11b management frames */
#define WI_RXSTAT_MSG_TYPE 0xE000
#define WI_ENC_TX_802_3 0x00
#define WI_ENC_TX_802_11 0x11
#define WI_ENC_TX_MGMT 0x08
#define WI_ENC_TX_E_II 0x0E
#define WI_ENC_TX_1042 0x00
@ -595,6 +609,9 @@ struct wi_frame {
#define WI_TXCNTL_MACPORT 0x00FF
#define WI_TXCNTL_STRUCTTYPE 0xFF00
#define WI_TXCNTL_TX_EX 0x0004
#define WI_TXCNTL_TX_OK 0x0002
#define WI_TXCNTL_NOCRYPT 0x0080
/*
* SNAP (sub-network access protocol) constants for transmission
@ -608,3 +625,4 @@ struct wi_frame {
#define WI_SNAP_WORD0 (WI_SNAP_K1 | (WI_SNAP_K1 << 8))
#define WI_SNAP_WORD1 (WI_SNAP_K2 | (WI_SNAP_CONTROL << 8))
#define WI_SNAPHDR_LEN 0x6
#define WI_FCS_LEN 0x4

View File

@ -136,6 +136,7 @@ struct wi_softc {
u_int16_t wi_pm_enabled;
u_int16_t wi_mor_enabled;
u_int16_t wi_max_sleep;
u_int16_t wi_supprates;
u_int16_t wi_authtype;
u_int16_t wi_roaming;
@ -148,12 +149,17 @@ struct wi_softc {
struct wi_counters wi_stats;
int wi_has_wep;
int wi_use_wep;
int wi_authmode;
int wi_tx_key;
struct wi_ltv_keys wi_keys;
#ifdef WICACHE
int wi_sigitems;
struct wi_sigcache wi_sigcache[MAXWICACHE];
int wi_nextitem;
#endif
#ifdef WI_HOSTAP
struct wihap_info wi_hostap_info;
u_int32_t wi_icv;
#endif
struct callout_handle wi_stat_ch;
struct mtx wi_mtx;
@ -193,3 +199,4 @@ void wi_shutdown(device_t);
int wi_alloc(device_t, int);
void wi_free(device_t);
extern devclass_t wi_devclass;
int wi_mgmt_xmit(struct wi_softc *, caddr_t, int);

1189
sys/dev/wi/wi_hostap.c Normal file

File diff suppressed because it is too large Load Diff

136
sys/dev/wi/wi_hostap.h Normal file
View File

@ -0,0 +1,136 @@
/*
* Copyright (c) 2002
* Thomas Skibo <skibo@pacbell.net>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Thomas Skibo.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Thomas Skibo AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Thomas Skibo OR HIS DRINKING PALS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef __WI_HOSTAP_H__
#define __WI_HOSTAP_H__
#define WIHAP_MAX_STATIONS 1800
struct hostap_sta {
u_int8_t addr[6];
u_int16_t asid;
u_int16_t flags;
u_int16_t sig_info; /* 15:8 signal, 7:0 noise */
u_int16_t capinfo;
u_int8_t rates;
};
#define HOSTAP_FLAGS_AUTHEN 0x0001
#define HOSTAP_FLAGS_ASSOC 0x0002
#define HOSTAP_FLAGS_PERM 0x0004
#define SIOCHOSTAP_GET _IOWR('i', 210, struct ifreq)
#define SIOCHOSTAP_ADD _IOWR('i', 211, struct ifreq)
#define SIOCHOSTAP_DEL _IOWR('i', 212, struct ifreq)
#define SIOCHOSTAP_GETALL _IOWR('i', 213, struct ifreq)
#define SIOCHOSTAP_GFLAGS _IOWR('i', 214, struct ifreq)
#define SIOCHOSTAP_SFLAGS _IOWR('i', 215, struct ifreq)
/* Flags for SIOCHOSTAP_GFLAGS/SFLAGS */
#define WIHAPFL_ACTIVE 0x0001
#define WIHAPFL_MAC_FILT 0x0002
/* Flags set inernally only: */
#define WIHAPFL_CANTCHANGE (WIHAPFL_ACTIVE)
struct hostap_getall {
int nstations;
struct hostap_sta *addr;
int size;
};
#ifdef _KERNEL
struct wihap_sta_info {
LIST_ENTRY(wihap_sta_info) list;
LIST_ENTRY(wihap_sta_info) hash;
u_int8_t addr[6];
u_short flags;
int inactivity_timer;
u_int16_t asid;
u_int16_t capinfo;
u_int16_t sig_info; /* 15:8 signal, 7:0 noise */
u_int8_t rates;
u_int8_t tx_curr_rate;
u_int8_t tx_max_rate;
};
#define WI_SIFLAGS_ASSOC HOSTAP_FLAGS_ASSOC
#define WI_SIFLAGS_AUTHEN HOSTAP_FLAGS_AUTHEN
#define WI_SIFLAGS_PERM HOSTAP_FLAGS_PERM
#define WI_STA_HASH_SIZE 113
#if WI_STA_HASH_SIZE*16 >= 2007 /* will generate ASID's too large. */
#error "WI_STA_HASH_SIZE too big"
#endif
#if WI_STA_HASH_SIZE*16 < WIHAP_MAX_STATIONS
#error "WI_STA_HASH_SIZE too small"
#endif
struct wihap_info {
LIST_HEAD(sta_list, wihap_sta_info) sta_list;
LIST_HEAD(sta_hash, wihap_sta_info) sta_hash[WI_STA_HASH_SIZE];
u_int16_t apflags;
int n_stations;
u_int16_t asid_inuse_mask[WI_STA_HASH_SIZE];
int inactivity_time;
struct callout_handle hostap_ch;
};
#define WIHAP_INTERVAL 5
#define WIHAP_DFLT_INACTIVITY_TIME (120/WIHAP_INTERVAL) /* 2 minutes */
struct wi_softc;
struct wi_frame;
void wihap_timer __P((void *));
void wihap_mgmt_input __P((struct wi_softc *, struct wi_frame *,
struct mbuf *));
int wihap_data_input __P((struct wi_softc *, struct wi_frame *,
struct mbuf *));
int wihap_check_tx __P((struct wihap_info *, u_int8_t [],
u_int8_t *));
void wihap_init __P((struct wi_softc *));
void wihap_shutdown __P((struct wi_softc *));
int wihap_ioctl __P((struct wi_softc *, u_long, caddr_t));
#endif /* _KERNEL */
#endif /* __WI_HOSTAP_H__ */