1 /* $OpenBSD: labelmapping.c,v 1.56 2016/07/15 17:05:50 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_SIZE; 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 if (me->map.flags & F_MAP_PW_ID) 89 msg_size += PW_STATUS_TLV_LEN; 90 if (me->map.flags & F_MAP_PW_IFMTU) 91 msg_size += FEC_SUBTLV_IFMTU_SIZE; 92 if (me->map.flags & F_MAP_PW_STATUS) 93 msg_size += PW_STATUS_TLV_SIZE; 94 break; 95 } 96 if (me->map.label != NO_LABEL) 97 msg_size += LABEL_TLV_SIZE; 98 if (me->map.flags & F_MAP_REQ_ID) 99 msg_size += REQID_TLV_SIZE; 100 if (me->map.flags & F_MAP_STATUS) 101 msg_size += STATUS_SIZE; 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 err |= gen_msg_hdr(buf, type, msg_size); 114 err |= gen_fec_tlv(buf, &me->map); 115 if (me->map.label != NO_LABEL) 116 err |= gen_label_tlv(buf, me->map.label); 117 if (me->map.flags & F_MAP_REQ_ID) 118 err |= gen_reqid_tlv(buf, me->map.requestid); 119 if (me->map.flags & F_MAP_PW_STATUS) 120 err |= gen_pw_status_tlv(buf, me->map.pw_status); 121 if (me->map.flags & F_MAP_STATUS) 122 err |= gen_status_tlv(buf, me->map.st.status_code, 123 me->map.st.msg_id, me->map.st.msg_type); 124 if (err) { 125 ibuf_free(buf); 126 return; 127 } 128 129 TAILQ_REMOVE(mh, me, entry); 130 free(me); 131 } 132 133 enqueue_pdu(nbr, buf, size); 134 135 nbr_fsm(nbr, NBR_EVT_PDU_SENT); 136 } 137 138 /* Generic function that handles all Label Message types */ 139 int 140 recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) 141 { 142 struct ldp_msg msg; 143 struct tlv ft; 144 uint32_t label = NO_LABEL, reqid = 0; 145 uint32_t pw_status = 0; 146 uint8_t flags = 0; 147 int feclen, lbllen, tlen; 148 struct mapping_entry *me; 149 struct mapping_head mh; 150 struct map map; 151 152 memcpy(&msg, buf, sizeof(msg)); 153 buf += LDP_MSG_SIZE; 154 len -= LDP_MSG_SIZE; 155 156 /* FEC TLV */ 157 if (len < sizeof(ft)) { 158 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 159 return (-1); 160 } 161 162 memcpy(&ft, buf, sizeof(ft)); 163 if (ntohs(ft.type) != TLV_TYPE_FEC) { 164 send_notification_nbr(nbr, S_MISS_MSG, msg.id, msg.type); 165 return (-1); 166 } 167 feclen = ntohs(ft.length); 168 if (feclen > len - TLV_HDR_SIZE) { 169 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 170 return (-1); 171 } 172 173 buf += TLV_HDR_SIZE; /* just advance to the end of the fec header */ 174 len -= TLV_HDR_SIZE; 175 176 TAILQ_INIT(&mh); 177 do { 178 memset(&map, 0, sizeof(map)); 179 map.msg_id = msg.id; 180 181 if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf, feclen, 182 &map)) == -1) 183 goto err; 184 if (map.type == MAP_TYPE_PWID && 185 !(map.flags & F_MAP_PW_ID) && 186 type != MSG_TYPE_LABELWITHDRAW && 187 type != MSG_TYPE_LABELRELEASE) { 188 send_notification_nbr(nbr, S_MISS_MSG, msg.id, 189 msg.type); 190 return (-1); 191 } 192 193 /* 194 * The Wildcard FEC Element can be used only in the 195 * Label Withdraw and Label Release messages. 196 */ 197 if (map.type == MAP_TYPE_WILDCARD) { 198 switch (type) { 199 case MSG_TYPE_LABELMAPPING: 200 case MSG_TYPE_LABELREQUEST: 201 case MSG_TYPE_LABELABORTREQ: 202 session_shutdown(nbr, S_UNKNOWN_FEC, msg.id, 203 msg.type); 204 goto err; 205 default: 206 break; 207 } 208 } 209 210 /* 211 * LDP supports the use of multiple FEC Elements per 212 * FEC for the Label Mapping message only. 213 */ 214 if (type != MSG_TYPE_LABELMAPPING && 215 tlen != feclen) { 216 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.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, &msg, 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, msg.id, msg.type); 245 goto err; 246 } 247 248 memcpy(&tlv, buf, TLV_HDR_SIZE); 249 buf += TLV_HDR_SIZE; 250 len -= TLV_HDR_SIZE; 251 tlv_len = ntohs(tlv.length); 252 253 switch (ntohs(tlv.type)) { 254 case TLV_TYPE_LABELREQUEST: 255 switch (type) { 256 case MSG_TYPE_LABELMAPPING: 257 case MSG_TYPE_LABELREQUEST: 258 if (tlv_len != REQID_TLV_LEN) { 259 session_shutdown(nbr, S_BAD_TLV_LEN, 260 msg.id, msg.type); 261 goto err; 262 } 263 264 flags |= F_MAP_REQ_ID; 265 memcpy(&reqbuf, buf, sizeof(reqbuf)); 266 reqid = ntohl(reqbuf); 267 break; 268 default: 269 /* ignore */ 270 break; 271 } 272 break; 273 case TLV_TYPE_HOPCOUNT: 274 case TLV_TYPE_PATHVECTOR: 275 /* ignore */ 276 break; 277 case TLV_TYPE_GENERICLABEL: 278 switch (type) { 279 case MSG_TYPE_LABELWITHDRAW: 280 case MSG_TYPE_LABELRELEASE: 281 if (tlv_len != LABEL_TLV_LEN) { 282 session_shutdown(nbr, S_BAD_TLV_LEN, 283 msg.id, msg.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, msg.id, 302 msg.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, msg.id, 313 msg.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 != PW_STATUS_TLV_LEN) { 322 session_shutdown(nbr, S_BAD_TLV_LEN, 323 msg.id, msg.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 msg.id, msg.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 msg.id, msg.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 msg.id, msg.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, msg.id, 381 msg.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(LABEL_TLV_LEN); 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 *msg, 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, msg->id, msg->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, msg->id, msg->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_SIZE) { 474 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, 475 msg->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, msg->id, 486 msg->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, msg->id, msg->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(REQID_TLV_LEN); 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(PW_STATUS_TLV_LEN); 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 += PW_STATUS_TLV_LEN; 559 if (map->flags & F_MAP_PW_IFMTU) 560 pw_len += FEC_SUBTLV_IFMTU_SIZE; 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_SIZE; 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 *msg, 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, msg->id, 614 msg->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, msg->id, 621 msg->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, msg->id, 633 msg->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, msg->id, 642 msg->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, msg->id, 656 msg->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, msg->id, 675 msg->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, msg->id, 690 msg->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, msg->id, 706 msg->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_SIZE) { 714 session_shutdown(nbr, S_BAD_TLV_LEN, 715 msg->id, msg->type); 716 return (-1); 717 } 718 memcpy(&map->fec.pwid.ifmtu, buf + off + 719 SUBTLV_HDR_SIZE, 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, msg->id, msg->type); 734 break; 735 } 736 737 return (-1); 738 } 739