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 message class definition
26 #include "netlink-message.hpp"
27 #include "netlink.hpp"
28 #include "base-exception.hpp"
29 #include "logger/logger.hpp"
37 #include <linux/netlink.h>
38 #include <linux/rtnetlink.h>
39 #include <sys/socket.h>
44 inline const rtattr* asAttr(const void* data) { return reinterpret_cast<const rtattr*>(data); }
45 inline const nlmsghdr* asHdr(const void* data) { return reinterpret_cast<const nlmsghdr*>(data); }
46 inline rtattr* asAttr(void* data) { return reinterpret_cast<rtattr*>(data); }
47 inline nlmsghdr* asHdr(void* data) { return reinterpret_cast<nlmsghdr*>(data); }
48 inline char* NLMSG_TAIL(nlmsghdr* nmsg)
50 return reinterpret_cast<char*>(nmsg) + NLMSG_ALIGN(nmsg->nlmsg_len);
58 NetlinkResponse send(const NetlinkMessage& msg)
63 NetlinkMessage::NetlinkMessage(uint16_t type, uint16_t flags)
65 static std::atomic<uint32_t> seq(0);
66 mNlmsg.resize(NLMSG_HDRLEN, 0);
67 hdr().nlmsg_len = NLMSG_HDRLEN;
68 hdr().nlmsg_flags = flags | NLM_F_ACK;
69 hdr().nlmsg_type = type;
70 hdr().nlmsg_seq = ++seq;
71 hdr().nlmsg_pid = getpid();
74 NetlinkMessage& NetlinkMessage::beginNested(int ifla)
76 auto offset = std::distance(reinterpret_cast<char*>(&hdr()), NLMSG_TAIL(&hdr()));
82 NetlinkMessage& NetlinkMessage::endNested()
84 assert(!mNested.empty());
85 rtattr* nest = asAttr(reinterpret_cast<char*>(&hdr()) + mNested.top());
86 nest->rta_len = std::distance(reinterpret_cast<char*>(nest), NLMSG_TAIL(&hdr()));
91 NetlinkMessage& NetlinkMessage::put(int ifla, const std::string& value)
93 return put(ifla, value.c_str(), value.size() + 1);
96 NetlinkMessage& NetlinkMessage::put(int ifla, const void* data, int len)
99 size_t rtalen = RTA_LENGTH(len);
100 int newLen = NLMSG_ALIGN(hdr().nlmsg_len) + RTA_ALIGN(rtalen);
102 setMinCapacity(newLen);
103 rta = asAttr(NLMSG_TAIL(&hdr()));
104 rta->rta_type = ifla;
105 rta->rta_len = rtalen;
106 memcpy(RTA_DATA(rta), data, len);
107 hdr().nlmsg_len = newLen;
111 NetlinkMessage& NetlinkMessage::put(const void* data, int len)
113 setMinCapacity(hdr().nlmsg_len + len);
114 memcpy((reinterpret_cast<char*>(&hdr()) + hdr().nlmsg_len), data, len);
115 hdr().nlmsg_len += len;
119 nlmsghdr& NetlinkMessage::hdr() {
120 return *asHdr(mNlmsg.data());
123 const nlmsghdr& NetlinkMessage::hdr() const {
124 return *asHdr(mNlmsg.data());
127 void NetlinkMessage::setMinCapacity(unsigned int size)
129 if (mNlmsg.size() < size) {
130 mNlmsg.resize(size, 0);
134 NetlinkResponse::NetlinkResponse(std::unique_ptr<std::vector<char>>&& message)
135 : mNlmsg(std::move(message))
136 , mNlmsgHdr(asHdr(mNlmsg.get()->data()))
137 , mPosition(NLMSG_HDRLEN)
141 bool NetlinkResponse::hasMessage() const
143 unsigned int tail = size() - getHdrPosition();
144 bool hasHeader = NLMSG_OK(mNlmsgHdr, tail);
148 //Check if isn't ACK message
149 return NLMSG_PAYLOAD(mNlmsgHdr,0) > sizeof(uint32_t);
152 int NetlinkResponse::getMessageType() const
154 return mNlmsgHdr->nlmsg_type;
157 void NetlinkResponse::fetchNextMessage()
159 if (mNlmsgHdr->nlmsg_type == NLMSG_DONE) {
160 throw VasumException("There is no next message");
162 int tail = size() - mPosition;
163 mNlmsgHdr = NLMSG_NEXT(mNlmsgHdr, tail);
164 mPosition = getHdrPosition() + NLMSG_HDRLEN;
167 bool NetlinkResponse::hasAttribute() const
169 assert(mPosition >= getHdrPosition());
170 int tail = mNlmsgHdr->nlmsg_len - (mPosition - getHdrPosition());
171 return RTA_OK(asAttr(get(0)), tail);
174 bool NetlinkResponse::isNestedAttribute() const
176 return asAttr(get(RTA_LENGTH(0)))->rta_len == RTA_LENGTH(0);
179 void NetlinkResponse::skipAttribute()
181 const rtattr *rta = asAttr(get(RTA_LENGTH(0)));
182 if (size() < mPosition + RTA_ALIGN(rta->rta_len)) {
183 LOGE("Skipping out of buffer:"
184 << " to: " << mPosition + RTA_ALIGN(rta->rta_len)
185 << ", buf size: " << size());
186 throw VasumException("Skipping out of buffer");
188 seek(RTA_ALIGN(rta->rta_len));
191 NetlinkResponse& NetlinkResponse::openNested(int ifla)
193 const rtattr *rta = asAttr(get(RTA_LENGTH(0)));
194 if (rta->rta_type == ifla) {
195 LOGE("Wrong attribute type, expected: " << ifla << ", got: " << rta->rta_type);
196 throw VasumException("Wrong attribute type");
204 NetlinkResponse& NetlinkResponse::closeNested()
206 assert(!mNested.empty());
207 int pos = mNested.top();
208 const rtattr *rta = asAttr(mNlmsg->data() + pos);
209 if (rta->rta_len != mPosition - pos) {
210 LOGE("There is no nested attribute end. Did you read all attributes (read: "
211 << mPosition - pos << ", length: " << rta->rta_len);
212 throw VasumException("There is no nested attribute end");
219 NetlinkResponse& NetlinkResponse::fetch(int ifla, std::string& value, int maxSize)
221 value = std::string(get(ifla, maxSize));
226 const char* NetlinkResponse::get(int ifla, int len) const
228 const rtattr *rta = asAttr(get(RTA_LENGTH(len < 0 ? 0 : len)));
229 if (rta->rta_type != ifla) {
230 LOGE("Wrong attribute type, expected:" << ifla << ", got: " << rta->rta_type);
231 throw VasumException("Wrong attribute type");
233 if (len >= 0 && rta->rta_len != RTA_LENGTH(len)) {
234 LOGE("Wrong attribute length, expected: " << rta->rta_len << ", got " << len);
235 throw VasumException("Wrong attribute length");
237 return reinterpret_cast<const char*>(RTA_DATA(get(rta->rta_len)));
240 const char* NetlinkResponse::get(int len) const
242 if (size() < mPosition + len) {
243 LOGE("Read out of buffer:"
244 << " from: " << mPosition + len
245 << ", buf size: " << size());
246 throw VasumException("Read out of buffer");
248 return mNlmsg->data() + mPosition;
251 NetlinkResponse& NetlinkResponse::fetch(int ifla, char* data, int len)
253 std::copy_n(get(ifla, len), len, data);
258 NetlinkResponse& NetlinkResponse::fetch(char* data, int len)
260 std::copy_n(get(len), len, data);
265 int NetlinkResponse::getAttributeType() const
267 return asAttr(get(RTA_LENGTH(0)))->rta_type;
270 NetlinkResponse& NetlinkResponse::seek(int len)
272 if (size() < mPosition + len) {
273 throw VasumException("Skipping out of buffer");
279 int NetlinkResponse::size() const
281 return mNlmsg->size();
284 inline int NetlinkResponse::getHdrPosition() const
286 return std::distance(reinterpret_cast<const char*>(mNlmsg->data()),
287 reinterpret_cast<const char*>(mNlmsgHdr));
290 NetlinkResponse send(const NetlinkMessage& msg, int pid)
292 assert(msg.hdr().nlmsg_flags & NLM_F_ACK);
294 std::unique_ptr<std::vector<char>> data;
299 data = nl.rcv(msg.hdr().nlmsg_seq);
300 } catch (const std::exception& ex) {
301 LOGE("Sending failed (" << ex.what() << ")");
306 return NetlinkResponse(std::move(data));
309 } // namespace netlink