xref: /aosp_15_r20/external/ethtool/libmnl/src/socket.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1 /*
2  * (C) 2008-2010 by Pablo Neira Ayuso <[email protected]>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation; either version 2.1 of the License, or
7  * (at your option) any later version.
8  */
9 
10 #include <libmnl/libmnl.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <time.h>
16 #include <errno.h>
17 #include "internal.h"
18 
19 /**
20  * \mainpage
21  *
22  * libmnl is a minimalistic user-space library oriented to Netlink developers.
23  * There are a lot of common tasks in parsing, validating, constructing of
24  * both the Netlink header and TLVs that are repetitive and easy to get wrong.
25  * This library aims to provide simple helpers that allows you to avoid
26  * re-inventing the wheel in common Netlink tasks.
27  *
28  * \verbatim
29 "Simplify, simplify" -- Henry David Thoureau. Walden (1854)
30 \endverbatim
31  *
32  * The acronym libmnl stands for LIBrary Minimalistic NetLink.
33  *
34  * libmnl homepage is:
35  *      http://www.netfilter.org/projects/libmnl/
36  *
37  * \section features Main Features
38  * - Small: the shared library requires around 30KB for an x86-based computer.
39  * - Simple: this library avoids complex abstractions that tend to hide Netlink
40  *   details. It avoids elaborated object-oriented infrastructure and complex
41  *   callback-based workflow.
42  * - Easy to use: the library simplifies the work for Netlink-wise developers.
43  *   It provides functions to make socket handling, message building,
44  *   validating, parsing and sequence tracking, easier.
45  * - Easy to re-use: you can use this library to build your own abstraction
46  *   layer upon this library, if you want to provide another library that
47  *   hides Netlink details to your users.
48  * - Decoupling: the interdependency of the main bricks that compose this
49  *   library is reduced, i.e. the library provides many helpers, but the
50  *   programmer is not forced to use them.
51  *
52  * \section licensing Licensing terms
53  * This library is released under the LGPLv2.1 or any later (at your option).
54  *
55  * \section Dependencies
56  * You have to install the Linux kernel headers that you want to use to develop
57  * your application. Moreover, this library requires that you have some basics
58  * on Netlink.
59  *
60  * \section scm Git Tree
61  * The current development version of libmnl can be accessed at:
62  * https://git.netfilter.org/libmnl/
63  *
64  * \section using Using libmnl
65  * You can access several example files under examples/ in the libmnl source
66  * code tree.
67  */
68 
69 struct mnl_socket {
70 	int 			fd;
71 	struct sockaddr_nl	addr;
72 };
73 
74 /**
75  * \defgroup socket Netlink socket helpers
76  * @{
77  */
78 
79 /**
80  * mnl_socket_get_fd - obtain file descriptor from netlink socket
81  * \param nl netlink socket obtained via mnl_socket_open()
82  *
83  * This function returns the file descriptor of a given netlink socket.
84  */
mnl_socket_get_fd(const struct mnl_socket * nl)85 EXPORT_SYMBOL int mnl_socket_get_fd(const struct mnl_socket *nl)
86 {
87 	return nl->fd;
88 }
89 
90 /**
91  * mnl_socket_get_portid - obtain Netlink PortID from netlink socket
92  * \param nl netlink socket obtained via mnl_socket_open()
93  *
94  * This function returns the Netlink PortID of a given netlink socket.
95  * It's a common mistake to assume that this PortID equals the process ID
96  * which is not always true. This is the case if you open more than one
97  * socket that is binded to the same Netlink subsystem from the same process.
98  */
mnl_socket_get_portid(const struct mnl_socket * nl)99 EXPORT_SYMBOL unsigned int mnl_socket_get_portid(const struct mnl_socket *nl)
100 {
101 	return nl->addr.nl_pid;
102 }
103 
__mnl_socket_open(int bus,int flags)104 static struct mnl_socket *__mnl_socket_open(int bus, int flags)
105 {
106 	struct mnl_socket *nl;
107 
108 	nl = calloc(1, sizeof(struct mnl_socket));
109 	if (nl == NULL)
110 		return NULL;
111 
112 	nl->fd = socket(AF_NETLINK, SOCK_RAW | flags, bus);
113 	if (nl->fd == -1) {
114 		free(nl);
115 		return NULL;
116 	}
117 
118 	return nl;
119 }
120 
121 /**
122  * mnl_socket_open - open a netlink socket
123  * \param bus the netlink socket bus ID (see NETLINK_* constants)
124  *
125  * On error, it returns NULL and errno is appropriately set. Otherwise, it
126  * returns a valid pointer to the mnl_socket structure.
127  */
mnl_socket_open(int bus)128 EXPORT_SYMBOL struct mnl_socket *mnl_socket_open(int bus)
129 {
130 	return __mnl_socket_open(bus, 0);
131 }
132 
133 /**
134  * mnl_socket_open2 - open a netlink socket with appropriate flags
135  * \param bus the netlink socket bus ID (see NETLINK_* constants)
136  * \param flags the netlink socket flags (see SOCK_* constants in socket(2))
137  *
138  * This is similar to mnl_socket_open(), but allows one to set flags like
139  * SOCK_CLOEXEC at socket creation time (useful for multi-threaded programs
140  * performing exec calls).
141  *
142  * On error, it returns NULL and errno is appropriately set. Otherwise, it
143  * returns a valid pointer to the mnl_socket structure.
144  */
mnl_socket_open2(int bus,int flags)145 EXPORT_SYMBOL struct mnl_socket *mnl_socket_open2(int bus, int flags)
146 {
147 	return __mnl_socket_open(bus, flags);
148 }
149 
150 /**
151  * mnl_socket_fdopen - associates a mnl_socket object with pre-existing socket.
152  * \param fd pre-existing socket descriptor.
153  *
154  * On error, it returns NULL and errno is appropriately set. Otherwise, it
155  * returns a valid pointer to the mnl_socket structure. It also sets the portID
156  * if the socket fd is already bound and it is AF_NETLINK.
157  *
158  * Note that mnl_socket_get_portid() returns 0 if this function is used with
159  * non-netlink socket.
160  */
mnl_socket_fdopen(int fd)161 EXPORT_SYMBOL struct mnl_socket *mnl_socket_fdopen(int fd)
162 {
163 	int ret;
164 	struct mnl_socket *nl;
165 	struct sockaddr_nl addr;
166 	socklen_t addr_len = sizeof(struct sockaddr_nl);
167 
168 	ret = getsockname(fd, (struct sockaddr *) &addr, &addr_len);
169 	if (ret == -1)
170 		return NULL;
171 
172 	nl = calloc(1, sizeof(struct mnl_socket));
173 	if (nl == NULL)
174 		return NULL;
175 
176 	nl->fd = fd;
177 	if (addr.nl_family == AF_NETLINK)
178 		nl->addr = addr;
179 
180 	return nl;
181 }
182 
183 /**
184  * mnl_socket_bind - bind netlink socket
185  * \param nl netlink socket obtained via mnl_socket_open()
186  * \param groups the group of message you're interested in
187  * \param pid the port ID you want to use (use zero for automatic selection)
188  *
189  * On error, this function returns -1 and errno is appropriately set. On
190  * success, 0 is returned. You can use MNL_SOCKET_AUTOPID which is 0 for
191  * automatic port ID selection.
192  */
mnl_socket_bind(struct mnl_socket * nl,unsigned int groups,pid_t pid)193 EXPORT_SYMBOL int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups,
194 				  pid_t pid)
195 {
196 	int ret;
197 	socklen_t addr_len;
198 
199 	nl->addr.nl_family = AF_NETLINK;
200 	nl->addr.nl_groups = groups;
201 	nl->addr.nl_pid = pid;
202 
203 	ret = bind(nl->fd, (struct sockaddr *) &nl->addr, sizeof (nl->addr));
204 	if (ret < 0)
205 		return ret;
206 
207 	addr_len = sizeof(nl->addr);
208 	ret = getsockname(nl->fd, (struct sockaddr *) &nl->addr, &addr_len);
209 	if (ret < 0)
210 		return ret;
211 
212 	if (addr_len != sizeof(nl->addr)) {
213 		errno = EINVAL;
214 		return -1;
215 	}
216 	if (nl->addr.nl_family != AF_NETLINK) {
217 		errno = EINVAL;
218 		return -1;
219 	}
220 	return 0;
221 }
222 
223 /**
224  * mnl_socket_sendto - send a netlink message of a certain size
225  * \param nl netlink socket obtained via mnl_socket_open()
226  * \param buf buffer containing the netlink message to be sent
227  * \param len number of bytes in the buffer that you want to send
228  *
229  * On error, it returns -1 and errno is appropriately set. Otherwise, it
230  * returns the number of bytes sent.
231  */
mnl_socket_sendto(const struct mnl_socket * nl,const void * buf,size_t len)232 EXPORT_SYMBOL ssize_t mnl_socket_sendto(const struct mnl_socket *nl,
233 					const void *buf, size_t len)
234 {
235 	static const struct sockaddr_nl snl = {
236 		.nl_family = AF_NETLINK
237 	};
238 	return sendto(nl->fd, buf, len, 0,
239 		      (struct sockaddr *) &snl, sizeof(snl));
240 }
241 
242 /**
243  * mnl_socket_recvfrom - receive a netlink message
244  * \param nl netlink socket obtained via mnl_socket_open()
245  * \param buf buffer that you want to use to store the netlink message
246  * \param bufsiz size of the buffer passed to store the netlink message
247  *
248  * On error, it returns -1 and errno is appropriately set. If errno is set
249  * to ENOSPC, it means that the buffer that you have passed to store the
250  * netlink message is too small, so you have received a truncated message.
251  * To avoid this, you have to allocate a buffer of MNL_SOCKET_BUFFER_SIZE
252  * (which is 8KB, see linux/netlink.h for more information). Using this
253  * buffer size ensures that your buffer is big enough to store the netlink
254  * message without truncating it.
255  */
mnl_socket_recvfrom(const struct mnl_socket * nl,void * buf,size_t bufsiz)256 EXPORT_SYMBOL ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl,
257 					  void *buf, size_t bufsiz)
258 {
259 	ssize_t ret;
260 	struct sockaddr_nl addr;
261 	struct iovec iov = {
262 		.iov_base	= buf,
263 		.iov_len	= bufsiz,
264 	};
265 	struct msghdr msg = {
266 		.msg_name	= &addr,
267 		.msg_namelen	= sizeof(struct sockaddr_nl),
268 		.msg_iov	= &iov,
269 		.msg_iovlen	= 1,
270 		.msg_control	= NULL,
271 		.msg_controllen	= 0,
272 		.msg_flags	= 0,
273 	};
274 	ret = recvmsg(nl->fd, &msg, 0);
275 	if (ret == -1)
276 		return ret;
277 
278 	if (msg.msg_flags & MSG_TRUNC) {
279 		errno = ENOSPC;
280 		return -1;
281 	}
282 	if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
283 		errno = EINVAL;
284 		return -1;
285 	}
286 	return ret;
287 }
288 
289 /**
290  * mnl_socket_close - close a given netlink socket
291  * \param nl netlink socket obtained via mnl_socket_open()
292  *
293  * On error, this function returns -1 and errno is appropriately set.
294  * On success, it returns 0.
295  */
mnl_socket_close(struct mnl_socket * nl)296 EXPORT_SYMBOL int mnl_socket_close(struct mnl_socket *nl)
297 {
298 	int ret = close(nl->fd);
299 	free(nl);
300 	return ret;
301 }
302 
303 /**
304  * mnl_socket_setsockopt - set Netlink socket option
305  * \param nl netlink socket obtained via mnl_socket_open()
306  * \param type type of Netlink socket options
307  * \param buf the buffer that contains the data about this option
308  * \param len the size of the buffer passed
309  *
310  * This function allows you to set some Netlink socket option. As of writing
311  * this (see linux/netlink.h), the existing options are:
312  *
313  *	- \#define NETLINK_ADD_MEMBERSHIP  1
314  *	- \#define NETLINK_DROP_MEMBERSHIP 2
315  *	- \#define NETLINK_PKTINFO         3
316  *	- \#define NETLINK_BROADCAST_ERROR 4
317  *	- \#define NETLINK_NO_ENOBUFS      5
318  *
319  * In the early days, Netlink only supported 32 groups expressed in a
320  * 32-bits mask. However, since 2.6.14, Netlink may have up to 2^32 multicast
321  * groups but you have to use setsockopt() with NETLINK_ADD_MEMBERSHIP to
322  * join a given multicast group. This function internally calls setsockopt()
323  * to join a given netlink multicast group. You can still use mnl_bind()
324  * and the 32-bit mask to join a set of Netlink multicast groups.
325  *
326  * On error, this function returns -1 and errno is appropriately set.
327  */
mnl_socket_setsockopt(const struct mnl_socket * nl,int type,void * buf,socklen_t len)328 EXPORT_SYMBOL int mnl_socket_setsockopt(const struct mnl_socket *nl, int type,
329 					void *buf, socklen_t len)
330 {
331 	return setsockopt(nl->fd, SOL_NETLINK, type, buf, len);
332 }
333 
334 /**
335  * mnl_socket_getsockopt - get a Netlink socket option
336  * \param nl netlink socket obtained via mnl_socket_open()
337  * \param type type of Netlink socket options
338  * \param buf pointer to the buffer to store the value of this option
339  * \param len size of the information written in the buffer
340  *
341  * On error, this function returns -1 and errno is appropriately set.
342  */
mnl_socket_getsockopt(const struct mnl_socket * nl,int type,void * buf,socklen_t * len)343 EXPORT_SYMBOL int mnl_socket_getsockopt(const struct mnl_socket *nl, int type,
344 					void *buf, socklen_t *len)
345 {
346 	return getsockopt(nl->fd, SOL_NETLINK, type, buf, len);
347 }
348 
349 /**
350  * @}
351  */
352