1 /* $OpenBSD: if_mpip.c,v 1.8 2019/06/26 08:13:13 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Rafael Zalamena <rzalamena@openbsd.org> 5 * Copyright (c) 2019 David Gwynne <dlg@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include "bpfilter.h" 21 22 #include <sys/param.h> 23 #include <sys/systm.h> 24 #include <sys/mbuf.h> 25 #include <sys/socket.h> 26 #include <sys/ioctl.h> 27 #include <sys/errno.h> 28 29 #include <net/if.h> 30 #include <net/if_var.h> 31 #include <net/if_dl.h> 32 #include <net/if_types.h> 33 #include <net/route.h> 34 35 #include <netinet/in.h> 36 #include <netinet/ip.h> 37 38 #ifdef INET6 39 #include <netinet/ip6.h> 40 #endif 41 42 #include <netmpls/mpls.h> 43 44 #if NBPFILTER > 0 45 #include <net/bpf.h> 46 #endif /* NBPFILTER */ 47 48 struct mpip_neighbor { 49 struct shim_hdr n_rshim; 50 struct sockaddr_storage n_nexthop; 51 }; 52 53 struct mpip_softc { 54 struct ifnet sc_if; 55 unsigned int sc_dead; 56 uint32_t sc_flow; /* xor for mbuf flowid */ 57 58 int sc_txhprio; 59 int sc_rxhprio; 60 struct ifaddr sc_ifa; 61 struct sockaddr_mpls sc_smpls; /* Local label */ 62 unsigned int sc_rdomain; 63 struct mpip_neighbor *sc_neighbor; 64 65 unsigned int sc_cword; /* control word */ 66 unsigned int sc_fword; /* flow-aware transport */ 67 int sc_ttl; 68 }; 69 70 void mpipattach(int); 71 int mpip_clone_create(struct if_clone *, int); 72 int mpip_clone_destroy(struct ifnet *); 73 int mpip_ioctl(struct ifnet *, u_long, caddr_t); 74 int mpip_output(struct ifnet *, struct mbuf *, struct sockaddr *, 75 struct rtentry *); 76 void mpip_start(struct ifnet *); 77 78 struct if_clone mpip_cloner = 79 IF_CLONE_INITIALIZER("mpip", mpip_clone_create, mpip_clone_destroy); 80 81 void 82 mpipattach(int n) 83 { 84 if_clone_attach(&mpip_cloner); 85 } 86 87 int 88 mpip_clone_create(struct if_clone *ifc, int unit) 89 { 90 struct mpip_softc *sc; 91 struct ifnet *ifp; 92 93 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO); 94 if (sc == NULL) 95 return (ENOMEM); 96 97 sc->sc_txhprio = 0; 98 sc->sc_rxhprio = IF_HDRPRIO_PACKET; 99 sc->sc_neighbor = 0; 100 sc->sc_cword = 0; /* default to no control word */ 101 sc->sc_fword = 0; /* both sides have to agree on FAT first */ 102 sc->sc_flow = arc4random() & 0xfffff; 103 sc->sc_smpls.smpls_len = sizeof(sc->sc_smpls); 104 sc->sc_smpls.smpls_family = AF_MPLS; 105 sc->sc_ttl = -1; 106 107 ifp = &sc->sc_if; 108 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 109 ifc->ifc_name, unit); 110 ifp->if_softc = sc; 111 ifp->if_type = IFT_TUNNEL; 112 ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 113 ifp->if_xflags = IFXF_CLONED; 114 ifp->if_ioctl = mpip_ioctl; 115 ifp->if_output = mpip_output; 116 ifp->if_start = mpip_start; 117 ifp->if_rtrequest = p2p_rtrequest; 118 ifp->if_mtu = 1500; 119 ifp->if_hardmtu = 65535; 120 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 121 122 if_attach(ifp); 123 if_counters_alloc(ifp); 124 if_alloc_sadl(ifp); 125 126 #if NBPFILTER > 0 127 bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t)); 128 #endif 129 130 sc->sc_ifa.ifa_ifp = ifp; 131 sc->sc_ifa.ifa_addr = sdltosa(ifp->if_sadl); 132 133 return (0); 134 } 135 136 int 137 mpip_clone_destroy(struct ifnet *ifp) 138 { 139 struct mpip_softc *sc = ifp->if_softc; 140 141 NET_LOCK(); 142 ifp->if_flags &= ~IFF_RUNNING; 143 sc->sc_dead = 1; 144 145 if (sc->sc_smpls.smpls_label) { 146 rt_ifa_del(&sc->sc_ifa, RTF_LOCAL | RTF_MPLS, 147 smplstosa(&sc->sc_smpls), 0); 148 } 149 NET_UNLOCK(); 150 151 ifq_barrier(&ifp->if_snd); 152 153 if_detach(ifp); 154 155 free(sc->sc_neighbor, M_DEVBUF, sizeof(*sc->sc_neighbor)); 156 free(sc, M_DEVBUF, sizeof(*sc)); 157 158 return (0); 159 } 160 161 static int 162 mpip_set_route(struct mpip_softc *sc, uint32_t shim, unsigned int rdomain) 163 { 164 int error; 165 166 rt_ifa_del(&sc->sc_ifa, RTF_MPLS | RTF_LOCAL, 167 smplstosa(&sc->sc_smpls), 0); 168 169 sc->sc_smpls.smpls_label = shim; 170 sc->sc_rdomain = rdomain; 171 172 error = rt_ifa_add(&sc->sc_ifa, RTF_MPLS | RTF_LOCAL, 173 smplstosa(&sc->sc_smpls), 0); 174 if (error) { 175 sc->sc_smpls.smpls_label = MPLS_LABEL2SHIM(0); 176 return (error); 177 } 178 179 return (0); 180 } 181 182 static int 183 mpip_set_label(struct mpip_softc *sc, struct ifreq *ifr) 184 { 185 struct shim_hdr label; 186 uint32_t shim; 187 int error; 188 189 error = copyin(ifr->ifr_data, &label, sizeof(label)); 190 if (error != 0) 191 return (error); 192 193 if (label.shim_label > MPLS_LABEL_MAX || 194 label.shim_label <= MPLS_LABEL_RESERVED_MAX) 195 return (EINVAL); 196 197 shim = MPLS_LABEL2SHIM(label.shim_label); 198 199 if (sc->sc_smpls.smpls_label == shim) 200 return (0); 201 202 return (mpip_set_route(sc, shim, sc->sc_rdomain)); 203 } 204 205 static int 206 mpip_get_label(struct mpip_softc *sc, struct ifreq *ifr) 207 { 208 struct shim_hdr label; 209 210 label.shim_label = MPLS_SHIM2LABEL(sc->sc_smpls.smpls_label); 211 212 if (label.shim_label == 0) 213 return (EADDRNOTAVAIL); 214 215 return (copyout(&label, ifr->ifr_data, sizeof(label))); 216 } 217 218 static int 219 mpip_del_label(struct mpip_softc *sc) 220 { 221 if (sc->sc_smpls.smpls_label != MPLS_LABEL2SHIM(0)) { 222 rt_ifa_del(&sc->sc_ifa, RTF_MPLS | RTF_LOCAL, 223 smplstosa(&sc->sc_smpls), 0); 224 } 225 226 sc->sc_smpls.smpls_label = MPLS_LABEL2SHIM(0); 227 228 return (0); 229 } 230 231 static int 232 mpip_set_neighbor(struct mpip_softc *sc, struct if_laddrreq *req) 233 { 234 struct mpip_neighbor *n, *o; 235 struct sockaddr *sa = (struct sockaddr *)&req->addr; 236 struct sockaddr_mpls *smpls = (struct sockaddr_mpls *)&req->dstaddr; 237 uint32_t label; 238 239 if (smpls->smpls_family != AF_MPLS) 240 return (EINVAL); 241 label = smpls->smpls_label; 242 if (label > MPLS_LABEL_MAX || label <= MPLS_LABEL_RESERVED_MAX) 243 return (EINVAL); 244 245 switch (sa->sa_family) { 246 case AF_INET: { 247 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 248 249 if (in_nullhost(sin->sin_addr) || 250 IN_MULTICAST(sin->sin_addr.s_addr)) 251 return (EINVAL); 252 253 break; 254 } 255 #ifdef INET6 256 case AF_INET6: { 257 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 258 259 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || 260 IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 261 return (EINVAL); 262 263 /* check scope */ 264 265 break; 266 } 267 #endif 268 default: 269 return (EAFNOSUPPORT); 270 } 271 272 if (sc->sc_dead) 273 return (ENXIO); 274 275 n = malloc(sizeof(*n), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO); 276 if (n == NULL) 277 return (ENOMEM); 278 279 n->n_rshim.shim_label = MPLS_LABEL2SHIM(label); 280 n->n_nexthop = req->addr; 281 282 o = sc->sc_neighbor; 283 sc->sc_neighbor = n; 284 285 NET_UNLOCK(); 286 ifq_barrier(&sc->sc_if.if_snd); 287 NET_LOCK(); 288 289 free(o, M_DEVBUF, sizeof(*o)); 290 291 return (0); 292 } 293 294 static int 295 mpip_get_neighbor(struct mpip_softc *sc, struct if_laddrreq *req) 296 { 297 struct sockaddr_mpls *smpls = (struct sockaddr_mpls *)&req->dstaddr; 298 struct mpip_neighbor *n = sc->sc_neighbor; 299 300 if (n == NULL) 301 return (EADDRNOTAVAIL); 302 303 smpls->smpls_len = sizeof(*smpls); 304 smpls->smpls_family = AF_MPLS; 305 smpls->smpls_label = MPLS_SHIM2LABEL(n->n_rshim.shim_label); 306 req->addr = n->n_nexthop; 307 308 return (0); 309 } 310 311 static int 312 mpip_del_neighbor(struct mpip_softc *sc, struct ifreq *req) 313 { 314 struct mpip_neighbor *o; 315 316 if (sc->sc_dead) 317 return (ENXIO); 318 319 o = sc->sc_neighbor; 320 sc->sc_neighbor = NULL; 321 322 NET_UNLOCK(); 323 ifq_barrier(&sc->sc_if.if_snd); 324 NET_LOCK(); 325 326 free(o, M_DEVBUF, sizeof(*o)); 327 328 return (0); 329 } 330 331 int 332 mpip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 333 { 334 struct mpip_softc *sc = ifp->if_softc; 335 struct ifreq *ifr = (struct ifreq *)data; 336 int error = 0; 337 338 switch (cmd) { 339 case SIOCSIFADDR: 340 break; 341 case SIOCSIFFLAGS: 342 if ((ifp->if_flags & IFF_UP)) 343 ifp->if_flags |= IFF_RUNNING; 344 else 345 ifp->if_flags &= ~IFF_RUNNING; 346 break; 347 case SIOCSIFMTU: 348 if (ifr->ifr_mtu < 60 || /* XXX */ 349 ifr->ifr_mtu > 65536) /* XXX */ 350 error = EINVAL; 351 else 352 ifp->if_mtu = ifr->ifr_mtu; 353 break; 354 355 case SIOCGPWE3: 356 ifr->ifr_pwe3 = IF_PWE3_IP; 357 break; 358 case SIOCSPWE3CTRLWORD: 359 sc->sc_cword = ifr->ifr_pwe3 ? 1 : 0; 360 break; 361 case SIOCGPWE3CTRLWORD: 362 ifr->ifr_pwe3 = sc->sc_cword; 363 break; 364 case SIOCSPWE3FAT: 365 sc->sc_fword = ifr->ifr_pwe3 ? 1 : 0; 366 break; 367 case SIOCGPWE3FAT: 368 ifr->ifr_pwe3 = sc->sc_fword; 369 break; 370 371 case SIOCSETLABEL: 372 error = mpip_set_label(sc, ifr); 373 break; 374 case SIOCGETLABEL: 375 error = mpip_get_label(sc, ifr); 376 break; 377 case SIOCDELLABEL: 378 error = mpip_del_label(sc); 379 break; 380 381 case SIOCSPWE3NEIGHBOR: 382 error = mpip_set_neighbor(sc, (struct if_laddrreq *)data); 383 break; 384 case SIOCGPWE3NEIGHBOR: 385 error = mpip_get_neighbor(sc, (struct if_laddrreq *)data); 386 break; 387 case SIOCDPWE3NEIGHBOR: 388 error = mpip_del_neighbor(sc, ifr); 389 break; 390 391 case SIOCSLIFPHYRTABLE: 392 if (ifr->ifr_rdomainid < 0 || 393 ifr->ifr_rdomainid > RT_TABLEID_MAX || 394 !rtable_exists(ifr->ifr_rdomainid) || 395 ifr->ifr_rdomainid != rtable_l2(ifr->ifr_rdomainid)) { 396 error = EINVAL; 397 break; 398 } 399 if (sc->sc_rdomain != ifr->ifr_rdomainid) { 400 error = mpip_set_route(sc, sc->sc_smpls.smpls_label, 401 ifr->ifr_rdomainid); 402 } 403 break; 404 case SIOCGLIFPHYRTABLE: 405 ifr->ifr_rdomainid = sc->sc_rdomain; 406 break; 407 408 case SIOCSLIFPHYTTL: 409 if (ifr->ifr_ttl != -1 && 410 (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff)) { 411 error = EINVAL; 412 break; 413 } 414 415 /* commit */ 416 sc->sc_ttl = ifr->ifr_ttl; 417 break; 418 case SIOCGLIFPHYTTL: 419 ifr->ifr_ttl = sc->sc_ttl; 420 break; 421 422 case SIOCSTXHPRIO: 423 error = if_txhprio_l3_check(ifr->ifr_hdrprio); 424 if (error != 0) 425 break; 426 427 sc->sc_txhprio = ifr->ifr_hdrprio; 428 break; 429 case SIOCGTXHPRIO: 430 ifr->ifr_hdrprio = sc->sc_txhprio; 431 break; 432 433 case SIOCSRXHPRIO: 434 error = if_rxhprio_l3_check(ifr->ifr_hdrprio); 435 if (error != 0) 436 break; 437 438 sc->sc_rxhprio = ifr->ifr_hdrprio; 439 break; 440 case SIOCGRXHPRIO: 441 ifr->ifr_hdrprio = sc->sc_rxhprio; 442 break; 443 444 case SIOCADDMULTI: 445 case SIOCDELMULTI: 446 break; 447 448 default: 449 error = ENOTTY; 450 break; 451 } 452 453 return (error); 454 } 455 456 static void 457 mpip_input(struct mpip_softc *sc, struct mbuf *m) 458 { 459 struct ifnet *ifp = &sc->sc_if; 460 int rxprio = sc->sc_rxhprio; 461 uint32_t shim, exp; 462 struct mbuf *n; 463 uint8_t ttl, tos; 464 void (*input)(struct ifnet *, struct mbuf *); 465 466 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 467 goto drop; 468 469 shim = *mtod(m, uint32_t *); 470 m_adj(m, sizeof(shim)); 471 472 ttl = ntohl(shim & MPLS_TTL_MASK); 473 exp = ntohl(shim & MPLS_EXP_MASK) >> MPLS_EXP_OFFSET; 474 475 if (sc->sc_fword) { 476 uint32_t label; 477 478 if (MPLS_BOS_ISSET(shim)) 479 goto drop; 480 481 if (m->m_len < sizeof(shim)) { 482 m = m_pullup(m, sizeof(shim)); 483 if (m == NULL) 484 return; 485 } 486 487 shim = *mtod(m, uint32_t *); 488 if (!MPLS_BOS_ISSET(shim)) 489 goto drop; 490 491 label = MPLS_SHIM2LABEL(shim); 492 if (label <= MPLS_LABEL_RESERVED_MAX) { 493 counters_inc(ifp->if_counters, ifc_noproto); /* ? */ 494 goto drop; 495 } 496 497 label -= MPLS_LABEL_RESERVED_MAX + 1; 498 label ^= sc->sc_flow; 499 m->m_pkthdr.ph_flowid = M_FLOWID_VALID | label; 500 501 m_adj(m, sizeof(shim)); 502 } else if (!MPLS_BOS_ISSET(shim)) 503 goto drop; 504 505 if (sc->sc_cword) { 506 if (m->m_len < sizeof(shim)) { 507 m = m_pullup(m, sizeof(shim)); 508 if (m == NULL) 509 return; 510 } 511 shim = *mtod(m, uint32_t *); 512 513 /* 514 * The first 4 bits identifies that this packet is a 515 * control word. If the control word is configured and 516 * we received an IP datagram we shall drop it. 517 */ 518 if (shim & CW_ZERO_MASK) { 519 counters_inc(ifp->if_counters, ifc_ierrors); 520 goto drop; 521 } 522 523 /* We don't support fragmentation just yet. */ 524 if (shim & CW_FRAG_MASK) { 525 counters_inc(ifp->if_counters, ifc_ierrors); 526 goto drop; 527 } 528 529 m_adj(m, sizeof(shim)); 530 } 531 532 n = m; 533 while (n->m_len == 0) { 534 n = n->m_next; 535 if (n == NULL) 536 goto drop; 537 } 538 539 switch (*mtod(n, uint8_t *) >> 4) { 540 case 4: { 541 struct ip *ip; 542 if (m->m_len < sizeof(*ip)) { 543 m = m_pullup(m, sizeof(*ip)); 544 if (m == NULL) 545 return; 546 } 547 ip = mtod(m, struct ip *); 548 tos = ip->ip_tos; 549 550 if (sc->sc_ttl == -1) { 551 m = mpls_ip_adjttl(m, ttl); 552 if (m == NULL) 553 return; 554 } 555 input = ipv4_input; 556 m->m_pkthdr.ph_family = AF_INET; 557 break; 558 } 559 #ifdef INET6 560 case 6: { 561 struct ip6_hdr *ip6; 562 uint32_t flow; 563 if (m->m_len < sizeof(*ip6)) { 564 m = m_pullup(m, sizeof(*ip6)); 565 if (m == NULL) 566 return; 567 } 568 ip6 = mtod(m, struct ip6_hdr *); 569 flow = bemtoh32(&ip6->ip6_flow); 570 tos = flow >> 20; 571 572 if (sc->sc_ttl == -1) { 573 m = mpls_ip6_adjttl(m, ttl); 574 if (m == NULL) 575 return; 576 } 577 input = ipv6_input; 578 m->m_pkthdr.ph_family = AF_INET6; 579 break; 580 } 581 #endif /* INET6 */ 582 default: 583 counters_inc(ifp->if_counters, ifc_noproto); 584 goto drop; 585 } 586 587 switch (rxprio) { 588 case IF_HDRPRIO_PACKET: 589 /* nop */ 590 break; 591 case IF_HDRPRIO_OUTER: 592 m->m_pkthdr.pf.prio = exp; 593 break; 594 case IF_HDRPRIO_PAYLOAD: 595 m->m_pkthdr.pf.prio = IFQ_TOS2PRIO(tos); 596 break; 597 default: 598 m->m_pkthdr.pf.prio = rxprio; 599 break; 600 } 601 602 m->m_pkthdr.ph_ifidx = ifp->if_index; 603 m->m_pkthdr.ph_rtableid = ifp->if_rdomain; 604 605 /* packet has not been processed by PF yet. */ 606 KASSERT(m->m_pkthdr.pf.statekey == NULL); 607 608 #if NBPFILTER > 0 609 { 610 caddr_t if_bpf = ifp->if_bpf; 611 if (if_bpf) { 612 bpf_mtap_af(if_bpf, m->m_pkthdr.ph_family, 613 m, BPF_DIRECTION_IN); 614 } 615 } 616 #endif 617 618 (*input)(ifp, m); 619 return; 620 drop: 621 m_freem(m); 622 } 623 624 int 625 mpip_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 626 struct rtentry *rt) 627 { 628 struct mpip_softc *sc = ifp->if_softc; 629 int error; 630 631 if (dst->sa_family == AF_LINK && 632 rt != NULL && ISSET(rt->rt_flags, RTF_LOCAL)) { 633 mpip_input(sc, m); 634 return (0); 635 } 636 637 if (!ISSET(ifp->if_flags, IFF_RUNNING)) { 638 error = ENETDOWN; 639 goto drop; 640 } 641 642 switch (dst->sa_family) { 643 case AF_INET: 644 #ifdef INET6 645 case AF_INET6: 646 #endif 647 break; 648 default: 649 error = EAFNOSUPPORT; 650 goto drop; 651 } 652 653 m->m_pkthdr.ph_family = dst->sa_family; 654 655 error = if_enqueue(ifp, m); 656 if (error) 657 counters_inc(ifp->if_counters, ifc_oerrors); 658 return (error); 659 660 drop: 661 m_freem(m); 662 return (error); 663 } 664 665 void 666 mpip_start(struct ifnet *ifp) 667 { 668 struct mpip_softc *sc = ifp->if_softc; 669 struct mpip_neighbor *n = sc->sc_neighbor; 670 struct rtentry *rt; 671 struct ifnet *ifp0; 672 struct mbuf *m; 673 uint32_t shim; 674 struct sockaddr_mpls smpls = { 675 .smpls_len = sizeof(smpls), 676 .smpls_family = AF_MPLS, 677 }; 678 int txprio = sc->sc_txhprio; 679 uint32_t exp, bos; 680 uint8_t tos, prio, ttl; 681 682 if (!ISSET(ifp->if_flags, IFF_RUNNING) || n == NULL) { 683 IFQ_PURGE(&ifp->if_snd); 684 return; 685 } 686 687 rt = rtalloc(sstosa(&n->n_nexthop), RT_RESOLVE, sc->sc_rdomain); 688 if (!rtisvalid(rt)) { 689 IFQ_PURGE(&ifp->if_snd); 690 goto rtfree; 691 } 692 693 ifp0 = if_get(rt->rt_ifidx); 694 if (ifp0 == NULL) { 695 IFQ_PURGE(&ifp->if_snd); 696 goto rtfree; 697 } 698 699 while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) { 700 #if NBPFILTER > 0 701 caddr_t if_bpf = sc->sc_if.if_bpf; 702 if (if_bpf) { 703 bpf_mtap_af(if_bpf, m->m_pkthdr.ph_family, 704 m, BPF_DIRECTION_OUT); 705 } 706 #endif /* NBPFILTER */ 707 708 if (sc->sc_ttl == -1) { 709 switch (m->m_pkthdr.ph_family) { 710 case AF_INET: { 711 struct ip *ip; 712 ip = mtod(m, struct ip *); 713 ttl = ip->ip_ttl; 714 break; 715 } 716 #ifdef INET6 717 case AF_INET6: { 718 struct ip6_hdr *ip6; 719 ip6 = mtod(m, struct ip6_hdr *); 720 ttl = ip6->ip6_hlim; 721 break; 722 } 723 #endif 724 default: 725 unhandled_af(m->m_pkthdr.ph_family); 726 } 727 } else 728 ttl = mpls_defttl; 729 730 switch (txprio) { 731 case IF_HDRPRIO_PACKET: 732 prio = m->m_pkthdr.pf.prio; 733 break; 734 case IF_HDRPRIO_PAYLOAD: 735 switch (m->m_pkthdr.ph_family) { 736 case AF_INET: { 737 struct ip *ip; 738 ip = mtod(m, struct ip *); 739 tos = ip->ip_tos; 740 break; 741 } 742 #ifdef INET6 743 case AF_INET6: { 744 struct ip6_hdr *ip6; 745 uint32_t flow; 746 ip6 = mtod(m, struct ip6_hdr *); 747 flow = bemtoh32(&ip6->ip6_flow); 748 tos = flow >> 20; 749 break; 750 } 751 #endif 752 default: 753 unhandled_af(m->m_pkthdr.ph_family); 754 } 755 756 prio = IFQ_TOS2PRIO(tos); 757 break; 758 default: 759 prio = txprio; 760 break; 761 } 762 exp = htonl(prio << MPLS_EXP_OFFSET); 763 764 if (sc->sc_cword) { 765 m = m_prepend(m, sizeof(shim), M_NOWAIT); 766 if (m == NULL) 767 continue; 768 769 *mtod(m, uint32_t *) = 0; 770 } 771 772 bos = MPLS_BOS_MASK; 773 774 if (sc->sc_fword) { 775 uint32_t flow = 0; 776 m = m_prepend(m, sizeof(shim), M_NOWAIT); 777 if (m == NULL) 778 continue; 779 780 if (ISSET(m->m_pkthdr.ph_flowid, M_FLOWID_VALID)) 781 flow = m->m_pkthdr.ph_flowid & M_FLOWID_MASK; 782 flow ^= sc->sc_flow; 783 flow += MPLS_LABEL_RESERVED_MAX + 1; 784 785 shim = htonl(1) & MPLS_TTL_MASK; 786 shim |= htonl(flow << MPLS_LABEL_OFFSET) & 787 MPLS_LABEL_MASK; 788 shim |= exp | bos; 789 *mtod(m, uint32_t *) = shim; 790 791 bos = 0; 792 } 793 794 m = m_prepend(m, sizeof(shim), M_NOWAIT); 795 if (m == NULL) 796 continue; 797 798 shim = htonl(ttl) & MPLS_TTL_MASK; 799 shim |= n->n_rshim.shim_label; 800 shim |= exp | bos; 801 *mtod(m, uint32_t *) = shim; 802 803 m->m_pkthdr.ph_rtableid = sc->sc_rdomain; 804 CLR(m->m_flags, M_BCAST|M_MCAST); 805 806 mpls_output(ifp0, m, (struct sockaddr *)&smpls, rt); 807 } 808 809 if_put(ifp0); 810 rtfree: 811 rtfree(rt); 812 } 813