From owner-p4-projects@FreeBSD.ORG Sun Jan 21 19:55:01 2007 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 649E716A404; Sun, 21 Jan 2007 19:55:01 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id ECD4616A400 for ; Sun, 21 Jan 2007 19:55:00 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.freebsd.org (Postfix) with ESMTP id CED4213C44B for ; Sun, 21 Jan 2007 19:55:00 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id l0LJt0pS020287 for ; Sun, 21 Jan 2007 19:55:00 GMT (envelope-from sam@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id l0LJt0Cg020272 for perforce@freebsd.org; Sun, 21 Jan 2007 19:55:00 GMT (envelope-from sam@freebsd.org) Date: Sun, 21 Jan 2007 19:55:00 GMT Message-Id: <200701211955.l0LJt0Cg020272@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to sam@freebsd.org using -f From: Sam Leffler To: Perforce Change Reviews Cc: Subject: PERFORCE change 113264 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 21 Jan 2007 19:55:01 -0000 http://perforce.freebsd.org/chv.cgi?CH=113264 Change 113264 by sam@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;