• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
4  */
5 
6 #ifndef NETLINK_UTILS_PRIV_H_
7 #define NETLINK_UTILS_PRIV_H_
8 
9 #include <byteswap.h>
10 #include <assert.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <stdbool.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
17 
18 #if __BYTE_ORDER == __BIG_ENDIAN
19 #define ntohll(x) (x)
20 #elif __BYTE_ORDER == __LITTLE_ENDIAN
21 #define ntohll(x) bswap_64((x))
22 #endif
23 #define htonll(x) ntohll(x)
24 
25 /*****************************************************************************/
26 
27 #define _NL_STRINGIFY_ARG(contents)       #contents
28 #define _NL_STRINGIFY(macro_or_string)    _NL_STRINGIFY_ARG (macro_or_string)
29 
30 /*****************************************************************************/
31 
32 #if defined (__GNUC__)
33 #define _NL_PRAGMA_WARNING_DO(warning)       _NL_STRINGIFY(GCC diagnostic ignored warning)
34 #elif defined (__clang__)
35 #define _NL_PRAGMA_WARNING_DO(warning)       _NL_STRINGIFY(clang diagnostic ignored warning)
36 #endif
37 
38 /* you can only suppress a specific warning that the compiler
39  * understands. Otherwise you will get another compiler warning
40  * about invalid pragma option.
41  * It's not that bad however, because gcc and clang often have the
42  * same name for the same warning. */
43 
44 #if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
45 #define _NL_PRAGMA_WARNING_DISABLE(warning) \
46         _Pragma("GCC diagnostic push") \
47         _Pragma(_NL_PRAGMA_WARNING_DO("-Wpragmas")) \
48         _Pragma(_NL_PRAGMA_WARNING_DO(warning))
49 #elif defined (__clang__)
50 #define _NL_PRAGMA_WARNING_DISABLE(warning) \
51         _Pragma("clang diagnostic push") \
52         _Pragma(_NL_PRAGMA_WARNING_DO("-Wunknown-warning-option")) \
53         _Pragma(_NL_PRAGMA_WARNING_DO(warning))
54 #else
55 #define _NL_PRAGMA_WARNING_DISABLE(warning)
56 #endif
57 
58 #if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
59 #define _NL_PRAGMA_WARNING_REENABLE \
60     _Pragma("GCC diagnostic pop")
61 #elif defined (__clang__)
62 #define _NL_PRAGMA_WARNING_REENABLE \
63     _Pragma("clang diagnostic pop")
64 #else
65 #define _NL_PRAGMA_WARNING_REENABLE
66 #endif
67 
68 /*****************************************************************************/
69 
70 #define _nl_unused                  __attribute__ ((__unused__))
71 #define _nl_auto(fcn)               __attribute__ ((__cleanup__(fcn)))
72 
73 /*****************************************************************************/
74 
75 #ifdef thread_local
76 #define _nl_thread_local thread_local
77 /*
78  * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
79  * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
80  */
81 #elif __STDC_VERSION__ >= 201112L &&                                           \
82 	!(defined(__STDC_NO_THREADS__) ||                                      \
83 	  (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 &&                       \
84 	   __GLIBC_MINOR__ < 16))
85 #define _nl_thread_local _Thread_local
86 #else
87 #define _nl_thread_local __thread
88 #endif
89 
90 /*****************************************************************************/
91 
92 #define _NL_STATIC_ASSERT(cond) ((void) sizeof (char[(cond) ? 1 : -1]))
93 
94 /*****************************************************************************/
95 
96 #if defined(NL_MORE_ASSERTS) && NL_MORE_ASSERTS > 0
97 #define _nl_assert(cond) assert(cond)
98 #else
99 #define _nl_assert(cond) do { if (0) { assert(cond); } } while (0)
100 #endif
101 
102 #define _nl_assert_not_reached() assert(0)
103 
104 /*****************************************************************************/
105 
106 #define _nl_assert_addr_family_or_unspec(addr_family)                          \
107 	do {                                                                   \
108 		typeof(addr_family) _addr_family = (addr_family);              \
109                                                                                \
110 		_nl_assert(_addr_family == AF_UNSPEC ||                        \
111 			   _addr_family == AF_INET ||                          \
112 			   _addr_family == AF_INET6);                          \
113 	} while (0)
114 
115 #define _nl_assert_addr_family(addr_family)                                    \
116 	do {                                                                   \
117 		typeof(addr_family) _addr_family = (addr_family);              \
118                                                                                \
119 		_nl_assert(_addr_family == AF_INET ||                          \
120 			   _addr_family == AF_INET6);                          \
121 	} while (0)
122 
123 /*****************************************************************************/
124 
125 #define _NL_SWAP(pa, pb)                                                       \
126 	do {                                                                   \
127 		typeof(*(pa)) *_pa = (pa);                                     \
128 		typeof(*(pb)) *_pb = (pb);                                     \
129 		typeof(*_pa) _tmp;                                             \
130                                                                                \
131 		_nl_assert(_pa);                                               \
132 		_nl_assert(_pb);                                               \
133 		_tmp = *_pa;                                                   \
134 		*_pa = *_pb;                                                   \
135 		*_pb = _tmp;                                                   \
136 	} while (0)
137 
138 /*****************************************************************************/
139 
140 #define _NL_N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0]))
141 
142 /*****************************************************************************/
143 
144 extern const char *nl_strerror_l(int err);
145 
146 /*****************************************************************************/
147 
148 /* internal macro to calculate the size of a struct @type up to (and including) @field.
149  * this will be used for .minlen policy fields, so that we require only a field of up
150  * to the given size. */
151 #define _nl_offsetofend(type, field) (offsetof (type, field) + sizeof (((type *) NULL)->field))
152 
153 /*****************************************************************************/
154 
155 #define _nl_clear_pointer(pp, destroy) \
156 	({ \
157 		__typeof__ (*(pp)) *_pp = (pp); \
158 		__typeof__ (*_pp) _p; \
159 		int _changed = 0; \
160 		\
161 		if (   _pp \
162 			&& (_p = *_pp)) { \
163 			_nl_unused const void *const _p_check_is_pointer = _p; \
164 			\
165 			*_pp = NULL; \
166 			\
167 			(destroy) (_p); \
168 			\
169 			_changed = 1; \
170 		} \
171 		_changed; \
172 	})
173 
174 #define _nl_clear_free(pp) _nl_clear_pointer (pp, free)
175 
176 #define _nl_steal_pointer(pp) \
177 	({ \
178 		__typeof__ (*(pp)) *const _pp = (pp); \
179 		__typeof__ (*_pp) _p = NULL; \
180 		\
181 		if (   _pp \
182 		    && (_p = *_pp)) { \
183 			*_pp = NULL; \
184 		} \
185 		\
186 		_p; \
187 	})
188 
189 /*****************************************************************************/
190 
191 #define _nl_malloc_maybe_a(alloca_maxlen, bytes, to_free) \
192 	({ \
193 		const size_t _bytes = (bytes); \
194 		__typeof__ (to_free) _to_free = (to_free); \
195 		__typeof__ (*_to_free) _ptr; \
196 		\
197 		_NL_STATIC_ASSERT ((alloca_maxlen) <= 500); \
198 		_nl_assert (_to_free && !*_to_free); \
199 		\
200 		if (_bytes <= (alloca_maxlen)) { \
201 			_ptr = alloca (_bytes); \
202 		} else { \
203 			_ptr = malloc (_bytes); \
204 			*_to_free = _ptr; \
205 		}; \
206 		\
207 		_ptr; \
208 	})
209 
210 /*****************************************************************************/
211 
_nl_streq(const char * a,const char * b)212 static inline bool _nl_streq(const char *a, const char *b)
213 {
214 	return !strcmp(a, b);
215 }
216 
_nl_streq0(const char * a,const char * b)217 static inline bool _nl_streq0(const char *a, const char *b)
218 {
219 	return a == b || (a && b && _nl_streq(a, b));
220 }
221 
222 static inline char *
_nl_strncpy_trunc(char * dst,const char * src,size_t len)223 _nl_strncpy_trunc(char *dst, const char *src, size_t len)
224 {
225 	/* we don't use/reimplement strlcpy(), because we want the fill-all-with-NUL
226 	 * behavior of strncpy(). This is just strncpy() with gracefully handling truncation
227 	 * (and disabling the "-Wstringop-truncation" warning).
228 	 *
229 	 * Note that truncation is silently accepted.
230 	 */
231 
232 	_NL_PRAGMA_WARNING_DISABLE ("-Wstringop-truncation");
233 	_NL_PRAGMA_WARNING_DISABLE ("-Wstringop-overflow");
234 
235 	if (len > 0) {
236 		_nl_assert(dst);
237 		_nl_assert(src);
238 
239 		strncpy(dst, src, len);
240 
241 		dst[len - 1] = '\0';
242 	}
243 
244 	_NL_PRAGMA_WARNING_REENABLE;
245 	_NL_PRAGMA_WARNING_REENABLE;
246 
247 	return dst;
248 }
249 
250 static inline char *
_nl_strncpy_assert(char * dst,const char * src,size_t len)251 _nl_strncpy_assert(char *dst, const char *src, size_t len)
252 {
253 	/* we don't use/reimplement strlcpy(), because we want the fill-all-with-NUL
254 	 * behavior of strncpy(). This is just strncpy() with assertion against truncation
255 	 * (and disabling the "-Wstringop-truncation" warning).
256 	 *
257 	 * Note that truncation is still a bug and there is an _nl_assert()
258 	 * against that.
259 	 */
260 
261 	_NL_PRAGMA_WARNING_DISABLE ("-Wstringop-truncation");
262 	_NL_PRAGMA_WARNING_DISABLE ("-Wstringop-overflow");
263 
264 	if (len > 0) {
265 		_nl_assert(dst);
266 		_nl_assert(src);
267 
268 		strncpy(dst, src, len);
269 
270 		_nl_assert (dst[len - 1] == '\0');
271 
272 		dst[len - 1] = '\0';
273 	}
274 
275 	_NL_PRAGMA_WARNING_REENABLE;
276 	_NL_PRAGMA_WARNING_REENABLE;
277 
278 	return dst;
279 }
280 
281 #include "nl-auto.h"
282 
283 #define _NL_RETURN_ON_ERR(cmd) \
284 	do { \
285 		int _err; \
286 		\
287 		_err = (cmd); \
288 		if (_err < 0) \
289 			return _err; \
290 	} while (0)
291 
292 #define _NL_RETURN_E_ON_ERR(e, cmd) \
293 	do { \
294 		int _err; \
295 		\
296 		_err = (cmd); \
297 		if (_err < 0) { \
298 			_NL_STATIC_ASSERT((e) > 0); \
299 			return -(e); \
300 		} \
301 	} while (0)
302 
303 /* _NL_RETURN_ON_PUT_ERR() shall only be used with a put command (nla_put or nlmsg_append).
304  * These commands can either fail with a regular error code (which gets propagated)
305  * or with -NLE_NOMEM. However, they don't really try to allocate memory, so we don't
306  * want to propagate -NLE_NOMEM. Instead, we coerce such failure to -NLE_MSGSIZE. */
307 #define _NL_RETURN_ON_PUT_ERR(put_cmd) \
308 	do { \
309 		int _err; \
310 		\
311 		_err = (put_cmd); \
312 		if (_err < 0) { \
313 			if (_err == -NLE_NOMEM) { \
314 				/* nla_put() returns -NLE_NOMEM in case of out of buffer size. We don't
315 				 * want to propagate that error and map it to -NLE_MSGSIZE. */ \
316 				return -NLE_MSGSIZE; \
317 			} \
318 			/* any other error can only be due to invalid parameters. Propagate the
319 			 * error, however also assert that it cannot be reached. */ \
320 			_nl_assert_not_reached (); \
321 			return _err; \
322 		} else \
323 			_nl_assert (_err == 0); \
324 	} while (0)
325 
326 static inline int
_nl_close(int fd)327 _nl_close(int fd)
328 {
329 	int r;
330 
331 	r = close(fd);
332 	_nl_assert(r == 0 || fd < 0 || errno != EBADF);
333 	return r;
334 }
335 
336 static inline void *
_nl_memdup(const void * ptr,size_t len)337 _nl_memdup(const void *ptr, size_t len)
338 {
339 	void *p;
340 
341 	if (len == 0) {
342 		/* malloc() leaves it implementation defined whether to return NULL.
343 		 * Callers rely on returning NULL if len is zero. */
344 		return NULL;
345 	}
346 
347 	p = malloc(len);
348 	if (!p)
349 		return NULL;
350 	memcpy(p, ptr, len);
351 	return p;
352 }
353 
354 #define _nl_memdup_ptr(ptr) ((__typeof__(ptr)) _nl_memdup((ptr), sizeof(*(ptr))))
355 
356 /*****************************************************************************/
357 
358 typedef union {
359 	in_addr_t addr4;
360 	struct in_addr a4;
361 	struct in6_addr a6;
362 } _NLIPAddr;
363 
_nl_inet_ntop(int addr_family,const void * addr,char buf[static INET_ADDRSTRLEN])364 static inline char *_nl_inet_ntop(int addr_family, const void *addr,
365 				  char buf[static INET_ADDRSTRLEN])
366 {
367 	char *r;
368 
369 	_nl_assert_addr_family(addr_family);
370 	_nl_assert(addr);
371 
372 	/* inet_ntop() is documented to fail, but if we pass a known address family
373 	 * and a suitably large buffer, it cannot. Assert for that. */
374 
375 	r = (char *)inet_ntop(addr_family, addr, buf,
376 			      (addr_family == AF_INET) ? INET_ADDRSTRLEN :
377 							       INET6_ADDRSTRLEN);
378 	_nl_assert(r == buf);
379 	_nl_assert(strlen(r) < ((addr_family == AF_INET) ? INET_ADDRSTRLEN :
380 								 INET6_ADDRSTRLEN));
381 
382 	return r;
383 }
384 
_nl_inet_ntop_dup(int addr_family,const void * addr)385 static inline char *_nl_inet_ntop_dup(int addr_family, const void *addr)
386 {
387 	return (char *)_nl_inet_ntop(addr_family, addr,
388 				     malloc((addr_family == AF_INET) ?
389 						    INET_ADDRSTRLEN :
390 							  INET6_ADDRSTRLEN));
391 }
392 
393 #endif
394