blob: 9d8caa3369fed3492feb17cf05e5a71721861d27 [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
43#include "shill/kernel_bound_nlmessage.h"
44#include "shill/scope_logger.h"
45
46namespace shill {
47
48//
49// NetlinkSocket::Callback.
50//
51
52NetlinkSocket::Callback::~Callback() {
53 if (cb_) {
54 nl_cb_put(cb_);
55 cb_ = NULL;
56 }
57}
58
59bool NetlinkSocket::Callback::Init() {
60 cb_ = nl_cb_alloc(NL_CB_DEFAULT);
61 if (!cb_) {
62 LOG(ERROR) << "NULL cb_";
63 return false;
64 }
65 return true;
66}
67
68bool NetlinkSocket::Callback::ErrHandler(enum nl_cb_kind kind,
69 nl_recvmsg_err_cb_t func,
70 void *arg) {
71 int result = nl_cb_err(cb_, kind, func, arg);
72 if (result) {
73 LOG(ERROR) << "nl_cb_err returned " << result;
74 return false;
75 }
76 return true;
77}
78
79bool NetlinkSocket::Callback::SetHandler(enum nl_cb_type type,
80 enum nl_cb_kind kind,
81 nl_recvmsg_msg_cb_t func,
82 void *arg) {
83 int result = nl_cb_set(cb_, type, kind, func, arg);
84 if (result) {
85 LOG(ERROR) << "nl_cb_set returned " << result;
86 return false;
87 }
88 return true;
89}
90
91//
92// NetlinkSocket.
93//
94
95NetlinkSocket::~NetlinkSocket() {
96 if (nl_sock_) {
97 nl_socket_free(nl_sock_);
98 nl_sock_ = NULL;
99 }
100}
101
102bool NetlinkSocket::Init() {
103 nl_sock_ = nl_socket_alloc();
104 if (!nl_sock_) {
105 LOG(ERROR) << "Failed to allocate netlink socket.";
106 return false;
107 }
108
109 if (genl_connect(nl_sock_)) {
110 LOG(ERROR) << "Failed to connect to generic netlink.";
111 return false;
112 }
113
114 return true;
115}
116
117bool NetlinkSocket::DisableSequenceChecking() {
118 if (!nl_sock_) {
119 LOG(ERROR) << "NULL socket";
120 return false;
121 }
122
123 // NOTE: can't use nl_socket_disable_seq_check(); it's not in this version
124 // of the library.
125 int result = nl_socket_modify_cb(nl_sock_, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
126 NetlinkSocket::IgnoreSequenceCheck, NULL);
127 if (result) {
128 LOG(ERROR) << "Failed call to nl_socket_modify_cb: " << result;
129 return false;
130 }
131
132 return true;
133}
134
135int NetlinkSocket::GetFd() const {
136 if (!nl_sock_) {
137 LOG(ERROR) << "NULL socket";
138 return -1;
139 }
140 return nl_socket_get_fd(nl_sock_);
141}
142
143bool NetlinkSocket::GetMessages() {
144 // TODO(wdg): make this non-blocking.
145 // Blocks until a message is available. When that happens, the message is
146 // read and passed to the default callback (i.e., the one set with
147 // NetlinkSocket::SetNetlinkCallback).
148 int result = nl_recvmsgs_default(nl_sock_);
149 if (result < 0) {
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700150 LOG(ERROR) << "Failed call to nl_recvmsgs_default: " << strerror(-result)
151 << " (" << result << ")";
Wade Guthrie0d438532012-05-18 14:18:50 -0700152 return false;
153 }
154 return true;
155}
156
157bool NetlinkSocket::GetMessagesUsingCallback(
158 NetlinkSocket::Callback *on_netlink_data) {
159 if (!on_netlink_data || !on_netlink_data->cb_)
160 return GetMessages(); // Default to generic callback.
161
162 int result = nl_recvmsgs(nl_sock_, on_netlink_data->cb_);
163 if (result < 0) {
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700164 LOG(ERROR) << "Failed call to nl_recvmsgs: " << strerror(-result)
165 << " (" << result << ")";
Wade Guthrie0d438532012-05-18 14:18:50 -0700166 return false;
167 }
168 return true;
169}
170
171bool NetlinkSocket::SetNetlinkCallback(nl_recvmsg_msg_cb_t on_netlink_data,
172 void *callback_parameter) {
173 if (!nl_sock_) {
174 LOG(ERROR) << "NULL socket";
175 return false;
176 }
177
178 int result = nl_socket_modify_cb(nl_sock_, NL_CB_VALID, NL_CB_CUSTOM,
179 on_netlink_data, callback_parameter);
180 if (result) {
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700181 LOG(ERROR) << "nl_socket_modify_cb returned " << strerror(-result)
182 << " (" << result << ")";
Wade Guthrie0d438532012-05-18 14:18:50 -0700183 return false;
184 }
185 return true;
186}
187
188int NetlinkSocket::IgnoreSequenceCheck(struct nl_msg *ignored_msg,
189 void *ignored_arg) {
190 return NL_OK; // Proceed.
191}
192
193} // namespace shill.