Changeset View
Changeset View
Standalone View
Standalone View
sys/net80211/ieee80211.c
Show First 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | const uint8_t ieee80211broadcastaddr[IEEE80211_ADDR_LEN] = | ||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||||
static void ieee80211_syncflag_locked(struct ieee80211com *ic, int flag); | 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_ht_locked(struct ieee80211com *ic, int flag); | ||||
static void ieee80211_syncflag_ext_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, | static int ieee80211_media_setup(struct ieee80211com *ic, | ||||
struct ifmedia *media, int caps, int addsta, | struct ifmedia *media, int caps, int addsta, | ||||
ifm_change_cb_t media_change, ifm_stat_cb_t media_stat); | 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, | static int media_status(enum ieee80211_opmode, | ||||
const struct ieee80211_channel *); | const struct ieee80211_channel *); | ||||
static uint64_t ieee80211_get_counter(struct ifnet *, ift_counter); | static uint64_t ieee80211_get_counter(struct ifnet *, ift_counter); | ||||
MALLOC_DEFINE(M_80211_VAP, "80211vap", "802.11 vap state"); | MALLOC_DEFINE(M_80211_VAP, "80211vap", "802.11 vap state"); | ||||
/* | /* | ||||
* Default supported rates for 802.11 operation (in IEEE .5Mb units). | * Default supported rates for 802.11 operation (in IEEE .5Mb units). | ||||
Show All 12 Lines | static const struct ieee80211_rateset ieee80211_rateset_11g = | ||||
{ 12, { B(2), B(4), B(11), B(22), 12, 18, 24, 36, 48, 72, 96, 108 } }; | { 12, { B(2), B(4), B(11), B(22), 12, 18, 24, 36, 48, 72, 96, 108 } }; | ||||
#undef B | #undef B | ||||
/* | /* | ||||
* Fill in 802.11 available channel set, mark | * Fill in 802.11 available channel set, mark | ||||
* all available channels as active, and pick | * all available channels as active, and pick | ||||
* a default channel if not already specified. | * a default channel if not already specified. | ||||
*/ | */ | ||||
static void | void | ||||
ieee80211_chan_init(struct ieee80211com *ic) | ieee80211_chan_init(struct ieee80211com *ic) | ||||
{ | { | ||||
#define DEFAULTRATES(m, def) do { \ | #define DEFAULTRATES(m, def) do { \ | ||||
if (ic->ic_sup_rates[m].rs_nrates == 0) \ | if (ic->ic_sup_rates[m].rs_nrates == 0) \ | ||||
ic->ic_sup_rates[m] = def; \ | ic->ic_sup_rates[m] = def; \ | ||||
} while (0) | } while (0) | ||||
struct ieee80211_channel *c; | struct ieee80211_channel *c; | ||||
int i; | int i; | ||||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
null_update_promisc(struct ieee80211com *ic) | null_update_promisc(struct ieee80211com *ic) | ||||
{ | { | ||||
ic_printf(ic, "need promiscuous mode update callback\n"); | ic_printf(ic, "need promiscuous mode update callback\n"); | ||||
} | } | ||||
static int | |||||
null_transmit(struct ifnet *ifp, struct mbuf *m) | |||||
{ | |||||
m_freem(m); | |||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | |||||
return EACCES; /* XXX EIO/EPERM? */ | |||||
} | |||||
static int | |||||
null_output(struct ifnet *ifp, struct mbuf *m, | |||||
const struct sockaddr *dst, struct route *ro) | |||||
{ | |||||
if_printf(ifp, "discard raw packet\n"); | |||||
return null_transmit(ifp, m); | |||||
} | |||||
static void | static void | ||||
null_input(struct ifnet *ifp, struct mbuf *m) | |||||
{ | |||||
if_printf(ifp, "if_input should not be called\n"); | |||||
m_freem(m); | |||||
} | |||||
static void | |||||
null_update_chw(struct ieee80211com *ic) | null_update_chw(struct ieee80211com *ic) | ||||
{ | { | ||||
ic_printf(ic, "%s: need callback\n", __func__); | ic_printf(ic, "%s: need callback\n", __func__); | ||||
} | } | ||||
static LIST_HEAD(, ieee80211com) ic_head = LIST_HEAD_INITIALIZER(ic_head); | |||||
int | int | ||||
ic_printf(struct ieee80211com *ic, const char * fmt, ...) | ic_printf(struct ieee80211com *ic, const char * fmt, ...) | ||||
{ | { | ||||
va_list ap; | va_list ap; | ||||
int retval; | int retval; | ||||
retval = printf("%s: ", ic->ic_name); | retval = printf("%s: ", ic->ic_name); | ||||
va_start(ap, fmt); | va_start(ap, fmt); | ||||
retval += vprintf(fmt, ap); | retval += vprintf(fmt, ap); | ||||
va_end(ap); | va_end(ap); | ||||
return (retval); | return (retval); | ||||
} | } | ||||
/* | /* | ||||
* Attach/setup the common net80211 state. Called by | * Attach/setup the common net80211 state. Called by | ||||
* the driver on attach to prior to creating any vap's. | * the driver on attach to prior to creating any vap's. | ||||
*/ | */ | ||||
void | void | ||||
ieee80211_ifattach(struct ieee80211com *ic, | ieee80211_ifattach(struct ieee80211com *ic) | ||||
const uint8_t macaddr[IEEE80211_ADDR_LEN]) | |||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | |||||
struct sockaddr_dl *sdl; | |||||
struct ifaddr *ifa; | |||||
KASSERT(ifp->if_type == IFT_IEEE80211, ("if_type %d", ifp->if_type)); | |||||
IEEE80211_LOCK_INIT(ic, ic->ic_name); | IEEE80211_LOCK_INIT(ic, ic->ic_name); | ||||
IEEE80211_TX_LOCK_INIT(ic, ic->ic_name); | IEEE80211_TX_LOCK_INIT(ic, ic->ic_name); | ||||
TAILQ_INIT(&ic->ic_vaps); | TAILQ_INIT(&ic->ic_vaps); | ||||
/* Create a taskqueue for all state changes */ | /* Create a taskqueue for all state changes */ | ||||
ic->ic_tq = taskqueue_create("ic_taskq", M_WAITOK | M_ZERO, | ic->ic_tq = taskqueue_create("ic_taskq", M_WAITOK | M_ZERO, | ||||
taskqueue_thread_enqueue, &ic->ic_tq); | taskqueue_thread_enqueue, &ic->ic_tq); | ||||
taskqueue_start_threads(&ic->ic_tq, 1, PI_NET, "%s net80211 taskq", | taskqueue_start_threads(&ic->ic_tq, 1, PI_NET, "%s net80211 taskq", | ||||
ic->ic_name); | ic->ic_name); | ||||
ic->ic_ierrors = counter_u64_alloc(M_WAITOK); | ic->ic_ierrors = counter_u64_alloc(M_WAITOK); | ||||
ic->ic_oerrors = counter_u64_alloc(M_WAITOK); | ic->ic_oerrors = counter_u64_alloc(M_WAITOK); | ||||
/* | /* | ||||
* Fill in 802.11 available channel set, mark all | * Fill in 802.11 available channel set, mark all | ||||
* available channels as active, and pick a default | * available channels as active, and pick a default | ||||
* channel if not already specified. | * channel if not already specified. | ||||
*/ | */ | ||||
ieee80211_media_init(ic); | ieee80211_chan_init(ic); | ||||
ic->ic_update_mcast = null_update_mcast; | ic->ic_update_mcast = null_update_mcast; | ||||
ic->ic_update_promisc = null_update_promisc; | ic->ic_update_promisc = null_update_promisc; | ||||
ic->ic_update_chw = null_update_chw; | ic->ic_update_chw = null_update_chw; | ||||
ic->ic_hash_key = arc4random(); | ic->ic_hash_key = arc4random(); | ||||
ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; | ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; | ||||
ic->ic_lintval = ic->ic_bintval; | ic->ic_lintval = ic->ic_bintval; | ||||
ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; | ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; | ||||
ieee80211_crypto_attach(ic); | ieee80211_crypto_attach(ic); | ||||
ieee80211_node_attach(ic); | ieee80211_node_attach(ic); | ||||
ieee80211_power_attach(ic); | ieee80211_power_attach(ic); | ||||
ieee80211_proto_attach(ic); | ieee80211_proto_attach(ic); | ||||
#ifdef IEEE80211_SUPPORT_SUPERG | #ifdef IEEE80211_SUPPORT_SUPERG | ||||
ieee80211_superg_attach(ic); | ieee80211_superg_attach(ic); | ||||
#endif | #endif | ||||
ieee80211_ht_attach(ic); | ieee80211_ht_attach(ic); | ||||
ieee80211_scan_attach(ic); | ieee80211_scan_attach(ic); | ||||
ieee80211_regdomain_attach(ic); | ieee80211_regdomain_attach(ic); | ||||
ieee80211_dfs_attach(ic); | ieee80211_dfs_attach(ic); | ||||
ieee80211_sysctl_attach(ic); | ieee80211_sysctl_attach(ic); | ||||
ifp->if_addrlen = IEEE80211_ADDR_LEN; | LIST_INSERT_HEAD(&ic_head, ic, ic_next); | ||||
ifp->if_hdrlen = 0; | |||||
CURVNET_SET(vnet0); | |||||
if_attach(ifp); | |||||
ifp->if_mtu = IEEE80211_MTU_MAX; | |||||
ifp->if_broadcastaddr = ieee80211broadcastaddr; | |||||
ifp->if_output = null_output; | |||||
ifp->if_input = null_input; /* just in case */ | |||||
ifp->if_resolvemulti = NULL; /* NB: callers check */ | |||||
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), macaddr); | |||||
ifa_free(ifa); | |||||
CURVNET_RESTORE(); | |||||
} | } | ||||
/* | /* | ||||
* Detach net80211 state on device detach. Tear down | * Detach net80211 state on device detach. Tear down | ||||
* all vap's and reclaim all common state prior to the | * all vap's and reclaim all common state prior to the | ||||
* device state going away. Note we may call back into | * device state going away. Note we may call back into | ||||
* driver; it must be prepared for this. | * driver; it must be prepared for this. | ||||
*/ | */ | ||||
void | void | ||||
ieee80211_ifdetach(struct ieee80211com *ic) | ieee80211_ifdetach(struct ieee80211com *ic) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | |||||
struct ieee80211vap *vap; | struct ieee80211vap *vap; | ||||
/* | LIST_REMOVE(ic, ic_next); | ||||
* This detaches the main interface, but not the vaps. | |||||
* Each VAP may be in a separate VIMAGE. | |||||
*/ | |||||
CURVNET_SET(ifp->if_vnet); | |||||
if_detach(ifp); | |||||
CURVNET_RESTORE(); | |||||
/* | /* | ||||
* The VAP is responsible for setting and clearing | * The VAP is responsible for setting and clearing | ||||
* the VIMAGE context. | * the VIMAGE context. | ||||
*/ | */ | ||||
while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL) | while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL) | ||||
ieee80211_vap_destroy(vap); | ieee80211_vap_destroy(vap); | ||||
ieee80211_waitfor_parent(ic); | ieee80211_waitfor_parent(ic); | ||||
ieee80211_sysctl_detach(ic); | ieee80211_sysctl_detach(ic); | ||||
ieee80211_dfs_detach(ic); | ieee80211_dfs_detach(ic); | ||||
ieee80211_regdomain_detach(ic); | ieee80211_regdomain_detach(ic); | ||||
ieee80211_scan_detach(ic); | ieee80211_scan_detach(ic); | ||||
#ifdef IEEE80211_SUPPORT_SUPERG | #ifdef IEEE80211_SUPPORT_SUPERG | ||||
ieee80211_superg_detach(ic); | ieee80211_superg_detach(ic); | ||||
#endif | #endif | ||||
ieee80211_ht_detach(ic); | ieee80211_ht_detach(ic); | ||||
/* NB: must be called before ieee80211_node_detach */ | /* NB: must be called before ieee80211_node_detach */ | ||||
ieee80211_proto_detach(ic); | ieee80211_proto_detach(ic); | ||||
ieee80211_crypto_detach(ic); | ieee80211_crypto_detach(ic); | ||||
ieee80211_power_detach(ic); | ieee80211_power_detach(ic); | ||||
ieee80211_node_detach(ic); | ieee80211_node_detach(ic); | ||||
/* XXX VNET needed? */ | |||||
ifmedia_removeall(&ic->ic_media); | |||||
counter_u64_free(ic->ic_ierrors); | counter_u64_free(ic->ic_ierrors); | ||||
counter_u64_free(ic->ic_oerrors); | counter_u64_free(ic->ic_oerrors); | ||||
taskqueue_free(ic->ic_tq); | taskqueue_free(ic->ic_tq); | ||||
IEEE80211_TX_LOCK_DESTROY(ic); | IEEE80211_TX_LOCK_DESTROY(ic); | ||||
IEEE80211_LOCK_DESTROY(ic); | IEEE80211_LOCK_DESTROY(ic); | ||||
} | } | ||||
struct ieee80211com * | |||||
ieee80211_find_com(const char *name) | |||||
{ | |||||
struct ieee80211com *ic; | |||||
LIST_FOREACH(ic, &ic_head, ic_next) | |||||
if (strcmp(ic->ic_name, name) == 0) | |||||
break; | |||||
return (ic); | |||||
} | |||||
/* | /* | ||||
* Default reset method for use with the ioctl support. This | * Default reset method for use with the ioctl support. This | ||||
* method is invoked after any state change in the 802.11 | * method is invoked after any state change in the 802.11 | ||||
* layer that should be propagated to the hardware but not | * layer that should be propagated to the hardware but not | ||||
* require re-initialization of the 802.11 state machine (e.g | * require re-initialization of the 802.11 state machine (e.g | ||||
* rescanning for an ap). We always return ENETRESET which | * rescanning for an ap). We always return ENETRESET which | ||||
* should cause the driver to re-initialize the device. Drivers | * should cause the driver to re-initialize the device. Drivers | ||||
* can override this method to implement more optimized support. | * can override this method to implement more optimized support. | ||||
Show All 32 Lines | |||||
/* | /* | ||||
* Prepare a vap for use. Drivers use this call to | * Prepare a vap for use. Drivers use this call to | ||||
* setup net80211 state in new vap's prior attaching | * setup net80211 state in new vap's prior attaching | ||||
* them with ieee80211_vap_attach (below). | * them with ieee80211_vap_attach (below). | ||||
*/ | */ | ||||
int | int | ||||
ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, | ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, | ||||
const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode, | const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode, | ||||
int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], | int flags, const uint8_t bssid[IEEE80211_ADDR_LEN]) | ||||
const uint8_t macaddr[IEEE80211_ADDR_LEN]) | |||||
{ | { | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
ifp = if_alloc(IFT_ETHER); | ifp = if_alloc(IFT_ETHER); | ||||
if (ifp == NULL) { | if (ifp == NULL) { | ||||
ic_printf(ic, "%s: unable to allocate ifnet\n", | ic_printf(ic, "%s: unable to allocate ifnet\n", | ||||
__func__); | __func__); | ||||
return ENOMEM; | return ENOMEM; | ||||
Show All 12 Lines | ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, | ||||
vap->iv_flags = ic->ic_flags; /* propagate common flags */ | vap->iv_flags = ic->ic_flags; /* propagate common flags */ | ||||
vap->iv_flags_ext = ic->ic_flags_ext; | vap->iv_flags_ext = ic->ic_flags_ext; | ||||
vap->iv_flags_ven = ic->ic_flags_ven; | vap->iv_flags_ven = ic->ic_flags_ven; | ||||
vap->iv_caps = ic->ic_caps &~ IEEE80211_C_OPMODE; | vap->iv_caps = ic->ic_caps &~ IEEE80211_C_OPMODE; | ||||
vap->iv_htcaps = ic->ic_htcaps; | vap->iv_htcaps = ic->ic_htcaps; | ||||
vap->iv_htextcaps = ic->ic_htextcaps; | vap->iv_htextcaps = ic->ic_htextcaps; | ||||
vap->iv_opmode = opmode; | vap->iv_opmode = opmode; | ||||
vap->iv_caps |= ieee80211_opcap[opmode]; | vap->iv_caps |= ieee80211_opcap[opmode]; | ||||
vap->iv_myaddr = ic->ic_macaddr; | |||||
switch (opmode) { | switch (opmode) { | ||||
case IEEE80211_M_WDS: | case IEEE80211_M_WDS: | ||||
/* | /* | ||||
* WDS links must specify the bssid of the far end. | * WDS links must specify the bssid of the far end. | ||||
* For legacy operation this is a static relationship. | * For legacy operation this is a static relationship. | ||||
* For non-legacy operation the station must associate | * For non-legacy operation the station must associate | ||||
* and be authorized to pass traffic. Plumbing the | * and be authorized to pass traffic. Plumbing the | ||||
* vap to the proper node happens when the vap | * vap to the proper node happens when the vap | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | #endif | ||||
vap->iv_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; | vap->iv_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; | ||||
vap->iv_dtim_period = IEEE80211_DTIM_DEFAULT; | vap->iv_dtim_period = IEEE80211_DTIM_DEFAULT; | ||||
/* | /* | ||||
* Install a default reset method for the ioctl support; | * Install a default reset method for the ioctl support; | ||||
* the driver can override this. | * the driver can override this. | ||||
*/ | */ | ||||
vap->iv_reset = default_reset; | vap->iv_reset = default_reset; | ||||
IEEE80211_ADDR_COPY(vap->iv_myaddr, macaddr); | |||||
ieee80211_sysctl_vattach(vap); | ieee80211_sysctl_vattach(vap); | ||||
ieee80211_crypto_vattach(vap); | ieee80211_crypto_vattach(vap); | ||||
ieee80211_node_vattach(vap); | ieee80211_node_vattach(vap); | ||||
ieee80211_power_vattach(vap); | ieee80211_power_vattach(vap); | ||||
ieee80211_proto_vattach(vap); | ieee80211_proto_vattach(vap); | ||||
#ifdef IEEE80211_SUPPORT_SUPERG | #ifdef IEEE80211_SUPPORT_SUPERG | ||||
ieee80211_superg_vattach(vap); | ieee80211_superg_vattach(vap); | ||||
#endif | #endif | ||||
ieee80211_ht_vattach(vap); | ieee80211_ht_vattach(vap); | ||||
ieee80211_scan_vattach(vap); | ieee80211_scan_vattach(vap); | ||||
ieee80211_regdomain_vattach(vap); | ieee80211_regdomain_vattach(vap); | ||||
ieee80211_radiotap_vattach(vap); | ieee80211_radiotap_vattach(vap); | ||||
ieee80211_ratectl_set(vap, IEEE80211_RATECTL_NONE); | ieee80211_ratectl_set(vap, IEEE80211_RATECTL_NONE); | ||||
return 0; | return 0; | ||||
} | } | ||||
/* | /* | ||||
* Activate a vap. State should have been prepared with a | * Activate a vap. State should have been prepared with a | ||||
* call to ieee80211_vap_setup and by the driver. On return | * call to ieee80211_vap_setup and by the driver. On return | ||||
* from this call the vap is ready for use. | * from this call the vap is ready for use. | ||||
*/ | */ | ||||
int | int | ||||
ieee80211_vap_attach(struct ieee80211vap *vap, | ieee80211_vap_attach(struct ieee80211vap *vap, ifm_change_cb_t media_change, | ||||
ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) | ifm_stat_cb_t media_stat, const uint8_t macaddr[IEEE80211_ADDR_LEN]) | ||||
{ | { | ||||
struct ifnet *ifp = vap->iv_ifp; | struct ifnet *ifp = vap->iv_ifp; | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct ifmediareq imr; | struct ifmediareq imr; | ||||
int maxrate; | int maxrate; | ||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, | IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, | ||||
"%s: %s parent %s flags 0x%x flags_ext 0x%x\n", | "%s: %s parent %s flags 0x%x flags_ext 0x%x\n", | ||||
Show All 11 Lines | maxrate = ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps, | ||||
vap->iv_opmode == IEEE80211_M_STA, media_change, media_stat); | vap->iv_opmode == IEEE80211_M_STA, media_change, media_stat); | ||||
ieee80211_media_status(ifp, &imr); | ieee80211_media_status(ifp, &imr); | ||||
/* NB: strip explicit mode; we're actually in autoselect */ | /* NB: strip explicit mode; we're actually in autoselect */ | ||||
ifmedia_set(&vap->iv_media, | ifmedia_set(&vap->iv_media, | ||||
imr.ifm_active &~ (IFM_MMASK | IFM_IEEE80211_TURBO)); | imr.ifm_active &~ (IFM_MMASK | IFM_IEEE80211_TURBO)); | ||||
if (maxrate) | if (maxrate) | ||||
ifp->if_baudrate = IF_Mbps(maxrate); | ifp->if_baudrate = IF_Mbps(maxrate); | ||||
ether_ifattach(ifp, vap->iv_myaddr); | ether_ifattach(ifp, macaddr); | ||||
vap->iv_myaddr = IF_LLADDR(ifp); | |||||
/* hook output method setup by ether_ifattach */ | /* hook output method setup by ether_ifattach */ | ||||
vap->iv_output = ifp->if_output; | vap->iv_output = ifp->if_output; | ||||
ifp->if_output = ieee80211_output; | ifp->if_output = ieee80211_output; | ||||
/* NB: if_mtu set by ether_ifattach to ETHERMTU */ | /* NB: if_mtu set by ether_ifattach to ETHERMTU */ | ||||
IEEE80211_LOCK(ic); | IEEE80211_LOCK(ic); | ||||
TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next); | TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next); | ||||
ieee80211_syncflag_locked(ic, IEEE80211_F_WME); | ieee80211_syncflag_locked(ic, IEEE80211_F_WME); | ||||
#ifdef IEEE80211_SUPPORT_SUPERG | #ifdef IEEE80211_SUPPORT_SUPERG | ||||
ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP); | ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP); | ||||
#endif | #endif | ||||
ieee80211_syncflag_locked(ic, IEEE80211_F_PCF); | ieee80211_syncflag_locked(ic, IEEE80211_F_PCF); | ||||
ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); | ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); | ||||
ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); | ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); | ||||
ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); | ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); | ||||
ieee80211_syncifflag_locked(ic, IFF_PROMISC); | |||||
ieee80211_syncifflag_locked(ic, IFF_ALLMULTI); | |||||
IEEE80211_UNLOCK(ic); | IEEE80211_UNLOCK(ic); | ||||
return 1; | return 1; | ||||
} | } | ||||
/* | /* | ||||
* Tear down vap state and reclaim the ifnet. | * Tear down vap state and reclaim the ifnet. | ||||
* The driver is assumed to have prepared for | * The driver is assumed to have prepared for | ||||
Show All 33 Lines | #ifdef IEEE80211_SUPPORT_SUPERG | ||||
ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP); | ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP); | ||||
#endif | #endif | ||||
ieee80211_syncflag_locked(ic, IEEE80211_F_PCF); | ieee80211_syncflag_locked(ic, IEEE80211_F_PCF); | ||||
ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); | ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); | ||||
ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); | ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); | ||||
ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); | ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); | ||||
/* NB: this handles the bpfdetach done below */ | /* NB: this handles the bpfdetach done below */ | ||||
ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_BPF); | ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_BPF); | ||||
ieee80211_syncifflag_locked(ic, IFF_PROMISC); | if (vap->iv_ifflags & IFF_PROMISC) | ||||
ieee80211_syncifflag_locked(ic, IFF_ALLMULTI); | ieee80211_promisc(vap, false); | ||||
if (vap->iv_ifflags & IFF_ALLMULTI) | |||||
ieee80211_allmulti(vap, false); | |||||
IEEE80211_UNLOCK(ic); | IEEE80211_UNLOCK(ic); | ||||
ifmedia_removeall(&vap->iv_media); | ifmedia_removeall(&vap->iv_media); | ||||
ieee80211_radiotap_vdetach(vap); | ieee80211_radiotap_vdetach(vap); | ||||
ieee80211_regdomain_vdetach(vap); | ieee80211_regdomain_vdetach(vap); | ||||
ieee80211_scan_vdetach(vap); | ieee80211_scan_vdetach(vap); | ||||
#ifdef IEEE80211_SUPPORT_SUPERG | #ifdef IEEE80211_SUPPORT_SUPERG | ||||
ieee80211_superg_vdetach(vap); | ieee80211_superg_vdetach(vap); | ||||
#endif | #endif | ||||
ieee80211_ht_vdetach(vap); | ieee80211_ht_vdetach(vap); | ||||
/* NB: must be before ieee80211_node_vdetach */ | /* NB: must be before ieee80211_node_vdetach */ | ||||
ieee80211_proto_vdetach(vap); | ieee80211_proto_vdetach(vap); | ||||
ieee80211_crypto_vdetach(vap); | ieee80211_crypto_vdetach(vap); | ||||
ieee80211_power_vdetach(vap); | ieee80211_power_vdetach(vap); | ||||
ieee80211_node_vdetach(vap); | ieee80211_node_vdetach(vap); | ||||
ieee80211_sysctl_vdetach(vap); | ieee80211_sysctl_vdetach(vap); | ||||
if_free(ifp); | if_free(ifp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
/* | /* | ||||
* Synchronize flag bit state in the parent ifnet structure | * Count number of vaps in promisc, and issue promisc on | ||||
* according to the state of all vap ifnet's. This is used, | * parent respectively. | ||||
* for example, to handle IFF_PROMISC and IFF_ALLMULTI. | |||||
*/ | */ | ||||
void | void | ||||
ieee80211_syncifflag_locked(struct ieee80211com *ic, int flag) | ieee80211_promisc(struct ieee80211vap *vap, bool on) | ||||
{ | { | ||||
struct ifnet *ifp = ic->ic_ifp; | struct ieee80211com *ic = vap->iv_ic; | ||||
struct ieee80211vap *vap; | |||||
int bit, oflags; | |||||
IEEE80211_LOCK_ASSERT(ic); | |||||
bit = 0; | |||||
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) | |||||
if (vap->iv_ifp->if_flags & flag) { | |||||
/* | /* | ||||
* XXX the bridge sets PROMISC but we don't want to | * XXX the bridge sets PROMISC but we don't want to | ||||
* enable it on the device, discard here so all the | * enable it on the device, discard here so all the | ||||
* drivers don't need to special-case it | * drivers don't need to special-case it | ||||
*/ | */ | ||||
if (flag == IFF_PROMISC && | if (!(vap->iv_opmode == IEEE80211_M_MONITOR || | ||||
!(vap->iv_opmode == IEEE80211_M_MONITOR || | |||||
(vap->iv_opmode == IEEE80211_M_AHDEMO && | (vap->iv_opmode == IEEE80211_M_AHDEMO && | ||||
(vap->iv_caps & IEEE80211_C_TDMA) == 0))) | (vap->iv_caps & IEEE80211_C_TDMA) == 0))) | ||||
continue; | return; | ||||
bit = 1; | |||||
break; | IEEE80211_LOCK(ic); | ||||
} | if (on) { | ||||
oflags = ifp->if_flags; | if (++ic->ic_promisc == 1) | ||||
avos: here | |||||
Not Done Inline ActionsYep, good catch. Thanks! glebius: Yep, good catch. Thanks! | |||||
if (bit) | |||||
ifp->if_flags |= flag; | |||||
else | |||||
ifp->if_flags &= ~flag; | |||||
if ((ifp->if_flags ^ oflags) & flag) { | |||||
/* XXX should we return 1/0 and let caller do this? */ | |||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | |||||
if (flag == IFF_PROMISC) | |||||
ieee80211_runtask(ic, &ic->ic_promisc_task); | ieee80211_runtask(ic, &ic->ic_promisc_task); | ||||
else if (flag == IFF_ALLMULTI) | } else { | ||||
ieee80211_runtask(ic, &ic->ic_mcast_task); | KASSERT(ic->ic_promisc > 0, ("%s: ic %p not promisc", | ||||
__func__, ic)); | |||||
if (--ic->ic_promisc == 0) | |||||
Done Inline Actionshere avos: here | |||||
ieee80211_runtask(ic, &ic->ic_promisc_task); | |||||
} | } | ||||
IEEE80211_UNLOCK(ic); | |||||
} | } | ||||
/* | |||||
* Count number of vaps in allmulti, and issue allmulti on | |||||
* parent respectively. | |||||
*/ | |||||
void | |||||
ieee80211_allmulti(struct ieee80211vap *vap, bool on) | |||||
{ | |||||
struct ieee80211com *ic = vap->iv_ic; | |||||
IEEE80211_LOCK(ic); | |||||
if (on) { | |||||
if (++ic->ic_allmulti == 1) | |||||
Done Inline Actionshere avos: here | |||||
ieee80211_runtask(ic, &ic->ic_mcast_task); | |||||
} else { | |||||
KASSERT(ic->ic_allmulti > 0, ("%s: ic %p not allmulti", | |||||
__func__, ic)); | |||||
if (--ic->ic_allmulti == 0) | |||||
Done Inline Actionsand here avos: and here | |||||
ieee80211_runtask(ic, &ic->ic_mcast_task); | |||||
} | } | ||||
IEEE80211_UNLOCK(ic); | |||||
} | |||||
/* | /* | ||||
* Synchronize flag bit state in the com structure | * Synchronize flag bit state in the com structure | ||||
* according to the state of all vap's. This is used, | * according to the state of all vap's. This is used, | ||||
* for example, to handle state changes via ioctls. | * for example, to handle state changes via ioctls. | ||||
*/ | */ | ||||
static void | static void | ||||
ieee80211_syncflag_locked(struct ieee80211com *ic, int flag) | ieee80211_syncflag_locked(struct ieee80211com *ic, int flag) | ||||
▲ Show 20 Lines • Show All 471 Lines • ▼ Show 20 Lines | if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) || | ||||
else | else | ||||
rate = ieee80211_htrates[i].ht20_rate_800ns; | rate = ieee80211_htrates[i].ht20_rate_800ns; | ||||
if (rate > maxrate) | if (rate > maxrate) | ||||
maxrate = rate; | maxrate = rate; | ||||
} | } | ||||
return maxrate; | return maxrate; | ||||
} | } | ||||
void | |||||
ieee80211_media_init(struct ieee80211com *ic) | |||||
{ | |||||
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 | IFM_IEEE80211_TURBO)); | |||||
if (maxrate) | |||||
ifp->if_baudrate = IF_Mbps(maxrate); | |||||
/* XXX need to propagate new media settings to vap's */ | |||||
} | |||||
/* XXX inline or eliminate? */ | /* XXX inline or eliminate? */ | ||||
const struct ieee80211_rateset * | const struct ieee80211_rateset * | ||||
ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c) | ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c) | ||||
{ | { | ||||
/* XXX does this work for 11ng basic rates? */ | /* XXX does this work for 11ng basic rates? */ | ||||
return &ic->ic_sup_rates[ieee80211_chan2mode(c)]; | return &ic->ic_sup_rates[ieee80211_chan2mode(c)]; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | if (ime->ifm_media & IFM_IEEE80211_TURBO) { | ||||
else | else | ||||
return 0; | return 0; | ||||
} | } | ||||
/* XXX HT40 +/- */ | /* XXX HT40 +/- */ | ||||
return 1; | return 1; | ||||
} | } | ||||
/* | /* | ||||
* Handle a media change request on the underlying interface. | |||||
*/ | |||||
int | |||||
ieee80211com_media_change(struct ifnet *ifp) | |||||
{ | |||||
return EINVAL; | |||||
} | |||||
/* | |||||
* Handle a media change request on the vap interface. | * Handle a media change request on the vap interface. | ||||
*/ | */ | ||||
int | int | ||||
ieee80211_media_change(struct ifnet *ifp) | ieee80211_media_change(struct ifnet *ifp) | ||||
{ | { | ||||
struct ieee80211vap *vap = ifp->if_softc; | struct ieee80211vap *vap = ifp->if_softc; | ||||
struct ifmedia_entry *ime = vap->iv_media.ifm_cur; | struct ifmedia_entry *ime = vap->iv_media.ifm_cur; | ||||
uint16_t newmode; | uint16_t newmode; | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | if (IEEE80211_IS_CHAN_TURBO(chan)) | ||||
status |= IFM_IEEE80211_TURBO; | status |= IFM_IEEE80211_TURBO; | ||||
#if 0 | #if 0 | ||||
if (IEEE80211_IS_CHAN_HT20(chan)) | if (IEEE80211_IS_CHAN_HT20(chan)) | ||||
status |= IFM_IEEE80211_HT20; | status |= IFM_IEEE80211_HT20; | ||||
if (IEEE80211_IS_CHAN_HT40(chan)) | if (IEEE80211_IS_CHAN_HT40(chan)) | ||||
status |= IFM_IEEE80211_HT40; | status |= IFM_IEEE80211_HT40; | ||||
#endif | #endif | ||||
return status; | return status; | ||||
} | |||||
static void | |||||
ieee80211com_media_status(struct ifnet *ifp, struct ifmediareq *imr) | |||||
{ | |||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
struct ieee80211vap *vap; | |||||
imr->ifm_status = IFM_AVALID; | |||||
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) | |||||
if (vap->iv_ifp->if_flags & IFF_UP) { | |||||
imr->ifm_status |= IFM_ACTIVE; | |||||
break; | |||||
} | |||||
imr->ifm_active = media_status(ic->ic_opmode, ic->ic_curchan); | |||||
if (imr->ifm_status & IFM_ACTIVE) | |||||
imr->ifm_current = imr->ifm_active; | |||||
} | } | ||||
void | void | ||||
ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) | ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) | ||||
{ | { | ||||
struct ieee80211vap *vap = ifp->if_softc; | struct ieee80211vap *vap = ifp->if_softc; | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
enum ieee80211_phymode mode; | enum ieee80211_phymode mode; | ||||
▲ Show 20 Lines • Show All 372 Lines • Show Last 20 Lines |
here