rtnl_message.cc revision b691efd71561246065eae3cdd73a96ca1b8a528d
1f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart// Copyright (c) 2012 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 <sys/socket.h>
8dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart#include <linux/netlink.h>
9dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart#include <linux/rtnetlink.h>
10dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
11b691efd71561246065eae3cdd73a96ca1b8a528dChristopher Wiley#include "shill/logging.h"
12b691efd71561246065eae3cdd73a96ca1b8a528dChristopher Wiley
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()
299a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    : type_(kTypeUnknown),
309a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      mode_(kModeUnknown),
31dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      flags_(0),
32e636c6945299da860b360c4ed83c318e3ec41edeDarin Petkov      seq_(0),
33e636c6945299da860b360c4ed83c318e3ec41edeDarin Petkov      pid_(0),
34dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      interface_index_(0),
357355ce1937c504d836a303ac809bd436272212b3Paul Stewart      family_(IPAddress::kFamilyUnknown) {}
36dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
379a908080fc2a72dbf06f995b878fc8a3693b725aPaul StewartRTNLMessage::RTNLMessage(Type type,
389a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                         Mode mode,
39dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         unsigned int flags,
40dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         uint32 seq,
41dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         uint32 pid,
42dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         int interface_index,
43dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         IPAddress::Family family)
44dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    : type_(type),
45dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      mode_(mode),
46dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      flags_(flags),
47dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      seq_(seq),
48dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      pid_(pid),
49dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      interface_index_(interface_index),
50dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      family_(family) {}
51dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
52dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::Decode(const ByteString &msg) {
53dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  bool ret = DecodeInternal(msg);
54dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (!ret) {
55f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    Reset();
56dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
57dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return ret;
58dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
59dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
60dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeInternal(const ByteString &msg) {
61dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  const RTNLHeader *hdr =
62dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      reinterpret_cast<const RTNLHeader *>(msg.GetConstData());
63dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
64dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (msg.GetLength() < sizeof(hdr->hdr) ||
65dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      msg.GetLength() < hdr->hdr.nlmsg_len)
66dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
67dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
689a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  Mode mode = kModeUnknown;
69dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  switch (hdr->hdr.nlmsg_type) {
70dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWLINK:
71dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWADDR:
72dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWROUTE:
739a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    mode = kModeAdd;
74dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
75dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
76dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELLINK:
77dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELADDR:
78dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELROUTE:
799a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    mode = kModeDelete;
80dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
81dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
82dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  default:
83dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
84dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
85dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
86dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  rtattr *attr_data = NULL;
87dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  int attr_length = 0;
88dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
89dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  switch (hdr->hdr.nlmsg_type) {
90dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWLINK:
91dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELLINK:
92dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeLink(hdr, mode, &attr_data, &attr_length))
93dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
94dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
95dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
96dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWADDR:
97dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELADDR:
98dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeAddress(hdr, mode, &attr_data, &attr_length))
99dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
100dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
101dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
102dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWROUTE:
103dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELROUTE:
104dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeRoute(hdr, mode, &attr_data, &attr_length))
105dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
106dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
107dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
108dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  default:
109dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    NOTREACHED();
110dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
111dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
112dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  flags_ = hdr->hdr.nlmsg_flags;
113dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  seq_ = hdr->hdr.nlmsg_seq;
114dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  pid_ = hdr->hdr.nlmsg_pid;
115dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
116dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  while (attr_data && RTA_OK(attr_data, attr_length)) {
117dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    SetAttribute(
118dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart        attr_data->rta_type,
119dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart        ByteString(reinterpret_cast<unsigned char *>(RTA_DATA(attr_data)),
120dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                   RTA_PAYLOAD(attr_data)));
121dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_data = RTA_NEXT(attr_data, attr_length);
122dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
123dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
124dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (attr_length) {
125dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    // We hit a parse error while going through the attributes
126dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes_.clear();
127dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
128dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
129dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
130dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
131dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
132dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
133dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeLink(const RTNLHeader *hdr,
1349a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                             Mode mode,
135dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             rtattr **attr_data,
136dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             int *attr_length) {
137dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifi))) {
138dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
139dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
140dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
141dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
142dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = IFLA_RTA(NLMSG_DATA(&hdr->hdr));
143dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = IFLA_PAYLOAD(&hdr->hdr);
144dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
1459a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  type_ = kTypeLink;
146dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->ifi.ifi_family;
147dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  interface_index_ = hdr->ifi.ifi_index;
148dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_link_status(LinkStatus(hdr->ifi.ifi_type,
149dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             hdr->ifi.ifi_flags,
150dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             hdr->ifi.ifi_change));
151dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
152dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
153dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
154dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeAddress(const RTNLHeader *hdr,
1559a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                                Mode mode,
156dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                rtattr **attr_data,
157dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                int *attr_length) {
158dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifa))) {
159dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
160dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
161dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
162dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = IFA_RTA(NLMSG_DATA(&hdr->hdr));
163dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = IFA_PAYLOAD(&hdr->hdr);
164dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
1659a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  type_ = kTypeAddress;
166dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->ifa.ifa_family;
167dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  interface_index_ = hdr->ifa.ifa_index;
168dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_address_status(AddressStatus(hdr->ifa.ifa_prefixlen,
169dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                   hdr->ifa.ifa_flags,
170dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                   hdr->ifa.ifa_scope));
171dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
172dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
173dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
174dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeRoute(const RTNLHeader *hdr,
1759a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                              Mode mode,
176dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                              rtattr **attr_data,
177dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                              int *attr_length) {
178dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->rtm))) {
179dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
180dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
181dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
182dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = RTM_RTA(NLMSG_DATA(&hdr->hdr));
183dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = RTM_PAYLOAD(&hdr->hdr);
184dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
1859a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  type_ = kTypeRoute;
186dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->rtm.rtm_family;
187dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_route_status(RouteStatus(hdr->rtm.rtm_dst_len,
188dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_src_len,
189dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_table,
190dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_protocol,
191dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_scope,
192dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_type,
193dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_flags));
194dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
195dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
196dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
197f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul StewartByteString RTNLMessage::Encode() const {
1989a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (type_ != kTypeLink &&
1999a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      type_ != kTypeAddress &&
2009a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      type_ != kTypeRoute) {
201dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return ByteString();
202dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
203dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
204dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  RTNLHeader hdr;
205dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_flags = flags_;
206dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_seq = seq_;
207dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_pid = pid_;
208dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
2099a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (mode_ == kModeGet) {
2109a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    if (type_ == kTypeLink) {
211dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETLINK;
2129a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    } else if (type_ == kTypeAddress) {
213dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETADDR;
2149a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    } else if (type_ == kTypeRoute) {
215dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETROUTE;
216f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    } else {
217f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
218f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return ByteString();
219dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    }
220dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr.gen));
2219a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    hdr.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
222dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.gen.rtgen_family = family_;
223dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  } else {
224dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    switch (type_) {
2259a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    case kTypeLink:
226f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (!EncodeLink(&hdr)) {
227f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart        return ByteString();
228f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      }
229dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
230dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
2319a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    case kTypeAddress:
232f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (!EncodeAddress(&hdr)) {
233f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart        return ByteString();
234f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      }
235dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
236dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
2379a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    case kTypeRoute:
238f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (!EncodeRoute(&hdr)) {
239f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart        return ByteString();
240f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      }
241dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
242dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
243dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    default:
244dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      NOTREACHED();
245dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    }
246dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
247dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
248dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  size_t header_length = hdr.hdr.nlmsg_len;
249dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  ByteString attributes;
250dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
251f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  base::hash_map<uint16, ByteString>::const_iterator attr;
252dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  for (attr = attributes_.begin(); attr != attributes_.end(); ++attr) {
253dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    size_t len = RTA_LENGTH(attr->second.GetLength());
254dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.hdr.nlmsg_len = NLMSG_ALIGN(hdr.hdr.nlmsg_len) + RTA_ALIGN(len);
255dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
256b970b8fa6d18145234ee243a7b6e7d77b411b88aHan Shen    struct rtattr rt_attr = { static_cast<unsigned short>(len), attr->first };
257dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    ByteString attr_header(reinterpret_cast<unsigned char *>(&rt_attr),
258dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                           sizeof(rt_attr));
259dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_header.Resize(RTA_ALIGN(attr_header.GetLength()));
260dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes.Append(attr_header);
261dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
262dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    ByteString attr_data(attr->second);
263dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_data.Resize(RTA_ALIGN(attr_data.GetLength()));
264dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes.Append(attr_data);
265dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
266dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
267dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  ByteString packet(reinterpret_cast<unsigned char *>(&hdr), header_length);
268dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  packet.Append(attributes);
269dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
270dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return packet;
271dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
272dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
273f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartbool RTNLMessage::EncodeLink(RTNLHeader *hdr) const {
274f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  switch (mode_) {
275f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeAdd:
276f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_NEWLINK;
277f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
278f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeDelete:
279f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_DELLINK;
280f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
281f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeQuery:
282f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_GETLINK;
283f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
284f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    default:
285f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
286f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return false;
287f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
288dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifi));
289dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_family = family_;
290cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  hdr->ifi.ifi_index = interface_index_;
291dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_type = link_status_.type;
292dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_flags = link_status_.flags;
293dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_change = link_status_.change;
294f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
295dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
296dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
297f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartbool RTNLMessage::EncodeAddress(RTNLHeader *hdr) const {
298f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  switch (mode_) {
299f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeAdd:
300f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_NEWADDR;
301f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
302f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeDelete:
303f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_DELADDR;
304f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
305f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeQuery:
306f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_GETADDR;
307f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
308f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    default:
309f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
310f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return false;
311f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
312dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifa));
313dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_family = family_;
314dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_prefixlen = address_status_.prefix_len;
315dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_flags = address_status_.flags;
316dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_scope = address_status_.scope;
317dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_index = interface_index_;
318f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
319dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
320dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
321f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartbool RTNLMessage::EncodeRoute(RTNLHeader *hdr) const {
322f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  switch (mode_) {
323f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeAdd:
324f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_NEWROUTE;
325f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
326f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeDelete:
327f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_DELROUTE;
328f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
329f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeQuery:
330f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_GETROUTE;
331f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
332f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    default:
333f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
334f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return false;
335f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
336dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->rtm));
337dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_family = family_;
338dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_dst_len = route_status_.dst_prefix;
339dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_src_len = route_status_.src_prefix;
340dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_table = route_status_.table;
341dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_protocol = route_status_.protocol;
342dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_scope = route_status_.scope;
343dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_type = route_status_.type;
344dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_flags = route_status_.flags;
345f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
346f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart}
347f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
348f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartvoid RTNLMessage::Reset() {
349f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  mode_ = kModeUnknown;
350f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  type_ = kTypeUnknown;
351f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  flags_ = 0;
352f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  seq_ = 0;
353e636c6945299da860b360c4ed83c318e3ec41edeDarin Petkov  pid_ = 0;
354f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  interface_index_ = 0;
355f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  family_ = IPAddress::kFamilyUnknown;
356f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  link_status_ = LinkStatus();
357f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  address_status_ = AddressStatus();
358f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  route_status_ = RouteStatus();
359f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  attributes_.clear();
360dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
361dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
362dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}  // namespace shill
363