Merge pull request #412 from mdlayher/vendor-wifi

Vendor github.com/mdlayher/wifi and dependencies
This commit is contained in:
Johannes 'fish' Ziemke 2017-01-10 23:04:34 +01:00 committed by GitHub
commit 8ee7f5bad2
34 changed files with 8970 additions and 0 deletions

12
NOTICE
View file

@ -3,3 +3,15 @@ Copyright 2013-2015 The Prometheus Authors
This product includes software developed at
SoundCloud Ltd. (http://soundcloud.com/).
The following components are included in this product:
wifi
https://github.com/mdlayher/wifi
Copyright 2016-2017 Matt Layher
Licensed under the MIT License
netlink
https://github.com/mdlayher/netlink
Copyright 2016-2017 Matt Layher
Licensed under the MIT License

10
vendor/github.com/mdlayher/netlink/LICENSE.md generated vendored Normal file
View file

@ -0,0 +1,10 @@
MIT License
===========
Copyright (C) 2016 Matt Layher
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

21
vendor/github.com/mdlayher/netlink/README.md generated vendored Normal file
View file

@ -0,0 +1,21 @@
netlink [![Build Status](https://travis-ci.org/mdlayher/netlink.svg?branch=master)](https://travis-ci.org/mdlayher/netlink) [![GoDoc](https://godoc.org/github.com/mdlayher/netlink?status.svg)](https://godoc.org/github.com/mdlayher/netlink) [![Go Report Card](https://goreportcard.com/badge/github.com/mdlayher/netlink)](https://goreportcard.com/report/github.com/mdlayher/netlink)
=======
Package `netlink` provides low-level access to Linux netlink sockets.
MIT Licensed.
Why?
----
A [number of netlink packages](https://godoc.org/?q=netlink) are already
available for Go, but I wasn't able to find one that aligned with what
I wanted in a netlink package:
- Simple, idiomatic API
- Well tested
- Well documented
- Makes use of Go best practices
- Doesn't need root to work
My goal for this package is to use it as a building block for the creation
of other netlink protocol family packages.

39
vendor/github.com/mdlayher/netlink/align.go generated vendored Normal file
View file

@ -0,0 +1,39 @@
package netlink
import (
"unsafe"
)
// Functions and values used to properly align netlink messages, headers,
// and attributes. Definitions taken from Linux kernel source.
// #define NLMSG_ALIGNTO 4U
const nlmsgAlignTo = 4
// #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
func nlmsgAlign(len int) int {
return ((len) + nlmsgAlignTo - 1) & ^(nlmsgAlignTo - 1)
}
// #define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
func nlmsgLength(len int) int {
return len + nlmsgHeaderLen
}
// #define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
var nlmsgHeaderLen = nlmsgAlign(int(unsafe.Sizeof(Header{})))
// #define NLA_ALIGNTO 4
const nlaAlignTo = 4
// #define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
func nlaAlign(len int) int {
return ((len) + nlaAlignTo - 1) & ^(nlaAlignTo - 1)
}
// Because this package's Attribute type contains a byte slice, unsafe.Sizeof
// can't be used to determine the correct length.
const sizeofAttribute = 4
// #define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
var nlaHeaderLen = nlaAlign(sizeofAttribute)

122
vendor/github.com/mdlayher/netlink/attribute.go generated vendored Normal file
View file

@ -0,0 +1,122 @@
package netlink
import (
"errors"
"github.com/mdlayher/netlink/nlenc"
)
var (
// errInvalidAttribute specifies if an Attribute's length is incorrect.
errInvalidAttribute = errors.New("invalid attribute; length too short or too large")
)
// An Attribute is a netlink attribute. Attributes are packed and unpacked
// to and from the Data field of Message for some netlink protocol families.
type Attribute struct {
// Length of an Attribute, including this field and Type.
Length uint16
// The type of this Attribute, typically matched to a constant.
Type uint16
// An arbitrary payload which is specified by Type.
Data []byte
}
// MarshalBinary marshals an Attribute into a byte slice.
func (a Attribute) MarshalBinary() ([]byte, error) {
if int(a.Length) < nlaHeaderLen {
return nil, errInvalidAttribute
}
b := make([]byte, nlaAlign(int(a.Length)))
nlenc.PutUint16(b[0:2], a.Length)
nlenc.PutUint16(b[2:4], a.Type)
copy(b[4:], a.Data)
return b, nil
}
// UnmarshalBinary unmarshals the contents of a byte slice into an Attribute.
func (a *Attribute) UnmarshalBinary(b []byte) error {
if len(b) < nlaHeaderLen {
return errInvalidAttribute
}
a.Length = nlenc.Uint16(b[0:2])
a.Type = nlenc.Uint16(b[2:4])
if nlaAlign(int(a.Length)) > len(b) {
return errInvalidAttribute
}
switch {
// No length, no data
case a.Length == 0:
a.Data = make([]byte, 0)
// Not enough length for any data
case a.Length < 4:
return errInvalidAttribute
// Data present
case a.Length >= 4:
a.Data = make([]byte, len(b[4:a.Length]))
copy(a.Data, b[4:a.Length])
}
return nil
}
// MarshalAttributes packs a slice of Attributes into a single byte slice.
// In most cases, the Length field of each Attribute should be set to 0, so it
// can be calculated and populated automatically for each Attribute.
func MarshalAttributes(attrs []Attribute) ([]byte, error) {
var c int
for _, a := range attrs {
c += nlaAlign(len(a.Data))
}
b := make([]byte, 0, c)
for _, a := range attrs {
if a.Length == 0 {
a.Length = uint16(nlaHeaderLen + len(a.Data))
}
ab, err := a.MarshalBinary()
if err != nil {
return nil, err
}
b = append(b, ab...)
}
return b, nil
}
// UnmarshalAttributes unpacks a slice of Attributes from a single byte slice.
func UnmarshalAttributes(b []byte) ([]Attribute, error) {
var attrs []Attribute
var i int
for {
if len(b[i:]) == 0 {
break
}
var a Attribute
if err := (&a).UnmarshalBinary(b[i:]); err != nil {
return nil, err
}
if a.Length == 0 {
i += nlaHeaderLen
continue
}
i += nlaAlign(int(a.Length))
attrs = append(attrs, a)
}
return attrs, nil
}

220
vendor/github.com/mdlayher/netlink/conn.go generated vendored Normal file
View file

@ -0,0 +1,220 @@
package netlink
import (
"errors"
"math"
"os"
"sync/atomic"
)
// Error messages which can be returned by Validate.
var (
errMismatchedSequence = errors.New("mismatched sequence in netlink reply")
errMismatchedPID = errors.New("mismatched PID in netlink reply")
errShortErrorMessage = errors.New("not enough data for netlink error code")
)
// A Conn is a connection to netlink. A Conn can be used to send and
// receives messages to and from netlink.
type Conn struct {
// osConn is the operating system-specific implementation of
// a netlink sockets connection.
c osConn
// seq is an atomically incremented integer used to provide sequence
// numbers when Conn.Send is called.
seq *uint32
}
// An osConn is an operating-system specific implementation of netlink
// sockets used by Conn.
type osConn interface {
Close() error
Send(m Message) error
Receive() ([]Message, error)
JoinGroup(group uint32) error
LeaveGroup(group uint32) error
}
// Dial dials a connection to netlink, using the specified protocol number.
// Config specifies optional configuration for Conn. If config is nil, a default
// configuration will be used.
func Dial(proto int, config *Config) (*Conn, error) {
// Use OS-specific dial() to create osConn
c, err := dial(proto, config)
if err != nil {
return nil, err
}
return newConn(c), nil
}
// newConn is the internal constructor for Conn, used in tests.
func newConn(c osConn) *Conn {
return &Conn{
c: c,
seq: new(uint32),
}
}
// Close closes the connection.
func (c *Conn) Close() error {
return c.c.Close()
}
// Execute sends a single Message to netlink using Conn.Send, receives one or more
// replies using Conn.Receive, and then checks the validity of the replies against
// the request using Validate.
//
// See the documentation of Conn.Send, Conn.Receive, and Validate for details about
// each function.
func (c *Conn) Execute(m Message) ([]Message, error) {
req, err := c.Send(m)
if err != nil {
return nil, err
}
replies, err := c.Receive()
if err != nil {
return nil, err
}
if err := Validate(req, replies); err != nil {
return nil, err
}
return replies, nil
}
// Send sends a single Message to netlink. In most cases, m.Header's Length,
// Sequence, and PID fields should be set to 0, so they can be populated
// automatically before the Message is sent. On success, Send returns a copy
// of the Message with all parameters populated, for later validation.
//
// If m.Header.Length is 0, it will be automatically populated using the
// correct length for the Message, including its payload.
//
// If m.Header.Sequence is 0, it will be automatically populated using the
// next sequence number for this connection.
//
// If m.Header.PID is 0, it will be automatically populated using the
// process ID (PID) of this process.
func (c *Conn) Send(m Message) (Message, error) {
ml := nlmsgLength(len(m.Data))
// TODO(mdlayher): fine-tune this limit. ~4GiB is a huge message.
if ml > math.MaxUint32 {
return Message{}, errors.New("netlink message data too large")
}
if m.Header.Length == 0 {
m.Header.Length = uint32(nlmsgAlign(ml))
}
if m.Header.Sequence == 0 {
m.Header.Sequence = c.nextSequence()
}
if m.Header.PID == 0 {
m.Header.PID = uint32(os.Getpid())
}
if err := c.c.Send(m); err != nil {
return Message{}, err
}
return m, nil
}
// Receive receives one or more messages from netlink. Multi-part messages are
// handled transparently and returned as a single slice of Messages, with the
// final empty "multi-part done" message removed. If any of the messages
// indicate a netlink error, that error will be returned.
func (c *Conn) Receive() ([]Message, error) {
msgs, err := c.receive()
if err != nil {
return nil, err
}
// Trim the final message with multi-part done indicator if
// present
if m := msgs[len(msgs)-1]; m.Header.Flags&HeaderFlagsMulti != 0 && m.Header.Type == HeaderTypeDone {
return msgs[:len(msgs)-1], nil
}
return msgs, nil
}
// receive is the internal implementation of Conn.Receive, which can be called
// recursively to handle multi-part messages.
func (c *Conn) receive() ([]Message, error) {
msgs, err := c.c.Receive()
if err != nil {
return nil, err
}
// If this message is multi-part, we will need to perform an recursive call
// to continue draining the socket
var multi bool
for _, m := range msgs {
// Is this a multi-part message and is it not done yet?
if m.Header.Flags&HeaderFlagsMulti != 0 && m.Header.Type != HeaderTypeDone {
multi = true
}
if err := checkMessage(m); err != nil {
return nil, err
}
}
if !multi {
return msgs, nil
}
// More messages waiting
mmsgs, err := c.receive()
if err != nil {
return nil, err
}
return append(msgs, mmsgs...), nil
}
// JoinGroup joins a netlink multicast group by its ID.
func (c *Conn) JoinGroup(group uint32) error {
return c.c.JoinGroup(group)
}
// LeaveGroup leaves a netlink multicast group by its ID.
func (c *Conn) LeaveGroup(group uint32) error {
return c.c.LeaveGroup(group)
}
// nextSequence atomically increments Conn's sequence number and returns
// the incremented value.
func (c *Conn) nextSequence() uint32 {
return atomic.AddUint32(c.seq, 1)
}
// Validate validates one or more reply Messages against a request Message,
// ensuring that they contain matching sequence numbers and PIDs.
func Validate(request Message, replies []Message) error {
for _, m := range replies {
if m.Header.Sequence != request.Header.Sequence {
return errMismatchedSequence
}
if m.Header.PID != request.Header.PID {
return errMismatchedPID
}
}
return nil
}
// Config contains options for a Conn.
type Config struct {
// Groups is a bitmask which specifies multicast groups. If set to 0,
// no multicast group subscriptions will be made.
Groups uint32
}

194
vendor/github.com/mdlayher/netlink/conn_linux.go generated vendored Normal file
View file

@ -0,0 +1,194 @@
//+build linux
package netlink
import (
"errors"
"os"
"syscall"
"unsafe"
)
var (
errInvalidSockaddr = errors.New("expected syscall.SockaddrNetlink but received different syscall.Sockaddr")
errInvalidFamily = errors.New("received invalid netlink family")
)
var _ osConn = &conn{}
// A conn is the Linux implementation of a netlink sockets connection.
type conn struct {
s socket
sa *syscall.SockaddrNetlink
}
// A socket is an interface over socket system calls.
type socket interface {
Bind(sa syscall.Sockaddr) error
Close() error
Recvfrom(p []byte, flags int) (int, syscall.Sockaddr, error)
Sendto(p []byte, flags int, to syscall.Sockaddr) error
SetSockopt(level, name int, v unsafe.Pointer, l uint32) error
}
// dial is the entry point for Dial. dial opens a netlink socket using
// system calls.
func dial(family int, config *Config) (*conn, error) {
fd, err := syscall.Socket(
syscall.AF_NETLINK,
syscall.SOCK_RAW,
family,
)
if err != nil {
return nil, err
}
return bind(&sysSocket{fd: fd}, config)
}
// bind binds a connection to netlink using the input socket, which may be
// a system call implementation or a mocked one for tests.
func bind(s socket, config *Config) (*conn, error) {
if config == nil {
config = &Config{}
}
addr := &syscall.SockaddrNetlink{
Family: syscall.AF_NETLINK,
Groups: config.Groups,
}
if err := s.Bind(addr); err != nil {
return nil, err
}
return &conn{
s: s,
sa: addr,
}, nil
}
// Send sends a single Message to netlink.
func (c *conn) Send(m Message) error {
b, err := m.MarshalBinary()
if err != nil {
return err
}
return c.s.Sendto(b, 0, &syscall.SockaddrNetlink{
Family: syscall.AF_NETLINK,
})
}
// Receive receives one or more Messages from netlink.
func (c *conn) Receive() ([]Message, error) {
b := make([]byte, os.Getpagesize())
for {
// Peek at the buffer to see how many bytes are available
n, _, err := c.s.Recvfrom(b, syscall.MSG_PEEK)
if err != nil {
return nil, err
}
// Break when we can read all messages
if n < len(b) {
break
}
// Double in size if not enough bytes
b = make([]byte, len(b)*2)
}
// Read out all available messages
n, from, err := c.s.Recvfrom(b, 0)
if err != nil {
return nil, err
}
addr, ok := from.(*syscall.SockaddrNetlink)
if !ok {
return nil, errInvalidSockaddr
}
if addr.Family != syscall.AF_NETLINK {
return nil, errInvalidFamily
}
raw, err := syscall.ParseNetlinkMessage(b[:n])
if err != nil {
return nil, err
}
msgs := make([]Message, 0, len(raw))
for _, r := range raw {
m := Message{
Header: sysToHeader(r.Header),
Data: r.Data,
}
msgs = append(msgs, m)
}
return msgs, nil
}
// Close closes the connection.
func (c *conn) Close() error {
return c.s.Close()
}
const (
// #define SOL_NETLINK 270
solNetlink = 270
)
// JoinGroup joins a multicast group by ID.
func (c *conn) JoinGroup(group uint32) error {
return c.s.SetSockopt(
solNetlink,
syscall.NETLINK_ADD_MEMBERSHIP,
unsafe.Pointer(&group),
uint32(unsafe.Sizeof(group)),
)
}
// LeaveGroup leaves a multicast group by ID.
func (c *conn) LeaveGroup(group uint32) error {
return c.s.SetSockopt(
solNetlink,
syscall.NETLINK_DROP_MEMBERSHIP,
unsafe.Pointer(&group),
uint32(unsafe.Sizeof(group)),
)
}
// sysToHeader converts a syscall.NlMsghdr to a Header.
func sysToHeader(r syscall.NlMsghdr) Header {
// NB: the memory layout of Header and syscall.NlMsgHdr must be
// exactly the same for this unsafe cast to work
return *(*Header)(unsafe.Pointer(&r))
}
// newError converts an error number from netlink into the appropriate
// system call error for Linux.
func newError(errno int) error {
return syscall.Errno(errno)
}
var _ socket = &sysSocket{}
// A sysSocket is a socket which uses system calls for socket operations.
type sysSocket struct {
fd int
}
func (s *sysSocket) Bind(sa syscall.Sockaddr) error { return syscall.Bind(s.fd, sa) }
func (s *sysSocket) Close() error { return syscall.Close(s.fd) }
func (s *sysSocket) Recvfrom(p []byte, flags int) (int, syscall.Sockaddr, error) {
return syscall.Recvfrom(s.fd, p, flags)
}
func (s *sysSocket) Sendto(p []byte, flags int, to syscall.Sockaddr) error {
return syscall.Sendto(s.fd, p, flags, to)
}
func (s *sysSocket) SetSockopt(level, name int, v unsafe.Pointer, l uint32) error {
return setsockopt(s.fd, level, name, v, l)
}

55
vendor/github.com/mdlayher/netlink/conn_others.go generated vendored Normal file
View file

@ -0,0 +1,55 @@
//+build !linux
package netlink
import (
"fmt"
"runtime"
)
var (
// errUnimplemented is returned by all functions on platforms that
// cannot make use of netlink sockets.
errUnimplemented = fmt.Errorf("netlink sockets not implemented on %s/%s",
runtime.GOOS, runtime.GOARCH)
)
var _ osConn = &conn{}
// A conn is the no-op implementation of a netlink sockets connection.
type conn struct{}
// dial is the entry point for Dial. dial always returns an error.
func dial(family int, config *Config) (*conn, error) {
return nil, errUnimplemented
}
// Send always returns an error.
func (c *conn) Send(m Message) error {
return errUnimplemented
}
// Receive always returns an error.
func (c *conn) Receive() ([]Message, error) {
return nil, errUnimplemented
}
// Close always returns an error.
func (c *conn) Close() error {
return errUnimplemented
}
// JoinGroup always returns an error.
func (c *conn) JoinGroup(group uint32) error {
return errUnimplemented
}
// LeaveGroup always returns an error.
func (c *conn) LeaveGroup(group uint32) error {
return errUnimplemented
}
// newError always returns an error.
func newError(errno int) error {
return errUnimplemented
}

2
vendor/github.com/mdlayher/netlink/doc.go generated vendored Normal file
View file

@ -0,0 +1,2 @@
// Package netlink provides low-level access to Linux netlink sockets.
package netlink

34
vendor/github.com/mdlayher/netlink/fuzz.go generated vendored Normal file
View file

@ -0,0 +1,34 @@
//+build gofuzz
package netlink
func Fuzz(data []byte) int {
return fuzzAttributes(data)
//return fuzzMessage(data)
}
func fuzzAttributes(data []byte) int {
attrs, err := UnmarshalAttributes(data)
if err != nil {
return 0
}
if _, err := MarshalAttributes(attrs); err != nil {
panic(err)
}
return 1
}
func fuzzMessage(data []byte) int {
var m Message
if err := (&m).UnmarshalBinary(data); err != nil {
return 0
}
if _, err := m.MarshalBinary(); err != nil {
panic(err)
}
return 1
}

139
vendor/github.com/mdlayher/netlink/genetlink/conn.go generated vendored Normal file
View file

@ -0,0 +1,139 @@
package genetlink
import "github.com/mdlayher/netlink"
// Controller is the generic netlink controller family ID, used to issue
// requests to the controller.
const Controller = 0x10
// Protocol is the netlink protocol constant used to specify generic netlink.
const Protocol = 0x10
// A Conn is a generic netlink connection. A Conn can be used to send and
// receive generic netlink messages to and from netlink.
type Conn struct {
// Family provides functions to help retrieve generic netlink families.
Family *FamilyService
c conn
}
var _ conn = &netlink.Conn{}
// A conn is a netlink connection, which can be swapped for tests.
type conn interface {
Close() error
JoinGroup(group uint32) error
LeaveGroup(group uint32) error
Send(m netlink.Message) (netlink.Message, error)
Receive() ([]netlink.Message, error)
}
// Dial dials a generic netlink connection. Config specifies optional
// configuration for the underlying netlink connection. If config is
// nil, a default configuration will be used.
func Dial(config *netlink.Config) (*Conn, error) {
c, err := netlink.Dial(Protocol, config)
if err != nil {
return nil, err
}
return newConn(c), nil
}
// newConn is the internal constructor for Conn, used in tests.
func newConn(c conn) *Conn {
gc := &Conn{
c: c,
}
gc.Family = &FamilyService{c: gc}
return gc
}
// Close closes the connection.
func (c *Conn) Close() error {
return c.c.Close()
}
// JoinGroup joins a netlink multicast group by its ID.
func (c *Conn) JoinGroup(group uint32) error {
return c.c.JoinGroup(group)
}
// LeaveGroup leaves a netlink multicast group by its ID.
func (c *Conn) LeaveGroup(group uint32) error {
return c.c.LeaveGroup(group)
}
// Send sends a single Message to netlink, wrapping it in a netlink.Message
// using the specified generic netlink family and flags. On success, Send
// returns a copy of the netlink.Message with all parameters populated, for
// later validation.
func (c *Conn) Send(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) {
nm := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType(family),
Flags: flags,
},
}
mb, err := m.MarshalBinary()
if err != nil {
return netlink.Message{}, err
}
nm.Data = mb
reqnm, err := c.c.Send(nm)
if err != nil {
return netlink.Message{}, err
}
return reqnm, nil
}
// Receive receives one or more Messages from netlink. The netlink.Messages
// used to wrap each Message are available for later validation.
func (c *Conn) Receive() ([]Message, []netlink.Message, error) {
msgs, err := c.c.Receive()
if err != nil {
return nil, nil, err
}
gmsgs := make([]Message, 0, len(msgs))
for _, nm := range msgs {
var gm Message
if err := (&gm).UnmarshalBinary(nm.Data); err != nil {
return nil, nil, err
}
gmsgs = append(gmsgs, gm)
}
return gmsgs, msgs, nil
}
// Execute sends a single Message to netlink using Conn.Send, receives one or
// more replies using Conn.Receive, and then checks the validity of the replies
// against the request using netlink.Validate.
//
// See the documentation of Conn.Send, Conn.Receive, and netlink.Validate for
// details about each function.
func (c *Conn) Execute(m Message, family uint16, flags netlink.HeaderFlags) ([]Message, error) {
req, err := c.Send(m, family, flags)
if err != nil {
return nil, err
}
msgs, replies, err := c.Receive()
if err != nil {
return nil, err
}
if err := netlink.Validate(req, replies); err != nil {
return nil, err
}
return msgs, nil
}

2
vendor/github.com/mdlayher/netlink/genetlink/doc.go generated vendored Normal file
View file

@ -0,0 +1,2 @@
// Package genetlink implements generic netlink interactions and data types.
package genetlink

208
vendor/github.com/mdlayher/netlink/genetlink/family.go generated vendored Normal file
View file

@ -0,0 +1,208 @@
package genetlink
import (
"errors"
"fmt"
"math"
"github.com/mdlayher/netlink"
"github.com/mdlayher/netlink/nlenc"
)
// Constants used to request information from generic netlink controller.
// Reference: http://lxr.free-electrons.com/source/include/linux/genetlink.h?v=3.3#L35
const (
ctrlVersion = 1
ctrlCommandGetFamily = 3
)
var (
// errInvalidFamilyVersion is returned when a family's version is greater
// than an 8-bit integer.
errInvalidFamilyVersion = errors.New("invalid family version attribute")
// errInvalidMulticastGroupArray is returned when a multicast group array
// of attributes is malformed.
errInvalidMulticastGroupArray = errors.New("invalid multicast group attribute array")
)
// A Family is a generic netlink family.
type Family struct {
ID uint16
Version uint8
Name string
Groups []MulticastGroup
}
// A MulticastGroup is a generic netlink multicast group, which can be joined
// for notifications from generic netlink families when specific events take
// place.
type MulticastGroup struct {
ID uint32
Name string
}
// A FamilyService is used to retrieve generic netlink family information.
type FamilyService struct {
c *Conn
}
// Get retrieves a generic netlink family with the specified name. If the
// family does not exist, the error value can be checked using os.IsNotExist.
func (s *FamilyService) Get(name string) (Family, error) {
b, err := netlink.MarshalAttributes([]netlink.Attribute{{
Type: attrFamilyName,
Data: nlenc.Bytes(name),
}})
if err != nil {
return Family{}, err
}
req := Message{
Header: Header{
Command: ctrlCommandGetFamily,
Version: ctrlVersion,
},
Data: b,
}
msgs, err := s.c.Execute(req, Controller, netlink.HeaderFlagsRequest)
if err != nil {
return Family{}, err
}
// TODO(mdlayher): consider interpreting generic netlink header values
families, err := buildFamilies(msgs)
if err != nil {
return Family{}, err
}
if len(families) != 1 {
// If this were to ever happen, netlink must be in a state where
// its answers cannot be trusted
panic(fmt.Sprintf("netlink returned multiple families for name: %q", name))
}
return families[0], nil
}
// List retrieves all registered generic netlink families.
func (s *FamilyService) List() ([]Family, error) {
req := Message{
Header: Header{
Command: ctrlCommandGetFamily,
Version: ctrlVersion,
},
}
flags := netlink.HeaderFlagsRequest | netlink.HeaderFlagsDump
msgs, err := s.c.Execute(req, Controller, flags)
if err != nil {
return nil, err
}
return buildFamilies(msgs)
}
// buildFamilies builds a slice of Families by parsing attributes from the
// input Messages.
func buildFamilies(msgs []Message) ([]Family, error) {
families := make([]Family, 0, len(msgs))
for _, m := range msgs {
attrs, err := netlink.UnmarshalAttributes(m.Data)
if err != nil {
return nil, err
}
var f Family
if err := (&f).parseAttributes(attrs); err != nil {
return nil, err
}
families = append(families, f)
}
return families, nil
}
// Attribute IDs mapped to specific family fields.
const (
// TODO(mdlayher): parse additional attributes
// Family attributes
attrUnspecified = 0
attrFamilyID = 1
attrFamilyName = 2
attrVersion = 3
attrMulticastGroups = 7
// Multicast group-specific attributes
attrMGName = 1
attrMGID = 2
)
// 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
}
// 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
}

