PERFORCE change 133353 for review
Sam Leffler
sam at FreeBSD.org
Tue Jan 15 13:31:04 PST 2008
http://perforce.freebsd.org/chv.cgi?CH=133353
Change 133353 by sam at sam_ebb on 2008/01/15 21:30:15
backout mis-auto-merge
Affected files ...
.. //depot/projects/vap/sys/net80211/ieee80211.c#20 edit
Differences ...
==== //depot/projects/vap/sys/net80211/ieee80211.c#20 (text+ko) ====
@@ -25,11 +25,12 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.45 2007/12/07 01:46:12 kmacy Exp $");
+__FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.44 2007/11/23 05:57:20 sam Exp $");
/*
* IEEE 802.11 generic handler
*/
+#include "opt_wlan.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -38,10 +39,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 +61,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 +93,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 +111,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 +145,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 +169,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 +217,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_llsoftc == NULL, ("oops, hosed"));
- ifp->if_llsoftc = ic;
+ 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 +263,357 @@
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],
+ const uint8_t macaddr[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, macaddr);
+
+ 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 +727,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 +778,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,
+ IFM_IEEE80211_11A,
+ IFM_IEEE80211_11B,
+ IFM_IEEE80211_11G,
+ IFM_IEEE80211_FH,
+ IFM_IEEE80211_11A | IFM_IEEE80211_TURBO,
+ IFM_IEEE80211_11G | IFM_IEEE80211_TURBO,
+ IFM_IEEE80211_11A | IFM_IEEE80211_TURBO,
+ IFM_IEEE80211_11NA,
+ IFM_IEEE80211_11NG,
};
u_int mopt;
- KASSERT(mode < IEEE80211_MODE_MAX, ("bad mode %u", mode));
mopt = mopts[mode];
- KASSERT(mopt != 0 || mode == IEEE80211_MODE_AUTO,
- ("no media mapping for mode %u", mode));
-
- ADD(ic, mword, mopt); /* e.g. 11a auto */
- if (ic->ic_caps & IEEE80211_C_IBSS)
- ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC);
- if (ic->ic_caps & IEEE80211_C_HOSTAP)
- ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP);
- if (ic->ic_caps & IEEE80211_C_AHDEMO)
- ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
- if (ic->ic_caps & IEEE80211_C_MONITOR)
- ADD(ic, mword, mopt | IFM_IEEE80211_MONITOR);
+ 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);
#undef ADD
-#undef TURBO
}
/*
* Setup the media data structures according to the channel and
- * rate tables. This must be called by the driver after
- * ieee80211_attach and before most anything else.
+ * rate tables.
*/
-void
-ieee80211_media_init(struct ieee80211com *ic,
+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)
{
- struct ifnet *ifp = ic->ic_ifp;
int i, j, mode, rate, maxrate, mword, r;
const struct ieee80211_rateset *rs;
struct ieee80211_rateset allrates;
- /* NB: this works because the structure is initialized to zero */
- if (LIST_EMPTY(&ic->ic_media.ifm_list)) {
- /*
- * Do late attach work that must wait for any subclass
- * (i.e. driver) work such as overriding methods.
- */
- ieee80211_node_lateattach(ic);
- } else {
- /*
- * We are re-initializing the channel list; clear
- * the existing media state as the media routines
- * don't suppress duplicates.
- */
- ifmedia_removeall(&ic->ic_media);
- ieee80211_chan_init(ic);
- }
- ieee80211_power_lateattach(ic);
-
/*
* Fill in media characteristics.
*/
- ifmedia_init(&ic->ic_media, 0, media_change, media_stat);
+ ifmedia_init(media, 0, media_change, media_stat);
maxrate = 0;
/*
* Add media for legacy operating modes.
@@ -549,7 +838,7 @@
for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) {
if (isclr(ic->ic_modecaps, mode))
continue;
- addmedia(ic, mode, IFM_AUTO);
+ addmedia(media, caps, addsta, mode, IFM_AUTO);
if (mode == IEEE80211_MODE_AUTO)
continue;
rs = &ic->ic_sup_rates[mode];
@@ -558,7 +847,7 @@
mword = ieee80211_rate2media(ic, rate, mode);
if (mword == 0)
continue;
- addmedia(ic, mode, mword);
+ addmedia(media, caps, addsta, mode, mword);
/*
* Add legacy rate to the collection of all rates.
*/
@@ -582,7 +871,8 @@
if (mword == 0)
continue;
/* NB: remove media options from mword */
- addmedia(ic, IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword));
+ addmedia(media, caps, addsta,
+ IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword));
}
/*
* Add HT/11n media. Note that we do not have enough
@@ -593,24 +883,52 @@
for (; mode < IEEE80211_MODE_MAX; mode++) {
if (isclr(ic->ic_modecaps, mode))
continue;
- addmedia(ic, mode, IFM_AUTO);
- addmedia(ic, mode, IFM_IEEE80211_MCS);
+ 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(ic, IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS);
+ addmedia(media, caps, addsta,
+ IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS);
/* XXX could walk htrates */
/* XXX known array size */
if (ieee80211_htrates[15] > maxrate)
maxrate = ieee80211_htrates[15];
}
+ return maxrate;
+}
+
+void
+ieee80211_media_init(struct ieee80211com *ic,
+ ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ int maxrate;
+
+ /* NB: this works because the structure is initialized to zero */
+ if (!LIST_EMPTY(&ic->ic_media.ifm_list)) {
+ /*
+ * We are re-initializing the channel list; clear
+ * the existing media state as the media routines
+ * don't suppress duplicates.
+ */
+ ifmedia_removeall(&ic->ic_media);
+ }
+ ieee80211_chan_init(ic);
+ /*
+ * Recalculate media settings in case new channel list changes
+ * the set of available modes.
+ */
+ maxrate = ieee80211_media_setup(ic, &ic->ic_media, ic->ic_caps, 1,
+ ieee80211com_media_change, ieee80211com_media_status);
/* NB: strip explicit mode; we're actually in autoselect */
ifmedia_set(&ic->ic_media,
media_status(ic->ic_opmode, ic->ic_curchan) &~ IFM_MMASK);
-
if (maxrate)
ifp->if_baudrate = IF_Mbps(maxrate);
+
+ /* XXX need to propagate new media settings to vap's */
}
const struct ieee80211_rateset *
@@ -701,216 +1019,134 @@
}
}
-/*
- * Find an instance by it's mac address.
- */
-struct ieee80211com *
-ieee80211_find_vap(const uint8_t mac[IEEE80211_ADDR_LEN])
-{
- struct ieee80211com *ic;
-
- /* XXX lock */
- SLIST_FOREACH(ic, &ieee80211_list, ic_next)
- if (IEEE80211_ADDR_EQ(mac, ic->ic_myaddr))
- return ic;
- return NULL;
-}
-
-static struct ieee80211com *
-ieee80211_find_instance(struct ifnet *ifp)
-{
- struct ieee80211com *ic;
-
- /* XXX lock */
- /* XXX not right for multiple instances but works for now */
- SLIST_FOREACH(ic, &ieee80211_list, ic_next)
- if (ic->ic_ifp == ifp)
- return ic;
- return NULL;
-}
-
static int
-findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
-{
-#define IEEERATE(_ic,_m,_i) \
- ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
- int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
- for (i = 0; i < nrates; i++)
- if (IEEERATE(ic, mode, i) == rate)
- return i;
- return -1;
-#undef IEEERATE
-}
-
-/*
- * Convert a media specification to a rate index and possibly a mode
- * (if the rate is fixed and the mode is specified as ``auto'' then
- * we need to lock down the mode so the index is meanginful).
- */
-static int
-checkrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
-{
-
- /*
- * Check the rate table for the specified/current phy.
- */
- if (mode == IEEE80211_MODE_AUTO) {
- int i;
- /*
- * In autoselect mode search for the rate.
- */
- for (i = IEEE80211_MODE_11A; i < IEEE80211_MODE_MAX; i++) {
- if (isset(ic->ic_modecaps, i) &&
- findrate(ic, i, rate) != -1)
- return 1;
- }
- return 0;
- } else {
- /*
- * Mode is fixed, check for rate.
- */
- return (findrate(ic, mode, rate) != -1);
- }
-}
-
-/*
- * Handle a media change request.
- */
-int
-ieee80211_media_change(struct ifnet *ifp)
+media2mode(const struct ieee80211com *ic,
+ const struct ifmedia_entry *ime, enum ieee80211_phymode *mode)
{
- struct ieee80211com *ic;
- struct ifmedia_entry *ime;
- enum ieee80211_opmode newopmode;
- enum ieee80211_phymode newphymode;
- int newrate, error = 0;
-
- ic = ieee80211_find_instance(ifp);
- if (!ic) {
- if_printf(ifp, "%s: no 802.11 instance!\n", __func__);
- return EINVAL;
- }
- ime = ic->ic_media.ifm_cur;
- /*
- * First, identify the phy mode.
- */
switch (IFM_MODE(ime->ifm_media)) {
case IFM_IEEE80211_11A:
- newphymode = IEEE80211_MODE_11A;
+ *mode = IEEE80211_MODE_11A;
break;
case IFM_IEEE80211_11B:
- newphymode = IEEE80211_MODE_11B;
+ *mode = IEEE80211_MODE_11B;
break;
case IFM_IEEE80211_11G:
- newphymode = IEEE80211_MODE_11G;
+ *mode = IEEE80211_MODE_11G;
break;
case IFM_IEEE80211_FH:
- newphymode = IEEE80211_MODE_FH;
+ *mode = IEEE80211_MODE_FH;
break;
case IFM_IEEE80211_11NA:
- newphymode = IEEE80211_MODE_11NA;
+ *mode = IEEE80211_MODE_11NA;
break;
case IFM_IEEE80211_11NG:
- newphymode = IEEE80211_MODE_11NG;
+ *mode = IEEE80211_MODE_11NG;
break;
case IFM_AUTO:
- newphymode = IEEE80211_MODE_AUTO;
+ *mode = IEEE80211_MODE_AUTO;
break;
default:
- return EINVAL;
+ return 0;
}
/*
* Turbo mode is an ``option''.
* XXX does not apply to AUTO
*/
if (ime->ifm_media & IFM_IEEE80211_TURBO) {
- if (newphymode == IEEE80211_MODE_11A) {
+ if (*mode == IEEE80211_MODE_11A) {
if (ic->ic_flags & IEEE80211_F_TURBOP)
- newphymode = IEEE80211_MODE_TURBO_A;
+ *mode = IEEE80211_MODE_TURBO_A;
else
- newphymode = IEEE80211_MODE_STURBO_A;
- } else if (newphymode == IEEE80211_MODE_11G)
- newphymode = IEEE80211_MODE_TURBO_G;
+ *mode = IEEE80211_MODE_STURBO_A;
+ } else if (*mode == IEEE80211_MODE_11G)
+ *mode = IEEE80211_MODE_TURBO_G;
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list