Files

147 lines
3.1 KiB
Go

// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import (
"os"
"path"
"strings"
"syscall"
"unsafe"
)
// NetworkDevice information.
type NetworkDevice struct {
Name string `json:"name,omitempty"`
Driver string `json:"driver,omitempty"`
MACAddress string `json:"macaddress,omitempty"`
Port string `json:"port,omitempty"`
Speed uint `json:"speed,omitempty"` // device max supported speed in Mbps
}
func getPortType(supp uint32) (port string) {
for i, p := range [...]string{"tp", "aui", "mii", "fibre", "bnc"} {
if supp&(1<<uint(i+7)) > 0 {
port += p + "/"
}
}
port = strings.TrimRight(port, "/")
return
}
func getMaxSpeed(supp uint32) (speed uint) {
// Fancy, right?
switch {
case supp&0x78000000 > 0:
speed = 56000
case supp&0x07800000 > 0:
speed = 40000
case supp&0x00600000 > 0:
speed = 20000
case supp&0x001c1000 > 0:
speed = 10000
case supp&0x00008000 > 0:
speed = 2500
case supp&0x00020030 > 0:
speed = 1000
case supp&0x0000000c > 0:
speed = 100
case supp&0x00000003 > 0:
speed = 10
}
return
}
func getSupported(name string) uint32 {
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_IP)
if err != nil {
return 0
}
defer syscall.Close(fd)
// struct ethtool_cmd from /usr/include/linux/ethtool.h
var ethtool struct {
Cmd uint32
Supported uint32
Advertising uint32
Speed uint16
Duplex uint8
Port uint8
PhyAddress uint8
Transceiver uint8
Autoneg uint8
MdioSupport uint8
Maxtxpkt uint32
Maxrxpkt uint32
SpeedHi uint16
EthTpMdix uint8
Reserved2 uint8
LpAdvertising uint32
Reserved [2]uint32
}
// ETHTOOL_GSET from /usr/include/linux/ethtool.h
const GSET = 0x1
ethtool.Cmd = GSET
// struct ifreq from /usr/include/linux/if.h
var ifr struct {
Name [16]byte
Data uintptr
}
copy(ifr.Name[:], name+"\000")
ifr.Data = uintptr(unsafe.Pointer(&ethtool))
// SIOCETHTOOL from /usr/include/linux/sockios.h
const SIOCETHTOOL = 0x8946
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(SIOCETHTOOL), uintptr(unsafe.Pointer(&ifr)))
if errno == 0 {
return ethtool.Supported
}
return 0
}
func (si *SysInfo) getNetworkInfo() {
sysClassNet := "/sys/class/net"
devices, err := os.ReadDir(sysClassNet)
if err != nil {
return
}
si.Network = make([]NetworkDevice, 0)
for _, link := range devices {
fullpath := path.Join(sysClassNet, link.Name())
dev, err := os.Readlink(fullpath)
if err != nil {
continue
}
if strings.HasPrefix(dev, "../../devices/virtual/") {
continue
}
supp := getSupported(link.Name())
device := NetworkDevice{
Name: link.Name(),
MACAddress: slurpFile(path.Join(fullpath, "address")),
Port: getPortType(supp),
Speed: getMaxSpeed(supp),
}
if driver, err := os.Readlink(path.Join(fullpath, "device", "driver")); err == nil {
device.Driver = path.Base(driver)
}
si.Network = append(si.Network, device)
}
}