20
vendor/github.com/mdlayher/netlink/genetlink/fuzz.go generated vendored Normal file
View file

@ -0,0 +1,20 @@
//+build gofuzz
package genetlink
func Fuzz(data []byte) int {
return fuzzMessage(data)
}
func fuzzMessage(data []byte) int {
var m Message
if err := (&m).UnmarshalBinary(data); err != nil {
return 0
}
if _, err := m.MarshalBinary(); err != nil {
panic(err)
}
return 1
}

View file

@ -0,0 +1,65 @@
package genetlink
import (
"errors"
)
var (
// errInvalidMessage is returned when a Message is malformed.
errInvalidMessage = errors.New("generic netlink message is invalid or too short")
)
// A Header is a generic netlink header. A Header is sent and received with
// each generic netlink message to indicate metadata regarding a Message.
type Header struct {
// Command specifies a command to issue to netlink.
Command uint8
// Version specifies the version of a command to use.
Version uint8
}
// headerLen is the length of a Header.
const headerLen = 4
// A Message is a generic netlink message. It contains a Header and an
// arbitrary byte payload, which may be decoded using information from the
// Header.
//
// Data is encoded using the native endianness of the host system. Use
// the netlink.Uint* and netlink.PutUint* functions to encode and decode
// integers.
type Message struct {
Header Header
Data []byte
}
// MarshalBinary marshals a Message into a byte slice.
func (m Message) MarshalBinary() ([]byte, error) {
b := make([]byte, headerLen)
b[0] = m.Header.Command
b[1] = m.Header.Version
// b[2] and b[3] are padding bytes and set to zero
return append(b, m.Data...), nil
}
// UnmarshalBinary unmarshals the contents of a byte slice into a Message.
func (m *Message) UnmarshalBinary(b []byte) error {
if len(b) < headerLen {
return errInvalidMessage
}
// Don't allow reserved pad bytes to be set
if b[2] != 0 || b[3] != 0 {
return errInvalidMessage
}
m.Header.Command = b[0]
m.Header.Version = b[1]
m.Data = b[4:]
return nil
}

