blob: 66639f5f0cc4431c7fe7eeeb686b3680be719433 [file] [log] [blame]
Paul Stewarta3c56f92011-05-26 07:08:52 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// 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
Paul Stewarta3c56f92011-05-26 07:08:52 -070019#include <base/logging.h>
Paul Stewarta3c56f92011-05-26 07:08:52 -070020
Paul Stewart26b327e2011-10-19 11:38:09 -070021#include "shill/event_dispatcher.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070022#include "shill/io_handler.h"
Paul Stewart1d18e8c2011-07-15 11:00:31 -070023#include "shill/ip_address.h"
Paul Stewartc39f1132011-06-22 12:02:28 -070024#include "shill/ipconfig.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070025#include "shill/rtnl_handler.h"
26#include "shill/rtnl_listener.h"
Paul Stewart75e89d22011-08-01 10:00:02 -070027#include "shill/rtnl_message.h"
Darin Petkov633ac6f2011-07-08 13:56:13 -070028#include "shill/sockets.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070029
30using std::string;
31
32namespace shill {
33
Paul Stewart0d2ada32011-08-09 17:01:57 -070034static base::LazyInstance<RTNLHandler> g_rtnl_handler(
35 base::LINKER_INITIALIZED);
36
Paul Stewarta3c56f92011-05-26 07:08:52 -070037RTNLHandler::RTNLHandler()
Darin Petkov633ac6f2011-07-08 13:56:13 -070038 : sockets_(NULL),
Paul Stewarta3c56f92011-05-26 07:08:52 -070039 in_request_(false),
Paul Stewarta3c56f92011-05-26 07:08:52 -070040 rtnl_socket_(-1),
41 request_flags_(0),
mukesh agrawalf60e4062011-05-27 13:13:41 -070042 request_sequence_(0),
Paul Stewart9a908082011-08-31 12:18:48 -070043 last_dump_sequence_(0),
mukesh agrawalf60e4062011-05-27 13:13:41 -070044 rtnl_callback_(NewCallback(this, &RTNLHandler::ParseRTNL)) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070045 VLOG(2) << "RTNLHandler created";
46}
47
48RTNLHandler::~RTNLHandler() {
49 VLOG(2) << "RTNLHandler removed";
50 Stop();
51}
52
53RTNLHandler* RTNLHandler::GetInstance() {
Paul Stewart0d2ada32011-08-09 17:01:57 -070054 return g_rtnl_handler.Pointer();
Paul Stewarta3c56f92011-05-26 07:08:52 -070055}
56
Darin Petkov633ac6f2011-07-08 13:56:13 -070057void RTNLHandler::Start(EventDispatcher *dispatcher, Sockets *sockets) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070058 struct sockaddr_nl addr;
59
Darin Petkov633ac6f2011-07-08 13:56:13 -070060 if (sockets_) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070061 return;
Darin Petkov633ac6f2011-07-08 13:56:13 -070062 }
Paul Stewarta3c56f92011-05-26 07:08:52 -070063
Darin Petkov633ac6f2011-07-08 13:56:13 -070064 rtnl_socket_ = sockets->Socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
Paul Stewarta3c56f92011-05-26 07:08:52 -070065 if (rtnl_socket_ < 0) {
66 LOG(ERROR) << "Failed to open rtnl socket";
67 return;
68 }
69
70 memset(&addr, 0, sizeof(addr));
71 addr.nl_family = AF_NETLINK;
Paul Stewart9a908082011-08-31 12:18:48 -070072 addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
73 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
Paul Stewarta3c56f92011-05-26 07:08:52 -070074
Darin Petkov633ac6f2011-07-08 13:56:13 -070075 if (sockets->Bind(rtnl_socket_,
76 reinterpret_cast<struct sockaddr *>(&addr),
77 sizeof(addr)) < 0) {
78 sockets->Close(rtnl_socket_);
Paul Stewarta3c56f92011-05-26 07:08:52 -070079 rtnl_socket_ = -1;
80 LOG(ERROR) << "RTNL socket bind failed";
81 return;
82 }
83
84 rtnl_handler_.reset(dispatcher->CreateInputHandler(rtnl_socket_,
85 rtnl_callback_.get()));
Darin Petkov633ac6f2011-07-08 13:56:13 -070086 sockets_ = sockets;
Paul Stewarta3c56f92011-05-26 07:08:52 -070087
Paul Stewart9a908082011-08-31 12:18:48 -070088 NextRequest(last_dump_sequence_);
Paul Stewarta3c56f92011-05-26 07:08:52 -070089 VLOG(2) << "RTNLHandler started";
90}
91
92void RTNLHandler::Stop() {
Darin Petkov633ac6f2011-07-08 13:56:13 -070093 if (!sockets_)
Paul Stewarta3c56f92011-05-26 07:08:52 -070094 return;
95
Paul Stewart7355ce12011-09-02 10:47:01 -070096 rtnl_handler_.reset();
Darin Petkov633ac6f2011-07-08 13:56:13 -070097 sockets_->Close(rtnl_socket_);
Paul Stewarta3c56f92011-05-26 07:08:52 -070098 in_request_ = false;
Darin Petkov633ac6f2011-07-08 13:56:13 -070099 sockets_ = NULL;
Paul Stewart65c40f52011-08-08 07:27:46 -0700100 request_flags_ = 0;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700101 VLOG(2) << "RTNLHandler stopped";
102}
103
104void RTNLHandler::AddListener(RTNLListener *to_add) {
105 std::vector<RTNLListener *>::iterator it;
106 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
107 if (to_add == *it)
108 return;
109 }
110 listeners_.push_back(to_add);
111 VLOG(2) << "RTNLHandler added listener";
112}
113
114void RTNLHandler::RemoveListener(RTNLListener *to_remove) {
115 std::vector<RTNLListener *>::iterator it;
116 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
117 if (to_remove == *it) {
118 listeners_.erase(it);
119 return;
120 }
121 }
122 VLOG(2) << "RTNLHandler removed listener";
123}
124
125void RTNLHandler::SetInterfaceFlags(int interface_index, unsigned int flags,
Darin Petkov0828f5f2011-08-11 10:18:52 -0700126 unsigned int change) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700127 struct rtnl_request {
128 struct nlmsghdr hdr;
129 struct ifinfomsg msg;
130 } req;
131
132 request_sequence_++;
133 memset(&req, 0, sizeof(req));
134
135 req.hdr.nlmsg_len = sizeof(req);
136 req.hdr.nlmsg_flags = NLM_F_REQUEST;
137 req.hdr.nlmsg_pid = 0;
138 req.hdr.nlmsg_seq = request_sequence_;
139 req.hdr.nlmsg_type = RTM_NEWLINK;
140 req.msg.ifi_index = interface_index;
141 req.msg.ifi_flags = flags;
142 req.msg.ifi_change = change;
143
Darin Petkov633ac6f2011-07-08 13:56:13 -0700144 if (sockets_->Send(rtnl_socket_, &req, sizeof(req), 0) < 0) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700145 LOG(ERROR) << "RTNL sendto failed: " << strerror(errno);
146 }
147}
148
149void RTNLHandler::RequestDump(int request_flags) {
150 request_flags_ |= request_flags;
151
mukesh agrawal47009f82011-08-25 14:07:35 -0700152 VLOG(2) << "RTNLHandler got request to dump "
153 << std::showbase << std::hex
154 << request_flags
155 << std::dec << std::noshowbase;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700156
Darin Petkov633ac6f2011-07-08 13:56:13 -0700157 if (!in_request_ && sockets_)
Paul Stewart9a908082011-08-31 12:18:48 -0700158 NextRequest(last_dump_sequence_);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700159}
160
Chris Masone2aa97072011-08-09 17:35:08 -0700161void RTNLHandler::DispatchEvent(int type, const RTNLMessage &msg) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700162 std::vector<RTNLListener *>::iterator it;
163 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
Chris Masone2aa97072011-08-09 17:35:08 -0700164 (*it)->NotifyEvent(type, msg);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700165 }
166}
167
168void RTNLHandler::NextRequest(uint32_t seq) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700169 int flag = 0;
Paul Stewart9a908082011-08-31 12:18:48 -0700170 RTNLMessage::Type type;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700171
Paul Stewart9a908082011-08-31 12:18:48 -0700172 VLOG(2) << "RTNLHandler nextrequest " << seq << " " << last_dump_sequence_
mukesh agrawal47009f82011-08-25 14:07:35 -0700173 << std::showbase << std::hex
174 << " " << request_flags_
175 << std::dec << std::noshowbase;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700176
Paul Stewart9a908082011-08-31 12:18:48 -0700177 if (seq != last_dump_sequence_)
Paul Stewarta3c56f92011-05-26 07:08:52 -0700178 return;
179
Paul Stewarta3c56f92011-05-26 07:08:52 -0700180 if ((request_flags_ & kRequestLink) != 0) {
Paul Stewart9a908082011-08-31 12:18:48 -0700181 type = RTNLMessage::kTypeLink;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700182 flag = kRequestLink;
183 } else if ((request_flags_ & kRequestAddr) != 0) {
Paul Stewart9a908082011-08-31 12:18:48 -0700184 type = RTNLMessage::kTypeAddress;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700185 flag = kRequestAddr;
186 } else if ((request_flags_ & kRequestRoute) != 0) {
Paul Stewart9a908082011-08-31 12:18:48 -0700187 type = RTNLMessage::kTypeRoute;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700188 flag = kRequestRoute;
189 } else {
Paul Stewart9a908082011-08-31 12:18:48 -0700190 VLOG(2) << "Done with requests";
Paul Stewarta3c56f92011-05-26 07:08:52 -0700191 in_request_ = false;
192 return;
193 }
194
Paul Stewart9a908082011-08-31 12:18:48 -0700195 RTNLMessage msg(
196 type,
197 RTNLMessage::kModeGet,
198 0,
199 0,
200 0,
201 0,
Paul Stewart7355ce12011-09-02 10:47:01 -0700202 IPAddress::kFamilyUnknown);
Paul Stewart9a908082011-08-31 12:18:48 -0700203 CHECK(SendMessage(&msg));
Paul Stewarta3c56f92011-05-26 07:08:52 -0700204
Paul Stewart9a908082011-08-31 12:18:48 -0700205 last_dump_sequence_ = msg.seq();
Paul Stewarta3c56f92011-05-26 07:08:52 -0700206 request_flags_ &= ~flag;
207 in_request_ = true;
208}
209
210void RTNLHandler::ParseRTNL(InputData *data) {
211 unsigned char *buf = data->buf;
212 unsigned char *end = buf + data->len;
213
214 while (buf < end) {
215 struct nlmsghdr *hdr = reinterpret_cast<struct nlmsghdr *>(buf);
mukesh agrawalf60e4062011-05-27 13:13:41 -0700216 if (!NLMSG_OK(hdr, static_cast<unsigned int>(end - buf)))
Paul Stewarta3c56f92011-05-26 07:08:52 -0700217 break;
218
Paul Stewart7355ce12011-09-02 10:47:01 -0700219 VLOG(3) << __func__ << ": received payload (" << end - buf << ")";
220
Chris Masone2aa97072011-08-09 17:35:08 -0700221 RTNLMessage msg;
222 if (!msg.Decode(ByteString(reinterpret_cast<unsigned char *>(hdr),
223 hdr->nlmsg_len))) {
Paul Stewart7355ce12011-09-02 10:47:01 -0700224 VLOG(3) << __func__ << ": rtnl packet type "
225 << hdr->nlmsg_type << " length " << hdr->nlmsg_len;
Chris Masone2aa97072011-08-09 17:35:08 -0700226 switch (hdr->nlmsg_type) {
227 case NLMSG_NOOP:
228 case NLMSG_OVERRUN:
229 break;
230 case NLMSG_DONE:
231 NextRequest(hdr->nlmsg_seq);
232 break;
233 case NLMSG_ERROR:
234 {
235 struct nlmsgerr *err =
236 reinterpret_cast<nlmsgerr *>(NLMSG_DATA(hdr));
237 LOG(ERROR) << "error " << -err->error << " ("
238 << strerror(-err->error) << ")";
239 break;
240 }
241 default:
242 NOTIMPLEMENTED() << "Unknown NL message type.";
243 }
244 } else {
245 switch (msg.type()) {
Paul Stewart9a908082011-08-31 12:18:48 -0700246 case RTNLMessage::kTypeLink:
Chris Masone2aa97072011-08-09 17:35:08 -0700247 DispatchEvent(kRequestLink, msg);
248 break;
Paul Stewart9a908082011-08-31 12:18:48 -0700249 case RTNLMessage::kTypeAddress:
Chris Masone2aa97072011-08-09 17:35:08 -0700250 DispatchEvent(kRequestAddr, msg);
251 break;
Paul Stewart9a908082011-08-31 12:18:48 -0700252 case RTNLMessage::kTypeRoute:
Chris Masone2aa97072011-08-09 17:35:08 -0700253 DispatchEvent(kRequestRoute, msg);
254 break;
255 default:
256 NOTIMPLEMENTED() << "Unknown RTNL message type.";
257 }
258 }
Paul Stewarta3c56f92011-05-26 07:08:52 -0700259 buf += hdr->nlmsg_len;
260 }
261}
262
Paul Stewart9a908082011-08-31 12:18:48 -0700263bool RTNLHandler::AddressRequest(int interface_index,
264 RTNLMessage::Mode mode,
265 int flags,
266 const IPAddress &local,
267 const IPAddress &gateway) {
268 CHECK(local.family() == gateway.family());
Paul Stewartc39f1132011-06-22 12:02:28 -0700269
Paul Stewart9a908082011-08-31 12:18:48 -0700270 RTNLMessage msg(
271 RTNLMessage::kTypeAddress,
272 mode,
273 NLM_F_REQUEST | flags,
274 0,
275 0,
276 interface_index,
277 local.family());
Paul Stewartc39f1132011-06-22 12:02:28 -0700278
Paul Stewart9a908082011-08-31 12:18:48 -0700279 msg.set_address_status(RTNLMessage::AddressStatus(
280 local.prefix(),
281 0,
282 0));
Paul Stewartc39f1132011-06-22 12:02:28 -0700283
284 // TODO(pstew): This code only works for Ethernet-like setups,
285 // not with devices that have a peer address like PPP.
Paul Stewart9a908082011-08-31 12:18:48 -0700286 msg.SetAttribute(IFA_LOCAL, local.address());
287 if (!gateway.IsDefault()) {
288 msg.SetAttribute(IFA_BROADCAST, gateway.address());
Paul Stewartc39f1132011-06-22 12:02:28 -0700289 }
290
Paul Stewart9a908082011-08-31 12:18:48 -0700291 return SendMessage(&msg);
Paul Stewartc39f1132011-06-22 12:02:28 -0700292}
293
294bool RTNLHandler::AddInterfaceAddress(int interface_index,
Paul Stewart9a908082011-08-31 12:18:48 -0700295 const IPAddress &local,
296 const IPAddress &broadcast) {
297 return AddressRequest(interface_index,
298 RTNLMessage::kModeAdd,
299 NLM_F_CREATE | NLM_F_EXCL,
300 local,
301 broadcast);
Paul Stewartc39f1132011-06-22 12:02:28 -0700302}
303
304bool RTNLHandler::RemoveInterfaceAddress(int interface_index,
Paul Stewart9a908082011-08-31 12:18:48 -0700305 const IPAddress &local) {
306 return AddressRequest(interface_index,
307 RTNLMessage::kModeDelete,
308 0,
309 local,
310 IPAddress(local.family()));
Paul Stewartc39f1132011-06-22 12:02:28 -0700311}
312
Paul Stewartcba0f7f2012-02-29 16:33:05 -0800313bool RTNLHandler::RemoveInterface(int interface_index) {
314 RTNLMessage msg(
315 RTNLMessage::kTypeLink,
316 RTNLMessage::kModeDelete,
317 NLM_F_REQUEST,
318 0,
319 0,
320 interface_index,
321 IPAddress::kFamilyUnknown);
322 return SendMessage(&msg);
323}
324
Darin Petkove0a312e2011-07-20 13:45:28 -0700325int RTNLHandler::GetInterfaceIndex(const string &interface_name) {
326 if (interface_name.empty()) {
327 LOG(ERROR) << "Empty interface name -- unable to obtain index.";
328 return -1;
329 }
330 struct ifreq ifr;
331 if (interface_name.size() >= sizeof(ifr.ifr_name)) {
332 LOG(ERROR) << "Interface name too long: " << interface_name.size() << " >= "
333 << sizeof(ifr.ifr_name);
334 return -1;
335 }
336 int socket = sockets_->Socket(PF_INET, SOCK_DGRAM, 0);
337 if (socket < 0) {
338 PLOG(ERROR) << "Unable to open INET socket";
339 return -1;
340 }
341 ScopedSocketCloser socket_closer(sockets_, socket);
342 memset(&ifr, 0, sizeof(ifr));
343 strncpy(ifr.ifr_name, interface_name.c_str(), sizeof(ifr.ifr_name));
344 if (sockets_->Ioctl(socket, SIOCGIFINDEX, &ifr) < 0) {
345 PLOG(ERROR) << "SIOCGIFINDEX error for " << interface_name;
346 return -1;
347 }
348 return ifr.ifr_ifindex;
349}
350
Paul Stewart75e89d22011-08-01 10:00:02 -0700351bool RTNLHandler::SendMessage(RTNLMessage *message) {
352 message->set_seq(request_sequence_++);
353 ByteString msgdata = message->Encode();
354
355 if (msgdata.GetLength() == 0) {
356 return false;
357 }
358
359 if (sockets_->Send(rtnl_socket_,
Paul Stewart9a908082011-08-31 12:18:48 -0700360 msgdata.GetConstData(),
Paul Stewart75e89d22011-08-01 10:00:02 -0700361 msgdata.GetLength(),
362 0) < 0) {
363 PLOG(ERROR) << "RTNL send failed: " << strerror(errno);
364 return false;
365 }
366
367 return true;
368}
369
Paul Stewarta3c56f92011-05-26 07:08:52 -0700370} // namespace shill