xref: /freebsd/sys/netlink/netlink_message_parser.c (revision e145afc9eb9187be7e7cfdd42043cefc07b6e8d6)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #include "opt_inet.h"
30 #include "opt_inet6.h"
31 #include <sys/types.h>
32 #include <sys/malloc.h>
33 #include <sys/rmlock.h>
34 #include <sys/socket.h>
35 #include <sys/stdarg.h>
36 
37 #include <net/if.h>
38 #include <net/route.h>
39 #include <net/route/nhop.h>
40 
41 #include <net/route/route_ctl.h>
42 #include <netinet/in.h>
43 #include <netlink/netlink.h>
44 #include <netlink/netlink_ctl.h>
45 #include <netlink/netlink_var.h>
46 #include <netlink/netlink_route.h>
47 
48 #define	DEBUG_MOD_NAME	nl_parser
49 #define	DEBUG_MAX_LEVEL	LOG_DEBUG3
50 #include <netlink/netlink_debug.h>
51 _DECLARE_DEBUG(LOG_INFO);
52 
53 /*
54  * Some applications try to provide only the non-zero part of the required
55  * message header instead of a full one.  It happens when fetching routes or
56  * interface addresses, where the first header byte is the family.
57  * This behavior is "illegal" under the "strict" Netlink socket option, however
58  * there are many applications out there doing things in the "old" way.
59  * Support this usecase by copying the provided bytes into the temporary
60  * zero-filled header and running the parser on this header instead.
61  */
62 struct nlmsghdr *
nl_alloc_compat_hdr(struct nlmsghdr * hdr,uint32_t len,struct nl_pstate * npt)63 nl_alloc_compat_hdr(struct nlmsghdr *hdr, uint32_t len, struct nl_pstate *npt)
64 {
65 	struct nlmsghdr *tmp;
66 
67 	MPASS(hdr->nlmsg_len < sizeof(struct nlmsghdr) + len);
68 
69 	len += sizeof(struct nlmsghdr);
70 	if (npt->strict) {
71 		nlmsg_report_err_msg(npt,
72 		    "header too short: expected %d, got %d",
73 		     len, hdr->nlmsg_len);
74 		return (NULL);
75 	}
76 	tmp = npt_alloc(npt, len);
77 	if (tmp == NULL)
78 		return (NULL);
79 	memcpy(tmp, hdr, hdr->nlmsg_len);
80 	tmp->nlmsg_len = len;
81 
82 	return (tmp);
83 }
84 
85 bool
nlmsg_report_err_msg(struct nl_pstate * npt,const char * fmt,...)86 nlmsg_report_err_msg(struct nl_pstate *npt, const char *fmt, ...)
87 {
88 	va_list ap;
89 
90 	if (npt->err_msg != NULL)
91 		return (false);
92 	char *buf = npt_alloc(npt, NL_MAX_ERROR_BUF);
93 	if (buf == NULL)
94 		return (false);
95 	va_start(ap, fmt);
96 	vsnprintf(buf, NL_MAX_ERROR_BUF, fmt, ap);
97 	va_end(ap);
98 
99 	npt->err_msg = buf;
100 	return (true);
101 }
102 
103 bool
nlmsg_report_err_offset(struct nl_pstate * npt,uint32_t off)104 nlmsg_report_err_offset(struct nl_pstate *npt, uint32_t off)
105 {
106 	if (npt->err_off != 0)
107 		return (false);
108 	npt->err_off = off;
109 	return (true);
110 }
111 
112 void
nlmsg_report_cookie(struct nl_pstate * npt,struct nlattr * nla)113 nlmsg_report_cookie(struct nl_pstate *npt, struct nlattr *nla)
114 {
115 	MPASS(nla->nla_type == NLMSGERR_ATTR_COOKIE);
116 	MPASS(nla->nla_len >= sizeof(struct nlattr));
117 	npt->cookie = nla;
118 }
119 
120 void
nlmsg_report_cookie_u32(struct nl_pstate * npt,uint32_t val)121 nlmsg_report_cookie_u32(struct nl_pstate *npt, uint32_t val)
122 {
123 	struct nlattr *nla = npt_alloc(npt, sizeof(*nla) + sizeof(uint32_t));
124 
125 	nla->nla_type = NLMSGERR_ATTR_COOKIE;
126 	nla->nla_len = sizeof(*nla) + sizeof(uint32_t);
127 	memcpy(nla + 1, &val, sizeof(uint32_t));
128 	nlmsg_report_cookie(npt, nla);
129 }
130 
131 static const struct nlattr_parser *
search_states(const struct nlattr_parser * ps,u_int pslen,int key)132 search_states(const struct nlattr_parser *ps, u_int pslen, int key)
133 {
134 	int left_i = 0, right_i = pslen - 1;
135 
136 	if (key < ps[0].type || key > ps[pslen - 1].type)
137 		return (NULL);
138 
139 	while (left_i + 1 < right_i) {
140 		int mid_i = (left_i + right_i) / 2;
141 		if (key < ps[mid_i].type)
142 			right_i = mid_i;
143 		else if (key > ps[mid_i].type)
144 			left_i = mid_i + 1;
145 		else
146 			return (&ps[mid_i]);
147 	}
148 	if (ps[left_i].type == key)
149 		return (&ps[left_i]);
150 	else if (ps[right_i].type == key)
151 		return (&ps[right_i]);
152 	return (NULL);
153 }
154 
155 int
nl_parse_attrs_raw(struct nlattr * nla_head,uint16_t len,const struct nlattr_parser * ps,u_int pslen,struct nl_pstate * npt,void * target)156 nl_parse_attrs_raw(struct nlattr *nla_head, uint16_t len,
157     const struct nlattr_parser *ps, u_int pslen, struct nl_pstate *npt,
158     void *target)
159 {
160 	const struct nlattr_parser *s;
161 	struct nlattr *nla;
162 	uint16_t orig_len, off;
163 	int error = 0;
164 
165 	NL_LOG(LOG_DEBUG3, "parse %p remaining_len %d", nla_head, len);
166 	orig_len = len;
167 	NLA_FOREACH(nla, nla_head, len) {
168 		NL_LOG(LOG_DEBUG3, ">> parsing %p attr_type %u len %u (rem %u)",
169 		    nla, nla->nla_type, nla->nla_len, len);
170 		if (nla->nla_len < sizeof(struct nlattr)) {
171 			NLMSG_REPORT_ERR_MSG(npt,
172 			    "Invalid attr %p type %u len: %u",
173 			    nla, nla->nla_type, nla->nla_len);
174 			off = (char *)nla - (char *)npt->hdr;
175 			nlmsg_report_err_offset(npt, off);
176 			return (EINVAL);
177 		}
178 
179 		s = search_states(ps, pslen, nla->nla_type & NLA_TYPE_MASK);
180 		if (s != NULL) {
181 			void *ptr;
182 
183 			ptr = (void *)((char *)target + s->off);
184 			error = s->cb(nla, npt, s->arg, ptr);
185 			if (error != 0) {
186 				off = (char *)nla - (char *)npt->hdr;
187 				nlmsg_report_err_offset(npt, off);
188 				NL_LOG(LOG_DEBUG3,
189 				    "parse failed at offset %u", off);
190 				return (error);
191 			}
192 		} else {
193 			/* Ignore non-specified attributes */
194 			NL_LOG(LOG_DEBUG3, "ignoring attr %u", nla->nla_type);
195 		}
196 	}
197 	if (len >= sizeof(struct nlattr)) {
198 		nla = (struct nlattr *)((char *)nla_head + (orig_len - len));
199 		NL_LOG(LOG_DEBUG3, " >>> end %p attr_type %u len %u", nla,
200 		    nla->nla_type, nla->nla_len);
201 	}
202 	NL_LOG(LOG_DEBUG3, "end parse: %p remaining_len %u", nla, len);
203 
204 	return (0);
205 }
206 
207 void
nl_get_attrs_bmask_raw(struct nlattr * nla_head,uint32_t len,struct nlattr_bmask * bm)208 nl_get_attrs_bmask_raw(struct nlattr *nla_head, uint32_t len,
209     struct nlattr_bmask *bm)
210 {
211 	struct nlattr *nla = NULL;
212 	uint16_t nla_type;
213 
214 	BIT_ZERO(NL_ATTR_BMASK_SIZE, bm);
215 
216 	NLA_FOREACH(nla, nla_head, len) {
217 		if (nla->nla_len < sizeof(struct nlattr))
218 			return;
219 		nla_type = nla->nla_type & NLA_TYPE_MASK;
220 		if (nla_type < NL_ATTR_BMASK_SIZE)
221 			BIT_SET(NL_ATTR_BMASK_SIZE, nla_type, bm);
222 		else
223 			NL_LOG(LOG_DEBUG2,
224 			    "Skipping type %u in the mask: too short",
225 			    nla_type);
226 	}
227 }
228 
229 bool
nl_has_attr(const struct nlattr_bmask * bm,uint16_t nla_type)230 nl_has_attr(const struct nlattr_bmask *bm, uint16_t nla_type)
231 {
232 	MPASS(nla_type < NL_ATTR_BMASK_SIZE);
233 
234 	return (BIT_ISSET(NL_ATTR_BMASK_SIZE, nla_type, bm));
235 }
236 
237 int
nlattr_get_flag(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)238 nlattr_get_flag(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
239     void *target)
240 {
241 	if (__predict_false(NLA_DATA_LEN(nla) != 0)) {
242 		NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not a flag",
243 		    nla->nla_type, NLA_DATA_LEN(nla));
244 		return (EINVAL);
245 	}
246 
247 	*((uint8_t *)target) = 1;
248 	return (0);
249 }
250 
251 static struct sockaddr *
parse_rta_ip4(void * rta_data,struct nl_pstate * npt,int * perror)252 parse_rta_ip4(void *rta_data, struct nl_pstate *npt, int *perror)
253 {
254 	struct sockaddr_in *sin;
255 
256 	sin = (struct sockaddr_in *)npt_alloc_sockaddr(npt,
257 	    sizeof(struct sockaddr_in));
258 	if (__predict_false(sin == NULL)) {
259 		*perror = ENOBUFS;
260 		return (NULL);
261 	}
262 	sin->sin_len = sizeof(struct sockaddr_in);
263 	sin->sin_family = AF_INET;
264 	memcpy(&sin->sin_addr, rta_data, sizeof(struct in_addr));
265 	return ((struct sockaddr *)sin);
266 }
267 
268 static struct sockaddr *
parse_rta_ip6(void * rta_data,struct nl_pstate * npt,int * perror)269 parse_rta_ip6(void *rta_data, struct nl_pstate *npt, int *perror)
270 {
271 	struct sockaddr_in6 *sin6;
272 
273 	sin6 = (struct sockaddr_in6 *)npt_alloc_sockaddr(npt,
274 	    sizeof(struct sockaddr_in6));
275 	if (__predict_false(sin6 == NULL)) {
276 		*perror = ENOBUFS;
277 		return (NULL);
278 	}
279 	sin6->sin6_len = sizeof(struct sockaddr_in6);
280 	sin6->sin6_family = AF_INET6;
281 	memcpy(&sin6->sin6_addr, rta_data, sizeof(struct in6_addr));
282 	return ((struct sockaddr *)sin6);
283 }
284 
285 static struct sockaddr *
parse_rta_ip(struct rtattr * rta,struct nl_pstate * npt,int * perror)286 parse_rta_ip(struct rtattr *rta, struct nl_pstate *npt, int *perror)
287 {
288 	void *rta_data = NL_RTA_DATA(rta);
289 	int rta_len = NL_RTA_DATA_LEN(rta);
290 
291 	if (rta_len == sizeof(struct in_addr)) {
292 		return (parse_rta_ip4(rta_data, npt, perror));
293 	} else if (rta_len == sizeof(struct in6_addr)) {
294 		return (parse_rta_ip6(rta_data, npt, perror));
295 	} else {
296 		NLMSG_REPORT_ERR_MSG(npt, "unknown IP len: %d for rta type %d",
297 		    rta_len, rta->rta_type);
298 		*perror = ENOTSUP;
299 		return (NULL);
300 	}
301 	return (NULL);
302 }
303 
304 int
nlattr_get_ip(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)305 nlattr_get_ip(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
306     void *target)
307 {
308 	int error = 0;
309 
310 	struct sockaddr *sa = parse_rta_ip((struct rtattr *)nla, npt, &error);
311 
312 	*((struct sockaddr **)target) = sa;
313 	return (error);
314 }
315 
316 static struct sockaddr *
parse_rta_via(struct rtattr * rta,struct nl_pstate * npt,int * perror)317 parse_rta_via(struct rtattr *rta, struct nl_pstate *npt, int *perror)
318 {
319 	struct rtvia *via = NL_RTA_DATA(rta);
320 	int data_len = NL_RTA_DATA_LEN(rta);
321 
322 	if (__predict_false(data_len) < sizeof(struct rtvia)) {
323 		NLMSG_REPORT_ERR_MSG(npt, "undersized RTA_VIA(%d) attr: len %d",
324 		    rta->rta_type, data_len);
325 		*perror = EINVAL;
326 		return (NULL);
327 	}
328 	data_len -= offsetof(struct rtvia, rtvia_addr);
329 
330 	switch (via->rtvia_family) {
331 	case AF_INET:
332 		if (__predict_false(data_len < sizeof(struct in_addr))) {
333 			*perror = EINVAL;
334 			return (NULL);
335 		}
336 		return (parse_rta_ip4(via->rtvia_addr, npt, perror));
337 	case AF_INET6:
338 		if (__predict_false(data_len < sizeof(struct in6_addr))) {
339 			*perror = EINVAL;
340 			return (NULL);
341 		}
342 		return (parse_rta_ip6(via->rtvia_addr, npt, perror));
343 	default:
344 		*perror = ENOTSUP;
345 		return (NULL);
346 	}
347 }
348 
349 int
nlattr_get_ipvia(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)350 nlattr_get_ipvia(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
351     void *target)
352 {
353 	int error = 0;
354 
355 	struct sockaddr *sa = parse_rta_via((struct rtattr *)nla, npt, &error);
356 
357 	*((struct sockaddr **)target) = sa;
358 	return (error);
359 }
360 
361 int
nlattr_get_bool(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)362 nlattr_get_bool(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
363     void *target)
364 {
365 	if (__predict_false(NLA_DATA_LEN(nla) != sizeof(bool))) {
366 		NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not bool",
367 		    nla->nla_type, NLA_DATA_LEN(nla));
368 		return (EINVAL);
369 	}
370 	*((bool *)target) = *((const bool *)NL_RTA_DATA_CONST(nla));
371 	return (0);
372 }
373 
374 int
nlattr_get_uint8(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)375 nlattr_get_uint8(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
376     void *target)
377 {
378 	if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint8_t))) {
379 		NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint8",
380 		    nla->nla_type, NLA_DATA_LEN(nla));
381 		return (EINVAL);
382 	}
383 	*((uint8_t *)target) = *((const uint8_t *)NL_RTA_DATA_CONST(nla));
384 	return (0);
385 }
386 
387 int
nlattr_get_uint16(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)388 nlattr_get_uint16(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
389     void *target)
390 {
391 	if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint16_t))) {
392 		NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint16",
393 		    nla->nla_type, NLA_DATA_LEN(nla));
394 		return (EINVAL);
395 	}
396 	*((uint16_t *)target) = *((const uint16_t *)NL_RTA_DATA_CONST(nla));
397 	return (0);
398 }
399 
400 int
nlattr_get_uint32(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)401 nlattr_get_uint32(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
402     void *target)
403 {
404 	if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint32_t))) {
405 		NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint32",
406 		    nla->nla_type, NLA_DATA_LEN(nla));
407 		return (EINVAL);
408 	}
409 	*((uint32_t *)target) = *((const uint32_t *)NL_RTA_DATA_CONST(nla));
410 	return (0);
411 }
412 
413 int
nlattr_get_uint64(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)414 nlattr_get_uint64(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
415     void *target)
416 {
417 	if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint64_t))) {
418 		NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint64",
419 		    nla->nla_type, NLA_DATA_LEN(nla));
420 		return (EINVAL);
421 	}
422 	memcpy(target, NL_RTA_DATA_CONST(nla), sizeof(uint64_t));
423 	return (0);
424 }
425 
426 int
nlattr_get_in_addr(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)427 nlattr_get_in_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
428     void *target)
429 {
430 	if (__predict_false(NLA_DATA_LEN(nla) != sizeof(in_addr_t))) {
431 		NLMSG_REPORT_ERR_MSG(npt,
432 		    "nla type %d size(%u) is not in_addr_t",
433 		    nla->nla_type, NLA_DATA_LEN(nla));
434 		return (EINVAL);
435 	}
436 	memcpy(target, NLA_DATA_CONST(nla), sizeof(in_addr_t));
437 	return (0);
438 }
439 
440 int
nlattr_get_in6_addr(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)441 nlattr_get_in6_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
442     void *target)
443 {
444 	if (__predict_false(NLA_DATA_LEN(nla) != sizeof(struct in6_addr))) {
445 		NLMSG_REPORT_ERR_MSG(npt,
446 		    "nla type %d size(%u) is not struct in6_addr",
447 		    nla->nla_type, NLA_DATA_LEN(nla));
448 		return (EINVAL);
449 	}
450 	memcpy(target, NLA_DATA_CONST(nla), sizeof(struct in6_addr));
451 	return (0);
452 }
453 
454 static int
nlattr_get_ifp_internal(struct nlattr * nla,struct nl_pstate * npt,void * target,bool zero_ok)455 nlattr_get_ifp_internal(struct nlattr *nla, struct nl_pstate *npt,
456     void *target, bool zero_ok)
457 {
458 	struct ifnet *ifp;
459 	u_int ifindex;
460 
461 	if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint32_t))) {
462 		NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint32",
463 		    nla->nla_type, NLA_DATA_LEN(nla));
464 		return (EINVAL);
465 	}
466 	ifindex = *((const u_int *)NLA_DATA_CONST(nla));
467 
468 	if (ifindex == 0 && zero_ok) {
469 		*((struct ifnet **)target) = NULL;
470 		return (0);
471 	}
472 
473 	NET_EPOCH_ASSERT();
474 
475 	ifp = ifnet_byindex(ifindex);
476 	if (__predict_false(ifp == NULL)) {
477 		NLMSG_REPORT_ERR_MSG(npt, "nla type %d: ifindex %u invalid",
478 		    nla->nla_type, ifindex);
479 		return (ENOENT);
480 	}
481 	*((struct ifnet **)target) = ifp;
482 	NL_LOG(LOG_DEBUG3, "nla type %d: ifindex %u -> %s", nla->nla_type,
483 	    ifindex, if_name(ifp));
484 
485 	return (0);
486 }
487 
488 int
nlattr_get_ifp(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)489 nlattr_get_ifp(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
490     void *target)
491 {
492 	return (nlattr_get_ifp_internal(nla, npt, target, false));
493 }
494 
495 int
nlattr_get_ifpz(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)496 nlattr_get_ifpz(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
497     void *target)
498 {
499 	return (nlattr_get_ifp_internal(nla, npt, target, true));
500 }
501 
502 int
nlattr_get_chara(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)503 nlattr_get_chara(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
504     void *target)
505 {
506 	int maxlen = NLA_DATA_LEN(nla);
507 	int target_size = (size_t)arg;
508 	int len = strnlen((char *)NLA_DATA(nla), maxlen);
509 
510 	if (__predict_false(len >= maxlen) ||
511 	    __predict_false(len >= target_size)) {
512 		NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not "
513 		    "NULL-terminated or longer than %u",
514 		    nla->nla_type, maxlen, target_size);
515 		return (EINVAL);
516 	}
517 
518 	strncpy((char *)target, (char *)NLA_DATA(nla), target_size);
519 	return (0);
520 }
521 
522 int
nlattr_get_string(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)523 nlattr_get_string(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
524     void *target)
525 {
526 	int maxlen = NLA_DATA_LEN(nla);
527 
528 	if (__predict_false(strnlen((char *)NLA_DATA(nla), maxlen) >= maxlen)) {
529 		NLMSG_REPORT_ERR_MSG(npt,
530 		    "nla type %d size(%u) is not NULL-terminated",
531 		    nla->nla_type, maxlen);
532 		return (EINVAL);
533 	}
534 
535 	*((char **)target) = (char *)NLA_DATA(nla);
536 	return (0);
537 }
538 
539 int
nlattr_get_stringn(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)540 nlattr_get_stringn(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
541     void *target)
542 {
543 	int maxlen = NLA_DATA_LEN(nla);
544 
545 	char *buf = npt_alloc(npt, maxlen + 1);
546 	if (buf == NULL)
547 		return (ENOMEM);
548 	buf[maxlen] = '\0';
549 	memcpy(buf, NLA_DATA(nla), maxlen);
550 
551 	*((char **)target) = buf;
552 	return (0);
553 }
554 
555 int
nlattr_get_bytes(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)556 nlattr_get_bytes(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
557     void *target)
558 {
559 	size_t size = (size_t)arg;
560 
561 	if (NLA_DATA_LEN(nla) != size)
562 		return (EINVAL);
563 
564 	memcpy(target, NLA_DATA(nla), size);
565 
566 	return (0);
567 }
568 
569 int
nlattr_get_nla(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)570 nlattr_get_nla(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
571     void *target)
572 {
573 	NL_LOG(LOG_DEBUG3, "STORING %p len %d", nla, nla->nla_len);
574 	*((struct nlattr **)target) = nla;
575 	return (0);
576 }
577 
578 int
nlattr_get_nested(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)579 nlattr_get_nested(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
580     void *target)
581 {
582 	const struct nlhdr_parser *p = (const struct nlhdr_parser *)arg;
583 
584 	/* Assumes target points to the beginning of the structure. */
585 	return (nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), p, npt,
586 	    target));
587 }
588 
589 int
nlattr_get_nested_ptr(struct nlattr * nla,struct nl_pstate * npt,const void * arg,void * target)590 nlattr_get_nested_ptr(struct nlattr *nla, struct nl_pstate *npt,
591     const void *arg, void *target)
592 {
593 	const struct nlhdr_parser *p = (const struct nlhdr_parser *)arg;
594 
595 	/* Assumes target points to the beginning of the structure. */
596 	return (nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), p, npt,
597 	    *(void **)target));
598 }
599 
600 int
nlf_get_ifp(void * src,struct nl_pstate * npt,void * target)601 nlf_get_ifp(void *src, struct nl_pstate *npt, void *target)
602 {
603 	struct ifnet *ifp;
604 	u_int ifindex;
605 
606 	NET_EPOCH_ASSERT();
607 
608 	ifindex = *((const u_int *)src);
609 	ifp = ifnet_byindex(ifindex);
610 	if (ifp == NULL) {
611 		NL_LOG(LOG_DEBUG, "ifindex %u invalid", ifindex);
612 		return (ENOENT);
613 	}
614 	*((struct ifnet **)target) = ifp;
615 
616 	return (0);
617 }
618 
619 int
nlf_get_ifpz(void * src,struct nl_pstate * npt,void * target)620 nlf_get_ifpz(void *src, struct nl_pstate *npt, void *target)
621 {
622 	struct ifnet *ifp;
623 	u_int ifindex;
624 
625 	NET_EPOCH_ASSERT();
626 
627 	ifindex = *((const u_int *)src);
628 	ifp = ifnet_byindex(ifindex);
629 	if (ifindex != 0 && ifp == NULL) {
630 		NL_LOG(LOG_DEBUG, "ifindex %u invalid", ifindex);
631 		return (ENOENT);
632 	}
633 	*((struct ifnet **)target) = ifp;
634 
635 	return (0);
636 }
637 
638 int
nlf_get_u8(void * src,struct nl_pstate * npt,void * target)639 nlf_get_u8(void *src, struct nl_pstate *npt, void *target)
640 {
641 	uint8_t val = *((const uint8_t *)src);
642 
643 	*((uint8_t *)target) = val;
644 
645 	return (0);
646 }
647 
648 int
nlf_get_u8_u32(void * src,struct nl_pstate * npt,void * target)649 nlf_get_u8_u32(void *src, struct nl_pstate *npt, void *target)
650 {
651 	*((uint32_t *)target) = *((const uint8_t *)src);
652 	return (0);
653 }
654 
655 int
nlf_get_u16(void * src,struct nl_pstate * npt,void * target)656 nlf_get_u16(void *src, struct nl_pstate *npt, void *target)
657 {
658 	*((uint16_t *)target) = *((const uint16_t *)src);
659 	return (0);
660 }
661 
662 int
nlf_get_u32(void * src,struct nl_pstate * npt,void * target)663 nlf_get_u32(void *src, struct nl_pstate *npt, void *target)
664 {
665 	*((uint32_t *)target) = *((const uint32_t *)src);
666 	return (0);
667 }
668