OSDN Git Service

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