blob: 185275f0f536788d46ccaadc7b2a6140af3a8f9b [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
21#include "shill/io_handler.h"
Paul Stewart1d18e8c2011-07-15 11:00:31 -070022#include "shill/ip_address.h"
Paul Stewartc39f1132011-06-22 12:02:28 -070023#include "shill/ipconfig.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070024#include "shill/rtnl_handler.h"
25#include "shill/rtnl_listener.h"
Paul Stewart75e89d22011-08-01 10:00:02 -070026#include "shill/rtnl_message.h"
Paul Stewarta3c56f92011-05-26 07:08:52 -070027#include "shill/shill_event.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
34RTNLHandler::RTNLHandler()
Darin Petkov633ac6f2011-07-08 13:56:13 -070035 : sockets_(NULL),
Paul Stewarta3c56f92011-05-26 07:08:52 -070036 in_request_(false),
Paul Stewarta3c56f92011-05-26 07:08:52 -070037 rtnl_socket_(-1),
38 request_flags_(0),
mukesh agrawalf60e4062011-05-27 13:13:41 -070039 request_sequence_(0),
40 rtnl_callback_(NewCallback(this, &RTNLHandler::ParseRTNL)) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070041 VLOG(2) << "RTNLHandler created";
42}
43
44RTNLHandler::~RTNLHandler() {
45 VLOG(2) << "RTNLHandler removed";
46 Stop();
47}
48
49RTNLHandler* RTNLHandler::GetInstance() {
50 return Singleton<RTNLHandler>::get();
51}
52
Darin Petkov633ac6f2011-07-08 13:56:13 -070053void RTNLHandler::Start(EventDispatcher *dispatcher, Sockets *sockets) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070054 struct sockaddr_nl addr;
55
Darin Petkov633ac6f2011-07-08 13:56:13 -070056 if (sockets_) {
Paul Stewarta3c56f92011-05-26 07:08:52 -070057 return;
Darin Petkov633ac6f2011-07-08 13:56:13 -070058 }
Paul Stewarta3c56f92011-05-26 07:08:52 -070059
Darin Petkov633ac6f2011-07-08 13:56:13 -070060 rtnl_socket_ = sockets->Socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
Paul Stewarta3c56f92011-05-26 07:08:52 -070061 if (rtnl_socket_ < 0) {
62 LOG(ERROR) << "Failed to open rtnl socket";
63 return;
64 }
65
66 memset(&addr, 0, sizeof(addr));
67 addr.nl_family = AF_NETLINK;
68 addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
69
Darin Petkov633ac6f2011-07-08 13:56:13 -070070 if (sockets->Bind(rtnl_socket_,
71 reinterpret_cast<struct sockaddr *>(&addr),
72 sizeof(addr)) < 0) {
73 sockets->Close(rtnl_socket_);
Paul Stewarta3c56f92011-05-26 07:08:52 -070074 rtnl_socket_ = -1;
75 LOG(ERROR) << "RTNL socket bind failed";
76 return;
77 }
78
79 rtnl_handler_.reset(dispatcher->CreateInputHandler(rtnl_socket_,
80 rtnl_callback_.get()));
Darin Petkov633ac6f2011-07-08 13:56:13 -070081 sockets_ = sockets;
Paul Stewarta3c56f92011-05-26 07:08:52 -070082
83 NextRequest(request_sequence_);
Paul Stewarta3c56f92011-05-26 07:08:52 -070084 VLOG(2) << "RTNLHandler started";
85}
86
87void RTNLHandler::Stop() {
Darin Petkov633ac6f2011-07-08 13:56:13 -070088 if (!sockets_)
Paul Stewarta3c56f92011-05-26 07:08:52 -070089 return;
90
91 rtnl_handler_.reset(NULL);
Darin Petkov633ac6f2011-07-08 13:56:13 -070092 sockets_->Close(rtnl_socket_);
Paul Stewarta3c56f92011-05-26 07:08:52 -070093 in_request_ = false;
Darin Petkov633ac6f2011-07-08 13:56:13 -070094 sockets_ = NULL;
Paul Stewart65c40f52011-08-08 07:27:46 -070095 request_flags_ = 0;
Paul Stewarta3c56f92011-05-26 07:08:52 -070096 VLOG(2) << "RTNLHandler stopped";
97}
98
99void RTNLHandler::AddListener(RTNLListener *to_add) {
100 std::vector<RTNLListener *>::iterator it;
101 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
102 if (to_add == *it)
103 return;
104 }
105 listeners_.push_back(to_add);
106 VLOG(2) << "RTNLHandler added listener";
107}
108
109void RTNLHandler::RemoveListener(RTNLListener *to_remove) {
110 std::vector<RTNLListener *>::iterator it;
111 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
112 if (to_remove == *it) {
113 listeners_.erase(it);
114 return;
115 }
116 }
117 VLOG(2) << "RTNLHandler removed listener";
118}
119
120void RTNLHandler::SetInterfaceFlags(int interface_index, unsigned int flags,
121 unsigned int change) {
122 struct rtnl_request {
123 struct nlmsghdr hdr;
124 struct ifinfomsg msg;
125 } req;
126
127 request_sequence_++;
128 memset(&req, 0, sizeof(req));
129
130 req.hdr.nlmsg_len = sizeof(req);
131 req.hdr.nlmsg_flags = NLM_F_REQUEST;
132 req.hdr.nlmsg_pid = 0;
133 req.hdr.nlmsg_seq = request_sequence_;
134 req.hdr.nlmsg_type = RTM_NEWLINK;
135 req.msg.ifi_index = interface_index;
136 req.msg.ifi_flags = flags;
137 req.msg.ifi_change = change;
138
Darin Petkov633ac6f2011-07-08 13:56:13 -0700139 if (sockets_->Send(rtnl_socket_, &req, sizeof(req), 0) < 0) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700140 LOG(ERROR) << "RTNL sendto failed: " << strerror(errno);
141 }
142}
143
144void RTNLHandler::RequestDump(int request_flags) {
145 request_flags_ |= request_flags;
146
147 VLOG(2) << "RTNLHandler got request to dump " << request_flags;
148
Darin Petkov633ac6f2011-07-08 13:56:13 -0700149 if (!in_request_ && sockets_)
Paul Stewarta3c56f92011-05-26 07:08:52 -0700150 NextRequest(request_sequence_);
151}
152
Chris Masone2aa97072011-08-09 17:35:08 -0700153void RTNLHandler::DispatchEvent(int type, const RTNLMessage &msg) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700154 std::vector<RTNLListener *>::iterator it;
155 for (it = listeners_.begin(); it != listeners_.end(); ++it) {
Chris Masone2aa97072011-08-09 17:35:08 -0700156 (*it)->NotifyEvent(type, msg);
Paul Stewarta3c56f92011-05-26 07:08:52 -0700157 }
158}
159
160void RTNLHandler::NextRequest(uint32_t seq) {
161 struct rtnl_request {
162 struct nlmsghdr hdr;
163 struct rtgenmsg msg;
164 } req;
165 struct sockaddr_nl addr;
166 int flag = 0;
167
Darin Petkov633ac6f2011-07-08 13:56:13 -0700168 VLOG(2) << "RTNLHandler nextrequest " << seq << " " << request_sequence_
169 << " " << request_flags_;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700170
171 if (seq != request_sequence_)
172 return;
173
174 request_sequence_++;
175 memset(&req, 0, sizeof(req));
176
177 req.hdr.nlmsg_len = sizeof(req);
178 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
179 req.hdr.nlmsg_pid = 0;
180 req.hdr.nlmsg_seq = request_sequence_;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700181
182 if ((request_flags_ & kRequestLink) != 0) {
Paul Stewart75e89d22011-08-01 10:00:02 -0700183 req.msg.rtgen_family = AF_INET;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700184 req.hdr.nlmsg_type = RTM_GETLINK;
185 flag = kRequestLink;
186 } else if ((request_flags_ & kRequestAddr) != 0) {
Paul Stewart75e89d22011-08-01 10:00:02 -0700187 req.msg.rtgen_family = AF_INET;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700188 req.hdr.nlmsg_type = RTM_GETADDR;
189 flag = kRequestAddr;
190 } else if ((request_flags_ & kRequestRoute) != 0) {
Paul Stewart75e89d22011-08-01 10:00:02 -0700191 req.msg.rtgen_family = AF_INET;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700192 req.hdr.nlmsg_type = RTM_GETROUTE;
193 flag = kRequestRoute;
Paul Stewart75e89d22011-08-01 10:00:02 -0700194 } else if ((request_flags_ & kRequestAddr6) != 0) {
195 req.msg.rtgen_family = AF_INET6;
196 req.hdr.nlmsg_type = RTM_GETADDR;
197 flag = kRequestAddr6;
198 } else if ((request_flags_ & kRequestRoute6) != 0) {
199 req.msg.rtgen_family = AF_INET6;
200 req.hdr.nlmsg_type = RTM_GETROUTE;
201 flag = kRequestRoute6;
Paul Stewarta3c56f92011-05-26 07:08:52 -0700202 } else {
203 in_request_ = false;
204 return;
205 }
206
207 memset(&addr, 0, sizeof(addr));
208 addr.nl_family = AF_NETLINK;
209
Darin Petkov633ac6f2011-07-08 13:56:13 -0700210 if (sockets_->SendTo(rtnl_socket_,
211 &req,
212 sizeof(req),
213 0,
214 reinterpret_cast<struct sockaddr *>(&addr),
215 sizeof(addr)) < 0) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700216 LOG(ERROR) << "RTNL sendto failed";
217 return;
218 }
219 request_flags_ &= ~flag;
220 in_request_ = true;
221}
222
223void RTNLHandler::ParseRTNL(InputData *data) {
224 unsigned char *buf = data->buf;
225 unsigned char *end = buf + data->len;
226
227 while (buf < end) {
228 struct nlmsghdr *hdr = reinterpret_cast<struct nlmsghdr *>(buf);
mukesh agrawalf60e4062011-05-27 13:13:41 -0700229 if (!NLMSG_OK(hdr, static_cast<unsigned int>(end - buf)))
Paul Stewarta3c56f92011-05-26 07:08:52 -0700230 break;
231
Chris Masone2aa97072011-08-09 17:35:08 -0700232 RTNLMessage msg;
233 if (!msg.Decode(ByteString(reinterpret_cast<unsigned char *>(hdr),
234 hdr->nlmsg_len))) {
Paul Stewarta3c56f92011-05-26 07:08:52 -0700235
Chris Masone2aa97072011-08-09 17:35:08 -0700236 switch (hdr->nlmsg_type) {
237 case NLMSG_NOOP:
238 case NLMSG_OVERRUN:
239 break;
240 case NLMSG_DONE:
241 NextRequest(hdr->nlmsg_seq);
242 break;
243 case NLMSG_ERROR:
244 {
245 struct nlmsgerr *err =
246 reinterpret_cast<nlmsgerr *>(NLMSG_DATA(hdr));
247 LOG(ERROR) << "error " << -err->error << " ("
248 << strerror(-err->error) << ")";
249 break;
250 }
251 default:
252 NOTIMPLEMENTED() << "Unknown NL message type.";
253 }
254 } else {
255 switch (msg.type()) {
256 case RTNLMessage::kMessageTypeLink:
257 DispatchEvent(kRequestLink, msg);
258 break;
259 case RTNLMessage::kMessageTypeAddress:
260 DispatchEvent(kRequestAddr, msg);
261 break;
262 case RTNLMessage::kMessageTypeRoute:
263 DispatchEvent(kRequestRoute, msg);
264 break;
265 default:
266 NOTIMPLEMENTED() << "Unknown RTNL message type.";
267 }
268 }
Paul Stewarta3c56f92011-05-26 07:08:52 -0700269 buf += hdr->nlmsg_len;
270 }
271}
272
Paul Stewartc39f1132011-06-22 12:02:28 -0700273static bool AddAtribute(struct nlmsghdr *hdr, int max_msg_size, int attr_type,
274 const void *attr_data, int attr_len) {
275 int len = RTA_LENGTH(attr_len);
276 int new_msg_size = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(len);
277 struct rtattr *rt_attr;
278
279 if (new_msg_size > max_msg_size)
280 return false;
281
282 rt_attr = reinterpret_cast<struct rtattr *> (reinterpret_cast<unsigned char *>
283 (hdr) +
284 NLMSG_ALIGN(hdr->nlmsg_len));
285 rt_attr->rta_type = attr_type;
286 rt_attr->rta_len = len;
287 memcpy(RTA_DATA(rt_attr), attr_data, attr_len);
288 hdr->nlmsg_len = new_msg_size;
289 return true;
290}
291
292bool RTNLHandler::AddressRequest(int interface_index, int cmd, int flags,
293 const IPConfig &ipconfig) {
294 const IPConfig::Properties &properties = ipconfig.properties();
295 int address_family;
296 int address_size;
297 unsigned char *attrs, *attrs_end;
298 int max_msg_size;
299 struct {
300 struct nlmsghdr hdr;
301 struct ifaddrmsg ifa;
302 unsigned char attrs[256];
303 } req;
304 union {
305 in_addr ip4;
306 in6_addr in6;
307 } addr;
308
Paul Stewart1d18e8c2011-07-15 11:00:31 -0700309 if (properties.address_family == IPAddress::kAddressFamilyIPv4) {
Paul Stewartc39f1132011-06-22 12:02:28 -0700310 address_family = AF_INET;
311 address_size = sizeof(struct in_addr);
Paul Stewart1d18e8c2011-07-15 11:00:31 -0700312 } else if (properties.address_family == IPAddress::kAddressFamilyIPv6) {
Paul Stewartc39f1132011-06-22 12:02:28 -0700313 address_family = AF_INET6;
314 address_size = sizeof(struct in6_addr);
Paul Stewart75e89d22011-08-01 10:00:02 -0700315 } else {
Paul Stewartc39f1132011-06-22 12:02:28 -0700316 return false;
Paul Stewart75e89d22011-08-01 10:00:02 -0700317 }
Paul Stewartc39f1132011-06-22 12:02:28 -0700318
319 request_sequence_++;
320 memset(&req, 0, sizeof(req));
321 req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
322 req.hdr.nlmsg_flags = NLM_F_REQUEST | flags;
323 req.hdr.nlmsg_type = cmd;
324 req.ifa.ifa_family = address_family;
325 req.ifa.ifa_index = interface_index;
326
327 max_msg_size = req.hdr.nlmsg_len + sizeof(req.attrs);
328
329 // TODO(pstew): This code only works for Ethernet-like setups,
330 // not with devices that have a peer address like PPP.
331 if (inet_pton(address_family, properties.address.c_str(), &addr) <= 0 ||
332 !AddAtribute(&req.hdr, max_msg_size, IFA_LOCAL, &addr, address_size))
333 return false;
334
335 if (inet_pton(address_family, properties.broadcast_address.c_str(),
336 &addr) <= 0 ||
337 !AddAtribute(&req.hdr, max_msg_size, IFA_BROADCAST, &addr, address_size))
338 return false;
339
340 req.ifa.ifa_prefixlen = properties.subnet_cidr;
341
Darin Petkov633ac6f2011-07-08 13:56:13 -0700342 if (sockets_->Send(rtnl_socket_, &req, req.hdr.nlmsg_len, 0) < 0) {
Paul Stewartc39f1132011-06-22 12:02:28 -0700343 LOG(ERROR) << "RTNL sendto failed: " << strerror(errno);
344 return false;
345 }
346
347 return true;
348}
349
350bool RTNLHandler::AddInterfaceAddress(int interface_index,
351 const IPConfig &ipconfig) {
352 return AddressRequest(interface_index, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
353 ipconfig);
354}
355
356bool RTNLHandler::RemoveInterfaceAddress(int interface_index,
357 const IPConfig &ipconfig) {
358 return AddressRequest(interface_index, RTM_DELADDR, 0, ipconfig);
359}
360
Darin Petkove0a312e2011-07-20 13:45:28 -0700361int RTNLHandler::GetInterfaceIndex(const string &interface_name) {
362 if (interface_name.empty()) {
363 LOG(ERROR) << "Empty interface name -- unable to obtain index.";
364 return -1;
365 }
366 struct ifreq ifr;
367 if (interface_name.size() >= sizeof(ifr.ifr_name)) {
368 LOG(ERROR) << "Interface name too long: " << interface_name.size() << " >= "
369 << sizeof(ifr.ifr_name);
370 return -1;
371 }
372 int socket = sockets_->Socket(PF_INET, SOCK_DGRAM, 0);
373 if (socket < 0) {
374 PLOG(ERROR) << "Unable to open INET socket";
375 return -1;
376 }
377 ScopedSocketCloser socket_closer(sockets_, socket);
378 memset(&ifr, 0, sizeof(ifr));
379 strncpy(ifr.ifr_name, interface_name.c_str(), sizeof(ifr.ifr_name));
380 if (sockets_->Ioctl(socket, SIOCGIFINDEX, &ifr) < 0) {
381 PLOG(ERROR) << "SIOCGIFINDEX error for " << interface_name;
382 return -1;
383 }
384 return ifr.ifr_ifindex;
385}
386
Paul Stewart75e89d22011-08-01 10:00:02 -0700387bool RTNLHandler::SendMessage(RTNLMessage *message) {
388 message->set_seq(request_sequence_++);
389 ByteString msgdata = message->Encode();
390
391 if (msgdata.GetLength() == 0) {
392 return false;
393 }
394
395 if (sockets_->Send(rtnl_socket_,
396 msgdata.GetData(),
397 msgdata.GetLength(),
398 0) < 0) {
399 PLOG(ERROR) << "RTNL send failed: " << strerror(errno);
400 return false;
401 }
402
403 return true;
404}
405
Paul Stewarta3c56f92011-05-26 07:08:52 -0700406} // namespace shill