xref: /openbsd/usr.sbin/ldpd/labelmapping.c (revision b2cd1366)
1 /*	$OpenBSD: labelmapping.c,v 1.18 2010/12/31 21:22:42 guenther Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/uio.h>
22 
23 #include <netinet/in.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/ip.h>
26 #include <arpa/inet.h>
27 #include <net/if_dl.h>
28 #include <unistd.h>
29 
30 #include <errno.h>
31 #include <event.h>
32 #include <limits.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "ldpd.h"
37 #include "ldp.h"
38 #include "log.h"
39 #include "ldpe.h"
40 
41 void		gen_label_tlv(struct ibuf *, u_int32_t);
42 void		gen_reqid_tlv(struct ibuf *, u_int32_t);
43 void		gen_fec_tlv(struct ibuf *, struct in_addr, u_int8_t);
44 
45 int	tlv_decode_label(char *, u_int16_t, u_int32_t *);
46 int	tlv_decode_reqid(char *, u_int16_t, u_int32_t *);
47 int	tlv_decode_fec_elm(char *, u_int16_t, u_int8_t *, u_int32_t *,
48 	    u_int8_t *);
49 
50 /* Label Mapping Message */
51 void
52 send_labelmapping(struct nbr *nbr)
53 {
54 	struct ibuf		*buf;
55 	struct mapping_entry	*me;
56 	struct ldp_hdr		*ldp_hdr;
57 	u_int16_t		 tlv_size, size;
58 
59 	if (nbr->iface->passive)
60 		return;
61 
62 	if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL)
63 		fatal("send_labelmapping");
64 
65 	/* real size will be set up later */
66 	gen_ldp_hdr(buf, nbr->iface, 0);
67 
68 	size = LDP_HDR_SIZE - TLV_HDR_LEN;
69 
70 	TAILQ_FOREACH(me, &nbr->mapping_list, entry) {
71 		tlv_size = BASIC_LABEL_MAP_LEN + PREFIX_SIZE(me->map.prefixlen);
72 		if (me->map.flags & F_MAP_REQ_ID)
73 			tlv_size += REQID_TLV_LEN;
74 		size += tlv_size;
75 
76 		gen_msg_tlv(buf, MSG_TYPE_LABELMAPPING, tlv_size);
77 		gen_fec_tlv(buf, me->map.prefix, me->map.prefixlen);
78 		gen_label_tlv(buf, me->map.label);
79 		if (me->map.flags & F_MAP_REQ_ID)
80 			gen_reqid_tlv(buf, me->map.requestid);
81 	}
82 
83 	/* XXX: should we remove them first? */
84 	nbr_mapping_list_clr(nbr, &nbr->mapping_list);
85 
86 	ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr));
87 	ldp_hdr->length = htons(size);
88 
89 	evbuf_enqueue(&nbr->wbuf, buf);
90 }
91 
92 int
93 recv_labelmapping(struct nbr *nbr, char *buf, u_int16_t len)
94 {
95 	struct ldp_msg		lm;
96 	struct fec_tlv		ft;
97 	struct map		map;
98 	u_int32_t		label;
99 	int			feclen, lbllen, tlen;
100 	u_int8_t		addr_type;
101 
102 	if (nbr->state != NBR_STA_OPER) {
103 		log_debug("recv_labelmapping: neighbor ID %s not operational",
104 		    inet_ntoa(nbr->id));
105 		return (-1);
106 	}
107 
108 	bcopy(buf, &lm, sizeof(lm));
109 
110 	buf += sizeof(struct ldp_msg);
111 	len -= sizeof(struct ldp_msg);
112 
113 	if (len < sizeof(ft)) {
114 		session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type);
115 		return (-1);
116 	}
117 
118 	bcopy(buf, &ft, sizeof(ft));
119 	feclen = ntohs(ft.length);
120 
121 	if (feclen > len - TLV_HDR_LEN) {
122 		session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type);
123 		return (-1);
124 	}
125 
126 	buf += TLV_HDR_LEN;	/* just advance to the end of the fec header */
127 	len -= TLV_HDR_LEN;
128 
129 	lbllen = tlv_decode_label(buf + feclen, len - feclen, &label);
130 	if (lbllen == -1) {
131 		session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, lm.type);
132 		return (-1);
133 	}
134 	if (label == NO_LABEL) {
135 		session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, lm.type);
136 		return (-1);
137 	}
138 
139 	/* TODO opt label request msg id, hop cnt and path vektor TLV */
140 
141 	bzero(&map, sizeof(map));
142 	map.messageid = lm.msgid;
143 	map.label = label;
144 	do {
145 		if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type,
146 		    &map.prefix.s_addr, &map.prefixlen)) == -1 ||
147 		    addr_type == FEC_WILDCARD) {
148 			session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, lm.type);
149 			return (-1);
150 		}
151 
152 		ldpe_imsg_compose_lde(IMSG_LABEL_MAPPING, nbr->peerid, 0, &map,
153 		    sizeof(map));
154 
155 		buf += tlen;
156 		feclen -= tlen;
157 	} while (feclen > 0);
158 
159 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
160 
161 	return (ntohs(lm.length));
162 }
163 
164 /* Label Request Message */
165 void
166 send_labelrequest(struct nbr *nbr)
167 {
168 	struct ibuf		*buf;
169 	struct mapping_entry	*me;
170 	struct ldp_hdr		*ldp_hdr;
171 	u_int16_t		 tlv_size, size;
172 
173 	if (nbr->iface->passive)
174 		return;
175 
176 	if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL)
177 		fatal("send_labelrequest");
178 
179 	/* real size will be set up later */
180 	gen_ldp_hdr(buf, nbr->iface, 0);
181 
182 	size = LDP_HDR_SIZE - TLV_HDR_LEN;
183 
184 	TAILQ_FOREACH(me, &nbr->request_list, entry) {
185 		tlv_size = PREFIX_SIZE(me->map.prefixlen);
186 		size += tlv_size;
187 
188 		gen_msg_tlv(buf, MSG_TYPE_LABELREQUEST, tlv_size);
189 		gen_fec_tlv(buf, me->map.prefix, me->map.prefixlen);
190 	}
191 
192 	/* XXX: should we remove them first? */
193 	nbr_mapping_list_clr(nbr, &nbr->request_list);
194 
195 	ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr));
196 	ldp_hdr->length = htons(size);
197 
198 	evbuf_enqueue(&nbr->wbuf, buf);
199 }
200 
201 int
202 recv_labelrequest(struct nbr *nbr, char *buf, u_int16_t len)
203 {
204 	struct ldp_msg	lr;
205 	struct fec_tlv	ft;
206 	struct map	map;
207 	int		feclen, tlen;
208 	u_int8_t	addr_type;
209 
210 	if (nbr->state != NBR_STA_OPER) {
211 		log_debug("recv_labelrequest: neighbor ID %s not operational",
212 		    inet_ntoa(nbr->id));
213 		return (-1);
214 	}
215 
216 	bcopy(buf, &lr, sizeof(lr));
217 
218 	buf += sizeof(struct ldp_msg);
219 	len -= sizeof(struct ldp_msg);
220 
221 	if (len < sizeof(ft)) {
222 		session_shutdown(nbr, S_BAD_MSG_LEN, lr.msgid, lr.type);
223 		return (-1);
224 	}
225 
226 	bcopy(buf, &ft, sizeof(ft));
227 	feclen = ntohs(ft.length);
228 
229 	if (feclen > len - TLV_HDR_LEN) {
230 		session_shutdown(nbr, S_BAD_TLV_LEN, lr.msgid, lr.type);
231 		return (-1);
232 	}
233 
234 	buf += TLV_HDR_LEN;	/* just advance to the end of the fec header */
235 	len -= TLV_HDR_LEN;
236 
237 	/* TODO opt hop cnt and path vektor TLV */
238 
239 	bzero(&map, sizeof(map));
240 	map.messageid = lr.msgid;
241 	do {
242 		if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type,
243 		    &map.prefix.s_addr, &map.prefixlen)) == -1 ||
244 		    addr_type == FEC_WILDCARD) {
245 			session_shutdown(nbr, S_BAD_TLV_VAL, lr.msgid, lr.type);
246 			return (-1);
247 		}
248 
249 		ldpe_imsg_compose_lde(IMSG_LABEL_REQUEST, nbr->peerid, 0, &map,
250 		    sizeof(map));
251 
252 		buf += tlen;
253 		feclen -= tlen;
254 	} while (feclen > 0);
255 
256 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
257 
258 	return (ntohs(lr.length));
259 }
260 
261 /* Label Withdraw Message */
262 void
263 send_labelwithdraw(struct nbr *nbr)
264 {
265 	struct ibuf		*buf;
266 	struct mapping_entry	*me;
267 	struct ldp_hdr		*ldp_hdr;
268 	u_int16_t		 tlv_size, size;
269 
270 	if (nbr->iface->passive)
271 		return;
272 
273 	if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL)
274 		fatal("send_labelwithdraw");
275 
276 	/* real size will be set up later */
277 	gen_ldp_hdr(buf, nbr->iface, 0);
278 
279 	size = LDP_HDR_SIZE - TLV_HDR_LEN;
280 
281 	TAILQ_FOREACH(me, &nbr->withdraw_list, entry) {
282 		if (me->map.label == NO_LABEL)
283 			tlv_size = PREFIX_SIZE(me->map.prefixlen);
284 		else
285 			tlv_size = BASIC_LABEL_MAP_LEN +
286 			    PREFIX_SIZE(me->map.prefixlen);
287 
288 		size += tlv_size;
289 
290 		gen_msg_tlv(buf, MSG_TYPE_LABELWITHDRAW, tlv_size);
291 		gen_fec_tlv(buf, me->map.prefix, me->map.prefixlen);
292 
293 		if (me->map.label != NO_LABEL)
294 			gen_label_tlv(buf, me->map.label);
295 	}
296 
297 	/* XXX: should we remove them first? */
298 	nbr_mapping_list_clr(nbr, &nbr->withdraw_list);
299 
300 	ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr));
301 	ldp_hdr->length = htons(size);
302 
303 	evbuf_enqueue(&nbr->wbuf, buf);
304 }
305 
306 int
307 recv_labelwithdraw(struct nbr *nbr, char *buf, u_int16_t len)
308 {
309 	struct map	map;
310 	struct ldp_msg	lw;
311 	struct fec_tlv	ft;
312 	u_int32_t	label = NO_LABEL;
313 	int		feclen, tlen, numfec = 0;
314 	u_int8_t	addr_type;
315 
316 	if (nbr->state != NBR_STA_OPER) {
317 		log_debug("recv_labelwithdraw: neighbor ID %s not operational",
318 		    inet_ntoa(nbr->id));
319 		return (-1);
320 	}
321 
322 	bcopy(buf, &lw, sizeof(lw));
323 
324 	buf += sizeof(struct ldp_msg);
325 	len -= sizeof(struct ldp_msg);
326 
327 	if (len < sizeof(ft)) {
328 		session_shutdown(nbr, S_BAD_MSG_LEN, lw.msgid, lw.type);
329 		return (-1);
330 	}
331 
332 	bcopy(buf, &ft, sizeof(ft));
333 	feclen = ntohs(ft.length);
334 
335 	if (feclen > len - TLV_HDR_LEN) {
336 		session_shutdown(nbr, S_BAD_TLV_LEN, lw.msgid, lw.type);
337 		return (-1);
338 	}
339 
340 	buf += TLV_HDR_LEN;	/* just advance to the end of the fec header */
341 	len -= TLV_HDR_LEN;
342 
343 	/* withdraw may include optional label */
344 	if (len > feclen) {
345 		int r;
346 
347 		r = tlv_decode_label(buf + feclen, len - feclen, &label);
348 		if (r == -1 || len != feclen + r) {
349 			session_shutdown(nbr, S_BAD_TLV_VAL, lw.msgid,
350 			    lw.type);
351 			return (-1);
352 		}
353 	}
354 
355 	bzero(&map, sizeof(map));
356 	map.messageid = lw.msgid;
357 	if (label != NO_LABEL) {
358 		map.label = label;
359 		map.flags = F_MAP_OPTLABEL;
360 	}
361 	do {
362 		if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type,
363 		    &map.prefix.s_addr, &map.prefixlen)) == -1) {
364 			session_shutdown(nbr, S_BAD_TLV_VAL, lw.msgid, lw.type);
365 			return (-1);
366 		}
367 
368 		if (addr_type == FEC_WILDCARD) {
369 			/* Wildcard FEC must be the only FEC element */
370 			if (numfec != 0) {
371 				session_shutdown(nbr, S_BAD_TLV_VAL, lw.msgid,
372 				    lw.type);
373 				return (-1);
374 			}
375 			map.prefix.s_addr = 0;
376 			map.prefixlen = 0;
377 			map.flags |= F_MAP_WILDCARD;
378 			numfec = -1;
379 		} else {
380 			/* Wildcard FEC must be the only FEC element */
381 			if (numfec == -1) {
382 				session_shutdown(nbr, S_BAD_TLV_VAL, lw.msgid,
383 				    lw.type);
384 				return (-1);
385 			}
386 			numfec++;
387 			map.flags &= ~F_MAP_WILDCARD;
388 		}
389 
390 		ldpe_imsg_compose_lde(IMSG_LABEL_WITHDRAW, nbr->peerid, 0, &map,
391 		    sizeof(map));
392 
393 		buf += tlen;
394 		feclen -= tlen;
395 	} while (feclen > 0);
396 
397 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
398 
399 	return (ntohs(lw.length));
400 }
401 
402 /* Label Release Message */
403 void
404 send_labelrelease(struct nbr *nbr)
405 {
406 	struct ibuf		*buf;
407 	struct mapping_entry	*me;
408 	struct ldp_hdr		*ldp_hdr;
409 	u_int16_t		 tlv_size, size;
410 
411 	if (nbr->iface->passive)
412 		return;
413 
414 	if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL)
415 		fatal("send_labelrelease");
416 
417 	/* real size will be set up later */
418 	gen_ldp_hdr(buf, nbr->iface, 0);
419 
420 	size = LDP_HDR_SIZE - TLV_HDR_LEN;
421 
422 	TAILQ_FOREACH(me, &nbr->release_list, entry) {
423 		if (me->map.label == NO_LABEL)
424 			tlv_size = PREFIX_SIZE(me->map.prefixlen);
425 		else
426 			tlv_size = BASIC_LABEL_MAP_LEN +
427 			    PREFIX_SIZE(me->map.prefixlen);
428 
429 		size += tlv_size;
430 
431 		gen_msg_tlv(buf, MSG_TYPE_LABELRELEASE, tlv_size);
432 		gen_fec_tlv(buf, me->map.prefix, me->map.prefixlen);
433 
434 		if (me->map.label != NO_LABEL)
435 			gen_label_tlv(buf, me->map.label);
436 	}
437 
438 	/* XXX: should we remove them first? */
439 	nbr_mapping_list_clr(nbr, &nbr->release_list);
440 
441 	ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr));
442 	ldp_hdr->length = htons(size);
443 
444 	evbuf_enqueue(&nbr->wbuf, buf);
445 }
446 
447 int
448 recv_labelrelease(struct nbr *nbr, char *buf, u_int16_t len)
449 {
450 	struct map	map;
451 	struct ldp_msg	lr;
452 	struct fec_tlv	ft;
453 	u_int32_t	label = NO_LABEL;
454 	int		feclen, tlen, numfec = 0;
455 	u_int8_t	addr_type;
456 
457 	if (nbr->state != NBR_STA_OPER) {
458 		log_debug("recv_labelrelease: neighbor ID %s not operational",
459 		    inet_ntoa(nbr->id));
460 		return (-1);
461 	}
462 
463 	bcopy(buf, &lr, sizeof(lr));
464 
465 	buf += sizeof(struct ldp_msg);
466 	len -= sizeof(struct ldp_msg);
467 
468 	if (len < sizeof(ft)) {
469 		session_shutdown(nbr, S_BAD_MSG_LEN, lr.msgid, lr.type);
470 		return (-1);
471 	}
472 
473 	bcopy(buf, &ft, sizeof(ft));
474 	feclen = ntohs(ft.length);
475 
476 	if (feclen > len - TLV_HDR_LEN) {
477 		session_shutdown(nbr, S_BAD_TLV_LEN, lr.msgid, lr.type);
478 		return (-1);
479 	}
480 
481 	buf += TLV_HDR_LEN;	/* just advance to the end of the fec header */
482 	len -= TLV_HDR_LEN;
483 
484 	/* release may include optional label */
485 	if (len > feclen) {
486 		int r;
487 
488 		r = tlv_decode_label(buf + feclen, len - feclen, &label);
489 		if (r == -1 || len != feclen + r) {
490 			session_shutdown(nbr, S_BAD_TLV_VAL, lr.msgid,
491 			    lr.type);
492 			return (-1);
493 		}
494 	}
495 
496 	bzero(&map, sizeof(map));
497 	map.messageid = lr.msgid;
498 	if (label != NO_LABEL) {
499 		map.label = label;
500 		map.flags = F_MAP_OPTLABEL;
501 	}
502 	do {
503 		if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type,
504 		    &map.prefix.s_addr, &map.prefixlen)) == -1) {
505 			session_shutdown(nbr, S_BAD_TLV_VAL, lr.msgid, lr.type);
506 			return (-1);
507 		}
508 
509 		if (addr_type == FEC_WILDCARD) {
510 			/* Wildcard FEC must be the only FEC element */
511 			if (numfec != 0) {
512 				session_shutdown(nbr, S_BAD_TLV_VAL, lr.msgid,
513 				    lr.type);
514 				return (-1);
515 			}
516 			map.prefix.s_addr = 0;
517 			map.prefixlen = 0;
518 			map.flags |= F_MAP_WILDCARD;
519 
520 		} else {
521 			/* Wildcard FEC must be the only FEC element */
522 			if (numfec == -1) {
523 				session_shutdown(nbr, S_BAD_TLV_VAL, lr.msgid,
524 				    lr.type);
525 				return (-1);
526 			}
527 			map.flags &= ~F_MAP_WILDCARD;
528 		}
529 
530 		ldpe_imsg_compose_lde(IMSG_LABEL_RELEASE, nbr->peerid, 0, &map,
531 		    sizeof(map));
532 
533 		buf += tlen;
534 		feclen -= tlen;
535 	} while (feclen > 0);
536 
537 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
538 
539 	return (ntohs(lr.length));
540 }
541 
542 /* Label Abort Req Message */
543 void
544 send_labelabortreq(struct nbr *nbr)
545 {
546 	struct ibuf	*buf;
547 	u_int16_t	 size;
548 
549 	if (nbr->iface->passive)
550 		return;
551 
552 	if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL)
553 		fatal("send_labelabortreq");
554 
555 	size = LDP_HDR_SIZE + sizeof(struct ldp_msg);
556 
557 	gen_ldp_hdr(buf, nbr->iface, size);
558 
559 	size -= LDP_HDR_SIZE;
560 
561 	gen_msg_tlv(buf, MSG_TYPE_LABELABORTREQ, size);
562 
563 	evbuf_enqueue(&nbr->wbuf, buf);
564 }
565 
566 int
567 recv_labelabortreq(struct nbr *nbr, char *buf, u_int16_t len)
568 {
569 	struct map	map;
570 	struct ldp_msg	la;
571 	struct fec_tlv	ft;
572 	int		feclen, tlen;
573 	u_int8_t	addr_type;
574 
575 	if (nbr->state != NBR_STA_OPER) {
576 		log_debug("recv_labelabortreq: neighbor ID %s not operational",
577 		    inet_ntoa(nbr->id));
578 		return (-1);
579 	}
580 
581 	log_debug("recv_labelabortreq: neighbor ID %s", inet_ntoa(nbr->id));
582 
583 	bcopy(buf, &la, sizeof(la));
584 
585 	buf += sizeof(struct ldp_msg);
586 	len -= sizeof(struct ldp_msg);
587 
588 	if (len < sizeof(ft)) {
589 		session_shutdown(nbr, S_BAD_MSG_LEN, la.msgid, la.type);
590 		return (-1);
591 	}
592 
593 	bcopy(buf, &ft, sizeof(ft));
594 	feclen = ntohs(ft.length);
595 
596 	if (feclen > len - TLV_HDR_LEN) {
597 		session_shutdown(nbr, S_BAD_TLV_LEN, la.msgid, la.type);
598 		return (-1);
599 	}
600 
601 	buf += TLV_HDR_LEN;	/* just advance to the end of the fec header */
602 	len -= TLV_HDR_LEN;
603 
604 	bzero(&map, sizeof(map));
605 	map.messageid = la.msgid;
606 
607 	/* abort request may include optional request msg id */
608 	if (len > feclen) {
609 		int r;
610 
611 		r = tlv_decode_reqid(buf + feclen, len - feclen,
612 		    &map.requestid);
613 		if (r == -1 || len != feclen + r) {
614 			session_shutdown(nbr, S_BAD_TLV_VAL, la.msgid,
615 			    la.type);
616 			return (-1);
617 		}
618 		map.flags = F_MAP_REQ_ID;
619 	}
620 
621 	do {
622 		if ((tlen = tlv_decode_fec_elm(buf, feclen, &addr_type,
623 		    &map.prefix.s_addr, &map.prefixlen)) == -1 ||
624 		    addr_type == FEC_WILDCARD) {
625 			session_shutdown(nbr, S_BAD_TLV_VAL, la.msgid, la.type);
626 			return (-1);
627 		}
628 
629 		ldpe_imsg_compose_lde(IMSG_LABEL_ABORT, nbr->peerid, 0, &map,
630 		    sizeof(map));
631 
632 		buf += tlen;
633 		feclen -= tlen;
634 	} while (feclen > 0);
635 
636 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
637 
638 	return (ntohs(la.length));
639 }
640 
641 /* Other TLV related functions */
642 void
643 gen_label_tlv(struct ibuf *buf, u_int32_t label)
644 {
645 	struct label_tlv	lt;
646 
647 	lt.type = htons(TLV_TYPE_GENERICLABEL);
648 	lt.length = htons(sizeof(label));
649 	lt.label = htonl(label);
650 
651 	ibuf_add(buf, &lt, sizeof(lt));
652 }
653 
654 int
655 tlv_decode_label(char *buf, u_int16_t len, u_int32_t *label)
656 {
657 	struct label_tlv lt;
658 
659 	if (len < sizeof(lt))
660 		return (-1);
661 	bcopy(buf, &lt, sizeof(lt));
662 
663 	if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_LEN)
664 		return (-1);
665 
666 	if (lt.type != htons(TLV_TYPE_GENERICLABEL))
667 		return (-1);
668 
669 	*label = ntohl(lt.label);
670 
671 	return (sizeof(lt));
672 }
673 
674 void
675 gen_reqid_tlv(struct ibuf *buf, u_int32_t reqid)
676 {
677 	struct reqid_tlv	rt;
678 
679 	rt.type = htons(TLV_TYPE_LABELREQUEST);
680 	rt.length = htons(sizeof(reqid));
681 	rt.reqid = htonl(reqid);
682 
683 	ibuf_add(buf, &rt, sizeof(rt));
684 }
685 
686 int
687 tlv_decode_reqid(char *buf, u_int16_t len, u_int32_t *reqid)
688 {
689 	struct reqid_tlv rt;
690 
691 	if (len < sizeof(rt))
692 		return (-1);
693 	bcopy(buf, &rt, sizeof(rt));
694 
695 	if (ntohs(rt.length) != sizeof(rt) - TLV_HDR_LEN)
696 		return (-1);
697 
698 	if (rt.type != htons(TLV_TYPE_LABELREQUEST))
699 		return (-1);
700 
701 	*reqid = ntohl(rt.reqid);
702 
703 	return (sizeof(rt));
704 }
705 
706 
707 void
708 gen_fec_tlv(struct ibuf *buf, struct in_addr prefix, u_int8_t prefixlen)
709 {
710 	struct fec_tlv	ft;
711 	u_int8_t	type;
712 	u_int16_t	family;
713 	u_int8_t	len;
714 
715 	len = PREFIX_SIZE(prefixlen);
716 	ft.type = htons(TLV_TYPE_FEC);
717 	ft.length = htons(sizeof(type) + sizeof(family) + sizeof(prefixlen) +
718 	    len);
719 
720 	ibuf_add(buf, &ft, sizeof(ft));
721 
722 	type = FEC_PREFIX;
723 	family = htons(FEC_IPV4);
724 
725 	ibuf_add(buf, &type, sizeof(type));
726 	ibuf_add(buf, &family, sizeof(family));
727 	ibuf_add(buf, &prefixlen, sizeof(prefixlen));
728 	if (len)
729 		ibuf_add(buf, &prefix, len);
730 }
731 
732 int
733 tlv_decode_fec_elm(char *buf, u_int16_t len, u_int8_t *type, u_int32_t *prefix,
734     u_int8_t *prefixlen)
735 {
736 	u_int16_t	family, off = 0;
737 
738 	*type = *buf;
739 	off += sizeof(u_int8_t);
740 
741 	if (*type == FEC_WILDCARD) {
742 		if (len == 0)
743 			return (off);
744 		else
745 			return (-1); /* XXX Malformed TLV Value */
746 	}
747 
748 	if (*type != FEC_PREFIX)
749 		return (-1);	/* XXX "Unknown FEC" Notification */
750 
751 	if (len < FEC_ELM_MIN_LEN)
752 		return (-1);	/* XXX Bad TLV Length */
753 
754 	bcopy(buf + off, &family, sizeof(family));
755 	off += sizeof(family);
756 
757 	if (family != htons(FEC_IPV4))
758 		return (-1);	/* XXX "Unsupported Address Family" */
759 
760 	*prefixlen = buf[off];
761 	off += sizeof(u_int8_t);
762 
763 	if (len < off + PREFIX_SIZE(*prefixlen))
764 		return (-1);	/* XXX Bad TLV Length */
765 
766 	*prefix = 0;
767 	bcopy(buf + off, prefix, PREFIX_SIZE(*prefixlen));
768 
769 	return (off + PREFIX_SIZE(*prefixlen));
770 }
771