2 * Copyright (C) 2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
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>.
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
18 #include <sys/socket.h>
19 #include <linux/netlink.h>
20 #include <linux/rtnetlink.h>
24 #include "kernel_netlink_shared.h"
28 typedef struct private_netlink_socket_t private_netlink_socket_t
;
31 * Private variables and functions of netlink_socket_t class.
33 struct private_netlink_socket_t
{
35 * public part of the netlink_socket_t object.
37 netlink_socket_t
public;
40 * mutex to lock access to netlink socket
42 pthread_mutex_t mutex
;
45 * current sequence number for netlink request
56 * Implementation of netlink_socket_t.send
58 static status_t
netlink_send(private_netlink_socket_t
*this, struct nlmsghdr
*in
,
59 struct nlmsghdr
**out
, size_t *out_len
)
62 struct sockaddr_nl addr
;
63 chunk_t result
= chunk_empty
, tmp
;
64 struct nlmsghdr
*msg
, peek
;
66 pthread_mutex_lock(&this->mutex
);
68 in
->nlmsg_seq
= ++this->seq
;
69 in
->nlmsg_pid
= getpid();
71 memset(&addr
, 0, sizeof(addr
));
72 addr
.nl_family
= AF_NETLINK
;
78 len
= sendto(this->socket
, in
, in
->nlmsg_len
, 0,
79 (struct sockaddr
*)&addr
, sizeof(addr
));
81 if (len
!= in
->nlmsg_len
)
85 /* interrupted, try again */
88 pthread_mutex_unlock(&this->mutex
);
89 DBG1(DBG_KNL
, "error sending to netlink socket: %s", strerror(errno
));
98 tmp
.len
= sizeof(buf
);
100 msg
= (struct nlmsghdr
*)tmp
.ptr
;
102 memset(&addr
, 0, sizeof(addr
));
103 addr
.nl_family
= AF_NETLINK
;
104 addr
.nl_pid
= getpid();
106 addr_len
= sizeof(addr
);
108 len
= recvfrom(this->socket
, tmp
.ptr
, tmp
.len
, 0,
109 (struct sockaddr
*)&addr
, &addr_len
);
115 DBG1(DBG_KNL
, "got interrupted");
116 /* interrupted, try again */
119 DBG1(DBG_KNL
, "error reading from netlink socket: %s", strerror(errno
));
120 pthread_mutex_unlock(&this->mutex
);
124 if (!NLMSG_OK(msg
, len
))
126 DBG1(DBG_KNL
, "received corrupted netlink message");
127 pthread_mutex_unlock(&this->mutex
);
131 if (msg
->nlmsg_seq
!= this->seq
)
133 DBG1(DBG_KNL
, "received invalid netlink sequence number");
134 if (msg
->nlmsg_seq
< this->seq
)
138 pthread_mutex_unlock(&this->mutex
);
144 result
.ptr
= realloc(result
.ptr
, result
.len
+ tmp
.len
);
145 memcpy(result
.ptr
+ result
.len
, tmp
.ptr
, tmp
.len
);
146 result
.len
+= tmp
.len
;
148 /* NLM_F_MULTI flag does not seem to be set correctly, we use sequence
149 * numbers to detect multi header messages */
150 len
= recvfrom(this->socket
, &peek
, sizeof(peek
), MSG_PEEK
| MSG_DONTWAIT
,
151 (struct sockaddr
*)&addr
, &addr_len
);
153 if (len
== sizeof(peek
) && peek
.nlmsg_seq
== this->seq
)
155 /* seems to be multipart */
161 *out_len
= result
.len
;
162 *out
= (struct nlmsghdr
*)result
.ptr
;
164 pthread_mutex_unlock(&this->mutex
);
170 * Implementation of netlink_socket_t.send_ack.
172 static status_t
netlink_send_ack(private_netlink_socket_t
*this, struct nlmsghdr
*in
)
174 struct nlmsghdr
*out
, *hdr
;
177 if (netlink_send(this, in
, &out
, &len
) != SUCCESS
)
182 while (NLMSG_OK(hdr
, len
))
184 switch (hdr
->nlmsg_type
)
188 struct nlmsgerr
* err
= (struct nlmsgerr
*)NLMSG_DATA(hdr
);
192 if (-err
->error
== EEXIST
)
193 { /* do not report existing routes */
197 DBG1(DBG_KNL
, "received netlink error: %s (%d)",
198 strerror(-err
->error
), -err
->error
);
206 hdr
= NLMSG_NEXT(hdr
, len
);
213 DBG1(DBG_KNL
, "netlink request not acknowledged");
219 * Implementation of netlink_socket_t.destroy.
221 static void destroy(private_netlink_socket_t
*this)
228 * Described in header.
230 netlink_socket_t
*netlink_socket_create(int protocol
) {
231 private_netlink_socket_t
*this = malloc_thing(private_netlink_socket_t
);
232 struct sockaddr_nl addr
;
234 /* public functions */
235 this->public.send
= (status_t(*)(netlink_socket_t
*,struct nlmsghdr
*, struct nlmsghdr
**, size_t*))netlink_send
;
236 this->public.send_ack
= (status_t(*)(netlink_socket_t
*,struct nlmsghdr
*))netlink_send_ack
;
237 this->public.destroy
= (void(*)(netlink_socket_t
*))destroy
;
239 /* private members */
241 pthread_mutex_init(&this->mutex
, NULL
);
243 memset(&addr
, 0, sizeof(addr
));
244 addr
.nl_family
= AF_NETLINK
;
246 this->socket
= socket(AF_NETLINK
, SOCK_RAW
, protocol
);
247 if (this->socket
<= 0)
249 charon
->kill(charon
, "unable to create netlink socket");
253 if (bind(this->socket
, (struct sockaddr
*)&addr
, sizeof(addr
)))
255 charon
->kill(charon
, "unable to bind netlink socket");
258 return &this->public;
262 * Described in header.
264 void netlink_add_attribute(struct nlmsghdr
*hdr
, int rta_type
, chunk_t data
,
269 if (NLMSG_ALIGN(hdr
->nlmsg_len
) + RTA_ALIGN(data
.len
) > buflen
)
271 DBG1(DBG_KNL
, "unable to add attribute, buffer too small");
275 rta
= (struct rtattr
*)(((char*)hdr
) + NLMSG_ALIGN(hdr
->nlmsg_len
));
276 rta
->rta_type
= rta_type
;
277 rta
->rta_len
= RTA_LENGTH(data
.len
);
278 memcpy(RTA_DATA(rta
), data
.ptr
, data
.len
);
279 hdr
->nlmsg_len
= NLMSG_ALIGN(hdr
->nlmsg_len
) + rta
->rta_len
;