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