golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/lif/link.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build solaris 6 7 package lif 8 9 import ( 10 "syscall" 11 "unsafe" 12 ) 13 14 // A Link represents logical data link information. 15 // 16 // It also represents base information for logical network interface. 17 // On Solaris, each logical network interface represents network layer 18 // adjacency information and the interface has a only single network 19 // address or address pair for tunneling. It's usual that multiple 20 // logical network interfaces share the same logical data link. 21 type Link struct { 22 Name string // name, equivalent to IP interface name 23 Index int // index, equivalent to IP interface index 24 Type int // type 25 Flags int // flags 26 MTU int // maximum transmission unit, basically link MTU but may differ between IP address families 27 Addr []byte // address 28 } 29 30 func (ll *Link) fetch(s uintptr) { 31 var lifr lifreq 32 for i := 0; i < len(ll.Name); i++ { 33 lifr.Name[i] = int8(ll.Name[i]) 34 } 35 ioc := int64(syscall.SIOCGLIFINDEX) 36 if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil { 37 ll.Index = int(nativeEndian.Uint32(lifr.Lifru[:4])) 38 } 39 ioc = int64(syscall.SIOCGLIFFLAGS) 40 if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil { 41 ll.Flags = int(nativeEndian.Uint64(lifr.Lifru[:8])) 42 } 43 ioc = int64(syscall.SIOCGLIFMTU) 44 if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil { 45 ll.MTU = int(nativeEndian.Uint32(lifr.Lifru[:4])) 46 } 47 switch ll.Type { 48 case syscall.IFT_IPV4, syscall.IFT_IPV6, syscall.IFT_6TO4: 49 default: 50 ioc = int64(syscall.SIOCGLIFHWADDR) 51 if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil { 52 ll.Addr, _ = parseLinkAddr(lifr.Lifru[4:]) 53 } 54 } 55 } 56 57 // Links returns a list of logical data links. 58 // 59 // The provided af must be an address family and name must be a data 60 // link name. The zero value of af or name means a wildcard. 61 func Links(af int, name string) ([]Link, error) { 62 eps, err := newEndpoints(af) 63 if len(eps) == 0 { 64 return nil, err 65 } 66 defer func() { 67 for _, ep := range eps { 68 ep.close() 69 } 70 }() 71 return links(eps, name) 72 } 73 74 func links(eps []endpoint, name string) ([]Link, error) { 75 var lls []Link 76 lifn := lifnum{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP} 77 lifc := lifconf{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP} 78 for _, ep := range eps { 79 lifn.Family = uint16(ep.af) 80 ioc := int64(syscall.SIOCGLIFNUM) 81 if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifn)); err != nil { 82 continue 83 } 84 if lifn.Count == 0 { 85 continue 86 } 87 b := make([]byte, lifn.Count*sizeofLifreq) 88 lifc.Family = uint16(ep.af) 89 lifc.Len = lifn.Count * sizeofLifreq 90 if len(lifc.Lifcu) == 8 { 91 nativeEndian.PutUint64(lifc.Lifcu[:], uint64(uintptr(unsafe.Pointer(&b[0])))) 92 } else { 93 nativeEndian.PutUint32(lifc.Lifcu[:], uint32(uintptr(unsafe.Pointer(&b[0])))) 94 } 95 ioc = int64(syscall.SIOCGLIFCONF) 96 if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifc)); err != nil { 97 continue 98 } 99 nb := make([]byte, 32) // see LIFNAMSIZ in net/if.h 100 for i := 0; i < int(lifn.Count); i++ { 101 lifr := (*lifreq)(unsafe.Pointer(&b[i*sizeofLifreq])) 102 for i := 0; i < 32; i++ { 103 if lifr.Name[i] == 0 { 104 nb = nb[:i] 105 break 106 } 107 nb[i] = byte(lifr.Name[i]) 108 } 109 llname := string(nb) 110 nb = nb[:32] 111 if isDupLink(lls, llname) || name != "" && name != llname { 112 continue 113 } 114 ll := Link{Name: llname, Type: int(lifr.Type)} 115 ll.fetch(ep.s) 116 lls = append(lls, ll) 117 } 118 } 119 return lls, nil 120 } 121 122 func isDupLink(lls []Link, name string) bool { 123 for _, ll := range lls { 124 if ll.Name == name { 125 return true 126 } 127 } 128 return false 129 }