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