Date: Mon, 3 Dec 2007 18:39:27 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 130106 for review Message-ID: <200712031839.lB3IdRAC084058@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=130106 Change 130106 by sam@sam_ebb on 2007/12/03 18:39:25 checkpoint vap integration; compiles but needs major work and is still missing pieces Supported by: Marvell Affected files ... .. //depot/projects/vap/sys/conf/files#8 edit .. //depot/projects/vap/sys/conf/options#6 edit .. //depot/projects/vap/sys/modules/Makefile#7 edit .. //depot/projects/vap/sys/modules/wlan/Makefile#6 edit .. //depot/projects/vap/sys/net/if_media.h#7 edit .. //depot/projects/vap/sys/net80211/_ieee80211.h#8 edit .. //depot/projects/vap/sys/net80211/ieee80211.c#16 edit .. //depot/projects/vap/sys/net80211/ieee80211.h#6 edit .. //depot/projects/vap/sys/net80211/ieee80211_acl.c#6 edit .. //depot/projects/vap/sys/net80211/ieee80211_adhoc.c#1 add .. //depot/projects/vap/sys/net80211/ieee80211_adhoc.h#1 add .. //depot/projects/vap/sys/net80211/ieee80211_amrr.c#4 edit .. //depot/projects/vap/sys/net80211/ieee80211_amrr.h#4 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto.c#8 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto.h#9 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto_ccmp.c#8 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto_none.c#8 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto_tkip.c#8 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto_wep.c#8 edit .. //depot/projects/vap/sys/net80211/ieee80211_dfs.c#1 add .. //depot/projects/vap/sys/net80211/ieee80211_dfs.h#1 add .. //depot/projects/vap/sys/net80211/ieee80211_freebsd.c#13 edit .. //depot/projects/vap/sys/net80211/ieee80211_freebsd.h#12 edit .. //depot/projects/vap/sys/net80211/ieee80211_hostap.c#1 add .. //depot/projects/vap/sys/net80211/ieee80211_hostap.h#1 add .. //depot/projects/vap/sys/net80211/ieee80211_ht.c#4 edit .. //depot/projects/vap/sys/net80211/ieee80211_ht.h#4 edit .. //depot/projects/vap/sys/net80211/ieee80211_input.c#22 edit .. //depot/projects/vap/sys/net80211/ieee80211_ioctl.c#18 edit .. //depot/projects/vap/sys/net80211/ieee80211_ioctl.h#10 edit .. //depot/projects/vap/sys/net80211/ieee80211_monitor.c#1 add .. //depot/projects/vap/sys/net80211/ieee80211_monitor.h#1 add .. //depot/projects/vap/sys/net80211/ieee80211_node.c#16 edit .. //depot/projects/vap/sys/net80211/ieee80211_node.h#11 edit .. //depot/projects/vap/sys/net80211/ieee80211_output.c#19 edit .. //depot/projects/vap/sys/net80211/ieee80211_power.c#6 edit .. //depot/projects/vap/sys/net80211/ieee80211_proto.c#16 edit .. //depot/projects/vap/sys/net80211/ieee80211_proto.h#11 edit .. //depot/projects/vap/sys/net80211/ieee80211_radiotap.h#6 edit .. //depot/projects/vap/sys/net80211/ieee80211_scan.c#11 edit .. //depot/projects/vap/sys/net80211/ieee80211_scan.h#9 edit .. //depot/projects/vap/sys/net80211/ieee80211_scan_ap.c#7 delete .. //depot/projects/vap/sys/net80211/ieee80211_scan_sta.c#13 edit .. //depot/projects/vap/sys/net80211/ieee80211_sta.c#1 add .. //depot/projects/vap/sys/net80211/ieee80211_sta.h#1 add .. //depot/projects/vap/sys/net80211/ieee80211_var.h#21 edit .. //depot/projects/vap/sys/net80211/ieee80211_wds.c#1 add .. //depot/projects/vap/sys/net80211/ieee80211_wds.h#1 add .. //depot/projects/vap/sys/net80211/ieee80211_xauth.c#6 edit Differences ... ==== //depot/projects/vap/sys/conf/files#8 (text+ko) ==== @@ -1650,24 +1650,29 @@ mxge | ppp_deflate | netgraph_deflate net80211/ieee80211.c optional wlan net80211/ieee80211_acl.c optional wlan_acl +net80211/ieee80211_adhoc.c optional wlan net80211/ieee80211_amrr.c optional wlan_amrr net80211/ieee80211_crypto.c optional wlan net80211/ieee80211_crypto_ccmp.c optional wlan_ccmp net80211/ieee80211_crypto_none.c optional wlan net80211/ieee80211_crypto_tkip.c optional wlan_tkip net80211/ieee80211_crypto_wep.c optional wlan_wep +net80211/ieee80211_dfs.c optional wlan net80211/ieee80211_freebsd.c optional wlan +net80211/ieee80211_hostap.c optional wlan net80211/ieee80211_ht.c optional wlan net80211/ieee80211_input.c optional wlan net80211/ieee80211_ioctl.c optional wlan +net80211/ieee80211_monitor.c optional wlan net80211/ieee80211_node.c optional wlan net80211/ieee80211_output.c optional wlan net80211/ieee80211_power.c optional wlan net80211/ieee80211_proto.c optional wlan net80211/ieee80211_regdomain.c optional wlan net80211/ieee80211_scan.c optional wlan -net80211/ieee80211_scan_ap.c optional wlan_scan_ap net80211/ieee80211_scan_sta.c optional wlan_scan_sta +net80211/ieee80211_sta.c optional wlan +net80211/ieee80211_wds.c optional wlan net80211/ieee80211_xauth.c optional wlan_xauth netatalk/aarp.c optional netatalk netatalk/at_control.c optional netatalk ==== //depot/projects/vap/sys/conf/options#6 (text+ko) ==== @@ -750,3 +750,8 @@ # Interrupt filtering INTR_FILTER opt_global.h + +# 802.11 support layer +IEEE80211_DEBUG opt_wlan.h +IEEE80211_DEBUG_REFCNT opt_wlan.h +IEEE80211_AMPDU_AGE opt_wlan.h ==== //depot/projects/vap/sys/modules/Makefile#7 (text+ko) ==== @@ -304,7 +304,6 @@ wlan_acl \ wlan_amrr \ wlan_ccmp \ - wlan_scan_ap \ wlan_scan_sta \ wlan_tkip \ wlan_wep \ ==== //depot/projects/vap/sys/modules/wlan/Makefile#6 (text+ko) ==== @@ -3,16 +3,18 @@ .PATH: ${.CURDIR}/../../net80211 KMOD= wlan -SRCS= ieee80211.c ieee80211_crypto.c ieee80211_crypto_none.c \ +SRCS= ieee80211.c ieee80211_crypto.c ieee80211_crypto_none.c ieee80211_dfs.c \ ieee80211_freebsd.c ieee80211_input.c ieee80211_ioctl.c \ ieee80211_node.c ieee80211_output.c ieee80211_power.c \ ieee80211_proto.c ieee80211_scan.c ieee80211_regdomain.c \ - ieee80211_ht.c -SRCS+= bus_if.h device_if.h opt_compat.h opt_inet.h opt_ipx.h + ieee80211_ht.c \ + ieee80211_adhoc.c ieee80211_hostap.c ieee80211_monitor.c \ + ieee80211_sta.c ieee80211_wds.c +SRCS+= bus_if.h device_if.h opt_inet.h opt_ipx.h opt_wlan.h .if !defined(KERNBUILDDIR) -opt_compat.h: - echo "#define COMPAT_FREEBSD6 1" > ${.TARGET} +opt_wlan.h: + echo "#define IEEE80211_DEBUG 1" > opt_wlan.h opt_inet.h: echo "#define INET 1" > opt_inet.h ==== //depot/projects/vap/sys/net/if_media.h#7 (text+ko) ==== @@ -208,7 +208,7 @@ #define IFM_IEEE80211_ADHOC 0x00000100 /* Operate in Adhoc mode */ #define IFM_IEEE80211_HOSTAP 0x00000200 /* Operate in Host AP mode */ #define IFM_IEEE80211_IBSS 0x00000400 /* Operate in IBSS mode */ -#define IFM_IEEE80211_IBSSMASTER 0x00000800 /* Operate as an IBSS master */ +#define IFM_IEEE80211_WDS 0x00000800 /* Operate in WDS mode */ #define IFM_IEEE80211_TURBO 0x00001000 /* Operate in turbo mode */ #define IFM_IEEE80211_MONITOR 0x00002000 /* Operate in monitor mode */ @@ -495,7 +495,7 @@ { IFM_IEEE80211_ADHOC, "adhoc" }, \ { IFM_IEEE80211_HOSTAP, "hostap" }, \ { IFM_IEEE80211_IBSS, "ibss" }, \ - { IFM_IEEE80211_IBSSMASTER, "ibss-master" }, \ + { IFM_IEEE80211_WDS, "wds" }, \ { IFM_IEEE80211_TURBO, "turbo" }, \ { IFM_IEEE80211_MONITOR, "monitor" }, \ { 0, NULL }, \ ==== //depot/projects/vap/sys/net80211/_ieee80211.h#8 (text+ko) ==== @@ -28,16 +28,31 @@ #ifndef _NET80211__IEEE80211_H_ #define _NET80211__IEEE80211_H_ +/* + * 802.11 implementation definitions. + * + * NB: this file is used by applications. + */ + +/* + * PHY type; mostly used to identify FH phys. + */ enum ieee80211_phytype { IEEE80211_T_DS, /* direct sequence spread spectrum */ IEEE80211_T_FH, /* frequency hopping */ IEEE80211_T_OFDM, /* frequency division multiplexing */ IEEE80211_T_TURBO, /* high rate OFDM, aka turbo mode */ - IEEE80211_T_HT, /* high throughput, full GI */ + IEEE80211_T_HT, /* high throughput */ }; #define IEEE80211_T_CCK IEEE80211_T_DS /* more common nomenclature */ -/* XXX not really a mode; there are really multiple PHY's */ +/* + * PHY mode; this is not really a mode as multi-mode devices + * have multiple PHY's. Mode is mostly used as a shorthand + * for constraining which channels to consider in setting up + * operation. Modes used to be used more extensively when + * channels were identified as IEEE channel numbers. + */ enum ieee80211_phymode { IEEE80211_MODE_AUTO = 0, /* autoselect */ IEEE80211_MODE_11A = 1, /* 5GHz, OFDM */ @@ -52,13 +67,18 @@ }; #define IEEE80211_MODE_MAX (IEEE80211_MODE_11NG+1) +/* + * Operating mode. Devices do not necessarily support + * all modes; they indicate which are supported in their + * capabilities. + */ enum ieee80211_opmode { + IEEE80211_M_IBSS = 0, /* IBSS (adhoc) station */ IEEE80211_M_STA = 1, /* infrastructure station */ - IEEE80211_M_IBSS = 0, /* IBSS (adhoc) station */ + IEEE80211_M_WDS = 2, /* WDS link */ IEEE80211_M_AHDEMO = 3, /* Old lucent compatible adhoc demo */ - IEEE80211_M_HOSTAP = 6, /* Software Access Point */ - IEEE80211_M_MONITOR = 8, /* Monitor mode */ - IEEE80211_M_WDS = 2 /* WDS link */ + IEEE80211_M_HOSTAP = 4, /* Software Access Point */ + IEEE80211_M_MONITOR = 5, /* Monitor mode */ }; #define IEEE80211_OPMODE_MAX (IEEE80211_M_MONITOR+1) @@ -72,7 +92,11 @@ }; /* - * Authentication mode. + * Authentication mode. The open and shared key authentication + * modes are implemented within the 802.11 layer. 802.1x and + * WPA/802.11i are implemented in user mode by setting the + * 802.11 layer into IEEE80211_AUTH_8021X and deferring + * authentication to user space programs. */ enum ieee80211_authmode { IEEE80211_AUTH_NONE = 0, @@ -265,18 +289,28 @@ #define IEEE80211_NONQOS_TID WME_NUM_TID /* index for non-QoS sta */ /* + * The 802.11 spec says at most 2007 stations may be + * associated at once. For most AP's this is way more + * than is feasible so we use a default of 128. This + * number may be overridden by the driver and/or by + * user configuration but may not be less than IEEE80211_AID_MIN. + */ +#define IEEE80211_AID_DEF 128 +#define IEEE80211_AID_MIN 16 + +/* * 802.11 rate set. */ #define IEEE80211_RATE_SIZE 8 /* 802.11 standard */ #define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */ struct ieee80211_rateset { - uint8_t rs_nrates; - uint8_t rs_rates[IEEE80211_RATE_MAXSIZE]; + uint8_t rs_nrates; + uint8_t rs_rates[IEEE80211_RATE_MAXSIZE]; }; /* - * 802.11n variant of ieee80211_rateset. Instead + * 802.11n variant of ieee80211_rateset. Instead of * legacy rates the entries are MCS rates. We define * the structure such that it can be used interchangeably * with an ieee80211_rateset (modulo structure size). @@ -284,27 +318,58 @@ #define IEEE80211_HTRATE_MAXSIZE 127 struct ieee80211_htrateset { - uint8_t rs_nrates; - uint8_t rs_rates[IEEE80211_HTRATE_MAXSIZE]; + uint8_t rs_nrates; + uint8_t rs_rates[IEEE80211_HTRATE_MAXSIZE]; }; #define IEEE80211_RATE_MCS 0x80 /* - * Roaming state visible to user space. There are two - * thresholds that control whether roaming is considered; - * when either is exceeded the 802.11 layer will check - * the scan cache for another AP. If the cache is stale - * then a scan may be triggered. + * Per-mode transmit parameters/controls visible to user space. + * These can be used to set fixed transmit rate for all operating + * modes or on a per-client basis according to the capabilities + * of the client (e.g. an 11b client associated to an 11g ap). + * + * MCS are distinguished from legacy rates by or'ing in 0x80. + */ +struct ieee80211_txparam { + uint8_t ucastrate; /* ucast data rate (legacy/MCS|0x80) */ + uint8_t mgmtrate; /* mgmt frame rate (legacy/MCS|0x80) */ + uint8_t mcastrate; /* multicast rate (legacy/MCS|0x80) */ + uint8_t maxretry; /* max unicast data retry count */ +}; + +/* + * Per-mode roaming state visible to user space. There are two + * thresholds that control whether roaming is considered; when + * either is exceeded the 802.11 layer will check the scan cache + * for another AP. If the cache is stale then a scan may be + * triggered. + */ +struct ieee80211_roamparam { + int8_t rssi; /* rssi thresh (.5 dBm) */ + uint8_t rate; /* tx rate thresh (.5 Mb/s or MCS) */ + uint16_t pad; /* reserve */ +}; + +/* + * Regulatory Information. + */ +struct ieee80211_regdomain { + uint16_t regdomain; /* SKU */ + uint16_t country; /* ISO country code */ + uint8_t location; /* I (indoor), O (outdoor), other */ + uint8_t ecm; /* Extended Channel Mode */ + char isocc[2]; /* country code string */ + short pad[2]; +}; + +/* + * MIMO antenna/radio state. */ -struct ieee80211_roam { - int8_t rssi11a; /* rssi thresh for 11a bss */ - int8_t rssi11b; /* for 11g sta in 11b bss */ - int8_t rssi11bOnly; /* for 11b sta */ - uint8_t pad1; - uint8_t rate11a; /* rate thresh for 11a bss */ - uint8_t rate11b; /* for 11g sta in 11b bss */ - uint8_t rate11bOnly; /* for 11b sta */ - uint8_t pad2; +struct ieee80211_mimo_info { + int8_t rssi[3]; /* per-antenna rssi */ + int8_t noise[3]; /* per-antenna noise floor */ + uint32_t evm[3]; /* EVM data */ }; #endif /* _NET80211__IEEE80211_H_ */ ==== //depot/projects/vap/sys/net80211/ieee80211.c#16 (text+ko) ==== @@ -38,10 +38,13 @@ #include <sys/socket.h> #include <net/if.h> +#include <net/if_dl.h> #include <net/if_media.h> +#include <net/if_types.h> #include <net/ethernet.h> #include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_regdomain.h> #include <net/bpf.h> @@ -57,7 +60,21 @@ "11na", /* IEEE80211_MODE_11NA */ "11ng", /* IEEE80211_MODE_11NG */ }; +static const uint8_t ieee80211broadcastaddr[IEEE80211_ADDR_LEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +static void ieee80211_syncflag_locked(struct ieee80211com *ic, int flag); +static void ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag); +static int ieee80211_media_setup(struct ieee80211com *ic, + struct ifmedia *media, int caps, int addsta, + ifm_change_cb_t media_change, ifm_stat_cb_t media_stat); +static void ieee80211com_media_status(struct ifnet *, struct ifmediareq *); +static int ieee80211com_media_change(struct ifnet *); +static int media_status(enum ieee80211_opmode, + const struct ieee80211_channel *); +MALLOC_DEFINE(M_80211_VAP, "80211vap", "802.11 vap state"); + /* * Default supported rates for 802.11 operation (in IEEE .5Mb units). */ @@ -75,66 +92,6 @@ { 12, { B(2), B(4), B(11), B(22), 12, 18, 24, 36, 48, 72, 96, 108 } }; #undef B -static int media_status(enum ieee80211_opmode , - const struct ieee80211_channel *); - -/* list of all instances */ -SLIST_HEAD(ieee80211_list, ieee80211com); -static struct ieee80211_list ieee80211_list = - SLIST_HEAD_INITIALIZER(ieee80211_list); -static uint8_t ieee80211_vapmap[32]; /* enough for 256 */ -static struct mtx ieee80211_vap_mtx; -MTX_SYSINIT(ieee80211, &ieee80211_vap_mtx, "net80211 instances", MTX_DEF); - -static void -ieee80211_add_vap(struct ieee80211com *ic) -{ -#define N(a) (sizeof(a)/sizeof(a[0])) - int i; - uint8_t b; - - mtx_lock(&ieee80211_vap_mtx); - ic->ic_vap = 0; - for (i = 0; i < N(ieee80211_vapmap) && ieee80211_vapmap[i] == 0xff; i++) - ic->ic_vap += NBBY; - if (i == N(ieee80211_vapmap)) - panic("vap table full"); - for (b = ieee80211_vapmap[i]; b & 1; b >>= 1) - ic->ic_vap++; - setbit(ieee80211_vapmap, ic->ic_vap); - SLIST_INSERT_HEAD(&ieee80211_list, ic, ic_next); - mtx_unlock(&ieee80211_vap_mtx); -#undef N -} - -static void -ieee80211_remove_vap(struct ieee80211com *ic) -{ - mtx_lock(&ieee80211_vap_mtx); - SLIST_REMOVE(&ieee80211_list, ic, ieee80211com, ic_next); - KASSERT(ic->ic_vap < sizeof(ieee80211_vapmap)*NBBY, - ("invalid vap id %d", ic->ic_vap)); - KASSERT(isset(ieee80211_vapmap, ic->ic_vap), - ("vap id %d not allocated", ic->ic_vap)); - clrbit(ieee80211_vapmap, ic->ic_vap); - mtx_unlock(&ieee80211_vap_mtx); -} - -/* - * Default reset method for use with the ioctl support. This - * method is invoked after any state change in the 802.11 - * layer that should be propagated to the hardware but not - * require re-initialization of the 802.11 state machine (e.g - * rescanning for an ap). We always return ENETRESET which - * should cause the driver to re-initialize the device. Drivers - * can override this method to implement more optimized support. - */ -static int -ieee80211_default_reset(struct ifnet *ifp) -{ - return ENETRESET; -} - /* * Fill in 802.11 available channel set, mark * all available channels as active, and pick @@ -153,6 +110,7 @@ KASSERT(0 < ic->ic_nchans && ic->ic_nchans < IEEE80211_CHAN_MAX, ("invalid number of channels specified: %u", ic->ic_nchans)); memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); + memset(ic->ic_modecaps, 0, sizeof(ic->ic_modecaps)); setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO); for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; @@ -186,9 +144,13 @@ memcpy(ic->ic_chan_active, ic->ic_chan_avail, sizeof(ic->ic_chan_avail)); - ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ + /* sort channel table to allow lookup optimizations */ + ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans); + + /* invalidate any previous state */ ic->ic_bsschan = IEEE80211_CHAN_ANYC; ic->ic_prevchan = NULL; + ic->ic_csa_newchan = NULL; /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[0]; @@ -206,54 +168,45 @@ #undef DEFAULTRATES } +static void +null_update_mcast(struct ifnet *ifp) +{ + if_printf(ifp, "need multicast update callback\n"); +} + +static void +null_update_promisc(struct ifnet *ifp) +{ + if_printf(ifp, "need promiscuous mode update callback\n"); +} + +/* + * Attach/setup the common net80211 state. Called by + * the driver on attach to prior to creating any vap's. + */ void ieee80211_ifattach(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; + struct sockaddr_dl *sdl; + struct ifaddr *ifa; ether_ifattach(ifp, ic->ic_myaddr); - ifp->if_output = ieee80211_output; - bpfattach2(ifp, DLT_IEEE802_11, - sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf); - - /* override the 802.3 setting */ - ifp->if_hdrlen = ic->ic_headroom - + sizeof(struct ieee80211_qosframe_addr4) - + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN - + IEEE80211_WEP_EXTIVLEN; - /* XXX no way to recalculate on ifdetach */ - if (ALIGN(ifp->if_hdrlen) > max_linkhdr) { - /* XXX sanity check... */ - max_linkhdr = ALIGN(ifp->if_hdrlen); - max_hdr = max_linkhdr + max_protohdr; - max_datalen = MHLEN - max_hdr; - } - + IEEE80211_LOCK_INIT(ic, "ieee80211com"); + TAILQ_INIT(&ic->ic_vaps); /* * Fill in 802.11 available channel set, mark all * available channels as active, and pick a default * channel if not already specified. */ - ieee80211_chan_init(ic); + ieee80211_media_init(ic, + ieee80211com_media_change, ieee80211com_media_status); - if (ic->ic_caps & IEEE80211_C_BGSCAN) /* enable if capable */ - ic->ic_flags |= IEEE80211_F_BGSCAN; -#if 0 - /* XXX not until WME+WPA issues resolved */ - if (ic->ic_caps & IEEE80211_C_WME) /* enable if capable */ - ic->ic_flags |= IEEE80211_F_WME; -#endif - if (ic->ic_caps & IEEE80211_C_BURST) - ic->ic_flags |= IEEE80211_F_BURST; - ic->ic_flags |= IEEE80211_F_DOTH; /* XXX out of caps, just ena */ + ic->ic_update_mcast = null_update_mcast; + ic->ic_update_promisc = null_update_promisc; ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; - ic->ic_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; - ic->ic_dtim_period = IEEE80211_DTIM_DEFAULT; - IEEE80211_LOCK_INIT(ic, "ieee80211com"); - IEEE80211_BEACON_LOCK_INIT(ic, "beacon"); - ic->ic_lintval = ic->ic_bintval; ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; @@ -263,30 +216,43 @@ ieee80211_proto_attach(ic); ieee80211_ht_attach(ic); ieee80211_scan_attach(ic); + ieee80211_regdomain_attach(ic); - ieee80211_add_vap(ic); + ieee80211_sysctl_attach(ic); - ieee80211_sysctl_attach(ic); /* NB: requires ic_vap */ - - /* - * Install a default reset method for the ioctl support. - * The driver is expected to fill this in before calling us. - */ - if (ic->ic_reset == NULL) - ic->ic_reset = ieee80211_default_reset; - - KASSERT(ifp->if_spare2 == NULL, ("oops, hosed")); - ifp->if_spare2 = ic; /* XXX temp backpointer */ + ifp->if_type = IFT_IEEE80211; /* NB: not IFT_ETHER */ + ifp->if_addrlen = IEEE80211_ADDR_LEN; + ifp->if_hdrlen = 0; + if_attach(ifp); + /* NB: must do after 'cuz if_attach resets state */ + ifp->if_mtu = IEEE80211_MTU_MAX; + ifa = ifaddr_byindex(ifp->if_index); + KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + sdl->sdl_type = IFT_ETHER; /* XXX IFT_IEEE80211? */ + sdl->sdl_alen = IEEE80211_ADDR_LEN; + IEEE80211_ADDR_COPY(LLADDR(sdl), ic->ic_myaddr); + ifp->if_broadcastaddr = ieee80211broadcastaddr; } +/* + * Detach net80211 state on device detach. Tear down + * all vap's and reclaim all common state prior to the + * device state going away. Note we may call back into + * driver; it must be prepared for this. + */ void ieee80211_ifdetach(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; + struct ieee80211vap *vap; - ieee80211_remove_vap(ic); + /* XXX ieee80211_stop_all? */ + while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL) + ic->ic_vap_delete(vap); ieee80211_sysctl_detach(ic); + ieee80211_regdomain_detach(ic); ieee80211_scan_detach(ic); ieee80211_ht_detach(ic); /* NB: must be called before ieee80211_node_detach */ @@ -296,13 +262,356 @@ ieee80211_node_detach(ic); ifmedia_removeall(&ic->ic_media); + bpfdetach(ifp); + ether_ifdetach(ifp); + IEEE80211_LOCK_DESTROY(ic); - IEEE80211_BEACON_LOCK_DESTROY(ic); + if_detach(ifp); +} + +/* + * Default reset method for use with the ioctl support. This + * method is invoked after any state change in the 802.11 + * layer that should be propagated to the hardware but not + * require re-initialization of the 802.11 state machine (e.g + * rescanning for an ap). We always return ENETRESET which + * should cause the driver to re-initialize the device. Drivers + * can override this method to implement more optimized support. + */ +static int +default_reset(struct ieee80211vap *vap) +{ + return ENETRESET; +} + +/* + * Prepare a vap for use. Drivers use this call to + * setup net80211 state in new vap's prior attaching + * them with ieee80211_vap_attach (below). + */ +int +ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, + const char name[IFNAMSIZ], int unit, int opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN]) +{ +#define IEEE80211_C_OPMODE \ + (IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | IEEE80211_C_AHDEMO | \ + IEEE80211_C_MONITOR | IEEE80211_C_WDS) + struct ifnet *ifp; + + ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) { + /* XXX msg,stat? */ + return 0; + } + if_initname(ifp, name, unit); + ifp->if_softc = vap; /* back pointer */ + ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; + ifp->if_start = ieee80211_start; + ifp->if_ioctl = ieee80211_ioctl; + ifp->if_watchdog = NULL; /* NB: no watchdog routine */ + ifp->if_init = ieee80211_init; + /* NB: input+output filled in by ether_ifattach */ + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; + IFQ_SET_READY(&ifp->if_snd); + + vap->iv_ifp = ifp; + vap->iv_ic = ic; + vap->iv_flags = ic->ic_flags; /* propagate common flags */ + vap->iv_flags_ext = ic->ic_flags_ext; + vap->iv_flags_ven = ic->ic_flags_ven; + vap->iv_caps = ic->ic_caps &~ IEEE80211_C_OPMODE; + vap->iv_htcaps = ic->ic_htcaps; + vap->iv_opmode = opmode; + switch (opmode) { + case IEEE80211_M_STA: + /* auto-enable s/w beacon miss support */ + if (flags & IEEE80211_CLONE_NOBEACONS) + vap->iv_flags_ext |= IEEE80211_FEXT_SWBMISS; + break; + case IEEE80211_M_IBSS: + vap->iv_caps |= IEEE80211_C_IBSS; + break; + case IEEE80211_M_AHDEMO: + vap->iv_caps |= IEEE80211_C_AHDEMO; + break; + case IEEE80211_M_HOSTAP: + vap->iv_caps |= IEEE80211_C_HOSTAP; + break; + case IEEE80211_M_MONITOR: + vap->iv_caps |= IEEE80211_C_MONITOR; + break; + case IEEE80211_M_WDS: + vap->iv_caps |= IEEE80211_C_WDS; + /* + * WDS links must specify the bssid of the far end. + * For legacy operation this is a static relationship. + * For non-legacy operation the station must associate + * and be authorized to pass traffic. Plumbing the + * vap to the proper node happens when the vap + * transitions to RUN state. + */ + IEEE80211_ADDR_COPY(vap->iv_des_bssid, bssid); + vap->iv_flags |= IEEE80211_F_DESBSSID; + if (flags & IEEE80211_CLONE_WDSLEGACY) + vap->iv_flags_ext |= IEEE80211_FEXT_WDSLEGACY; + break; + } + /* + * Enable various functionality by default if we're + * capable; the driver can override us if it knows better. + */ + if (vap->iv_caps & IEEE80211_C_WME) + vap->iv_flags |= IEEE80211_F_WME; + if (vap->iv_caps & IEEE80211_C_BURST) + vap->iv_flags |= IEEE80211_F_BURST; + if (vap->iv_caps & IEEE80211_C_FF) + vap->iv_flags |= IEEE80211_F_FF; + if (vap->iv_caps & IEEE80211_C_TURBOP) + vap->iv_flags |= IEEE80211_F_TURBOP; + /* NB: bg scanning only makes sense for station mode right now */ + if (vap->iv_opmode == IEEE80211_M_STA && + (vap->iv_caps & IEEE80211_C_BGSCAN)) + vap->iv_flags |= IEEE80211_F_BGSCAN; + vap->iv_flags |= IEEE80211_F_DOTH; /* XXX out of caps, just ena */ + /* XXX out of caps, just ena */ + if (vap->iv_opmode == IEEE80211_M_HOSTAP) + vap->iv_flags_ext |= IEEE80211_FEXT_DFS; + + vap->iv_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ + vap->iv_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; + vap->iv_dtim_period = IEEE80211_DTIM_DEFAULT; + /* + * Install a default reset method for the ioctl support; + * the driver can override this. + */ + vap->iv_reset = default_reset; + + IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_myaddr); + + ieee80211_sysctl_vattach(vap); + ieee80211_crypto_vattach(vap); + ieee80211_node_vattach(vap); + ieee80211_power_vattach(vap); + ieee80211_proto_vattach(vap); + ieee80211_ht_vattach(vap); + ieee80211_scan_vattach(vap); + ieee80211_regdomain_vattach(vap); + + return 1; +#undef IEEE80211_C_OPMODE +} + +/* + * Activate a vap. State should have been prepared with a + * call to ieee80211_vap_setup and by the driver. On return + * from this call the vap is ready for use. + */ +int +ieee80211_vap_attach(struct ieee80211vap *vap, + ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) +{ + struct ifnet *ifp = vap->iv_ifp; + struct ieee80211com *ic = vap->iv_ic; + struct ifmediareq imr; + int maxrate; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, + "%s: %s parent %s flags 0x%x flags_ext 0x%x\n", + __func__, ieee80211_opmode_name[vap->iv_opmode], + ic->ic_ifp->if_xname, vap->iv_flags, vap->iv_flags_ext); + + /* + * Do late attach work that cannot happen until after + * the driver has had a chance to override defaults. + */ + ieee80211_node_latevattach(vap); + ieee80211_power_latevattach(vap); + + maxrate = ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps, + vap->iv_opmode == IEEE80211_M_STA, media_change, media_stat); + ieee80211_media_status(ifp, &imr); + /* NB: strip explicit mode; we're actually in autoselect */ + ifmedia_set(&vap->iv_media, imr.ifm_active &~ IFM_MMASK); + if (maxrate) + ifp->if_baudrate = IF_Mbps(maxrate); + + ether_ifattach(ifp, vap->iv_myaddr); + /* hook output method setup by ether_ifattach */ + vap->iv_output = ifp->if_output; + ifp->if_output = ieee80211_output; + /* NB: if_mtu set by ether_ifattach to ETHERMTU */ + bpfattach2(ifp, DLT_IEEE802_11, ifp->if_hdrlen, &vap->iv_rawbpf); + + IEEE80211_LOCK(ic); + TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next); + ieee80211_syncflag_locked(ic, IEEE80211_F_WME); + ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP); + ieee80211_syncflag_locked(ic, IEEE80211_F_PCF); + ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); + ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_HT); + ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_USEHT40); + ieee80211_syncifflag_locked(ic, IFF_PROMISC); + ieee80211_syncifflag_locked(ic, IFF_ALLMULTI); + IEEE80211_UNLOCK(ic); + + return 1; +} + +/* + * Tear down vap state prior to reclaiming the ifnet. + */ +void +ieee80211_vap_detach(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ifnet *ifp = vap->iv_ifp; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s parent %s\n", + __func__, ieee80211_opmode_name[vap->iv_opmode], + ic->ic_ifp->if_xname); + /* + * Mark interface down so we ignore calls by the bridge + * to turn off promiscuous mode as a result of calling + * ether_ifdetach. + */ + ifp->if_flags &= ~IFF_UP; + ieee80211_stop(vap); bpfdetach(ifp); ether_ifdetach(ifp); + + IEEE80211_LOCK(ic); + TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next); + ieee80211_syncflag_locked(ic, IEEE80211_F_WME); + ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP); + ieee80211_syncflag_locked(ic, IEEE80211_F_PCF); + ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); + ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_HT); + ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_USEHT40); + ieee80211_syncifflag_locked(ic, IFF_PROMISC); + ieee80211_syncifflag_locked(ic, IFF_ALLMULTI); + IEEE80211_UNLOCK(ic); + + ifmedia_removeall(&vap->iv_media); + + ieee80211_regdomain_vdetach(vap); + ieee80211_scan_vdetach(vap); + ieee80211_ht_vdetach(vap); + /* NB: must be before ieee80211_node_vdetach */ + ieee80211_proto_vdetach(vap); + ieee80211_crypto_vdetach(vap); + ieee80211_power_vdetach(vap); + ieee80211_node_vdetach(vap); + ieee80211_sysctl_vdetach(vap); } +/* + * Synchronize flag bit state in the parent ifnet structure + * according to the state of all vap ifnet's. This is used, + * for example, to handle IFF_PROMISC and IFF_ALLMULTI. + */ +void +ieee80211_syncifflag_locked(struct ieee80211com *ic, int flag) +{ + struct ieee80211vap *vap; + int bit; + + IEEE80211_LOCK_ASSERT(ic); + + bit = 0; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if (vap->iv_ifp->if_flags & flag) { + bit = 1; + break; + } + if (bit) + ic->ic_ifp->if_flags |= flag; + else + ic->ic_ifp->if_flags &= ~flag; +} + +/* + * Synchronize flag bit state in the com structure + * according to the state of all vap's. This is used, + * for example, to handle state changes via ioctls. + */ +static void +ieee80211_syncflag_locked(struct ieee80211com *ic, int flag) +{ + struct ieee80211vap *vap; + int bit; + + IEEE80211_LOCK_ASSERT(ic); + + bit = 0; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if (vap->iv_flags & flag) { + bit = 1; + break; + } + if (bit) + ic->ic_flags |= flag; + else + ic->ic_flags &= ~flag; +} + +void +ieee80211_syncflag(struct ieee80211vap *vap, int flag) +{ + struct ieee80211com *ic = vap->iv_ic; + + IEEE80211_LOCK(ic); + if (flag < 0) { + flag = -flag; + vap->iv_flags &= ~flag; + } else + vap->iv_flags |= flag; + ieee80211_syncflag_locked(ic, flag); + IEEE80211_UNLOCK(ic); +} + +/* + * Synchronize flag bit state in the com structure + * according to the state of all vap's. This is used, + * for example, to handle state changes via ioctls. + */ +static void +ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag) +{ + struct ieee80211vap *vap; + int bit; + + IEEE80211_LOCK_ASSERT(ic); + + bit = 0; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if (vap->iv_flags_ext & flag) { + bit = 1; + break; + } + if (bit) + ic->ic_flags_ext |= flag; + else + ic->ic_flags_ext &= ~flag; +} + +void +ieee80211_syncflag_ext(struct ieee80211vap *vap, int flag) +{ + struct ieee80211com *ic = vap->iv_ic; + + IEEE80211_LOCK(ic); + if (flag < 0) { + flag = -flag; + vap->iv_flags_ext &= ~flag; + } else + vap->iv_flags_ext |= flag; + ieee80211_syncflag_ext_locked(ic, flag); + IEEE80211_UNLOCK(ic); +} + static __inline int mapgsm(u_int freq, u_int flags) { @@ -416,7 +725,7 @@ /* * Locate a channel given a frequency+flags. We cache - * the previous lookup to optimize swithing between two + * the previous lookup to optimize switching between two * channels--as happens with dynamic turbo. */ struct ieee80211_channel * @@ -467,80 +776,58 @@ } static void -addmedia(struct ieee80211com *ic, int mode, int mword) +addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword) { -#define TURBO(m) ((m) | IFM_IEEE80211_TURBO) #define ADD(_ic, _s, _o) \ - ifmedia_add(&(_ic)->ic_media, \ + ifmedia_add(media, \ IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL) static const u_int mopts[IEEE80211_MODE_MAX] = { - IFM_AUTO, /* IEEE80211_MODE_AUTO */ - IFM_IEEE80211_11A, /* IEEE80211_MODE_11A */ - IFM_IEEE80211_11B, /* IEEE80211_MODE_11B */ - IFM_IEEE80211_11G, /* IEEE80211_MODE_11G */ - IFM_IEEE80211_FH, /* IEEE80211_MODE_FH */ - TURBO(IFM_IEEE80211_11A), /* IEEE80211_MODE_TURBO_A */ - TURBO(IFM_IEEE80211_11G), /* IEEE80211_MODE_TURBO_G */ - TURBO(IFM_IEEE80211_11A), /* IEEE80211_MODE_STURBO_A */ - IFM_IEEE80211_11NA, /* IEEE80211_MODE_11NA */ - IFM_IEEE80211_11NG, /* IEEE80211_MODE_11NG */ + IFM_AUTO, >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200712031839.lB3IdRAC084058>