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