Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 8 Sep 2015 18:22:33 +0300
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        Adrian Chadd <adrian@freebsd.org>, Andriy Voskoboinyk <s3erios@gmail.com>
Cc:        "net@freebsd.org" <net@freebsd.org>
Subject:   more net80211 changes :/
Message-ID:  <20150908152233.GV1023@glebius.int.ru>

next in thread | raw e-mail | index | archive | help

--mxv5cy4qt+RJ9ypb
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

  Hi!

  It looks like another sweep over net80211 drivers is required. It isn't
going to be as huge as previous one.

The problem is that in the "new world order", there will be only if_attach(),
instead of if_alloc() / fill & hack / ether_ifattach. What right now happens
with net80211 is that all drivers have the same copy & paste in their
ic_vap_create, which yields in a sequence of:

- if_alloc
- driver specific code
- ether_ifattach

Which isn't possible to collapse into if_attach(), since driver code is
in the middle.

Another problem is embedding if ieee80211_vap into driver's softc. This
is a bad habit, which was proved by ifnet experience (fixed decade ago).

What patch does:

- Inline ieee80211_vap_setup() and ieee80211_vap_attach() into wlan_clone_create().
  Note, that this moves code from ieee80211.c to into ieee80211_freebsd.c,
  which is good, since this code about interaction with ifnet layer, which
  is FreeBSD specific and will be more FreeBSD specific.
  As dependency ifmedia support code and ieee80211_get_counter() also naturally
  move to the same file.

- In the new long wlan_clone_create(), after initial error checking call
  ic_vap_preattach() to allow driver do its own error checking. I predict
  that for now ath(4) will be the only driver to use ic_vap_preattach().

- If no errors, go with allocating and attaching the interface, and then
  call ic_vap_postattach.

- The ic_vap_postattach() for all drivers (save ath) would be remnants
  of ic_vap_create(), where all copy and paste is removed and only driver
  specific bits remain.

- ic_vap_postattach() may allocate driver specific softc for vap, which
  now longer has ieee80211_vap embedded.

This also removes all ambiguities with mac address handling, which was
juggled between three functions before.

The current patch covers iwn(4) only. Now sending this mail with patched
driver. Changing MAC aldo tested - works.

I'm starting to convert rest of drivers and meanwhile, waiting for your
input. May be you have ideas what else can be improved here.

-- 
Totus tuus, Glebius.

--mxv5cy4qt+RJ9ypb
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="new_vap_attach.diff"

Index: sys/dev/iwn/if_iwn.c
===================================================================
--- sys/dev/iwn/if_iwn.c	(revision 287554)
+++ sys/dev/iwn/if_iwn.c	(working copy)
@@ -136,10 +136,7 @@ static int	iwn5000_attach(struct iwn_softc *, uint
 static int	iwn_config_specific(struct iwn_softc *, uint16_t);
 static void	iwn_radiotap_attach(struct iwn_softc *);
 static void	iwn_sysctlattach(struct iwn_softc *);
-static struct ieee80211vap *iwn_vap_create(struct ieee80211com *,
-		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
-		    const uint8_t [IEEE80211_ADDR_LEN],
-		    const uint8_t [IEEE80211_ADDR_LEN]);
+static void	iwn_vap_postattach(struct ieee80211com *, struct ieee80211vap *);
 static void	iwn_vap_delete(struct ieee80211vap *);
 static int	iwn_detach(device_t);
 static int	iwn_shutdown(device_t);
@@ -640,7 +637,7 @@ iwn_attach(device_t dev)
 	}
 
 	ieee80211_ifattach(ic);
-	ic->ic_vap_create = iwn_vap_create;
+	ic->ic_vap_postattach = iwn_vap_postattach;
 	ic->ic_ioctl = iwn_ioctl;
 	ic->ic_parent = iwn_parent;
 	ic->ic_vap_delete = iwn_vap_delete;
@@ -666,6 +663,7 @@ iwn_attach(device_t dev)
 	ic->ic_scan_curchan = iwn_scan_curchan;
 	ic->ic_scan_mindwell = iwn_scan_mindwell;
 	ic->ic_setregdomain = iwn_setregdomain;
+	ic->ic_media_change = iwn_media_change;
 
 	iwn_radiotap_attach(sc);
 
@@ -1317,22 +1315,13 @@ iwn_sysctlattach(struct iwn_softc *sc)
 #endif
 }
 
-static struct ieee80211vap *
-iwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
-    enum ieee80211_opmode opmode, int flags,
-    const uint8_t bssid[IEEE80211_ADDR_LEN],
-    const uint8_t mac[IEEE80211_ADDR_LEN])
+static void
+iwn_vap_postattach(struct ieee80211com *ic, struct ieee80211vap *vap)
 {
 	struct iwn_softc *sc = ic->ic_softc;
 	struct iwn_vap *ivp;
-	struct ieee80211vap *vap;
 
-	if (!TAILQ_EMPTY(&ic->ic_vaps))		/* only one at a time */
-		return NULL;
-
-	ivp = malloc(sizeof(struct iwn_vap), M_80211_VAP, M_WAITOK | M_ZERO);
-	vap = &ivp->iv_vap;
-	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);
+	ivp = malloc(sizeof(struct iwn_vap), M_80211_VAP, M_WAITOK);
 	ivp->ctx = IWN_RXON_BSS_CTX;
 	vap->iv_bmissthreshold = 10;		/* override default */
 	/* Override with driver methods. */
