xref: /openbsd/usr.sbin/ldpd/labelmapping.c (revision 297a8bbe)
1 /*	$OpenBSD: labelmapping.c,v 1.64 2017/03/03 23:50:45 renato Exp $ */
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 <sys/types.h>
21 #include <sys/socket.h>
22 #include <arpa/inet.h>
23 #include <netmpls/mpls.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "ldpd.h"
29 #include "ldpe.h"
30 #include "log.h"
31 
32 static void	 enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
33 static int	 gen_label_tlv(struct ibuf *, uint32_t);
34 static int	 tlv_decode_label(struct nbr *, struct ldp_msg *, char *,
35 		    uint16_t, uint32_t *);
36 static int	 gen_reqid_tlv(struct ibuf *, uint32_t);
37 static void	 log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
38 
39 static void
40 enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size)
41 {
42 	struct ldp_hdr		*ldp_hdr;
43 
44 	ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr));
45 	ldp_hdr->length = htons(size);
46 	evbuf_enqueue(&nbr->tcp->wbuf, buf);
47 }
48 
49 /* Generic function that handles all Label Message types */
50 void
51 send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
52 {
53 	struct ibuf		*buf = NULL;
54 	struct mapping_entry	*me;
55 	uint16_t		 msg_size, size = 0;
56 	int			 first = 1;
57 	int			 err = 0;
58 
59 	/* nothing to send */
60 	if (TAILQ_EMPTY(mh))
61 		return;
62 
63 	while ((me = TAILQ_FIRST(mh)) != NULL) {
64 		/* generate pdu */
65 		if (first) {
66 			if ((buf = ibuf_open(nbr->max_pdu_len +
67 			    LDP_HDR_DEAD_LEN)) == NULL)
68 				fatal(__func__);
69 
70 			/* real size will be set up later */
71 			err |= gen_ldp_hdr(buf, 0);
72 
73 			size = LDP_HDR_PDU_LEN;
74 			first = 0;
75 		}
76 
77 		/* calculate size */
78 		msg_size = LDP_MSG_SIZE + TLV_HDR_SIZE;
79 		switch (me->map.type) {
80 		case MAP_TYPE_WILDCARD:
81 			msg_size += FEC_ELM_WCARD_LEN;
82 			break;
83 		case MAP_TYPE_PREFIX:
84 			msg_size += FEC_ELM_PREFIX_MIN_LEN +
85 			    PREFIX_SIZE(me->map.fec.prefix.prefixlen);
86 			break;
87 		case MAP_TYPE_PWID:
88 			msg_size += FEC_PWID_ELM_MIN_LEN;
89 			if (me->map.flags & F_MAP_PW_ID)
90 				msg_size += PW_STATUS_TLV_LEN;
91 			if (me->map.flags & F_MAP_PW_IFMTU)
92 				msg_size += FEC_SUBTLV_IFMTU_SIZE;
93 	    		if (me->map.flags & F_MAP_PW_STATUS)
94 				msg_size += PW_STATUS_TLV_SIZE;
95 			break;
96 		}
97 		if (me->map.label != NO_LABEL)
98 			msg_size += LABEL_TLV_SIZE;
99 		if (me->map.flags & F_MAP_REQ_ID)
100 			msg_size += REQID_TLV_SIZE;
101 		if (me->map.flags & F_MAP_STATUS)
102 			msg_size += STATUS_SIZE;
103 
104 		/* maximum pdu length exceeded, we need a new ldp pdu */
105 		if (size + msg_size > nbr->max_pdu_len) {
106 			enqueue_pdu(nbr, buf, size);
107 			first = 1;
108 			continue;
109 		}
110 
111 		size += msg_size;
112 
113 		/* append message and tlvs */
114 		err |= gen_msg_hdr(buf, type, msg_size);
115 		err |= gen_fec_tlv(buf, &me->map);
116 		if (me->map.label != NO_LABEL)
117 			err |= gen_label_tlv(buf, me->map.label);
118 		if (me->map.flags & F_MAP_REQ_ID)
119 			err |= gen_reqid_tlv(buf, me->map.requestid);
120 	    	if (me->map.flags & F_MAP_PW_STATUS)
121 			err |= gen_pw_status_tlv(buf, me->map.pw_status);
122 		if (me->map.flags & F_MAP_STATUS)
123 			err |= gen_status_tlv(buf, me->map.st.status_code,
124 			    me->map.st.msg_id, me->map.st.msg_type);
125 		if (err) {
126 			ibuf_free(buf);
127 			mapping_list_clr(mh);
128 			return;
129 		}
130 
131 		log_msg_mapping(1, type, nbr, &me->map);
132 
133 		TAILQ_REMOVE(mh, me, entry);
134 		free(me);
135 	}
136 
137 	enqueue_pdu(nbr, 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, lbllen, tlen;
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 			return (-1);
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 		 * LDP supports the use of multiple FEC Elements per
216 		 * FEC for the Label Mapping message only.
217 		 */
218 		if (type != MSG_TYPE_LABELMAPPING &&
219 		    tlen != feclen) {
220 			session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
221 			goto err;
222 		}
223 
224 		mapping_list_add(&mh, &map);
225 
226 		buf += tlen;
227 		len -= tlen;
228 		feclen -= tlen;
229 	} while (feclen > 0);
230 
231 	/* Mandatory Label TLV */
232 	if (type == MSG_TYPE_LABELMAPPING) {
233 		lbllen = tlv_decode_label(nbr, &msg, buf, len, &label);
234 		if (lbllen == -1)
235 			goto err;
236 
237 		buf += lbllen;
238 		len -= lbllen;
239 	}
240 
241 	/* Optional Parameters */
242 	while (len > 0) {
243 		struct tlv 	tlv;
244 		uint16_t	tlv_len;
245 		uint32_t	reqbuf, labelbuf, statusbuf;
246 
247 		if (len < sizeof(tlv)) {
248 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
249 			goto err;
250 		}
251 
252 		memcpy(&tlv, buf, TLV_HDR_SIZE);
253 		tlv_len = ntohs(tlv.length);
254 		if (tlv_len + TLV_HDR_SIZE > len) {
255 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
256 			goto err;
257 		}
258 		buf += TLV_HDR_SIZE;
259 		len -= TLV_HDR_SIZE;
260 
261 		switch (ntohs(tlv.type)) {
262 		case TLV_TYPE_LABELREQUEST:
263 			switch (type) {
264 			case MSG_TYPE_LABELMAPPING:
265 			case MSG_TYPE_LABELREQUEST:
266 				if (tlv_len != REQID_TLV_LEN) {
267 					session_shutdown(nbr, S_BAD_TLV_LEN,
268 					    msg.id, msg.type);
269 					goto err;
270 				}
271 
272 				flags |= F_MAP_REQ_ID;
273 				memcpy(&reqbuf, buf, sizeof(reqbuf));
274 				reqid = ntohl(reqbuf);
275 				break;
276 			default:
277 				/* ignore */
278 				break;
279 			}
280 			break;
281 		case TLV_TYPE_HOPCOUNT:
282 		case TLV_TYPE_PATHVECTOR:
283 			/* ignore */
284 			break;
285 		case TLV_TYPE_GENERICLABEL:
286 			switch (type) {
287 			case MSG_TYPE_LABELWITHDRAW:
288 			case MSG_TYPE_LABELRELEASE:
289 				if (tlv_len != LABEL_TLV_LEN) {
290 					session_shutdown(nbr, S_BAD_TLV_LEN,
291 					    msg.id, msg.type);
292 					goto err;
293 				}
294 
295 				memcpy(&labelbuf, buf, sizeof(labelbuf));
296 				label = ntohl(labelbuf);
297 				break;
298 			default:
299 				/* ignore */
300 				break;
301 			}
302 			break;
303 		case TLV_TYPE_ATMLABEL:
304 		case TLV_TYPE_FRLABEL:
305 			switch (type) {
306 			case MSG_TYPE_LABELWITHDRAW:
307 			case MSG_TYPE_LABELRELEASE:
308 				/* unsupported */
309 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
310 				    msg.type);
311 				goto err;
312 				break;
313 			default:
314 				/* ignore */
315 				break;
316 			}
317 			break;
318 		case TLV_TYPE_STATUS:
319 			if (tlv_len != STATUS_TLV_LEN) {
320 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
321 				    msg.type);
322 				goto err;
323 			}
324 			/* ignore */
325 			break;
326 		case TLV_TYPE_PW_STATUS:
327 			switch (type) {
328 			case MSG_TYPE_LABELMAPPING:
329 				if (tlv_len != PW_STATUS_TLV_LEN) {
330 					session_shutdown(nbr, S_BAD_TLV_LEN,
331 					    msg.id, msg.type);
332 					goto err;
333 				}
334 
335 				flags |= F_MAP_PW_STATUS;
336 				memcpy(&statusbuf, buf, sizeof(statusbuf));
337 				pw_status = ntohl(statusbuf);
338 				break;
339 			default:
340 				/* ignore */
341 				break;
342 			}
343 			break;
344 		default:
345 			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
346 				send_notification(nbr->tcp, S_UNKNOWN_TLV,
347 				    msg.id, msg.type);
348 			/* ignore unknown tlv */
349 			break;
350 		}
351 		buf += tlv_len;
352 		len -= tlv_len;
353 	}
354 
355 	/* notify lde about the received message. */
356 	while ((me = TAILQ_FIRST(&mh)) != NULL) {
357 		int imsg_type = IMSG_NONE;
358 
359 		me->map.flags |= flags;
360 		switch (me->map.type) {
361 		case MAP_TYPE_PREFIX:
362 			switch (me->map.fec.prefix.af) {
363 			case AF_INET:
364 				if (label == MPLS_LABEL_IPV6NULL) {
365 					session_shutdown(nbr, S_BAD_TLV_VAL,
366 					    msg.id, msg.type);
367 					goto err;
368 				}
369 				if (!nbr->v4_enabled)
370 					goto next;
371 				break;
372 			case AF_INET6:
373 				if (label == MPLS_LABEL_IPV4NULL) {
374 					session_shutdown(nbr, S_BAD_TLV_VAL,
375 					    msg.id, msg.type);
376 					goto err;
377 				}
378 				if (!nbr->v6_enabled)
379 					goto next;
380 				break;
381 			default:
382 				fatalx("recv_labelmessage: unknown af");
383 			}
384 			break;
385 		case MAP_TYPE_PWID:
386 			if (label <= MPLS_LABEL_RESERVED_MAX) {
387 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
388 				    msg.type);
389 				goto err;
390 			}
391 			if (me->map.flags & F_MAP_PW_STATUS)
392 				me->map.pw_status = pw_status;
393 			break;
394 		default:
395 			break;
396 		}
397 		me->map.label = label;
398 		if (me->map.flags & F_MAP_REQ_ID)
399 			me->map.requestid = reqid;
400 
401 		log_msg_mapping(0, type, nbr, &me->map);
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->tcp, 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 += FEC_PWID_SIZE;
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->tcp, 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->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
757 		break;
758 	}
759 
760 	return (-1);
761 }
762 
763 static void
764 log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
765 {
766 	log_debug("msg-%s: %s: lsr-id %s, fec %s, label %s",
767 	    (out) ? "out" : "in", msg_name(msg_type), inet_ntoa(nbr->id),
768 	    log_map(map), log_label(map->label));
769 }
770