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