| // Copyright 2011 The Go Authors.  All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | // Netlink sockets and messages | 
 |  | 
 | package syscall | 
 |  | 
 | import "unsafe" | 
 |  | 
 | // Round the length of a netlink message up to align it properly. | 
 | func nlmAlignOf(msglen int) int { | 
 | 	return (msglen + NLMSG_ALIGNTO - 1) & ^(NLMSG_ALIGNTO - 1) | 
 | } | 
 |  | 
 | // Round the length of a netlink route attribute up to align it | 
 | // properly. | 
 | func rtaAlignOf(attrlen int) int { | 
 | 	return (attrlen + RTA_ALIGNTO - 1) & ^(RTA_ALIGNTO - 1) | 
 | } | 
 |  | 
 | // NetlinkRouteRequest represents a request message to receive routing | 
 | // and link states from the kernel. | 
 | type NetlinkRouteRequest struct { | 
 | 	Header NlMsghdr | 
 | 	Data   RtGenmsg | 
 | } | 
 |  | 
 | func (rr *NetlinkRouteRequest) toWireFormat() []byte { | 
 | 	b := make([]byte, rr.Header.Len) | 
 | 	*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len | 
 | 	*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type | 
 | 	*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags | 
 | 	*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq | 
 | 	*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid | 
 | 	b[16] = byte(rr.Data.Family) | 
 | 	return b | 
 | } | 
 |  | 
 | func newNetlinkRouteRequest(proto, seq, family int) []byte { | 
 | 	rr := &NetlinkRouteRequest{} | 
 | 	rr.Header.Len = uint32(NLMSG_HDRLEN + SizeofRtGenmsg) | 
 | 	rr.Header.Type = uint16(proto) | 
 | 	rr.Header.Flags = NLM_F_DUMP | NLM_F_REQUEST | 
 | 	rr.Header.Seq = uint32(seq) | 
 | 	rr.Data.Family = uint8(family) | 
 | 	return rr.toWireFormat() | 
 | } | 
 |  | 
 | // NetlinkRIB returns routing information base, as known as RIB, which | 
 | // consists of network facility information, states and parameters. | 
 | func NetlinkRIB(proto, family int) ([]byte, error) { | 
 | 	s, err := Socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) | 
 | 	if err != nil { | 
 | 		return nil, err | 
 | 	} | 
 | 	defer Close(s) | 
 | 	lsa := &SockaddrNetlink{Family: AF_NETLINK} | 
 | 	if err := Bind(s, lsa); err != nil { | 
 | 		return nil, err | 
 | 	} | 
 | 	wb := newNetlinkRouteRequest(proto, 1, family) | 
 | 	if err := Sendto(s, wb, 0, lsa); err != nil { | 
 | 		return nil, err | 
 | 	} | 
 | 	var tab []byte | 
 | 	rbNew := make([]byte, Getpagesize()) | 
 | done: | 
 | 	for { | 
 | 		rb := rbNew | 
 | 		nr, _, err := Recvfrom(s, rb, 0) | 
 | 		if err != nil { | 
 | 			return nil, err | 
 | 		} | 
 | 		if nr < NLMSG_HDRLEN { | 
 | 			return nil, EINVAL | 
 | 		} | 
 | 		rb = rb[:nr] | 
 | 		tab = append(tab, rb...) | 
 | 		msgs, err := ParseNetlinkMessage(rb) | 
 | 		if err != nil { | 
 | 			return nil, err | 
 | 		} | 
 | 		for _, m := range msgs { | 
 | 			lsa, err := Getsockname(s) | 
 | 			if err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			switch v := lsa.(type) { | 
 | 			case *SockaddrNetlink: | 
 | 				if m.Header.Seq != 1 || m.Header.Pid != v.Pid { | 
 | 					return nil, EINVAL | 
 | 				} | 
 | 			default: | 
 | 				return nil, EINVAL | 
 | 			} | 
 | 			if m.Header.Type == NLMSG_DONE { | 
 | 				break done | 
 | 			} | 
 | 			if m.Header.Type == NLMSG_ERROR { | 
 | 				return nil, EINVAL | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	return tab, nil | 
 | } | 
 |  | 
 | // NetlinkMessage represents a netlink message. | 
 | type NetlinkMessage struct { | 
 | 	Header NlMsghdr | 
 | 	Data   []byte | 
 | } | 
 |  | 
 | // ParseNetlinkMessage parses b as an array of netlink messages and | 
 | // returns the slice containing the NetlinkMessage structures. | 
 | func ParseNetlinkMessage(b []byte) ([]NetlinkMessage, error) { | 
 | 	var msgs []NetlinkMessage | 
 | 	for len(b) >= NLMSG_HDRLEN { | 
 | 		h, dbuf, dlen, err := netlinkMessageHeaderAndData(b) | 
 | 		if err != nil { | 
 | 			return nil, err | 
 | 		} | 
 | 		m := NetlinkMessage{Header: *h, Data: dbuf[:int(h.Len)-NLMSG_HDRLEN]} | 
 | 		msgs = append(msgs, m) | 
 | 		b = b[dlen:] | 
 | 	} | 
 | 	return msgs, nil | 
 | } | 
 |  | 
 | func netlinkMessageHeaderAndData(b []byte) (*NlMsghdr, []byte, int, error) { | 
 | 	h := (*NlMsghdr)(unsafe.Pointer(&b[0])) | 
 | 	if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(b) { | 
 | 		return nil, nil, 0, EINVAL | 
 | 	} | 
 | 	return h, b[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil | 
 | } | 
 |  | 
 | // NetlinkRouteAttr represents a netlink route attribute. | 
 | type NetlinkRouteAttr struct { | 
 | 	Attr  RtAttr | 
 | 	Value []byte | 
 | } | 
 |  | 
 | // ParseNetlinkRouteAttr parses m's payload as an array of netlink | 
 | // route attributes and returns the slice containing the | 
 | // NetlinkRouteAttr structures. | 
 | func ParseNetlinkRouteAttr(m *NetlinkMessage) ([]NetlinkRouteAttr, error) { | 
 | 	var b []byte | 
 | 	switch m.Header.Type { | 
 | 	case RTM_NEWLINK, RTM_DELLINK: | 
 | 		b = m.Data[SizeofIfInfomsg:] | 
 | 	case RTM_NEWADDR, RTM_DELADDR: | 
 | 		b = m.Data[SizeofIfAddrmsg:] | 
 | 	case RTM_NEWROUTE, RTM_DELROUTE: | 
 | 		b = m.Data[SizeofRtMsg:] | 
 | 	default: | 
 | 		return nil, EINVAL | 
 | 	} | 
 | 	var attrs []NetlinkRouteAttr | 
 | 	for len(b) >= SizeofRtAttr { | 
 | 		a, vbuf, alen, err := netlinkRouteAttrAndValue(b) | 
 | 		if err != nil { | 
 | 			return nil, err | 
 | 		} | 
 | 		ra := NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-SizeofRtAttr]} | 
 | 		attrs = append(attrs, ra) | 
 | 		b = b[alen:] | 
 | 	} | 
 | 	return attrs, nil | 
 | } | 
 |  | 
 | func netlinkRouteAttrAndValue(b []byte) (*RtAttr, []byte, int, error) { | 
 | 	a := (*RtAttr)(unsafe.Pointer(&b[0])) | 
 | 	if int(a.Len) < SizeofRtAttr || int(a.Len) > len(b) { | 
 | 		return nil, nil, 0, EINVAL | 
 | 	} | 
 | 	return a, b[SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil | 
 | } |