1// Copyright 2011 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// +build darwin dragonfly freebsd netbsd openbsd
6
7package net
8
9import (
10	"syscall"
11
12	"golang_org/x/net/route"
13)
14
15// If the ifindex is zero, interfaceTable returns mappings of all
16// network interfaces. Otherwise it returns a mapping of a specific
17// interface.
18func interfaceTable(ifindex int) ([]Interface, error) {
19	msgs, err := interfaceMessages(ifindex)
20	if err != nil {
21		return nil, err
22	}
23	n := len(msgs)
24	if ifindex != 0 {
25		n = 1
26	}
27	ift := make([]Interface, n)
28	n = 0
29	for _, m := range msgs {
30		switch m := m.(type) {
31		case *route.InterfaceMessage:
32			if ifindex != 0 && ifindex != m.Index {
33				continue
34			}
35			ift[n].Index = m.Index
36			ift[n].Name = m.Name
37			ift[n].Flags = linkFlags(m.Flags)
38			if sa, ok := m.Addrs[syscall.RTAX_IFP].(*route.LinkAddr); ok && len(sa.Addr) > 0 {
39				ift[n].HardwareAddr = make([]byte, len(sa.Addr))
40				copy(ift[n].HardwareAddr, sa.Addr)
41			}
42			for _, sys := range m.Sys() {
43				if imx, ok := sys.(*route.InterfaceMetrics); ok {
44					ift[n].MTU = imx.MTU
45					break
46				}
47			}
48			n++
49			if ifindex == m.Index {
50				return ift[:n], nil
51			}
52		}
53	}
54	return ift[:n], nil
55}
56
57func linkFlags(rawFlags int) Flags {
58	var f Flags
59	if rawFlags&syscall.IFF_UP != 0 {
60		f |= FlagUp
61	}
62	if rawFlags&syscall.IFF_BROADCAST != 0 {
63		f |= FlagBroadcast
64	}
65	if rawFlags&syscall.IFF_LOOPBACK != 0 {
66		f |= FlagLoopback
67	}
68	if rawFlags&syscall.IFF_POINTOPOINT != 0 {
69		f |= FlagPointToPoint
70	}
71	if rawFlags&syscall.IFF_MULTICAST != 0 {
72		f |= FlagMulticast
73	}
74	return f
75}
76
77// If the ifi is nil, interfaceAddrTable returns addresses for all
78// network interfaces. Otherwise it returns addresses for a specific
79// interface.
80func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
81	index := 0
82	if ifi != nil {
83		index = ifi.Index
84	}
85	msgs, err := interfaceMessages(index)
86	if err != nil {
87		return nil, err
88	}
89	ifat := make([]Addr, 0, len(msgs))
90	for _, m := range msgs {
91		switch m := m.(type) {
92		case *route.InterfaceAddrMessage:
93			if index != 0 && index != m.Index {
94				continue
95			}
96			var mask IPMask
97			switch sa := m.Addrs[syscall.RTAX_NETMASK].(type) {
98			case *route.Inet4Addr:
99				mask = IPv4Mask(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
100			case *route.Inet6Addr:
101				mask = make(IPMask, IPv6len)
102				copy(mask, sa.IP[:])
103			}
104			var ip IP
105			switch sa := m.Addrs[syscall.RTAX_IFA].(type) {
106			case *route.Inet4Addr:
107				ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
108			case *route.Inet6Addr:
109				ip = make(IP, IPv6len)
110				copy(ip, sa.IP[:])
111			}
112			if ip != nil && mask != nil { // NetBSD may contain route.LinkAddr
113				ifat = append(ifat, &IPNet{IP: ip, Mask: mask})
114			}
115		}
116	}
117	return ifat, nil
118}
119