On Tue, Sep 02, 2025 at 01:36:02PM +0200, Johannes Berg wrote: > To maybe describe where I'm confused more clearly: > > > > * ->chan points to the primary 1MHz or 2MHz channel > > This was based on something I said. When I first read it it, I thought > this was because 2 MHz primary channel was a completely independent mode > of operation of the two 1 MHz frequency ranges that make up this 2 MHz > range. > > But maybe that was wrong? Because you also said this: > > > > As mentioned, the one difference is that S1G primary channels can be 2MHz. > > > The standard (and by extension, the S1G Operation element) uses the notion of > > > primary channel location. When we have a 2MHz primary channel, the AP must > > > specify which 1MHz subchannel _within_ this 2MHz primary channel is used. > > So this seems to indicate the primary channel is always 1 MHz? Not necessarily, in fact most cases we use a 2MHz primary when possible. In cases like this, beacons are transmitted on the center frequency of the 2MHz primary channel (And I realise Im just saying "channel" again). This is a composite of 2 1MHz subchannels and we then specify the location of the 1MHz subchannel and advertise this to STAs (This is done in hostapd anyway, so not really a concern here). With the flag you suggested below, this is fine though. > Looking at the spec, the S1G operation says you have _both_: > - the primary width [B0] > - the overall width 1/2/4/8/16 MHz [B1-B4] > - the location of the 1 MHz primary inside the 2 MHz primary [B5] > - the overall channel center frequency (as a channel number) > > So something like Channel 44/8MHz with 1 MHz primary in the upper half > of the primary 2 MHz would be > > - primary 1 MHz width B0 == 0 > - 8 MHz width B1-B4 == 7 > (? Table 10-41 S1G BSS operation channel width) > - primary channel num 38 > - channel center freq 44 > > > But I don't think we necessarily have to capture this the same way in > our chandef. > > We could also say that the 'control' channel pointer always points to > the primary 1 MHz. Then, we only need a single flag in the *chandef* to > capture the whole definition, in this example: > > - chan: pointer to struct ieee80211_channel for channel 37 > - width: 8 MHz > - center_freq1: 925 Mhz (== channel 44) > - s1g_primary_2mhz: true This makes sense to me. One misunderstanding I had (that you brought up in the email before this one) was that only 20MHz control channels are advertised, for example, with VHT. I think I better now understand the structure of the chandef (hopefully) such that now the driver would advertise _only_ 1MHz control channels. Then the flag can indicate if we have a 2MHz primary and then the actual chandef fields can describe the wider operating channel. > All the locations automatically follow, you just need a little bit of a > helper to calculate the "primary channel num" for the S1G operating > element, since that's now no longer obvious - but basically just > > if (!chandef->s1g_primary_2mhz) > return channel_number(chandef->chan); > BUG_ON(chandef->width == 1MHz); > > ... depends on width and distance between chandef->center_freq1 > and chandef->chan->center_freq but I'm too lazy to write it down > since that also depends on the _khz bits. something like > > diff = 1000 * chandef->center_freq1 + chandef->center_freq1_offset > - 1000 * chandef->chan->center_freq > - chandef->chan->center_freq_offset; > diff = abs(diff) > > and then take the figure you had before into account: > > > |------|---------------------------------------------|*| > > c | 8MHz | | 44 | |*| > > h |------|---------------------------------------------|*| > > a | 4MHz | | 40 | 48 | |*| > > n |------|---------------------------------------------|*| > > n | 2MHz | | 38 | 42 | 46 | 50 | |*| > > e |------|---------------------------------------------|*| > > l | 1MHz | | 37 | 39 | 41 | 43 | 45 | 47 | 49 | 51 | |*| > > |======|=============================================|*| > > |******| 920 921 922 923 924 925 926 927 928 |*| > > |******|---------------------------------------------|*| > > frequency (MHz) > > > That should work? > > > Then we also only need struct ieee80211_channel for each 1 MHz channel, > your thing with the regulatory "non-primary flag" also works more > easily? Yes this works. If we have the s1g_primary_2mhz set to true we'd need to do some validation that both 1Mhz subchannels dont contain the NO_PRIMARY flag, but that should be fairly straightforward. These emails have been very helpful, will go ahead and draft the patchset then probably send sometime next week for RFC. lachlan