]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/labelmapping.c
ldpd: implement RFC 5561 (LDP Capabilities)
[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 *, struct ibuf *, uint16_t);
30 static int gen_label_tlv(struct ibuf *, uint32_t);
31 static int tlv_decode_label(struct nbr *, struct ldp_msg *, char *,
32 uint16_t, uint32_t *);
33 static int gen_reqid_tlv(struct ibuf *, uint32_t);
34 static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
35
36 static void
37 enqueue_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 */
47 void
48 send_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
128 log_msg_mapping(1, type, nbr, &me->map);
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 */
140 int
141 recv_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) {
165 send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
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) {
189 send_notification(nbr->tcp, S_MISS_MSG, msg.id,
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_type;
242 uint16_t tlv_len;
243 uint32_t reqbuf, labelbuf, statusbuf;
244
245 if (len < sizeof(tlv)) {
246 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
247 goto err;
248 }
249
250 memcpy(&tlv, buf, TLV_HDR_SIZE);
251 tlv_type = ntohs(tlv.type);
252 tlv_len = ntohs(tlv.length);
253 if (tlv_len + TLV_HDR_SIZE > len) {
254 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
255 goto err;
256 }
257 buf += TLV_HDR_SIZE;
258 len -= TLV_HDR_SIZE;
259
260 switch (tlv_type) {
261 case TLV_TYPE_LABELREQUEST:
262 switch (type) {
263 case MSG_TYPE_LABELMAPPING:
264 case MSG_TYPE_LABELREQUEST:
265 if (tlv_len != REQID_TLV_LEN) {
266 session_shutdown(nbr, S_BAD_TLV_LEN,
267 msg.id, msg.type);
268 goto err;
269 }
270
271 flags |= F_MAP_REQ_ID;
272 memcpy(&reqbuf, buf, sizeof(reqbuf));
273 reqid = ntohl(reqbuf);
274 break;
275 default:
276 /* ignore */
277 break;
278 }
279 break;
280 case TLV_TYPE_HOPCOUNT:
281 case TLV_TYPE_PATHVECTOR:
282 /* ignore */
283 break;
284 case TLV_TYPE_GENERICLABEL:
285 switch (type) {
286 case MSG_TYPE_LABELWITHDRAW:
287 case MSG_TYPE_LABELRELEASE:
288 if (tlv_len != LABEL_TLV_LEN) {
289 session_shutdown(nbr, S_BAD_TLV_LEN,
290 msg.id, msg.type);
291 goto err;
292 }
293
294 memcpy(&labelbuf, buf, sizeof(labelbuf));
295 label = ntohl(labelbuf);
296 break;
297 default:
298 /* ignore */
299 break;
300 }
301 break;
302 case TLV_TYPE_ATMLABEL:
303 case TLV_TYPE_FRLABEL:
304 switch (type) {
305 case MSG_TYPE_LABELWITHDRAW:
306 case MSG_TYPE_LABELRELEASE:
307 /* unsupported */
308 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
309 msg.type);
310 goto err;
311 break;
312 default:
313 /* ignore */
314 break;
315 }
316 break;
317 case TLV_TYPE_STATUS:
318 if (tlv_len != STATUS_TLV_LEN) {
319 session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
320 msg.type);
321 goto err;
322 }
323 /* ignore */
324 break;
325 case TLV_TYPE_PW_STATUS:
326 switch (type) {
327 case MSG_TYPE_LABELMAPPING:
328 if (tlv_len != PW_STATUS_TLV_LEN) {
329 session_shutdown(nbr, S_BAD_TLV_LEN,
330 msg.id, msg.type);
331 goto err;
332 }
333
334 flags |= F_MAP_PW_STATUS;
335 memcpy(&statusbuf, buf, sizeof(statusbuf));
336 pw_status = ntohl(statusbuf);
337 break;
338 default:
339 /* ignore */
340 break;
341 }
342 break;
343 default:
344 if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
345 send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
346 msg.id, msg.type, tlv_type, tlv_len, buf);
347 /* ignore unknown tlv */
348 break;
349 }
350 buf += tlv_len;
351 len -= tlv_len;
352 }
353
354 /* notify lde about the received message. */
355 while ((me = TAILQ_FIRST(&mh)) != NULL) {
356 int imsg_type = IMSG_NONE;
357
358 me->map.flags |= flags;
359 switch (me->map.type) {
360 case MAP_TYPE_PREFIX:
361 switch (me->map.fec.prefix.af) {
362 case AF_INET:
363 if (label == MPLS_LABEL_IPV6NULL) {
364 session_shutdown(nbr, S_BAD_TLV_VAL,
365 msg.id, msg.type);
366 goto err;
367 }
368 if (!nbr->v4_enabled)
369 goto next;
370 break;
371 case AF_INET6:
372 if (label == MPLS_LABEL_IPV4NULL) {
373 session_shutdown(nbr, S_BAD_TLV_VAL,
374 msg.id, msg.type);
375 goto err;
376 }
377 if (!nbr->v6_enabled)
378 goto next;
379 break;
380 default:
381 fatalx("recv_labelmessage: unknown af");
382 }
383 break;
384 case MAP_TYPE_PWID:
385 if (label <= MPLS_LABEL_RESERVED_MAX) {
386 session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
387 msg.type);
388 goto err;
389 }
390 if (me->map.flags & F_MAP_PW_STATUS)
391 me->map.pw_status = pw_status;
392 break;
393 default:
394 break;
395 }
396 me->map.label = label;
397 if (me->map.flags & F_MAP_REQ_ID)
398 me->map.requestid = reqid;
399
400 log_msg_mapping(0, type, nbr, &me->map);
401
402 switch (type) {
403 case MSG_TYPE_LABELMAPPING:
404 imsg_type = IMSG_LABEL_MAPPING;
405 break;
406 case MSG_TYPE_LABELREQUEST:
407 imsg_type = IMSG_LABEL_REQUEST;
408 break;
409 case MSG_TYPE_LABELWITHDRAW:
410 imsg_type = IMSG_LABEL_WITHDRAW;
411 break;
412 case MSG_TYPE_LABELRELEASE:
413 imsg_type = IMSG_LABEL_RELEASE;
414 break;
415 case MSG_TYPE_LABELABORTREQ:
416 imsg_type = IMSG_LABEL_ABORT;
417 break;
418 default:
419 break;
420 }
421
422 ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
423 sizeof(struct map));
424
425 next:
426 TAILQ_REMOVE(&mh, me, entry);
427 free(me);
428 }
429
430 return (0);
431
432 err:
433 mapping_list_clr(&mh);
434
435 return (-1);
436 }
437
438 /* Other TLV related functions */
439 static int
440 gen_label_tlv(struct ibuf *buf, uint32_t label)
441 {
442 struct label_tlv lt;
443
444 lt.type = htons(TLV_TYPE_GENERICLABEL);
445 lt.length = htons(LABEL_TLV_LEN);
446 lt.label = htonl(label);
447
448 return (ibuf_add(buf, &lt, sizeof(lt)));
449 }
450
451 static int
452 tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf,
453 uint16_t len, uint32_t *label)
454 {
455 struct label_tlv lt;
456
457 if (len < sizeof(lt)) {
458 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type);
459 return (-1);
460 }
461 memcpy(&lt, buf, sizeof(lt));
462
463 if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) {
464 send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type);
465 return (-1);
466 }
467
468 switch (htons(lt.type)) {
469 case TLV_TYPE_GENERICLABEL:
470 if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) {
471 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
472 msg->type);
473 return (-1);
474 }
475
476 *label = ntohl(lt.label);
477 if (*label > MPLS_LABEL_MAX ||
478 (*label <= MPLS_LABEL_RESERVED_MAX &&
479 *label != MPLS_LABEL_IPV4NULL &&
480 *label != MPLS_LABEL_IPV6NULL &&
481 *label != MPLS_LABEL_IMPLNULL)) {
482 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
483 msg->type);
484 return (-1);
485 }
486 break;
487 case TLV_TYPE_ATMLABEL:
488 case TLV_TYPE_FRLABEL:
489 default:
490 /* unsupported */
491 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type);
492 return (-1);
493 }
494
495 return (sizeof(lt));
496 }
497
498 static int
499 gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
500 {
501 struct reqid_tlv rt;
502
503 rt.type = htons(TLV_TYPE_LABELREQUEST);
504 rt.length = htons(REQID_TLV_LEN);
505 rt.reqid = htonl(reqid);
506
507 return (ibuf_add(buf, &rt, sizeof(rt)));
508 }
509
510 int
511 gen_pw_status_tlv(struct ibuf *buf, uint32_t status)
512 {
513 struct pw_status_tlv st;
514
515 st.type = htons(TLV_TYPE_PW_STATUS);
516 st.length = htons(PW_STATUS_TLV_LEN);
517 st.value = htonl(status);
518
519 return (ibuf_add(buf, &st, sizeof(st)));
520 }
521
522 int
523 gen_fec_tlv(struct ibuf *buf, struct map *map)
524 {
525 struct tlv ft;
526 uint16_t family, len, pw_type, ifmtu;
527 uint8_t pw_len = 0;
528 uint32_t group_id, pwid;
529 int err = 0;
530
531 ft.type = htons(TLV_TYPE_FEC);
532
533 switch (map->type) {
534 case MAP_TYPE_WILDCARD:
535 ft.length = htons(sizeof(uint8_t));
536 err |= ibuf_add(buf, &ft, sizeof(ft));
537 err |= ibuf_add(buf, &map->type, sizeof(map->type));
538 break;
539 case MAP_TYPE_PREFIX:
540 len = PREFIX_SIZE(map->fec.prefix.prefixlen);
541 ft.length = htons(sizeof(map->type) + sizeof(family) +
542 sizeof(map->fec.prefix.prefixlen) + len);
543 err |= ibuf_add(buf, &ft, sizeof(ft));
544 err |= ibuf_add(buf, &map->type, sizeof(map->type));
545 switch (map->fec.prefix.af) {
546 case AF_INET:
547 family = htons(AF_IPV4);
548 break;
549 case AF_INET6:
550 family = htons(AF_IPV6);
551 break;
552 default:
553 fatalx("gen_fec_tlv: unknown af");
554 break;
555 }
556 err |= ibuf_add(buf, &family, sizeof(family));
557 err |= ibuf_add(buf, &map->fec.prefix.prefixlen,
558 sizeof(map->fec.prefix.prefixlen));
559 if (len)
560 err |= ibuf_add(buf, &map->fec.prefix.prefix, len);
561 break;
562 case MAP_TYPE_PWID:
563 if (map->flags & F_MAP_PW_ID)
564 pw_len += FEC_PWID_SIZE;
565 if (map->flags & F_MAP_PW_IFMTU)
566 pw_len += FEC_SUBTLV_IFMTU_SIZE;
567
568 len = FEC_PWID_ELM_MIN_LEN + pw_len;
569
570 ft.length = htons(len);
571 err |= ibuf_add(buf, &ft, sizeof(ft));
572
573 err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
574 pw_type = map->fec.pwid.type;
575 if (map->flags & F_MAP_PW_CWORD)
576 pw_type |= CONTROL_WORD_FLAG;
577 pw_type = htons(pw_type);
578 err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
579 err |= ibuf_add(buf, &pw_len, sizeof(uint8_t));
580 group_id = htonl(map->fec.pwid.group_id);
581 err |= ibuf_add(buf, &group_id, sizeof(uint32_t));
582 if (map->flags & F_MAP_PW_ID) {
583 pwid = htonl(map->fec.pwid.pwid);
584 err |= ibuf_add(buf, &pwid, sizeof(uint32_t));
585 }
586 if (map->flags & F_MAP_PW_IFMTU) {
587 struct subtlv stlv;
588
589 stlv.type = SUBTLV_IFMTU;
590 stlv.length = FEC_SUBTLV_IFMTU_SIZE;
591 err |= ibuf_add(buf, &stlv, sizeof(uint16_t));
592
593 ifmtu = htons(map->fec.pwid.ifmtu);
594 err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t));
595 }
596 break;
597 default:
598 break;
599 }
600
601 return (err);
602 }
603
604 int
605 tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
606 uint16_t len, struct map *map)
607 {
608 uint16_t off = 0;
609 uint8_t pw_len;
610
611 map->type = *buf;
612 off += sizeof(uint8_t);
613
614 switch (map->type) {
615 case MAP_TYPE_WILDCARD:
616 if (len == FEC_ELM_WCARD_LEN)
617 return (off);
618 else {
619 session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
620 msg->type);
621 return (-1);
622 }
623 break;
624 case MAP_TYPE_PREFIX:
625 if (len < FEC_ELM_PREFIX_MIN_LEN) {
626 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
627 msg->type);
628 return (-1);
629 }
630
631 /* Address Family */
632 memcpy(&map->fec.prefix.af, buf + off,
633 sizeof(map->fec.prefix.af));
634 off += sizeof(map->fec.prefix.af);
635 map->fec.prefix.af = ntohs(map->fec.prefix.af);
636 switch (map->fec.prefix.af) {
637 case AF_IPV4:
638 map->fec.prefix.af = AF_INET;
639 break;
640 case AF_IPV6:
641 map->fec.prefix.af = AF_INET6;
642 break;
643 default:
644 send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
645 msg->type);
646 return (-1);
647 }
648
649 /* Prefix Length */
650 map->fec.prefix.prefixlen = buf[off];
651 off += sizeof(uint8_t);
652 if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) {
653 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
654 msg->type);
655 return (-1);
656 }
657
658 /* Prefix */
659 memset(&map->fec.prefix.prefix, 0,
660 sizeof(map->fec.prefix.prefix));
661 memcpy(&map->fec.prefix.prefix, buf + off,
662 PREFIX_SIZE(map->fec.prefix.prefixlen));
663
664 /* Just in case... */
665 ldp_applymask(map->fec.prefix.af, &map->fec.prefix.prefix,
666 &map->fec.prefix.prefix, map->fec.prefix.prefixlen);
667
668 return (off + PREFIX_SIZE(map->fec.prefix.prefixlen));
669 case MAP_TYPE_PWID:
670 if (len < FEC_PWID_ELM_MIN_LEN) {
671 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
672 msg->type);
673 return (-1);
674 }
675
676 /* PW type */
677 memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t));
678 map->fec.pwid.type = ntohs(map->fec.pwid.type);
679 if (map->fec.pwid.type & CONTROL_WORD_FLAG) {
680 map->flags |= F_MAP_PW_CWORD;
681 map->fec.pwid.type &= ~CONTROL_WORD_FLAG;
682 }
683 off += sizeof(uint16_t);
684
685 /* PW info Length */
686 pw_len = buf[off];
687 off += sizeof(uint8_t);
688
689 if (len != FEC_PWID_ELM_MIN_LEN + pw_len) {
690 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
691 msg->type);
692 return (-1);
693 }
694
695 /* Group ID */
696 memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t));
697 map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id);
698 off += sizeof(uint32_t);
699
700 /* PW ID */
701 if (pw_len == 0)
702 return (off);
703
704 if (pw_len < sizeof(uint32_t)) {
705 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
706 msg->type);
707 return (-1);
708 }
709
710 memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t));
711 map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid);
712 map->flags |= F_MAP_PW_ID;
713 off += sizeof(uint32_t);
714 pw_len -= sizeof(uint32_t);
715
716 /* Optional Interface Parameter Sub-TLVs */
717 while (pw_len > 0) {
718 struct subtlv stlv;
719
720 if (pw_len < sizeof(stlv)) {
721 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
722 msg->type);
723 return (-1);
724 }
725
726 memcpy(&stlv, buf + off, sizeof(stlv));
727 if (stlv.length > pw_len) {
728 session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
729 msg->type);
730 return (-1);
731 }
732
733 switch (stlv.type) {
734 case SUBTLV_IFMTU:
735 if (stlv.length != FEC_SUBTLV_IFMTU_SIZE) {
736 session_shutdown(nbr, S_BAD_TLV_LEN,
737 msg->id, msg->type);
738 return (-1);
739 }
740 memcpy(&map->fec.pwid.ifmtu, buf + off +
741 SUBTLV_HDR_SIZE, sizeof(uint16_t));
742 map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu);
743 map->flags |= F_MAP_PW_IFMTU;
744 break;
745 default:
746 /* ignore */
747 break;
748 }
749 off += stlv.length;
750 pw_len -= stlv.length;
751 }
752
753 return (off);
754 default:
755 send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
756 break;
757 }
758
759 return (-1);
760 }
761
762 static void
763 log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
764 {
765 debug_msg(out, "%s: lsr-id %s, fec %s, label %s", msg_name(msg_type),
766 inet_ntoa(nbr->id), log_map(map), log_label(map->label));
767 }