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