OSDN Git Service

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