1 /* $OpenBSD: labelmapping.c,v 1.69 2023/07/03 11:51:27 claudio 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 <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "ldpd.h"
30 #include "ldpe.h"
31 #include "log.h"
32
33 static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
34 static int gen_label_tlv(struct ibuf *, uint32_t);
35 static int tlv_decode_label(struct nbr *, struct ldp_msg *, char *,
36 uint16_t, uint32_t *);
37 static int gen_reqid_tlv(struct ibuf *, uint32_t);
38 static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
39
40 static void
enqueue_pdu(struct nbr * nbr,struct ibuf * buf,uint16_t size)41 enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size)
42 {
43 if (ibuf_set_n16(buf, offsetof(struct ldp_hdr, length), size) == -1)
44 fatal(__func__);
45 evbuf_enqueue(&nbr->tcp->wbuf, buf);
46 }
47
48 /* Generic function that handles all Label Message types */
49 void
send_labelmessage(struct nbr * nbr,uint16_t type,struct mapping_head * mh)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;
78 msg_size += len_fec_tlv(&me->map);
79 if (me->map.label != NO_LABEL)
80 msg_size += LABEL_TLV_SIZE;
81 if (me->map.flags & F_MAP_REQ_ID)
82 msg_size += REQID_TLV_SIZE;
83 if (me->map.flags & F_MAP_STATUS)
84 msg_size += STATUS_SIZE;
85
86 /* maximum pdu length exceeded, we need a new ldp pdu */
87 if (size + msg_size > nbr->max_pdu_len) {
88 enqueue_pdu(nbr, buf, size);
89 first = 1;
90 continue;
91 }
92
93 size += msg_size;
94
95 /* append message and tlvs */
96 err |= gen_msg_hdr(buf, type, msg_size);
97 err |= gen_fec_tlv(buf, &me->map);
98 if (me->map.label != NO_LABEL)
99 err |= gen_label_tlv(buf, me->map.label);
100 if (me->map.flags & F_MAP_REQ_ID)
101 err |= gen_reqid_tlv(buf, me->map.requestid);
102 if (me->map.flags & F_MAP_PW_STATUS)
103 err |= gen_pw_status_tlv(buf, me->map.pw_status);
104 if (me->map.flags & F_MAP_STATUS)
105 err |= gen_status_tlv(buf, me->map.st.status_code,
106 me->map.st.msg_id, me->map.st.msg_type);
107 if (err) {
108 ibuf_free(buf);
109 mapping_list_clr(mh);
110 return;
111 }
112
113 log_msg_mapping(1, type, nbr, &me->map);
114
115 TAILQ_REMOVE(mh, me, entry);
116 free(me);
117 }
118
119 enqueue_pdu(nbr, buf, size);
120
121 nbr_fsm(nbr, NBR_EVT_PDU_SENT);
122 }
123
124 /* Generic function that handles all Label Message types */
125 int
recv_labelmessage(struct nbr * nbr,char * buf,uint16_t len,uint16_t type)126 recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
127 {
128 struct ldp_msg msg;
129 struct tlv ft;
130 uint32_t label = NO_LABEL, reqid = 0;
131 uint32_t pw_status = 0;
132 uint8_t flags = 0;
133 int feclen, lbllen, tlen;
134 struct mapping_entry *me;
135 struct mapping_head mh;
136 struct map map;
137
138 memcpy(&msg, buf, sizeof(msg));
139 buf += LDP_MSG_SIZE;
140 len -= LDP_MSG_SIZE;
141
142 /* FEC TLV */
143 if (len < sizeof(ft)) {
144 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
145 return (-1);
146 }
147
148 memcpy(&ft, buf, sizeof(ft));
149 if (ntohs(ft.type) != TLV_TYPE_FEC) {
150 send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
151 return (-1);
152 }
153 feclen = ntohs(ft.length);
154 if (feclen > len - TLV_HDR_SIZE) {
155 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
156 return (-1);
157 }
158
159 buf += TLV_HDR_SIZE; /* just advance to the end of the fec header */
160 len -= TLV_HDR_SIZE;
161
162 TAILQ_INIT(&mh);
163 do {
164 memset(&map, 0, sizeof(map));
165 map.msg_id = msg.id;
166
167 if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf, feclen,
168 &map)) == -1)
169 goto err;
170 if (map.type == MAP_TYPE_PWID &&
171 !(map.flags & F_MAP_PW_ID) &&
172 type != MSG_TYPE_LABELWITHDRAW &&
173 type != MSG_TYPE_LABELRELEASE) {
174 send_notification(nbr->tcp, S_MISS_MSG, msg.id,
175 msg.type);
176 return (-1);
177 }
178
179 /*
180 * The Wildcard FEC Element can be used only in the
181 * Label Withdraw and Label Release messages.
182 */
183 if (map.type == MAP_TYPE_WILDCARD) {
184 switch (type) {
185 case MSG_TYPE_LABELMAPPING:
186 case MSG_TYPE_LABELREQUEST:
187 case MSG_TYPE_LABELABORTREQ:
188 session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
189 msg.type);
190 goto err;
191 default:
192 break;
193 }
194 }
195
196 /*
197 * RFC 5561 - Section 4:
198 * "An LDP implementation that supports the Typed Wildcard
199 * FEC Element MUST support its use in Label Request, Label
200 * Withdraw, and Label Release messages".
201 */
202 if (map.type == MAP_TYPE_TYPED_WCARD) {
203 switch (type) {
204 case MSG_TYPE_LABELMAPPING:
205 case MSG_TYPE_LABELABORTREQ:
206 session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
207 msg.type);
208 goto err;
209 default:
210 break;
211 }
212 }
213
214 /*
215 * LDP supports the use of multiple FEC Elements per
216 * FEC for the Label Mapping message only.
217 */
218 if (type != MSG_TYPE_LABELMAPPING &&
219 tlen != feclen) {
220 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
221 goto err;
222 }
223
224 mapping_list_add(&mh, &map);
225
226 buf += tlen;
227 len -= tlen;
228 feclen -= tlen;
229 } while (feclen > 0);
230
231 /* Mandatory Label TLV */
232 if (type == MSG_TYPE_LABELMAPPING) {
233 lbllen = tlv_decode_label(nbr, &msg, buf, len, &label);
234 if (lbllen == -1)
235 goto err;
236
237 buf += lbllen;
238 len -= lbllen;
239 }
240
241 /* Optional Parameters */
242 while (len > 0) {
243 struct tlv tlv;
244 uint16_t tlv_type;
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_type = ntohs(tlv.type);
255 tlv_len = ntohs(tlv.length);
256 if (tlv_len + TLV_HDR_SIZE > len) {
257 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
258 goto err;
259 }
260 buf += TLV_HDR_SIZE;
261 len -= TLV_HDR_SIZE;
262
263 switch (tlv_type) {
264 case TLV_TYPE_LABELREQUEST:
265 switch (type) {
266 case MSG_TYPE_LABELMAPPING:
267 case MSG_TYPE_LABELREQUEST:
268 if (tlv_len != REQID_TLV_LEN) {
269 session_shutdown(nbr, S_BAD_TLV_LEN,
270 msg.id, msg.type);
271 goto err;
272 }
273
274 flags |= F_MAP_REQ_ID;
275 memcpy(&reqbuf, buf, sizeof(reqbuf));
276 reqid = ntohl(reqbuf);
277 break;
278 default:
279 /* ignore */
280 break;
281 }
282 break;
283 case TLV_TYPE_HOPCOUNT:
284 case TLV_TYPE_PATHVECTOR:
285 /* ignore */
286 break;
287 case TLV_TYPE_GENERICLABEL:
288 switch (type) {
289 case MSG_TYPE_LABELWITHDRAW:
290 case MSG_TYPE_LABELRELEASE:
291 if (tlv_len != LABEL_TLV_LEN) {
292 session_shutdown(nbr, S_BAD_TLV_LEN,
293 msg.id, msg.type);
294 goto err;
295 }
296
297 memcpy(&labelbuf, buf, sizeof(labelbuf));
298 label = ntohl(labelbuf);
299 break;
300 default:
301 /* ignore */
302 break;
303 }
304 break;
305 case TLV_TYPE_ATMLABEL:
306 case TLV_TYPE_FRLABEL:
307 switch (type) {
308 case MSG_TYPE_LABELWITHDRAW:
309 case MSG_TYPE_LABELRELEASE:
310 /* unsupported */
311 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
312 msg.type);
313 goto err;
314 break;
315 default:
316 /* ignore */
317 break;
318 }
319 break;
320 case TLV_TYPE_STATUS:
321 if (tlv_len != STATUS_TLV_LEN) {
322 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
323 msg.type);
324 goto err;
325 }
326 /* ignore */
327 break;
328 case TLV_TYPE_PW_STATUS:
329 switch (type) {
330 case MSG_TYPE_LABELMAPPING:
331 if (tlv_len != PW_STATUS_TLV_LEN) {
332 session_shutdown(nbr, S_BAD_TLV_LEN,
333 msg.id, msg.type);
334 goto err;
335 }
336
337 flags |= F_MAP_PW_STATUS;
338 memcpy(&statusbuf, buf, sizeof(statusbuf));
339 pw_status = ntohl(statusbuf);
340 break;
341 default:
342 /* ignore */
343 break;
344 }
345 break;
346 default:
347 if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
348 send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
349 msg.id, msg.type, tlv_type, tlv_len, buf);
350 /* ignore unknown tlv */
351 break;
352 }
353 buf += tlv_len;
354 len -= tlv_len;
355 }
356
357 /* notify lde about the received message. */
358 while ((me = TAILQ_FIRST(&mh)) != NULL) {
359 int imsg_type = IMSG_NONE;
360
361 me->map.flags |= flags;
362 switch (me->map.type) {
363 case MAP_TYPE_PREFIX:
364 switch (me->map.fec.prefix.af) {
365 case AF_INET:
366 if (label == MPLS_LABEL_IPV6NULL) {
367 session_shutdown(nbr, S_BAD_TLV_VAL,
368 msg.id, msg.type);
369 goto err;
370 }
371 if (!nbr->v4_enabled)
372 goto next;
373 break;
374 case AF_INET6:
375 if (label == MPLS_LABEL_IPV4NULL) {
376 session_shutdown(nbr, S_BAD_TLV_VAL,
377 msg.id, msg.type);
378 goto err;
379 }
380 if (!nbr->v6_enabled)
381 goto next;
382 break;
383 default:
384 fatalx("recv_labelmessage: unknown af");
385 }
386 break;
387 case MAP_TYPE_PWID:
388 if (label <= MPLS_LABEL_RESERVED_MAX) {
389 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
390 msg.type);
391 goto err;
392 }
393 if (me->map.flags & F_MAP_PW_STATUS)
394 me->map.pw_status = pw_status;
395 break;
396 default:
397 break;
398 }
399 me->map.label = label;
400 if (me->map.flags & F_MAP_REQ_ID)
401 me->map.requestid = reqid;
402
403 log_msg_mapping(0, type, nbr, &me->map);
404
405 switch (type) {
406 case MSG_TYPE_LABELMAPPING:
407 imsg_type = IMSG_LABEL_MAPPING;
408 break;
409 case MSG_TYPE_LABELREQUEST:
410 imsg_type = IMSG_LABEL_REQUEST;
411 break;
412 case MSG_TYPE_LABELWITHDRAW:
413 imsg_type = IMSG_LABEL_WITHDRAW;
414 break;
415 case MSG_TYPE_LABELRELEASE:
416 imsg_type = IMSG_LABEL_RELEASE;
417 break;
418 case MSG_TYPE_LABELABORTREQ:
419 imsg_type = IMSG_LABEL_ABORT;
420 break;
421 default:
422 break;
423 }
424
425 ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
426 sizeof(struct map));
427
428 next:
429 TAILQ_REMOVE(&mh, me, entry);
430 free(me);
431 }
432
433 return (0);
434
435 err:
436 mapping_list_clr(&mh);
437
438 return (-1);
439 }
440
441 /* Other TLV related functions */
442 static int
gen_label_tlv(struct ibuf * buf,uint32_t label)443 gen_label_tlv(struct ibuf *buf, uint32_t label)
444 {
445 struct label_tlv lt;
446
447 lt.type = htons(TLV_TYPE_GENERICLABEL);
448 lt.length = htons(LABEL_TLV_LEN);
449 lt.label = htonl(label);
450
451 return (ibuf_add(buf, <, sizeof(lt)));
452 }
453
454 static int
tlv_decode_label(struct nbr * nbr,struct ldp_msg * msg,char * buf,uint16_t len,uint32_t * label)455 tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf,
456 uint16_t len, uint32_t *label)
457 {
458 struct label_tlv lt;
459
460 if (len < sizeof(lt)) {
461 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type);
462 return (-1);
463 }
464 memcpy(<, buf, sizeof(lt));
465
466 if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) {
467 send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type);
468 return (-1);
469 }
470
471 switch (htons(lt.type)) {
472 case TLV_TYPE_GENERICLABEL:
473 if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) {
474 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
475 msg->type);
476 return (-1);
477 }
478
479 *label = ntohl(lt.label);
480 if (*label > MPLS_LABEL_MAX ||
481 (*label <= MPLS_LABEL_RESERVED_MAX &&
482 *label != MPLS_LABEL_IPV4NULL &&
483 *label != MPLS_LABEL_IPV6NULL &&
484 *label != MPLS_LABEL_IMPLNULL)) {
485 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
486 msg->type);
487 return (-1);
488 }
489 break;
490 case TLV_TYPE_ATMLABEL:
491 case TLV_TYPE_FRLABEL:
492 default:
493 /* unsupported */
494 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type);
495 return (-1);
496 }
497
498 return (sizeof(lt));
499 }
500
501 static int
gen_reqid_tlv(struct ibuf * buf,uint32_t reqid)502 gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
503 {
504 struct reqid_tlv rt;
505
506 rt.type = htons(TLV_TYPE_LABELREQUEST);
507 rt.length = htons(REQID_TLV_LEN);
508 rt.reqid = htonl(reqid);
509
510 return (ibuf_add(buf, &rt, sizeof(rt)));
511 }
512
513 int
gen_pw_status_tlv(struct ibuf * buf,uint32_t status)514 gen_pw_status_tlv(struct ibuf *buf, uint32_t status)
515 {
516 struct pw_status_tlv st;
517
518 st.type = htons(TLV_TYPE_PW_STATUS);
519 st.length = htons(PW_STATUS_TLV_LEN);
520 st.value = htonl(status);
521
522 return (ibuf_add(buf, &st, sizeof(st)));
523 }
524
525 uint16_t
len_fec_tlv(struct map * map)526 len_fec_tlv(struct map *map)
527 {
528 uint16_t len = TLV_HDR_SIZE;
529
530 switch (map->type) {
531 case MAP_TYPE_WILDCARD:
532 len += FEC_ELM_WCARD_LEN;
533 break;
534 case MAP_TYPE_PREFIX:
535 len += FEC_ELM_PREFIX_MIN_LEN +
536 PREFIX_SIZE(map->fec.prefix.prefixlen);
537 break;
538 case MAP_TYPE_PWID:
539 len += FEC_PWID_ELM_MIN_LEN;
540 if (map->flags & F_MAP_PW_ID)
541 len += PW_STATUS_TLV_LEN;
542 if (map->flags & F_MAP_PW_IFMTU)
543 len += FEC_SUBTLV_IFMTU_SIZE;
544 if (map->flags & F_MAP_PW_STATUS)
545 len += PW_STATUS_TLV_SIZE;
546 break;
547 case MAP_TYPE_TYPED_WCARD:
548 len += FEC_ELM_TWCARD_MIN_LEN;
549 switch (map->fec.twcard.type) {
550 case MAP_TYPE_PREFIX:
551 case MAP_TYPE_PWID:
552 len += sizeof(uint16_t);
553 break;
554 default:
555 fatalx("len_fec_tlv: unexpected fec type");
556 }
557 break;
558 default:
559 fatalx("len_fec_tlv: unexpected fec type");
560 }
561
562 return (len);
563 }
564
565 int
gen_fec_tlv(struct ibuf * buf,struct map * map)566 gen_fec_tlv(struct ibuf *buf, struct map *map)
567 {
568 struct tlv ft;
569 uint16_t family, len, pw_type, ifmtu;
570 uint8_t pw_len = 0, twcard_len;
571 uint32_t group_id, pwid;
572 int err = 0;
573
574 ft.type = htons(TLV_TYPE_FEC);
575
576 switch (map->type) {
577 case MAP_TYPE_WILDCARD:
578 ft.length = htons(sizeof(uint8_t));
579 err |= ibuf_add(buf, &ft, sizeof(ft));
580 err |= ibuf_add(buf, &map->type, sizeof(map->type));
581 break;
582 case MAP_TYPE_PREFIX:
583 len = PREFIX_SIZE(map->fec.prefix.prefixlen);
584 ft.length = htons(sizeof(map->type) + sizeof(family) +
585 sizeof(map->fec.prefix.prefixlen) + len);
586 err |= ibuf_add(buf, &ft, sizeof(ft));
587 err |= ibuf_add(buf, &map->type, sizeof(map->type));
588 switch (map->fec.prefix.af) {
589 case AF_INET:
590 family = htons(AF_IPV4);
591 break;
592 case AF_INET6:
593 family = htons(AF_IPV6);
594 break;
595 default:
596 fatalx("gen_fec_tlv: unknown af");
597 break;
598 }
599 err |= ibuf_add(buf, &family, sizeof(family));
600 err |= ibuf_add(buf, &map->fec.prefix.prefixlen,
601 sizeof(map->fec.prefix.prefixlen));
602 if (len)
603 err |= ibuf_add(buf, &map->fec.prefix.prefix, len);
604 break;
605 case MAP_TYPE_PWID:
606 if (map->flags & F_MAP_PW_ID)
607 pw_len += FEC_PWID_SIZE;
608 if (map->flags & F_MAP_PW_IFMTU)
609 pw_len += FEC_SUBTLV_IFMTU_SIZE;
610
611 len = FEC_PWID_ELM_MIN_LEN + pw_len;
612
613 ft.length = htons(len);
614 err |= ibuf_add(buf, &ft, sizeof(ft));
615
616 err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
617 pw_type = map->fec.pwid.type;
618 if (map->flags & F_MAP_PW_CWORD)
619 pw_type |= CONTROL_WORD_FLAG;
620 pw_type = htons(pw_type);
621 err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
622 err |= ibuf_add(buf, &pw_len, sizeof(uint8_t));
623 group_id = htonl(map->fec.pwid.group_id);
624 err |= ibuf_add(buf, &group_id, sizeof(uint32_t));
625 if (map->flags & F_MAP_PW_ID) {
626 pwid = htonl(map->fec.pwid.pwid);
627 err |= ibuf_add(buf, &pwid, sizeof(uint32_t));
628 }
629 if (map->flags & F_MAP_PW_IFMTU) {
630 struct subtlv stlv;
631
632 stlv.type = SUBTLV_IFMTU;
633 stlv.length = FEC_SUBTLV_IFMTU_SIZE;
634 err |= ibuf_add(buf, &stlv, sizeof(uint16_t));
635
636 ifmtu = htons(map->fec.pwid.ifmtu);
637 err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t));
638 }
639 break;
640 case MAP_TYPE_TYPED_WCARD:
641 len = FEC_ELM_TWCARD_MIN_LEN;
642 switch (map->fec.twcard.type) {
643 case MAP_TYPE_PREFIX:
644 case MAP_TYPE_PWID:
645 len += sizeof(uint16_t);
646 break;
647 default:
648 fatalx("gen_fec_tlv: unexpected fec type");
649 }
650 ft.length = htons(len);
651 err |= ibuf_add(buf, &ft, sizeof(ft));
652 err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
653 err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t));
654
655 switch (map->fec.twcard.type) {
656 case MAP_TYPE_PREFIX:
657 twcard_len = sizeof(uint16_t);
658 err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
659
660 switch (map->fec.twcard.u.prefix_af) {
661 case AF_INET:
662 family = htons(AF_IPV4);
663 break;
664 case AF_INET6:
665 family = htons(AF_IPV6);
666 break;
667 default:
668 fatalx("gen_fec_tlv: unknown af");
669 break;
670 }
671
672 err |= ibuf_add(buf, &family, sizeof(uint16_t));
673 break;
674 case MAP_TYPE_PWID:
675 twcard_len = sizeof(uint16_t);
676 err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
677 pw_type = htons(map->fec.twcard.u.pw_type);
678 err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
679 break;
680 default:
681 fatalx("gen_fec_tlv: unexpected fec type");
682 }
683 break;
684 default:
685 break;
686 }
687
688 return (err);
689 }
690
691 int
tlv_decode_fec_elm(struct nbr * nbr,struct ldp_msg * msg,char * buf,uint16_t len,struct map * map)692 tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
693 uint16_t len, struct map *map)
694 {
695 uint16_t off = 0;
696 uint8_t pw_len, twcard_len;
697
698 map->type = *buf;
699 off += sizeof(uint8_t);
700
701 switch (map->type) {
702 case MAP_TYPE_WILDCARD:
703 if (len == FEC_ELM_WCARD_LEN)
704 return (off);
705 else {
706 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
707 msg->type);
708 return (-1);
709 }
710 break;
711 case MAP_TYPE_PREFIX:
712 if (len < FEC_ELM_PREFIX_MIN_LEN) {
713 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
714 msg->type);
715 return (-1);
716 }
717
718 /* Address Family */
719 memcpy(&map->fec.prefix.af, buf + off,
720 sizeof(map->fec.prefix.af));
721 off += sizeof(map->fec.prefix.af);
722 map->fec.prefix.af = ntohs(map->fec.prefix.af);
723 switch (map->fec.prefix.af) {
724 case AF_IPV4:
725 map->fec.prefix.af = AF_INET;
726 break;
727 case AF_IPV6:
728 map->fec.prefix.af = AF_INET6;
729 break;
730 default:
731 send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
732 msg->type);
733 return (-1);
734 }
735
736 /* Prefix Length */
737 map->fec.prefix.prefixlen = buf[off];
738 off += sizeof(uint8_t);
739 if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) {
740 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
741 msg->type);
742 return (-1);
743 }
744
745 /* Prefix */
746 memset(&map->fec.prefix.prefix, 0,
747 sizeof(map->fec.prefix.prefix));
748 memcpy(&map->fec.prefix.prefix, buf + off,
749 PREFIX_SIZE(map->fec.prefix.prefixlen));
750
751 /* Just in case... */
752 ldp_applymask(map->fec.prefix.af, &map->fec.prefix.prefix,
753 &map->fec.prefix.prefix, map->fec.prefix.prefixlen);
754
755 return (off + PREFIX_SIZE(map->fec.prefix.prefixlen));
756 case MAP_TYPE_PWID:
757 if (len < FEC_PWID_ELM_MIN_LEN) {
758 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
759 msg->type);
760 return (-1);
761 }
762
763 /* PW type */
764 memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t));
765 map->fec.pwid.type = ntohs(map->fec.pwid.type);
766 if (map->fec.pwid.type & CONTROL_WORD_FLAG) {
767 map->flags |= F_MAP_PW_CWORD;
768 map->fec.pwid.type &= ~CONTROL_WORD_FLAG;
769 }
770 off += sizeof(uint16_t);
771
772 /* PW info Length */
773 pw_len = buf[off];
774 off += sizeof(uint8_t);
775
776 if (len != FEC_PWID_ELM_MIN_LEN + pw_len) {
777 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
778 msg->type);
779 return (-1);
780 }
781
782 /* Group ID */
783 memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t));
784 map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id);
785 off += sizeof(uint32_t);
786
787 /* PW ID */
788 if (pw_len == 0)
789 return (off);
790
791 if (pw_len < sizeof(uint32_t)) {
792 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
793 msg->type);
794 return (-1);
795 }
796
797 memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t));
798 map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid);
799 map->flags |= F_MAP_PW_ID;
800 off += sizeof(uint32_t);
801 pw_len -= sizeof(uint32_t);
802
803 /* Optional Interface Parameter Sub-TLVs */
804 while (pw_len > 0) {
805 struct subtlv stlv;
806
807 if (pw_len < sizeof(stlv)) {
808 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
809 msg->type);
810 return (-1);
811 }
812
813 memcpy(&stlv, buf + off, sizeof(stlv));
814 if (stlv.length > pw_len) {
815 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
816 msg->type);
817 return (-1);
818 }
819
820 switch (stlv.type) {
821 case SUBTLV_IFMTU:
822 if (stlv.length != FEC_SUBTLV_IFMTU_SIZE) {
823 session_shutdown(nbr, S_BAD_TLV_LEN,
824 msg->id, msg->type);
825 return (-1);
826 }
827 memcpy(&map->fec.pwid.ifmtu, buf + off +
828 SUBTLV_HDR_SIZE, sizeof(uint16_t));
829 map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu);
830 map->flags |= F_MAP_PW_IFMTU;
831 break;
832 default:
833 /* ignore */
834 break;
835 }
836 off += stlv.length;
837 pw_len -= stlv.length;
838 }
839
840 return (off);
841 case MAP_TYPE_TYPED_WCARD:
842 if (len < FEC_ELM_TWCARD_MIN_LEN) {
843 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
844 msg->type);
845 return (-1);
846 }
847
848 memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t));
849 off += sizeof(uint8_t);
850 memcpy(&twcard_len, buf + off, sizeof(uint8_t));
851 off += sizeof(uint8_t);
852 if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) {
853 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
854 msg->type);
855 return (-1);
856 }
857
858 switch (map->fec.twcard.type) {
859 case MAP_TYPE_PREFIX:
860 if (twcard_len != sizeof(uint16_t)) {
861 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
862 msg->type);
863 return (-1);
864 }
865
866 memcpy(&map->fec.twcard.u.prefix_af, buf + off,
867 sizeof(uint16_t));
868 map->fec.twcard.u.prefix_af =
869 ntohs(map->fec.twcard.u.prefix_af);
870 off += sizeof(uint16_t);
871
872 switch (map->fec.twcard.u.prefix_af) {
873 case AF_IPV4:
874 map->fec.twcard.u.prefix_af = AF_INET;
875 break;
876 case AF_IPV6:
877 map->fec.twcard.u.prefix_af = AF_INET6;
878 break;
879 default:
880 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
881 msg->type);
882 return (-1);
883 }
884 break;
885 case MAP_TYPE_PWID:
886 if (twcard_len != sizeof(uint16_t)) {
887 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
888 msg->type);
889 return (-1);
890 }
891
892 memcpy(&map->fec.twcard.u.pw_type, buf + off,
893 sizeof(uint16_t));
894 map->fec.twcard.u.pw_type =
895 ntohs(map->fec.twcard.u.pw_type);
896 /* ignore the reserved bit as per RFC 6667 */
897 map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT;
898 off += sizeof(uint16_t);
899 break;
900 default:
901 send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id,
902 msg->type);
903 return (-1);
904 }
905
906 return (off);
907 default:
908 send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
909 break;
910 }
911
912 return (-1);
913 }
914
915 static void
log_msg_mapping(int out,uint16_t msg_type,struct nbr * nbr,struct map * map)916 log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
917 {
918 log_debug("msg-%s: %s: lsr-id %s, fec %s, label %s",
919 (out) ? "out" : "in", msg_name(msg_type), inet_ntoa(nbr->id),
920 log_map(map), log_label(map->label));
921 }
922