rtnl_message.cc revision dd7df792d2401741183a954f3f6e97d4c6de1e22
1dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart// Use of this source code is governed by a BSD-style license that can be
3dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart// found in the LICENSE file.
4dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
5dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart#include "shill/rtnl_message.h"
6dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
7dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart#include <base/logging.h>
8dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
9dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart#include <sys/socket.h>
10dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart#include <linux/netlink.h>
11dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart#include <linux/rtnetlink.h>
12dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
13dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartnamespace shill {
14dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
15dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartstruct RTNLHeader {
16dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  RTNLHeader() {
17dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    memset(this, 0, sizeof(*this));
18dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
19dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  struct nlmsghdr hdr;
20dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  union {
21dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct ifinfomsg ifi;
22dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct ifaddrmsg ifa;
23dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct rtmsg rtm;
24dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct rtgenmsg gen;
25dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  };
26dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart};
27dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
28dd7df792d2401741183a954f3f6e97d4c6de1e22Paul StewartRTNLMessage::RTNLMessage()
29dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    : type_(kMessageTypeUnknown),
30dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      mode_(kMessageModeUnknown),
31dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      flags_(0),
32dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      interface_index_(0),
33dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      family_(IPAddress::kAddressFamilyUnknown) {}
34dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
35dd7df792d2401741183a954f3f6e97d4c6de1e22Paul StewartRTNLMessage::RTNLMessage(MessageType type,
36dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         MessageMode mode,
37dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         unsigned int flags,
38dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         uint32 seq,
39dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         uint32 pid,
40dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         int interface_index,
41dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         IPAddress::Family family)
42dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    : type_(type),
43dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      mode_(mode),
44dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      flags_(flags),
45dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      seq_(seq),
46dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      pid_(pid),
47dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      interface_index_(interface_index),
48dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      family_(family) {}
49dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
50dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::Decode(const ByteString &msg) {
51dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  bool ret = DecodeInternal(msg);
52dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (!ret) {
53dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    mode_ = kMessageModeUnknown;
54dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    type_ = kMessageTypeUnknown;
55dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
56dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return ret;
57dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
58dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
59dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeInternal(const ByteString &msg) {
60dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  const RTNLHeader *hdr =
61dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      reinterpret_cast<const RTNLHeader *>(msg.GetConstData());
62dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
63dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (msg.GetLength() < sizeof(hdr->hdr) ||
64dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      msg.GetLength() < hdr->hdr.nlmsg_len)
65dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
66dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
67dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  MessageMode mode = kMessageModeUnknown;
68dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  switch (hdr->hdr.nlmsg_type) {
69dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWLINK:
70dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWADDR:
71dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWROUTE:
72dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    mode = kMessageModeAdd;
73dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
74dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
75dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELLINK:
76dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELADDR:
77dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELROUTE:
78dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    mode = kMessageModeDelete;
79dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
80dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
81dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  default:
82dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
83dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
84dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
85dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  rtattr *attr_data = NULL;
86dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  int attr_length = 0;
87dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
88dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  switch (hdr->hdr.nlmsg_type) {
89dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWLINK:
90dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELLINK:
91dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeLink(hdr, mode, &attr_data, &attr_length))
92dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
93dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
94dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
95dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWADDR:
96dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELADDR:
97dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeAddress(hdr, mode, &attr_data, &attr_length))
98dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
99dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
100dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
101dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWROUTE:
102dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELROUTE:
103dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeRoute(hdr, mode, &attr_data, &attr_length))
104dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
105dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
106dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
107dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  default:
108dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    NOTREACHED();
109dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
110dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
111dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  flags_ = hdr->hdr.nlmsg_flags;
112dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  seq_ = hdr->hdr.nlmsg_seq;
113dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  pid_ = hdr->hdr.nlmsg_pid;
114dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
115dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  while (attr_data && RTA_OK(attr_data, attr_length)) {
116dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    SetAttribute(
117dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart        attr_data->rta_type,
118dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart        ByteString(reinterpret_cast<unsigned char *>(RTA_DATA(attr_data)),
119dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                   RTA_PAYLOAD(attr_data)));
120dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_data = RTA_NEXT(attr_data, attr_length);
121dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
122dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
123dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (attr_length) {
124dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    // We hit a parse error while going through the attributes
125dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes_.clear();
126dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
127dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
128dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
129dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
130dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
131dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
132dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeLink(const RTNLHeader *hdr,
133dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             MessageMode mode,
134dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             rtattr **attr_data,
135dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             int *attr_length) {
136dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifi))) {
137dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
138dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
139dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
140dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
141dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = IFLA_RTA(NLMSG_DATA(&hdr->hdr));
142dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = IFLA_PAYLOAD(&hdr->hdr);
143dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
144dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  type_ = kMessageTypeLink;
145dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->ifi.ifi_family;
146dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  interface_index_ = hdr->ifi.ifi_index;
147dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_link_status(LinkStatus(hdr->ifi.ifi_type,
148dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             hdr->ifi.ifi_flags,
149dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             hdr->ifi.ifi_change));
150dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
151dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
152dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
153dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeAddress(const RTNLHeader *hdr,
154dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                MessageMode mode,
155dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                rtattr **attr_data,
156dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                int *attr_length) {
157dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifa))) {
158dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
159dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
160dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
161dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = IFA_RTA(NLMSG_DATA(&hdr->hdr));
162dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = IFA_PAYLOAD(&hdr->hdr);
163dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
164dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  type_ = kMessageTypeAddress;
165dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->ifa.ifa_family;
166dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  interface_index_ = hdr->ifa.ifa_index;
167dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_address_status(AddressStatus(hdr->ifa.ifa_prefixlen,
168dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                   hdr->ifa.ifa_flags,
169dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                   hdr->ifa.ifa_scope));
170dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
171dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
172dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
173dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeRoute(const RTNLHeader *hdr,
174dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                              MessageMode mode,
175dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                              rtattr **attr_data,
176dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                              int *attr_length) {
177dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->rtm))) {
178dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
179dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
180dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
181dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = RTM_RTA(NLMSG_DATA(&hdr->hdr));
182dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = RTM_PAYLOAD(&hdr->hdr);
183dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
184dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  type_ = kMessageTypeRoute;
185dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->rtm.rtm_family;
186dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_route_status(RouteStatus(hdr->rtm.rtm_dst_len,
187dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_src_len,
188dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_table,
189dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_protocol,
190dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_scope,
191dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_type,
192dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_flags));
193dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
194dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
195dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
196dd7df792d2401741183a954f3f6e97d4c6de1e22Paul StewartByteString RTNLMessage::Encode() {
197dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (type_ != kMessageTypeLink &&
198dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      type_ != kMessageTypeAddress &&
199dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      type_ != kMessageTypeRoute) {
200dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return ByteString();
201dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
202dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
203dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  RTNLHeader hdr;
204dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_flags = flags_;
205dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_seq = seq_;
206dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_pid = pid_;
207dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_seq = 0;
208dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
209dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (mode_ == kMessageModeGet) {
210dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (type_ == kMessageTypeLink) {
211dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETLINK;
212dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    } else if (type_ == kMessageTypeAddress) {
213dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETADDR;
214dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    } else if (type_ == kMessageTypeRoute) {
215dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETROUTE;
216dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    }
217dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr.gen));
218dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.gen.rtgen_family = family_;
219dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  } else {
220dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    switch (type_) {
221dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    case kMessageTypeLink:
222dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      EncodeLink(&hdr);
223dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
224dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
225dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    case kMessageTypeAddress:
226dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      EncodeAddress(&hdr);
227dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
228dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
229dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    case kMessageTypeRoute:
230dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      EncodeRoute(&hdr);
231dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
232dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
233dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    default:
234dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      NOTREACHED();
235dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    }
236dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
237dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
238dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  size_t header_length = hdr.hdr.nlmsg_len;
239dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  ByteString attributes;
240dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
241dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  base::hash_map<uint16, ByteString>::iterator attr;
242dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  for (attr = attributes_.begin(); attr != attributes_.end(); ++attr) {
243dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    size_t len = RTA_LENGTH(attr->second.GetLength());
244dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.hdr.nlmsg_len = NLMSG_ALIGN(hdr.hdr.nlmsg_len) + RTA_ALIGN(len);
245dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
246dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct rtattr rt_attr = { len, attr->first };
247dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    ByteString attr_header(reinterpret_cast<unsigned char *>(&rt_attr),
248dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                           sizeof(rt_attr));
249dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_header.Resize(RTA_ALIGN(attr_header.GetLength()));
250dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes.Append(attr_header);
251dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
252dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    ByteString attr_data(attr->second);
253dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_data.Resize(RTA_ALIGN(attr_data.GetLength()));
254dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes.Append(attr_data);
255dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
256dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
257dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  ByteString packet(reinterpret_cast<unsigned char *>(&hdr), header_length);
258dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  packet.Append(attributes);
259dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
260dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return packet;
261dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
262dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
263dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartvoid RTNLMessage::EncodeLink(RTNLHeader *hdr) {
264dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_type = (mode_ == kMessageModeAdd) ? RTM_NEWLINK : RTM_DELLINK;
265dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifi));
266dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_family = family_;
267dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_type = link_status_.type;
268dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_flags = link_status_.flags;
269dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_change = link_status_.change;
270dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
271dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
272dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartvoid RTNLMessage::EncodeAddress(RTNLHeader *hdr) {
273dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_type = (mode_ == kMessageModeAdd) ? RTM_NEWADDR : RTM_DELADDR;
274dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifa));
275dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_family = family_;
276dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_prefixlen = address_status_.prefix_len;
277dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_flags = address_status_.flags;
278dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_scope = address_status_.scope;
279dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_index = interface_index_;
280dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
281dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
282dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartvoid RTNLMessage::EncodeRoute(RTNLHeader *hdr) {
283dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_type =
284dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      (mode_ == kMessageModeAdd) ? RTM_NEWROUTE : RTM_DELROUTE;
285dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->rtm));
286dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_family = family_;
287dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_dst_len = route_status_.dst_prefix;
288dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_src_len = route_status_.src_prefix;
289dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_table = route_status_.table;
290dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_protocol = route_status_.protocol;
291dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_scope = route_status_.scope;
292dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_type = route_status_.type;
293dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_flags = route_status_.flags;
294dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
295dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
296dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}  // namespace shill
297