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 * 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 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 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 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 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 if (nla == NULL) 126 return; 127 nla->nla_type = NLMSGERR_ATTR_COOKIE; 128 nla->nla_len = sizeof(*nla) + sizeof(uint32_t); 129 memcpy(nla + 1, &val, sizeof(uint32_t)); 130 nlmsg_report_cookie(npt, nla); 131 } 132 133 static const struct nlattr_parser * 134 search_states(const struct nlattr_parser *ps, u_int pslen, int key) 135 { 136 int left_i = 0, right_i = pslen - 1; 137 138 if (key < ps[0].type || key > ps[pslen - 1].type) 139 return (NULL); 140 141 while (left_i + 1 < right_i) { 142 int mid_i = (left_i + right_i) / 2; 143 if (key < ps[mid_i].type) 144 right_i = mid_i; 145 else if (key > ps[mid_i].type) 146 left_i = mid_i + 1; 147 else 148 return (&ps[mid_i]); 149 } 150 if (ps[left_i].type == key) 151 return (&ps[left_i]); 152 else if (ps[right_i].type == key) 153 return (&ps[right_i]); 154 return (NULL); 155 } 156 157 int 158 nl_parse_attrs_raw(struct nlattr *nla_head, uint16_t len, 159 const struct nlattr_parser *ps, u_int pslen, struct nl_pstate *npt, 160 void *target) 161 { 162 const struct nlattr_parser *s; 163 struct nlattr *nla; 164 uint16_t orig_len, off; 165 int error = 0; 166 167 NL_LOG(LOG_DEBUG3, "parse %p remaining_len %d", nla_head, len); 168 orig_len = len; 169 NLA_FOREACH(nla, nla_head, len) { 170 NL_LOG(LOG_DEBUG3, ">> parsing %p attr_type %u len %u (rem %u)", 171 nla, nla->nla_type, nla->nla_len, len); 172 if (nla->nla_len < sizeof(struct nlattr)) { 173 NLMSG_REPORT_ERR_MSG(npt, 174 "Invalid attr %p type %u len: %u", 175 nla, nla->nla_type, nla->nla_len); 176 off = (char *)nla - (char *)npt->hdr; 177 nlmsg_report_err_offset(npt, off); 178 return (EINVAL); 179 } 180 181 s = search_states(ps, pslen, nla->nla_type & NLA_TYPE_MASK); 182 if (s != NULL) { 183 void *ptr; 184 185 ptr = (void *)((char *)target + s->off); 186 error = s->cb(nla, npt, s->arg, ptr); 187 if (error != 0) { 188 off = (char *)nla - (char *)npt->hdr; 189 nlmsg_report_err_offset(npt, off); 190 NL_LOG(LOG_DEBUG3, 191 "parse failed at offset %u", off); 192 return (error); 193 } 194 } else { 195 /* Ignore non-specified attributes */ 196 NL_LOG(LOG_DEBUG3, "ignoring attr %u", nla->nla_type); 197 } 198 } 199 if (len >= sizeof(struct nlattr)) { 200 nla = (struct nlattr *)((char *)nla_head + (orig_len - len)); 201 NL_LOG(LOG_DEBUG3, " >>> end %p attr_type %u len %u", nla, 202 nla->nla_type, nla->nla_len); 203 } 204 NL_LOG(LOG_DEBUG3, "end parse: %p remaining_len %u", nla, len); 205 206 return (0); 207 } 208 209 void 210 nl_get_attrs_bmask_raw(struct nlattr *nla_head, uint32_t len, 211 struct nlattr_bmask *bm) 212 { 213 struct nlattr *nla = NULL; 214 uint16_t nla_type; 215 216 BIT_ZERO(NL_ATTR_BMASK_SIZE, bm); 217 218 NLA_FOREACH(nla, nla_head, len) { 219 if (nla->nla_len < sizeof(struct nlattr)) 220 return; 221 nla_type = nla->nla_type & NLA_TYPE_MASK; 222 if (nla_type < NL_ATTR_BMASK_SIZE) 223 BIT_SET(NL_ATTR_BMASK_SIZE, nla_type, bm); 224 else 225 NL_LOG(LOG_DEBUG2, 226 "Skipping type %u in the mask: too short", 227 nla_type); 228 } 229 } 230 231 bool 232 nl_has_attr(const struct nlattr_bmask *bm, uint16_t nla_type) 233 { 234 MPASS(nla_type < NL_ATTR_BMASK_SIZE); 235 236 return (BIT_ISSET(NL_ATTR_BMASK_SIZE, nla_type, bm)); 237 } 238 239 int 240 nlattr_get_flag(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 241 void *target) 242 { 243 if (__predict_false(NLA_DATA_LEN(nla) != 0)) { 244 NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not a flag", 245 nla->nla_type, NLA_DATA_LEN(nla)); 246 return (EINVAL); 247 } 248 249 *((uint8_t *)target) = 1; 250 return (0); 251 } 252 253 static struct sockaddr * 254 parse_rta_ip4(void *rta_data, struct nl_pstate *npt, int *perror) 255 { 256 struct sockaddr_in *sin; 257 258 sin = (struct sockaddr_in *)npt_alloc_sockaddr(npt, 259 sizeof(struct sockaddr_in)); 260 if (__predict_false(sin == NULL)) { 261 *perror = ENOBUFS; 262 return (NULL); 263 } 264 sin->sin_len = sizeof(struct sockaddr_in); 265 sin->sin_family = AF_INET; 266 memcpy(&sin->sin_addr, rta_data, sizeof(struct in_addr)); 267 return ((struct sockaddr *)sin); 268 } 269 270 static struct sockaddr * 271 parse_rta_ip6(void *rta_data, struct nl_pstate *npt, int *perror) 272 { 273 struct sockaddr_in6 *sin6; 274 275 sin6 = (struct sockaddr_in6 *)npt_alloc_sockaddr(npt, 276 sizeof(struct sockaddr_in6)); 277 if (__predict_false(sin6 == NULL)) { 278 *perror = ENOBUFS; 279 return (NULL); 280 } 281 sin6->sin6_len = sizeof(struct sockaddr_in6); 282 sin6->sin6_family = AF_INET6; 283 memcpy(&sin6->sin6_addr, rta_data, sizeof(struct in6_addr)); 284 return ((struct sockaddr *)sin6); 285 } 286 287 static struct sockaddr * 288 parse_rta_ip(struct rtattr *rta, struct nl_pstate *npt, int *perror) 289 { 290 void *rta_data = NL_RTA_DATA(rta); 291 int rta_len = NL_RTA_DATA_LEN(rta); 292 293 if (rta_len == sizeof(struct in_addr)) { 294 return (parse_rta_ip4(rta_data, npt, perror)); 295 } else if (rta_len == sizeof(struct in6_addr)) { 296 return (parse_rta_ip6(rta_data, npt, perror)); 297 } else { 298 NLMSG_REPORT_ERR_MSG(npt, "unknown IP len: %d for rta type %d", 299 rta_len, rta->rta_type); 300 *perror = ENOTSUP; 301 return (NULL); 302 } 303 return (NULL); 304 } 305 306 int 307 nlattr_get_ip(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 308 void *target) 309 { 310 int error = 0; 311 312 struct sockaddr *sa = parse_rta_ip((struct rtattr *)nla, npt, &error); 313 314 *((struct sockaddr **)target) = sa; 315 return (error); 316 } 317 318 static struct sockaddr * 319 parse_rta_via(struct rtattr *rta, struct nl_pstate *npt, int *perror) 320 { 321 struct rtvia *via = NL_RTA_DATA(rta); 322 int data_len = NL_RTA_DATA_LEN(rta); 323 324 if (__predict_false(data_len) < sizeof(struct rtvia)) { 325 NLMSG_REPORT_ERR_MSG(npt, "undersized RTA_VIA(%d) attr: len %d", 326 rta->rta_type, data_len); 327 *perror = EINVAL; 328 return (NULL); 329 } 330 data_len -= offsetof(struct rtvia, rtvia_addr); 331 332 switch (via->rtvia_family) { 333 case AF_INET: 334 if (__predict_false(data_len < sizeof(struct in_addr))) { 335 *perror = EINVAL; 336 return (NULL); 337 } 338 return (parse_rta_ip4(via->rtvia_addr, npt, perror)); 339 case AF_INET6: 340 if (__predict_false(data_len < sizeof(struct in6_addr))) { 341 *perror = EINVAL; 342 return (NULL); 343 } 344 return (parse_rta_ip6(via->rtvia_addr, npt, perror)); 345 default: 346 *perror = ENOTSUP; 347 return (NULL); 348 } 349 } 350 351 int 352 nlattr_get_ipvia(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 353 void *target) 354 { 355 int error = 0; 356 357 struct sockaddr *sa = parse_rta_via((struct rtattr *)nla, npt, &error); 358 359 *((struct sockaddr **)target) = sa; 360 return (error); 361 } 362 363 int 364 nlattr_get_bool(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 365 void *target) 366 { 367 if (__predict_false(NLA_DATA_LEN(nla) != sizeof(bool))) { 368 NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not bool", 369 nla->nla_type, NLA_DATA_LEN(nla)); 370 return (EINVAL); 371 } 372 *((bool *)target) = *((const bool *)NL_RTA_DATA_CONST(nla)); 373 return (0); 374 } 375 376 int 377 nlattr_get_uint8(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 378 void *target) 379 { 380 if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint8_t))) { 381 NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint8", 382 nla->nla_type, NLA_DATA_LEN(nla)); 383 return (EINVAL); 384 } 385 *((uint8_t *)target) = *((const uint8_t *)NL_RTA_DATA_CONST(nla)); 386 return (0); 387 } 388 389 int 390 nlattr_get_uint16(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 391 void *target) 392 { 393 if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint16_t))) { 394 NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint16", 395 nla->nla_type, NLA_DATA_LEN(nla)); 396 return (EINVAL); 397 } 398 *((uint16_t *)target) = *((const uint16_t *)NL_RTA_DATA_CONST(nla)); 399 return (0); 400 } 401 402 int 403 nlattr_get_uint32(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 404 void *target) 405 { 406 if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint32_t))) { 407 NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint32", 408 nla->nla_type, NLA_DATA_LEN(nla)); 409 return (EINVAL); 410 } 411 *((uint32_t *)target) = *((const uint32_t *)NL_RTA_DATA_CONST(nla)); 412 return (0); 413 } 414 415 int 416 nlattr_get_uint64(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 417 void *target) 418 { 419 if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint64_t))) { 420 NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint64", 421 nla->nla_type, NLA_DATA_LEN(nla)); 422 return (EINVAL); 423 } 424 memcpy(target, NL_RTA_DATA_CONST(nla), sizeof(uint64_t)); 425 return (0); 426 } 427 428 int 429 nlattr_get_in_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 430 void *target) 431 { 432 if (__predict_false(NLA_DATA_LEN(nla) != sizeof(in_addr_t))) { 433 NLMSG_REPORT_ERR_MSG(npt, 434 "nla type %d size(%u) is not in_addr_t", 435 nla->nla_type, NLA_DATA_LEN(nla)); 436 return (EINVAL); 437 } 438 memcpy(target, NLA_DATA_CONST(nla), sizeof(in_addr_t)); 439 return (0); 440 } 441 442 int 443 nlattr_get_in6_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 444 void *target) 445 { 446 if (__predict_false(NLA_DATA_LEN(nla) != sizeof(struct in6_addr))) { 447 NLMSG_REPORT_ERR_MSG(npt, 448 "nla type %d size(%u) is not struct in6_addr", 449 nla->nla_type, NLA_DATA_LEN(nla)); 450 return (EINVAL); 451 } 452 memcpy(target, NLA_DATA_CONST(nla), sizeof(struct in6_addr)); 453 return (0); 454 } 455 456 static int 457 nlattr_get_ifp_internal(struct nlattr *nla, struct nl_pstate *npt, 458 void *target, bool zero_ok) 459 { 460 struct ifnet *ifp; 461 u_int ifindex; 462 463 if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint32_t))) { 464 NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint32", 465 nla->nla_type, NLA_DATA_LEN(nla)); 466 return (EINVAL); 467 } 468 ifindex = *((const u_int *)NLA_DATA_CONST(nla)); 469 470 if (ifindex == 0 && zero_ok) { 471 *((struct ifnet **)target) = NULL; 472 return (0); 473 } 474 475 NET_EPOCH_ASSERT(); 476 477 ifp = ifnet_byindex(ifindex); 478 if (__predict_false(ifp == NULL)) { 479 NLMSG_REPORT_ERR_MSG(npt, "nla type %d: ifindex %u invalid", 480 nla->nla_type, ifindex); 481 return (ENOENT); 482 } 483 *((struct ifnet **)target) = ifp; 484 NL_LOG(LOG_DEBUG3, "nla type %d: ifindex %u -> %s", nla->nla_type, 485 ifindex, if_name(ifp)); 486 487 return (0); 488 } 489 490 int 491 nlattr_get_ifp(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 492 void *target) 493 { 494 return (nlattr_get_ifp_internal(nla, npt, target, false)); 495 } 496 497 int 498 nlattr_get_ifpz(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 499 void *target) 500 { 501 return (nlattr_get_ifp_internal(nla, npt, target, true)); 502 } 503 504 int 505 nlattr_get_chara(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 506 void *target) 507 { 508 int maxlen = NLA_DATA_LEN(nla); 509 int target_size = (size_t)arg; 510 int len = strnlen((char *)NLA_DATA(nla), maxlen); 511 512 if (__predict_false(len >= maxlen) || 513 __predict_false(len >= target_size)) { 514 NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not " 515 "NULL-terminated or longer than %u", 516 nla->nla_type, maxlen, target_size); 517 return (EINVAL); 518 } 519 520 strncpy((char *)target, (char *)NLA_DATA(nla), target_size); 521 return (0); 522 } 523 524 int 525 nlattr_get_string(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 526 void *target) 527 { 528 int maxlen = NLA_DATA_LEN(nla); 529 530 if (__predict_false(strnlen((char *)NLA_DATA(nla), maxlen) >= maxlen)) { 531 NLMSG_REPORT_ERR_MSG(npt, 532 "nla type %d size(%u) is not NULL-terminated", 533 nla->nla_type, maxlen); 534 return (EINVAL); 535 } 536 537 *((char **)target) = (char *)NLA_DATA(nla); 538 return (0); 539 } 540 541 int 542 nlattr_get_stringn(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 543 void *target) 544 { 545 int maxlen = NLA_DATA_LEN(nla); 546 547 char *buf = npt_alloc(npt, maxlen + 1); 548 if (buf == NULL) 549 return (ENOMEM); 550 buf[maxlen] = '\0'; 551 memcpy(buf, NLA_DATA(nla), maxlen); 552 553 *((char **)target) = buf; 554 return (0); 555 } 556 557 int 558 nlattr_get_bytes(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 559 void *target) 560 { 561 size_t size = (size_t)arg; 562 563 if (NLA_DATA_LEN(nla) != size) 564 return (EINVAL); 565 566 memcpy(target, NLA_DATA(nla), size); 567 568 return (0); 569 } 570 571 int 572 nlattr_get_nla(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 573 void *target) 574 { 575 NL_LOG(LOG_DEBUG3, "STORING %p len %d", nla, nla->nla_len); 576 *((struct nlattr **)target) = nla; 577 return (0); 578 } 579 580 int 581 nlattr_get_nested(struct nlattr *nla, struct nl_pstate *npt, const void *arg, 582 void *target) 583 { 584 const struct nlhdr_parser *p = (const struct nlhdr_parser *)arg; 585 586 /* Assumes target points to the beginning of the structure. */ 587 return (nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), p, npt, 588 target)); 589 } 590 591 int 592 nlattr_get_nested_ptr(struct nlattr *nla, struct nl_pstate *npt, 593 const void *arg, void *target) 594 { 595 const struct nlhdr_parser *p = (const struct nlhdr_parser *)arg; 596 597 /* Assumes target points to the beginning of the structure. */ 598 return (nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), p, npt, 599 *(void **)target)); 600 } 601 602 int 603 nlf_get_ifp(void *src, struct nl_pstate *npt, void *target) 604 { 605 struct ifnet *ifp; 606 u_int ifindex; 607 608 NET_EPOCH_ASSERT(); 609 610 ifindex = *((const u_int *)src); 611 ifp = ifnet_byindex(ifindex); 612 if (ifp == NULL) { 613 NL_LOG(LOG_DEBUG, "ifindex %u invalid", ifindex); 614 return (ENOENT); 615 } 616 *((struct ifnet **)target) = ifp; 617 618 return (0); 619 } 620 621 int 622 nlf_get_ifpz(void *src, struct nl_pstate *npt, void *target) 623 { 624 struct ifnet *ifp; 625 u_int ifindex; 626 627 NET_EPOCH_ASSERT(); 628 629 ifindex = *((const u_int *)src); 630 ifp = ifnet_byindex(ifindex); 631 if (ifindex != 0 && ifp == NULL) { 632 NL_LOG(LOG_DEBUG, "ifindex %u invalid", ifindex); 633 return (ENOENT); 634 } 635 *((struct ifnet **)target) = ifp; 636 637 return (0); 638 } 639 640 int 641 nlf_get_u8(void *src, struct nl_pstate *npt, void *target) 642 { 643 uint8_t val = *((const uint8_t *)src); 644 645 *((uint8_t *)target) = val; 646 647 return (0); 648 } 649 650 int 651 nlf_get_u8_u32(void *src, struct nl_pstate *npt, void *target) 652 { 653 *((uint32_t *)target) = *((const uint8_t *)src); 654 return (0); 655 } 656 657 int 658 nlf_get_u16(void *src, struct nl_pstate *npt, void *target) 659 { 660 *((uint16_t *)target) = *((const uint16_t *)src); 661 return (0); 662 } 663 664 int 665 nlf_get_u32(void *src, struct nl_pstate *npt, void *target) 666 { 667 *((uint32_t *)target) = *((const uint32_t *)src); 668 return (0); 669 } 670