OSDN Git Service

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