blob: 71082755d7b1435ec0a94253e019dee3c16fffca [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>
29
30#include <net/if.h>
31#include <netlink/attr.h>
32#include <netlink/genl/ctrl.h>
33#include <netlink/genl/family.h>
34#include <netlink/genl/genl.h>
35#include <netlink/msg.h>
36#include <netlink/netlink.h>
37
38#include <iomanip>
39
40#include <base/logging.h>
41
42#include "shill/kernel_bound_nlmessage.h"
43#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
116bool NetlinkSocket::DisableSequenceChecking() {
117 if (!nl_sock_) {
118 LOG(ERROR) << "NULL socket";
119 return false;
120 }
121
122 // NOTE: can't use nl_socket_disable_seq_check(); it's not in this version
123 // of the library.
124 int result = nl_socket_modify_cb(nl_sock_, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
125 NetlinkSocket::IgnoreSequenceCheck, NULL);
126 if (result) {
127 LOG(ERROR) << "Failed call to nl_socket_modify_cb: " << result;
128 return false;
129 }
130
131 return true;
132}
133
134int NetlinkSocket::GetFd() const {
135 if (!nl_sock_) {
136 LOG(ERROR) << "NULL socket";
137 return -1;
138 }
139 return nl_socket_get_fd(nl_sock_);
140}
141
142bool NetlinkSocket::GetMessages() {
143 // TODO(wdg): make this non-blocking.
144 // Blocks until a message is available. When that happens, the message is
145 // read and passed to the default callback (i.e., the one set with
146 // NetlinkSocket::SetNetlinkCallback).
147 int result = nl_recvmsgs_default(nl_sock_);
148 if (result < 0) {
149 LOG(ERROR) << "Failed call to nl_recvmsgs_default: " << result;
150 return false;
151 }
152 return true;
153}
154
155bool NetlinkSocket::GetMessagesUsingCallback(
156 NetlinkSocket::Callback *on_netlink_data) {
157 if (!on_netlink_data || !on_netlink_data->cb_)
158 return GetMessages(); // Default to generic callback.
159
160 int result = nl_recvmsgs(nl_sock_, on_netlink_data->cb_);
161 if (result < 0) {
162 LOG(ERROR) << "Failed call to nl_recvmsgs: " << result;
163 return false;
164 }
165 return true;
166}
167
168bool NetlinkSocket::SetNetlinkCallback(nl_recvmsg_msg_cb_t on_netlink_data,
169 void *callback_parameter) {
170 if (!nl_sock_) {
171 LOG(ERROR) << "NULL socket";
172 return false;
173 }
174
175 int result = nl_socket_modify_cb(nl_sock_, NL_CB_VALID, NL_CB_CUSTOM,
176 on_netlink_data, callback_parameter);
177 if (result) {
178 LOG(ERROR) << "nl_socket_modify_cb returned " << result;
179 return false;
180 }
181 return true;
182}
183
184int NetlinkSocket::IgnoreSequenceCheck(struct nl_msg *ignored_msg,
185 void *ignored_arg) {
186 return NL_OK; // Proceed.
187}
188
189} // namespace shill.