Imported Upstream version 4.7.2
[platform/upstream/gcc48.git] / libgo / go / net / interface_bsd.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 // +build darwin freebsd netbsd openbsd
6
7 // Network interface identification for BSD variants
8
9 package net
10
11 import (
12         "os"
13         "syscall"
14         "unsafe"
15 )
16
17 // If the ifindex is zero, interfaceTable returns mappings of all
18 // network interfaces.  Otherwise it returns a mapping of a specific
19 // interface.
20 func interfaceTable(ifindex int) ([]Interface, error) {
21         tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
22         if err != nil {
23                 return nil, os.NewSyscallError("route rib", err)
24         }
25
26         msgs, err := syscall.ParseRoutingMessage(tab)
27         if err != nil {
28                 return nil, os.NewSyscallError("route message", err)
29         }
30
31         var ift []Interface
32         for _, m := range msgs {
33                 switch v := m.(type) {
34                 case *syscall.InterfaceMessage:
35                         if ifindex == 0 || ifindex == int(v.Header.Index) {
36                                 ifi, err := newLink(v)
37                                 if err != nil {
38                                         return nil, err
39                                 }
40                                 ift = append(ift, ifi...)
41                         }
42                 }
43         }
44         return ift, nil
45 }
46
47 func newLink(m *syscall.InterfaceMessage) ([]Interface, error) {
48         sas, err := syscall.ParseRoutingSockaddr(m)
49         if err != nil {
50                 return nil, os.NewSyscallError("route sockaddr", err)
51         }
52
53         var ift []Interface
54         for _, s := range sas {
55                 switch v := s.(type) {
56                 case *syscall.SockaddrDatalink:
57                         // NOTE: SockaddrDatalink.Data is minimum work area,
58                         // can be larger.
59                         m.Data = m.Data[unsafe.Offsetof(v.Data):]
60                         ifi := Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
61                         var name [syscall.IFNAMSIZ]byte
62                         for i := 0; i < int(v.Nlen); i++ {
63                                 name[i] = byte(m.Data[i])
64                         }
65                         ifi.Name = string(name[:v.Nlen])
66                         ifi.MTU = int(m.Header.Data.Mtu)
67                         addr := make([]byte, v.Alen)
68                         for i := 0; i < int(v.Alen); i++ {
69                                 addr[i] = byte(m.Data[int(v.Nlen)+i])
70                         }
71                         ifi.HardwareAddr = addr[:v.Alen]
72                         ift = append(ift, ifi)
73                 }
74         }
75         return ift, nil
76 }
77
78 func linkFlags(rawFlags int32) Flags {
79         var f Flags
80         if rawFlags&syscall.IFF_UP != 0 {
81                 f |= FlagUp
82         }
83         if rawFlags&syscall.IFF_BROADCAST != 0 {
84                 f |= FlagBroadcast
85         }
86         if rawFlags&syscall.IFF_LOOPBACK != 0 {
87                 f |= FlagLoopback
88         }
89         if rawFlags&syscall.IFF_POINTOPOINT != 0 {
90                 f |= FlagPointToPoint
91         }
92         if rawFlags&syscall.IFF_MULTICAST != 0 {
93                 f |= FlagMulticast
94         }
95         return f
96 }
97
98 // If the ifindex is zero, interfaceAddrTable returns addresses
99 // for all network interfaces.  Otherwise it returns addresses
100 // for a specific interface.
101 func interfaceAddrTable(ifindex int) ([]Addr, error) {
102         tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
103         if err != nil {
104                 return nil, os.NewSyscallError("route rib", err)
105         }
106
107         msgs, err := syscall.ParseRoutingMessage(tab)
108         if err != nil {
109                 return nil, os.NewSyscallError("route message", err)
110         }
111
112         var ifat []Addr
113         for _, m := range msgs {
114                 switch v := m.(type) {
115                 case *syscall.InterfaceAddrMessage:
116                         if ifindex == 0 || ifindex == int(v.Header.Index) {
117                                 ifa, err := newAddr(v)
118                                 if err != nil {
119                                         return nil, err
120                                 }
121                                 ifat = append(ifat, ifa)
122                         }
123                 }
124         }
125         return ifat, nil
126 }
127
128 func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) {
129         sas, err := syscall.ParseRoutingSockaddr(m)
130         if err != nil {
131                 return nil, os.NewSyscallError("route sockaddr", err)
132         }
133
134         ifa := &IPNet{}
135         for i, s := range sas {
136                 switch v := s.(type) {
137                 case *syscall.SockaddrInet4:
138                         switch i {
139                         case 0:
140                                 ifa.Mask = IPv4Mask(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
141                         case 1:
142                                 ifa.IP = IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
143                         }
144                 case *syscall.SockaddrInet6:
145                         switch i {
146                         case 0:
147                                 ifa.Mask = make(IPMask, IPv6len)
148                                 copy(ifa.Mask, v.Addr[:])
149                         case 1:
150                                 ifa.IP = make(IP, IPv6len)
151                                 copy(ifa.IP, v.Addr[:])
152                                 // NOTE: KAME based IPv6 protcol stack usually embeds
153                                 // the interface index in the interface-local or link-
154                                 // local address as the kernel-internal form.
155                                 if ifa.IP.IsLinkLocalUnicast() {
156                                         // remove embedded scope zone ID
157                                         ifa.IP[2], ifa.IP[3] = 0, 0
158                                 }
159                         }
160                 }
161         }
162         return ifa, nil
163 }