diff --git a/sys/net/if_ieee80211.h b/sys/net/if_ieee80211.h deleted file mode 100644 index 7e5d04bbe5fd..000000000000 --- a/sys/net/if_ieee80211.h +++ /dev/null @@ -1,614 +0,0 @@ -/* $NetBSD: if_ieee80211.h,v 1.23 2002/10/15 08:51:50 onoe Exp $ */ -/* $FreeBSD$ */ - -/*- - * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. - * 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 the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 THE FOUNDATION OR CONTRIBUTORS - * 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. - */ - -#ifndef _NET_IF_IEEE80211_H_ -#define _NET_IF_IEEE80211_H_ - -#include -#include - -#define IEEE80211_ADDR_LEN ETHER_ADDR_LEN - -/* - * generic definitions for IEEE 802.11 frames - */ -struct ieee80211_frame { - u_int8_t i_fc[2]; - u_int8_t i_dur[2]; - u_int8_t i_addr1[IEEE80211_ADDR_LEN]; - u_int8_t i_addr2[IEEE80211_ADDR_LEN]; - u_int8_t i_addr3[IEEE80211_ADDR_LEN]; - u_int8_t i_seq[2]; - /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ - /* see below */ -} __attribute__((__packed__)); - -struct ieee80211_frame_addr4 { - u_int8_t i_fc[2]; - u_int8_t i_dur[2]; - u_int8_t i_addr1[IEEE80211_ADDR_LEN]; - u_int8_t i_addr2[IEEE80211_ADDR_LEN]; - u_int8_t i_addr3[IEEE80211_ADDR_LEN]; - u_int8_t i_seq[2]; - u_int8_t i_addr4[IEEE80211_ADDR_LEN]; -} __attribute__((__packed__)); - -#define IEEE80211_FC0_VERSION_MASK 0x03 -#define IEEE80211_FC0_VERSION_SHIFT 0 -#define IEEE80211_FC0_VERSION_0 0x00 -#define IEEE80211_FC0_TYPE_MASK 0x0c -#define IEEE80211_FC0_TYPE_SHIFT 2 -#define IEEE80211_FC0_TYPE_MGT 0x00 -#define IEEE80211_FC0_TYPE_CTL 0x04 -#define IEEE80211_FC0_TYPE_DATA 0x08 - -#define IEEE80211_FC0_SUBTYPE_MASK 0xf0 -#define IEEE80211_FC0_SUBTYPE_SHIFT 4 -/* for TYPE_MGT */ -#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 -#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 -#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 -#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 -#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 -#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 -#define IEEE80211_FC0_SUBTYPE_BEACON 0x80 -#define IEEE80211_FC0_SUBTYPE_ATIM 0x90 -#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 -#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 -#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 -/* for TYPE_CTL */ -#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0 -#define IEEE80211_FC0_SUBTYPE_RTS 0xb0 -#define IEEE80211_FC0_SUBTYPE_CTS 0xc0 -#define IEEE80211_FC0_SUBTYPE_ACK 0xd0 -#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0 -#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0 -/* for TYPE_DATA (bit combination) */ -#define IEEE80211_FC0_SUBTYPE_DATA 0x00 -#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10 -#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20 -#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30 -#define IEEE80211_FC0_SUBTYPE_NODATA 0x40 -#define IEEE80211_FC0_SUBTYPE_CFACK 0x50 -#define IEEE80211_FC0_SUBTYPE_CFPOLL 0x60 -#define IEEE80211_FC0_SUBTYPE_CF_ACK_CF_ACK 0x70 - -#define IEEE80211_FC1_DIR_MASK 0x03 -#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ -#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ -#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ -#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ - -#define IEEE80211_FC1_MORE_FRAG 0x04 -#define IEEE80211_FC1_RETRY 0x08 -#define IEEE80211_FC1_PWR_MGT 0x10 -#define IEEE80211_FC1_MORE_DATA 0x20 -#define IEEE80211_FC1_WEP 0x40 -#define IEEE80211_FC1_ORDER 0x80 - -#define IEEE80211_SEQ_FRAG_MASK 0x000f -#define IEEE80211_SEQ_FRAG_SHIFT 0 -#define IEEE80211_SEQ_SEQ_MASK 0xfff0 -#define IEEE80211_SEQ_SEQ_SHIFT 4 - -#define IEEE80211_NWID_LEN 32 - -/* - * BEACON management packets - * - * octet timestamp[8] - * octet beacon interval[2] - * octet capability information[2] - * information element - * octet elemid - * octet length - * octet information[length] - */ - -typedef uint8_t *ieee80211_mgt_beacon_t; - -#define IEEE80211_BEACON_INTERVAL(beacon) \ - ((beacon)[8] | ((beacon)[9] << 8)) -#define IEEE80211_BEACON_CAPABILITY(beacon) \ - ((beacon)[10] | ((beacon)[11] << 8)) - -#define IEEE80211_CAPINFO_ESS 0x0001 -#define IEEE80211_CAPINFO_IBSS 0x0002 -#define IEEE80211_CAPINFO_CF_POLLABLE 0x0004 -#define IEEE80211_CAPINFO_CF_POLLREQ 0x0008 -#define IEEE80211_CAPINFO_PRIVACY 0x0010 -#define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020 -#define IEEE80211_CAPINFO_PBCC 0x0040 -#define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080 - -#define IEEE80211_RATE_BASIC 0x80 -#define IEEE80211_RATE_VAL 0x7f - -/* - * Management information elements - */ - -struct ieee80211_information { - char ssid[IEEE80211_NWID_LEN+1]; - struct rates { - u_int8_t *p; - } rates; - struct fh { - u_int16_t dwell; - u_int8_t set; - u_int8_t pattern; - u_int8_t index; - } fh; - struct ds { - u_int8_t channel; - } ds; - struct cf { - u_int8_t count; - u_int8_t period; - u_int8_t maxdur[2]; - u_int8_t dur[2]; - } cf; - struct tim { - u_int8_t count; - u_int8_t period; - u_int8_t bitctl; - /* u_int8_t pvt[251]; The driver needs to use this. */ - } tim; - struct ibss { - u_int16_t atim; - } ibss; - struct challenge { - u_int8_t *p; - u_int8_t len; - } challenge; -}; - -#define IEEE80211_ELEMID_SSID 0 -#define IEEE80211_ELEMID_RATES 1 -#define IEEE80211_ELEMID_FHPARMS 2 -#define IEEE80211_ELEMID_DSPARMS 3 -#define IEEE80211_ELEMID_CFPARMS 4 -#define IEEE80211_ELEMID_TIM 5 -#define IEEE80211_ELEMID_IBSSPARMS 6 -#define IEEE80211_ELEMID_CHALLENGE 16 - -/* - * AUTH management packets - * - * octet algo[2] - * octet seq[2] - * octet status[2] - * octet chal.id - * octet chal.length - * octet chal.text[253] - */ - -typedef u_int8_t *ieee80211_mgt_auth_t; - -#define IEEE80211_AUTH_ALGORITHM(auth) \ - ((auth)[0] | ((auth)[1] << 8)) -#define IEEE80211_AUTH_TRANSACTION(auth) \ - ((auth)[2] | ((auth)[3] << 8)) -#define IEEE80211_AUTH_STATUS(auth) \ - ((auth)[4] | ((auth)[5] << 8)) - -#define IEEE80211_AUTH_ALG_OPEN 0x0000 -#define IEEE80211_AUTH_ALG_SHARED 0x0001 - -#define IEEE80211_AUTH_OPEN_REQUEST 1 -#define IEEE80211_AUTH_OPEN_RESPONSE 2 - -#define IEEE80211_AUTH_SHARED_REQUEST 1 -#define IEEE80211_AUTH_SHARED_CHALLENGE 2 -#define IEEE80211_AUTH_SHARED_RESPONSE 3 -#define IEEE80211_AUTH_SHARED_PASS 4 - -/* - * Reason codes - * - * Unlisted codes are reserved - */ - -#define IEEE80211_REASON_UNSPECIFIED 1 -#define IEEE80211_REASON_AUTH_EXPIRE 2 -#define IEEE80211_REASON_AUTH_LEAVE 3 -#define IEEE80211_REASON_ASSOC_EXPIRE 4 -#define IEEE80211_REASON_ASSOC_TOOMANY 5 -#define IEEE80211_REASON_NOT_AUTHED 6 -#define IEEE80211_REASON_NOT_ASSOCED 7 -#define IEEE80211_REASON_ASSOC_LEAVE 8 -#define IEEE80211_REASON_ASSOC_NOT_AUTHED 9 - -#define IEEE80211_STATUS_SUCCESS 0 -#define IEEE80211_STATUS_UNSPECIFIED 1 -#define IEEE80211_STATUS_CAPINFO 10 -#define IEEE80211_STATUS_NOT_ASSOCED 11 -#define IEEE80211_STATUS_OTHER 12 -#define IEEE80211_STATUS_ALG 13 -#define IEEE80211_STATUS_SEQUENCE 14 -#define IEEE80211_STATUS_CHALLENGE 15 -#define IEEE80211_STATUS_TIMEOUT 16 -#define IEEE80211_STATUS_TOOMANY 17 -#define IEEE80211_STATUS_BASIC_RATE 18 -#define IEEE80211_STATUS_SP_REQUIRED 19 -#define IEEE80211_STATUS_PBCC_REQUIRED 20 -#define IEEE80211_STATUS_CA_REQUIRED 21 -#define IEEE80211_STATUS_TOO_MANY_STATIONS 22 -#define IEEE80211_STATUS_RATES 23 - -#define IEEE80211_WEP_KEYLEN 5 /* 40bit */ -#define IEEE80211_WEP_IVLEN 3 /* 24bit */ -#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */ -#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */ -#define IEEE80211_WEP_NKID 4 /* number of key ids */ - -#define IEEE80211_CRC_LEN 4 - -#define IEEE80211_MTU 1500 -#define IEEE80211_MAX_LEN (2300 + IEEE80211_CRC_LEN + \ - (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN)) - -/* - * ioctls - */ - -/* nwid is pointed at by ifr.ifr_data */ -struct ieee80211_nwid { - u_int8_t i_len; - u_int8_t i_nwid[IEEE80211_NWID_LEN]; -}; - -#define SIOCS80211NWID _IOWR('i', 230, struct ifreq) -#define SIOCG80211NWID _IOWR('i', 231, struct ifreq) - -/* the first member must be matched with struct ifreq */ -struct ieee80211_nwkey { - char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ - int i_wepon; /* wep enabled flag */ - int i_defkid; /* default encrypt key id */ - struct { - int i_keylen; - u_int8_t *i_keydat; - } i_key[IEEE80211_WEP_NKID]; -}; -#define SIOCS80211NWKEY _IOW('i', 232, struct ieee80211_nwkey) -#define SIOCG80211NWKEY _IOWR('i', 233, struct ieee80211_nwkey) -/* i_wepon */ -#define IEEE80211_NWKEY_OPEN 0 /* No privacy */ -#define IEEE80211_NWKEY_WEP 1 /* WEP enabled */ -#define IEEE80211_NWKEY_EAP 2 /* EAP enabled */ -#define IEEE80211_NWKEY_PERSIST 0x100 /* designate persist keyset */ - -/* power management parameters */ -struct ieee80211_power { - char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ - int i_enabled; /* 1 == on, 0 == off */ - int i_maxsleep; /* max sleep in ms */ -}; -#ifdef __NetBSD__ -#define SIOCS80211POWER _IOW('i', 234, struct ieee80211_power) -#define SIOCG80211POWER _IOWR('i', 235, struct ieee80211_power) -#else -#define SIOCS80211POWER _IOW('i', 242, struct ieee80211_power) -#define SIOCG80211POWER _IOWR('i', 243, struct ieee80211_power) -#endif - -struct ieee80211_auth { - char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ - int i_authtype; -}; - -#define IEEE80211_AUTH_NONE 0 -#define IEEE80211_AUTH_OPEN 1 -#define IEEE80211_AUTH_SHARED 2 - -#define SIOCS80211AUTH _IOW('i', 236, struct ieee80211_auth) -#define SIOCG80211AUTH _IOWR('i', 237, struct ieee80211_auth) - -struct ieee80211_channel { - char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ - u_int16_t i_channel; -}; - -#define IEEE80211_CHAN_ANY 0xffff - -#define SIOCS80211CHANNEL _IOW('i', 238, struct ieee80211_channel) -#define SIOCG80211CHANNEL _IOWR('i', 239, struct ieee80211_channel) - -struct ieee80211_bssid { - char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ - u_int8_t i_bssid[IEEE80211_ADDR_LEN]; -}; - -#define SIOCS80211BSSID _IOW('i', 240, struct ieee80211_bssid) -#define SIOCG80211BSSID _IOWR('i', 241, struct ieee80211_bssid) - -/* - * FreeBSD-style ioctls. - */ -/* the first member must be matched with struct ifreq */ -struct ieee80211req { - char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ - u_int16_t i_type; /* req type */ - int16_t i_val; /* Index or simple value */ - int16_t i_len; /* Index or simple value */ - void *i_data; /* Extra data */ -}; -#ifdef __FreeBSD__ -#define SIOCS80211 _IOW('i', 234, struct ieee80211req) -#define SIOCG80211 _IOWR('i', 235, struct ieee80211req) -#else -#define SIOCS80211 _IOW('i', 242, struct ieee80211req) -#define SIOCG80211 _IOWR('i', 243, struct ieee80211req) -#endif - -#define IEEE80211_IOC_SSID 1 -#define IEEE80211_IOC_NUMSSIDS 2 -#define IEEE80211_IOC_WEP 3 -#define IEEE80211_WEP_NOSUP -1 -#define IEEE80211_WEP_OFF 0 -#define IEEE80211_WEP_ON 1 -#define IEEE80211_WEP_MIXED 2 -#define IEEE80211_IOC_WEPKEY 4 -#define IEEE80211_IOC_NUMWEPKEYS 5 -#define IEEE80211_IOC_WEPTXKEY 6 -#define IEEE80211_IOC_AUTHMODE 7 -#define IEEE80211_IOC_STATIONNAME 8 -#define IEEE80211_IOC_CHANNEL 9 -#define IEEE80211_IOC_POWERSAVE 10 -#define IEEE80211_POWERSAVE_NOSUP -1 -#define IEEE80211_POWERSAVE_OFF 0 -#define IEEE80211_POWERSAVE_CAM 1 -#define IEEE80211_POWERSAVE_PSP 2 -#define IEEE80211_POWERSAVE_PSP_CAM 3 -#define IEEE80211_POWERSAVE_ON IEEE80211_POWERSAVE_CAM -#define IEEE80211_IOC_POWERSAVESLEEP 11 - -#ifdef _KERNEL - -#define IEEE80211_ASCAN_WAIT 2 /* active scan wait */ -#define IEEE80211_PSCAN_WAIT 5 /* passive scan wait */ -#define IEEE80211_TRANS_WAIT 5 /* transition wait */ -#define IEEE80211_INACT_WAIT 5 /* inactivity timer interval */ -#define IEEE80211_INACT_MAX (300/IEEE80211_INACT_WAIT) - -/* - * Structure for IEEE 802.11 drivers. - */ - -#define IEEE80211_CHAN_MAX 255 -#define IEEE80211_RATE_SIZE 12 -#define IEEE80211_KEYBUF_SIZE 16 -#define IEEE80211_NODE_HASHSIZE 32 -/* simple hash is enough for variation of macaddr */ -#define IEEE80211_NODE_HASH(addr) \ - (((u_int8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % IEEE80211_NODE_HASHSIZE) - -enum ieee80211_phytype { - IEEE80211_T_DS, /* direct sequence spread spectrum */ - IEEE80211_T_FH, /* frequency hopping */ - IEEE80211_T_OFDM, /* frequency division multiplexing */ - IEEE80211_T_HRDS /* high rate DS */ -}; - -enum ieee80211_opmode { - IEEE80211_M_STA = 1, /* infrastructure station */ - IEEE80211_M_IBSS = 0, /* IBSS (adhoc) station */ - IEEE80211_M_AHDEMO = 3, /* Old lucent compatible adhoc demo */ - IEEE80211_M_HOSTAP = 6 /* Software Access Point */ -}; - -enum ieee80211_state { - IEEE80211_S_INIT, /* default state */ - IEEE80211_S_SCAN, /* scanning */ - IEEE80211_S_AUTH, /* try to authenticate */ - IEEE80211_S_ASSOC, /* try to assoc */ - IEEE80211_S_RUN /* associated */ -}; - -/* - * Node specific information. - */ -struct ieee80211_node { - TAILQ_ENTRY(ieee80211_node) ni_list; - LIST_ENTRY(ieee80211_node) ni_hash; - - /* hardware */ - u_int8_t ni_rssi; - u_int32_t ni_rstamp; - - /* header */ - u_int8_t ni_macaddr[IEEE80211_ADDR_LEN]; - u_int8_t ni_bssid[IEEE80211_ADDR_LEN]; - - /* beacon, probe response */ - u_int8_t ni_tstamp[8]; - u_int16_t ni_intval; - u_int16_t ni_capinfo; - u_int8_t ni_esslen; - u_int8_t ni_essid[IEEE80211_NWID_LEN]; - int ni_nrate; - u_int8_t ni_rates[IEEE80211_RATE_SIZE]; - u_int8_t ni_chan; - u_int16_t ni_fhdwell; /* FH only */ - u_int8_t ni_fhindex; /* FH only */ - - /* DTIM and contention free period (CFP) */ - u_int8_t ni_dtimperiod; - u_int8_t ni_cfpperiod; /* # of DTIMs between CFPs */ - u_int16_t ni_cfpmaxduration;/* max CFP duration in TU */ - u_int16_t ni_cfpduremain; /* remaining duration */ - u_int16_t ni_timoffset; - - /* others */ - u_int16_t ni_associd; /* assoc response */ - u_int16_t ni_txseq; /* seq to be transmitted */ - u_int16_t ni_rxseq; /* seq previous received */ - int ni_fails; /* failure count to associate */ - int ni_inact; /* inactivity mark count */ - int ni_txrate; /* index to ni_rates[] */ - void *ni_private; /* driver private */ -}; - -/* ni_chan encoding for FH phy */ -#define IEEE80211_FH_CHANMOD 80 -#define IEEE80211_FH_CHAN(set,pat) (((set)-1)*IEEE80211_FH_CHANMOD+(pat)) -#define IEEE80211_FH_CHANSET(chan) ((chan)/IEEE80211_FH_CHANMOD+1) -#define IEEE80211_FH_CHANPAT(chan) ((chan)%IEEE80211_FH_CHANMOD) - -struct ieee80211_wepkey { - int wk_len; - u_int8_t wk_key[IEEE80211_KEYBUF_SIZE]; -}; - -struct ieee80211com { -#ifdef __NetBSD__ - struct ethercom ic_ec; -#endif -#ifdef __FreeBSD__ - struct arpcom ic_ac; - struct mtx ic_mtx; -#endif - void (*ic_recv_mgmt[16])(struct ieee80211com *, - struct mbuf *, int, u_int32_t); - int (*ic_send_mgmt[16])(struct ieee80211com *, - struct ieee80211_node *, int, int); - int (*ic_newstate)(void *, enum ieee80211_state); - int (*ic_chancheck)(void *, u_char *); - u_int8_t ic_myaddr[IEEE80211_ADDR_LEN]; - u_int8_t ic_sup_rates[IEEE80211_RATE_SIZE]; - u_char ic_chan_avail[roundup(IEEE80211_CHAN_MAX,NBBY)]; - u_char ic_chan_active[roundup(IEEE80211_CHAN_MAX, NBBY)]; - struct ifqueue ic_mgtq; - int ic_flags; - enum ieee80211_phytype ic_phytype; - enum ieee80211_opmode ic_opmode; - enum ieee80211_state ic_state; - struct bpf_if *ic_rawbpf; /* packet filter structure */ - struct ieee80211_node ic_bss; /* information for this node */ - int ic_node_privlen;/* size for ni_private */ - void (*ic_node_free)(struct ieee80211com *, - struct ieee80211_node *); /* callback */ - u_int8_t ic_ibss_chan; - int ic_fixed_rate; /* index to ic_sup_rates[] */ - TAILQ_HEAD(, ieee80211_node) ic_node; /* information of all nodes */ - LIST_HEAD(, ieee80211_node) ic_hash[IEEE80211_NODE_HASHSIZE]; - u_int16_t ic_lintval; /* listen interval */ - int ic_mgt_timer; /* mgmt timeout */ - int ic_scan_timer; /* scant wait */ - int ic_inact_timer; /* inactivity timer wait */ - int ic_des_esslen; - u_int8_t ic_des_essid[IEEE80211_NWID_LEN]; - int ic_des_chan; /* desired channel */ - u_int8_t ic_des_bssid[IEEE80211_ADDR_LEN]; - struct ieee80211_wepkey ic_nw_keys[IEEE80211_WEP_NKID]; - int ic_wep_txkey; /* default tx key index */ - void *ic_wep_ctx; /* wep crypt context */ - u_int32_t ic_iv; /* initial vector for wep */ -}; -#ifdef __NetBSD__ -#define ic_if ic_ec.ec_if -#define IEEE80211_LOCK(_ic) do { s = splnet(); } while (0) -#define IEEE80211_UNLOCK(_ic) splx(s) -#endif -#ifdef __FreeBSD__ -#define ic_if ic_ac.ac_if -#define IEEE80211_LOCK(_ic) mtx_lock(&(_ic)->ic_mtx) -#define IEEE80211_UNLOCK(_ic) mtx_unlock(&(_ic)->ic_mtx) -#endif -#define ic_softc ic_if.if_softc - -#define IEEE80211_SEND_MGMT(ic,ni,type,arg) do { \ - if ((ic)->ic_send_mgmt[(type)>>IEEE80211_FC0_SUBTYPE_SHIFT] != NULL) \ - (*(ic)->ic_send_mgmt[(type)>>IEEE80211_FC0_SUBTYPE_SHIFT]) \ - (ic,ni,type,arg); \ -} while (0) - -#define IEEE80211_ADDR_EQ(a1,a2) (memcmp(a1,a2,IEEE80211_ADDR_LEN) == 0) -#define IEEE80211_ADDR_COPY(dst,src) memcpy(dst,src,IEEE80211_ADDR_LEN) - -#define IEEE80211_IS_MULTICAST(a) ETHER_IS_MULTICAST(a) - -/* ic_flags */ -#define IEEE80211_F_ASCAN 0x00000001 /* STATUS: active scan */ -#define IEEE80211_F_SIBSS 0x00000002 /* STATUS: start IBSS */ -#define IEEE80211_F_WEPON 0x00000100 /* CONF: WEP enabled */ -#define IEEE80211_F_IBSSON 0x00000200 /* CONF: IBSS creation enable */ -#define IEEE80211_F_PMGTON 0x00000400 /* CONF: Power mgmt enable */ -#define IEEE80211_F_DESBSSID 0x00000800 /* CONF: des_bssid is set */ -#define IEEE80211_F_SCANAP 0x00001000 /* CONF: Scanning AP */ -#define IEEE80211_F_HASWEP 0x00010000 /* CAPABILITY: WEP available */ -#define IEEE80211_F_HASIBSS 0x00020000 /* CAPABILITY: IBSS available */ -#define IEEE80211_F_HASPMGT 0x00040000 /* CAPABILITY: Power mgmt */ -#define IEEE80211_F_HASHOSTAP 0x00080000 /* CAPABILITY: HOSTAP avail */ -#define IEEE80211_F_HASAHDEMO 0x00100000 /* CAPABILITY: Old Adhoc Demo */ - -/* flags for ieee80211_fix_rate() */ -#define IEEE80211_F_DOSORT 0x00000001 /* sort rate list */ -#define IEEE80211_F_DOFRATE 0x00000002 /* use fixed rate */ -#define IEEE80211_F_DONEGO 0x00000004 /* calc negotiated rate */ -#define IEEE80211_F_DODEL 0x00000008 /* delete ignore rate */ - -void ieee80211_ifattach(struct ifnet *); -void ieee80211_ifdetach(struct ifnet *); -void ieee80211_input(struct ifnet *, struct mbuf *, int, u_int32_t); -int ieee80211_mgmt_output(struct ifnet *, struct ieee80211_node *, - struct mbuf *, int); -struct mbuf *ieee80211_encap(struct ifnet *, struct mbuf *); -struct mbuf *ieee80211_decap(struct ifnet *, struct mbuf *); -int ieee80211_ioctl(struct ifnet *, u_long, caddr_t); -void ieee80211_print_essid(u_int8_t *, int); -void ieee80211_dump_pkt(u_int8_t *, int, int, int); -void ieee80211_watchdog(struct ifnet *); -void ieee80211_next_scan(struct ifnet *); -void ieee80211_end_scan(struct ifnet *); -struct ieee80211_node *ieee80211_alloc_node(struct ieee80211com *, u_int8_t *, - int); -struct ieee80211_node *ieee80211_find_node(struct ieee80211com *, u_int8_t *); -void ieee80211_free_node(struct ieee80211com *, struct ieee80211_node *); -void ieee80211_free_allnodes(struct ieee80211com *); -int ieee80211_fix_rate(struct ieee80211com *, struct ieee80211_node *, int); -int ieee80211_new_state(struct ifnet *, enum ieee80211_state, int); -struct mbuf *ieee80211_wep_crypt(struct ifnet *, struct mbuf *, int); -int ieee80211_rate2media(int, enum ieee80211_phytype); -int ieee80211_media2rate(int, enum ieee80211_phytype); - -int ieee80211_cfgget(struct ifnet *, u_long, caddr_t); -int ieee80211_cfgset(struct ifnet *, u_long, caddr_t); - -#endif /* _KERNEL */ - -#endif /* _NET_IF_IEEE80211_H_ */ diff --git a/sys/net/if_ieee80211subr.c b/sys/net/if_ieee80211subr.c deleted file mode 100644 index 9f2ec0acdab5..000000000000 --- a/sys/net/if_ieee80211subr.c +++ /dev/null @@ -1,3413 +0,0 @@ -/* $NetBSD: if_ieee80211subr.c,v 1.22 2002/10/16 11:29:30 onoe Exp $ */ -/* $FreeBSD$ */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Atsushi Onoe. - * - * 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 the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 THE FOUNDATION OR CONTRIBUTORS - * 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. - */ - -/* - * IEEE 802.11 generic handler - */ - -#include - -#include "opt_inet.h" -#define NBPFILTER 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#define arc4_ctxlen() sizeof (struct rc4_state) -#define arc4_setkey(_c,_k,_l) rc4_init(_c,_k,_l) -#define arc4_encrypt(_c,_d,_s,_l) rc4_crypt(_c,_s,_d,_l) - -#include -#include -#include -#include -#include -#include - -#if NBPFILTER > 0 -#include -#endif - -#ifdef INET -#include -#include -#endif - -#include - -#define IEEE80211_DEBUG -#ifdef IEEE80211_DEBUG -int ieee80211_debug = 0; -#define DPRINTF(X) if (ieee80211_debug) printf X -#define DPRINTF2(X) if (ieee80211_debug>1) printf X - -SYSCTL_INT(_debug, OID_AUTO, ieee80211, CTLFLAG_RW, &ieee80211_debug, - 0, "IEEE 802.11 media debugging printfs"); -#else -#define DPRINTF(X) -#define DPRINTF2(X) -#endif - -/* XXX belongs elsewhere */ -#ifndef ALIGNED_POINTER -/* - * ALIGNED_POINTER is a boolean macro that checks whether an address - * is valid to fetch data elements of type t from on this architecture. - * This does not reflect the optimal alignment, just the possibility - * (within reasonable limits). - * - */ -#define ALIGNED_POINTER(p,t) 1 -#endif - -static int ieee80211_send_prreq(struct ieee80211com *, - struct ieee80211_node *, int, int); -static int ieee80211_send_prresp(struct ieee80211com *, - struct ieee80211_node *, int, int); -static int ieee80211_send_auth(struct ieee80211com *, - struct ieee80211_node *, int, int); -static int ieee80211_send_deauth(struct ieee80211com *, - struct ieee80211_node *, int, int); -static int ieee80211_send_asreq(struct ieee80211com *, - struct ieee80211_node *, int, int); -static int ieee80211_send_asresp(struct ieee80211com *, - struct ieee80211_node *, int, int); -static int ieee80211_send_disassoc(struct ieee80211com *, - struct ieee80211_node *, int, int); - -static void ieee80211_recv_beacon(struct ieee80211com *, - struct mbuf *, int, u_int32_t); -static void ieee80211_recv_prreq(struct ieee80211com *, - struct mbuf *, int, u_int32_t); -static void ieee80211_recv_auth(struct ieee80211com *, - struct mbuf *, int, u_int32_t); -static void ieee80211_recv_asreq(struct ieee80211com *, - struct mbuf *, int, u_int32_t); -static void ieee80211_recv_asresp(struct ieee80211com *, - struct mbuf *, int, u_int32_t); -static void ieee80211_recv_disassoc(struct ieee80211com *, - struct mbuf *, int, u_int32_t); -static void ieee80211_recv_deauth(struct ieee80211com *, - struct mbuf *, int, u_int32_t); - -static void ieee80211_crc_init(void); -static u_int32_t ieee80211_crc_update(u_int32_t, u_int8_t *, int); - -static const char *ieee80211_mgt_subtype_name[] = { - "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", - "probe_req", "probe_resp", "reserved#6", "reserved#7", - "beacon", "atim", "disassoc", "auth", - "deauth", "reserved#13", "reserved#14", "reserved#15" -}; - -void -ieee80211_ifattach(struct ifnet *ifp) -{ - struct ieee80211com *ic = (void *)ifp; - int i, rate; - - /* XXX need unit */ - mtx_init(&ic->ic_mtx, ifp->if_name, "802.11 link layer", MTX_DEF); - - ether_ifattach(ifp, ic->ic_myaddr); -#if NBPFILTER > 0 - bpfattach2(ifp, DLT_IEEE802_11, - sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf); -#endif - ieee80211_crc_init(); - ic->ic_iv = arc4random(); - memcpy(ic->ic_chan_active, ic->ic_chan_avail, - sizeof(ic->ic_chan_active)); - if (isclr(ic->ic_chan_active, ic->ic_ibss_chan)) { - for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { - if (isset(ic->ic_chan_active, i)) { - ic->ic_ibss_chan = i; - break; - } - } - } - ic->ic_des_chan = IEEE80211_CHAN_ANY; - ic->ic_fixed_rate = -1; - if (ic->ic_lintval == 0) - ic->ic_lintval = 100; /* default sleep */ - TAILQ_INIT(&ic->ic_node); - mtx_init(&ic->ic_mgtq.ifq_mtx, ifp->if_name, "mgmt send q", MTX_DEF); - - rate = 0; - for (i = 0; i < IEEE80211_RATE_SIZE; i++) { - if (ic->ic_sup_rates[i] != 0) - rate = (ic->ic_sup_rates[i] & IEEE80211_RATE_VAL) / 2; - } - if (rate) - ifp->if_baudrate = IF_Mbps(rate); - ifp->if_hdrlen = sizeof(struct ieee80211_frame); - - /* initialize management frame handler */ - ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_RESP - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_beacon; - ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_BEACON - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_beacon; - ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_REQ - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_prreq; - ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_AUTH - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_auth; - ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_REQ - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asreq; - ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_REQ - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asreq; - ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_RESP - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asresp; - ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_RESP - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asresp; - ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_DEAUTH - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_deauth; - ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_DISASSOC - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_disassoc; - - ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_REQ - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_prreq; - ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_RESP - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_prresp; - ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_AUTH - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_auth; - ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_DEAUTH - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_deauth; - ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_REQ - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asreq; - ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_REQ - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asreq; - ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_RESP - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asresp; - ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_RESP - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asresp; - ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_DISASSOC - >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_disassoc; -} - -void -ieee80211_ifdetach(struct ifnet *ifp) -{ - struct ieee80211com *ic = (void *)ifp; - - IEEE80211_LOCK(ic); - IF_DRAIN(&ic->ic_mgtq); - mtx_destroy(&ic->ic_mgtq.ifq_mtx); - if (ic->ic_wep_ctx != NULL) { - free(ic->ic_wep_ctx, M_DEVBUF); - ic->ic_wep_ctx = NULL; - } - ieee80211_free_allnodes(ic); -#if NBPFILTER > 0 - bpfdetach(ifp); -#endif - ether_ifdetach(ifp); - IEEE80211_UNLOCK(ic); - mtx_destroy(&ic->ic_mtx); -} - -void -ieee80211_input(struct ifnet *ifp, struct mbuf *m, int rssi, u_int32_t rstamp) -{ - struct ieee80211com *ic = (void *)ifp; - struct ieee80211_node *ni = NULL; - struct ieee80211_frame *wh; - struct ether_header *eh; - void (*rh)(struct ieee80211com *, struct mbuf *, int, u_int); - struct mbuf *m1; - int len; - u_int8_t dir, subtype; - u_int8_t *bssid; - u_int16_t rxseq; - - /* trim CRC here for WEP can find its own CRC at the end of packet. */ - if (m->m_flags & M_HASFCS) { - m_adj(m, -IEEE80211_CRC_LEN); - m->m_flags &= ~M_HASFCS; - } - - wh = mtod(m, struct ieee80211_frame *); - if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != - IEEE80211_FC0_VERSION_0) { - if (ifp->if_flags & IFF_DEBUG) - if_printf(ifp, "receive packet with wrong version: %x\n", - wh->i_fc[0]); - goto err; - } - - dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; - - if (ic->ic_state != IEEE80211_S_SCAN) { - switch (ic->ic_opmode) { - case IEEE80211_M_STA: - ni = &ic->ic_bss; - if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) { - DPRINTF2(("ieee80211_input: other bss %s\n", - ether_sprintf(wh->i_addr2))); - /* not interested in */ - goto out; - } - break; - case IEEE80211_M_IBSS: - case IEEE80211_M_AHDEMO: - case IEEE80211_M_HOSTAP: - if (dir == IEEE80211_FC1_DIR_NODS) - bssid = wh->i_addr3; - else - bssid = wh->i_addr1; - if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss.ni_bssid) && - !IEEE80211_ADDR_EQ(bssid, ifp->if_broadcastaddr)) { - /* not interested in */ - DPRINTF2(("ieee80211_input: other bss %s\n", - ether_sprintf(wh->i_addr3))); - goto out; - } - ni = ieee80211_find_node(ic, wh->i_addr2); - if (ni == NULL) { - DPRINTF2(("ieee80211_input: unknown src %s\n", - ether_sprintf(wh->i_addr2))); - ni = &ic->ic_bss; /* XXX allocate? */ - } - break; - } - ni->ni_rssi = rssi; - ni->ni_rstamp = rstamp; - rxseq = ni->ni_rxseq; - ni->ni_rxseq = - le16toh(*(u_int16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT; - /* TODO: fragment */ - if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) && - rxseq == ni->ni_rxseq) { - /* duplicate, silently discarded */ - goto out; - } - ni->ni_inact = 0; - } - - switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { - case IEEE80211_FC0_TYPE_DATA: - switch (ic->ic_opmode) { - case IEEE80211_M_STA: - if (dir != IEEE80211_FC1_DIR_FROMDS) - goto out; - if ((ifp->if_flags & IFF_SIMPLEX) && - IEEE80211_IS_MULTICAST(wh->i_addr1) && - IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_myaddr)) { - /* - * In IEEE802.11 network, multicast packet - * sent from me is broadcasted from AP. - * It should be silently discarded for - * SIMPLEX interface. - */ - goto out; - } - break; - case IEEE80211_M_IBSS: - case IEEE80211_M_AHDEMO: - if (dir != IEEE80211_FC1_DIR_NODS) - goto out; - break; - case IEEE80211_M_HOSTAP: - if (dir != IEEE80211_FC1_DIR_TODS) - goto out; - /* check if source STA is associated */ - ni = ieee80211_find_node(ic, wh->i_addr2); - if (ni == NULL) { - DPRINTF(("ieee80211_input: " - "data from unknown src %s\n", - ether_sprintf(wh->i_addr2))); - if ((ni = ieee80211_alloc_node(ic, wh->i_addr2, - 1)) != NULL) { - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_DEAUTH, - IEEE80211_REASON_NOT_AUTHED); - ieee80211_free_node(ic, ni); - } - goto err; - } - if (ni->ni_associd == 0) { - DPRINTF(("ieee80211_input: " - "data from unassoc src %s\n", - ether_sprintf(wh->i_addr2))); - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_DISASSOC, - IEEE80211_REASON_NOT_ASSOCED); - goto err; - } - break; - } - if (wh->i_fc[1] & IEEE80211_FC1_WEP) { - if (ic->ic_flags & IEEE80211_F_WEPON) { - m = ieee80211_wep_crypt(ifp, m, 0); - if (m == NULL) - goto err; - wh = mtod(m, struct ieee80211_frame *); - } else - goto out; - } - /* copy to listener after decrypt */ -#if NBPFILTER > 0 - if (ic->ic_rawbpf) - bpf_mtap(ic->ic_rawbpf, m); -#endif - m = ieee80211_decap(ifp, m); - if (m == NULL) - goto err; - ifp->if_ipackets++; - - /* perform as a bridge within the AP */ - m1 = NULL; - if (ic->ic_opmode == IEEE80211_M_HOSTAP) { - eh = mtod(m, struct ether_header *); - if (ETHER_IS_MULTICAST(eh->ether_dhost)) { - m1 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); - if (m1 == NULL) - ifp->if_oerrors++; - else - m1->m_flags |= M_MCAST; - } else { - ni = ieee80211_find_node(ic, eh->ether_dhost); - if (ni != NULL && ni->ni_associd != 0) { - m1 = m; - m = NULL; - } - } - if (m1 != NULL) { -#ifdef ALTQ - if (ALTQ_IS_ENABLED(&ifp->if_snd)) - altq_etherclassify(&ifp->if_snd, m1, - &pktattr); -#endif - len = m1->m_pkthdr.len; - IF_ENQUEUE(&ifp->if_snd, m1); - if (m != NULL) - ifp->if_omcasts++; - ifp->if_obytes += len; - } - } - if (m != NULL) - (*ifp->if_input)(ifp, m); - return; - - case IEEE80211_FC0_TYPE_MGT: - if (dir != IEEE80211_FC1_DIR_NODS) - goto err; - if (ic->ic_opmode == IEEE80211_M_AHDEMO) - goto out; - subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; - - /* drop frames without interest */ - if (ic->ic_state == IEEE80211_S_SCAN) { - if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && - subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) - goto out; - } else { - if (ic->ic_opmode != IEEE80211_M_IBSS && - subtype == IEEE80211_FC0_SUBTYPE_BEACON) - goto out; - } - - if (ifp->if_flags & IFF_DEBUG) { - /* avoid to print too many frames */ - int doprint = 0; - - switch (subtype) { - case IEEE80211_FC0_SUBTYPE_BEACON: - if (ic->ic_state == IEEE80211_S_SCAN) - doprint = 1; - break; - case IEEE80211_FC0_SUBTYPE_PROBE_REQ: - if (ic->ic_opmode == IEEE80211_M_IBSS) - doprint = 1; - break; - default: - doprint = 1; - break; - } -#ifdef IEEE80211_DEBUG - doprint += ieee80211_debug; -#endif - if (doprint) - if_printf(ifp, "received %s from %s rssi %d\n", - ieee80211_mgt_subtype_name[subtype - >> IEEE80211_FC0_SUBTYPE_SHIFT], - ether_sprintf(wh->i_addr2), rssi); - } -#if NBPFILTER > 0 - if (ic->ic_rawbpf) - bpf_mtap(ic->ic_rawbpf, m); -#endif - rh = ic->ic_recv_mgmt[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]; - if (rh != NULL) - (*rh)(ic, m, rssi, rstamp); - m_freem(m); - return; - - case IEEE80211_FC0_TYPE_CTL: - default: - DPRINTF(("ieee80211_input: bad type %x\n", wh->i_fc[0])); - /* should not come here */ - break; - } - err: - ifp->if_ierrors++; - out: - if (m != NULL) { -#if NBPFILTER > 0 - if (ic->ic_rawbpf) - bpf_mtap(ic->ic_rawbpf, m); -#endif - m_freem(m); - } -} - -int -ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni, - struct mbuf *m, int type) -{ - struct ieee80211com *ic = (void *)ifp; - struct ieee80211_frame *wh; - - if (ni == NULL) - ni = &ic->ic_bss; - ni->ni_inact = 0; - M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); - if (m == NULL) - return ENOMEM; - wh = mtod(m, struct ieee80211_frame *); - wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type; - wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; - *(u_int16_t *)wh->i_dur = 0; - *(u_int16_t *)wh->i_seq = - htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); - ni->ni_txseq++; - IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); - IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); - IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); - - if (ifp->if_flags & IFF_DEBUG) { - /* avoid to print too many frames */ - if (ic->ic_opmode == IEEE80211_M_IBSS || -#ifdef IEEE80211_DEBUG - ieee80211_debug > 1 || -#endif - (type & IEEE80211_FC0_SUBTYPE_MASK) != - IEEE80211_FC0_SUBTYPE_PROBE_RESP) - if_printf(ifp, "sending %s to %s\n", - ieee80211_mgt_subtype_name[ - (type & IEEE80211_FC0_SUBTYPE_MASK) - >> IEEE80211_FC0_SUBTYPE_SHIFT], - ether_sprintf(ni->ni_macaddr)); - } - IF_ENQUEUE(&ic->ic_mgtq, m); - ifp->if_timer = 1; - (*ifp->if_start)(ifp); - return 0; -} - -struct mbuf * -ieee80211_encap(struct ifnet *ifp, struct mbuf *m) -{ - struct ieee80211com *ic = (void *)ifp; - struct ether_header eh; - struct ieee80211_frame *wh; - struct llc *llc; - struct ieee80211_node *ni; - - if (m->m_len < sizeof(struct ether_header)) { - m = m_pullup(m, sizeof(struct ether_header)); - if (m == NULL) - return NULL; - } - memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header)); - - if (!IEEE80211_IS_MULTICAST(eh.ether_dhost) && - (ic->ic_opmode == IEEE80211_M_IBSS || - ic->ic_opmode == IEEE80211_M_HOSTAP)) { - ni = ieee80211_find_node(ic, eh.ether_dhost); - if (ni == NULL) - ni = &ic->ic_bss; /*XXX*/ - } else - ni = &ic->ic_bss; - ni->ni_inact = 0; - - m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); - llc = mtod(m, struct llc *); - llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; - llc->llc_control = LLC_UI; - llc->llc_snap.org_code[0] = 0; - llc->llc_snap.org_code[1] = 0; - llc->llc_snap.org_code[2] = 0; - llc->llc_snap.ether_type = eh.ether_type; - M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); - if (m == NULL) - return NULL; - wh = mtod(m, struct ieee80211_frame *); - wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; - *(u_int16_t *)wh->i_dur = 0; - *(u_int16_t *)wh->i_seq = - htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); - ni->ni_txseq++; - switch (ic->ic_opmode) { - case IEEE80211_M_STA: - wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; - IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); - IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); - IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); - break; - case IEEE80211_M_IBSS: - case IEEE80211_M_AHDEMO: - wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; - IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); - IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); - IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); - break; - case IEEE80211_M_HOSTAP: - wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; - IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); - IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); - IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); - break; - } - return m; -} - -struct mbuf * -ieee80211_decap(struct ifnet *ifp, struct mbuf *m) -{ - struct ether_header *eh; - struct ieee80211_frame wh; - struct llc *llc; - - if (m->m_len < sizeof(wh) + sizeof(*llc)) { - m = m_pullup(m, sizeof(wh) + sizeof(*llc)); - if (m == NULL) - return NULL; - } - memcpy(&wh, mtod(m, caddr_t), sizeof(wh)); - llc = (struct llc *)(mtod(m, caddr_t) + sizeof(wh)); - if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP && - llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 && - llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0) { - m_adj(m, sizeof(wh) + sizeof(struct llc) - sizeof(*eh)); - llc = NULL; - } else { - m_adj(m, sizeof(wh) - sizeof(*eh)); - } - eh = mtod(m, struct ether_header *); - switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) { - case IEEE80211_FC1_DIR_NODS: - IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1); - IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2); - break; - case IEEE80211_FC1_DIR_TODS: - IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr3); - IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2); - break; - case IEEE80211_FC1_DIR_FROMDS: - IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1); - IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr3); - break; - case IEEE80211_FC1_DIR_DSTODS: - /* not yet supported */ - DPRINTF(("ieee80211_decap: DS to DS\n")); - m_freem(m); - return NULL; - } - if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), u_int32_t)) { - struct mbuf *n, *n0, **np; - caddr_t newdata; - int off, pktlen; - - n0 = NULL; - np = &n0; - off = 0; - pktlen = m->m_pkthdr.len; - while (pktlen > off) { - if (n0 == NULL) { - MGETHDR(n, M_DONTWAIT, MT_DATA); - if (n == NULL) { - m_freem(m); - return NULL; - } - M_MOVE_PKTHDR(n, m); - n->m_len = MHLEN; - } else { - MGET(n, M_DONTWAIT, MT_DATA); - if (n == NULL) { - m_freem(m); - m_freem(n0); - return NULL; - } - n->m_len = MLEN; - } - if (pktlen - off >= MINCLSIZE) { - MCLGET(n, M_DONTWAIT); - if (n->m_flags & M_EXT) - n->m_len = n->m_ext.ext_size; - } - if (n0 == NULL) { - newdata = - (caddr_t)ALIGN(n->m_data + sizeof(*eh)) - - sizeof(*eh); - n->m_len -= newdata - n->m_data; - n->m_data = newdata; - } - if (n->m_len > pktlen - off) - n->m_len = pktlen - off; - m_copydata(m, off, n->m_len, mtod(n, caddr_t)); - off += n->m_len; - *np = n; - np = &n->m_next; - } - m_freem(m); - m = n0; - } - if (llc != NULL) { - eh = mtod(m, struct ether_header *); - eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh)); - } - return m; -} - -int -ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) -{ - struct ieee80211com *ic = (void *)ifp; - int error = 0; - u_int kid, len; - struct ieee80211req *ireq; - u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE]; - char tmpssid[IEEE80211_NWID_LEN]; - - switch (cmd) { - case SIOCG80211: - ireq = (struct ieee80211req *) data; - switch (ireq->i_type) { - case IEEE80211_IOC_SSID: - switch (ic->ic_state) { - case IEEE80211_S_INIT: - case IEEE80211_S_SCAN: - ireq->i_len = ic->ic_des_esslen; - memcpy(tmpssid, ic->ic_des_essid, ireq->i_len); - break; - default: - ireq->i_len = ic->ic_bss.ni_esslen; - memcpy(tmpssid, ic->ic_bss.ni_essid, - ireq->i_len); - break; - } - error = copyout(tmpssid, ireq->i_data, ireq->i_len); - break; - case IEEE80211_IOC_NUMSSIDS: - ireq->i_val = 1; - break; - case IEEE80211_IOC_WEP: - if ((ic->ic_flags & IEEE80211_F_HASWEP) == 0) { - ireq->i_val = IEEE80211_WEP_NOSUP; - } else { - if (ic->ic_flags & IEEE80211_F_WEPON) { - ireq->i_val = - IEEE80211_WEP_MIXED; - } else { - ireq->i_val = - IEEE80211_WEP_OFF; - } - } - break; - case IEEE80211_IOC_WEPKEY: - if ((ic->ic_flags & IEEE80211_F_HASWEP) == 0) { - error = EINVAL; - break; - } - kid = (u_int) ireq->i_val; - if (kid >= IEEE80211_WEP_NKID) { - error = EINVAL; - break; - } - len = (u_int) ic->ic_nw_keys[kid].wk_len; - /* NB: only root can read WEP keys */ - if (suser(curthread)) { - bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len); - } else { - bzero(tmpkey, len); - } - ireq->i_len = len; - error = copyout(tmpkey, ireq->i_data, len); - break; - case IEEE80211_IOC_NUMWEPKEYS: - if ((ic->ic_flags & IEEE80211_F_HASWEP) == 0) - error = EINVAL; - else - ireq->i_val = IEEE80211_WEP_NKID; - break; - case IEEE80211_IOC_WEPTXKEY: - if ((ic->ic_flags & IEEE80211_F_HASWEP) == 0) - error = EINVAL; - else - ireq->i_val = ic->ic_wep_txkey; - break; - case IEEE80211_IOC_AUTHMODE: - ireq->i_val = IEEE80211_AUTH_OPEN; - break; - case IEEE80211_IOC_CHANNEL: - switch (ic->ic_state) { - case IEEE80211_S_INIT: - case IEEE80211_S_SCAN: - if (ic->ic_opmode == IEEE80211_M_STA) - ireq->i_val = ic->ic_des_chan; - else - ireq->i_val = ic->ic_ibss_chan; - break; - default: - ireq->i_val = ic->ic_bss.ni_chan; - break; - } - break; - case IEEE80211_IOC_POWERSAVE: - if (ic->ic_flags & IEEE80211_F_PMGTON) - ireq->i_val = IEEE80211_POWERSAVE_ON; - else - ireq->i_val = IEEE80211_POWERSAVE_OFF; - break; - case IEEE80211_IOC_POWERSAVESLEEP: - ireq->i_val = ic->ic_lintval; - break; - default: - error = EINVAL; - } - break; - case SIOCS80211: - error = suser(curthread); - if (error) - break; - ireq = (struct ieee80211req *) data; - switch (ireq->i_type) { - case IEEE80211_IOC_SSID: - if (ireq->i_val != 0 || - ireq->i_len > IEEE80211_NWID_LEN) { - error = EINVAL; - break; - } - error = copyin(ireq->i_data, tmpssid, ireq->i_len); - if (error) - break; - memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); - ic->ic_des_esslen = ireq->i_len; - memcpy(ic->ic_des_essid, tmpssid, ireq->i_len); - error = ENETRESET; - break; - case IEEE80211_IOC_WEP: - /* - * These cards only support one mode so - * we just turn wep on what ever is - * passed in if it's not OFF. - */ - if (ireq->i_val == IEEE80211_WEP_OFF) { - ic->ic_flags &= ~IEEE80211_F_WEPON; - } else { - ic->ic_flags |= IEEE80211_F_WEPON; - } - error = ENETRESET; - break; - case IEEE80211_IOC_WEPKEY: - if ((ic->ic_flags & IEEE80211_F_HASWEP) == 0) { - error = EINVAL; - break; - } - kid = (u_int) ireq->i_val; - if (kid >= IEEE80211_WEP_NKID) { - error = EINVAL; - break; - } - if (ireq->i_len > sizeof(tmpkey)) { - error = EINVAL; - break; - } - memset(tmpkey, 0, sizeof(tmpkey)); - error = copyin(ireq->i_data, tmpkey, ireq->i_len); - if (error) - break; - memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey, - sizeof(tmpkey)); - ic->ic_nw_keys[kid].wk_len = ireq->i_len; - error = ENETRESET; - break; - case IEEE80211_IOC_WEPTXKEY: - kid = (u_int) ireq->i_val; - if (kid >= IEEE80211_WEP_NKID) { - error = EINVAL; - break; - } - ic->ic_wep_txkey = kid; - error = ENETRESET; - break; -#if 0 - case IEEE80211_IOC_AUTHMODE: - sc->wi_authmode = ireq->i_val; - break; -#endif - case IEEE80211_IOC_CHANNEL: - /* XXX 0xffff overflows 16-bit signed */ - if (ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) - ic->ic_des_chan = IEEE80211_CHAN_ANY; - else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX || - isclr(ic->ic_chan_active, ireq->i_val)) { - error = EINVAL; - break; - } else - ic->ic_ibss_chan = ic->ic_des_chan = ireq->i_val; - switch (ic->ic_state) { - case IEEE80211_S_INIT: - case IEEE80211_S_SCAN: - error = ENETRESET; - break; - default: - if (ic->ic_opmode == IEEE80211_M_STA) { - if (ic->ic_des_chan != IEEE80211_CHAN_ANY && - ic->ic_bss.ni_chan != ic->ic_des_chan) - error = ENETRESET; - } else { - if (ic->ic_bss.ni_chan != ic->ic_ibss_chan) - error = ENETRESET; - } - break; - } - break; - case IEEE80211_IOC_POWERSAVE: - switch (ireq->i_val) { - case IEEE80211_POWERSAVE_OFF: - if (ic->ic_flags & IEEE80211_F_PMGTON) { - ic->ic_flags &= ~IEEE80211_F_PMGTON; - error = ENETRESET; - } - break; - case IEEE80211_POWERSAVE_ON: - if ((ic->ic_flags & IEEE80211_F_HASPMGT) == 0) - error = EINVAL; - else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { - ic->ic_flags |= IEEE80211_F_PMGTON; - error = ENETRESET; - } - break; - default: - error = EINVAL; - break; - } - break; - case IEEE80211_IOC_POWERSAVESLEEP: - if (ireq->i_val < 0) { - error = EINVAL; - break; - } - ic->ic_lintval = ireq->i_val; - error = ENETRESET; - break; - default: - error = EINVAL; - break; - } - break; - case SIOCGIFGENERIC: - error = ieee80211_cfgget(ifp, cmd, data); - break; - case SIOCSIFGENERIC: - error = suser(curthread); - if (error) - break; - error = ieee80211_cfgset(ifp, cmd, data); - break; - default: - error = ether_ioctl(ifp, cmd, data); - break; - } - return error; -} - -void -ieee80211_print_essid(u_int8_t *essid, int len) -{ - int i; - u_int8_t *p; - - if (len > IEEE80211_NWID_LEN) - len = IEEE80211_NWID_LEN; - /* determine printable or not */ - for (i = 0, p = essid; i < len; i++, p++) { - if (*p < ' ' || *p > 0x7e) - break; - } - if (i == len) { - printf("\""); - for (i = 0, p = essid; i < len; i++, p++) - printf("%c", *p); - printf("\""); - } else { - printf("0x"); - for (i = 0, p = essid; i < len; i++, p++) - printf("%02x", *p); - } -} - -void -ieee80211_dump_pkt(u_int8_t *buf, int len, int rate, int rssi) -{ - struct ieee80211_frame *wh; - int i; - - wh = (struct ieee80211_frame *)buf; - switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { - case IEEE80211_FC1_DIR_NODS: - printf("NODS %s", ether_sprintf(wh->i_addr2)); - printf("->%s", ether_sprintf(wh->i_addr1)); - printf("(%s)", ether_sprintf(wh->i_addr3)); - break; - case IEEE80211_FC1_DIR_TODS: - printf("TODS %s", ether_sprintf(wh->i_addr2)); - printf("->%s", ether_sprintf(wh->i_addr3)); - printf("(%s)", ether_sprintf(wh->i_addr1)); - break; - case IEEE80211_FC1_DIR_FROMDS: - printf("FRDS %s", ether_sprintf(wh->i_addr3)); - printf("->%s", ether_sprintf(wh->i_addr1)); - printf("(%s)", ether_sprintf(wh->i_addr2)); - break; - case IEEE80211_FC1_DIR_DSTODS: - printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1])); - printf("->%s", ether_sprintf(wh->i_addr3)); - printf("(%s", ether_sprintf(wh->i_addr2)); - printf("->%s)", ether_sprintf(wh->i_addr1)); - break; - } - switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { - case IEEE80211_FC0_TYPE_DATA: - printf(" data"); - break; - case IEEE80211_FC0_TYPE_MGT: - printf(" %s", ieee80211_mgt_subtype_name[ - (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) - >> IEEE80211_FC0_SUBTYPE_SHIFT]); - break; - default: - printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); - break; - } - if (wh->i_fc[1] & IEEE80211_FC1_WEP) - printf(" WEP"); - if (rate >= 0) - printf(" %dM", rate / 2); - if (rssi >= 0) - printf(" +%d", rssi); - printf("\n"); - if (len > 0) { - for (i = 0; i < len; i++) { - if ((i & 1) == 0) - printf(" "); - printf("%02x", buf[i]); - } - printf("\n"); - } -} - -void -ieee80211_watchdog(struct ifnet *ifp) -{ - struct ieee80211com *ic = (void *)ifp; - struct ieee80211_node *ni, *nextbs; - - if (ic->ic_scan_timer) { - if (--ic->ic_scan_timer == 0) { - if (ic->ic_state == IEEE80211_S_SCAN) - ieee80211_end_scan(ifp); - } - } - if (ic->ic_mgt_timer) { - if (--ic->ic_mgt_timer == 0) - ieee80211_new_state(ifp, IEEE80211_S_SCAN, -1); - } - if (ic->ic_inact_timer) { - if (--ic->ic_inact_timer == 0) { - for (ni = TAILQ_FIRST(&ic->ic_node); ni != NULL; ) { - if (++ni->ni_inact <= IEEE80211_INACT_MAX) { - ni = TAILQ_NEXT(ni, ni_list); - continue; - } - if (ifp->if_flags & IFF_DEBUG) - if_printf(ifp, "station %s deauthenticate" - " (reason %d)\n", - ether_sprintf(ni->ni_macaddr), - IEEE80211_REASON_AUTH_EXPIRE); - nextbs = TAILQ_NEXT(ni, ni_list); - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_DEAUTH, - IEEE80211_REASON_AUTH_EXPIRE); - ieee80211_free_node(ic, ni); - ni = nextbs; - } - if (!TAILQ_EMPTY(&ic->ic_node)) - ic->ic_inact_timer = IEEE80211_INACT_WAIT; - } - } - if (ic->ic_scan_timer != 0 || ic->ic_mgt_timer != 0 || - ic->ic_inact_timer != 0) - ifp->if_timer = 1; -} - -void -ieee80211_next_scan(struct ifnet *ifp) -{ - struct ieee80211com *ic = (void *)ifp; - int chan; - - chan = ic->ic_bss.ni_chan; - for (;;) { - chan = (chan + 1) % (IEEE80211_CHAN_MAX + 1); - if (isset(ic->ic_chan_active, chan)) - break; - if (chan == ic->ic_bss.ni_chan) { - DPRINTF(("ieee80211_next_scan: no chan available\n")); - return; - } - } - DPRINTF(("ieee80211_next_scan: chan %d->%d\n", - ic->ic_bss.ni_chan, chan)); - ic->ic_bss.ni_chan = chan; - ieee80211_new_state(ifp, IEEE80211_S_SCAN, -1); -} - -void -ieee80211_end_scan(struct ifnet *ifp) -{ - struct ieee80211com *ic = (void *)ifp; - struct ieee80211_node *ni, *nextbs, *selbs; - void *p; - u_int8_t rate; - int i, fail; - - ni = TAILQ_FIRST(&ic->ic_node); - if (ni == NULL) { - DPRINTF(("ieee80211_end_scan: no scan candidate\n")); - notfound: - if (ic->ic_opmode == IEEE80211_M_IBSS && - (ic->ic_flags & IEEE80211_F_IBSSON) && - ic->ic_des_esslen != 0) { - ni = &ic->ic_bss; - if (ifp->if_flags & IFF_DEBUG) - if_printf(ifp, "creating ibss\n"); - ic->ic_flags |= IEEE80211_F_SIBSS; - ni->ni_nrate = 0; - for (i = 0; i < IEEE80211_RATE_SIZE; i++) { - if (ic->ic_sup_rates[i]) - ni->ni_rates[ni->ni_nrate++] = - ic->ic_sup_rates[i]; - } - IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr); - IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr); - ni->ni_bssid[0] |= 0x02; /* local bit for IBSS */ - ni->ni_esslen = ic->ic_des_esslen; - memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen); - ni->ni_rssi = 0; - ni->ni_rstamp = 0; - memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp)); - ni->ni_intval = ic->ic_lintval; - ni->ni_capinfo = IEEE80211_CAPINFO_IBSS; - if (ic->ic_flags & IEEE80211_F_WEPON) - ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; - ni->ni_chan = ic->ic_ibss_chan; - if (ic->ic_phytype == IEEE80211_T_FH) { - ni->ni_fhdwell = 200; /* XXX */ - ni->ni_fhindex = 1; - } - ieee80211_new_state(ifp, IEEE80211_S_RUN, -1); - return; - } - if (ic->ic_flags & IEEE80211_F_ASCAN) { - if (ifp->if_flags & IFF_DEBUG) - if_printf(ifp, "entering passive scan mode\n"); - ic->ic_flags &= ~IEEE80211_F_ASCAN; - } - ieee80211_next_scan(ifp); - return; - } - selbs = NULL; - if (ifp->if_flags & IFF_DEBUG) - if_printf(ifp, "\tmacaddr bssid chan rssi rate flag wep essid\n"); - for (; ni != NULL; ni = nextbs) { - nextbs = TAILQ_NEXT(ni, ni_list); - if (ni->ni_fails) { - /* - * The configuration of the access points may change - * during my scan. So delete the entry for the AP - * and retry to associate if there is another beacon. - */ - if (ni->ni_fails++ > 2) - ieee80211_free_node(ic, ni); - continue; - } - fail = 0; - if (isclr(ic->ic_chan_active, ni->ni_chan)) - fail |= 0x01; - if (ic->ic_des_chan != IEEE80211_CHAN_ANY && - ni->ni_chan != ic->ic_des_chan) - fail |= 0x01; - if (ic->ic_opmode == IEEE80211_M_IBSS) { - if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) - fail |= 0x02; - } else { - if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) - fail |= 0x02; - } - if (ic->ic_flags & IEEE80211_F_WEPON) { - if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) - fail |= 0x04; - } else { - if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) - fail |= 0x04; - } - rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO); - if (rate & IEEE80211_RATE_BASIC) - fail |= 0x08; - if (ic->ic_des_esslen != 0 && - (ni->ni_esslen != ic->ic_des_esslen || - memcmp(ni->ni_essid, ic->ic_des_essid, - ic->ic_des_esslen != 0))) - fail |= 0x10; - if ((ic->ic_flags & IEEE80211_F_DESBSSID) && - !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) - fail |= 0x20; - if (ifp->if_flags & IFF_DEBUG) { - printf(" %c %s", fail ? '-' : '+', - ether_sprintf(ni->ni_macaddr)); - printf(" %s%c", ether_sprintf(ni->ni_bssid), - fail & 0x20 ? '!' : ' '); - printf(" %3d%c", ni->ni_chan, fail & 0x01 ? '!' : ' '); - printf(" %+4d", ni->ni_rssi); - printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, - fail & 0x08 ? '!' : ' '); - printf(" %4s%c", - (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : - (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : - "????", - fail & 0x02 ? '!' : ' '); - printf(" %3s%c ", - (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? - "wep" : "no", - fail & 0x04 ? '!' : ' '); - ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); - printf("%s\n", fail & 0x10 ? "!" : ""); - } - if (!fail) { - if (selbs == NULL || ni->ni_rssi > selbs->ni_rssi) - selbs = ni; - } - } - if (selbs == NULL) - goto notfound; - p = ic->ic_bss.ni_private; - ic->ic_bss = *selbs; - ic->ic_bss.ni_private = p; - if (p != NULL && ic->ic_node_privlen) - memcpy(p, selbs->ni_private, ic->ic_node_privlen); - if (ic->ic_opmode == IEEE80211_M_IBSS) { - ieee80211_fix_rate(ic, &ic->ic_bss, IEEE80211_F_DOFRATE | - IEEE80211_F_DONEGO | IEEE80211_F_DODEL); - if (ic->ic_bss.ni_nrate == 0) { - selbs->ni_fails++; - goto notfound; - } - ieee80211_new_state(ifp, IEEE80211_S_RUN, -1); - } else - ieee80211_new_state(ifp, IEEE80211_S_AUTH, -1); -} - -struct ieee80211_node * -ieee80211_alloc_node(struct ieee80211com *ic, u_int8_t *macaddr, int copy) -{ - struct ieee80211_node *ni; - int hash; - - ni = malloc(sizeof(struct ieee80211_node) + ic->ic_node_privlen, - M_DEVBUF, M_NOWAIT); - if (ni == NULL) - return NULL; - if (copy) - memcpy(ni, &ic->ic_bss, sizeof(struct ieee80211_node)); - else - memset(ni, 0, sizeof(struct ieee80211_node)); - IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); - if (ic->ic_node_privlen) { - ni->ni_private = &ni[1]; - memset(ni->ni_private, 0, ic->ic_node_privlen); - } else - ni->ni_private = NULL; - - hash = IEEE80211_NODE_HASH(macaddr); - IEEE80211_LOCK(ic); - TAILQ_INSERT_TAIL(&ic->ic_node, ni, ni_list); - LIST_INSERT_HEAD(&ic->ic_hash[hash], ni, ni_hash); - IEEE80211_UNLOCK(ic); - ic->ic_inact_timer = IEEE80211_INACT_WAIT; - return ni; -} - -struct ieee80211_node * -ieee80211_find_node(struct ieee80211com *ic, u_int8_t *macaddr) -{ - struct ieee80211_node *ni; - int hash; - - hash = IEEE80211_NODE_HASH(macaddr); - IEEE80211_LOCK(ic); - LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) { - if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) - break; - } - IEEE80211_UNLOCK(ic); - return ni; -} - -void -ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni) -{ - IEEE80211_LOCK(ic); - if (ic->ic_node_free != NULL) - (*ic->ic_node_free)(ic, ni); - TAILQ_REMOVE(&ic->ic_node, ni, ni_list); - LIST_REMOVE(ni, ni_hash); - IEEE80211_UNLOCK(ic); - free(ni, M_DEVBUF); - if (TAILQ_EMPTY(&ic->ic_node)) - ic->ic_inact_timer = 0; -} - -void -ieee80211_free_allnodes(struct ieee80211com *ic) -{ - struct ieee80211_node *ni; - - while ((ni = TAILQ_FIRST(&ic->ic_node)) != NULL) - ieee80211_free_node(ic, ni); -} - -int -ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags) -{ - int i, j, ignore, error; - int okrate, badrate; - u_int8_t r; - - error = 0; - okrate = badrate = 0; - for (i = 0; i < ni->ni_nrate; ) { - ignore = 0; - if (flags & IEEE80211_F_DOSORT) { - for (j = i + 1; j < ni->ni_nrate; j++) { - if ((ni->ni_rates[i] & IEEE80211_RATE_VAL) > - (ni->ni_rates[j] & IEEE80211_RATE_VAL)) { - r = ni->ni_rates[i]; - ni->ni_rates[i] = ni->ni_rates[j]; - ni->ni_rates[j] = r; - } - } - } - r = ni->ni_rates[i] & IEEE80211_RATE_VAL; - badrate = r; - if (flags & IEEE80211_F_DOFRATE) { - if (ic->ic_fixed_rate >= 0 && - r != (ic->ic_sup_rates[ic->ic_fixed_rate] & - IEEE80211_RATE_VAL)) - ignore++; - } - if (flags & IEEE80211_F_DONEGO) { - for (j = 0; j < IEEE80211_RATE_SIZE; j++) { - if (r == - (ic->ic_sup_rates[j] & IEEE80211_RATE_VAL)) - break; - } - if (j == IEEE80211_RATE_SIZE) { - if (ni->ni_rates[i] & IEEE80211_RATE_BASIC) - error++; - ignore++; - } - } - if (flags & IEEE80211_F_DODEL) { - if (ignore) { - ni->ni_nrate--; - for (j = i; j < ni->ni_nrate; j++) - ni->ni_rates[j] = ni->ni_rates[j + 1]; - ni->ni_rates[j] = 0; - continue; - } - } - if (!ignore) - okrate = ni->ni_rates[i]; - i++; - } - if (okrate == 0 || error != 0) - return badrate | IEEE80211_RATE_BASIC; - return okrate & IEEE80211_RATE_VAL; -} - -static int -ieee80211_send_prreq(struct ieee80211com *ic, struct ieee80211_node *ni, - int type, int dummy) -{ - int i, ret; - struct mbuf *m; - u_int8_t *frm; - - /* - * prreq frame format - * [tlv] ssid - * [tlv] supported rates - */ - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return ENOMEM; - m->m_data += sizeof(struct ieee80211_frame); - frm = mtod(m, u_int8_t *); - - *frm++ = IEEE80211_ELEMID_SSID; - *frm++ = ic->ic_des_esslen; - memcpy(frm, ic->ic_des_essid, ic->ic_des_esslen); - frm += ic->ic_des_esslen; - - *frm++ = IEEE80211_ELEMID_RATES; - for (i = 0; i < IEEE80211_RATE_SIZE; i++) { - if (ic->ic_sup_rates[i] != 0) - frm[i + 1] = ic->ic_sup_rates[i]; - } - *frm++ = i; - frm += i; - m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); - - ret = ieee80211_mgmt_output(&ic->ic_if, ni, m, type); - ic->ic_mgt_timer = IEEE80211_TRANS_WAIT; - return ret; -} - -static int -ieee80211_send_prresp(struct ieee80211com *ic, struct ieee80211_node *bs0, - int type, int dummy) -{ - struct mbuf *m; - u_int8_t *frm; - struct ieee80211_node *ni = &ic->ic_bss; - u_int16_t capinfo; - - /* - * probe response frame format - * [8] time stamp - * [2] beacon interval - * [2] cabability information - * [tlv] ssid - * [tlv] supported rates - * [tlv] parameter set (IBSS) - */ - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return ENOMEM; - m->m_data += sizeof(struct ieee80211_frame); - frm = mtod(m, u_int8_t *); - - memset(frm, 0, 8); /* timestamp should be filled later */ - frm += 8; - *(u_int16_t *)frm = htole16(ni->ni_intval); - frm += 2; - if (ic->ic_opmode == IEEE80211_M_IBSS) - capinfo = IEEE80211_CAPINFO_IBSS; - else - capinfo = IEEE80211_CAPINFO_ESS; - if (ic->ic_flags & IEEE80211_F_WEPON) - capinfo |= IEEE80211_CAPINFO_PRIVACY; - *(u_int16_t *)frm = htole16(capinfo); - frm += 2; - *frm++ = IEEE80211_ELEMID_SSID; - *frm++ = ni->ni_esslen; - memcpy(frm, ni->ni_essid, ni->ni_esslen); - frm += ni->ni_esslen; - *frm++ = IEEE80211_ELEMID_RATES; - *frm++ = ni->ni_nrate; - memcpy(frm, ni->ni_rates, ni->ni_nrate); - frm += ni->ni_nrate; - if (ic->ic_opmode == IEEE80211_M_IBSS) { - *frm++ = IEEE80211_ELEMID_IBSSPARMS; - *frm++ = 2; - *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ - } else { /* IEEE80211_M_HOSTAP */ - /* TODO: TIM */ - *frm++ = IEEE80211_ELEMID_TIM; - *frm++ = 4; /* length */ - *frm++ = 0; /* DTIM count */ - *frm++ = 1; /* DTIM period */ - *frm++ = 0; /* bitmap control */ - *frm++ = 0; /* Partial Virtual Bitmap (variable length) */ - } - /* TODO: check MHLEN limit */ - m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); - - return ieee80211_mgmt_output(&ic->ic_if, bs0, m, type); -} - -static int -ieee80211_send_auth(struct ieee80211com *ic, struct ieee80211_node *ni, - int type, int seq) -{ - struct mbuf *m; - u_int16_t *frm; - int ret; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return ENOMEM; - MH_ALIGN(m, 2 * 3); - m->m_pkthdr.len = m->m_len = 6; - frm = mtod(m, u_int16_t *); - /* TODO: shared key auth */ - frm[0] = htole16(IEEE80211_AUTH_ALG_OPEN); - frm[1] = htole16(seq); - frm[2] = 0; /* status */ - ret = ieee80211_mgmt_output(&ic->ic_if, ni, m, type); - if (ic->ic_opmode == IEEE80211_M_STA) - ic->ic_mgt_timer = IEEE80211_TRANS_WAIT; - return ret; -} - -static int -ieee80211_send_deauth(struct ieee80211com *ic, struct ieee80211_node *ni, - int type, int reason) -{ - struct ifnet *ifp = &ic->ic_if; - struct mbuf *m; - - if (ifp->if_flags & IFF_DEBUG) - if_printf(ifp, "station %s deauthenticate (reason %d)\n", - ether_sprintf(ni->ni_macaddr), reason); - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return ENOMEM; - MH_ALIGN(m, 2); - m->m_pkthdr.len = m->m_len = 2; - *mtod(m, u_int16_t *) = htole16(reason); - return ieee80211_mgmt_output(&ic->ic_if, ni, m, type); -} - -static int -ieee80211_send_asreq(struct ieee80211com *ic, struct ieee80211_node *ni, - int type, int dummy) -{ - struct mbuf *m; - u_int8_t *frm, *rates; - u_int16_t capinfo; - int i, ret; - - /* - * asreq frame format - * [2] capability information - * [2] listen interval - * [6*] current AP address (reassoc only) - * [tlv] ssid - * [tlv] supported rates - */ - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return ENOMEM; - m->m_data += sizeof(struct ieee80211_frame); - frm = mtod(m, u_int8_t *); - - capinfo = 0; - if (ic->ic_opmode == IEEE80211_M_IBSS) - capinfo |= IEEE80211_CAPINFO_IBSS; - else /* IEEE80211_M_STA */ - capinfo |= IEEE80211_CAPINFO_ESS; - if (ic->ic_flags & IEEE80211_F_WEPON) - capinfo |= IEEE80211_CAPINFO_PRIVACY; - *(u_int16_t *)frm = htole16(capinfo); - frm += 2; - - *(u_int16_t *)frm = htole16(ic->ic_lintval); - frm += 2; - - if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { - IEEE80211_ADDR_COPY(frm, ic->ic_bss.ni_bssid); - frm += IEEE80211_ADDR_LEN; - } - - *frm++ = IEEE80211_ELEMID_SSID; - *frm++ = ni->ni_esslen; - memcpy(frm, ni->ni_essid, ni->ni_esslen); - frm += ni->ni_esslen; - - *frm++ = IEEE80211_ELEMID_RATES; - rates = frm++; /* update later */ - for (i = 0; i < IEEE80211_RATE_SIZE; i++) { - if (ni->ni_rates[i] != 0) - *frm++ = ni->ni_rates[i]; - } - *rates = frm - (rates + 1); - m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); - ret = ieee80211_mgmt_output(&ic->ic_if, ni, m, type); - ic->ic_mgt_timer = IEEE80211_TRANS_WAIT; - return ret; -} - -static int -ieee80211_send_asresp(struct ieee80211com *ic, struct ieee80211_node *ni, - int type, int status) -{ - struct mbuf *m; - u_int8_t *frm, *rates, *r; - u_int16_t capinfo; - int i; - - /* - * asreq frame format - * [2] capability information - * [2] status - * [2] association ID - * [tlv] supported rates - */ - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return ENOMEM; - m->m_data += sizeof(struct ieee80211_frame); - frm = mtod(m, u_int8_t *); - - capinfo = IEEE80211_CAPINFO_ESS; - if (ic->ic_flags & IEEE80211_F_WEPON) - capinfo |= IEEE80211_CAPINFO_PRIVACY; - *(u_int16_t *)frm = htole16(capinfo); - frm += 2; - - *(u_int16_t *)frm = htole16(status); - frm += 2; - - if (status == IEEE80211_STATUS_SUCCESS && ni != NULL) - *(u_int16_t *)frm = htole16(ni->ni_associd); - else - *(u_int16_t *)frm = htole16(0); - frm += 2; - - *frm++ = IEEE80211_ELEMID_RATES; - rates = frm++; /* update later */ - if (ni != NULL) - r = ni->ni_rates; - else - r = ic->ic_bss.ni_rates; - for (i = 0; i < IEEE80211_RATE_SIZE; i++, r++) { - if (*r != 0) - *frm++ = *r; - } - *rates = frm - (rates + 1); - m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); - return ieee80211_mgmt_output(&ic->ic_if, ni, m, type); -} - -static int -ieee80211_send_disassoc(struct ieee80211com *ic, struct ieee80211_node *ni, - int type, int reason) -{ - struct ifnet *ifp = &ic->ic_if; - struct mbuf *m; - - if (ifp->if_flags & IFF_DEBUG) - if_printf(ifp, "station %s disassociate (reason %d)\n", - ether_sprintf(ni->ni_macaddr), reason); - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return ENOMEM; - MH_ALIGN(m, 2); - m->m_pkthdr.len = m->m_len = 2; - *mtod(m, u_int16_t *) = htole16(reason); - return ieee80211_mgmt_output(&ic->ic_if, ni, m, - IEEE80211_FC0_SUBTYPE_DISASSOC); -} - -static void -ieee80211_recv_beacon(struct ieee80211com *ic, struct mbuf *m0, int rssi, - u_int32_t rstamp) -{ - struct ieee80211_frame *wh; - struct ieee80211_node *ni; - u_int8_t *frm, *efrm, *tstamp, *bintval, *capinfo, *ssid, *rates; - u_int8_t chan, fhindex; - u_int16_t fhdwell; - - if (ic->ic_opmode != IEEE80211_M_IBSS && - ic->ic_state != IEEE80211_S_SCAN) { - /* XXX: may be useful for background scan */ - return; - } - - wh = mtod(m0, struct ieee80211_frame *); - frm = (u_int8_t *)&wh[1]; - efrm = mtod(m0, u_int8_t *) + m0->m_len; - /* - * beacon frame format - * [8] time stamp - * [2] beacon interval - * [2] cabability information - * [tlv] ssid - * [tlv] supported rates - * [tlv] parameter set (FH/DS) - */ - tstamp = frm; frm += 8; - bintval = frm; frm += 2; - capinfo = frm; frm += 2; - ssid = rates = NULL; - chan = ic->ic_bss.ni_chan; - fhdwell = 0; - fhindex = 0; - while (frm < efrm) { - switch (*frm) { - case IEEE80211_ELEMID_SSID: - ssid = frm; - break; - case IEEE80211_ELEMID_RATES: - rates = frm; - break; - case IEEE80211_ELEMID_FHPARMS: - if (ic->ic_phytype == IEEE80211_T_FH) { - fhdwell = (frm[3] << 8) | frm[2]; - chan = IEEE80211_FH_CHAN(frm[4], frm[5]); - fhindex = frm[6]; - } - break; - case IEEE80211_ELEMID_DSPARMS: - if (ic->ic_phytype == IEEE80211_T_DS) - chan = frm[2]; - break; - } - frm += frm[1] + 2; - } - if (ssid == NULL || rates == NULL) { - DPRINTF(("ieee80211_recv_beacon: ssid=%p, rates=%p, chan=%d\n", - ssid, rates, chan)); - return; - } - if (ssid[1] > IEEE80211_NWID_LEN) { - DPRINTF(("ieee80211_recv_beacon: bad ssid len %d from %s\n", - ssid[1], ether_sprintf(wh->i_addr2))); - return; - } - ni = ieee80211_find_node(ic, wh->i_addr2); -#ifdef IEEE80211_DEBUG - if (ieee80211_debug && - (ieee80211_debug > 1 || ni == NULL || - ic->ic_state == IEEE80211_S_SCAN)) { - printf("ieee80211_recv_prreq: %sbeacon on chan %u (bss chan %u) ", - (ni == NULL ? "new " : ""), chan, ic->ic_bss.ni_chan); - ieee80211_print_essid(ssid + 2, ssid[1]); - printf(" from %s\n", ether_sprintf(wh->i_addr2)); - } -#endif - if (ni == NULL) { - if ((ni = ieee80211_alloc_node(ic, wh->i_addr2, 0)) == NULL) - return; - ni->ni_esslen = ssid[1]; - memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); - memcpy(ni->ni_essid, ssid + 2, ssid[1]); - } else { - if (ssid[1] != 0) { - /* - * Update ESSID at probe response to adopt hidden AP by - * Lucent/Cisco, which announces null ESSID in beacon. - */ - if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == - IEEE80211_FC0_SUBTYPE_PROBE_RESP) { - ni->ni_esslen = ssid[1]; - memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); - memcpy(ni->ni_essid, ssid + 2, ssid[1]); - } - } - } - IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); - memset(ni->ni_rates, 0, IEEE80211_RATE_SIZE); - ni->ni_nrate = rates[1]; - memcpy(ni->ni_rates, rates + 2, ni->ni_nrate); - ieee80211_fix_rate(ic, ni, IEEE80211_F_DOSORT); - ni->ni_rssi = rssi; - ni->ni_rstamp = rstamp; - memcpy(ni->ni_tstamp, tstamp, sizeof(ni->ni_tstamp)); - ni->ni_intval = le16toh(*(u_int16_t *)bintval); - ni->ni_capinfo = le16toh(*(u_int16_t *)capinfo); - ni->ni_chan = chan; - ni->ni_fhdwell = fhdwell; - ni->ni_fhindex = fhindex; - if (ic->ic_state == IEEE80211_S_SCAN && ic->ic_scan_timer == 0) - ieee80211_end_scan(&ic->ic_if); -} - -static void -ieee80211_recv_prreq(struct ieee80211com *ic, struct mbuf *m0, int rssi, - u_int32_t rstamp) -{ - struct ieee80211_frame *wh; - struct ieee80211_node *ni; - u_int8_t *frm, *efrm, *ssid, *rates; - u_int8_t rate; - int allocbs; - - if (ic->ic_opmode == IEEE80211_M_STA) - return; - if (ic->ic_state != IEEE80211_S_RUN) - return; - - wh = mtod(m0, struct ieee80211_frame *); - frm = (u_int8_t *)&wh[1]; - efrm = mtod(m0, u_int8_t *) + m0->m_len; - /* - * prreq frame format - * [tlv] ssid - * [tlv] supported rates - */ - ssid = rates = NULL; - while (frm < efrm) { - switch (*frm) { - case IEEE80211_ELEMID_SSID: - ssid = frm; - break; - case IEEE80211_ELEMID_RATES: - rates = frm; - break; - } - frm += frm[1] + 2; - } - if (ssid == NULL || rates == NULL) { - DPRINTF(("ieee80211_recv_prreq: ssid=%p, rates=%p\n", - ssid, rates)); - return; - } - if (ssid[1] != 0 && - (ssid[1] != ic->ic_bss.ni_esslen || - memcmp(ssid + 2, ic->ic_bss.ni_essid, ic->ic_bss.ni_esslen) != 0)) { -#ifdef IEEE80211_DEBUG - if (ieee80211_debug) { - printf("ieee80211_recv_prreq: ssid unmatch "); - ieee80211_print_essid(ssid + 2, ssid[1]); - printf(" from %s\n", ether_sprintf(wh->i_addr2)); - } -#endif - return; - } - - ni = ieee80211_find_node(ic, wh->i_addr2); - if (ni == NULL) { - if ((ni = ieee80211_alloc_node(ic, wh->i_addr2, 1)) == NULL) - return; - DPRINTF(("ieee80211_recv_prreq: new req from %s\n", - ether_sprintf(wh->i_addr2))); - allocbs = 1; - } else - allocbs = 0; - memset(ni->ni_rates, 0, IEEE80211_RATE_SIZE); - ni->ni_nrate = rates[1]; - memcpy(ni->ni_rates, rates + 2, ni->ni_nrate); - ni->ni_rssi = rssi; - ni->ni_rstamp = rstamp; - rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DOSORT | - IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); - if (rate & IEEE80211_RATE_BASIC) { - DPRINTF(("ieee80211_recv_prreq: rate negotiation failed: %s\n", - ether_sprintf(wh->i_addr2))); - } else { - IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP, - 0); - } - if (allocbs && (ic->ic_opmode == IEEE80211_M_HOSTAP)) - ieee80211_free_node(ic, ni); -} - -static void -ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, int rssi, - u_int32_t rstamp) -{ - struct ifnet *ifp = &ic->ic_if; - struct ieee80211_frame *wh; - struct ieee80211_node *ni; - u_int8_t *frm, *efrm; - u_int16_t algo, seq, status; - int allocbs; - - wh = mtod(m0, struct ieee80211_frame *); - frm = (u_int8_t *)&wh[1]; - efrm = mtod(m0, u_int8_t *) + m0->m_len; - /* - * auth frame format - * [2] algorithm - * [2] sequence - * [2] status - * [tlv*] challenge - */ - if (frm + 6 > efrm) { - DPRINTF(("ieee80211_recv_auth: too short from %s\n", - ether_sprintf(wh->i_addr2))); - return; - } - algo = le16toh(*(u_int16_t *)frm); - seq = le16toh(*(u_int16_t *)(frm + 2)); - status = le16toh(*(u_int16_t *)(frm + 4)); - if (algo != IEEE80211_AUTH_ALG_OPEN) { - /* TODO: shared key auth */ - DPRINTF(("ieee80211_recv_auth: unsupported auth %d from %s\n", - algo, ether_sprintf(wh->i_addr2))); - return; - } - switch (ic->ic_opmode) { - case IEEE80211_M_IBSS: - if (ic->ic_state != IEEE80211_S_RUN || seq != 1) - return; - ieee80211_new_state(&ic->ic_if, IEEE80211_S_AUTH, - wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); - break; - - case IEEE80211_M_AHDEMO: - /* should not come here */ - break; - - case IEEE80211_M_HOSTAP: - if (ic->ic_state != IEEE80211_S_RUN || seq != 1) - return; - allocbs = 0; - ni = ieee80211_find_node(ic, wh->i_addr2); - if (ni == NULL) { - ni = ieee80211_alloc_node(ic, wh->i_addr2, 0); - if (ni == NULL) - return; - IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss.ni_bssid); - allocbs = 1; - } - IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH, 2); - if (ifp->if_flags & IFF_DEBUG) - if_printf(ifp, "station %s %s authenticated\n", - (allocbs ? "newly" : "already"), - ether_sprintf(ni->ni_macaddr)); - break; - - case IEEE80211_M_STA: - if (ic->ic_state != IEEE80211_S_AUTH || seq != 2) - return; - if (status != 0) { - if_printf(&ic->ic_if, - "authentication failed (reason %d) for %s\n", - status, - ether_sprintf(wh->i_addr3)); - ni = ieee80211_find_node(ic, wh->i_addr2); - if (ni != NULL) - ni->ni_fails++; - return; - } - ieee80211_new_state(&ic->ic_if, IEEE80211_S_ASSOC, - wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); - break; - } -} - -static void -ieee80211_recv_asreq(struct ieee80211com *ic, struct mbuf *m0, int rssi, - u_int32_t rstamp) -{ - struct ifnet *ifp = &ic->ic_if; - struct ieee80211_frame *wh; - struct ieee80211_node *ni = &ic->ic_bss; - u_int8_t *frm, *efrm, *ssid, *rates; - u_int16_t capinfo, bintval; - int reassoc, resp, newassoc; - - if (ic->ic_opmode != IEEE80211_M_HOSTAP || - (ic->ic_state != IEEE80211_S_RUN)) - return; - - wh = mtod(m0, struct ieee80211_frame *); - frm = (u_int8_t *)&wh[1]; - efrm = mtod(m0, u_int8_t *) + m0->m_len; - if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == - IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { - reassoc = 1; - resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP; - } else { - reassoc = 0; - resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP; - } - /* - * asreq frame format - * [2] capability information - * [2] listen interval - * [6*] current AP address (reassoc only) - * [tlv] ssid - * [tlv] supported rates - */ - if (frm + (reassoc ? 10 : 4) > efrm) { - DPRINTF(("ieee80211_recv_asreq: too short from %s\n", - ether_sprintf(wh->i_addr2))); - return; - } - - if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss.ni_bssid)) { - DPRINTF(("ieee80211_recv_asreq: ignore other bss from %s\n", - ether_sprintf(wh->i_addr2))); - return; - } - capinfo = le16toh(*(u_int16_t *)frm); frm += 2; - bintval = le16toh(*(u_int16_t *)frm); frm += 2; - if (reassoc) - frm += 6; /* ignore current AP info */ - ssid = rates = NULL; - while (frm < efrm) { - switch (*frm) { - case IEEE80211_ELEMID_SSID: - ssid = frm; - break; - case IEEE80211_ELEMID_RATES: - rates = frm; - break; - } - frm += frm[1] + 2; - } - if (ssid == NULL || rates == NULL) { - DPRINTF(("ieee80211_recv_asreq: ssid=%p, rates=%p\n", - ssid, rates)); - return; - } - if (ssid[1] > IEEE80211_NWID_LEN) { - DPRINTF(("ieee80211_recv_asreq: bad ssid len %d from %s\n", - ssid[1], ether_sprintf(wh->i_addr2))); - return; - } - if (ssid[1] != ic->ic_bss.ni_esslen || - memcmp(ssid + 2, ic->ic_bss.ni_essid, ssid[1]) != 0) { -#ifdef IEEE80211_DEBUG - if (ieee80211_debug) { - printf("ieee80211_recv_asreq: ssid unmatch "); - ieee80211_print_essid(ssid + 2, ssid[1]); - printf(" from %s\n", ether_sprintf(wh->i_addr2)); - } -#endif - return; - } - ni = ieee80211_find_node(ic, wh->i_addr2); - if (ni == NULL) { - DPRINTF(("ieee80211_recv_asreq: not authenticated for %s\n", - ether_sprintf(wh->i_addr2))); - if ((ni = ieee80211_alloc_node(ic, wh->i_addr2, 1)) == NULL) - return; - IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, - IEEE80211_REASON_ASSOC_NOT_AUTHED); - ieee80211_free_node(ic, ni); - return; - } - if ((capinfo & IEEE80211_CAPINFO_ESS) == 0 || - (capinfo & IEEE80211_CAPINFO_PRIVACY) != - ((ic->ic_flags & IEEE80211_F_WEPON) ? - IEEE80211_CAPINFO_PRIVACY : 0)) { - DPRINTF(("ieee80211_recv_asreq: capability unmatch %x for %s\n", - capinfo, ether_sprintf(wh->i_addr2))); - ni->ni_associd = 0; - IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_CAPINFO); - return; - } - memset(ni->ni_rates, 0, IEEE80211_RATE_SIZE); - ni->ni_nrate = rates[1]; - memcpy(ni->ni_rates, rates + 2, ni->ni_nrate); - ieee80211_fix_rate(ic, ni, IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | - IEEE80211_F_DONEGO | IEEE80211_F_DODEL); - if (ni->ni_nrate == 0) { - DPRINTF(("ieee80211_recv_asreq: rate unmatch for %s\n", - ether_sprintf(wh->i_addr2))); - ni->ni_associd = 0; - IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_BASIC_RATE); - return; - } - ni->ni_rssi = rssi; - ni->ni_rstamp = rstamp; - ni->ni_intval = bintval; - ni->ni_capinfo = capinfo; - ni->ni_chan = ic->ic_bss.ni_chan; - ni->ni_fhdwell = ic->ic_bss.ni_fhdwell; - ni->ni_fhindex = ic->ic_bss.ni_fhindex; - if (ni->ni_associd == 0) { - ni->ni_associd = 0xc000 | ic->ic_bss.ni_associd++; - newassoc = 1; - } else - newassoc = 0; - IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS); - if (ifp->if_flags & IFF_DEBUG) - if_printf(ifp, "station %s %s associated\n", - (newassoc ? "newly" : "already"), - ether_sprintf(ni->ni_macaddr)); -} - -static void -ieee80211_recv_asresp(struct ieee80211com *ic, struct mbuf *m0, int rssi, - u_int32_t rstamp) -{ - struct ifnet *ifp = &ic->ic_if; - struct ieee80211_frame *wh; - struct ieee80211_node *ni = &ic->ic_bss; - u_int8_t *frm, *efrm, *rates; - int status; - - if (ic->ic_opmode != IEEE80211_M_STA || - ic->ic_state != IEEE80211_S_ASSOC) - return; - - wh = mtod(m0, struct ieee80211_frame *); - frm = (u_int8_t *)&wh[1]; - efrm = mtod(m0, u_int8_t *) + m0->m_len; - /* - * asresp frame format - * [2] capability information - * [2] status - * [2] association ID - * [tlv] supported rates - */ - if (frm + 6 > efrm) { - DPRINTF(("ieee80211_recv_asresp: too short from %s\n", - ether_sprintf(wh->i_addr2))); - return; - } - - ni->ni_capinfo = le16toh(*(u_int16_t *)frm); - frm += 2; - - status = le16toh(*(u_int16_t *)frm); - frm += 2; - if (status != 0) { - if_printf(ifp, "association failed (reason %d) for %s\n", - status, ether_sprintf(wh->i_addr3)); - ni = ieee80211_find_node(ic, wh->i_addr2); - if (ni != NULL) - ni->ni_fails++; - return; - } - ni->ni_associd = le16toh(*(u_int16_t *)frm); - frm += 2; - rates = frm; - - memset(ni->ni_rates, 0, IEEE80211_RATE_SIZE); - ni->ni_nrate = rates[1]; - memcpy(ni->ni_rates, rates + 2, ni->ni_nrate); - ieee80211_fix_rate(ic, ni, IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | - IEEE80211_F_DONEGO | IEEE80211_F_DODEL); - if (ni->ni_nrate == 0) - return; - ieee80211_new_state(ifp, IEEE80211_S_RUN, - wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); -} - -static void -ieee80211_recv_disassoc(struct ieee80211com *ic, struct mbuf *m0, int rssi, - u_int32_t rstamp) -{ - struct ifnet *ifp = &ic->ic_if; - struct ieee80211_frame *wh; - struct ieee80211_node *ni; - u_int8_t *frm, *efrm; - u_int16_t reason; - - wh = mtod(m0, struct ieee80211_frame *); - frm = (u_int8_t *)&wh[1]; - efrm = mtod(m0, u_int8_t *) + m0->m_len; - /* - * disassoc frame format - * [2] reason - */ - if (frm + 2 > efrm) { - DPRINTF(("ieee80211_recv_disassoc: too short from %s\n", - ether_sprintf(wh->i_addr2))); - return; - } - reason = le16toh(*(u_int16_t *)frm); - switch (ic->ic_opmode) { - case IEEE80211_M_STA: - ieee80211_new_state(&ic->ic_if, IEEE80211_S_ASSOC, - wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); - break; - case IEEE80211_M_HOSTAP: - if ((ni = ieee80211_find_node(ic, wh->i_addr2)) != NULL) { - if (ifp->if_flags & IFF_DEBUG) - if_printf(ifp, "station %s disassociated" - " by peer (reason %d)\n", - ether_sprintf(ni->ni_macaddr), reason); - ni->ni_associd = 0; - } - break; - default: - break; - } -} - -static void -ieee80211_recv_deauth(struct ieee80211com *ic, struct mbuf *m0, int rssi, - u_int32_t rstamp) -{ - struct ifnet *ifp = &ic->ic_if; - struct ieee80211_frame *wh; - struct ieee80211_node *ni; - u_int8_t *frm, *efrm; - u_int16_t reason; - - wh = mtod(m0, struct ieee80211_frame *); - frm = (u_int8_t *)&wh[1]; - efrm = mtod(m0, u_int8_t *) + m0->m_len; - /* - * dauth frame format - * [2] reason - */ - if (frm + 2 > efrm) { - DPRINTF(("ieee80211_recv_deauth: too short from %s\n", - ether_sprintf(wh->i_addr2))); - return; - } - reason = le16toh(*(u_int16_t *)frm); - switch (ic->ic_opmode) { - case IEEE80211_M_STA: - ieee80211_new_state(&ic->ic_if, IEEE80211_S_AUTH, - wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); - break; - case IEEE80211_M_HOSTAP: - if ((ni = ieee80211_find_node(ic, wh->i_addr2)) != NULL) { - if (ifp->if_flags & IFF_DEBUG) - if_printf(ifp, "station %s deauthenticated" - " by peer (reason %d)\n", - ether_sprintf(ni->ni_macaddr), reason); - ieee80211_free_node(ic, ni); - } - break; - default: - break; - } -} - -int -ieee80211_new_state(struct ifnet *ifp, enum ieee80211_state nstate, int mgt) -{ - struct ieee80211com *ic = (void *)ifp; - struct ieee80211_node *ni = &ic->ic_bss; - int i, error, ostate; -#ifdef IEEE80211_DEBUG - static const char *stname[] = - { "INIT", "SCAN", "AUTH", "ASSOC", "RUN" }; -#endif - - ostate = ic->ic_state; - DPRINTF(("ieee80211_new_state: %s -> %s\n", - stname[ostate], stname[nstate])); - if (ic->ic_newstate) { - error = (*ic->ic_newstate)(ic->ic_softc, nstate); - if (error == EINPROGRESS) - return 0; - if (error != 0) - return error; - } - - /* state transition */ - ic->ic_state = nstate; - switch (nstate) { - case IEEE80211_S_INIT: - switch (ostate) { - case IEEE80211_S_INIT: - break; - case IEEE80211_S_RUN: - switch (ic->ic_opmode) { - case IEEE80211_M_STA: - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_DISASSOC, - IEEE80211_REASON_ASSOC_LEAVE); - break; - case IEEE80211_M_HOSTAP: - TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { - if (ni->ni_associd == 0) - continue; - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_DISASSOC, - IEEE80211_REASON_ASSOC_LEAVE); - } - break; - default: - break; - } - /* FALLTHRU */ - case IEEE80211_S_ASSOC: - switch (ic->ic_opmode) { - case IEEE80211_M_STA: - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_DEAUTH, - IEEE80211_REASON_AUTH_LEAVE); - break; - case IEEE80211_M_HOSTAP: - TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_DEAUTH, - IEEE80211_REASON_AUTH_LEAVE); - } - break; - default: - break; - } - /* FALLTHRU */ - case IEEE80211_S_AUTH: - case IEEE80211_S_SCAN: - ic->ic_scan_timer = 0; - ic->ic_mgt_timer = 0; - IF_DRAIN(&ic->ic_mgtq); - if (ic->ic_wep_ctx != NULL) { - free(ic->ic_wep_ctx, M_DEVBUF); - ic->ic_wep_ctx = NULL; - } - ieee80211_free_allnodes(ic); - break; - } - break; - case IEEE80211_S_SCAN: - ic->ic_flags &= ~IEEE80211_F_SIBSS; - ni = &ic->ic_bss; - /* initialize bss for probe request */ - IEEE80211_ADDR_COPY(ni->ni_macaddr, ifp->if_broadcastaddr); - IEEE80211_ADDR_COPY(ni->ni_bssid, ifp->if_broadcastaddr); - ni->ni_nrate = 0; - memset(ni->ni_rates, 0, IEEE80211_RATE_SIZE); - for (i = 0; i < IEEE80211_RATE_SIZE; i++) { - if (ic->ic_sup_rates[i] != 0) - ni->ni_rates[ni->ni_nrate++] = - ic->ic_sup_rates[i]; - } - ni->ni_associd = 0; - ni->ni_rstamp = 0; - switch (ostate) { - case IEEE80211_S_INIT: - ic->ic_flags |= IEEE80211_F_ASCAN; - ic->ic_scan_timer = IEEE80211_ASCAN_WAIT; - /* use lowest rate */ - ni->ni_txrate = 0; - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); - break; - case IEEE80211_S_SCAN: - /* scan next */ - if (ic->ic_flags & IEEE80211_F_ASCAN) { - if (ic->ic_scan_timer == 0) - ic->ic_scan_timer = - IEEE80211_ASCAN_WAIT; - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); - } else { - if (ic->ic_scan_timer == 0) - ic->ic_scan_timer = - IEEE80211_PSCAN_WAIT; - ifp->if_timer = 1; - } - break; - case IEEE80211_S_RUN: - /* beacon miss */ - if (ifp->if_flags & IFF_DEBUG) { - /* XXX bssid clobbered above */ - if_printf(ifp, "no recent beacons from %s;" - " rescanning\n", - ether_sprintf(ic->ic_bss.ni_bssid)); - } - ieee80211_free_allnodes(ic); - /* FALLTHRU */ - case IEEE80211_S_AUTH: - case IEEE80211_S_ASSOC: - /* timeout restart scan */ - ni = ieee80211_find_node(ic, ic->ic_bss.ni_macaddr); - if (ni != NULL) - ni->ni_fails++; - ic->ic_flags |= IEEE80211_F_ASCAN; - ic->ic_scan_timer = IEEE80211_ASCAN_WAIT; - IEEE80211_SEND_MGMT(ic, &ic->ic_bss, - IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); - break; - } - break; - case IEEE80211_S_AUTH: - switch (ostate) { - case IEEE80211_S_INIT: - DPRINTF(("ieee80211_new_state: invalid transition\n")); - break; - case IEEE80211_S_SCAN: - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_AUTH, 1); - break; - case IEEE80211_S_AUTH: - case IEEE80211_S_ASSOC: - switch (mgt) { - case IEEE80211_FC0_SUBTYPE_AUTH: - /* ??? */ - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_AUTH, 2); - break; - case IEEE80211_FC0_SUBTYPE_DEAUTH: - /* ignore and retry scan on timeout */ - break; - } - break; - case IEEE80211_S_RUN: - switch (mgt) { - case IEEE80211_FC0_SUBTYPE_AUTH: - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_AUTH, 2); - ic->ic_state = ostate; /* stay RUN */ - break; - case IEEE80211_FC0_SUBTYPE_DEAUTH: - /* try to reauth */ - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_AUTH, 1); - break; - } - break; - } - break; - case IEEE80211_S_ASSOC: - switch (ostate) { - case IEEE80211_S_INIT: - case IEEE80211_S_SCAN: - case IEEE80211_S_ASSOC: - DPRINTF(("ieee80211_new_state: invalid transition\n")); - break; - case IEEE80211_S_AUTH: - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); - break; - case IEEE80211_S_RUN: - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); - break; - } - break; - case IEEE80211_S_RUN: - switch (ostate) { - case IEEE80211_S_INIT: - case IEEE80211_S_AUTH: - case IEEE80211_S_RUN: - DPRINTF(("ieee80211_new_state: invalid transition\n")); - break; - case IEEE80211_S_SCAN: /* adhoc mode */ - case IEEE80211_S_ASSOC: /* infra mode */ - if (ifp->if_flags & IFF_DEBUG) { - if_printf(ifp, " "); - if (ic->ic_opmode == IEEE80211_M_STA) - printf("associated "); - else - printf("synchronized "); - printf("with %s ssid ", - ether_sprintf(ic->ic_bss.ni_bssid)); - ieee80211_print_essid(ic->ic_bss.ni_essid, - ic->ic_bss.ni_esslen); - printf(" channel %d\n", ic->ic_bss.ni_chan); - } - /* start with highest negotiated rate */ - ic->ic_bss.ni_txrate = ic->ic_bss.ni_nrate - 1; - ic->ic_mgt_timer = 0; - (*ifp->if_start)(ifp); - break; - } - break; - } - return 0; -} - -struct mbuf * -ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag) -{ - struct ieee80211com *ic = (void *)ifp; - struct mbuf *m, *n, *n0; - struct ieee80211_frame *wh; - int i, left, len, moff, noff, kid; - u_int32_t iv, crc; - u_int8_t *ivp; - void *ctx; - u_int8_t keybuf[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE]; - u_int8_t crcbuf[IEEE80211_WEP_CRCLEN]; - - n0 = NULL; - if ((ctx = ic->ic_wep_ctx) == NULL) { - ctx = malloc(arc4_ctxlen(), M_DEVBUF, M_NOWAIT); - if (ctx == NULL) - goto fail; - ic->ic_wep_ctx = ctx; - } - m = m0; - left = m->m_pkthdr.len; - MGET(n, M_DONTWAIT, m->m_type); - n0 = n; - if (n == NULL) - goto fail; - M_MOVE_PKTHDR(n, m); - len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; - if (txflag) { - n->m_pkthdr.len += len; - } else { - n->m_pkthdr.len -= len; - left -= len; - } - n->m_len = MHLEN; - if (n->m_pkthdr.len >= MINCLSIZE) { - MCLGET(n, M_DONTWAIT); - if (n->m_flags & M_EXT) - n->m_len = n->m_ext.ext_size; - } - len = sizeof(struct ieee80211_frame); - memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len); - wh = mtod(n, struct ieee80211_frame *); - left -= len; - moff = len; - noff = len; - if (txflag) { - kid = ic->ic_wep_txkey; - wh->i_fc[1] |= IEEE80211_FC1_WEP; - iv = ic->ic_iv; - /* - * Skip 'bad' IVs from Fluhrer/Mantin/Shamir: - * (B, 255, N) with 3 <= B < 8 - */ - if (iv >= 0x03ff00 && - (iv & 0xf8ff00) == 0x00ff00) - iv += 0x000100; - ic->ic_iv = iv + 1; - /* put iv in little endian to prepare 802.11i */ - ivp = mtod(n, u_int8_t *) + noff; - for (i = 0; i < IEEE80211_WEP_IVLEN; i++) { - ivp[i] = iv & 0xff; - iv >>= 8; - } - ivp[IEEE80211_WEP_IVLEN] = kid << 6; /* pad and keyid */ - noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; - } else { - wh->i_fc[1] &= ~IEEE80211_FC1_WEP; - ivp = mtod(m, u_int8_t *) + moff; - kid = ivp[IEEE80211_WEP_IVLEN] >> 6; - moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; - } - memcpy(keybuf, ivp, IEEE80211_WEP_IVLEN); - memcpy(keybuf + IEEE80211_WEP_IVLEN, ic->ic_nw_keys[kid].wk_key, - ic->ic_nw_keys[kid].wk_len); - arc4_setkey(ctx, keybuf, - IEEE80211_WEP_IVLEN + ic->ic_nw_keys[kid].wk_len); - - /* encrypt with calculating CRC */ - crc = ~0; - while (left > 0) { - len = m->m_len - moff; - if (len == 0) { - m = m->m_next; - moff = 0; - continue; - } - if (len > n->m_len - noff) { - len = n->m_len - noff; - if (len == 0) { - MGET(n->m_next, M_DONTWAIT, n->m_type); - if (n->m_next == NULL) - goto fail; - n = n->m_next; - n->m_len = MLEN; - if (left >= MINCLSIZE) { - MCLGET(n, M_DONTWAIT); - if (n->m_flags & M_EXT) - n->m_len = n->m_ext.ext_size; - } - noff = 0; - continue; - } - } - if (len > left) - len = left; - arc4_encrypt(ctx, mtod(n, caddr_t) + noff, - mtod(m, caddr_t) + moff, len); - if (txflag) - crc = ieee80211_crc_update(crc, - mtod(m, u_int8_t *) + moff, len); - else - crc = ieee80211_crc_update(crc, - mtod(n, u_int8_t *) + noff, len); - left -= len; - moff += len; - noff += len; - } - crc = ~crc; - if (txflag) { - *(u_int32_t *)crcbuf = htole32(crc); - if (n->m_len >= noff + sizeof(crcbuf)) - n->m_len = noff + sizeof(crcbuf); - else { - n->m_len = noff; - MGET(n->m_next, M_DONTWAIT, n->m_type); - if (n->m_next == NULL) - goto fail; - n = n->m_next; - n->m_len = sizeof(crcbuf); - noff = 0; - } - arc4_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf, - sizeof(crcbuf)); - } else { - n->m_len = noff; - for (noff = 0; noff < sizeof(crcbuf); noff += len) { - len = sizeof(crcbuf) - noff; - if (len > m->m_len - moff) - len = m->m_len - moff; - if (len > 0) - arc4_encrypt(ctx, crcbuf + noff, - mtod(m, caddr_t) + moff, len); - m = m->m_next; - moff = 0; - } - if (crc != le32toh(*(u_int32_t *)crcbuf)) { -#ifdef IEEE80211_DEBUG - if (ieee80211_debug) { - if_printf(ifp, "decrypt CRC error\n"); - if (ieee80211_debug > 1) - ieee80211_dump_pkt(n0->m_data, - n0->m_len, -1, -1); - } -#endif - goto fail; - } - } - m_freem(m0); - return n0; - - fail: - m_freem(m0); - m_freem(n0); - return NULL; -} - -/* - * CRC 32 -- routine from RFC 2083 - */ - -/* Table of CRCs of all 8-bit messages */ -static u_int32_t ieee80211_crc_table[256]; - -/* Make the table for a fast CRC. */ -static void -ieee80211_crc_init(void) -{ - u_int32_t c; - int n, k; - - for (n = 0; n < 256; n++) { - c = (u_int32_t)n; - for (k = 0; k < 8; k++) { - if (c & 1) - c = 0xedb88320UL ^ (c >> 1); - else - c = c >> 1; - } - ieee80211_crc_table[n] = c; - } -} - -/* - * Update a running CRC with the bytes buf[0..len-1]--the CRC - * should be initialized to all 1's, and the transmitted value - * is the 1's complement of the final running CRC - */ - -static u_int32_t -ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len) -{ - u_int8_t *endbuf; - - for (endbuf = buf + len; buf < endbuf; buf++) - crc = ieee80211_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); - return crc; -} - -/* - * convert IEEE80211 rate value to ifmedia subtype. - * ieee80211 rate is in unit of 0.5Mbps. - */ - -int -ieee80211_rate2media(int rate, enum ieee80211_phytype phytype) -{ - int mword; - - mword = 0; - switch (phytype) { - case IEEE80211_T_FH: - switch (rate & IEEE80211_RATE_VAL) { - case 0: - mword = IFM_AUTO; - break; - case 2: - mword = IFM_IEEE80211_FH1; - break; - case 4: - mword = IFM_IEEE80211_FH2; - break; - default: - mword = IFM_NONE; - break; - } - break; - - case IEEE80211_T_DS: - switch (rate & IEEE80211_RATE_VAL) { - case 0: - mword = IFM_AUTO; - break; - case 2: - mword = IFM_IEEE80211_DS1; - break; - case 4: - mword = IFM_IEEE80211_DS2; - break; - case 11: - mword = IFM_IEEE80211_DS5; - break; - case 22: - mword = IFM_IEEE80211_DS11; - break; - default: - mword = IFM_NONE; - break; - } - break; - - case IEEE80211_T_OFDM: - switch (rate & IEEE80211_RATE_VAL) { - case 0: - mword = IFM_AUTO; - break; - case 12: - mword = IFM_IEEE80211_OFDM6; - break; - case 18: - mword = IFM_IEEE80211_OFDM9; - break; - case 24: - mword = IFM_IEEE80211_OFDM12; - break; - case 36: - mword = IFM_IEEE80211_OFDM18; - break; - case 48: - mword = IFM_IEEE80211_OFDM24; - break; - case 72: - mword = IFM_IEEE80211_OFDM36; - break; - case 108: - mword = IFM_IEEE80211_OFDM54; - break; - case 144: - mword = IFM_IEEE80211_OFDM72; - break; - default: - mword = IFM_NONE; - break; - } - break; - - default: - mword = IFM_MANUAL; - break; - } - return mword; -} - -int -ieee80211_media2rate(int mword, enum ieee80211_phytype phytype) -{ - int rate; - - rate = 0; - switch (phytype) { - case IEEE80211_T_FH: - switch (IFM_SUBTYPE(mword)) { - case IFM_IEEE80211_FH1: - rate = 2; - break; - case IFM_IEEE80211_FH2: - rate = 4; - break; - } - break; - - case IEEE80211_T_DS: - switch (IFM_SUBTYPE(mword)) { - case IFM_IEEE80211_DS1: - rate = 2; - break; - case IFM_IEEE80211_DS2: - rate = 4; - break; - case IFM_IEEE80211_DS5: - rate = 11; - break; - case IFM_IEEE80211_DS11: - rate = 22; - break; - } - break; - - default: - break; - } - return rate; -} - -/* - * XXX - * Wireless LAN specific configuration interface, which is compatible - * with wiconfig(8). - */ - -int -ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data) -{ - struct ieee80211com *ic = (void *)ifp; - int i, j, error; - struct ifreq *ifr = (struct ifreq *)data; - struct wi_req wreq; - struct wi_ltv_keys *keys; - struct wi_apinfo *ap; - struct ieee80211_node *ni; - struct wi_sigcache wsc; - - error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); - if (error) - return error; - wreq.wi_len = 0; - switch (wreq.wi_type) { - case WI_RID_SERIALNO: - /* nothing appropriate */ - break; - case WI_RID_NODENAME: - strcpy((char *)&wreq.wi_val[1], hostname); - wreq.wi_val[0] = htole16(strlen(hostname)); - wreq.wi_len = (1 + strlen(hostname) + 1) / 2; - break; - case WI_RID_CURRENT_SSID: - if (ic->ic_state != IEEE80211_S_RUN) { - wreq.wi_val[0] = 0; - wreq.wi_len = 1; - break; - } - wreq.wi_val[0] = htole16(ic->ic_bss.ni_esslen); - memcpy(&wreq.wi_val[1], ic->ic_bss.ni_essid, - ic->ic_bss.ni_esslen); - wreq.wi_len = (1 + ic->ic_bss.ni_esslen + 1) / 2; - break; - case WI_RID_OWN_SSID: - case WI_RID_DESIRED_SSID: - wreq.wi_val[0] = htole16(ic->ic_des_esslen); - memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen); - wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2; - break; - case WI_RID_CURRENT_BSSID: - if (ic->ic_state == IEEE80211_S_RUN) - IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss.ni_bssid); - else - memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN); - wreq.wi_len = IEEE80211_ADDR_LEN / 2; - break; - case WI_RID_CHANNEL_LIST: - memset(wreq.wi_val, 0, sizeof(wreq.wi_val)); - /* - * Since channel 0 is not available for DS, channel 1 - * is assigned to LSB on WaveLAN. - */ - if (ic->ic_phytype == IEEE80211_T_DS) - i = 1; - else - i = 0; - for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) { - if (isset(ic->ic_chan_active, i)) { - setbit((u_int8_t *)wreq.wi_val, j); - wreq.wi_len = j / 16 + 1; - } - } - break; - case WI_RID_OWN_CHNL: - wreq.wi_val[0] = htole16(ic->ic_ibss_chan); - wreq.wi_len = 1; - break; - case WI_RID_CURRENT_CHAN: - wreq.wi_val[0] = htole16(ic->ic_bss.ni_chan); - wreq.wi_len = 1; - break; - case WI_RID_COMMS_QUALITY: - wreq.wi_val[0] = 0; /* quality */ - wreq.wi_val[1] = htole16(ic->ic_bss.ni_rssi); /* signal */ - wreq.wi_val[2] = 0; /* noise */ - wreq.wi_len = 3; - break; - case WI_RID_PROMISC: - wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0); - wreq.wi_len = 1; - break; - case WI_RID_PORTTYPE: - wreq.wi_val[0] = htole16(ic->ic_opmode); - wreq.wi_len = 1; - break; - case WI_RID_MAC_NODE: - IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr); - wreq.wi_len = IEEE80211_ADDR_LEN / 2; - break; - case WI_RID_TX_RATE: - if (ic->ic_fixed_rate == -1) - wreq.wi_val[0] = 0; /* auto */ - else - wreq.wi_val[0] = htole16( - (ic->ic_sup_rates[ic->ic_fixed_rate] & - IEEE80211_RATE_VAL) / 2); - wreq.wi_len = 1; - break; - case WI_RID_CUR_TX_RATE: - wreq.wi_val[0] = htole16( - (ic->ic_bss.ni_rates[ic->ic_bss.ni_txrate] & - IEEE80211_RATE_VAL) / 2); - wreq.wi_len = 1; - break; - case WI_RID_RTS_THRESH: - wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN); /* TODO: RTS */ - wreq.wi_len = 1; - break; - case WI_RID_CREATE_IBSS: - wreq.wi_val[0] = - htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0); - wreq.wi_len = 1; - break; - case WI_RID_MICROWAVE_OVEN: - wreq.wi_val[0] = 0; /* no ... not supported */ - wreq.wi_len = 1; - break; - case WI_RID_ROAMING_MODE: - wreq.wi_val[0] = htole16(1); /* enabled ... not supported */ - wreq.wi_len = 1; - break; - case WI_RID_SYSTEM_SCALE: - wreq.wi_val[0] = htole16(1); /* low density ... not supp */ - wreq.wi_len = 1; - break; - case WI_RID_PM_ENABLED: - wreq.wi_val[0] = - htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0); - wreq.wi_len = 1; - break; - case WI_RID_MAX_SLEEP: - wreq.wi_val[0] = htole16(ic->ic_lintval); - wreq.wi_len = 1; - break; - case WI_RID_CUR_BEACON_INT: - wreq.wi_val[0] = htole16(ic->ic_bss.ni_intval); - wreq.wi_len = 1; - break; - case WI_RID_WEP_AVAIL: - wreq.wi_val[0] = - htole16((ic->ic_flags & IEEE80211_F_HASWEP) ? 1 : 0); - wreq.wi_len = 1; - break; - case WI_RID_CNFAUTHMODE: - wreq.wi_val[0] = htole16(1); /* TODO: open system only */ - wreq.wi_len = 1; - break; - case WI_RID_ENCRYPTION: - wreq.wi_val[0] = - htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0); - wreq.wi_len = 1; - break; - case WI_RID_TX_CRYPT_KEY: - wreq.wi_val[0] = htole16(ic->ic_wep_txkey); - wreq.wi_len = 1; - break; - case WI_RID_DEFLT_CRYPT_KEYS: - keys = (struct wi_ltv_keys *)&wreq; - /* do not show keys to non-root user */ - error = suser(curthread); - if (error) { - memset(keys, 0, sizeof(*keys)); - error = 0; - break; - } - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - keys->wi_keys[i].wi_keylen = - htole16(ic->ic_nw_keys[i].wk_len); - memcpy(keys->wi_keys[i].wi_keydat, - ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len); - } - wreq.wi_len = sizeof(*keys) / 2; - break; - case WI_RID_MAX_DATALEN: - wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN); /* TODO: frag */ - wreq.wi_len = 1; - break; - case WI_RID_IFACE_STATS: - /* XXX: should be implemented in lower drivers */ - break; - case WI_RID_READ_APS: - if (ic->ic_opmode != IEEE80211_M_HOSTAP) { - for (i = 0; i < IEEE80211_PSCAN_WAIT; i++) { - tsleep((caddr_t)ic, PWAIT | PCATCH, "i80211", - hz); - if (ic->ic_state != IEEE80211_S_SCAN || - (ic->ic_flags & IEEE80211_F_SCANAP) == 0 || - (ic->ic_flags & IEEE80211_F_ASCAN) == 0) - break; - } - ic->ic_flags &= ~IEEE80211_F_SCANAP; - memcpy(ic->ic_chan_active, ic->ic_chan_avail, - sizeof(ic->ic_chan_active)); - } - i = 0; - ap = (void *)((char *)wreq.wi_val + sizeof(i)); - TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { - if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1)) - break; - memset(ap, 0, sizeof(*ap)); - if (ic->ic_opmode == IEEE80211_M_HOSTAP) { - IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr); - ap->namelen = ic->ic_des_esslen; - if (ic->ic_des_esslen) - memcpy(ap->name, ic->ic_des_essid, - ic->ic_des_esslen); - } else { - IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid); - ap->namelen = ni->ni_esslen; - if (ni->ni_esslen) - memcpy(ap->name, ni->ni_essid, - ni->ni_esslen); - } - ap->channel = ni->ni_chan; - ap->signal = ni->ni_rssi; - ap->capinfo = ni->ni_capinfo; - ap->interval = ni->ni_intval; - for (j = 0; j < ni->ni_nrate; j++) { - if (ni->ni_rates[j] & IEEE80211_RATE_BASIC) { - ap->rate = (ni->ni_rates[j] & - IEEE80211_RATE_VAL) * 5; /* XXX */ - } - } - i++; - ap++; - } - memcpy(wreq.wi_val, &i, sizeof(i)); - wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2; - break; - case WI_RID_READ_CACHE: - i = 0; - TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { - if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1) - break; - IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr); - memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc)); - wsc.signal = ni->ni_rssi; - wsc.noise = 0; - wsc.quality = 0; - memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i, - &wsc, sizeof(wsc)); - i++; - } - wreq.wi_len = sizeof(wsc) * i / 2; - break; - case WI_RID_SCAN_APS: - error = EINVAL; - break; - default: - error = EINVAL; - break; - } - if (error == 0) { - wreq.wi_len++; - error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); - } - return error; -} - -int -ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data) -{ - struct ieee80211com *ic = (void *)ifp; - int i, j, len, error; - struct ifreq *ifr = (struct ifreq *)data; - struct wi_ltv_keys *keys; - struct wi_req wreq; - u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)]; - - error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); - if (error) - return error; - if (wreq.wi_len-- < 1) - return EINVAL; - switch (wreq.wi_type) { - case WI_RID_SERIALNO: - case WI_RID_NODENAME: - return EPERM; - case WI_RID_CURRENT_SSID: - return EPERM; - case WI_RID_OWN_SSID: - case WI_RID_DESIRED_SSID: - len = le16toh(wreq.wi_val[0]); - if (wreq.wi_len < (1 + len + 1) / 2) - return EINVAL; - if (len > IEEE80211_NWID_LEN) - return EINVAL; - ic->ic_des_esslen = len; - memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid)); - memcpy(ic->ic_des_essid, &wreq.wi_val[1], len); - error = ENETRESET; - break; - case WI_RID_CURRENT_BSSID: - return EPERM; - case WI_RID_OWN_CHNL: - if (wreq.wi_len != 1) - return EINVAL; - i = le16toh(wreq.wi_val[0]); - if (i < 0 || - i > IEEE80211_CHAN_MAX || - isclr(ic->ic_chan_active, i)) - return EINVAL; - ic->ic_ibss_chan = i; - if (ic->ic_flags & IEEE80211_F_SIBSS) - error = ENETRESET; - break; - case WI_RID_CURRENT_CHAN: - return EPERM; - case WI_RID_COMMS_QUALITY: - return EPERM; - case WI_RID_PROMISC: - if (wreq.wi_len != 1) - return EINVAL; - if (ifp->if_flags & IFF_PROMISC) { - if (wreq.wi_val[0] == 0) { - ifp->if_flags &= ~IFF_PROMISC; - error = ENETRESET; - } - } else { - if (wreq.wi_val[0] != 0) { - ifp->if_flags |= IFF_PROMISC; - error = ENETRESET; - } - } - break; - case WI_RID_PORTTYPE: - if (wreq.wi_len != 1) - return EINVAL; - switch (le16toh(wreq.wi_val[0])) { - case IEEE80211_M_STA: - break; - case IEEE80211_M_IBSS: - if (!(ic->ic_flags & IEEE80211_F_HASIBSS)) - return EINVAL; - break; - case IEEE80211_M_AHDEMO: - if (ic->ic_phytype != IEEE80211_T_DS || - !(ic->ic_flags & IEEE80211_F_HASAHDEMO)) - return EINVAL; - break; - case IEEE80211_M_HOSTAP: - if (!(ic->ic_flags & IEEE80211_F_HASHOSTAP)) - return EINVAL; - break; - default: - return EINVAL; - } - if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) { - ic->ic_opmode = le16toh(wreq.wi_val[0]); - error = ENETRESET; - } - break; -#if 0 - case WI_RID_MAC_NODE: - if (wreq.wi_len != IEEE80211_ADDR_LEN / 2) - return EINVAL; - IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val); - /* if_init will copy lladdr into ic_myaddr */ - error = ENETRESET; - break; -#endif - case WI_RID_TX_RATE: - if (wreq.wi_len != 1) - return EINVAL; - if (wreq.wi_val[0] == 0) { - /* auto */ - ic->ic_fixed_rate = -1; - break; - } - for (i = 0; i < IEEE80211_RATE_SIZE; i++) { - if (le16toh(wreq.wi_val[0]) == - (ic->ic_sup_rates[i] & IEEE80211_RATE_VAL) / 2) - break; - } - if (i == IEEE80211_RATE_SIZE) - return EINVAL; - ic->ic_fixed_rate = i; - error = ENETRESET; - break; - case WI_RID_CUR_TX_RATE: - return EPERM; - break; - case WI_RID_RTS_THRESH: - if (wreq.wi_len != 1) - return EINVAL; - if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN) - return EINVAL; /* TODO: RTS */ - break; - case WI_RID_CREATE_IBSS: - if (wreq.wi_len != 1) - return EINVAL; - if (wreq.wi_val[0] != 0) { - if ((ic->ic_flags & IEEE80211_F_HASIBSS) == 0) - return EINVAL; - if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) { - ic->ic_flags |= IEEE80211_F_IBSSON; - if (ic->ic_opmode == IEEE80211_M_IBSS && - ic->ic_state == IEEE80211_S_SCAN) - error = ENETRESET; - } - } else { - if (ic->ic_flags & IEEE80211_F_IBSSON) { - ic->ic_flags &= ~IEEE80211_F_IBSSON; - if (ic->ic_flags & IEEE80211_F_SIBSS) { - ic->ic_flags &= ~IEEE80211_F_SIBSS; - error = ENETRESET; - } - } - } - break; - case WI_RID_MICROWAVE_OVEN: - if (wreq.wi_len != 1) - return EINVAL; - if (wreq.wi_val[0] != 0) - return EINVAL; /* not supported */ - break; - case WI_RID_ROAMING_MODE: - if (wreq.wi_len != 1) - return EINVAL; - if (le16toh(wreq.wi_val[0]) != 1) - return EINVAL; /* not supported */ - break; - case WI_RID_SYSTEM_SCALE: - if (wreq.wi_len != 1) - return EINVAL; - if (le16toh(wreq.wi_val[0]) != 1) - return EINVAL; /* not supported */ - break; - case WI_RID_PM_ENABLED: - if (wreq.wi_len != 1) - return EINVAL; - if (wreq.wi_val[0] != 0) { - if ((ic->ic_flags & IEEE80211_F_HASPMGT) == 0) - return EINVAL; - if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { - ic->ic_flags |= IEEE80211_F_PMGTON; - error = ENETRESET; - } - } else { - if (ic->ic_flags & IEEE80211_F_PMGTON) { - ic->ic_flags &= ~IEEE80211_F_PMGTON; - error = ENETRESET; - } - } - break; - case WI_RID_MAX_SLEEP: - if (wreq.wi_len != 1) - return EINVAL; - ic->ic_lintval = le16toh(wreq.wi_val[0]); - if (ic->ic_flags & IEEE80211_F_PMGTON) - error = ENETRESET; - break; - case WI_RID_CUR_BEACON_INT: - return EPERM; - case WI_RID_WEP_AVAIL: - return EPERM; - case WI_RID_CNFAUTHMODE: - if (wreq.wi_len != 1) - return EINVAL; - if (le16toh(wreq.wi_val[0]) != 1) - return EINVAL; /* TODO: shared key auth */ - break; - case WI_RID_ENCRYPTION: - if (wreq.wi_len != 1) - return EINVAL; - if (wreq.wi_val[0] != 0) { - if ((ic->ic_flags & IEEE80211_F_HASWEP) == 0) - return EINVAL; - if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) { - ic->ic_flags |= IEEE80211_F_WEPON; - error = ENETRESET; - } - } else { - if (ic->ic_flags & IEEE80211_F_WEPON) { - ic->ic_flags &= ~IEEE80211_F_WEPON; - error = ENETRESET; - } - } - break; - case WI_RID_TX_CRYPT_KEY: - if (wreq.wi_len != 1) - return EINVAL; - i = le16toh(wreq.wi_val[0]); - if (i >= IEEE80211_WEP_NKID) - return EINVAL; - ic->ic_wep_txkey = i; - break; - case WI_RID_DEFLT_CRYPT_KEYS: - if (wreq.wi_len != sizeof(struct wi_ltv_keys) / 2) - return EINVAL; - keys = (struct wi_ltv_keys *)&wreq; - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - len = le16toh(keys->wi_keys[i].wi_keylen); - if (len != 0 && len < IEEE80211_WEP_KEYLEN) - return EINVAL; - if (len > sizeof(ic->ic_nw_keys[i].wk_key)) - return EINVAL; - } - memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys)); - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - len = le16toh(keys->wi_keys[i].wi_keylen); - ic->ic_nw_keys[i].wk_len = len; - memcpy(ic->ic_nw_keys[i].wk_key, - keys->wi_keys[i].wi_keydat, len); - } - error = ENETRESET; - break; - case WI_RID_MAX_DATALEN: - if (wreq.wi_len != 1) - return EINVAL; - len = le16toh(wreq.wi_val[0]); - if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN) - return EINVAL; - if (len != IEEE80211_MAX_LEN) - return EINVAL; /* TODO: fragment */ - break; - case WI_RID_IFACE_STATS: - error = EPERM; - break; - case WI_RID_SCAN_APS: - if (ic->ic_opmode == IEEE80211_M_HOSTAP) - break; - wreq.wi_len -= 2; /* XXX: tx rate? */ - /* FALLTHRU */ - case WI_RID_CHANNEL_LIST: - memset(chanlist, 0, sizeof(chanlist)); - /* - * Since channel 0 is not available for DS, channel 1 - * is assigned to LSB on WaveLAN. - */ - if (ic->ic_phytype == IEEE80211_T_DS) - i = 1; - else - i = 0; - for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) { - if (j / 16 >= wreq.wi_len) - break; - if (isclr((u_int8_t *)wreq.wi_val, j)) - continue; - if (isclr(ic->ic_chan_avail, i)) { - if (wreq.wi_type == WI_RID_CHANNEL_LIST) - error = EPERM; - else - continue; - } - setbit(chanlist, i); - } - if (error == EPERM && ic->ic_chancheck != NULL) - error = (*ic->ic_chancheck)(ic->ic_softc, chanlist); - if (error) - return error; - memcpy(ic->ic_chan_active, chanlist, - sizeof(ic->ic_chan_active)); - if (isclr(chanlist, ic->ic_ibss_chan)) { - for (i = 0; i <= IEEE80211_CHAN_MAX; i++) - if (isset(chanlist, i)) { - ic->ic_ibss_chan = i; - break; - } - } - if (isclr(chanlist, ic->ic_bss.ni_chan)) - ic->ic_bss.ni_chan = ic->ic_ibss_chan; - if (wreq.wi_type == WI_RID_CHANNEL_LIST) - error = ENETRESET; - else { - ic->ic_flags |= IEEE80211_F_SCANAP; - error = ieee80211_new_state(ifp, IEEE80211_S_SCAN, -1); - } - break; - default: - error = EINVAL; - break; - } - return error; -} - -/* - * Module glue. - * - * NB: the module name is "wlan" for compatibility with NetBSD. - */ - -static int -ieee80211_modevent(module_t mod, int type, void *unused) -{ - switch (type) { - case MOD_LOAD: - if (bootverbose) - printf("wlan: <802.11 Link Layer>\n"); - return 0; - case MOD_UNLOAD: - return 0; - } - return EINVAL; -} - -static moduledata_t ieee80211_mod = { - "wlan", - ieee80211_modevent, - 0 -}; -DECLARE_MODULE(wlan, ieee80211_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); -MODULE_VERSION(wlan, 1); -MODULE_DEPEND(wlan, rc4, 1, 1, 1);