2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Mateusz Malicki <m.malicki2@samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
21 * @author Mateusz Malicki (m.malicki2@samsung.com)
22 * @brief Netlink class definition
26 #include "netlink.hpp"
28 #include "utils/exception.hpp"
29 #include "utils/make-clean.hpp"
30 #include "utils/environment.hpp"
31 #include "base-exception.hpp"
32 #include "logger/logger.hpp"
36 #include <sys/socket.h>
38 #include <linux/netlink.h>
41 #define PAGE_SIZE 4096
44 using namespace utils;
45 using namespace vasum;
49 const int NLMSG_RCV_GOOD_SIZE = 2*PAGE_SIZE;
51 int vsm_recvmsg(int fd, struct msghdr *msg, int flags)
53 int ret = recvmsg(fd, msg, flags);
55 LOGE("Can't receive message: " + getSystemErrorMessage());
56 } else if (ret == 0 && msg->msg_iov && msg->msg_iov->iov_len > 0) {
57 LOGE("Peer has performed an orderly shutdown");
58 } else if (msg->msg_flags & MSG_TRUNC) {
59 LOGE("Can't receive message: " + getSystemErrorMessage(EMSGSIZE));
60 } else if (msg->msg_flags & MSG_ERRQUEUE) {
61 LOGE("No data was received but an extended error");
62 } else if (msg->msg_flags & MSG_OOB) {
63 LOGE("Internal error (expedited or out-of-band data were received)");
64 } else if (msg->msg_flags & MSG_CTRUNC) {
65 LOGE("Some control data were discarded");
66 } else if (msg->msg_flags & MSG_EOR) {
67 LOGE("End-of-record");
72 throw VasumException("Can't receive netlink message");
75 void vsm_sendmsg(int fd, const struct msghdr *msg, int flags)
77 int ret = sendmsg(fd, msg, flags);
79 LOGE("Can't send message: " << getSystemErrorMessage());
80 throw VasumException("Can't send netlink message");
89 Netlink::Netlink() : mFd(-1)
98 void Netlink::open(int netNsPid)
100 auto fdFactory = []{ return socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); };
103 if (netNsPid == 0 || netNsPid == getpid()) {
106 LOGE("Can't open socket: " << getSystemErrorMessage());
109 mFd = utils::passNamespacedFd(netNsPid, CLONE_NEWNET, fdFactory);
112 throw VasumException("Can't open netlink connection");
115 sockaddr_nl local = utils::make_clean<sockaddr_nl>();
116 local.nl_family = AF_NETLINK;
118 if (bind(mFd, (struct sockaddr *)&local, sizeof(local)) < 0) {
121 LOGE("Can't bind to socket: " << getSystemErrorMessage(err));
122 throw VasumException("Can't set up netlink connection");
126 void Netlink::close()
134 unsigned int Netlink::send(const void *nlmsg)
136 msghdr msg = utils::make_clean<msghdr>();
137 sockaddr_nl nladdr = utils::make_clean<sockaddr_nl>();
138 iovec iov = utils::make_clean<iovec>();
140 iov.iov_base = const_cast<void*>(nlmsg);
141 iov.iov_len = reinterpret_cast<const nlmsghdr*>(nlmsg)->nlmsg_len;
142 msg.msg_name = &nladdr;
143 msg.msg_namelen = sizeof(nladdr);
146 nladdr.nl_family = AF_NETLINK;
148 vsm_sendmsg(mFd, &msg, 0);
149 return reinterpret_cast<const nlmsghdr*>(nlmsg)->nlmsg_seq;
152 std::unique_ptr<std::vector<char>> Netlink::rcv(unsigned int nlmsgSeq)
154 std::unique_ptr<std::vector<char>> buf(new std::vector<char>());
156 msghdr msg = utils::make_clean<msghdr>();
157 sockaddr_nl nladdr = utils::make_clean<sockaddr_nl>();
158 iovec iov = utils::make_clean<iovec>();
160 msg.msg_name = &nladdr;
161 msg.msg_namelen = sizeof(nladdr);
164 nladdr.nl_family = AF_NETLINK;
167 nlmsghdr* lastOk = NULL;
170 buf->resize(offset + NLMSG_RCV_GOOD_SIZE);
171 answer = reinterpret_cast<nlmsghdr*>(buf->data() + offset);
172 iov.iov_base = answer;
173 iov.iov_len = buf->size() - offset;
174 unsigned int ret = vsm_recvmsg(mFd, &msg, 0);
175 for (unsigned int len = ret; NLMSG_OK(answer, len); answer = NLMSG_NEXT(answer, len)) {
177 if (answer->nlmsg_type == NLMSG_ERROR) {
178 // It is NACK/ACK message
179 nlmsgerr *err = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(answer));
180 if (answer->nlmsg_seq != nlmsgSeq) {
181 throw VasumException("Sending failed: answer message was mismatched");
184 throw VasumException("Sending failed: " + getSystemErrorMessage(-err->error));
186 } else if (answer->nlmsg_type == NLMSG_OVERRUN) {
187 throw VasumException("Sending failed: data lost");
190 if (lastOk == NULL) {
191 LOGE("Something went terribly wrong. Check vsm_recvmsg function");
192 throw VasumException("Can't receive data from system");
194 offset += NLMSG_ALIGN(ret);
195 } while (lastOk->nlmsg_type != NLMSG_DONE && lastOk->nlmsg_flags & NLM_F_MULTI);
201 } //namespace netlink