1 /*
2 * Copyright 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "netlink_socket.h"
18
19 #include "log.h"
20 #include "netlink_message.h"
21
22 #include <netlink/genl/ctrl.h>
23 #include <netlink/genl/genl.h>
24 #include <netlink/netlink.h>
25
NetlinkSocket()26 NetlinkSocket::NetlinkSocket() {
27 }
28
~NetlinkSocket()29 NetlinkSocket::~NetlinkSocket() {
30 if (mSocket) {
31 nl_socket_free(mSocket);
32 mSocket = nullptr;
33 mCallback = nullptr;
34 }
35 }
36
init()37 Result NetlinkSocket::init() {
38 if (mSocket || mCallback) {
39 return Result::error("Netlink socket already initialized");
40 }
41 mCallback = nl_cb_alloc(NL_CB_CUSTOM);
42 if (!mCallback) {
43 return Result::error("Netlink socket failed to allocate callbacks");
44 }
45 mSocket = nl_socket_alloc_cb(mCallback);
46 if (!mSocket) {
47 return Result::error("Failed to allocate netlink socket");
48 }
49 return Result::success();
50 }
51
setBufferSizes(int rxBufferSize,int txBufferSize)52 Result NetlinkSocket::setBufferSizes(int rxBufferSize, int txBufferSize) {
53 int res = nl_socket_set_buffer_size(mSocket, rxBufferSize, txBufferSize);
54 if (res != 0) {
55 return Result::error("Failed to set buffer sizes: %s",
56 nl_geterror(res));
57 }
58 return Result::success();
59 }
60
setOnMsgInCallback(int (* callback)(struct nl_msg *,void *),void * context)61 Result NetlinkSocket::setOnMsgInCallback(int (*callback)(struct nl_msg*, void*),
62 void* context) {
63 if (nl_cb_set(mCallback, NL_CB_MSG_IN, NL_CB_CUSTOM, callback, context)) {
64 return Result::error("Failed to set OnMsgIn callback");
65 }
66 return Result::success();
67 }
68
setOnMsgOutCallback(int (* callback)(struct nl_msg *,void *),void * context)69 Result NetlinkSocket::setOnMsgOutCallback(int (*callback)(struct nl_msg*,
70 void*),
71 void* context) {
72 if (nl_cb_set(mCallback, NL_CB_MSG_OUT, NL_CB_CUSTOM, callback, context)) {
73 return Result::error("Failed to set OnMsgOut callback");
74 }
75 return Result::success();
76 }
77
setOnSeqCheckCallback(int (* callback)(struct nl_msg *,void *),void * context)78 Result NetlinkSocket::setOnSeqCheckCallback(int (*callback)(struct nl_msg*,
79 void*),
80 void* context) {
81 if (nl_cb_set(mCallback, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
82 callback, context)) {
83 return Result::error("Failed to set OnSeqCheck callback");
84 }
85 return Result::success();
86 }
87
setOnAckCallback(int (* callback)(struct nl_msg *,void *),void * context)88 Result NetlinkSocket::setOnAckCallback(int (*callback)(struct nl_msg*, void*),
89 void* context) {
90 if (nl_cb_set(mCallback, NL_CB_ACK, NL_CB_CUSTOM, callback, context)) {
91 return Result::error("Failed to set OnAck callback");
92 }
93 return Result::success();
94 }
95
setOnErrorCallback(int (* callback)(struct sockaddr_nl *,struct nlmsgerr *,void *),void * context)96 Result NetlinkSocket::setOnErrorCallback(int (*callback)(struct sockaddr_nl*,
97 struct nlmsgerr*,
98 void*),
99 void* context) {
100 if (nl_cb_err(mCallback, NL_CB_CUSTOM, callback, context)) {
101 return Result::error("Failed to set OnError callback");
102 }
103 return Result::success();
104 }
105
connectGeneric()106 Result NetlinkSocket::connectGeneric() {
107 int status = genl_connect(mSocket);
108 if (status < 0) {
109 return Result::error("WifiNetlinkForwarder socket connect failed: %d",
110 status);
111 }
112 return Result::success();
113 }
114
resolveNetlinkFamily(const char * familyName)115 int NetlinkSocket::resolveNetlinkFamily(const char* familyName) {
116 return genl_ctrl_resolve(mSocket, familyName);
117 }
118
send(NetlinkMessage & message)119 bool NetlinkSocket::send(NetlinkMessage& message) {
120 int status = nl_send_auto(mSocket, message.get()) >= 0;
121 if (status < 0) {
122 ALOGE("Failed to send on netlink socket: %s", nl_geterror(status));
123 return false;
124 }
125 return true;
126 }
127
receive()128 bool NetlinkSocket::receive() {
129 int res = nl_recvmsgs_default(mSocket);
130 if (res != 0) {
131 ALOGE("Failed to receive messages on netlink socket: %s",
132 nl_geterror(res));
133 return false;
134 }
135 return true;
136 }
137
getFd() const138 int NetlinkSocket::getFd() const {
139 if (!mSocket) {
140 return -1;
141 }
142 return nl_socket_get_fd(mSocket);
143 }
144