Unify all the wifi *_ioctl routines

- Limit grabbing the lock to SIOCSIFFLAGS.
 - Move ieee80211_start_all() to SIOCSIFFLAGS.
 - Remove SIOCSIFMEDIA as it is not useful.
 - Limit ether_ioctl to only SIOCGIFADDR. SIOCSIFADDR and SIOCSIFMTU have no
   affect as there is no input/output path in the vap parent.  The vap code
   will handle the reinit of the mac address changes.
 - Split off ndis_ioctl_80211 as it was getting too different to wired devices.

This fixes a copyout while locked and a lock recursion.

Reviewed by:		sam
This commit is contained in:
Andrew Thompson 2008-05-01 04:55:00 +00:00
parent a239061a54
commit 31a8c1edd8
11 changed files with 131 additions and 88 deletions

View File

@ -6277,9 +6277,9 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifreq *ifr = (struct ifreq *)data;
int error = 0;
ATH_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
ATH_LOCK(sc);
if (IS_RUNNING(ifp)) {
/*
* To avoid rescanning another access point,
@ -6301,6 +6301,7 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
ath_init(sc); /* XXX lose error */
} else
ath_stop_locked(ifp);
ATH_UNLOCK(sc);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
@ -6315,27 +6316,20 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
&sc->sc_stats.ast_rx_noise);
#endif
sc->sc_stats.ast_tx_rate = sc->sc_hwmap[sc->sc_txrate].ieeerate;
ATH_UNLOCK(sc);
/*
* NB: Drop the softc lock in case of a page fault;
* we'll accept any potential inconsisentcy in the
* statistics. The alternative is to copy the data
* to a local structure.
*/
return copyout(&sc->sc_stats,
ifr->ifr_data, sizeof (sc->sc_stats));
ifr->ifr_data, sizeof (sc->sc_stats));
#ifdef ATH_DIAGAPI
case SIOCGATHDIAG:
ATH_UNLOCK(sc);
error = ath_ioctl_diag(sc, (struct ath_diag *) ifr);
ATH_LOCK(sc);
break;
#endif
default:
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
default:
error = EINVAL;
break;
}
ATH_UNLOCK(sc);
return error;
#undef IS_RUNNING
}

View File

@ -147,6 +147,7 @@ static void ndis_starttask (device_object *, void *);
static void ndis_resettask (device_object *, void *);
static void ndis_inputtask (device_object *, void *);
static int ndis_ioctl (struct ifnet *, u_long, caddr_t);
static int ndis_ioctl_80211 (struct ifnet *, u_long, caddr_t);
static int ndis_newstate (struct ieee80211vap *, enum ieee80211_state,
int);
static int ndis_nettype_chan (uint32_t);
@ -714,6 +715,7 @@ ndis_attach(dev)
device_get_nameunit(dev));
TASK_INIT(&sc->ndis_scantask, 0, ndis_scan, sc);
ifp->if_ioctl = ndis_ioctl_80211;
ic->ic_ifp = ifp;
ic->ic_opmode = IEEE80211_M_STA;
ic->ic_phytype = IEEE80211_T_DS;
@ -2705,11 +2707,7 @@ ndis_ioctl(ifp, command, data)
caddr_t data;
{
struct ndis_softc *sc = ifp->if_softc;
struct ieee80211com *ic = ifp->if_l2com;
struct ifreq *ifr = (struct ifreq *) data;
struct ndis_oid_data oid;
struct ndis_evt evt;
void *oidbuf;
int i, error = 0;
/*NDIS_LOCK(sc);*/
@ -2751,10 +2749,7 @@ ndis_ioctl(ifp, command, data)
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
if (sc->ndis_80211)
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, command);
else
error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
break;
case SIOCSIFCAP:
ifp->if_capenable = ifr->ifr_reqcap;
@ -2764,6 +2759,46 @@ ndis_ioctl(ifp, command, data)
ifp->if_hwassist = 0;
ndis_set_offload(sc);
break;
default:
error = ether_ioctl(ifp, command, data);
break;
}
/*NDIS_UNLOCK(sc);*/
return(error);
}
static int
ndis_ioctl_80211(ifp, command, data)
struct ifnet *ifp;
u_long command;
caddr_t data;
{
struct ndis_softc *sc = ifp->if_softc;
struct ieee80211com *ic = ifp->if_l2com;
struct ifreq *ifr = (struct ifreq *) data;
struct ndis_oid_data oid;
struct ndis_evt evt;
void *oidbuf;
int error = 0;
switch(command) {
case SIOCSIFFLAGS:
/*NDIS_LOCK(sc);*/
if (ifp->if_flags & IFF_UP) {
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
ndis_init(sc);
ieee80211_start_all(ic);
}
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
ndis_stop(sc);
}
sc->ndis_if_flags = ifp->if_flags;
error = 0;
/*NDIS_UNLOCK(sc);*/
break;
case SIOCGDRVSPEC:
if ((error = priv_check(curthread, PRIV_DRIVER)))
break;
@ -2863,13 +2898,16 @@ ndis_ioctl(ifp, command, data)
NDIS_EVTINC(sc->ndis_evtcidx);
NDIS_UNLOCK(sc);
break;
default:
case SIOCGIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, command);
break;
case SIOCGIFADDR:
error = ether_ioctl(ifp, command, data);
break;
default:
error = EINVAL;
break;
}
/*NDIS_UNLOCK(sc);*/
return(error);
}

