OSDN Git Service

syscall: Portability code for epoll_event on GNU/Linux.
[pf3gnuchains/gcc-fork.git] / libgo / go / syscall / route_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 openbsd
6
7 // Routing sockets and messages
8
9 package syscall
10
11 import (
12         "unsafe"
13 )
14
15 // Round the length of a raw sockaddr up to align it properly.
16 func rsaAlignOf(salen int) int {
17         salign := sizeofPtr
18         // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
19         // aligned access to BSD subsystem.
20         if darwinAMD64 {
21                 salign = 4
22         }
23         if salen == 0 {
24                 return salign
25         }
26         return (salen + salign - 1) & ^(salign - 1)
27 }
28
29 // RouteRIB returns routing information base, as known as RIB,
30 // which consists of network facility information, states and
31 // parameters.
32 func RouteRIB(facility, param int) ([]byte, int) {
33         var (
34                 tab []byte
35                 e   int
36         )
37
38         mib := []_C_int{CTL_NET, AF_ROUTE, 0, 0, _C_int(facility), _C_int(param)}
39
40         // Find size.
41         n := uintptr(0)
42         if e = sysctl(mib, nil, &n, nil, 0); e != 0 {
43                 return nil, e
44         }
45         if n == 0 {
46                 return nil, 0
47         }
48
49         tab = make([]byte, n)
50         if e = sysctl(mib, &tab[0], &n, nil, 0); e != 0 {
51                 return nil, e
52         }
53
54         return tab[:n], 0
55 }
56
57 // RoutingMessage represents a routing message.
58 type RoutingMessage interface {
59         sockaddr() []Sockaddr
60 }
61
62 const anyMessageLen = int(unsafe.Sizeof(anyMessage{}))
63
64 type anyMessage struct {
65         Msglen  uint16
66         Version uint8
67         Type    uint8
68 }
69
70 // RouteMessage represents a routing message containing routing
71 // entries.
72 type RouteMessage struct {
73         Header RtMsghdr
74         Data   []byte
75 }
76
77 const rtaRtMask = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK
78
79 func (m *RouteMessage) sockaddr() []Sockaddr {
80         var (
81                 af  int
82                 sas [4]Sockaddr
83         )
84
85         buf := m.Data[:]
86         for i := uint(0); i < RTAX_MAX; i++ {
87                 if m.Header.Addrs&rtaRtMask&(1<<i) == 0 {
88                         continue
89                 }
90                 rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
91                 switch i {
92                 case RTAX_DST, RTAX_GATEWAY:
93                         sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
94                         if e != 0 {
95                                 return nil
96                         }
97                         if i == RTAX_DST {
98                                 af = int(rsa.Family)
99                         }
100                         sas[i] = sa
101                 case RTAX_NETMASK, RTAX_GENMASK:
102                         switch af {
103                         case AF_INET:
104                                 rsa4 := (*RawSockaddrInet4)(unsafe.Pointer(&buf[0]))
105                                 sa := new(SockaddrInet4)
106                                 for j := 0; rsa4.Len > 0 && j < int(rsa4.Len)-int(unsafe.Offsetof(rsa4.Addr)); j++ {
107                                         sa.Addr[j] = rsa4.Addr[j]
108                                 }
109                                 sas[i] = sa
110                         case AF_INET6:
111                                 rsa6 := (*RawSockaddrInet6)(unsafe.Pointer(&buf[0]))
112                                 sa := new(SockaddrInet6)
113                                 for j := 0; rsa6.Len > 0 && j < int(rsa6.Len)-int(unsafe.Offsetof(rsa6.Addr)); j++ {
114                                         sa.Addr[j] = rsa6.Addr[j]
115                                 }
116                                 sas[i] = sa
117                         }
118                 }
119                 buf = buf[rsaAlignOf(int(rsa.Len)):]
120         }
121
122         return sas[:]
123 }
124
125 // InterfaceMessage represents a routing message containing
126 // network interface entries.
127 type InterfaceMessage struct {
128         Header IfMsghdr
129         Data   []byte
130 }
131
132 func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) {
133         if m.Header.Addrs&RTA_IFP == 0 {
134                 return nil
135         }
136         sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
137         if e != 0 {
138                 return nil
139         }
140         return append(sas, sa)
141 }
142
143 // InterfaceAddrMessage represents a routing message containing
144 // network interface address entries.
145 type InterfaceAddrMessage struct {
146         Header IfaMsghdr
147         Data   []byte
148 }
149
150 const rtaIfaMask = RTA_IFA | RTA_NETMASK | RTA_BRD
151
152 func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
153         if m.Header.Addrs&rtaIfaMask == 0 {
154                 return nil
155         }
156
157         buf := m.Data[:]
158         for i := uint(0); i < RTAX_MAX; i++ {
159                 if m.Header.Addrs&rtaIfaMask&(1<<i) == 0 {
160                         continue
161                 }
162                 rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
163                 switch i {
164                 case RTAX_IFA:
165                         sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
166                         if e != 0 {
167                                 return nil
168                         }
169                         sas = append(sas, sa)
170                 case RTAX_NETMASK, RTAX_BRD:
171                         // nothing to do
172                 }
173                 buf = buf[rsaAlignOf(int(rsa.Len)):]
174         }
175
176         return sas
177 }
178
179 // ParseRoutingMessage parses buf as routing messages and returns
180 // the slice containing the RoutingMessage interfaces.
181 func ParseRoutingMessage(buf []byte) (msgs []RoutingMessage, errno int) {
182         for len(buf) >= anyMessageLen {
183                 any := (*anyMessage)(unsafe.Pointer(&buf[0]))
184                 if any.Version != RTM_VERSION {
185                         return nil, EINVAL
186                 }
187                 msgs = append(msgs, any.toRoutingMessage(buf))
188                 buf = buf[any.Msglen:]
189         }
190         return msgs, 0
191 }
192
193 // ParseRoutingMessage parses msg's payload as raw sockaddrs and
194 // returns the slice containing the Sockaddr interfaces.
195 func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, errno int) {
196         return append(sas, msg.sockaddr()...), 0
197 }