mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			183 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			183 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
// Copyright 2011 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.
 | 
						|
 | 
						|
// +build darwin dragonfly freebsd netbsd openbsd
 | 
						|
 | 
						|
package net
 | 
						|
 | 
						|
import (
 | 
						|
	"os"
 | 
						|
	"syscall"
 | 
						|
	"unsafe"
 | 
						|
)
 | 
						|
 | 
						|
// 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 := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
 | 
						|
	if err != nil {
 | 
						|
		return nil, os.NewSyscallError("route rib", err)
 | 
						|
	}
 | 
						|
	msgs, err := syscall.ParseRoutingMessage(tab)
 | 
						|
	if err != nil {
 | 
						|
		return nil, os.NewSyscallError("route message", err)
 | 
						|
	}
 | 
						|
	return parseInterfaceTable(ifindex, msgs)
 | 
						|
}
 | 
						|
 | 
						|
func parseInterfaceTable(ifindex int, msgs []syscall.RoutingMessage) ([]Interface, error) {
 | 
						|
	var ift []Interface
 | 
						|
loop:
 | 
						|
	for _, m := range msgs {
 | 
						|
		switch m := m.(type) {
 | 
						|
		case *syscall.InterfaceMessage:
 | 
						|
			if ifindex == 0 || ifindex == int(m.Header.Index) {
 | 
						|
				ifi, err := newLink(m)
 | 
						|
				if err != nil {
 | 
						|
					return nil, err
 | 
						|
				}
 | 
						|
				ift = append(ift, *ifi)
 | 
						|
				if ifindex == int(m.Header.Index) {
 | 
						|
					break loop
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return ift, nil
 | 
						|
}
 | 
						|
 | 
						|
func newLink(m *syscall.InterfaceMessage) (*Interface, error) {
 | 
						|
	sas, err := syscall.ParseRoutingSockaddr(m)
 | 
						|
	if err != nil {
 | 
						|
		return nil, os.NewSyscallError("route sockaddr", err)
 | 
						|
	}
 | 
						|
	ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
 | 
						|
	for _, sa := range sas {
 | 
						|
		switch sa := sa.(type) {
 | 
						|
		case *syscall.SockaddrDatalink:
 | 
						|
			// NOTE: SockaddrDatalink.Data is minimum work area,
 | 
						|
			// can be larger.
 | 
						|
			m.Data = m.Data[unsafe.Offsetof(sa.Data):]
 | 
						|
			var name [syscall.IFNAMSIZ]byte
 | 
						|
			for i := 0; i < int(sa.Nlen); i++ {
 | 
						|
				name[i] = byte(m.Data[i])
 | 
						|
			}
 | 
						|
			ifi.Name = string(name[:sa.Nlen])
 | 
						|
			ifi.MTU = int(m.Header.Data.Mtu)
 | 
						|
			addr := make([]byte, sa.Alen)
 | 
						|
			for i := 0; i < int(sa.Alen); i++ {
 | 
						|
				addr[i] = byte(m.Data[int(sa.Nlen)+i])
 | 
						|
			}
 | 
						|
			ifi.HardwareAddr = addr[:sa.Alen]
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return ifi, 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) {
 | 
						|
	index := 0
 | 
						|
	if ifi != nil {
 | 
						|
		index = ifi.Index
 | 
						|
	}
 | 
						|
	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index)
 | 
						|
	if err != nil {
 | 
						|
		return nil, os.NewSyscallError("route rib", err)
 | 
						|
	}
 | 
						|
	msgs, err := syscall.ParseRoutingMessage(tab)
 | 
						|
	if err != nil {
 | 
						|
		return nil, os.NewSyscallError("route message", err)
 | 
						|
	}
 | 
						|
	var ift []Interface
 | 
						|
	if index == 0 {
 | 
						|
		ift, err = parseInterfaceTable(index, msgs)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	var ifat []Addr
 | 
						|
	for _, m := range msgs {
 | 
						|
		switch m := m.(type) {
 | 
						|
		case *syscall.InterfaceAddrMessage:
 | 
						|
			if index == 0 || index == int(m.Header.Index) {
 | 
						|
				if index == 0 {
 | 
						|
					var err error
 | 
						|
					ifi, err = interfaceByIndex(ift, int(m.Header.Index))
 | 
						|
					if err != nil {
 | 
						|
						return nil, err
 | 
						|
					}
 | 
						|
				}
 | 
						|
				ifa, err := newAddr(ifi, m)
 | 
						|
				if err != nil {
 | 
						|
					return nil, err
 | 
						|
				}
 | 
						|
				if ifa != nil {
 | 
						|
					ifat = append(ifat, ifa)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return ifat, nil
 | 
						|
}
 | 
						|
 | 
						|
func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (Addr, error) {
 | 
						|
	sas, err := syscall.ParseRoutingSockaddr(m)
 | 
						|
	if err != nil {
 | 
						|
		return nil, os.NewSyscallError("route sockaddr", err)
 | 
						|
	}
 | 
						|
	ifa := &IPNet{}
 | 
						|
	for i, sa := range sas {
 | 
						|
		switch sa := sa.(type) {
 | 
						|
		case *syscall.SockaddrInet4:
 | 
						|
			switch i {
 | 
						|
			case 0:
 | 
						|
				ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
 | 
						|
			case 1:
 | 
						|
				ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
 | 
						|
			}
 | 
						|
		case *syscall.SockaddrInet6:
 | 
						|
			switch i {
 | 
						|
			case 0:
 | 
						|
				ifa.Mask = make(IPMask, IPv6len)
 | 
						|
				copy(ifa.Mask, sa.Addr[:])
 | 
						|
			case 1:
 | 
						|
				ifa.IP = make(IP, IPv6len)
 | 
						|
				copy(ifa.IP, sa.Addr[:])
 | 
						|
				// NOTE: KAME based IPv6 protcol stack usually embeds
 | 
						|
				// the interface index in the interface-local or link-
 | 
						|
				// local address as the kernel-internal form.
 | 
						|
				if ifa.IP.IsLinkLocalUnicast() {
 | 
						|
					ifa.IP[2], ifa.IP[3] = 0, 0
 | 
						|
				}
 | 
						|
			}
 | 
						|
		default: // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
 | 
						|
			return nil, nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return ifa, nil
 | 
						|
}
 |