Source file src/net/interface_aix.go

     1  // Copyright 2018 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  package net
     6  
     7  import (
     8  	"internal/poll"
     9  	"internal/syscall/unix"
    10  	"syscall"
    11  	"unsafe"
    12  )
    13  
    14  type rawSockaddrDatalink struct {
    15  	Len    uint8
    16  	Family uint8
    17  	Index  uint16
    18  	Type   uint8
    19  	Nlen   uint8
    20  	Alen   uint8
    21  	Slen   uint8
    22  	Data   [120]byte
    23  }
    24  
    25  type ifreq struct {
    26  	Name [16]uint8
    27  	Ifru [16]byte
    28  }
    29  
    30  const _KINFO_RT_IFLIST = (0x1 << 8) | 3 | (1 << 30)
    31  
    32  const _RTAX_NETMASK = 2
    33  const _RTAX_IFA = 5
    34  const _RTAX_MAX = 8
    35  
    36  func getIfList() ([]byte, error) {
    37  	needed, err := syscall.Getkerninfo(_KINFO_RT_IFLIST, 0, 0, 0)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	tab := make([]byte, needed)
    42  	_, err = syscall.Getkerninfo(_KINFO_RT_IFLIST, uintptr(unsafe.Pointer(&tab[0])), uintptr(unsafe.Pointer(&needed)), 0)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	return tab[:needed], nil
    47  }
    48  
    49  // If the ifindex is zero, interfaceTable returns mappings of all
    50  // network interfaces. Otherwise it returns a mapping of a specific
    51  // interface.
    52  func interfaceTable(ifindex int) ([]Interface, error) {
    53  	tab, err := getIfList()
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	sock, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	defer poll.CloseFunc(sock)
    63  
    64  	var ift []Interface
    65  	for len(tab) > 0 {
    66  		ifm := (*syscall.IfMsgHdr)(unsafe.Pointer(&tab[0]))
    67  		if ifm.Msglen == 0 {
    68  			break
    69  		}
    70  		if ifm.Type == syscall.RTM_IFINFO {
    71  			if ifindex == 0 || ifindex == int(ifm.Index) {
    72  				sdl := (*rawSockaddrDatalink)(unsafe.Pointer(&tab[syscall.SizeofIfMsghdr]))
    73  
    74  				ifi := &Interface{Index: int(ifm.Index), Flags: linkFlags(ifm.Flags)}
    75  				ifi.Name = string(sdl.Data[:sdl.Nlen])
    76  				ifi.HardwareAddr = sdl.Data[sdl.Nlen : sdl.Nlen+sdl.Alen]
    77  
    78  				// Retrieve MTU
    79  				ifr := &ifreq{}
    80  				copy(ifr.Name[:], ifi.Name)
    81  				err = unix.Ioctl(sock, syscall.SIOCGIFMTU, unsafe.Pointer(ifr))
    82  				if err != nil {
    83  					return nil, err
    84  				}
    85  				ifi.MTU = int(ifr.Ifru[0])<<24 | int(ifr.Ifru[1])<<16 | int(ifr.Ifru[2])<<8 | int(ifr.Ifru[3])
    86  
    87  				ift = append(ift, *ifi)
    88  				if ifindex == int(ifm.Index) {
    89  					break
    90  				}
    91  			}
    92  		}
    93  		tab = tab[ifm.Msglen:]
    94  	}
    95  
    96  	return ift, nil
    97  }
    98  
    99  func linkFlags(rawFlags int32) Flags {
   100  	var f Flags
   101  	if rawFlags&syscall.IFF_UP != 0 {
   102  		f |= FlagUp
   103  	}
   104  	if rawFlags&syscall.IFF_RUNNING != 0 {
   105  		f |= FlagRunning
   106  	}
   107  	if rawFlags&syscall.IFF_BROADCAST != 0 {
   108  		f |= FlagBroadcast
   109  	}
   110  	if rawFlags&syscall.IFF_LOOPBACK != 0 {
   111  		f |= FlagLoopback
   112  	}
   113  	if rawFlags&syscall.IFF_POINTOPOINT != 0 {
   114  		f |= FlagPointToPoint
   115  	}
   116  	if rawFlags&syscall.IFF_MULTICAST != 0 {
   117  		f |= FlagMulticast
   118  	}
   119  	return f
   120  }
   121  
   122  // If the ifi is nil, interfaceAddrTable returns addresses for all
   123  // network interfaces. Otherwise it returns addresses for a specific
   124  // interface.
   125  func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
   126  	tab, err := getIfList()
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	var ifat []Addr
   132  	for len(tab) > 0 {
   133  		ifm := (*syscall.IfMsgHdr)(unsafe.Pointer(&tab[0]))
   134  		if ifm.Msglen == 0 {
   135  			break
   136  		}
   137  		if ifm.Type == syscall.RTM_NEWADDR {
   138  			if ifi == nil || ifi.Index == int(ifm.Index) {
   139  				mask := ifm.Addrs
   140  				off := uint(syscall.SizeofIfMsghdr)
   141  
   142  				var iprsa, nmrsa *syscall.RawSockaddr
   143  				for i := uint(0); i < _RTAX_MAX; i++ {
   144  					if mask&(1<<i) == 0 {
   145  						continue
   146  					}
   147  					rsa := (*syscall.RawSockaddr)(unsafe.Pointer(&tab[off]))
   148  					if i == _RTAX_NETMASK {
   149  						nmrsa = rsa
   150  					}
   151  					if i == _RTAX_IFA {
   152  						iprsa = rsa
   153  					}
   154  					off += (uint(rsa.Len) + 3) &^ 3
   155  				}
   156  				if iprsa != nil && nmrsa != nil {
   157  					var mask IPMask
   158  					var ip IP
   159  
   160  					switch iprsa.Family {
   161  					case syscall.AF_INET:
   162  						ipsa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(iprsa))
   163  						nmsa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(nmrsa))
   164  						ip = IPv4(ipsa.Addr[0], ipsa.Addr[1], ipsa.Addr[2], ipsa.Addr[3])
   165  						mask = IPv4Mask(nmsa.Addr[0], nmsa.Addr[1], nmsa.Addr[2], nmsa.Addr[3])
   166  					case syscall.AF_INET6:
   167  						ipsa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(iprsa))
   168  						nmsa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(nmrsa))
   169  						ip = make(IP, IPv6len)
   170  						copy(ip, ipsa.Addr[:])
   171  						mask = make(IPMask, IPv6len)
   172  						copy(mask, nmsa.Addr[:])
   173  					}
   174  					ifa := &IPNet{IP: ip, Mask: mask}
   175  					ifat = append(ifat, ifa)
   176  				}
   177  			}
   178  		}
   179  		tab = tab[ifm.Msglen:]
   180  	}
   181  
   182  	return ifat, nil
   183  }
   184  
   185  // interfaceMulticastAddrTable returns addresses for a specific
   186  // interface.
   187  func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
   188  	return nil, nil
   189  }
   190  

View as plain text