232
vendor/github.com/mdlayher/netlink/message.go generated vendored Normal file
View file

@ -0,0 +1,232 @@
package netlink
import (
"errors"
"fmt"
"github.com/mdlayher/netlink/nlenc"
)
// Various errors which may occur when attempting to marshal or unmarshal
// a Message to and from its binary form.
var (
errIncorrectMessageLength = errors.New("netlink message header length incorrect")
errShortMessage = errors.New("not enough data to create a netlink message")
errUnalignedMessage = errors.New("input data is not properly aligned for netlink message")
)
// HeaderFlags specify flags which may be present in a Header.
type HeaderFlags uint16
const (
// General netlink communication flags.
// HeaderFlagsRequest indicates a request to netlink.
HeaderFlagsRequest HeaderFlags = 1
// HeaderFlagsMulti indicates a multi-part message, terminated
// by HeaderTypeDone on the last message.
HeaderFlagsMulti HeaderFlags = 2
// HeaderFlagsAcknowledge requests that netlink reply with
// an acknowledgement using HeaderTypeError and, if needed,
// an error code.
HeaderFlagsAcknowledge HeaderFlags = 4
// HeaderFlagsEcho requests that netlink echo this request
// back to the sender.
HeaderFlagsEcho HeaderFlags = 8
// HeaderFlagsDumpInterrupted indicates that a dump was
// inconsistent due to a sequence change.
HeaderFlagsDumpInterrupted HeaderFlags = 16
// HeaderFlagsDumpFiltered indicates that a dump was filtered
// as requested.
HeaderFlagsDumpFiltered HeaderFlags = 32
// Flags used to retrieve data from netlink.
// HeaderFlagsRoot requests that netlink return a complete table instead
// of a single entry.
HeaderFlagsRoot HeaderFlags = 0x100
// HeaderFlagsMatch requests that netlink return a list of all matching
// entries.
HeaderFlagsMatch HeaderFlags = 0x200
// HeaderFlagsAtomic requests that netlink send an atomic snapshot of
// its entries. Requires CAP_NET_ADMIN or an effective UID of 0.
// May be obsolete.
HeaderFlagsAtomic HeaderFlags = 0x400
// HeaderFlagsDump requests that netlink return a complete list of
// all entries.
HeaderFlagsDump HeaderFlags = HeaderFlagsRoot | HeaderFlagsMatch
)
// String returns the string representation of a HeaderFlags.
func (f HeaderFlags) String() string {
names := []string{
"request",
"multi",
"acknowledge",
"echo",
"dumpinterrupted",
"dumpfiltered",
"1<<6",
"1<<7",
"root",
"match",
"atomic",
}
var s string
for i, name := range names {
if f&(1<<uint(i)) != 0 {
if s != "" {
s += "|"
}
s += name
}
}
if s == "" {
s = "0"
}
return s
}
// HeaderType specifies the type of a Header.
type HeaderType uint16
const (
// HeaderTypeNoop indicates that no action was taken.
HeaderTypeNoop HeaderType = 0x1
// HeaderTypeError indicates an error code is present, which is also
// used to indicate success when the code is 0.
HeaderTypeError HeaderType = 0x2
// HeaderTypeDone indicates the end of a multi-part message.
HeaderTypeDone HeaderType = 0x3
// HeaderTypeOverrun indicates that data was lost from this message.
HeaderTypeOverrun HeaderType = 0x4
)
// String returns the string representation of a HeaderType.
func (t HeaderType) String() string {
switch t {
case HeaderTypeNoop:
return "noop"
case HeaderTypeError:
return "error"
case HeaderTypeDone:
return "done"
case HeaderTypeOverrun:
return "overrun"
default:
return fmt.Sprintf("unknown(%d)", t)
}
}
// NB: the memory layout of Header and Linux's syscall.NlMsgHdr must be
// exactly the same. Cannot reorder, change data type, add, or remove fields.
// Named types of the same size (e.g. HeaderFlags is a uint16) are okay.
// A Header is a netlink header. A Header is sent and received with each
// Message to indicate metadata regarding a Message.
type Header struct {
// Length of a Message, including this Header.
Length uint32
// Contents of a Message.
Type HeaderType
// Flags which may be used to modify a request or response.
Flags HeaderFlags
// The sequence number of a Message.
Sequence uint32
// The process ID of the sending process.
PID uint32
}
// A Message is a netlink message. It contains a Header and an arbitrary
// byte payload, which may be decoded using information from the Header.
//
// Data is encoded in the native endianness of the host system. Use this
// package's Uint* and PutUint* functions to encode and decode integers.
type Message struct {
Header Header
Data []byte
}
// MarshalBinary marshals a Message into a byte slice.
func (m Message) MarshalBinary() ([]byte, error) {
ml := nlmsgAlign(int(m.Header.Length))
if ml < nlmsgHeaderLen || ml != int(m.Header.Length) {
return nil, errIncorrectMessageLength
}
b := make([]byte, ml)
nlenc.PutUint32(b[0:4], m.Header.Length)
nlenc.PutUint16(b[4:6], uint16(m.Header.Type))
nlenc.PutUint16(b[6:8], uint16(m.Header.Flags))
nlenc.PutUint32(b[8:12], m.Header.Sequence)
nlenc.PutUint32(b[12:16], m.Header.PID)
copy(b[16:], m.Data)
return b, 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
}
// checkMessage checks a single Message for netlink errors.
func checkMessage(m Message) error {
const success = 0
// HeaderTypeError may indicate an error code, or success
if m.Header.Type != HeaderTypeError {
return nil
}
if len(m.Data) < 4 {
return errShortErrorMessage
}
if c := nlenc.Int32(m.Data[0:4]); c != success {
// Error code is a negative integer, convert it into
// an OS-specific system call error
return newError(-1 * int(c))
}
return nil
}

