diff options
Diffstat (limited to 'src/pkg/net/interface_linux.go')
| -rw-r--r-- | src/pkg/net/interface_linux.go | 208 | 
1 files changed, 208 insertions, 0 deletions
| diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go new file mode 100644 index 000000000..5c9657834 --- /dev/null +++ b/src/pkg/net/interface_linux.go @@ -0,0 +1,208 @@ +// 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. + +// Network interface identification for Linux + +package net + +import ( +	"os" +	"syscall" +	"unsafe" +) + +// IsUp returns true if ifi is up. +func (ifi *Interface) IsUp() bool { +	if ifi == nil { +		return false +	} +	return ifi.rawFlags&syscall.IFF_UP != 0 +} + +// IsLoopback returns true if ifi is a loopback interface. +func (ifi *Interface) IsLoopback() bool { +	if ifi == nil { +		return false +	} +	return ifi.rawFlags&syscall.IFF_LOOPBACK != 0 +} + +// CanBroadcast returns true if ifi supports a broadcast access +// capability. +func (ifi *Interface) CanBroadcast() bool { +	if ifi == nil { +		return false +	} +	return ifi.rawFlags&syscall.IFF_BROADCAST != 0 +} + +// IsPointToPoint returns true if ifi belongs to a point-to-point +// link. +func (ifi *Interface) IsPointToPoint() bool { +	if ifi == nil { +		return false +	} +	return ifi.rawFlags&syscall.IFF_POINTOPOINT != 0 +} + +// CanMulticast returns true if ifi supports a multicast access +// capability. +func (ifi *Interface) CanMulticast() bool { +	if ifi == nil { +		return false +	} +	return ifi.rawFlags&syscall.IFF_MULTICAST != 0 +} + +// If the ifindex is zero, interfaceTable returns mappings of all +// network interfaces.  Otheriwse it returns a mapping of a specific +// interface. +func interfaceTable(ifindex int) ([]Interface, os.Error) { +	var ( +		ift  []Interface +		tab  []byte +		msgs []syscall.NetlinkMessage +		e    int +	) + +	tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) +	if e != 0 { +		return nil, os.NewSyscallError("netlink rib", e) +	} + +	msgs, e = syscall.ParseNetlinkMessage(tab) +	if e != 0 { +		return nil, os.NewSyscallError("netlink message", e) +	} + +	for _, m := range msgs { +		switch m.Header.Type { +		case syscall.NLMSG_DONE: +			goto done +		case syscall.RTM_NEWLINK: +			ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0])) +			if ifindex == 0 || ifindex == int(ifim.Index) { +				attrs, e := syscall.ParseNetlinkRouteAttr(&m) +				if e != 0 { +					return nil, os.NewSyscallError("netlink routeattr", e) +				} +				ifi := newLink(attrs, ifim) +				ift = append(ift, ifi) +			} +		} +	} + +done: +	return ift, nil +} + +func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface { +	ifi := Interface{Index: int(ifim.Index), rawFlags: int(ifim.Flags)} +	for _, a := range attrs { +		switch a.Attr.Type { +		case syscall.IFLA_ADDRESS: +			var nonzero bool +			for _, b := range a.Value { +				if b != 0 { +					nonzero = true +				} +			} +			if nonzero { +				ifi.HardwareAddr = a.Value[:] +			} +		case syscall.IFLA_IFNAME: +			ifi.Name = string(a.Value[:]) +		case syscall.IFLA_MTU: +			ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0])) +		} +	} +	return ifi +} + +// If the ifindex is zero, interfaceAddrTable returns addresses +// for all network interfaces.  Otherwise it returns addresses +// for a specific interface. +func interfaceAddrTable(ifindex int) ([]Addr, os.Error) { +	var ( +		ifat4 []Addr +		ifat6 []Addr +		tab   []byte +		msgs4 []syscall.NetlinkMessage +		msgs6 []syscall.NetlinkMessage +		e     int +		err   os.Error +	) + +	tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET) +	if e != 0 { +		return nil, os.NewSyscallError("netlink rib", e) +	} +	msgs4, e = syscall.ParseNetlinkMessage(tab) +	if e != 0 { +		return nil, os.NewSyscallError("netlink message", e) +	} +	ifat4, err = addrTable(msgs4, ifindex) +	if err != nil { +		return nil, err +	} + +	tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET6) +	if e != 0 { +		return nil, os.NewSyscallError("netlink rib", e) +	} +	msgs6, e = syscall.ParseNetlinkMessage(tab) +	if e != 0 { +		return nil, os.NewSyscallError("netlink message", e) +	} +	ifat6, err = addrTable(msgs6, ifindex) +	if err != nil { +		return nil, err +	} + +	return append(ifat4, ifat6...), nil +} + +func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, os.Error) { +	var ifat []Addr + +	for _, m := range msgs { +		switch m.Header.Type { +		case syscall.NLMSG_DONE: +			goto done +		case syscall.RTM_NEWADDR: +			ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0])) +			if ifindex == 0 || ifindex == int(ifam.Index) { +				attrs, e := syscall.ParseNetlinkRouteAttr(&m) +				if e != 0 { +					return nil, os.NewSyscallError("netlink routeattr", e) +				} +				ifat = append(ifat, newAddr(attrs, int(ifam.Family))...) +			} +		} +	} + +done: +	return ifat, nil +} + +func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr { +	var ifat []Addr + +	for _, a := range attrs { +		switch a.Attr.Type { +		case syscall.IFA_ADDRESS: +			ifa := IPAddr{} +			switch family { +			case syscall.AF_INET: +				ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]) +			case syscall.AF_INET6: +				ifa.IP = make(IP, IPv6len) +				copy(ifa.IP, a.Value[:]) +			} +			ifat = append(ifat, ifa.toAddr()) +		} +	} + +	return ifat +} | 
