blob: 6b089205be986604e10218f7ba8c752d04bffdd0 [file] [log] [blame]
Wade Guthrie0d438532012-05-18 14:18:50 -07001// Copyright (c) 2012 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// This code is derived from the 'iw' source code. The copyright and license
6// of that code is as follows:
7//
8// Copyright (c) 2007, 2008 Johannes Berg
9// Copyright (c) 2007 Andy Lutomirski
10// Copyright (c) 2007 Mike Kershaw
11// Copyright (c) 2008-2009 Luis R. Rodriguez
12//
13// Permission to use, copy, modify, and/or distribute this software for any
14// purpose with or without fee is hereby granted, provided that the above
15// copyright notice and this permission notice appear in all copies.
16//
17// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
18// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
19// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
20// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
22// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
23// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25#include "shill/netlink_socket.h"
26
27#include <ctype.h>
28#include <errno.h>
Wade Guthrieb1ec8602012-10-18 17:26:14 -070029#include <string.h>
Wade Guthrie0d438532012-05-18 14:18:50 -070030
31#include <net/if.h>
32#include <netlink/attr.h>
33#include <netlink/genl/ctrl.h>
34#include <netlink/genl/family.h>
35#include <netlink/genl/genl.h>
36#include <netlink/msg.h>
37#include <netlink/netlink.h>
38
39#include <iomanip>
40
41#include <base/logging.h>
42
Wade Guthrie0d438532012-05-18 14:18:50 -070043#include "shill/scope_logger.h"
44
45namespace shill {
46
47//
48// NetlinkSocket::Callback.
49//
50
51NetlinkSocket::Callback::~Callback() {
52 if (cb_) {
53 nl_cb_put(cb_);
54 cb_ = NULL;
55 }
56}
57
58bool NetlinkSocket::Callback::Init() {
59 cb_ = nl_cb_alloc(NL_CB_DEFAULT);
60 if (!cb_) {
61 LOG(ERROR) << "NULL cb_";
62 return false;
63 }
64 return true;
65}
66
67bool NetlinkSocket::Callback::ErrHandler(enum nl_cb_kind kind,
68 nl_recvmsg_err_cb_t func,
69 void *arg) {
70 int result = nl_cb_err(cb_, kind, func, arg);
71 if (result) {
72 LOG(ERROR) << "nl_cb_err returned " << result;
73 return false;
74 }
75 return true;
76}
77
78bool NetlinkSocket::Callback::SetHandler(enum nl_cb_type type,
79 enum nl_cb_kind kind,
80 nl_recvmsg_msg_cb_t func,
81 void *arg) {
82 int result = nl_cb_set(cb_, type, kind, func, arg);
83 if (result) {
84 LOG(ERROR) << "nl_cb_set returned " << result;
85 return false;
86 }
87 return true;
88}
89
90//
91// NetlinkSocket.
92//
93
94NetlinkSocket::~NetlinkSocket() {
95 if (nl_sock_) {
96 nl_socket_free(nl_sock_);
97 nl_sock_ = NULL;
98 }
99}
100
101bool NetlinkSocket::Init() {
102 nl_sock_ = nl_socket_alloc();
103 if (!nl_sock_) {
104 LOG(ERROR) << "Failed to allocate netlink socket.";
105 return false;
106 }
107
108 if (genl_connect(nl_sock_)) {
109 LOG(ERROR) << "Failed to connect to generic netlink.";
110 return false;
111 }
112
113 return true;
114}
115
Wade Guthrie5d53d492012-11-07 09:53:31 -0800116bool NetlinkSocket::Send(struct nl_msg *message) {
117 if (!message) {
118 LOG(ERROR) << "NULL |message|.";
119 return false;
120 }
121
122 if (!nl_sock_) {
123 LOG(ERROR) << "Need to initialize the socket first.";
124 return false;
125 }
126
127 int result = nl_send_auto_complete(nl_sock_, message);
128 if (result < 0) {
129 LOG(ERROR) << "Failed call to 'nl_send_auto_complete': " << result;
130 return false;
131 }
132 return true;
133}
134
135
Wade Guthrie0d438532012-05-18 14:18:50 -0700136bool NetlinkSocket::DisableSequenceChecking() {
137 if (!nl_sock_) {
138 LOG(ERROR) << "NULL socket";
139 return false;
140 }
141
142 // NOTE: can't use nl_socket_disable_seq_check(); it's not in this version
143 // of the library.
144 int result = nl_socket_modify_cb(nl_sock_, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
145 NetlinkSocket::IgnoreSequenceCheck, NULL);
146 if (result) {
147 LOG(ERROR) << "Failed call to nl_socket_modify_cb: " << result;
148 return false;
149 }
150
151 return true;
152}
153
154int NetlinkSocket::GetFd() const {
155 if (!nl_sock_) {
156 LOG(ERROR) << "NULL socket";
157 return -1;
158 }
159 return nl_socket_get_fd(nl_sock_);
160}
161
162bool NetlinkSocket::GetMessages() {
163 // TODO(wdg): make this non-blocking.
164 // Blocks until a message is available. When that happens, the message is
165 // read and passed to the default callback (i.e., the one set with
166 // NetlinkSocket::SetNetlinkCallback).
167 int result = nl_recvmsgs_default(nl_sock_);
168 if (result < 0) {
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700169 LOG(ERROR) << "Failed call to nl_recvmsgs_default: " << strerror(-result)
170 << " (" << result << ")";
Wade Guthrie0d438532012-05-18 14:18:50 -0700171 return false;
172 }
173 return true;
174}
175
176bool NetlinkSocket::GetMessagesUsingCallback(
177 NetlinkSocket::Callback *on_netlink_data) {
178 if (!on_netlink_data || !on_netlink_data->cb_)
179 return GetMessages(); // Default to generic callback.
180
181 int result = nl_recvmsgs(nl_sock_, on_netlink_data->cb_);
182 if (result < 0) {
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700183 LOG(ERROR) << "Failed call to nl_recvmsgs: " << strerror(-result)
184 << " (" << result << ")";
Wade Guthrie0d438532012-05-18 14:18:50 -0700185 return false;
186 }
187 return true;
188}
189
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700190unsigned int NetlinkSocket::GetSequenceNumber() {
191 unsigned int number = nl_socket_use_seq(nl_sock_);
192 if (number == 0) {
193 number = nl_socket_use_seq(nl_sock_);
194 }
195 if (number == 0) {
196 LOG(WARNING) << "Couldn't get non-zero sequence number";
197 number = 1;
198 }
199 return number;
200}
201
Wade Guthrie0d438532012-05-18 14:18:50 -0700202bool NetlinkSocket::SetNetlinkCallback(nl_recvmsg_msg_cb_t on_netlink_data,
203 void *callback_parameter) {
204 if (!nl_sock_) {
205 LOG(ERROR) << "NULL socket";
206 return false;
207 }
208
209 int result = nl_socket_modify_cb(nl_sock_, NL_CB_VALID, NL_CB_CUSTOM,
210 on_netlink_data, callback_parameter);
211 if (result) {
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700212 LOG(ERROR) << "nl_socket_modify_cb returned " << strerror(-result)
213 << " (" << result << ")";
Wade Guthrie0d438532012-05-18 14:18:50 -0700214 return false;
215 }
216 return true;
217}
218
219int NetlinkSocket::IgnoreSequenceCheck(struct nl_msg *ignored_msg,
220 void *ignored_arg) {
221 return NL_OK; // Proceed.
222}
223
224} // namespace shill.