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