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