@@ -1339,19 +1328,14 @@ iwn_sysctlattach(struct iwn_softc *sc)
 	ivp->iv_newstate = vap->iv_newstate;
 	vap->iv_newstate = iwn_newstate;
 	sc->ivap[IWN_RXON_BSS_CTX] = vap;
-
+	vap->iv_softc = ivp;
 	ieee80211_ratectl_init(vap);
-	/* Complete setup. */
-	ieee80211_vap_attach(vap, iwn_media_change, ieee80211_media_status,
-	    mac);
-	ic->ic_opmode = opmode;
-	return vap;
 }
 
 static void
 iwn_vap_delete(struct ieee80211vap *vap)
 {
-	struct iwn_vap *ivp = IWN_VAP(vap);
+	struct iwn_vap *ivp = vap->iv_softc;
 
 	ieee80211_ratectl_deinit(vap);
 	ieee80211_vap_detach(vap);
@@ -2814,7 +2798,7 @@ iwn_media_change(struct ifnet *ifp)
 static int
 iwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
 {
-	struct iwn_vap *ivp = IWN_VAP(vap);
+	struct iwn_vap *ivp = vap->iv_softc;
 	struct ieee80211com *ic = vap->iv_ic;
 	struct iwn_softc *sc = ic->ic_softc;
 	int error = 0;
Index: sys/dev/iwn/if_iwnvar.h
===================================================================
--- sys/dev/iwn/if_iwnvar.h	(revision 287554)
+++ sys/dev/iwn/if_iwnvar.h	(working copy)
@@ -221,16 +221,11 @@ struct iwn_ops {
 };
 
 struct iwn_vap {
-	struct ieee80211vap	iv_vap;
-	uint8_t			iv_ridx;
-
 	int			(*iv_newstate)(struct ieee80211vap *,
 				    enum ieee80211_state, int);
 	int			ctx;
-	int			beacon_int;
 
 };
-#define	IWN_VAP(_vap)	((struct iwn_vap *)(_vap))
 
 struct iwn_softc {
 	device_t		sc_dev;
Index: sys/net80211/ieee80211.c
===================================================================
--- sys/net80211/ieee80211.c	(revision 287554)
+++ sys/net80211/ieee80211.c	(working copy)
@@ -86,15 +86,8 @@ const int ieee80211_opcap[IEEE80211_OPMODE_MAX] =
 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_ht_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	int media_status(enum ieee80211_opmode,
 		const struct ieee80211_channel *);
-static uint64_t ieee80211_get_counter(struct ifnet *, ift_counter);
 
 MALLOC_DEFINE(M_80211_VAP, "80211vap", "802.11 vap state");
 
@@ -400,224 +393,6 @@ ieee80211_find_com(const char *name)
 	return (ic);
 }
 
-/*
- * 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, u_long cmd)
-{
-	return ENETRESET;
-}
-
-/*
- * Add underlying device errors to vap errors.
- */
-static uint64_t
-ieee80211_get_counter(struct ifnet *ifp, ift_counter cnt)
-{
-	struct ieee80211vap *vap = ifp->if_softc;
-	struct ieee80211com *ic = vap->iv_ic;
-	uint64_t rv;
-
-	rv = if_get_counter_default(ifp, cnt);
-	switch (cnt) {
-	case IFCOUNTER_OERRORS:
-		rv += counter_u64_fetch(ic->ic_oerrors);
-		break;
-	case IFCOUNTER_IERRORS:
-		rv += counter_u64_fetch(ic->ic_ierrors);
-		break;
-	default:
-		break;
-	}
-
-	return (rv);
-}
-
-/*
- * 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, enum ieee80211_opmode opmode,
-    int flags, const uint8_t bssid[IEEE80211_ADDR_LEN])
-{
-	struct ifnet *ifp;
-
-	ifp = if_alloc(IFT_ETHER);
-	if (ifp == NULL) {
-		ic_printf(ic, "%s: unable to allocate ifnet\n",
-		    __func__);
-		return ENOMEM;
-	}
-	if_initname(ifp, name, unit);
-	ifp->if_softc = vap;			/* back pointer */
-	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
-	ifp->if_transmit = ieee80211_vap_transmit;
-	ifp->if_qflush = ieee80211_vap_qflush;
-	ifp->if_ioctl = ieee80211_ioctl;
-	ifp->if_init = ieee80211_init;
-	ifp->if_get_counter = ieee80211_get_counter;
-
-	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_htextcaps = ic->ic_htextcaps;
-	vap->iv_opmode = opmode;
-	vap->iv_caps |= ieee80211_opcap[opmode];
-	vap->iv_myaddr = ic->ic_macaddr;
-	switch (opmode) {
-	case IEEE80211_M_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;
-#ifdef IEEE80211_SUPPORT_TDMA
-	case IEEE80211_M_AHDEMO:
-		if (flags & IEEE80211_CLONE_TDMA) {
-			/* NB: checked before clone operation allowed */
-			KASSERT(ic->ic_caps & IEEE80211_C_TDMA,
-			    ("not TDMA capable, ic_caps 0x%x", ic->ic_caps));
-			/*
-			 * Propagate TDMA capability to mark vap; this
-			 * cannot be removed and is used to distinguish
-			 * regular ahdemo operation from ahdemo+tdma.
-			 */
-			vap->iv_caps |= IEEE80211_C_TDMA;
-		}
-		break;
-#endif
-	default:
-		break;
-	}
-	/* auto-enable s/w beacon miss support */
-	if (flags & IEEE80211_CLONE_NOBEACONS)
-		vap->iv_flags_ext |= IEEE80211_FEXT_SWBMISS;
-	/* auto-generated or user supplied MAC address */
-	if (flags & (IEEE80211_CLONE_BSSID|IEEE80211_CLONE_MACADDR))
-		vap->iv_flags_ext |= IEEE80211_FEXT_UNIQMAC;
-	/*
-	 * 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;
-	/* 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 no cap, just ena */
-	/* NB: DFS support only makes sense for ap mode right now */
-	if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
-	    (vap->iv_caps & IEEE80211_C_DFS))
-		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_sysctl_vattach(vap);
-	ieee80211_crypto_vattach(vap);
-	ieee80211_node_vattach(vap);
-	ieee80211_power_vattach(vap);
-	ieee80211_proto_vattach(vap);
-#ifdef IEEE80211_SUPPORT_SUPERG
-	ieee80211_superg_vattach(vap);
-#endif
-	ieee80211_ht_vattach(vap);
-	ieee80211_scan_vattach(vap);
-	ieee80211_regdomain_vattach(vap);
-	ieee80211_radiotap_vattach(vap);
-	ieee80211_ratectl_set(vap, IEEE80211_RATECTL_NONE);
-
-	return 0;
-}
-
-/*
- * 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, const uint8_t macaddr[IEEE80211_ADDR_LEN])
-{
-	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_name, 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 | IFM_IEEE80211_TURBO));
-	if (maxrate)
-		ifp->if_baudrate = IF_Mbps(maxrate);
-
-	ether_ifattach(ifp, macaddr);
-	vap->iv_myaddr = IF_LLADDR(ifp);
-	/* 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 */
-
-	IEEE80211_LOCK(ic);
-	TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next);
-	ieee80211_syncflag_locked(ic, IEEE80211_F_WME);
-#ifdef IEEE80211_SUPPORT_SUPERG
-	ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP);
-#endif
-	ieee80211_syncflag_locked(ic, IEEE80211_F_PCF);
-	ieee80211_syncflag_locked(ic, IEEE80211_F_BURST);
-	ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT);
-	ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40);
-	IEEE80211_UNLOCK(ic);
-
-	return 1;
-}
-
 /* 
  * Tear down vap state and reclaim the ifnet.
  * The driver is assumed to have prepared for
@@ -748,7 +523,7 @@ ieee80211_allmulti(struct ieee80211vap *vap, bool
  * according to the state of all vap's.  This is used,
  * for example, to handle state changes via ioctls.
  */
