xref: /openbsd-src/usr.sbin/ldpd/hello.c (revision 8bc5e3a3aaccee091c0a327f1a8daa3593d0f628)
1*8bc5e3a3Sclaudio /*	$OpenBSD: hello.c,v 1.59 2023/07/03 11:51:27 claudio Exp $ */
2ab0c2486Smichele 
3ab0c2486Smichele /*
45dc9330aSrenato  * Copyright (c) 2013, 2016 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 <arpa/inet.h>
22ab0c2486Smichele #include <string.h>
23ab0c2486Smichele 
24ab0c2486Smichele #include "ldpd.h"
25ab0c2486Smichele #include "ldpe.h"
265411bbb6Srenato #include "log.h"
27ab0c2486Smichele 
28c28a25a1Srenato static int	gen_hello_prms_tlv(struct ibuf *buf, uint16_t, uint16_t);
29c28a25a1Srenato static int	gen_opt4_hello_prms_tlv(struct ibuf *, uint16_t, uint32_t);
30c28a25a1Srenato static int	gen_opt16_hello_prms_tlv(struct ibuf *, uint16_t, uint8_t *);
31c28a25a1Srenato static int	gen_ds_hello_prms_tlv(struct ibuf *, uint32_t);
32c28a25a1Srenato static int	tlv_decode_hello_prms(char *, uint16_t, uint16_t *, uint16_t *);
33c28a25a1Srenato static int	tlv_decode_opt_hello_prms(char *, uint16_t, int *, int,
34a8c39dc0Srenato 		    union ldpd_addr *, uint32_t *, uint16_t *);
35ab0c2486Smichele 
36ab0c2486Smichele int
send_hello(enum hello_type type,struct iface_af * ia,struct tnbr * tnbr)37a8c39dc0Srenato send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
38ab0c2486Smichele {
39a8c39dc0Srenato 	int			 af;
40a8c39dc0Srenato 	union ldpd_addr		 dst;
413de94509Srenato 	uint16_t		 size, holdtime = 0, flags = 0;
4283dcf737Sclaudio 	int			 fd = 0;
43a8c39dc0Srenato 	struct ibuf		*buf;
4465f1d9c1Srenato 	int			 err = 0;
4583dcf737Sclaudio 
4683dcf737Sclaudio 	switch (type) {
4783dcf737Sclaudio 	case HELLO_LINK:
48a8c39dc0Srenato 		af = ia->af;
49a8c39dc0Srenato 		holdtime = ia->hello_holdtime;
5083dcf737Sclaudio 		flags = 0;
51a8c39dc0Srenato 		fd = (ldp_af_global_get(&global, af))->ldp_disc_socket;
52a8c39dc0Srenato 
53a8c39dc0Srenato 		/* multicast destination address */
54a8c39dc0Srenato 		switch (af) {
55a8c39dc0Srenato 		case AF_INET:
565ff72af8Srenato 			if (!(leconf->ipv4.flags & F_LDPD_AF_NO_GTSM))
57d7525efdSrenato 				flags |= F_HELLO_GTSM;
58a8c39dc0Srenato 			dst.v4 = global.mcast_addr_v4;
59a8c39dc0Srenato 			break;
60a8c39dc0Srenato 		case AF_INET6:
61a8c39dc0Srenato 			dst.v6 = global.mcast_addr_v6;
62a8c39dc0Srenato 			break;
63a8c39dc0Srenato 		default:
64a8c39dc0Srenato 			fatalx("send_hello: unknown af");
65a8c39dc0Srenato 		}
6683dcf737Sclaudio 		break;
6783dcf737Sclaudio 	case HELLO_TARGETED:
68a8c39dc0Srenato 		af = tnbr->af;
6983dcf737Sclaudio 		holdtime = tnbr->hello_holdtime;
70d7525efdSrenato 		flags = F_HELLO_TARGETED;
716399cec1Srenato 		if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count)
72d7525efdSrenato 			flags |= F_HELLO_REQ_TARG;
73a8c39dc0Srenato 		fd = (ldp_af_global_get(&global, af))->ldp_edisc_socket;
74a8c39dc0Srenato 
75a8c39dc0Srenato 		/* unicast destination address */
76a8c39dc0Srenato 		dst = tnbr->addr;
7783dcf737Sclaudio 		break;
78a8c39dc0Srenato 	default:
79a8c39dc0Srenato 		fatalx("send_hello: unknown hello type");
8083dcf737Sclaudio 	}
81ab0c2486Smichele 
82a8c39dc0Srenato 	/* calculate message size */
83a8c39dc0Srenato 	size = LDP_HDR_SIZE + LDP_MSG_SIZE + sizeof(struct hello_prms_tlv);
84a8c39dc0Srenato 	switch (af) {
85a8c39dc0Srenato 	case AF_INET:
86a8c39dc0Srenato 		size += sizeof(struct hello_prms_opt4_tlv);
87a8c39dc0Srenato 		break;
88a8c39dc0Srenato 	case AF_INET6:
89a8c39dc0Srenato 		size += sizeof(struct hello_prms_opt16_tlv);
90a8c39dc0Srenato 		break;
91a8c39dc0Srenato 	default:
92a8c39dc0Srenato 		fatalx("send_hello: unknown af");
93a8c39dc0Srenato 	}
940e35860dSrenato 	size += sizeof(struct hello_prms_opt4_tlv);
95a8c39dc0Srenato 	if (ldp_is_dual_stack(leconf))
96a8c39dc0Srenato 		size += sizeof(struct hello_prms_opt4_tlv);
97ab0c2486Smichele 
989277622bSrenato 	/* generate message */
999277622bSrenato 	if ((buf = ibuf_open(size)) == NULL)
1009277622bSrenato 		fatal(__func__);
1019277622bSrenato 
10265f1d9c1Srenato 	err |= gen_ldp_hdr(buf, size);
103ab0c2486Smichele 	size -= LDP_HDR_SIZE;
10465f1d9c1Srenato 	err |= gen_msg_hdr(buf, MSG_TYPE_HELLO, size);
10565f1d9c1Srenato 	err |= gen_hello_prms_tlv(buf, holdtime, flags);
106ab0c2486Smichele 
107a8c39dc0Srenato 	/*
108a8c39dc0Srenato 	 * RFC 7552 - Section 6.1:
109a8c39dc0Srenato 	 * "An LSR MUST include only the transport address whose address
110a8c39dc0Srenato 	 * family is the same as that of the IP packet carrying the Hello
111a8c39dc0Srenato 	 * message".
112a8c39dc0Srenato 	 */
113a8c39dc0Srenato 	switch (af) {
114a8c39dc0Srenato 	case AF_INET:
11565f1d9c1Srenato 		err |= gen_opt4_hello_prms_tlv(buf, TLV_TYPE_IPV4TRANSADDR,
116a8c39dc0Srenato 		    leconf->ipv4.trans_addr.v4.s_addr);
117a8c39dc0Srenato 		break;
118a8c39dc0Srenato 	case AF_INET6:
11965f1d9c1Srenato 		err |= gen_opt16_hello_prms_tlv(buf, TLV_TYPE_IPV6TRANSADDR,
120a8c39dc0Srenato 		    leconf->ipv6.trans_addr.v6.s6_addr);
121a8c39dc0Srenato 		break;
122a8c39dc0Srenato 	default:
123a8c39dc0Srenato 		fatalx("send_hello: unknown af");
124a8c39dc0Srenato 	}
125a8c39dc0Srenato 
12665f1d9c1Srenato 	err |= gen_opt4_hello_prms_tlv(buf, TLV_TYPE_CONFIG,
1270e35860dSrenato 	    htonl(global.conf_seqnum));
1280e35860dSrenato 
129a8c39dc0Srenato    	/*
130a8c39dc0Srenato 	 * RFC 7552 - Section 6.1.1:
131a8c39dc0Srenato 	 * "A Dual-stack LSR (i.e., an LSR supporting Dual-stack LDP for a peer)
132a8c39dc0Srenato 	 * MUST include the Dual-Stack capability TLV in all of its LDP Hellos".
133a8c39dc0Srenato 	 */
134a8c39dc0Srenato 	if (ldp_is_dual_stack(leconf))
13565f1d9c1Srenato 		err |= gen_ds_hello_prms_tlv(buf, leconf->trans_pref);
13665f1d9c1Srenato 
13765f1d9c1Srenato 	if (err) {
13865f1d9c1Srenato 		ibuf_free(buf);
13965f1d9c1Srenato 		return (-1);
14065f1d9c1Srenato 	}
141a8c39dc0Srenato 
142*8bc5e3a3Sclaudio 	send_packet(fd, af, &dst, ia, ibuf_data(buf), ibuf_size(buf));
143e39620e5Snicm 	ibuf_free(buf);
144ab0c2486Smichele 
145ab0c2486Smichele 	return (0);
146ab0c2486Smichele }
147ab0c2486Smichele 
148ab0c2486Smichele void
recv_hello(struct in_addr lsr_id,struct ldp_msg * msg,int af,union ldpd_addr * src,struct iface * iface,int multicast,char * buf,uint16_t len)14960e1e0e7Srenato recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
150a8c39dc0Srenato     union ldpd_addr *src, struct iface *iface, int multicast, char *buf,
151a8c39dc0Srenato     uint16_t len)
152ab0c2486Smichele {
153a8c39dc0Srenato 	struct adj		*adj = NULL;
15420eeeb6fSrenato 	struct nbr		*nbr, *nbrt;
1553de94509Srenato 	uint16_t		 holdtime, flags;
156a8c39dc0Srenato 	int			 tlvs_rcvd;
157a8c39dc0Srenato 	int			 ds_tlv;
158a8c39dc0Srenato 	union ldpd_addr		 trans_addr;
159a8c39dc0Srenato 	uint32_t		 scope_id = 0;
1600e35860dSrenato 	uint32_t		 conf_seqnum;
161a8c39dc0Srenato 	uint16_t		 trans_pref;
16289f23408Sclaudio 	int			 r;
16383dcf737Sclaudio 	struct hello_source	 source;
164a8c39dc0Srenato 	struct iface_af		*ia = NULL;
16583dcf737Sclaudio 	struct tnbr		*tnbr = NULL;
166ab0c2486Smichele 
16789f23408Sclaudio 	r = tlv_decode_hello_prms(buf, len, &holdtime, &flags);
16889f23408Sclaudio 	if (r == -1) {
169d99a8fc3Srenato 		log_debug("%s: lsr-id %s: failed to decode params", __func__,
170bde0ea4fSclaudio 		    inet_ntoa(lsr_id));
171ab0c2486Smichele 		return;
17289f23408Sclaudio 	}
173caebcba6Srenato 	/* safety checks */
17469eaa65aSrenato 	if (holdtime != 0 && holdtime < MIN_HOLDTIME) {
175d99a8fc3Srenato 		log_debug("%s: lsr-id %s: invalid hello holdtime (%u)",
17669eaa65aSrenato 		    __func__, inet_ntoa(lsr_id), holdtime);
17769eaa65aSrenato 		return;
17869eaa65aSrenato 	}
179d7525efdSrenato 	if (multicast && (flags & F_HELLO_TARGETED)) {
180d99a8fc3Srenato 		log_debug("%s: lsr-id %s: multicast targeted hello", __func__,
181ac5a809bSrenato 		    inet_ntoa(lsr_id));
182ac5a809bSrenato 		return;
183ac5a809bSrenato 	}
184d7525efdSrenato 	if (!multicast && !((flags & F_HELLO_TARGETED))) {
185d99a8fc3Srenato 		log_debug("%s: lsr-id %s: unicast link hello", __func__,
186ac5a809bSrenato 		    inet_ntoa(lsr_id));
187ac5a809bSrenato 		return;
188ac5a809bSrenato 	}
189caebcba6Srenato 	buf += r;
190caebcba6Srenato 	len -= r;
191caebcba6Srenato 
192caebcba6Srenato 	r = tlv_decode_opt_hello_prms(buf, len, &tlvs_rcvd, af, &trans_addr,
1930e35860dSrenato 	    &conf_seqnum, &trans_pref);
194caebcba6Srenato 	if (r == -1) {
195caebcba6Srenato 		log_debug("%s: lsr-id %s: failed to decode optional params",
196caebcba6Srenato 		    __func__, inet_ntoa(lsr_id));
197caebcba6Srenato 		return;
198caebcba6Srenato 	}
199caebcba6Srenato 	if (r != len) {
200caebcba6Srenato 		log_debug("%s: lsr-id %s: unexpected data in message",
201caebcba6Srenato 		    __func__, inet_ntoa(lsr_id));
202caebcba6Srenato 		return;
203caebcba6Srenato 	}
204caebcba6Srenato 
205caebcba6Srenato 	/* implicit transport address */
206caebcba6Srenato 	if (!(tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR))
207caebcba6Srenato 		trans_addr = *src;
208caebcba6Srenato 	if (bad_addr(af, &trans_addr)) {
209caebcba6Srenato 		log_debug("%s: lsr-id %s: invalid transport address %s",
210caebcba6Srenato 		    __func__, inet_ntoa(lsr_id), log_addr(af, &trans_addr));
211caebcba6Srenato 		return;
212caebcba6Srenato 	}
213caebcba6Srenato 	if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&trans_addr.v6)) {
214caebcba6Srenato 		/*
215caebcba6Srenato 	 	 * RFC 7552 - Section 6.1:
21620eeeb6fSrenato 		 * "An LSR MUST use a global unicast IPv6 address in an IPv6
217caebcba6Srenato 		 * Transport Address optional object of outgoing targeted
218caebcba6Srenato 		 * Hellos and check for the same in incoming targeted Hellos
219caebcba6Srenato 		 * (i.e., MUST discard the targeted Hello if it failed the
220caebcba6Srenato 		 * check)".
221caebcba6Srenato 		 */
222d7525efdSrenato 		if (flags & F_HELLO_TARGETED) {
22320eeeb6fSrenato 			log_debug("%s: lsr-id %s: invalid targeted hello "
22420eeeb6fSrenato 			    "transport address %s", __func__, inet_ntoa(lsr_id),
22520eeeb6fSrenato 			     log_addr(af, &trans_addr));
226caebcba6Srenato 			return;
22720eeeb6fSrenato 		}
228caebcba6Srenato 		scope_id = iface->ifindex;
229caebcba6Srenato 	}
230ab0c2486Smichele 
2313de94509Srenato 	memset(&source, 0, sizeof(source));
232ddc8fec1Syasuoka 	source.lsr_id = lsr_id;
233d7525efdSrenato 	if (flags & F_HELLO_TARGETED) {
234a8c39dc0Srenato 		/*
235a8c39dc0Srenato 	 	 * RFC 7552 - Section 5.2:
236a8c39dc0Srenato 		* "The link-local IPv6 addresses MUST NOT be used as the
237d3e006a4Srenato 		* targeted LDP Hello packet's source or destination addresses".
238a8c39dc0Srenato 		*/
239a8c39dc0Srenato 		if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&src->v6)) {
240a8c39dc0Srenato 			log_debug("%s: lsr-id %s: targeted hello with "
241a8c39dc0Srenato 			    "link-local source address", __func__,
242a8c39dc0Srenato 			    inet_ntoa(lsr_id));
243a8c39dc0Srenato 			return;
244a8c39dc0Srenato 		}
245a8c39dc0Srenato 
246a8c39dc0Srenato 		tnbr = tnbr_find(leconf, af, src);
24799170248Srenato 
24899170248Srenato 		/* remove the dynamic tnbr if the 'R' bit was cleared */
24999170248Srenato 		if (tnbr && (tnbr->flags & F_TNBR_DYNAMIC) &&
250d7525efdSrenato 		    !((flags & F_HELLO_REQ_TARG))) {
25199170248Srenato 			tnbr->flags &= ~F_TNBR_DYNAMIC;
25299170248Srenato 			tnbr = tnbr_check(tnbr);
25399170248Srenato 		}
25499170248Srenato 
25583dcf737Sclaudio 		if (!tnbr) {
256d7525efdSrenato 			if (!((flags & F_HELLO_REQ_TARG) &&
257a8c39dc0Srenato 			    ((ldp_af_conf_get(leconf, af))->flags &
258a8c39dc0Srenato 			    F_LDPD_AF_THELLO_ACCEPT)))
25983dcf737Sclaudio 				return;
26083dcf737Sclaudio 
261a8c39dc0Srenato 			tnbr = tnbr_new(leconf, af, src);
26299170248Srenato 			tnbr->flags |= F_TNBR_DYNAMIC;
263b5921293Srenato 			tnbr_update(tnbr);
26483dcf737Sclaudio 			LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
26583dcf737Sclaudio 		}
26699170248Srenato 
26783dcf737Sclaudio 		source.type = HELLO_TARGETED;
26883dcf737Sclaudio 		source.target = tnbr;
26983dcf737Sclaudio 	} else {
270a8c39dc0Srenato 		ia = iface_af_get(iface, af);
27183dcf737Sclaudio 		source.type = HELLO_LINK;
272a8c39dc0Srenato 		source.link.ia = ia;
273a8c39dc0Srenato 		source.link.src_addr = *src;
27483dcf737Sclaudio 	}
27583dcf737Sclaudio 
276a8c39dc0Srenato 	adj = adj_find(&source);
277a8c39dc0Srenato 	nbr = nbr_find_ldpid(lsr_id.s_addr);
278a8c39dc0Srenato 
279a8c39dc0Srenato 	/* check dual-stack tlv */
280a8c39dc0Srenato 	ds_tlv = (tlvs_rcvd & F_HELLO_TLV_RCVD_DS) ? 1 : 0;
281a8c39dc0Srenato 	if (ds_tlv && trans_pref != leconf->trans_pref) {
282a8c39dc0Srenato 		/*
283a8c39dc0Srenato 	 	 * RFC 7552 - Section 6.1.1:
284a8c39dc0Srenato 		 * "If the Dual-Stack capability TLV is present and the remote
285a8c39dc0Srenato 		 * preference does not match the local preference (or does not
286a8c39dc0Srenato 		 * get recognized), then the LSR MUST discard the Hello message
287a8c39dc0Srenato 		 * and log an error.
288a8c39dc0Srenato 		 * If an LDP session was already in place, then the LSR MUST
289a8c39dc0Srenato 		 * send a fatal Notification message with status code of
290a8c39dc0Srenato 		 * 'Transport Connection Mismatch' and reset the session".
291a8c39dc0Srenato 		 */
292a8c39dc0Srenato 		log_debug("%s: lsr-id %s: remote transport preference does not "
293a8c39dc0Srenato 		    "match the local preference", __func__, inet_ntoa(lsr_id));
294a8c39dc0Srenato 		if (nbr)
29560e1e0e7Srenato 			session_shutdown(nbr, S_TRANS_MISMTCH, msg->id,
29660e1e0e7Srenato 			    msg->type);
297a8c39dc0Srenato 		if (adj)
298e373a269Srenato 			adj_del(adj, S_SHUTDOWN);
299ac5a809bSrenato 		return;
300ac5a809bSrenato 	}
301ac5a809bSrenato 
302a8c39dc0Srenato 	/*
303a8c39dc0Srenato 	 * Check for noncompliant dual-stack neighbor according to
304a8c39dc0Srenato 	 * RFC 7552 section 6.1.1.
305a8c39dc0Srenato 	 */
30620eeeb6fSrenato 	if (nbr && !ds_tlv) {
307a8c39dc0Srenato 		switch (af) {
308a8c39dc0Srenato 		case AF_INET:
309a8c39dc0Srenato 			if (nbr_adj_count(nbr, AF_INET6) > 0) {
310a8c39dc0Srenato 				session_shutdown(nbr, S_DS_NONCMPLNCE,
31160e1e0e7Srenato 				    msg->id, msg->type);
312a8c39dc0Srenato 				return;
313a8c39dc0Srenato 			}
314a8c39dc0Srenato 			break;
315a8c39dc0Srenato 		case AF_INET6:
316a8c39dc0Srenato 			if (nbr_adj_count(nbr, AF_INET) > 0) {
317a8c39dc0Srenato 				session_shutdown(nbr, S_DS_NONCMPLNCE,
31860e1e0e7Srenato 				    msg->id, msg->type);
319a8c39dc0Srenato 				return;
320a8c39dc0Srenato 			}
321a8c39dc0Srenato 			break;
322a8c39dc0Srenato 		default:
323a8c39dc0Srenato 			fatalx("recv_hello: unknown af");
324a8c39dc0Srenato 		}
325a8c39dc0Srenato 	}
326a8c39dc0Srenato 
327a8c39dc0Srenato 	/*
32820eeeb6fSrenato 	 * Protections against misconfigured networks and buggy implementations.
329a8c39dc0Srenato 	 */
33020eeeb6fSrenato 	if (nbr && nbr->af == af &&
331a8c39dc0Srenato 	    (ldp_addrcmp(af, &nbr->raddr, &trans_addr) ||
332a8c39dc0Srenato 	    nbr->raddr_scope != scope_id)) {
33320eeeb6fSrenato 		log_warnx("%s: lsr-id %s: hello packet advertising a different "
33420eeeb6fSrenato 		    "transport address", __func__, inet_ntoa(lsr_id));
33520eeeb6fSrenato 		if (adj)
336e373a269Srenato 			adj_del(adj, S_SHUTDOWN);
33720eeeb6fSrenato 		return;
33820eeeb6fSrenato 	}
33920eeeb6fSrenato 	if (nbr == NULL) {
34020eeeb6fSrenato 		nbrt = nbr_find_addr(af, &trans_addr);
34120eeeb6fSrenato 		if (nbrt) {
34220eeeb6fSrenato 			log_debug("%s: transport address %s is already being "
34320eeeb6fSrenato 			    "used by lsr-id %s", __func__, log_addr(af,
34420eeeb6fSrenato 			    &trans_addr), inet_ntoa(nbrt->id));
34520eeeb6fSrenato 			if (adj)
346e373a269Srenato 				adj_del(adj, S_SHUTDOWN);
347a8c39dc0Srenato 			return;
34883dcf737Sclaudio 		}
349ab0c2486Smichele 	}
350ab0c2486Smichele 
35120eeeb6fSrenato 	if (adj == NULL) {
35220eeeb6fSrenato 		adj = adj_new(lsr_id, &source, &trans_addr);
35320eeeb6fSrenato 		if (nbr) {
35420eeeb6fSrenato 			adj->nbr = nbr;
35520eeeb6fSrenato 			LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry);
35620eeeb6fSrenato 		}
35720eeeb6fSrenato 	}
35820eeeb6fSrenato 
35920eeeb6fSrenato 	/*
36020eeeb6fSrenato 	 * If the hello adjacency's address-family doesn't match the local
36120eeeb6fSrenato 	 * preference, then an adjacency is still created but we don't attempt
36220eeeb6fSrenato 	 * to start an LDP session.
36320eeeb6fSrenato 	 */
36420eeeb6fSrenato 	if (nbr == NULL && (!ds_tlv ||
3658eeefd1dSrenato 	    ((trans_pref == DUAL_STACK_LDPOV4 && af == AF_INET) ||
3668eeefd1dSrenato 	    (trans_pref == DUAL_STACK_LDPOV6 && af == AF_INET6))))
36720eeeb6fSrenato 		nbr = nbr_new(lsr_id, af, ds_tlv, &trans_addr, scope_id);
36820eeeb6fSrenato 
3695ff72af8Srenato 	/* dynamic LDPv4 GTSM negotiation as per RFC 6720 */
3705ff72af8Srenato 	if (nbr) {
371d7525efdSrenato 		if (flags & F_HELLO_GTSM)
3725ff72af8Srenato 			nbr->flags |= F_NBR_GTSM_NEGOTIATED;
3735ff72af8Srenato 		else
3745ff72af8Srenato 			nbr->flags &= ~F_NBR_GTSM_NEGOTIATED;
3755ff72af8Srenato 	}
3765ff72af8Srenato 
3770e35860dSrenato 	/* update neighbor's configuration sequence number */
3780e35860dSrenato 	if (nbr && (tlvs_rcvd & F_HELLO_TLV_RCVD_CONF)) {
3790e35860dSrenato 		if (conf_seqnum > nbr->conf_seqnum &&
3800e35860dSrenato 		    nbr_pending_idtimer(nbr))
3810e35860dSrenato 			nbr_stop_idtimer(nbr);
3820e35860dSrenato 		nbr->conf_seqnum = conf_seqnum;
3830e35860dSrenato 	}
3840e35860dSrenato 
38583dcf737Sclaudio 	/* always update the holdtime to properly handle runtime changes */
38683dcf737Sclaudio 	switch (source.type) {
38783dcf737Sclaudio 	case HELLO_LINK:
38883dcf737Sclaudio 		if (holdtime == 0)
38983dcf737Sclaudio 			holdtime = LINK_DFLT_HOLDTIME;
39071256830Srenato 
391a8c39dc0Srenato 		adj->holdtime = min(ia->hello_holdtime, holdtime);
39283dcf737Sclaudio 		break;
39383dcf737Sclaudio 	case HELLO_TARGETED:
39483dcf737Sclaudio 		if (holdtime == 0)
39583dcf737Sclaudio 			holdtime = TARGETED_DFLT_HOLDTIME;
39671256830Srenato 
39771256830Srenato 		adj->holdtime = min(tnbr->hello_holdtime, holdtime);
39883dcf737Sclaudio 	}
39983dcf737Sclaudio 	if (adj->holdtime != INFINITE_HOLDTIME)
40083dcf737Sclaudio 		adj_start_itimer(adj);
40183dcf737Sclaudio 	else
40283dcf737Sclaudio 		adj_stop_itimer(adj);
403ab0c2486Smichele 
40420eeeb6fSrenato 	if (nbr && nbr->state == NBR_STA_PRESENT && !nbr_pending_idtimer(nbr) &&
40520eeeb6fSrenato 	    nbr_session_active_role(nbr) && !nbr_pending_connect(nbr))
4061f7e7d77Sclaudio 		nbr_establish_connection(nbr);
407ab0c2486Smichele }
408ab0c2486Smichele 
409c28a25a1Srenato static int
gen_hello_prms_tlv(struct ibuf * buf,uint16_t holdtime,uint16_t flags)4103de94509Srenato gen_hello_prms_tlv(struct ibuf *buf, uint16_t holdtime, uint16_t flags)
411ab0c2486Smichele {
412ab0c2486Smichele 	struct hello_prms_tlv	parms;
413ab0c2486Smichele 
4143de94509Srenato 	memset(&parms, 0, sizeof(parms));
415ab0c2486Smichele 	parms.type = htons(TLV_TYPE_COMMONHELLO);
416f9479091Sclaudio 	parms.length = htons(sizeof(parms.holdtime) + sizeof(parms.flags));
41783dcf737Sclaudio 	parms.holdtime = htons(holdtime);
41883dcf737Sclaudio 	parms.flags = htons(flags);
419ab0c2486Smichele 
420e39620e5Snicm 	return (ibuf_add(buf, &parms, sizeof(parms)));
421ab0c2486Smichele }
422ab0c2486Smichele 
423c28a25a1Srenato static int
gen_opt4_hello_prms_tlv(struct ibuf * buf,uint16_t type,uint32_t value)4243de94509Srenato gen_opt4_hello_prms_tlv(struct ibuf *buf, uint16_t type, uint32_t value)
425f9479091Sclaudio {
426f9479091Sclaudio 	struct hello_prms_opt4_tlv	parms;
427f9479091Sclaudio 
4283de94509Srenato 	memset(&parms, 0, sizeof(parms));
42983dcf737Sclaudio 	parms.type = htons(type);
430a8c39dc0Srenato 	parms.length = htons(sizeof(parms.value));
43183dcf737Sclaudio 	parms.value = value;
432f9479091Sclaudio 
433f9479091Sclaudio 	return (ibuf_add(buf, &parms, sizeof(parms)));
434f9479091Sclaudio }
435f9479091Sclaudio 
436c28a25a1Srenato static int
gen_opt16_hello_prms_tlv(struct ibuf * buf,uint16_t type,uint8_t * value)437a8c39dc0Srenato gen_opt16_hello_prms_tlv(struct ibuf *buf, uint16_t type, uint8_t *value)
438a8c39dc0Srenato {
439a8c39dc0Srenato 	struct hello_prms_opt16_tlv	parms;
440a8c39dc0Srenato 
441a8c39dc0Srenato 	memset(&parms, 0, sizeof(parms));
442a8c39dc0Srenato 	parms.type = htons(type);
443a8c39dc0Srenato 	parms.length = htons(sizeof(parms.value));
444a8c39dc0Srenato 	memcpy(&parms.value, value, sizeof(parms.value));
445a8c39dc0Srenato 
446a8c39dc0Srenato 	return (ibuf_add(buf, &parms, sizeof(parms)));
447a8c39dc0Srenato }
448a8c39dc0Srenato 
449c28a25a1Srenato static int
gen_ds_hello_prms_tlv(struct ibuf * buf,uint32_t value)450a8c39dc0Srenato gen_ds_hello_prms_tlv(struct ibuf *buf, uint32_t value)
451a8c39dc0Srenato {
452a8c39dc0Srenato 	if (leconf->flags & F_LDPD_DS_CISCO_INTEROP)
453a8c39dc0Srenato 		value = htonl(value);
454a8c39dc0Srenato 	else
455a8c39dc0Srenato 		value = htonl(value << 28);
456a8c39dc0Srenato 
457a8c39dc0Srenato 	return (gen_opt4_hello_prms_tlv(buf, TLV_TYPE_DUALSTACK, value));
458a8c39dc0Srenato }
459a8c39dc0Srenato 
460c28a25a1Srenato static int
tlv_decode_hello_prms(char * buf,uint16_t len,uint16_t * holdtime,uint16_t * flags)4613de94509Srenato tlv_decode_hello_prms(char *buf, uint16_t len, uint16_t *holdtime,
4623de94509Srenato     uint16_t *flags)
463ab0c2486Smichele {
46489f23408Sclaudio 	struct hello_prms_tlv	tlv;
465ab0c2486Smichele 
46689f23408Sclaudio 	if (len < sizeof(tlv))
46789f23408Sclaudio 		return (-1);
4683de94509Srenato 	memcpy(&tlv, buf, sizeof(tlv));
469ab0c2486Smichele 
47089f23408Sclaudio 	if (tlv.type != htons(TLV_TYPE_COMMONHELLO))
47189f23408Sclaudio 		return (-1);
47260e1e0e7Srenato 	if (ntohs(tlv.length) != sizeof(tlv) - TLV_HDR_SIZE)
473ac5a809bSrenato 		return (-1);
474ab0c2486Smichele 
47589f23408Sclaudio 	*holdtime = ntohs(tlv.holdtime);
47689f23408Sclaudio 	*flags = ntohs(tlv.flags);
477ab0c2486Smichele 
47889f23408Sclaudio 	return (sizeof(tlv));
479ab0c2486Smichele }
480ab0c2486Smichele 
481c28a25a1Srenato static int
tlv_decode_opt_hello_prms(char * buf,uint16_t len,int * tlvs_rcvd,int af,union ldpd_addr * addr,uint32_t * conf_number,uint16_t * trans_pref)482a8c39dc0Srenato tlv_decode_opt_hello_prms(char *buf, uint16_t len, int *tlvs_rcvd, int af,
483a8c39dc0Srenato     union ldpd_addr *addr, uint32_t *conf_number, uint16_t *trans_pref)
484ab0c2486Smichele {
4854bde5742Sclaudio 	struct tlv	tlv;
4863de94509Srenato 	uint16_t	tlv_len;
4873de94509Srenato 	int		total = 0;
4880493f73aSmichele 
489a8c39dc0Srenato 	*tlvs_rcvd = 0;
4903de94509Srenato 	memset(addr, 0, sizeof(*addr));
4910493f73aSmichele 	*conf_number = 0;
492a8c39dc0Srenato 	*trans_pref = 0;
4930493f73aSmichele 
494a8c39dc0Srenato 	/*
495a8c39dc0Srenato 	 * RFC 7552 - Section 6.1:
496a8c39dc0Srenato 	 * "An LSR SHOULD accept the Hello message that contains both IPv4 and
497a8c39dc0Srenato 	 * IPv6 Transport Address optional objects but MUST use only the
498a8c39dc0Srenato 	 * transport address whose address family is the same as that of the
499a8c39dc0Srenato 	 * IP packet carrying the Hello message.  An LSR SHOULD accept only
500a8c39dc0Srenato 	 * the first Transport Address optional object for a given address
501a8c39dc0Srenato 	 * family in the received Hello message and ignore the rest if the
502a8c39dc0Srenato 	 * LSR receives more than one Transport Address optional object for a
503a8c39dc0Srenato 	 * given address family".
504a8c39dc0Srenato 	 */
50589f23408Sclaudio 	while (len >= sizeof(tlv)) {
50660e1e0e7Srenato 		memcpy(&tlv, buf, TLV_HDR_SIZE);
507a78ea73fSrenato 		tlv_len = ntohs(tlv.length);
508a78ea73fSrenato 		if (tlv_len + TLV_HDR_SIZE > len)
509a78ea73fSrenato 			return (-1);
51060e1e0e7Srenato 		buf += TLV_HDR_SIZE;
51160e1e0e7Srenato 		len -= TLV_HDR_SIZE;
51260e1e0e7Srenato 		total += TLV_HDR_SIZE;
5132c943183Srenato 
51489f23408Sclaudio 		switch (ntohs(tlv.type)) {
5150493f73aSmichele 		case TLV_TYPE_IPV4TRANSADDR:
516a8c39dc0Srenato 			if (tlv_len != sizeof(addr->v4))
5174bde5742Sclaudio 				return (-1);
518a87a4ad1Srenato 			if (af != AF_INET)
519a87a4ad1Srenato 				return (-1);
520a87a4ad1Srenato 			if (*tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR)
521a8c39dc0Srenato 				break;
5222c943183Srenato 			memcpy(&addr->v4, buf, sizeof(addr->v4));
523a8c39dc0Srenato 			*tlvs_rcvd |= F_HELLO_TLV_RCVD_ADDR;
524a8c39dc0Srenato 			break;
525a8c39dc0Srenato 		case TLV_TYPE_IPV6TRANSADDR:
526a8c39dc0Srenato 			if (tlv_len != sizeof(addr->v6))
527a8c39dc0Srenato 				return (-1);
528a87a4ad1Srenato 			if (af != AF_INET6)
529a87a4ad1Srenato 				return (-1);
530a87a4ad1Srenato 			if (*tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR)
531a8c39dc0Srenato 				break;
5322c943183Srenato 			memcpy(&addr->v6, buf, sizeof(addr->v6));
533a8c39dc0Srenato 			*tlvs_rcvd |= F_HELLO_TLV_RCVD_ADDR;
5340493f73aSmichele 			break;
5350493f73aSmichele 		case TLV_TYPE_CONFIG:
5363de94509Srenato 			if (tlv_len != sizeof(uint32_t))
5374bde5742Sclaudio 				return (-1);
5382c943183Srenato 			memcpy(conf_number, buf, sizeof(uint32_t));
539a8c39dc0Srenato 			*tlvs_rcvd |= F_HELLO_TLV_RCVD_CONF;
540a8c39dc0Srenato 			break;
541a8c39dc0Srenato 		case TLV_TYPE_DUALSTACK:
542a8c39dc0Srenato 			if (tlv_len != sizeof(uint32_t))
543a8c39dc0Srenato 				return (-1);
544a8c39dc0Srenato    			/*
545a8c39dc0Srenato 	 		 * RFC 7552 - Section 6.1:
546a8c39dc0Srenato 			 * "A Single-stack LSR does not need to use the
547a8c39dc0Srenato 			 * Dual-Stack capability in Hello messages and SHOULD
548a8c39dc0Srenato 			 * ignore this capability if received".
549a8c39dc0Srenato 			 */
550a8c39dc0Srenato 			if (!ldp_is_dual_stack(leconf))
551a8c39dc0Srenato 				break;
552a8c39dc0Srenato 			/* Shame on you, Cisco! */
553a8c39dc0Srenato 			if (leconf->flags & F_LDPD_DS_CISCO_INTEROP) {
5542c943183Srenato 				memcpy(trans_pref, buf + sizeof(uint16_t),
5552c943183Srenato 				    sizeof(uint16_t));
556a8c39dc0Srenato 				*trans_pref = ntohs(*trans_pref);
557a8c39dc0Srenato 			} else {
5582c943183Srenato 				memcpy(trans_pref, buf , sizeof(uint16_t));
559a8c39dc0Srenato 				*trans_pref = ntohs(*trans_pref) >> 12;
560a8c39dc0Srenato 			}
561a8c39dc0Srenato 			*tlvs_rcvd |= F_HELLO_TLV_RCVD_DS;
5620493f73aSmichele 			break;
5630493f73aSmichele 		default:
5644bde5742Sclaudio 			/* if unknown flag set, ignore TLV */
5654bde5742Sclaudio 			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
5660493f73aSmichele 				return (-1);
5674bde5742Sclaudio 			break;
5680493f73aSmichele 		}
5692c943183Srenato 		buf += tlv_len;
5702c943183Srenato 		len -= tlv_len;
5712c943183Srenato 		total += tlv_len;
5720493f73aSmichele 	}
5730493f73aSmichele 
5742d825b92Srenato 	return (total);
575ab0c2486Smichele }
576