xref: /openbsd/usr.sbin/ldpd/labelmapping.c (revision 8bc5e3a3)
1 /*	$OpenBSD: labelmapping.c,v 1.69 2023/07/03 11:51:27 claudio 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 <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "ldpd.h"
30 #include "ldpe.h"
31 #include "log.h"
32 
33 static void	 enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
34 static int	 gen_label_tlv(struct ibuf *, uint32_t);
35 static int	 tlv_decode_label(struct nbr *, struct ldp_msg *, char *,
36 		    uint16_t, uint32_t *);
37 static int	 gen_reqid_tlv(struct ibuf *, uint32_t);
38 static void	 log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
39 
40 static void
enqueue_pdu(struct nbr * nbr,struct ibuf * buf,uint16_t size)41 enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size)
42 {
43 	if (ibuf_set_n16(buf, offsetof(struct ldp_hdr, length), size) == -1)
44 		fatal(__func__);
45 	evbuf_enqueue(&nbr->tcp->wbuf, buf);
46 }
47 
48 /* Generic function that handles all Label Message types */
49 void
send_labelmessage(struct nbr * nbr,uint16_t type,struct mapping_head * mh)50 send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
51 {
52 	struct ibuf		*buf = NULL;
53 	struct mapping_entry	*me;
54 	uint16_t		 msg_size, size = 0;
55 	int			 first = 1;
56 	int			 err = 0;
57 
58 	/* nothing to send */
59 	if (TAILQ_EMPTY(mh))
60 		return;
61 
62 	while ((me = TAILQ_FIRST(mh)) != NULL) {
63 		/* generate pdu */
64 		if (first) {
65 			if ((buf = ibuf_open(nbr->max_pdu_len +
66 			    LDP_HDR_DEAD_LEN)) == NULL)
67 				fatal(__func__);
68 
69 			/* real size will be set up later */
70 			err |= gen_ldp_hdr(buf, 0);
71 
72 			size = LDP_HDR_PDU_LEN;
73 			first = 0;
74 		}
75 
76 		/* calculate size */
77 		msg_size = LDP_MSG_SIZE;
78 		msg_size += len_fec_tlv(&me->map);
79 		if (me->map.label != NO_LABEL)
80 			msg_size += LABEL_TLV_SIZE;
81 		if (me->map.flags & F_MAP_REQ_ID)
82 			msg_size += REQID_TLV_SIZE;
83 		if (me->map.flags & F_MAP_STATUS)
84 			msg_size += STATUS_SIZE;
85 
86 		/* maximum pdu length exceeded, we need a new ldp pdu */
87 		if (size + msg_size > nbr->max_pdu_len) {
88 			enqueue_pdu(nbr, buf, size);
89 			first = 1;
90 			continue;
91 		}
92 
93 		size += msg_size;
94 
95 		/* append message and tlvs */
96 		err |= gen_msg_hdr(buf, type, msg_size);
97 		err |= gen_fec_tlv(buf, &me->map);
98 		if (me->map.label != NO_LABEL)
99 			err |= gen_label_tlv(buf, me->map.label);
100 		if (me->map.flags & F_MAP_REQ_ID)
101 			err |= gen_reqid_tlv(buf, me->map.requestid);
102 	    	if (me->map.flags & F_MAP_PW_STATUS)
103 			err |= gen_pw_status_tlv(buf, me->map.pw_status);
104 		if (me->map.flags & F_MAP_STATUS)
105 			err |= gen_status_tlv(buf, me->map.st.status_code,
106 			    me->map.st.msg_id, me->map.st.msg_type);
107 		if (err) {
108 			ibuf_free(buf);
109 			mapping_list_clr(mh);
110 			return;
111 		}
112 
113 		log_msg_mapping(1, type, nbr, &me->map);
114 
115 		TAILQ_REMOVE(mh, me, entry);
116 		free(me);
117 	}
118 
119 	enqueue_pdu(nbr, buf, size);
120 
121 	nbr_fsm(nbr, NBR_EVT_PDU_SENT);
122 }
123 
124 /* Generic function that handles all Label Message types */
125 int
recv_labelmessage(struct nbr * nbr,char * buf,uint16_t len,uint16_t type)126 recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
127 {
128 	struct ldp_msg		 msg;
129 	struct tlv		 ft;
130 	uint32_t		 label = NO_LABEL, reqid = 0;
131 	uint32_t		 pw_status = 0;
132 	uint8_t			 flags = 0;
133 	int			 feclen, lbllen, tlen;
134 	struct mapping_entry	*me;
135 	struct mapping_head	 mh;
136 	struct map		 map;
137 
138 	memcpy(&msg, buf, sizeof(msg));
139 	buf += LDP_MSG_SIZE;
140 	len -= LDP_MSG_SIZE;
141 
142 	/* FEC TLV */
143 	if (len < sizeof(ft)) {
144 		session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
145 		return (-1);
146 	}
147 
148 	memcpy(&ft, buf, sizeof(ft));
149 	if (ntohs(ft.type) != TLV_TYPE_FEC) {
150 		send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
151 		return (-1);
152 	}
153 	feclen = ntohs(ft.length);
154 	if (feclen > len - TLV_HDR_SIZE) {
155 		session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
156 		return (-1);
157 	}
158 
159 	buf += TLV_HDR_SIZE;	/* just advance to the end of the fec header */
160 	len -= TLV_HDR_SIZE;
161 
162 	TAILQ_INIT(&mh);
163 	do {
164 		memset(&map, 0, sizeof(map));
165 		map.msg_id = msg.id;
166 
167 		if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf, feclen,
168 		    &map)) == -1)
169 			goto err;
170 		if (map.type == MAP_TYPE_PWID &&
171 		    !(map.flags & F_MAP_PW_ID) &&
172 		    type != MSG_TYPE_LABELWITHDRAW &&
173 		    type != MSG_TYPE_LABELRELEASE) {
174 			send_notification(nbr->tcp, S_MISS_MSG, msg.id,
175 			    msg.type);
176 			return (-1);
177 		}
178 
179 		/*
180 		 * The Wildcard FEC Element can be used only in the
181 		 * Label Withdraw and Label Release messages.
182 		 */
183 		if (map.type == MAP_TYPE_WILDCARD) {
184 			switch (type) {
185 			case MSG_TYPE_LABELMAPPING:
186 			case MSG_TYPE_LABELREQUEST:
187 			case MSG_TYPE_LABELABORTREQ:
188 				session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
189 				    msg.type);
190 				goto err;
191 			default:
192 				break;
193 			}
194 		}
195 
196 		/*
197 		 * RFC 5561 - Section 4:
198 		 * "An LDP implementation that supports the Typed Wildcard
199 		 * FEC Element MUST support its use in Label Request, Label
200 		 * Withdraw, and Label Release messages".
201 		 */
202 		if (map.type == MAP_TYPE_TYPED_WCARD) {
203 			switch (type) {
204 			case MSG_TYPE_LABELMAPPING:
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
gen_label_tlv(struct ibuf * buf,uint32_t label)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
tlv_decode_label(struct nbr * nbr,struct ldp_msg * msg,char * buf,uint16_t len,uint32_t * label)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
gen_reqid_tlv(struct ibuf * buf,uint32_t reqid)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
gen_pw_status_tlv(struct ibuf * buf,uint32_t status)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 uint16_t
len_fec_tlv(struct map * map)526 len_fec_tlv(struct map *map)
527 {
528 	uint16_t	 len = TLV_HDR_SIZE;
529 
530 	switch (map->type) {
531 	case MAP_TYPE_WILDCARD:
532 		len += FEC_ELM_WCARD_LEN;
533 		break;
534 	case MAP_TYPE_PREFIX:
535 		len += FEC_ELM_PREFIX_MIN_LEN +
536 		    PREFIX_SIZE(map->fec.prefix.prefixlen);
537 		break;
538 	case MAP_TYPE_PWID:
539 		len += FEC_PWID_ELM_MIN_LEN;
540 		if (map->flags & F_MAP_PW_ID)
541 			len += PW_STATUS_TLV_LEN;
542 		if (map->flags & F_MAP_PW_IFMTU)
543 			len += FEC_SUBTLV_IFMTU_SIZE;
544     		if (map->flags & F_MAP_PW_STATUS)
545 			len += PW_STATUS_TLV_SIZE;
546 		break;
547 	case MAP_TYPE_TYPED_WCARD:
548 		len += FEC_ELM_TWCARD_MIN_LEN;
549 		switch (map->fec.twcard.type) {
550 		case MAP_TYPE_PREFIX:
551 		case MAP_TYPE_PWID:
552 			len += sizeof(uint16_t);
553 			break;
554 		default:
555 			fatalx("len_fec_tlv: unexpected fec type");
556 		}
557 		break;
558 	default:
559 		fatalx("len_fec_tlv: unexpected fec type");
560 	}
561 
562 	return (len);
563 }
564 
565 int
gen_fec_tlv(struct ibuf * buf,struct map * map)566 gen_fec_tlv(struct ibuf *buf, struct map *map)
567 {
568 	struct tlv	ft;
569 	uint16_t	family, len, pw_type, ifmtu;
570 	uint8_t		pw_len = 0, twcard_len;
571 	uint32_t	group_id, pwid;
572 	int		err = 0;
573 
574 	ft.type = htons(TLV_TYPE_FEC);
575 
576 	switch (map->type) {
577 	case MAP_TYPE_WILDCARD:
578 		ft.length = htons(sizeof(uint8_t));
579 		err |= ibuf_add(buf, &ft, sizeof(ft));
580 		err |= ibuf_add(buf, &map->type, sizeof(map->type));
581 		break;
582 	case MAP_TYPE_PREFIX:
583 		len = PREFIX_SIZE(map->fec.prefix.prefixlen);
584 		ft.length = htons(sizeof(map->type) + sizeof(family) +
585 		    sizeof(map->fec.prefix.prefixlen) + len);
586 		err |= ibuf_add(buf, &ft, sizeof(ft));
587 		err |= ibuf_add(buf, &map->type, sizeof(map->type));
588 		switch (map->fec.prefix.af) {
589 		case AF_INET:
590 			family = htons(AF_IPV4);
591 			break;
592 		case AF_INET6:
593 			family = htons(AF_IPV6);
594 			break;
595 		default:
596 			fatalx("gen_fec_tlv: unknown af");
597 			break;
598 		}
599 		err |= ibuf_add(buf, &family, sizeof(family));
600 		err |= ibuf_add(buf, &map->fec.prefix.prefixlen,
601 		    sizeof(map->fec.prefix.prefixlen));
602 		if (len)
603 			err |= ibuf_add(buf, &map->fec.prefix.prefix, len);
604 		break;
605 	case MAP_TYPE_PWID:
606 		if (map->flags & F_MAP_PW_ID)
607 			pw_len += FEC_PWID_SIZE;
608 		if (map->flags & F_MAP_PW_IFMTU)
609 			pw_len += FEC_SUBTLV_IFMTU_SIZE;
610 
611 		len = FEC_PWID_ELM_MIN_LEN + pw_len;
612 
613 		ft.length = htons(len);
614 		err |= ibuf_add(buf, &ft, sizeof(ft));
615 
616 		err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
617 		pw_type = map->fec.pwid.type;
618 		if (map->flags & F_MAP_PW_CWORD)
619 			pw_type |= CONTROL_WORD_FLAG;
620 		pw_type = htons(pw_type);
621 		err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
622 		err |= ibuf_add(buf, &pw_len, sizeof(uint8_t));
623 		group_id = htonl(map->fec.pwid.group_id);
624 		err |= ibuf_add(buf, &group_id, sizeof(uint32_t));
625 		if (map->flags & F_MAP_PW_ID) {
626 			pwid = htonl(map->fec.pwid.pwid);
627 			err |= ibuf_add(buf, &pwid, sizeof(uint32_t));
628 		}
629 		if (map->flags & F_MAP_PW_IFMTU) {
630 			struct subtlv 	stlv;
631 
632 			stlv.type = SUBTLV_IFMTU;
633 			stlv.length = FEC_SUBTLV_IFMTU_SIZE;
634 			err |= ibuf_add(buf, &stlv, sizeof(uint16_t));
635 
636 			ifmtu = htons(map->fec.pwid.ifmtu);
637 			err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t));
638 		}
639 		break;
640 	case MAP_TYPE_TYPED_WCARD:
641 		len = FEC_ELM_TWCARD_MIN_LEN;
642 		switch (map->fec.twcard.type) {
643 		case MAP_TYPE_PREFIX:
644 		case MAP_TYPE_PWID:
645 			len += sizeof(uint16_t);
646 			break;
647 		default:
648 			fatalx("gen_fec_tlv: unexpected fec type");
649 		}
650 		ft.length = htons(len);
651 		err |= ibuf_add(buf, &ft, sizeof(ft));
652 		err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
653 		err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t));
654 
655 		switch (map->fec.twcard.type) {
656 		case MAP_TYPE_PREFIX:
657 			twcard_len = sizeof(uint16_t);
658 			err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
659 
660 			switch (map->fec.twcard.u.prefix_af) {
661 			case AF_INET:
662 				family = htons(AF_IPV4);
663 				break;
664 			case AF_INET6:
665 				family = htons(AF_IPV6);
666 				break;
667 			default:
668 				fatalx("gen_fec_tlv: unknown af");
669 				break;
670 			}
671 
672 			err |= ibuf_add(buf, &family, sizeof(uint16_t));
673 			break;
674 		case MAP_TYPE_PWID:
675 			twcard_len = sizeof(uint16_t);
676 			err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
677 			pw_type = htons(map->fec.twcard.u.pw_type);
678 			err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
679 			break;
680 		default:
681 			fatalx("gen_fec_tlv: unexpected fec type");
682 		}
683 		break;
684 	default:
685 		break;
686 	}
687 
688 	return (err);
689 }
690 
691 int
tlv_decode_fec_elm(struct nbr * nbr,struct ldp_msg * msg,char * buf,uint16_t len,struct map * map)692 tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
693     uint16_t len, struct map *map)
694 {
695 	uint16_t	off = 0;
696 	uint8_t		pw_len, twcard_len;
697 
698 	map->type = *buf;
699 	off += sizeof(uint8_t);
700 
701 	switch (map->type) {
702 	case MAP_TYPE_WILDCARD:
703 		if (len == FEC_ELM_WCARD_LEN)
704 			return (off);
705 		else {
706 			session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
707 			    msg->type);
708 			return (-1);
709 		}
710 		break;
711 	case MAP_TYPE_PREFIX:
712 		if (len < FEC_ELM_PREFIX_MIN_LEN) {
713 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
714 			    msg->type);
715 			return (-1);
716 		}
717 
718 		/* Address Family */
719 		memcpy(&map->fec.prefix.af, buf + off,
720 		    sizeof(map->fec.prefix.af));
721 		off += sizeof(map->fec.prefix.af);
722 		map->fec.prefix.af = ntohs(map->fec.prefix.af);
723 		switch (map->fec.prefix.af) {
724 		case AF_IPV4:
725 			map->fec.prefix.af = AF_INET;
726 			break;
727 		case AF_IPV6:
728 			map->fec.prefix.af = AF_INET6;
729 			break;
730 		default:
731 			send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
732 			    msg->type);
733 			return (-1);
734 		}
735 
736 		/* Prefix Length */
737 		map->fec.prefix.prefixlen = buf[off];
738 		off += sizeof(uint8_t);
739 		if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) {
740 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
741 			    msg->type);
742 			return (-1);
743 		}
744 
745 		/* Prefix */
746 		memset(&map->fec.prefix.prefix, 0,
747 		    sizeof(map->fec.prefix.prefix));
748 		memcpy(&map->fec.prefix.prefix, buf + off,
749 		    PREFIX_SIZE(map->fec.prefix.prefixlen));
750 
751 		/* Just in case... */
752 		ldp_applymask(map->fec.prefix.af, &map->fec.prefix.prefix,
753 		    &map->fec.prefix.prefix, map->fec.prefix.prefixlen);
754 
755 		return (off + PREFIX_SIZE(map->fec.prefix.prefixlen));
756 	case MAP_TYPE_PWID:
757 		if (len < FEC_PWID_ELM_MIN_LEN) {
758 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
759 			    msg->type);
760 			return (-1);
761 		}
762 
763 		/* PW type */
764 		memcpy(&map->fec.pwid.type, buf + off, sizeof(uint16_t));
765 		map->fec.pwid.type = ntohs(map->fec.pwid.type);
766 		if (map->fec.pwid.type & CONTROL_WORD_FLAG) {
767 			map->flags |= F_MAP_PW_CWORD;
768 			map->fec.pwid.type &= ~CONTROL_WORD_FLAG;
769 		}
770 		off += sizeof(uint16_t);
771 
772 		/* PW info Length */
773 		pw_len = buf[off];
774 		off += sizeof(uint8_t);
775 
776 		if (len != FEC_PWID_ELM_MIN_LEN + pw_len) {
777 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
778 			    msg->type);
779 			return (-1);
780 		}
781 
782 		/* Group ID */
783 		memcpy(&map->fec.pwid.group_id, buf + off, sizeof(uint32_t));
784 		map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id);
785 		off += sizeof(uint32_t);
786 
787 		/* PW ID */
788 		if (pw_len == 0)
789 			return (off);
790 
791 		if (pw_len < sizeof(uint32_t)) {
792 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
793 			    msg->type);
794 			return (-1);
795 		}
796 
797 		memcpy(&map->fec.pwid.pwid, buf + off, sizeof(uint32_t));
798 		map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid);
799 		map->flags |= F_MAP_PW_ID;
800 		off += sizeof(uint32_t);
801 		pw_len -= sizeof(uint32_t);
802 
803 		/* Optional Interface Parameter Sub-TLVs */
804 		while (pw_len > 0) {
805 			struct subtlv 	stlv;
806 
807 			if (pw_len < sizeof(stlv)) {
808 				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
809 				    msg->type);
810 				return (-1);
811 			}
812 
813 			memcpy(&stlv, buf + off, sizeof(stlv));
814 			if (stlv.length > pw_len) {
815 				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
816 				    msg->type);
817 				return (-1);
818 			}
819 
820 			switch (stlv.type) {
821 			case SUBTLV_IFMTU:
822 				if (stlv.length != FEC_SUBTLV_IFMTU_SIZE) {
823 					session_shutdown(nbr, S_BAD_TLV_LEN,
824 					    msg->id, msg->type);
825 					return (-1);
826 				}
827 				memcpy(&map->fec.pwid.ifmtu, buf + off +
828 				    SUBTLV_HDR_SIZE, sizeof(uint16_t));
829 				map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu);
830 				map->flags |= F_MAP_PW_IFMTU;
831 				break;
832 			default:
833 				/* ignore */
834 				break;
835 			}
836 			off += stlv.length;
837 			pw_len -= stlv.length;
838 		}
839 
840 		return (off);
841 	case MAP_TYPE_TYPED_WCARD:
842 		if (len < FEC_ELM_TWCARD_MIN_LEN) {
843 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
844 			    msg->type);
845 			return (-1);
846 		}
847 
848 		memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t));
849 		off += sizeof(uint8_t);
850 		memcpy(&twcard_len, buf + off, sizeof(uint8_t));
851 		off += sizeof(uint8_t);
852 		if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) {
853 			session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
854 			    msg->type);
855 			return (-1);
856 		}
857 
858 		switch (map->fec.twcard.type) {
859 		case MAP_TYPE_PREFIX:
860 			if (twcard_len != sizeof(uint16_t)) {
861 				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
862 				    msg->type);
863 				return (-1);
864 			}
865 
866 			memcpy(&map->fec.twcard.u.prefix_af, buf + off,
867 			    sizeof(uint16_t));
868 			map->fec.twcard.u.prefix_af =
869 			    ntohs(map->fec.twcard.u.prefix_af);
870 			off += sizeof(uint16_t);
871 
872 			switch (map->fec.twcard.u.prefix_af) {
873 			case AF_IPV4:
874 				map->fec.twcard.u.prefix_af = AF_INET;
875 				break;
876 			case AF_IPV6:
877 				map->fec.twcard.u.prefix_af = AF_INET6;
878 				break;
879 			default:
880 				session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
881 				    msg->type);
882 				return (-1);
883 			}
884 			break;
885 		case MAP_TYPE_PWID:
886 			if (twcard_len != sizeof(uint16_t)) {
887 				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
888 				    msg->type);
889 				return (-1);
890 			}
891 
892 			memcpy(&map->fec.twcard.u.pw_type, buf + off,
893 			    sizeof(uint16_t));
894 			map->fec.twcard.u.pw_type =
895 			    ntohs(map->fec.twcard.u.pw_type);
896 			/* ignore the reserved bit as per RFC 6667 */
897 			map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT;
898 			off += sizeof(uint16_t);
899 			break;
900 		default:
901 			send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id,
902 			    msg->type);
903 			return (-1);
904 		}
905 
906 		return (off);
907 	default:
908 		send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
909 		break;
910 	}
911 
912 	return (-1);
913 }
914 
915 static void
log_msg_mapping(int out,uint16_t msg_type,struct nbr * nbr,struct map * map)916 log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
917 {
918 	log_debug("msg-%s: %s: lsr-id %s, fec %s, label %s",
919 	    (out) ? "out" : "in", msg_name(msg_type), inet_ntoa(nbr->id),
920 	    log_map(map), log_label(map->label));
921 }
922