-static void
+void
 ieee80211_syncflag_locked(struct ieee80211com *ic, int flag)
 {
 	struct ieee80211vap *vap;
@@ -788,7 +563,7 @@ ieee80211_syncflag(struct ieee80211vap *vap, int f
  * according to the state of all vap's.  This is used,
  * for example, to handle state changes via ioctls.
  */
-static void
+void
 ieee80211_syncflag_ht_locked(struct ieee80211com *ic, int flag)
 {
 	struct ieee80211vap *vap;
@@ -828,7 +603,7 @@ ieee80211_syncflag_ht(struct ieee80211vap *vap, in
  * according to the state of all vap's.  This is used,
  * for example, to handle state changes via ioctls.
  */
-static void
+void
 ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag)
 {
 	struct ieee80211vap *vap;
@@ -1095,140 +870,6 @@ ieee80211_lookup_channel_rxstatus(struct ieee80211
 	return (c);
 }
 
-static void
-addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword)
-{
-#define	ADD(_ic, _s, _o) \
-	ifmedia_add(media, \
-		IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
-	static const u_int mopts[IEEE80211_MODE_MAX] = { 
-	    [IEEE80211_MODE_AUTO]	= IFM_AUTO,
-	    [IEEE80211_MODE_11A]	= IFM_IEEE80211_11A,
-	    [IEEE80211_MODE_11B]	= IFM_IEEE80211_11B,
-	    [IEEE80211_MODE_11G]	= IFM_IEEE80211_11G,
-	    [IEEE80211_MODE_FH]		= IFM_IEEE80211_FH,
-	    [IEEE80211_MODE_TURBO_A]	= IFM_IEEE80211_11A|IFM_IEEE80211_TURBO,
-	    [IEEE80211_MODE_TURBO_G]	= IFM_IEEE80211_11G|IFM_IEEE80211_TURBO,
-	    [IEEE80211_MODE_STURBO_A]	= IFM_IEEE80211_11A|IFM_IEEE80211_TURBO,
-	    [IEEE80211_MODE_HALF]	= IFM_IEEE80211_11A,	/* XXX */
-	    [IEEE80211_MODE_QUARTER]	= IFM_IEEE80211_11A,	/* XXX */
-	    [IEEE80211_MODE_11NA]	= IFM_IEEE80211_11NA,
-	    [IEEE80211_MODE_11NG]	= IFM_IEEE80211_11NG,
-	};
-	u_int mopt;
-
-	mopt = mopts[mode];
-	if (addsta)
-		ADD(ic, mword, mopt);	/* STA mode has no cap */
-	if (caps & IEEE80211_C_IBSS)
-		ADD(media, mword, mopt | IFM_IEEE80211_ADHOC);
-	if (caps & IEEE80211_C_HOSTAP)
-		ADD(media, mword, mopt | IFM_IEEE80211_HOSTAP);
-	if (caps & IEEE80211_C_AHDEMO)
-		ADD(media, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
-	if (caps & IEEE80211_C_MONITOR)
-		ADD(media, mword, mopt | IFM_IEEE80211_MONITOR);
-	if (caps & IEEE80211_C_WDS)
-		ADD(media, mword, mopt | IFM_IEEE80211_WDS);
-	if (caps & IEEE80211_C_MBSS)
-		ADD(media, mword, mopt | IFM_IEEE80211_MBSS);
-#undef ADD
-}
-
-/*
- * Setup the media data structures according to the channel and
- * rate tables.
- */
-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)
-{
-	int i, j, rate, maxrate, mword, r;
-	enum ieee80211_phymode mode;
-	const struct ieee80211_rateset *rs;
-	struct ieee80211_rateset allrates;
-
-	/*
-	 * Fill in media characteristics.
-	 */
-	ifmedia_init(media, 0, media_change, media_stat);
-	maxrate = 0;
-	/*
-	 * Add media for legacy operating modes.
-	 */
-	memset(&allrates, 0, sizeof(allrates));
-	for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) {
-		if (isclr(ic->ic_modecaps, mode))
-			continue;
-		addmedia(media, caps, addsta, mode, IFM_AUTO);
-		if (mode == IEEE80211_MODE_AUTO)
-			continue;
-		rs = &ic->ic_sup_rates[mode];
-		for (i = 0; i < rs->rs_nrates; i++) {
-			rate = rs->rs_rates[i];
-			mword = ieee80211_rate2media(ic, rate, mode);
-			if (mword == 0)
-				continue;
-			addmedia(media, caps, addsta, mode, mword);
-			/*
-			 * Add legacy rate to the collection of all rates.
-			 */
-			r = rate & IEEE80211_RATE_VAL;
-			for (j = 0; j < allrates.rs_nrates; j++)
-				if (allrates.rs_rates[j] == r)
-					break;
-			if (j == allrates.rs_nrates) {
-				/* unique, add to the set */
-				allrates.rs_rates[j] = r;
-				allrates.rs_nrates++;
-			}
-			rate = (rate & IEEE80211_RATE_VAL) / 2;
-			if (rate > maxrate)
-				maxrate = rate;
-		}
-	}
-	for (i = 0; i < allrates.rs_nrates; i++) {
-		mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
-				IEEE80211_MODE_AUTO);
-		if (mword == 0)
-			continue;
-		/* NB: remove media options from mword */
-		addmedia(media, caps, addsta,
-		    IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword));
-	}
-	/*
-	 * Add HT/11n media.  Note that we do not have enough
-	 * bits in the media subtype to express the MCS so we
-	 * use a "placeholder" media subtype and any fixed MCS
-	 * must be specified with a different mechanism.
-	 */
-	for (; mode <= IEEE80211_MODE_11NG; mode++) {
-		if (isclr(ic->ic_modecaps, mode))
-			continue;
-		addmedia(media, caps, addsta, mode, IFM_AUTO);
-		addmedia(media, caps, addsta, mode, IFM_IEEE80211_MCS);
-	}
-	if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) ||
-	    isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) {
-		addmedia(media, caps, addsta,
-		    IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS);
-		i = ic->ic_txstream * 8 - 1;
-		if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
-		    (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40))
-			rate = ieee80211_htrates[i].ht40_rate_400ns;
-		else if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40))
-			rate = ieee80211_htrates[i].ht40_rate_800ns;
-		else if ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20))
-			rate = ieee80211_htrates[i].ht20_rate_400ns;
-		else
-			rate = ieee80211_htrates[i].ht20_rate_800ns;
-		if (rate > maxrate)
-			maxrate = rate;
-	}
-	return maxrate;
-}
-
 /* XXX inline or eliminate? */
 const struct ieee80211_rateset *
 ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c)