3
vendor/github.com/mdlayher/netlink/nlenc/doc.go generated vendored Normal file
View file

@ -0,0 +1,3 @@
// Package nlenc implements encoding and decoding functions for netlink
// messages and attributes.
package nlenc

103
vendor/github.com/mdlayher/netlink/nlenc/int.go generated vendored Normal file
View file

@ -0,0 +1,103 @@
package nlenc
import (
"fmt"
"unsafe"
)
// PutUint16 encodes a uint16 into b using the host machine's native endianness.
// If b is not exactly 2 bytes in length, PutUint16 will panic.
func PutUint16(b []byte, v uint16) {
if l := len(b); l != 2 {
panic(fmt.Sprintf("PutUint16: unexpected byte slice length: %d", l))
}
*(*uint16)(unsafe.Pointer(&b[0])) = v
}
// PutUint32 encodes a uint32 into b using the host machine's native endianness.
// If b is not exactly 4 bytes in length, PutUint32 will panic.
func PutUint32(b []byte, v uint32) {
if l := len(b); l != 4 {
panic(fmt.Sprintf("PutUint32: unexpected byte slice length: %d", l))
}
*(*uint32)(unsafe.Pointer(&b[0])) = v
}
// PutUint64 encodes a uint64 into b using the host machine's native endianness.
// If b is not exactly 8 bytes in length, PutUint64 will panic.
func PutUint64(b []byte, v uint64) {
if l := len(b); l != 8 {
panic(fmt.Sprintf("PutUint64: unexpected byte slice length: %d", l))
}
*(*uint64)(unsafe.Pointer(&b[0])) = v
}
// Uint16 decodes a uint16 from b using the host machine's native endianness.
// If b is not exactly 2 bytes in length, Uint16 will panic.
func Uint16(b []byte) uint16 {
if l := len(b); l != 2 {
panic(fmt.Sprintf("Uint16: unexpected byte slice length: %d", l))
}
return *(*uint16)(unsafe.Pointer(&b[0]))
}
// Uint32 decodes a uint32 from b using the host machine's native endianness.
// If b is not exactly 4 bytes in length, Uint32 will panic.
func Uint32(b []byte) uint32 {
if l := len(b); l != 4 {
panic(fmt.Sprintf("Uint32: unexpected byte slice length: %d", l))
}
return *(*uint32)(unsafe.Pointer(&b[0]))
}
// Uint64 decodes a uint64 from b using the host machine's native endianness.
// If b is not exactly 8 bytes in length, Uint64 will panic.
func Uint64(b []byte) uint64 {
if l := len(b); l != 8 {
panic(fmt.Sprintf("Uint64: unexpected byte slice length: %d", l))
}
return *(*uint64)(unsafe.Pointer(&b[0]))
}
// Int32 decodes an int32 from b using the host machine's native endianness.
// If b is not exactly 4 bytes in length, Int32 will panic.
func Int32(b []byte) int32 {
if l := len(b); l != 4 {
panic(fmt.Sprintf("Int32: unexpected byte slice length: %d", l))
}
return *(*int32)(unsafe.Pointer(&b[0]))
}
// Uint16Bytes encodes a uint16 into a newly-allocated byte slice using the
// host machine's native endianness. It is a shortcut for allocating a new
// byte slice and filling it using PutUint16.
func Uint16Bytes(v uint16) []byte {
b := make([]byte, 2)
PutUint16(b, v)
return b
}
// Uint32Bytes encodes a uint32 into a newly-allocated byte slice using the
// host machine's native endianness. It is a shortcut for allocating a new
// byte slice and filling it using PutUint32.
func Uint32Bytes(v uint32) []byte {
b := make([]byte, 4)
PutUint32(b, v)
return b
}
// Uint64Bytes encodes a uint64 into a newly-allocated byte slice using the
// host machine's native endianness. It is a shortcut for allocating a new
// byte slice and filling it using PutUint64.
func Uint64Bytes(v uint64) []byte {
b := make([]byte, 8)
PutUint64(b, v)
return b
}

