xref: /openbsd/usr.sbin/ldpd/init.c (revision 9246985a)
1*9246985aSrenato /*	$OpenBSD: init.c,v 1.37 2017/03/04 00:15:35 renato Exp $ */
2ab0c2486Smichele 
3ab0c2486Smichele /*
4ab0c2486Smichele  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
5ab0c2486Smichele  *
6ab0c2486Smichele  * Permission to use, copy, modify, and distribute this software for any
7ab0c2486Smichele  * purpose with or without fee is hereby granted, provided that the above
8ab0c2486Smichele  * copyright notice and this permission notice appear in all copies.
9ab0c2486Smichele  *
10ab0c2486Smichele  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11ab0c2486Smichele  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12ab0c2486Smichele  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13ab0c2486Smichele  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14ab0c2486Smichele  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15ab0c2486Smichele  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16ab0c2486Smichele  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17ab0c2486Smichele  */
18ab0c2486Smichele 
19ab0c2486Smichele #include <sys/types.h>
20ab0c2486Smichele #include <arpa/inet.h>
21ab0c2486Smichele #include <string.h>
22ab0c2486Smichele 
23ab0c2486Smichele #include "ldpd.h"
24ab0c2486Smichele #include "ldpe.h"
255411bbb6Srenato #include "log.h"
26ab0c2486Smichele 
27d3e006a4Srenato static int	gen_init_prms_tlv(struct ibuf *, struct nbr *);
283b4c1866Srenato static int	gen_cap_dynamic_tlv(struct ibuf *);
29c7c5a728Srenato static int	gen_cap_twcard_tlv(struct ibuf *, int);
30*9246985aSrenato static int	gen_cap_unotif_tlv(struct ibuf *, int);
31ab0c2486Smichele 
32a6fc12d8Smichele void
send_init(struct nbr * nbr)33ab0c2486Smichele send_init(struct nbr *nbr)
34ab0c2486Smichele {
35e39620e5Snicm 	struct ibuf		*buf;
363de94509Srenato 	uint16_t		 size;
3765f1d9c1Srenato 	int			 err = 0;
38ab0c2486Smichele 
39d99a8fc3Srenato 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
40ab0c2486Smichele 
413b4c1866Srenato 	size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE +
42*9246985aSrenato 	    CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE + CAP_TLV_UNOTIF_SIZE;
439277622bSrenato 	if ((buf = ibuf_open(size)) == NULL)
44b7b4db73Srenato 		fatal(__func__);
45ab0c2486Smichele 
4665f1d9c1Srenato 	err |= gen_ldp_hdr(buf, size);
47ab0c2486Smichele 	size -= LDP_HDR_SIZE;
4865f1d9c1Srenato 	err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size);
49d3e006a4Srenato 	err |= gen_init_prms_tlv(buf, nbr);
503b4c1866Srenato 	err |= gen_cap_dynamic_tlv(buf);
51c7c5a728Srenato 	err |= gen_cap_twcard_tlv(buf, 1);
52*9246985aSrenato 	err |= gen_cap_unotif_tlv(buf, 1);
5365f1d9c1Srenato 	if (err) {
5465f1d9c1Srenato 		ibuf_free(buf);
5565f1d9c1Srenato 		return;
5665f1d9c1Srenato 	}
57ab0c2486Smichele 
58699b7d06Sclaudio 	evbuf_enqueue(&nbr->tcp->wbuf, buf);
59ab0c2486Smichele }
60ab0c2486Smichele 
61ab0c2486Smichele int
recv_init(struct nbr * nbr,char * buf,uint16_t len)623de94509Srenato recv_init(struct nbr *nbr, char *buf, uint16_t len)
63ab0c2486Smichele {
6460e1e0e7Srenato 	struct ldp_msg		msg;
6589f23408Sclaudio 	struct sess_prms_tlv	sess;
66feeedd8aSrenato 	uint16_t		max_pdu_len;
673b4c1866Srenato 	int			caps_rcvd = 0;
68ab0c2486Smichele 
69d99a8fc3Srenato 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
70ab0c2486Smichele 
7160e1e0e7Srenato 	memcpy(&msg, buf, sizeof(msg));
723de94509Srenato 	buf += LDP_MSG_SIZE;
733de94509Srenato 	len -= LDP_MSG_SIZE;
74ab0c2486Smichele 
7589f23408Sclaudio 	if (len < SESS_PRMS_SIZE) {
7660e1e0e7Srenato 		session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
7789f23408Sclaudio 		return (-1);
7889f23408Sclaudio 	}
793de94509Srenato 	memcpy(&sess, buf, sizeof(sess));
8060e1e0e7Srenato 	if (ntohs(sess.length) != SESS_PRMS_LEN) {
8160e1e0e7Srenato 		session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
82ab0c2486Smichele 		return (-1);
83ab0c2486Smichele 	}
8435791d36Srenato 	if (ntohs(sess.proto_version) != LDP_VERSION) {
8560e1e0e7Srenato 		session_shutdown(nbr, S_BAD_PROTO_VER, msg.id, msg.type);
8635791d36Srenato 		return (-1);
8735791d36Srenato 	}
88d3e006a4Srenato 	if (ntohs(sess.keepalive_time) < MIN_KEEPALIVE) {
8960e1e0e7Srenato 		session_shutdown(nbr, S_KEEPALIVE_BAD, msg.id, msg.type);
90d3e006a4Srenato 		return (-1);
91d3e006a4Srenato 	}
926af85cd7Srenato 	if (sess.lsr_id != leconf->rtr_id.s_addr ||
936af85cd7Srenato 	    ntohs(sess.lspace_id) != 0) {
9460e1e0e7Srenato 		session_shutdown(nbr, S_NO_HELLO, msg.id, msg.type);
956af85cd7Srenato 		return (-1);
966af85cd7Srenato 	}
9735791d36Srenato 
98080776f3Sclaudio 	buf += SESS_PRMS_SIZE;
99080776f3Sclaudio 	len -= SESS_PRMS_SIZE;
100080776f3Sclaudio 
101a78ea73fSrenato 	/* Optional Parameters */
102a78ea73fSrenato 	while (len > 0) {
103a78ea73fSrenato 		struct tlv 	tlv;
1043b4c1866Srenato 		uint16_t	tlv_type;
105a78ea73fSrenato 		uint16_t	tlv_len;
106a78ea73fSrenato 
107a78ea73fSrenato 		if (len < sizeof(tlv)) {
108a78ea73fSrenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
109a78ea73fSrenato 			return (-1);
110a78ea73fSrenato 		}
111a78ea73fSrenato 
112a78ea73fSrenato 		memcpy(&tlv, buf, TLV_HDR_SIZE);
1133b4c1866Srenato 		tlv_type = ntohs(tlv.type);
114a78ea73fSrenato 		tlv_len = ntohs(tlv.length);
115a78ea73fSrenato 		if (tlv_len + TLV_HDR_SIZE > len) {
116a78ea73fSrenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
117a78ea73fSrenato 			return (-1);
118a78ea73fSrenato 		}
119a78ea73fSrenato 		buf += TLV_HDR_SIZE;
120a78ea73fSrenato 		len -= TLV_HDR_SIZE;
121a78ea73fSrenato 
1223b4c1866Srenato 		/*
1233b4c1866Srenato 		 * RFC 5561 - Section 6:
1243b4c1866Srenato 		 * "The S-bit of a Capability Parameter in an Initialization
1253b4c1866Srenato 		 * message MUST be 1 and SHOULD be ignored on receipt".
1263b4c1866Srenato 		 */
1273b4c1866Srenato 		switch (tlv_type) {
128a78ea73fSrenato 		case TLV_TYPE_ATMSESSIONPAR:
12960e1e0e7Srenato 			session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
130080776f3Sclaudio 			return (-1);
131a78ea73fSrenato 		case TLV_TYPE_FRSESSION:
132a78ea73fSrenato 			session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
133a78ea73fSrenato 			return (-1);
1343b4c1866Srenato 		case TLV_TYPE_DYNAMIC_CAP:
1353b4c1866Srenato 			if (tlv_len != CAP_TLV_DYNAMIC_LEN) {
1363b4c1866Srenato 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
1373b4c1866Srenato 				    msg.type);
1383b4c1866Srenato 				return (-1);
1393b4c1866Srenato 			}
1403b4c1866Srenato 
1413b4c1866Srenato 			if (caps_rcvd & F_CAP_TLV_RCVD_DYNAMIC) {
1423b4c1866Srenato 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
1433b4c1866Srenato 				    msg.type);
1443b4c1866Srenato 				return (-1);
1453b4c1866Srenato 			}
1463b4c1866Srenato 			caps_rcvd |= F_CAP_TLV_RCVD_DYNAMIC;
1473b4c1866Srenato 
1483b4c1866Srenato 			nbr->flags |= F_NBR_CAP_DYNAMIC;
1493b4c1866Srenato 
1503b4c1866Srenato 			log_debug("%s: lsr-id %s announced the Dynamic "
1513b4c1866Srenato 			    "Capability Announcement capability", __func__,
1523b4c1866Srenato 			    inet_ntoa(nbr->id));
1533b4c1866Srenato 			break;
154c7c5a728Srenato 		case TLV_TYPE_TWCARD_CAP:
155c7c5a728Srenato 			if (tlv_len != CAP_TLV_TWCARD_LEN) {
156c7c5a728Srenato 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
157c7c5a728Srenato 				    msg.type);
158c7c5a728Srenato 				return (-1);
159c7c5a728Srenato 			}
160c7c5a728Srenato 
161c7c5a728Srenato 			if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
162c7c5a728Srenato 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
163c7c5a728Srenato 				    msg.type);
164c7c5a728Srenato 				return (-1);
165c7c5a728Srenato 			}
166c7c5a728Srenato 			caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
167c7c5a728Srenato 
168c7c5a728Srenato 			nbr->flags |= F_NBR_CAP_TWCARD;
169c7c5a728Srenato 
170c7c5a728Srenato 			log_debug("%s: lsr-id %s announced the Typed Wildcard "
171c7c5a728Srenato 			    "FEC capability", __func__, inet_ntoa(nbr->id));
172c7c5a728Srenato 			break;
173*9246985aSrenato 		case TLV_TYPE_UNOTIF_CAP:
174*9246985aSrenato 			if (tlv_len != CAP_TLV_UNOTIF_LEN) {
175*9246985aSrenato 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
176*9246985aSrenato 				    msg.type);
177*9246985aSrenato 				return (-1);
178*9246985aSrenato 			}
179*9246985aSrenato 
180*9246985aSrenato 			if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
181*9246985aSrenato 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
182*9246985aSrenato 				    msg.type);
183*9246985aSrenato 				return (-1);
184*9246985aSrenato 			}
185*9246985aSrenato 			caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
186*9246985aSrenato 
187*9246985aSrenato 			nbr->flags |= F_NBR_CAP_UNOTIF;
188*9246985aSrenato 
189*9246985aSrenato 			log_debug("%s: lsr-id %s announced the Unrecognized "
190*9246985aSrenato 			    "Notification capability", __func__,
191*9246985aSrenato 			    inet_ntoa(nbr->id));
192*9246985aSrenato 			break;
193a78ea73fSrenato 		default:
194a78ea73fSrenato 			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
1953b4c1866Srenato 				send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
1963b4c1866Srenato 				    msg.id, msg.type, tlv_type, tlv_len, buf);
197a78ea73fSrenato 			/* ignore unknown tlv */
198a78ea73fSrenato 			break;
199a78ea73fSrenato 		}
200a78ea73fSrenato 		buf += tlv_len;
201a78ea73fSrenato 		len -= tlv_len;
202080776f3Sclaudio 	}
20389f23408Sclaudio 
204a8c39dc0Srenato 	nbr->keepalive = min(nbr_get_keepalive(nbr->af, nbr->id),
2053d39db89Srenato 	    ntohs(sess.keepalive_time));
206ab0c2486Smichele 
207feeedd8aSrenato 	max_pdu_len = ntohs(sess.max_pdu_len);
208feeedd8aSrenato 	/*
209feeedd8aSrenato 	 * RFC 5036 - Section 3.5.3:
210feeedd8aSrenato 	 * "A value of 255 or less specifies the default maximum length of
211feeedd8aSrenato 	 * 4096 octets".
212feeedd8aSrenato 	 */
213feeedd8aSrenato 	if (max_pdu_len <= 255)
214feeedd8aSrenato 		max_pdu_len = LDP_MAX_LEN;
215feeedd8aSrenato 	nbr->max_pdu_len = min(max_pdu_len, LDP_MAX_LEN);
216feeedd8aSrenato 
217ab0c2486Smichele 	nbr_fsm(nbr, NBR_EVT_INIT_RCVD);
218ab0c2486Smichele 
2199277622bSrenato 	return (0);
220ab0c2486Smichele }
221ab0c2486Smichele 
2223b4c1866Srenato void
send_capability(struct nbr * nbr,uint16_t capability,int enable)2233b4c1866Srenato send_capability(struct nbr *nbr, uint16_t capability, int enable)
2243b4c1866Srenato {
2253b4c1866Srenato 	struct ibuf		*buf;
2263b4c1866Srenato 	uint16_t		 size;
2273b4c1866Srenato 	int			 err = 0;
2283b4c1866Srenato 
2293b4c1866Srenato 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
2303b4c1866Srenato 
2313b4c1866Srenato 	size = LDP_HDR_SIZE + LDP_MSG_SIZE + CAP_TLV_DYNAMIC_SIZE;
2323b4c1866Srenato 	if ((buf = ibuf_open(size)) == NULL)
2333b4c1866Srenato 		fatal(__func__);
2343b4c1866Srenato 
2353b4c1866Srenato 	err |= gen_ldp_hdr(buf, size);
2363b4c1866Srenato 	size -= LDP_HDR_SIZE;
2373b4c1866Srenato 	err |= gen_msg_hdr(buf, MSG_TYPE_CAPABILITY, size);
2383b4c1866Srenato 
2393b4c1866Srenato 	switch (capability) {
240c7c5a728Srenato 	case TLV_TYPE_TWCARD_CAP:
241c7c5a728Srenato 		err |= gen_cap_twcard_tlv(buf, enable);
242c7c5a728Srenato 		break;
243*9246985aSrenato 	case TLV_TYPE_UNOTIF_CAP:
244*9246985aSrenato 		err |= gen_cap_unotif_tlv(buf, enable);
245*9246985aSrenato 		break;
2463b4c1866Srenato 	case TLV_TYPE_DYNAMIC_CAP:
2473b4c1866Srenato 		/*
2483b4c1866Srenato 		 * RFC 5561 - Section 9:
2493b4c1866Srenato 		 * "An LDP speaker MUST NOT include the Dynamic Capability
2503b4c1866Srenato 		 * Announcement Parameter in Capability messages sent to
2513b4c1866Srenato 		 * its peers".
2523b4c1866Srenato 		 */
2533b4c1866Srenato 		/* FALLTHROUGH */
2543b4c1866Srenato 	default:
2553b4c1866Srenato 		fatalx("send_capability: unsupported capability");
2563b4c1866Srenato 	}
2573b4c1866Srenato 
2583b4c1866Srenato 	if (err) {
2593b4c1866Srenato 		ibuf_free(buf);
2603b4c1866Srenato 		return;
2613b4c1866Srenato 	}
2623b4c1866Srenato 
2633b4c1866Srenato 	evbuf_enqueue(&nbr->tcp->wbuf, buf);
2643b4c1866Srenato 	nbr_fsm(nbr, NBR_EVT_PDU_SENT);
2653b4c1866Srenato }
2663b4c1866Srenato 
2673b4c1866Srenato int
recv_capability(struct nbr * nbr,char * buf,uint16_t len)2683b4c1866Srenato recv_capability(struct nbr *nbr, char *buf, uint16_t len)
2693b4c1866Srenato {
2703b4c1866Srenato 	struct ldp_msg	 msg;
271c7c5a728Srenato 	int		 enable = 0;
272c7c5a728Srenato 	int		 caps_rcvd = 0;
2733b4c1866Srenato 
2743b4c1866Srenato 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
2753b4c1866Srenato 
2763b4c1866Srenato 	memcpy(&msg, buf, sizeof(msg));
2773b4c1866Srenato 	buf += LDP_MSG_SIZE;
2783b4c1866Srenato 	len -= LDP_MSG_SIZE;
2793b4c1866Srenato 
2803b4c1866Srenato 	/* Optional Parameters */
2813b4c1866Srenato 	while (len > 0) {
2823b4c1866Srenato 		struct tlv 	 tlv;
2833b4c1866Srenato 		uint16_t	 tlv_type;
2843b4c1866Srenato 		uint16_t	 tlv_len;
285c7c5a728Srenato 		uint8_t		 reserved;
2863b4c1866Srenato 
2873b4c1866Srenato 		if (len < sizeof(tlv)) {
2883b4c1866Srenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
2893b4c1866Srenato 			return (-1);
2903b4c1866Srenato 		}
2913b4c1866Srenato 
2923b4c1866Srenato 		memcpy(&tlv, buf, TLV_HDR_SIZE);
2933b4c1866Srenato 		tlv_type = ntohs(tlv.type);
2943b4c1866Srenato 		tlv_len = ntohs(tlv.length);
2953b4c1866Srenato 		if (tlv_len + TLV_HDR_SIZE > len) {
2963b4c1866Srenato 			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
2973b4c1866Srenato 			return (-1);
2983b4c1866Srenato 		}
2993b4c1866Srenato 		buf += TLV_HDR_SIZE;
3003b4c1866Srenato 		len -= TLV_HDR_SIZE;
3013b4c1866Srenato 
3023b4c1866Srenato 		switch (tlv_type) {
303c7c5a728Srenato 		case TLV_TYPE_TWCARD_CAP:
304c7c5a728Srenato 			if (tlv_len != CAP_TLV_TWCARD_LEN) {
305c7c5a728Srenato 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
306c7c5a728Srenato 				    msg.type);
307c7c5a728Srenato 				return (-1);
308c7c5a728Srenato 			}
309c7c5a728Srenato 
310c7c5a728Srenato 			if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
311c7c5a728Srenato 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
312c7c5a728Srenato 				    msg.type);
313c7c5a728Srenato 				return (-1);
314c7c5a728Srenato 			}
315c7c5a728Srenato 			caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
316c7c5a728Srenato 
317c7c5a728Srenato 			memcpy(&reserved, buf, sizeof(reserved));
318c7c5a728Srenato 			enable = reserved & STATE_BIT;
319c7c5a728Srenato 			if (enable)
320c7c5a728Srenato 				nbr->flags |= F_NBR_CAP_TWCARD;
321c7c5a728Srenato 			else
322c7c5a728Srenato 				nbr->flags &= ~F_NBR_CAP_TWCARD;
323c7c5a728Srenato 
324c7c5a728Srenato 			log_debug("%s: lsr-id %s %s the Typed Wildcard FEC "
325c7c5a728Srenato 			    "capability", __func__, inet_ntoa(nbr->id),
326c7c5a728Srenato 			    (enable) ? "announced" : "withdrew");
327c7c5a728Srenato 			break;
328*9246985aSrenato 		case TLV_TYPE_UNOTIF_CAP:
329*9246985aSrenato 			if (tlv_len != CAP_TLV_UNOTIF_LEN) {
330*9246985aSrenato 				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
331*9246985aSrenato 				    msg.type);
332*9246985aSrenato 				return (-1);
333*9246985aSrenato 			}
334*9246985aSrenato 
335*9246985aSrenato 			if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
336*9246985aSrenato 				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
337*9246985aSrenato 				    msg.type);
338*9246985aSrenato 				return (-1);
339*9246985aSrenato 			}
340*9246985aSrenato 			caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
341*9246985aSrenato 
342*9246985aSrenato 			memcpy(&reserved, buf, sizeof(reserved));
343*9246985aSrenato 			enable = reserved & STATE_BIT;
344*9246985aSrenato 			if (enable)
345*9246985aSrenato 				nbr->flags |= F_NBR_CAP_UNOTIF;
346*9246985aSrenato 			else
347*9246985aSrenato 				nbr->flags &= ~F_NBR_CAP_UNOTIF;
348*9246985aSrenato 
349*9246985aSrenato 			log_debug("%s: lsr-id %s %s the Unrecognized "
350*9246985aSrenato 			    "Notification capability", __func__,
351*9246985aSrenato 			    inet_ntoa(nbr->id), (enable) ? "announced" :
352*9246985aSrenato 			    "withdrew");
353*9246985aSrenato 			break;
3543b4c1866Srenato 		case TLV_TYPE_DYNAMIC_CAP:
3553b4c1866Srenato 			/*
3563b4c1866Srenato 		 	 * RFC 5561 - Section 9:
3573b4c1866Srenato 			 * "An LDP speaker that receives a Capability message
3583b4c1866Srenato 			 * from a peer that includes the Dynamic Capability
3593b4c1866Srenato 			 * Announcement Parameter SHOULD silently ignore the
3603b4c1866Srenato 			 * parameter and process any other Capability Parameters
3613b4c1866Srenato 			 * in the message".
3623b4c1866Srenato 			 */
3633b4c1866Srenato 			/* FALLTHROUGH */
3643b4c1866Srenato 		default:
3653b4c1866Srenato 			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
3663b4c1866Srenato 				send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
3673b4c1866Srenato 				    msg.id, msg.type, tlv_type, tlv_len, buf);
3683b4c1866Srenato 			/* ignore unknown tlv */
3693b4c1866Srenato 			break;
3703b4c1866Srenato 		}
3713b4c1866Srenato 		buf += tlv_len;
3723b4c1866Srenato 		len -= tlv_len;
3733b4c1866Srenato 	}
3743b4c1866Srenato 
3753b4c1866Srenato 	nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
3763b4c1866Srenato 
3773b4c1866Srenato 	return (0);
3783b4c1866Srenato }
3793b4c1866Srenato 
380c28a25a1Srenato static int
gen_init_prms_tlv(struct ibuf * buf,struct nbr * nbr)381d3e006a4Srenato gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr)
382ab0c2486Smichele {
383ab0c2486Smichele 	struct sess_prms_tlv	parms;
384ab0c2486Smichele 
3853de94509Srenato 	memset(&parms, 0, sizeof(parms));
386ab0c2486Smichele 	parms.type = htons(TLV_TYPE_COMMONSESSION);
38760e1e0e7Srenato 	parms.length = htons(SESS_PRMS_LEN);
388ab0c2486Smichele 	parms.proto_version = htons(LDP_VERSION);
389a8c39dc0Srenato 	parms.keepalive_time = htons(nbr_get_keepalive(nbr->af, nbr->id));
390ab0c2486Smichele 	parms.reserved = 0;
391ab0c2486Smichele 	parms.pvlim = 0;
392ab0c2486Smichele 	parms.max_pdu_len = 0;
393ab0c2486Smichele 	parms.lsr_id = nbr->id.s_addr;
394ab0c2486Smichele 	parms.lspace_id = 0;
395ab0c2486Smichele 
396e39620e5Snicm 	return (ibuf_add(buf, &parms, SESS_PRMS_SIZE));
397ab0c2486Smichele }
3983b4c1866Srenato 
3993b4c1866Srenato static int
gen_cap_dynamic_tlv(struct ibuf * buf)4003b4c1866Srenato gen_cap_dynamic_tlv(struct ibuf *buf)
4013b4c1866Srenato {
4023b4c1866Srenato 	struct capability_tlv	cap;
4033b4c1866Srenato 
4043b4c1866Srenato 	memset(&cap, 0, sizeof(cap));
4053b4c1866Srenato 	cap.type = htons(TLV_TYPE_DYNAMIC_CAP);
4063b4c1866Srenato 	cap.length = htons(CAP_TLV_DYNAMIC_LEN);
4073b4c1866Srenato 	/* the S-bit is always 1 for the Dynamic Capability Announcement */
4083b4c1866Srenato 	cap.reserved = STATE_BIT;
4093b4c1866Srenato 
4103b4c1866Srenato 	return (ibuf_add(buf, &cap, CAP_TLV_DYNAMIC_SIZE));
4113b4c1866Srenato }
412c7c5a728Srenato 
413c7c5a728Srenato static int
gen_cap_twcard_tlv(struct ibuf * buf,int enable)414c7c5a728Srenato gen_cap_twcard_tlv(struct ibuf *buf, int enable)
415c7c5a728Srenato {
416c7c5a728Srenato 	struct capability_tlv	cap;
417c7c5a728Srenato 
418c7c5a728Srenato 	memset(&cap, 0, sizeof(cap));
419c7c5a728Srenato 	cap.type = htons(TLV_TYPE_TWCARD_CAP);
420c7c5a728Srenato 	cap.length = htons(CAP_TLV_TWCARD_LEN);
421c7c5a728Srenato 	if (enable)
422c7c5a728Srenato 		cap.reserved = STATE_BIT;
423c7c5a728Srenato 
424c7c5a728Srenato 	return (ibuf_add(buf, &cap, CAP_TLV_TWCARD_SIZE));
425c7c5a728Srenato }
426*9246985aSrenato 
427*9246985aSrenato static int
gen_cap_unotif_tlv(struct ibuf * buf,int enable)428*9246985aSrenato gen_cap_unotif_tlv(struct ibuf *buf, int enable)
429*9246985aSrenato {
430*9246985aSrenato 	struct capability_tlv	cap;
431*9246985aSrenato 
432*9246985aSrenato 	memset(&cap, 0, sizeof(cap));
433*9246985aSrenato 	cap.type = htons(TLV_TYPE_UNOTIF_CAP);
434*9246985aSrenato 	cap.length = htons(CAP_TLV_UNOTIF_LEN);
435*9246985aSrenato 	if (enable)
436*9246985aSrenato 		cap.reserved = STATE_BIT;
437*9246985aSrenato 
438*9246985aSrenato 	return (ibuf_add(buf, &cap, CAP_TLV_UNOTIF_SIZE));
439*9246985aSrenato }
440