Creating netdev
[platform/core/security/vasum.git] / common / netlink / netlink.cpp
1 /*
2  *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Mateusz Malicki <m.malicki2@samsung.com>
5  *
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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
17  */
18
19 /**
20  * @file
21  * @author  Mateusz Malicki (m.malicki2@samsung.com)
22  * @brief   Netlink class definition
23  */
24
25 #include "config.hpp"
26 #include "netlink.hpp"
27 #include "utils.hpp"
28 #include "base-exception.hpp"
29
30 #include <logger/logger.hpp>
31 #include <cassert>
32 #include <algorithm>
33 #include <sys/socket.h>
34 #include <unistd.h>
35 #include <linux/netlink.h>
36
37 namespace vasum {
38
39 namespace {
40
41 template<class T>
42 T make_clean()
43 {
44     static_assert(std::is_pod<T>::value, "make_clean require trivial and standard-layout");
45     T value;
46     std::fill_n(reinterpret_cast<char*>(&value), sizeof(value), 0);
47     return value;
48 }
49
50 } // namespace
51
52 Netlink::Netlink() : mFd(-1)
53 {
54 }
55
56 Netlink::~Netlink()
57 {
58     close();
59 }
60
61 void Netlink::open()
62 {
63     assert(mFd == -1);
64     mFd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
65     if (mFd == -1) {
66         LOGE("Can't open socket (" << getSystemErrorMessage() << ")");
67         throw VasumException("Can't open netlink connection");
68     }
69
70     sockaddr_nl local = make_clean<sockaddr_nl>();
71     local.nl_family = AF_NETLINK;
72
73     if (bind(mFd, (struct sockaddr *)&local, sizeof(local)) < 0) {
74         int err = errno;
75         close();
76         LOGE("Can't bind to socket (" << getSystemErrorMessage(err) << ")");
77         throw VasumException("Can't set up netlink connection");
78     }
79 }
80
81 void Netlink::close()
82 {
83     if (mFd != -1) {
84         ::close(mFd);
85         mFd = -1;
86     }
87 }
88
89 void Netlink::send(const nlmsghdr *nlmsg)
90 {
91     msghdr msg = make_clean<msghdr>();
92     sockaddr_nl nladdr = make_clean<sockaddr_nl>();
93     iovec iov = make_clean<iovec>();
94
95     iov.iov_base = (void *)nlmsg;
96     iov.iov_len = nlmsg->nlmsg_len;
97     msg.msg_name = &nladdr;
98     msg.msg_namelen = sizeof(nladdr);
99     msg.msg_iov = &iov;
100     msg.msg_iovlen = 1;
101     nladdr.nl_family = AF_NETLINK;
102
103     int ret = sendmsg(mFd, &msg, 0);
104     if (ret < 0) {
105         LOGE("Can't send message (" << getSystemErrorMessage() << ")");
106         throw VasumException("Can't send netlink message");
107     }
108 }
109
110 int Netlink::rcv(nlmsghdr *answer)
111 {
112     //TODO: Handle too small buffer situation (buffer resizing)
113     msghdr msg = make_clean<msghdr>();
114     sockaddr_nl nladdr = make_clean<sockaddr_nl>();
115     iovec iov = make_clean<iovec>();
116
117     iov.iov_base = answer;
118     iov.iov_len = answer->nlmsg_len;
119     msg.msg_name = &nladdr;
120     msg.msg_namelen = sizeof(nladdr);
121     msg.msg_iov = &iov;
122     msg.msg_iovlen = 1;
123     nladdr.nl_family = AF_NETLINK;
124
125     int ret = recvmsg(mFd, &msg, 0);
126     if (ret < 0) {
127         LOGE("Can't receive message (" + getSystemErrorMessage() + ")");
128         throw VasumException("Can't receive netlink message");
129     }
130     if (ret == 0) {
131         LOGE("Peer has performed an orderly shutdown");
132         throw VasumException("Can't receive netlink message");
133     }
134     if (msg.msg_flags & MSG_TRUNC) {
135         LOGE("Can't receive message (" + getSystemErrorMessage(EMSGSIZE) + ")");
136         throw VasumException("Can't receive netlink message");
137     }
138     if (msg.msg_flags & MSG_ERRQUEUE) {
139         LOGE("No data was received but an extended error");
140         throw VasumException("Can't receive netlink message");
141     }
142     if (msg.msg_flags & MSG_OOB) {
143         LOGE("Internal error (expedited or out-of-band data were received)");
144         throw VasumException("Can't receive netlink message");
145     }
146     if (msg.msg_flags & (MSG_EOR | MSG_CTRUNC)) {
147         assert(!"This should not happen!");
148         LOGE("Internal error (" << std::to_string(msg.msg_flags) << ")");
149         throw VasumException("Internal error while recaiving netlink message");
150     }
151
152     return ret;
153 }
154
155 } //namespace vasum