14
vendor/github.com/mdlayher/netlink/nlenc/string.go generated vendored Normal file
View file

@ -0,0 +1,14 @@
package nlenc
import "bytes"
// Bytes returns a null-terminated byte slice with the contents of s.
func Bytes(s string) []byte {
return append([]byte(s), 0x00)
}
// String returns a string with the contents of b from a null-terminated
// byte slice.
func String(b []byte) string {
return string(bytes.TrimSuffix(b, []byte{0x00}))
}

26
vendor/github.com/mdlayher/netlink/sockopt_linux.go generated vendored Normal file
View file

@ -0,0 +1,26 @@
// +build linux,!386
package netlink
import (
"syscall"
"unsafe"
)
// setsockopt provides access to the setsockopt syscall.
func setsockopt(fd, level, name int, v unsafe.Pointer, l uint32) error {
_, _, errno := syscall.Syscall6(
syscall.SYS_SETSOCKOPT,
uintptr(fd),
uintptr(level),
uintptr(name),
uintptr(v),
uintptr(l),
0,
)
if errno != 0 {
return error(errno)
}
return nil
}

View file

@ -0,0 +1,36 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux,386
package raw
import (
"syscall"
"unsafe"
)
const (
sysSETSOCKOPT = 0xe
)
func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
// setsockopt provides access to the setsockopt syscall.
func setsockopt(fd, level, name int, v unsafe.Pointer, l uint32) error {
_, errno := socketcall(
sysSETSOCKOPT,
uintptr(fd),
uintptr(level),
uintptr(name),
uintptr(v),
uintptr(l),
0,
)
if errno != 0 {
return error(errno)
}
return nil
}

