Merge pull request #425 from mdlayher/wifi-update
Update vendored wifi, handle stations with missing infopull/431/head
commit
acb495ccab
|
@ -155,12 +155,6 @@ func (c *wifiCollector) Update(ch chan<- prometheus.Metric) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := stat.StationInfo(ifi)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to retrieve station info for device %s: %v",
|
|
||||||
ifi.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.InterfaceFrequencyHertz,
|
c.InterfaceFrequencyHertz,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
|
@ -168,6 +162,16 @@ func (c *wifiCollector) Update(ch chan<- prometheus.Metric) error {
|
||||||
ifi.Name,
|
ifi.Name,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
info, err := stat.StationInfo(ifi)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("failed to retrieve station info for device %s: %v",
|
||||||
|
ifi.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
c.updateStationStats(ch, ifi.Name, info)
|
c.updateStationStats(ch, ifi.Name, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,19 @@ package wifi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// errNotStation is returned when attempting to query station info for
|
// errNotStation is returned when attempting to query station info for
|
||||||
// an interface which is not a station.
|
// an interface which is not a station.
|
||||||
errNotStation = errors.New("interface is not a station")
|
errNotStation = errors.New("interface is not a station")
|
||||||
|
|
||||||
|
// errUnimplemented is returned by all functions on platforms that
|
||||||
|
// do not have package wifi implemented.
|
||||||
|
errUnimplemented = fmt.Errorf("package wifi not implemented on %s/%s",
|
||||||
|
runtime.GOOS, runtime.GOARCH)
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Client is a type which can access WiFi device actions and statistics
|
// A Client is a type which can access WiFi device actions and statistics
|
||||||
|
@ -38,6 +45,11 @@ func (c *Client) Interfaces() ([]*Interface, error) {
|
||||||
return c.c.Interfaces()
|
return c.c.Interfaces()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BSS retrieves the BSS associated with a WiFi interface.
|
||||||
|
func (c *Client) BSS(ifi *Interface) (*BSS, error) {
|
||||||
|
return c.c.BSS(ifi)
|
||||||
|
}
|
||||||
|
|
||||||
// StationInfo retrieves statistics about a WiFi interface operating in
|
// StationInfo retrieves statistics about a WiFi interface operating in
|
||||||
// station mode.
|
// station mode.
|
||||||
func (c *Client) StationInfo(ifi *Interface) (*StationInfo, error) {
|
func (c *Client) StationInfo(ifi *Interface) (*StationInfo, error) {
|
||||||
|
@ -52,5 +64,6 @@ func (c *Client) StationInfo(ifi *Interface) (*StationInfo, error) {
|
||||||
type osClient interface {
|
type osClient interface {
|
||||||
Close() error
|
Close() error
|
||||||
Interfaces() ([]*Interface, error)
|
Interfaces() ([]*Interface, error)
|
||||||
|
BSS(ifi *Interface) (*BSS, error)
|
||||||
StationInfo(ifi *Interface) (*StationInfo, error)
|
StationInfo(ifi *Interface) (*StationInfo, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,13 @@
|
||||||
package wifi
|
package wifi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/mdlayher/netlink"
|
"github.com/mdlayher/netlink"
|
||||||
"github.com/mdlayher/netlink/genetlink"
|
"github.com/mdlayher/netlink/genetlink"
|
||||||
|
@ -96,10 +98,40 @@ func (c *client) Interfaces() ([]*Interface, error) {
|
||||||
return parseInterfaces(msgs)
|
return parseInterfaces(msgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BSS requests that nl80211 return the BSS for the specified Interface.
|
||||||
|
func (c *client) BSS(ifi *Interface) (*BSS, error) {
|
||||||
|
b, err := netlink.MarshalAttributes(ifi.idAttrs())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ask nl80211 to retrieve BSS information for the interface specified
|
||||||
|
// by its attributes
|
||||||
|
req := genetlink.Message{
|
||||||
|
Header: genetlink.Header{
|
||||||
|
Command: nl80211.CmdGetScan,
|
||||||
|
Version: c.familyVersion,
|
||||||
|
},
|
||||||
|
Data: b,
|
||||||
|
}
|
||||||
|
|
||||||
|
flags := netlink.HeaderFlagsRequest | netlink.HeaderFlagsDump
|
||||||
|
msgs, err := c.c.Execute(req, c.familyID, flags)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.checkMessages(msgs, nl80211.CmdNewScanResults); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseBSS(msgs)
|
||||||
|
}
|
||||||
|
|
||||||
// StationInfo requests that nl80211 return station info for the specified
|
// StationInfo requests that nl80211 return station info for the specified
|
||||||
// Interface.
|
// Interface.
|
||||||
func (c *client) StationInfo(ifi *Interface) (*StationInfo, error) {
|
func (c *client) StationInfo(ifi *Interface) (*StationInfo, error) {
|
||||||
b, err := netlink.MarshalAttributes(ifi.stationInfoAttrs())
|
b, err := netlink.MarshalAttributes(ifi.idAttrs())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -176,9 +208,9 @@ func parseInterfaces(msgs []genetlink.Message) ([]*Interface, error) {
|
||||||
return ifis, nil
|
return ifis, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// stationInfoAttrs returns the netlink attributes required from an Interface
|
// idAttrs returns the netlink attributes required from an Interface to retrieve
|
||||||
// to retrieve a StationInfo.
|
// more data about it.
|
||||||
func (ifi *Interface) stationInfoAttrs() []netlink.Attribute {
|
func (ifi *Interface) idAttrs() []netlink.Attribute {
|
||||||
return []netlink.Attribute{
|
return []netlink.Attribute{
|
||||||
{
|
{
|
||||||
Type: nl80211.AttrIfindex,
|
Type: nl80211.AttrIfindex,
|
||||||
|
@ -217,6 +249,80 @@ func (ifi *Interface) parseAttributes(attrs []netlink.Attribute) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseBSS parses a single BSS with a status attribute from nl80211 BSS messages.
|
||||||
|
func parseBSS(msgs []genetlink.Message) (*BSS, error) {
|
||||||
|
for _, m := range msgs {
|
||||||
|
attrs, err := netlink.UnmarshalAttributes(m.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range attrs {
|
||||||
|
if a.Type != nl80211.AttrBss {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
nattrs, err := netlink.UnmarshalAttributes(a.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The BSS which is associated with an interface will have a status
|
||||||
|
// attribute
|
||||||
|
if !attrsContain(nattrs, nl80211.BssStatus) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var bss BSS
|
||||||
|
if err := (&bss).parseAttributes(nattrs); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &bss, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, os.ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseAttributes parses netlink attributes into a BSS's fields.
|
||||||
|
func (b *BSS) parseAttributes(attrs []netlink.Attribute) error {
|
||||||
|
for _, a := range attrs {
|
||||||
|
switch a.Type {
|
||||||
|
case nl80211.BssBssid:
|
||||||
|
b.BSSID = net.HardwareAddr(a.Data)
|
||||||
|
case nl80211.BssFrequency:
|
||||||
|
b.Frequency = int(nlenc.Uint32(a.Data))
|
||||||
|
case nl80211.BssBeaconInterval:
|
||||||
|
// Raw value is in "Time Units (TU)". See:
|
||||||
|
// https://en.wikipedia.org/wiki/Beacon_frame
|
||||||
|
b.BeaconInterval = time.Duration(nlenc.Uint16(a.Data)) * 1024 * time.Microsecond
|
||||||
|
case nl80211.BssSeenMsAgo:
|
||||||
|
// * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
|
||||||
|
b.LastSeen = time.Duration(nlenc.Uint32(a.Data)) * time.Millisecond
|
||||||
|
case nl80211.BssStatus:
|
||||||
|
// NOTE: BSSStatus copies the ordering of nl80211's BSS status
|
||||||
|
// constants. This may not be the case on other operating systems.
|
||||||
|
b.Status = BSSStatus(nlenc.Uint32(a.Data))
|
||||||
|
case nl80211.BssInformationElements:
|
||||||
|
ies, err := parseIEs(a.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(mdlayher): return more IEs if they end up being generally useful
|
||||||
|
for _, ie := range ies {
|
||||||
|
switch ie.ID {
|
||||||
|
case ieSSID:
|
||||||
|
b.SSID = decodeSSID(ie.Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// parseStationInfo parses StationInfo attributes from a byte slice of
|
// parseStationInfo parses StationInfo attributes from a byte slice of
|
||||||
// netlink attributes.
|
// netlink attributes.
|
||||||
func parseStationInfo(b []byte) (*StationInfo, error) {
|
func parseStationInfo(b []byte) (*StationInfo, error) {
|
||||||
|
@ -262,23 +368,23 @@ func (info *StationInfo) parseAttributes(attrs []netlink.Attribute) error {
|
||||||
// * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
|
// * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
|
||||||
info.Inactive = time.Duration(nlenc.Uint32(a.Data)) * time.Millisecond
|
info.Inactive = time.Duration(nlenc.Uint32(a.Data)) * time.Millisecond
|
||||||
case nl80211.StaInfoRxBytes64:
|
case nl80211.StaInfoRxBytes64:
|
||||||
info.ReceivedBytes = nlenc.Uint64(a.Data)
|
info.ReceivedBytes = int(nlenc.Uint64(a.Data))
|
||||||
case nl80211.StaInfoTxBytes64:
|
case nl80211.StaInfoTxBytes64:
|
||||||
info.TransmittedBytes = nlenc.Uint64(a.Data)
|
info.TransmittedBytes = int(nlenc.Uint64(a.Data))
|
||||||
case nl80211.StaInfoSignal:
|
case nl80211.StaInfoSignal:
|
||||||
// Converted into the typical negative strength format
|
// Converted into the typical negative strength format
|
||||||
// * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
|
// * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
|
||||||
info.Signal = int(a.Data[0]) - math.MaxUint8
|
info.Signal = int(a.Data[0]) - math.MaxUint8
|
||||||
case nl80211.StaInfoRxPackets:
|
case nl80211.StaInfoRxPackets:
|
||||||
info.ReceivedPackets = nlenc.Uint32(a.Data)
|
info.ReceivedPackets = int(nlenc.Uint32(a.Data))
|
||||||
case nl80211.StaInfoTxPackets:
|
case nl80211.StaInfoTxPackets:
|
||||||
info.TransmittedPackets = nlenc.Uint32(a.Data)
|
info.TransmittedPackets = int(nlenc.Uint32(a.Data))
|
||||||
case nl80211.StaInfoTxRetries:
|
case nl80211.StaInfoTxRetries:
|
||||||
info.TransmitRetries = nlenc.Uint32(a.Data)
|
info.TransmitRetries = int(nlenc.Uint32(a.Data))
|
||||||
case nl80211.StaInfoTxFailed:
|
case nl80211.StaInfoTxFailed:
|
||||||
info.TransmitFailed = nlenc.Uint32(a.Data)
|
info.TransmitFailed = int(nlenc.Uint32(a.Data))
|
||||||
case nl80211.StaInfoBeaconLoss:
|
case nl80211.StaInfoBeaconLoss:
|
||||||
info.BeaconLoss = nlenc.Uint32(a.Data)
|
info.BeaconLoss = int(nlenc.Uint32(a.Data))
|
||||||
case nl80211.StaInfoRxBitrate, nl80211.StaInfoTxBitrate:
|
case nl80211.StaInfoRxBitrate, nl80211.StaInfoTxBitrate:
|
||||||
rate, err := parseRateInfo(a.Data)
|
rate, err := parseRateInfo(a.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -299,10 +405,10 @@ func (info *StationInfo) parseAttributes(attrs []netlink.Attribute) error {
|
||||||
// If the 64-bit counters appear later in the slice, they will overwrite
|
// If the 64-bit counters appear later in the slice, they will overwrite
|
||||||
// these values.
|
// these values.
|
||||||
if info.ReceivedBytes == 0 && a.Type == nl80211.StaInfoRxBytes {
|
if info.ReceivedBytes == 0 && a.Type == nl80211.StaInfoRxBytes {
|
||||||
info.ReceivedBytes = uint64(nlenc.Uint32(a.Data))
|
info.ReceivedBytes = int(nlenc.Uint32(a.Data))
|
||||||
}
|
}
|
||||||
if info.TransmittedBytes == 0 && a.Type == nl80211.StaInfoTxBytes {
|
if info.TransmittedBytes == 0 && a.Type == nl80211.StaInfoTxBytes {
|
||||||
info.TransmittedBytes = uint64(nlenc.Uint32(a.Data))
|
info.TransmittedBytes = int(nlenc.Uint32(a.Data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,6 +451,32 @@ func parseRateInfo(b []byte) (*rateInfo, error) {
|
||||||
return &info, nil
|
return &info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// attrsContain checks if a slice of netlink attributes contains an attribute
|
||||||
|
// with the specified type.
|
||||||
|
func attrsContain(attrs []netlink.Attribute, typ uint16) bool {
|
||||||
|
for _, a := range attrs {
|
||||||
|
if a.Type == typ {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeSSID safely parses a byte slice into UTF-8 runes, and returns the
|
||||||
|
// resulting string from the runes.
|
||||||
|
func decodeSSID(b []byte) string {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
for len(b) > 0 {
|
||||||
|
r, size := utf8.DecodeRune(b)
|
||||||
|
b = b[size:]
|
||||||
|
|
||||||
|
buf.WriteRune(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
var _ genl = &sysGENL{}
|
var _ genl = &sysGENL{}
|
||||||
|
|
||||||
// sysGENL is the system implementation of genl, using generic netlink.
|
// sysGENL is the system implementation of genl, using generic netlink.
|
||||||
|
|
|
@ -2,18 +2,6 @@
|
||||||
|
|
||||||
package wifi
|
package wifi
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// errUnimplemented is returned by all functions on platforms that
|
|
||||||
// do not have package wifi implemented.
|
|
||||||
errUnimplemented = fmt.Errorf("package wifi not implemented on %s/%s",
|
|
||||||
runtime.GOOS, runtime.GOARCH)
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ osClient = &client{}
|
var _ osClient = &client{}
|
||||||
|
|
||||||
// A conn is the no-op implementation of a netlink sockets connection.
|
// A conn is the no-op implementation of a netlink sockets connection.
|
||||||
|
@ -34,6 +22,11 @@ func (c *client) Interfaces() ([]*Interface, error) {
|
||||||
return nil, errUnimplemented
|
return nil, errUnimplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BSS always returns an error.
|
||||||
|
func (c *client) BSS(ifi *Interface) (*BSS, error) {
|
||||||
|
return nil, errUnimplemented
|
||||||
|
}
|
||||||
|
|
||||||
// StationInfo always returns an error.
|
// StationInfo always returns an error.
|
||||||
func (c *client) StationInfo(ifi *Interface) (*StationInfo, error) {
|
func (c *client) StationInfo(ifi *Interface) (*StationInfo, error) {
|
||||||
return nil, errUnimplemented
|
return nil, errUnimplemented
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
package wifi
|
package wifi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// errInvalidIE is returned when one or more IEs are malformed.
|
||||||
|
errInvalidIE = errors.New("invalid 802.11 information element")
|
||||||
|
)
|
||||||
|
|
||||||
// An InterfaceType is the operating mode of an Interface.
|
// An InterfaceType is the operating mode of an Interface.
|
||||||
type InterfaceType int
|
type InterfaceType int
|
||||||
|
|
||||||
|
@ -96,16 +103,16 @@ type StationInfo struct {
|
||||||
Inactive time.Duration
|
Inactive time.Duration
|
||||||
|
|
||||||
// The number of bytes received by this station.
|
// The number of bytes received by this station.
|
||||||
ReceivedBytes uint64
|
ReceivedBytes int
|
||||||
|
|
||||||
// The number of bytes transmitted by this station.
|
// The number of bytes transmitted by this station.
|
||||||
TransmittedBytes uint64
|
TransmittedBytes int
|
||||||
|
|
||||||
// The number of packets received by this station.
|
// The number of packets received by this station.
|
||||||
ReceivedPackets uint32
|
ReceivedPackets int
|
||||||
|
|
||||||
// The number of packets transmitted by this station.
|
// The number of packets transmitted by this station.
|
||||||
TransmittedPackets uint32
|
TransmittedPackets int
|
||||||
|
|
||||||
// The current data receive bitrate, in bits/second.
|
// The current data receive bitrate, in bits/second.
|
||||||
ReceiveBitrate int
|
ReceiveBitrate int
|
||||||
|
@ -117,11 +124,109 @@ type StationInfo struct {
|
||||||
Signal int
|
Signal int
|
||||||
|
|
||||||
// The number of times the station has had to retry while sending a packet.
|
// The number of times the station has had to retry while sending a packet.
|
||||||
TransmitRetries uint32
|
TransmitRetries int
|
||||||
|
|
||||||
// The number of times a packet transmission failed.
|
// The number of times a packet transmission failed.
|
||||||
TransmitFailed uint32
|
TransmitFailed int
|
||||||
|
|
||||||
// The number of times a beacon loss was detected.
|
// The number of times a beacon loss was detected.
|
||||||
BeaconLoss uint32
|
BeaconLoss int
|
||||||
|
}
|
||||||
|
|
||||||
|
// A BSS is an 802.11 basic service set. It contains information about a wireless
|
||||||
|
// network associated with an Interface.
|
||||||
|
type BSS struct {
|
||||||
|
// The service set identifier, or "network name" of the BSS.
|
||||||
|
SSID string
|
||||||
|
|
||||||
|
// The BSS service set identifier. In infrastructure mode, this is the
|
||||||
|
// hardware address of the wireless access point that a client is associated
|
||||||
|
// with.
|
||||||
|
BSSID net.HardwareAddr
|
||||||
|
|
||||||
|
// The frequency used by the BSS, in MHz.
|
||||||
|
Frequency int
|
||||||
|
|
||||||
|
// The interval between beacon transmissions for this BSS.
|
||||||
|
BeaconInterval time.Duration
|
||||||
|
|
||||||
|
// The time since the client last scanned this BSS's information.
|
||||||
|
LastSeen time.Duration
|
||||||
|
|
||||||
|
// The status of the client within the BSS.
|
||||||
|
Status BSSStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
// A BSSStatus indicates the current status of client within a BSS.
|
||||||
|
type BSSStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// BSSStatusAuthenticated indicates that a client is authenticated with a BSS.
|
||||||
|
BSSStatusAuthenticated BSSStatus = iota
|
||||||
|
|
||||||
|
// BSSStatusAssociated indicates that a client is associated with a BSS.
|
||||||
|
BSSStatusAssociated
|
||||||
|
|
||||||
|
// BSSStatusIBSSJoined indicates that a client has joined an independent BSS.
|
||||||
|
BSSStatusIBSSJoined
|
||||||
|
)
|
||||||
|
|
||||||
|
// String returns the string representation of a BSSStatus.
|
||||||
|
func (s BSSStatus) String() string {
|
||||||
|
switch s {
|
||||||
|
case BSSStatusAuthenticated:
|
||||||
|
return "authenticated"
|
||||||
|
case BSSStatusAssociated:
|
||||||
|
return "associated"
|
||||||
|
case BSSStatusIBSSJoined:
|
||||||
|
return "IBSS joined"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown(%d)", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List of 802.11 Information Element types.
|
||||||
|
const (
|
||||||
|
ieSSID = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// An ie is an 802.11 information element.
|
||||||
|
type ie struct {
|
||||||
|
ID uint8
|
||||||
|
// Length field implied by length of data
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseIEs parses zero or more ies from a byte slice.
|
||||||
|
// Reference:
|
||||||
|
// https://www.safaribooksonline.com/library/view/80211-wireless-networks/0596100523/ch04.html#wireless802dot112-CHP-4-FIG-31
|
||||||
|
func parseIEs(b []byte) ([]ie, error) {
|
||||||
|
var ies []ie
|
||||||
|
var i int
|
||||||
|
for {
|
||||||
|
if len(b[i:]) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if len(b[i:]) < 2 {
|
||||||
|
return nil, errInvalidIE
|
||||||
|
}
|
||||||
|
|
||||||
|
id := b[i]
|
||||||
|
i++
|
||||||
|
l := int(b[i])
|
||||||
|
i++
|
||||||
|
|
||||||
|
if len(b[i:]) < l {
|
||||||
|
return nil, errInvalidIE
|
||||||
|
}
|
||||||
|
|
||||||
|
ies = append(ies, ie{
|
||||||
|
ID: id,
|
||||||
|
Data: b[i : i+l],
|
||||||
|
})
|
||||||
|
|
||||||
|
i += l
|
||||||
|
}
|
||||||
|
|
||||||
|
return ies, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,10 +69,10 @@
|
||||||
"revisionTime": "2017-01-04T04:59:06Z"
|
"revisionTime": "2017-01-04T04:59:06Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "l8M/rZH5s/ZVtCCyeiUQXZ5FosA=",
|
"checksumSHA1": "J6L0K9aHO8riicB4BY8/WHb6wBI=",
|
||||||
"path": "github.com/mdlayher/wifi",
|
"path": "github.com/mdlayher/wifi",
|
||||||
"revision": "eb8b29b956ba5ff2fdd2d2f1f0b988b57fd3d8a3",
|
"revision": "85a20a7adc659e5007fb9dd0961ba4e8b7ea2f80",
|
||||||
"revisionTime": "2017-01-12T20:47:29Z"
|
"revisionTime": "2017-01-17T05:43:47Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "VzutdH69PUqRqhrDVv6F91ebQd4=",
|
"checksumSHA1": "VzutdH69PUqRqhrDVv6F91ebQd4=",
|
||||||
|
|
Loading…
Reference in New Issue