1 /* $OpenBSD: labelmapping.c,v 1.47 2016/06/11 01:44:02 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_BAD_TLV_VAL, 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 uint32_t reqbuf, labelbuf, statusbuf; 236 237 if (len < sizeof(tlv)) { 238 session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, 239 lm.type); 240 goto err; 241 } 242 243 memcpy(&tlv, buf, sizeof(tlv)); 244 buf += TLV_HDR_LEN; 245 len -= TLV_HDR_LEN; 246 247 switch (ntohs(tlv.type) & ~UNKNOWN_FLAG) { 248 case TLV_TYPE_LABELREQUEST: 249 switch (type) { 250 case MSG_TYPE_LABELMAPPING: 251 case MSG_TYPE_LABELREQUEST: 252 if (ntohs(tlv.length) != 4) { 253 session_shutdown(nbr, S_BAD_TLV_LEN, 254 lm.msgid, lm.type); 255 goto err; 256 } 257 258 flags |= F_MAP_REQ_ID; 259 memcpy(&reqbuf, buf, sizeof(reqbuf)); 260 reqid = ntohl(reqbuf); 261 break; 262 default: 263 /* ignore */ 264 break; 265 } 266 break; 267 case TLV_TYPE_HOPCOUNT: 268 case TLV_TYPE_PATHVECTOR: 269 /* TODO just ignore for now */ 270 break; 271 case TLV_TYPE_GENERICLABEL: 272 switch (type) { 273 case MSG_TYPE_LABELWITHDRAW: 274 case MSG_TYPE_LABELRELEASE: 275 if (ntohs(tlv.length) != 4) { 276 session_shutdown(nbr, S_BAD_TLV_LEN, 277 lm.msgid, lm.type); 278 goto err; 279 } 280 281 memcpy(&labelbuf, buf, sizeof(labelbuf)); 282 label = ntohl(labelbuf); 283 break; 284 default: 285 /* ignore */ 286 break; 287 } 288 break; 289 case TLV_TYPE_ATMLABEL: 290 case TLV_TYPE_FRLABEL: 291 switch (type) { 292 case MSG_TYPE_LABELWITHDRAW: 293 case MSG_TYPE_LABELRELEASE: 294 /* unsupported */ 295 session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, 296 lm.type); 297 goto err; 298 break; 299 default: 300 /* ignore */ 301 break; 302 } 303 break; 304 case TLV_TYPE_PW_STATUS: 305 switch (type) { 306 case MSG_TYPE_LABELMAPPING: 307 if (ntohs(tlv.length) != 4) { 308 session_shutdown(nbr, S_BAD_TLV_LEN, 309 lm.msgid, lm.type); 310 goto err; 311 } 312 313 flags |= F_MAP_PW_STATUS; 314 memcpy(&statusbuf, buf, sizeof(statusbuf)); 315 pw_status = ntohl(statusbuf); 316 break; 317 default: 318 /* ignore */ 319 break; 320 } 321 break; 322 default: 323 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) { 324 send_notification_nbr(nbr, S_UNKNOWN_TLV, 325 lm.msgid, lm.type); 326 } 327 /* ignore unknown tlv */ 328 break; 329 } 330 buf += ntohs(tlv.length); 331 len -= ntohs(tlv.length); 332 } 333 334 /* notify lde about the received message. */ 335 while ((me = TAILQ_FIRST(&mh)) != NULL) { 336 int imsg_type = IMSG_NONE; 337 338 me->map.flags |= flags; 339 switch (me->map.type) { 340 case MAP_TYPE_PREFIX: 341 switch (me->map.fec.prefix.af) { 342 case AF_IPV4: 343 if (label == MPLS_LABEL_IPV6NULL) { 344 session_shutdown(nbr, S_BAD_TLV_VAL, 345 lm.msgid, lm.type); 346 goto err; 347 } 348 if (!nbr->v4_enabled) 349 goto next; 350 break; 351 case AF_IPV6: 352 if (label == MPLS_LABEL_IPV4NULL) { 353 session_shutdown(nbr, S_BAD_TLV_VAL, 354 lm.msgid, lm.type); 355 goto err; 356 } 357 if (!nbr->v6_enabled) 358 goto next; 359 break; 360 default: 361 fatalx("recv_labelmessage: unknown af"); 362 } 363 break; 364 case MAP_TYPE_PWID: 365 if (label <= MPLS_LABEL_RESERVED_MAX) { 366 session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, 367 lm.type); 368 goto err; 369 } 370 if (me->map.flags & F_MAP_PW_STATUS) 371 me->map.pw_status = pw_status; 372 break; 373 default: 374 break; 375 } 376 me->map.label = label; 377 if (me->map.flags & F_MAP_REQ_ID) 378 me->map.requestid = reqid; 379 380 switch (type) { 381 case MSG_TYPE_LABELMAPPING: 382 log_debug("label mapping from nbr %s, FEC %s, " 383 "label %u", inet_ntoa(nbr->id), 384 log_map(&me->map), me->map.label); 385 imsg_type = IMSG_LABEL_MAPPING; 386 break; 387 case MSG_TYPE_LABELREQUEST: 388 log_debug("label request from nbr %s, FEC %s", 389 inet_ntoa(nbr->id), log_map(&me->map)); 390 imsg_type = IMSG_LABEL_REQUEST; 391 break; 392 case MSG_TYPE_LABELWITHDRAW: 393 log_debug("label withdraw from nbr %s, FEC %s", 394 inet_ntoa(nbr->id), log_map(&me->map)); 395 imsg_type = IMSG_LABEL_WITHDRAW; 396 break; 397 case MSG_TYPE_LABELRELEASE: 398 log_debug("label release from nbr %s, FEC %s", 399 inet_ntoa(nbr->id), log_map(&me->map)); 400 imsg_type = IMSG_LABEL_RELEASE; 401 break; 402 case MSG_TYPE_LABELABORTREQ: 403 log_debug("label abort from nbr %s, FEC %s", 404 inet_ntoa(nbr->id), log_map(&me->map)); 405 imsg_type = IMSG_LABEL_ABORT; 406 break; 407 default: 408 break; 409 } 410 411 ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map, 412 sizeof(struct map)); 413 414 next: 415 TAILQ_REMOVE(&mh, me, entry); 416 free(me); 417 } 418 419 return (0); 420 421 err: 422 mapping_list_clr(&mh); 423 424 return (-1); 425 } 426 427 /* Other TLV related functions */ 428 static void 429 gen_label_tlv(struct ibuf *buf, uint32_t label) 430 { 431 struct label_tlv lt; 432 433 lt.type = htons(TLV_TYPE_GENERICLABEL); 434 lt.length = htons(sizeof(label)); 435 lt.label = htonl(label); 436 437 ibuf_add(buf, <, sizeof(lt)); 438 } 439 440 static int 441 tlv_decode_label(struct nbr *nbr, struct ldp_msg *lm, char *buf, 442 uint16_t len, uint32_t *label) 443 { 444 struct label_tlv lt; 445 446 if (len < sizeof(lt)) { 447 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); 448 return (-1); 449 } 450 memcpy(<, buf, sizeof(lt)); 451 452 if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) { 453 send_notification_nbr(nbr, S_MISS_MSG, lm->msgid, lm->type); 454 return (-1); 455 } 456 457 switch (htons(lt.type)) { 458 case TLV_TYPE_GENERICLABEL: 459 if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_LEN) { 460 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 461 lm->type); 462 return (-1); 463 } 464 465 *label = ntohl(lt.label); 466 if (*label > MPLS_LABEL_MAX || 467 (*label <= MPLS_LABEL_RESERVED_MAX && 468 *label != MPLS_LABEL_IPV4NULL && 469 *label != MPLS_LABEL_IPV6NULL && 470 *label != MPLS_LABEL_IMPLNULL)) { 471 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, 472 lm->type); 473 return (-1); 474 } 475 break; 476 case TLV_TYPE_ATMLABEL: 477 case TLV_TYPE_FRLABEL: 478 default: 479 /* unsupported */ 480 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, lm->type); 481 return (-1); 482 } 483 484 return (sizeof(lt)); 485 } 486 487 static void 488 gen_reqid_tlv(struct ibuf *buf, uint32_t reqid) 489 { 490 struct reqid_tlv rt; 491 492 rt.type = htons(TLV_TYPE_LABELREQUEST); 493 rt.length = htons(sizeof(reqid)); 494 rt.reqid = htonl(reqid); 495 496 ibuf_add(buf, &rt, sizeof(rt)); 497 } 498 499 void 500 gen_pw_status_tlv(struct ibuf *buf, uint32_t status) 501 { 502 struct pw_status_tlv st; 503 504 st.type = htons(TLV_TYPE_PW_STATUS); 505 st.length = htons(sizeof(status)); 506 st.value = htonl(status); 507 508 ibuf_add(buf, &st, sizeof(st)); 509 } 510 511 void 512 gen_fec_tlv(struct ibuf *buf, struct map *map) 513 { 514 struct tlv ft; 515 uint16_t family, len, pw_type, ifmtu; 516 uint8_t pw_len = 0; 517 uint32_t group_id, pwid; 518 519 ft.type = htons(TLV_TYPE_FEC); 520 521 switch (map->type) { 522 case MAP_TYPE_WILDCARD: 523 ft.length = htons(sizeof(uint8_t)); 524 ibuf_add(buf, &ft, sizeof(ft)); 525 ibuf_add(buf, &map->type, sizeof(map->type)); 526 break; 527 case MAP_TYPE_PREFIX: 528 len = PREFIX_SIZE(map->fec.prefix.prefixlen); 529 ft.length = htons(sizeof(map->type) + sizeof(family) + 530 sizeof(map->fec.prefix.prefixlen) + len); 531 ibuf_add(buf, &ft, sizeof(ft)); 532 533 ibuf_add(buf, &map->type, sizeof(map->type)); 534 family = htons(map->fec.prefix.af); 535 ibuf_add(buf, &family, sizeof(family)); 536 ibuf_add(buf, &map->fec.prefix.prefixlen, 537 sizeof(map->fec.prefix.prefixlen)); 538 if (len) 539 ibuf_add(buf, &map->fec.prefix.prefix, len); 540 break; 541 case MAP_TYPE_PWID: 542 if (map->flags & F_MAP_PW_ID) 543 pw_len += sizeof(uint32_t); 544 if (map->flags & F_MAP_PW_IFMTU) 545 pw_len += FEC_SUBTLV_IFMTU_LEN; 546 547 len = FEC_PWID_ELM_MIN_LEN + pw_len; 548 549 ft.length = htons(len); 550 ibuf_add(buf, &ft, sizeof(ft)); 551 552 ibuf_add(buf, &map->type, sizeof(uint8_t)); 553 pw_type = map->fec.pwid.type; 554 if (map->flags & F_MAP_PW_CWORD) 555 pw_type |= CONTROL_WORD_FLAG; 556 pw_type = htons(pw_type); 557 ibuf_add(buf, &pw_type, sizeof(uint16_t)); 558 ibuf_add(buf, &pw_len, sizeof(uint8_t)); 559 group_id = htonl(map->fec.pwid.group_id); 560 ibuf_add(buf, &group_id, sizeof(uint32_t)); 561 if (map->flags & F_MAP_PW_ID) { 562 pwid = htonl(map->fec.pwid.pwid); 563 ibuf_add(buf, &pwid, sizeof(uint32_t)); 564 } 565 if (map->flags & F_MAP_PW_IFMTU) { 566 struct subtlv stlv; 567 568 stlv.type = SUBTLV_IFMTU; 569 stlv.length = FEC_SUBTLV_IFMTU_LEN; 570 ibuf_add(buf, &stlv, sizeof(uint16_t)); 571 572 ifmtu = htons(map->fec.pwid.ifmtu); 573 ibuf_add(buf, &ifmtu, sizeof(uint16_t)); 574 } 575 break; 576 default: 577 break; 578 } 579 } 580 581 int 582 tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf, 583 uint16_t len, struct map *map) 584 { 585 uint16_t off = 0; 586 uint8_t pw_len; 587 588 map->type = *buf; 589 off += sizeof(uint8_t); 590 591 switch (map->type) { 592 case MAP_TYPE_WILDCARD: 593 if (len == FEC_ELM_WCARD_LEN) 594 return (off); 595 else { 596 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, 597 lm->type); 598 return (-1); 599 } 600 break; 601 case MAP_TYPE_PREFIX: 602 if (len < FEC_ELM_PREFIX_MIN_LEN) { 603 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 604 lm->type); 605 return (-1); 606 } 607 608 /* Address Family */ 609 memcpy(&map->fec.prefix.af, buf + off, 610 sizeof(map->fec.prefix.af)); 611 map->fec.prefix.af = ntohs(map->fec.prefix.af); 612 off += sizeof(map->fec.prefix.af); 613 if (map->fec.prefix.af != AF_IPV4 && 614 map->fec.prefix.af != AF_IPV6) { 615 send_notification_nbr(nbr, S_UNSUP_ADDR, lm->msgid, 616 lm->type); 617 return (-1); 618 } 619 620 /* Prefix Length */ 621 map->fec.prefix.prefixlen = buf[off]; 622 off += sizeof(uint8_t); 623 if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) { 624 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 625 lm->type); 626 return (-1); 627 } 628 629 /* Prefix */ 630 memset(&map->fec.prefix.prefix, 0, 631 sizeof(map->fec.prefix.prefix)); 632 memcpy(&map->fec.prefix.prefix, buf + off, 633 PREFIX_SIZE(map->fec.prefix.prefixlen)); 634 635 return (off + PREFIX_SIZE(map->fec.prefix.prefixlen)); 636 case MAP_TYPE_PWID: 637 if (len < FEC_PWID_ELM_MIN_LEN) { 638 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 639 lm->type); 640 return (-1); 641 } 642 643 /* PW type */ 644 memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t)); 645 map->fec.pwid.type = ntohs(map->fec.pwid.type); 646 if (map->fec.pwid.type & CONTROL_WORD_FLAG) { 647 map->flags |= F_MAP_PW_CWORD; 648 map->fec.pwid.type &= ~CONTROL_WORD_FLAG; 649 } 650 off += sizeof(uint16_t); 651 652 /* PW info Length */ 653 pw_len = buf[off]; 654 off += sizeof(uint8_t); 655 656 if (len != FEC_PWID_ELM_MIN_LEN + pw_len) { 657 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 658 lm->type); 659 return (-1); 660 } 661 662 /* Group ID */ 663 memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t)); 664 map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id); 665 off += sizeof(uint32_t); 666 667 /* PW ID */ 668 if (pw_len == 0) 669 return (off); 670 671 if (pw_len < sizeof(uint32_t)) { 672 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 673 lm->type); 674 return (-1); 675 } 676 677 memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t)); 678 map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid); 679 map->flags |= F_MAP_PW_ID; 680 off += sizeof(uint32_t); 681 pw_len -= sizeof(uint32_t); 682 683 /* Optional Interface Parameter Sub-TLVs */ 684 while (pw_len > 0) { 685 struct subtlv stlv; 686 687 if (pw_len < sizeof(stlv)) { 688 session_shutdown(nbr, S_BAD_TLV_LEN, 689 lm->msgid, lm->type); 690 return (-1); 691 } 692 693 memcpy(&stlv, buf + off, sizeof(stlv)); 694 off += SUBTLV_HDR_LEN; 695 pw_len -= SUBTLV_HDR_LEN; 696 697 switch (stlv.type) { 698 case SUBTLV_IFMTU: 699 if (stlv.length != FEC_SUBTLV_IFMTU_LEN) { 700 session_shutdown(nbr, S_BAD_TLV_LEN, 701 lm->msgid, lm->type); 702 return (-1); 703 } 704 memcpy(&map->fec.pwid.ifmtu, buf + off, 705 sizeof(uint16_t)); 706 map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu); 707 map->flags |= F_MAP_PW_IFMTU; 708 break; 709 default: 710 /* ignore */ 711 break; 712 } 713 off += stlv.length - SUBTLV_HDR_LEN; 714 pw_len -= stlv.length - SUBTLV_HDR_LEN; 715 } 716 717 return (off); 718 default: 719 send_notification_nbr(nbr, S_UNKNOWN_FEC, lm->msgid, lm->type); 720 break; 721 } 722 723 return (-1); 724 } 725