1 /* $OpenBSD: labelmapping.c,v 1.28 2013/10/17 17:52:20 renato 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 <netmpls/mpls.h> 29 #include <unistd.h> 30 31 #include <errno.h> 32 #include <event.h> 33 #include <limits.h> 34 #include <stdlib.h> 35 #include <string.h> 36 37 #include "ldpd.h" 38 #include "ldp.h" 39 #include "log.h" 40 #include "ldpe.h" 41 42 void gen_label_tlv(struct ibuf *, u_int32_t); 43 void gen_reqid_tlv(struct ibuf *, u_int32_t); 44 void gen_fec_tlv(struct ibuf *, struct in_addr, u_int8_t); 45 46 int tlv_decode_label(struct nbr *, struct ldp_msg *, char *, u_int16_t, 47 u_int32_t *); 48 int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *, u_int16_t, 49 u_int8_t *, u_int32_t *, u_int8_t *); 50 51 static void 52 enqueue_pdu(struct nbr *nbr, struct ibuf *buf, u_int16_t size) 53 { 54 struct ldp_hdr *ldp_hdr; 55 56 ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr)); 57 ldp_hdr->length = htons(size); 58 evbuf_enqueue(&nbr->tcp->wbuf, buf); 59 } 60 61 /* Generic function that handles all Label Message types */ 62 void 63 send_labelmessage(struct nbr *nbr, u_int16_t type, struct mapping_head *mh) 64 { 65 struct ibuf *buf = NULL; 66 struct mapping_entry *me; 67 u_int16_t tlv_size, size = 0; 68 int first = 1; 69 70 while ((me = TAILQ_FIRST(mh)) != NULL) { 71 /* generate pdu */ 72 if (first) { 73 if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL) 74 fatal("send_labelmapping"); 75 76 /* real size will be set up later */ 77 gen_ldp_hdr(buf, 0); 78 79 size = LDP_HDR_PDU_LEN; 80 first = 0; 81 } 82 83 /* calculate size */ 84 tlv_size = LDP_MSG_LEN + TLV_HDR_LEN + FEC_ELM_MIN_LEN + 85 PREFIX_SIZE(me->map.prefixlen); 86 if (type == MSG_TYPE_LABELMAPPING || 87 me->map.flags & F_MAP_OPTLABEL) 88 tlv_size += LABEL_TLV_LEN; 89 if (me->map.flags & F_MAP_REQ_ID) 90 tlv_size += REQID_TLV_LEN; 91 92 /* maximum pdu length exceeded, we need a new ldp pdu */ 93 if (size + tlv_size > LDP_MAX_LEN) { 94 enqueue_pdu(nbr, buf, size); 95 first = 1; 96 continue; 97 } 98 99 size += tlv_size; 100 101 /* append message and tlvs */ 102 gen_msg_tlv(buf, type, tlv_size); 103 gen_fec_tlv(buf, me->map.prefix, me->map.prefixlen); 104 if (type == MSG_TYPE_LABELMAPPING || 105 me->map.flags & F_MAP_OPTLABEL) 106 gen_label_tlv(buf, me->map.label); 107 if (me->map.flags & F_MAP_REQ_ID) 108 gen_reqid_tlv(buf, me->map.requestid); 109 110 TAILQ_REMOVE(mh, me, entry); 111 free(me); 112 } 113 114 enqueue_pdu(nbr, buf, size); 115 116 nbr_fsm(nbr, NBR_EVT_PDU_SENT); 117 } 118 119 /* Generic function that handles all Label Message types */ 120 int 121 recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type) 122 { 123 struct ldp_msg lm; 124 struct tlv ft; 125 u_int32_t label, reqid; 126 u_int8_t flags = 0; 127 128 int feclen, lbllen, tlen; 129 u_int8_t addr_type; 130 struct mapping_entry *me; 131 struct mapping_head mh; 132 133 bcopy(buf, &lm, sizeof(lm)); 134 135 buf += sizeof(struct ldp_msg); 136 len -= sizeof(struct ldp_msg); 137 138 /* FEC TLV */ 139 if (len < sizeof(ft)) { 140 session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type); 141 return (-1); 142 } 143 144 bcopy(buf, &ft, sizeof(ft)); 145 if (ntohs(ft.type) != TLV_TYPE_FEC) { 146 send_notification_nbr(nbr, S_MISS_MSG, lm.msgid, lm.type); 147 return (-1); 148 } 149 feclen = ntohs(ft.length); 150 151 if (feclen > len - TLV_HDR_LEN) { 152 session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type); 153 return (-1); 154 } 155 156 buf += TLV_HDR_LEN; /* just advance to the end of the fec header */ 157 len -= TLV_HDR_LEN; 158 159 TAILQ_INIT(&mh); 160 do { 161 me = calloc(1, sizeof(*me)); 162 me->map.messageid = lm.msgid; 163 TAILQ_INSERT_HEAD(&mh, me, entry); 164 165 if ((tlen = tlv_decode_fec_elm(nbr, &lm, buf, feclen, 166 &addr_type, &me->map.prefix.s_addr, &me->map.prefixlen)) == -1) 167 goto err; 168 169 /* 170 * The Wildcard FEC Element can be used only in the 171 * Label Withdraw and Label Release messages. 172 */ 173 if (addr_type == FEC_WILDCARD) { 174 switch (type) { 175 case MSG_TYPE_LABELWITHDRAW: 176 case MSG_TYPE_LABELRELEASE: 177 me->map.flags |= F_MAP_WILDCARD; 178 break; 179 default: 180 session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, 181 lm.type); 182 goto err; 183 break; 184 } 185 } 186 187 /* 188 * LDP supports the use of multiple FEC Elements per 189 * FEC for the Label Mapping message only. 190 */ 191 if (type != MSG_TYPE_LABELMAPPING && 192 tlen != feclen) { 193 session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, 194 lm.type); 195 goto err; 196 } 197 198 buf += tlen; 199 len -= tlen; 200 feclen -= tlen; 201 } while (feclen > 0); 202 203 /* Mandatory Label TLV */ 204 if (type == MSG_TYPE_LABELMAPPING) { 205 lbllen = tlv_decode_label(nbr, &lm, buf, len, &label); 206 if (lbllen == -1) 207 goto err; 208 209 buf += lbllen; 210 len -= lbllen; 211 } 212 213 /* Optional Parameters */ 214 while (len > 0) { 215 struct tlv tlv; 216 217 if (len < sizeof(tlv)) { 218 session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, 219 lm.type); 220 goto err; 221 } 222 223 bcopy(buf, &tlv, sizeof(tlv)); 224 buf += TLV_HDR_LEN; 225 len -= TLV_HDR_LEN; 226 227 switch (ntohs(tlv.type)) { 228 case TLV_TYPE_LABELREQUEST: 229 switch (type) { 230 case MSG_TYPE_LABELMAPPING: 231 case MSG_TYPE_LABELABORTREQ: 232 if (ntohs(tlv.length) != 4) { 233 session_shutdown(nbr, S_BAD_TLV_LEN, 234 lm.msgid, lm.type); 235 goto err; 236 } 237 238 flags |= F_MAP_REQ_ID; 239 reqid = ntohl(*(u_int32_t *)buf); 240 break; 241 default: 242 /* ignore */ 243 break; 244 } 245 break; 246 case TLV_TYPE_HOPCOUNT: 247 case TLV_TYPE_PATHVECTOR: 248 /* TODO just ignore for now */ 249 break; 250 case TLV_TYPE_GENERICLABEL: 251 switch (type) { 252 case MSG_TYPE_LABELWITHDRAW: 253 case MSG_TYPE_LABELRELEASE: 254 if (ntohs(tlv.length) != 4) { 255 session_shutdown(nbr, S_BAD_TLV_LEN, 256 lm.msgid, lm.type); 257 goto err; 258 } 259 260 label = ntohl(*(u_int32_t *)buf); 261 flags |= F_MAP_OPTLABEL; 262 break; 263 default: 264 /* ignore */ 265 break; 266 } 267 break; 268 case TLV_TYPE_ATMLABEL: 269 case TLV_TYPE_FRLABEL: 270 switch (type) { 271 case MSG_TYPE_LABELWITHDRAW: 272 case MSG_TYPE_LABELRELEASE: 273 /* unsupported */ 274 session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, 275 lm.type); 276 goto err; 277 break; 278 default: 279 /* ignore */ 280 break; 281 } 282 break; 283 default: 284 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) { 285 send_notification_nbr(nbr, S_UNKNOWN_TLV, 286 lm.msgid, lm.type); 287 } 288 /* ignore unknown tlv */ 289 break; 290 } 291 buf += ntohs(tlv.length); 292 len -= ntohs(tlv.length); 293 } 294 295 /* notify lde about the received message. */ 296 while ((me = TAILQ_FIRST(&mh)) != NULL) { 297 int imsg_type = IMSG_NONE; 298 299 me->map.flags |= flags; 300 if (type == MSG_TYPE_LABELMAPPING || 301 me->map.flags & F_MAP_OPTLABEL) 302 me->map.label = label; 303 if (me->map.flags & F_MAP_REQ_ID) 304 me->map.requestid = reqid; 305 306 switch (type) { 307 case MSG_TYPE_LABELMAPPING: 308 imsg_type = IMSG_LABEL_MAPPING; 309 break; 310 case MSG_TYPE_LABELREQUEST: 311 imsg_type = IMSG_LABEL_REQUEST; 312 break; 313 case MSG_TYPE_LABELWITHDRAW: 314 imsg_type = IMSG_LABEL_WITHDRAW; 315 break; 316 case MSG_TYPE_LABELRELEASE: 317 imsg_type = IMSG_LABEL_RELEASE; 318 break; 319 case MSG_TYPE_LABELABORTREQ: 320 imsg_type = IMSG_LABEL_ABORT; 321 break; 322 default: 323 break; 324 } 325 326 ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map, 327 sizeof(struct map)); 328 329 TAILQ_REMOVE(&mh, me, entry); 330 free(me); 331 } 332 333 return (ntohs(lm.length)); 334 335 err: 336 mapping_list_clr(&mh); 337 338 return (-1); 339 } 340 341 /* Other TLV related functions */ 342 void 343 gen_label_tlv(struct ibuf *buf, u_int32_t label) 344 { 345 struct label_tlv lt; 346 347 lt.type = htons(TLV_TYPE_GENERICLABEL); 348 lt.length = htons(sizeof(label)); 349 lt.label = htonl(label); 350 351 ibuf_add(buf, <, sizeof(lt)); 352 } 353 354 int 355 tlv_decode_label(struct nbr *nbr, struct ldp_msg *lm, char *buf, 356 u_int16_t len, u_int32_t *label) 357 { 358 struct label_tlv lt; 359 360 if (len < sizeof(lt)) { 361 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); 362 return (-1); 363 } 364 bcopy(buf, <, sizeof(lt)); 365 366 if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) { 367 send_notification_nbr(nbr, S_MISS_MSG, lm->msgid, lm->type); 368 return (-1); 369 } 370 371 switch (htons(lt.type)) { 372 case TLV_TYPE_GENERICLABEL: 373 if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_LEN) { 374 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, 375 lm->type); 376 return (-1); 377 } 378 379 *label = ntohl(lt.label); 380 if (*label > MPLS_LABEL_MAX || 381 (*label <= MPLS_LABEL_RESERVED_MAX && 382 *label != MPLS_LABEL_IPV4NULL && 383 *label != MPLS_LABEL_IMPLNULL)) { 384 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, 385 lm->type); 386 return (-1); 387 } 388 break; 389 case TLV_TYPE_ATMLABEL: 390 case TLV_TYPE_FRLABEL: 391 default: 392 /* unsupported */ 393 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, lm->type); 394 return (-1); 395 } 396 397 return (sizeof(lt)); 398 } 399 400 void 401 gen_reqid_tlv(struct ibuf *buf, u_int32_t reqid) 402 { 403 struct reqid_tlv rt; 404 405 rt.type = htons(TLV_TYPE_LABELREQUEST); 406 rt.length = htons(sizeof(reqid)); 407 rt.reqid = htonl(reqid); 408 409 ibuf_add(buf, &rt, sizeof(rt)); 410 } 411 412 void 413 gen_fec_tlv(struct ibuf *buf, struct in_addr prefix, u_int8_t prefixlen) 414 { 415 struct tlv ft; 416 u_int8_t type; 417 u_int16_t family; 418 u_int8_t len; 419 420 len = PREFIX_SIZE(prefixlen); 421 ft.type = htons(TLV_TYPE_FEC); 422 ft.length = htons(sizeof(type) + sizeof(family) + sizeof(prefixlen) + 423 len); 424 425 ibuf_add(buf, &ft, sizeof(ft)); 426 427 type = FEC_PREFIX; 428 family = htons(FEC_IPV4); 429 430 ibuf_add(buf, &type, sizeof(type)); 431 ibuf_add(buf, &family, sizeof(family)); 432 ibuf_add(buf, &prefixlen, sizeof(prefixlen)); 433 if (len) 434 ibuf_add(buf, &prefix, len); 435 } 436 437 int 438 tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf, 439 u_int16_t len, u_int8_t *type, u_int32_t *prefix, u_int8_t *prefixlen) 440 { 441 u_int16_t family, off = 0; 442 443 *type = *buf; 444 off += sizeof(u_int8_t); 445 446 if (*type == FEC_WILDCARD) { 447 if (len == 0) 448 return (off); 449 else { 450 session_shutdown(nbr, S_BAD_TLV_VAL, lm->msgid, 451 lm->type); 452 return (-1); 453 } 454 } 455 456 if (*type != FEC_PREFIX) { 457 send_notification_nbr(nbr, S_UNKNOWN_FEC, lm->msgid, lm->type); 458 return (-1); 459 } 460 461 if (len < FEC_ELM_MIN_LEN) { 462 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); 463 return (-1); 464 } 465 466 bcopy(buf + off, &family, sizeof(family)); 467 off += sizeof(family); 468 469 if (family != htons(FEC_IPV4)) { 470 send_notification_nbr(nbr, S_UNSUP_ADDR, lm->msgid, lm->type); 471 return (-1); 472 } 473 474 *prefixlen = buf[off]; 475 off += sizeof(u_int8_t); 476 477 if (len < off + PREFIX_SIZE(*prefixlen)) { 478 session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); 479 return (-1); 480 } 481 482 *prefix = 0; 483 bcopy(buf + off, prefix, PREFIX_SIZE(*prefixlen)); 484 485 return (off + PREFIX_SIZE(*prefixlen)); 486 } 487