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  }