From owner-svn-src-projects@FreeBSD.ORG Sat Feb 7 01:51:22 2009 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D82BE106564A; Sat, 7 Feb 2009 01:51:22 +0000 (UTC) (envelope-from sam@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id C63B18FC19; Sat, 7 Feb 2009 01:51:22 +0000 (UTC) (envelope-from sam@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n171pMj3077404; Sat, 7 Feb 2009 01:51:22 GMT (envelope-from sam@svn.freebsd.org) Received: (from sam@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n171pMGV077401; Sat, 7 Feb 2009 01:51:22 GMT (envelope-from sam@svn.freebsd.org) Message-Id: <200902070151.n171pMGV077401@svn.freebsd.org> From: Sam Leffler Date: Sat, 7 Feb 2009 01:51:22 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r188262 - projects/vap7/sbin/ifconfig X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 07 Feb 2009 01:51:23 -0000 Author: sam Date: Sat Feb 7 01:51:22 2009 New Revision: 188262 URL: http://svn.freebsd.org/changeset/base/188262 Log: merge r188258: regulatory fixups Modified: projects/vap7/sbin/ifconfig/ (props changed) projects/vap7/sbin/ifconfig/ifieee80211.c projects/vap7/sbin/ifconfig/regdomain.c projects/vap7/sbin/ifconfig/regdomain.h Modified: projects/vap7/sbin/ifconfig/ifieee80211.c ============================================================================== --- projects/vap7/sbin/ifconfig/ifieee80211.c Sat Feb 7 01:50:43 2009 (r188261) +++ projects/vap7/sbin/ifconfig/ifieee80211.c Sat Feb 7 01:51:22 2009 (r188262) @@ -99,10 +99,6 @@ #define IEEE80211_FIXED_RATE_NONE 0xff #endif -#define REQ_ECM 0x01000000 /* enable if ECM set */ -#define REQ_OUTDOOR 0x02000000 /* enable for outdoor operation */ -#define REQ_FLAGS 0xff000000 /* private flags, don't pass to os */ - /* XXX need these publicly defined or similar */ #ifndef IEEE80211_NODE_AUTH #define IEEE80211_NODE_AUTH 0x0001 /* authorized for data */ @@ -1802,6 +1798,57 @@ chanfind(const struct ieee80211_channel return 0; } +/* + * Check channel compatibility. + */ +static int +checkchan(const struct ieee80211req_chaninfo *avail, int freq, int flags) +{ + flags &= ~REQ_FLAGS; + /* + * Check if exact channel is in the calibration table; + * everything below is to deal with channels that we + * want to include but that are not explicitly listed. + */ + if (flags & IEEE80211_CHAN_HT40) { + /* NB: we use an HT40 channel center that matches HT20 */ + flags = (flags &~ IEEE80211_CHAN_HT40) | IEEE80211_CHAN_HT20; + } + if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, flags) != NULL) + return 1; + if (flags & IEEE80211_CHAN_GSM) { + /* + * XXX GSM frequency mapping is handled in the kernel + * so we cannot find them in the calibration table; + * just accept the channel and the kernel will reject + * the channel list if it's wrong. + */ + return 1; + } + /* + * If this is a 1/2 or 1/4 width channel allow it if a full + * width channel is present for this frequency, and the device + * supports fractional channels on this band. This is a hack + * that avoids bloating the calibration table; it may be better + * by per-band attributes though (we are effectively calculating + * this attribute by scanning the channel list ourself). + */ + if ((flags & (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == 0) + return 0; + if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, + flags &~ (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == NULL) + return 0; + if (flags & IEEE80211_CHAN_HALF) { + return chanfind(avail->ic_chans, avail->ic_nchans, + IEEE80211_CHAN_HALF | + (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ))); + } else { + return chanfind(avail->ic_chans, avail->ic_nchans, + IEEE80211_CHAN_QUARTER | + (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ))); + } +} + static void regdomain_addchans(struct ieee80211req_chaninfo *ci, const netband_head *bands, @@ -1812,15 +1859,12 @@ regdomain_addchans(struct ieee80211req_c const struct netband *nb; const struct freqband *b; struct ieee80211_channel *c, *prev; - int freq, channelSep, hasHalfChans, hasQuarterChans; + int freq, hi_adj, lo_adj, channelSep; + uint32_t flags; + hi_adj = (chanFlags & IEEE80211_CHAN_HT40U) ? -20 : 0; + lo_adj = (chanFlags & IEEE80211_CHAN_HT40D) ? 20 : 0; channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40; - hasHalfChans = chanfind(avail->ic_chans, avail->ic_nchans, - IEEE80211_CHAN_HALF | - (chanFlags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ))); - hasQuarterChans = chanfind(avail->ic_chans, avail->ic_nchans, - IEEE80211_CHAN_QUARTER | - (chanFlags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ))); LIST_FOREACH(nb, bands, next) { b = nb->band; if (verbose) { @@ -1831,63 +1875,80 @@ regdomain_addchans(struct ieee80211req_c putchar('\n'); } prev = NULL; - for (freq = b->freqStart; freq <= b->freqEnd; freq += b->chanSep) { - uint32_t flags = nb->flags | b->flags; - - /* check if device can operate on this frequency */ + for (freq = b->freqStart + lo_adj; + freq <= b->freqEnd + hi_adj; freq += b->chanSep) { + /* + * Construct flags for the new channel. We take + * the attributes from the band descriptions except + * for HT40 which is enabled generically (i.e. +/- + * extension channel) in the band description and + * then constrained according by channel separation. + */ + flags = nb->flags | b->flags; + if (flags & IEEE80211_CHAN_HT) { + /* + * HT channels are generated specially; we're + * called to add HT20, HT40+, and HT40- chan's + * so we need to expand only band specs for + * the HT channel type being added. + */ + if ((chanFlags & IEEE80211_CHAN_HT20) && + (flags & IEEE80211_CHAN_HT20) == 0) { + if (verbose) + printf("%u: skip, not an " + "HT20 channel\n", freq); + continue; + } + if ((chanFlags & IEEE80211_CHAN_HT40) && + (flags & IEEE80211_CHAN_HT40) == 0) { + if (verbose) + printf("%u: skip, not an " + "HT40 channel\n", freq); + continue; + } + /* + * DFS and HT40 don't mix. This should be + * expressed in the regdomain database but + * just in case enforce it here. + */ + if ((chanFlags & IEEE80211_CHAN_HT40) && + (flags & IEEE80211_CHAN_DFS)) { + if (verbose) + printf("%u: skip, HT40+DFS " + "not permitted\n", freq); + continue; + } + /* NB: HT attribute comes from caller */ + flags &= ~IEEE80211_CHAN_HT; + flags |= chanFlags & IEEE80211_CHAN_HT; + } /* - * XXX GSM frequency mapping is handled in the kernel - * so we cannot find them in the calibration table; - * just construct the list and the kernel will reject - * if it's wrong. + * Check if device can operate on this frequency. */ - if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, chanFlags) == NULL && - (flags & IEEE80211_CHAN_GSM) == 0) { + if (!checkchan(avail, freq, flags)) { if (verbose) { printf("%u: skip, ", freq); - printb("flags", chanFlags, + printb("flags", flags, IEEE80211_CHAN_BITS); printf(" not available\n"); } continue; } - if ((flags & IEEE80211_CHAN_HALF) && !hasHalfChans) { + if ((flags & REQ_ECM) && !reg->ecm) { if (verbose) - printf("%u: skip, device does not " - "support half-rate channel\n", - freq); + printf("%u: skip, ECM channel\n", freq); continue; } - if ((flags & IEEE80211_CHAN_QUARTER) && - !hasQuarterChans) { + if ((flags & REQ_INDOOR) && reg->location == 'O') { if (verbose) - printf("%u: skip, device does not " - "support quarter-rate channel\n", + printf("%u: skip, indoor channel\n", freq); continue; } - if ((flags & IEEE80211_CHAN_HT20) && - (chanFlags & IEEE80211_CHAN_HT20) == 0) { - if (verbose) - printf("%u: skip, device does not " - "support HT20 operation\n", freq); - continue; - } - if ((flags & IEEE80211_CHAN_HT40) && - (chanFlags & IEEE80211_CHAN_HT40) == 0) { - if (verbose) - printf("%u: skip, device does not " - "support HT40 operation\n", freq); - continue; - } - if ((flags & REQ_ECM) && !reg->ecm) { - if (verbose) - printf("%u: skip, ECM channel\n", freq); - continue; - } if ((flags & REQ_OUTDOOR) && reg->location == 'I') { if (verbose) - printf("%u: skip, outdoor channel\n", freq); + printf("%u: skip, outdoor channel\n", + freq); continue; } if ((flags & IEEE80211_CHAN_HT40) && @@ -1907,8 +1968,7 @@ regdomain_addchans(struct ieee80211req_c 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)); + c->ic_flags = flags; if (c->ic_flags & IEEE80211_CHAN_DFS) c->ic_maxregpower = nb->maxPowerDFS; else @@ -1973,27 +2033,31 @@ regdomain_makechannels( if (!LIST_EMPTY(&rd->bands_11a)) regdomain_addchans(ci, &rd->bands_11a, reg, IEEE80211_CHAN_A, &dc->dc_chaninfo); - if (!LIST_EMPTY(&rd->bands_11na)) { + if (!LIST_EMPTY(&rd->bands_11na) && dc->dc_htcaps != 0) { regdomain_addchans(ci, &rd->bands_11na, reg, IEEE80211_CHAN_A | IEEE80211_CHAN_HT20, &dc->dc_chaninfo); - regdomain_addchans(ci, &rd->bands_11na, reg, - IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U, - &dc->dc_chaninfo); - regdomain_addchans(ci, &rd->bands_11na, reg, - IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D, - &dc->dc_chaninfo); + if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) { + regdomain_addchans(ci, &rd->bands_11na, reg, + IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U, + &dc->dc_chaninfo); + regdomain_addchans(ci, &rd->bands_11na, reg, + IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D, + &dc->dc_chaninfo); + } } - if (!LIST_EMPTY(&rd->bands_11ng)) { + if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) { regdomain_addchans(ci, &rd->bands_11ng, reg, IEEE80211_CHAN_G | IEEE80211_CHAN_HT20, &dc->dc_chaninfo); - regdomain_addchans(ci, &rd->bands_11ng, reg, - IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U, - &dc->dc_chaninfo); - regdomain_addchans(ci, &rd->bands_11ng, reg, - IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D, - &dc->dc_chaninfo); + if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) { + regdomain_addchans(ci, &rd->bands_11ng, reg, + IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U, + &dc->dc_chaninfo); + regdomain_addchans(ci, &rd->bands_11ng, reg, + IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D, + &dc->dc_chaninfo); + } } qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]), regdomain_sort); Modified: projects/vap7/sbin/ifconfig/regdomain.c ============================================================================== --- projects/vap7/sbin/ifconfig/regdomain.c Sat Feb 7 01:50:43 2009 (r188261) +++ projects/vap7/sbin/ifconfig/regdomain.c Sat Feb 7 01:51:22 2009 (r188262) @@ -208,6 +208,9 @@ decode_flag(struct mystate *mt, const ch FLAG(IEEE80211_CHAN_108A), FLAG(IEEE80211_CHAN_108G), #undef FLAG + { "ECM", 3, REQ_ECM }, + { "INDOOR", 6, REQ_INDOOR }, + { "OUTDOOR", 7, REQ_OUTDOOR }, }; int i; Modified: projects/vap7/sbin/ifconfig/regdomain.h ============================================================================== --- projects/vap7/sbin/ifconfig/regdomain.h Sat Feb 7 01:50:43 2009 (r188261) +++ projects/vap7/sbin/ifconfig/regdomain.h Sat Feb 7 01:51:22 2009 (r188262) @@ -45,6 +45,13 @@ struct freqband { LIST_ENTRY(freqband) next; }; +/* private flags, don't pass to os */ +#define REQ_ECM 0x1 /* enable if ECM set */ +#define REQ_INDOOR 0x2 /* enable only for indoor operation */ +#define REQ_OUTDOOR 0x4 /* enable only for outdoor operation */ + +#define REQ_FLAGS (REQ_ECM|REQ_INDOOR|REQ_OUTDOOR) + struct netband { const struct freqband *band; /* channel list description */ uint8_t maxPower; /* regulatory cap on tx power (dBm) */