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