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