xref: /openbsd-src/usr.sbin/ldpd/labelmapping.c (revision 8bc5e3a3aaccee091c0a327f1a8daa3593d0f628)
1*8bc5e3a3Sclaudio /*	$OpenBSD: labelmapping.c,v 1.69 2023/07/03 11:51:27 claudio Exp $ */
2ab0c2486Smichele 
3ab0c2486Smichele /*
45dc9330aSrenato  * Copyright (c) 2014, 2015 Renato Westphal <renato@openbsd.org>
5ab0c2486Smichele  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
6ab0c2486Smichele  *
7ab0c2486Smichele  * Permission to use, copy, modify, and distribute this software for any
8ab0c2486Smichele  * purpose with or without fee is hereby granted, provided that the above
9ab0c2486Smichele  * copyright notice and this permission notice appear in all copies.
10ab0c2486Smichele  *
11ab0c2486Smichele  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12ab0c2486Smichele  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13ab0c2486Smichele  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14ab0c2486Smichele  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15ab0c2486Smichele  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16ab0c2486Smichele  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17ab0c2486Smichele  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18ab0c2486Smichele  */
19ab0c2486Smichele 
20ab0c2486Smichele #include <sys/types.h>
21ab0c2486Smichele #include <sys/socket.h>
22ab0c2486Smichele #include <arpa/inet.h>
2335791d36Srenato #include <netmpls/mpls.h>
24b2cd1366Sguenther #include <limits.h>
25*8bc5e3a3Sclaudio #include <stddef.h>
26ab0c2486Smichele #include <stdlib.h>
27ab0c2486Smichele #include <string.h>
28ab0c2486Smichele 
29ab0c2486Smichele #include "ldpd.h"
30ab0c2486Smichele #include "ldpe.h"
315411bbb6Srenato #include "log.h"
32ab0c2486Smichele 
33c28a25a1Srenato static void	 enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
3465f1d9c1Srenato static int	 gen_label_tlv(struct ibuf *, uint32_t);
35c28a25a1Srenato static int	 tlv_decode_label(struct nbr *, struct ldp_msg *, char *,
36c28a25a1Srenato 		    uint16_t, uint32_t *);
3765f1d9c1Srenato static int	 gen_reqid_tlv(struct ibuf *, uint32_t);
38297a8bbeSrenato static void	 log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
39ab0c2486Smichele 
40bb21b33cSrenato static void
enqueue_pdu(struct nbr * nbr,struct ibuf * buf,uint16_t size)413de94509Srenato enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size)
42ab0c2486Smichele {
43*8bc5e3a3Sclaudio 	if (ibuf_set_n16(buf, offsetof(struct ldp_hdr, length), size) == -1)
44*8bc5e3a3Sclaudio 		fatal(__func__);
45bb21b33cSrenato 	evbuf_enqueue(&nbr->tcp->wbuf, buf);
46bb21b33cSrenato }
47bb21b33cSrenato 
48bb21b33cSrenato /* Generic function that handles all Label Message types */
49bb21b33cSrenato void
send_labelmessage(struct nbr * nbr,uint16_t type,struct mapping_head * mh)503de94509Srenato send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
51bb21b33cSrenato {
52bb21b33cSrenato 	struct ibuf		*buf = NULL;
53bb21b33cSrenato 	struct mapping_entry	*me;
543de94509Srenato 	uint16_t		 msg_size, size = 0;
55bb21b33cSrenato 	int			 first = 1;
5665f1d9c1Srenato 	int			 err = 0;
57bb21b33cSrenato 
5834f55a3fSrenato 	/* nothing to send */
5934f55a3fSrenato 	if (TAILQ_EMPTY(mh))
6034f55a3fSrenato 		return;
6134f55a3fSrenato 
62bb21b33cSrenato 	while ((me = TAILQ_FIRST(mh)) != NULL) {
63bb21b33cSrenato 		/* generate pdu */
64bb21b33cSrenato 		if (first) {
653de94509Srenato 			if ((buf = ibuf_open(nbr->max_pdu_len +
663de94509Srenato 			    LDP_HDR_DEAD_LEN)) == NULL)
67b7b4db73Srenato 				fatal(__func__);
68ab0c2486Smichele 
69ab0c2486Smichele 			/* real size will be set up later */
7065f1d9c1Srenato 			err |= gen_ldp_hdr(buf, 0);
71ab0c2486Smichele 
72bb21b33cSrenato 			size = LDP_HDR_PDU_LEN;
73bb21b33cSrenato 			first = 0;
74bb21b33cSrenato 		}
75ab0c2486Smichele 
76bb21b33cSrenato 		/* calculate size */
779246985aSrenato 		msg_size = LDP_MSG_SIZE;
789246985aSrenato 		msg_size += len_fec_tlv(&me->map);
79cf483f25Srenato 		if (me->map.label != NO_LABEL)
8060e1e0e7Srenato 			msg_size += LABEL_TLV_SIZE;
813220fd77Sclaudio 		if (me->map.flags & F_MAP_REQ_ID)
8260e1e0e7Srenato 			msg_size += REQID_TLV_SIZE;
835ba85977Srenato 		if (me->map.flags & F_MAP_STATUS)
845ba85977Srenato 			msg_size += STATUS_SIZE;
85bb21b33cSrenato 
86bb21b33cSrenato 		/* maximum pdu length exceeded, we need a new ldp pdu */
873de94509Srenato 		if (size + msg_size > nbr->max_pdu_len) {
88bb21b33cSrenato 			enqueue_pdu(nbr, buf, size);
89bb21b33cSrenato 			first = 1;
90bb21b33cSrenato 			continue;
91bb21b33cSrenato 		}
92bb21b33cSrenato 
933de94509Srenato 		size += msg_size;
94ab0c2486Smichele 
95bb21b33cSrenato 		/* append message and tlvs */
9665f1d9c1Srenato 		err |= gen_msg_hdr(buf, type, msg_size);
9765f1d9c1Srenato 		err |= gen_fec_tlv(buf, &me->map);
98cf483f25Srenato 		if (me->map.label != NO_LABEL)
9965f1d9c1Srenato 			err |= gen_label_tlv(buf, me->map.label);
1003220fd77Sclaudio 		if (me->map.flags & F_MAP_REQ_ID)
10165f1d9c1Srenato 			err |= gen_reqid_tlv(buf, me->map.requestid);
1026399cec1Srenato 	    	if (me->map.flags & F_MAP_PW_STATUS)
10365f1d9c1Srenato 			err |= gen_pw_status_tlv(buf, me->map.pw_status);
1045ba85977Srenato 		if (me->map.flags & F_MAP_STATUS)
10560e1e0e7Srenato 			err |= gen_status_tlv(buf, me->map.st.status_code,
10660e1e0e7Srenato 			    me->map.st.msg_id, me->map.st.msg_type);
10765f1d9c1Srenato 		if (err) {
10865f1d9c1Srenato 			ibuf_free(buf);
1092163d027Srenato 			mapping_list_clr(mh);
11065f1d9c1Srenato 			return;
11165f1d9c1Srenato 		}
112bb21b33cSrenato 
113297a8bbeSrenato 		log_msg_mapping(1, type, nbr, &me->map);
114c0cfacb4Srenato 
115bb21b33cSrenato 		TAILQ_REMOVE(mh, me, entry);
116bb21b33cSrenato 		free(me);
117ab0c2486Smichele 	}
118ab0c2486Smichele 
119bb21b33cSrenato 	enqueue_pdu(nbr, buf, size);
120ab0c2486Smichele 
121b93f77ccSclaudio 	nbr_fsm(nbr, NBR_EVT_PDU_SENT);
122ab0c2486Smichele }
123ab0c2486Smichele 
124cf650e8bSrenato /* Generic function that handles all Label Message types */
125ab0c2486Smichele int
recv_labelmessage(struct nbr * nbr,char * buf,uint16_t len,uint16_t type)1263de94509Srenato recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
127ab0c2486Smichele {
12860e1e0e7Srenato 	struct ldp_msg		 msg;
12928970269Sclaudio 	struct tlv		 ft;
1303de94509Srenato 	uint32_t		 label = NO_LABEL, reqid = 0;
1313de94509Srenato 	uint32_t		 pw_status = 0;
1323de94509Srenato 	uint8_t			 flags = 0;
133cf650e8bSrenato 	int			 feclen, lbllen, tlen;
134cf650e8bSrenato 	struct mapping_entry	*me;
135cf650e8bSrenato 	struct mapping_head	 mh;
1368d99d653Srenato 	struct map		 map;
13789f23408Sclaudio 
13860e1e0e7Srenato 	memcpy(&msg, buf, sizeof(msg));
1393de94509Srenato 	buf += LDP_MSG_SIZE;
1403de94509Srenato 	len -= LDP_MSG_SIZE;
141ab0c2486Smichele 
142cf650e8bSrenato 	/* FEC TLV */
14389f23408Sclaudio 	if (len < sizeof(ft)) {
14460e1e0e7Srenato 		session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
14589f23408Sclaudio 		return (-1);
14689f23408Sclaudio 	}
14789f23408Sclaudio 
1483de94509Srenato 	memcpy(&ft, buf, sizeof(ft));
14935791d36Srenato 	if (ntohs(ft.type) != TLV_TYPE_FEC) {
1500101edf8Srenato 		send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
15135791d36Srenato 		return (-1);
15235791d36Srenato 	}
15389f23408Sclaudio 	feclen = ntohs(ft.length);
15460e1e0e7Srenato 	if (feclen > len - TLV_HDR_SIZE) {
15560e1e0e7Srenato 		session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
15689f23408Sclaudio 		return (-1);
15789f23408Sclaudio 	}
15889f23408Sclaudio 
15960e1e0e7Srenato 	buf += TLV_HDR_SIZE;	/* just advance to the end of the fec header */
16060e1e0e7Srenato 	len -= TLV_HDR_SIZE;
16189f23408Sclaudio 
162cf650e8bSrenato 	TAILQ_INIT(&mh);
16389f23408Sclaudio 	do {
1648d99d653Srenato 		memset(&map, 0, sizeof(map));
16560e1e0e7Srenato 		map.msg_id = msg.id;
166cf650e8bSrenato 
16760e1e0e7Srenato 		if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf, feclen,
1688d99d653Srenato 		    &map)) == -1)
169cf650e8bSrenato 			goto err;
170cf09440fSrenato 		if (map.type == MAP_TYPE_PWID &&
171912987a0Srenato 		    !(map.flags & F_MAP_PW_ID) &&
172912987a0Srenato 		    type != MSG_TYPE_LABELWITHDRAW &&
173912987a0Srenato 		    type != MSG_TYPE_LABELRELEASE) {
1740101edf8Srenato 			send_notification(nbr->tcp, S_MISS_MSG, msg.id,
17560e1e0e7Srenato 			    msg.type);
1766399cec1Srenato 			return (-1);
1776399cec1Srenato 		}
178cf650e8bSrenato 
179cf650e8bSrenato 		/*
180cf650e8bSrenato 		 * The Wildcard FEC Element can be used only in the
181cf650e8bSrenato 		 * Label Withdraw and Label Release messages.
182cf650e8bSrenato 		 */
183cf09440fSrenato 		if (map.type == MAP_TYPE_WILDCARD) {
184cf650e8bSrenato 			switch (type) {
1856399cec1Srenato 			case MSG_TYPE_LABELMAPPING:
1866399cec1Srenato 			case MSG_TYPE_LABELREQUEST:
1876399cec1Srenato 			case MSG_TYPE_LABELABORTREQ:
18860e1e0e7Srenato 				session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
18960e1e0e7Srenato 				    msg.type);
190cf650e8bSrenato 				goto err;
1916399cec1Srenato 			default:
192cf650e8bSrenato 				break;
193cf650e8bSrenato 			}
19489f23408Sclaudio 		}
19589f23408Sclaudio 
196cf650e8bSrenato 		/*
197c7c5a728Srenato 		 * RFC 5561 - Section 4:
198c7c5a728Srenato 		 * "An LDP implementation that supports the Typed Wildcard
199c7c5a728Srenato 		 * FEC Element MUST support its use in Label Request, Label
200c7c5a728Srenato 		 * Withdraw, and Label Release messages".
201c7c5a728Srenato 		 */
202c7c5a728Srenato 		if (map.type == MAP_TYPE_TYPED_WCARD) {
203c7c5a728Srenato 			switch (type) {
204c7c5a728Srenato 			case MSG_TYPE_LABELMAPPING:
205c7c5a728Srenato 			case MSG_TYPE_LABELABORTREQ:
206c7c5a728Srenato 				session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
207c7c5a728Srenato 				    msg.type);
208c7c5a728Srenato 				goto err;
209c7c5a728Srenato 			default:
210c7c5a728Srenato 				break;
211c7c5a728Srenato 			}
212c7c5a728Srenato 		}
213c7c5a728Srenato 
214c7c5a728Srenato 		/*
215cf650e8bSrenato 		 * LDP supports the use of multiple FEC Elements per
216cf650e8bSrenato 		 * FEC for the Label Mapping message only.
217cf650e8bSrenato 		 */
218cf650e8bSrenato 		if (type != MSG_TYPE_LABELMAPPING &&
219cf650e8bSrenato 		    tlen != feclen) {
22060e1e0e7Srenato 			session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
221cf650e8bSrenato 			goto err;
222cf650e8bSrenato 		}
22389f23408Sclaudio 
2248d99d653Srenato 		mapping_list_add(&mh, &map);
2258d99d653Srenato 
22689f23408Sclaudio 		buf += tlen;
227cf650e8bSrenato 		len -= tlen;
22889f23408Sclaudio 		feclen -= tlen;
22989f23408Sclaudio 	} while (feclen > 0);
23001302d08Sclaudio 
231cf650e8bSrenato 	/* Mandatory Label TLV */
232cf650e8bSrenato 	if (type == MSG_TYPE_LABELMAPPING) {
23360e1e0e7Srenato 		lbllen = tlv_decode_label(nbr, &msg, buf, len, &label);
234cf650e8bSrenato 		if (lbllen == -1)
235cf650e8bSrenato 			goto err;
236cf650e8bSrenato 
237cf650e8bSrenato 		buf += lbllen;
238cf650e8bSrenato 		len -= lbllen;
239cf650e8bSrenato 	}
240cf650e8bSrenato 
241cf650e8bSrenato 	/* Optional Parameters */
242cf650e8bSrenato 	while (len > 0) {
243cf650e8bSrenato 		struct tlv 	tlv;
2443b4c1866Srenato 		uint16_t	tlv_type;
2452c943183Srenato 		uint16_t	tlv_len;
2463de94509Srenato 		uint32_t	reqbuf, labelbuf, statusbuf;
247cf650e8bSrenato 
248cf650e8bSrenato 		if (len < sizeof(tlv)) {
24960e1e0e7Srenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
250cf650e8bSrenato 			goto err;
251cf650e8bSrenato 		}
252cf650e8bSrenato 
25360e1e0e7Srenato 		memcpy(&tlv, buf, TLV_HDR_SIZE);
2543b4c1866Srenato 		tlv_type = ntohs(tlv.type);
255a78ea73fSrenato 		tlv_len = ntohs(tlv.length);
256a78ea73fSrenato 		if (tlv_len + TLV_HDR_SIZE > len) {
257a78ea73fSrenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
258a78ea73fSrenato 			goto err;
259a78ea73fSrenato 		}
26060e1e0e7Srenato 		buf += TLV_HDR_SIZE;
26160e1e0e7Srenato 		len -= TLV_HDR_SIZE;
262cf650e8bSrenato 
2633b4c1866Srenato 		switch (tlv_type) {
264cf650e8bSrenato 		case TLV_TYPE_LABELREQUEST:
265cf650e8bSrenato 			switch (type) {
266cf650e8bSrenato 			case MSG_TYPE_LABELMAPPING:
267cf483f25Srenato 			case MSG_TYPE_LABELREQUEST:
26860e1e0e7Srenato 				if (tlv_len != REQID_TLV_LEN) {
269cf650e8bSrenato 					session_shutdown(nbr, S_BAD_TLV_LEN,
27060e1e0e7Srenato 					    msg.id, msg.type);
271cf650e8bSrenato 					goto err;
272cf650e8bSrenato 				}
273cf650e8bSrenato 
274cf650e8bSrenato 				flags |= F_MAP_REQ_ID;
27583a7713fSderaadt 				memcpy(&reqbuf, buf, sizeof(reqbuf));
27683a7713fSderaadt 				reqid = ntohl(reqbuf);
277cf650e8bSrenato 				break;
278cf650e8bSrenato 			default:
279cf650e8bSrenato 				/* ignore */
280cf650e8bSrenato 				break;
281cf650e8bSrenato 			}
282cf650e8bSrenato 			break;
2835953eecfSrenato 		case TLV_TYPE_HOPCOUNT:
2845953eecfSrenato 		case TLV_TYPE_PATHVECTOR:
2855953eecfSrenato 			/* ignore */
2865953eecfSrenato 			break;
287cf650e8bSrenato 		case TLV_TYPE_GENERICLABEL:
288cf650e8bSrenato 			switch (type) {
289cf650e8bSrenato 			case MSG_TYPE_LABELWITHDRAW:
290cf650e8bSrenato 			case MSG_TYPE_LABELRELEASE:
29160e1e0e7Srenato 				if (tlv_len != LABEL_TLV_LEN) {
292cf650e8bSrenato 					session_shutdown(nbr, S_BAD_TLV_LEN,
29360e1e0e7Srenato 					    msg.id, msg.type);
294cf650e8bSrenato 					goto err;
295cf650e8bSrenato 				}
296cf650e8bSrenato 
29783a7713fSderaadt 				memcpy(&labelbuf, buf, sizeof(labelbuf));
29883a7713fSderaadt 				label = ntohl(labelbuf);
299cf650e8bSrenato 				break;
300cf650e8bSrenato 			default:
301cf650e8bSrenato 				/* ignore */
302cf650e8bSrenato 				break;
303cf650e8bSrenato 			}
304cf650e8bSrenato 			break;
305cf650e8bSrenato 		case TLV_TYPE_ATMLABEL:
306cf650e8bSrenato 		case TLV_TYPE_FRLABEL:
307cf650e8bSrenato 			switch (type) {
308cf650e8bSrenato 			case MSG_TYPE_LABELWITHDRAW:
309cf650e8bSrenato 			case MSG_TYPE_LABELRELEASE:
310cf650e8bSrenato 				/* unsupported */
31160e1e0e7Srenato 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
31260e1e0e7Srenato 				    msg.type);
313cf650e8bSrenato 				goto err;
314cf650e8bSrenato 				break;
315cf650e8bSrenato 			default:
316cf650e8bSrenato 				/* ignore */
317cf650e8bSrenato 				break;
318cf650e8bSrenato 			}
319cf650e8bSrenato 			break;
3205ba85977Srenato 		case TLV_TYPE_STATUS:
3215ba85977Srenato 			if (tlv_len != STATUS_TLV_LEN) {
32260e1e0e7Srenato 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
32360e1e0e7Srenato 				    msg.type);
3245ba85977Srenato 				goto err;
3255ba85977Srenato 			}
3265ba85977Srenato 			/* ignore */
3275ba85977Srenato 			break;
3286399cec1Srenato 		case TLV_TYPE_PW_STATUS:
3296399cec1Srenato 			switch (type) {
3306399cec1Srenato 			case MSG_TYPE_LABELMAPPING:
33160e1e0e7Srenato 				if (tlv_len != PW_STATUS_TLV_LEN) {
3326399cec1Srenato 					session_shutdown(nbr, S_BAD_TLV_LEN,
33360e1e0e7Srenato 					    msg.id, msg.type);
3346399cec1Srenato 					goto err;
3356399cec1Srenato 				}
3366399cec1Srenato 
3376399cec1Srenato 				flags |= F_MAP_PW_STATUS;
3386399cec1Srenato 				memcpy(&statusbuf, buf, sizeof(statusbuf));
3396399cec1Srenato 				pw_status = ntohl(statusbuf);
3406399cec1Srenato 				break;
3416399cec1Srenato 			default:
3426399cec1Srenato 				/* ignore */
3436399cec1Srenato 				break;
3446399cec1Srenato 			}
3456399cec1Srenato 			break;
346cf650e8bSrenato 		default:
347a78ea73fSrenato 			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
3483b4c1866Srenato 				send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
3493b4c1866Srenato 				    msg.id, msg.type, tlv_type, tlv_len, buf);
350cf650e8bSrenato 			/* ignore unknown tlv */
351cf650e8bSrenato 			break;
352cf650e8bSrenato 		}
3532c943183Srenato 		buf += tlv_len;
3542c943183Srenato 		len -= tlv_len;
355cf650e8bSrenato 	}
356cf650e8bSrenato 
357cf650e8bSrenato 	/* notify lde about the received message. */
358cf650e8bSrenato 	while ((me = TAILQ_FIRST(&mh)) != NULL) {
359cf650e8bSrenato 		int imsg_type = IMSG_NONE;
360cf650e8bSrenato 
361cf650e8bSrenato 		me->map.flags |= flags;
362a8c39dc0Srenato 		switch (me->map.type) {
363a8c39dc0Srenato 		case MAP_TYPE_PREFIX:
364a8c39dc0Srenato 			switch (me->map.fec.prefix.af) {
36500f5e67fSrenato 			case AF_INET:
366a8c39dc0Srenato 				if (label == MPLS_LABEL_IPV6NULL) {
367a8c39dc0Srenato 					session_shutdown(nbr, S_BAD_TLV_VAL,
36860e1e0e7Srenato 					    msg.id, msg.type);
369a8c39dc0Srenato 					goto err;
370a8c39dc0Srenato 				}
371a8c39dc0Srenato 				if (!nbr->v4_enabled)
372a8c39dc0Srenato 					goto next;
373a8c39dc0Srenato 				break;
37400f5e67fSrenato 			case AF_INET6:
375a8c39dc0Srenato 				if (label == MPLS_LABEL_IPV4NULL) {
376a8c39dc0Srenato 					session_shutdown(nbr, S_BAD_TLV_VAL,
37760e1e0e7Srenato 					    msg.id, msg.type);
378a8c39dc0Srenato 					goto err;
379a8c39dc0Srenato 				}
380a8c39dc0Srenato 				if (!nbr->v6_enabled)
381a8c39dc0Srenato 					goto next;
382a8c39dc0Srenato 				break;
383a8c39dc0Srenato 			default:
384a8c39dc0Srenato 				fatalx("recv_labelmessage: unknown af");
385a8c39dc0Srenato 			}
386a8c39dc0Srenato 			break;
387a8c39dc0Srenato 		case MAP_TYPE_PWID:
388998f69edSrenato 			if (label <= MPLS_LABEL_RESERVED_MAX) {
38960e1e0e7Srenato 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
39060e1e0e7Srenato 				    msg.type);
391998f69edSrenato 				goto err;
392998f69edSrenato 			}
393998f69edSrenato 			if (me->map.flags & F_MAP_PW_STATUS)
394998f69edSrenato 				me->map.pw_status = pw_status;
395a8c39dc0Srenato 			break;
396a8c39dc0Srenato 		default:
397a8c39dc0Srenato 			break;
398998f69edSrenato 		}
399cf650e8bSrenato 		me->map.label = label;
400cf650e8bSrenato 		if (me->map.flags & F_MAP_REQ_ID)
401cf650e8bSrenato 			me->map.requestid = reqid;
402cf650e8bSrenato 
403297a8bbeSrenato 		log_msg_mapping(0, type, nbr, &me->map);
404c0cfacb4Srenato 
405cf650e8bSrenato 		switch (type) {
406cf650e8bSrenato 		case MSG_TYPE_LABELMAPPING:
407cf650e8bSrenato 			imsg_type = IMSG_LABEL_MAPPING;
408cf650e8bSrenato 			break;
409cf650e8bSrenato 		case MSG_TYPE_LABELREQUEST:
410cf650e8bSrenato 			imsg_type = IMSG_LABEL_REQUEST;
411cf650e8bSrenato 			break;
412cf650e8bSrenato 		case MSG_TYPE_LABELWITHDRAW:
413cf650e8bSrenato 			imsg_type = IMSG_LABEL_WITHDRAW;
414cf650e8bSrenato 			break;
415cf650e8bSrenato 		case MSG_TYPE_LABELRELEASE:
416cf650e8bSrenato 			imsg_type = IMSG_LABEL_RELEASE;
417cf650e8bSrenato 			break;
418cf650e8bSrenato 		case MSG_TYPE_LABELABORTREQ:
419cf650e8bSrenato 			imsg_type = IMSG_LABEL_ABORT;
420cf650e8bSrenato 			break;
421cf650e8bSrenato 		default:
422cf650e8bSrenato 			break;
423cf650e8bSrenato 		}
424cf650e8bSrenato 
425cf650e8bSrenato 		ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
426cf650e8bSrenato 		    sizeof(struct map));
427cf650e8bSrenato 
428a8c39dc0Srenato  next:
429cf650e8bSrenato 		TAILQ_REMOVE(&mh, me, entry);
430cf650e8bSrenato 		free(me);
431cf650e8bSrenato 	}
432cf650e8bSrenato 
4339277622bSrenato 	return (0);
434cf650e8bSrenato 
435cf650e8bSrenato  err:
436cf650e8bSrenato 	mapping_list_clr(&mh);
437cf650e8bSrenato 
438cf650e8bSrenato 	return (-1);
439ab0c2486Smichele }
440ab0c2486Smichele 
441ab0c2486Smichele /* Other TLV related functions */
44265f1d9c1Srenato static int
gen_label_tlv(struct ibuf * buf,uint32_t label)4433de94509Srenato gen_label_tlv(struct ibuf *buf, uint32_t label)
4443220fd77Sclaudio {
4453220fd77Sclaudio 	struct label_tlv	lt;
4463220fd77Sclaudio 
4473220fd77Sclaudio 	lt.type = htons(TLV_TYPE_GENERICLABEL);
44860e1e0e7Srenato 	lt.length = htons(LABEL_TLV_LEN);
4493220fd77Sclaudio 	lt.label = htonl(label);
4503220fd77Sclaudio 
45165f1d9c1Srenato 	return (ibuf_add(buf, &lt, sizeof(lt)));
4523220fd77Sclaudio }
4533220fd77Sclaudio 
454c28a25a1Srenato static int
tlv_decode_label(struct nbr * nbr,struct ldp_msg * msg,char * buf,uint16_t len,uint32_t * label)45560e1e0e7Srenato tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf,
4563de94509Srenato     uint16_t len, uint32_t *label)
4573220fd77Sclaudio {
45889f23408Sclaudio 	struct label_tlv lt;
4593220fd77Sclaudio 
46035791d36Srenato 	if (len < sizeof(lt)) {
46160e1e0e7Srenato 		session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type);
46289f23408Sclaudio 		return (-1);
46335791d36Srenato 	}
4643de94509Srenato 	memcpy(&lt, buf, sizeof(lt));
4653220fd77Sclaudio 
46635791d36Srenato 	if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) {
4670101edf8Srenato 		send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type);
46889f23408Sclaudio 		return (-1);
46935791d36Srenato 	}
47089f23408Sclaudio 
47135791d36Srenato 	switch (htons(lt.type)) {
47235791d36Srenato 	case TLV_TYPE_GENERICLABEL:
47360e1e0e7Srenato 		if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) {
47460e1e0e7Srenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
47560e1e0e7Srenato 			    msg->type);
47689f23408Sclaudio 			return (-1);
47735791d36Srenato 		}
47889f23408Sclaudio 
47989f23408Sclaudio 		*label = ntohl(lt.label);
48035791d36Srenato 		if (*label > MPLS_LABEL_MAX ||
48135791d36Srenato 		    (*label <= MPLS_LABEL_RESERVED_MAX &&
48235791d36Srenato 		     *label != MPLS_LABEL_IPV4NULL &&
483a8c39dc0Srenato 		     *label != MPLS_LABEL_IPV6NULL &&
48435791d36Srenato 		     *label != MPLS_LABEL_IMPLNULL)) {
48560e1e0e7Srenato 			session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
48660e1e0e7Srenato 			    msg->type);
48735791d36Srenato 			return (-1);
48835791d36Srenato 		}
48935791d36Srenato 		break;
49035791d36Srenato 	case TLV_TYPE_ATMLABEL:
49135791d36Srenato 	case TLV_TYPE_FRLABEL:
49235791d36Srenato 	default:
49335791d36Srenato 		/* unsupported */
49460e1e0e7Srenato 		session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type);
49535791d36Srenato 		return (-1);
49635791d36Srenato 	}
49789f23408Sclaudio 
49889f23408Sclaudio 	return (sizeof(lt));
4993220fd77Sclaudio }
5003220fd77Sclaudio 
50165f1d9c1Srenato static int
gen_reqid_tlv(struct ibuf * buf,uint32_t reqid)5023de94509Srenato gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
5033220fd77Sclaudio {
5043220fd77Sclaudio 	struct reqid_tlv	rt;
5053220fd77Sclaudio 
5063220fd77Sclaudio 	rt.type = htons(TLV_TYPE_LABELREQUEST);
50760e1e0e7Srenato 	rt.length = htons(REQID_TLV_LEN);
5083220fd77Sclaudio 	rt.reqid = htonl(reqid);
5093220fd77Sclaudio 
51065f1d9c1Srenato 	return (ibuf_add(buf, &rt, sizeof(rt)));
5113220fd77Sclaudio }
5123220fd77Sclaudio 
51365f1d9c1Srenato int
gen_pw_status_tlv(struct ibuf * buf,uint32_t status)5143de94509Srenato gen_pw_status_tlv(struct ibuf *buf, uint32_t status)
515ab0c2486Smichele {
5166399cec1Srenato 	struct pw_status_tlv	st;
517ab0c2486Smichele 
5186399cec1Srenato 	st.type = htons(TLV_TYPE_PW_STATUS);
51960e1e0e7Srenato 	st.length = htons(PW_STATUS_TLV_LEN);
5206399cec1Srenato 	st.value = htonl(status);
521ab0c2486Smichele 
52265f1d9c1Srenato 	return (ibuf_add(buf, &st, sizeof(st)));
523ab0c2486Smichele }
524ab0c2486Smichele 
5259246985aSrenato uint16_t
len_fec_tlv(struct map * map)5269246985aSrenato len_fec_tlv(struct map *map)
5279246985aSrenato {
5289246985aSrenato 	uint16_t	 len = TLV_HDR_SIZE;
5299246985aSrenato 
5309246985aSrenato 	switch (map->type) {
5319246985aSrenato 	case MAP_TYPE_WILDCARD:
5329246985aSrenato 		len += FEC_ELM_WCARD_LEN;
5339246985aSrenato 		break;
5349246985aSrenato 	case MAP_TYPE_PREFIX:
5359246985aSrenato 		len += FEC_ELM_PREFIX_MIN_LEN +
5369246985aSrenato 		    PREFIX_SIZE(map->fec.prefix.prefixlen);
5379246985aSrenato 		break;
5389246985aSrenato 	case MAP_TYPE_PWID:
5399246985aSrenato 		len += FEC_PWID_ELM_MIN_LEN;
5409246985aSrenato 		if (map->flags & F_MAP_PW_ID)
5419246985aSrenato 			len += PW_STATUS_TLV_LEN;
5429246985aSrenato 		if (map->flags & F_MAP_PW_IFMTU)
5439246985aSrenato 			len += FEC_SUBTLV_IFMTU_SIZE;
5449246985aSrenato     		if (map->flags & F_MAP_PW_STATUS)
5459246985aSrenato 			len += PW_STATUS_TLV_SIZE;
5469246985aSrenato 		break;
5479246985aSrenato 	case MAP_TYPE_TYPED_WCARD:
5489246985aSrenato 		len += FEC_ELM_TWCARD_MIN_LEN;
5499246985aSrenato 		switch (map->fec.twcard.type) {
5509246985aSrenato 		case MAP_TYPE_PREFIX:
5519246985aSrenato 		case MAP_TYPE_PWID:
5529246985aSrenato 			len += sizeof(uint16_t);
5539246985aSrenato 			break;
5549246985aSrenato 		default:
5559246985aSrenato 			fatalx("len_fec_tlv: unexpected fec type");
5569246985aSrenato 		}
5579246985aSrenato 		break;
5589246985aSrenato 	default:
5599246985aSrenato 		fatalx("len_fec_tlv: unexpected fec type");
5609246985aSrenato 	}
5619246985aSrenato 
5629246985aSrenato 	return (len);
5639246985aSrenato }
5649246985aSrenato 
56565f1d9c1Srenato int
gen_fec_tlv(struct ibuf * buf,struct map * map)5666399cec1Srenato gen_fec_tlv(struct ibuf *buf, struct map *map)
567cf483f25Srenato {
568cf483f25Srenato 	struct tlv	ft;
5693de94509Srenato 	uint16_t	family, len, pw_type, ifmtu;
570c7c5a728Srenato 	uint8_t		pw_len = 0, twcard_len;
5713de94509Srenato 	uint32_t	group_id, pwid;
57265f1d9c1Srenato 	int		err = 0;
573cf483f25Srenato 
574cf483f25Srenato 	ft.type = htons(TLV_TYPE_FEC);
5756399cec1Srenato 
5766399cec1Srenato 	switch (map->type) {
5773de94509Srenato 	case MAP_TYPE_WILDCARD:
5783de94509Srenato 		ft.length = htons(sizeof(uint8_t));
57965f1d9c1Srenato 		err |= ibuf_add(buf, &ft, sizeof(ft));
58065f1d9c1Srenato 		err |= ibuf_add(buf, &map->type, sizeof(map->type));
5816399cec1Srenato 		break;
5823de94509Srenato 	case MAP_TYPE_PREFIX:
583a8c39dc0Srenato 		len = PREFIX_SIZE(map->fec.prefix.prefixlen);
5846399cec1Srenato 		ft.length = htons(sizeof(map->type) + sizeof(family) +
585a8c39dc0Srenato 		    sizeof(map->fec.prefix.prefixlen) + len);
58665f1d9c1Srenato 		err |= ibuf_add(buf, &ft, sizeof(ft));
58765f1d9c1Srenato 		err |= ibuf_add(buf, &map->type, sizeof(map->type));
58800f5e67fSrenato 		switch (map->fec.prefix.af) {
58900f5e67fSrenato 		case AF_INET:
59000f5e67fSrenato 			family = htons(AF_IPV4);
59100f5e67fSrenato 			break;
59200f5e67fSrenato 		case AF_INET6:
59300f5e67fSrenato 			family = htons(AF_IPV6);
59400f5e67fSrenato 			break;
59500f5e67fSrenato 		default:
59600f5e67fSrenato 			fatalx("gen_fec_tlv: unknown af");
59700f5e67fSrenato 			break;
59800f5e67fSrenato 		}
59965f1d9c1Srenato 		err |= ibuf_add(buf, &family, sizeof(family));
60065f1d9c1Srenato 		err |= ibuf_add(buf, &map->fec.prefix.prefixlen,
601a8c39dc0Srenato 		    sizeof(map->fec.prefix.prefixlen));
6026399cec1Srenato 		if (len)
60365f1d9c1Srenato 			err |= ibuf_add(buf, &map->fec.prefix.prefix, len);
6046399cec1Srenato 		break;
605cf09440fSrenato 	case MAP_TYPE_PWID:
6066399cec1Srenato 		if (map->flags & F_MAP_PW_ID)
60702a212eeSrenato 			pw_len += FEC_PWID_SIZE;
6086399cec1Srenato 		if (map->flags & F_MAP_PW_IFMTU)
60960e1e0e7Srenato 			pw_len += FEC_SUBTLV_IFMTU_SIZE;
6106399cec1Srenato 
6116399cec1Srenato 		len = FEC_PWID_ELM_MIN_LEN + pw_len;
6126399cec1Srenato 
6136399cec1Srenato 		ft.length = htons(len);
61465f1d9c1Srenato 		err |= ibuf_add(buf, &ft, sizeof(ft));
6156399cec1Srenato 
61665f1d9c1Srenato 		err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
6176399cec1Srenato 		pw_type = map->fec.pwid.type;
6186399cec1Srenato 		if (map->flags & F_MAP_PW_CWORD)
6196399cec1Srenato 			pw_type |= CONTROL_WORD_FLAG;
6206399cec1Srenato 		pw_type = htons(pw_type);
62165f1d9c1Srenato 		err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
62265f1d9c1Srenato 		err |= ibuf_add(buf, &pw_len, sizeof(uint8_t));
6236399cec1Srenato 		group_id = htonl(map->fec.pwid.group_id);
62465f1d9c1Srenato 		err |= ibuf_add(buf, &group_id, sizeof(uint32_t));
6256399cec1Srenato 		if (map->flags & F_MAP_PW_ID) {
6266399cec1Srenato 			pwid = htonl(map->fec.pwid.pwid);
62765f1d9c1Srenato 			err |= ibuf_add(buf, &pwid, sizeof(uint32_t));
6286399cec1Srenato 		}
6296399cec1Srenato 		if (map->flags & F_MAP_PW_IFMTU) {
6306399cec1Srenato 			struct subtlv 	stlv;
6316399cec1Srenato 
6326399cec1Srenato 			stlv.type = SUBTLV_IFMTU;
63360e1e0e7Srenato 			stlv.length = FEC_SUBTLV_IFMTU_SIZE;
63465f1d9c1Srenato 			err |= ibuf_add(buf, &stlv, sizeof(uint16_t));
6356399cec1Srenato 
6366399cec1Srenato 			ifmtu = htons(map->fec.pwid.ifmtu);
63765f1d9c1Srenato 			err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t));
6386399cec1Srenato 		}
6396399cec1Srenato 		break;
640c7c5a728Srenato 	case MAP_TYPE_TYPED_WCARD:
641c7c5a728Srenato 		len = FEC_ELM_TWCARD_MIN_LEN;
642c7c5a728Srenato 		switch (map->fec.twcard.type) {
643c7c5a728Srenato 		case MAP_TYPE_PREFIX:
6446702dd25Srenato 		case MAP_TYPE_PWID:
645c7c5a728Srenato 			len += sizeof(uint16_t);
646c7c5a728Srenato 			break;
647c7c5a728Srenato 		default:
648c7c5a728Srenato 			fatalx("gen_fec_tlv: unexpected fec type");
649c7c5a728Srenato 		}
650c7c5a728Srenato 		ft.length = htons(len);
651c7c5a728Srenato 		err |= ibuf_add(buf, &ft, sizeof(ft));
652c7c5a728Srenato 		err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
653c7c5a728Srenato 		err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t));
654c7c5a728Srenato 
655c7c5a728Srenato 		switch (map->fec.twcard.type) {
656c7c5a728Srenato 		case MAP_TYPE_PREFIX:
657c7c5a728Srenato 			twcard_len = sizeof(uint16_t);
658c7c5a728Srenato 			err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
659c7c5a728Srenato 
660c7c5a728Srenato 			switch (map->fec.twcard.u.prefix_af) {
661c7c5a728Srenato 			case AF_INET:
662c7c5a728Srenato 				family = htons(AF_IPV4);
663c7c5a728Srenato 				break;
664c7c5a728Srenato 			case AF_INET6:
665c7c5a728Srenato 				family = htons(AF_IPV6);
666c7c5a728Srenato 				break;
667c7c5a728Srenato 			default:
668c7c5a728Srenato 				fatalx("gen_fec_tlv: unknown af");
669c7c5a728Srenato 				break;
670c7c5a728Srenato 			}
671c7c5a728Srenato 
672c7c5a728Srenato 			err |= ibuf_add(buf, &family, sizeof(uint16_t));
673c7c5a728Srenato 			break;
6746702dd25Srenato 		case MAP_TYPE_PWID:
6756702dd25Srenato 			twcard_len = sizeof(uint16_t);
6766702dd25Srenato 			err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
6776702dd25Srenato 			pw_type = htons(map->fec.twcard.u.pw_type);
6786702dd25Srenato 			err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
6796702dd25Srenato 			break;
680c7c5a728Srenato 		default:
681c7c5a728Srenato 			fatalx("gen_fec_tlv: unexpected fec type");
682c7c5a728Srenato 		}
683c7c5a728Srenato 		break;
6846399cec1Srenato 	default:
6856399cec1Srenato 		break;
6866399cec1Srenato 	}
68765f1d9c1Srenato 
68865f1d9c1Srenato 	return (err);
689cf483f25Srenato }
690cf483f25Srenato 
691ab0c2486Smichele int
tlv_decode_fec_elm(struct nbr * nbr,struct ldp_msg * msg,char * buf,uint16_t len,struct map * map)69260e1e0e7Srenato tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
6933de94509Srenato     uint16_t len, struct map *map)
694ab0c2486Smichele {
695a8c39dc0Srenato 	uint16_t	off = 0;
696c7c5a728Srenato 	uint8_t		pw_len, twcard_len;
697ab0c2486Smichele 
6986399cec1Srenato 	map->type = *buf;
6993de94509Srenato 	off += sizeof(uint8_t);
700dc9c556eSmichele 
7016399cec1Srenato 	switch (map->type) {
702cf09440fSrenato 	case MAP_TYPE_WILDCARD:
703cf483f25Srenato 		if (len == FEC_ELM_WCARD_LEN)
704fae3538eSclaudio 			return (off);
70535791d36Srenato 		else {
70660e1e0e7Srenato 			session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
70760e1e0e7Srenato 			    msg->type);
70835791d36Srenato 			return (-1);
70935791d36Srenato 		}
7106399cec1Srenato 		break;
711cf09440fSrenato 	case MAP_TYPE_PREFIX:
712cf483f25Srenato 		if (len < FEC_ELM_PREFIX_MIN_LEN) {
71360e1e0e7Srenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
71460e1e0e7Srenato 			    msg->type);
71535791d36Srenato 			return (-1);
71635791d36Srenato 		}
717ab0c2486Smichele 
7186399cec1Srenato 		/* Address Family */
719a8c39dc0Srenato 		memcpy(&map->fec.prefix.af, buf + off,
720a8c39dc0Srenato 		    sizeof(map->fec.prefix.af));
721a8c39dc0Srenato 		off += sizeof(map->fec.prefix.af);
72200f5e67fSrenato 		map->fec.prefix.af = ntohs(map->fec.prefix.af);
72300f5e67fSrenato 		switch (map->fec.prefix.af) {
72400f5e67fSrenato 		case AF_IPV4:
72500f5e67fSrenato 			map->fec.prefix.af = AF_INET;
72600f5e67fSrenato 			break;
72700f5e67fSrenato 		case AF_IPV6:
72800f5e67fSrenato 			map->fec.prefix.af = AF_INET6;
72900f5e67fSrenato 			break;
73000f5e67fSrenato 		default:
7310101edf8Srenato 			send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
73260e1e0e7Srenato 			    msg->type);
73335791d36Srenato 			return (-1);
73435791d36Srenato 		}
735ab0c2486Smichele 
736a8c39dc0Srenato 		/* Prefix Length */
737a8c39dc0Srenato 		map->fec.prefix.prefixlen = buf[off];
7383de94509Srenato 		off += sizeof(uint8_t);
739a8c39dc0Srenato 		if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) {
74060e1e0e7Srenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
74160e1e0e7Srenato 			    msg->type);
74235791d36Srenato 			return (-1);
74335791d36Srenato 		}
744fae3538eSclaudio 
7456399cec1Srenato 		/* Prefix */
746a8c39dc0Srenato 		memset(&map->fec.prefix.prefix, 0,
747a8c39dc0Srenato 		    sizeof(map->fec.prefix.prefix));
748a8c39dc0Srenato 		memcpy(&map->fec.prefix.prefix, buf + off,
749a8c39dc0Srenato 		    PREFIX_SIZE(map->fec.prefix.prefixlen));
750fae3538eSclaudio 
75100f5e67fSrenato 		/* Just in case... */
75200f5e67fSrenato 		ldp_applymask(map->fec.prefix.af, &map->fec.prefix.prefix,
75300f5e67fSrenato 		    &map->fec.prefix.prefix, map->fec.prefix.prefixlen);
75400f5e67fSrenato 
755a8c39dc0Srenato 		return (off + PREFIX_SIZE(map->fec.prefix.prefixlen));
756cf09440fSrenato 	case MAP_TYPE_PWID:
7576399cec1Srenato 		if (len < FEC_PWID_ELM_MIN_LEN) {
75860e1e0e7Srenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
75960e1e0e7Srenato 			    msg->type);
7606399cec1Srenato 			return (-1);
7616399cec1Srenato 		}
7626399cec1Srenato 
7636399cec1Srenato 		/* PW type */
7643de94509Srenato 		memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t));
7656399cec1Srenato 		map->fec.pwid.type = ntohs(map->fec.pwid.type);
7666399cec1Srenato 		if (map->fec.pwid.type & CONTROL_WORD_FLAG) {
7676399cec1Srenato 			map->flags |= F_MAP_PW_CWORD;
7686399cec1Srenato 			map->fec.pwid.type &= ~CONTROL_WORD_FLAG;
7696399cec1Srenato 		}
7703de94509Srenato 		off += sizeof(uint16_t);
7716399cec1Srenato 
7726399cec1Srenato 		/* PW info Length */
7736399cec1Srenato 		pw_len = buf[off];
7743de94509Srenato 		off += sizeof(uint8_t);
7756399cec1Srenato 
7766399cec1Srenato 		if (len != FEC_PWID_ELM_MIN_LEN + pw_len) {
77760e1e0e7Srenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
77860e1e0e7Srenato 			    msg->type);
7796399cec1Srenato 			return (-1);
7806399cec1Srenato 		}
7816399cec1Srenato 
7826399cec1Srenato 		/* Group ID */
7833de94509Srenato 		memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t));
7846399cec1Srenato 		map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id);
7853de94509Srenato 		off += sizeof(uint32_t);
7866399cec1Srenato 
7876399cec1Srenato 		/* PW ID */
7886399cec1Srenato 		if (pw_len == 0)
7896399cec1Srenato 			return (off);
7906399cec1Srenato 
7913de94509Srenato 		if (pw_len < sizeof(uint32_t)) {
79260e1e0e7Srenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
79360e1e0e7Srenato 			    msg->type);
7946399cec1Srenato 			return (-1);
7956399cec1Srenato 		}
7966399cec1Srenato 
7973de94509Srenato 		memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t));
7986399cec1Srenato 		map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid);
7996399cec1Srenato 		map->flags |= F_MAP_PW_ID;
8003de94509Srenato 		off += sizeof(uint32_t);
8013de94509Srenato 		pw_len -= sizeof(uint32_t);
8026399cec1Srenato 
8036399cec1Srenato 		/* Optional Interface Parameter Sub-TLVs */
8046399cec1Srenato 		while (pw_len > 0) {
8056399cec1Srenato 			struct subtlv 	stlv;
8066399cec1Srenato 
8076399cec1Srenato 			if (pw_len < sizeof(stlv)) {
80860e1e0e7Srenato 				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
80960e1e0e7Srenato 				    msg->type);
8106399cec1Srenato 				return (-1);
8116399cec1Srenato 			}
8126399cec1Srenato 
8133de94509Srenato 			memcpy(&stlv, buf + off, sizeof(stlv));
814a78ea73fSrenato 			if (stlv.length > pw_len) {
815a78ea73fSrenato 				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
816a78ea73fSrenato 				    msg->type);
817a78ea73fSrenato 				return (-1);
818a78ea73fSrenato 			}
819a78ea73fSrenato 
8206399cec1Srenato 			switch (stlv.type) {
8216399cec1Srenato 			case SUBTLV_IFMTU:
82260e1e0e7Srenato 				if (stlv.length != FEC_SUBTLV_IFMTU_SIZE) {
8236399cec1Srenato 					session_shutdown(nbr, S_BAD_TLV_LEN,
82460e1e0e7Srenato 					    msg->id, msg->type);
8256399cec1Srenato 					return (-1);
8266399cec1Srenato 				}
827d3e006a4Srenato 				memcpy(&map->fec.pwid.ifmtu, buf + off +
82860e1e0e7Srenato 				    SUBTLV_HDR_SIZE, sizeof(uint16_t));
8296399cec1Srenato 				map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu);
8306399cec1Srenato 				map->flags |= F_MAP_PW_IFMTU;
8316399cec1Srenato 				break;
8326399cec1Srenato 			default:
8336399cec1Srenato 				/* ignore */
8346399cec1Srenato 				break;
8356399cec1Srenato 			}
836d3e006a4Srenato 			off += stlv.length;
837d3e006a4Srenato 			pw_len -= stlv.length;
8386399cec1Srenato 		}
8396399cec1Srenato 
8406399cec1Srenato 		return (off);
841c7c5a728Srenato 	case MAP_TYPE_TYPED_WCARD:
842c7c5a728Srenato 		if (len < FEC_ELM_TWCARD_MIN_LEN) {
843c7c5a728Srenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
844c7c5a728Srenato 			    msg->type);
845c7c5a728Srenato 			return (-1);
846c7c5a728Srenato 		}
847c7c5a728Srenato 
848c7c5a728Srenato 		memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t));
849c7c5a728Srenato 		off += sizeof(uint8_t);
850c7c5a728Srenato 		memcpy(&twcard_len, buf + off, sizeof(uint8_t));
851c7c5a728Srenato 		off += sizeof(uint8_t);
852c7c5a728Srenato 		if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) {
853c7c5a728Srenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
854c7c5a728Srenato 			    msg->type);
855c7c5a728Srenato 			return (-1);
856c7c5a728Srenato 		}
857c7c5a728Srenato 
858c7c5a728Srenato 		switch (map->fec.twcard.type) {
859c7c5a728Srenato 		case MAP_TYPE_PREFIX:
860c7c5a728Srenato 			if (twcard_len != sizeof(uint16_t)) {
861c7c5a728Srenato 				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
862c7c5a728Srenato 				    msg->type);
863c7c5a728Srenato 				return (-1);
864c7c5a728Srenato 			}
865c7c5a728Srenato 
866c7c5a728Srenato 			memcpy(&map->fec.twcard.u.prefix_af, buf + off,
867c7c5a728Srenato 			    sizeof(uint16_t));
868c7c5a728Srenato 			map->fec.twcard.u.prefix_af =
869c7c5a728Srenato 			    ntohs(map->fec.twcard.u.prefix_af);
870c7c5a728Srenato 			off += sizeof(uint16_t);
871c7c5a728Srenato 
872c7c5a728Srenato 			switch (map->fec.twcard.u.prefix_af) {
873c7c5a728Srenato 			case AF_IPV4:
874c7c5a728Srenato 				map->fec.twcard.u.prefix_af = AF_INET;
875c7c5a728Srenato 				break;
876c7c5a728Srenato 			case AF_IPV6:
877c7c5a728Srenato 				map->fec.twcard.u.prefix_af = AF_INET6;
878c7c5a728Srenato 				break;
879c7c5a728Srenato 			default:
880c7c5a728Srenato 				session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
881c7c5a728Srenato 				    msg->type);
882c7c5a728Srenato 				return (-1);
883c7c5a728Srenato 			}
884c7c5a728Srenato 			break;
8856702dd25Srenato 		case MAP_TYPE_PWID:
8866702dd25Srenato 			if (twcard_len != sizeof(uint16_t)) {
8876702dd25Srenato 				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
8886702dd25Srenato 				    msg->type);
8896702dd25Srenato 				return (-1);
8906702dd25Srenato 			}
8916702dd25Srenato 
8926702dd25Srenato 			memcpy(&map->fec.twcard.u.pw_type, buf + off,
8936702dd25Srenato 			    sizeof(uint16_t));
8946702dd25Srenato 			map->fec.twcard.u.pw_type =
8956702dd25Srenato 			    ntohs(map->fec.twcard.u.pw_type);
8966702dd25Srenato 			/* ignore the reserved bit as per RFC 6667 */
8976702dd25Srenato 			map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT;
8986702dd25Srenato 			off += sizeof(uint16_t);
8996702dd25Srenato 			break;
900c7c5a728Srenato 		default:
901c7c5a728Srenato 			send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id,
902c7c5a728Srenato 			    msg->type);
903c7c5a728Srenato 			return (-1);
904c7c5a728Srenato 		}
905c7c5a728Srenato 
906c7c5a728Srenato 		return (off);
9076399cec1Srenato 	default:
9080101edf8Srenato 		send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
9096399cec1Srenato 		break;
9106399cec1Srenato 	}
9116399cec1Srenato 
9126399cec1Srenato 	return (-1);
913ab0c2486Smichele }
914297a8bbeSrenato 
915297a8bbeSrenato static void
log_msg_mapping(int out,uint16_t msg_type,struct nbr * nbr,struct map * map)916297a8bbeSrenato log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
917297a8bbeSrenato {
918297a8bbeSrenato 	log_debug("msg-%s: %s: lsr-id %s, fec %s, label %s",
919297a8bbeSrenato 	    (out) ? "out" : "in", msg_name(msg_type), inet_ntoa(nbr->id),
920297a8bbeSrenato 	    log_map(map), log_label(map->label));
921297a8bbeSrenato }
922