Removed strayed code fragment
[strongswan.git] / src / charon / plugins / kernel_netlink / kernel_netlink_shared.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <sys/socket.h>
17 #include <linux/netlink.h>
18 #include <linux/rtnetlink.h>
19 #include <errno.h>
20 #include <unistd.h>
21
22 #include "kernel_netlink_shared.h"
23
24 #include <daemon.h>
25 #include <threading/mutex.h>
26
27 typedef struct private_netlink_socket_t private_netlink_socket_t;
28
29 /**
30 * Private variables and functions of netlink_socket_t class.
31 */
32 struct private_netlink_socket_t {
33 /**
34 * public part of the netlink_socket_t object.
35 */
36 netlink_socket_t public;
37
38 /**
39 * mutex to lock access to netlink socket
40 */
41 mutex_t *mutex;
42
43 /**
44 * current sequence number for netlink request
45 */
46 int seq;
47
48 /**
49 * netlink socket protocol
50 */
51 int protocol;
52
53 /**
54 * netlink socket
55 */
56 int socket;
57 };
58
59 /**
60 * Imported from kernel_netlink_ipsec.c
61 */
62 extern enum_name_t *xfrm_msg_names;
63
64 /**
65 * Implementation of netlink_socket_t.send
66 */
67 static status_t netlink_send(private_netlink_socket_t *this, struct nlmsghdr *in,
68 struct nlmsghdr **out, size_t *out_len)
69 {
70 int len, addr_len;
71 struct sockaddr_nl addr;
72 chunk_t result = chunk_empty, tmp;
73 struct nlmsghdr *msg, peek;
74
75 this->mutex->lock(this->mutex);
76
77 in->nlmsg_seq = ++this->seq;
78 in->nlmsg_pid = getpid();
79
80 memset(&addr, 0, sizeof(addr));
81 addr.nl_family = AF_NETLINK;
82 addr.nl_pid = 0;
83 addr.nl_groups = 0;
84
85 if (this->protocol == NETLINK_XFRM)
86 {
87 chunk_t in_chunk = { (u_char*)in, in->nlmsg_len };
88
89 DBG3(DBG_KNL, "sending %N: %B", xfrm_msg_names, in->nlmsg_type, &in_chunk);
90 }
91
92 while (TRUE)
93 {
94 len = sendto(this->socket, in, in->nlmsg_len, 0,
95 (struct sockaddr*)&addr, sizeof(addr));
96
97 if (len != in->nlmsg_len)
98 {
99 if (errno == EINTR)
100 {
101 /* interrupted, try again */
102 continue;
103 }
104 this->mutex->unlock(this->mutex);
105 DBG1(DBG_KNL, "error sending to netlink socket: %s", strerror(errno));
106 return FAILED;
107 }
108 break;
109 }
110
111 while (TRUE)
112 {
113 char buf[4096];
114 tmp.len = sizeof(buf);
115 tmp.ptr = buf;
116 msg = (struct nlmsghdr*)tmp.ptr;
117
118 memset(&addr, 0, sizeof(addr));
119 addr.nl_family = AF_NETLINK;
120 addr.nl_pid = getpid();
121 addr.nl_groups = 0;
122 addr_len = sizeof(addr);
123
124 len = recvfrom(this->socket, tmp.ptr, tmp.len, 0,
125 (struct sockaddr*)&addr, &addr_len);
126
127 if (len < 0)
128 {
129 if (errno == EINTR)
130 {
131 DBG1(DBG_KNL, "got interrupted");
132 /* interrupted, try again */
133 continue;
134 }
135 DBG1(DBG_KNL, "error reading from netlink socket: %s", strerror(errno));
136 this->mutex->unlock(this->mutex);
137 free(result.ptr);
138 return FAILED;
139 }
140 if (!NLMSG_OK(msg, len))
141 {
142 DBG1(DBG_KNL, "received corrupted netlink message");
143 this->mutex->unlock(this->mutex);
144 free(result.ptr);
145 return FAILED;
146 }
147 if (msg->nlmsg_seq != this->seq)
148 {
149 DBG1(DBG_KNL, "received invalid netlink sequence number");
150 if (msg->nlmsg_seq < this->seq)
151 {
152 continue;
153 }
154 this->mutex->unlock(this->mutex);
155 free(result.ptr);
156 return FAILED;
157 }
158
159 tmp.len = len;
160 result.ptr = realloc(result.ptr, result.len + tmp.len);
161 memcpy(result.ptr + result.len, tmp.ptr, tmp.len);
162 result.len += tmp.len;
163
164 /* NLM_F_MULTI flag does not seem to be set correctly, we use sequence
165 * numbers to detect multi header messages */
166 len = recvfrom(this->socket, &peek, sizeof(peek), MSG_PEEK | MSG_DONTWAIT,
167 (struct sockaddr*)&addr, &addr_len);
168
169 if (len == sizeof(peek) && peek.nlmsg_seq == this->seq)
170 {
171 /* seems to be multipart */
172 continue;
173 }
174 break;
175 }
176
177 *out_len = result.len;
178 *out = (struct nlmsghdr*)result.ptr;
179
180 this->mutex->unlock(this->mutex);
181
182 return SUCCESS;
183 }
184
185 /**
186 * Implementation of netlink_socket_t.send_ack.
187 */
188 static status_t netlink_send_ack(private_netlink_socket_t *this, struct nlmsghdr *in)
189 {
190 struct nlmsghdr *out, *hdr;
191 size_t len;
192
193 if (netlink_send(this, in, &out, &len) != SUCCESS)
194 {
195 return FAILED;
196 }
197 hdr = out;
198 while (NLMSG_OK(hdr, len))
199 {
200 switch (hdr->nlmsg_type)
201 {
202 case NLMSG_ERROR:
203 {
204 struct nlmsgerr* err = (struct nlmsgerr*)NLMSG_DATA(hdr);
205
206 if (err->error)
207 {
208 if (-err->error == EEXIST)
209 { /* do not report existing routes */
210 free(out);
211 return ALREADY_DONE;
212 }
213 DBG1(DBG_KNL, "received netlink error: %s (%d)",
214 strerror(-err->error), -err->error);
215 free(out);
216 return FAILED;
217 }
218 free(out);
219 return SUCCESS;
220 }
221 default:
222 hdr = NLMSG_NEXT(hdr, len);
223 continue;
224 case NLMSG_DONE:
225 break;
226 }
227 break;
228 }
229 DBG1(DBG_KNL, "netlink request not acknowledged");
230 free(out);
231 return FAILED;
232 }
233
234 /**
235 * Implementation of netlink_socket_t.destroy.
236 */
237 static void destroy(private_netlink_socket_t *this)
238 {
239 if (this->socket > 0)
240 {
241 close(this->socket);
242 }
243 this->mutex->destroy(this->mutex);
244 free(this);
245 }
246
247 /**
248 * Described in header.
249 */
250 netlink_socket_t *netlink_socket_create(int protocol)
251 {
252 private_netlink_socket_t *this = malloc_thing(private_netlink_socket_t);
253 struct sockaddr_nl addr;
254
255 /* public functions */
256 this->public.send = (status_t(*)(netlink_socket_t*,struct nlmsghdr*, struct nlmsghdr**, size_t*))netlink_send;
257 this->public.send_ack = (status_t(*)(netlink_socket_t*,struct nlmsghdr*))netlink_send_ack;
258 this->public.destroy = (void(*)(netlink_socket_t*))destroy;
259
260 /* private members */
261 this->seq = 200;
262 this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
263
264 memset(&addr, 0, sizeof(addr));
265 addr.nl_family = AF_NETLINK;
266
267 this->protocol = protocol;
268 this->socket = socket(AF_NETLINK, SOCK_RAW, protocol);
269 if (this->socket < 0)
270 {
271 DBG1(DBG_KNL, "unable to create netlink socket");
272 destroy(this);
273 return NULL;
274 }
275
276 addr.nl_groups = 0;
277 if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)))
278 {
279 DBG1(DBG_KNL, "unable to bind netlink socket");
280 destroy(this);
281 return NULL;
282 }
283
284 return &this->public;
285 }
286
287 /**
288 * Described in header.
289 */
290 void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
291 size_t buflen)
292 {
293 struct rtattr *rta;
294
295 if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(data.len) > buflen)
296 {
297 DBG1(DBG_KNL, "unable to add attribute, buffer too small");
298 return;
299 }
300
301 rta = (struct rtattr*)(((char*)hdr) + NLMSG_ALIGN(hdr->nlmsg_len));
302 rta->rta_type = rta_type;
303 rta->rta_len = RTA_LENGTH(data.len);
304 memcpy(RTA_DATA(rta), data.ptr, data.len);
305 hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
306 }