Skip to content

Feat: extended rate parsing#142

Open
lukas-mbag wants to merge 12 commits into
mdlayher:mainfrom
mercedes-benz:feat-better-rate-parsing
Open

Feat: extended rate parsing#142
lukas-mbag wants to merge 12 commits into
mdlayher:mainfrom
mercedes-benz:feat-better-rate-parsing

Conversation

@lukas-mbag

Copy link
Copy Markdown
Contributor

This Pull Request makes the RateInfo available for the user.

I am looking for feedback (@SuperQ ?)on the API-Design for the User of this Library. If nobody objects, I will add in testcases and cleanup the documentation before un-drafting this Pull Request.

My Usecase
I want to access the MCS-Index and the number of Spacial Stream (NSS) for RX and TX of the current Connection together with a string description similar to the one provided by the iw wlan0 link command (i.e. rx bitrate: 173.3 MBit/s VHT-MCS 8 short GI VHT-NSS 2).

Changes

  • Introduce a new public Interface RateModulationInfo with the following Methodes:
    • GetMCS() int
    • GetNSS() int
    • Description() string
    • WifiGeneration() string
  • Introduce 4 concrete Types that implement the interface: HTModulationInfo, VHTModulationInfo, HEModulationInfo and EHTModulationInfo
  • Move Type rateInfo from client_linux.go to wifi.go and make it public
  • Add the new RateModulationInfo Interface to the RateInfo struct. Also add ChannelWidth and ModulationType
  • extend the parseRateInfo(b []byte) (*RateInfo, error) function to populate the new fields
  • Add RateInfo (for Rx and Tx) to the StationInfo Struct

Caveats

  1. We return an Interface in the RateInfo Struct. If user wants to use parts of the types that are not in the Interface, they have type-cast the concrete struct to the desired type. MCS. NSS, Description and WiFiGeneration are available for all Types
  2. Sorting of the sub-stings in Description() can differ from the iw output (i.e. in my real-world testcase the "shortGI" string is placed at the End of the string not in-between MCS and NSS as in the iw output)
  3. Within Station Info there is now duplicate Information (the bitrate itself) is available directly via StationInfo.ReceiveBitrate and is also Part of the RateInfo Type StationInfo.ReceiveRateInfo.Bitrate. This keeps the API of Station Info backwards-compatible but also groups it with the rest of the rate and modulation info.
  4. No Test-Cases yet (see above, will be added if we go forward with the current design)

The program was tested solely for our own use cases, which might differ from yours.

Lukas Raffelt < lukas.raffelt@mercedes-benz.com > on behalf of Mercedes-Benz Tech Innovation GmbH, Provider Information

Licensed under MIT

add basic MCS Decoding
test: add additional station info test case with MCS attributes
feat: add support for VHT MCS indexes in StationInfo and related parsing logic
feat: enhance StationInfo with detailed rate information and VHT support
expose Interface
create subtypes that implement the interface
@lukas-mbag lukas-mbag force-pushed the feat-better-rate-parsing branch from d82f780 to c608a43 Compare January 21, 2026 14:10
@lukas-mbag lukas-mbag marked this pull request as ready for review January 21, 2026 15:11
@lukas-mbag

Copy link
Copy Markdown
Contributor Author

I have added several testcases in TestLinux_clientStationInfoOK in order to increase the test coverage of the new Functionality

@SuperQ

SuperQ commented Apr 1, 2026

Copy link
Copy Markdown
Collaborator

Thanks, I'll try and get to this soon.

Maybe @nickgarlis would also like to take a look.

@nickgarlis nickgarlis left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not familiar with this module but I've left some comments on things that I've noticed.

Overall, it seems like a good idea to extend StationInfo with those extra attributes.

Comment thread client_linux_test.go
func modulationAttributes(rateInfo RateModulationInfo) (attr []netlink.Attribute) {
// attr = append(attr, netlink.Attribute{Type: unix.NL80211_RATE_INFO_BITRATE, Data: nlenc.Uint16Bytes(uint16(bitrateAttr(s.ReceiveBitrate)))})
// attr = append(attr, netlink.Attribute{Type: unix.NL80211_RATE_INFO_BITRATE32, Data: nlenc.Uint32Bytes(bitrateAttr(s.ReceiveBitrate))})
switch ri := rateInfo.(type) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the RateModulationInfo interface also implement a marshal and unmarshal function so that this becomes a bit easier to read ?

Comment thread wifi.go
type BaseModulationInfo struct {
MCS int
NSS int
IwDescription string

@nickgarlis nickgarlis Apr 1, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can IwDescription be built by the Description function instead ?

This would mean that it'd have to be implemented on each type that implements BaseModulationInfo. If you also turned those attributes into their own types, you could use their String methods.

Personally, I prefer to keep the deserialization/serialization logic focused on fields returned/sent from/to the kernel.

Comment thread client_linux.go
iwDescription += fmt.Sprintf(" VHT-MCS %d", vhtModulationInfo.MCS)
case unix.NL80211_RATE_INFO_40_MHZ_WIDTH:
channelWidth = ChannelWidth40
iwDescription += " 40MHz"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChannelWidth implements a String function which seems to be returning the same values. Can it be reused ?

Comment thread client_linux.go
vhtModulationInfo.ShortGI = true
iwDescription += " Short GI"
case unix.NL80211_RATE_INFO_VHT_NSS:
vhtModulationInfo.NSS = int(nlenc.Uint8(a.Data))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could there be a custom type (just like ChannelWidth) for NSS, MCS etc. ? If so then the type could implement a String function too.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, NVM. This would be an overkill given that the values are not fixed.

Comment thread client_linux.go

// parseRateInfo parses a rateInfo from netlink attributes.
func parseRateInfo(b []byte) (*rateInfo, error) {
func parseRateInfo(b []byte) (*RateInfo, error) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize that parseRateInfo returned a pointer of *rateInfo before but I am wondering whether this could be changed to RateInfo now since it's being dereferenced downstream.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants