blob: 98ac7f05b552934d29a5a6bd0672b95027da6d13 [file] [log] [blame]
Paul Stewart0af98bf2011-05-10 17:38:08 -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 <time.h>
6
7#include <unistd.h>
8#include <string.h>
9#include <sys/socket.h>
10#include <arpa/inet.h>
11#include <netinet/ether.h>
12#include <net/if.h>
13#include <net/if_arp.h>
14#include <linux/netlink.h>
15#include <linux/rtnetlink.h>
16#include <string>
17
Chris Masone487b8bf2011-05-13 16:27:57 -070018#include <base/callback_old.h>
Chris Masone0e1d1042011-05-09 18:07:03 -070019#include <base/hash_tables.h>
Chris Masone487b8bf2011-05-13 16:27:57 -070020#include <base/logging.h>
21#include <base/memory/scoped_ptr.h>
Paul Stewart0af98bf2011-05-10 17:38:08 -070022
23#include "shill/control_interface.h"
Paul Stewart0af98bf2011-05-10 17:38:08 -070024#include "shill/device_info.h"
Chris Masone487b8bf2011-05-13 16:27:57 -070025#include "shill/service.h"
Paul Stewart0af98bf2011-05-10 17:38:08 -070026
27using std::string;
28
29namespace shill {
30DeviceInfo::DeviceInfo(EventDispatcher *dispatcher)
31 : running_(false),
32 dispatcher_(dispatcher),
Chris Masone0e1d1042011-05-09 18:07:03 -070033 rtnl_callback_(NewCallback(this, &DeviceInfo::ParseRTNL)),
Paul Stewart0af98bf2011-05-10 17:38:08 -070034 rtnl_socket_(-1),
35 request_flags_(0),
36 request_sequence_(0) {
37 LOG(INFO) << "DeviceInfo initialized";
38}
39
40DeviceInfo::~DeviceInfo() {
41 Stop();
42}
43
44void DeviceInfo::Start()
45{
46 struct sockaddr_nl addr;
47
48 if (running_)
49 return;
50
51 rtnl_socket_ = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
52 if (rtnl_socket_ < 0) {
53 LOG(ERROR) << "Failed to open rtnl socket";
54 return;
55 }
56
57 memset(&addr, 0, sizeof(addr));
58 addr.nl_family = AF_NETLINK;
59 addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
60
61 if (bind(rtnl_socket_, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
62 close(rtnl_socket_);
63 rtnl_socket_ = -1;
64 LOG(ERROR) << "RTNL socket bind failed";
65 return;
66 }
67
68 rtnl_handler_.reset(dispatcher_->CreateInputHandler(rtnl_socket_,
Chris Masone0e1d1042011-05-09 18:07:03 -070069 rtnl_callback_.get()));
Paul Stewart0af98bf2011-05-10 17:38:08 -070070 running_ = true;
71
72 request_flags_ = REQUEST_LINK | REQUEST_ADDR | REQUEST_ROUTE;
73 NextRequest(request_sequence_);
74
75 LOG(INFO) << "DeviceInfo started";
76}
77
78void DeviceInfo::Stop()
79{
80 if (!running_)
81 return;
82
83 rtnl_handler_.reset(NULL);
84 close(rtnl_socket_);
85 running_ = false;
86}
87
88void DeviceInfo::NextRequest(uint32_t seq) {
89 struct rtnl_request {
90 struct nlmsghdr hdr;
91 struct rtgenmsg msg;
92 } req;
93 struct sockaddr_nl addr;
94 int flag = 0;
95
96 LOG(INFO) << __func__ << ": " << seq << " :: " << request_sequence_;
97
98 if (seq != request_sequence_)
99 return;
100
101 request_sequence_++;
102 memset(&req, 0, sizeof(req));
103
104 req.hdr.nlmsg_len = sizeof(req);
105 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
106 req.hdr.nlmsg_pid = 0;
107 req.hdr.nlmsg_seq = request_sequence_;
108 req.msg.rtgen_family = AF_INET;
109
110 if ((request_flags_ & REQUEST_LINK) != 0) {
111 req.hdr.nlmsg_type = RTM_GETLINK;
112 flag = REQUEST_LINK;
113 } else if ((request_flags_ & REQUEST_ADDR) != 0) {
114 req.hdr.nlmsg_type = RTM_GETADDR;
115 flag = REQUEST_ADDR;
116 } else if ((request_flags_ & REQUEST_ROUTE) != 0) {
117 req.hdr.nlmsg_type = RTM_GETROUTE;
118 flag = REQUEST_ROUTE;
119 } else
120 return;
121
122 memset(&addr, 0, sizeof(addr));
123 addr.nl_family = AF_NETLINK;
124
125 if (sendto(rtnl_socket_, &req, sizeof(req), 0,
126 (struct sockaddr *) &addr, sizeof(addr)) < 0) {
127 LOG(ERROR) << "RTNL sendto failed";
128 return;
129 }
130 request_flags_ &= ~flag;
131}
132
133
134void DeviceInfo::LinkMsg(unsigned char *buf, bool del) {
135 struct nlmsghdr *hdr = (struct nlmsghdr *) buf;
136 struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
137 int bytes = IFLA_PAYLOAD(hdr);
138
139 LOG(INFO) << "index " << msg->ifi_index << " flags " << msg->ifi_flags <<
140 ": del = " << del;
141}
142
143void DeviceInfo::AddrMsg(unsigned char *buf, bool del) {
144 struct nlmsghdr *hdr = (struct nlmsghdr *) buf;
145 struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
146 LOG(INFO) << "index " << msg->ifi_index << " flags " << msg->ifi_flags <<
147 ": del = " << del;
148}
149
150void DeviceInfo::RouteMsg(unsigned char *buf, bool del) {
151 struct nlmsghdr *hdr = (struct nlmsghdr *) buf;
152 struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
153 LOG(INFO) << "index " << msg->ifi_index << " flags " << msg->ifi_flags <<
154 ": del = " << del;
155}
156
157void DeviceInfo::ParseRTNL(InputData *data) {
158 unsigned char *buf = data->buf;
159 unsigned char *end = buf + data->len;
160
161 while (buf < end) {
162 struct nlmsghdr *hdr = (struct nlmsghdr *) buf;
163 struct nlmsgerr *err;
164
165 if (!NLMSG_OK(hdr, end - buf))
166 break;
167
168 switch (hdr->nlmsg_type) {
169 case NLMSG_NOOP:
170 case NLMSG_OVERRUN:
171 return;
172 case NLMSG_DONE:
173 NextRequest(hdr->nlmsg_seq);
174 return;
175 case NLMSG_ERROR:
176 err = (nlmsgerr *) NLMSG_DATA(hdr);
177 LOG(ERROR) << "error " << -err->error << " (" << strerror(-err->error) <<
178 ")";
179 return;
180 case RTM_NEWLINK:
181 LinkMsg(buf, false);
182 break;
183 case RTM_DELLINK:
184 LinkMsg(buf, true);
185 break;
186 case RTM_NEWADDR:
187 AddrMsg(buf, false);
188 break;
189 case RTM_DELADDR:
190 AddrMsg(buf, true);
191 break;
192 case RTM_NEWROUTE:
193 RouteMsg(buf, false);
194 break;
195 case RTM_DELROUTE:
196 RouteMsg(buf, true);
197 break;
198 }
199
200 buf += hdr->nlmsg_len;
201 }
202}
203
204} // namespace shill