]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/labelmapping.c
ldpd: implement support for PWid group wildcards
[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;
93 }
94 if (me->map.label != NO_LABEL)
95 msg_size += LABEL_TLV_SIZE;
96 if (me->map.flags & F_MAP_REQ_ID)
97 msg_size += REQID_TLV_SIZE;
98 if (me->map.flags & F_MAP_STATUS)
99 msg_size += STATUS_SIZE;
100
101 /* maximum pdu length exceeded, we need a new ldp pdu */
102 if (size + msg_size > nbr->max_pdu_len) {
103 enqueue_pdu(nbr, buf, size);
104 first = 1;
105 continue;
106 }
107
108 size += msg_size;
109
110 /* append message and tlvs */
111 err |= gen_msg_hdr(buf, type, msg_size);
112 err |= gen_fec_tlv(buf, &me->map);
113 if (me->map.label != NO_LABEL)
114 err |= gen_label_tlv(buf, me->map.label);
115 if (me->map.flags & F_MAP_REQ_ID)
116 err |= gen_reqid_tlv(buf, me->map.requestid);
117 if (me->map.flags & F_MAP_PW_STATUS)
118 err |= gen_pw_status_tlv(buf, me->map.pw_status);
119 if (me->map.flags & F_MAP_STATUS)
120 err |= gen_status_tlv(buf, me->map.st.status_code,
121 me->map.st.msg_id, me->map.st.msg_type);
122 if (err) {
123 ibuf_free(buf);
124 mapping_list_clr(mh);
125 return;
126 }
127
faf75793 128 log_msg_mapping(1, type, nbr, &me->map);
8429abe0
RW
129
130 TAILQ_REMOVE(mh, me, entry);
131 free(me);
132 }
133
134 enqueue_pdu(nbr, buf, size);
135
136 nbr_fsm(nbr, NBR_EVT_PDU_SENT);
137}
138
139/* Generic function that handles all Label Message types */
140int
141recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
142{
143 struct ldp_msg msg;
144 struct tlv ft;
145 uint32_t label = NO_LABEL, reqid = 0;
146 uint32_t pw_status = 0;
147 uint8_t flags = 0;
148 int feclen, lbllen, tlen;
149 struct mapping_entry *me;
150 struct mapping_head mh;
151 struct map map;
152
153 memcpy(&msg, buf, sizeof(msg));
154 buf += LDP_MSG_SIZE;
155 len -= LDP_MSG_SIZE;
156
157 /* FEC TLV */
158 if (len < sizeof(ft)) {
159 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
160 return (-1);
161 }
162
163 memcpy(&ft, buf, sizeof(ft));
164 if (ntohs(ft.type) != TLV_TYPE_FEC) {
adbdf465 165 send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
8429abe0
RW
166 return (-1);
167 }
168 feclen = ntohs(ft.length);
169 if (feclen > len - TLV_HDR_SIZE) {
170 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
171 return (-1);
172 }
173
174 buf += TLV_HDR_SIZE; /* just advance to the end of the fec header */
175 len -= TLV_HDR_SIZE;
176
177 TAILQ_INIT(&mh);
178 do {
179 memset(&map, 0, sizeof(map));
180 map.msg_id = msg.id;
181
182 if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf, feclen,
183 &map)) == -1)
184 goto err;
185 if (map.type == MAP_TYPE_PWID &&
186 !(map.flags & F_MAP_PW_ID) &&
187 type != MSG_TYPE_LABELWITHDRAW &&
188 type != MSG_TYPE_LABELRELEASE) {
adbdf465 189 send_notification(nbr->tcp, S_MISS_MSG, msg.id,
8429abe0
RW
190 msg.type);
191 return (-1);
192 }
193
194 /*
195 * The Wildcard FEC Element can be used only in the
196 * Label Withdraw and Label Release messages.
197 */
198 if (map.type == MAP_TYPE_WILDCARD) {
199 switch (type) {
200 case MSG_TYPE_LABELMAPPING:
201 case MSG_TYPE_LABELREQUEST:
202 case MSG_TYPE_LABELABORTREQ:
203 session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
204 msg.type);
205 goto err;
206 default:
207 break;
208 }
209 }
210
211 /*
212 * LDP supports the use of multiple FEC Elements per
213 * FEC for the Label Mapping message only.
214 */
215 if (type != MSG_TYPE_LABELMAPPING &&
216 tlen != feclen) {
217 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
218 goto err;
219 }
220
221 mapping_list_add(&mh, &map);
222
223 buf += tlen;
224 len -= tlen;
225 feclen -= tlen;
226 } while (feclen > 0);
227
228 /* Mandatory Label TLV */
229 if (type == MSG_TYPE_LABELMAPPING) {
230 lbllen = tlv_decode_label(nbr, &msg, buf, len, &label);
231 if (lbllen == -1)
232 goto err;
233
234 buf += lbllen;
235 len -= lbllen;
236 }
237
238 /* Optional Parameters */
239 while (len > 0) {
240 struct tlv tlv;
241 uint16_t tlv_len;
242 uint32_t reqbuf, labelbuf, statusbuf;
243
244 if (len < sizeof(tlv)) {
245 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
246 goto err;
247 }
248
249 memcpy(&tlv, buf, TLV_HDR_SIZE);
250 tlv_len = ntohs(tlv.length);
251 if (tlv_len + TLV_HDR_SIZE > len) {
252 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
253 goto err;
254 }
255 buf += TLV_HDR_SIZE;
256 len -= TLV_HDR_SIZE;
257
258 switch (ntohs(tlv.type)) {
259 case TLV_TYPE_LABELREQUEST:
260 switch (type) {
261 case MSG_TYPE_LABELMAPPING:
262 case MSG_TYPE_LABELREQUEST:
263 if (tlv_len != REQID_TLV_LEN) {
264 session_shutdown(nbr, S_BAD_TLV_LEN,
265 msg.id, msg.type);
266 goto err;
267 }
268
269 flags |= F_MAP_REQ_ID;
270 memcpy(&reqbuf, buf, sizeof(reqbuf));
271 reqid = ntohl(reqbuf);
272 break;
273 default:
274 /* ignore */
275 break;
276 }
277 break;
278 case TLV_TYPE_HOPCOUNT:
279 case TLV_TYPE_PATHVECTOR:
280 /* ignore */
281 break;
282 case TLV_TYPE_GENERICLABEL:
283 switch (type) {
284 case MSG_TYPE_LABELWITHDRAW:
285 case MSG_TYPE_LABELRELEASE:
286 if (tlv_len != LABEL_TLV_LEN) {
287 session_shutdown(nbr, S_BAD_TLV_LEN,
288 msg.id, msg.type);
289 goto err;
290 }
291
292 memcpy(&labelbuf, buf, sizeof(labelbuf));
293 label = ntohl(labelbuf);
294 break;
295 default:
296 /* ignore */
297 break;
298 }
299 break;
300 case TLV_TYPE_ATMLABEL:
301 case TLV_TYPE_FRLABEL:
302 switch (type) {
303 case MSG_TYPE_LABELWITHDRAW:
304 case MSG_TYPE_LABELRELEASE:
305 /* unsupported */
306 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
307 msg.type);
308 goto err;
309 break;
310 default:
311 /* ignore */
312 break;
313 }
314 break;
315 case TLV_TYPE_STATUS:
316 if (tlv_len != STATUS_TLV_LEN) {
317 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
318 msg.type);
319 goto err;
320 }
321 /* ignore */
322 break;
323 case TLV_TYPE_PW_STATUS:
324 switch (type) {
325 case MSG_TYPE_LABELMAPPING:
326 if (tlv_len != PW_STATUS_TLV_LEN) {
327 session_shutdown(nbr, S_BAD_TLV_LEN,
328 msg.id, msg.type);
329 goto err;
330 }
331
332 flags |= F_MAP_PW_STATUS;
333 memcpy(&statusbuf, buf, sizeof(statusbuf));
334 pw_status = ntohl(statusbuf);
335 break;
336 default:
337 /* ignore */
338 break;
339 }
340 break;
341 default:
342 if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
adbdf465 343 send_notification(nbr->tcp, S_UNKNOWN_TLV,
8429abe0
RW
344 msg.id, msg.type);
345 /* ignore unknown tlv */
346 break;
347 }
348 buf += tlv_len;
349 len -= tlv_len;
350 }
351
352 /* notify lde about the received message. */
353 while ((me = TAILQ_FIRST(&mh)) != NULL) {
354 int imsg_type = IMSG_NONE;
355
356 me->map.flags |= flags;
357 switch (me->map.type) {
358 case MAP_TYPE_PREFIX:
359 switch (me->map.fec.prefix.af) {
360 case AF_INET:
361 if (label == MPLS_LABEL_IPV6NULL) {
362 session_shutdown(nbr, S_BAD_TLV_VAL,
363 msg.id, msg.type);
364 goto err;
365 }
366 if (!nbr->v4_enabled)
367 goto next;
368 break;
369 case AF_INET6:
370 if (label == MPLS_LABEL_IPV4NULL) {
371 session_shutdown(nbr, S_BAD_TLV_VAL,
372 msg.id, msg.type);
373 goto err;
374 }
375 if (!nbr->v6_enabled)
376 goto next;
377 break;
378 default:
379 fatalx("recv_labelmessage: unknown af");
380 }
381 break;
382 case MAP_TYPE_PWID:
383 if (label <= MPLS_LABEL_RESERVED_MAX) {
384 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
385 msg.type);
386 goto err;
387 }
388 if (me->map.flags & F_MAP_PW_STATUS)
389 me->map.pw_status = pw_status;
390 break;
391 default:
392 break;
393 }
394 me->map.label = label;
395 if (me->map.flags & F_MAP_REQ_ID)
396 me->map.requestid = reqid;
397
faf75793 398 log_msg_mapping(0, type, nbr, &me->map);
8429abe0
RW
399
400 switch (type) {
401 case MSG_TYPE_LABELMAPPING:
402 imsg_type = IMSG_LABEL_MAPPING;
403 break;
404 case MSG_TYPE_LABELREQUEST:
405 imsg_type = IMSG_LABEL_REQUEST;
406 break;
407 case MSG_TYPE_LABELWITHDRAW:
408 imsg_type = IMSG_LABEL_WITHDRAW;
409 break;
410 case MSG_TYPE_LABELRELEASE:
411 imsg_type = IMSG_LABEL_RELEASE;
412 break;
413 case MSG_TYPE_LABELABORTREQ:
414 imsg_type = IMSG_LABEL_ABORT;
415 break;
416 default:
417 break;
418 }
419
420 ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
421 sizeof(struct map));
422
05aac414 423 next:
8429abe0
RW
424 TAILQ_REMOVE(&mh, me, entry);
425 free(me);
426 }
427
428 return (0);
429
05aac414 430 err:
8429abe0
RW
431 mapping_list_clr(&mh);
432
433 return (-1);
434}
435
436/* Other TLV related functions */
437static int
438gen_label_tlv(struct ibuf *buf, uint32_t label)
439{
440 struct label_tlv lt;
441
442 lt.type = htons(TLV_TYPE_GENERICLABEL);
443 lt.length = htons(LABEL_TLV_LEN);
444 lt.label = htonl(label);
445
446 return (ibuf_add(buf, &lt, sizeof(lt)));
447}
448
449static int
450tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf,
451 uint16_t len, uint32_t *label)
452{
453 struct label_tlv lt;
454
455 if (len < sizeof(lt)) {
456 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type);
457 return (-1);
458 }
459 memcpy(&lt, buf, sizeof(lt));
460
461 if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) {
adbdf465 462 send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type);
8429abe0
RW
463 return (-1);
464 }
465
466 switch (htons(lt.type)) {
467 case TLV_TYPE_GENERICLABEL:
468 if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) {
469 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
470 msg->type);
471 return (-1);
472 }
473
474 *label = ntohl(lt.label);
475 if (*label > MPLS_LABEL_MAX ||
476 (*label <= MPLS_LABEL_RESERVED_MAX &&
477 *label != MPLS_LABEL_IPV4NULL &&
478 *label != MPLS_LABEL_IPV6NULL &&
479 *label != MPLS_LABEL_IMPLNULL)) {
480 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
481 msg->type);
482 return (-1);
483 }
484 break;
485 case TLV_TYPE_ATMLABEL:
486 case TLV_TYPE_FRLABEL:
487 default:
488 /* unsupported */
489 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type);
490 return (-1);
491 }
492
493 return (sizeof(lt));
494}
495
496static int
497gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
498{
499 struct reqid_tlv rt;
500
501 rt.type = htons(TLV_TYPE_LABELREQUEST);
502 rt.length = htons(REQID_TLV_LEN);
503 rt.reqid = htonl(reqid);
504
505 return (ibuf_add(buf, &rt, sizeof(rt)));
506}
507
508int
509gen_pw_status_tlv(struct ibuf *buf, uint32_t status)
510{
511 struct pw_status_tlv st;
512
513 st.type = htons(TLV_TYPE_PW_STATUS);
514 st.length = htons(PW_STATUS_TLV_LEN);
515 st.value = htonl(status);
516
517 return (ibuf_add(buf, &st, sizeof(st)));
518}
519
520int
521gen_fec_tlv(struct ibuf *buf, struct map *map)
522{
523 struct tlv ft;
524 uint16_t family, len, pw_type, ifmtu;
525 uint8_t pw_len = 0;
526 uint32_t group_id, pwid;
527 int err = 0;
528
529 ft.type = htons(TLV_TYPE_FEC);
530
531 switch (map->type) {
532 case MAP_TYPE_WILDCARD:
533 ft.length = htons(sizeof(uint8_t));
534 err |= ibuf_add(buf, &ft, sizeof(ft));
535 err |= ibuf_add(buf, &map->type, sizeof(map->type));
536 break;
537 case MAP_TYPE_PREFIX:
538 len = PREFIX_SIZE(map->fec.prefix.prefixlen);
539 ft.length = htons(sizeof(map->type) + sizeof(family) +
540 sizeof(map->fec.prefix.prefixlen) + len);
541 err |= ibuf_add(buf, &ft, sizeof(ft));
542 err |= ibuf_add(buf, &map->type, sizeof(map->type));
543 switch (map->fec.prefix.af) {
544 case AF_INET:
545 family = htons(AF_IPV4);
546 break;
547 case AF_INET6:
548 family = htons(AF_IPV6);
549 break;
550 default:
551 fatalx("gen_fec_tlv: unknown af");
552 break;
553 }
554 err |= ibuf_add(buf, &family, sizeof(family));
555 err |= ibuf_add(buf, &map->fec.prefix.prefixlen,
556 sizeof(map->fec.prefix.prefixlen));
557 if (len)
558 err |= ibuf_add(buf, &map->fec.prefix.prefix, len);
559 break;
560 case MAP_TYPE_PWID:
561 if (map->flags & F_MAP_PW_ID)
05aac414 562 pw_len += FEC_PWID_SIZE;
8429abe0
RW
563 if (map->flags & F_MAP_PW_IFMTU)
564 pw_len += FEC_SUBTLV_IFMTU_SIZE;
565
566 len = FEC_PWID_ELM_MIN_LEN + pw_len;
567
568 ft.length = htons(len);
569 err |= ibuf_add(buf, &ft, sizeof(ft));
570
571 err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
572 pw_type = map->fec.pwid.type;
573 if (map->flags & F_MAP_PW_CWORD)
574 pw_type |= CONTROL_WORD_FLAG;
575 pw_type = htons(pw_type);
576 err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
577 err |= ibuf_add(buf, &pw_len, sizeof(uint8_t));
578 group_id = htonl(map->fec.pwid.group_id);
579 err |= ibuf_add(buf, &group_id, sizeof(uint32_t));
580 if (map->flags & F_MAP_PW_ID) {
581 pwid = htonl(map->fec.pwid.pwid);
582 err |= ibuf_add(buf, &pwid, sizeof(uint32_t));
583 }
584 if (map->flags & F_MAP_PW_IFMTU) {
585 struct subtlv stlv;
586
587 stlv.type = SUBTLV_IFMTU;
588 stlv.length = FEC_SUBTLV_IFMTU_SIZE;
589 err |= ibuf_add(buf, &stlv, sizeof(uint16_t));
590
591 ifmtu = htons(map->fec.pwid.ifmtu);
592 err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t));
593 }
594 break;
595 default:
596 break;
597 }
598
599 return (err);
600}
601
602int
603tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
604 uint16_t len, struct map *map)
605{
606 uint16_t off = 0;
607 uint8_t pw_len;
608
609 map->type = *buf;
610 off += sizeof(uint8_t);
611
612 switch (map->type) {
613 case MAP_TYPE_WILDCARD:
614 if (len == FEC_ELM_WCARD_LEN)
615 return (off);
616 else {
617 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
618 msg->type);
619 return (-1);
620 }
621 break;
622 case MAP_TYPE_PREFIX:
623 if (len < FEC_ELM_PREFIX_MIN_LEN) {
624 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
625 msg->type);
626 return (-1);
627 }
628
629 /* Address Family */
630 memcpy(&map->fec.prefix.af, buf + off,
631 sizeof(map->fec.prefix.af));
632 off += sizeof(map->fec.prefix.af);
633 map->fec.prefix.af = ntohs(map->fec.prefix.af);
634 switch (map->fec.prefix.af) {
635 case AF_IPV4:
636 map->fec.prefix.af = AF_INET;
637 break;
638 case AF_IPV6:
639 map->fec.prefix.af = AF_INET6;
640 break;
641 default:
adbdf465 642 send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
8429abe0
RW
643 msg->type);
644 return (-1);
645 }
646
647 /* Prefix Length */
648 map->fec.prefix.prefixlen = buf[off];
649 off += sizeof(uint8_t);
650 if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) {
651 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
652 msg->type);
653 return (-1);
654 }
655
656 /* Prefix */
657 memset(&map->fec.prefix.prefix, 0,
658 sizeof(map->fec.prefix.prefix));
659 memcpy(&map->fec.prefix.prefix, buf + off,
660 PREFIX_SIZE(map->fec.prefix.prefixlen));
661
662 /* Just in case... */
663 ldp_applymask(map->fec.prefix.af, &map->fec.prefix.prefix,
664 &map->fec.prefix.prefix, map->fec.prefix.prefixlen);
665
666 return (off + PREFIX_SIZE(map->fec.prefix.prefixlen));
667 case MAP_TYPE_PWID:
668 if (len < FEC_PWID_ELM_MIN_LEN) {
669 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
670 msg->type);
671 return (-1);
672 }
673
674 /* PW type */
675 memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t));
676 map->fec.pwid.type = ntohs(map->fec.pwid.type);
677 if (map->fec.pwid.type & CONTROL_WORD_FLAG) {
678 map->flags |= F_MAP_PW_CWORD;
679 map->fec.pwid.type &= ~CONTROL_WORD_FLAG;
680 }
681 off += sizeof(uint16_t);
682
683 /* PW info Length */
684 pw_len = buf[off];
685 off += sizeof(uint8_t);
686
687 if (len != FEC_PWID_ELM_MIN_LEN + pw_len) {
688 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
689 msg->type);
690 return (-1);
691 }
692
693 /* Group ID */
694 memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t));
695 map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id);
696 off += sizeof(uint32_t);
697
698 /* PW ID */
699 if (pw_len == 0)
700 return (off);
701
702 if (pw_len < sizeof(uint32_t)) {
703 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
704 msg->type);
705 return (-1);
706 }
707
708 memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t));
709 map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid);
710 map->flags |= F_MAP_PW_ID;
711 off += sizeof(uint32_t);
712 pw_len -= sizeof(uint32_t);
713
714 /* Optional Interface Parameter Sub-TLVs */
715 while (pw_len > 0) {
716 struct subtlv stlv;
717
718 if (pw_len < sizeof(stlv)) {
719 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
720 msg->type);
721 return (-1);
722 }
723
724 memcpy(&stlv, buf + off, sizeof(stlv));
725 if (stlv.length > pw_len) {
726 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
727 msg->type);
728 return (-1);
729 }
730
731 switch (stlv.type) {
732 case SUBTLV_IFMTU:
733 if (stlv.length != FEC_SUBTLV_IFMTU_SIZE) {
734 session_shutdown(nbr, S_BAD_TLV_LEN,
735 msg->id, msg->type);
736 return (-1);
737 }
738 memcpy(&map->fec.pwid.ifmtu, buf + off +
739 SUBTLV_HDR_SIZE, sizeof(uint16_t));
740 map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu);
741 map->flags |= F_MAP_PW_IFMTU;
742 break;
743 default:
744 /* ignore */
745 break;
746 }
747 off += stlv.length;
748 pw_len -= stlv.length;
749 }
750
751 return (off);
752 default:
adbdf465 753 send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
8429abe0
RW
754 break;
755 }
756
757 return (-1);
758}
faf75793
RW
759
760static void
761log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
762{
763 debug_msg(out, "%s: lsr-id %s, fec %s, label %s", msg_name(msg_type),
764 inet_ntoa(nbr->id), log_map(map), log_label(map->label));
765}