]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/labelmapping.c
Merge branch 'master' into pim-ssm
[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 free(me);
134 }
135
136 enqueue_pdu(nbr, type, buf, size);
137
138 nbr_fsm(nbr, NBR_EVT_PDU_SENT);
139 }
140
141 /* Generic function that handles all Label Message types */
142 int
143 recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
144 {
145 struct ldp_msg msg;
146 struct tlv ft;
147 uint32_t label = NO_LABEL, reqid = 0;
148 uint32_t pw_status = 0;
149 uint8_t flags = 0;
150 int feclen, tlen;
151 uint16_t current_tlv = 1;
152 struct mapping_entry *me;
153 struct mapping_head mh;
154 struct map map;
155
156 memcpy(&msg, buf, sizeof(msg));
157 buf += LDP_MSG_SIZE;
158 len -= LDP_MSG_SIZE;
159
160 /* FEC TLV */
161 if (len < sizeof(ft)) {
162 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
163 return (-1);
164 }
165
166 memcpy(&ft, buf, sizeof(ft));
167 if (ntohs(ft.type) != TLV_TYPE_FEC) {
168 send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
169 return (-1);
170 }
171 feclen = ntohs(ft.length);
172 if (feclen > len - TLV_HDR_SIZE) {
173 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
174 return (-1);
175 }
176
177 buf += TLV_HDR_SIZE; /* just advance to the end of the fec header */
178 len -= TLV_HDR_SIZE;
179
180 TAILQ_INIT(&mh);
181 do {
182 memset(&map, 0, sizeof(map));
183 map.msg_id = msg.id;
184
185 if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf, feclen,
186 &map)) == -1)
187 goto err;
188 if (map.type == MAP_TYPE_PWID &&
189 !(map.flags & F_MAP_PW_ID) &&
190 type != MSG_TYPE_LABELWITHDRAW &&
191 type != MSG_TYPE_LABELRELEASE) {
192 send_notification(nbr->tcp, S_MISS_MSG, msg.id,
193 msg.type);
194 goto err;
195 }
196
197 /*
198 * The Wildcard FEC Element can be used only in the
199 * Label Withdraw and Label Release messages.
200 */
201 if (map.type == MAP_TYPE_WILDCARD) {
202 switch (type) {
203 case MSG_TYPE_LABELMAPPING:
204 case MSG_TYPE_LABELREQUEST:
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 * RFC 5561 - Section 4:
216 * "An LDP implementation that supports the Typed Wildcard
217 * FEC Element MUST support its use in Label Request, Label
218 * Withdraw, and Label Release messages".
219 */
220 if (map.type == MAP_TYPE_TYPED_WCARD) {
221 switch (type) {
222 case MSG_TYPE_LABELMAPPING:
223 case MSG_TYPE_LABELABORTREQ:
224 session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
225 msg.type);
226 goto err;
227 default:
228 break;
229 }
230 }
231
232 /*
233 * LDP supports the use of multiple FEC Elements per
234 * FEC for the Label Mapping message only.
235 */
236 if (type != MSG_TYPE_LABELMAPPING &&
237 tlen != feclen) {
238 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
239 goto err;
240 }
241
242 mapping_list_add(&mh, &map);
243
244 buf += tlen;
245 len -= tlen;
246 feclen -= tlen;
247 } while (feclen > 0);
248
249 /* Optional Parameters */
250 while (len > 0) {
251 struct tlv tlv;
252 uint16_t tlv_type;
253 uint16_t tlv_len;
254 uint32_t reqbuf, labelbuf, statusbuf;
255
256 if (len < sizeof(tlv)) {
257 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
258 goto err;
259 }
260
261 memcpy(&tlv, buf, TLV_HDR_SIZE);
262 tlv_type = ntohs(tlv.type);
263 tlv_len = ntohs(tlv.length);
264 if (tlv_len + TLV_HDR_SIZE > len) {
265 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
266 goto err;
267 }
268 buf += TLV_HDR_SIZE;
269 len -= TLV_HDR_SIZE;
270
271 /*
272 * For Label Mapping messages the Label TLV is mandatory and
273 * should appear right after the FEC TLV.
274 */
275 if (current_tlv == 1 && type == MSG_TYPE_LABELMAPPING &&
276 !(tlv_type & TLV_TYPE_GENERICLABEL)) {
277 send_notification(nbr->tcp, S_MISS_MSG, msg.id,
278 msg.type);
279 goto err;
280 }
281
282 switch (tlv_type) {
283 case TLV_TYPE_LABELREQUEST:
284 switch (type) {
285 case MSG_TYPE_LABELMAPPING:
286 case MSG_TYPE_LABELREQUEST:
287 if (tlv_len != REQID_TLV_LEN) {
288 session_shutdown(nbr, S_BAD_TLV_LEN,
289 msg.id, msg.type);
290 goto err;
291 }
292
293 flags |= F_MAP_REQ_ID;
294 memcpy(&reqbuf, buf, sizeof(reqbuf));
295 reqid = ntohl(reqbuf);
296 break;
297 default:
298 /* ignore */
299 break;
300 }
301 break;
302 case TLV_TYPE_HOPCOUNT:
303 case TLV_TYPE_PATHVECTOR:
304 /* ignore */
305 break;
306 case TLV_TYPE_GENERICLABEL:
307 switch (type) {
308 case MSG_TYPE_LABELMAPPING:
309 case MSG_TYPE_LABELWITHDRAW:
310 case MSG_TYPE_LABELRELEASE:
311 if (tlv_len != LABEL_TLV_LEN) {
312 session_shutdown(nbr, S_BAD_TLV_LEN,
313 msg.id, msg.type);
314 goto err;
315 }
316
317 memcpy(&labelbuf, buf, sizeof(labelbuf));
318 label = ntohl(labelbuf);
319 /* do not accept invalid labels */
320 if (label > MPLS_LABEL_MAX ||
321 (label <= MPLS_LABEL_RESERVED_MAX &&
322 label != MPLS_LABEL_IPV4NULL &&
323 label != MPLS_LABEL_IPV6NULL &&
324 label != MPLS_LABEL_IMPLNULL)) {
325 session_shutdown(nbr, S_BAD_TLV_VAL,
326 msg.id, msg.type);
327 goto err;
328 }
329 break;
330 default:
331 /* ignore */
332 break;
333 }
334 break;
335 case TLV_TYPE_ATMLABEL:
336 case TLV_TYPE_FRLABEL:
337 switch (type) {
338 case MSG_TYPE_LABELMAPPING:
339 case MSG_TYPE_LABELWITHDRAW:
340 case MSG_TYPE_LABELRELEASE:
341 /* unsupported */
342 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
343 msg.type);
344 goto err;
345 break;
346 default:
347 /* ignore */
348 break;
349 }
350 break;
351 case TLV_TYPE_STATUS:
352 if (tlv_len != STATUS_TLV_LEN) {
353 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
354 msg.type);
355 goto err;
356 }
357 /* ignore */
358 break;
359 case TLV_TYPE_PW_STATUS:
360 switch (type) {
361 case MSG_TYPE_LABELMAPPING:
362 if (tlv_len != PW_STATUS_TLV_LEN) {
363 session_shutdown(nbr, S_BAD_TLV_LEN,
364 msg.id, msg.type);
365 goto err;
366 }
367
368 flags |= F_MAP_PW_STATUS;
369 memcpy(&statusbuf, buf, sizeof(statusbuf));
370 pw_status = ntohl(statusbuf);
371 break;
372 default:
373 /* ignore */
374 break;
375 }
376 break;
377 default:
378 if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
379 send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
380 msg.id, msg.type, tlv_type, tlv_len, buf);
381 /* ignore unknown tlv */
382 break;
383 }
384 buf += tlv_len;
385 len -= tlv_len;
386 current_tlv++;
387 }
388
389 /* notify lde about the received message. */
390 while ((me = TAILQ_FIRST(&mh)) != NULL) {
391 int imsg_type = IMSG_NONE;
392
393 me->map.flags |= flags;
394 switch (me->map.type) {
395 case MAP_TYPE_PREFIX:
396 switch (me->map.fec.prefix.af) {
397 case AF_INET:
398 if (label == MPLS_LABEL_IPV6NULL) {
399 session_shutdown(nbr, S_BAD_TLV_VAL,
400 msg.id, msg.type);
401 goto err;
402 }
403 if (!nbr->v4_enabled)
404 goto next;
405 break;
406 case AF_INET6:
407 if (label == MPLS_LABEL_IPV4NULL) {
408 session_shutdown(nbr, S_BAD_TLV_VAL,
409 msg.id, msg.type);
410 goto err;
411 }
412 if (!nbr->v6_enabled)
413 goto next;
414 break;
415 default:
416 fatalx("recv_labelmessage: unknown af");
417 }
418 break;
419 case MAP_TYPE_PWID:
420 if (label <= MPLS_LABEL_RESERVED_MAX) {
421 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
422 msg.type);
423 goto err;
424 }
425 if (me->map.flags & F_MAP_PW_STATUS)
426 me->map.pw_status = pw_status;
427 break;
428 default:
429 break;
430 }
431 me->map.label = label;
432 if (me->map.flags & F_MAP_REQ_ID)
433 me->map.requestid = reqid;
434
435 log_msg_mapping(0, type, nbr, &me->map);
436
437 switch (type) {
438 case MSG_TYPE_LABELMAPPING:
439 imsg_type = IMSG_LABEL_MAPPING;
440 break;
441 case MSG_TYPE_LABELREQUEST:
442 imsg_type = IMSG_LABEL_REQUEST;
443 break;
444 case MSG_TYPE_LABELWITHDRAW:
445 imsg_type = IMSG_LABEL_WITHDRAW;
446 break;
447 case MSG_TYPE_LABELRELEASE:
448 imsg_type = IMSG_LABEL_RELEASE;
449 break;
450 case MSG_TYPE_LABELABORTREQ:
451 imsg_type = IMSG_LABEL_ABORT;
452 break;
453 default:
454 break;
455 }
456
457 ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
458 sizeof(struct map));
459
460 next:
461 TAILQ_REMOVE(&mh, me, entry);
462 free(me);
463 }
464
465 return (0);
466
467 err:
468 mapping_list_clr(&mh);
469
470 return (-1);
471 }
472
473 /* Other TLV related functions */
474 static int
475 gen_label_tlv(struct ibuf *buf, uint32_t label)
476 {
477 struct label_tlv lt;
478
479 lt.type = htons(TLV_TYPE_GENERICLABEL);
480 lt.length = htons(LABEL_TLV_LEN);
481 lt.label = htonl(label);
482
483 return (ibuf_add(buf, &lt, sizeof(lt)));
484 }
485
486 static int
487 gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
488 {
489 struct reqid_tlv rt;
490
491 rt.type = htons(TLV_TYPE_LABELREQUEST);
492 rt.length = htons(REQID_TLV_LEN);
493 rt.reqid = htonl(reqid);
494
495 return (ibuf_add(buf, &rt, sizeof(rt)));
496 }
497
498 int
499 gen_pw_status_tlv(struct ibuf *buf, uint32_t status)
500 {
501 struct pw_status_tlv st;
502
503 st.type = htons(TLV_TYPE_PW_STATUS);
504 st.length = htons(PW_STATUS_TLV_LEN);
505 st.value = htonl(status);
506
507 return (ibuf_add(buf, &st, sizeof(st)));
508 }
509
510 uint16_t
511 len_fec_tlv(struct map *map)
512 {
513 uint16_t len = TLV_HDR_SIZE;
514
515 switch (map->type) {
516 case MAP_TYPE_WILDCARD:
517 len += FEC_ELM_WCARD_LEN;
518 break;
519 case MAP_TYPE_PREFIX:
520 len += FEC_ELM_PREFIX_MIN_LEN +
521 PREFIX_SIZE(map->fec.prefix.prefixlen);
522 break;
523 case MAP_TYPE_PWID:
524 len += FEC_PWID_ELM_MIN_LEN;
525 if (map->flags & F_MAP_PW_ID)
526 len += PW_STATUS_TLV_LEN;
527 if (map->flags & F_MAP_PW_IFMTU)
528 len += FEC_SUBTLV_IFMTU_SIZE;
529 if (map->flags & F_MAP_PW_STATUS)
530 len += PW_STATUS_TLV_SIZE;
531 break;
532 case MAP_TYPE_TYPED_WCARD:
533 len += FEC_ELM_TWCARD_MIN_LEN;
534 switch (map->fec.twcard.type) {
535 case MAP_TYPE_PREFIX:
536 case MAP_TYPE_PWID:
537 len += sizeof(uint16_t);
538 break;
539 default:
540 fatalx("len_fec_tlv: unexpected fec type");
541 }
542 break;
543 default:
544 fatalx("len_fec_tlv: unexpected fec type");
545 }
546
547 return (len);
548 }
549
550 int
551 gen_fec_tlv(struct ibuf *buf, struct map *map)
552 {
553 struct tlv ft;
554 uint16_t family, len, pw_type, ifmtu;
555 uint8_t pw_len = 0, twcard_len;
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)
592 pw_len += FEC_PWID_SIZE;
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;
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 case MAP_TYPE_PWID:
630 len += sizeof(uint16_t);
631 break;
632 default:
633 fatalx("gen_fec_tlv: unexpected fec type");
634 }
635 ft.length = htons(len);
636 err |= ibuf_add(buf, &ft, sizeof(ft));
637 err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
638 err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t));
639
640 switch (map->fec.twcard.type) {
641 case MAP_TYPE_PREFIX:
642 twcard_len = sizeof(uint16_t);
643 err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
644
645 switch (map->fec.twcard.u.prefix_af) {
646 case AF_INET:
647 family = htons(AF_IPV4);
648 break;
649 case AF_INET6:
650 family = htons(AF_IPV6);
651 break;
652 default:
653 fatalx("gen_fec_tlv: unknown af");
654 break;
655 }
656
657 err |= ibuf_add(buf, &family, sizeof(uint16_t));
658 break;
659 case MAP_TYPE_PWID:
660 twcard_len = sizeof(uint16_t);
661 err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
662 pw_type = htons(map->fec.twcard.u.pw_type);
663 err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
664 break;
665 default:
666 fatalx("gen_fec_tlv: unexpected fec type");
667 }
668 break;
669 default:
670 break;
671 }
672
673 return (err);
674 }
675
676 int
677 tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
678 uint16_t len, struct map *map)
679 {
680 uint16_t off = 0;
681 uint8_t pw_len, twcard_len;
682
683 map->type = *buf;
684 off += sizeof(uint8_t);
685
686 switch (map->type) {
687 case MAP_TYPE_WILDCARD:
688 if (len == FEC_ELM_WCARD_LEN)
689 return (off);
690 else {
691 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
692 msg->type);
693 return (-1);
694 }
695 break;
696 case MAP_TYPE_PREFIX:
697 if (len < FEC_ELM_PREFIX_MIN_LEN) {
698 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
699 msg->type);
700 return (-1);
701 }
702
703 /* Address Family */
704 memcpy(&map->fec.prefix.af, buf + off,
705 sizeof(map->fec.prefix.af));
706 off += sizeof(map->fec.prefix.af);
707 map->fec.prefix.af = ntohs(map->fec.prefix.af);
708 switch (map->fec.prefix.af) {
709 case AF_IPV4:
710 map->fec.prefix.af = AF_INET;
711 break;
712 case AF_IPV6:
713 map->fec.prefix.af = AF_INET6;
714 break;
715 default:
716 send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
717 msg->type);
718 return (-1);
719 }
720
721 /* Prefix Length */
722 map->fec.prefix.prefixlen = buf[off];
723 off += sizeof(uint8_t);
724 if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) {
725 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
726 msg->type);
727 return (-1);
728 }
729
730 /* Prefix */
731 memset(&map->fec.prefix.prefix, 0,
732 sizeof(map->fec.prefix.prefix));
733 memcpy(&map->fec.prefix.prefix, buf + off,
734 PREFIX_SIZE(map->fec.prefix.prefixlen));
735
736 /* Just in case... */
737 ldp_applymask(map->fec.prefix.af, &map->fec.prefix.prefix,
738 &map->fec.prefix.prefix, map->fec.prefix.prefixlen);
739
740 return (off + PREFIX_SIZE(map->fec.prefix.prefixlen));
741 case MAP_TYPE_PWID:
742 if (len < FEC_PWID_ELM_MIN_LEN) {
743 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
744 msg->type);
745 return (-1);
746 }
747
748 /* PW type */
749 memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t));
750 map->fec.pwid.type = ntohs(map->fec.pwid.type);
751 if (map->fec.pwid.type & CONTROL_WORD_FLAG) {
752 map->flags |= F_MAP_PW_CWORD;
753 map->fec.pwid.type &= ~CONTROL_WORD_FLAG;
754 }
755 off += sizeof(uint16_t);
756
757 /* PW info Length */
758 pw_len = buf[off];
759 off += sizeof(uint8_t);
760
761 if (len != FEC_PWID_ELM_MIN_LEN + pw_len) {
762 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
763 msg->type);
764 return (-1);
765 }
766
767 /* Group ID */
768 memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t));
769 map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id);
770 off += sizeof(uint32_t);
771
772 /* PW ID */
773 if (pw_len == 0)
774 return (off);
775
776 if (pw_len < sizeof(uint32_t)) {
777 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
778 msg->type);
779 return (-1);
780 }
781
782 memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t));
783 map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid);
784 map->flags |= F_MAP_PW_ID;
785 off += sizeof(uint32_t);
786 pw_len -= sizeof(uint32_t);
787
788 /* Optional Interface Parameter Sub-TLVs */
789 while (pw_len > 0) {
790 struct subtlv stlv;
791
792 if (pw_len < sizeof(stlv)) {
793 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
794 msg->type);
795 return (-1);
796 }
797
798 memcpy(&stlv, buf + off, sizeof(stlv));
799 if (stlv.length > pw_len) {
800 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
801 msg->type);
802 return (-1);
803 }
804
805 switch (stlv.type) {
806 case SUBTLV_IFMTU:
807 if (stlv.length != FEC_SUBTLV_IFMTU_SIZE) {
808 session_shutdown(nbr, S_BAD_TLV_LEN,
809 msg->id, msg->type);
810 return (-1);
811 }
812 memcpy(&map->fec.pwid.ifmtu, buf + off +
813 SUBTLV_HDR_SIZE, sizeof(uint16_t));
814 map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu);
815 map->flags |= F_MAP_PW_IFMTU;
816 break;
817 default:
818 /* ignore */
819 break;
820 }
821 off += stlv.length;
822 pw_len -= stlv.length;
823 }
824
825 return (off);
826 case MAP_TYPE_TYPED_WCARD:
827 if (len < FEC_ELM_TWCARD_MIN_LEN) {
828 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
829 msg->type);
830 return (-1);
831 }
832
833 memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t));
834 off += sizeof(uint8_t);
835 memcpy(&twcard_len, buf + off, sizeof(uint8_t));
836 off += sizeof(uint8_t);
837 if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) {
838 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
839 msg->type);
840 return (-1);
841 }
842
843 switch (map->fec.twcard.type) {
844 case MAP_TYPE_PREFIX:
845 if (twcard_len != sizeof(uint16_t)) {
846 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
847 msg->type);
848 return (-1);
849 }
850
851 memcpy(&map->fec.twcard.u.prefix_af, buf + off,
852 sizeof(uint16_t));
853 map->fec.twcard.u.prefix_af =
854 ntohs(map->fec.twcard.u.prefix_af);
855 off += sizeof(uint16_t);
856
857 switch (map->fec.twcard.u.prefix_af) {
858 case AF_IPV4:
859 map->fec.twcard.u.prefix_af = AF_INET;
860 break;
861 case AF_IPV6:
862 map->fec.twcard.u.prefix_af = AF_INET6;
863 break;
864 default:
865 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
866 msg->type);
867 return (-1);
868 }
869 break;
870 case MAP_TYPE_PWID:
871 if (twcard_len != sizeof(uint16_t)) {
872 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
873 msg->type);
874 return (-1);
875 }
876
877 memcpy(&map->fec.twcard.u.pw_type, buf + off,
878 sizeof(uint16_t));
879 map->fec.twcard.u.pw_type =
880 ntohs(map->fec.twcard.u.pw_type);
881 /* ignore the reserved bit as per RFC 6667 */
882 map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT;
883 off += sizeof(uint16_t);
884 break;
885 default:
886 send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id,
887 msg->type);
888 return (-1);
889 }
890
891 return (off);
892 default:
893 send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
894 break;
895 }
896
897 return (-1);
898 }
899
900 static void
901 log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
902 {
903 debug_msg(out, "%s: lsr-id %s, fec %s, label %s", msg_name(msg_type),
904 inet_ntoa(nbr->id), log_map(map), log_label(map->label));
905 }