1 // Copyright 2016 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.
12 // If the ifindex is zero, interfaceTable returns mappings of all
13 // network interfaces. Otherwise it returns a mapping of a specific
15 func interfaceTable(ifindex
int) ([]Interface
, error
) {
17 n
, err
:= interfaceCount()
21 ifcs
:= make([]Interface
, n
)
23 ifc
, err
:= readInterface(i
)
32 ifc
, err
:= readInterface(ifindex
- 1)
36 return []Interface
{*ifc
}, nil
39 func readInterface(i
int) (*Interface
, error
) {
41 Index
: i
+ 1, // Offset the index by one to suit the contract
42 Name
: netdir
+ "/ipifc/" + itoa(i
), // Name is the full path to the interface path in plan9
45 ifcstat
:= ifc
.Name
+ "/status"
46 ifcstatf
, err
:= open(ifcstat
)
50 defer ifcstatf
.close()
52 line
, ok
:= ifcstatf
.readLine()
54 return nil, errors
.New("invalid interface status file: " + ifcstat
)
57 fields
:= getFields(line
)
59 return nil, errors
.New("invalid interface status file: " + ifcstat
)
65 mtu
, _
, ok
:= dtoi(mtustr
)
67 return nil, errors
.New("invalid status file of interface: " + ifcstat
)
71 // Not a loopback device
72 if device
!= "/dev/null" {
73 deviceaddrf
, err
:= open(device
+ "/addr")
77 defer deviceaddrf
.close()
79 line
, ok
= deviceaddrf
.readLine()
81 return nil, errors
.New("invalid address file for interface: " + device
+ "/addr")
84 if len(line
) > 0 && len(line
)%2
== 0 {
85 ifc
.HardwareAddr
= make([]byte, len(line
)/2)
87 for i
:= range ifc
.HardwareAddr
{
89 ifc
.HardwareAddr
[i
], ok
= xtoi2(line
[i
*2:j
], 0)
91 ifc
.HardwareAddr
= ifc
.HardwareAddr
[:i
]
97 ifc
.Flags
= FlagUp | FlagBroadcast | FlagMulticast
99 ifc
.Flags
= FlagUp | FlagMulticast | FlagLoopback
105 func interfaceCount() (int, error
) {
106 d
, err
:= os
.Open(netdir
+ "/ipifc")
112 names
, err
:= d
.Readdirnames(0)
117 // Assumes that numbered files in ipifc are strictly
118 // the incrementing numbered directories for the
121 for _
, name
:= range names
{
122 if _
, _
, ok
:= dtoi(name
); !ok
{
131 // If the ifi is nil, interfaceAddrTable returns addresses for all
132 // network interfaces. Otherwise it returns addresses for a specific
134 func interfaceAddrTable(ifi
*Interface
) ([]Addr
, error
) {
138 ifcs
, err
= interfaceTable(0)
143 ifcs
= []Interface
{*ifi
}
146 addrs
:= make([]Addr
, len(ifcs
))
147 for i
, ifc
:= range ifcs
{
148 status
:= ifc
.Name
+ "/status"
149 statusf
, err
:= open(status
)
153 defer statusf
.close()
155 line
, ok
:= statusf
.readLine()
156 line
, ok
= statusf
.readLine()
158 return nil, errors
.New("cannot parse IP address for interface: " + status
)
161 // This assumes only a single address for the interface.
162 fields
:= getFields(line
)
164 return nil, errors
.New("cannot parse IP address for interface: " + status
)
169 return nil, errors
.New("cannot parse IP address for interface: " + status
)
172 // The mask is represented as CIDR relative to the IPv6 address.
173 // Plan 9 internal representation is always IPv6.
175 maskfld
= maskfld
[1:]
176 pfxlen
, _
, ok
:= dtoi(maskfld
)
178 return nil, errors
.New("cannot parse network mask for interface: " + status
)
181 if ip
.To4() != nil { // IPv4 or IPv6 IPv4-mapped address
182 mask
= CIDRMask(pfxlen
-8*len(v4InV6Prefix
), 8*IPv4len
)
184 if ip
.To16() != nil && ip
.To4() == nil { // IPv6 address
185 mask
= CIDRMask(pfxlen
, 8*IPv6len
)
188 addrs
[i
] = &IPNet
{IP
: ip
, Mask
: mask
}
194 // interfaceMulticastAddrTable returns addresses for a specific
196 func interfaceMulticastAddrTable(ifi
*Interface
) ([]Addr
, error
) {