Index: sys/net80211/ieee80211_ddb.c
===================================================================
--- sys/net80211/ieee80211_ddb.c	(revision 287554)
+++ sys/net80211/ieee80211_ddb.c	(working copy)
@@ -634,7 +634,8 @@ _db_show_com(const struct ieee80211com *ic, int sh
 	    ic->ic_montaps, ic->ic_th, ic->ic_txchan, ic->ic_rh, ic->ic_rxchan);
 
 	if (showprocs) {
-		DB_PRINTSYM("\t", "ic_vap_create", ic->ic_vap_create);
+		DB_PRINTSYM("\t", "ic_vap_preattach", ic->ic_vap_preattach);
+		DB_PRINTSYM("\t", "ic_vap_postattach", ic->ic_vap_postattach);
 		DB_PRINTSYM("\t", "ic_vap_delete", ic->ic_vap_delete);
 #if 0
 		/* operating mode attachment */
Index: sys/net80211/ieee80211_freebsd.c
===================================================================
--- sys/net80211/ieee80211_freebsd.c	(revision 287554)
+++ sys/net80211/ieee80211_freebsd.c	(working copy)
@@ -55,6 +55,8 @@ __FBSDID("$FreeBSD$");
 
 #include <net80211/ieee80211_var.h>
 #include <net80211/ieee80211_input.h>
+#include <net80211/ieee80211_ratectl.h>
+#include <net80211/ieee80211_regdomain.h>
 
 SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters");
 
@@ -66,6 +68,181 @@ SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW,
 
 static MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state");
 
+static void
+addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword)
+{
+#define	ADD(_ic, _s, _o) \
+	ifmedia_add(media, \
+		IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
+	static const u_int mopts[IEEE80211_MODE_MAX] = { 
+	    [IEEE80211_MODE_AUTO]	= IFM_AUTO,
+	    [IEEE80211_MODE_11A]	= IFM_IEEE80211_11A,
+	    [IEEE80211_MODE_11B]	= IFM_IEEE80211_11B,
+	    [IEEE80211_MODE_11G]	= IFM_IEEE80211_11G,
+	    [IEEE80211_MODE_FH]		= IFM_IEEE80211_FH,
+	    [IEEE80211_MODE_TURBO_A]	= IFM_IEEE80211_11A|IFM_IEEE80211_TURBO,
+	    [IEEE80211_MODE_TURBO_G]	= IFM_IEEE80211_11G|IFM_IEEE80211_TURBO,
+	    [IEEE80211_MODE_STURBO_A]	= IFM_IEEE80211_11A|IFM_IEEE80211_TURBO,
+	    [IEEE80211_MODE_HALF]	= IFM_IEEE80211_11A,	/* XXX */
+	    [IEEE80211_MODE_QUARTER]	= IFM_IEEE80211_11A,	/* XXX */
+	    [IEEE80211_MODE_11NA]	= IFM_IEEE80211_11NA,
+	    [IEEE80211_MODE_11NG]	= IFM_IEEE80211_11NG,
+	};
+	u_int mopt;
+
+	mopt = mopts[mode];
+	if (addsta)
+		ADD(ic, mword, mopt);	/* STA mode has no cap */
+	if (caps & IEEE80211_C_IBSS)
+		ADD(media, mword, mopt | IFM_IEEE80211_ADHOC);
+	if (caps & IEEE80211_C_HOSTAP)
+		ADD(media, mword, mopt | IFM_IEEE80211_HOSTAP);
+	if (caps & IEEE80211_C_AHDEMO)
+		ADD(media, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
+	if (caps & IEEE80211_C_MONITOR)
+		ADD(media, mword, mopt | IFM_IEEE80211_MONITOR);
+	if (caps & IEEE80211_C_WDS)
+		ADD(media, mword, mopt | IFM_IEEE80211_WDS);
+	if (caps & IEEE80211_C_MBSS)
+		ADD(media, mword, mopt | IFM_IEEE80211_MBSS);
+#undef ADD
+}
+
+/*
+ * Setup the media data structures according to the channel and
+ * rate tables.
+ */
+static int
+ieee80211_media_setup(struct ieee80211com *ic, struct ifmedia *media,
+    int caps, int addsta)
+{
+	int i, j, rate, maxrate, mword, r;
+	enum ieee80211_phymode mode;
+	const struct ieee80211_rateset *rs;
+	struct ieee80211_rateset allrates;
+
+	/*
+	 * Fill in media characteristics.
+	 */
+	ifmedia_init(media, 0,
+	    ic->ic_media_change ? ic->ic_media_change : ieee80211_media_change,
+	    ic->ic_media_stat ? ic->ic_media_stat : ieee80211_media_status);
+	maxrate = 0;
+	/*
+	 * Add media for legacy operating modes.
+	 */
+	memset(&allrates, 0, sizeof(allrates));
+	for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) {
+		if (isclr(ic->ic_modecaps, mode))
+			continue;
+		addmedia(media, caps, addsta, mode, IFM_AUTO);
+		if (mode == IEEE80211_MODE_AUTO)
+			continue;
+		rs = &ic->ic_sup_rates[mode];
+		for (i = 0; i < rs->rs_nrates; i++) {
+			rate = rs->rs_rates[i];
+			mword = ieee80211_rate2media(ic, rate, mode);
+			if (mword == 0)
+				continue;
+			addmedia(media, caps, addsta, mode, mword);
+			/*
+			 * Add legacy rate to the collection of all rates.
+			 */
+			r = rate & IEEE80211_RATE_VAL;
+			for (j = 0; j < allrates.rs_nrates; j++)
+				if (allrates.rs_rates[j] == r)
+					break;
+			if (j == allrates.rs_nrates) {
+				/* unique, add to the set */
+				allrates.rs_rates[j] = r;
+				allrates.rs_nrates++;
+			}
+			rate = (rate & IEEE80211_RATE_VAL) / 2;
+			if (rate > maxrate)
+				maxrate = rate;
+		}
+	}
+	for (i = 0; i < allrates.rs_nrates; i++) {
+		mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
+				IEEE80211_MODE_AUTO);
+		if (mword == 0)
+			continue;
+		/* NB: remove media options from mword */
+		addmedia(media, caps, addsta,
+		    IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword));
+	}
+	/*
+	 * Add HT/11n media.  Note that we do not have enough
+	 * bits in the media subtype to express the MCS so we
+	 * use a "placeholder" media subtype and any fixed MCS
+	 * must be specified with a different mechanism.
+	 */
+	for (; mode <= IEEE80211_MODE_11NG; mode++) {
+		if (isclr(ic->ic_modecaps, mode))
+			continue;
+		addmedia(media, caps, addsta, mode, IFM_AUTO);
+		addmedia(media, caps, addsta, mode, IFM_IEEE80211_MCS);
+	}
+	if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) ||
+	    isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) {
+		addmedia(media, caps, addsta,
+		    IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS);
+		i = ic->ic_txstream * 8 - 1;
+		if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
+		    (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40))
+			rate = ieee80211_htrates[i].ht40_rate_400ns;
+		else if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40))
+			rate = ieee80211_htrates[i].ht40_rate_800ns;
+		else if ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20))
+			rate = ieee80211_htrates[i].ht20_rate_400ns;
+		else
+			rate = ieee80211_htrates[i].ht20_rate_800ns;
+		if (rate > maxrate)
+			maxrate = rate;
+	}
+	return maxrate;
+}
+
+/*
+ * 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, u_long cmd)
+{
+	return ENETRESET;
+}
+
+/*
+ * Add underlying device errors to vap errors.
+ */
+static uint64_t
+ieee80211_get_counter(struct ifnet *ifp, ift_counter cnt)
+{
+	struct ieee80211vap *vap = ifp->if_softc;
+	struct ieee80211com *ic = vap->iv_ic;
+	uint64_t rv;
+
+	rv = if_get_counter_default(ifp, cnt);
+	switch (cnt) {
+	case IFCOUNTER_OERRORS:
+		rv += counter_u64_fetch(ic->ic_oerrors);
+		break;
+	case IFCOUNTER_IERRORS:
+		rv += counter_u64_fetch(ic->ic_ierrors);
+		break;
+	default:
+		break;
+	}
+
+	return (rv);
+}
+
 static const char wlanname[] = "wlan";
 static struct if_clone *wlan_cloner;
 
