1 /* $OpenBSD: labelmapping.c,v 1.2 2009/06/05 22:34:45 michele 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 u_int8_t decode_fec_len_elm(char *); 46 int validate_fec_elm(char *); 47 48 /* Label Mapping Message */ 49 int 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 (0); 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 + me->prefixlen/8; 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 bufferevent_write(nbr->bev, buf->buf, buf->wpos); 86 buf_free(buf); 87 88 return (0); 89 } 90 91 int 92 recv_labelmapping(struct nbr *nbr, char *buf, u_int16_t len) 93 { 94 struct ldp_msg *lm; 95 struct fec_tlv *ft; 96 struct label_tlv *lt; 97 struct map map; 98 int feclen; 99 100 log_debug("recv_labelmapping: neighbor ID %s", inet_ntoa(nbr->id)); 101 102 if (nbr->state != NBR_STA_OPER) 103 return (-1); 104 105 bzero(&map, sizeof(map)); 106 lm = (struct ldp_msg *)buf; 107 108 if ((len - TLV_HDR_LEN) < ntohs(lm->length)) { 109 session_shutdown(nbr, S_BAD_MSG_LEN, lm->msgid, lm->type); 110 return (-1); 111 } 112 113 buf += sizeof(struct ldp_msg); 114 len -= sizeof(struct ldp_msg); 115 116 ft = (struct fec_tlv *)buf; 117 lt = (struct label_tlv *)(buf + TLV_HDR_LEN + ntohs(ft->length)); 118 119 if (len < (sizeof(*ft) + LABEL_TLV_LEN)) { 120 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); 121 return (-1); 122 } 123 124 feclen = ntohs(ft->length); 125 if (len - TLV_HDR_LEN < feclen) { 126 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); 127 return (-1); 128 } 129 130 map.label = tlv_decode_label(lt); 131 if (map.label == NO_LABEL) { 132 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, lm->type); 133 return (-1); 134 } 135 136 buf += sizeof(struct fec_tlv); 137 len -= sizeof(struct fec_tlv); 138 139 while (feclen >= FEC_ELM_MIN_LEN) { 140 if (validate_fec_elm(buf) < 0) { 141 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, 142 lm->type); 143 return (-1); 144 } 145 146 map.prefix = decode_fec_elm(buf); 147 map.prefixlen = decode_fec_len_elm(buf); 148 map.prefix &= prefixlen2mask(map.prefixlen); 149 150 ldpe_imsg_compose_lde(IMSG_LABEL_MAPPING, nbr->peerid, 0, &map, 151 sizeof(map)); 152 153 buf += FEC_ELM_MIN_LEN + map.prefixlen/8; 154 feclen -= (FEC_ELM_MIN_LEN + map.prefixlen/8); 155 } 156 157 nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 158 159 return (ntohs(lm->length)); 160 } 161 162 /* Label Request Message */ 163 int 164 send_labelrequest(struct nbr *nbr) 165 { 166 struct buf *buf; 167 struct mapping_entry *me; 168 struct ldp_hdr *ldp_hdr; 169 u_int16_t tlv_size, size; 170 171 if (nbr->iface->passive) 172 return (0); 173 174 log_debug("send_labelrequest: neighbor ID %s", inet_ntoa(nbr->id)); 175 176 if ((buf = buf_open(LDP_MAX_LEN)) == NULL) 177 fatal("send_labelrequest"); 178 179 /* real size will be set up later */ 180 gen_ldp_hdr(buf, nbr->iface, 0); 181 182 size = LDP_HDR_SIZE - TLV_HDR_LEN; 183 184 TAILQ_FOREACH(me, &nbr->request_list, entry) { 185 tlv_size = me->prefixlen/8; 186 size += tlv_size; 187 188 gen_msg_tlv(buf, MSG_TYPE_LABELREQUEST, tlv_size); 189 gen_fec_tlv(buf, me->prefix, me->prefixlen); 190 } 191 192 /* XXX: should we remove them first? */ 193 nbr_mapping_list_clr(nbr, &nbr->request_list); 194 195 ldp_hdr = buf_seek(buf, 0, sizeof(struct ldp_hdr)); 196 ldp_hdr->length = htons(size); 197 198 bufferevent_write(nbr->bev, buf->buf, buf->wpos); 199 buf_free(buf); 200 201 return (0); 202 } 203 204 int 205 recv_labelrequest(struct nbr *nbr, char *buf, u_int16_t len) 206 { 207 struct ldp_msg *lr; 208 struct fec_tlv *ft; 209 struct map map; 210 int feclen; 211 212 log_debug("recv_labelrequest: neighbor ID %s", inet_ntoa(nbr->id)); 213 214 if (nbr->state != NBR_STA_OPER) 215 return (-1); 216 217 bzero(&map, sizeof(map)); 218 lr = (struct ldp_msg *)buf; 219 220 if ((len - TLV_HDR_LEN) < ntohs(lr->length)) { 221 session_shutdown(nbr, S_BAD_MSG_LEN, lr->msgid, lr->type); 222 return (-1); 223 } 224 225 buf += sizeof(struct ldp_msg); 226 len -= sizeof(struct ldp_msg); 227 228 ft = (struct fec_tlv *)buf; 229 230 if (len < sizeof(*ft) || 231 (len - TLV_HDR_LEN) < ntohs(ft->length)) { 232 session_shutdown(nbr, S_BAD_TLV_LEN, lr->msgid, lr->type); 233 return (-1); 234 } 235 236 feclen = ntohs(ft->length); 237 238 buf += sizeof(struct fec_tlv); 239 len -= sizeof(struct fec_tlv); 240 241 while (feclen >= FEC_ELM_MIN_LEN) { 242 if (validate_fec_elm(buf) < 0) { 243 session_shutdown(nbr, S_BAD_TLV_VAL, lr->msgid, 244 lr->type); 245 return (-1); 246 } 247 248 map.prefix = decode_fec_elm(buf); 249 map.prefixlen = decode_fec_len_elm(buf); 250 map.prefix &= prefixlen2mask(map.prefixlen); 251 map.messageid = lr->msgid; 252 253 ldpe_imsg_compose_lde(IMSG_LABEL_REQUEST, nbr->peerid, 0, &map, 254 sizeof(map)); 255 256 buf += FEC_ELM_MIN_LEN + map.prefixlen/8; 257 feclen -= (FEC_ELM_MIN_LEN + map.prefixlen/8); 258 } 259 260 nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 261 262 return (0); 263 } 264 265 /* Label Withdraw Message */ 266 int 267 send_labelwithdraw(struct nbr *nbr) 268 { 269 struct buf *buf; 270 struct mapping_entry *me; 271 struct ldp_hdr *ldp_hdr; 272 u_int16_t tlv_size, size; 273 274 if (nbr->iface->passive) 275 return (0); 276 277 log_debug("send_labelwithdraw: neighbor ID %s", inet_ntoa(nbr->id)); 278 279 if ((buf = buf_open(LDP_MAX_LEN)) == NULL) 280 fatal("send_labelwithdraw"); 281 282 /* real size will be set up later */ 283 gen_ldp_hdr(buf, nbr->iface, 0); 284 285 size = LDP_HDR_SIZE - TLV_HDR_LEN; 286 287 TAILQ_FOREACH(me, &nbr->withdraw_list, entry) { 288 if (me->label == NO_LABEL) 289 tlv_size = me->prefixlen/8; 290 else 291 tlv_size = BASIC_LABEL_MAP_LEN + me->prefixlen/8; 292 293 size += tlv_size; 294 295 gen_msg_tlv(buf, MSG_TYPE_LABELWITHDRAW, tlv_size); 296 gen_fec_tlv(buf, me->prefix, me->prefixlen); 297 298 if (me->label != NO_LABEL) 299 gen_label_tlv(buf, me->label); 300 } 301 302 /* XXX: should we remove them first? */ 303 nbr_mapping_list_clr(nbr, &nbr->withdraw_list); 304 305 ldp_hdr = buf_seek(buf, 0, sizeof(struct ldp_hdr)); 306 ldp_hdr->length = htons(size); 307 308 bufferevent_write(nbr->bev, buf->buf, buf->wpos); 309 310 buf_free(buf); 311 312 return (0); 313 } 314 315 int 316 recv_labelwithdraw(struct nbr *nbr, char *buf, u_int16_t len) 317 { 318 struct ldp_msg *lw; 319 320 log_debug("recv_labelwithdraw: neighbor ID %s", inet_ntoa(nbr->id)); 321 322 if (nbr->state != NBR_STA_OPER) 323 return (-1); 324 325 lw = (struct ldp_msg *)buf; 326 327 if ((len - TLV_HDR_LEN) < ntohs(lw->length)) { 328 session_shutdown(nbr, S_BAD_MSG_LEN, lw->msgid, lw->type); 329 return (-1); 330 } 331 332 buf += sizeof(struct ldp_msg); 333 len -= sizeof(struct ldp_msg); 334 335 nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 336 337 return (0); 338 } 339 340 /* Label Release Message */ 341 int 342 send_labelrelease(struct nbr *nbr) 343 { 344 struct buf *buf; 345 struct mapping_entry *me; 346 struct ldp_hdr *ldp_hdr; 347 u_int16_t tlv_size, size; 348 349 if (nbr->iface->passive) 350 return (0); 351 352 log_debug("send_labelrelease: neighbor ID %s", inet_ntoa(nbr->id)); 353 354 if ((buf = buf_open(LDP_MAX_LEN)) == NULL) 355 fatal("send_labelrelease"); 356 357 /* real size will be set up later */ 358 gen_ldp_hdr(buf, nbr->iface, 0); 359 360 size = LDP_HDR_SIZE - TLV_HDR_LEN; 361 362 TAILQ_FOREACH(me, &nbr->release_list, entry) { 363 if (me->label == NO_LABEL) 364 tlv_size = me->prefixlen/8; 365 else 366 tlv_size = BASIC_LABEL_MAP_LEN + me->prefixlen/8; 367 368 size += tlv_size; 369 370 gen_msg_tlv(buf, MSG_TYPE_LABELRELEASE, tlv_size); 371 gen_fec_tlv(buf, me->prefix, me->prefixlen); 372 373 if (me->label != NO_LABEL) 374 gen_label_tlv(buf, me->label); 375 } 376 377 /* XXX: should we remove them first? */ 378 nbr_mapping_list_clr(nbr, &nbr->release_list); 379 380 ldp_hdr = buf_seek(buf, 0, sizeof(struct ldp_hdr)); 381 ldp_hdr->length = htons(size); 382 383 bufferevent_write(nbr->bev, buf->buf, buf->wpos); 384 buf_free(buf); 385 386 return (0); 387 } 388 389 int 390 recv_labelrelease(struct nbr *nbr, char *buf, u_int16_t len) 391 { 392 struct ldp_msg *lr; 393 394 log_debug("recv_labelrelease: neighbor ID %s", inet_ntoa(nbr->id)); 395 396 if (nbr->state != NBR_STA_OPER) 397 return (-1); 398 399 lr = (struct ldp_msg *)buf; 400 401 if ((len - TLV_HDR_LEN) < ntohs(lr->length)) { 402 session_shutdown(nbr, S_BAD_MSG_LEN, lr->msgid, lr->type); 403 return (-1); 404 } 405 406 buf += sizeof(struct ldp_msg); 407 len -= sizeof(struct ldp_msg); 408 409 nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 410 411 return (0); 412 } 413 414 /* Label Abort Req Message */ 415 int 416 send_labelabortreq(struct nbr *nbr) 417 { 418 struct buf *buf; 419 u_int16_t size; 420 421 if (nbr->iface->passive) 422 return (0); 423 424 log_debug("send_labelabortreq: neighbor ID %s", inet_ntoa(nbr->id)); 425 426 if ((buf = buf_open(LDP_MAX_LEN)) == NULL) 427 fatal("send_labelabortreq"); 428 429 size = LDP_HDR_SIZE + sizeof(struct ldp_msg); 430 431 gen_ldp_hdr(buf, nbr->iface, size); 432 433 size -= LDP_HDR_SIZE; 434 435 gen_msg_tlv(buf, MSG_TYPE_LABELABORTREQ, size); 436 437 bufferevent_write(nbr->bev, buf->buf, buf->wpos); 438 439 buf_free(buf); 440 441 return (0); 442 } 443 444 int 445 recv_labelabortreq(struct nbr *nbr, char *buf, u_int16_t len) 446 { 447 struct ldp_msg *la; 448 449 log_debug("recv_labelabortreq: neighbor ID %s", inet_ntoa(nbr->id)); 450 451 if (nbr->state != NBR_STA_OPER) 452 return (-1); 453 454 la = (struct ldp_msg *)buf; 455 456 if ((len - TLV_HDR_LEN) < ntohs(la->length)) { 457 session_shutdown(nbr, S_BAD_MSG_LEN, la->msgid, la->type); 458 return (-1); 459 } 460 461 buf += sizeof(struct ldp_msg); 462 len -= sizeof(struct ldp_msg); 463 464 nbr_fsm(nbr, NBR_EVT_PDU_RCVD); 465 466 return (0); 467 } 468 469 /* Other TLV related functions */ 470 void 471 gen_fec_tlv(struct buf *buf, u_int32_t prefix, u_int8_t prefixlen) 472 { 473 struct fec_tlv ft; 474 u_int8_t type; 475 u_int16_t family; 476 u_int8_t len; 477 u_int32_t addr; 478 479 ft.type = htons(TLV_TYPE_FEC); 480 ft.length = htons(sizeof(ft) + (int)(prefixlen/8)); 481 482 buf_add(buf, &ft, sizeof(ft)); 483 484 if (prefixlen == 32) 485 type = FEC_ADDRESS; 486 else 487 type = FEC_PREFIX; 488 family = htons(FEC_IPV4); 489 len = prefixlen; 490 addr = prefix; 491 492 buf_add(buf, &type, sizeof(type)); 493 buf_add(buf, &family, sizeof(family)); 494 buf_add(buf, &len, sizeof(len)); 495 buf_add(buf, &addr, (int)(prefixlen/8)); 496 } 497 498 void 499 gen_label_tlv(struct buf *buf, u_int32_t label) 500 { 501 struct label_tlv lt; 502 503 lt.type = htons(TLV_TYPE_GENERICLABEL); 504 lt.length = htons(sizeof(label)); 505 lt.label = htonl(label); 506 507 buf_add(buf, <, sizeof(lt)); 508 } 509 510 u_int32_t 511 tlv_decode_label(struct label_tlv *lt) 512 { 513 if (lt->type != htons(TLV_TYPE_GENERICLABEL)) 514 return (NO_LABEL); 515 516 if (ntohs(lt->length) != sizeof(lt->label)) 517 return (NO_LABEL); 518 519 return (ntohl(lt->label)); 520 } 521 522 int 523 validate_fec_elm(char *buf) 524 { 525 u_int16_t *family; 526 527 if (*buf != FEC_WILDCARD && *buf != FEC_PREFIX && *buf != 528 FEC_ADDRESS) 529 return (-1); 530 531 buf += sizeof(u_int8_t); 532 family = (u_int16_t *)buf; 533 534 if (*family != htons(FEC_IPV4)) 535 return (-1); 536 537 return (0); 538 } 539 540 u_int32_t 541 decode_fec_elm(char *buf) 542 { 543 struct fec_elm *fe = (struct fec_elm *)buf; 544 545 return (fe->addr); 546 } 547 548 u_int8_t 549 decode_fec_len_elm(char *buf) 550 { 551 /* Skip type and family */ 552 buf += sizeof(u_int8_t); 553 buf += sizeof(u_int16_t); 554 555 return (*buf); 556 } 557