* Add wlan_global_serializer and wlan_*() API calls.
* Use the calls at all border crossings.
* NOTE: callout_stop() may still have deadlock issues if it catches a
callout in-progress.
--- /dev/null
+
+ README.DRAGONFLY
+
+ All ABI entry points into the wlan infrastructure must acquire the
+ wlan_global_serializer. Normally all wireless base drivers also
+ use this serializer to avoid deadlocks.
+
+modevent ieee80211_dragonfly.h
+ search for DECLARE_MODULE
+
+sysctl search for SYSCTL_HANDLER_ARGS
+
+eventhandler search for EVENTHANDLER_REGISTER
+
+taskq search for TASK_INIT
+
+callout search for callout_reset
+
+ search for callout_stop to deal with
+ potential deadlock issues
+
+ifnet wlan/ieee80211.c
+
+ Set if_serializer to &wlan_global_serializer. There are
+ a few places where if_ioctl is set to NULL and then later
+ restored. It is unclear why this is being done.
+
+ifnet, interrupt, devmethod, copyin/copyout
+
+ieee80211_ioctl()
+
+ This is called directly from the wlan's ifp->if_ioctl and
+ also from various wireless drivers. This function expects
+ the serializer to already be acquired.
+
+ The kernel will acquire if_serializer when making
+ ifp->if_ioctl() calls.
wlan_##name##_modevent(module_t mod, int type, void *unused) \
{ \
policy##_setup * const *iter, f; \
+ int error; \
+ \
+ wlan_serialize_enter(); \
+ \
switch (type) { \
case MOD_LOAD: \
SET_FOREACH(iter, policy##_set) { \
f = (void*) *iter; \
f(type); \
} \
- return 0; \
+ error = 0; \
+ break; \
case MOD_UNLOAD: \
if (nrefs) { \
- kprintf("wlan_##name: still in use (%u dynamic refs)\n",\
+ kprintf("wlan_##name: still in use (%u " \
+ "dynamic refs)\n", \
nrefs); \
return EBUSY; \
} \
f(type); \
} \
} \
- return 0; \
+ error = 0; \
+ break; \
+ default: \
+ error = EINVAL; \
+ break; \
} \
- return EINVAL; \
+ \
+ wlan_serialize_exit(); \
+ \
+ return error; \
} \
static moduledata_t name##_mod = { \
"wlan_" #name, \
static void \
name##_modevent(int type) \
{ \
+ wlan_serialize_enter(); \
if (type == MOD_LOAD) \
ieee80211_crypto_register(&name); \
else \
ieee80211_crypto_unregister(&name); \
+ wlan_serialize_exit(); \
} \
TEXT_SET(crypto##_set, name##_modevent)
static void \
name##_modevent(int type) \
{ \
+ wlan_serialize_enter(); \
if (type == MOD_LOAD) \
ieee80211_scanner_register(alg, &v); \
else \
ieee80211_scanner_unregister(alg, &v); \
+ wlan_serialize_exit(); \
} \
TEXT_SET(scanner_set, name##_modevent); \
static void \
alg##_modevent(int type) \
{ \
+ wlan_serialize_enter(); \
if (type == MOD_LOAD) \
ieee80211_aclator_register(&alg); \
else \
ieee80211_aclator_unregister(&alg); \
+ wlan_serialize_exit(); \
} \
TEXT_SET(acl_set, alg##_modevent); \
static void \
name##_modevent(int type) \
{ \
+ wlan_serialize_enter(); \
if (type == MOD_LOAD) \
ieee80211_authenticator_register(alg, &v); \
else \
ieee80211_authenticator_unregister(alg); \
+ wlan_serialize_exit(); \
} \
TEXT_SET(auth_set, name##_modevent)
static void \
alg##_modevent(int type) \
{ \
+ wlan_serialize_enter(); \
if (type == MOD_LOAD) \
ieee80211_ratectl_register(alg, &v); \
else \
ieee80211_ratectl_unregister(alg); \
+ wlan_serialize_exit(); \
} \
TEXT_SET(ratectl##_set, alg##_modevent)
const uint8_t macaddr[IEEE80211_ADDR_LEN]);
#endif
int ieee80211_node_delucastkey(struct ieee80211_node *);
-void ieee80211_node_timeout(void *arg);
typedef void ieee80211_iter_func(void *, struct ieee80211_node *);
void ieee80211_iterate_nodes(struct ieee80211_node_table *,
void ieee80211_suspend_all(struct ieee80211com *);
void ieee80211_resume_all(struct ieee80211com *);
void ieee80211_dturbo_switch(struct ieee80211vap *, int newflags);
-void ieee80211_swbmiss(void *arg);
+void ieee80211_swbmiss_callout(void *arg);
void ieee80211_beacon_miss(struct ieee80211com *);
int ieee80211_new_state(struct ieee80211vap *, enum ieee80211_state, int);
void ieee80211_print_essid(const uint8_t *, int);
return ENOMEM;
}
if_initname(ifp, name, unit);
+ ifp->if_serializer = &wlan_global_serializer;
ifp->if_softc = vap; /* back pointer */
ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
ifp->if_start = ieee80211_start;
int error;
error = sysctl_handle_int(oidp, &msecs, 0, req);
- if (error || !req->newptr)
- return error;
- amrr_setinterval(vap, msecs);
- return 0;
+ wlan_serialize_enter();
+ if (error == 0 && req->newptr)
+ amrr_setinterval(vap, msecs);
+ wlan_serialize_exit();
+
+ return error;
}
static void
}
static void
-cac_timeout(void *arg)
+cac_timeout_callout(void *arg)
{
struct ieee80211vap *vap = arg;
- struct ieee80211com *ic = vap->iv_ic;
- struct ieee80211_dfs_state *dfs = &ic->ic_dfs;
+ struct ieee80211com *ic;
+ struct ieee80211_dfs_state *dfs;
int i;
- if (vap->iv_state != IEEE80211_S_CAC) /* NB: just in case */
+ wlan_serialize_enter();
+ ic = vap->iv_ic;
+ dfs = &ic->ic_dfs;
+ if (vap->iv_state != IEEE80211_S_CAC) { /* NB: just in case */
+ wlan_serialize_exit();
return;
+ }
/*
* When radar is detected during a CAC we are woken
* up prematurely to switch to a new channel.
IEEE80211_NOTIFY_CAC_EXPIRE);
ieee80211_cac_completeswitch(vap);
}
+ wlan_serialize_exit();
}
/*
struct ieee80211com *ic = vap->iv_ic;
struct ieee80211_dfs_state *dfs = &ic->ic_dfs;
- callout_reset(&dfs->cac_timer, CAC_TIMEOUT, cac_timeout, vap);
+ callout_reset(&dfs->cac_timer, CAC_TIMEOUT, cac_timeout_callout, vap);
if_printf(vap->iv_ifp, "start %d second CAC timer on channel %u (%u MHz)\n",
ticks_to_secs(CAC_TIMEOUT),
ic->ic_curchan->ic_ieee, ic->ic_curchan->ic_freq);
}
static void
-dfs_timeout(void *arg)
+dfs_timeout_callout(void *arg)
{
struct ieee80211com *ic = arg;
struct ieee80211_dfs_state *dfs = &ic->ic_dfs;
struct ieee80211_channel *c;
int i, oldest, now;
+ wlan_serialize_enter();
now = oldest = ticks;
for (i = 0; i < ic->ic_nchans; i++) {
c = &ic->ic_channels[i];
if (oldest != now) {
/* arrange to process next channel up for a status change */
callout_reset(&dfs->nol_timer, oldest + NOL_TIMEOUT - now,
- dfs_timeout, ic);
+ dfs_timeout_callout, ic);
}
+ wlan_serialize_exit();
}
static void
}
ieee80211_notify_radar(ic, chan);
chan->ic_state |= IEEE80211_CHANSTATE_NORADAR;
- if (!callout_pending(&dfs->nol_timer))
- callout_reset(&dfs->nol_timer, NOL_TIMEOUT, dfs_timeout, ic);
+ if (!callout_pending(&dfs->nol_timer)) {
+ callout_reset(&dfs->nol_timer, NOL_TIMEOUT,
+ dfs_timeout_callout, ic);
+ }
/*
* If radar is detected on the bss channel while
announce_radar(ic->ic_ifp, chan, dfs->newchan);
#ifdef notyet
- if (callout_pending(&dfs->cac_timer))
- callout_reset(&dfs->cac_timer, 0, cac_timeout, vap);
+ if (callout_pending(&dfs->cac_timer)) {
+ callout_reset(&dfs->cac_timer, 0,
+ cac_timeout_callout, vap);
+ }
else if (dfs->newchan != NULL) {
/* XXX mode 1, switch count 2 */
/* XXX calculate switch count based on max
if_clone_destroy(vap->iv_ifp->if_xname);
}
+/*
+ * NOTE: This handler is used generally to convert milliseconds
+ * to ticks for various simple sysctl variables and does not
+ * need to be serialized.
+ */
int
ieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS)
{
int error, t;
error = sysctl_handle_int(oidp, &msecs, 0, req);
- if (error || !req->newptr)
- return error;
- t = msecs_to_ticks(msecs);
- *(int *)arg1 = (t < 1) ? 1 : t;
- return 0;
+ if (error == 0 && req->newptr) {
+ t = msecs_to_ticks(msecs);
+ *(int *)arg1 = (t < 1) ? 1 : t;
+ }
+
+ return error;
}
static int
int error;
error = sysctl_handle_int(oidp, &inact, 0, req);
- if (error || !req->newptr)
- return error;
- *(int *)arg1 = inact / IEEE80211_INACT_WAIT;
- return 0;
+ wlan_serialize_enter();
+ if (error == 0 && req->newptr)
+ *(int *)arg1 = inact / IEEE80211_INACT_WAIT;
+ wlan_serialize_exit();
+
+ return error;
}
static int
int t = 0, error;
error = sysctl_handle_int(oidp, &t, 0, req);
- if (error || !req->newptr)
- return error;
- ieee80211_dfs_notify_radar(ic, ic->ic_curchan);
- return 0;
+ wlan_serialize_enter();
+ if (error == 0 && req->newptr)
+ ieee80211_dfs_notify_radar(ic, ic->ic_curchan);
+ wlan_serialize_exit();
+
+ return error;
}
void
bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach)
{
/* NB: identify vap's by if_start */
+
+ wlan_serialize_enter();
if (dlt == DLT_IEEE802_11_RADIO && ifp->if_start == ieee80211_start) {
struct ieee80211vap *vap = ifp->if_softc;
/*
atomic_subtract_int(&vap->iv_ic->ic_montaps, 1);
}
}
+ wlan_serialize_exit();
}
static void
struct ieee80211com *ic = ifp->if_l2com;
struct ieee80211vap *vap, *next;
- if (ifp->if_type != IFT_IEEE80211 || ic == NULL)
+ wlan_serialize_enter();
+ if (ifp->if_type != IFT_IEEE80211 || ic == NULL) {
+ wlan_serialize_exit();
return;
+ }
TAILQ_FOREACH_MUTABLE(vap, &ic->ic_vaps, iv_next, next) {
/*
wlan_serialize_enter();
}
}
+ wlan_serialize_exit();
}
/*
static int
wlan_modevent(module_t mod, int type, void *unused)
{
+ int error;
+
+ wlan_serialize_enter();
+
switch (type) {
case MOD_LOAD:
if (bootverbose)
kprintf("wlan: <802.11 Link Layer>\n");
wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track,
- bpf_track, 0, EVENTHANDLER_PRI_ANY);
- if (wlan_bpfevent == NULL)
- return ENOMEM;
+ bpf_track, 0,
+ EVENTHANDLER_PRI_ANY);
+ if (wlan_bpfevent == NULL) {
+ error = ENOMEM;
+ break;
+ }
wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event,
- wlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
+ wlan_iflladdr, NULL,
+ EVENTHANDLER_PRI_ANY);
if (wlan_ifllevent == NULL) {
EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
- return ENOMEM;
+ error = ENOMEM;
+ break;
}
if_clone_attach(&wlan_cloner);
if_register_com_alloc(IFT_IEEE80211, wlan_alloc, wlan_free);
- return 0;
+ error = 0;
+ break;
case MOD_UNLOAD:
if_deregister_com_alloc(IFT_IEEE80211);
if_clone_detach(&wlan_cloner);
EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
EVENTHANDLER_DEREGISTER(iflladdr_event, wlan_ifllevent);
- return 0;
+ error = 0;
+ break;
+ default:
+ error = EINVAL;
+ break;
}
- return EINVAL;
+ wlan_serialize_exit();
+
+ return error;
}
static moduledata_t wlan_mod = {
}
static void
-addba_timeout(void *arg)
+addba_timeout_callout(void *arg)
{
struct ieee80211_tx_ampdu *tap = arg;
+ wlan_serialize_enter();
/* XXX ? */
tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
tap->txa_attempts++;
+ wlan_serialize_exit();
}
static void
{
/* XXX use CALLOUT_PENDING instead? */
callout_reset(&tap->txa_timer, ieee80211_addba_timeout,
- addba_timeout, tap);
+ addba_timeout_callout, tap);
tap->txa_flags |= IEEE80211_AGGR_XCHGPEND;
tap->txa_nextrequest = ticks + ieee80211_addba_timeout;
}
}
static void
-bar_timeout(void *arg)
+bar_timeout_callout(void *arg)
{
struct ieee80211_tx_ampdu *tap = arg;
- struct ieee80211_node *ni = tap->txa_ni;
+ struct ieee80211_node *ni;
+ wlan_serialize_enter();
+ ni = tap->txa_ni;
KASSERT((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0,
("bar/addba collision, flags 0x%x", tap->txa_flags));
tap->txa_ac, tap->txa_flags, tap->txa_attempts);
/* guard against race with bar_tx_complete */
- if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
- return;
- /* XXX ? */
- if (tap->txa_attempts >= ieee80211_bar_maxtries)
- ieee80211_ampdu_stop(ni, tap, IEEE80211_REASON_TIMEOUT);
- else
- ieee80211_send_bar(ni, tap, tap->txa_seqpending);
+ if (tap->txa_flags & IEEE80211_AGGR_BARPEND) {
+ /* XXX ? */
+ if (tap->txa_attempts >= ieee80211_bar_maxtries)
+ ieee80211_ampdu_stop(ni, tap, IEEE80211_REASON_TIMEOUT);
+ else
+ ieee80211_send_bar(ni, tap, tap->txa_seqpending);
+ }
+ wlan_serialize_exit();
}
static void
bar_start_timer(struct ieee80211_tx_ampdu *tap)
{
- callout_reset(&tap->txa_timer, ieee80211_bar_timeout, bar_timeout, tap);
+ callout_reset(&tap->txa_timer, ieee80211_bar_timeout,
+ bar_timeout_callout, tap);
}
static void
static uint8_t * hwmp_add_meshrann(uint8_t *,
const struct ieee80211_meshrann_ie *);
static void hwmp_rootmode_setup(struct ieee80211vap *);
-static void hwmp_rootmode_cb(void *);
-static void hwmp_rootmode_rann_cb(void *);
+static void hwmp_rootmode_callout(void *);
+static void hwmp_rootmode_rann_callout(void *);
static void hwmp_recv_preq(struct ieee80211vap *, struct ieee80211_node *,
const struct ieee80211_frame *,
const struct ieee80211_meshpreq_ie *);
case IEEE80211_HWMP_ROOTMODE_NORMAL:
case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rootint,
- hwmp_rootmode_cb, vap);
+ hwmp_rootmode_callout, vap);
break;
case IEEE80211_HWMP_ROOTMODE_RANN:
callout_reset(&hs->hs_roottimer, ieee80211_hwmp_rannint,
- hwmp_rootmode_rann_cb, vap);
+ hwmp_rootmode_rann_callout, vap);
break;
}
}
#define PREQ_TADDR(n) preq.preq_targets[n].target_addr
#define PREQ_TSEQ(n) preq.preq_targets[n].target_seq
static void
-hwmp_rootmode_cb(void *arg)
+hwmp_rootmode_callout(void *arg)
{
struct ieee80211vap *vap = (struct ieee80211vap *)arg;
- struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
- struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct ieee80211_hwmp_state *hs;
+ struct ieee80211_mesh_state *ms;
struct ieee80211_meshpreq_ie preq;
+ wlan_serialize_enter();
+ hs = vap->iv_hwmp;
+ ms = vap->iv_mesh;
+
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
"%s", "send broadcast PREQ");
vap->iv_stats.is_hwmp_rootreqs++;
hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq);
hwmp_rootmode_setup(vap);
+ wlan_serialize_exit();
}
#undef PREQ_TFLAGS
#undef PREQ_TADDR
* called when the vap is configured as a HWMP RANN root node.
*/
static void
-hwmp_rootmode_rann_cb(void *arg)
+hwmp_rootmode_rann_callout(void *arg)
{
struct ieee80211vap *vap = (struct ieee80211vap *)arg;
- struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
- struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct ieee80211_hwmp_state *hs;
+ struct ieee80211_mesh_state *ms;
struct ieee80211_meshrann_ie rann;
+ wlan_serialize_enter();
+ hs = vap->iv_hwmp;
+ ms = vap->iv_mesh;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
"%s", "send broadcast RANN");
vap->iv_stats.is_hwmp_rootrann++;
hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &rann);
hwmp_rootmode_setup(vap);
+ wlan_serialize_exit();
}
#define PREQ_TFLAGS(n) preq->preq_targets[n].target_flags
static int mesh_select_proto_metric(struct ieee80211vap *, const char *);
static void mesh_vattach(struct ieee80211vap *);
static int mesh_newstate(struct ieee80211vap *, enum ieee80211_state, int);
-static void mesh_rt_cleanup_cb(void *);
+static void mesh_rt_cleanup_callout(void *);
static void mesh_linkchange(struct ieee80211_node *,
enum ieee80211_mesh_mlstate);
static void mesh_checkid(void *, struct ieee80211_node *);
int, int);
static void mesh_peer_timeout_setup(struct ieee80211_node *);
static void mesh_peer_timeout_backoff(struct ieee80211_node *);
-static void mesh_peer_timeout_cb(void *);
+static void mesh_peer_timeout_callout(void *);
static __inline void
mesh_peer_timeout_stop(struct ieee80211_node *);
static int mesh_verify_meshid(struct ieee80211vap *, const uint8_t *);
}
ieee80211_node_authorize(vap->iv_bss);
callout_reset(&ms->ms_cleantimer, ms->ms_ppath->mpp_inact,
- mesh_rt_cleanup_cb, vap);
+ mesh_rt_cleanup_callout, vap);
break;
default:
break;
}
static void
-mesh_rt_cleanup_cb(void *arg)
+mesh_rt_cleanup_callout(void *arg)
{
struct ieee80211vap *vap = arg;
struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ wlan_serialize_enter();
mesh_rt_flush_invalid(vap);
callout_reset(&ms->ms_cleantimer, ms->ms_ppath->mpp_inact,
- mesh_rt_cleanup_cb, vap);
+ mesh_rt_cleanup_callout, vap);
+ wlan_serialize_exit();
}
ni->ni_mltval = ieee80211_mesh_retrytimeout;
break;
}
- if (ni->ni_mltval)
+ if (ni->ni_mltval) {
callout_reset(&ni->ni_mltimer, ni->ni_mltval,
- mesh_peer_timeout_cb, ni);
+ mesh_peer_timeout_callout, ni);
+ }
}
/*
r = karc4random();
ni->ni_mltval += r % ni->ni_mltval;
- callout_reset(&ni->ni_mltimer, ni->ni_mltval, mesh_peer_timeout_cb,
- ni);
+ callout_reset(&ni->ni_mltimer, ni->ni_mltval,
+ mesh_peer_timeout_callout, ni);
}
static __inline void
* Mesh Peer Link Management FSM timeout handling.
*/
static void
-mesh_peer_timeout_cb(void *arg)
+mesh_peer_timeout_callout(void *arg)
{
struct ieee80211_node *ni = (struct ieee80211_node *)arg;
uint16_t args[3];
+ wlan_serialize_enter();
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_MESH,
ni, "mesh link timeout, state %d, retry counter %d",
ni->ni_mlstate, ni->ni_mlrcnt);
mesh_linkchange(ni, IEEE80211_NODE_MESH_IDLE);
break;
}
+ wlan_serialize_exit();
}
static int
static void node_getsignal(const struct ieee80211_node *, int8_t *, int8_t *);
static void node_getmimoinfo(const struct ieee80211_node *,
struct ieee80211_mimo_info *);
+static void ieee80211_node_timeout_callout(void *arg);
static void _ieee80211_free_node(struct ieee80211_node *);
IEEE80211_INACT_INIT, ic->ic_max_keyix);
callout_init_mp(&ic->ic_inact);
callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
- ieee80211_node_timeout, ic);
+ ieee80211_node_timeout_callout, ic);
ic->ic_node_alloc = node_alloc;
ic->ic_node_free = node_free;
/*
* Per-ieee80211com inactivity timer callback.
*/
-void
-ieee80211_node_timeout(void *arg)
+static void
+ieee80211_node_timeout_callout(void *arg)
{
struct ieee80211com *ic = arg;
* idle counters) but this should be ok unless the CSA is
* active for an unusually long time.
*/
+ wlan_serialize_enter();
if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) {
ieee80211_scan_timeout(ic);
ieee80211_timeout_stations(ic);
ieee80211_ht_timeout(ic);
}
callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
- ieee80211_node_timeout, ic);
+ ieee80211_node_timeout_callout, ic);
+ wlan_serialize_exit();
}
void
}
static void
-ieee80211_tx_mgt_timeout(void *arg)
+ieee80211_tx_mgt_timeout_callout(void *arg)
{
struct ieee80211_node *ni = arg;
- struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211vap *vap;
+ wlan_serialize_enter();
+ vap = ni->ni_vap;
if (vap->iv_state != IEEE80211_S_INIT &&
(vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) {
/*
ieee80211_new_state(vap, IEEE80211_S_SCAN,
IEEE80211_SCAN_FAIL_TIMEOUT);
}
+ wlan_serialize_exit();
}
static void
if (vap->iv_state == ostate)
callout_reset(&vap->iv_mgtsend,
status == 0 ? IEEE80211_TRANS_WAIT*hz : 0,
- ieee80211_tx_mgt_timeout, ni);
+ ieee80211_tx_mgt_timeout_callout, ni);
}
static void
"WME_UPSD",
};
-static void beacon_miss(void *, int);
-static void beacon_swmiss(void *, int);
-static void parent_updown(void *, int);
-static void update_mcast(void *, int);
-static void update_promisc(void *, int);
-static void update_channel(void *, int);
-static void ieee80211_newstate_cb(void *, int);
+static void beacon_miss_task(void *, int);
+static void beacon_swmiss_task(void *, int);
+static void parent_updown_task(void *, int);
+static void update_mcast_task(void *, int);
+static void update_promisc_task(void *, int);
+static void update_channel_task(void *, int);
+static void ieee80211_newstate_task(void *, int);
static int ieee80211_new_state_locked(struct ieee80211vap *,
enum ieee80211_state, int);
}
ic->ic_protmode = IEEE80211_PROT_CTSONLY;
- TASK_INIT(&ic->ic_parent_task, 0, parent_updown, ifp);
- TASK_INIT(&ic->ic_mcast_task, 0, update_mcast, ic);
- TASK_INIT(&ic->ic_promisc_task, 0, update_promisc, ic);
- TASK_INIT(&ic->ic_chan_task, 0, update_channel, ic);
- TASK_INIT(&ic->ic_bmiss_task, 0, beacon_miss, ic);
+ TASK_INIT(&ic->ic_parent_task, 0, parent_updown_task, ifp);
+ TASK_INIT(&ic->ic_mcast_task, 0, update_mcast_task, ic);
+ TASK_INIT(&ic->ic_promisc_task, 0, update_promisc_task, ic);
+ TASK_INIT(&ic->ic_chan_task, 0, update_channel_task, ic);
+ TASK_INIT(&ic->ic_bmiss_task, 0, beacon_miss_task, ic);
ic->ic_wme.wme_hipri_switch_hysteresis =
AGGRESSIVE_MODE_SWITCH_HYSTERESIS;
vap->iv_bmiss_max = IEEE80211_BMISS_MAX;
callout_init_mp(&vap->iv_swbmiss);
callout_init_mp(&vap->iv_mgtsend);
- TASK_INIT(&vap->iv_nstate_task, 0, ieee80211_newstate_cb, vap);
- TASK_INIT(&vap->iv_swbmiss_task, 0, beacon_swmiss, vap);
+ TASK_INIT(&vap->iv_nstate_task, 0, ieee80211_newstate_task, vap);
+ TASK_INIT(&vap->iv_swbmiss_task, 0, beacon_swmiss_task, vap);
/*
* Install default tx rate handling: no fixed rate, lowest
* supported rate for mgmt and multicast frames. Default
}
static void
-parent_updown(void *arg, int npending)
+parent_updown_task(void *arg, int npending)
{
struct ifnet *parent = arg;
+ wlan_serialize_enter();
parent->if_ioctl(parent, SIOCSIFFLAGS, NULL, curthread->td_ucred);
+ wlan_serialize_exit();
}
static void
-update_mcast(void *arg, int npending)
+update_mcast_task(void *arg, int npending)
{
struct ieee80211com *ic = arg;
struct ifnet *parent = ic->ic_ifp;
+ wlan_serialize_enter();
ic->ic_update_mcast(parent);
+ wlan_serialize_exit();
}
static void
-update_promisc(void *arg, int npending)
+update_promisc_task(void *arg, int npending)
{
struct ieee80211com *ic = arg;
struct ifnet *parent = ic->ic_ifp;
+ wlan_serialize_enter();
ic->ic_update_promisc(parent);
+ wlan_serialize_exit();
}
static void
-update_channel(void *arg, int npending)
+update_channel_task(void *arg, int npending)
{
struct ieee80211com *ic = arg;
+ wlan_serialize_enter();
ic->ic_set_channel(ic);
ieee80211_radiotap_chan_change(ic);
+ wlan_serialize_exit();
}
/*
void
ieee80211_waitfor_parent(struct ieee80211com *ic)
{
+ wlan_serialize_exit();
taskqueue_block(ic->ic_tq);
ieee80211_draintask(ic, &ic->ic_parent_task);
ieee80211_draintask(ic, &ic->ic_mcast_task);
ieee80211_draintask(ic, &ic->ic_chan_task);
ieee80211_draintask(ic, &ic->ic_bmiss_task);
taskqueue_unblock(ic->ic_tq);
+ wlan_serialize_enter();
}
/*
}
static void
-beacon_miss(void *arg, int npending)
+beacon_miss_task(void *arg, int npending)
{
struct ieee80211com *ic = arg;
struct ieee80211vap *vap;
- /* XXX locking */
+ wlan_serialize_enter();
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
/*
* We only pass events through for sta vap's in RUN state;
vap->iv_bmiss != NULL)
vap->iv_bmiss(vap);
}
+ wlan_serialize_exit();
}
static void
-beacon_swmiss(void *arg, int npending)
+beacon_swmiss_task(void *arg, int npending)
{
struct ieee80211vap *vap = arg;
- if (vap->iv_state != IEEE80211_S_RUN)
- return;
-
- /* XXX Call multiple times if npending > zero? */
- vap->iv_bmiss(vap);
+ wlan_serialize_enter();
+ if (vap->iv_state == IEEE80211_S_RUN) {
+ /* XXX Call multiple times if npending > zero? */
+ vap->iv_bmiss(vap);
+ }
+ wlan_serialize_exit();
}
/*
* beacon miss; otherwise reset the counter.
*/
void
-ieee80211_swbmiss(void *arg)
+ieee80211_swbmiss_callout(void *arg)
{
struct ieee80211vap *vap = arg;
struct ieee80211com *ic = vap->iv_ic;
- /* XXX sleep state? */
+ wlan_serialize_enter();
KASSERT(vap->iv_state == IEEE80211_S_RUN,
("wrong state %d", vap->iv_state));
if (vap->iv_bmiss != NULL)
ieee80211_runtask(ic, &vap->iv_swbmiss_task);
if (vap->iv_bmiss_count == 0) /* don't re-arm timer */
- return;
- } else
+ goto done;
+ } else {
vap->iv_swbmiss_count = 0;
+ }
callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
- ieee80211_swbmiss, vap);
+ ieee80211_swbmiss_callout, vap);
+done:
+ wlan_serialize_exit();
}
/*
* Handle post state change work common to all operating modes.
*/
static void
-ieee80211_newstate_cb(void *xvap, int npending)
+ieee80211_newstate_task(void *xvap, int npending)
{
struct ieee80211vap *vap = xvap;
- struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211com *ic;
enum ieee80211_state nstate, ostate;
int arg, rc;
+ wlan_serialize_enter();
+
+ ic = vap->iv_ic;
nstate = vap->iv_nstate;
arg = vap->iv_nstate_arg;
ieee80211_flush_ifq((struct ifqueue *)&ic->ic_ifp->if_snd, vap);
}
done:
- ;
+ wlan_serialize_exit();
}
/*
int error;
error = sysctl_handle_int(oidp, &msecs, 0, req);
- if (error || !req->newptr)
- return error;
- rssadapt_setinterval(vap, msecs);
- return 0;
+ wlan_serialize_enter();
+ if (error == 0 && req->newptr)
+ rssadapt_setinterval(vap, msecs);
+ wlan_serialize_exit();
+
+ return error;
}
static void
static void scan_curchan(struct ieee80211_scan_state *, unsigned long);
static void scan_mindwell(struct ieee80211_scan_state *);
-static void scan_signal(void *);
+static void scan_signal_callout(void *);
+static void scan_signal(struct ieee80211_scan_state *ss);
static void scan_task(void *, int);
MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state");
if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
ieee80211_probe_curchan(vap, 0);
callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer,
- maxdwell, scan_signal, ss);
+ maxdwell, scan_signal_callout, ss);
}
static void
-scan_signal(void *arg)
+scan_signal_callout(void *arg)
{
struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;
+ wlan_serialize_enter();
+ scan_signal(ss);
+ wlan_serialize_exit();
+}
+
+static void
+scan_signal(struct ieee80211_scan_state *ss)
+{
wlan_cv_signal(&SCAN_PRIVATE(ss)->ss_scan_cv, 0);
}
{
#define ISCAN_REP (ISCAN_MINDWELL | ISCAN_DISCARD)
struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;
- struct ieee80211vap *vap = ss->ss_vap;
- struct ieee80211com *ic = ss->ss_ic;
+ struct ieee80211vap *vap;
+ struct ieee80211com *ic;
struct ieee80211_channel *chan;
unsigned long maxdwell, scanend;
int scandone = 0;
+ wlan_serialize_enter();
+ vap = ss->ss_vap;
+ ic = ss->ss_ic;
+
if (vap == NULL || (ic->ic_flags & IEEE80211_F_SCAN) == 0 ||
(SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)) {
/* Cancelled before we started */
}
SCAN_PRIVATE(ss)->ss_iflags &= ~(ISCAN_CANCEL|ISCAN_ABORT);
ss->ss_flags &= ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST);
+ wlan_serialize_exit();
#undef ISCAN_REP
}
2 * vap->iv_bmissthreshold * ni->ni_intval);
vap->iv_swbmiss_count = 0;
callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
- ieee80211_swbmiss, vap);
+ ieee80211_swbmiss_callout, vap);
}
/*
* When 802.1x is not in use mark the port authorized
((ts->tdma_slotcnt * ts->tdma_slotlen) / 1024));
vap->iv_swbmiss_count = 0;
callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
- ieee80211_swbmiss, vap);
+ ieee80211_swbmiss_callout, vap);
}
return status;
}