View file

@ -0,0 +1,6 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
TEXT ·socketcall(SB),4,$0-36
JMP syscall·socketcall(SB)

10
vendor/github.com/mdlayher/wifi/LICENSE.md generated vendored Normal file
View file

@ -0,0 +1,10 @@
MIT License
===========
Copyright (C) 2016 Matt Layher
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

13
vendor/github.com/mdlayher/wifi/README.md generated vendored Normal file
View file

@ -0,0 +1,13 @@
wifi [![Build Status](https://travis-ci.org/mdlayher/wifi.svg?branch=master)](https://travis-ci.org/mdlayher/wifi) [![GoDoc](https://godoc.org/github.com/mdlayher/wifi?status.svg)](https://godoc.org/github.com/mdlayher/wifi) [![Go Report Card](https://goreportcard.com/badge/github.com/mdlayher/wifi)](https://goreportcard.com/report/github.com/mdlayher/wifi)
====
Package `wifi` provides access to IEEE 802.11 WiFi device actions and statistics.
MIT Licensed.
At this time, package `wifi` supports the following operating systems:
- **Linux**: using netlink, generic netlink, and nl80211.
If you would like to contribute support for another operating system, your
contributions would be very welcome! Feel free to file an issue to discuss
your plans.

36
vendor/github.com/mdlayher/wifi/client.go generated vendored Normal file
View file

@ -0,0 +1,36 @@
package wifi
// A Client is a type which can access WiFi device actions and statistics
// using operating system-specific operations.
type Client struct {
c osClient
}
// New creates a new Client.
func New() (*Client, error) {
c, err := newClient()
if err != nil {
return nil, err
}
return &Client{
c: c,
}, nil
}
// Interfaces returns a list of the system's WiFi network interfaces.
func (c *Client) Interfaces() ([]*Interface, error) {
return c.c.Interfaces()
}
// StationInfo retrieves statistics about a WiFi interface operating in
// station mode.
func (c *Client) StationInfo(ifi *Interface) (*StationInfo, error) {
return c.c.StationInfo(ifi)
}
// An osClient is the operating system-specific implementation of Client.
type osClient interface {
Interfaces() ([]*Interface, error)
StationInfo(ifi *Interface) (*StationInfo, error)
}

347
vendor/github.com/mdlayher/wifi/client_linux.go generated vendored Normal file
View file

@ -0,0 +1,347 @@
//+build linux
package wifi
import (
"errors"
"math"
"net"
"os"
"time"
"github.com/mdlayher/netlink"
"github.com/mdlayher/netlink/genetlink"
"github.com/mdlayher/netlink/nlenc"
"github.com/mdlayher/wifi/internal/nl80211"
)
// Errors which may occur when interacting with generic netlink.
var (
errMultipleMessages = errors.New("expected only one generic netlink message")
errInvalidCommand = errors.New("invalid generic netlink response command")
errInvalidFamilyVersion = errors.New("invalid generic netlink response family version")
)
var _ osClient = &client{}
// A client is the Linux implementation of osClient, which makes use of
// netlink, generic netlink, and nl80211 to provide access to WiFi device
// actions and statistics.
type client struct {
c genl
familyID uint16
familyVersion uint8
}
// genl is an interface over generic netlink, so netlink interactions can
// be stubbed in tests.
type genl interface {
GetFamily(name string) (genetlink.Family, error)
Execute(m genetlink.Message, family uint16, flags netlink.HeaderFlags) ([]genetlink.Message, error)
}
// newClient dials a generic netlink connection and verifies that nl80211
// is available for use by this package.
func newClient() (*client, error) {
c, err := genetlink.Dial(nil)
if err != nil {
return nil, err
}
g := &sysGENL{Conn: c}
return initClient(g)
}
// initClient is the internal constructor for a client, used in tests.
func initClient(c genl) (*client, error) {
family, err := c.GetFamily(nl80211.GenlName)
if err != nil {
return nil, err
}
return &client{
c: c,
familyID: family.ID,
familyVersion: family.Version,
}, nil
}
// Interfaces requests that nl80211 return a list of all WiFi interfaces present
// on this system.
func (c *client) Interfaces() ([]*Interface, error) {
// Ask nl80211 to dump a list of all WiFi interfaces
req := genetlink.Message{
Header: genetlink.Header{
Command: nl80211.CmdGetInterface,
Version: c.familyVersion,
},
}
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.CmdNewInterface); err != nil {
return nil, err
}
return parseInterfaces(msgs)
}
// StationInfo requests that nl80211 return station info for the specified
// Interface.
func (c *client) StationInfo(ifi *Interface) (*StationInfo, error) {
b, err := netlink.MarshalAttributes(ifi.stationInfoAttrs())
if err != nil {
return nil, err
}
// Ask nl80211 to retrieve station info for the interface specified
// by its attributes
req := genetlink.Message{
Header: genetlink.Header{
// From nl80211.h:
// * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
// * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
Command: nl80211.CmdGetStation,
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 len(msgs) > 1 {
return nil, errMultipleMessages
}
if err := c.checkMessages(msgs, nl80211.CmdNewStation); err != nil {
return nil, err
}
return parseStationInfo(msgs[0].Data)
}
// checkMessages verifies that response messages from generic netlink contain
// the command and family version we expect.
func (c *client) checkMessages(msgs []genetlink.Message, command uint8) error {
for _, m := range msgs {
if m.Header.Command != command {
return errInvalidCommand
}
if m.Header.Version != c.familyVersion {
return errInvalidFamilyVersion
}
}
return nil
}
// parseInterfaces parses zero or more Interfaces from nl80211 interface
// messages.
func parseInterfaces(msgs []genetlink.Message) ([]*Interface, error) {
ifis := make([]*Interface, 0, len(msgs))
for _, m := range msgs {
attrs, err := netlink.UnmarshalAttributes(m.Data)
if err != nil {
return nil, err
}
var ifi Interface
if err := (&ifi).parseAttributes(attrs); err != nil {
return nil, err
}
ifis = append(ifis, &ifi)
}
return ifis, nil
}
// stationInfoAttrs returns the netlink attributes required from an Interface
// to retrieve a StationInfo.
func (ifi *Interface) stationInfoAttrs() []netlink.Attribute {
return []netlink.Attribute{
{
Type: nl80211.AttrIfindex,
Data: nlenc.Uint32Bytes(uint32(ifi.Index)),
},
{
Type: nl80211.AttrMac,
Data: ifi.HardwareAddr,
},
}
}
// 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
}
// parseStationInfo parses StationInfo attributes from a byte slice of
// netlink attributes.
func parseStationInfo(b []byte) (*StationInfo, error) {
attrs, err := netlink.UnmarshalAttributes(b)
if err != nil {
return nil, err
}
for _, a := range attrs {
// The other attributes that are returned here appear to indicate the
// interface index and MAC address, which is information we already
// possess. No need to parse them for now.
if a.Type != nl80211.AttrStaInfo {
continue
}
nattrs, err := netlink.UnmarshalAttributes(a.Data)
if err != nil {
return nil, err
}
var info StationInfo
if err := (&info).parseAttributes(nattrs); err != nil {
return nil, err
}
return &info, nil
}
// No station info found
return nil, os.ErrNotExist
}
// 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
}
// rateInfo provides statistics about the receive or transmit rate of
// an interface.
type rateInfo struct {
// Bitrate in bits per second.
Bitrate int
}
// 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
}
var _ genl = &sysGENL{}
// sysGENL is the system implementation of genl, using generic netlink.
type sysGENL struct {
*genetlink.Conn
}
// GetFamily is a small adapter to make *genetlink.Conn implement genl.
func (g *sysGENL) GetFamily(name string) (genetlink.Family, error) {
return g.Conn.Family.Get(name)
}

