xref: /netbsd-src/usr.sbin/ldpd/socketops.c (revision 7feed94cb3ae21ac1bffa4c2e571d46d10bf8fb3)
1*7feed94cSriastradh /* $NetBSD: socketops.c,v 1.36 2022/06/26 17:55:38 riastradh Exp $ */
2e7341adaSkefren 
3269ea2d3Skefren /*
4e7341adaSkefren  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5e7341adaSkefren  * All rights reserved.
6e7341adaSkefren  *
7e7341adaSkefren  * This code is derived from software contributed to The NetBSD Foundation
8e7341adaSkefren  * by Mihai Chelaru <kefren@NetBSD.org>
9e7341adaSkefren  *
10e7341adaSkefren  * Redistribution and use in source and binary forms, with or without
11e7341adaSkefren  * modification, are permitted provided that the following conditions
12e7341adaSkefren  * are met:
13e7341adaSkefren  * 1. Redistributions of source code must retain the above copyright
14e7341adaSkefren  *    notice, this list of conditions and the following disclaimer.
15e7341adaSkefren  * 2. Redistributions in binary form must reproduce the above copyright
16e7341adaSkefren  *    notice, this list of conditions and the following disclaimer in the
17e7341adaSkefren  *    documentation and/or other materials provided with the distribution.
18e7341adaSkefren  *
19e7341adaSkefren  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20e7341adaSkefren  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21e7341adaSkefren  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22e7341adaSkefren  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23e7341adaSkefren  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24e7341adaSkefren  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25e7341adaSkefren  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26e7341adaSkefren  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27e7341adaSkefren  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28e7341adaSkefren  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29e7341adaSkefren  * POSSIBILITY OF SUCH DAMAGE.
30e7341adaSkefren  */
31e7341adaSkefren 
32e7341adaSkefren #include <sys/types.h>
33e7341adaSkefren #include <sys/stat.h>
34e7341adaSkefren #include <sys/socket.h>
35e7341adaSkefren #include <sys/ioctl.h>
36e7341adaSkefren #include <net/if.h>
37e7341adaSkefren #include <netinet/in.h>
38e7341adaSkefren #include <arpa/inet.h>
39e7341adaSkefren 
409b733c1cSkefren #include <assert.h>
41e7341adaSkefren #include <errno.h>
42e7341adaSkefren #include <ifaddrs.h>
43e7341adaSkefren #include <poll.h>
449b733c1cSkefren #include <signal.h>
459b733c1cSkefren #include <stdio.h>
469b733c1cSkefren #include <stdlib.h>
479b733c1cSkefren #include <strings.h>
489b733c1cSkefren #include <unistd.h>
49e7341adaSkefren 
50dd2b4ae9Skefren #include "conffile.h"
51e7341adaSkefren #include "fsm.h"
52e7341adaSkefren #include "ldp.h"
53e7341adaSkefren #include "ldp_command.h"
54e7341adaSkefren #include "tlv.h"
55e7341adaSkefren #include "ldp_peer.h"
56e7341adaSkefren #include "notifications.h"
57e7341adaSkefren #include "tlv_stack.h"
58e7341adaSkefren #include "mpls_interface.h"
59e7341adaSkefren #include "label.h"
60e7341adaSkefren #include "mpls_routes.h"
61e7341adaSkefren #include "ldp_errors.h"
62e7341adaSkefren #include "socketops.h"
63e7341adaSkefren 
642d8c8469Sjoerg struct hello_info_head hello_info_head;
652d8c8469Sjoerg static SLIST_HEAD(,hello_socket) hello_socket_head;
662d8c8469Sjoerg 
67e7341adaSkefren int ls;				/* TCP listening socket on port 646 */
68e7341adaSkefren int route_socket;		/* used to see when a route is added/deleted */
69e7341adaSkefren int command_socket;		/* Listening socket for interface command */
70e7341adaSkefren int current_msg_id = 0x233;
71e7341adaSkefren int command_port = LDP_COMMAND_PORT;
72e7341adaSkefren extern int      replay_index;
73e7341adaSkefren extern struct rt_msg replay_rt[REPLAY_MAX];
74e7341adaSkefren extern struct com_sock	csockets[MAX_COMMAND_SOCKETS];
75e7341adaSkefren 
76e7341adaSkefren int	ldp_hello_time = LDP_HELLO_TIME;
77e64aab24Skefren int	ldp_keepalive_time = LDP_KEEPALIVE_TIME;
78e64aab24Skefren int	ldp_holddown_time = LDP_HOLDTIME;
799b733c1cSkefren int	no_default_route = 1;
806cb06423Skefren int	loop_detection = 0;
81898c6f9fSkefren bool	may_connect;
82e7341adaSkefren 
83e7341adaSkefren void	recv_pdu(int);
84e7341adaSkefren void	send_hello_alarm(int);
85bec77c5fSjoerg __dead static void bail_out(int);
869b2110ebSkefren static void print_info(int);
87269ea2d3Skefren static int bind_socket(int s, int stype);
886cb06423Skefren static int set_tos(int);
896cb06423Skefren static int socket_reuse_port(int);
90e7341adaSkefren static int get_local_addr(struct sockaddr_dl *, struct in_addr *);
91269ea2d3Skefren static int is_hello_socket(int);
922cc7bf11Skefren static int is_passive_if(const char *if_name);
93e7341adaSkefren 
94e7341adaSkefren int
create_hello_sockets()956cb06423Skefren create_hello_sockets()
96e7341adaSkefren {
97e7341adaSkefren 	struct ip_mreq  mcast_addr;
98269ea2d3Skefren 	int s, joined_groups;
99269ea2d3Skefren 	struct ifaddrs *ifa, *ifb;
100269ea2d3Skefren 	uint lastifindex;
101ef9728bbSkefren #ifdef INET6
102ef9728bbSkefren 	struct ipv6_mreq mcast_addr6;
103269ea2d3Skefren 	struct sockaddr_in6 *if_sa6;
1046cb06423Skefren #endif
105269ea2d3Skefren 	struct hello_socket *hs;
106269ea2d3Skefren 
107269ea2d3Skefren 	SLIST_INIT(&hello_socket_head);
108e7341adaSkefren 
1096cb06423Skefren 	s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
110e7341adaSkefren 	if (s < 0)
111e7341adaSkefren 		return s;
112269ea2d3Skefren 	debugp("INET4 socket created (%d)\n", s);
113e7341adaSkefren 	/*
1146cb06423Skefren 	 * RFC5036 specifies we should listen to all subnet routers multicast
115e7341adaSkefren 	 * group
116e7341adaSkefren 	 */
117ad456077Skefren 	mcast_addr.imr_multiaddr.s_addr = htonl(INADDR_ALLRTRS_GROUP);
1186cb06423Skefren 
1196cb06423Skefren 	if (socket_reuse_port(s) < 0)
1206cb06423Skefren 		goto chs_error;
121269ea2d3Skefren 	/* Bind it to port 646 */
122269ea2d3Skefren 	if (bind_socket(s, AF_INET) == -1) {
1236cb06423Skefren 		warnp("Cannot bind INET hello socket\n");
1246cb06423Skefren 		goto chs_error;
125e7341adaSkefren 	}
1266cb06423Skefren 
127e7341adaSkefren 	/* We don't need to receive back our messages */
1285d14e920Skefren 	if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &(u_char){0},
1295d14e920Skefren 	    sizeof(u_char)) == -1) {
1306cb06423Skefren 		fatalp("INET setsockopt IP_MCAST_LOOP: %s\n", strerror(errno));
1316cb06423Skefren 		goto chs_error;
132e7341adaSkefren 	}
133269ea2d3Skefren 	/* Finally join the group on all interfaces */
134269ea2d3Skefren 	if (getifaddrs(&ifa) == -1) {
135269ea2d3Skefren 		fatalp("Cannot iterate interfaces\n");
136269ea2d3Skefren 		return -1;
1376cb06423Skefren 	}
138269ea2d3Skefren 	lastifindex = UINT_MAX;
139269ea2d3Skefren 	joined_groups = 0;
140269ea2d3Skefren 	for (ifb = ifa; ifb; ifb = ifb->ifa_next) {
141269ea2d3Skefren 		struct sockaddr_in *if_sa = (struct sockaddr_in *) ifb->ifa_addr;
142269ea2d3Skefren 		if (if_sa->sin_family != AF_INET || (!(ifb->ifa_flags & IFF_UP)) ||
143269ea2d3Skefren 		    (ifb->ifa_flags & IFF_LOOPBACK) ||
144dd2b4ae9Skefren 		    (!(ifb->ifa_flags & IFF_MULTICAST)) ||
145269ea2d3Skefren 		    (ntohl(if_sa->sin_addr.s_addr) >> 24 == IN_LOOPBACKNET) ||
146dd2b4ae9Skefren 		    is_passive_if(ifb->ifa_name) ||
147269ea2d3Skefren 		    lastifindex == if_nametoindex(ifb->ifa_name))
148269ea2d3Skefren 			continue;
149269ea2d3Skefren 		lastifindex = if_nametoindex(ifb->ifa_name);
1506cb06423Skefren 
151269ea2d3Skefren 		mcast_addr.imr_interface.s_addr = if_sa->sin_addr.s_addr;
152269ea2d3Skefren 		debugp("Join IPv4 mcast on %s\n", ifb->ifa_name);
153e7341adaSkefren         	if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mcast_addr,
154e7341adaSkefren 		    sizeof(mcast_addr)) == -1) {
1556cb06423Skefren         	        fatalp("setsockopt ADD_MEMBER: %s\n", strerror(errno));
1566cb06423Skefren 			goto chs_error;
157e7341adaSkefren         	}
158269ea2d3Skefren 		joined_groups++;
159269ea2d3Skefren 		if (joined_groups == IP_MAX_MEMBERSHIPS) {
160269ea2d3Skefren 			warnp("Maximum group memberships reached for INET socket\n");
161269ea2d3Skefren 			break;
162269ea2d3Skefren 		}
163269ea2d3Skefren 	}
164269ea2d3Skefren 	/* TTL:1 for IPv4 */
165269ea2d3Skefren 	if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &(int){1},
166269ea2d3Skefren 	    sizeof(int)) == -1) {
167269ea2d3Skefren 		fatalp("set mcast ttl: %s\n", strerror(errno));
1686cb06423Skefren 		goto chs_error;
1696cb06423Skefren 	}
170269ea2d3Skefren 	/* TOS :0xc0 for IPv4 */
171e7341adaSkefren 	if (set_tos(s) == -1) {
172e7341adaSkefren 		fatalp("set_tos: %s", strerror(errno));
1736cb06423Skefren 		goto chs_error;
174e7341adaSkefren 	}
1756cb06423Skefren 	/* we need to get the input interface for message processing */
176269ea2d3Skefren 	if (setsockopt(s, IPPROTO_IP, IP_RECVIF, &(uint32_t){1},
177269ea2d3Skefren 	    sizeof(uint32_t)) == -1) {
178e7341adaSkefren 		fatalp("Cannot set IP_RECVIF\n");
1796cb06423Skefren 		goto chs_error;
180e7341adaSkefren 	}
181269ea2d3Skefren 
182269ea2d3Skefren 	hs = (struct hello_socket *)malloc(sizeof(*hs));
183269ea2d3Skefren 	if (hs == NULL) {
184269ea2d3Skefren 		fatalp("Cannot alloc hello_socket structure\n");
1856cb06423Skefren 		goto chs_error;
186269ea2d3Skefren 	}
187269ea2d3Skefren 	hs->type = AF_INET;
188269ea2d3Skefren 	hs->socket = s;
189269ea2d3Skefren 	SLIST_INSERT_HEAD(&hello_socket_head, hs, listentry);
1906cb06423Skefren 
1916cb06423Skefren #ifdef INET6
192269ea2d3Skefren 	/*
193269ea2d3Skefren 	 * Now we do the same for IPv6
194269ea2d3Skefren 	 */
195269ea2d3Skefren 	s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
196269ea2d3Skefren 	if (s < 0) {
197269ea2d3Skefren 		fatalp("Cannot create INET6 socket\n");
198269ea2d3Skefren 		return -1;
199269ea2d3Skefren 	}
200269ea2d3Skefren 	debugp("INET6 socket created (%d)\n", s);
2016cb06423Skefren 
202269ea2d3Skefren 	if (socket_reuse_port(s) < 0)
203269ea2d3Skefren 		goto chs_error;
204269ea2d3Skefren 
205269ea2d3Skefren 	if (bind_socket(s, AF_INET6) == -1) {
206269ea2d3Skefren 		fatalp("Cannot bind INET6 hello socket\n");
207269ea2d3Skefren 		goto chs_error;
208269ea2d3Skefren 	}
209269ea2d3Skefren 
210269ea2d3Skefren 	if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
211269ea2d3Skefren 	    &(uint){0}, sizeof(uint)) == -1) {
212269ea2d3Skefren 		fatalp("INET6 setsocketopt IP_MCAST_LOOP: %s\n",
213269ea2d3Skefren 		    strerror(errno));
214269ea2d3Skefren 		goto chs_error;
215269ea2d3Skefren 	}
216269ea2d3Skefren 
217269ea2d3Skefren 	lastifindex = UINT_MAX;
218ad456077Skefren 	mcast_addr6.ipv6mr_multiaddr = in6addr_linklocal_allrouters;
219269ea2d3Skefren 	for (ifb = ifa; ifb; ifb = ifb->ifa_next) {
220269ea2d3Skefren 		if_sa6 = (struct sockaddr_in6 *) ifb->ifa_addr;
221269ea2d3Skefren 		if (if_sa6->sin6_family != AF_INET6 ||
222269ea2d3Skefren 		    (!(ifb->ifa_flags & IFF_UP)) ||
223dd2b4ae9Skefren 		    (!(ifb->ifa_flags & IFF_MULTICAST)) ||
224269ea2d3Skefren 		    (ifb->ifa_flags & IFF_LOOPBACK) ||
225dd2b4ae9Skefren 		    is_passive_if(ifb->ifa_name) ||
226269ea2d3Skefren 		    IN6_IS_ADDR_LOOPBACK(&if_sa6->sin6_addr))
227269ea2d3Skefren 			continue;
228269ea2d3Skefren 		/*
229269ea2d3Skefren 		 * draft-ietf-mpls-ldp-ipv6-07 Section 5.1:
230269ea2d3Skefren 		 * Additionally, the link-local
231269ea2d3Skefren 		 * IPv6 address MUST be used as the source IP address in IPv6
232269ea2d3Skefren 		 * LDP Link Hellos.
233269ea2d3Skefren 		 */
234269ea2d3Skefren 		if (IN6_IS_ADDR_LINKLOCAL(&if_sa6->sin6_addr) == 0)
235269ea2d3Skefren 			continue;
236269ea2d3Skefren 		/* We should have only one LLADDR per interface, but... */
237269ea2d3Skefren 		if (lastifindex == if_nametoindex(ifb->ifa_name))
238269ea2d3Skefren 			continue;
239269ea2d3Skefren 		mcast_addr6.ipv6mr_interface = lastifindex =
240269ea2d3Skefren 		    if_nametoindex(ifb->ifa_name);
241269ea2d3Skefren 
242269ea2d3Skefren 		debugp("Join IPv6 mcast on %s\n", ifb->ifa_name);
243269ea2d3Skefren 		if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP,
244269ea2d3Skefren 		    (char *)&mcast_addr6, sizeof(mcast_addr6)) == -1) {
245269ea2d3Skefren 			fatalp("INET6 setsockopt JOIN: %s\n", strerror(errno));
246269ea2d3Skefren 			goto chs_error;
247269ea2d3Skefren 		}
248269ea2d3Skefren 	}
249269ea2d3Skefren 	freeifaddrs(ifa);
250269ea2d3Skefren 
251269ea2d3Skefren 	/* TTL: 255 for IPv6 - draft-ietf-mpls-ldp-ipv6-07 Section 9 */
252269ea2d3Skefren 	if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
253269ea2d3Skefren 	    &(int){255}, sizeof(int)) == -1) {
254269ea2d3Skefren 		fatalp("set mcast hops: %s\n", strerror(errno));
255269ea2d3Skefren 		goto chs_error;
256269ea2d3Skefren 	}
257269ea2d3Skefren 	if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
258269ea2d3Skefren 	    &(uint32_t){1}, sizeof(uint32_t)) == -1)
259269ea2d3Skefren 		goto chs_error;
260269ea2d3Skefren 
261269ea2d3Skefren 	hs = (struct hello_socket *)malloc(sizeof(*hs));
262269ea2d3Skefren 	if (hs == NULL) {
263269ea2d3Skefren 		fatalp("Memory alloc problem: hs\n");
264269ea2d3Skefren 		goto chs_error;
265269ea2d3Skefren 	}
266269ea2d3Skefren 
267269ea2d3Skefren 	hs->type = AF_INET6;
268269ea2d3Skefren 	hs->socket = s;
269269ea2d3Skefren 	SLIST_INSERT_HEAD(&hello_socket_head, hs, listentry);
270269ea2d3Skefren #endif
2716cb06423Skefren 	return 0;
2726cb06423Skefren chs_error:
2736cb06423Skefren 	close(s);
2746cb06423Skefren 	return -1;
275e7341adaSkefren }
276e7341adaSkefren 
277269ea2d3Skefren /* Check if parameter is a hello socket */
278269ea2d3Skefren int
is_hello_socket(int s)279269ea2d3Skefren is_hello_socket(int s)
280269ea2d3Skefren {
281269ea2d3Skefren 	struct hello_socket *hs;
282269ea2d3Skefren 
283269ea2d3Skefren 	SLIST_FOREACH(hs, &hello_socket_head, listentry)
284269ea2d3Skefren 		if (hs->socket == s)
285269ea2d3Skefren 			return 1;
286269ea2d3Skefren 	return 0;
287269ea2d3Skefren }
288269ea2d3Skefren 
289dd2b4ae9Skefren /* Check if interface is passive */
290dd2b4ae9Skefren static int
is_passive_if(const char * if_name)2912cc7bf11Skefren is_passive_if(const char *if_name)
292dd2b4ae9Skefren {
293f86d4fa9Skefren 	struct conf_interface *coif;
294dd2b4ae9Skefren 
295f86d4fa9Skefren 	SLIST_FOREACH(coif, &coifs_head, iflist)
296f86d4fa9Skefren 		if (strncasecmp(if_name, coif->if_name, IF_NAMESIZE) == 0 &&
297f86d4fa9Skefren 		    coif->passive != 0)
298dd2b4ae9Skefren 			return 1;
299dd2b4ae9Skefren 	return 0;
300dd2b4ae9Skefren }
301dd2b4ae9Skefren 
302e7341adaSkefren /* Sets the TTL to 1 as we don't want to transmit outside this subnet */
303e7341adaSkefren int
set_ttl(int s)304e7341adaSkefren set_ttl(int s)
305e7341adaSkefren {
306e7341adaSkefren 	int             ret;
307e7341adaSkefren 	if ((ret = setsockopt(s, IPPROTO_IP, IP_TTL, &(int){1}, sizeof(int)))
308e7341adaSkefren 	    == -1)
309e7341adaSkefren 		fatalp("set_ttl: %s", strerror(errno));
310e7341adaSkefren 	return ret;
311e7341adaSkefren }
312e7341adaSkefren 
313e7341adaSkefren /* Sets TOS to 0xc0 aka IP Precedence 6 */
3146cb06423Skefren static int
set_tos(int s)315e7341adaSkefren set_tos(int s)
316e7341adaSkefren {
317e7341adaSkefren 	int             ret;
318e7341adaSkefren 	if ((ret = setsockopt(s, IPPROTO_IP, IP_TOS, &(int){0xc0},
319e7341adaSkefren 	    sizeof(int))) == -1)
320e7341adaSkefren 		fatalp("set_tos: %s", strerror(errno));
321e7341adaSkefren 	return ret;
322e7341adaSkefren }
323e7341adaSkefren 
3246cb06423Skefren static int
socket_reuse_port(int s)325e7341adaSkefren socket_reuse_port(int s)
326e7341adaSkefren {
327e7341adaSkefren 	int ret;
328e7341adaSkefren 	if ((ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &(int){1},
329e7341adaSkefren 	    sizeof(int))) == -1)
330e7341adaSkefren 		fatalp("socket_reuse_port: %s", strerror(errno));
331e7341adaSkefren 	return ret;
332e7341adaSkefren }
333e7341adaSkefren 
334e7341adaSkefren /* binds an UDP socket */
3356cb06423Skefren static int
bind_socket(int s,int stype)336269ea2d3Skefren bind_socket(int s, int stype)
337e7341adaSkefren {
3385d14e920Skefren 	union sockunion su;
339e7341adaSkefren 
340269ea2d3Skefren 	assert (stype == AF_INET || stype == AF_INET6);
3416cb06423Skefren 
342ef05d886Smrg 	memset(&su, 0, sizeof su);
343269ea2d3Skefren 	if (stype == AF_INET) {
3445d14e920Skefren 		su.sin.sin_len = sizeof(su.sin);
3455d14e920Skefren 		su.sin.sin_family = AF_INET;
346269ea2d3Skefren 		su.sin.sin_addr.s_addr = htonl(INADDR_ANY);
3475d14e920Skefren 		su.sin.sin_port = htons(LDP_PORT);
3486cb06423Skefren 	}
3496cb06423Skefren #ifdef INET6
350269ea2d3Skefren 	else if (stype == AF_INET6) {
3515d14e920Skefren 		su.sin6.sin6_len = sizeof(su.sin6);
3525d14e920Skefren 		su.sin6.sin6_family = AF_INET6;
3535d14e920Skefren 		su.sin6.sin6_addr = in6addr_any;
3545d14e920Skefren 		su.sin6.sin6_port = htons(LDP_PORT);
3556cb06423Skefren 	}
3566cb06423Skefren #endif
3575d14e920Skefren 	if (bind(s, &su.sa, su.sa.sa_len)) {
3586cb06423Skefren 		fatalp("bind_socket: %s\n", strerror(errno));
359e7341adaSkefren 		return -1;
360e7341adaSkefren 	}
361e7341adaSkefren 	return 0;
362e7341adaSkefren }
363e7341adaSkefren 
364e7341adaSkefren /* Create / bind the TCP socket */
365e7341adaSkefren int
create_listening_socket(void)366e7341adaSkefren create_listening_socket(void)
367e7341adaSkefren {
368e7341adaSkefren 	struct sockaddr_in sa;
369e7341adaSkefren 	int             s;
370e7341adaSkefren 
371e7341adaSkefren 	sa.sin_len = sizeof(sa);
372e7341adaSkefren 	sa.sin_family = AF_INET;
373e7341adaSkefren 	sa.sin_port = htons(LDP_PORT);
374e7341adaSkefren 	sa.sin_addr.s_addr = htonl(INADDR_ANY);
375e7341adaSkefren 
3766cb06423Skefren 	s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
377e7341adaSkefren 	if (s < 0)
378e7341adaSkefren 		return s;
379e7341adaSkefren 	if (bind(s, (struct sockaddr *) & sa, sizeof(sa))) {
380e7341adaSkefren 		fatalp("bind: %s", strerror(errno));
381e7341adaSkefren 		close(s);
382e7341adaSkefren 		return -1;
383e7341adaSkefren 	}
384e7341adaSkefren 	if (listen(s, 10) == -1) {
385e7341adaSkefren 		fatalp("listen: %s", strerror(errno));
386e7341adaSkefren 		close(s);
387e7341adaSkefren 		return -1;
388e7341adaSkefren 	}
389e7341adaSkefren /*	if (set_tos(s) == -1) {
390e7341adaSkefren 		fatalp("set_tos: %s", strerror(errno));
391e7341adaSkefren 		close(s);
392e7341adaSkefren 		return -1;
393e7341adaSkefren 	}
394e7341adaSkefren */	return s;
395e7341adaSkefren }
396e7341adaSkefren 
397e7341adaSkefren /*
398e7341adaSkefren  * It's ugly. We need a function to pass all tlvs and create pdu but since I
399e7341adaSkefren  * use UDP socket only to send hellos, I didn't bother
400e7341adaSkefren  */
401e7341adaSkefren void
send_hello(void)402e7341adaSkefren send_hello(void)
403e7341adaSkefren {
404e7341adaSkefren 	struct hello_tlv *t;
405e7341adaSkefren 	struct common_hello_tlv *cht;
406e7341adaSkefren 	struct ldp_pdu  *spdu;
407*7feed94cSriastradh 	struct in_addr ldp_id;
408e7341adaSkefren 	struct transport_address_tlv *trtlv;
409e7341adaSkefren 	void *v;
410e7341adaSkefren 	struct sockaddr_in sadest;	/* Destination ALL_ROUTERS */
4116cb06423Skefren 	ssize_t sb = 0;			/* sent bytes */
412e7341adaSkefren 	struct ifaddrs *ifa, *ifb;
413e7341adaSkefren 	struct sockaddr_in *if_sa;
414269ea2d3Skefren 	int ip4socket = -1;
415269ea2d3Skefren 	uint lastifindex;
416269ea2d3Skefren 	struct hello_socket *hs;
417f86d4fa9Skefren 	struct conf_interface *coif;
418f86d4fa9Skefren 	bool bad_tr_addr;
4196cb06423Skefren #ifdef INET6
4206cb06423Skefren 	struct sockaddr_in6 sadest6;
421269ea2d3Skefren 	int ip6socket = -1;
4226cb06423Skefren #endif
423e7341adaSkefren 
4246cb06423Skefren #define BASIC_HELLO_MSG_SIZE (sizeof(struct ldp_pdu) + 	/* PDU */	\
425e7341adaSkefren 			TLV_TYPE_LENGTH + MSGID_SIZE +	/* Hello TLV */	\
426e7341adaSkefren 			/* Common Hello TLV */				\
4276cb06423Skefren 			sizeof(struct common_hello_tlv))
4286cb06423Skefren #define GENERAL_HELLO_MSG_SIZE BASIC_HELLO_MSG_SIZE + 			\
4296cb06423Skefren 			/* Transport Address */				\
4306cb06423Skefren 			sizeof(struct transport_address_tlv)
4316cb06423Skefren #define IPV4_HELLO_MSG_SIZE BASIC_HELLO_MSG_SIZE + 4 + sizeof(struct in_addr)
4326cb06423Skefren #define IPV6_HELLO_MSG_SIZE BASIC_HELLO_MSG_SIZE + 4 + sizeof(struct in6_addr)
433e7341adaSkefren 
4346cb06423Skefren 	if ((v = calloc(1, GENERAL_HELLO_MSG_SIZE)) == NULL) {
4356cb06423Skefren 		fatalp("alloc problem in send_hello()\n");
436e7341adaSkefren 		return;
437e7341adaSkefren 	}
438e7341adaSkefren 
439e7341adaSkefren 	spdu = (struct ldp_pdu *)((char *)v);
440e7341adaSkefren 	t = (struct hello_tlv *)(spdu + 1);
441e7341adaSkefren 	cht = &t->ch;	/* Hello tlv struct includes CHT */
442e7341adaSkefren 	trtlv = (struct transport_address_tlv *)(t + 1);
443e7341adaSkefren 
444e7341adaSkefren 	/* Prepare PDU envelope */
445e7341adaSkefren 	spdu->version = htons(LDP_VERSION);
4466cb06423Skefren 	spdu->length = htons(IPV4_HELLO_MSG_SIZE - PDU_VER_LENGTH);
447*7feed94cSriastradh 	inet_aton(LDP_ID, &ldp_id);
448*7feed94cSriastradh 	spdu->ldp_id = ldp_id;
449e7341adaSkefren 
450e7341adaSkefren 	/* Prepare Hello TLV */
451e7341adaSkefren 	t->type = htons(LDP_HELLO);
452e7341adaSkefren 	t->length = htons(MSGID_SIZE +
453e7341adaSkefren 			sizeof(struct common_hello_tlv) +
4546cb06423Skefren 			IPV4_HELLO_MSG_SIZE - BASIC_HELLO_MSG_SIZE);
455e7341adaSkefren 	/*
4562cc7bf11Skefren 	 * We used ID 0 instead of htonl(get_message_id()) because we've
4576cb06423Skefren 	 * seen hellos from Cisco routers doing the same thing
458e7341adaSkefren 	 */
459e7341adaSkefren 	t->messageid = 0;
460e7341adaSkefren 
461e7341adaSkefren 	/* Prepare Common Hello attributes */
462e7341adaSkefren 	cht->type = htons(TLV_COMMON_HELLO);
463e7341adaSkefren 	cht->length = htons(sizeof(cht->holdtime) + sizeof(cht->res));
464e64aab24Skefren 	cht->holdtime = htons(ldp_holddown_time);
465e7341adaSkefren 	cht->res = 0;
466e7341adaSkefren 
467e7341adaSkefren 	/*
4686cb06423Skefren 	 * Prepare Transport Address TLV RFC5036 says: "If this optional TLV
469e7341adaSkefren 	 * is not present the IPv4 source address for the UDP packet carrying
470e7341adaSkefren 	 * the Hello should be used." But we send it because everybody seems
471e7341adaSkefren 	 * to do so
472e7341adaSkefren 	 */
473e7341adaSkefren 	trtlv->type = htons(TLV_IPV4_TRANSPORT);
474e7341adaSkefren 	trtlv->length = htons(sizeof(struct in_addr));
475e7341adaSkefren 	/* trtlv->address will be set for each socket */
476e7341adaSkefren 
477e7341adaSkefren 	/* Destination sockaddr */
478e7341adaSkefren 	memset(&sadest, 0, sizeof(sadest));
479e7341adaSkefren 	sadest.sin_len = sizeof(sadest);
480e7341adaSkefren 	sadest.sin_family = AF_INET;
481e7341adaSkefren 	sadest.sin_port = htons(LDP_PORT);
482ad456077Skefren 	sadest.sin_addr.s_addr = htonl(INADDR_ALLRTRS_GROUP);
483e7341adaSkefren 
484269ea2d3Skefren 	/* Find our socket */
485269ea2d3Skefren 	SLIST_FOREACH(hs, &hello_socket_head, listentry)
486269ea2d3Skefren 		if (hs->type == AF_INET) {
487269ea2d3Skefren 			ip4socket = hs->socket;
488269ea2d3Skefren 			break;
489269ea2d3Skefren 		}
490269ea2d3Skefren 	assert(ip4socket >= 0);
491269ea2d3Skefren 
492e7341adaSkefren 	if (getifaddrs(&ifa) == -1) {
493e7341adaSkefren 		free(v);
494269ea2d3Skefren 		fatalp("Cannot enumerate interfaces\n");
495e7341adaSkefren 		return;
496e7341adaSkefren 	}
497e7341adaSkefren 
498269ea2d3Skefren 	lastifindex = UINT_MAX;
4996cb06423Skefren 	/* Loop all interfaces in order to send IPv4 hellos */
500e7341adaSkefren 	for (ifb = ifa; ifb; ifb = ifb->ifa_next) {
501e7341adaSkefren 		if_sa = (struct sockaddr_in *) ifb->ifa_addr;
502dd2b4ae9Skefren 		if (if_sa->sin_family != AF_INET ||
503dd2b4ae9Skefren 		    (!(ifb->ifa_flags & IFF_UP)) ||
504dd2b4ae9Skefren 		    (ifb->ifa_flags & IFF_LOOPBACK) ||
505dd2b4ae9Skefren 		    (!(ifb->ifa_flags & IFF_MULTICAST)) ||
506dd2b4ae9Skefren 		    is_passive_if(ifb->ifa_name) ||
507dd2b4ae9Skefren 		    (ntohl(if_sa->sin_addr.s_addr) >> 24 == IN_LOOPBACKNET) ||
508dd2b4ae9Skefren 		    lastifindex == if_nametoindex(ifb->ifa_name))
509e7341adaSkefren 			continue;
5106cb06423Skefren 
5116cb06423Skefren 		/* Send only once per interface, using primary address */
512269ea2d3Skefren 		if (lastifindex == if_nametoindex(ifb->ifa_name))
513e7341adaSkefren 			continue;
514f86d4fa9Skefren 		/* Check if there is transport address set for this interface */
515f86d4fa9Skefren 		bad_tr_addr = false;
516f86d4fa9Skefren 		SLIST_FOREACH(coif, &coifs_head, iflist)
517f86d4fa9Skefren 			if (strncasecmp(coif->if_name, ifb->ifa_name,
518f86d4fa9Skefren 			    IF_NAMESIZE) == 0 &&
519f86d4fa9Skefren 			    coif->tr_addr.s_addr != 0 &&
520f86d4fa9Skefren 			    coif->tr_addr.s_addr != if_sa->sin_addr.s_addr)
521f86d4fa9Skefren 				bad_tr_addr = true;
522f86d4fa9Skefren 		if (bad_tr_addr == true)
523f86d4fa9Skefren 			continue;
524269ea2d3Skefren 		lastifindex = if_nametoindex(ifb->ifa_name);
525269ea2d3Skefren 
526269ea2d3Skefren 		if (setsockopt(ip4socket, IPPROTO_IP, IP_MULTICAST_IF,
527e7341adaSkefren 		    &if_sa->sin_addr, sizeof(struct in_addr)) == -1) {
528e7341adaSkefren 			warnp("setsockopt failed: %s\n", strerror(errno));
529e7341adaSkefren 			continue;
530e7341adaSkefren 		}
5316cb06423Skefren 		trtlv->address.ip4addr.s_addr = if_sa->sin_addr.s_addr;
532e7341adaSkefren 
533269ea2d3Skefren 		/* Put it on the wire */
534269ea2d3Skefren 		sb = sendto(ip4socket, v, IPV4_HELLO_MSG_SIZE, 0,
535269ea2d3Skefren 			    (struct sockaddr *) & sadest, sizeof(sadest));
5366cb06423Skefren 		if (sb < (ssize_t)(IPV4_HELLO_MSG_SIZE))
537e7341adaSkefren 		    fatalp("send: %s", strerror(errno));
538e7341adaSkefren 		else
539269ea2d3Skefren 		    debugp("Sent (IPv4) %zd bytes on %s"
5406cb06423Skefren 			" (PDU: %d, Hello TLV: %d, CH: %d, TR: %d)\n",
5416cb06423Skefren 			sb, ifb->ifa_name,
5426cb06423Skefren 			ntohs(spdu->length), ntohs(t->length),
5436cb06423Skefren 			ntohs(cht->length), ntohs(trtlv->length));
5446cb06423Skefren 	}
5456cb06423Skefren #ifdef INET6
5466cb06423Skefren 	/* Adjust lengths */
5476cb06423Skefren 	spdu->length = htons(IPV6_HELLO_MSG_SIZE - PDU_VER_LENGTH);
5486cb06423Skefren 	t->length = htons(MSGID_SIZE +
5496cb06423Skefren 			sizeof(struct common_hello_tlv) +
5506cb06423Skefren 			IPV6_HELLO_MSG_SIZE - BASIC_HELLO_MSG_SIZE);
5516cb06423Skefren 	trtlv->length = htons(sizeof(struct in6_addr));
5526cb06423Skefren 	trtlv->type = htons(TLV_IPV6_TRANSPORT);
5536cb06423Skefren 
5546cb06423Skefren 	/* Prepare destination sockaddr */
5556cb06423Skefren 	memset(&sadest6, 0, sizeof(sadest6));
5566cb06423Skefren 	sadest6.sin6_len = sizeof(sadest6);
5576cb06423Skefren 	sadest6.sin6_family = AF_INET6;
5586cb06423Skefren 	sadest6.sin6_port = htons(LDP_PORT);
559ad456077Skefren 	sadest6.sin6_addr = in6addr_linklocal_allrouters;
5606cb06423Skefren 
561269ea2d3Skefren 	SLIST_FOREACH(hs, &hello_socket_head, listentry)
562269ea2d3Skefren 		if (hs->type == AF_INET6) {
563269ea2d3Skefren 			ip6socket = hs->socket;
564269ea2d3Skefren 			break;
565269ea2d3Skefren 		}
566269ea2d3Skefren 
567269ea2d3Skefren 	lastifindex = UINT_MAX;
5686cb06423Skefren 	for (ifb = ifa; ifb; ifb = ifb->ifa_next) {
569269ea2d3Skefren 		struct sockaddr_in6 * if_sa6 =
570269ea2d3Skefren 		    (struct sockaddr_in6 *) ifb->ifa_addr;
571269ea2d3Skefren 		if (if_sa6->sin6_family != AF_INET6 ||
572269ea2d3Skefren 		    (!(ifb->ifa_flags & IFF_UP)) ||
573dd2b4ae9Skefren 		    (!(ifb->ifa_flags & IFF_MULTICAST)) ||
574269ea2d3Skefren 		    (ifb->ifa_flags & IFF_LOOPBACK) ||
575dd2b4ae9Skefren 		    is_passive_if(ifb->ifa_name) ||
576269ea2d3Skefren 		    IN6_IS_ADDR_LOOPBACK(&if_sa6->sin6_addr))
5776cb06423Skefren 			continue;
57827b5caabSkefren 		/*
57927b5caabSkefren 		 * draft-ietf-mpls-ldp-ipv6-07 Section 5.1:
58027b5caabSkefren 		 * Additionally, the link-local
58127b5caabSkefren 		 * IPv6 address MUST be used as the source IP address in IPv6
58227b5caabSkefren 		 * LDP Link Hellos.
58327b5caabSkefren 		 */
58427b5caabSkefren 		if (IN6_IS_ADDR_LINKLOCAL(&if_sa6->sin6_addr) == 0)
58527b5caabSkefren 			continue;
586269ea2d3Skefren 		/* We should have only one LLADDR per interface, but... */
587269ea2d3Skefren 		if (lastifindex == if_nametoindex(ifb->ifa_name))
588269ea2d3Skefren 			continue;
589269ea2d3Skefren 		lastifindex = if_nametoindex(ifb->ifa_name);
5906cb06423Skefren 
591269ea2d3Skefren 		if (setsockopt(ip6socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
592269ea2d3Skefren 		    &lastifindex, sizeof(int)) == -1) {
593269ea2d3Skefren 			fatalp("ssopt6 IPV6_MULTICAST_IF failed: %s for %s\n",
594269ea2d3Skefren 			    strerror(errno), ifb->ifa_name);
5956cb06423Skefren 			continue;
5966cb06423Skefren 		}
597269ea2d3Skefren 
5986cb06423Skefren 		memcpy(&trtlv->address.ip6addr, &if_sa6->sin6_addr,
5996cb06423Skefren 		    sizeof(struct in6_addr));
6006cb06423Skefren 
6016cb06423Skefren 		/* Put it on the wire */
602269ea2d3Skefren 		sb = sendto(ip6socket, v, IPV6_HELLO_MSG_SIZE,
6036cb06423Skefren 			    0, (struct sockaddr *)&sadest6, sizeof(sadest6));
6046cb06423Skefren 		if (sb < (ssize_t)(IPV6_HELLO_MSG_SIZE))
605269ea2d3Skefren 		    fatalp("send6: %s", strerror(errno));
6066cb06423Skefren 		else
60776b8726cSpgoyette 		    debugp("Sent (IPv6) %zd bytes on %s "
6086cb06423Skefren 			"(PDU: %d, Hello TLV: %d, CH: %d TR: %d)\n",
609269ea2d3Skefren 			sb, ifb->ifa_name, htons(spdu->length),
610269ea2d3Skefren 			htons(t->length), htons(cht->length),
611269ea2d3Skefren 			htons(trtlv->length));
612e7341adaSkefren 	}
6136cb06423Skefren #endif
614e7341adaSkefren 	freeifaddrs(ifa);
615e7341adaSkefren 	free(v);
616e7341adaSkefren }
617e7341adaSkefren 
618e7341adaSkefren int
get_message_id(void)619e7341adaSkefren get_message_id(void)
620e7341adaSkefren {
621e7341adaSkefren 	current_msg_id++;
622e7341adaSkefren 	return current_msg_id;
623e7341adaSkefren }
624e7341adaSkefren 
625e7341adaSkefren static int
get_local_addr(struct sockaddr_dl * sdl,struct in_addr * sin)626e7341adaSkefren get_local_addr(struct sockaddr_dl *sdl, struct in_addr *sin)
627e7341adaSkefren {
628e7341adaSkefren 	struct ifaddrs *ifa, *ifb;
629e7341adaSkefren 	struct sockaddr_in *sinet;
630e7341adaSkefren 
631e7341adaSkefren 	if (sdl == NULL)
632e7341adaSkefren 		return -1;
633e7341adaSkefren 
634e7341adaSkefren 	if (getifaddrs(&ifa) == -1)
635e7341adaSkefren 		return -1;
636e7341adaSkefren 	for (ifb = ifa; ifb; ifb = ifb->ifa_next)
637e7341adaSkefren 		if (ifb->ifa_addr->sa_family == AF_INET) {
638e7341adaSkefren 			if (if_nametoindex(ifb->ifa_name) != sdl->sdl_index)
639e7341adaSkefren 				continue;
640e7341adaSkefren 			sinet = (struct sockaddr_in*) ifb->ifa_addr;
641e7341adaSkefren 			sin->s_addr = sinet->sin_addr.s_addr;
642e7341adaSkefren 			freeifaddrs(ifa);
643e7341adaSkefren 			return 0;
644e7341adaSkefren 		}
645e7341adaSkefren 	freeifaddrs(ifa);
646e7341adaSkefren 	return -1;
647e7341adaSkefren }
648e7341adaSkefren 
649e7341adaSkefren /* Receive PDUs on Multicast UDP socket */
650e7341adaSkefren void
recv_pdu(int sock)651e7341adaSkefren recv_pdu(int sock)
652e7341adaSkefren {
653e7341adaSkefren 	struct ldp_pdu  rpdu;
654e7341adaSkefren 	int             c, i;
655e7341adaSkefren 	struct msghdr msg;
656e7341adaSkefren 	struct iovec iov[1];
657e7341adaSkefren 	unsigned char recvspace[MAX_PDU_SIZE];
658e7341adaSkefren 	struct hello_tlv *t;
659269ea2d3Skefren 	union sockunion sender;
660e7341adaSkefren 	struct sockaddr_dl *sdl = NULL;
661e7341adaSkefren 	struct in_addr my_ldp_addr, local_addr;
662e7341adaSkefren 	struct cmsghdr *cmptr;
663e7341adaSkefren 	union {
664e7341adaSkefren 		struct cmsghdr cm;
665e7341adaSkefren 		char control[1024];
666e7341adaSkefren 	} control_un;
667e7341adaSkefren 
668e7341adaSkefren 	memset(&msg, 0, sizeof(msg));
669e7341adaSkefren 	msg.msg_control = control_un.control;
670e7341adaSkefren 	msg.msg_controllen = sizeof(control_un.control);
671e7341adaSkefren 	msg.msg_flags = 0;
672269ea2d3Skefren 	msg.msg_name = &sender;
673269ea2d3Skefren 	msg.msg_namelen = sizeof(sender);
674e7341adaSkefren 	iov[0].iov_base = recvspace;
675e7341adaSkefren 	iov[0].iov_len = sizeof(recvspace);
676e7341adaSkefren 	msg.msg_iov = iov;
677e7341adaSkefren 	msg.msg_iovlen = 1;
678e7341adaSkefren 
679e7341adaSkefren 	c = recvmsg(sock, &msg, MSG_WAITALL);
680e7341adaSkefren 
681e7341adaSkefren 	/* Check to see if this is larger than MIN_PDU_SIZE */
682e7341adaSkefren 	if (c < MIN_PDU_SIZE)
683e7341adaSkefren 		return;
684e7341adaSkefren 
685e7341adaSkefren 	/* Read the PDU */
686e7341adaSkefren 	i = get_pdu(recvspace, &rpdu);
687e7341adaSkefren 
688269ea2d3Skefren 	debugp("recv_pdu(%d): PDU(size: %d) from: %s\n", sock,
689269ea2d3Skefren 	    c, satos(&sender.sa));
690269ea2d3Skefren 
691e7341adaSkefren 	/* We currently understand Version 1 */
692e7341adaSkefren 	if (rpdu.version != LDP_VERSION) {
693269ea2d3Skefren 		warnp("recv_pdu: Version mismatch\n");
694e7341adaSkefren 		return;
695e7341adaSkefren 	}
696e7341adaSkefren 
697269ea2d3Skefren 	/* Check if it's our hello */
698e7341adaSkefren 	inet_aton(LDP_ID, &my_ldp_addr);
699e7341adaSkefren 	if (rpdu.ldp_id.s_addr == my_ldp_addr.s_addr) {
700269ea2d3Skefren 		/* It should not be looped. We set MULTICAST_LOOP 0 */
701269ea2d3Skefren 		fatalp("Received our PDU. Ignoring it\n");
702e7341adaSkefren 		return;
703e7341adaSkefren 	}
704e7341adaSkefren 
705e7341adaSkefren 	if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
706e7341adaSkefren 	    (msg.msg_flags & MSG_CTRUNC))
707e7341adaSkefren 		local_addr.s_addr = my_ldp_addr.s_addr;
708e7341adaSkefren 	else {
709e7341adaSkefren 		for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
710e7341adaSkefren 		    cmptr = CMSG_NXTHDR(&msg, cmptr))
711e7341adaSkefren 			if (cmptr->cmsg_level == IPPROTO_IP &&
712e7341adaSkefren 			    cmptr->cmsg_type == IP_RECVIF) {
713e7341adaSkefren 				sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
714e7341adaSkefren 				break;
715e7341adaSkefren 			}
716e7341adaSkefren 		if (get_local_addr(sdl, &local_addr) != 0)
717e7341adaSkefren 			local_addr.s_addr = my_ldp_addr.s_addr;
718e7341adaSkefren 	}
719e7341adaSkefren 
720e7341adaSkefren 
721e7341adaSkefren 	debugp("Read %d bytes from address %s Length: %.4d Version: %d\n",
722e7341adaSkefren 	       c, inet_ntoa(rpdu.ldp_id), rpdu.length, rpdu.version);
723e7341adaSkefren 
724e7341adaSkefren 	/* Fill the TLV messages */
725e7341adaSkefren 	t = get_hello_tlv(recvspace + i, c - i);
726898c6f9fSkefren 	run_ldp_hello(&rpdu, t, &sender.sa, &local_addr, sock, may_connect);
727e7341adaSkefren }
728e7341adaSkefren 
729e7341adaSkefren void
send_hello_alarm(int unused)730e7341adaSkefren send_hello_alarm(int unused)
731e7341adaSkefren {
7320c3c6bf2Skefren 	struct ldp_peer *p, *ptmp;
733e64aab24Skefren 	struct hello_info *hi, *hinext;
734e7341adaSkefren 	time_t          t = time(NULL);
735e7341adaSkefren 	int             olderrno = errno;
736e7341adaSkefren 
737898c6f9fSkefren 	if (may_connect == false)
738898c6f9fSkefren 		may_connect = true;
739e7341adaSkefren 	/* Send hellos */
740e7341adaSkefren 	if (!(t % ldp_hello_time))
741e7341adaSkefren 		send_hello();
742e7341adaSkefren 
743e7341adaSkefren 	/* Timeout -- */
744e7341adaSkefren 	SLIST_FOREACH(p, &ldp_peer_head, peers)
745e7341adaSkefren 		p->timeout--;
746e7341adaSkefren 
747e7341adaSkefren 	/* Check for timeout */
7480c3c6bf2Skefren 	SLIST_FOREACH_SAFE(p, &ldp_peer_head, peers, ptmp)
749e7341adaSkefren 		if (p->timeout < 1)
750e7341adaSkefren 			switch (p->state) {
751e7341adaSkefren 			case LDP_PEER_HOLDDOWN:
752e7341adaSkefren 				debugp("LDP holddown expired for peer %s\n",
753e7341adaSkefren 				       inet_ntoa(p->ldp_id));
754e7341adaSkefren 				ldp_peer_delete(p);
7550c3c6bf2Skefren 				break;
756e7341adaSkefren 			case LDP_PEER_ESTABLISHED:
757e7341adaSkefren 			case LDP_PEER_CONNECTED:
758e7341adaSkefren 				send_notification(p, 0,
759fcfdc0a1Skefren 				    NOTIF_FATAL|NOTIF_KEEP_ALIVE_TIMER_EXPIRED);
760e7341adaSkefren 				warnp("Keepalive expired for %s\n",
761e7341adaSkefren 				    inet_ntoa(p->ldp_id));
762e7341adaSkefren 				ldp_peer_holddown(p);
763e7341adaSkefren 				break;
764e7341adaSkefren 			}	/* switch */
765e7341adaSkefren 
766e7341adaSkefren 	/* send keepalives */
767e64aab24Skefren 	if (!(t % ldp_keepalive_time)) {
768e7341adaSkefren 		SLIST_FOREACH(p, &ldp_peer_head, peers)
769e7341adaSkefren 		    if (p->state == LDP_PEER_ESTABLISHED) {
770e7341adaSkefren 			debugp("Sending KeepAlive to %s\n",
771e7341adaSkefren 			    inet_ntoa(p->ldp_id));
772e7341adaSkefren 			keep_alive(p);
773e7341adaSkefren 		    }
774e7341adaSkefren 	}
775e7341adaSkefren 
77697dccf75Skefren 	/* Decrement and Check hello keepalives */
77797dccf75Skefren 	SLIST_FOREACH_SAFE(hi, &hello_info_head, infos, hinext) {
778c2db1af7Skefren 		if (hi->keepalive != 0xFFFF)
779e7341adaSkefren 			hi->keepalive--;
780e64aab24Skefren 		if (hi->keepalive < 1)
781e7341adaSkefren 			SLIST_REMOVE(&hello_info_head, hi, hello_info, infos);
78297dccf75Skefren 	}
783e7341adaSkefren 
784e7341adaSkefren 	/* Set the alarm again and bail out */
785e7341adaSkefren 	alarm(1);
786e7341adaSkefren 	errno = olderrno;
787e7341adaSkefren }
788e7341adaSkefren 
789bec77c5fSjoerg static void
bail_out(int x)790e7341adaSkefren bail_out(int x)
791e7341adaSkefren {
792e7341adaSkefren 	ldp_peer_holddown_all();
793e7341adaSkefren 	flush_mpls_routes();
794e7341adaSkefren 	exit(0);
795e7341adaSkefren }
796e7341adaSkefren 
7979b2110ebSkefren static void
print_info(int x)7989b2110ebSkefren print_info(int x)
7999b2110ebSkefren {
8009b2110ebSkefren 	printf("Info for %s\n-------\n", LDP_ID);
8019b2110ebSkefren 	printf("Neighbours:\n");
8029b2110ebSkefren 	show_neighbours(1, NULL);
8039b2110ebSkefren 	printf("Bindings:\n");
8049b2110ebSkefren 	show_bindings(1, NULL);
8059b2110ebSkefren 	printf("Labels:\n");
8069b2110ebSkefren 	show_labels(1, NULL);
8079b2110ebSkefren 	printf("--------\n");
8089b2110ebSkefren }
8099b2110ebSkefren 
810e7341adaSkefren /*
811e7341adaSkefren  * The big poll that catches every single event
812e7341adaSkefren  * on every socket.
813e7341adaSkefren  */
8149b733c1cSkefren int
the_big_loop(void)815e7341adaSkefren the_big_loop(void)
816e7341adaSkefren {
817e7341adaSkefren 	int		sock_error;
818e7341adaSkefren 	uint32_t	i;
819e7341adaSkefren 	socklen_t       sock_error_size = sizeof(int);
820e7341adaSkefren 	struct ldp_peer *p;
821e7341adaSkefren 	struct com_sock	*cs;
822e7341adaSkefren 	struct pollfd	pfd[MAX_POLL_FDS];
823269ea2d3Skefren 	struct hello_socket *hs;
824269ea2d3Skefren 	nfds_t pollsum;
825de09325dSroy #ifdef RO_MSGFILTER
826de09325dSroy 	unsigned char msgfilter[] = {
827de09325dSroy 		RTM_NEWADDR, RTM_DELADDR,
828de09325dSroy 		RTM_ADD, RTM_DELETE, RTM_CHANGE,
829de09325dSroy 	};
830de09325dSroy #endif
831e7341adaSkefren 
832269ea2d3Skefren 	assert(MAX_POLL_FDS > 5);
8339b733c1cSkefren 
834e7341adaSkefren 	SLIST_INIT(&hello_info_head);
835e7341adaSkefren 
836e7341adaSkefren 	signal(SIGALRM, send_hello_alarm);
837e7341adaSkefren 	signal(SIGPIPE, SIG_IGN);
838c2db1af7Skefren 	signal(SIGINT, bail_out);
839e7341adaSkefren 	signal(SIGTERM, bail_out);
8409b2110ebSkefren 	signal(SIGINFO, print_info);
841269ea2d3Skefren 
842269ea2d3Skefren 	/* Send first hellos in 5 seconds. Avoid No hello notifications */
843898c6f9fSkefren 	may_connect = false;
844269ea2d3Skefren 	alarm(5);
845e7341adaSkefren 
846e7341adaSkefren 	route_socket = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
8479b2110ebSkefren 	setsockopt(route_socket, SOL_SOCKET, SO_USELOOPBACK, &(int){0},
8489b2110ebSkefren 		sizeof(int));
849de09325dSroy #ifdef RO_MSGFILTER
850de09325dSroy 	setsockopt(route_socket, PF_ROUTE, RO_MSGFILTER, &msgfilter,
851de09325dSroy 		sizeof(msgfilter));
852de09325dSroy #endif
853e7341adaSkefren 
8549b733c1cSkefren 	sock_error = bind_current_routes();
8559b733c1cSkefren 	if (sock_error != LDP_E_OK) {
856e7341adaSkefren 		fatalp("Cannot get current routes\n");
8579b733c1cSkefren 		return sock_error;
8589b733c1cSkefren 	}
859e7341adaSkefren 
860e7341adaSkefren 	for (;;) {
861e7341adaSkefren 		pfd[0].fd = ls;
862e7341adaSkefren 		pfd[0].events = POLLRDNORM;
863e7341adaSkefren 		pfd[0].revents = 0;
864e7341adaSkefren 
865e7341adaSkefren 		pfd[1].fd = route_socket;
866e7341adaSkefren 		pfd[1].events = POLLRDNORM;
867e7341adaSkefren 		pfd[1].revents = 0;
868e7341adaSkefren 
869e7341adaSkefren 		pfd[2].fd = command_socket;
870e7341adaSkefren 		pfd[2].events = POLLRDNORM;
871e7341adaSkefren 		pfd[2].revents = 0;
872e7341adaSkefren 
873269ea2d3Skefren 		/* Hello sockets */
874269ea2d3Skefren 		pollsum = 3;
875269ea2d3Skefren 		SLIST_FOREACH(hs, &hello_socket_head, listentry) {
876269ea2d3Skefren 			pfd[pollsum].fd = hs->socket;
877269ea2d3Skefren 			pfd[pollsum].events = POLLIN;
878269ea2d3Skefren 			pfd[pollsum].revents = 0;
879269ea2d3Skefren 			pollsum++;
880269ea2d3Skefren 		}
881e7341adaSkefren 
882e7341adaSkefren 		/* Command sockets */
883e7341adaSkefren 		for (i=0; i < MAX_COMMAND_SOCKETS; i++)
884e7341adaSkefren 			if (csockets[i].socket != -1) {
8859b733c1cSkefren 				if (pollsum >= MAX_POLL_FDS)
8869b733c1cSkefren 					break;
887e7341adaSkefren 				pfd[pollsum].fd = csockets[i].socket;
888e7341adaSkefren 				pfd[pollsum].events = POLLIN;
889e7341adaSkefren 				pfd[pollsum].revents = 0;
890e7341adaSkefren 				pollsum++;
891e7341adaSkefren 			}
892e7341adaSkefren 
893e7341adaSkefren 		/* LDP Peer sockets */
894e7341adaSkefren 		SLIST_FOREACH(p, &ldp_peer_head, peers) {
895e7341adaSkefren 			if (p->socket < 1)
896e7341adaSkefren 				continue;
897e7341adaSkefren 			switch (p->state) {
898e7341adaSkefren 			    case LDP_PEER_CONNECTED:
899e7341adaSkefren 			    case LDP_PEER_ESTABLISHED:
9009b733c1cSkefren 				if (pollsum >= MAX_POLL_FDS)
9019b733c1cSkefren 					break;
902e7341adaSkefren 				pfd[pollsum].fd = p->socket;
903e7341adaSkefren 				pfd[pollsum].events = POLLRDNORM;
904e7341adaSkefren 				pfd[pollsum].revents = 0;
905e7341adaSkefren 				pollsum++;
906e7341adaSkefren 				break;
907e7341adaSkefren 			    case LDP_PEER_CONNECTING:
9089b733c1cSkefren 				if (pollsum >= MAX_POLL_FDS)
9099b733c1cSkefren 					break;
910e7341adaSkefren 				pfd[pollsum].fd = p->socket;
911e7341adaSkefren 				pfd[pollsum].events = POLLWRNORM;
912e7341adaSkefren 				pfd[pollsum].revents = 0;
913e7341adaSkefren 				pollsum++;
914e7341adaSkefren 				break;
915e7341adaSkefren 			}
916e7341adaSkefren 		}
917e7341adaSkefren 
918e7341adaSkefren 		if (pollsum >= MAX_POLL_FDS) {
919e7341adaSkefren 			fatalp("Too many sockets. Increase MAX_POLL_FDS\n");
9209b733c1cSkefren 			return LDP_E_TOO_MANY_FDS;
921e7341adaSkefren 		}
922e7341adaSkefren 		if (poll(pfd, pollsum, INFTIM) < 0) {
923e7341adaSkefren 			if (errno != EINTR)
924e7341adaSkefren 				fatalp("poll: %s", strerror(errno));
925e7341adaSkefren 			continue;
926e7341adaSkefren 		}
927e7341adaSkefren 
928e7341adaSkefren 		for (i = 0; i < pollsum; i++) {
929e7341adaSkefren 			if ((pfd[i].revents & POLLRDNORM) ||
930e7341adaSkefren 			    (pfd[i].revents & POLLIN)) {
931374dea10Skefren 				if(pfd[i].fd == ls)
932e7341adaSkefren 					new_peer_connection();
933374dea10Skefren 				else if (pfd[i].fd == route_socket) {
934e7341adaSkefren 					struct rt_msg xbuf;
9357eaad7a3Skefren 					int l, rtmlen = sizeof(xbuf);
9367eaad7a3Skefren 					/* Read at least rtm_msglen */
9377eaad7a3Skefren 					l = recv(route_socket, &xbuf,
9387eaad7a3Skefren 					  sizeof(u_short), MSG_PEEK);
9397eaad7a3Skefren 					if (l == sizeof(u_short))
9407eaad7a3Skefren 						rtmlen = xbuf.m_rtm.rtm_msglen;
941e7341adaSkefren 					do {
9427eaad7a3Skefren 						l = recv(route_socket, &xbuf,
9437eaad7a3Skefren 						    rtmlen, MSG_WAITALL);
944e7341adaSkefren 					} while ((l == -1) && (errno == EINTR));
945e7341adaSkefren 
946e7341adaSkefren 					if (l == -1)
947e7341adaSkefren 						break;
948e7341adaSkefren 
949374dea10Skefren 					check_route(&xbuf, l);
950e7341adaSkefren 
951269ea2d3Skefren 				} else if (is_hello_socket(pfd[i].fd) == 1) {
952e7341adaSkefren 					/* Receiving hello socket */
953e7341adaSkefren 					recv_pdu(pfd[i].fd);
954e7341adaSkefren 				} else if (pfd[i].fd == command_socket) {
955e7341adaSkefren 					command_accept(command_socket);
956e7341adaSkefren 				} else if ((cs = is_command_socket(pfd[i].fd))
957e7341adaSkefren 						!= NULL) {
958e7341adaSkefren 					command_dispatch(cs);
959e7341adaSkefren 				} else {
960e7341adaSkefren 					/* ldp peer socket */
961e7341adaSkefren 					p = get_ldp_peer_by_socket(pfd[i].fd);
962e7341adaSkefren 					if (p)
963e7341adaSkefren 						recv_session_pdu(p);
964e7341adaSkefren 				}
965e7341adaSkefren 			} else if(pfd[i].revents & POLLWRNORM) {
966e7341adaSkefren 				p = get_ldp_peer_by_socket(pfd[i].fd);
967e7341adaSkefren 				if (!p)
968e7341adaSkefren 					continue;
969ae8b7d00Skefren 				assert(p->state == LDP_PEER_CONNECTING);
9704671a6acSkefren 				if (getsockopt(pfd[i].fd, SOL_SOCKET, SO_ERROR,
9714671a6acSkefren 				    &sock_error, &sock_error_size) != 0 ||
9724671a6acSkefren 				    sock_error != 0) {
973e7341adaSkefren 					ldp_peer_holddown(p);
9744671a6acSkefren 					sock_error = 0;
975e7341adaSkefren 				} else {
976e7341adaSkefren 					p->state = LDP_PEER_CONNECTED;
977e7341adaSkefren 					send_initialize(p);
978e7341adaSkefren 				}
979e7341adaSkefren 			}
980e7341adaSkefren 		}
981e7341adaSkefren 
982e7341adaSkefren 		for (int ri = 0; ri < replay_index; ri++) {
983e7341adaSkefren 			debugp("Replaying: PID %d, SEQ %d\n",
984e7341adaSkefren 				replay_rt[ri].m_rtm.rtm_pid,
985e7341adaSkefren 				replay_rt[ri].m_rtm.rtm_seq);
986e7341adaSkefren 			check_route(&replay_rt[ri], sizeof(struct rt_msg));
987e7341adaSkefren                 }
988e7341adaSkefren 		replay_index = 0;
989e7341adaSkefren 	}	/* for (;;) */
990e7341adaSkefren }
991e7341adaSkefren 
992e7341adaSkefren void
new_peer_connection()993e7341adaSkefren new_peer_connection()
994e7341adaSkefren {
9950c72a2ffSkefren 	union sockunion peer_address, my_address;
9960c72a2ffSkefren 	struct in_addr *peer_ldp_id = NULL;
9970c72a2ffSkefren 	struct hello_info *hi;
998e7341adaSkefren 	int s;
999e7341adaSkefren 
10000c72a2ffSkefren 	s = accept(ls, &peer_address.sa,
10010c72a2ffSkefren 		& (socklen_t) { sizeof(union sockunion) } );
1002e7341adaSkefren 	if (s < 0) {
1003e7341adaSkefren 		fatalp("accept: %s", strerror(errno));
1004e7341adaSkefren 		return;
1005e7341adaSkefren 	}
1006e7341adaSkefren 
10070c72a2ffSkefren 	if (getsockname(s, &my_address.sa,
10080c72a2ffSkefren 	    & (socklen_t) { sizeof(union sockunion) } )) {
1009e7341adaSkefren 		fatalp("new_peer_connection(): cannot getsockname\n");
1010e7341adaSkefren 		close(s);
1011e7341adaSkefren 		return;
1012e7341adaSkefren 	}
1013bed325c4Skefren 
10140c72a2ffSkefren 	if (peer_address.sa.sa_family == AF_INET)
10150c72a2ffSkefren 		peer_address.sin.sin_port = 0;
10160c72a2ffSkefren 	else if (peer_address.sa.sa_family == AF_INET6)
10170c72a2ffSkefren 		peer_address.sin6.sin6_port = 0;
10180c72a2ffSkefren 	else {
10190c72a2ffSkefren 		fatalp("Unknown peer address family\n");
1020e7341adaSkefren 		close(s);
1021e7341adaSkefren 		return;
1022e7341adaSkefren 	}
10230c72a2ffSkefren 
1024bed325c4Skefren 	/* Already peered or in holddown ? */
1025bed325c4Skefren 	if (get_ldp_peer(&peer_address.sa) != NULL) {
1026bed325c4Skefren 		close(s);
1027bed325c4Skefren 		return;
1028bed325c4Skefren 	}
1029bed325c4Skefren 
1030bed325c4Skefren 	warnp("Accepted a connection from %s\n", satos(&peer_address.sa));
1031bed325c4Skefren 
10320c72a2ffSkefren 	/* Verify if it should connect - XXX: no check for INET6 */
10330c72a2ffSkefren 	if (peer_address.sa.sa_family == AF_INET &&
10340c72a2ffSkefren 	    ntohl(peer_address.sin.sin_addr.s_addr) <
10350c72a2ffSkefren 	    ntohl(my_address.sin.sin_addr.s_addr)) {
10360c72a2ffSkefren 		fatalp("Peer %s: connect from lower ID\n",
10370c72a2ffSkefren 		    satos(&peer_address.sa));
10380c72a2ffSkefren 		close(s);
10390c72a2ffSkefren 		return;
10400c72a2ffSkefren 	}
10410c72a2ffSkefren 
10420c72a2ffSkefren 	/* Match hello info in order to get ldp_id */
10430c72a2ffSkefren 	SLIST_FOREACH(hi, &hello_info_head, infos) {
10440c72a2ffSkefren 		if (sockaddr_cmp(&peer_address.sa,
10450c72a2ffSkefren 		    &hi->transport_address.sa) == 0) {
10460c72a2ffSkefren 			peer_ldp_id = &hi->ldp_id;
10470c72a2ffSkefren 			break;
10480c72a2ffSkefren 		}
10490c72a2ffSkefren 	}
10500c72a2ffSkefren 	if (peer_ldp_id == NULL) {
10519b2110ebSkefren 		warnp("Got connection from %s, but no hello info exists\n",
10520c72a2ffSkefren 		    satos(&peer_address.sa));
10530c72a2ffSkefren 		close(s);
10540c72a2ffSkefren 		return;
10550c72a2ffSkefren 	} else
10560c72a2ffSkefren 		ldp_peer_new(peer_ldp_id, &peer_address.sa, NULL,
10570c72a2ffSkefren 		    ldp_holddown_time, s);
1058e7341adaSkefren 
1059e7341adaSkefren }
1060e7341adaSkefren 
1061e7341adaSkefren void
send_initialize(const struct ldp_peer * p)10622cc7bf11Skefren send_initialize(const struct ldp_peer * p)
1063e7341adaSkefren {
1064e7341adaSkefren 	struct init_tlv ti;
1065e7341adaSkefren 
1066e7341adaSkefren 	ti.type = htons(LDP_INITIALIZE);
1067e7341adaSkefren 	ti.length = htons(sizeof(struct init_tlv) - TLV_TYPE_LENGTH);
1068e7341adaSkefren 	ti.messageid = htonl(get_message_id());
1069e7341adaSkefren 	ti.cs_type = htons(TLV_COMMON_SESSION);
1070e7341adaSkefren 	ti.cs_len = htons(CS_LEN);
1071e7341adaSkefren 	ti.cs_version = htons(LDP_VERSION);
1072e64aab24Skefren 	ti.cs_keepalive = htons(2 * ldp_keepalive_time);
1073e7341adaSkefren 	ti.cs_adpvlim = 0;
1074e7341adaSkefren 	ti.cs_maxpdulen = htons(MAX_PDU_SIZE);
1075e7341adaSkefren 	ti.cs_peeraddress.s_addr = p->ldp_id.s_addr;
1076e7341adaSkefren 	ti.cs_peeraddrspace = 0;
1077e7341adaSkefren 
1078e7341adaSkefren 	send_tlv(p, (struct tlv *) (void *) &ti);
1079e7341adaSkefren }
1080e7341adaSkefren 
1081e7341adaSkefren void
keep_alive(const struct ldp_peer * p)10822cc7bf11Skefren keep_alive(const struct ldp_peer * p)
1083e7341adaSkefren {
1084e7341adaSkefren 	struct ka_tlv   kt;
1085e7341adaSkefren 
1086e7341adaSkefren 	kt.type = htons(LDP_KEEPALIVE);
1087e7341adaSkefren 	kt.length = htons(sizeof(kt.messageid));
1088e7341adaSkefren 	kt.messageid = htonl(get_message_id());
1089e7341adaSkefren 
1090e7341adaSkefren 	send_tlv(p, (struct tlv *) (void *) &kt);
1091e7341adaSkefren }
1092e7341adaSkefren 
10939b2110ebSkefren /*
10949b2110ebSkefren  * Process a message received from a peer
10959b2110ebSkefren  */
1096e7341adaSkefren void
recv_session_pdu(struct ldp_peer * p)1097e7341adaSkefren recv_session_pdu(struct ldp_peer * p)
1098e7341adaSkefren {
1099e7341adaSkefren 	struct ldp_pdu *rpdu;
1100e7341adaSkefren 	struct address_tlv *atlv;
1101e7341adaSkefren 	struct al_tlv  *altlv;
1102e7341adaSkefren 	struct init_tlv	*itlv;
1103e7341adaSkefren 	struct label_map_tlv *lmtlv;
1104e7341adaSkefren 	struct fec_tlv *fectlv;
1105e4a17560Sjoerg 	struct label_tlv *labeltlv;
1106e7341adaSkefren 	struct notification_tlv *nottlv;
1107e7341adaSkefren 	struct hello_info *hi;
1108e7341adaSkefren 
1109e7341adaSkefren 	int             c;
1110e7341adaSkefren 	int32_t         wo = 0;
1111e7341adaSkefren 	struct tlv     *ttmp;
1112e7341adaSkefren 	unsigned char   recvspace[MAX_PDU_SIZE];
1113e7341adaSkefren 
1114e7341adaSkefren 	memset(recvspace, 0, MAX_PDU_SIZE);
1115e7341adaSkefren 
1116ae8b7d00Skefren 	do {
1117e7341adaSkefren 		c = recv(p->socket, (void *) recvspace, MAX_PDU_SIZE, MSG_PEEK);
1118ae8b7d00Skefren 	} while (c == -1 && errno == EINTR);
1119e7341adaSkefren 
1120e7341adaSkefren 	debugp("Ready to read %d bytes\n", c);
1121e7341adaSkefren 
1122e7341adaSkefren 	if (c < 1) {		/* Session closed */
1123e7341adaSkefren 		warnp("Error in connection with %s\n", inet_ntoa(p->ldp_id));
1124e7341adaSkefren 		ldp_peer_holddown(p);
1125e7341adaSkefren 		return;
1126e7341adaSkefren 	}
1127e7341adaSkefren 	if (c > MAX_PDU_SIZE) {
1128e7341adaSkefren 		debugp("Incoming PDU size exceeds MAX_PDU_SIZE !\n");
1129e7341adaSkefren 		return;
1130e7341adaSkefren 	}
1131e7341adaSkefren 	if (c < MIN_PDU_SIZE) {
11322cc7bf11Skefren 		debugp("PDU too small received from peer %s\n",
11332cc7bf11Skefren 		    inet_ntoa(p->ldp_id));
1134e7341adaSkefren 		return;
1135e7341adaSkefren 	}
1136e7341adaSkefren 	rpdu = (struct ldp_pdu *) recvspace;
1137ae8b7d00Skefren 	do {
1138e7341adaSkefren 		c = recv(p->socket, (void *) recvspace,
1139e7341adaSkefren 		    ntohs(rpdu->length) + PDU_VER_LENGTH, MSG_WAITALL);
1140ae8b7d00Skefren 	} while (c == -1 && errno == EINTR);
1141e7341adaSkefren 
1142ae8b7d00Skefren 	/* sanity check */
1143e7341adaSkefren 	if (check_recv_pdu(p, rpdu, c) != 0)
1144e7341adaSkefren 		return;
1145e7341adaSkefren 
1146e7341adaSkefren 	debugp("Read %d bytes, PDU size: %d bytes\n", c, ntohs(rpdu->length));
1147e7341adaSkefren 	wo = sizeof(struct ldp_pdu);
1148e7341adaSkefren 
1149e7341adaSkefren 	while (wo + TLV_TYPE_LENGTH < (uint)c) {
1150e7341adaSkefren 
1151e7341adaSkefren 		ttmp = (struct tlv *) (&recvspace[wo]);
1152e7341adaSkefren 
1153e7341adaSkefren 		if ((ntohs(ttmp->type) != LDP_KEEPALIVE) &&
1154e7341adaSkefren 		    (ntohs(ttmp->type) != LDP_LABEL_MAPPING)) {
1155e7341adaSkefren 			debugp("Got Type: 0x%.4X (Length: %d) from %s\n",
1156e7341adaSkefren 			    ntohs(ttmp->type), ntohs(ttmp->length),
1157e7341adaSkefren 			    inet_ntoa(p->ldp_id));
1158e7341adaSkefren 		} else
1159e7341adaSkefren 			debugp("Got Type: 0x%.4X (Length: %d) from %s\n",
1160e7341adaSkefren 			    ntohs(ttmp->type), ntohs(ttmp->length),
1161e7341adaSkefren 			    inet_ntoa(p->ldp_id));
1162e7341adaSkefren 
1163e7341adaSkefren 		/* Should we get the message ? */
1164e7341adaSkefren 		if (p->state != LDP_PEER_ESTABLISHED &&
1165e7341adaSkefren 		    ntohs(ttmp->type) != LDP_INITIALIZE &&
116621574795Skefren 		    ntohs(ttmp->type) != LDP_KEEPALIVE &&
116721574795Skefren 		    ntohs(ttmp->type) != LDP_NOTIFICATION)
1168e7341adaSkefren 			break;
1169e7341adaSkefren 		/* The big switch */
1170e7341adaSkefren 		switch (ntohs(ttmp->type)) {
1171e7341adaSkefren 		case LDP_INITIALIZE:
1172e7341adaSkefren 			itlv = (struct init_tlv *)ttmp;
1173e7341adaSkefren 			/* Check size */
1174e7341adaSkefren 			if (ntohs(itlv->length) <
1175e7341adaSkefren 			    sizeof(struct init_tlv) - TLV_TYPE_LENGTH) {
1176269ea2d3Skefren 				debugp("Bad size\n");
1177e7341adaSkefren 				send_notification(p, 0,
1178e7341adaSkefren 				    NOTIF_BAD_PDU_LEN | NOTIF_FATAL);
1179e7341adaSkefren 				ldp_peer_holddown(p);
1180e7341adaSkefren 				break;
1181e7341adaSkefren 			}
1182e7341adaSkefren 			/* Check version */
1183e7341adaSkefren 			if (ntohs(itlv->cs_version) != LDP_VERSION) {
1184269ea2d3Skefren 				debugp("Bad version");
1185e7341adaSkefren 				send_notification(p, ntohl(itlv->messageid),
1186e7341adaSkefren 					NOTIF_BAD_LDP_VER | NOTIF_FATAL);
1187e7341adaSkefren 				ldp_peer_holddown(p);
1188e7341adaSkefren 				break;
1189e7341adaSkefren 			}
1190e7341adaSkefren 			/* Check if we got any hello from this one */
1191e7341adaSkefren 			SLIST_FOREACH(hi, &hello_info_head, infos)
1192e7341adaSkefren 				if (hi->ldp_id.s_addr == rpdu->ldp_id.s_addr)
1193e7341adaSkefren 					break;
1194e7341adaSkefren 			if (hi == NULL) {
1195269ea2d3Skefren 			    debugp("No hello. Moving peer to holddown\n");
1196e7341adaSkefren 			    send_notification(p, ntohl(itlv->messageid),
1197e7341adaSkefren 				NOTIF_SESSION_REJECTED_NO_HELLO | NOTIF_FATAL);
1198e7341adaSkefren 			    ldp_peer_holddown(p);
1199e7341adaSkefren 			    break;
1200e7341adaSkefren 			}
1201e7341adaSkefren 
1202e7341adaSkefren 			if (!p->master) {
1203e7341adaSkefren 				send_initialize(p);
120412d5f1b2Skefren 				keep_alive(p);
1205e7341adaSkefren 			} else {
1206e7341adaSkefren 				p->state = LDP_PEER_ESTABLISHED;
1207e7341adaSkefren 				p->established_t = time(NULL);
1208e7341adaSkefren 				keep_alive(p);
1209e7341adaSkefren 
1210e7341adaSkefren 				/*
1211e7341adaSkefren 				 * Recheck here ldp id because we accepted
1212e7341adaSkefren 				 * connection without knowing who is it for sure
1213e7341adaSkefren 				 */
1214e7341adaSkefren 				p->ldp_id.s_addr = rpdu->ldp_id.s_addr;
1215e7341adaSkefren 
1216e7341adaSkefren 				fatalp("LDP neighbour %s is UP\n",
1217e7341adaSkefren 				    inet_ntoa(p->ldp_id));
1218e7341adaSkefren 				mpls_add_ldp_peer(p);
1219e7341adaSkefren 				send_addresses(p);
1220e7341adaSkefren 				send_all_bindings(p);
1221e7341adaSkefren 			}
1222e7341adaSkefren 			break;
1223e7341adaSkefren 		case LDP_KEEPALIVE:
1224e7341adaSkefren 			if ((p->state == LDP_PEER_CONNECTED) && (!p->master)) {
1225e7341adaSkefren 				p->state = LDP_PEER_ESTABLISHED;
1226e7341adaSkefren 				p->established_t = time(NULL);
1227e7341adaSkefren 				fatalp("LDP neighbour %s is UP\n",
1228e7341adaSkefren 				    inet_ntoa(p->ldp_id));
1229e7341adaSkefren 				mpls_add_ldp_peer(p);
1230e7341adaSkefren 				send_addresses(p);
1231e7341adaSkefren 				send_all_bindings(p);
1232e7341adaSkefren 			}
1233e7341adaSkefren 			p->timeout = p->holdtime;
1234e7341adaSkefren 			break;
1235e7341adaSkefren 		case LDP_ADDRESS:
1236e7341adaSkefren 			/* Add peer addresses */
1237e7341adaSkefren 			atlv = (struct address_tlv *) ttmp;
1238e7341adaSkefren 			altlv = (struct al_tlv *) (&atlv[1]);
1239e7341adaSkefren 			add_ifaddresses(p, altlv);
12409b2110ebSkefren 			/*
12419b2110ebSkefren 			 * try to see if we have labels with null peer that
12429b2110ebSkefren 			 * would match the new peer
12439b2110ebSkefren 			 */
12449b2110ebSkefren 			label_check_assoc(p);
1245e7341adaSkefren 			print_bounded_addresses(p);
1246e7341adaSkefren 			break;
1247e7341adaSkefren 		case LDP_ADDRESS_WITHDRAW:
1248e7341adaSkefren 			atlv = (struct address_tlv *) ttmp;
1249e7341adaSkefren 			altlv = (struct al_tlv *) (&atlv[1]);
1250e7341adaSkefren 			del_ifaddresses(p, altlv);
1251e7341adaSkefren 			break;
1252e7341adaSkefren 		case LDP_LABEL_MAPPING:
1253e7341adaSkefren 			lmtlv = (struct label_map_tlv *) ttmp;
1254e7341adaSkefren 			fectlv = (struct fec_tlv *) (&lmtlv[1]);
1255e7341adaSkefren 			labeltlv = (struct label_tlv *)((unsigned char *)fectlv
1256e7341adaSkefren 				+ ntohs(fectlv->length) + TLV_TYPE_LENGTH);
1257e7341adaSkefren 			map_label(p, fectlv, labeltlv);
1258e7341adaSkefren 			break;
1259e7341adaSkefren 		case LDP_LABEL_REQUEST:
1260e7341adaSkefren 			lmtlv = (struct label_map_tlv *) ttmp;
1261e7341adaSkefren 			fectlv = (struct fec_tlv *) (&lmtlv[1]);
1262e7341adaSkefren 			switch (request_respond(p, lmtlv, fectlv)) {
1263e7341adaSkefren 			case LDP_E_BAD_FEC:
1264e7341adaSkefren 				send_notification(p, ntohl(lmtlv->messageid),
1265e7341adaSkefren 					NOTIF_UNKNOWN_TLV);
1266e7341adaSkefren 				break;
1267e7341adaSkefren 			case LDP_E_BAD_AF:
1268e7341adaSkefren 				send_notification(p, ntohl(lmtlv->messageid),
1269e7341adaSkefren 					NOTIF_UNSUPPORTED_AF);
1270e7341adaSkefren 				break;
1271e7341adaSkefren 			case LDP_E_NO_SUCH_ROUTE:
1272e7341adaSkefren 				send_notification(p, ntohl(lmtlv->messageid),
1273e7341adaSkefren 					NOTIF_NO_ROUTE);
1274e7341adaSkefren 				break;
1275e7341adaSkefren 			}
1276e7341adaSkefren 			break;
1277e7341adaSkefren 		case LDP_LABEL_WITHDRAW:
1278e7341adaSkefren 			lmtlv = (struct label_map_tlv *) ttmp;
1279e7341adaSkefren 			fectlv = (struct fec_tlv *) (&lmtlv[1]);
1280e7341adaSkefren 			if (withdraw_label(p, fectlv) == LDP_E_OK) {
1281e7341adaSkefren 				/* Send RELEASE */
1282e7341adaSkefren 				prepare_release(ttmp);
1283e7341adaSkefren 				send_tlv(p, ttmp);
1284e7341adaSkefren 				}
1285e7341adaSkefren 			break;
1286e7341adaSkefren 		case LDP_LABEL_RELEASE:
1287e7341adaSkefren 			/*
1288e7341adaSkefren 			 * XXX: we need to make a timed queue...
1289e7341adaSkefren 			 * For now I just assume peers are processing messages
1290e7341adaSkefren 			 * correctly so I just ignore confirmations
1291e7341adaSkefren 			 */
1292e7341adaSkefren 			wo = -1;	/* Ignore rest of message */
1293e7341adaSkefren 			break;
1294e7341adaSkefren 		case LDP_LABEL_ABORT:
1295e7341adaSkefren 		/* XXX: For now I pretend I can process everything
12966cb06423Skefren 		 * RFC 5036, Section 3.5.9.1
1297e7341adaSkefren 		 * If an LSR receives a Label Abort Request Message after it
1298e7341adaSkefren 		 * has responded to the Label Request in question with a Label
1299e7341adaSkefren 		 * Mapping message or a Notification message, it ignores the
1300e7341adaSkefren 		 * abort request.
1301e7341adaSkefren 		 */
1302e7341adaSkefren 			wo = -1;
1303e7341adaSkefren 			break;
1304e7341adaSkefren 		case LDP_NOTIFICATION:
1305e7341adaSkefren 			nottlv = (struct notification_tlv *) ttmp;
1306e7341adaSkefren 			nottlv->st_code = ntohl(nottlv->st_code);
1307e7341adaSkefren 			fatalp("Got notification 0x%X from peer %s\n",
1308e7341adaSkefren 			    nottlv->st_code, inet_ntoa(p->ldp_id));
1309e7341adaSkefren 			if (nottlv->st_code >> 31) {
1310e7341adaSkefren 				fatalp("LDP peer %s signalized %s\n",
1311e7341adaSkefren 				    inet_ntoa(p->ldp_id),
1312e7341adaSkefren 				    NOTIF_STR[(nottlv->st_code << 1) >> 1]);
1313e7341adaSkefren 				ldp_peer_holddown(p);
1314e7341adaSkefren 				wo = -1;
1315e7341adaSkefren 			}
1316e7341adaSkefren 			break;
1317e7341adaSkefren 		case LDP_HELLO:
1318e7341adaSkefren 			/* No hellos should came on tcp session */
1319e7341adaSkefren 			wo = -1;
1320e7341adaSkefren 			break;
1321e7341adaSkefren 		default:
1322e7341adaSkefren 			warnp("Unknown TLV received from %s\n",
1323e7341adaSkefren 			    inet_ntoa(p->ldp_id));
1324e7341adaSkefren 			debug_tlv(ttmp);
1325e7341adaSkefren 			wo = -1;/* discard the rest of the message */
1326e7341adaSkefren 			break;
1327e7341adaSkefren 		}
1328e7341adaSkefren 		if (wo < 0) {
1329e7341adaSkefren 			debugp("Discarding the rest of the message\n");
1330e7341adaSkefren 			break;
1331e7341adaSkefren 		} else {
1332e7341adaSkefren 			wo += ntohs(ttmp->length) + TLV_TYPE_LENGTH;
1333e7341adaSkefren 			debugp("WORKED ON %u bytes (Left %d)\n", wo, c - wo);
1334e7341adaSkefren 		}
1335e7341adaSkefren 	}			/* while */
1336e7341adaSkefren 
1337e7341adaSkefren }
1338e7341adaSkefren 
1339e7341adaSkefren /* Sends a pdu, tlv pair to a connected peer */
1340e7341adaSkefren int
send_message(const struct ldp_peer * p,const struct ldp_pdu * pdu,const struct tlv * t)13412cc7bf11Skefren send_message(const struct ldp_peer * p, const struct ldp_pdu * pdu,
13422cc7bf11Skefren 	const struct tlv * t)
1343e7341adaSkefren {
1344e7341adaSkefren 	unsigned char   sendspace[MAX_PDU_SIZE];
1345e7341adaSkefren 
1346e7341adaSkefren 	/* Check if peer is connected */
1347e7341adaSkefren 	switch (p->state) {
1348e7341adaSkefren 	case LDP_PEER_CONNECTED:
1349e7341adaSkefren 	case LDP_PEER_ESTABLISHED:
1350e7341adaSkefren 		break;
1351e7341adaSkefren 	default:
1352e7341adaSkefren 		return -1;
1353e7341adaSkefren 	}
1354e7341adaSkefren 
1355e7341adaSkefren 	/* Check length validity first */
1356e7341adaSkefren 	if (ntohs(pdu->length) !=
1357e7341adaSkefren 	    ntohs(t->length) + TLV_TYPE_LENGTH + PDU_PAYLOAD_LENGTH) {
1358e7341adaSkefren 		fatalp("LDP: TLV - PDU incompability. Message discarded\n");
1359e7341adaSkefren 		fatalp("LDP: TLV len %d - PDU len %d\n", ntohs(t->length),
1360e7341adaSkefren 		    ntohs(pdu->length));
1361e7341adaSkefren 		return -1;
1362e7341adaSkefren 	}
1363e7341adaSkefren 	if (ntohs(t->length) + PDU_VER_LENGTH > MAX_PDU_SIZE) {
1364e7341adaSkefren 		fatalp("Message to large discarded\n");
1365e7341adaSkefren 		return -1;
1366e7341adaSkefren 	}
1367e7341adaSkefren 	/* Arrange them in a buffer and send */
1368e7341adaSkefren 	memcpy(sendspace, pdu, sizeof(struct ldp_pdu));
1369e7341adaSkefren 	memcpy(sendspace + sizeof(struct ldp_pdu), t,
1370e7341adaSkefren 	    ntohs(t->length) + TLV_TYPE_LENGTH);
1371e7341adaSkefren 
1372e7341adaSkefren 	/* Report keepalives only for DEBUG */
1373e7341adaSkefren 	if ((ntohs(t->type) != 0x201) && (ntohs(t->type) != 0x400)) {
1374e7341adaSkefren 		debugp("Sending message type 0x%.4X to %s (size: %d)\n",
1375e7341adaSkefren 		    ntohs(t->type), inet_ntoa(p->ldp_id), ntohs(t->length));
1376e7341adaSkefren 	} else
1377e7341adaSkefren 	/* downgraded from warnp to debugp for now */
1378e7341adaSkefren 		debugp("Sending message type 0x%.4X to %s (size: %d)\n",
1379e7341adaSkefren 		    ntohs(t->type), inet_ntoa(p->ldp_id), ntohs(t->length));
1380e7341adaSkefren 
1381e7341adaSkefren 	/* Send it finally */
1382e7341adaSkefren 	return send(p->socket, sendspace,
1383e7341adaSkefren 		ntohs(pdu->length) + PDU_VER_LENGTH, 0);
1384e7341adaSkefren }
1385e7341adaSkefren 
1386e7341adaSkefren /*
1387e7341adaSkefren  * Encapsulates TLV into a PDU and sends it to a peer
1388e7341adaSkefren  */
1389e7341adaSkefren int
send_tlv(const struct ldp_peer * p,const struct tlv * t)13902cc7bf11Skefren send_tlv(const struct ldp_peer * p, const struct tlv * t)
1391e7341adaSkefren {
1392*7feed94cSriastradh 	struct in_addr ldp_id;
1393e7341adaSkefren 	struct ldp_pdu  pdu;
1394e7341adaSkefren 
1395*7feed94cSriastradh 	inet_aton(LDP_ID, &ldp_id);
1396*7feed94cSriastradh 
1397e7341adaSkefren 	pdu.version = htons(LDP_VERSION);
1398*7feed94cSriastradh 	pdu.ldp_id = ldp_id;
1399e7341adaSkefren 	pdu.label_space = 0;
1400e7341adaSkefren 	pdu.length = htons(ntohs(t->length) + TLV_TYPE_LENGTH +
1401e7341adaSkefren 		PDU_PAYLOAD_LENGTH);
1402e7341adaSkefren 
1403e7341adaSkefren 	return send_message(p, &pdu, t);
1404e7341adaSkefren }
1405e7341adaSkefren 
1406e7341adaSkefren 
1407e7341adaSkefren int
send_addresses(const struct ldp_peer * p)14082cc7bf11Skefren send_addresses(const struct ldp_peer * p)
1409e7341adaSkefren {
1410e7341adaSkefren 	struct address_list_tlv *t;
1411e7341adaSkefren 	int             ret;
1412e7341adaSkefren 
1413e7341adaSkefren 	t = build_address_list_tlv();
1414e7341adaSkefren 
1415e7341adaSkefren 	ret = send_tlv(p, (struct tlv *) t);
1416e7341adaSkefren 	free(t);
1417e7341adaSkefren 	return ret;
1418e7341adaSkefren 
1419e7341adaSkefren }
1420