summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net80211/ieee80211_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/net80211/ieee80211_ioctl.c')
-rw-r--r--freebsd/sys/net80211/ieee80211_ioctl.c107
1 files changed, 83 insertions, 24 deletions
diff --git a/freebsd/sys/net80211/ieee80211_ioctl.c b/freebsd/sys/net80211/ieee80211_ioctl.c
index 52712514..0396e8be 100644
--- a/freebsd/sys/net80211/ieee80211_ioctl.c
+++ b/freebsd/sys/net80211/ieee80211_ioctl.c
@@ -2206,18 +2206,6 @@ ieee80211_ioctl_setregdomain(struct ieee80211vap *vap,
}
static int
-ieee80211_ioctl_setroam(struct ieee80211vap *vap,
- const struct ieee80211req *ireq)
-{
- if (ireq->i_len != sizeof(vap->iv_roamparms))
- return EINVAL;
- /* XXX validate params */
- /* XXX? ENETRESET to push to device? */
- return copyin(ireq->i_data, vap->iv_roamparms,
- sizeof(vap->iv_roamparms));
-}
-
-static int
checkrate(const struct ieee80211_rateset *rs, int rate)
{
int i;
@@ -2247,6 +2235,73 @@ checkmcs(const struct ieee80211_htrateset *rs, int mcs)
}
static int
+ieee80211_ioctl_setroam(struct ieee80211vap *vap,
+ const struct ieee80211req *ireq)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211_roamparams_req *parms;
+ struct ieee80211_roamparam *src, *dst;
+ const struct ieee80211_htrateset *rs_ht;
+ const struct ieee80211_rateset *rs;
+ int changed, error, mode, is11n, nmodes;
+
+ if (ireq->i_len != sizeof(vap->iv_roamparms))
+ return EINVAL;
+
+ parms = IEEE80211_MALLOC(sizeof(*parms), M_TEMP,
+ IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
+ if (parms == NULL)
+ return ENOMEM;
+
+ error = copyin(ireq->i_data, parms, ireq->i_len);
+ if (error != 0)
+ goto fail;
+
+ changed = 0;
+ nmodes = IEEE80211_MODE_MAX;
+
+ /* validate parameters and check if anything changed */
+ for (mode = IEEE80211_MODE_11A; mode < nmodes; mode++) {
+ if (isclr(ic->ic_modecaps, mode))
+ continue;
+ src = &parms->params[mode];
+ dst = &vap->iv_roamparms[mode];
+ rs = &ic->ic_sup_rates[mode]; /* NB: 11n maps to legacy */
+ rs_ht = &ic->ic_sup_htrates;
+ is11n = (mode == IEEE80211_MODE_11NA ||
+ mode == IEEE80211_MODE_11NG);
+ /* XXX TODO: 11ac */
+ if (src->rate != dst->rate) {
+ if (!checkrate(rs, src->rate) &&
+ (!is11n || !checkmcs(rs_ht, src->rate))) {
+ error = EINVAL;
+ goto fail;
+ }
+ changed++;
+ }
+ if (src->rssi != dst->rssi)
+ changed++;
+ }
+ if (changed) {
+ /*
+ * Copy new parameters in place and notify the
+ * driver so it can push state to the device.
+ */
+ /* XXX locking? */
+ for (mode = IEEE80211_MODE_11A; mode < nmodes; mode++) {
+ if (isset(ic->ic_modecaps, mode))
+ vap->iv_roamparms[mode] = parms->params[mode];
+ }
+
+ if (vap->iv_roaming == IEEE80211_ROAMING_DEVICE)
+ error = ERESTART;
+ }
+
+fail: IEEE80211_FREE(parms, M_TEMP);
+ return error;
+}
+
+static int
ieee80211_ioctl_settxparams(struct ieee80211vap *vap,
const struct ieee80211req *ireq)
{
@@ -2517,20 +2572,12 @@ ieee80211_scanreq(struct ieee80211vap *vap, struct ieee80211_scan_req *sr)
sr->sr_duration > IEEE80211_IOC_SCAN_DURATION_MAX)
return EINVAL;
sr->sr_duration = msecs_to_ticks(sr->sr_duration);
- if (sr->sr_duration < 1)
- sr->sr_duration = 1;
}
/* convert min/max channel dwell */
- if (sr->sr_mindwell != 0) {
+ if (sr->sr_mindwell != 0)
sr->sr_mindwell = msecs_to_ticks(sr->sr_mindwell);
- if (sr->sr_mindwell < 1)
- sr->sr_mindwell = 1;
- }
- if (sr->sr_maxdwell != 0) {
+ if (sr->sr_maxdwell != 0)
sr->sr_maxdwell = msecs_to_ticks(sr->sr_maxdwell);
- if (sr->sr_maxdwell < 1)
- sr->sr_maxdwell = 1;
- }
/* NB: silently reduce ssid count to what is supported */
if (sr->sr_nssid > IEEE80211_SCAN_MAX_SSID)
sr->sr_nssid = IEEE80211_SCAN_MAX_SSID;
@@ -3482,10 +3529,14 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct ieee80211vap *vap = ifp->if_softc;
struct ieee80211com *ic = vap->iv_ic;
- int error = 0, wait = 0;
+ int error = 0, wait = 0, ic_used;
struct ifreq *ifr;
struct ifaddr *ifa; /* XXX */
+ ic_used = (cmd != SIOCSIFMTU && cmd != SIOCG80211STATS);
+ if (ic_used && (error = ieee80211_com_vincref(vap)) != 0)
+ return (error);
+
switch (cmd) {
case SIOCSIFFLAGS:
IEEE80211_LOCK(ic);
@@ -3539,9 +3590,13 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
/*
* Check if the MAC address was changed
* via SIOCSIFLLADDR ioctl.
+ *
+ * NB: device may be detached during initialization;
+ * use if_ioctl for existence check.
*/
if_addr_rlock(ifp);
- if ((ifp->if_flags & IFF_UP) == 0 &&
+ if (ifp->if_ioctl == ieee80211_ioctl &&
+ (ifp->if_flags & IFF_UP) == 0 &&
!IEEE80211_ADDR_EQ(vap->iv_myaddr, IF_LLADDR(ifp)))
IEEE80211_ADDR_COPY(vap->iv_myaddr,
IF_LLADDR(ifp));
@@ -3618,5 +3673,9 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = ether_ioctl(ifp, cmd, data);
break;
}
+
+ if (ic_used)
+ ieee80211_com_vdecref(vap);
+
return (error);
}