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