1 /* $OpenBSD: labelmapping.c,v 1.64 2017/03/03 23:50:45 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 } 97 if (me->map.label != NO_LABEL) 98 msg_size += LABEL_TLV_SIZE; 99 if (me->map.flags & F_MAP_REQ_ID) 100 msg_size += REQID_TLV_SIZE; 101 if (me->map.flags & F_MAP_STATUS) 102 msg_size += STATUS_SIZE; 103 104 /* maximum pdu length exceeded, we need a new ldp pdu */ 105 if (size + msg_size > nbr->max_pdu_len) { 106 enqueue_pdu(nbr, buf, size); 107 first = 1; 108 continue; 109 } 110 111 size += msg_size; 112 113 /* append message and tlvs */ 114 err |= gen_msg_hdr(buf, type, msg_size); 115 err |= gen_fec_tlv(buf, &me->map); 116 if (me->map.label != NO_LABEL) 117 err |= gen_label_tlv(buf, me->map.label); 118 if (me->map.flags & F_MAP_REQ_ID) 119 err |= gen_reqid_tlv(buf, me->map.requestid); 120 if (me->map.flags & F_MAP_PW_STATUS) 121 err |= gen_pw_status_tlv(buf, me->map.pw_status); 122 if (me->map.flags & F_MAP_STATUS) 123 err |= gen_status_tlv(buf, me->map.st.status_code, 124 me->map.st.msg_id, me->map.st.msg_type); 125 if (err) { 126 ibuf_free(buf); 127 mapping_list_clr(mh); 128 return; 129 } 130 131 log_msg_mapping(1, type, nbr, &me->map); 132 133 TAILQ_REMOVE(mh, me, entry); 134 free(me); 135 } 136 137 enqueue_pdu(nbr, buf, size); 138 139 nbr_fsm(nbr, NBR_EVT_PDU_SENT); 140 } 141 142 /* Generic function that handles all Label Message types */ 143 int 144 recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) 145 { 146 struct ldp_msg msg; 147 struct tlv ft; 148 uint32_t label = NO_LABEL, reqid = 0; 149 uint32_t pw_status = 0; 150 uint8_t flags = 0; 151 int feclen, lbllen, tlen; 152 struct mapping_entry *me; 153 struct mapping_head mh; 154 struct map map; 155 156 memcpy(&msg, buf, sizeof(msg)); 157 buf += LDP_MSG_SIZE; 158 len -= LDP_MSG_SIZE; 159 160 /* FEC TLV */ 161 if (len < sizeof(ft)) { 162 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 163 return (-1); 164 } 165 166 memcpy(&ft, buf, sizeof(ft)); 167 if (ntohs(ft.type) != TLV_TYPE_FEC) { 168 send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); 169 return (-1); 170 } 171 feclen = ntohs(ft.length); 172 if (feclen > len - TLV_HDR_SIZE) { 173 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 174 return (-1); 175 } 176 177 buf += TLV_HDR_SIZE; /* just advance to the end of the fec header */ 178 len -= TLV_HDR_SIZE; 179 180 TAILQ_INIT(&mh); 181 do { 182 memset(&map, 0, sizeof(map)); 183 map.msg_id = msg.id; 184 185 if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf, feclen, 186 &map)) == -1) 187 goto err; 188 if (map.type == MAP_TYPE_PWID && 189 !(map.flags & F_MAP_PW_ID) && 190 type != MSG_TYPE_LABELWITHDRAW && 191 type != MSG_TYPE_LABELRELEASE) { 192 send_notification(nbr->tcp, S_MISS_MSG, msg.id, 193 msg.type); 194 return (-1); 195 } 196 197 /* 198 * The Wildcard FEC Element can be used only in the 199 * Label Withdraw and Label Release messages. 200 */ 201 if (map.type == MAP_TYPE_WILDCARD) { 202 switch (type) { 203 case MSG_TYPE_LABELMAPPING: 204 case MSG_TYPE_LABELREQUEST: 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_len; 245 uint32_t reqbuf, labelbuf, statusbuf; 246 247 if (len < sizeof(tlv)) { 248 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 249 goto err; 250 } 251 252 memcpy(&tlv, buf, TLV_HDR_SIZE); 253 tlv_len = ntohs(tlv.length); 254 if (tlv_len + TLV_HDR_SIZE > len) { 255 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 256 goto err; 257 } 258 buf += TLV_HDR_SIZE; 259 len -= TLV_HDR_SIZE; 260 261 switch (ntohs(tlv.type)) { 262 case TLV_TYPE_LABELREQUEST: 263 switch (type) { 264 case MSG_TYPE_LABELMAPPING: 265 case MSG_TYPE_LABELREQUEST: 266 if (tlv_len != REQID_TLV_LEN) { 267 session_shutdown(nbr, S_BAD_TLV_LEN, 268 msg.id, msg.type); 269 goto err; 270 } 271 272 flags |= F_MAP_REQ_ID; 273 memcpy(&reqbuf, buf, sizeof(reqbuf)); 274 reqid = ntohl(reqbuf); 275 break; 276 default: 277 /* ignore */ 278 break; 279 } 280 break; 281 case TLV_TYPE_HOPCOUNT: 282 case TLV_TYPE_PATHVECTOR: 283 /* ignore */ 284 break; 285 case TLV_TYPE_GENERICLABEL: 286 switch (type) { 287 case MSG_TYPE_LABELWITHDRAW: 288 case MSG_TYPE_LABELRELEASE: 289 if (tlv_len != LABEL_TLV_LEN) { 290 session_shutdown(nbr, S_BAD_TLV_LEN, 291 msg.id, msg.type); 292 goto err; 293 } 294 295 memcpy(&labelbuf, buf, sizeof(labelbuf)); 296 label = ntohl(labelbuf); 297 break; 298 default: 299 /* ignore */ 300 break; 301 } 302 break; 303 case TLV_TYPE_ATMLABEL: 304 case TLV_TYPE_FRLABEL: 305 switch (type) { 306 case MSG_TYPE_LABELWITHDRAW: 307 case MSG_TYPE_LABELRELEASE: 308 /* unsupported */ 309 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, 310 msg.type); 311 goto err; 312 break; 313 default: 314 /* ignore */ 315 break; 316 } 317 break; 318 case TLV_TYPE_STATUS: 319 if (tlv_len != STATUS_TLV_LEN) { 320 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, 321 msg.type); 322 goto err; 323 } 324 /* ignore */ 325 break; 326 case TLV_TYPE_PW_STATUS: 327 switch (type) { 328 case MSG_TYPE_LABELMAPPING: 329 if (tlv_len != PW_STATUS_TLV_LEN) { 330 session_shutdown(nbr, S_BAD_TLV_LEN, 331 msg.id, msg.type); 332 goto err; 333 } 334 335 flags |= F_MAP_PW_STATUS; 336 memcpy(&statusbuf, buf, sizeof(statusbuf)); 337 pw_status = ntohl(statusbuf); 338 break; 339 default: 340 /* ignore */ 341 break; 342 } 343 break; 344 default: 345 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) 346 send_notification(nbr->tcp, S_UNKNOWN_TLV, 347 msg.id, msg.type); 348 /* ignore unknown tlv */ 349 break; 350 } 351 buf += tlv_len; 352 len -= tlv_len; 353 } 354 355 /* notify lde about the received message. */ 356 while ((me = TAILQ_FIRST(&mh)) != NULL) { 357 int imsg_type = IMSG_NONE; 358 359 me->map.flags |= flags; 360 switch (me->map.type) { 361 case MAP_TYPE_PREFIX: 362 switch (me->map.fec.prefix.af) { 363 case AF_INET: 364 if (label == MPLS_LABEL_IPV6NULL) { 365 session_shutdown(nbr, S_BAD_TLV_VAL, 366 msg.id, msg.type); 367 goto err; 368 } 369 if (!nbr->v4_enabled) 370 goto next; 371 break; 372 case AF_INET6: 373 if (label == MPLS_LABEL_IPV4NULL) { 374 session_shutdown(nbr, S_BAD_TLV_VAL, 375 msg.id, msg.type); 376 goto err; 377 } 378 if (!nbr->v6_enabled) 379 goto next; 380 break; 381 default: 382 fatalx("recv_labelmessage: unknown af"); 383 } 384 break; 385 case MAP_TYPE_PWID: 386 if (label <= MPLS_LABEL_RESERVED_MAX) { 387 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, 388 msg.type); 389 goto err; 390 } 391 if (me->map.flags & F_MAP_PW_STATUS) 392 me->map.pw_status = pw_status; 393 break; 394 default: 395 break; 396 } 397 me->map.label = label; 398 if (me->map.flags & F_MAP_REQ_ID) 399 me->map.requestid = reqid; 400 401 log_msg_mapping(0, type, nbr, &me->map); 402 403 switch (type) { 404 case MSG_TYPE_LABELMAPPING: 405 imsg_type = IMSG_LABEL_MAPPING; 406 break; 407 case MSG_TYPE_LABELREQUEST: 408 imsg_type = IMSG_LABEL_REQUEST; 409 break; 410 case MSG_TYPE_LABELWITHDRAW: 411 imsg_type = IMSG_LABEL_WITHDRAW; 412 break; 413 case MSG_TYPE_LABELRELEASE: 414 imsg_type = IMSG_LABEL_RELEASE; 415 break; 416 case MSG_TYPE_LABELABORTREQ: 417 imsg_type = IMSG_LABEL_ABORT; 418 break; 419 default: 420 break; 421 } 422 423 ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map, 424 sizeof(struct map)); 425 426 next: 427 TAILQ_REMOVE(&mh, me, entry); 428 free(me); 429 } 430 431 return (0); 432 433 err: 434 mapping_list_clr(&mh); 435 436 return (-1); 437 } 438 439 /* Other TLV related functions */ 440 static int 441 gen_label_tlv(struct ibuf *buf, uint32_t label) 442 { 443 struct label_tlv lt; 444 445 lt.type = htons(TLV_TYPE_GENERICLABEL); 446 lt.length = htons(LABEL_TLV_LEN); 447 lt.label = htonl(label); 448 449 return (ibuf_add(buf, <, sizeof(lt))); 450 } 451 452 static int 453 tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf, 454 uint16_t len, uint32_t *label) 455 { 456 struct label_tlv lt; 457 458 if (len < sizeof(lt)) { 459 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type); 460 return (-1); 461 } 462 memcpy(<, buf, sizeof(lt)); 463 464 if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) { 465 send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type); 466 return (-1); 467 } 468 469 switch (htons(lt.type)) { 470 case TLV_TYPE_GENERICLABEL: 471 if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) { 472 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 473 msg->type); 474 return (-1); 475 } 476 477 *label = ntohl(lt.label); 478 if (*label > MPLS_LABEL_MAX || 479 (*label <= MPLS_LABEL_RESERVED_MAX && 480 *label != MPLS_LABEL_IPV4NULL && 481 *label != MPLS_LABEL_IPV6NULL && 482 *label != MPLS_LABEL_IMPLNULL)) { 483 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, 484 msg->type); 485 return (-1); 486 } 487 break; 488 case TLV_TYPE_ATMLABEL: 489 case TLV_TYPE_FRLABEL: 490 default: 491 /* unsupported */ 492 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type); 493 return (-1); 494 } 495 496 return (sizeof(lt)); 497 } 498 499 static int 500 gen_reqid_tlv(struct ibuf *buf, uint32_t reqid) 501 { 502 struct reqid_tlv rt; 503 504 rt.type = htons(TLV_TYPE_LABELREQUEST); 505 rt.length = htons(REQID_TLV_LEN); 506 rt.reqid = htonl(reqid); 507 508 return (ibuf_add(buf, &rt, sizeof(rt))); 509 } 510 511 int 512 gen_pw_status_tlv(struct ibuf *buf, uint32_t status) 513 { 514 struct pw_status_tlv st; 515 516 st.type = htons(TLV_TYPE_PW_STATUS); 517 st.length = htons(PW_STATUS_TLV_LEN); 518 st.value = htonl(status); 519 520 return (ibuf_add(buf, &st, sizeof(st))); 521 } 522 523 int 524 gen_fec_tlv(struct ibuf *buf, struct map *map) 525 { 526 struct tlv ft; 527 uint16_t family, len, pw_type, ifmtu; 528 uint8_t pw_len = 0; 529 uint32_t group_id, pwid; 530 int err = 0; 531 532 ft.type = htons(TLV_TYPE_FEC); 533 534 switch (map->type) { 535 case MAP_TYPE_WILDCARD: 536 ft.length = htons(sizeof(uint8_t)); 537 err |= ibuf_add(buf, &ft, sizeof(ft)); 538 err |= ibuf_add(buf, &map->type, sizeof(map->type)); 539 break; 540 case MAP_TYPE_PREFIX: 541 len = PREFIX_SIZE(map->fec.prefix.prefixlen); 542 ft.length = htons(sizeof(map->type) + sizeof(family) + 543 sizeof(map->fec.prefix.prefixlen) + len); 544 err |= ibuf_add(buf, &ft, sizeof(ft)); 545 err |= ibuf_add(buf, &map->type, sizeof(map->type)); 546 switch (map->fec.prefix.af) { 547 case AF_INET: 548 family = htons(AF_IPV4); 549 break; 550 case AF_INET6: 551 family = htons(AF_IPV6); 552 break; 553 default: 554 fatalx("gen_fec_tlv: unknown af"); 555 break; 556 } 557 err |= ibuf_add(buf, &family, sizeof(family)); 558 err |= ibuf_add(buf, &map->fec.prefix.prefixlen, 559 sizeof(map->fec.prefix.prefixlen)); 560 if (len) 561 err |= ibuf_add(buf, &map->fec.prefix.prefix, len); 562 break; 563 case MAP_TYPE_PWID: 564 if (map->flags & F_MAP_PW_ID) 565 pw_len += FEC_PWID_SIZE; 566 if (map->flags & F_MAP_PW_IFMTU) 567 pw_len += FEC_SUBTLV_IFMTU_SIZE; 568 569 len = FEC_PWID_ELM_MIN_LEN + pw_len; 570 571 ft.length = htons(len); 572 err |= ibuf_add(buf, &ft, sizeof(ft)); 573 574 err |= ibuf_add(buf, &map->type, sizeof(uint8_t)); 575 pw_type = map->fec.pwid.type; 576 if (map->flags & F_MAP_PW_CWORD) 577 pw_type |= CONTROL_WORD_FLAG; 578 pw_type = htons(pw_type); 579 err |= ibuf_add(buf, &pw_type, sizeof(uint16_t)); 580 err |= ibuf_add(buf, &pw_len, sizeof(uint8_t)); 581 group_id = htonl(map->fec.pwid.group_id); 582 err |= ibuf_add(buf, &group_id, sizeof(uint32_t)); 583 if (map->flags & F_MAP_PW_ID) { 584 pwid = htonl(map->fec.pwid.pwid); 585 err |= ibuf_add(buf, &pwid, sizeof(uint32_t)); 586 } 587 if (map->flags & F_MAP_PW_IFMTU) { 588 struct subtlv stlv; 589 590 stlv.type = SUBTLV_IFMTU; 591 stlv.length = FEC_SUBTLV_IFMTU_SIZE; 592 err |= ibuf_add(buf, &stlv, sizeof(uint16_t)); 593 594 ifmtu = htons(map->fec.pwid.ifmtu); 595 err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t)); 596 } 597 break; 598 default: 599 break; 600 } 601 602 return (err); 603 } 604 605 int 606 tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, 607 uint16_t len, struct map *map) 608 { 609 uint16_t off = 0; 610 uint8_t pw_len; 611 612 map->type = *buf; 613 off += sizeof(uint8_t); 614 615 switch (map->type) { 616 case MAP_TYPE_WILDCARD: 617 if (len == FEC_ELM_WCARD_LEN) 618 return (off); 619 else { 620 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, 621 msg->type); 622 return (-1); 623 } 624 break; 625 case MAP_TYPE_PREFIX: 626 if (len < FEC_ELM_PREFIX_MIN_LEN) { 627 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 628 msg->type); 629 return (-1); 630 } 631 632 /* Address Family */ 633 memcpy(&map->fec.prefix.af, buf + off, 634 sizeof(map->fec.prefix.af)); 635 off += sizeof(map->fec.prefix.af); 636 map->fec.prefix.af = ntohs(map->fec.prefix.af); 637 switch (map->fec.prefix.af) { 638 case AF_IPV4: 639 map->fec.prefix.af = AF_INET; 640 break; 641 case AF_IPV6: 642 map->fec.prefix.af = AF_INET6; 643 break; 644 default: 645 send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id, 646 msg->type); 647 return (-1); 648 } 649 650 /* Prefix Length */ 651 map->fec.prefix.prefixlen = buf[off]; 652 off += sizeof(uint8_t); 653 if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) { 654 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 655 msg->type); 656 return (-1); 657 } 658 659 /* Prefix */ 660 memset(&map->fec.prefix.prefix, 0, 661 sizeof(map->fec.prefix.prefix)); 662 memcpy(&map->fec.prefix.prefix, buf + off, 663 PREFIX_SIZE(map->fec.prefix.prefixlen)); 664 665 /* Just in case... */ 666 ldp_applymask(map->fec.prefix.af, &map->fec.prefix.prefix, 667 &map->fec.prefix.prefix, map->fec.prefix.prefixlen); 668 669 return (off + PREFIX_SIZE(map->fec.prefix.prefixlen)); 670 case MAP_TYPE_PWID: 671 if (len < FEC_PWID_ELM_MIN_LEN) { 672 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 673 msg->type); 674 return (-1); 675 } 676 677 /* PW type */ 678 memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t)); 679 map->fec.pwid.type = ntohs(map->fec.pwid.type); 680 if (map->fec.pwid.type & CONTROL_WORD_FLAG) { 681 map->flags |= F_MAP_PW_CWORD; 682 map->fec.pwid.type &= ~CONTROL_WORD_FLAG; 683 } 684 off += sizeof(uint16_t); 685 686 /* PW info Length */ 687 pw_len = buf[off]; 688 off += sizeof(uint8_t); 689 690 if (len != FEC_PWID_ELM_MIN_LEN + pw_len) { 691 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 692 msg->type); 693 return (-1); 694 } 695 696 /* Group ID */ 697 memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t)); 698 map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id); 699 off += sizeof(uint32_t); 700 701 /* PW ID */ 702 if (pw_len == 0) 703 return (off); 704 705 if (pw_len < sizeof(uint32_t)) { 706 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 707 msg->type); 708 return (-1); 709 } 710 711 memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t)); 712 map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid); 713 map->flags |= F_MAP_PW_ID; 714 off += sizeof(uint32_t); 715 pw_len -= sizeof(uint32_t); 716 717 /* Optional Interface Parameter Sub-TLVs */ 718 while (pw_len > 0) { 719 struct subtlv stlv; 720 721 if (pw_len < sizeof(stlv)) { 722 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 723 msg->type); 724 return (-1); 725 } 726 727 memcpy(&stlv, buf + off, sizeof(stlv)); 728 if (stlv.length > pw_len) { 729 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 730 msg->type); 731 return (-1); 732 } 733 734 switch (stlv.type) { 735 case SUBTLV_IFMTU: 736 if (stlv.length != FEC_SUBTLV_IFMTU_SIZE) { 737 session_shutdown(nbr, S_BAD_TLV_LEN, 738 msg->id, msg->type); 739 return (-1); 740 } 741 memcpy(&map->fec.pwid.ifmtu, buf + off + 742 SUBTLV_HDR_SIZE, sizeof(uint16_t)); 743 map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu); 744 map->flags |= F_MAP_PW_IFMTU; 745 break; 746 default: 747 /* ignore */ 748 break; 749 } 750 off += stlv.length; 751 pw_len -= stlv.length; 752 } 753 754 return (off); 755 default: 756 send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type); 757 break; 758 } 759 760 return (-1); 761 } 762 763 static void 764 log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map) 765 { 766 log_debug("msg-%s: %s: lsr-id %s, fec %s, label %s", 767 (out) ? "out" : "in", msg_name(msg_type), inet_ntoa(nbr->id), 768 log_map(map), log_label(map->label)); 769 } 770