diff options
Diffstat (limited to 'sys/net80211/ieee80211_proto.c')
-rw-r--r-- | sys/net80211/ieee80211_proto.c | 76 |
1 files changed, 56 insertions, 20 deletions
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index 01c60e1..cbcf6b1 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -122,23 +122,23 @@ null_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, void ieee80211_proto_attach(struct ieee80211com *ic) { - struct ifnet *ifp = ic->ic_ifp; + uint8_t hdrlen; /* override the 802.3 setting */ - ifp->if_hdrlen = ic->ic_headroom + 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) { + if (ALIGN(hdrlen) > max_linkhdr) { /* XXX sanity check... */ - max_linkhdr = ALIGN(ifp->if_hdrlen); + max_linkhdr = ALIGN(hdrlen); max_hdr = max_linkhdr + max_protohdr; max_datalen = MHLEN - max_hdr; } ic->ic_protmode = IEEE80211_PROT_CTSONLY; - TASK_INIT(&ic->ic_parent_task, 0, parent_updown, ifp); + TASK_INIT(&ic->ic_parent_task, 0, parent_updown, ic); 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); @@ -188,7 +188,10 @@ ieee80211_proto_vattach(struct ieee80211vap *vap) int i; /* override the 802.3 setting */ - ifp->if_hdrlen = ic->ic_ifp->if_hdrlen; + ifp->if_hdrlen = ic->ic_headroom + + sizeof(struct ieee80211_qosframe_addr4) + + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + + IEEE80211_WEP_EXTIVLEN; vap->iv_rtsthreshold = IEEE80211_RTS_DEFAULT; vap->iv_fragthreshold = IEEE80211_FRAG_DEFAULT; @@ -1155,9 +1158,9 @@ ieee80211_wme_updateparams(struct ieee80211vap *vap) static void parent_updown(void *arg, int npending) { - struct ifnet *parent = arg; + struct ieee80211com *ic = arg; - parent->if_ioctl(parent, SIOCSIFFLAGS, NULL); + ic->ic_parent(ic); } static void @@ -1215,6 +1218,41 @@ ieee80211_waitfor_parent(struct ieee80211com *ic) } /* + * Check to see whether the current channel needs reset. + * + * Some devices don't handle being given an invalid channel + * in their operating mode very well (eg wpi(4) will throw a + * firmware exception.) + * + * Return 0 if we're ok, 1 if the channel needs to be reset. + * + * See PR kern/202502. + */ +static int +ieee80211_start_check_reset_chan(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + + if ((vap->iv_opmode == IEEE80211_M_IBSS && + IEEE80211_IS_CHAN_NOADHOC(ic->ic_curchan)) || + (vap->iv_opmode == IEEE80211_M_HOSTAP && + IEEE80211_IS_CHAN_NOHOSTAP(ic->ic_curchan))) + return (1); + return (0); +} + +/* + * Reset the curchan to a known good state. + */ +static void +ieee80211_start_reset_chan(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + + ic->ic_curchan = &ic->ic_channels[0]; +} + +/* * Start a vap running. If this is the first vap to be * set running on the underlying device then we * automatically bring the device up. @@ -1224,7 +1262,6 @@ ieee80211_start_locked(struct ieee80211vap *vap) { struct ifnet *ifp = vap->iv_ifp; struct ieee80211com *ic = vap->iv_ic; - struct ifnet *parent = ic->ic_ifp; IEEE80211_LOCK_ASSERT(ic); @@ -1246,12 +1283,15 @@ ieee80211_start_locked(struct ieee80211vap *vap) * We are not running; if this we are the first vap * to be brought up auto-up the parent if necessary. */ - if (ic->ic_nrunning++ == 0 && - (parent->if_drv_flags & IFF_DRV_RUNNING) == 0) { + if (ic->ic_nrunning++ == 0) { + + /* reset the channel to a known good channel */ + if (ieee80211_start_check_reset_chan(vap)) + ieee80211_start_reset_chan(vap); + IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, - "%s: up parent %s\n", __func__, parent->if_xname); - parent->if_flags |= IFF_UP; + "%s: up parent %s\n", __func__, ic->ic_name); ieee80211_runtask(ic, &ic->ic_parent_task); return; } @@ -1260,8 +1300,7 @@ ieee80211_start_locked(struct ieee80211vap *vap) * If the parent is up and running, then kick the * 802.11 state machine as appropriate. */ - if ((parent->if_drv_flags & IFF_DRV_RUNNING) && - vap->iv_roaming != IEEE80211_ROAMING_MANUAL) { + if (vap->iv_roaming != IEEE80211_ROAMING_MANUAL) { if (vap->iv_opmode == IEEE80211_M_STA) { #if 0 /* XXX bypasses scan too easily; disable for now */ @@ -1344,7 +1383,6 @@ ieee80211_stop_locked(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = vap->iv_ifp; - struct ifnet *parent = ic->ic_ifp; IEEE80211_LOCK_ASSERT(ic); @@ -1354,12 +1392,10 @@ ieee80211_stop_locked(struct ieee80211vap *vap) ieee80211_new_state_locked(vap, IEEE80211_S_INIT, -1); if (ifp->if_drv_flags & IFF_DRV_RUNNING) { ifp->if_drv_flags &= ~IFF_DRV_RUNNING; /* mark us stopped */ - if (--ic->ic_nrunning == 0 && - (parent->if_drv_flags & IFF_DRV_RUNNING)) { + if (--ic->ic_nrunning == 0) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, - "down parent %s\n", parent->if_xname); - parent->if_flags &= ~IFF_UP; + "down parent %s\n", ic->ic_name); ieee80211_runtask(ic, &ic->ic_parent_task); } } |