PERFORCE change 113264 for review
Sam Leffler
sam at FreeBSD.org
Sun Jan 21 19:55:01 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=113264
Change 113264 by sam at sam_ebb on 2007/01/21 19:54:46
Overhaul channel handling:
o purge freq<->ieee mapping; get the complete channel list
from the kernel and use it to do the mapping
o use new IEEE80211_IOC_CURCHAN ioctl to get+set the current
channel; still needs more work to enable specifying a channel
with additional attributes such as channel width
o fixup channel status display; now -v shows the correct
frequency and also channel information (may want to enable
this by default)
Affected files ...
.. //depot/projects/wifi/sbin/ifconfig/ifieee80211.c#58 edit
Differences ...
==== //depot/projects/wifi/sbin/ifconfig/ifieee80211.c#58 (text+ko) ====
@@ -94,12 +94,78 @@
#include "ifconfig.h"
-static void set80211(int s, int type, int val, int len, u_int8_t *data);
+static void set80211(int s, int type, int val, int len, void *data);
static const char *get_string(const char *val, const char *sep,
u_int8_t *buf, int *lenp);
static void print_string(const u_int8_t *buf, int len);
+static struct ieee80211req_chaninfo chaninfo;
+
+static void
+getchaninfo(int s)
+{
+ struct ieee80211req ireq;
+
+ if (chaninfo.ic_nchans != 0)
+ return;
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_CHANINFO;
+ ireq.i_data = &chaninfo;
+ ireq.i_len = sizeof(chaninfo);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get channel information");
+}
+
+static void
+mapfreq(struct ieee80211_channel *c, int freq, int flags)
+{
+ int i;
+
+ for (i = 0; i < chaninfo.ic_nchans; i++)
+ if (chaninfo.ic_chans[i].ic_freq == freq) {
+ /* when ambiguous take 11g over 11b */
+ if (flags == 0 &&
+ IEEE80211_IS_CHAN_B(&chaninfo.ic_chans[i]) &&
+ i+1 < chaninfo.ic_nchans &&
+ chaninfo.ic_chans[i+1].ic_freq == freq) {
+ i++;
+ }
+ *c = chaninfo.ic_chans[i];
+ return;
+ }
+ errx(1, "unknown/undefined frequency %u/0x%x", freq, flags);
+}
+
+static void
+mapchan(struct ieee80211_channel *c, int ieee, int flags)
+{
+ int i;
+
+ for (i = 0; i < chaninfo.ic_nchans; i++)
+ if (chaninfo.ic_chans[i].ic_ieee == ieee) {
+ /* when ambiguous take 11g over 11b */
+ if (flags == 0 &&
+ IEEE80211_IS_CHAN_B(&chaninfo.ic_chans[i]) &&
+ i+1 < chaninfo.ic_nchans &&
+ chaninfo.ic_chans[i+1].ic_ieee == ieee) {
+ i++;
+ }
+ *c = chaninfo.ic_chans[i];
+ return;
+ }
+ errx(1, "unknown/undefined channel number %d", ieee);
+}
+
static int
+ieee80211_mhz2ieee(int freq, int flags)
+{
+ struct ieee80211_channel chan;
+ mapfreq(&chan, freq, flags);
+ return chan.ic_ieee;
+}
+
+static int
isanyarg(const char *arg)
{
return (strcmp(arg, "-") == 0 ||
@@ -141,74 +207,26 @@
set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
}
-/*
- * Convert IEEE channel number to MHz frequency.
- */
-static u_int
-ieee80211_ieee2mhz(u_int chan)
-{
- if (chan == 14)
- return 2484;
- if (chan < 14) /* 0-13 */
- return 2407 + chan*5;
- if (chan < 27) /* 15-26 */
- return 2512 + ((chan-15)*20);
- return 5000 + (chan*5);
-}
-
-static __inline int
-mapgsm(u_int freq, u_int flags)
-{
- freq *= 10;
- if (flags & IEEE80211_CHAN_QUARTER)
- freq += 5;
- else if (flags & IEEE80211_CHAN_HALF)
- freq += 10;
- else
- freq += 20;
- /* NB: there is no 907/20 wide but leave room */
- return (freq - 906*10) / 5;
-}
-
-static __inline int
-mappsb(u_int freq, u_int flags)
-{
- return 37 + ((freq * 10) + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5;
-}
-
-/*
- * Convert MHz frequency to IEEE channel number.
- */
-static u_int
-ieee80211_mhz2ieee(u_int freq, u_int flags)
-{
- if ((flags & IEEE80211_CHAN_GSM) || (907 <= freq && freq <= 922))
- return mapgsm(freq, flags);
- if (freq == 2484)
- return 14;
- if (freq < 2484)
- return (freq - 2407) / 5;
- if (freq < 5000) {
- if (flags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER))
- return mappsb(freq, flags);
- else if (freq > 4900)
- return (freq - 4000) / 5;
- else
- return 15 + ((freq - 2512) / 20);
- }
- return (freq - 5000) / 5;
-}
-
static void
set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
{
+ struct ieee80211_channel chan;
+
+ memset(&chan, 0, sizeof(chan));
if (!isanyarg(val)) {
+ /* XXX freq/width */
int v = atoi(val);
- if (v > 255) /* treat as frequency */
- v = ieee80211_mhz2ieee(v, 0);
- set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
- } else
- set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
+
+ getchaninfo(s);
+ if (v > 255) { /* treat as frequency */
+ mapfreq(&chan, v, 0);
+ } else {
+ mapchan(&chan, v, 0);
+ }
+ } else {
+ chan.ic_freq = IEEE80211_CHAN_ANY;
+ }
+ set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan);
}
static void
@@ -503,8 +521,7 @@
break;
cp = tp;
}
- set80211(s, IEEE80211_IOC_CHANLIST, 0,
- sizeof(chanlist), (uint8_t *) &chanlist);
+ set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
#undef MAXCHAN
}
@@ -688,7 +705,7 @@
mlme.im_op = IEEE80211_MLME_DEAUTH;
mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
- set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
+ set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme);
}
static
@@ -1242,6 +1259,8 @@
if (len < sizeof(struct ieee80211req_scan_result))
return;
+ getchaninfo(s);
+
ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n"
, ssidmax, ssidmax, "SSID"
@@ -1356,6 +1375,8 @@
if (len < sizeof(struct ieee80211req_sta_info))
return;
+ getchaninfo(s);
+
printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n"
, "ADDR"
, "AID"
@@ -1395,77 +1416,103 @@
} while (len >= sizeof(struct ieee80211req_sta_info));
}
-static void
-print_chaninfo(const struct ieee80211_channel *c)
+static const char *
+get_chaninfo(const struct ieee80211_channel *c, char buf[], size_t bsize)
{
-#define IEEE80211_IS_CHAN_PASSIVE(_c) \
- (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
- char buf[14];
-
buf[0] = '\0';
if (IEEE80211_IS_CHAN_FHSS(c))
- strlcat(buf, " FHSS", sizeof(buf));
+ strlcat(buf, " FHSS", bsize);
if (IEEE80211_IS_CHAN_A(c)) {
if (IEEE80211_IS_CHAN_HALF(c))
- strlcat(buf, " 11a/10Mhz", sizeof(buf));
+ strlcat(buf, " 11a/10Mhz", bsize);
else if (IEEE80211_IS_CHAN_QUARTER(c))
- strlcat(buf, " 11a/5Mhz", sizeof(buf));
+ strlcat(buf, " 11a/5Mhz", bsize);
else
- strlcat(buf, " 11a", sizeof(buf));
+ strlcat(buf, " 11a", bsize);
}
if (IEEE80211_IS_CHAN_ANYG(c)) {
if (IEEE80211_IS_CHAN_HALF(c))
- strlcat(buf, " 11g/10Mhz", sizeof(buf));
+ strlcat(buf, " 11g/10Mhz", bsize);
else if (IEEE80211_IS_CHAN_QUARTER(c))
- strlcat(buf, " 11g/5Mhz", sizeof(buf));
+ strlcat(buf, " 11g/5Mhz", bsize);
else
- strlcat(buf, " 11g", sizeof(buf));
+ strlcat(buf, " 11g", bsize);
} else if (IEEE80211_IS_CHAN_B(c))
- strlcat(buf, " 11b", sizeof(buf));
+ strlcat(buf, " 11b", bsize);
if (IEEE80211_IS_CHAN_TURBO(c))
- strlcat(buf, " Turbo", sizeof(buf));
+ strlcat(buf, " Turbo", bsize);
+ return buf;
+}
+
+static void
+print_chaninfo(const struct ieee80211_channel *c)
+{
+ char buf[14];
+
printf("Channel %3u : %u%c Mhz%-14.14s",
ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
- IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
-#undef IEEE80211_IS_CHAN_PASSIVE
+ IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
+ get_chaninfo(c, buf, sizeof(buf)));
}
static void
list_channels(int s, int allchans)
{
- struct ieee80211req ireq;
- struct ieee80211req_chaninfo chans;
struct ieee80211req_chaninfo achans;
+ uint8_t reported[IEEE80211_CHAN_BYTES];
const struct ieee80211_channel *c;
- int i, half, ieee;
+ int i, half;
- (void) memset(&ireq, 0, sizeof(ireq));
- (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
- ireq.i_type = IEEE80211_IOC_CHANINFO;
- ireq.i_data = &chans;
- ireq.i_len = sizeof(chans);
- if (ioctl(s, SIOCG80211, &ireq) < 0)
- errx(1, "unable to get channel information");
+ getchaninfo(s);
+ memset(&achans, 0, sizeof(achans));
+ memset(reported, 0, sizeof(reported));
if (!allchans) {
struct ieee80211req_chanlist active;
+ struct ieee80211req ireq;
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
ireq.i_type = IEEE80211_IOC_CHANLIST;
ireq.i_data = &active;
ireq.i_len = sizeof(active);
if (ioctl(s, SIOCG80211, &ireq) < 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];
- ieee = ieee80211_mhz2ieee(c->ic_freq, c->ic_flags);
- if (isset(active.ic_channels, ieee) || allchans)
+ for (i = 0; i < chaninfo.ic_nchans; i++) {
+ c = &chaninfo.ic_chans[i];
+ if (!isset(active.ic_channels, c->ic_ieee))
+ continue;
+ /*
+ * Suppress compatible duplicates unless
+ * verbose. The kernel gives us it's
+ * complete channel list which has separate
+ * entries for 11g/11b and 11a/turbo.
+ */
+ if (isset(reported, c->ic_ieee) && !verbose) {
+ /* XXX we assume duplicates are adjacent */
+ achans.ic_chans[achans.ic_nchans-1] = *c;
+ } else {
+ achans.ic_chans[achans.ic_nchans++] = *c;
+ setbit(reported, c->ic_ieee);
+ }
+ }
+ } else {
+ 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 */
+ achans.ic_chans[achans.ic_nchans-1] = *c;
+ } else {
achans.ic_chans[achans.ic_nchans++] = *c;
+ setbit(reported, c->ic_ieee);
+ }
}
- } else
- achans = chans;
+ }
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]);
print_chaninfo(&achans.ic_chans[half+i]);
@@ -1663,31 +1710,6 @@
return IEEE80211_M_STA;
}
-static const struct ieee80211_channel *
-getchaninfo(int s, int chan)
-{
- struct ieee80211req ireq;
- static struct ieee80211req_chaninfo chans;
- static struct ieee80211_channel undef;
- const struct ieee80211_channel *c;
- int i, freq;
-
- (void) memset(&ireq, 0, sizeof(ireq));
- (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
- ireq.i_type = IEEE80211_IOC_CHANINFO;
- ireq.i_data = &chans;
- ireq.i_len = sizeof(chans);
- if (ioctl(s, SIOCG80211, &ireq) < 0)
- errx(1, "unable to get channel information");
- freq = ieee80211_ieee2mhz(chan);
- for (i = 0; i < chans.ic_nchans; i++) {
- c = &chans.ic_chans[i];
- if (c->ic_freq == freq)
- return c;
- }
- return &undef;
-}
-
#if 0
static void
printcipher(int s, struct ieee80211req *ireq, int keylenop)
@@ -1833,6 +1855,7 @@
int i, num, wpa, wme, bgscan, bgscaninterval;
struct ieee80211req ireq;
u_int8_t data[32];
+ struct ieee80211_channel chan;
const struct ieee80211_channel *c;
(void) memset(&ireq, 0, sizeof(ireq));
@@ -1864,14 +1887,27 @@
} else
print_string(data, ireq.i_len);
- ireq.i_type = IEEE80211_IOC_CHANNEL;
- if (ioctl(s, SIOCG80211, &ireq) < 0)
- goto end;
- c = getchaninfo(s, ireq.i_val);
- if (ireq.i_val != -1) {
- printf(" channel %d", ireq.i_val);
- if (verbose)
- printf(" (%u)", c->ic_freq);
+ ireq.i_data = &chan;
+ ireq.i_len = sizeof(chan);
+ ireq.i_type = IEEE80211_IOC_CURCHAN;
+ if (ioctl(s, SIOCG80211, &ireq) < 0) {
+ /* fall back to legacy ioctl */
+ ireq.i_data = NULL;
+ ireq.i_len = 0;
+ ireq.i_type = IEEE80211_IOC_CHANNEL;
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ goto end;
+ getchaninfo(s);
+ mapchan(&chan, ireq.i_val, 0);
+ }
+ c = &chan;
+ if (c->ic_freq != IEEE80211_CHAN_ANY) {
+ printf(" channel %d", c->ic_ieee);
+ if (verbose) {
+ char buf[14];
+ printf(" (%u Mhz%s)", c->ic_freq,
+ get_chaninfo(c, buf, sizeof(buf)));
+ }
} else if (verbose)
printf(" channel UNDEF");
@@ -2275,7 +2311,7 @@
}
static void
-set80211(int s, int type, int val, int len, u_int8_t *data)
+set80211(int s, int type, int val, int len, void *data)
{
struct ieee80211req ireq;
More information about the p4-projects
mailing list