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