diff options
Diffstat (limited to 'src/net/interface_aix.go')
-rw-r--r-- | src/net/interface_aix.go | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/src/net/interface_aix.go b/src/net/interface_aix.go new file mode 100644 index 0000000..49f78c2 --- /dev/null +++ b/src/net/interface_aix.go @@ -0,0 +1,186 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "internal/poll" + "internal/syscall/unix" + "syscall" + "unsafe" +) + +type rawSockaddrDatalink struct { + Len uint8 + Family uint8 + Index uint16 + Type uint8 + Nlen uint8 + Alen uint8 + Slen uint8 + Data [120]byte +} + +type ifreq struct { + Name [16]uint8 + Ifru [16]byte +} + +const _KINFO_RT_IFLIST = (0x1 << 8) | 3 | (1 << 30) + +const _RTAX_NETMASK = 2 +const _RTAX_IFA = 5 +const _RTAX_MAX = 8 + +func getIfList() ([]byte, error) { + needed, err := syscall.Getkerninfo(_KINFO_RT_IFLIST, 0, 0, 0) + if err != nil { + return nil, err + } + tab := make([]byte, needed) + _, err = syscall.Getkerninfo(_KINFO_RT_IFLIST, uintptr(unsafe.Pointer(&tab[0])), uintptr(unsafe.Pointer(&needed)), 0) + if err != nil { + return nil, err + } + return tab[:needed], nil +} + +// If the ifindex is zero, interfaceTable returns mappings of all +// network interfaces. Otherwise it returns a mapping of a specific +// interface. +func interfaceTable(ifindex int) ([]Interface, error) { + tab, err := getIfList() + if err != nil { + return nil, err + } + + sock, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, 0) + if err != nil { + return nil, err + } + defer poll.CloseFunc(sock) + + var ift []Interface + for len(tab) > 0 { + ifm := (*syscall.IfMsgHdr)(unsafe.Pointer(&tab[0])) + if ifm.Msglen == 0 { + break + } + if ifm.Type == syscall.RTM_IFINFO { + if ifindex == 0 || ifindex == int(ifm.Index) { + sdl := (*rawSockaddrDatalink)(unsafe.Pointer(&tab[syscall.SizeofIfMsghdr])) + + ifi := &Interface{Index: int(ifm.Index), Flags: linkFlags(ifm.Flags)} + ifi.Name = string(sdl.Data[:sdl.Nlen]) + ifi.HardwareAddr = sdl.Data[sdl.Nlen : sdl.Nlen+sdl.Alen] + + // Retrieve MTU + ifr := &ifreq{} + copy(ifr.Name[:], ifi.Name) + err = unix.Ioctl(sock, syscall.SIOCGIFMTU, uintptr(unsafe.Pointer(ifr))) + if err != nil { + return nil, err + } + ifi.MTU = int(ifr.Ifru[0])<<24 | int(ifr.Ifru[1])<<16 | int(ifr.Ifru[2])<<8 | int(ifr.Ifru[3]) + + ift = append(ift, *ifi) + if ifindex == int(ifm.Index) { + break + } + } + } + tab = tab[ifm.Msglen:] + } + + return ift, nil +} + +func linkFlags(rawFlags int32) Flags { + var f Flags + if rawFlags&syscall.IFF_UP != 0 { + f |= FlagUp + } + if rawFlags&syscall.IFF_BROADCAST != 0 { + f |= FlagBroadcast + } + if rawFlags&syscall.IFF_LOOPBACK != 0 { + f |= FlagLoopback + } + if rawFlags&syscall.IFF_POINTOPOINT != 0 { + f |= FlagPointToPoint + } + if rawFlags&syscall.IFF_MULTICAST != 0 { + f |= FlagMulticast + } + return f +} + +// If the ifi is nil, interfaceAddrTable returns addresses for all +// network interfaces. Otherwise it returns addresses for a specific +// interface. +func interfaceAddrTable(ifi *Interface) ([]Addr, error) { + tab, err := getIfList() + if err != nil { + return nil, err + } + + var ifat []Addr + for len(tab) > 0 { + ifm := (*syscall.IfMsgHdr)(unsafe.Pointer(&tab[0])) + if ifm.Msglen == 0 { + break + } + if ifm.Type == syscall.RTM_NEWADDR { + if ifi == nil || ifi.Index == int(ifm.Index) { + mask := ifm.Addrs + off := uint(syscall.SizeofIfMsghdr) + + var iprsa, nmrsa *syscall.RawSockaddr + for i := uint(0); i < _RTAX_MAX; i++ { + if mask&(1<<i) == 0 { + continue + } + rsa := (*syscall.RawSockaddr)(unsafe.Pointer(&tab[off])) + if i == _RTAX_NETMASK { + nmrsa = rsa + } + if i == _RTAX_IFA { + iprsa = rsa + } + off += (uint(rsa.Len) + 3) &^ 3 + } + if iprsa != nil && nmrsa != nil { + var mask IPMask + var ip IP + + switch iprsa.Family { + case syscall.AF_INET: + ipsa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(iprsa)) + nmsa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(nmrsa)) + ip = IPv4(ipsa.Addr[0], ipsa.Addr[1], ipsa.Addr[2], ipsa.Addr[3]) + mask = IPv4Mask(nmsa.Addr[0], nmsa.Addr[1], nmsa.Addr[2], nmsa.Addr[3]) + case syscall.AF_INET6: + ipsa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(iprsa)) + nmsa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(nmrsa)) + ip = make(IP, IPv6len) + copy(ip, ipsa.Addr[:]) + mask = make(IPMask, IPv6len) + copy(mask, nmsa.Addr[:]) + } + ifa := &IPNet{IP: ip, Mask: mask} + ifat = append(ifat, ifa) + } + } + } + tab = tab[ifm.Msglen:] + } + + return ifat, nil +} + +// interfaceMulticastAddrTable returns addresses for a specific +// interface. +func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { + return nil, nil +} |