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