rtnl_message.cc revision ad576bffebd92b9adf42ea6b9e43515169787cee
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
58d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/rtnl_message.h"
6dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
7dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart#include <linux/netlink.h>
8dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart#include <linux/rtnetlink.h>
93ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu#include <netinet/in.h>
10a41ab517725d036b63420f8445550246f8f50b99Alex Vakulenko#include <sys/socket.h>
11dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
128d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include <base/logging.h>
138d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu
148d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/ndisc.h"
15b691efd71561246065eae3cdd73a96ca1b8a528dChristopher Wiley
16dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartnamespace shill {
17dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
18dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartstruct RTNLHeader {
19dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  RTNLHeader() {
20dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    memset(this, 0, sizeof(*this));
21dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
22dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  struct nlmsghdr hdr;
23dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  union {
24dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct ifinfomsg ifi;
25dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct ifaddrmsg ifa;
26dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct rtmsg rtm;
27dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct rtgenmsg gen;
283ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    struct nduseroptmsg nd_user_opt;
29ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    struct ndmsg ndm;
30dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  };
31dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart};
32dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
33dd7df792d2401741183a954f3f6e97d4c6de1e22Paul StewartRTNLMessage::RTNLMessage()
349a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    : type_(kTypeUnknown),
359a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      mode_(kModeUnknown),
36dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      flags_(0),
37e636c6945299da860b360c4ed83c318e3ec41edeDarin Petkov      seq_(0),
38e636c6945299da860b360c4ed83c318e3ec41edeDarin Petkov      pid_(0),
39dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      interface_index_(0),
407355ce1937c504d836a303ac809bd436272212b3Paul Stewart      family_(IPAddress::kFamilyUnknown) {}
41dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
429a908080fc2a72dbf06f995b878fc8a3693b725aPaul StewartRTNLMessage::RTNLMessage(Type type,
439a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                         Mode mode,
44dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         unsigned int flags,
457fab89734d88724a288e96a9996b15548c5294c7Ben Chan                         uint32_t seq,
467fab89734d88724a288e96a9996b15548c5294c7Ben Chan                         uint32_t pid,
47dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         int interface_index,
48dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         IPAddress::Family family)
49dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    : type_(type),
50dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      mode_(mode),
51dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      flags_(flags),
52dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      seq_(seq),
53dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      pid_(pid),
54dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      interface_index_(interface_index),
55dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      family_(family) {}
56dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
57dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::Decode(const ByteString &msg) {
58dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  bool ret = DecodeInternal(msg);
59dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (!ret) {
60f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    Reset();
61dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
62dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return ret;
63dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
64dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
65dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeInternal(const ByteString &msg) {
66dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  const RTNLHeader *hdr =
67dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      reinterpret_cast<const RTNLHeader *>(msg.GetConstData());
68dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
69dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (msg.GetLength() < sizeof(hdr->hdr) ||
70dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      msg.GetLength() < hdr->hdr.nlmsg_len)
71dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
72dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
739a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  Mode mode = kModeUnknown;
74dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  switch (hdr->hdr.nlmsg_type) {
75dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWLINK:
76dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWADDR:
77dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWROUTE:
783ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  case RTM_NEWNDUSEROPT:
79ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  case RTM_NEWNEIGH:
809a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    mode = kModeAdd;
81dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
82dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
83dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELLINK:
84dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELADDR:
85dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELROUTE:
86ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  case RTM_DELNEIGH:
879a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    mode = kModeDelete;
88dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
89dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
90dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  default:
91dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
92dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
93dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
94cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan  rtattr *attr_data = nullptr;
95dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  int attr_length = 0;
96dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
97dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  switch (hdr->hdr.nlmsg_type) {
98dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWLINK:
99dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELLINK:
100dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeLink(hdr, mode, &attr_data, &attr_length))
101dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
102dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
103dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
104dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWADDR:
105dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELADDR:
106dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeAddress(hdr, mode, &attr_data, &attr_length))
107dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
108dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
109dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
110dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWROUTE:
111dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELROUTE:
112dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeRoute(hdr, mode, &attr_data, &attr_length))
113dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
114dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
115dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
1163ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  case RTM_NEWNDUSEROPT:
1173ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    if (!DecodeNdUserOption(hdr, mode, &attr_data, &attr_length))
1183ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu      return false;
1193ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    break;
1203ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
121ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  case RTM_NEWNEIGH:
122ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  case RTM_DELNEIGH:
123ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    if (!DecodeNeighbor(hdr, mode, &attr_data, &attr_length))
124ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      return false;
125ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    break;
126ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
127dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  default:
128dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    NOTREACHED();
129dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
130dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
131dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  flags_ = hdr->hdr.nlmsg_flags;
132dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  seq_ = hdr->hdr.nlmsg_seq;
133dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  pid_ = hdr->hdr.nlmsg_pid;
134dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
135dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  while (attr_data && RTA_OK(attr_data, attr_length)) {
136dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    SetAttribute(
137dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart        attr_data->rta_type,
138dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart        ByteString(reinterpret_cast<unsigned char *>(RTA_DATA(attr_data)),
139dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                   RTA_PAYLOAD(attr_data)));
140dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_data = RTA_NEXT(attr_data, attr_length);
141dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
142dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
143dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (attr_length) {
144dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    // We hit a parse error while going through the attributes
145dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes_.clear();
146dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
147dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
148dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
149dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
150dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
151dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
152dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeLink(const RTNLHeader *hdr,
1539a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                             Mode mode,
154dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             rtattr **attr_data,
155dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             int *attr_length) {
156dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifi))) {
157dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
158dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
159dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
160dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
161dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = IFLA_RTA(NLMSG_DATA(&hdr->hdr));
162dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = IFLA_PAYLOAD(&hdr->hdr);
163dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
1649a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  type_ = kTypeLink;
165dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->ifi.ifi_family;
166dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  interface_index_ = hdr->ifi.ifi_index;
167dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_link_status(LinkStatus(hdr->ifi.ifi_type,
168dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             hdr->ifi.ifi_flags,
169dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             hdr->ifi.ifi_change));
170dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
171dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
172dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
173dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeAddress(const RTNLHeader *hdr,
1749a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                                Mode mode,
175dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                rtattr **attr_data,
176dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                int *attr_length) {
177dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifa))) {
178dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
179dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
180dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
181dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = IFA_RTA(NLMSG_DATA(&hdr->hdr));
182dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = IFA_PAYLOAD(&hdr->hdr);
183dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
1849a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  type_ = kTypeAddress;
185dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->ifa.ifa_family;
186dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  interface_index_ = hdr->ifa.ifa_index;
187dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_address_status(AddressStatus(hdr->ifa.ifa_prefixlen,
188dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                   hdr->ifa.ifa_flags,
189dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                   hdr->ifa.ifa_scope));
190dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
191dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
192dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
193dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartbool RTNLMessage::DecodeRoute(const RTNLHeader *hdr,
1949a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                              Mode mode,
195dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                              rtattr **attr_data,
196dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                              int *attr_length) {
197dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->rtm))) {
198dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
199dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
200dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
201dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = RTM_RTA(NLMSG_DATA(&hdr->hdr));
202dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = RTM_PAYLOAD(&hdr->hdr);
203dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
2049a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  type_ = kTypeRoute;
205dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->rtm.rtm_family;
206dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_route_status(RouteStatus(hdr->rtm.rtm_dst_len,
207dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_src_len,
208dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_table,
209dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_protocol,
210dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_scope,
211dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_type,
212dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_flags));
213dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
214dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
215dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
2163ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiubool RTNLMessage::DecodeNdUserOption(const RTNLHeader *hdr,
2173ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu                                     Mode mode,
2183ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu                                     rtattr **attr_data,
2193ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu                                     int *attr_length) {
2203ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->nd_user_opt))) {
2213ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return false;
2223ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2233ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2243ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  mode_ = mode;
2253ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  interface_index_ = hdr->nd_user_opt.nduseropt_ifindex;
2263ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  family_ = hdr->nd_user_opt.nduseropt_family;
2273ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2283ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Verify IP family.
2293ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (family_ != IPAddress::kFamilyIPv6) {
2303ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return false;
2313ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2323ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Verify message must at-least contain the option header.
2333ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (hdr->nd_user_opt.nduseropt_opts_len < sizeof(NDUserOptionHeader)) {
2343ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return false;
2353ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2363ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2373ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Parse the option header.
2383ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  const NDUserOptionHeader *nd_user_option_header =
2393ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu      reinterpret_cast<const NDUserOptionHeader *>(
2407fab89734d88724a288e96a9996b15548c5294c7Ben Chan          reinterpret_cast<const uint8_t *>(&hdr->nd_user_opt) +
2413ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu          sizeof(struct nduseroptmsg));
2427fab89734d88724a288e96a9996b15548c5294c7Ben Chan  uint32_t lifetime = ntohl(nd_user_option_header->lifetime);
2433ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2443ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Verify option length.
2453ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // The length field in the header is in units of 8 octets.
2463ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  int opt_len = static_cast<int>(nd_user_option_header->length) * 8;
2473ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (opt_len != hdr->nd_user_opt.nduseropt_opts_len) {
2483ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return false;
2493ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2503ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2513ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Determine option data pointer and data length.
2527fab89734d88724a288e96a9996b15548c5294c7Ben Chan  const uint8_t *option_data =
2537fab89734d88724a288e96a9996b15548c5294c7Ben Chan      reinterpret_cast<const uint8_t *>(nd_user_option_header + 1);
2543ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  int data_len = opt_len - sizeof(NDUserOptionHeader);
2553ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2563ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (nd_user_option_header->type == ND_OPT_DNSSL) {
2573ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    // TODO(zqiu): Parse DNSSL (DNS Search List) option.
2583ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    type_ = kTypeDnssl;
2593ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return true;
2603ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  } else if (nd_user_option_header->type == ND_OPT_RDNSS) {
2613ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    // Parse RNDSS (Recursive DNS Server) option.
2623ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    type_ = kTypeRdnss;
2633ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return ParseRdnssOption(option_data, data_len, lifetime);
2643ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2653ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2663ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  return false;
2673ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu}
2683ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2697fab89734d88724a288e96a9996b15548c5294c7Ben Chanbool RTNLMessage::ParseRdnssOption(const uint8_t *data,
2703ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu                                   int length,
2717fab89734d88724a288e96a9996b15548c5294c7Ben Chan                                   uint32_t lifetime) {
2723ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  const int addr_length = IPAddress::GetAddressLength(IPAddress::kFamilyIPv6);
2733ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2743ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Verify data size are multiple of individual address size.
2753ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (length % addr_length != 0) {
2763ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return false;
2773ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2783ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2793ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Parse the DNS server addresses.
2803ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  std::vector<IPAddress> dns_server_addresses;
2813ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  while (length > 0) {
2823ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    dns_server_addresses.push_back(
2833ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu        IPAddress(IPAddress::kFamilyIPv6,
2843ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu                  ByteString(data, addr_length)));
2853ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    length -= addr_length;
2863ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    data += addr_length;
2873ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2883ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  set_rdnss_option(RdnssOption(lifetime, dns_server_addresses));
2893ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  return true;
2903ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu}
2913ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
292ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kellybool RTNLMessage::DecodeNeighbor(const RTNLHeader *hdr,
293ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly                                 Mode mode,
294ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly                                 rtattr **attr_data,
295ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly                                 int *attr_length) {
296ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ndm))) {
297ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    return false;
298ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  }
299ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
300ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  mode_ = mode;
301ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  interface_index_ = hdr->ndm.ndm_ifindex;
302ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  family_ = hdr->ndm.ndm_family;
303ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  type_ = kTypeNeighbor;
304ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
305ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  *attr_data = RTM_RTA(NLMSG_DATA(&hdr->hdr));
306ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  *attr_length = RTM_PAYLOAD(&hdr->hdr);
307ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
308ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  set_neighbor_status(NeighborStatus(hdr->ndm.ndm_state,
309ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly                                     hdr->ndm.ndm_flags,
310ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly                                     hdr->ndm.ndm_type));
311ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  return true;
312ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly}
313ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
314f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul StewartByteString RTNLMessage::Encode() const {
3159a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (type_ != kTypeLink &&
3169a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      type_ != kTypeAddress &&
317ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      type_ != kTypeRoute &&
318ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      type_ != kTypeNeighbor) {
319dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return ByteString();
320dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
321dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
322dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  RTNLHeader hdr;
323dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_flags = flags_;
324dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_seq = seq_;
325dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_pid = pid_;
326dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
3279a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (mode_ == kModeGet) {
3289a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    if (type_ == kTypeLink) {
329dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETLINK;
3309a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    } else if (type_ == kTypeAddress) {
331dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETADDR;
3329a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    } else if (type_ == kTypeRoute) {
333dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETROUTE;
334ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    } else if (type_ == kTypeNeighbor) {
335ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      hdr.hdr.nlmsg_type = RTM_GETNEIGH;
336f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    } else {
337f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
338f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return ByteString();
339dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    }
340dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr.gen));
3419a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    hdr.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
342dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.gen.rtgen_family = family_;
343dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  } else {
344dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    switch (type_) {
3459a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    case kTypeLink:
346f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (!EncodeLink(&hdr)) {
347f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart        return ByteString();
348f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      }
349dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
350dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
3519a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    case kTypeAddress:
352f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (!EncodeAddress(&hdr)) {
353f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart        return ByteString();
354f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      }
355dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
356dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
3579a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    case kTypeRoute:
358f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (!EncodeRoute(&hdr)) {
359f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart        return ByteString();
360f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      }
361dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
362dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
363ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    case kTypeNeighbor:
364ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      if (!EncodeNeighbor(&hdr)) {
365ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly        return ByteString();
366ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      }
367ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      break;
368ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
369dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    default:
370dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      NOTREACHED();
371dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    }
372dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
373dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
374dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  size_t header_length = hdr.hdr.nlmsg_len;
375dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  ByteString attributes;
376dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
3778a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko  for (auto attr = attributes_.begin(); attr != attributes_.end(); ++attr) {
378dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    size_t len = RTA_LENGTH(attr->second.GetLength());
379dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.hdr.nlmsg_len = NLMSG_ALIGN(hdr.hdr.nlmsg_len) + RTA_ALIGN(len);
380dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
3818a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko    struct rtattr rt_attr = {
3828a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko      static_cast<unsigned short>(len),  // NOLINT(runtime/int)
3838a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko      attr->first
3848a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko    };
385dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    ByteString attr_header(reinterpret_cast<unsigned char *>(&rt_attr),
386dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                           sizeof(rt_attr));
387dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_header.Resize(RTA_ALIGN(attr_header.GetLength()));
388dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes.Append(attr_header);
389dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
390dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    ByteString attr_data(attr->second);
391dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_data.Resize(RTA_ALIGN(attr_data.GetLength()));
392dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes.Append(attr_data);
393dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
394dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
395dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  ByteString packet(reinterpret_cast<unsigned char *>(&hdr), header_length);
396dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  packet.Append(attributes);
397dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
398dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return packet;
399dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
400dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
401f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartbool RTNLMessage::EncodeLink(RTNLHeader *hdr) const {
402f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  switch (mode_) {
403f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeAdd:
404f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_NEWLINK;
405f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
406f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeDelete:
407f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_DELLINK;
408f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
409f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeQuery:
410f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_GETLINK;
411f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
412f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    default:
413f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
414f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return false;
415f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
416dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifi));
417dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_family = family_;
418cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  hdr->ifi.ifi_index = interface_index_;
419dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_type = link_status_.type;
420dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_flags = link_status_.flags;
421dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_change = link_status_.change;
422f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
423dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
424dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
425f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartbool RTNLMessage::EncodeAddress(RTNLHeader *hdr) const {
426f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  switch (mode_) {
427f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeAdd:
428f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_NEWADDR;
429f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
430f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeDelete:
431f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_DELADDR;
432f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
433f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeQuery:
434f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_GETADDR;
435f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
436f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    default:
437f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
438f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return false;
439f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
440dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifa));
441dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_family = family_;
442dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_prefixlen = address_status_.prefix_len;
443dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_flags = address_status_.flags;
444dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_scope = address_status_.scope;
445dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_index = interface_index_;
446f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
447dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
448dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
449f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartbool RTNLMessage::EncodeRoute(RTNLHeader *hdr) const {
450f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  switch (mode_) {
451f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeAdd:
452f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_NEWROUTE;
453f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
454f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeDelete:
455f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_DELROUTE;
456f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
457f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeQuery:
458f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_GETROUTE;
459f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
460f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    default:
461f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
462f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return false;
463f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
464dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->rtm));
465dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_family = family_;
466dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_dst_len = route_status_.dst_prefix;
467dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_src_len = route_status_.src_prefix;
468dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_table = route_status_.table;
469dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_protocol = route_status_.protocol;
470dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_scope = route_status_.scope;
471dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_type = route_status_.type;
472dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_flags = route_status_.flags;
473f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
474f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart}
475f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
476ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kellybool RTNLMessage::EncodeNeighbor(RTNLHeader *hdr) const {
477ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  switch (mode_) {
478ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    case kModeAdd:
479ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      hdr->hdr.nlmsg_type = RTM_NEWNEIGH;
480ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      break;
481ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    case kModeDelete:
482ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      hdr->hdr.nlmsg_type = RTM_DELNEIGH;
483ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      break;
484ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    case kModeQuery:
485ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      hdr->hdr.nlmsg_type = RTM_GETNEIGH;
486ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      break;
487ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    default:
488ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      NOTIMPLEMENTED();
489ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      return false;
490ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  }
491ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ndm));
492ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->ndm.ndm_family = family_;
493ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->ndm.ndm_ifindex = interface_index_;
494ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->ndm.ndm_state = neighbor_status_.state;
495ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->ndm.ndm_flags = neighbor_status_.flags;
496ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->ndm.ndm_type = neighbor_status_.type;
497ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  return true;
498ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly}
499ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
500f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartvoid RTNLMessage::Reset() {
501f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  mode_ = kModeUnknown;
502f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  type_ = kTypeUnknown;
503f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  flags_ = 0;
504f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  seq_ = 0;
505e636c6945299da860b360c4ed83c318e3ec41edeDarin Petkov  pid_ = 0;
506f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  interface_index_ = 0;
507f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  family_ = IPAddress::kFamilyUnknown;
508f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  link_status_ = LinkStatus();
509f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  address_status_ = AddressStatus();
510f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  route_status_ = RouteStatus();
511f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  attributes_.clear();
512dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
513dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
514dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}  // namespace shill
515