blob: c6780c15b339b6545394b2f7052f86ec0a899f6a [file] [log] [blame]
Paul Stewartf748a362012-03-07 12:01:20 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewarta3c56f92011-05-26 07:08:52 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <errno.h>
6#include <time.h>
7#include <unistd.h>
8#include <string.h>
Darin Petkove0a312e2011-07-20 13:45:28 -07009#include <sys/ioctl.h>
Paul Stewarta3c56f92011-05-26 07:08:52 -070010#include <sys/socket.h>
11#include <arpa/inet.h>
12#include <netinet/ether.h>
13#include <net/if.h>
14#include <net/if_arp.h>
15#include <linux/netlink.h>
16#include <linux/rtnetlink.h>
17#include <fcntl.h>
Paul Stewarta3c56f92011-05-26 07:08:52 -070018
Eric Shienbrood3e20a232012-02-16 11:35:56 -050019#include <base/bind.h>
Paul Stewarta3c56f92011-05-26 07:08:52 -070020
Paul Stewart5f06a0e2012-12-20 11:11:33 -080021#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070022#include "shill/event_dispatcher.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070023#include "shill/io_handler.h"
Paul Stewart1d18e8c2011-07-15 11:00:31 -070024#include "shill/ip_address.h"
Paul Stewartc39f1132011-06-22 12:02:28 -070025#include "shill/ipconfig.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070026#include "shill/logging.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070027#include "shill/rtnl_handler.h"
28#include "shill/rtnl_listener.h"
Paul Stewart75e89d22011-08-01 10:00:02 -070029#include "shill/rtnl_message.h"
Darin Petkov633ac6f2011-07-08 13:56:13 -070030#include "shill/sockets.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070031
Eric Shienbrood3e20a232012-02-16 11:35:56 -050032using base::Bind;
33using base::Unretained;
Paul Stewarta3c56f92011-05-26 07:08:52 -070034using std::string;
35
36namespace shill {
37
Julius Wernerf253c842012-12-20 14:52:30 -080038// Keep this large enough to avoid overflows on IPv6 SNM routing update spikes
Julius Werner13a7e042013-01-25 13:00:15 -080039const int RTNLHandler::kReceiveBufferSize = 512 * 1024;
Julius Wernerf253c842012-12-20 14:52:30 -080040
Ben Chanbbdef5f2012-04-23 13:58:15 -070041namespace {
42base::LazyInstance<RTNLHandler> g_rtnl_handler = LAZY_INSTANCE_INITIALIZER;
43} // namespace
Paul Stewart0d2ada32011-08-09 17:01:57 -070044
Paul Stewarta3c56f92011-05-26 07:08:52 -070045RTNLHandler::RTNLHandler()
Darin Petkov633ac6f2011-07-08 13:56:13 -070046 : sockets_(NULL),
Paul Stewarta3c56f92011-05-26 07:08:52 -070047 in_request_(false),
Paul Stewarta3c56f92011-05-26 07:08:52 -070048 rtnl_socket_(-1),
49 request_flags_(0),
mukesh agrawalf60e4062011-05-27 13:13:41 -070050 request_sequence_(0),
Paul Stewart9a908082011-08-31 12:18:48 -070051 last_dump_sequence_(0),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050052 rtnl_callback_(Bind(&RTNLHandler::ParseRTNL, Unretained(this))) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070053 SLOG(RTNL, 2) << "RTNLHandler created";
Paul Stewarta3c56f92011-05-26 07:08:52 -070054}
55
56RTNLHandler::~RTNLHandler() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070057 SLOG(RTNL, 2) << "RTNLHandler removed";
Paul Stewarta3c56f92011-05-26 07:08:52 -070058 Stop();
59}
60
61RTNLHandler* RTNLHandler::GetInstance() {
Paul Stewart0d2ada32011-08-09 17:01:57 -070062 return g_rtnl_handler.Pointer();
Paul Stewarta3c56f92011-05-26 07:08:52 -070063}
64
Darin Petkov633ac6f2011-07-08 13:56:13 -070065void RTNLHandler::Start(EventDispatcher *dispatcher, Sockets *sockets) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070066 struct sockaddr_nl addr;
67
Darin Petkov633ac6f2011-07-08 13:56:13 -070068 if (sockets_) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070069 return;
Darin Petkov633ac6f2011-07-08 13:56:13 -070070 }
Paul Stewarta3c56f92011-05-26 07:08:52 -070071
Darin Petkov633ac6f2011-07-08 13:56:13 -070072 rtnl_socket_ = sockets->Socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
Paul Stewarta3c56f92011-05-26 07:08:52 -070073 if (rtnl_socket_ < 0) {
74 LOG(ERROR) << "Failed to open rtnl socket";
75 return;
76 }
77
Julius Wernerf253c842012-12-20 14:52:30 -080078 if (sockets->SetReceiveBuffer(rtnl_socket_, kReceiveBufferSize)) {
79 LOG(ERROR) << "Failed to increase receive buffer size";
80 }
81
Paul Stewarta3c56f92011-05-26 07:08:52 -070082 memset(&addr, 0, sizeof(addr));
83 addr.nl_family = AF_NETLINK;
Paul Stewart9a908082011-08-31 12:18:48 -070084 addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
85 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
Paul Stewarta3c56f92011-05-26 07:08:52 -070086
Darin Petkov633ac6f2011-07-08 13:56:13 -070087 if (sockets->Bind(rtnl_socket_,
88 reinterpret_cast<struct sockaddr *>(&addr),
89 sizeof(addr)) < 0) {
90 sockets->Close(rtnl_socket_);
Paul Stewarta3c56f92011-05-26 07:08:52 -070091 rtnl_socket_ = -1;
92 LOG(ERROR) << "RTNL socket bind failed";
93 return;
94 }
95
Paul Stewart5f06a0e2012-12-20 11:11:33 -080096 rtnl_handler_.reset(dispatcher->CreateInputHandler(
97 rtnl_socket_,
98 rtnl_callback_,
99 Bind(&RTNLHandler::OnReadError, Unretained(this))));
Darin Petkov633ac6f2011-07-08 13:56:13 -0700100 sockets_ = sockets;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700101
Paul Stewart9a908082011-08-31 12:18:48 -0700102 NextRequest(last_dump_sequence_);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700103 SLOG(RTNL, 2) << "RTNLHandler started";
Paul Stewarta3c56f92011-05-26 07:08:52 -0700104}
105
106void RTNLHandler::Stop() {
Darin Petkov633ac6f2011-07-08 13:56:13 -0700107 if (!sockets_)
Paul Stewarta3c56f92011-05-26 07:08:52 -0700108 return;
109
Paul Stewart7355ce12011-09-02 10:47:01 -0700110 rtnl_handler_.reset();
Darin Petkov633ac6f2011-07-08 13:56:13 -0700111 sockets_->Close(rtnl_socket_);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700112 in_request_ = false;
Darin Petkov633ac6f2011-07-08 13:56:13 -0700113 sockets_ = NULL;
Paul Stewart65c40f52011-08-08 07:27:46 -0700114 request_flags_ = 0;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700115 SLOG(RTNL, 2) << "RTNLHandler stopped";
Paul Stewarta3c56f92011-05-26 07:08:52 -0700116}
117
118void RTNLHandler::AddListener(RTNLListener *to_add) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700119 for (const auto &listener : listeners_) {
120 if (to_add == listener)
Paul Stewarta3c56f92011-05-26 07:08:52 -0700121 return;
122 }
123 listeners_.push_back(to_add);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700124 SLOG(RTNL, 2) << "RTNLHandler added listener";
Paul Stewarta3c56f92011-05-26 07:08:52 -0700125}
126
127void RTNLHandler::RemoveListener(RTNLListener *to_remove) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700128 for (auto it = listeners_.begin(); it != listeners_.end(); ++it) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700129 if (to_remove == *it) {
130 listeners_.erase(it);
131 return;
132 }
133 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700134 SLOG(RTNL, 2) << "RTNLHandler removed listener";
Paul Stewarta3c56f92011-05-26 07:08:52 -0700135}
136
137void RTNLHandler::SetInterfaceFlags(int interface_index, unsigned int flags,
Darin Petkov0828f5f2011-08-11 10:18:52 -0700138 unsigned int change) {
Paul Stewart536820d2012-03-19 16:05:59 -0700139 if (!sockets_) {
140 LOG(ERROR) << __func__ << " called while not started. "
141 "Assuming we are in unit tests.";
142 return;
143 }
144
Paul Stewarta3c56f92011-05-26 07:08:52 -0700145 struct rtnl_request {
146 struct nlmsghdr hdr;
147 struct ifinfomsg msg;
148 } req;
149
150 request_sequence_++;
151 memset(&req, 0, sizeof(req));
152
153 req.hdr.nlmsg_len = sizeof(req);
154 req.hdr.nlmsg_flags = NLM_F_REQUEST;
155 req.hdr.nlmsg_pid = 0;
156 req.hdr.nlmsg_seq = request_sequence_;
157 req.hdr.nlmsg_type = RTM_NEWLINK;
158 req.msg.ifi_index = interface_index;
159 req.msg.ifi_flags = flags;
160 req.msg.ifi_change = change;
161
Darin Petkov633ac6f2011-07-08 13:56:13 -0700162 if (sockets_->Send(rtnl_socket_, &req, sizeof(req), 0) < 0) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700163 LOG(ERROR) << "RTNL sendto failed: " << strerror(errno);
164 }
165}
166
167void RTNLHandler::RequestDump(int request_flags) {
168 request_flags_ |= request_flags;
169
Ben Chanfad4a0b2012-04-18 15:49:59 -0700170 SLOG(RTNL, 2) << "RTNLHandler got request to dump "
mukesh agrawal47009f82011-08-25 14:07:35 -0700171 << std::showbase << std::hex
172 << request_flags
173 << std::dec << std::noshowbase;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700174
Darin Petkov633ac6f2011-07-08 13:56:13 -0700175 if (!in_request_ && sockets_)
Paul Stewart9a908082011-08-31 12:18:48 -0700176 NextRequest(last_dump_sequence_);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700177}
178
Chris Masone2aa97072011-08-09 17:35:08 -0700179void RTNLHandler::DispatchEvent(int type, const RTNLMessage &msg) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700180 for (const auto &listener : listeners_) {
181 listener->NotifyEvent(type, msg);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700182 }
183}
184
Paul Stewartf748a362012-03-07 12:01:20 -0800185void RTNLHandler::NextRequest(uint32 seq) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700186 int flag = 0;
Paul Stewart9a908082011-08-31 12:18:48 -0700187 RTNLMessage::Type type;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700188
Ben Chanfad4a0b2012-04-18 15:49:59 -0700189 SLOG(RTNL, 2) << "RTNLHandler nextrequest " << seq << " "
190 << last_dump_sequence_
191 << std::showbase << std::hex
192 << " " << request_flags_
193 << std::dec << std::noshowbase;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700194
Paul Stewart9a908082011-08-31 12:18:48 -0700195 if (seq != last_dump_sequence_)
Paul Stewarta3c56f92011-05-26 07:08:52 -0700196 return;
197
Paul Stewart8c116a92012-05-02 18:30:03 -0700198 if ((request_flags_ & kRequestAddr) != 0) {
Paul Stewart9a908082011-08-31 12:18:48 -0700199 type = RTNLMessage::kTypeAddress;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700200 flag = kRequestAddr;
201 } else if ((request_flags_ & kRequestRoute) != 0) {
Paul Stewart9a908082011-08-31 12:18:48 -0700202 type = RTNLMessage::kTypeRoute;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700203 flag = kRequestRoute;
Paul Stewart8c116a92012-05-02 18:30:03 -0700204 } else if ((request_flags_ & kRequestLink) != 0) {
205 type = RTNLMessage::kTypeLink;
206 flag = kRequestLink;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700207 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700208 SLOG(RTNL, 2) << "Done with requests";
Paul Stewarta3c56f92011-05-26 07:08:52 -0700209 in_request_ = false;
210 return;
211 }
212
Paul Stewart9a908082011-08-31 12:18:48 -0700213 RTNLMessage msg(
214 type,
215 RTNLMessage::kModeGet,
216 0,
217 0,
218 0,
219 0,
Paul Stewart7355ce12011-09-02 10:47:01 -0700220 IPAddress::kFamilyUnknown);
Paul Stewart9a908082011-08-31 12:18:48 -0700221 CHECK(SendMessage(&msg));
Paul Stewarta3c56f92011-05-26 07:08:52 -0700222
Paul Stewart9a908082011-08-31 12:18:48 -0700223 last_dump_sequence_ = msg.seq();
Paul Stewarta3c56f92011-05-26 07:08:52 -0700224 request_flags_ &= ~flag;
225 in_request_ = true;
226}
227
228void RTNLHandler::ParseRTNL(InputData *data) {
229 unsigned char *buf = data->buf;
230 unsigned char *end = buf + data->len;
231
232 while (buf < end) {
233 struct nlmsghdr *hdr = reinterpret_cast<struct nlmsghdr *>(buf);
mukesh agrawalf60e4062011-05-27 13:13:41 -0700234 if (!NLMSG_OK(hdr, static_cast<unsigned int>(end - buf)))
Paul Stewarta3c56f92011-05-26 07:08:52 -0700235 break;
236
Ben Chanfad4a0b2012-04-18 15:49:59 -0700237 SLOG(RTNL, 3) << __func__ << ": received payload (" << end - buf << ")";
Paul Stewart7355ce12011-09-02 10:47:01 -0700238
Chris Masone2aa97072011-08-09 17:35:08 -0700239 RTNLMessage msg;
Paul Stewart44f08cb2012-04-27 16:53:05 -0700240 ByteString payload(reinterpret_cast<unsigned char *>(hdr), hdr->nlmsg_len);
241 SLOG(RTNL, 5) << "RTNL received payload length " << payload.GetLength()
242 << ": \"" << payload.HexEncode() << "\"";
243 if (!msg.Decode(payload)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700244 SLOG(RTNL, 3) << __func__ << ": rtnl packet type "
Paul Stewart44f08cb2012-04-27 16:53:05 -0700245 << hdr->nlmsg_type
246 << " length " << hdr->nlmsg_len
247 << " sequence " << hdr->nlmsg_seq;
248
Chris Masone2aa97072011-08-09 17:35:08 -0700249 switch (hdr->nlmsg_type) {
250 case NLMSG_NOOP:
251 case NLMSG_OVERRUN:
252 break;
253 case NLMSG_DONE:
254 NextRequest(hdr->nlmsg_seq);
255 break;
256 case NLMSG_ERROR:
257 {
258 struct nlmsgerr *err =
259 reinterpret_cast<nlmsgerr *>(NLMSG_DATA(hdr));
260 LOG(ERROR) << "error " << -err->error << " ("
261 << strerror(-err->error) << ")";
262 break;
263 }
264 default:
265 NOTIMPLEMENTED() << "Unknown NL message type.";
266 }
267 } else {
268 switch (msg.type()) {
Paul Stewart9a908082011-08-31 12:18:48 -0700269 case RTNLMessage::kTypeLink:
Chris Masone2aa97072011-08-09 17:35:08 -0700270 DispatchEvent(kRequestLink, msg);
271 break;
Paul Stewart9a908082011-08-31 12:18:48 -0700272 case RTNLMessage::kTypeAddress:
Chris Masone2aa97072011-08-09 17:35:08 -0700273 DispatchEvent(kRequestAddr, msg);
274 break;
Paul Stewart9a908082011-08-31 12:18:48 -0700275 case RTNLMessage::kTypeRoute:
Chris Masone2aa97072011-08-09 17:35:08 -0700276 DispatchEvent(kRequestRoute, msg);
277 break;
278 default:
279 NOTIMPLEMENTED() << "Unknown RTNL message type.";
280 }
281 }
Paul Stewarta3c56f92011-05-26 07:08:52 -0700282 buf += hdr->nlmsg_len;
283 }
284}
285
Paul Stewart9a908082011-08-31 12:18:48 -0700286bool RTNLHandler::AddressRequest(int interface_index,
287 RTNLMessage::Mode mode,
288 int flags,
289 const IPAddress &local,
Paul Stewart1062d9d2012-04-27 10:42:27 -0700290 const IPAddress &broadcast,
Paul Stewart48100b02012-03-19 07:53:52 -0700291 const IPAddress &peer) {
Paul Stewart1062d9d2012-04-27 10:42:27 -0700292 CHECK(local.family() == broadcast.family());
Paul Stewart48100b02012-03-19 07:53:52 -0700293 CHECK(local.family() == peer.family());
Paul Stewartc39f1132011-06-22 12:02:28 -0700294
Paul Stewart9a908082011-08-31 12:18:48 -0700295 RTNLMessage msg(
296 RTNLMessage::kTypeAddress,
297 mode,
298 NLM_F_REQUEST | flags,
299 0,
300 0,
301 interface_index,
302 local.family());
Paul Stewartc39f1132011-06-22 12:02:28 -0700303
Paul Stewart9a908082011-08-31 12:18:48 -0700304 msg.set_address_status(RTNLMessage::AddressStatus(
305 local.prefix(),
306 0,
307 0));
Paul Stewartc39f1132011-06-22 12:02:28 -0700308
Paul Stewart9a908082011-08-31 12:18:48 -0700309 msg.SetAttribute(IFA_LOCAL, local.address());
Paul Stewart1062d9d2012-04-27 10:42:27 -0700310 if (!broadcast.IsDefault()) {
311 msg.SetAttribute(IFA_BROADCAST, broadcast.address());
Paul Stewartc39f1132011-06-22 12:02:28 -0700312 }
Paul Stewart48100b02012-03-19 07:53:52 -0700313 if (!peer.IsDefault()) {
314 msg.SetAttribute(IFA_ADDRESS, peer.address());
315 }
Paul Stewartc39f1132011-06-22 12:02:28 -0700316
Paul Stewart9a908082011-08-31 12:18:48 -0700317 return SendMessage(&msg);
Paul Stewartc39f1132011-06-22 12:02:28 -0700318}
319
320bool RTNLHandler::AddInterfaceAddress(int interface_index,
Paul Stewart9a908082011-08-31 12:18:48 -0700321 const IPAddress &local,
Paul Stewart48100b02012-03-19 07:53:52 -0700322 const IPAddress &broadcast,
323 const IPAddress &peer) {
Paul Stewart9a908082011-08-31 12:18:48 -0700324 return AddressRequest(interface_index,
325 RTNLMessage::kModeAdd,
Paul Stewart8c116a92012-05-02 18:30:03 -0700326 NLM_F_CREATE | NLM_F_EXCL | NLM_F_ECHO,
Paul Stewart9a908082011-08-31 12:18:48 -0700327 local,
Paul Stewart48100b02012-03-19 07:53:52 -0700328 broadcast,
329 peer);
Paul Stewartc39f1132011-06-22 12:02:28 -0700330}
331
332bool RTNLHandler::RemoveInterfaceAddress(int interface_index,
Paul Stewart9a908082011-08-31 12:18:48 -0700333 const IPAddress &local) {
334 return AddressRequest(interface_index,
335 RTNLMessage::kModeDelete,
Paul Stewart8c116a92012-05-02 18:30:03 -0700336 NLM_F_ECHO,
Paul Stewart9a908082011-08-31 12:18:48 -0700337 local,
Paul Stewart48100b02012-03-19 07:53:52 -0700338 IPAddress(local.family()),
Paul Stewart9a908082011-08-31 12:18:48 -0700339 IPAddress(local.family()));
Paul Stewartc39f1132011-06-22 12:02:28 -0700340}
341
Paul Stewartcba0f7f2012-02-29 16:33:05 -0800342bool RTNLHandler::RemoveInterface(int interface_index) {
343 RTNLMessage msg(
344 RTNLMessage::kTypeLink,
345 RTNLMessage::kModeDelete,
346 NLM_F_REQUEST,
347 0,
348 0,
349 interface_index,
350 IPAddress::kFamilyUnknown);
351 return SendMessage(&msg);
352}
353
Darin Petkove0a312e2011-07-20 13:45:28 -0700354int RTNLHandler::GetInterfaceIndex(const string &interface_name) {
355 if (interface_name.empty()) {
356 LOG(ERROR) << "Empty interface name -- unable to obtain index.";
357 return -1;
358 }
359 struct ifreq ifr;
360 if (interface_name.size() >= sizeof(ifr.ifr_name)) {
361 LOG(ERROR) << "Interface name too long: " << interface_name.size() << " >= "
362 << sizeof(ifr.ifr_name);
363 return -1;
364 }
365 int socket = sockets_->Socket(PF_INET, SOCK_DGRAM, 0);
366 if (socket < 0) {
367 PLOG(ERROR) << "Unable to open INET socket";
368 return -1;
369 }
370 ScopedSocketCloser socket_closer(sockets_, socket);
371 memset(&ifr, 0, sizeof(ifr));
372 strncpy(ifr.ifr_name, interface_name.c_str(), sizeof(ifr.ifr_name));
373 if (sockets_->Ioctl(socket, SIOCGIFINDEX, &ifr) < 0) {
374 PLOG(ERROR) << "SIOCGIFINDEX error for " << interface_name;
375 return -1;
376 }
377 return ifr.ifr_ifindex;
378}
379
Paul Stewart75e89d22011-08-01 10:00:02 -0700380bool RTNLHandler::SendMessage(RTNLMessage *message) {
Paul Stewart44f08cb2012-04-27 16:53:05 -0700381 message->set_seq(request_sequence_);
Paul Stewart75e89d22011-08-01 10:00:02 -0700382 ByteString msgdata = message->Encode();
383
384 if (msgdata.GetLength() == 0) {
385 return false;
386 }
387
Paul Stewart44f08cb2012-04-27 16:53:05 -0700388 SLOG(RTNL, 5) << "RTNL sending payload with request sequence "
389 << request_sequence_ << ", length " << msgdata.GetLength()
390 << ": \"" << msgdata.HexEncode() << "\"";
391
392 request_sequence_++;
393
Paul Stewart75e89d22011-08-01 10:00:02 -0700394 if (sockets_->Send(rtnl_socket_,
Paul Stewart9a908082011-08-31 12:18:48 -0700395 msgdata.GetConstData(),
Paul Stewart75e89d22011-08-01 10:00:02 -0700396 msgdata.GetLength(),
397 0) < 0) {
398 PLOG(ERROR) << "RTNL send failed: " << strerror(errno);
399 return false;
400 }
401
402 return true;
403}
404
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800405void RTNLHandler::OnReadError(const Error &error) {
406 LOG(FATAL) << "RTNL Socket read returns error: "
407 << error.message();
408}
409
Paul Stewarta3c56f92011-05-26 07:08:52 -0700410} // namespace shill