mirror of
https://github.com/prometheus/node_exporter.git
synced 2024-12-28 23:19:46 -08:00
Merge pull request #412 from mdlayher/vendor-wifi
Vendor github.com/mdlayher/wifi and dependencies
This commit is contained in:
commit
8ee7f5bad2
12
NOTICE
12
NOTICE
|
@ -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
10
vendor/github.com/mdlayher/netlink/LICENSE.md
generated
vendored
Normal 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
21
vendor/github.com/mdlayher/netlink/README.md
generated
vendored
Normal 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
39
vendor/github.com/mdlayher/netlink/align.go
generated
vendored
Normal 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
122
vendor/github.com/mdlayher/netlink/attribute.go
generated
vendored
Normal 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
220
vendor/github.com/mdlayher/netlink/conn.go
generated
vendored
Normal 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
194
vendor/github.com/mdlayher/netlink/conn_linux.go
generated
vendored
Normal 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
55
vendor/github.com/mdlayher/netlink/conn_others.go
generated
vendored
Normal 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
2
vendor/github.com/mdlayher/netlink/doc.go
generated
vendored
Normal 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
34
vendor/github.com/mdlayher/netlink/fuzz.go
generated
vendored
Normal 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
139
vendor/github.com/mdlayher/netlink/genetlink/conn.go
generated
vendored
Normal 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
2
vendor/github.com/mdlayher/netlink/genetlink/doc.go
generated
vendored
Normal 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
208
vendor/github.com/mdlayher/netlink/genetlink/family.go
generated
vendored
Normal 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
20
vendor/github.com/mdlayher/netlink/genetlink/fuzz.go
generated
vendored
Normal 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
|
||||
}
|
65
vendor/github.com/mdlayher/netlink/genetlink/message.go
generated
vendored
Normal file
65
vendor/github.com/mdlayher/netlink/genetlink/message.go
generated
vendored
Normal 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
232
vendor/github.com/mdlayher/netlink/message.go
generated
vendored
Normal 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
3
vendor/github.com/mdlayher/netlink/nlenc/doc.go
generated
vendored
Normal 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
103
vendor/github.com/mdlayher/netlink/nlenc/int.go
generated
vendored
Normal 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
14
vendor/github.com/mdlayher/netlink/nlenc/string.go
generated
vendored
Normal 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
26
vendor/github.com/mdlayher/netlink/sockopt_linux.go
generated
vendored
Normal 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
|
||||
}
|
36
vendor/github.com/mdlayher/netlink/sockopt_linux_386.go
generated
vendored
Normal file
36
vendor/github.com/mdlayher/netlink/sockopt_linux_386.go
generated
vendored
Normal 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
|
||||
}
|
6
vendor/github.com/mdlayher/netlink/sockopt_linux_386.s
generated
vendored
Normal file
6
vendor/github.com/mdlayher/netlink/sockopt_linux_386.s
generated
vendored
Normal 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
10
vendor/github.com/mdlayher/wifi/LICENSE.md
generated
vendored
Normal 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
13
vendor/github.com/mdlayher/wifi/README.md
generated
vendored
Normal 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
36
vendor/github.com/mdlayher/wifi/client.go
generated
vendored
Normal 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
347
vendor/github.com/mdlayher/wifi/client_linux.go
generated
vendored
Normal 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
35
vendor/github.com/mdlayher/wifi/client_others.go
generated
vendored
Normal 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
2
vendor/github.com/mdlayher/wifi/doc.go
generated
vendored
Normal 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
1692
vendor/github.com/mdlayher/wifi/internal/nl80211/const.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
15
vendor/github.com/mdlayher/wifi/internal/nl80211/doc.go
generated
vendored
Normal file
15
vendor/github.com/mdlayher/wifi/internal/nl80211/doc.go
generated
vendored
Normal 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
|
5080
vendor/github.com/mdlayher/wifi/internal/nl80211/nl80211.h
generated
vendored
Normal file
5080
vendor/github.com/mdlayher/wifi/internal/nl80211/nl80211.h
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
20
vendor/github.com/mdlayher/wifi/internal/nl80211/nl80211.yml
generated
vendored
Normal file
20
vendor/github.com/mdlayher/wifi/internal/nl80211/nl80211.yml
generated
vendored
Normal 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
127
vendor/github.com/mdlayher/wifi/wifi.go
generated
vendored
Normal 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
30
vendor/vendor.json
vendored
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue