1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2012 The Android Open Source Project
3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Licensed under the Apache License, Version 2.0 (the "License");
5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// you may not use this file except in compliance with the License.
6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// You may obtain a copy of the License at
7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//      http://www.apache.org/licenses/LICENSE-2.0
9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Unless required by applicable law or agreed to in writing, software
11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// distributed under the License is distributed on an "AS IS" BASIS,
12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// See the License for the specific language governing permissions and
14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// limitations under the License.
15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
16dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
178d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/rtnl_message.h"
18dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
19dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart#include <linux/netlink.h>
20dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart#include <linux/rtnetlink.h>
213ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu#include <netinet/in.h>
22a41ab517725d036b63420f8445550246f8f50b99Alex Vakulenko#include <sys/socket.h>
23dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
248d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include <base/logging.h>
258d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu
268d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/ndisc.h"
27b691efd71561246065eae3cdd73a96ca1b8a528dChristopher Wiley
28dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartnamespace shill {
29dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
30dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewartstruct RTNLHeader {
31dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  RTNLHeader() {
32dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    memset(this, 0, sizeof(*this));
33dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
34dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  struct nlmsghdr hdr;
35dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  union {
36dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct ifinfomsg ifi;
37dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct ifaddrmsg ifa;
38dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct rtmsg rtm;
39dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    struct rtgenmsg gen;
403ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    struct nduseroptmsg nd_user_opt;
41ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    struct ndmsg ndm;
42dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  };
43dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart};
44dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
45dd7df792d2401741183a954f3f6e97d4c6de1e22Paul StewartRTNLMessage::RTNLMessage()
469a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    : type_(kTypeUnknown),
479a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      mode_(kModeUnknown),
48dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      flags_(0),
49e636c6945299da860b360c4ed83c318e3ec41edeDarin Petkov      seq_(0),
50e636c6945299da860b360c4ed83c318e3ec41edeDarin Petkov      pid_(0),
51dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      interface_index_(0),
527355ce1937c504d836a303ac809bd436272212b3Paul Stewart      family_(IPAddress::kFamilyUnknown) {}
53dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
549a908080fc2a72dbf06f995b878fc8a3693b725aPaul StewartRTNLMessage::RTNLMessage(Type type,
559a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                         Mode mode,
56dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         unsigned int flags,
577fab89734d88724a288e96a9996b15548c5294c7Ben Chan                         uint32_t seq,
587fab89734d88724a288e96a9996b15548c5294c7Ben Chan                         uint32_t pid,
59dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         int interface_index,
60dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                         IPAddress::Family family)
61dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    : type_(type),
62dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      mode_(mode),
63dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      flags_(flags),
64dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      seq_(seq),
65dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      pid_(pid),
66dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      interface_index_(interface_index),
67dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      family_(family) {}
68dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
69e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::Decode(const ByteString& msg) {
70dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  bool ret = DecodeInternal(msg);
71dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (!ret) {
72f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    Reset();
73dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
74dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return ret;
75dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
76dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
77e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::DecodeInternal(const ByteString& msg) {
78e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart  const RTNLHeader* hdr =
79e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart      reinterpret_cast<const RTNLHeader*>(msg.GetConstData());
80dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
81dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (msg.GetLength() < sizeof(hdr->hdr) ||
82dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      msg.GetLength() < hdr->hdr.nlmsg_len)
83dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
84dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
859a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  Mode mode = kModeUnknown;
86dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  switch (hdr->hdr.nlmsg_type) {
87dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWLINK:
88dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWADDR:
89dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWROUTE:
903ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  case RTM_NEWNDUSEROPT:
91ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  case RTM_NEWNEIGH:
929a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    mode = kModeAdd;
93dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
94dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
95dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELLINK:
96dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELADDR:
97dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELROUTE:
98ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  case RTM_DELNEIGH:
999a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    mode = kModeDelete;
100dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
101dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
102dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  default:
103dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
104dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
105dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
106e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart  rtattr* attr_data = nullptr;
107dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  int attr_length = 0;
108dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
109dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  switch (hdr->hdr.nlmsg_type) {
110dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWLINK:
111dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELLINK:
112dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeLink(hdr, mode, &attr_data, &attr_length))
113dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
114dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
115dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
116dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWADDR:
117dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELADDR:
118dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeAddress(hdr, mode, &attr_data, &attr_length))
119dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
120dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
121dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
122dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_NEWROUTE:
123dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  case RTM_DELROUTE:
124dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    if (!DecodeRoute(hdr, mode, &attr_data, &attr_length))
125dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      return false;
126dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    break;
127dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
1283ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  case RTM_NEWNDUSEROPT:
1293ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    if (!DecodeNdUserOption(hdr, mode, &attr_data, &attr_length))
1303ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu      return false;
1313ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    break;
1323ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
133ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  case RTM_NEWNEIGH:
134ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  case RTM_DELNEIGH:
135ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    if (!DecodeNeighbor(hdr, mode, &attr_data, &attr_length))
136ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      return false;
137ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    break;
138ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
139dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  default:
140dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    NOTREACHED();
141dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
142dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
143dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  flags_ = hdr->hdr.nlmsg_flags;
144dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  seq_ = hdr->hdr.nlmsg_seq;
145dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  pid_ = hdr->hdr.nlmsg_pid;
146dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
147dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  while (attr_data && RTA_OK(attr_data, attr_length)) {
148dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    SetAttribute(
149dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart        attr_data->rta_type,
150e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart        ByteString(reinterpret_cast<unsigned char*>(RTA_DATA(attr_data)),
151dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                   RTA_PAYLOAD(attr_data)));
152dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_data = RTA_NEXT(attr_data, attr_length);
153dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
154dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
155dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (attr_length) {
156dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    // We hit a parse error while going through the attributes
157dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes_.clear();
158dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
159dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
160dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
161dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
162dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
163dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
164e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::DecodeLink(const RTNLHeader* hdr,
1659a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                             Mode mode,
166e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart                             rtattr** attr_data,
167e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart                             int* attr_length) {
168dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifi))) {
169dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
170dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
171dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
172dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
173dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = IFLA_RTA(NLMSG_DATA(&hdr->hdr));
174dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = IFLA_PAYLOAD(&hdr->hdr);
175dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
1769a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  type_ = kTypeLink;
177dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->ifi.ifi_family;
178dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  interface_index_ = hdr->ifi.ifi_index;
179dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_link_status(LinkStatus(hdr->ifi.ifi_type,
180dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             hdr->ifi.ifi_flags,
181dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                             hdr->ifi.ifi_change));
182dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
183dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
184dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
185e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::DecodeAddress(const RTNLHeader* hdr,
1869a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                                Mode mode,
187e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart                                rtattr** attr_data,
188e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart                                int* attr_length) {
189dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifa))) {
190dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
191dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
192dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
193dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = IFA_RTA(NLMSG_DATA(&hdr->hdr));
194dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = IFA_PAYLOAD(&hdr->hdr);
195dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
1969a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  type_ = kTypeAddress;
197dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->ifa.ifa_family;
198dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  interface_index_ = hdr->ifa.ifa_index;
199dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_address_status(AddressStatus(hdr->ifa.ifa_prefixlen,
200dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                   hdr->ifa.ifa_flags,
201dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                                   hdr->ifa.ifa_scope));
202dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
203dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
204dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
205e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::DecodeRoute(const RTNLHeader* hdr,
2069a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                              Mode mode,
207e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart                              rtattr** attr_data,
208e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart                              int* attr_length) {
209dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->rtm))) {
210dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return false;
211dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
212dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  mode_ = mode;
213dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_data = RTM_RTA(NLMSG_DATA(&hdr->hdr));
214dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  *attr_length = RTM_PAYLOAD(&hdr->hdr);
215dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
2169a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  type_ = kTypeRoute;
217dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  family_ = hdr->rtm.rtm_family;
218dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  set_route_status(RouteStatus(hdr->rtm.rtm_dst_len,
219dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_src_len,
220dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_table,
221dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_protocol,
222dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_scope,
223dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_type,
224dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                               hdr->rtm.rtm_flags));
225dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return true;
226dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
227dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
228e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::DecodeNdUserOption(const RTNLHeader* hdr,
2293ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu                                     Mode mode,
230e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart                                     rtattr** attr_data,
231e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart                                     int* attr_length) {
2323ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->nd_user_opt))) {
2333ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return false;
2343ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2353ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2363ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  mode_ = mode;
2373ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  interface_index_ = hdr->nd_user_opt.nduseropt_ifindex;
2383ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  family_ = hdr->nd_user_opt.nduseropt_family;
2393ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2403ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Verify IP family.
2413ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (family_ != IPAddress::kFamilyIPv6) {
2423ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return false;
2433ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2443ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Verify message must at-least contain the option header.
2453ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (hdr->nd_user_opt.nduseropt_opts_len < sizeof(NDUserOptionHeader)) {
2463ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return false;
2473ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2483ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2493ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Parse the option header.
250e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart  const NDUserOptionHeader* nd_user_option_header =
251e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart      reinterpret_cast<const NDUserOptionHeader*>(
252e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart          reinterpret_cast<const uint8_t*>(&hdr->nd_user_opt) +
2533ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu          sizeof(struct nduseroptmsg));
2547fab89734d88724a288e96a9996b15548c5294c7Ben Chan  uint32_t lifetime = ntohl(nd_user_option_header->lifetime);
2553ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2563ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Verify option length.
2573ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // The length field in the header is in units of 8 octets.
2583ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  int opt_len = static_cast<int>(nd_user_option_header->length) * 8;
2593ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (opt_len != hdr->nd_user_opt.nduseropt_opts_len) {
2603ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return false;
2613ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2623ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2633ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Determine option data pointer and data length.
264e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart  const uint8_t* option_data =
265e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart      reinterpret_cast<const uint8_t*>(nd_user_option_header + 1);
2663ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  int data_len = opt_len - sizeof(NDUserOptionHeader);
2673ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2683ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (nd_user_option_header->type == ND_OPT_DNSSL) {
2693ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    // TODO(zqiu): Parse DNSSL (DNS Search List) option.
2703ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    type_ = kTypeDnssl;
2713ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return true;
2723ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  } else if (nd_user_option_header->type == ND_OPT_RDNSS) {
2733ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    // Parse RNDSS (Recursive DNS Server) option.
2743ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    type_ = kTypeRdnss;
2753ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return ParseRdnssOption(option_data, data_len, lifetime);
2763ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2773ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2783ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  return false;
2793ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu}
2803ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
281e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::ParseRdnssOption(const uint8_t* data,
2823ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu                                   int length,
2837fab89734d88724a288e96a9996b15548c5294c7Ben Chan                                   uint32_t lifetime) {
2843ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  const int addr_length = IPAddress::GetAddressLength(IPAddress::kFamilyIPv6);
2853ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2863ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Verify data size are multiple of individual address size.
2873ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  if (length % addr_length != 0) {
2883ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    return false;
2893ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
2903ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
2913ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  // Parse the DNS server addresses.
2923ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  std::vector<IPAddress> dns_server_addresses;
2933ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  while (length > 0) {
2943ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    dns_server_addresses.push_back(
2953ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu        IPAddress(IPAddress::kFamilyIPv6,
2963ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu                  ByteString(data, addr_length)));
2973ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    length -= addr_length;
2983ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu    data += addr_length;
2993ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  }
3003ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  set_rdnss_option(RdnssOption(lifetime, dns_server_addresses));
3013ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu  return true;
3023ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu}
3033ef4f53096a10056a26ea38ad85b8a9a12845a9dPeter Qiu
304e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::DecodeNeighbor(const RTNLHeader* hdr,
305ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly                                 Mode mode,
306e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart                                 rtattr** attr_data,
307e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart                                 int* attr_length) {
308ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ndm))) {
309ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    return false;
310ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  }
311ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
312ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  mode_ = mode;
313ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  interface_index_ = hdr->ndm.ndm_ifindex;
314ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  family_ = hdr->ndm.ndm_family;
315ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  type_ = kTypeNeighbor;
316ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
317ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  *attr_data = RTM_RTA(NLMSG_DATA(&hdr->hdr));
318ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  *attr_length = RTM_PAYLOAD(&hdr->hdr);
319ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
320ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  set_neighbor_status(NeighborStatus(hdr->ndm.ndm_state,
321ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly                                     hdr->ndm.ndm_flags,
322ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly                                     hdr->ndm.ndm_type));
323ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  return true;
324ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly}
325ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
326f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul StewartByteString RTNLMessage::Encode() const {
3279a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (type_ != kTypeLink &&
3289a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      type_ != kTypeAddress &&
329ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      type_ != kTypeRoute &&
330ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      type_ != kTypeNeighbor) {
331dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    return ByteString();
332dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
333dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
334dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  RTNLHeader hdr;
335dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_flags = flags_;
336dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_seq = seq_;
337dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr.hdr.nlmsg_pid = pid_;
338dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
3399a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (mode_ == kModeGet) {
3409a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    if (type_ == kTypeLink) {
341dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETLINK;
3429a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    } else if (type_ == kTypeAddress) {
343dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETADDR;
3449a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    } else if (type_ == kTypeRoute) {
345dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      hdr.hdr.nlmsg_type = RTM_GETROUTE;
346ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    } else if (type_ == kTypeNeighbor) {
347ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      hdr.hdr.nlmsg_type = RTM_GETNEIGH;
348f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    } else {
349f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
350f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return ByteString();
351dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    }
352dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr.gen));
3539a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    hdr.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
354dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.gen.rtgen_family = family_;
355dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  } else {
356dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    switch (type_) {
3579a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    case kTypeLink:
358f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (!EncodeLink(&hdr)) {
359f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart        return ByteString();
360f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      }
361dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
362dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
3639a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    case kTypeAddress:
364f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (!EncodeAddress(&hdr)) {
365f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart        return ByteString();
366f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      }
367dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
368dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
3699a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    case kTypeRoute:
370f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (!EncodeRoute(&hdr)) {
371f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart        return ByteString();
372f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      }
373dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      break;
374dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
375ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    case kTypeNeighbor:
376ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      if (!EncodeNeighbor(&hdr)) {
377ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly        return ByteString();
378ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      }
379ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      break;
380ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
381dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    default:
382dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart      NOTREACHED();
383dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    }
384dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
385dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
386dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  size_t header_length = hdr.hdr.nlmsg_len;
387dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  ByteString attributes;
388dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
3898a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko  for (auto attr = attributes_.begin(); attr != attributes_.end(); ++attr) {
390dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    size_t len = RTA_LENGTH(attr->second.GetLength());
391dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    hdr.hdr.nlmsg_len = NLMSG_ALIGN(hdr.hdr.nlmsg_len) + RTA_ALIGN(len);
392dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
3938a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko    struct rtattr rt_attr = {
3948a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko      static_cast<unsigned short>(len),  // NOLINT(runtime/int)
3958a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko      attr->first
3968a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko    };
397e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart    ByteString attr_header(reinterpret_cast<unsigned char*>(&rt_attr),
398dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart                           sizeof(rt_attr));
399dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_header.Resize(RTA_ALIGN(attr_header.GetLength()));
400dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes.Append(attr_header);
401dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
402dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    ByteString attr_data(attr->second);
403dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attr_data.Resize(RTA_ALIGN(attr_data.GetLength()));
404dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart    attributes.Append(attr_data);
405dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  }
406dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
407e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewart  ByteString packet(reinterpret_cast<unsigned char*>(&hdr), header_length);
408dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  packet.Append(attributes);
409dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
410dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  return packet;
411dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
412dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
413e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::EncodeLink(RTNLHeader* hdr) const {
414f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  switch (mode_) {
415f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeAdd:
416f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_NEWLINK;
417f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
418f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeDelete:
419f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_DELLINK;
420f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
421f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeQuery:
422f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_GETLINK;
423f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
424f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    default:
425f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
426f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return false;
427f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
428dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifi));
429dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_family = family_;
430cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  hdr->ifi.ifi_index = interface_index_;
431dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_type = link_status_.type;
432dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_flags = link_status_.flags;
433dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifi.ifi_change = link_status_.change;
434f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
435dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
436dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
437e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::EncodeAddress(RTNLHeader* hdr) const {
438f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  switch (mode_) {
439f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeAdd:
440f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_NEWADDR;
441f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
442f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeDelete:
443f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_DELADDR;
444f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
445f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeQuery:
446f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_GETADDR;
447f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
448f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    default:
449f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
450f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return false;
451f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
452dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifa));
453dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_family = family_;
454dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_prefixlen = address_status_.prefix_len;
455dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_flags = address_status_.flags;
456dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_scope = address_status_.scope;
457dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->ifa.ifa_index = interface_index_;
458f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
459dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
460dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
461e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::EncodeRoute(RTNLHeader* hdr) const {
462f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  switch (mode_) {
463f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeAdd:
464f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_NEWROUTE;
465f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
466f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeDelete:
467f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_DELROUTE;
468f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
469f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    case kModeQuery:
470f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      hdr->hdr.nlmsg_type = RTM_GETROUTE;
471f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      break;
472f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    default:
473f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NOTIMPLEMENTED();
474f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      return false;
475f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
476dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->rtm));
477dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_family = family_;
478dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_dst_len = route_status_.dst_prefix;
479dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_src_len = route_status_.src_prefix;
480dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_table = route_status_.table;
481dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_protocol = route_status_.protocol;
482dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_scope = route_status_.scope;
483dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_type = route_status_.type;
484dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart  hdr->rtm.rtm_flags = route_status_.flags;
485f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
486f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart}
487f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
488e67a78539a05ea7fc68ed5ca18f6d1de333a3086Paul Stewartbool RTNLMessage::EncodeNeighbor(RTNLHeader* hdr) const {
489ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  switch (mode_) {
490ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    case kModeAdd:
491ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      hdr->hdr.nlmsg_type = RTM_NEWNEIGH;
492ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      break;
493ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    case kModeDelete:
494ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      hdr->hdr.nlmsg_type = RTM_DELNEIGH;
495ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      break;
496ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    case kModeQuery:
497ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      hdr->hdr.nlmsg_type = RTM_GETNEIGH;
498ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      break;
499ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly    default:
500ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      NOTIMPLEMENTED();
501ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly      return false;
502ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  }
503ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ndm));
504ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->ndm.ndm_family = family_;
505ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->ndm.ndm_ifindex = interface_index_;
506ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->ndm.ndm_state = neighbor_status_.state;
507ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->ndm.ndm_flags = neighbor_status_.flags;
508ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  hdr->ndm.ndm_type = neighbor_status_.type;
509ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly  return true;
510ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly}
511ad576bffebd92b9adf42ea6b9e43515169787ceeGarret Kelly
512f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartvoid RTNLMessage::Reset() {
513f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  mode_ = kModeUnknown;
514f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  type_ = kTypeUnknown;
515f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  flags_ = 0;
516f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  seq_ = 0;
517e636c6945299da860b360c4ed83c318e3ec41edeDarin Petkov  pid_ = 0;
518f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  interface_index_ = 0;
519f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  family_ = IPAddress::kFamilyUnknown;
520f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  link_status_ = LinkStatus();
521f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  address_status_ = AddressStatus();
522f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  route_status_ = RouteStatus();
523f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  attributes_.clear();
524dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}
525dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart
526dd7df792d2401741183a954f3f6e97d4c6de1e22Paul Stewart}  // namespace shill
527