OSDN Git Service

Implement new syscall package.
[pf3gnuchains/gcc-fork.git] / libgo / go / syscall / netlink_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 // Netlink sockets and messages
6
7 package syscall
8
9 import (
10         "unsafe"
11 )
12
13 // Round the length of a netlink message up to align it properly.
14 func nlmAlignOf(msglen int) int {
15         return (msglen + NLMSG_ALIGNTO - 1) & ^(NLMSG_ALIGNTO - 1)
16 }
17
18 // Round the length of a netlink route attribute up to align it
19 // properly.
20 func rtaAlignOf(attrlen int) int {
21         return (attrlen + RTA_ALIGNTO - 1) & ^(RTA_ALIGNTO - 1)
22 }
23
24 // NetlinkRouteRequest represents the request message to receive
25 // routing and link states from the kernel.
26 type NetlinkRouteRequest struct {
27         Header NlMsghdr
28         Data   RtGenmsg
29 }
30
31 func (rr *NetlinkRouteRequest) toWireFormat() []byte {
32         b := make([]byte, rr.Header.Len)
33         b[0] = byte(rr.Header.Len)
34         b[1] = byte(rr.Header.Len >> 8)
35         b[2] = byte(rr.Header.Len >> 16)
36         b[3] = byte(rr.Header.Len >> 24)
37         b[4] = byte(rr.Header.Type)
38         b[5] = byte(rr.Header.Type >> 8)
39         b[6] = byte(rr.Header.Flags)
40         b[7] = byte(rr.Header.Flags >> 8)
41         b[8] = byte(rr.Header.Seq)
42         b[9] = byte(rr.Header.Seq >> 8)
43         b[10] = byte(rr.Header.Seq >> 16)
44         b[11] = byte(rr.Header.Seq >> 24)
45         b[12] = byte(rr.Header.Pid)
46         b[13] = byte(rr.Header.Pid >> 8)
47         b[14] = byte(rr.Header.Pid >> 16)
48         b[15] = byte(rr.Header.Pid >> 24)
49         b[16] = byte(rr.Data.Family)
50         return b
51 }
52
53 func newNetlinkRouteRequest(proto, seq, family int) []byte {
54         rr := &NetlinkRouteRequest{}
55         rr.Header.Len = uint32(NLMSG_HDRLEN + SizeofRtGenmsg)
56         rr.Header.Type = uint16(proto)
57         rr.Header.Flags = NLM_F_DUMP | NLM_F_REQUEST
58         rr.Header.Seq = uint32(seq)
59         rr.Data.Family = uint8(family)
60         return rr.toWireFormat()
61 }
62
63 // NetlinkRIB returns routing information base, as known as RIB,
64 // which consists of network facility information, states and
65 // parameters.
66 func NetlinkRIB(proto, family int) ([]byte, int) {
67         var (
68                 s     int
69                 e     int
70                 lsanl SockaddrNetlink
71                 seq   int
72                 tab   []byte
73         )
74
75         s, e = Socket(AF_NETLINK, SOCK_RAW, 0)
76         if e != 0 {
77                 return nil, e
78         }
79         defer Close(s)
80
81         lsanl.Family = AF_NETLINK
82         e = Bind(s, &lsanl)
83         if e != 0 {
84                 return nil, e
85         }
86
87         seq++
88         wb := newNetlinkRouteRequest(proto, seq, family)
89         e = Sendto(s, wb, 0, &lsanl)
90         if e != 0 {
91                 return nil, e
92         }
93
94         for {
95                 var (
96                         rb  []byte
97                         nr  int
98                         lsa Sockaddr
99                 )
100
101                 rb = make([]byte, Getpagesize())
102                 nr, _, e = Recvfrom(s, rb, 0)
103                 if e != 0 {
104                         return nil, e
105                 }
106                 if nr < NLMSG_HDRLEN {
107                         return nil, EINVAL
108                 }
109                 rb = rb[:nr]
110                 tab = append(tab, rb...)
111
112                 msgs, _ := ParseNetlinkMessage(rb)
113                 for _, m := range msgs {
114                         if lsa, e = Getsockname(s); e != 0 {
115                                 return nil, e
116                         }
117                         switch v := lsa.(type) {
118                         case *SockaddrNetlink:
119                                 if m.Header.Seq != uint32(seq) || m.Header.Pid != v.Pid {
120                                         return nil, EINVAL
121                                 }
122                         default:
123                                 return nil, EINVAL
124                         }
125                         if m.Header.Type == NLMSG_DONE {
126                                 goto done
127                         }
128                         if m.Header.Type == NLMSG_ERROR {
129                                 return nil, EINVAL
130                         }
131                 }
132         }
133
134 done:
135         return tab, 0
136 }
137
138 // NetlinkMessage represents the netlink message.
139 type NetlinkMessage struct {
140         Header NlMsghdr
141         Data   []byte
142 }
143
144 // ParseNetlinkMessage parses buf as netlink messages and returns
145 // the slice containing the NetlinkMessage structs.
146 func ParseNetlinkMessage(buf []byte) ([]NetlinkMessage, int) {
147         var (
148                 h    *NlMsghdr
149                 dbuf []byte
150                 dlen int
151                 e    int
152                 msgs []NetlinkMessage
153         )
154
155         for len(buf) >= NLMSG_HDRLEN {
156                 h, dbuf, dlen, e = netlinkMessageHeaderAndData(buf)
157                 if e != 0 {
158                         break
159                 }
160                 m := NetlinkMessage{}
161                 m.Header = *h
162                 m.Data = dbuf[:int(h.Len)-NLMSG_HDRLEN]
163                 msgs = append(msgs, m)
164                 buf = buf[dlen:]
165         }
166
167         return msgs, e
168 }
169
170 func netlinkMessageHeaderAndData(buf []byte) (*NlMsghdr, []byte, int, int) {
171         h := (*NlMsghdr)(unsafe.Pointer(&buf[0]))
172         if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(buf) {
173                 return nil, nil, 0, EINVAL
174         }
175         return h, buf[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), 0
176 }
177
178 // NetlinkRouteAttr represents the netlink route attribute.
179 type NetlinkRouteAttr struct {
180         Attr  RtAttr
181         Value []byte
182 }
183
184 // ParseNetlinkRouteAttr parses msg's payload as netlink route
185 // attributes and returns the slice containing the NetlinkRouteAttr
186 // structs.
187 func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, int) {
188         var (
189                 buf   []byte
190                 a     *RtAttr
191                 alen  int
192                 vbuf  []byte
193                 e     int
194                 attrs []NetlinkRouteAttr
195         )
196
197         switch msg.Header.Type {
198         case RTM_NEWLINK, RTM_DELLINK:
199                 buf = msg.Data[SizeofIfInfomsg:]
200         case RTM_NEWADDR, RTM_DELADDR:
201                 buf = msg.Data[SizeofIfAddrmsg:]
202         case RTM_NEWROUTE, RTM_DELROUTE:
203                 buf = msg.Data[SizeofRtMsg:]
204         default:
205                 return nil, EINVAL
206         }
207
208         for len(buf) >= SizeofRtAttr {
209                 a, vbuf, alen, e = netlinkRouteAttrAndValue(buf)
210                 if e != 0 {
211                         break
212                 }
213                 ra := NetlinkRouteAttr{}
214                 ra.Attr = *a
215                 ra.Value = vbuf[:int(a.Len)-SizeofRtAttr]
216                 attrs = append(attrs, ra)
217                 buf = buf[alen:]
218         }
219
220         return attrs, 0
221 }
222
223 func netlinkRouteAttrAndValue(buf []byte) (*RtAttr, []byte, int, int) {
224         h := (*RtAttr)(unsafe.Pointer(&buf[0]))
225         if int(h.Len) < SizeofRtAttr || int(h.Len) > len(buf) {
226                 return nil, nil, 0, EINVAL
227         }
228         return h, buf[SizeofRtAttr:], rtaAlignOf(int(h.Len)), 0
229 }