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