1 /* $OpenBSD: labelmapping.c,v 1.50 2016/06/11 02:01:46 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 void 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 void gen_reqid_tlv(struct ibuf *, uint32_t); 37 38 static void 39 enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size) 40 { 41 struct ldp_hdr *ldp_hdr; 42 43 ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr)); 44 ldp_hdr->length = htons(size); 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 57 /* nothing to send */ 58 if (TAILQ_EMPTY(mh)) 59 return; 60 61 while ((me = TAILQ_FIRST(mh)) != NULL) { 62 /* generate pdu */ 63 if (first) { 64 if ((buf = ibuf_open(nbr->max_pdu_len + 65 LDP_HDR_DEAD_LEN)) == NULL) 66 fatal(__func__); 67 68 /* real size will be set up later */ 69 gen_ldp_hdr(buf, 0); 70 71 size = LDP_HDR_PDU_LEN; 72 first = 0; 73 } 74 75 /* calculate size */ 76 msg_size = LDP_MSG_SIZE + TLV_HDR_LEN; 77 78 switch (me->map.type) { 79 case MAP_TYPE_WILDCARD: 80 msg_size += FEC_ELM_WCARD_LEN; 81 break; 82 case MAP_TYPE_PREFIX: 83 msg_size += FEC_ELM_PREFIX_MIN_LEN + 84 PREFIX_SIZE(me->map.fec.prefix.prefixlen); 85 break; 86 case MAP_TYPE_PWID: 87 msg_size += FEC_PWID_ELM_MIN_LEN; 88 89 if (me->map.flags & F_MAP_PW_ID) 90 msg_size += sizeof(uint32_t); 91 if (me->map.flags & F_MAP_PW_IFMTU) 92 msg_size += FEC_SUBTLV_IFMTU_LEN; 93 if (me->map.flags & F_MAP_PW_STATUS) 94 msg_size += PW_STATUS_TLV_LEN; 95 break; 96 } 97 98 if (me->map.label != NO_LABEL) 99 msg_size += LABEL_TLV_LEN; 100 if (me->map.flags & F_MAP_REQ_ID) 101 msg_size += REQID_TLV_LEN; 102 103 /* maximum pdu length exceeded, we need a new ldp pdu */ 104 if (size + msg_size > nbr->max_pdu_len) { 105 enqueue_pdu(nbr, buf, size); 106 first = 1; 107 continue; 108 } 109 110 size += msg_size; 111 112 /* append message and tlvs */ 113 gen_msg_hdr(buf, type, msg_size); 114 gen_fec_tlv(buf, &me->map); 115 if (me->map.label != NO_LABEL) 116 gen_label_tlv(buf, me->map.label); 117 if (me->map.flags & F_MAP_REQ_ID) 118 gen_reqid_tlv(buf, me->map.requestid); 119 if (me->map.flags & F_MAP_PW_STATUS) 120 gen_pw_status_tlv(buf, me->map.pw_status); 121 122 TAILQ_REMOVE(mh, me, entry); 123 free(me); 124 } 125 126 enqueue_pdu(nbr, buf, size); 127 128 nbr_fsm(nbr, NBR_EVT_PDU_SENT); 129 } 130 131 /* Generic function that handles all Label Message types */ 132 int 133 recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) 134 { 135 struct ldp_msg lm; 136 struct tlv ft; 137 uint32_t label = NO_LABEL, reqid = 0; 138 uint32_t pw_status = 0; 139 uint8_t flags = 0; 140 int feclen, lbllen, tlen; 141 struct mapping_entry *me; 142 struct mapping_head mh; 143 struct map map; 144 145 memcpy(&lm, buf, sizeof(lm)); 146 buf += LDP_MSG_SIZE; 147 len -= LDP_MSG_SIZE; 148 149 /* FEC TLV */ 150 if (len < sizeof(ft)) { 151 session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type); 152 return (-1); 153 } 154 155 memcpy(&ft, buf, sizeof(ft)); 156 if (ntohs(ft.type) != TLV_TYPE_FEC) { 157 send_notification_nbr(nbr, S_MISS_MSG, lm.msgid, lm.type); 158 return (-1); 159 } 160 feclen = ntohs(ft.length); 161 162 if (feclen > len - TLV_HDR_LEN) { 163 session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type); 164 return (-1); 165 } 166 167 buf += TLV_HDR_LEN; /* just advance to the end of the fec header */ 168 len -= TLV_HDR_LEN; 169 170 TAILQ_INIT(&mh); 171 do { 172 memset(&map, 0, sizeof(map)); 173 map.messageid = lm.msgid; 174 175 if ((tlen = tlv_decode_fec_elm(nbr, &lm, buf, feclen, 176 &map)) == -1) 177 goto err; 178 if (map.type == MAP_TYPE_PWID && 179 !(map.flags & F_MAP_PW_ID) && 180 type != MSG_TYPE_LABELWITHDRAW && 181 type != MSG_TYPE_LABELRELEASE) { 182 send_notification_nbr(nbr, S_MISS_MSG, lm.msgid, 183 lm.type); 184 return (-1); 185 } 186 187 /* 188 * The Wildcard FEC Element can be used only in the 189 * Label Withdraw and Label Release messages. 190 */ 191 if (map.type == MAP_TYPE_WILDCARD) { 192 switch (type) { 193 case MSG_TYPE_LABELMAPPING: 194 case MSG_TYPE_LABELREQUEST: 195 case MSG_TYPE_LABELABORTREQ: 196 session_shutdown(nbr, S_UNKNOWN_FEC, lm.msgid, 197 lm.type); 198 goto err; 199 default: 200 break; 201 } 202 } 203 204 /* 205 * LDP supports the use of multiple FEC Elements per 206 * FEC for the Label Mapping message only. 207 */ 208 if (type != MSG_TYPE_LABELMAPPING && 209 tlen != feclen) { 210 session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, 211 lm.type); 212 goto err; 213 } 214 215 mapping_list_add(&mh, &map); 216 217 buf += tlen; 218 len -= tlen; 219 feclen -= tlen; 220 } while (feclen > 0); 221 222 /* Mandatory Label TLV */ 223 if (type == MSG_TYPE_LABELMAPPING) { 224 lbllen = tlv_decode_label(nbr, &lm, buf, len, &label); 225 if (lbllen == -1) 226 goto err; 227 228 buf += lbllen; 229 len -= lbllen; 230 } 231 232 /* Optional Parameters */ 233 while (len > 0) { 234 struct tlv tlv; 235 uint16_t tlv_len; 236 uint32_t reqbuf, labelbuf, statusbuf; 237 238 if (len < sizeof(tlv)) { 239 session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, 240 lm.type); 241 goto err; 242 } 243 244 memcpy(&tlv, buf, TLV_HDR_LEN); 245 buf += TLV_HDR_LEN; 246 len -= TLV_HDR_LEN; 247 tlv_len = ntohs(tlv.length); 248 249 switch (ntohs(tlv.type)) { 250 case TLV_TYPE_LABELREQUEST: 251 switch (type) { 252 case MSG_TYPE_LABELMAPPING: 253 case MSG_TYPE_LABELREQUEST: 254 if (tlv_len != 4) { 255 session_shutdown(nbr, S_BAD_TLV_LEN, 256 lm.msgid, lm.type); 257 goto err; 258 } 259 260 flags |= F_MAP_REQ_ID; 261 memcpy(&reqbuf, buf, sizeof(reqbuf)); 262 reqid = ntohl(reqbuf); 263 break; 264 default: 265 /* ignore */ 266 break; 267 } 268 break; 269 case TLV_TYPE_HOPCOUNT: 270 case TLV_TYPE_PATHVECTOR: 271 /* TODO just ignore for now */ 272 break; 273 case TLV_TYPE_GENERICLABEL: 274 switch (type) { 275 case MSG_TYPE_LABELWITHDRAW: 276 case MSG_TYPE_LABELRELEASE: 277 if (tlv_len != 4) { 278 session_shutdown(nbr, S_BAD_TLV_LEN, 279 lm.msgid, lm.type); 280 goto err; 281 } 282 283 memcpy(&labelbuf, buf, sizeof(labelbuf)); 284 label = ntohl(labelbuf); 285 break; 286 default: 287 /* ignore */ 288 break; 289 } 290 break; 291 case TLV_TYPE_ATMLABEL: 292 case TLV_TYPE_FRLABEL: 293 switch (type) { 294 case MSG_TYPE_LABELWITHDRAW: 295 case MSG_TYPE_LABELRELEASE: 296 /* unsupported */ 297 session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, 298 lm.type); 299 goto err; 300 break; 301 default: 302 /* ignore */ 303 break; 304 } 305 break; 306 case TLV_TYPE_PW_STATUS: 307 switch (type) { 308 case MSG_TYPE_LABELMAPPING: 309 if (tlv_len != 4) { 310 session_shutdown(nbr, S_BAD_TLV_LEN, 311 lm.msgid, lm.type); 312 goto err; 313 } 314 315 flags |= F_MAP_PW_STATUS; 316 memcpy(&statusbuf, buf, sizeof(statusbuf)); 317 pw_status = ntohl(statusbuf); 318 break; 319 default: 320 /* ignore */ 321 break; 322 } 323 break; 324 default: 325 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) { 326 send_notification_nbr(nbr, S_UNKNOWN_TLV, 327 lm.msgid, lm.type); 328 } 329 /* ignore unknown tlv */ 330 break; 331 } 332 buf += tlv_len; 333 len -= tlv_len; 334 } 335 336 /* notify lde about the received message. */ 337 while ((me = TAILQ_FIRST(&mh)) != NULL) { 338 int imsg_type = IMSG_NONE; 339 340 me->map.flags |= flags; 341 switch (me->map.type) { 342 case MAP_TYPE_PREFIX: 343 switch (me->map.fec.prefix.af) { 344 case AF_IPV4: 345 if (label == MPLS_LABEL_IPV6NULL) { 346 session_shutdown(nbr, S_BAD_TLV_VAL, 347 lm.msgid, lm.type); 348 goto err; 349 } 350 if (!nbr->v4_enabled) 351 goto next; 352 break; 353 case AF_IPV6: 354 if (label == MPLS_LABEL_IPV4NULL) { 355 session_shutdown(nbr, S_BAD_TLV_VAL, 356 lm.msgid, lm.type); 357 goto err; 358 } 359 if (!nbr->v6_enabled) 360 goto next; 361 break; 362 default: 363 fatalx("recv_labelmessage: unknown af"); 364 } 365 break; 366 case MAP_TYPE_PWID: 367 if (label <= MPLS_LABEL_RESERVED_MAX) { 368 session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, 369 lm.type); 370 goto err; 371 } 372 if (me->map.flags & F_MAP_PW_STATUS) 373 me->map.pw_status = pw_status; 374 break; 375 default: 376 break; 377 } 378 me->map.label = label; 379 if (me->map.flags & F_MAP_REQ_ID) 380 me->map.requestid = reqid; 381 382 switch (type) { 383 case MSG_TYPE_LABELMAPPING: 384 log_debug("label mapping from nbr %s, FEC %s, " 385 "label %u", inet_ntoa(nbr->id), 386 log_map(&me->map), me->map.label); 387 imsg_type = IMSG_LABEL_MAPPING; 388 break; 389 case MSG_TYPE_LABELREQUEST: 390 log_debug("label request from nbr %s, FEC %s", 391 inet_ntoa(nbr->id), log_map(&me->map)); 392 imsg_type = IMSG_LABEL_REQUEST; 393 break; 394 case MSG_TYPE_LABELWITHDRAW: 395 log_debug("label withdraw from nbr %s, FEC %s", 396 inet_ntoa(nbr->id), log_map(&me->map)); 397 imsg_type = IMSG_LABEL_WITHDRAW; 398 break; 399 case MSG_TYPE_LABELRELEASE: 400 log_debug("label release from nbr %s, FEC %s", 401 inet_ntoa(nbr->id), log_map(&me->map)); 402 imsg_type = IMSG_LABEL_RELEASE; 403 break; 404 case MSG_TYPE_LABELABORTREQ: 405 log_debug("label abort from nbr %s, FEC %s", 406 inet_ntoa(nbr->id), log_map(&me->map)); 407 imsg_type = IMSG_LABEL_ABORT; 408 break; 409 default: 410 break; 411 } 412 413 ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map, 414 sizeof(struct map)); 415 416 next: 417 TAILQ_REMOVE(&mh, me, entry); 418 free(me); 419 } 420 421 return (0); 422 423 err: 424 mapping_list_clr(&mh); 425 426 return (-1); 427 } 428 429 /* Other TLV related functions */ 430 static void 431 gen_label_tlv(struct ibuf *buf, uint32_t label) 432 { 433 struct label_tlv lt; 434 435 lt.type = htons(TLV_TYPE_GENERICLABEL); 436 lt.length = htons(sizeof(label)); 437 lt.label = htonl(label); 438 439 ibuf_add(buf, <, sizeof(lt)); 440 } 441 442 static int 443 tlv_decode_label(struct nbr *nbr, struct ldp_msg *lm, char *buf, 444 uint16_t len, uint32_t *label) 445 { 446 struct label_tlv lt; 447 448 if (len < sizeof(lt)) { 449 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); 450 return (-1); 451 } 452 memcpy(<, buf, sizeof(lt)); 453 454 if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) { 455 send_notification_nbr(nbr, S_MISS_MSG, lm->msgid, lm->type); 456 return (-1); 457 } 458 459 switch (htons(lt.type)) { 460 case TLV_TYPE_GENERICLABEL: 461 if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_LEN) { 462 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 463 lm->type); 464 return (-1); 465 } 466 467 *label = ntohl(lt.label); 468 if (*label > MPLS_LABEL_MAX || 469 (*label <= MPLS_LABEL_RESERVED_MAX && 470 *label != MPLS_LABEL_IPV4NULL && 471 *label != MPLS_LABEL_IPV6NULL && 472 *label != MPLS_LABEL_IMPLNULL)) { 473 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, 474 lm->type); 475 return (-1); 476 } 477 break; 478 case TLV_TYPE_ATMLABEL: 479 case TLV_TYPE_FRLABEL: 480 default: 481 /* unsupported */ 482 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, lm->type); 483 return (-1); 484 } 485 486 return (sizeof(lt)); 487 } 488 489 static void 490 gen_reqid_tlv(struct ibuf *buf, uint32_t reqid) 491 { 492 struct reqid_tlv rt; 493 494 rt.type = htons(TLV_TYPE_LABELREQUEST); 495 rt.length = htons(sizeof(reqid)); 496 rt.reqid = htonl(reqid); 497 498 ibuf_add(buf, &rt, sizeof(rt)); 499 } 500 501 void 502 gen_pw_status_tlv(struct ibuf *buf, uint32_t status) 503 { 504 struct pw_status_tlv st; 505 506 st.type = htons(TLV_TYPE_PW_STATUS); 507 st.length = htons(sizeof(status)); 508 st.value = htonl(status); 509 510 ibuf_add(buf, &st, sizeof(st)); 511 } 512 513 void 514 gen_fec_tlv(struct ibuf *buf, struct map *map) 515 { 516 struct tlv ft; 517 uint16_t family, len, pw_type, ifmtu; 518 uint8_t pw_len = 0; 519 uint32_t group_id, pwid; 520 521 ft.type = htons(TLV_TYPE_FEC); 522 523 switch (map->type) { 524 case MAP_TYPE_WILDCARD: 525 ft.length = htons(sizeof(uint8_t)); 526 ibuf_add(buf, &ft, sizeof(ft)); 527 ibuf_add(buf, &map->type, sizeof(map->type)); 528 break; 529 case MAP_TYPE_PREFIX: 530 len = PREFIX_SIZE(map->fec.prefix.prefixlen); 531 ft.length = htons(sizeof(map->type) + sizeof(family) + 532 sizeof(map->fec.prefix.prefixlen) + len); 533 ibuf_add(buf, &ft, sizeof(ft)); 534 535 ibuf_add(buf, &map->type, sizeof(map->type)); 536 family = htons(map->fec.prefix.af); 537 ibuf_add(buf, &family, sizeof(family)); 538 ibuf_add(buf, &map->fec.prefix.prefixlen, 539 sizeof(map->fec.prefix.prefixlen)); 540 if (len) 541 ibuf_add(buf, &map->fec.prefix.prefix, len); 542 break; 543 case MAP_TYPE_PWID: 544 if (map->flags & F_MAP_PW_ID) 545 pw_len += sizeof(uint32_t); 546 if (map->flags & F_MAP_PW_IFMTU) 547 pw_len += FEC_SUBTLV_IFMTU_LEN; 548 549 len = FEC_PWID_ELM_MIN_LEN + pw_len; 550 551 ft.length = htons(len); 552 ibuf_add(buf, &ft, sizeof(ft)); 553 554 ibuf_add(buf, &map->type, sizeof(uint8_t)); 555 pw_type = map->fec.pwid.type; 556 if (map->flags & F_MAP_PW_CWORD) 557 pw_type |= CONTROL_WORD_FLAG; 558 pw_type = htons(pw_type); 559 ibuf_add(buf, &pw_type, sizeof(uint16_t)); 560 ibuf_add(buf, &pw_len, sizeof(uint8_t)); 561 group_id = htonl(map->fec.pwid.group_id); 562 ibuf_add(buf, &group_id, sizeof(uint32_t)); 563 if (map->flags & F_MAP_PW_ID) { 564 pwid = htonl(map->fec.pwid.pwid); 565 ibuf_add(buf, &pwid, sizeof(uint32_t)); 566 } 567 if (map->flags & F_MAP_PW_IFMTU) { 568 struct subtlv stlv; 569 570 stlv.type = SUBTLV_IFMTU; 571 stlv.length = FEC_SUBTLV_IFMTU_LEN; 572 ibuf_add(buf, &stlv, sizeof(uint16_t)); 573 574 ifmtu = htons(map->fec.pwid.ifmtu); 575 ibuf_add(buf, &ifmtu, sizeof(uint16_t)); 576 } 577 break; 578 default: 579 break; 580 } 581 } 582 583 int 584 tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf, 585 uint16_t len, struct map *map) 586 { 587 uint16_t off = 0; 588 uint8_t pw_len; 589 590 map->type = *buf; 591 off += sizeof(uint8_t); 592 593 switch (map->type) { 594 case MAP_TYPE_WILDCARD: 595 if (len == FEC_ELM_WCARD_LEN) 596 return (off); 597 else { 598 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, 599 lm->type); 600 return (-1); 601 } 602 break; 603 case MAP_TYPE_PREFIX: 604 if (len < FEC_ELM_PREFIX_MIN_LEN) { 605 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 606 lm->type); 607 return (-1); 608 } 609 610 /* Address Family */ 611 memcpy(&map->fec.prefix.af, buf + off, 612 sizeof(map->fec.prefix.af)); 613 map->fec.prefix.af = ntohs(map->fec.prefix.af); 614 off += sizeof(map->fec.prefix.af); 615 if (map->fec.prefix.af != AF_IPV4 && 616 map->fec.prefix.af != AF_IPV6) { 617 send_notification_nbr(nbr, S_UNSUP_ADDR, lm->msgid, 618 lm->type); 619 return (-1); 620 } 621 622 /* Prefix Length */ 623 map->fec.prefix.prefixlen = buf[off]; 624 off += sizeof(uint8_t); 625 if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) { 626 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 627 lm->type); 628 return (-1); 629 } 630 631 /* Prefix */ 632 memset(&map->fec.prefix.prefix, 0, 633 sizeof(map->fec.prefix.prefix)); 634 memcpy(&map->fec.prefix.prefix, buf + off, 635 PREFIX_SIZE(map->fec.prefix.prefixlen)); 636 637 return (off + PREFIX_SIZE(map->fec.prefix.prefixlen)); 638 case MAP_TYPE_PWID: 639 if (len < FEC_PWID_ELM_MIN_LEN) { 640 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 641 lm->type); 642 return (-1); 643 } 644 645 /* PW type */ 646 memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t)); 647 map->fec.pwid.type = ntohs(map->fec.pwid.type); 648 if (map->fec.pwid.type & CONTROL_WORD_FLAG) { 649 map->flags |= F_MAP_PW_CWORD; 650 map->fec.pwid.type &= ~CONTROL_WORD_FLAG; 651 } 652 off += sizeof(uint16_t); 653 654 /* PW info Length */ 655 pw_len = buf[off]; 656 off += sizeof(uint8_t); 657 658 if (len != FEC_PWID_ELM_MIN_LEN + pw_len) { 659 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 660 lm->type); 661 return (-1); 662 } 663 664 /* Group ID */ 665 memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t)); 666 map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id); 667 off += sizeof(uint32_t); 668 669 /* PW ID */ 670 if (pw_len == 0) 671 return (off); 672 673 if (pw_len < sizeof(uint32_t)) { 674 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 675 lm->type); 676 return (-1); 677 } 678 679 memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t)); 680 map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid); 681 map->flags |= F_MAP_PW_ID; 682 off += sizeof(uint32_t); 683 pw_len -= sizeof(uint32_t); 684 685 /* Optional Interface Parameter Sub-TLVs */ 686 while (pw_len > 0) { 687 struct subtlv stlv; 688 689 if (pw_len < sizeof(stlv)) { 690 session_shutdown(nbr, S_BAD_TLV_LEN, 691 lm->msgid, lm->type); 692 return (-1); 693 } 694 695 memcpy(&stlv, buf + off, sizeof(stlv)); 696 off += SUBTLV_HDR_LEN; 697 pw_len -= SUBTLV_HDR_LEN; 698 699 switch (stlv.type) { 700 case SUBTLV_IFMTU: 701 if (stlv.length != FEC_SUBTLV_IFMTU_LEN) { 702 session_shutdown(nbr, S_BAD_TLV_LEN, 703 lm->msgid, lm->type); 704 return (-1); 705 } 706 memcpy(&map->fec.pwid.ifmtu, buf + off, 707 sizeof(uint16_t)); 708 map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu); 709 map->flags |= F_MAP_PW_IFMTU; 710 break; 711 default: 712 /* ignore */ 713 break; 714 } 715 off += stlv.length - SUBTLV_HDR_LEN; 716 pw_len -= stlv.length - SUBTLV_HDR_LEN; 717 } 718 719 return (off); 720 default: 721 send_notification_nbr(nbr, S_UNKNOWN_FEC, lm->msgid, lm->type); 722 break; 723 } 724 725 return (-1); 726 } 727