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