@@ -73,9 +250,11 @@ static int
 wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params)
 {
 	struct ieee80211_clone_params cp;
+	struct ifmediareq imr;
 	struct ieee80211vap *vap;
 	struct ieee80211com *ic;
-	int error;
+	struct ifnet *ifp;
+	int maxrate, error;
 
 	error = copyin(params, &cp, sizeof(cp));
 	if (error)
@@ -103,12 +282,170 @@ wlan_clone_create(struct if_clone *ifc, int unit,
 		ic_printf(ic, "TDMA not supported\n");
 		return EOPNOTSUPP;
 	}
-	vap = ic->ic_vap_create(ic, wlanname, unit,
-			cp.icp_opmode, cp.icp_flags, cp.icp_bssid,
-			cp.icp_flags & IEEE80211_CLONE_MACADDR ?
-			    cp.icp_macaddr : ic->ic_macaddr);
+	if (!TAILQ_EMPTY(&ic->ic_vaps) &&
+	    !(ic->ic_caps & IEEE80211_C_MULTIVAP)) {
+		ic_printf(ic, "can have only one interface configured");
+		return (EBUSY);
+	}
 
-	return (vap == NULL ? EIO : 0);
+	if (ic->ic_vap_preattach && (error =
+	    ic->ic_vap_preattach(ic, cp.icp_opmode, cp.icp_flags)) != 0)
+		return (error);
+
+	vap = malloc(sizeof(struct ieee80211vap), M_80211_VAP, M_WAITOK |
+	    M_ZERO);
+	ifp = if_alloc(IFT_ETHER);
+	KASSERT(ifp != NULL, ("%s: failed to allocate ifnet"));
+
+	if_initname(ifp, wlanname, unit);
+	ifp->if_softc = vap;			/* back pointer */
+	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
+	ifp->if_transmit = ieee80211_vap_transmit;
+	ifp->if_qflush = ieee80211_vap_qflush;
+	ifp->if_ioctl = ieee80211_ioctl;
+	ifp->if_init = ieee80211_init;
+	ifp->if_get_counter = ieee80211_get_counter;
+
+	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_htextcaps = ic->ic_htextcaps;
+	vap->iv_opmode = cp.icp_opmode;
+	vap->iv_caps |= ieee80211_opcap[cp.icp_opmode];
+	switch (cp.icp_opmode) {
+	case IEEE80211_M_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, cp.icp_bssid);
+		vap->iv_flags |= IEEE80211_F_DESBSSID;
+		if (cp.icp_flags & IEEE80211_CLONE_WDSLEGACY)
+			vap->iv_flags_ext |= IEEE80211_FEXT_WDSLEGACY;
+		break;
+#ifdef IEEE80211_SUPPORT_TDMA
+	case IEEE80211_M_AHDEMO:
+		if (cp.icp_flags & IEEE80211_CLONE_TDMA) {
+			/* NB: checked before clone operation allowed */
+			KASSERT(ic->ic_caps & IEEE80211_C_TDMA,
+			    ("not TDMA capable, ic_caps 0x%x", ic->ic_caps));
+			/*
+			 * Propagate TDMA capability to mark vap; this
+			 * cannot be removed and is used to distinguish
+			 * regular ahdemo operation from ahdemo+tdma.
+			 */
+			vap->iv_caps |= IEEE80211_C_TDMA;
+		}
+		break;
+#endif
+	default:
+		break;
+	}
+	/* auto-enable s/w beacon miss support */
+	if (cp.icp_flags & IEEE80211_CLONE_NOBEACONS)
+		vap->iv_flags_ext |= IEEE80211_FEXT_SWBMISS;
+	/* auto-generated or user supplied MAC address */
+	if (cp.icp_flags & (IEEE80211_CLONE_BSSID|IEEE80211_CLONE_MACADDR))
+		vap->iv_flags_ext |= IEEE80211_FEXT_UNIQMAC;
+	/*
+	 * 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;
+	/* 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 no cap, just ena */
+	/* NB: DFS support only makes sense for ap mode right now */
+	if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
+	    (vap->iv_caps & IEEE80211_C_DFS))
+		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_sysctl_vattach(vap);
+	ieee80211_crypto_vattach(vap);
+	ieee80211_node_vattach(vap);
+	ieee80211_power_vattach(vap);
+	ieee80211_proto_vattach(vap);
+#ifdef IEEE80211_SUPPORT_SUPERG
+	ieee80211_superg_vattach(vap);
+#endif
+	ieee80211_ht_vattach(vap);
+	ieee80211_scan_vattach(vap);
+	ieee80211_regdomain_vattach(vap);
+	ieee80211_radiotap_vattach(vap);
+	ieee80211_ratectl_set(vap, IEEE80211_RATECTL_NONE);
+
+	/*
+	 * Let device driver allocate its per-vap softc, and
+	 * optionally override some vap methods.
+	 */
+	ic->ic_vap_postattach(ic, vap);
+
+	/* Default to opmode of new vap. */
+	ic->ic_opmode = cp.icp_opmode;
+
+	/*
+	 * Do late attach work that cannot happen until after
+	 * the driver has had a chance to override defaults.
+	 *
+	 * XXXGL: the late attach requires iv_myaddr, so we
+	 * need to temporarily set it.
+	 */
+	vap->iv_myaddr = cp.icp_flags & IEEE80211_CLONE_MACADDR ?
+	    cp.icp_macaddr : ic->ic_macaddr;
+	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);
+	ieee80211_media_status(ifp, &imr);
+	/* NB: strip explicit mode; we're actually in autoselect */
+	ifmedia_set(&vap->iv_media,
+	    imr.ifm_active &~ (IFM_MMASK | IFM_IEEE80211_TURBO));
+	if (maxrate)
+		ifp->if_baudrate = IF_Mbps(maxrate);
+	ether_ifattach(ifp, cp.icp_flags & IEEE80211_CLONE_MACADDR ?
+	    cp.icp_macaddr : ic->ic_macaddr);
+	vap->iv_myaddr = IF_LLADDR(ifp);
+	/* 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 */
+
+	IEEE80211_LOCK(ic);
+	TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next);
+	ieee80211_syncflag_locked(ic, IEEE80211_F_WME);
+#ifdef IEEE80211_SUPPORT_SUPERG
+	ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP);
+#endif
+	ieee80211_syncflag_locked(ic, IEEE80211_F_PCF);
+	ieee80211_syncflag_locked(ic, IEEE80211_F_BURST);
+	ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT);
+	ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40);
+	IEEE80211_UNLOCK(ic);
+
+	return (0);
 }
 
 static void
