aboutsummaryrefslogtreecommitdiff
path: root/sys/net80211/ieee80211_ioctl.c
diff options
context:
space:
mode:
authorBernhard Schmidt <bschmidt@FreeBSD.org>2010-04-10 13:54:00 +0000
committerBernhard Schmidt <bschmidt@FreeBSD.org>2010-04-10 13:54:00 +0000
commit632ee7e3a4dd2287408bbc0b1e77c499d19f0a1c (patch)
tree54851ae20002dab4a38a642861b996e212912609 /sys/net80211/ieee80211_ioctl.c
parent9c251892c0a8612ee1cc6f53e5a7b89039b0f480 (diff)
downloadsrc-632ee7e3a4dd2287408bbc0b1e77c499d19f0a1c.tar.gz
src-632ee7e3a4dd2287408bbc0b1e77c499d19f0a1c.zip
Add WPA-None support:
* WPA-None requires ap_scan=2: The major difference between ap_scan=1 (default) and 2 is, that no IEEE80211_IOC_SCAN* ioctls/functions are called, though, there is a dependency on those. For example the call to wpa_driver_bsd_scan() sets the interface UP, this never happens, therefore the interface must be marked up in wpa_driver_bsd_associate(). IEEE80211_IOC_SSID also is not called, which means that the SSID has not been set prior to the IEEE80211_MLME_ASSOC call. * WPA-None has no support for sequence number updates, it doesn't make sense to check for replay violations.. * I had some crashes right after the switch to RUN state, issue is that sc->sc_lastrs was not yet defined. Approved by: rpaulo (mentor) MFC after: 3 weeks
Notes
Notes: svn path=/head/; revision=206457
Diffstat (limited to 'sys/net80211/ieee80211_ioctl.c')
-rw-r--r--sys/net80211/ieee80211_ioctl.c166
1 files changed, 106 insertions, 60 deletions
diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c
index 237e556f30c5..3c913cc3243c 100644
--- a/sys/net80211/ieee80211_ioctl.c
+++ b/sys/net80211/ieee80211_ioctl.c
@@ -70,6 +70,8 @@ __FBSDID("$FreeBSD$");
static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
static struct ieee80211_channel *findchannel(struct ieee80211com *,
int ieee, int mode);
+static int ieee80211_scanreq(struct ieee80211vap *,
+ struct ieee80211_scan_req *);
static __noinline int
ieee80211_ioctl_getkey(struct ieee80211vap *vap, struct ieee80211req *ireq)
@@ -1471,14 +1473,15 @@ mlmelookup(void *arg, const struct ieee80211_scan_entry *se)
}
static __noinline int
-setmlme_assoc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN],
- int ssid_len, const uint8_t ssid[IEEE80211_NWID_LEN])
+setmlme_assoc_sta(struct ieee80211vap *vap,
+ const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len,
+ const uint8_t ssid[IEEE80211_NWID_LEN])
{
struct scanlookup lookup;
- /* XXX ibss/ahdemo */
- if (vap->iv_opmode != IEEE80211_M_STA)
- return EINVAL;
+ KASSERT(vap->iv_opmode == IEEE80211_M_STA,
+ ("expected opmode STA not %s",
+ ieee80211_opmode_name[vap->iv_opmode]));
/* NB: this is racey if roaming is !manual */
lookup.se = NULL;
@@ -1495,6 +1498,36 @@ setmlme_assoc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN],
}
static __noinline int
+setmlme_assoc_adhoc(struct ieee80211vap *vap,
+ const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len,
+ const uint8_t ssid[IEEE80211_NWID_LEN])
+{
+ struct ieee80211_scan_req sr;
+
+ KASSERT(vap->iv_opmode == IEEE80211_M_IBSS ||
+ vap->iv_opmode == IEEE80211_M_AHDEMO,
+ ("expected opmode IBSS or AHDEMO not %s",
+ ieee80211_opmode_name[vap->iv_opmode]));
+
+ if (ssid_len == 0)
+ return EINVAL;
+
+ /* NB: IEEE80211_IOC_SSID call missing for ap_scan=2. */
+ memset(vap->iv_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
+ vap->iv_des_ssid[0].len = ssid_len;
+ memcpy(vap->iv_des_ssid[0].ssid, ssid, ssid_len);
+ vap->iv_des_nssid = 1;
+
+ sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE;
+ sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
+ memcpy(sr.sr_ssid[0].ssid, ssid, ssid_len);
+ sr.sr_ssid[0].len = ssid_len;
+ sr.sr_nssid = 1;
+
+ return ieee80211_scanreq(vap, &sr);
+}
+
+static __noinline int
ieee80211_ioctl_setmlme(struct ieee80211vap *vap, struct ieee80211req *ireq)
{
struct ieee80211req_mlme mlme;
@@ -1505,9 +1538,13 @@ ieee80211_ioctl_setmlme(struct ieee80211vap *vap, struct ieee80211req *ireq)
error = copyin(ireq->i_data, &mlme, sizeof(mlme));
if (error)
return error;
- if (mlme.im_op == IEEE80211_MLME_ASSOC)
- return setmlme_assoc(vap, mlme.im_macaddr,
+ if (vap->iv_opmode == IEEE80211_M_STA &&
+ mlme.im_op == IEEE80211_MLME_ASSOC)
+ return setmlme_assoc_sta(vap, mlme.im_macaddr,
vap->iv_des_ssid[0].len, vap->iv_des_ssid[0].ssid);
+ else if (mlme.im_op == IEEE80211_MLME_ASSOC)
+ return setmlme_assoc_adhoc(vap, mlme.im_macaddr,
+ mlme.im_ssid_len, mlme.im_ssid);
else
return setmlme_common(vap, mlme.im_op,
mlme.im_macaddr, mlme.im_reason);
@@ -2332,8 +2369,8 @@ ieee80211_ioctl_chanswitch(struct ieee80211vap *vap, struct ieee80211req *ireq)
return error;
}
-static __noinline int
-ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq)
+static int
+ieee80211_scanreq(struct ieee80211vap *vap, struct ieee80211_scan_req *sr)
{
#define IEEE80211_IOC_SCAN_FLAGS \
(IEEE80211_IOC_SCAN_NOPICK | IEEE80211_IOC_SCAN_ACTIVE | \
@@ -2342,48 +2379,38 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq)
IEEE80211_IOC_SCAN_NOJOIN | IEEE80211_IOC_SCAN_FLUSH | \
IEEE80211_IOC_SCAN_CHECK)
struct ieee80211com *ic = vap->iv_ic;
- struct ieee80211_scan_req sr; /* XXX off stack? */
- int error, i;
-
- /* NB: parent must be running */
- if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
- return ENXIO;
+ int i;
- if (ireq->i_len != sizeof(sr))
- return EINVAL;
- error = copyin(ireq->i_data, &sr, sizeof(sr));
- if (error != 0)
- return error;
/* convert duration */
- if (sr.sr_duration == IEEE80211_IOC_SCAN_FOREVER)
- sr.sr_duration = IEEE80211_SCAN_FOREVER;
+ if (sr->sr_duration == IEEE80211_IOC_SCAN_FOREVER)
+ sr->sr_duration = IEEE80211_SCAN_FOREVER;
else {
- if (sr.sr_duration < IEEE80211_IOC_SCAN_DURATION_MIN ||
- sr.sr_duration > IEEE80211_IOC_SCAN_DURATION_MAX)
+ if (sr->sr_duration < IEEE80211_IOC_SCAN_DURATION_MIN ||
+ 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;
+ 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) {
- sr.sr_mindwell = msecs_to_ticks(sr.sr_mindwell);
- if (sr.sr_mindwell < 1)
- sr.sr_mindwell = 1;
+ 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) {
- sr.sr_maxdwell = msecs_to_ticks(sr.sr_maxdwell);
- if (sr.sr_maxdwell < 1)
- sr.sr_maxdwell = 1;
+ 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;
- for (i = 0; i < sr.sr_nssid; i++)
- if (sr.sr_ssid[i].len > IEEE80211_NWID_LEN)
+ if (sr->sr_nssid > IEEE80211_SCAN_MAX_SSID)
+ sr->sr_nssid = IEEE80211_SCAN_MAX_SSID;
+ for (i = 0; i < sr->sr_nssid; i++)
+ if (sr->sr_ssid[i].len > IEEE80211_NWID_LEN)
return EINVAL;
/* cleanse flags just in case, could reject if invalid flags */
- sr.sr_flags &= IEEE80211_IOC_SCAN_FLAGS;
+ sr->sr_flags &= IEEE80211_IOC_SCAN_FLAGS;
/*
* Add an implicit NOPICK if the vap is not marked UP. This
* allows applications to scan without joining a bss (or picking
@@ -2391,13 +2418,13 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq)
* roaming mode--you just need to mark the parent device UP.
*/
if ((vap->iv_ifp->if_flags & IFF_UP) == 0)
- sr.sr_flags |= IEEE80211_IOC_SCAN_NOPICK;
+ sr->sr_flags |= IEEE80211_IOC_SCAN_NOPICK;
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
"%s: flags 0x%x%s duration 0x%x mindwell %u maxdwell %u nssid %d\n",
- __func__, sr.sr_flags,
+ __func__, sr->sr_flags,
(vap->iv_ifp->if_flags & IFF_UP) == 0 ? " (!IFF_UP)" : "",
- sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell, sr.sr_nssid);
+ sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell, sr->sr_nssid);
/*
* If we are in INIT state then the driver has never had a chance
* to setup hardware state to do a scan; we must use the state
@@ -2412,13 +2439,13 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq)
IEEE80211_LOCK(ic);
if (vap->iv_state == IEEE80211_S_INIT) {
/* NB: clobbers previous settings */
- vap->iv_scanreq_flags = sr.sr_flags;
- vap->iv_scanreq_duration = sr.sr_duration;
- vap->iv_scanreq_nssid = sr.sr_nssid;
- for (i = 0; i < sr.sr_nssid; i++) {
- vap->iv_scanreq_ssid[i].len = sr.sr_ssid[i].len;
- memcpy(vap->iv_scanreq_ssid[i].ssid, sr.sr_ssid[i].ssid,
- sr.sr_ssid[i].len);
+ vap->iv_scanreq_flags = sr->sr_flags;
+ vap->iv_scanreq_duration = sr->sr_duration;
+ vap->iv_scanreq_nssid = sr->sr_nssid;
+ for (i = 0; i < sr->sr_nssid; i++) {
+ vap->iv_scanreq_ssid[i].len = sr->sr_ssid[i].len;
+ memcpy(vap->iv_scanreq_ssid[i].ssid,
+ sr->sr_ssid[i].ssid, sr->sr_ssid[i].len);
}
vap->iv_flags_ext |= IEEE80211_FEXT_SCANREQ;
IEEE80211_UNLOCK(ic);
@@ -2427,25 +2454,44 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq)
vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
IEEE80211_UNLOCK(ic);
/* XXX neeed error return codes */
- if (sr.sr_flags & IEEE80211_IOC_SCAN_CHECK) {
- (void) ieee80211_check_scan(vap, sr.sr_flags,
- sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell,
- sr.sr_nssid,
+ if (sr->sr_flags & IEEE80211_IOC_SCAN_CHECK) {
+ (void) ieee80211_check_scan(vap, sr->sr_flags,
+ sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell,
+ sr->sr_nssid,
/* NB: cheat, we assume structures are compatible */
- (const struct ieee80211_scan_ssid *) &sr.sr_ssid[0]);
+ (const struct ieee80211_scan_ssid *) &sr->sr_ssid[0]);
} else {
- (void) ieee80211_start_scan(vap, sr.sr_flags,
- sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell,
- sr.sr_nssid,
+ (void) ieee80211_start_scan(vap, sr->sr_flags,
+ sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell,
+ sr->sr_nssid,
/* NB: cheat, we assume structures are compatible */
- (const struct ieee80211_scan_ssid *) &sr.sr_ssid[0]);
+ (const struct ieee80211_scan_ssid *) &sr->sr_ssid[0]);
}
}
- return error;
+ return 0;
#undef IEEE80211_IOC_SCAN_FLAGS
}
static __noinline int
+ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211_scan_req sr; /* XXX off stack? */
+ 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))
+ return EINVAL;
+ error = copyin(ireq->i_data, &sr, sizeof(sr));
+ if (error != 0)
+ return error;
+ return ieee80211_scanreq(vap, &sr);
+}
+
+static __noinline int
ieee80211_ioctl_setstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq)
{
struct ieee80211_node *ni;