OSDN Git Service

libgo: Update to weekly.2012-03-13.
[pf3gnuchains/gcc-fork.git] / libgo / go / net / interface_linux.go
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 // Network interface identification for Linux
6
7 package net
8
9 import (
10         "os"
11         "syscall"
12         "unsafe"
13 )
14
15 // If the ifindex is zero, interfaceTable returns mappings of all
16 // network interfaces.  Otheriwse it returns a mapping of a specific
17 // interface.
18 func interfaceTable(ifindex int) ([]Interface, error) {
19         tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
20         if err != nil {
21                 return nil, os.NewSyscallError("netlink rib", err)
22         }
23
24         msgs, err := syscall.ParseNetlinkMessage(tab)
25         if err != nil {
26                 return nil, os.NewSyscallError("netlink message", err)
27         }
28
29         var ift []Interface
30         for _, m := range msgs {
31                 switch m.Header.Type {
32                 case syscall.NLMSG_DONE:
33                         goto done
34                 case syscall.RTM_NEWLINK:
35                         ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
36                         if ifindex == 0 || ifindex == int(ifim.Index) {
37                                 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
38                                 if err != nil {
39                                         return nil, os.NewSyscallError("netlink routeattr", err)
40                                 }
41                                 ifi := newLink(ifim, attrs)
42                                 ift = append(ift, ifi)
43                         }
44                 }
45         }
46 done:
47         return ift, nil
48 }
49
50 func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interface {
51         ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
52         for _, a := range attrs {
53                 switch a.Attr.Type {
54                 case syscall.IFLA_ADDRESS:
55                         var nonzero bool
56                         for _, b := range a.Value {
57                                 if b != 0 {
58                                         nonzero = true
59                                 }
60                         }
61                         if nonzero {
62                                 ifi.HardwareAddr = a.Value[:]
63                         }
64                 case syscall.IFLA_IFNAME:
65                         ifi.Name = string(a.Value[:len(a.Value)-1])
66                 case syscall.IFLA_MTU:
67                         ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0]))
68                 }
69         }
70         return ifi
71 }
72
73 func linkFlags(rawFlags uint32) Flags {
74         var f Flags
75         if rawFlags&syscall.IFF_UP != 0 {
76                 f |= FlagUp
77         }
78         if rawFlags&syscall.IFF_BROADCAST != 0 {
79                 f |= FlagBroadcast
80         }
81         if rawFlags&syscall.IFF_LOOPBACK != 0 {
82                 f |= FlagLoopback
83         }
84         if rawFlags&syscall.IFF_POINTOPOINT != 0 {
85                 f |= FlagPointToPoint
86         }
87         if rawFlags&syscall.IFF_MULTICAST != 0 {
88                 f |= FlagMulticast
89         }
90         return f
91 }
92
93 // If the ifindex is zero, interfaceAddrTable returns addresses
94 // for all network interfaces.  Otherwise it returns addresses
95 // for a specific interface.
96 func interfaceAddrTable(ifindex int) ([]Addr, error) {
97         tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
98         if err != nil {
99                 return nil, os.NewSyscallError("netlink rib", err)
100         }
101
102         msgs, err := syscall.ParseNetlinkMessage(tab)
103         if err != nil {
104                 return nil, os.NewSyscallError("netlink message", err)
105         }
106
107         ifat, err := addrTable(msgs, ifindex)
108         if err != nil {
109                 return nil, err
110         }
111         return ifat, nil
112 }
113
114 func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
115         var ifat []Addr
116         for _, m := range msgs {
117                 switch m.Header.Type {
118                 case syscall.NLMSG_DONE:
119                         goto done
120                 case syscall.RTM_NEWADDR:
121                         ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
122                         if ifindex == 0 || ifindex == int(ifam.Index) {
123                                 attrs, err := syscall.ParseNetlinkRouteAttr(&m)
124                                 if err != nil {
125                                         return nil, os.NewSyscallError("netlink routeattr", err)
126                                 }
127                                 ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen)))
128                         }
129                 }
130         }
131 done:
132         return ifat, nil
133 }
134
135 func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr {
136         ifa := &IPNet{}
137         for _, a := range attrs {
138                 switch a.Attr.Type {
139                 case syscall.IFA_ADDRESS:
140                         switch family {
141                         case syscall.AF_INET:
142                                 ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
143                                 ifa.Mask = CIDRMask(pfxlen, 8*IPv4len)
144                         case syscall.AF_INET6:
145                                 ifa.IP = make(IP, IPv6len)
146                                 copy(ifa.IP, a.Value[:])
147                                 ifa.Mask = CIDRMask(pfxlen, 8*IPv6len)
148                         }
149                 }
150         }
151         return ifa
152 }
153
154 // If the ifindex is zero, interfaceMulticastAddrTable returns
155 // addresses for all network interfaces.  Otherwise it returns
156 // addresses for a specific interface.
157 func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
158         var (
159                 err error
160                 ifi *Interface
161         )
162         if ifindex > 0 {
163                 ifi, err = InterfaceByIndex(ifindex)
164                 if err != nil {
165                         return nil, err
166                 }
167         }
168         ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
169         ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
170         return append(ifmat4, ifmat6...), nil
171 }
172
173 func parseProcNetIGMP(path string, ifi *Interface) []Addr {
174         fd, err := open(path)
175         if err != nil {
176                 return nil
177         }
178         defer fd.close()
179
180         var (
181                 ifmat []Addr
182                 name  string
183         )
184         fd.readLine() // skip first line
185         b := make([]byte, IPv4len)
186         for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
187                 f := splitAtBytes(l, " :\r\t\n")
188                 if len(f) < 4 {
189                         continue
190                 }
191                 switch {
192                 case l[0] != ' ' && l[0] != '\t': // new interface line
193                         name = f[1]
194                 case len(f[0]) == 8:
195                         if ifi == nil || name == ifi.Name {
196                                 for i := 0; i+1 < len(f[0]); i += 2 {
197                                         b[i/2], _ = xtoi2(f[0][i:i+2], 0)
198                                 }
199                                 ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
200                                 ifmat = append(ifmat, ifma.toAddr())
201                         }
202                 }
203         }
204         return ifmat
205 }
206
207 func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
208         fd, err := open(path)
209         if err != nil {
210                 return nil
211         }
212         defer fd.close()
213
214         var ifmat []Addr
215         b := make([]byte, IPv6len)
216         for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
217                 f := splitAtBytes(l, " \r\t\n")
218                 if len(f) < 6 {
219                         continue
220                 }
221                 if ifi == nil || f[1] == ifi.Name {
222                         for i := 0; i+1 < len(f[2]); i += 2 {
223                                 b[i/2], _ = xtoi2(f[2][i:i+2], 0)
224                         }
225                         ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
226                         ifmat = append(ifmat, ifma.toAddr())
227                 }
228         }
229         return ifmat
230 }