35
vendor/github.com/mdlayher/wifi/client_others.go generated vendored Normal file
View file

@ -0,0 +1,35 @@
//+build !linux
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{}
// A conn is the no-op implementation of a netlink sockets connection.
type client struct{}
// newClient always returns an error.
func newClient() (*client, error) {
return nil, errUnimplemented
}
// Interfaces always returns an error.
func (c *client) Interfaces() ([]*Interface, error) {
return nil, errUnimplemented
}
// StationInfo always returns an error.
func (c *client) StationInfo(ifi *Interface) (*StationInfo, error) {
return nil, errUnimplemented
}

2
vendor/github.com/mdlayher/wifi/doc.go generated vendored Normal file
View file

@ -0,0 +1,2 @@
// Package wifi provides access to IEEE 802.11 WiFi device actions and statistics.
package wifi

1692
vendor/github.com/mdlayher/wifi/internal/nl80211/const.go generated vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,15 @@
// Package nl80211 is an auto-generated package which contains constants and
// types used to access nl80211 information using generic netlink.
//
// Special thanks to Maxim Kupriianov for the cgogen tool, which makes the
// automatic generation of Go constants possible.
//
// https://github.com/xlab/cgogen
//
// Maxim was also kind enough to provide the cgogen example configuration which
// was used to create this package.
//
// https://github.com/xlab/nl80211
package nl80211
//go:generate cgogen -out ../ -nocgo nl80211.yml

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,20 @@
---
GENERATOR:
PackageName: nl80211
PARSER:
IncludePaths: [/usr/include]
SourcesPaths: [nl80211.h]
TRANSLATOR:
ConstRules:
defines: expand
enum: expand
Rules:
const:
- {transform: lower}
- {action: accept, from: "(?i)nl80211_"}
- {action: replace, from: "(?i)nl80211_", to: _}
- {transform: export}
post-global:
- {load: snakecase}

