1 /* $OpenBSD: labelmapping.c,v 1.69 2023/07/03 11:51:27 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2014, 2015 Renato Westphal <renato@openbsd.org> 5 * Copyright (c) 2009 Michele Marchetto <michele@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 <sys/types.h> 21 #include <sys/socket.h> 22 #include <arpa/inet.h> 23 #include <netmpls/mpls.h> 24 #include <limits.h> 25 #include <stddef.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include "ldpd.h" 30 #include "ldpe.h" 31 #include "log.h" 32 33 static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t); 34 static int gen_label_tlv(struct ibuf *, uint32_t); 35 static int tlv_decode_label(struct nbr *, struct ldp_msg *, char *, 36 uint16_t, uint32_t *); 37 static int gen_reqid_tlv(struct ibuf *, uint32_t); 38 static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *); 39 40 static void 41 enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size) 42 { 43 if (ibuf_set_n16(buf, offsetof(struct ldp_hdr, length), size) == -1) 44 fatal(__func__); 45 evbuf_enqueue(&nbr->tcp->wbuf, buf); 46 } 47 48 /* Generic function that handles all Label Message types */ 49 void 50 send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) 51 { 52 struct ibuf *buf = NULL; 53 struct mapping_entry *me; 54 uint16_t msg_size, size = 0; 55 int first = 1; 56 int err = 0; 57 58 /* nothing to send */ 59 if (TAILQ_EMPTY(mh)) 60 return; 61 62 while ((me = TAILQ_FIRST(mh)) != NULL) { 63 /* generate pdu */ 64 if (first) { 65 if ((buf = ibuf_open(nbr->max_pdu_len + 66 LDP_HDR_DEAD_LEN)) == NULL) 67 fatal(__func__); 68 69 /* real size will be set up later */ 70 err |= gen_ldp_hdr(buf, 0); 71 72 size = LDP_HDR_PDU_LEN; 73 first = 0; 74 } 75 76 /* calculate size */ 77 msg_size = LDP_MSG_SIZE; 78 msg_size += len_fec_tlv(&me->map); 79 if (me->map.label != NO_LABEL) 80 msg_size += LABEL_TLV_SIZE; 81 if (me->map.flags & F_MAP_REQ_ID) 82 msg_size += REQID_TLV_SIZE; 83 if (me->map.flags & F_MAP_STATUS) 84 msg_size += STATUS_SIZE; 85 86 /* maximum pdu length exceeded, we need a new ldp pdu */ 87 if (size + msg_size > nbr->max_pdu_len) { 88 enqueue_pdu(nbr, buf, size); 89 first = 1; 90 continue; 91 } 92 93 size += msg_size; 94 95 /* append message and tlvs */ 96 err |= gen_msg_hdr(buf, type, msg_size); 97 err |= gen_fec_tlv(buf, &me->map); 98 if (me->map.label != NO_LABEL) 99 err |= gen_label_tlv(buf, me->map.label); 100 if (me->map.flags & F_MAP_REQ_ID) 101 err |= gen_reqid_tlv(buf, me->map.requestid); 102 if (me->map.flags & F_MAP_PW_STATUS) 103 err |= gen_pw_status_tlv(buf, me->map.pw_status); 104 if (me->map.flags & F_MAP_STATUS) 105 err |= gen_status_tlv(buf, me->map.st.status_code, 106 me->map.st.msg_id, me->map.st.msg_type); 107 if (err) { 108 ibuf_free(buf); 109 mapping_list_clr(mh); 110 return; 111 } 112 113 log_msg_mapping(1, type, nbr, &me->map); 114 115 TAILQ_REMOVE(mh, me, entry); 116 free(me); 117 } 118 119 enqueue_pdu(nbr, buf, size); 120 121 nbr_fsm(nbr, NBR_EVT_PDU_SENT); 122 } 123 124 /* Generic function that handles all Label Message types */ 125 int 126 recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) 127 { 128 struct ldp_msg msg; 129 struct tlv ft; 130 uint32_t label = NO_LABEL, reqid = 0; 131 uint32_t pw_status = 0; 132 uint8_t flags = 0; 133 int feclen, lbllen, tlen; 134 struct mapping_entry *me; 135 struct mapping_head mh; 136 struct map map; 137 138 memcpy(&msg, buf, sizeof(msg)); 139 buf += LDP_MSG_SIZE; 140 len -= LDP_MSG_SIZE; 141 142 /* FEC TLV */ 143 if (len < sizeof(ft)) { 144 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 145 return (-1); 146 } 147 148 memcpy(&ft, buf, sizeof(ft)); 149 if (ntohs(ft.type) != TLV_TYPE_FEC) { 150 send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); 151 return (-1); 152 } 153 feclen = ntohs(ft.length); 154 if (feclen > len - TLV_HDR_SIZE) { 155 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 156 return (-1); 157 } 158 159 buf += TLV_HDR_SIZE; /* just advance to the end of the fec header */ 160 len -= TLV_HDR_SIZE; 161 162 TAILQ_INIT(&mh); 163 do { 164 memset(&map, 0, sizeof(map)); 165 map.msg_id = msg.id; 166 167 if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf, feclen, 168 &map)) == -1) 169 goto err; 170 if (map.type == MAP_TYPE_PWID && 171 !(map.flags & F_MAP_PW_ID) && 172 type != MSG_TYPE_LABELWITHDRAW && 173 type != MSG_TYPE_LABELRELEASE) { 174 send_notification(nbr->tcp, S_MISS_MSG, msg.id, 175 msg.type); 176 return (-1); 177 } 178 179 /* 180 * The Wildcard FEC Element can be used only in the 181 * Label Withdraw and Label Release messages. 182 */ 183 if (map.type == MAP_TYPE_WILDCARD) { 184 switch (type) { 185 case MSG_TYPE_LABELMAPPING: 186 case MSG_TYPE_LABELREQUEST: 187 case MSG_TYPE_LABELABORTREQ: 188 session_shutdown(nbr, S_UNKNOWN_FEC, msg.id, 189 msg.type); 190 goto err; 191 default: 192 break; 193 } 194 } 195 196 /* 197 * RFC 5561 - Section 4: 198 * "An LDP implementation that supports the Typed Wildcard 199 * FEC Element MUST support its use in Label Request, Label 200 * Withdraw, and Label Release messages". 201 */ 202 if (map.type == MAP_TYPE_TYPED_WCARD) { 203 switch (type) { 204 case MSG_TYPE_LABELMAPPING: 205 case MSG_TYPE_LABELABORTREQ: 206 session_shutdown(nbr, S_UNKNOWN_FEC, msg.id, 207 msg.type); 208 goto err; 209 default: 210 break; 211 } 212 } 213 214 /* 215 * LDP supports the use of multiple FEC Elements per 216 * FEC for the Label Mapping message only. 217 */ 218 if (type != MSG_TYPE_LABELMAPPING && 219 tlen != feclen) { 220 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); 221 goto err; 222 } 223 224 mapping_list_add(&mh, &map); 225 226 buf += tlen; 227 len -= tlen; 228 feclen -= tlen; 229 } while (feclen > 0); 230 231 /* Mandatory Label TLV */ 232 if (type == MSG_TYPE_LABELMAPPING) { 233 lbllen = tlv_decode_label(nbr, &msg, buf, len, &label); 234 if (lbllen == -1) 235 goto err; 236 237 buf += lbllen; 238 len -= lbllen; 239 } 240 241 /* Optional Parameters */ 242 while (len > 0) { 243 struct tlv tlv; 244 uint16_t tlv_type; 245 uint16_t tlv_len; 246 uint32_t reqbuf, labelbuf, statusbuf; 247 248 if (len < sizeof(tlv)) { 249 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 250 goto err; 251 } 252 253 memcpy(&tlv, buf, TLV_HDR_SIZE); 254 tlv_type = ntohs(tlv.type); 255 tlv_len = ntohs(tlv.length); 256 if (tlv_len + TLV_HDR_SIZE > len) { 257 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 258 goto err; 259 } 260 buf += TLV_HDR_SIZE; 261 len -= TLV_HDR_SIZE; 262 263 switch (tlv_type) { 264 case TLV_TYPE_LABELREQUEST: 265 switch (type) { 266 case MSG_TYPE_LABELMAPPING: 267 case MSG_TYPE_LABELREQUEST: 268 if (tlv_len != REQID_TLV_LEN) { 269 session_shutdown(nbr, S_BAD_TLV_LEN, 270 msg.id, msg.type); 271 goto err; 272 } 273 274 flags |= F_MAP_REQ_ID; 275 memcpy(&reqbuf, buf, sizeof(reqbuf)); 276 reqid = ntohl(reqbuf); 277 break; 278 default: 279 /* ignore */ 280 break; 281 } 282 break; 283 case TLV_TYPE_HOPCOUNT: 284 case TLV_TYPE_PATHVECTOR: 285 /* ignore */ 286 break; 287 case TLV_TYPE_GENERICLABEL: 288 switch (type) { 289 case MSG_TYPE_LABELWITHDRAW: 290 case MSG_TYPE_LABELRELEASE: 291 if (tlv_len != LABEL_TLV_LEN) { 292 session_shutdown(nbr, S_BAD_TLV_LEN, 293 msg.id, msg.type); 294 goto err; 295 } 296 297 memcpy(&labelbuf, buf, sizeof(labelbuf)); 298 label = ntohl(labelbuf); 299 break; 300 default: 301 /* ignore */ 302 break; 303 } 304 break; 305 case TLV_TYPE_ATMLABEL: 306 case TLV_TYPE_FRLABEL: 307 switch (type) { 308 case MSG_TYPE_LABELWITHDRAW: 309 case MSG_TYPE_LABELRELEASE: 310 /* unsupported */ 311 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, 312 msg.type); 313 goto err; 314 break; 315 default: 316 /* ignore */ 317 break; 318 } 319 break; 320 case TLV_TYPE_STATUS: 321 if (tlv_len != STATUS_TLV_LEN) { 322 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, 323 msg.type); 324 goto err; 325 } 326 /* ignore */ 327 break; 328 case TLV_TYPE_PW_STATUS: 329 switch (type) { 330 case MSG_TYPE_LABELMAPPING: 331 if (tlv_len != PW_STATUS_TLV_LEN) { 332 session_shutdown(nbr, S_BAD_TLV_LEN, 333 msg.id, msg.type); 334 goto err; 335 } 336 337 flags |= F_MAP_PW_STATUS; 338 memcpy(&statusbuf, buf, sizeof(statusbuf)); 339 pw_status = ntohl(statusbuf); 340 break; 341 default: 342 /* ignore */ 343 break; 344 } 345 break; 346 default: 347 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) 348 send_notification_rtlvs(nbr, S_UNKNOWN_TLV, 349 msg.id, msg.type, tlv_type, tlv_len, buf); 350 /* ignore unknown tlv */ 351 break; 352 } 353 buf += tlv_len; 354 len -= tlv_len; 355 } 356 357 /* notify lde about the received message. */ 358 while ((me = TAILQ_FIRST(&mh)) != NULL) { 359 int imsg_type = IMSG_NONE; 360 361 me->map.flags |= flags; 362 switch (me->map.type) { 363 case MAP_TYPE_PREFIX: 364 switch (me->map.fec.prefix.af) { 365 case AF_INET: 366 if (label == MPLS_LABEL_IPV6NULL) { 367 session_shutdown(nbr, S_BAD_TLV_VAL, 368 msg.id, msg.type); 369 goto err; 370 } 371 if (!nbr->v4_enabled) 372 goto next; 373 break; 374 case AF_INET6: 375 if (label == MPLS_LABEL_IPV4NULL) { 376 session_shutdown(nbr, S_BAD_TLV_VAL, 377 msg.id, msg.type); 378 goto err; 379 } 380 if (!nbr->v6_enabled) 381 goto next; 382 break; 383 default: 384 fatalx("recv_labelmessage: unknown af"); 385 } 386 break; 387 case MAP_TYPE_PWID: 388 if (label <= MPLS_LABEL_RESERVED_MAX) { 389 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, 390 msg.type); 391 goto err; 392 } 393 if (me->map.flags & F_MAP_PW_STATUS) 394 me->map.pw_status = pw_status; 395 break; 396 default: 397 break; 398 } 399 me->map.label = label; 400 if (me->map.flags & F_MAP_REQ_ID) 401 me->map.requestid = reqid; 402 403 log_msg_mapping(0, type, nbr, &me->map); 404 405 switch (type) { 406 case MSG_TYPE_LABELMAPPING: 407 imsg_type = IMSG_LABEL_MAPPING; 408 break; 409 case MSG_TYPE_LABELREQUEST: 410 imsg_type = IMSG_LABEL_REQUEST; 411 break; 412 case MSG_TYPE_LABELWITHDRAW: 413 imsg_type = IMSG_LABEL_WITHDRAW; 414 break; 415 case MSG_TYPE_LABELRELEASE: 416 imsg_type = IMSG_LABEL_RELEASE; 417 break; 418 case MSG_TYPE_LABELABORTREQ: 419 imsg_type = IMSG_LABEL_ABORT; 420 break; 421 default: 422 break; 423 } 424 425 ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map, 426 sizeof(struct map)); 427 428 next: 429 TAILQ_REMOVE(&mh, me, entry); 430 free(me); 431 } 432 433 return (0); 434 435 err: 436 mapping_list_clr(&mh); 437 438 return (-1); 439 } 440 441 /* Other TLV related functions */ 442 static int 443 gen_label_tlv(struct ibuf *buf, uint32_t label) 444 { 445 struct label_tlv lt; 446 447 lt.type = htons(TLV_TYPE_GENERICLABEL); 448 lt.length = htons(LABEL_TLV_LEN); 449 lt.label = htonl(label); 450 451 return (ibuf_add(buf, <, sizeof(lt))); 452 } 453 454 static int 455 tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf, 456 uint16_t len, uint32_t *label) 457 { 458 struct label_tlv lt; 459 460 if (len < sizeof(lt)) { 461 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type); 462 return (-1); 463 } 464 memcpy(<, buf, sizeof(lt)); 465 466 if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) { 467 send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type); 468 return (-1); 469 } 470 471 switch (htons(lt.type)) { 472 case TLV_TYPE_GENERICLABEL: 473 if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) { 474 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 475 msg->type); 476 return (-1); 477 } 478 479 *label = ntohl(lt.label); 480 if (*label > MPLS_LABEL_MAX || 481 (*label <= MPLS_LABEL_RESERVED_MAX && 482 *label != MPLS_LABEL_IPV4NULL && 483 *label != MPLS_LABEL_IPV6NULL && 484 *label != MPLS_LABEL_IMPLNULL)) { 485 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, 486 msg->type); 487 return (-1); 488 } 489 break; 490 case TLV_TYPE_ATMLABEL: 491 case TLV_TYPE_FRLABEL: 492 default: 493 /* unsupported */ 494 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type); 495 return (-1); 496 } 497 498 return (sizeof(lt)); 499 } 500 501 static int 502 gen_reqid_tlv(struct ibuf *buf, uint32_t reqid) 503 { 504 struct reqid_tlv rt; 505 506 rt.type = htons(TLV_TYPE_LABELREQUEST); 507 rt.length = htons(REQID_TLV_LEN); 508 rt.reqid = htonl(reqid); 509 510 return (ibuf_add(buf, &rt, sizeof(rt))); 511 } 512 513 int 514 gen_pw_status_tlv(struct ibuf *buf, uint32_t status) 515 { 516 struct pw_status_tlv st; 517 518 st.type = htons(TLV_TYPE_PW_STATUS); 519 st.length = htons(PW_STATUS_TLV_LEN); 520 st.value = htonl(status); 521 522 return (ibuf_add(buf, &st, sizeof(st))); 523 } 524 525 uint16_t 526 len_fec_tlv(struct map *map) 527 { 528 uint16_t len = TLV_HDR_SIZE; 529 530 switch (map->type) { 531 case MAP_TYPE_WILDCARD: 532 len += FEC_ELM_WCARD_LEN; 533 break; 534 case MAP_TYPE_PREFIX: 535 len += FEC_ELM_PREFIX_MIN_LEN + 536 PREFIX_SIZE(map->fec.prefix.prefixlen); 537 break; 538 case MAP_TYPE_PWID: 539 len += FEC_PWID_ELM_MIN_LEN; 540 if (map->flags & F_MAP_PW_ID) 541 len += PW_STATUS_TLV_LEN; 542 if (map->flags & F_MAP_PW_IFMTU) 543 len += FEC_SUBTLV_IFMTU_SIZE; 544 if (map->flags & F_MAP_PW_STATUS) 545 len += PW_STATUS_TLV_SIZE; 546 break; 547 case MAP_TYPE_TYPED_WCARD: 548 len += FEC_ELM_TWCARD_MIN_LEN; 549 switch (map->fec.twcard.type) { 550 case MAP_TYPE_PREFIX: 551 case MAP_TYPE_PWID: 552 len += sizeof(uint16_t); 553 break; 554 default: 555 fatalx("len_fec_tlv: unexpected fec type"); 556 } 557 break; 558 default: 559 fatalx("len_fec_tlv: unexpected fec type"); 560 } 561 562 return (len); 563 } 564 565 int 566 gen_fec_tlv(struct ibuf *buf, struct map *map) 567 { 568 struct tlv ft; 569 uint16_t family, len, pw_type, ifmtu; 570 uint8_t pw_len = 0, twcard_len; 571 uint32_t group_id, pwid; 572 int err = 0; 573 574 ft.type = htons(TLV_TYPE_FEC); 575 576 switch (map->type) { 577 case MAP_TYPE_WILDCARD: 578 ft.length = htons(sizeof(uint8_t)); 579 err |= ibuf_add(buf, &ft, sizeof(ft)); 580 err |= ibuf_add(buf, &map->type, sizeof(map->type)); 581 break; 582 case MAP_TYPE_PREFIX: 583 len = PREFIX_SIZE(map->fec.prefix.prefixlen); 584 ft.length = htons(sizeof(map->type) + sizeof(family) + 585 sizeof(map->fec.prefix.prefixlen) + len); 586 err |= ibuf_add(buf, &ft, sizeof(ft)); 587 err |= ibuf_add(buf, &map->type, sizeof(map->type)); 588 switch (map->fec.prefix.af) { 589 case AF_INET: 590 family = htons(AF_IPV4); 591 break; 592 case AF_INET6: 593 family = htons(AF_IPV6); 594 break; 595 default: 596 fatalx("gen_fec_tlv: unknown af"); 597 break; 598 } 599 err |= ibuf_add(buf, &family, sizeof(family)); 600 err |= ibuf_add(buf, &map->fec.prefix.prefixlen, 601 sizeof(map->fec.prefix.prefixlen)); 602 if (len) 603 err |= ibuf_add(buf, &map->fec.prefix.prefix, len); 604 break; 605 case MAP_TYPE_PWID: 606 if (map->flags & F_MAP_PW_ID) 607 pw_len += FEC_PWID_SIZE; 608 if (map->flags & F_MAP_PW_IFMTU) 609 pw_len += FEC_SUBTLV_IFMTU_SIZE; 610 611 len = FEC_PWID_ELM_MIN_LEN + pw_len; 612 613 ft.length = htons(len); 614 err |= ibuf_add(buf, &ft, sizeof(ft)); 615 616 err |= ibuf_add(buf, &map->type, sizeof(uint8_t)); 617 pw_type = map->fec.pwid.type; 618 if (map->flags & F_MAP_PW_CWORD) 619 pw_type |= CONTROL_WORD_FLAG; 620 pw_type = htons(pw_type); 621 err |= ibuf_add(buf, &pw_type, sizeof(uint16_t)); 622 err |= ibuf_add(buf, &pw_len, sizeof(uint8_t)); 623 group_id = htonl(map->fec.pwid.group_id); 624 err |= ibuf_add(buf, &group_id, sizeof(uint32_t)); 625 if (map->flags & F_MAP_PW_ID) { 626 pwid = htonl(map->fec.pwid.pwid); 627 err |= ibuf_add(buf, &pwid, sizeof(uint32_t)); 628 } 629 if (map->flags & F_MAP_PW_IFMTU) { 630 struct subtlv stlv; 631 632 stlv.type = SUBTLV_IFMTU; 633 stlv.length = FEC_SUBTLV_IFMTU_SIZE; 634 err |= ibuf_add(buf, &stlv, sizeof(uint16_t)); 635 636 ifmtu = htons(map->fec.pwid.ifmtu); 637 err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t)); 638 } 639 break; 640 case MAP_TYPE_TYPED_WCARD: 641 len = FEC_ELM_TWCARD_MIN_LEN; 642 switch (map->fec.twcard.type) { 643 case MAP_TYPE_PREFIX: 644 case MAP_TYPE_PWID: 645 len += sizeof(uint16_t); 646 break; 647 default: 648 fatalx("gen_fec_tlv: unexpected fec type"); 649 } 650 ft.length = htons(len); 651 err |= ibuf_add(buf, &ft, sizeof(ft)); 652 err |= ibuf_add(buf, &map->type, sizeof(uint8_t)); 653 err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t)); 654 655 switch (map->fec.twcard.type) { 656 case MAP_TYPE_PREFIX: 657 twcard_len = sizeof(uint16_t); 658 err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t)); 659 660 switch (map->fec.twcard.u.prefix_af) { 661 case AF_INET: 662 family = htons(AF_IPV4); 663 break; 664 case AF_INET6: 665 family = htons(AF_IPV6); 666 break; 667 default: 668 fatalx("gen_fec_tlv: unknown af"); 669 break; 670 } 671 672 err |= ibuf_add(buf, &family, sizeof(uint16_t)); 673 break; 674 case MAP_TYPE_PWID: 675 twcard_len = sizeof(uint16_t); 676 err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t)); 677 pw_type = htons(map->fec.twcard.u.pw_type); 678 err |= ibuf_add(buf, &pw_type, sizeof(uint16_t)); 679 break; 680 default: 681 fatalx("gen_fec_tlv: unexpected fec type"); 682 } 683 break; 684 default: 685 break; 686 } 687 688 return (err); 689 } 690 691 int 692 tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, 693 uint16_t len, struct map *map) 694 { 695 uint16_t off = 0; 696 uint8_t pw_len, twcard_len; 697 698 map->type = *buf; 699 off += sizeof(uint8_t); 700 701 switch (map->type) { 702 case MAP_TYPE_WILDCARD: 703 if (len == FEC_ELM_WCARD_LEN) 704 return (off); 705 else { 706 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, 707 msg->type); 708 return (-1); 709 } 710 break; 711 case MAP_TYPE_PREFIX: 712 if (len < FEC_ELM_PREFIX_MIN_LEN) { 713 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 714 msg->type); 715 return (-1); 716 } 717 718 /* Address Family */ 719 memcpy(&map->fec.prefix.af, buf + off, 720 sizeof(map->fec.prefix.af)); 721 off += sizeof(map->fec.prefix.af); 722 map->fec.prefix.af = ntohs(map->fec.prefix.af); 723 switch (map->fec.prefix.af) { 724 case AF_IPV4: 725 map->fec.prefix.af = AF_INET; 726 break; 727 case AF_IPV6: 728 map->fec.prefix.af = AF_INET6; 729 break; 730 default: 731 send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id, 732 msg->type); 733 return (-1); 734 } 735 736 /* Prefix Length */ 737 map->fec.prefix.prefixlen = buf[off]; 738 off += sizeof(uint8_t); 739 if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) { 740 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 741 msg->type); 742 return (-1); 743 } 744 745 /* Prefix */ 746 memset(&map->fec.prefix.prefix, 0, 747 sizeof(map->fec.prefix.prefix)); 748 memcpy(&map->fec.prefix.prefix, buf + off, 749 PREFIX_SIZE(map->fec.prefix.prefixlen)); 750 751 /* Just in case... */ 752 ldp_applymask(map->fec.prefix.af, &map->fec.prefix.prefix, 753 &map->fec.prefix.prefix, map->fec.prefix.prefixlen); 754 755 return (off + PREFIX_SIZE(map->fec.prefix.prefixlen)); 756 case MAP_TYPE_PWID: 757 if (len < FEC_PWID_ELM_MIN_LEN) { 758 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 759 msg->type); 760 return (-1); 761 } 762 763 /* PW type */ 764 memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t)); 765 map->fec.pwid.type = ntohs(map->fec.pwid.type); 766 if (map->fec.pwid.type & CONTROL_WORD_FLAG) { 767 map->flags |= F_MAP_PW_CWORD; 768 map->fec.pwid.type &= ~CONTROL_WORD_FLAG; 769 } 770 off += sizeof(uint16_t); 771 772 /* PW info Length */ 773 pw_len = buf[off]; 774 off += sizeof(uint8_t); 775 776 if (len != FEC_PWID_ELM_MIN_LEN + pw_len) { 777 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 778 msg->type); 779 return (-1); 780 } 781 782 /* Group ID */ 783 memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t)); 784 map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id); 785 off += sizeof(uint32_t); 786 787 /* PW ID */ 788 if (pw_len == 0) 789 return (off); 790 791 if (pw_len < sizeof(uint32_t)) { 792 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 793 msg->type); 794 return (-1); 795 } 796 797 memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t)); 798 map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid); 799 map->flags |= F_MAP_PW_ID; 800 off += sizeof(uint32_t); 801 pw_len -= sizeof(uint32_t); 802 803 /* Optional Interface Parameter Sub-TLVs */ 804 while (pw_len > 0) { 805 struct subtlv stlv; 806 807 if (pw_len < sizeof(stlv)) { 808 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 809 msg->type); 810 return (-1); 811 } 812 813 memcpy(&stlv, buf + off, sizeof(stlv)); 814 if (stlv.length > pw_len) { 815 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 816 msg->type); 817 return (-1); 818 } 819 820 switch (stlv.type) { 821 case SUBTLV_IFMTU: 822 if (stlv.length != FEC_SUBTLV_IFMTU_SIZE) { 823 session_shutdown(nbr, S_BAD_TLV_LEN, 824 msg->id, msg->type); 825 return (-1); 826 } 827 memcpy(&map->fec.pwid.ifmtu, buf + off + 828 SUBTLV_HDR_SIZE, sizeof(uint16_t)); 829 map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu); 830 map->flags |= F_MAP_PW_IFMTU; 831 break; 832 default: 833 /* ignore */ 834 break; 835 } 836 off += stlv.length; 837 pw_len -= stlv.length; 838 } 839 840 return (off); 841 case MAP_TYPE_TYPED_WCARD: 842 if (len < FEC_ELM_TWCARD_MIN_LEN) { 843 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 844 msg->type); 845 return (-1); 846 } 847 848 memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t)); 849 off += sizeof(uint8_t); 850 memcpy(&twcard_len, buf + off, sizeof(uint8_t)); 851 off += sizeof(uint8_t); 852 if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) { 853 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 854 msg->type); 855 return (-1); 856 } 857 858 switch (map->fec.twcard.type) { 859 case MAP_TYPE_PREFIX: 860 if (twcard_len != sizeof(uint16_t)) { 861 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 862 msg->type); 863 return (-1); 864 } 865 866 memcpy(&map->fec.twcard.u.prefix_af, buf + off, 867 sizeof(uint16_t)); 868 map->fec.twcard.u.prefix_af = 869 ntohs(map->fec.twcard.u.prefix_af); 870 off += sizeof(uint16_t); 871 872 switch (map->fec.twcard.u.prefix_af) { 873 case AF_IPV4: 874 map->fec.twcard.u.prefix_af = AF_INET; 875 break; 876 case AF_IPV6: 877 map->fec.twcard.u.prefix_af = AF_INET6; 878 break; 879 default: 880 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, 881 msg->type); 882 return (-1); 883 } 884 break; 885 case MAP_TYPE_PWID: 886 if (twcard_len != sizeof(uint16_t)) { 887 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 888 msg->type); 889 return (-1); 890 } 891 892 memcpy(&map->fec.twcard.u.pw_type, buf + off, 893 sizeof(uint16_t)); 894 map->fec.twcard.u.pw_type = 895 ntohs(map->fec.twcard.u.pw_type); 896 /* ignore the reserved bit as per RFC 6667 */ 897 map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT; 898 off += sizeof(uint16_t); 899 break; 900 default: 901 send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, 902 msg->type); 903 return (-1); 904 } 905 906 return (off); 907 default: 908 send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type); 909 break; 910 } 911 912 return (-1); 913 } 914 915 static void 916 log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map) 917 { 918 log_debug("msg-%s: %s: lsr-id %s, fec %s, label %s", 919 (out) ? "out" : "in", msg_name(msg_type), inet_ntoa(nbr->id), 920 log_map(map), log_label(map->label)); 921 } 922