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