1 /* $NetBSD: if_mpls.c,v 1.41 2022/09/03 20:29:31 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Mihai Chelaru <kefren@NetBSD.org> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: if_mpls.c,v 1.41 2022/09/03 20:29:31 thorpej Exp $"); 34 35 #ifdef _KERNEL_OPT 36 #include "opt_inet.h" 37 #include "opt_mpls.h" 38 #endif 39 40 #include <sys/param.h> 41 42 #include <sys/errno.h> 43 #include <sys/malloc.h> 44 #include <sys/mbuf.h> 45 #include <sys/sysctl.h> 46 47 #include <net/bpf.h> 48 #include <net/if.h> 49 #include <net/if_types.h> 50 #include <net/route.h> 51 #include <sys/device.h> 52 #include <sys/module.h> 53 #include <sys/atomic.h> 54 55 #ifdef INET 56 #include <netinet/in.h> 57 #include <netinet/in_systm.h> 58 #include <netinet/in_var.h> 59 #include <netinet/ip.h> 60 #include <netinet/ip_var.h> 61 #endif 62 63 #ifdef INET6 64 #include <netinet/ip6.h> 65 #include <netinet6/in6_var.h> 66 #include <netinet6/ip6_var.h> 67 #endif 68 69 #include <netmpls/mpls.h> 70 #include <netmpls/mpls_var.h> 71 72 #include "if_mpls.h" 73 74 #include "ioconf.h" 75 76 static int mpls_clone_create(struct if_clone *, int); 77 static int mpls_clone_destroy(struct ifnet *); 78 79 static struct if_clone mpls_if_cloner = 80 IF_CLONE_INITIALIZER("mpls", mpls_clone_create, mpls_clone_destroy); 81 82 static void mpls_input(struct ifnet *, struct mbuf *); 83 static int mpls_output(struct ifnet *, struct mbuf *, const struct sockaddr *, 84 const struct rtentry *); 85 static int mpls_ioctl(struct ifnet *, u_long, void *); 86 static int mpls_send_frame(struct mbuf *, struct ifnet *, 87 const struct rtentry *); 88 static int mpls_lse(struct mbuf *); 89 90 #ifdef INET 91 static struct mbuf *mpls_unlabel_inet(struct mbuf *, int *error); 92 static struct mbuf *mpls_label_inet(struct mbuf *, union mpls_shim *, uint); 93 #endif 94 95 #ifdef INET6 96 static struct mbuf *mpls_unlabel_inet6(struct mbuf *, int *error); 97 static struct mbuf *mpls_label_inet6(struct mbuf *, union mpls_shim *, uint); 98 #endif 99 100 static struct mbuf *mpls_prepend_shim(struct mbuf *, union mpls_shim *); 101 102 extern int mpls_defttl, mpls_mapttl_inet, mpls_mapttl_inet6, mpls_icmp_respond, 103 mpls_forwarding, mpls_frame_accept, mpls_mapprec_inet, mpls_mapclass_inet6, 104 mpls_rfc4182; 105 106 static u_int mpls_count; 107 108 void mplsattach(int); 109 110 /* ARGSUSED */ 111 void 112 mplsattach(int count) 113 { 114 /* 115 * Nothing to do here, initialization is handled by the 116 * module initialization code in mplsinit() below). 117 */ 118 } 119 120 static void 121 mplsinit(void) 122 { 123 if_clone_attach(&mpls_if_cloner); 124 } 125 126 static int 127 mplsdetach(void) 128 { 129 int error = 0; 130 131 if (mpls_count != 0) 132 error = EBUSY; 133 134 if (error == 0) 135 if_clone_detach(&mpls_if_cloner); 136 137 return error; 138 } 139 140 static int 141 mpls_clone_create(struct if_clone *ifc, int unit) 142 { 143 struct mpls_softc *sc; 144 145 atomic_inc_uint(&mpls_count); 146 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 147 148 if_initname(&sc->sc_if, ifc->ifc_name, unit); 149 sc->sc_if.if_softc = sc; 150 sc->sc_if.if_type = IFT_MPLS; 151 sc->sc_if.if_addrlen = 0; 152 sc->sc_if.if_hdrlen = sizeof(union mpls_shim); 153 sc->sc_if.if_dlt = DLT_NULL; 154 sc->sc_if.if_mtu = 1500; 155 sc->sc_if.if_flags = 0; 156 sc->sc_if._if_input = mpls_input; 157 sc->sc_if.if_output = mpls_output; 158 sc->sc_if.if_ioctl = mpls_ioctl; 159 160 if_attach(&sc->sc_if); 161 if_alloc_sadl(&sc->sc_if); 162 bpf_attach(&sc->sc_if, DLT_NULL, sizeof(uint32_t)); 163 return 0; 164 } 165 166 static int 167 mpls_clone_destroy(struct ifnet *ifp) 168 { 169 170 bpf_detach(ifp); 171 if_detach(ifp); 172 173 free(ifp->if_softc, M_DEVBUF); 174 atomic_dec_uint(&mpls_count); 175 return 0; 176 } 177 178 static void 179 mpls_input(struct ifnet *ifp, struct mbuf *m) 180 { 181 #if 0 182 /* 183 * TODO - kefren 184 * I'd love to unshim the packet, guess family 185 * and pass it to bpf 186 */ 187 bpf_mtap_af(ifp, AF_MPLS, m, BPF_D_IN); 188 #endif 189 190 mpls_lse(m); 191 } 192 193 void 194 mplsintr(void *arg __unused) 195 { 196 struct mbuf *m; 197 198 while ((m = pktq_dequeue(mpls_pktq)) != NULL) { 199 if (((m->m_flags & M_PKTHDR) == 0) || 200 (m->m_pkthdr.rcvif_index == 0)) 201 panic("mplsintr(): no pkthdr or rcvif"); 202 203 #ifdef MBUFTRACE 204 m_claimm(m, &mpls_owner); 205 #endif 206 mpls_input(m_get_rcvif_NOMPSAFE(m), m); 207 } 208 } 209 210 /* 211 * prepend shim and deliver 212 */ 213 static int 214 mpls_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 215 const struct rtentry *rt) 216 { 217 union mpls_shim mh, *pms; 218 struct rtentry *rt1; 219 int err; 220 uint psize = sizeof(struct sockaddr_mpls); 221 222 KASSERT(KERNEL_LOCKED_P()); 223 224 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 225 m_freem(m); 226 return ENETDOWN; 227 } 228 229 if (rt_gettag(rt) == NULL || rt_gettag(rt)->sa_family != AF_MPLS) { 230 m_freem(m); 231 return EINVAL; 232 } 233 234 bpf_mtap_af(ifp, dst->sa_family, m, BPF_D_OUT); 235 236 memset(&mh, 0, sizeof(mh)); 237 mh.s_addr = MPLS_GETSADDR(rt); 238 mh.shim.bos = 1; 239 mh.shim.exp = 0; 240 mh.shim.ttl = mpls_defttl; 241 242 pms = &((struct sockaddr_mpls*)rt_gettag(rt))->smpls_addr; 243 244 while (psize <= rt_gettag(rt)->sa_len - sizeof(mh)) { 245 pms++; 246 if (mh.shim.label != MPLS_LABEL_IMPLNULL && 247 ((m = mpls_prepend_shim(m, &mh)) == NULL)) 248 return ENOBUFS; 249 memset(&mh, 0, sizeof(mh)); 250 mh.s_addr = ntohl(pms->s_addr); 251 mh.shim.bos = mh.shim.exp = 0; 252 mh.shim.ttl = mpls_defttl; 253 psize += sizeof(mh); 254 } 255 256 switch (dst->sa_family) { 257 #ifdef INET 258 case AF_INET: 259 m = mpls_label_inet(m, &mh, psize - sizeof(struct sockaddr_mpls)); 260 break; 261 #endif 262 #ifdef INET6 263 case AF_INET6: 264 m = mpls_label_inet6(m, &mh, psize - sizeof(struct sockaddr_mpls)); 265 break; 266 #endif 267 default: 268 m = mpls_prepend_shim(m, &mh); 269 break; 270 } 271 272 if (m == NULL) { 273 IF_DROP(&ifp->if_snd); 274 if_statinc(ifp, if_oerrors); 275 return ENOBUFS; 276 } 277 278 if_statadd2(ifp, if_opackets, 1, if_obytes, m->m_pkthdr.len); 279 280 if ((rt1 = rtalloc1(rt->rt_gateway, 1)) == NULL) { 281 m_freem(m); 282 return EHOSTUNREACH; 283 } 284 285 err = mpls_send_frame(m, rt1->rt_ifp, rt); 286 rt_unref(rt1); 287 return err; 288 } 289 290 static int 291 mpls_ioctl(struct ifnet *ifp, u_long cmd, void *data) 292 { 293 int error = 0, s = splnet(); 294 struct ifreq *ifr = data; 295 296 switch(cmd) { 297 case SIOCINITIFADDR: 298 ifp->if_flags |= IFF_UP | IFF_RUNNING; 299 break; 300 case SIOCSIFMTU: 301 if (ifr != NULL && ifr->ifr_mtu < 576) { 302 error = EINVAL; 303 break; 304 } 305 /* FALLTHROUGH */ 306 case SIOCGIFMTU: 307 if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 308 error = 0; 309 break; 310 case SIOCSIFFLAGS: 311 if ((error = ifioctl_common(ifp, cmd, data)) != 0) 312 break; 313 if (ifp->if_flags & IFF_UP) 314 ifp->if_flags |= IFF_RUNNING; 315 break; 316 default: 317 error = ifioctl_common(ifp, cmd, data); 318 break; 319 } 320 splx(s); 321 return error; 322 } 323 324 static inline struct mbuf * 325 mpls_trim_label(struct mbuf *m, union mpls_shim *sh) 326 { 327 m_adj(m, sizeof(union mpls_shim)); 328 329 if (m->m_len < sizeof(union mpls_shim) && 330 (m = m_pullup(m, sizeof(union mpls_shim))) == NULL) 331 return NULL; 332 333 sh->s_addr = ntohl(mtod(m, union mpls_shim *)->s_addr); 334 335 return m; 336 } 337 338 /* 339 * MPLS Label Switch Engine 340 */ 341 static int 342 mpls_lse(struct mbuf *m) 343 { 344 struct sockaddr_mpls dst; 345 union mpls_shim tshim, *htag; 346 struct rtentry *rt = NULL; 347 int error = ENOBUFS; 348 uint psize = sizeof(struct sockaddr_mpls); 349 bool push_back_alert = false; 350 351 /* If we're not accepting MPLS frames, leave now. */ 352 if (!mpls_frame_accept) { 353 error = EINVAL; 354 goto done; 355 } 356 357 if (m->m_len < sizeof(union mpls_shim) && 358 (m = m_pullup(m, sizeof(union mpls_shim))) == NULL) 359 goto done; 360 361 dst.smpls_len = sizeof(struct sockaddr_mpls); 362 dst.smpls_family = AF_MPLS; 363 dst.smpls_addr.s_addr = ntohl(mtod(m, union mpls_shim *)->s_addr); 364 365 error = EINVAL; 366 367 /* TTL decrement */ 368 if ((m = mpls_ttl_dec(m)) == NULL) 369 goto done; 370 371 /* RFC 4182 */ 372 if (mpls_rfc4182 != 0) { 373 while ((dst.smpls_addr.shim.label == MPLS_LABEL_IPV4NULL || 374 dst.smpls_addr.shim.label == MPLS_LABEL_IPV6NULL) && 375 __predict_false(dst.smpls_addr.shim.bos == 0)) { 376 m = mpls_trim_label(m, &dst.smpls_addr); 377 if (m == NULL) { 378 goto done; 379 } 380 } 381 } 382 383 /* RFC 3032 Section 2.1 Page 4 */ 384 if (__predict_false(dst.smpls_addr.shim.label == MPLS_LABEL_RTALERT) && 385 dst.smpls_addr.shim.bos == 0) { 386 m = mpls_trim_label(m, &dst.smpls_addr); 387 if (m == NULL) { 388 goto done; 389 } 390 push_back_alert = true; 391 } 392 393 if (dst.smpls_addr.shim.label <= MPLS_LABEL_RESMAX) { 394 /* Don't swap reserved labels */ 395 switch (dst.smpls_addr.shim.label) { 396 #ifdef INET 397 case MPLS_LABEL_IPV4NULL: 398 /* Pop shim and push mbuf to IP stack */ 399 if (dst.smpls_addr.shim.bos) { 400 m = mpls_unlabel_inet(m, &error); 401 } 402 break; 403 #endif 404 #ifdef INET6 405 case MPLS_LABEL_IPV6NULL: 406 /* Pop shim and push mbuf to IPv6 stack */ 407 if (dst.smpls_addr.shim.bos) { 408 m = mpls_unlabel_inet6(m, &error); 409 } 410 break; 411 #endif 412 case MPLS_LABEL_RTALERT: /* Yeah, I'm all alerted */ 413 case MPLS_LABEL_IMPLNULL: /* This is logical only */ 414 default: /* Rest are not allowed */ 415 break; 416 } 417 goto done; 418 } 419 420 /* Check if we should do MPLS forwarding */ 421 error = EHOSTUNREACH; 422 if (!mpls_forwarding) 423 goto done; 424 425 /* Get a route to dst */ 426 dst.smpls_addr.shim.ttl = 0; 427 dst.smpls_addr.shim.bos = 0; 428 dst.smpls_addr.shim.exp = 0; 429 dst.smpls_addr.s_addr = htonl(dst.smpls_addr.s_addr); 430 if ((rt = rtalloc1((const struct sockaddr*)&dst, 1)) == NULL) 431 goto done; 432 433 /* MPLS packet with no MPLS tagged route ? */ 434 if ((rt->rt_flags & RTF_GATEWAY) == 0 || 435 rt_gettag(rt) == NULL || 436 rt_gettag(rt)->sa_family != AF_MPLS) 437 goto done; 438 439 tshim.s_addr = MPLS_GETSADDR(rt); 440 441 /* Swap labels */ 442 if ((m->m_len < sizeof(union mpls_shim)) && 443 (m = m_pullup(m, sizeof(union mpls_shim))) == 0) { 444 error = ENOBUFS; 445 goto done; 446 } 447 448 /* Replace only the label */ 449 htag = mtod(m, union mpls_shim *); 450 htag->s_addr = ntohl(htag->s_addr); 451 htag->shim.label = tshim.shim.label; 452 htag->s_addr = htonl(htag->s_addr); 453 454 /* check if there is anything more to prepend */ 455 htag = &((struct sockaddr_mpls*)rt_gettag(rt))->smpls_addr; 456 while (psize <= rt_gettag(rt)->sa_len - sizeof(tshim)) { 457 htag++; 458 memset(&tshim, 0, sizeof(tshim)); 459 tshim.s_addr = ntohl(htag->s_addr); 460 tshim.shim.bos = tshim.shim.exp = 0; 461 tshim.shim.ttl = mpls_defttl; 462 if (tshim.shim.label != MPLS_LABEL_IMPLNULL && 463 ((m = mpls_prepend_shim(m, &tshim)) == NULL)) { 464 error = ENOBUFS; 465 goto done; 466 } 467 psize += sizeof(tshim); 468 } 469 470 if (__predict_false(push_back_alert == true)) { 471 /* re-add the router alert label */ 472 memset(&tshim, 0, sizeof(tshim)); 473 tshim.s_addr = MPLS_LABEL_RTALERT; 474 tshim.shim.bos = tshim.shim.exp = 0; 475 tshim.shim.ttl = mpls_defttl; 476 if ((m = mpls_prepend_shim(m, &tshim)) == NULL) { 477 error = ENOBUFS; 478 goto done; 479 } 480 } 481 482 if ((rt->rt_flags & RTF_GATEWAY) == 0) { 483 error = EHOSTUNREACH; 484 goto done; 485 } 486 487 rt->rt_use++; 488 error = mpls_send_frame(m, rt->rt_ifp, rt); 489 490 done: 491 if (error != 0 && m != NULL) 492 m_freem(m); 493 if (rt != NULL) 494 rt_unref(rt); 495 496 return error; 497 } 498 499 static int 500 mpls_send_frame(struct mbuf *m, struct ifnet *ifp, const struct rtentry *rt) 501 { 502 union mpls_shim msh; 503 int ret; 504 505 msh.s_addr = MPLS_GETSADDR(rt); 506 if (msh.shim.label == MPLS_LABEL_IMPLNULL || 507 (m->m_flags & (M_MCAST | M_BCAST))) { 508 m_adj(m, sizeof(union mpls_shim)); 509 m->m_pkthdr.csum_flags = 0; 510 } 511 512 switch(ifp->if_type) { 513 /* only these are supported for now */ 514 case IFT_ETHER: 515 case IFT_TUNNEL: 516 case IFT_LOOP: 517 #ifdef INET 518 ret = ip_if_output(ifp, m, rt->rt_gateway, rt); 519 #else 520 ret = if_output_lock(ifp, ifp, m, rt->rt_gateway, rt); 521 #endif 522 return ret; 523 break; 524 default: 525 return ENETUNREACH; 526 } 527 return 0; 528 } 529 530 #ifdef INET 531 static struct mbuf * 532 mpls_unlabel_inet(struct mbuf *m, int *error) 533 { 534 struct ip *iph; 535 union mpls_shim ms; 536 int iphlen; 537 538 if (mpls_mapttl_inet || mpls_mapprec_inet) { 539 /* get shim info */ 540 ms.s_addr = ntohl(mtod(m, union mpls_shim *)->s_addr); 541 542 /* and get rid of it */ 543 m_adj(m, sizeof(union mpls_shim)); 544 545 /* get ip header */ 546 if (m->m_len < sizeof(struct ip) && 547 (m = m_pullup(m, sizeof(struct ip))) == NULL) { 548 *error = ENOBUFS; 549 return NULL; 550 } 551 552 iph = mtod(m, struct ip *); 553 iphlen = iph->ip_hl << 2; 554 555 /* get it all */ 556 if (m->m_len < iphlen) { 557 if ((m = m_pullup(m, iphlen)) == NULL) { 558 *error = ENOBUFS; 559 return NULL; 560 } 561 iph = mtod(m, struct ip *); 562 } 563 564 /* check ipsum */ 565 if (in_cksum(m, iphlen) != 0) { 566 m_freem(m); 567 *error = EINVAL; 568 return NULL; 569 } 570 571 /* set IP ttl from MPLS ttl */ 572 if (mpls_mapttl_inet) 573 iph->ip_ttl = ms.shim.ttl; 574 575 /* set IP Precedence from MPLS Exp */ 576 if (mpls_mapprec_inet) { 577 iph->ip_tos = (iph->ip_tos << 3) >> 3; 578 iph->ip_tos |= ms.shim.exp << 5; 579 } 580 581 /* reset ipsum because we modified TTL and TOS */ 582 iph->ip_sum = 0; 583 iph->ip_sum = in_cksum(m, iphlen); 584 } else { 585 m_adj(m, sizeof(union mpls_shim)); 586 } 587 588 /* Put it on IP queue */ 589 if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) { 590 m_freem(m); 591 *error = ENOBUFS; 592 return NULL; 593 } 594 595 *error = 0; 596 return m; 597 } 598 599 /* 600 * Prepend MPLS label 601 */ 602 static struct mbuf * 603 mpls_label_inet(struct mbuf *m, union mpls_shim *ms, uint offset) 604 { 605 struct ip iphdr; 606 607 if (mpls_mapttl_inet || mpls_mapprec_inet) { 608 /* XXX Maybe just check m->m_pkthdr.len instead? */ 609 if ((m->m_len < offset + sizeof(struct ip)) && 610 (m = m_pullup(m, offset + sizeof(struct ip))) == 0) 611 return NULL; 612 613 m_copydata(m, offset, sizeof(struct ip), &iphdr); 614 615 /* Map TTL */ 616 if (mpls_mapttl_inet) 617 ms->shim.ttl = iphdr.ip_ttl; 618 619 /* Copy IP precedence to EXP */ 620 if (mpls_mapprec_inet) 621 ms->shim.exp = ((u_int8_t)iphdr.ip_tos) >> 5; 622 } 623 624 if ((m = mpls_prepend_shim(m, ms)) == NULL) 625 return NULL; 626 627 return m; 628 } 629 #endif /* INET */ 630 631 #ifdef INET6 632 static struct mbuf * 633 mpls_unlabel_inet6(struct mbuf *m, int *error) 634 { 635 struct ip6_hdr *ip6hdr; 636 union mpls_shim ms; 637 638 /* TODO: mapclass */ 639 if (mpls_mapttl_inet6) { 640 ms.s_addr = ntohl(mtod(m, union mpls_shim *)->s_addr); 641 m_adj(m, sizeof(union mpls_shim)); 642 643 if (m->m_len < sizeof(struct ip6_hdr) && 644 (m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) { 645 *error = ENOBUFS; 646 return NULL; 647 } 648 ip6hdr = mtod(m, struct ip6_hdr *); 649 650 /* Because we just decremented this in mpls_lse */ 651 ip6hdr->ip6_hlim = ms.shim.ttl + 1; 652 } else { 653 m_adj(m, sizeof(union mpls_shim)); 654 } 655 656 /* Put it back on IPv6 queue. */ 657 if (__predict_false(!pktq_enqueue(ip6_pktq, m, 0))) { 658 m_freem(m); 659 *error = ENOBUFS; 660 return NULL; 661 } 662 663 *error = 0; 664 return m; 665 } 666 667 static struct mbuf * 668 mpls_label_inet6(struct mbuf *m, union mpls_shim *ms, uint offset) 669 { 670 struct ip6_hdr ip6h; 671 672 if (mpls_mapttl_inet6 || mpls_mapclass_inet6) { 673 /* XXX Maybe just check m->m_pkthdr.len instead? */ 674 if ((m->m_len < offset + sizeof(struct ip6_hdr)) && 675 (m = m_pullup(m, offset + sizeof(struct ip6_hdr))) == 0) 676 return NULL; 677 678 m_copydata(m, offset, sizeof(struct ip6_hdr), &ip6h); 679 680 if (mpls_mapttl_inet6) 681 ms->shim.ttl = ip6h.ip6_hlim; 682 683 if (mpls_mapclass_inet6) 684 ms->shim.exp = ip6h.ip6_vfc << 1 >> 5; 685 } 686 687 if ((m = mpls_prepend_shim(m, ms)) == NULL) 688 return NULL; 689 690 return m; 691 } 692 #endif /* INET6 */ 693 694 static struct mbuf * 695 mpls_prepend_shim(struct mbuf *m, union mpls_shim *ms) 696 { 697 union mpls_shim *shim; 698 699 M_PREPEND(m, sizeof(*ms), M_DONTWAIT); 700 if (m == NULL) 701 return NULL; 702 703 if (m->m_len < sizeof(union mpls_shim) && 704 (m = m_pullup(m, sizeof(union mpls_shim))) == 0) 705 return NULL; 706 707 shim = mtod(m, union mpls_shim *); 708 709 memcpy(shim, ms, sizeof(*shim)); 710 shim->s_addr = htonl(shim->s_addr); 711 712 return m; 713 } 714 715 /* 716 * Module infrastructure 717 */ 718 #include "if_module.h" 719 720 IF_MODULE(MODULE_CLASS_DRIVER, mpls, NULL) 721