1 /* $OpenBSD: labelmapping.c,v 1.8 2010/04/15 14:47:12 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 #include <sys/uio.h> 22 23 #include <netinet/in.h> 24 #include <netinet/in_systm.h> 25 #include <netinet/ip.h> 26 #include <arpa/inet.h> 27 #include <net/if_dl.h> 28 #include <unistd.h> 29 30 #include <errno.h> 31 #include <event.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 #include "ldpd.h" 36 #include "ldp.h" 37 #include "log.h" 38 #include "ldpe.h" 39 40 void gen_fec_tlv(struct buf *, u_int32_t, u_int8_t); 41 void gen_label_tlv(struct buf *, u_int32_t); 42 43 u_int32_t tlv_decode_label(struct label_tlv *); 44 u_int32_t decode_fec_elm(char *); 45 int decode_fec_len_elm(char *, u_int8_t); 46 int validate_fec_elm(char *); 47 48 /* Label Mapping Message */ 49 void 50 send_labelmapping(struct nbr *nbr) 51 { 52 struct buf *buf; 53 struct mapping_entry *me; 54 struct ldp_hdr *ldp_hdr; 55 u_int16_t tlv_size, size; 56 57 if (nbr->iface->passive) 58 return; 59 60 log_debug("send_labelmapping: neighbor ID %s", inet_ntoa(nbr->id)); 61 62 if ((buf = buf_open(LDP_MAX_LEN)) == NULL) 63 fatal("send_labelmapping"); 64 65 /* real size will be set up later */ 66 gen_ldp_hdr(buf, nbr->iface, 0); 67 68 size = LDP_HDR_SIZE - TLV_HDR_LEN; 69 70 TAILQ_FOREACH(me, &nbr->mapping_list, entry) { 71 tlv_size = BASIC_LABEL_MAP_LEN + PREFIX_SIZE(me->prefixlen); 72 size += tlv_size; 73 74 gen_msg_tlv(buf, MSG_TYPE_LABELMAPPING, tlv_size); 75 gen_fec_tlv(buf, me->prefix, me->prefixlen); 76 gen_label_tlv(buf, me->label); 77 } 78 79 /* XXX: should we remove them first? */ 80 nbr_mapping_list_clr(nbr, &nbr->mapping_list); 81 82 ldp_hdr = buf_seek(buf, 0, sizeof(struct ldp_hdr)); 83 ldp_hdr->length = htons(size); 84 85 evbuf_enqueue(&nbr->wbuf, buf); 86 } 87 88 int 89 recv_labelmapping(struct nbr *nbr, char *buf, u_int16_t len) 90 { 91 struct ldp_msg *lm; 92 struct fec_tlv *ft; 93 struct label_tlv *lt; 94 struct map map; 95 int feclen, addr_type; 96 97 log_debug("recv_labelmapping: neighbor ID %s", inet_ntoa(nbr->id)); 98 99 if (nbr->state != NBR_STA_OPER) 100 return (-1); 101 102 bzero(&map, sizeof(map)); 103 lm = (struct ldp_msg *)buf; 104 105 if ((len - TLV_HDR_LEN) < ntohs(lm->length)) { 106 session_shutdown(nbr, S_BAD_MSG_LEN, lm->msgid, lm->type); 107 return (-1); 108 } 109 110 buf += sizeof(struct ldp_msg); 111 len -= sizeof(struct ldp_msg); 112 113 ft = (struct fec_tlv *)buf; 114 lt = (struct label_tlv *)(buf + TLV_HDR_LEN + ntohs(ft->length)); 115 116 if (len < (sizeof(*ft) + LABEL_TLV_LEN)) { 117 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); 118 return (-1); 119 } 120 121 feclen = ntohs(ft->length); 122 if (len - TLV_HDR_LEN < feclen) { 123 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); 124 return (-1); 125 } 126 127 map.label = tlv_decode_label(lt); 128 if (map.label == NO_LABEL) { 129 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, lm->type); 130 return (-1); 131 } 132 133 buf += sizeof(struct fec_tlv); 134 len -= sizeof(struct fec_tlv); 135 136 while (feclen >= FEC_ELM_MIN_LEN) { 137 addr_type = validate_fec_elm(buf); 138 if (addr_type < 0) { 139 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, 140 lm->type); 141 return (-1); 142 } 143 144 map.prefix = decode_fec_elm(buf); 145 map.prefixlen = decode_fec_len_elm(buf, addr_type); 146 map.prefix &= prefixlen2mask(map.prefixlen); 147 148 ldpe_imsg_compose_lde(IMSG_LABEL_MAPPING, nbr->peerid, 0, &map, 149 sizeof(map)); 150 151 buf += FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen); 152 feclen -= (FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen)); 153 } 154 155 nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 156 157 return (ntohs(lm->length)); 158 } 159 160 /* Label Request Message */ 161 void 162 send_labelrequest(struct nbr *nbr) 163 { 164 struct buf *buf; 165 struct mapping_entry *me; 166 struct ldp_hdr *ldp_hdr; 167 u_int16_t tlv_size, size; 168 169 if (nbr->iface->passive) 170 return; 171 172 log_debug("send_labelrequest: neighbor ID %s", inet_ntoa(nbr->id)); 173 174 if ((buf = buf_open(LDP_MAX_LEN)) == NULL) 175 fatal("send_labelrequest"); 176 177 /* real size will be set up later */ 178 gen_ldp_hdr(buf, nbr->iface, 0); 179 180 size = LDP_HDR_SIZE - TLV_HDR_LEN; 181 182 TAILQ_FOREACH(me, &nbr->request_list, entry) { 183 tlv_size = PREFIX_SIZE(me->prefixlen); 184 size += tlv_size; 185 186 gen_msg_tlv(buf, MSG_TYPE_LABELREQUEST, tlv_size); 187 gen_fec_tlv(buf, me->prefix, me->prefixlen); 188 } 189 190 /* XXX: should we remove them first? */ 191 nbr_mapping_list_clr(nbr, &nbr->request_list); 192 193 ldp_hdr = buf_seek(buf, 0, sizeof(struct ldp_hdr)); 194 ldp_hdr->length = htons(size); 195 196 evbuf_enqueue(&nbr->wbuf, buf); 197 } 198 199 int 200 recv_labelrequest(struct nbr *nbr, char *buf, u_int16_t len) 201 { 202 struct ldp_msg *lr; 203 struct fec_tlv *ft; 204 struct map map; 205 int feclen, addr_type; 206 207 log_debug("recv_labelrequest: neighbor ID %s", inet_ntoa(nbr->id)); 208 209 if (nbr->state != NBR_STA_OPER) 210 return (-1); 211 212 bzero(&map, sizeof(map)); 213 lr = (struct ldp_msg *)buf; 214 215 if ((len - TLV_HDR_LEN) < ntohs(lr->length)) { 216 session_shutdown(nbr, S_BAD_MSG_LEN, lr->msgid, lr->type); 217 return (-1); 218 } 219 220 buf += sizeof(struct ldp_msg); 221 len -= sizeof(struct ldp_msg); 222 223 ft = (struct fec_tlv *)buf; 224 225 if (len < sizeof(*ft) || 226 (len - TLV_HDR_LEN) < ntohs(ft->length)) { 227 session_shutdown(nbr, S_BAD_TLV_LEN, lr->msgid, lr->type); 228 return (-1); 229 } 230 231 feclen = ntohs(ft->length); 232 233 buf += sizeof(struct fec_tlv); 234 len -= sizeof(struct fec_tlv); 235 236 while (feclen >= FEC_ELM_MIN_LEN) { 237 addr_type = validate_fec_elm(buf); 238 if (addr_type < 0) { 239 session_shutdown(nbr, S_BAD_TLV_VAL, lr->msgid, 240 lr->type); 241 return (-1); 242 } 243 244 map.prefix = decode_fec_elm(buf); 245 map.prefixlen = decode_fec_len_elm(buf, addr_type); 246 map.prefix &= prefixlen2mask(map.prefixlen); 247 map.messageid = lr->msgid; 248 249 ldpe_imsg_compose_lde(IMSG_LABEL_REQUEST, nbr->peerid, 0, &map, 250 sizeof(map)); 251 252 buf += FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen); 253 feclen -= (FEC_ELM_MIN_LEN + PREFIX_SIZE(map.prefixlen)); 254 } 255 256 nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 257 258 return (ntohs(lr->length)); 259 } 260 261 /* Label Withdraw Message */ 262 void 263 send_labelwithdraw(struct nbr *nbr) 264 { 265 struct buf *buf; 266 struct mapping_entry *me; 267 struct ldp_hdr *ldp_hdr; 268 u_int16_t tlv_size, size; 269 270 if (nbr->iface->passive) 271 return; 272 273 log_debug("send_labelwithdraw: neighbor ID %s", inet_ntoa(nbr->id)); 274 275 if ((buf = buf_open(LDP_MAX_LEN)) == NULL) 276 fatal("send_labelwithdraw"); 277 278 /* real size will be set up later */ 279 gen_ldp_hdr(buf, nbr->iface, 0); 280 281 size = LDP_HDR_SIZE - TLV_HDR_LEN; 282 283 TAILQ_FOREACH(me, &nbr->withdraw_list, entry) { 284 if (me->label == NO_LABEL) 285 tlv_size = PREFIX_SIZE(me->prefixlen); 286 else 287 tlv_size = BASIC_LABEL_MAP_LEN + 288 PREFIX_SIZE(me->prefixlen); 289 290 size += tlv_size; 291 292 gen_msg_tlv(buf, MSG_TYPE_LABELWITHDRAW, tlv_size); 293 gen_fec_tlv(buf, me->prefix, me->prefixlen); 294 295 if (me->label != NO_LABEL) 296 gen_label_tlv(buf, me->label); 297 } 298 299 /* XXX: should we remove them first? */ 300 nbr_mapping_list_clr(nbr, &nbr->withdraw_list); 301 302 ldp_hdr = buf_seek(buf, 0, sizeof(struct ldp_hdr)); 303 ldp_hdr->length = htons(size); 304 305 evbuf_enqueue(&nbr->wbuf, buf); 306 } 307 308 int 309 recv_labelwithdraw(struct nbr *nbr, char *buf, u_int16_t len) 310 { 311 struct ldp_msg *lw; 312 313 log_debug("recv_labelwithdraw: neighbor ID %s", inet_ntoa(nbr->id)); 314 315 if (nbr->state != NBR_STA_OPER) 316 return (-1); 317 318 lw = (struct ldp_msg *)buf; 319 320 if ((len - TLV_HDR_LEN) < ntohs(lw->length)) { 321 session_shutdown(nbr, S_BAD_MSG_LEN, lw->msgid, lw->type); 322 return (-1); 323 } 324 325 buf += sizeof(struct ldp_msg); 326 len -= sizeof(struct ldp_msg); 327 328 /* XXX XXX */ 329 330 nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 331 332 return (ntohs(lw->length)); 333 } 334 335 /* Label Release Message */ 336 void 337 send_labelrelease(struct nbr *nbr) 338 { 339 struct buf *buf; 340 struct mapping_entry *me; 341 struct ldp_hdr *ldp_hdr; 342 u_int16_t tlv_size, size; 343 344 if (nbr->iface->passive) 345 return; 346 347 log_debug("send_labelrelease: neighbor ID %s", inet_ntoa(nbr->id)); 348 349 if ((buf = buf_open(LDP_MAX_LEN)) == NULL) 350 fatal("send_labelrelease"); 351 352 /* real size will be set up later */ 353 gen_ldp_hdr(buf, nbr->iface, 0); 354 355 size = LDP_HDR_SIZE - TLV_HDR_LEN; 356 357 TAILQ_FOREACH(me, &nbr->release_list, entry) { 358 if (me->label == NO_LABEL) 359 tlv_size = PREFIX_SIZE(me->prefixlen); 360 else 361 tlv_size = BASIC_LABEL_MAP_LEN + 362 PREFIX_SIZE(me->prefixlen); 363 364 size += tlv_size; 365 366 gen_msg_tlv(buf, MSG_TYPE_LABELRELEASE, tlv_size); 367 gen_fec_tlv(buf, me->prefix, me->prefixlen); 368 369 if (me->label != NO_LABEL) 370 gen_label_tlv(buf, me->label); 371 } 372 373 /* XXX: should we remove them first? */ 374 nbr_mapping_list_clr(nbr, &nbr->release_list); 375 376 ldp_hdr = buf_seek(buf, 0, sizeof(struct ldp_hdr)); 377 ldp_hdr->length = htons(size); 378 379 evbuf_enqueue(&nbr->wbuf, buf); 380 } 381 382 int 383 recv_labelrelease(struct nbr *nbr, char *buf, u_int16_t len) 384 { 385 struct ldp_msg *lr; 386 387 log_debug("recv_labelrelease: neighbor ID %s", inet_ntoa(nbr->id)); 388 389 if (nbr->state != NBR_STA_OPER) 390 return (-1); 391 392 lr = (struct ldp_msg *)buf; 393 394 if ((len - TLV_HDR_LEN) < ntohs(lr->length)) { 395 session_shutdown(nbr, S_BAD_MSG_LEN, lr->msgid, lr->type); 396 return (-1); 397 } 398 399 buf += sizeof(struct ldp_msg); 400 len -= sizeof(struct ldp_msg); 401 402 /* XXX XXX XXX */ 403 404 nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 405 406 return (ntohs(lr->length)); 407 } 408 409 /* Label Abort Req Message */ 410 void 411 send_labelabortreq(struct nbr *nbr) 412 { 413 struct buf *buf; 414 u_int16_t size; 415 416 if (nbr->iface->passive) 417 return; 418 419 log_debug("send_labelabortreq: neighbor ID %s", inet_ntoa(nbr->id)); 420 421 if ((buf = buf_open(LDP_MAX_LEN)) == NULL) 422 fatal("send_labelabortreq"); 423 424 size = LDP_HDR_SIZE + sizeof(struct ldp_msg); 425 426 gen_ldp_hdr(buf, nbr->iface, size); 427 428 size -= LDP_HDR_SIZE; 429 430 gen_msg_tlv(buf, MSG_TYPE_LABELABORTREQ, size); 431 432 evbuf_enqueue(&nbr->wbuf, buf); 433 } 434 435 int 436 recv_labelabortreq(struct nbr *nbr, char *buf, u_int16_t len) 437 { 438 struct ldp_msg *la; 439 440 log_debug("recv_labelabortreq: neighbor ID %s", inet_ntoa(nbr->id)); 441 442 if (nbr->state != NBR_STA_OPER) 443 return (-1); 444 445 la = (struct ldp_msg *)buf; 446 447 if ((len - TLV_HDR_LEN) < ntohs(la->length)) { 448 session_shutdown(nbr, S_BAD_MSG_LEN, la->msgid, la->type); 449 return (-1); 450 } 451 452 buf += sizeof(struct ldp_msg); 453 len -= sizeof(struct ldp_msg); 454 455 /* XXX XXX XXX */ 456 457 nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 458 459 return (ntohs(la->length)); 460 } 461 462 /* Other TLV related functions */ 463 void 464 gen_fec_tlv(struct buf *buf, u_int32_t prefix, u_int8_t prefixlen) 465 { 466 struct fec_tlv ft; 467 u_int8_t type; 468 u_int16_t family; 469 u_int8_t len; 470 471 len = PREFIX_SIZE(prefixlen); 472 ft.type = htons(TLV_TYPE_FEC); 473 ft.length = htons(sizeof(type) + sizeof(family) + sizeof(prefixlen) + 474 len); 475 476 buf_add(buf, &ft, sizeof(ft)); 477 478 type = FEC_PREFIX; 479 family = htons(FEC_IPV4); 480 481 buf_add(buf, &type, sizeof(type)); 482 buf_add(buf, &family, sizeof(family)); 483 buf_add(buf, &prefixlen, sizeof(prefixlen)); 484 if (len) 485 buf_add(buf, &prefix, len); 486 } 487 488 void 489 gen_label_tlv(struct buf *buf, u_int32_t label) 490 { 491 struct label_tlv lt; 492 493 lt.type = htons(TLV_TYPE_GENERICLABEL); 494 lt.length = htons(sizeof(label)); 495 lt.label = htonl(label); 496 497 buf_add(buf, <, sizeof(lt)); 498 } 499 500 u_int32_t 501 tlv_decode_label(struct label_tlv *lt) 502 { 503 if (lt->type != htons(TLV_TYPE_GENERICLABEL)) 504 return (NO_LABEL); 505 506 if (ntohs(lt->length) != sizeof(lt->label)) 507 return (NO_LABEL); 508 509 return (ntohl(lt->label)); 510 } 511 512 int 513 validate_fec_elm(char *buf) 514 { 515 u_int16_t *family; 516 u_int8_t type; 517 518 type = *buf; 519 520 if (type != FEC_WILDCARD && type != FEC_PREFIX && 521 type != FEC_ADDRESS) 522 return (-1); 523 524 buf += sizeof(u_int8_t); 525 family = (u_int16_t *)buf; 526 527 if (*family != htons(FEC_IPV4)) 528 return (-1); 529 530 return (type); 531 } 532 533 u_int32_t 534 decode_fec_elm(char *buf) 535 { 536 struct fec_elm *fe = (struct fec_elm *)buf; 537 538 return (fe->addr); 539 } 540 541 int 542 decode_fec_len_elm(char *buf, u_int8_t type) 543 { 544 u_int8_t len; 545 546 /* Skip type and family */ 547 buf += sizeof(u_int8_t); 548 buf += sizeof(u_int16_t); 549 550 len = *buf; 551 552 switch (type) { 553 case FEC_PREFIX: 554 return (len); 555 case FEC_ADDRESS: 556 return (len * 8); 557 case FEC_WILDCARD: 558 /* XXX: not handled for now */ 559 default: 560 /* Should not happen */ 561 return (-1); 562 } 563 564 /* NOTREACHED */ 565 return (-1); 566 } 567