// parseAttributes parses netlink attributes into a StationInfo's fields. func (info *StationInfo) parseAttributes(attrs []netlink.Attribute) error { for _, a := range attrs { switch a.Type { case nl80211.StaInfoConnectedTime: // Though nl80211 does not specify, this value appears to be in seconds: // * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected info.Connected = time.Duration(nlenc.Uint32(a.Data)) * time.Second case nl80211.StaInfoInactiveTime: // * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) info.Inactive = time.Duration(nlenc.Uint32(a.Data)) * time.Millisecond case nl80211.StaInfoRxBytes64: info.ReceivedBytes = nlenc.Uint64(a.Data) case nl80211.StaInfoTxBytes64: info.TransmittedBytes = nlenc.Uint64(a.Data) case nl80211.StaInfoSignal: // Converted into the typical negative strength format // * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) info.Signal = int(a.Data[0]) - math.MaxUint8 case nl80211.StaInfoRxPackets: info.ReceivedPackets = nlenc.Uint32(a.Data) case nl80211.StaInfoTxPackets: info.TransmittedPackets = nlenc.Uint32(a.Data) case nl80211.StaInfoTxRetries: info.TransmitRetries = nlenc.Uint32(a.Data) case nl80211.StaInfoTxFailed: info.TransmitFailed = nlenc.Uint32(a.Data) case nl80211.StaInfoBeaconLoss: info.BeaconLoss = nlenc.Uint32(a.Data) case nl80211.StaInfoRxBitrate, nl80211.StaInfoTxBitrate: rate, err := parseRateInfo(a.Data) if err != nil { return err } // TODO(mdlayher): return more statistics if they end up being // generally useful switch a.Type { case nl80211.StaInfoRxBitrate: info.ReceiveBitrate = rate.Bitrate case nl80211.StaInfoTxBitrate: info.TransmitBitrate = rate.Bitrate } } // Only use 32-bit counters if the 64-bit counters are not present. // If the 64-bit counters appear later in the slice, they will overwrite // these values. if info.ReceivedBytes == 0 && a.Type == nl80211.StaInfoRxBytes { info.ReceivedBytes = uint64(nlenc.Uint32(a.Data)) } if info.TransmittedBytes == 0 && a.Type == nl80211.StaInfoTxBytes { info.TransmittedBytes = uint64(nlenc.Uint32(a.Data)) } } return nil }
// parseRateInfo parses a rateInfo from netlink attributes. func parseRateInfo(b []byte) (*rateInfo, error) { attrs, err := netlink.UnmarshalAttributes(b) if err != nil { return nil, err } var info rateInfo for _, a := range attrs { switch a.Type { case nl80211.RateInfoBitrate32: info.Bitrate = int(nlenc.Uint32(a.Data)) } // Only use 16-bit counters if the 32-bit counters are not present. // If the 32-bit counters appear later in the slice, they will overwrite // these values. if info.Bitrate == 0 && a.Type == nl80211.RateInfoBitrate { info.Bitrate = int(nlenc.Uint16(a.Data)) } } // Scale bitrate to bits/second as base unit instead of 100kbits/second. // * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) info.Bitrate *= 100 * 1000 return &info, nil }
// parseMulticastGroups parses an array of multicast group nested attributes // into a slice of MulticastGroups. func parseMulticastGroups(b []byte) ([]MulticastGroup, error) { attrs, err := netlink.UnmarshalAttributes(b) if err != nil { return nil, err } groups := make([]MulticastGroup, 0, len(attrs)) for i, a := range attrs { // The type attribute is essentially an array index here; it starts // at 1 and should increment for each new array element if int(a.Type) != i+1 { return nil, errInvalidMulticastGroupArray } nattrs, err := netlink.UnmarshalAttributes(a.Data) if err != nil { return nil, err } var g MulticastGroup for _, na := range nattrs { switch na.Type { case attrMGName: g.Name = nlenc.String(na.Data) case attrMGID: g.ID = nlenc.Uint32(na.Data) } } groups = append(groups, g) } return groups, nil }
// parseAttributes parses netlink attributes into a Family's fields. func (f *Family) parseAttributes(attrs []netlink.Attribute) error { for _, a := range attrs { switch a.Type { case attrFamilyID: f.ID = nlenc.Uint16(a.Data) case attrFamilyName: f.Name = nlenc.String(a.Data) case attrVersion: v := nlenc.Uint32(a.Data) if v > math.MaxUint8 { return errInvalidFamilyVersion } f.Version = uint8(v) case attrMulticastGroups: groups, err := parseMulticastGroups(a.Data) if err != nil { return err } f.Groups = groups } } return nil }
// UnmarshalBinary unmarshals the contents of a byte slice into a Message. func (m *Message) UnmarshalBinary(b []byte) error { if len(b) < nlmsgHeaderLen { return errShortMessage } if len(b) != nlmsgAlign(len(b)) { return errUnalignedMessage } // Don't allow misleading length m.Header.Length = nlenc.Uint32(b[0:4]) if int(m.Header.Length) != len(b) { return errShortMessage } m.Header.Type = HeaderType(nlenc.Uint16(b[4:6])) m.Header.Flags = HeaderFlags(nlenc.Uint16(b[6:8])) m.Header.Sequence = nlenc.Uint32(b[8:12]) m.Header.PID = nlenc.Uint32(b[12:16]) m.Data = b[16:] return nil }
// parseAttributes parses netlink attributes into an Interface's fields. func (ifi *Interface) parseAttributes(attrs []netlink.Attribute) error { for _, a := range attrs { switch a.Type { case nl80211.AttrIfindex: ifi.Index = int(nlenc.Uint32(a.Data)) case nl80211.AttrIfname: ifi.Name = nlenc.String(a.Data) case nl80211.AttrMac: ifi.HardwareAddr = net.HardwareAddr(a.Data) case nl80211.AttrWiphy: ifi.PHY = int(nlenc.Uint32(a.Data)) case nl80211.AttrIftype: // NOTE: InterfaceType copies the ordering of nl80211's interface type // constants. This may not be the case on other operating systems. ifi.Type = InterfaceType(nlenc.Uint32(a.Data)) case nl80211.AttrWdev: ifi.Device = int(nlenc.Uint64(a.Data)) case nl80211.AttrWiphyFreq: ifi.Frequency = int(nlenc.Uint32(a.Data)) } } return nil }