Index: sys/net80211/ieee80211_proto.h
===================================================================
--- sys/net80211/ieee80211_proto.h	(revision 287554)
+++ sys/net80211/ieee80211_proto.h	(working copy)
@@ -61,6 +61,9 @@ void	ieee80211_allmulti(struct ieee80211vap *, boo
 void	ieee80211_syncflag(struct ieee80211vap *, int flag);
 void	ieee80211_syncflag_ht(struct ieee80211vap *, int flag);
 void	ieee80211_syncflag_ext(struct ieee80211vap *, int flag);
+void	ieee80211_syncflag_locked(struct ieee80211com *, int);
+void	ieee80211_syncflag_ht_locked(struct ieee80211com *, int);   
+void	ieee80211_syncflag_ext_locked(struct ieee80211com *, int);
 
 #define	IEEE80211_R_NF		0x0000001	/* global NF value valid */
 #define	IEEE80211_R_RSSI	0x0000002	/* global RSSI value valid */
Index: sys/net80211/ieee80211_var.h
===================================================================
--- sys/net80211/ieee80211_var.h	(revision 287554)
+++ sys/net80211/ieee80211_var.h	(working copy)
@@ -235,11 +235,10 @@ struct ieee80211com {
 	int			ic_montaps;	/* active monitor mode taps */
 
 	/* virtual ap create/delete */
-	struct ieee80211vap*	(*ic_vap_create)(struct ieee80211com *,
-				    const char [IFNAMSIZ], int,
-				    enum ieee80211_opmode, int,
-				    const uint8_t [IEEE80211_ADDR_LEN],
-				    const uint8_t [IEEE80211_ADDR_LEN]);
+	int			(*ic_vap_preattach)(struct ieee80211com *,
+				     enum ieee80211_opmode, int);
+	void			(*ic_vap_postattach)(struct ieee80211com *,
+				    struct ieee80211vap *);
 	void			(*ic_vap_delete)(struct ieee80211vap *);
 	/* device specific ioctls */
 	int			(*ic_ioctl)(struct ieee80211com *,
@@ -269,6 +268,10 @@ struct ieee80211com {
 	int			(*ic_raw_xmit)(struct ieee80211_node *,
 				    struct mbuf *,
 				    const struct ieee80211_bpf_params *);
+	/* media change */
+	ifm_change_cb_t		ic_media_change;
+	ifm_stat_cb_t		ic_media_stat;
+
 	/* update device state for 802.11 slot time change */
 	void			(*ic_updateslot)(struct ieee80211com *);
 	/* handle multicast state changes */
@@ -353,6 +356,7 @@ struct ieee80211_hwmp_state;
 struct ieee80211vap {
 	struct ifmedia		iv_media;	/* interface media config */
 	struct ifnet		*iv_ifp;	/* associated device */
+	void			*iv_softc;	/* driver's softc */
 	struct bpf_if		*iv_rawbpf;	/* packet filter structure */
 	struct sysctl_ctx_list	*iv_sysctl;	/* dynamic sysctl context */
 	struct sysctl_oid	*iv_oid;	/* net.wlan.X sysctl oid */
@@ -644,7 +648,8 @@ MALLOC_DECLARE(M_80211_VAP);
 #define	IEEE80211_C_DFS		0x00020000	/* CAPABILITY: DFS/radar avail*/
 #define	IEEE80211_C_MBSS	0x00040000	/* CAPABILITY: MBSS available */
 #define	IEEE80211_C_SWSLEEP	0x00080000	/* CAPABILITY: do sleep here */
-/* 0x7c0000 available */
+#define	IEEE80211_C_MULTIVAP	0x00100000	/* CAPABILITY: > 1 vaps */
+/* 0x6c0000 available */
 #define	IEEE80211_C_WPA1	0x00800000	/* CAPABILITY: WPA1 avail */
 #define	IEEE80211_C_WPA2	0x01000000	/* CAPABILITY: WPA2 avail */
 #define	IEEE80211_C_WPA		0x01800000	/* CAPABILITY: WPA1+WPA2 avail*/
@@ -692,13 +697,6 @@ MALLOC_DECLARE(M_80211_VAP);
 int	ic_printf(struct ieee80211com *, const char *, ...) __printflike(2, 3);
 void	ieee80211_ifattach(struct ieee80211com *);
 void	ieee80211_ifdetach(struct ieee80211com *);
-int	ieee80211_vap_setup(struct ieee80211com *, struct ieee80211vap *,
-		const char name[IFNAMSIZ], int unit,
-		enum ieee80211_opmode opmode, int flags,
-		const uint8_t bssid[IEEE80211_ADDR_LEN]);
-int	ieee80211_vap_attach(struct ieee80211vap *,
-		ifm_change_cb_t, ifm_stat_cb_t,
-		const uint8_t macaddr[IEEE80211_ADDR_LEN]);
 void	ieee80211_vap_detach(struct ieee80211vap *);
 const struct ieee80211_rateset *ieee80211_get_suprates(struct ieee80211com *ic,
 		const struct ieee80211_channel *);

--mxv5cy4qt+RJ9ypb--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20150908152233.GV1023>