127
vendor/github.com/mdlayher/wifi/wifi.go generated vendored Normal file
View file

@ -0,0 +1,127 @@
package wifi
import (
"net"
"time"
)
// An InterfaceType is the operating mode of an Interface.
type InterfaceType int
const (
// InterfaceTypeUnspecified indicates that an interface's type is unspecified
// and the driver determines its function.
InterfaceTypeUnspecified InterfaceType = iota
// InterfaceTypeAdHoc indicates that an interface is part of an independent
// basic service set (BSS) of client devices without a controlling access
// point.
InterfaceTypeAdHoc
// InterfaceTypeStation indicates that an interface is part of a managed
// basic service set (BSS) of client devices with a controlling access point.
InterfaceTypeStation
// InterfaceTypeAP indicates that an interface is an access point.
InterfaceTypeAP
// InterfaceTypeAPVLAN indicates that an interface is a VLAN interface
// associated with an access point.
InterfaceTypeAPVLAN
// InterfaceTypeWDS indicates that an interface is a wireless distribution
// interface, used as part of a network of multiple access points.
InterfaceTypeWDS
// InterfaceTypeMonitor indicates that an interface is a monitor interface,
// receiving all frames from all clients in a given network.
InterfaceTypeMonitor
// InterfaceTypeMeshPoint indicates that an interface is part of a wireless
// mesh network.
InterfaceTypeMeshPoint
// InterfaceTypeP2PClient indicates that an interface is a client within
// a peer-to-peer network.
InterfaceTypeP2PClient
// InterfaceTypeP2PGroupOwner indicates that an interface is the group
// owner within a peer-to-peer network.
InterfaceTypeP2PGroupOwner
// InterfaceTypeP2PDevice indicates that an interface is a device within
// a peer-to-peer client network.
InterfaceTypeP2PDevice
// InterfaceTypeOCB indicates that an interface is outside the context
// of a basic service set (BSS).
InterfaceTypeOCB
// InterfaceTypeNAN indicates that an interface is part of a near-me
// area network (NAN).
InterfaceTypeNAN
)
// An Interface is a WiFi network interface.
type Interface struct {
// The index of the interface.
Index int
// The name of the interface.
Name string
// The hardware address of the interface.
HardwareAddr net.HardwareAddr
// The physical device that this interface belongs to.
PHY int
// The virtual device number of this interface within a PHY.
Device int
// The operating mode of the interface.
Type InterfaceType
// The interface's wireless frequency in MHz.
Frequency int
}
// StationInfo contains statistics about a WiFi interface operating in
// station mode.
type StationInfo struct {
// The time since the station last connected.
Connected time.Duration
// The time since wireless activity last occurred.
Inactive time.Duration
// The number of bytes received by this station.
ReceivedBytes uint64
// The number of bytes transmitted by this station.
TransmittedBytes uint64
// The number of packets received by this station.
ReceivedPackets uint32
// The number of packets transmitted by this station.
TransmittedPackets uint32
// The current data receive bitrate, in bits/second.
ReceiveBitrate int
// The current data transmit bitrate, in bits/second.
TransmitBitrate int
// The signal strength of this station's connection, in dBm.
Signal int
// The number of times the station has had to retry while sending a packet.
TransmitRetries uint32
// The number of times a packet transmission failed.
TransmitFailed uint32
// The number of times a beacon loss was detected.
BeaconLoss uint32
}

30
vendor/vendor.json vendored
View file

@ -50,6 +50,36 @@
"revision": "c12348ce28de40eed0136aa2b644d0ee0650e56c",
"revisionTime": "2016-04-24T11:30:07Z"
},
{
"checksumSHA1": "dG2VS6m8AS9wvpZh7aSx5AX001U=",
"path": "github.com/mdlayher/netlink",
"revision": "1291b75abe0cc0cb335f110466bf1f02590c916d",
"revisionTime": "2017-01-04T04:59:06Z"
},
{
"checksumSHA1": "+2roeIWCAjCC58tZcs12Vqgf1Io=",
"path": "github.com/mdlayher/netlink/genetlink",
"revision": "1291b75abe0cc0cb335f110466bf1f02590c916d",
"revisionTime": "2017-01-04T04:59:06Z"
},
{
"checksumSHA1": "9udZUcU9bmkXtnkyLNqJ8jKRt0c=",
"path": "github.com/mdlayher/netlink/nlenc",
"revision": "1291b75abe0cc0cb335f110466bf1f02590c916d",
"revisionTime": "2017-01-04T04:59:06Z"
},
{
"checksumSHA1": "dSy4F6HRYyadhiQbv3Bof/Tdxec=",
"path": "github.com/mdlayher/wifi",
"revision": "88fd1c0ec178645c1b7d300090b5a9d4b226b8e1",
"revisionTime": "2017-01-07T15:17:58Z"
},
{
"checksumSHA1": "VzutdH69PUqRqhrDVv6F91ebQd4=",
"path": "github.com/mdlayher/wifi/internal/nl80211",
"revision": "88fd1c0ec178645c1b7d300090b5a9d4b226b8e1",
"revisionTime": "2017-01-07T15:17:58Z"
},
{
"checksumSHA1": "/j0HRFJPThv7HEkZZ/gurf+5fQI=",
"origin": "github.com/prometheus/node_exporter/vendor/github.com/prometheus/client_golang/prometheus",