Remove assumptions about the max # channels in ioctl's:

o change ioctl's that pass channel lists in/out to handle variable-size
  arrays instead of a fixed (compile-time) value; we do this in a way
  that maintains binary compatibility
o change ifconfig so all channel list data structures are now allocated
  to hold MAXCHAN entries (1536); this, for example, allows the kernel
  to return > IEEE80211_CHAN_MAX entries for calls like IEEE80211_IOC_DEVCAPS
This commit is contained in:
Sam Leffler 2009-01-27 23:42:14 +00:00
parent 5fe9f04492
commit 8658b18b82
3 changed files with 204 additions and 114 deletions

View File

@ -79,6 +79,7 @@
#include <net80211/ieee80211_ioctl.h>
#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
@ -119,6 +120,8 @@
#define IEEE80211_NODE_RIFS 0x4000 /* RIFS enabled */
#endif
#define MAXCHAN 1536 /* max 1.5K channels */
#define MAXCOL 78
static int col;
static char spacer;
@ -145,7 +148,7 @@ static void print_channels(int, const struct ieee80211req_chaninfo *,
static void regdomain_makechannels(struct ieee80211_regdomain_req *,
const struct ieee80211_devcaps_req *);
static struct ieee80211req_chaninfo chaninfo;
static struct ieee80211req_chaninfo *chaninfo;
static struct ieee80211_regdomain regdomain;
static int gotregdomain = 0;
static struct ieee80211_roamparams_req roamparams;
@ -175,10 +178,14 @@ gethtconf(int s)
static void
getchaninfo(int s)
{
if (chaninfo.ic_nchans != 0)
if (chaninfo != NULL)
return;
if (get80211(s, IEEE80211_IOC_CHANINFO, &chaninfo, sizeof(chaninfo)) < 0)
errx(1, "unable to get channel information");
chaninfo = malloc(IEEE80211_CHANINFO_SIZE(MAXCHAN));
if (chaninfo == NULL)
errx(1, "no space for channel list");
if (get80211(s, IEEE80211_IOC_CHANINFO, chaninfo,
IEEE80211_CHANINFO_SIZE(MAXCHAN)) < 0)
err(1, "unable to get channel information");
ifmr = ifmedia_getstate(s);
gethtconf(s);
}
@ -205,19 +212,19 @@ getregdata(void)
static int
canpromote(int i, int from, int to)
{
const struct ieee80211_channel *fc = &chaninfo.ic_chans[i];
const struct ieee80211_channel *fc = &chaninfo->ic_chans[i];
int j;
if ((fc->ic_flags & from) != from)
return i;
/* NB: quick check exploiting ordering of chans w/ same frequency */
if (i+1 < chaninfo.ic_nchans &&
chaninfo.ic_chans[i+1].ic_freq == fc->ic_freq &&
(chaninfo.ic_chans[i+1].ic_flags & to) == to)
if (i+1 < chaninfo->ic_nchans &&
chaninfo->ic_chans[i+1].ic_freq == fc->ic_freq &&
(chaninfo->ic_chans[i+1].ic_flags & to) == to)
return i+1;
/* brute force search in case channel list is not ordered */
for (j = 0; j < chaninfo.ic_nchans; j++) {
const struct ieee80211_channel *tc = &chaninfo.ic_chans[j];
for (j = 0; j < chaninfo->ic_nchans; j++) {
const struct ieee80211_channel *tc = &chaninfo->ic_chans[j];
if (j != i &&
tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to)
return j;
@ -287,13 +294,13 @@ mapfreq(struct ieee80211_channel *chan, int freq, int flags)
{
int i;
for (i = 0; i < chaninfo.ic_nchans; i++) {
const struct ieee80211_channel *c = &chaninfo.ic_chans[i];
for (i = 0; i < chaninfo->ic_nchans; i++) {
const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
if (c->ic_freq == freq && (c->ic_flags & flags) == flags) {
if (flags == 0) {
/* when ambiguous promote to ``best'' */
c = &chaninfo.ic_chans[promote(i)];
c = &chaninfo->ic_chans[promote(i)];
}
*chan = *c;
return;
@ -307,13 +314,13 @@ mapchan(struct ieee80211_channel *chan, int ieee, int flags)
{
int i;
for (i = 0; i < chaninfo.ic_nchans; i++) {
const struct ieee80211_channel *c = &chaninfo.ic_chans[i];
for (i = 0; i < chaninfo->ic_nchans; i++) {
const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) {
if (flags == 0) {
/* when ambiguous promote to ``best'' */
c = &chaninfo.ic_chans[promote(i)];
c = &chaninfo->ic_chans[promote(i)];
}
*chan = *c;
return;
@ -331,7 +338,7 @@ getcurchan(int s)
int val;
/* fall back to legacy ioctl */
if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0)
errx(-1, "cannot figure out current channel");
err(-1, "cannot figure out current channel");
getchaninfo(s);
mapchan(&curchan, val, 0);
}
@ -370,7 +377,7 @@ getroam(int s)
return;
if (get80211(s, IEEE80211_IOC_ROAM,
&roamparams, sizeof(roamparams)) < 0)
errx(1, "unable to get roaming parameters");
err(1, "unable to get roaming parameters");
gotroam = 1;
}
@ -388,7 +395,7 @@ gettxparams(int s)
return;
if (get80211(s, IEEE80211_IOC_TXPARAMS,
&txparams, sizeof(txparams)) < 0)
errx(1, "unable to get transmit parameters");
err(1, "unable to get transmit parameters");
gottxparams = 1;
}
@ -406,23 +413,24 @@ getregdomain(int s)
return;
if (get80211(s, IEEE80211_IOC_REGDOMAIN,
&regdomain, sizeof(regdomain)) < 0)
errx(1, "unable to get regulatory domain info");
err(1, "unable to get regulatory domain info");
gotregdomain = 1;
}
static void
getdevcaps(int s, struct ieee80211_devcaps_req *dc)
{
if (get80211(s, IEEE80211_IOC_DEVCAPS, dc, sizeof(*dc)) < 0)
errx(1, "unable to get device capabilities");
if (get80211(s, IEEE80211_IOC_DEVCAPS, dc,
IEEE80211_DEVCAPS_SPACE(dc)) < 0)
err(1, "unable to get device capabilities");
}
static void
setregdomain_cb(int s, void *arg)
{
struct ieee80211_regdomain_req req;
struct ieee80211_regdomain_req *req;
struct ieee80211_regdomain *rd = arg;
struct ieee80211_devcaps_req dc;
struct ieee80211_devcaps_req *dc;
struct regdata *rdp = getregdata();
if (rd->country != NO_COUNTRY) {
@ -462,34 +470,52 @@ setregdomain_cb(int s, void *arg)
rp->name);
}
}
req.rd = *rd;
/*
* Fetch the device capabilities and calculate the
* full set of netbands for which we request a new
* channel list be constructed. Once that's done we
* push the regdomain info + channel list to the kernel.
*/
getdevcaps(s, &dc);
dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
if (dc == NULL)
errx(1, "no space for device capabilities");
dc->dc_chaninfo.ic_nchans = MAXCHAN;
getdevcaps(s, dc);
#if 0
if (verbose) {
printf("drivercaps: 0x%x\n", dc.dc_drivercaps);
printf("cryptocaps: 0x%x\n", dc.dc_cryptocaps);
printf("htcaps : 0x%x\n", dc.dc_htcaps);
memcpy(&chaninfo, &dc.dc_chaninfo, sizeof(chaninfo));
print_channels(s, &dc.dc_chaninfo, 1/*allchans*/, 1/*verbose*/);
printf("drivercaps: 0x%x\n", dc->dc_drivercaps);
printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps);
printf("htcaps : 0x%x\n", dc->dc_htcaps);
memcpy(chaninfo, &dc->dc_chaninfo,
IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, 1/*verbose*/);
}
#endif
regdomain_makechannels(&req, &dc);
req = malloc(IEEE80211_REGDOMAIN_SIZE(dc->dc_chaninfo.ic_nchans));
if (req == NULL)
errx(1, "no space for regdomain request");
req->rd = *rd;
regdomain_makechannels(req, dc);
if (verbose) {
LINE_INIT(':');
print_regdomain(rd, 1/*verbose*/);
LINE_BREAK();
memcpy(&chaninfo, &req.chaninfo, sizeof(chaninfo));
print_channels(s, &req.chaninfo, 1/*allchans*/, 1/*verbose*/);
/* blech, reallocate channel list for new data */
if (chaninfo != NULL)
free(chaninfo);
chaninfo = malloc(IEEE80211_CHANINFO_SPACE(&req->chaninfo));
if (chaninfo == NULL)
errx(1, "no space for channel list");
memcpy(chaninfo, &req->chaninfo,
IEEE80211_CHANINFO_SPACE(&req->chaninfo));
print_channels(s, &req->chaninfo, 1/*allchans*/, 1/*verbose*/);
}
if (req.chaninfo.ic_nchans == 0)
if (req->chaninfo.ic_nchans == 0)
errx(1, "no channels calculated");
set80211(s, IEEE80211_IOC_REGDOMAIN, 0, sizeof(req), &req);
set80211(s, IEEE80211_IOC_REGDOMAIN, 0,
IEEE80211_REGDOMAIN_SPACE(req), req);
free(req);
free(dc);
}
static int
@ -980,7 +1006,6 @@ static void
set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
{
struct ieee80211req_chanlist chanlist;
#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
char *temp, *cp, *tp;
temp = malloc(strlen(val) + 1);
@ -997,18 +1022,18 @@ set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
*tp++ = '\0';
switch (sscanf(cp, "%u-%u", &first, &last)) {
case 1:
if (first > MAXCHAN)
if (first > IEEE80211_CHAN_MAX)
errx(-1, "channel %u out of range, max %zu",
first, MAXCHAN);
first, IEEE80211_CHAN_MAX);
setbit(chanlist.ic_channels, first);
break;
case 2:
if (first > MAXCHAN)
if (first > IEEE80211_CHAN_MAX)
errx(-1, "channel %u out of range, max %zu",
first, MAXCHAN);
if (last > MAXCHAN)
first, IEEE80211_CHAN_MAX);
if (last > IEEE80211_CHAN_MAX)
errx(-1, "channel %u out of range, max %zu",
last, MAXCHAN);
last, IEEE80211_CHAN_MAX);
if (first > last)
errx(-1, "void channel range, %u > %u",
first, last);
@ -1026,7 +1051,6 @@ set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
cp = tp;
}
set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
#undef MAXCHAN
}
static void
@ -1641,7 +1665,7 @@ set80211amsdu(const char *val, int d, int s, const struct afswtch *rafp)
int amsdu;
if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0)
errx(-1, "cannot get AMSDU setting");
err(-1, "cannot get AMSDU setting");
if (d < 0) {
d = -d;
amsdu &= ~d;
@ -1848,6 +1872,7 @@ regdomain_addchans(struct ieee80211req_chaninfo *ci,
break;
}
c = &ci->ic_chans[ci->ic_nchans++];
memset(c, 0, sizeof(*c));
c->ic_freq = freq;
c->ic_flags = chanFlags |
(flags &~ (REQ_FLAGS | IEEE80211_CHAN_HT40));
@ -1896,7 +1921,14 @@ regdomain_makechannels(
errx(1, "internal error, regdomain %d not found",
reg->regdomain);
if (rd->sku != SKU_DEBUG) {
memset(ci, 0, sizeof(*ci));
/*
* regdomain_addchans incrememnts the channel count for
* each channel it adds so initialize ic_nchans to zero.
* Note that we know we have enough space to hold all possible
* channels because the devcaps list size was used to
* allocate our request.
*/
ci->ic_nchans = 0;
if (!LIST_EMPTY(&rd->bands_11b))
regdomain_addchans(ci, &rd->bands_11b, reg,
IEEE80211_CHAN_B, &dc->dc_chaninfo);
@ -1945,7 +1977,8 @@ regdomain_makechannels(
qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]),
regdomain_sort);
} else
*ci = dc->dc_chaninfo;
memcpy(ci, &dc->dc_chaninfo,
IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
}
static void
@ -3113,19 +3146,21 @@ static void
print_channels(int s, const struct ieee80211req_chaninfo *chans,
int allchans, int verb)
{
struct ieee80211req_chaninfo achans;
struct ieee80211req_chaninfo *achans;
uint8_t reported[IEEE80211_CHAN_BYTES];
const struct ieee80211_channel *c;
int i, half;
memset(&achans, 0, sizeof(achans));
achans = malloc(IEEE80211_CHANINFO_SPACE(chans));
if (achans == NULL)
errx(1, "no space for active channel list");
achans->ic_nchans = 0;
memset(reported, 0, sizeof(reported));
if (!allchans) {
struct ieee80211req_chanlist active;
if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0)
errx(1, "unable to get active channel list");
memset(&achans, 0, sizeof(achans));
for (i = 0; i < chans->ic_nchans; i++) {
c = &chans->ic_chans[i];
if (!isset(active.ic_channels, c->ic_ieee))
@ -3138,9 +3173,9 @@ print_channels(int s, const struct ieee80211req_chaninfo *chans,
*/
if (isset(reported, c->ic_ieee) && !verb) {
/* XXX we assume duplicates are adjacent */
achans.ic_chans[achans.ic_nchans-1] = *c;
achans->ic_chans[achans->ic_nchans-1] = *c;
} else {
achans.ic_chans[achans.ic_nchans++] = *c;
achans->ic_chans[achans->ic_nchans++] = *c;
setbit(reported, c->ic_ieee);
}
}
@ -3150,33 +3185,34 @@ print_channels(int s, const struct ieee80211req_chaninfo *chans,
/* suppress duplicates as above */
if (isset(reported, c->ic_ieee) && !verb) {
/* XXX we assume duplicates are adjacent */
achans.ic_chans[achans.ic_nchans-1] = *c;
achans->ic_chans[achans->ic_nchans-1] = *c;
} else {
achans.ic_chans[achans.ic_nchans++] = *c;
achans->ic_chans[achans->ic_nchans++] = *c;
setbit(reported, c->ic_ieee);
}
}
}
half = achans.ic_nchans / 2;
if (achans.ic_nchans % 2)
half = achans->ic_nchans / 2;
if (achans->ic_nchans % 2)
half++;
for (i = 0; i < achans.ic_nchans / 2; i++) {
print_chaninfo(&achans.ic_chans[i], verb);
print_chaninfo(&achans.ic_chans[half+i], verb);
for (i = 0; i < achans->ic_nchans / 2; i++) {
print_chaninfo(&achans->ic_chans[i], verb);
print_chaninfo(&achans->ic_chans[half+i], verb);
printf("\n");
}
if (achans.ic_nchans % 2) {
print_chaninfo(&achans.ic_chans[i], verb);
if (achans->ic_nchans % 2) {
print_chaninfo(&achans->ic_chans[i], verb);
printf("\n");
}
free(achans);
}
static void
list_channels(int s, int allchans)
{
getchaninfo(s);
print_channels(s, &chaninfo, allchans, verbose);
print_channels(s, chaninfo, allchans, verbose);
}
static void
@ -3201,48 +3237,52 @@ print_txpow_verbose(const struct ieee80211_channel *c)
static void
list_txpow(int s)
{
struct ieee80211req_chaninfo achans;
struct ieee80211req_chaninfo *achans;
uint8_t reported[IEEE80211_CHAN_BYTES];
struct ieee80211_channel *c, *prev;
int i, half;
getchaninfo(s);
memset(&achans, 0, sizeof(achans));
achans = malloc(IEEE80211_CHANINFO_SPACE(chaninfo));
if (achans == NULL)
errx(1, "no space for active channel list");
achans->ic_nchans = 0;
memset(reported, 0, sizeof(reported));
for (i = 0; i < chaninfo.ic_nchans; i++) {
c = &chaninfo.ic_chans[i];
for (i = 0; i < chaninfo->ic_nchans; i++) {
c = &chaninfo->ic_chans[i];
/* suppress duplicates as above */
if (isset(reported, c->ic_ieee) && !verbose) {
/* XXX we assume duplicates are adjacent */
prev = &achans.ic_chans[achans.ic_nchans-1];
prev = &achans->ic_chans[achans->ic_nchans-1];
/* display highest power on channel */
if (c->ic_maxpower > prev->ic_maxpower)
*prev = *c;
} else {
achans.ic_chans[achans.ic_nchans++] = *c;
achans->ic_chans[achans->ic_nchans++] = *c;
setbit(reported, c->ic_ieee);
}
}
if (!verbose) {
half = achans.ic_nchans / 2;
if (achans.ic_nchans % 2)
half = achans->ic_nchans / 2;
if (achans->ic_nchans % 2)
half++;
for (i = 0; i < achans.ic_nchans / 2; i++) {
print_txpow(&achans.ic_chans[i]);
print_txpow(&achans.ic_chans[half+i]);
for (i = 0; i < achans->ic_nchans / 2; i++) {
print_txpow(&achans->ic_chans[i]);
print_txpow(&achans->ic_chans[half+i]);
printf("\n");
}
if (achans.ic_nchans % 2) {
print_txpow(&achans.ic_chans[i]);
if (achans->ic_nchans % 2) {
print_txpow(&achans->ic_chans[i]);
printf("\n");
}
} else {
for (i = 0; i < achans.ic_nchans; i++) {
print_txpow_verbose(&achans.ic_chans[i]);
for (i = 0; i < achans->ic_nchans; i++) {
print_txpow_verbose(&achans->ic_chans[i]);
printf("\n");
}
}
free(achans);
}
static void
@ -3259,19 +3299,24 @@ list_keys(int s)
static void
list_capabilities(int s)
{
struct ieee80211_devcaps_req dc;
struct ieee80211_devcaps_req *dc;
getdevcaps(s, &dc);
printb("drivercaps", dc.dc_drivercaps, IEEE80211_C_BITS);
if (dc.dc_cryptocaps != 0 || verbose) {
dc = malloc(IEEE80211_DEVCAPS_SIZE(1));
if (dc == NULL)
errx(1, "no space for device capabilities");
dc->dc_chaninfo.ic_nchans = 1;
getdevcaps(s, dc);
printb("drivercaps", dc->dc_drivercaps, IEEE80211_C_BITS);
if (dc->dc_cryptocaps != 0 || verbose) {
putchar('\n');
printb("cryptocaps", dc.dc_cryptocaps, IEEE80211_CRYPTO_BITS);
printb("cryptocaps", dc->dc_cryptocaps, IEEE80211_CRYPTO_BITS);
}
if (dc.dc_htcaps != 0 || verbose) {
if (dc->dc_htcaps != 0 || verbose) {
putchar('\n');
printb("htcaps", dc.dc_htcaps, IEEE80211_HTCAP_BITS);
printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS);
}
putchar('\n');
free(dc);
}
static int
@ -3550,7 +3595,7 @@ list_regdomain(int s, int channelsalso)
spacer = ':';
print_regdomain(&regdomain, 1);
LINE_BREAK();
print_channels(s, &chaninfo, 1/*allchans*/, 1/*verbose*/);
print_channels(s, chaninfo, 1/*allchans*/, 1/*verbose*/);
} else
print_regdomain(&regdomain, verbose);
}
@ -4362,6 +4407,7 @@ get80211len(int s, int type, void *data, int len, int *plen)
(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
ireq.i_type = type;
ireq.i_len = len;
assert(ireq.i_len == len); /* NB: check for 16-bit truncation */
ireq.i_data = data;
if (ioctl(s, SIOCG80211, &ireq) < 0)
return -1;
@ -4393,6 +4439,7 @@ set80211(int s, int type, int val, int len, void *data)
ireq.i_type = type;
ireq.i_val = val;
ireq.i_len = len;
assert(ireq.i_len == len); /* NB: check for 16-bit truncation */
ireq.i_data = data;
if (ioctl(s, SIOCS80211, &ireq) < 0)
err(1, "SIOCS80211");

View File

@ -696,21 +696,27 @@ ieee80211_ioctl_getdevcaps(struct ieee80211com *ic,
{
struct ieee80211_devcaps_req *dc;
struct ieee80211req_chaninfo *ci;
int error;
int maxchans, error;
if (ireq->i_len != sizeof(struct ieee80211_devcaps_req))
maxchans = 1 + ((ireq->i_len - sizeof(struct ieee80211_devcaps_req)) /
sizeof(struct ieee80211_channel));
/* NB: require 1 so we know ic_nchans is accessible */
if (maxchans < 1)
return EINVAL;
dc = (struct ieee80211_devcaps_req *) malloc(
sizeof(struct ieee80211_devcaps_req), M_TEMP, M_NOWAIT | M_ZERO);
/* constrain max request size, 2K channels is ~24Kbytes */
if (maxchans > 2048)
maxchans = 2048;
dc = (struct ieee80211_devcaps_req *)
malloc(IEEE80211_DEVCAPS_SIZE(maxchans), M_TEMP, M_NOWAIT | M_ZERO);
if (dc == NULL)
return ENOMEM;
dc->dc_drivercaps = ic->ic_caps;
dc->dc_cryptocaps = ic->ic_cryptocaps;
dc->dc_htcaps = ic->ic_htcaps;
ci = &dc->dc_chaninfo;
ic->ic_getradiocaps(ic, IEEE80211_CHAN_MAX, &ci->ic_nchans, ci->ic_chans);
ic->ic_getradiocaps(ic, maxchans, &ci->ic_nchans, ci->ic_chans);
ieee80211_sort_channels(ci->ic_chans, ci->ic_nchans);
error = copyout(dc, ireq->i_data, sizeof(*dc));
error = copyout(dc, ireq->i_data, IEEE80211_DEVCAPS_SPACE(dc));
free(dc, M_TEMP);
return error;
}
@ -1566,17 +1572,21 @@ static __noinline int
ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq)
{
struct ieee80211com *ic = vap->iv_ic;
struct ieee80211req_chanlist list;
u_char chanlist[IEEE80211_CHAN_BYTES];
int i, nchan, error;
uint8_t *chanlist, *list;
int i, nchan, maxchan, error;
if (ireq->i_len != sizeof(list))
return EINVAL;
error = copyin(ireq->i_data, &list, sizeof(list));
if (ireq->i_len > sizeof(ic->ic_chan_active))
ireq->i_len = sizeof(ic->ic_chan_active);
list = malloc(ireq->i_len + IEEE80211_CHAN_BYTES, M_TEMP,
M_NOWAIT | M_ZERO);
if (list == NULL)
return ENOMEM;
error = copyin(ireq->i_data, list, ireq->i_len);
if (error)
return error;
memset(chanlist, 0, sizeof(chanlist));
nchan = 0;
chanlist = list + ireq->i_len; /* NB: zero'd already */
maxchan = ireq->i_len * NBBY;
for (i = 0; i < ic->ic_nchans; i++) {
const struct ieee80211_channel *c = &ic->ic_channels[i];
/*
@ -1584,7 +1594,7 @@ ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq)
* available channels so users can do things like specify
* 1-255 to get all available channels.
*/
if (isset(list.ic_channels, c->ic_ieee)) {
if (c->ic_ieee < maxchan && isset(list, c->ic_ieee)) {
setbit(chanlist, c->ic_ieee);
nchan++;
}
@ -1594,8 +1604,9 @@ ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq)
if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && /* XXX */
isclr(chanlist, ic->ic_bsschan->ic_ieee))
ic->ic_bsschan = IEEE80211_CHAN_ANYC;
memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
memcpy(ic->ic_chan_active, chanlist, IEEE80211_CHAN_BYTES);
ieee80211_scan_flush(vap);
free(list, M_TEMP);
return ENETRESET;
}
@ -1993,17 +2004,34 @@ ieee80211_ioctl_setregdomain(struct ieee80211vap *vap,
const struct ieee80211req *ireq)
{
struct ieee80211_regdomain_req *reg;
int error;
int nchans, error;
if (ireq->i_len != sizeof(struct ieee80211_regdomain_req))
nchans = 1 + ((ireq->i_len - sizeof(struct ieee80211_regdomain_req)) /
sizeof(struct ieee80211_channel));
if (!(1 <= nchans && nchans <= IEEE80211_CHAN_MAX)) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
"%s: bad # chans, i_len %d nchans %d\n", __func__,
ireq->i_len, nchans);
return EINVAL;
reg = (struct ieee80211_regdomain_req *) malloc(
sizeof(struct ieee80211_regdomain_req), M_TEMP, M_NOWAIT);
if (reg == NULL)
}
reg = (struct ieee80211_regdomain_req *)
malloc(IEEE80211_REGDOMAIN_SIZE(nchans), M_TEMP, M_NOWAIT);
if (reg == NULL) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
"%s: no memory, nchans %d\n", __func__, nchans);
return ENOMEM;
error = copyin(ireq->i_data, reg, sizeof(*reg));
if (error == 0)
error = ieee80211_setregdomain(vap, reg);
}
error = copyin(ireq->i_data, reg, IEEE80211_REGDOMAIN_SIZE(nchans));
if (error == 0) {
/* NB: validate inline channel count against storage size */
if (reg->chaninfo.ic_nchans != nchans) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
"%s: chan cnt mismatch, %d != %d\n", __func__,
reg->chaninfo.ic_nchans, nchans);
error = EINVAL;
} else
error = ieee80211_setregdomain(vap, reg);
}
free(reg, M_TEMP);
return (error == 0 ? ENETRESET : error);

View File

@ -299,13 +299,13 @@ struct ieee80211req_maclist {
};
/*
* Set the active channel list. Note this list is
* intersected with the available channel list in
* calculating the set of channels actually used in
* scanning.
* Set the active channel list by IEEE channel #: each channel
* to be marked active is set in a bit vector. Note this list is
* intersected with the available channel list in calculating
* the set of channels actually used in scanning.
*/
struct ieee80211req_chanlist {
uint8_t ic_channels[IEEE80211_CHAN_BYTES];
uint8_t ic_channels[32]; /* NB: can be variable length */
};
/*
@ -313,8 +313,13 @@ struct ieee80211req_chanlist {
*/
struct ieee80211req_chaninfo {
u_int ic_nchans;
struct ieee80211_channel ic_chans[IEEE80211_CHAN_MAX];
struct ieee80211_channel ic_chans[1]; /* NB: variable length */
};
#define IEEE80211_CHANINFO_SIZE(_nchan) \
(sizeof(struct ieee80211req_chaninfo) + \
(((_nchan)-1) * sizeof(struct ieee80211_channel)))
#define IEEE80211_CHANINFO_SPACE(_ci) \
IEEE80211_CHANINFO_SIZE((_ci)->ic_nchans)
/*
* Retrieve the WPA/RSN information element for an associated station.
@ -463,6 +468,11 @@ struct ieee80211_regdomain_req {
struct ieee80211_regdomain rd;
struct ieee80211req_chaninfo chaninfo;
};
#define IEEE80211_REGDOMAIN_SIZE(_nchan) \
(sizeof(struct ieee80211_regdomain_req) + \
(((_nchan)-1) * sizeof(struct ieee80211_channel)))
#define IEEE80211_REGDOMAIN_SPACE(_req) \
IEEE80211_REGDOMAIN_SIZE((_req)->chaninfo.ic_nchans)
/*
* Get driver capabilities. Driver, hardware crypto, and
@ -475,6 +485,11 @@ struct ieee80211_devcaps_req {
uint32_t dc_htcaps; /* HT/802.11n support */
struct ieee80211req_chaninfo dc_chaninfo;
};
#define IEEE80211_DEVCAPS_SIZE(_nchan) \
(sizeof(struct ieee80211_devcaps_req) + \
(((_nchan)-1) * sizeof(struct ieee80211_channel)))
#define IEEE80211_DEVCAPS_SPACE(_dc) \
IEEE80211_DEVCAPS_SIZE((_dc)->dc_chaninfo.ic_nchans)
struct ieee80211_chanswitch_req {
struct ieee80211_channel csa_chan; /* new channel */