diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2002-03-28 18:21:07 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2002-03-28 18:21:07 +0000 |
commit | 289dfc780967b4da0f7dd57c6a47f8467d6ff6a3 (patch) | |
tree | 9e159a1b557d6d3c3beca201a2d1fad6369f8071 | |
parent | c0f5bab0151b6e3e013fd38bf461e9100792a838 (diff) |
basic host-ap implementation, more work is needed; from Thomas Skibo <skibo@pacbell.net>; millert@ ok
-rw-r--r-- | sys/dev/ic/if_wi.c | 252 | ||||
-rw-r--r-- | sys/dev/ic/if_wi_hostap.c | 1131 | ||||
-rw-r--r-- | sys/dev/ic/if_wi_hostap.h | 137 | ||||
-rw-r--r-- | sys/dev/ic/if_wi_ieee.h | 18 | ||||
-rw-r--r-- | sys/dev/ic/if_wireg.h | 29 | ||||
-rw-r--r-- | sys/dev/ic/if_wivar.h | 14 |
6 files changed, 1529 insertions, 52 deletions
diff --git a/sys/dev/ic/if_wi.c b/sys/dev/ic/if_wi.c index a8bf19ceeb1..21ffc2093d5 100644 --- a/sys/dev/ic/if_wi.c +++ b/sys/dev/ic/if_wi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wi.c,v 1.24 2002/03/28 17:41:02 mickey Exp $ */ +/* $OpenBSD: if_wi.c,v 1.25 2002/03/28 18:21:06 mickey Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -95,6 +95,8 @@ #include <machine/bus.h> +#include <dev/rndvar.h> + #include <dev/ic/if_wireg.h> #include <dev/ic/if_wi_ieee.h> #include <dev/ic/if_wivar.h> @@ -122,7 +124,7 @@ u_int32_t widebug = WIDEBUG; #if !defined(lint) && !defined(__OpenBSD__) static const char rcsid[] = - "$OpenBSD: if_wi.c,v 1.24 2002/03/28 17:41:02 mickey Exp $"; + "$OpenBSD: if_wi.c,v 1.25 2002/03/28 18:21:06 mickey Exp $"; #endif /* lint */ #ifdef foo @@ -150,7 +152,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 int wi_setdef(struct wi_softc *, struct wi_req *); -STATIC int wi_mgmt_xmit(struct wi_softc *, caddr_t, int); STATIC void wi_get_id(struct wi_softc *, int); STATIC int wi_media_change(struct ifnet *); @@ -254,24 +255,52 @@ wi_attach(sc, print_cis) bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats)); + /* Find supported rates. + */ + gen.wi_type = WI_RID_SUPPORT_RATE; + gen.wi_len = 2; + if (wi_read_record(sc, &gen)) + sc->wi_supprates = WI_SUPPRATES_1M | WI_SUPPRATES_2M | + WI_SUPPRATES_5M | WI_SUPPRATES_11M; + else + sc->wi_supprates = gen.wi_val; + ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status); #define ADD(m, c) ifmedia_add(&sc->sc_media, (m), (c), NULL) ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0); ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_ADHOC, 0), 0); - ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0); - ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, - IFM_IEEE80211_ADHOC, 0), 0); - ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0); - ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, - IFM_IEEE80211_ADHOC, 0), 0); - ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0); - ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, - IFM_IEEE80211_ADHOC, 0), 0); - ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0); - ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, - IFM_IEEE80211_ADHOC, 0), 0); - ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0); + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, + IFM_IEEE80211_HOSTAP, 0), 0); + if (sc->wi_supprates & WI_SUPPRATES_1M) { + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0); + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, + IFM_IEEE80211_ADHOC, 0), 0); + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, + IFM_IEEE80211_HOSTAP, 0), 0); + } + if (sc->wi_supprates & WI_SUPPRATES_2M) { + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0); + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, + IFM_IEEE80211_ADHOC, 0), 0); + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, + IFM_IEEE80211_HOSTAP, 0), 0); + } + if (sc->wi_supprates & WI_SUPPRATES_5M) { + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0); + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, + IFM_IEEE80211_ADHOC, 0), 0); + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, + IFM_IEEE80211_HOSTAP, 0), 0); + } + if (sc->wi_supprates & WI_SUPPRATES_11M) { + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0); + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, + IFM_IEEE80211_ADHOC, 0), 0); + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, + IFM_IEEE80211_HOSTAP, 0), 0); + ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0); + } #undef ADD ifmedia_set(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0)); @@ -401,6 +430,42 @@ wi_rxeof(sc) eh = mtod(m, struct ether_header *); m->m_pkthdr.rcvif = ifp; + 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) { + printf("%s: oversized mgmt packet received in " + "hostap mode (wi_dat_len=%d, wi_status=0x%x)\n", + sc->sc_dev.dv_xname, + 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); + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap: failed to copy header\n"); + 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; + } + if (rx_frame.wi_status == htole16(WI_STAT_1042) || rx_frame.wi_status == htole16(WI_STAT_TUNNEL) || rx_frame.wi_status == htole16(WI_STAT_WMP_MSG)) { @@ -454,6 +519,16 @@ wi_rxeof(sc) ifp->if_ipackets++; + 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; + } + #if NBPFILTER > 0 /* Handle BPF listeners. */ if (ifp->if_bpf) @@ -703,7 +778,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 (ltv->wi_val & htole16(0x01)) oltv->wi_val = htole16(1); @@ -752,7 +827,13 @@ wi_write_record(sc, ltv) p2ltv.wi_type = WI_RID_P2_ENCRYPTION; p2ltv.wi_len = 2; if (ltv->wi_val & htole16(0x01)) - p2ltv.wi_val = htole16(0x03); + if (sc->wi_ptype == WI_PORTTYPE_AP) + /* Disable tx encryption... + * it's broken. + */ + p2ltv.wi_val = htole16(0x13); + else + p2ltv.wi_val = htole16(0x03); else p2ltv.wi_val = htole16(0x90); ltv = &p2ltv; @@ -783,8 +864,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 (ltv->wi_val == htole16(1)) p2ltv.wi_val = htole16(0x01); @@ -1059,7 +1140,7 @@ wi_setdef(sc, wreq) case WI_RID_MAX_SLEEP: sc->wi_max_sleep = letoh16(wreq->wi_val[0]); break; - case WI_RID_AUTH_CNTL: + case WI_RID_CNFAUTHMODE: sc->wi_authtype = letoh16(wreq->wi_val[0]); break; case WI_RID_ROAMING_MODE: @@ -1271,6 +1352,15 @@ wi_ioctl(ifp, command, data) case SIOCG80211POWER: error = wi_get_pm(sc, (struct ieee80211_power *)data); break; + 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; default: error = EINVAL; break; @@ -1374,7 +1464,7 @@ wi_init(xsc) /* firm ver < 0.8 variant 3 */ WI_SETVAL(WI_RID_PROMISC, 1); } - WI_SETVAL(WI_RID_AUTH_CNTL, sc->wi_authtype); + WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype); } } @@ -1397,6 +1487,8 @@ wi_init(xsc) /* enable interrupts */ CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); + wihap_init(sc); + splx(s); ifp->if_flags |= IFF_RUNNING; @@ -1407,6 +1499,16 @@ wi_init(xsc) return; } +static void +wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len) +{ + if (!sc->wi_icv_flag) { + sc->wi_icv = arc4random(); + sc->wi_icv_flag++; + } + +} + STATIC void wi_start(ifp) struct ifnet *ifp; @@ -1427,6 +1529,7 @@ wi_start(ifp) if (ifp->if_flags & IFF_OACTIVE) return; +nextpkt: IFQ_DEQUEUE(&ifp->if_snd, m0); if (m0 == NULL) return; @@ -1435,6 +1538,18 @@ wi_start(ifp) id = sc->wi_tx_data_id; eh = mtod(m0, struct ether_header *); + if (sc->wi_ptype == WI_PORTTYPE_AP) { + if (!(ifp->if_flags & IFF_PROMISC) && + !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 %s\n", + ether_sprintf(eh->ether_dhost)); + m_freem(m0); + goto nextpkt; + } + } + /* * Use RFC1042 encoding for IP and ARP datagrams, * 802.3 for anything else. @@ -1445,8 +1560,18 @@ wi_start(ifp) ntohs(eh->ether_type) == ETHERTYPE_IPV6) { 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); + 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 + 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, @@ -1459,23 +1584,54 @@ wi_start(ifp) 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); + 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, (caddr_t)&sc->wi_txbuf, - (m0->m_pkthdr.len - sizeof(struct ether_header)) + 2); + 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 { + 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 = htole16(m0->m_pkthdr.len); - m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&sc->wi_txbuf); + 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 { + 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); + } } #if NBPFILTER > 0 @@ -1525,8 +1681,9 @@ 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 = htole16(len - WI_SNAPHDR_LEN); - tx_frame.wi_len = htons(len - WI_SNAPHDR_LEN); + tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT); + tx_frame.wi_dat_len = len - sizeof(struct wi_80211_hdr); + tx_frame.wi_len = htole16(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, @@ -1546,6 +1703,8 @@ wi_stop(sc) { struct ifnet *ifp; + wihap_shutdown(sc); + if (sc->wi_gone) return; @@ -1598,7 +1757,7 @@ wi_get_id(sc, print_cis) struct wi_softc *sc; int print_cis; { - struct wi_ltv_ver ver; + struct wi_ltv_ver ver; struct wi_ltv_cis cis; const char *p; @@ -1723,7 +1882,7 @@ wi_sync_media(sc, ptype, txrate) subtype = IFM_IEEE80211_DS11; break; default: - subtype = IFM_MANUAL; /* Unable to represent */ + subtype = IFM_MANUAL; /* Unable to represent */ break; } @@ -1735,7 +1894,7 @@ wi_sync_media(sc, ptype, txrate) options &= ~IFM_IEEE80211_ADHOC; break; default: - subtype = IFM_MANUAL; /* Unable to represent */ + subtype = IFM_MANUAL; /* Unable to represent */ break; } media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options, @@ -1756,8 +1915,14 @@ wi_media_change(ifp) int otype = sc->wi_ptype; int orate = sc->wi_tx_rate; - if ((sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0) + if ((sc->sc_media.ifm_cur->ifm_media & + (IFM_IEEE80211_ADHOC|IFM_IEEE80211_HOSTAP)) == + (IFM_IEEE80211_ADHOC|IFM_IEEE80211_HOSTAP)) + return (EINVAL); + if ((sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC)) sc->wi_ptype = WI_PORTTYPE_ADHOC; + else if ((sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_HOSTAP)) + sc->wi_ptype = WI_PORTTYPE_AP; else sc->wi_ptype = WI_PORTTYPE_BSS; @@ -1818,8 +1983,7 @@ wi_set_nwkey(sc, nwkey) if (!sc->wi_has_wep) return ENODEV; - if (nwkey->i_defkid <= 0 || - nwkey->i_defkid > IEEE80211_WEP_NKID) + if (nwkey->i_defkid <= 0 || nwkey->i_defkid > IEEE80211_WEP_NKID) return EINVAL; memcpy(wk, &sc->wi_keys, sizeof(*wk)); for (i = 0; i < IEEE80211_WEP_NKID; i++) { diff --git a/sys/dev/ic/if_wi_hostap.c b/sys/dev/ic/if_wi_hostap.c new file mode 100644 index 00000000000..8351c9f735e --- /dev/null +++ b/sys/dev/ic/if_wi_hostap.c @@ -0,0 +1,1131 @@ +/* $OpenBSD: if_wi_hostap.c,v 1.1 2002/03/28 18:21:06 mickey Exp $ */ + +/* + * 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. + * + */ + +/* This is experimental Host AP software for Prism 2 802.11b interfaces. + * + * Much of this is based upon the "Linux Host AP driver Host AP driver + * for Intersil Prism2" by Jouni Malinen <jkm@ssh.com> or <jkmaline@cc.hut.fi>. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/timeout.h> +#include <sys/proc.h> +#include <sys/ucred.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <sys/syslog.h> +#include <sys/sysctl.h> +#include <sys/device.h> + +#include <machine/bus.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> + +#include <net/if_ieee80211.h> + +#include <dev/ic/if_wireg.h> +#include <dev/ic/if_wi_ieee.h> +#include <dev/ic/if_wivar.h> + +void wihap_sta_timeout(void *v); +void wihap_sta_delete(struct wihap_sta_info *sta); + +/* + * take_hword() + * + * Used for parsing management frames. The pkt pointer and length + * variables are updated after the value is removed. + */ +static __inline u_int16_t +take_hword(caddr_t *ppkt, int *plen) +{ + u_int16_t s = letoh16(* (u_int16_t *) *ppkt); + *ppkt += sizeof(u_int16_t); + *plen -= sizeof(u_int16_t); + return s; +} + +/* take_tlv() + * + * Parse out TLV element from a packet, check for underflow of packet + * or overflow of buffer, update pkt/len. + */ +static int +take_tlv(caddr_t *ppkt, int *plen, int id_expect, void *dst, int maxlen) +{ + u_int8_t id, len; + + if (*plen < 2) + return -1; + + id = ((u_int8_t *)*ppkt)[0]; + len = ((u_int8_t *)*ppkt)[1]; + + if (id != id_expect || *plen < len+2 || maxlen < len) + return -1; + + bcopy(*ppkt+2, dst, len); + *plen -= 2+len; + *ppkt += 2+len; + + return len; +} + +/* put_hword() + * Put half-word element into management frames. + */ +static __inline void +put_hword(caddr_t *ppkt, u_int16_t s) +{ + * (u_int16_t *) *ppkt = htole16(s); + *ppkt += sizeof(u_int16_t); +} + +/* put_tlv() + * Put TLV elements into management frames. + */ +static void +put_tlv(caddr_t *ppkt, u_int8_t id, void *src, u_int8_t len) +{ + (*ppkt)[0] = id; + (*ppkt)[1] = len; + bcopy(src, (*ppkt)+2, len); + *ppkt += 2+len; +} + +static int +put_rates(caddr_t *ppkt, u_int16_t rates) +{ + int len = 0; + u_int8_t ratebuf[8]; + + if (rates & WI_SUPPRATES_1M) + ratebuf[len++] = 0x82; + if (rates & WI_SUPPRATES_2M) + ratebuf[len++] = 0x84; + if (rates & WI_SUPPRATES_5M) + ratebuf[len++] = 0x8b; + if (rates & WI_SUPPRATES_11M) + ratebuf[len++] = 0x96; + + put_tlv(ppkt, IEEE80211_ELEMID_RATES, ratebuf, len); + return len; +} + +/* wihap_init() + * + * Initialize host AP data structures. Called even if port type is + * not AP. + */ +void +wihap_init(struct wi_softc *sc) +{ + int i; + struct wihap_info *whi = &sc->wi_hostap_info; + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_init: sc=0x%x whi=0x%x\n", (int)sc, (int)whi); + + bzero(whi, sizeof(struct wihap_info)); + + if (sc->wi_ptype != WI_PORTTYPE_AP) + return; + + whi->apflags = WIHAPFL_ACTIVE; + + LIST_INIT(&whi->sta_list); + for (i=0; i<WI_STA_HASH_SIZE; i++) + LIST_INIT(&whi->sta_hash[i]); + + whi->inactivity_time = WIHAP_DFLT_INACTIVITY_TIME; +} + +/* wihap_sta_disassoc() + * + * Send a disassociation frame to a specified station. + */ +static void +wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason) +{ + struct wi_80211_hdr *resp_hdr; + caddr_t pkt; + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("Sending disassoc to sta %s\n", ether_sprintf(sta_addr)); + + /* Send disassoc packet. */ + resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf; + bzero(resp_hdr, sizeof(struct wi_80211_hdr)); + resp_hdr->frame_ctl = WI_FTYPE_MGMT | WI_STYPE_MGMT_DISAS; + pkt = sc->wi_txbuf + sizeof(struct wi_80211_hdr); + + bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN); + bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN); + bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr3, ETHER_ADDR_LEN); + + put_hword(&pkt, reason); + + wi_mgmt_xmit(sc, sc->wi_txbuf, 2+sizeof(struct wi_80211_hdr)); +} + +/* wihap_sta_deauth() + * + * Send a deauthentication message to a specified station. + */ +static void +wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason) +{ + struct wi_80211_hdr *resp_hdr; + caddr_t pkt; + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("Sending deauth to sta %s\n", ether_sprintf(sta_addr)); + + /* Send deauth packet. */ + resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf; + bzero(resp_hdr, sizeof(struct wi_80211_hdr)); + resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_DEAUTH); + pkt = sc->wi_txbuf + sizeof(struct wi_80211_hdr); + + bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN); + bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN); + bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr3, ETHER_ADDR_LEN); + + put_hword(&pkt, reason); + + wi_mgmt_xmit(sc, sc->wi_txbuf, 2+sizeof(struct wi_80211_hdr)); +} + +/* wihap_shutdown() + * + * Disassociate all stations and free up data structures. + */ +void +wihap_shutdown(struct wi_softc *sc) +{ + struct wihap_info *whi = &sc->wi_hostap_info; + struct wihap_sta_info *sta, *next; + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_shutdown: sc=0x%x whi=0x%x\n", + (int)sc, (int)whi); + + if (!(whi->apflags & WIHAPFL_ACTIVE)) + return; + + /* XXX: I read somewhere you can deauth all the stations with + * a single broadcast. Maybe try that someday. + */ + + sta = LIST_FIRST(&whi->sta_list); + while (sta) { + + if (!sc->wi_gone) { + /* Disassociate station. */ + if (sta->flags & WI_SIFLAGS_ASSOC) + wihap_sta_disassoc(sc, sta->addr, + IEEE80211_REASON_ASSOC_LEAVE); + /* Deauth station. */ + if (sta->flags & WI_SIFLAGS_AUTHEN) + wihap_sta_deauth(sc, sta->addr, + IEEE80211_REASON_AUTH_LEAVE); + } + + /* Delete the structure. */ + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_shutdown: FREE(sta=0x%x)\n", (int) sta); + next = LIST_NEXT(sta, list); + FREE(sta, M_DEVBUF); + sta = next; + } + + whi->apflags = 0; +} + +/* sta_hash_func() + * Hash function for finding stations from ethernet address. + */ +static __inline int +sta_hash_func(u_int8_t addr[]) +{ + return ((addr[3] + addr[4] + addr[5]) % WI_STA_HASH_SIZE); +} + +/* addr_cmp(): Maybe this is a faster way to compare addresses? */ +static __inline int +addr_cmp(u_int8_t a[], u_int8_t b[]) +{ + return (*(u_int16_t *)(a+4) == *(u_int16_t *)(b+4) && + *(u_int32_t *)a == *(u_int32_t *)b); +} + +void +wihap_sta_timeout(void *v) +{ + struct wihap_sta_info *sta = v; + struct wi_softc *sc = sta->sc; + int s; + + s = splimp(); + + if (sta->flags & WI_SIFLAGS_ASSOC) { + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_timer: disassoc due to inactivity: %s\n", + ether_sprintf(sta->addr)); + + /* Disassoc station. */ + wihap_sta_disassoc(sc, sta->addr, IEEE80211_REASON_ASSOC_EXPIRE); + sta->flags &= ~WI_SIFLAGS_ASSOC; + + } else if (sta->flags & WI_SIFLAGS_AUTHEN) { + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_timer: deauth due to inactivity: %s\n", + ether_sprintf(sta->addr)); + + /* Deauthenticate station. */ + wihap_sta_deauth(sc, sta->addr, IEEE80211_REASON_AUTH_EXPIRE); + sta->flags &= ~WI_SIFLAGS_AUTHEN; + + /* Delete the station if it's not permanent. */ + if (!(sta->flags & WI_SIFLAGS_PERM)) + wihap_sta_delete(sta); + } + splx(s); +} + +/* wihap_sta_delete() + * Delete a single station and free up its data structure. + */ +void +wihap_sta_delete(struct wihap_sta_info *sta) +{ + struct wi_softc *sc = sta->sc; + struct wihap_info *whi = &sc->wi_hostap_info; + int i = sta->asid - 0xc001; + + timeout_del(&sta->tmo); + + whi->asid_inuse_mask[i>>4] &= ~(1ul<<(i&0xf)); + + LIST_REMOVE(sta, list); + LIST_REMOVE(sta, hash); + FREE(sta, M_DEVBUF); + whi->n_stations--; +} + +/* wihap_sta_alloc() + * + * Create a new station data structure and put it in the list + * and hash table. + */ +static struct wihap_sta_info * +wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr) +{ + struct wihap_info *whi = &sc->wi_hostap_info; + struct wihap_sta_info *sta; + int i, hash = sta_hash_func(addr); + + /* Allocate structure. */ + MALLOC(sta, struct wihap_sta_info *, sizeof(struct wihap_sta_info), + M_DEVBUF, M_NOWAIT); + if (sta == NULL) + return(NULL); + + bzero(sta, sizeof(struct wihap_sta_info)); + + /* Allocate an ASID. */ + i=hash<<4; + while (whi->asid_inuse_mask[i>>4] & (1ul<<(i&0xf))) + i = (i==(WI_STA_HASH_SIZE<<4)-1) ? 0 : (i+1); + whi->asid_inuse_mask[i>>4] |= (1ul<<(i&0xf)); + sta->asid = 0xc001+i; + + /* Insert in list and hash list. */ + LIST_INSERT_HEAD(&whi->sta_list, sta, list); + LIST_INSERT_HEAD(&whi->sta_hash[hash], sta, hash); + + sta->sc = sc; + whi->n_stations++; + bcopy(addr, &sta->addr, ETHER_ADDR_LEN); + timeout_set(&sta->tmo, wihap_sta_timeout, sta); + timeout_add(&sta->tmo, hz * whi->inactivity_time); + + return(sta); +} + +/* wihap_sta_find() + * + * Find station structure given address. + */ +static struct wihap_sta_info * +wihap_sta_find(struct wihap_info *whi, u_int8_t *addr) +{ + int i; + struct wihap_sta_info *sta; + + i = sta_hash_func(addr); + LIST_FOREACH(sta, &whi->sta_hash[i], hash) + if (addr_cmp(addr,sta->addr)) + return sta; + + return(NULL); +} + +static int +wihap_check_rates(struct wihap_sta_info *sta, u_int8_t rates[], int rates_len) +{ + struct wi_softc *sc = sta->sc; + int i; + + sta->rates = 0; + sta->tx_max_rate = 0; + for (i=0; i<rates_len; i++) + switch (rates[i] & 0x7f) { + case 0x02: + sta->rates |= WI_SUPPRATES_1M; + break; + case 0x04: + sta->rates |= WI_SUPPRATES_2M; + if (sta->tx_max_rate<1) + sta->tx_max_rate = 1; + break; + case 0x0b: + sta->rates |= WI_SUPPRATES_5M; + if (sta->tx_max_rate<2) + sta->tx_max_rate = 2; + break; + case 0x16: + sta->rates |= WI_SUPPRATES_11M; + sta->tx_max_rate = 3; + break; + } + + sta->rates &= sc->wi_supprates; + sta->tx_curr_rate = sta->tx_max_rate; + + return (sta->rates == 0 ? -1 : 0); +} + + +/* wihap_auth_req() + * + * Handle incoming authentication request. Only handle OPEN + * requests. + */ +static void +wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm, + caddr_t pkt, int len) +{ + struct wihap_info *whi = &sc->wi_hostap_info; + struct wihap_sta_info *sta; + + u_int16_t algo; + u_int16_t seq; + u_int16_t status; + int challenge_len; + u_int8_t challenge[128]; + + struct wi_80211_hdr *resp_hdr; + + if (len<6) + return; + + /* Break open packet. */ + algo = take_hword(&pkt, &len); + seq = take_hword(&pkt, &len); + status = take_hword(&pkt, &len); + challenge_len=0; + if (len > 0 && (challenge_len=take_tlv(&pkt, &len, + IEEE80211_ELEMID_CHALLENGE, challenge, sizeof(challenge)))<0) + return; + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_auth_req: from station: %s\n", + ether_sprintf(rxfrm->wi_addr2)); + + switch (algo) { + case IEEE80211_AUTH_ALG_OPEN: + if (seq != 1) { + status = IEEE80211_STATUS_SEQUENCE; + goto fail; + } + challenge_len=0; + break; + case IEEE80211_AUTH_ALG_SHARED: + /* NOT YET */ + default: + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_auth_req: algorithm unsupported: %d\n", + algo); + status = IEEE80211_STATUS_ALG; + goto fail; + } + + sta = wihap_sta_find(whi, rxfrm->wi_addr2); + if (sta == NULL) { + + /* Are we allowing new stations? + */ + if (whi->apflags & WIHAPFL_MAC_FILT) { + status = IEEE80211_STATUS_OTHER; /* XXX */ + goto fail; + } + + /* Check for too many stations. + */ + if (whi->n_stations >= WIHAP_MAX_STATIONS) { + status = IEEE80211_STATUS_TOO_MANY_STATIONS; + goto fail; + } + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_auth_req: new station\n"); + + /* Create new station. */ + sta = wihap_sta_alloc(sc, rxfrm->wi_addr2); + if (sta == NULL) { + /* Out of memory! */ + status = IEEE80211_STATUS_TOO_MANY_STATIONS; + goto fail; + } + } + + sta->flags |= WI_SIFLAGS_AUTHEN; + timeout_add(&sta->tmo, hz * whi->inactivity_time); + status = IEEE80211_STATUS_SUCCESS; + +fail: + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_auth_req: returns status=0x%x\n", status); + + /* Send response. */ + resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf; + bzero(resp_hdr, sizeof(struct wi_80211_hdr)); + resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_AUTH); + bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN); + bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN); + bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr3, ETHER_ADDR_LEN); + + pkt = &sc->wi_txbuf[sizeof(struct wi_80211_hdr)]; + put_hword(&pkt, algo); + put_hword(&pkt, 2); + put_hword(&pkt, status); + if (challenge_len > 0) + put_tlv(&pkt, IEEE80211_ELEMID_CHALLENGE, + challenge, challenge_len); + + wi_mgmt_xmit(sc, sc->wi_txbuf, + 6 + sizeof(struct wi_80211_hdr) + + (challenge_len>0 ? challenge_len+2 : 0)); +} + + +/* wihap_assoc_req() + * + * Handle incoming association and reassociation requests. + */ +static void +wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, + caddr_t pkt, int len) +{ + struct wihap_info *whi = &sc->wi_hostap_info; + struct wihap_sta_info *sta; + struct wi_80211_hdr *resp_hdr; + u_int16_t capinfo; + u_int16_t lstintvl; + u_int8_t rates[8]; + int ssid_len, rates_len; + struct ieee80211_nwid ssid; + u_int16_t status; + u_int16_t asid = 0; + + if (len < 8) + return; + + /* Pull out request parameters. */ + capinfo = take_hword(&pkt, &len); + lstintvl = take_hword(&pkt, &len); + if ((ssid_len=take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID, + ssid.i_nwid, sizeof(ssid)-1))<0) + return; + ssid.i_len = ssid_len; + ssid.i_nwid[ssid_len] = '\0'; + if ((rates_len=take_tlv(&pkt, &len, IEEE80211_ELEMID_RATES, + rates, sizeof(rates)))<0) + return; + + if ((rxfrm->wi_frame_ctl & WI_FCTL_STYPE) == WI_STYPE_MGMT_REASREQ) { + /* Reassociation Request-- * Current AP. (Ignore?) */ + if (len < 6) + return; + } + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_assoc_req: from station %s\n", + ether_sprintf(rxfrm->wi_addr2)); + + /* If SSID doesn't match, simply drop. */ + if (sc->wi_net_name.i_len != ssid.i_len || + memcmp(sc->wi_net_name.i_nwid, ssid.i_nwid, ssid.i_len)) { + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_assoc_req: bad ssid: '%s' != '%s'\n", + ssid.i_nwid, sc->wi_net_name.i_nwid); + return; + } + + /* Is this station authenticated yet? */ + sta = wihap_sta_find(whi, rxfrm->wi_addr2); + if (sta == NULL || !(sta->flags & WI_SIFLAGS_AUTHEN)) { + wihap_sta_deauth(sc, rxfrm->wi_addr2, + IEEE80211_REASON_NOT_AUTHED); + return; + } + + /* Check capinfo. + * Check for ESS, not IBSS. + * Check WEP/PRIVACY flags match. XXX: WEP doesn't work for host AP. + * Refuse stations requesting to be put on CF-polling list. + */ + if ((capinfo & (IEEE80211_CAPINFO_ESS|IEEE80211_CAPINFO_IBSS)) != + IEEE80211_CAPINFO_ESS || + (sc->wi_use_wep && !(capinfo & IEEE80211_CAPINFO_PRIVACY)) || + (!sc->wi_use_wep && (capinfo & IEEE80211_CAPINFO_PRIVACY)) || + (capinfo & (IEEE80211_CAPINFO_CF_POLLABLE| + IEEE80211_CAPINFO_CF_POLLREQ)) == + IEEE80211_CAPINFO_CF_POLLABLE) { + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_assoc_req: capinfo mismatch: " + "capinfo=0x%x\n", capinfo); + + status = IEEE80211_STATUS_CAPINFO; + goto fail; + } + sta->capinfo = capinfo; + + /* Check supported rates against ours. */ + if (wihap_check_rates(sta, rates, rates_len)<0) { + status = IEEE80211_STATUS_RATES; + goto fail; + } + + /* Use ASID is allocated by whi_sta_alloc(). */ + asid = sta->asid; + + if (sta->flags & WI_SIFLAGS_ASSOC) { + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_assoc_req: already assoc'ed?\n"); + } + + sta->flags |= WI_SIFLAGS_ASSOC; + timeout_add(&sta->tmo, hz * whi->inactivity_time); + status = IEEE80211_STATUS_SUCCESS; + +fail: + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_assoc_req: returns status=0x%x\n", status); + + /* Send response. */ + resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf; + bzero(resp_hdr, sizeof(struct wi_80211_hdr)); + resp_hdr->frame_ctl = WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP; + pkt = sc->wi_txbuf + sizeof(struct wi_80211_hdr); + + bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN); + bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN); + bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr3, ETHER_ADDR_LEN); + + put_hword(&pkt, capinfo); + put_hword(&pkt, status); + put_hword(&pkt, asid); + rates_len=put_rates(&pkt, sc->wi_supprates); + + wi_mgmt_xmit(sc, sc->wi_txbuf, + 8+rates_len+sizeof(struct wi_80211_hdr)); +} + +/* wihap_deauth_req() + * + * Handle deauthentication requests. Delete the station. + */ +static void +wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm, + caddr_t pkt, int len) +{ + struct wihap_info *whi = &sc->wi_hostap_info; + struct wihap_sta_info *sta; + u_int16_t reason; + + if (len<2) + return; + + reason = take_hword(&pkt, &len); + + sta = wihap_sta_find(whi, rxfrm->wi_addr2); + if (sta == NULL) { + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_deauth_req: unknown station: 6D\n", + rxfrm->wi_addr2, ":"); + } + else + wihap_sta_delete(sta); +} + +/* wihap_disassoc_req() + * + * Handle disassociation requests. Just reset the assoc flag. + * We'll free up the station resources when we get a deauth + * request or when it times out. + */ +static void +wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, + caddr_t pkt, int len) +{ + struct wihap_info *whi = &sc->wi_hostap_info; + struct wihap_sta_info *sta; + u_int16_t reason; + + if (len<2) + return; + + reason = take_hword(&pkt, &len); + + sta = wihap_sta_find(whi, rxfrm->wi_addr2); + if (sta == NULL) { + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_disassoc_req: unknown station: 6D\n", + rxfrm->wi_addr2, ":"); + } + else if (!(sta->flags & WI_SIFLAGS_AUTHEN)) { + /* If station is not authenticated, send deauthentication + * frame. + */ + wihap_sta_deauth(sc, rxfrm->wi_addr2, + IEEE80211_REASON_NOT_AUTHED); + return; + } + else + sta->flags &= ~WI_SIFLAGS_ASSOC; +} + +/* wihap_debug_frame_type() + * + * Print out frame type. Used in early debugging. + */ +static void +wihap_debug_frame_type(struct wi_frame *rxfrm) +{ + printf("wihap_mgmt_input: len=%d ", rxfrm->wi_dat_len); + + if ((letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_FTYPE) == WI_FTYPE_MGMT) { + + printf("MGMT: "); + + switch (letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) { + case WI_STYPE_MGMT_ASREQ: + printf("assoc req: \n"); + break; + case WI_STYPE_MGMT_ASRESP: + printf("assoc resp: \n"); + break; + case WI_STYPE_MGMT_REASREQ: + printf("reassoc req: \n"); + break; + case WI_STYPE_MGMT_REASRESP: + printf("reassoc resp: \n"); + break; + case WI_STYPE_MGMT_PROBEREQ: + printf("probe req: \n"); + break; + case WI_STYPE_MGMT_PROBERESP: + printf("probe resp: \n"); + break; + case WI_STYPE_MGMT_BEACON: + printf("beacon: \n"); + break; + case WI_STYPE_MGMT_ATIM: + printf("ann traf ind \n"); + break; + case WI_STYPE_MGMT_DISAS: + printf("disassociation: \n"); + break; + case WI_STYPE_MGMT_AUTH: + printf("auth: \n"); + break; + case WI_STYPE_MGMT_DEAUTH: + printf("deauth: \n"); + break; + default: + printf("unknown (stype=0x%x)\n", + letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE); + } + + } + else { + printf("ftype=0x%x (ctl=0x%x)\n", + letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_FTYPE, + letoh16(rxfrm->wi_frame_ctl)); + } +} + +/* + * wihap_mgmt_input: + * + * Called for each management frame received in host ap mode. + * wihap_mgmt_input() is expected to free the mbuf. + */ +void +wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) +{ + caddr_t pkt; + int len; + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + wihap_debug_frame_type(rxfrm); + + pkt = mtod(m, caddr_t) + WI_802_11_OFFSET_RAW; + len = m->m_len - WI_802_11_OFFSET_RAW; + + if ((rxfrm->wi_frame_ctl & WI_FCTL_FTYPE) == WI_FTYPE_MGMT) { + + switch (letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) { + case WI_STYPE_MGMT_ASREQ: + wihap_assoc_req(sc, rxfrm, pkt, len); + break; + case WI_STYPE_MGMT_ASRESP: + break; + case WI_STYPE_MGMT_REASREQ: + wihap_assoc_req(sc, rxfrm, pkt, len); + break; + case WI_STYPE_MGMT_REASRESP: + break; + case WI_STYPE_MGMT_PROBEREQ: + break; + case WI_STYPE_MGMT_PROBERESP: + break; + case WI_STYPE_MGMT_BEACON: + break; + case WI_STYPE_MGMT_ATIM: + break; + case WI_STYPE_MGMT_DISAS: + wihap_disassoc_req(sc, rxfrm, pkt, len); + break; + case WI_STYPE_MGMT_AUTH: + wihap_auth_req(sc, rxfrm, pkt, len); + break; + case WI_STYPE_MGMT_DEAUTH: + wihap_deauth_req(sc, rxfrm, pkt, len); + break; + } + + } + + m_freem(m); +} + +/* wihap_sta_is_assoc() + * + * Determine if a station is assoc'ed. Update its activity + * counter as a side-effect. + */ +static int +wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]) +{ + struct wihap_sta_info *sta; + + sta = wihap_sta_find(whi, addr); + if (sta!=NULL && (sta->flags & WI_SIFLAGS_ASSOC)) { + /* Keep it active. */ + timeout_add(&sta->tmo, hz * whi->inactivity_time); + return(1); + } + else + return(0); +} + +/* wihap_check_tx() + * + * Determine if a station is assoc'ed, get its tx rate, and update + * its activity. + */ +int +wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate) +{ + struct wihap_sta_info *sta; + static u_int8_t txratetable[] = { 10, 20, 55, 110 }; + + if (addr[0] & 0x01) { + *txrate = 0; /* XXX: multicast rate? */ + return(1); + } + sta = wihap_sta_find(whi, addr); + if (sta!=NULL && (sta->flags & WI_SIFLAGS_ASSOC)) { + /* Keep it active. */ + timeout_add(&sta->tmo, hz * whi->inactivity_time); + *txrate = txratetable[ sta->tx_curr_rate ]; + return(1); + } + return(0); +} + +/* + * wihap_data_input() + * + * Handle all data input on interface when in Host AP mode. + * Some packets are destined for this machine, others are + * repeated to other stations. + * + * If wihap_data_input() returns a non-zero, it has processed + * the packet and will free the mbuf. + */ +int +wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct wihap_info *whi = &sc->wi_hostap_info; + struct wihap_sta_info *sta; + int mcast; + + /* TODS flag must be set. */ + if (!(letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_TODS)) { + if (ifp->if_flags & IFF_DEBUG) + printf("wihap_data_input: no TODS src=%s\n", + ether_sprintf(rxfrm->wi_addr2)); + return(1); + } + + /* Check BSSID. (Is this necessary?) */ + if (!addr_cmp(rxfrm->wi_addr1, sc->arpcom.ac_enaddr)) { + if (ifp->if_flags & IFF_DEBUG) + printf("wihap_data_input: incorrect bss: %s\n", + ether_sprintf(rxfrm->wi_addr1)); + return(1); + } + + /* Find source station. */ + sta = wihap_sta_find(whi, rxfrm->wi_addr2); + + /* Source station must be associated. */ + if (sta == NULL || !(sta->flags & WI_SIFLAGS_ASSOC)) { + if (ifp->if_flags & IFF_DEBUG) + printf("wihap_data_input: dropping unassoc src %s\n", + ether_sprintf(rxfrm->wi_addr2)); + return(1); + } + + timeout_add(&sta->tmo, hz * whi->inactivity_time); + sta->sig_info = rxfrm->wi_q_info; + + /* Repeat this packet to BSS? */ + mcast = (rxfrm->wi_addr3[0] & 0x01) != 0; + if (mcast || wihap_sta_is_assoc(whi, rxfrm->wi_addr3)) { + + /* If it's multicast, make a copy. + */ + if (mcast) { + m = m_copym(m, 0, M_COPYALL, M_DONTWAIT); + if (m == NULL) + return(0); + m->m_flags |= M_MCAST; /* XXX */ + } + + /* Queue up for repeating. + */ + if (IF_QFULL(&ifp->if_snd)) { + IF_DROP(&ifp->if_snd); + m_freem(m); + } + else { + ifp->if_obytes += m->m_pkthdr.len; + if (m->m_flags & M_MCAST) + ifp->if_omcasts++; + IF_ENQUEUE(&ifp->if_snd, m); + if ((ifp->if_flags & IFF_OACTIVE) == 0) + (*ifp->if_start)(ifp); + } + return (!mcast); + } + + return (0); +} + +/* wihap_ioctl() + * + * Handle Host AP specific ioctls. Called from wi_ioctl(). + */ +int +wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) +{ + struct proc *p = curproc; + struct ifreq *ifr = (struct ifreq *) data; + struct wihap_info *whi = &sc->wi_hostap_info; + struct wihap_sta_info *sta; + struct hostap_getall reqall; + struct hostap_sta reqsta; + struct hostap_sta stabuf; + int error = 0, n, flag; + + if (!(sc->arpcom.ac_if.if_flags & IFF_RUNNING)) + return ENODEV; + + switch (command) { + case SIOCHOSTAP_DEL: + if ((error = suser(p->p_ucred, &p->p_acflag))) + break; + if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) + break; + sta = wihap_sta_find(whi, reqsta.addr); + if (sta == NULL) + error = ENOENT; + else { + /* Disassociate station. */ + if (sta->flags & WI_SIFLAGS_ASSOC) + wihap_sta_disassoc(sc, sta->addr, + IEEE80211_REASON_ASSOC_LEAVE); + /* Deauth station. */ + if (sta->flags & WI_SIFLAGS_AUTHEN) + wihap_sta_deauth(sc, sta->addr, + IEEE80211_REASON_AUTH_LEAVE); + + wihap_sta_delete(sta); + } + break; + + case SIOCHOSTAP_GET: + if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) + break; + sta = wihap_sta_find(whi, reqsta.addr); + if (sta == NULL) + error = ENOENT; + else { + reqsta.flags = sta->flags; + reqsta.asid = sta->asid; + reqsta.capinfo = sta->capinfo; + reqsta.sig_info = sta->sig_info; + reqsta.rates = sta->rates; + + error = copyout(&reqsta, ifr->ifr_data, + sizeof(reqsta)); + } + break; + + case SIOCHOSTAP_ADD: + if ((error = suser(p->p_ucred, &p->p_acflag))) + break; + if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) + break; + sta = wihap_sta_find(whi, reqsta.addr); + if (sta != NULL) { + error = EEXIST; + break; + } + if (whi->n_stations >= WIHAP_MAX_STATIONS) { + error = ENOSPC; + break; + } + sta = wihap_sta_alloc(sc, reqsta.addr); + sta->flags = reqsta.flags; + timeout_add(&sta->tmo, hz * whi->inactivity_time); + break; + + case SIOCHOSTAP_SFLAGS: + if ((error = suser(p->p_ucred, &p->p_acflag))) + break; + if ((error = copyin(ifr->ifr_data, &flag, sizeof(int)))) + break; + + whi->apflags = + (whi->apflags & WIHAPFL_CANTCHANGE) | + (flag & ~WIHAPFL_CANTCHANGE); + break; + + case SIOCHOSTAP_GFLAGS: + flag = (int) whi->apflags; + error = copyout(&flag, ifr->ifr_data, sizeof(int)); + break; + + case SIOCHOSTAP_GETALL: + if ((error = copyin(ifr->ifr_data, &reqall, sizeof(reqall)))) + break; + + reqall.nstations = whi->n_stations; + n = 0; + sta = LIST_FIRST(&whi->sta_list); + while (sta && reqall.size >= n+sizeof(struct hostap_sta)) { + + bcopy(sta->addr, stabuf.addr, ETHER_ADDR_LEN); + stabuf.asid = sta->asid; + stabuf.flags = sta->flags; + stabuf.capinfo = sta->capinfo; + stabuf.sig_info = sta->sig_info; + stabuf.rates = sta->rates; + + error = copyout(&stabuf, (caddr_t) reqall.addr + n, + sizeof(struct hostap_sta)); + if (error) + break; + + sta = LIST_NEXT(sta, list); + n += sizeof(struct hostap_sta); + } + + if (!error) + error = copyout(&reqall, ifr->ifr_data, + sizeof(reqall)); + break; + default: + printf("wihap_ioctl: i shouldn't get other ioctls!\n"); + error = EINVAL; + } + + return(error); +} diff --git a/sys/dev/ic/if_wi_hostap.h b/sys/dev/ic/if_wi_hostap.h new file mode 100644 index 00000000000..0136a912dcc --- /dev/null +++ b/sys/dev/ic/if_wi_hostap.h @@ -0,0 +1,137 @@ +/* $OpenBSD: if_wi_hostap.h,v 1.1 2002/03/28 18:21:06 mickey Exp $ */ + +/* + * 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; + + struct wi_softc *sc; + u_int8_t addr[6]; + u_short flags; + struct timeout tmo; + + 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; +}; + +#define WIHAP_INTERVAL 5 +#define WIHAP_DFLT_INACTIVITY_TIME (120/WIHAP_INTERVAL) /* 2 minutes */ + +struct wi_softc; +struct wi_frame; + +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__ */ diff --git a/sys/dev/ic/if_wi_ieee.h b/sys/dev/ic/if_wi_ieee.h index fe05f082acc..55f15dead52 100644 --- a/sys/dev/ic/if_wi_ieee.h +++ b/sys/dev/ic/if_wi_ieee.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wi_ieee.h,v 1.3 2001/06/07 18:51:59 millert Exp $ */ +/* $OpenBSD: if_wi_ieee.h,v 1.4 2002/03/28 18:21:06 mickey Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -31,12 +31,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * From: if_wavelan_ieee.h,v 1.1 1999/05/05 07:36:50 wpaul Exp $ + * From: if_wavelan_ieee.h,v 1.5.2.1 2001/07/04 00:12:34 brooks Exp $ */ #ifndef _IF_WI_IEEE_H #define _IF_WI_IEEE_H +#pragma pack(1) + /* * This header defines a simple command interface to the FreeBSD * WaveLAN/IEEE driver (wi) driver, which is used to set certain @@ -82,6 +84,7 @@ struct wi_req { */ #define WI_RID_IFACE_STATS 0x0100 #define WI_RID_MGMT_XMIT 0x0200 +#define WI_RID_MONITOR_MODE 0x0500 struct wi_80211_hdr { u_int16_t frame_ctl; @@ -121,6 +124,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; @@ -204,7 +214,7 @@ struct wi_counters { #define WI_RID_P2_CRYPT_KEY3 0xFC27 #define WI_RID_P2_ENCRYPTION 0xFC28 #define WI_RID_WEP_MAPTABLE 0xFC29 -#define WI_RID_AUTH_CNTL 0xFC2A +#define WI_RID_CNFAUTHMODE 0xFC2A #define WI_RID_ROAMING_MODE 0xFC2D /* Roaming mode (1:firm,3:disable) */ #define WI_RID_BASIC_RATE 0xFCB3 #define WI_RID_SUPPORT_RATE 0xFCB4 @@ -314,4 +324,6 @@ struct wi_ltv_keys { #define WI_RID_MAC_PROC_DELAY 0xFDC5 /* MAC processing delay time */ #define WI_RID_DATA_RATES 0xFDC6 /* supported data rates */ +#pragma pack() + #endif diff --git a/sys/dev/ic/if_wireg.h b/sys/dev/ic/if_wireg.h index 9c94588db8d..de160672076 100644 --- a/sys/dev/ic/if_wireg.h +++ b/sys/dev/ic/if_wireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wireg.h,v 1.13 2002/03/28 17:41:02 mickey Exp $ */ +/* $OpenBSD: if_wireg.h,v 1.14 2002/03/28 18:21:06 mickey Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -31,9 +31,11 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * From: if_wireg.h,v 1.5 1999/07/20 20:03:42 wpaul Exp $ + * From: if_wireg.h,v 1.8.2.2 2001/08/25 00:48:25 nsayer Exp $ */ +#pragma pack(1) + #define WI_TIMEOUT 50000 /* 10x XXX just a guess at a good value. */ #define WI_PORT0 0 @@ -442,9 +444,11 @@ struct wi_ltv_pcf { * 2 == Wireless Distribudion System (WDS) * 3 == Pseudo IBSS */ +#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. @@ -484,6 +488,14 @@ struct wi_ltv_mcast { }; /* + * Supported rates. + */ +#define WI_SUPPRATES_1M 0x0001 +#define WI_SUPPRATES_2M 0x0002 +#define WI_SUPPRATES_5M 0x0004 +#define WI_SUPPRATES_11M 0x0008 + +/* * Information frame types. */ #define WI_INFO_NOTIFY 0xF000 /* Handover address */ @@ -501,7 +513,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; /* 0x0A */ u_int16_t wi_tx_ctl; /* 0x0C */ u_int16_t wi_frame_ctl; /* 0x0E */ u_int16_t wi_id; /* 0x10 */ @@ -521,6 +534,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 @@ -529,10 +543,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 @@ -540,6 +556,10 @@ 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 @@ -553,3 +573,6 @@ 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 + +#pragma pack() diff --git a/sys/dev/ic/if_wivar.h b/sys/dev/ic/if_wivar.h index baf95856f73..309bbf750ab 100644 --- a/sys/dev/ic/if_wivar.h +++ b/sys/dev/ic/if_wivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wivar.h,v 1.5 2002/02/19 01:24:58 mickey Exp $ */ +/* $OpenBSD: if_wivar.h,v 1.6 2002/03/28 18:21:06 mickey Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -31,9 +31,11 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * From: if_wireg.h,v 1.5 1999/07/20 20:03:42 wpaul Exp $ + * From: if_wireg.h,v 1.8.2.2 2001/08/25 00:48:25 nsayer Exp $ */ +#include <dev/ic/if_wi_hostap.h> + struct wi_softc { #ifndef __FreeBSD__ struct device sc_dev; @@ -59,6 +61,7 @@ struct wi_softc { u_int16_t wi_max_sleep; u_int16_t wi_authtype; u_int16_t wi_roaming; + u_int16_t wi_supprates; struct ieee80211_nwid wi_node_name; struct ieee80211_nwid wi_net_name; @@ -67,15 +70,22 @@ struct wi_softc { u_int8_t wi_txbuf[1596]; int wi_has_wep; int wi_use_wep; + int wi_authmode; int wi_tx_key; struct wi_ltv_keys wi_keys; struct wi_counters wi_stats; void *sc_ih; struct timeout sc_timo; + int sc_enabled; int sc_prism2; int sc_prism2_ver; int sc_pci; + struct wihap_info wi_hostap_info; + u_int32_t wi_icv; + int wi_icv_flag; }; #define WI_PRT_FMT "%s" #define WI_PRT_ARG(sc) (sc)->sc_dev.dv_xname + +int wi_mgmt_xmit(struct wi_softc *, caddr_t, int); |