Changeset View
Changeset View
Standalone View
Standalone View
sys/net80211/ieee80211_ioctl.c
Show First 20 Lines • Show All 1,323 Lines • ▼ Show 20 Lines | domlme(void *arg, struct ieee80211_node *ni) | ||||
} | } | ||||
ieee80211_node_leave(ni); | ieee80211_node_leave(ni); | ||||
} | } | ||||
static int | static int | ||||
setmlme_dropsta(struct ieee80211vap *vap, | setmlme_dropsta(struct ieee80211vap *vap, | ||||
const uint8_t mac[IEEE80211_ADDR_LEN], struct mlmeop *mlmeop) | const uint8_t mac[IEEE80211_ADDR_LEN], struct mlmeop *mlmeop) | ||||
{ | { | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211_node_table *nt = &vap->iv_ic->ic_sta; | ||||
struct ieee80211_node_table *nt = &ic->ic_sta; | |||||
struct ieee80211_node *ni; | struct ieee80211_node *ni; | ||||
int error = 0; | int error = 0; | ||||
/* NB: the broadcast address means do 'em all */ | /* NB: the broadcast address means do 'em all */ | ||||
if (!IEEE80211_ADDR_EQ(mac, ic->ic_ifp->if_broadcastaddr)) { | if (!IEEE80211_ADDR_EQ(mac, vap->iv_ifp->if_broadcastaddr)) { | ||||
IEEE80211_NODE_LOCK(nt); | IEEE80211_NODE_LOCK(nt); | ||||
ni = ieee80211_find_node_locked(nt, mac); | ni = ieee80211_find_node_locked(nt, mac); | ||||
IEEE80211_NODE_UNLOCK(nt); | IEEE80211_NODE_UNLOCK(nt); | ||||
/* | /* | ||||
* Don't do the node update inside the node | * Don't do the node update inside the node | ||||
* table lock. This unfortunately causes LORs | * table lock. This unfortunately causes LORs | ||||
* with drivers and their TX paths. | * with drivers and their TX paths. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 1,177 Lines • ▼ Show 20 Lines | #define IEEE80211_IOC_SCAN_FLAGS \ | ||||
} | } | ||||
return 0; | return 0; | ||||
#undef IEEE80211_IOC_SCAN_FLAGS | #undef IEEE80211_IOC_SCAN_FLAGS | ||||
} | } | ||||
static __noinline int | static __noinline int | ||||
ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) | ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) | ||||
{ | { | ||||
struct ieee80211com *ic = vap->iv_ic; | |||||
struct ieee80211_scan_req sr; /* XXX off stack? */ | struct ieee80211_scan_req sr; /* XXX off stack? */ | ||||
int error; | int error; | ||||
/* NB: parent must be running */ | |||||
if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | |||||
return ENXIO; | |||||
if (ireq->i_len != sizeof(sr)) | if (ireq->i_len != sizeof(sr)) | ||||
avos: Without this check net80211 enters SCAN state even when device is not initialized (for example… | |||||
Not Done Inline ActionsThe device should check its internal RUNNING flag in the handler. glebius: The device should check its internal RUNNING flag in the handler. | |||||
return EINVAL; | return EINVAL; | ||||
error = copyin(ireq->i_data, &sr, sizeof(sr)); | error = copyin(ireq->i_data, &sr, sizeof(sr)); | ||||
if (error != 0) | if (error != 0) | ||||
return error; | return error; | ||||
return ieee80211_scanreq(vap, &sr); | return ieee80211_scanreq(vap, &sr); | ||||
} | } | ||||
static __noinline int | static __noinline int | ||||
▲ Show 20 Lines • Show All 746 Lines • ▼ Show 20 Lines | if (error == ENETRESET) { | ||||
/* XXX need to re-think AUTO handling */ | /* XXX need to re-think AUTO handling */ | ||||
if (IS_UP_AUTO(vap)) | if (IS_UP_AUTO(vap)) | ||||
ieee80211_init(vap); | ieee80211_init(vap); | ||||
error = 0; | error = 0; | ||||
} | } | ||||
return error; | return error; | ||||
} | } | ||||
/* | |||||
* Rebuild the parent's multicast address list after an add/del | |||||
* of a multicast address for a vap. We have no way to tell | |||||
* what happened above to optimize the work so we purge the entire | |||||
* list and rebuild from scratch. This is way expensive. | |||||
* Note also the half-baked workaround for if_addmulti calling | |||||
* back to the parent device; there's no way to insert mcast | |||||
* entries quietly and/or cheaply. | |||||
*/ | |||||
static void | |||||
ieee80211_ioctl_updatemulti(struct ieee80211com *ic) | |||||
{ | |||||
struct ifnet *parent = ic->ic_ifp; | |||||
struct ieee80211vap *vap; | |||||
void *ioctl; | |||||
IEEE80211_LOCK(ic); | |||||
if_delallmulti(parent); | |||||
ioctl = parent->if_ioctl; /* XXX WAR if_allmulti */ | |||||
parent->if_ioctl = NULL; | |||||
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { | |||||
struct ifnet *ifp = vap->iv_ifp; | |||||
struct ifmultiaddr *ifma; | |||||
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | |||||
if (ifma->ifma_addr->sa_family != AF_LINK) | |||||
continue; | |||||
(void) if_addmulti(parent, ifma->ifma_addr, NULL); | |||||
} | |||||
} | |||||
parent->if_ioctl = ioctl; | |||||
ieee80211_runtask(ic, &ic->ic_mcast_task); | |||||
IEEE80211_UNLOCK(ic); | |||||
} | |||||
int | int | ||||
ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | ||||
{ | { | ||||
struct ieee80211vap *vap = ifp->if_softc; | struct ieee80211vap *vap = ifp->if_softc; | ||||
struct ieee80211com *ic = vap->iv_ic; | struct ieee80211com *ic = vap->iv_ic; | ||||
int error = 0; | int error = 0; | ||||
struct ifreq *ifr; | struct ifreq *ifr; | ||||
struct ifaddr *ifa; /* XXX */ | struct ifaddr *ifa; /* XXX */ | ||||
switch (cmd) { | switch (cmd) { | ||||
case SIOCSIFFLAGS: | case SIOCSIFFLAGS: | ||||
IEEE80211_LOCK(ic); | IEEE80211_LOCK(ic); | ||||
ieee80211_syncifflag_locked(ic, IFF_PROMISC); | if ((ifp->if_flags ^ vap->iv_ifflags) & IFF_PROMISC) | ||||
ieee80211_syncifflag_locked(ic, IFF_ALLMULTI); | ieee80211_promisc(vap, ifp->if_flags & IFF_PROMISC); | ||||
if ((ifp->if_flags ^ vap->iv_ifflags) & IFF_ALLMULTI) | |||||
ieee80211_allmulti(vap, ifp->if_flags & IFF_ALLMULTI); | |||||
vap->iv_ifflags = ifp->if_flags; | |||||
if (ifp->if_flags & IFF_UP) { | if (ifp->if_flags & IFF_UP) { | ||||
/* | /* | ||||
* Bring ourself up unless we're already operational. | * Bring ourself up unless we're already operational. | ||||
* If we're the first vap and the parent is not up | * If we're the first vap and the parent is not up | ||||
* then it will automatically be brought up as a | * then it will automatically be brought up as a | ||||
* side-effect of bringing ourself up. | * side-effect of bringing ourself up. | ||||
*/ | */ | ||||
if (vap->iv_state == IEEE80211_S_INIT) | if (vap->iv_state == IEEE80211_S_INIT) | ||||
ieee80211_start_locked(vap); | ieee80211_start_locked(vap); | ||||
} else if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | ||||
/* | /* | ||||
* Stop ourself. If we are the last vap to be | * Stop ourself. If we are the last vap to be | ||||
* marked down the parent will also be taken down. | * marked down the parent will also be taken down. | ||||
*/ | */ | ||||
ieee80211_stop_locked(vap); | ieee80211_stop_locked(vap); | ||||
} | } | ||||
IEEE80211_UNLOCK(ic); | IEEE80211_UNLOCK(ic); | ||||
/* Wait for parent ioctl handler if it was queued */ | /* Wait for parent ioctl handler if it was queued */ | ||||
ieee80211_waitfor_parent(ic); | ieee80211_waitfor_parent(ic); | ||||
break; | break; | ||||
case SIOCADDMULTI: | case SIOCADDMULTI: | ||||
case SIOCDELMULTI: | case SIOCDELMULTI: | ||||
ieee80211_ioctl_updatemulti(ic); | ieee80211_runtask(ic, &ic->ic_mcast_task); | ||||
break; | break; | ||||
case SIOCSIFMEDIA: | case SIOCSIFMEDIA: | ||||
case SIOCGIFMEDIA: | case SIOCGIFMEDIA: | ||||
ifr = (struct ifreq *)data; | ifr = (struct ifreq *)data; | ||||
error = ifmedia_ioctl(ifp, ifr, &vap->iv_media, cmd); | error = ifmedia_ioctl(ifp, ifr, &vap->iv_media, cmd); | ||||
break; | break; | ||||
case SIOCG80211: | case SIOCG80211: | ||||
error = ieee80211_ioctl_get80211(vap, cmd, | error = ieee80211_ioctl_get80211(vap, cmd, | ||||
Show All 39 Lines | #endif | ||||
default: | default: | ||||
if ((ifp->if_flags & IFF_UP) == 0) { | if ((ifp->if_flags & IFF_UP) == 0) { | ||||
ifp->if_flags |= IFF_UP; | ifp->if_flags |= IFF_UP; | ||||
ifp->if_init(ifp->if_softc); | ifp->if_init(ifp->if_softc); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
break; | break; | ||||
/* Pass NDIS ioctls up to the driver */ | |||||
case SIOCGDRVSPEC: | |||||
case SIOCSDRVSPEC: | |||||
case SIOCGPRIVATE_0: { | |||||
struct ifnet *parent = vap->iv_ic->ic_ifp; | |||||
error = parent->if_ioctl(parent, cmd, data); | |||||
break; | |||||
} | |||||
default: | default: | ||||
/* | |||||
* Pass unknown ioctls first to the driver, and if it | |||||
* returns ENOTTY, then to the generic Ethernet handler. | |||||
*/ | |||||
if (ic->ic_ioctl != NULL && | |||||
(error = ic->ic_ioctl(ic, cmd, data)) != ENOTTY) | |||||
break; | |||||
error = ether_ioctl(ifp, cmd, data); | error = ether_ioctl(ifp, cmd, data); | ||||
break; | break; | ||||
} | } | ||||
return error; | return (error); | ||||
} | } |
Without this check net80211 enters SCAN state even when device is not initialized (for example, issue wlandebug scan+state and then turn device off with RF switch)