git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/sysinfo/network.go (about) 1 // Copyright © 2016 Zlatko Čalušić 2 // 3 // Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. 4 5 package sysinfo 6 7 import ( 8 "io/ioutil" 9 "os" 10 "path" 11 "strings" 12 "syscall" 13 "unsafe" 14 ) 15 16 // NetworkDevice information. 17 type NetworkDevice struct { 18 Name string `json:"name,omitempty"` 19 Driver string `json:"driver,omitempty"` 20 MACAddress string `json:"macaddress,omitempty"` 21 Port string `json:"port,omitempty"` 22 Speed uint `json:"speed,omitempty"` // device max supported speed in Mbps 23 } 24 25 func getPortType(supp uint32) (port string) { 26 for i, p := range [...]string{"tp", "aui", "mii", "fibre", "bnc"} { 27 if supp&(1<<uint(i+7)) > 0 { 28 port += p + "/" 29 } 30 } 31 32 port = strings.TrimRight(port, "/") 33 return 34 } 35 36 func getMaxSpeed(supp uint32) (speed uint) { 37 // Fancy, right? 38 switch { 39 case supp&0x78000000 > 0: 40 speed = 56000 41 case supp&0x07800000 > 0: 42 speed = 40000 43 case supp&0x00600000 > 0: 44 speed = 20000 45 case supp&0x001c1000 > 0: 46 speed = 10000 47 case supp&0x00008000 > 0: 48 speed = 2500 49 case supp&0x00020030 > 0: 50 speed = 1000 51 case supp&0x0000000c > 0: 52 speed = 100 53 case supp&0x00000003 > 0: 54 speed = 10 55 } 56 57 return 58 } 59 60 func getSupported(name string) uint32 { 61 fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_IP) 62 if err != nil { 63 return 0 64 } 65 defer syscall.Close(fd) 66 67 // struct ethtool_cmd from /usr/include/linux/ethtool.h 68 var ethtool struct { 69 Cmd uint32 70 Supported uint32 71 Advertising uint32 72 Speed uint16 73 Duplex uint8 74 Port uint8 75 PhyAddress uint8 76 Transceiver uint8 77 Autoneg uint8 78 MdioSupport uint8 79 Maxtxpkt uint32 80 Maxrxpkt uint32 81 SpeedHi uint16 82 EthTpMdix uint8 83 Reserved2 uint8 84 LpAdvertising uint32 85 Reserved [2]uint32 86 } 87 88 // ETHTOOL_GSET from /usr/include/linux/ethtool.h 89 const GSET = 0x1 90 91 ethtool.Cmd = GSET 92 93 // struct ifreq from /usr/include/linux/if.h 94 var ifr struct { 95 Name [16]byte 96 Data uintptr 97 } 98 99 copy(ifr.Name[:], name+"\000") 100 ifr.Data = uintptr(unsafe.Pointer(ðtool)) 101 102 // SIOCETHTOOL from /usr/include/linux/sockios.h 103 const SIOCETHTOOL = 0x8946 104 105 _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(SIOCETHTOOL), uintptr(unsafe.Pointer(&ifr))) 106 if errno == 0 { 107 return ethtool.Supported 108 } 109 110 return 0 111 } 112 113 func (si *SysInfo) getNetworkInfo() { 114 sysClassNet := "/sys/class/net" 115 devices, err := ioutil.ReadDir(sysClassNet) 116 if err != nil { 117 return 118 } 119 120 si.Network = make([]NetworkDevice, 0) 121 for _, link := range devices { 122 fullpath := path.Join(sysClassNet, link.Name()) 123 dev, err := os.Readlink(fullpath) 124 if err != nil { 125 continue 126 } 127 128 if strings.HasPrefix(dev, "../../devices/virtual/") { 129 continue 130 } 131 132 supp := getSupported(link.Name()) 133 134 device := NetworkDevice{ 135 Name: link.Name(), 136 MACAddress: slurpFile(path.Join(fullpath, "address")), 137 Port: getPortType(supp), 138 Speed: getMaxSpeed(supp), 139 } 140 141 if driver, err := os.Readlink(path.Join(fullpath, "device", "driver")); err == nil { 142 device.Driver = path.Base(driver) 143 } 144 145 si.Network = append(si.Network, device) 146 } 147 }