View File

@ -1847,9 +1847,9 @@ ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
int error = 0, startall = 0;
IPW_LOCK_DECL;
IPW_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
IPW_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
ipw_init_locked(sc);
@ -1859,18 +1859,20 @@ ipw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
ipw_stop_locked(sc);
}
IPW_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
break;
default:
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
default:
error = EINVAL;
break;
}
IPW_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
return error;
}

View File

@ -2052,9 +2052,9 @@ iwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
int error = 0, startall = 0;
IWI_LOCK_DECL;
IWI_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
IWI_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
iwi_init_locked(sc);
@ -2064,19 +2064,20 @@ iwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
iwi_stop_locked(sc);
}
IWI_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
break;
default:
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
default:
error = EINVAL;
break;
}
IWI_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
return error;
}

View File

@ -2365,9 +2365,9 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifreq *ifr = (struct ifreq *) data;
int error = 0, startall = 0;
IWN_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
IWN_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
iwn_init_locked(sc);
@ -2377,19 +2377,20 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
iwn_stop_locked(sc);
}
IWN_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
break;
default:
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
default:
error = EINVAL;
break;
}
IWN_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
return error;
}

View File

@ -2005,9 +2005,9 @@ rt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifreq *ifr = (struct ifreq *) data;
int error = 0, startall = 0;
RAL_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
RAL_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
rt2560_init_locked(sc);
@ -2018,19 +2018,20 @@ rt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
rt2560_stop_locked(sc);
}
RAL_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
break;
default:
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
default:
error = EINVAL;
break;
}
RAL_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
return error;
}

View File

@ -1747,9 +1747,9 @@ rt2661_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifreq *ifr = (struct ifreq *) data;
int error = 0, startall = 0;
RAL_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
RAL_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
rt2661_init_locked(sc);
@ -1760,19 +1760,20 @@ rt2661_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
rt2661_stop_locked(sc);
}
RAL_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
break;
default:
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
default:
error = EINVAL;
break;
}
RAL_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
return error;
}

View File

@ -1427,9 +1427,9 @@ rum_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifreq *ifr = (struct ifreq *) data;
int error = 0, startall = 0;
RUM_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
RUM_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
rum_init(sc);
@ -1440,18 +1440,20 @@ rum_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
rum_stop(sc);
}
RUM_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
break;
default:
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
default:
error = EINVAL;
break;
}
RUM_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
return error;
}

View File

@ -2448,9 +2448,9 @@ zyd_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifreq *ifr = (struct ifreq *) data;
int error = 0, startall = 0;
ZYD_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
ZYD_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
if ((ifp->if_flags ^ sc->sc_if_flags) &
@ -2465,19 +2465,20 @@ zyd_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
zyd_stop(sc, 1);
}
sc->sc_if_flags = ifp->if_flags;
ZYD_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
break;
default:
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
default:
error = EINVAL;
break;
}
ZYD_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
return error;
}

View File

@ -1181,9 +1181,9 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifreq *ifr = (struct ifreq *) data;
int error = 0, startall = 0;
WI_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
WI_LOCK(sc);
/*
* Can't do promisc and hostap at the same time. If all that's
* changing is the promisc flag, try to short-circuit a call to
@ -1209,19 +1209,20 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->wi_gone = 0;
}
sc->sc_if_flags = ifp->if_flags;
WI_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
break;
default:
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
default:
error = EINVAL;
break;
}
WI_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
return error;
}

View File

@ -2083,9 +2083,9 @@ wpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifreq *ifr = (struct ifreq *) data;
int error = 0, startall = 0;
WPI_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
WPI_LOCK(sc);
if ((ifp->if_flags & IFF_UP)) {
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
wpi_init_locked(sc, 0);
@ -2094,19 +2094,20 @@ wpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
} else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) ||
(sc->flags & WPI_FLAG_HW_RADIO_OFF))
wpi_stop_locked(sc);
WPI_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
break;
default:
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
default:
error = EINVAL;
break;
}
WPI_UNLOCK(sc);
if (startall)
ieee80211_start_all(ic);
return error;
}