Module Name:    src
Committed By:   kefren
Date:           Mon Nov 12 18:39:01 UTC 2012

Modified Files:
        src/usr.sbin/ldpd: Makefile conffile.c fsm.c ldp.h ldp_peer.c
            ldp_peer.h ldpd.8 main.c notifications.h socketops.c socketops.h
            tlv.h tlv_stack.c

Log Message:
* add initial IPv6 support - still incomplete at this moment, but it sends
  out there IPv6 hellos. Interoperability not yet tested.
* sync man page with reality


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/usr.sbin/ldpd/Makefile \
    src/usr.sbin/ldpd/conffile.c src/usr.sbin/ldpd/ldp.h \
    src/usr.sbin/ldpd/ldp_peer.c
cvs rdiff -u -r1.5 -r1.6 src/usr.sbin/ldpd/fsm.c src/usr.sbin/ldpd/ldpd.8
cvs rdiff -u -r1.1 -r1.2 src/usr.sbin/ldpd/ldp_peer.h \
    src/usr.sbin/ldpd/notifications.h src/usr.sbin/ldpd/tlv.h
cvs rdiff -u -r1.6 -r1.7 src/usr.sbin/ldpd/main.c
cvs rdiff -u -r1.11 -r1.12 src/usr.sbin/ldpd/socketops.c
cvs rdiff -u -r1.2 -r1.3 src/usr.sbin/ldpd/socketops.h
cvs rdiff -u -r1.4 -r1.5 src/usr.sbin/ldpd/tlv_stack.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.sbin/ldpd/Makefile
diff -u src/usr.sbin/ldpd/Makefile:1.3 src/usr.sbin/ldpd/Makefile:1.4
--- src/usr.sbin/ldpd/Makefile:1.3	Thu Dec 30 11:29:21 2010
+++ src/usr.sbin/ldpd/Makefile	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.3 2010/12/30 11:29:21 kefren Exp $
+# $NetBSD: Makefile,v 1.4 2012/11/12 18:39:00 kefren Exp $
 
 .include <bsd.own.mk>
 
@@ -22,4 +22,8 @@ SRCS=   conffile.c \
 
 LDADD+=	-lcrypt
 
+.if (${USE_INET6} != "no")
+CPPFLAGS+=-DINET6
+.endif
+
 .include <bsd.prog.mk>
Index: src/usr.sbin/ldpd/conffile.c
diff -u src/usr.sbin/ldpd/conffile.c:1.3 src/usr.sbin/ldpd/conffile.c:1.4
--- src/usr.sbin/ldpd/conffile.c:1.3	Tue Jun 14 11:28:51 2011
+++ src/usr.sbin/ldpd/conffile.c	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: conffile.c,v 1.3 2011/06/14 11:28:51 kefren Exp $ */
+/* $NetBSD: conffile.c,v 1.4 2012/11/12 18:39:00 kefren Exp $ */
 
 /*
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -45,7 +45,7 @@
 #define LINEMAXSIZE 1024
 
 extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port,
-	min_label, max_label, no_default_route;
+	min_label, max_label, no_default_route, loop_detection;
 int confh;
 struct in_addr conf_ldp_id;
 
@@ -62,6 +62,7 @@ static int Fldpid(char*);
 static int Fneighbour(char*);
 static int Gneighbour(struct conf_neighbour *, char *);
 static int Fnodefault(char*);
+static int Floopdetection(char*);
 
 struct conf_func {
 	char com[64];
@@ -79,6 +80,7 @@ struct conf_func main_commands[] = {
 	{ "neighbor", Fneighbour },
 	{ "neighbour", Fneighbour },
 	{ "no-default-route", Fnodefault },
+	{ "loop-detection", Floopdetection },
 	{ "", NULL },
 };
 
@@ -312,3 +314,13 @@ Fnodefault(char *line)
 	no_default_route = nd;
 	return 0;
 }
+
+int
+Floopdetection(char *line)
+{
+	int loopd = atoi(line);
+	if (loopd < 0)
+		return E_CONF_PARAM;
+	loop_detection = loopd;
+	return 0;
+}
Index: src/usr.sbin/ldpd/ldp.h
diff -u src/usr.sbin/ldpd/ldp.h:1.3 src/usr.sbin/ldpd/ldp.h:1.4
--- src/usr.sbin/ldpd/ldp.h:1.3	Thu Jun 16 14:48:30 2011
+++ src/usr.sbin/ldpd/ldp.h	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: ldp.h,v 1.3 2011/06/16 14:48:30 kefren Exp $ */
+/* $NetBSD: ldp.h,v 1.4 2012/11/12 18:39:00 kefren Exp $ */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -36,10 +36,11 @@
 #include <netinet/in.h>
 
 #define	ALL_ROUTERS		"224.0.0.2"
+#define	ALL_ROUTERS6		"FF02::2"
 #define	LDP_PORT		646
 #define	LDP_COMMAND_PORT	2626
 
-#define	LDPD_VER		"0.3.0"
+#define	LDPD_VER		"0.4.0"
 
 #define CONFFILE		"/etc/ldpd.conf"
 
Index: src/usr.sbin/ldpd/ldp_peer.c
diff -u src/usr.sbin/ldpd/ldp_peer.c:1.3 src/usr.sbin/ldpd/ldp_peer.c:1.4
--- src/usr.sbin/ldpd/ldp_peer.c:1.3	Thu Dec 30 11:29:21 2010
+++ src/usr.sbin/ldpd/ldp_peer.c	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: ldp_peer.c,v 1.3 2010/12/30 11:29:21 kefren Exp $ */
+/* $NetBSD: ldp_peer.c,v 1.4 2012/11/12 18:39:00 kefren Exp $ */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -68,7 +68,8 @@ ldp_peer_init(void)
  */
 struct ldp_peer *
 ldp_peer_new(struct in_addr * ldp_id, struct in_addr * a,
-	     struct in_addr * tradd, uint16_t holdtime, int soc)
+	     struct in_addr * tradd, struct in6_addr * tradd6,
+	     uint16_t holdtime, int soc)
 {
 	struct ldp_peer *p;
 	int s = soc;

Index: src/usr.sbin/ldpd/fsm.c
diff -u src/usr.sbin/ldpd/fsm.c:1.5 src/usr.sbin/ldpd/fsm.c:1.6
--- src/usr.sbin/ldpd/fsm.c:1.5	Thu Jun 16 14:48:30 2011
+++ src/usr.sbin/ldpd/fsm.c	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: fsm.c,v 1.5 2011/06/16 14:48:30 kefren Exp $ */
+/* $NetBSD: fsm.c,v 1.6 2012/11/12 18:39:00 kefren Exp $ */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -56,6 +56,7 @@ run_ldp_hello(struct ldp_pdu * pduid, st
 {
 	struct ldp_peer *peer = NULL;
 	struct in_addr  peer_addr;
+	struct in6_addr	peer_addr6;
 	struct transport_address_tlv *trtlv;
 	struct hello_info *hi;
 
@@ -113,16 +114,20 @@ run_ldp_hello(struct ldp_pdu * pduid, st
 			if (trtlv->type == TLV_IPV4_TRANSPORT)
 				memcpy(&peer_addr, &trtlv->address,
 				    sizeof(struct in_addr));
+			else if (trtlv->type == TLV_IPV6_TRANSPORT)
+				memcpy(&peer_addr6, &trtlv->address,
+				    sizeof(struct in6_addr));
 		} else
 			trtlv = NULL;
 		/*
-		 * RFC says: If A1 > A2, LSR1 plays the active role;
+		 * RFC 5036 2.5.2: If A1 > A2, LSR1 plays the active role;
 		 * otherwise it is passive.
 		 */
 		if (ntohl(peer_addr.s_addr) < ntohl(ladd->s_addr)) {
-#define	TRADDR (trtlv && trtlv->type == TLV_IPV4_TRANSPORT) ? &peer_addr : NULL
+#define	TR_INET4_ADDR (trtlv && trtlv->type == TLV_IPV4_TRANSPORT) ? &peer_addr : NULL
+#define TR_INET6_ADDR NULL
 			peer = ldp_peer_new(&pduid->ldp_id, padd,
-				TRADDR, ht->ch.holdtime, 0);
+				TR_INET4_ADDR, TR_INET6_ADDR, ht->ch.holdtime, 0);
 			if (!peer)
 				return;
 			if (peer && peer->state == LDP_PEER_CONNECTED)
Index: src/usr.sbin/ldpd/ldpd.8
diff -u src/usr.sbin/ldpd/ldpd.8:1.5 src/usr.sbin/ldpd/ldpd.8:1.6
--- src/usr.sbin/ldpd/ldpd.8:1.5	Thu Jul  7 05:20:16 2011
+++ src/usr.sbin/ldpd/ldpd.8	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-.\" $NetBSD: ldpd.8,v 1.5 2011/07/07 05:20:16 kefren Exp $
+.\" $NetBSD: ldpd.8,v 1.6 2012/11/12 18:39:00 kefren Exp $
 .\"
 .\" Copyright (c) 2010 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -38,35 +38,40 @@
 .Sh DESCRIPTION
 .Nm
 is a utility used to automatically distribute labels between two MPLS LSRs
-almost conforming to RFC3036.
-Right now it is in BETA stage and many features
-are not implemented or may not work.
-As a security measure you SHOULD filter the LDP well-known (646)
+almost conforming to RFC5036.
+Right now some features requested by RFC5036 are not fully implemented.
+For more information please consult the
+.Sx BUGS
+section. As a security measure you SHOULD filter the LDP well-known (646)
 TCP and UDP ports using your favourite packet filter before starting
 .Nm .
-Also this is the current measure used to filter neighbours.
-You should see some logs reported via
+This is the current way used to filter neighbours and to protect the
+system of external attacks like route injections.
+.Pp
+.Nm
+logs information using the
 .Xr syslog 3
 interface.
-.Pp
 You can increase the log verbosity using the
 .Fl W
 and
 .Fl D
 flags.
-Also you can telnet to the control port (default: 2626) and use
-this interface in order to get informations about protocol, neighbours
-etc. but also to set runtime parameters.
-The required password is the same as the root password.
+.Pp
+Administrators can use
+.Xr telnet 1
+to connect to the control port (default: 2626) and use
+this interface in order to get informations about protocol status,
+neighbours et cetera but also to set runtime parameters.
+The password required for connecting is the same as the root password.
 .Pp
 .Nm
 computes existing routes and tries to match them on MPLS labels
 announced by other LDP peers.
-This means that
-.Dq normal
+This means that usual IP
 routes will be changed into tagged routes, and MPLS routing table
 will be populated.
-It will also announce its mappings to its peers.
+Any change in MPLS topology will also be announced to LDP neighbors.
 .Nm
 will listen on a route socket and compute the necessary changes in
 order to change untagged routes into tagged routes.
@@ -86,6 +91,8 @@ for configuration file format.
 Enable debug mode.
 .It Fl d
 Don't use route interception code.
+.Nm
+will not make any changes to routing table if started with this option.
 .It Fl f
 Run in foreground.
 Use STDOUT for warning and debug messages.
@@ -99,8 +106,8 @@ Enable output of warning messages.
 .Sh SEE ALSO
 .Rs
 .%R RFC
-.%N 3036
-.%D January 2001
+.%N 5036
+.%D October 2007
 .%T LDP Specification
 .Re
 .Rs

Index: src/usr.sbin/ldpd/ldp_peer.h
diff -u src/usr.sbin/ldpd/ldp_peer.h:1.1 src/usr.sbin/ldpd/ldp_peer.h:1.2
--- src/usr.sbin/ldpd/ldp_peer.h:1.1	Wed Dec  8 07:20:14 2010
+++ src/usr.sbin/ldpd/ldp_peer.h	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: ldp_peer.h,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
+/* $NetBSD: ldp_peer.h,v 1.2 2012/11/12 18:39:00 kefren Exp $ */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -86,7 +86,7 @@ struct peer_map {
 
 void            ldp_peer_init(void);
 struct ldp_peer *	ldp_peer_new(struct in_addr *, struct in_addr *,
-				struct in_addr *, uint16_t, int);
+				struct in_addr *, struct in6_addr *, uint16_t, int);
 void            ldp_peer_holddown(struct ldp_peer *);
 void            ldp_peer_delete(struct ldp_peer *);
 struct ldp_peer *	get_ldp_peer(struct in_addr *);
Index: src/usr.sbin/ldpd/notifications.h
diff -u src/usr.sbin/ldpd/notifications.h:1.1 src/usr.sbin/ldpd/notifications.h:1.2
--- src/usr.sbin/ldpd/notifications.h:1.1	Wed Dec  8 07:20:15 2010
+++ src/usr.sbin/ldpd/notifications.h	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: notifications.h,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
+/* $NetBSD: notifications.h,v 1.2 2012/11/12 18:39:00 kefren Exp $ */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
 #ifndef _NOTIFICATIONS_H_
 #define _NOTIFICATIONS_H_
 
-/* Notifications codes RFC3036 2.9 */
+/* Notifications codes from RFC5036 3.9 - Status code summary */
 #define	NOTIF_SUCCESS			0x00000000
 #define	NOTIF_BAD_LDP_ID		0x00000001
 #define	NOTIF_BAD_LDP_VER		0x00000002
Index: src/usr.sbin/ldpd/tlv.h
diff -u src/usr.sbin/ldpd/tlv.h:1.1 src/usr.sbin/ldpd/tlv.h:1.2
--- src/usr.sbin/ldpd/tlv.h:1.1	Wed Dec  8 07:20:15 2010
+++ src/usr.sbin/ldpd/tlv.h	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: tlv.h,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
+/* $NetBSD: tlv.h,v 1.2 2012/11/12 18:39:00 kefren Exp $ */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -91,7 +91,10 @@ struct hello_tlv {
 struct transport_address_tlv {
 	uint16_t       type;
 	uint16_t       length;
-	struct in_addr  address;
+	union {
+		struct in_addr  ip4addr;
+		struct in6_addr ip6addr;
+	} address;
 }               __packed;
 
 

Index: src/usr.sbin/ldpd/main.c
diff -u src/usr.sbin/ldpd/main.c:1.6 src/usr.sbin/ldpd/main.c:1.7
--- src/usr.sbin/ldpd/main.c:1.6	Sat Jul  2 18:17:12 2011
+++ src/usr.sbin/ldpd/main.c	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.6 2011/07/02 18:17:12 kefren Exp $ */
+/* $NetBSD: main.c,v 1.7 2012/11/12 18:39:00 kefren Exp $ */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -139,7 +139,7 @@ main(int argc, char *argv[])
 		fatalp("Cannot create command socket\n");
 		return EXIT_FAILURE;
 	}
-	if (create_hello_socket() < 1) {
+	if (create_hello_sockets() != 0) {
 		fatalp("Cannot create hello socket\n");
 		return EXIT_FAILURE;
 	}

Index: src/usr.sbin/ldpd/socketops.c
diff -u src/usr.sbin/ldpd/socketops.c:1.11 src/usr.sbin/ldpd/socketops.c:1.12
--- src/usr.sbin/ldpd/socketops.c:1.11	Wed Aug 31 13:32:38 2011
+++ src/usr.sbin/ldpd/socketops.c	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: socketops.c,v 1.11 2011/08/31 13:32:38 joerg Exp $ */
+/* $NetBSD: socketops.c,v 1.12 2012/11/12 18:39:00 kefren Exp $ */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -60,12 +60,15 @@
 #include "ldp_errors.h"
 #include "socketops.h"
 
-int             ls;			/* TCP listening socket on port 646 */
-int             route_socket;		/* used to see when a route is added/deleted */
-int		hello_socket;		/* hello multicast listener - transmitter */
-int		command_socket;		/* Listening socket for interface command */
-int             current_msg_id = 0x233;
-int		command_port = LDP_COMMAND_PORT;
+int ls;				/* TCP listening socket on port 646 */
+int route_socket;		/* used to see when a route is added/deleted */
+int hello_socket;		/* hello RX/TX multicast sockets */
+#ifdef INET6
+int hello6_socket;		/* same as above */
+#endif
+int command_socket;		/* Listening socket for interface command */
+int current_msg_id = 0x233;
+int command_port = LDP_COMMAND_PORT;
 extern int      replay_index;
 extern struct rt_msg replay_rt[REPLAY_MAX];
 extern struct com_sock	csockets[MAX_COMMAND_SOCKETS];
@@ -74,70 +77,141 @@ int	ldp_hello_time = LDP_HELLO_TIME;
 int	ldp_keepalive_time = LDP_KEEPALIVE_TIME;
 int	ldp_holddown_time = LDP_HOLDTIME;
 int	no_default_route = 1;
+int	loop_detection = 0;
 
 void	recv_pdu(int);
 void	send_hello_alarm(int);
 __dead static void bail_out(int);
+static	int bind_socket(int s, uint8_t stype);
+static int set_mcast_ttl(int, int);
+static int set_tos(int); 
+static int socket_reuse_port(int);
 static int get_local_addr(struct sockaddr_dl *, struct in_addr *);
 
 int 
-create_hello_socket()
+create_hello_sockets()
 {
 	struct ip_mreq  mcast_addr;
-	int             s = socket(PF_INET, SOCK_DGRAM, 17);
+	int s;
+#ifdef INET6
+	struct ipv6_mreq mcast_addr6;
+	int s6;
+#endif
 
+	s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
 	if (s < 0)
 		return s;
+#ifdef INET6
+	s6 = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+	if (s6 < 0) {
+		close(s);
+		return s6;
+	}
+#endif
 
 	/*
-	 * RFC3036 specifies we should listen to all subnet routers multicast
+	 * RFC5036 specifies we should listen to all subnet routers multicast
 	 * group
 	 */
-	mcast_addr.imr_multiaddr.s_addr = inet_addr(ALL_ROUTERS);
+	assert(inet_pton(AF_INET, ALL_ROUTERS, &mcast_addr.imr_multiaddr) == 1);
 	mcast_addr.imr_interface.s_addr = htonl(INADDR_ANY);
 
-	socket_reuse_port(s);
+#ifdef INET6
+	assert(inet_pton(AF_INET6, ALL_ROUTERS6,
+	    &mcast_addr6.ipv6mr_multiaddr) == 1);
+	/*
+	 * XXXXX: kefren. This should be 0, else I should create a socket
+	 * for every interface. Need to investigate why is not working
+	 * as documented in ip6(4)
+	 */
+	mcast_addr6.ipv6mr_interface = 1;
+#endif
+
+	if (socket_reuse_port(s) < 0)
+		goto chs_error;
+#ifdef INET6
+	if (socket_reuse_port(s6) < 0)
+		goto chs_error;
+#endif
+
 	/* Bind it to port 646 on specific address */
-	if (bind_socket(s, htonl(INADDR_ANY)) == -1) {
-		warnp("Cannot bind hello socket\n");
-		close(s);
-		return -1;
+	if (bind_socket(s, 4) == -1) {
+		warnp("Cannot bind INET hello socket\n");
+		goto chs_error;
+	}
+#ifdef INET6
+	if (bind_socket(s6, 6) == -1) {
+		fatalp("Cannot bind INET6 hello socket\n");
+		goto chs_error;
 	}
+#endif
+
 	/* We don't need to receive back our messages */
 	if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &(uint8_t){0},
 	    sizeof(uint8_t)) == -1) {
-		fatalp("setsockopt: %s", strerror(errno));
-		close(s);
-		return -1;
+		fatalp("INET setsockopt IP_MCAST_LOOP: %s\n", strerror(errno));
+		goto chs_error;
+	}
+#ifdef INET6
+	if (setsockopt(s6, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &(uint32_t){0},
+	    sizeof(uint32_t)) == -1) {
+		fatalp("INET6 setsocketopt IP_MCAST_LOOP: %s\n",
+		    strerror(errno));
+		goto chs_error;
 	}
+#endif
+
 	/* Finally join the group */
         if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mcast_addr,
 	    sizeof(mcast_addr)) == -1) {
-                fatalp("setsockopt: %s", strerror(errno));
-                close(s);
-                return -1;
+                fatalp("setsockopt ADD_MEMBER: %s\n", strerror(errno));
+		goto chs_error;
         }
-	/* TTL:1, TOS: 0xc0 */
-	if (set_mcast_ttl(s) == -1) {
-		close(s);
-		return -1;
+#ifdef INET6
+	if (setsockopt(s6, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcast_addr6,
+	    sizeof(mcast_addr6)) == -1) {
+		fatalp("INET6 setsockopt JOIN: %s\n", strerror(errno));
+		goto chs_error;
 	}
+#endif
+	/* TTL:1, TOS: 0xc0 */
+	if (set_mcast_ttl(s, 4) == -1)
+		goto chs_error;
+#ifdef INET6
+	if (set_mcast_ttl(s6, 6) == -1)
+		goto chs_error;
+#endif
 	if (set_tos(s) == -1) {
 		fatalp("set_tos: %s", strerror(errno));
-		close(s);
-		return -1;
+		goto chs_error;
 	}
+
+	/* we need to get the input interface for message processing */
 	if (setsockopt(s, IPPROTO_IP, IP_RECVIF, &(uint32_t){1}, sizeof(uint32_t)) == -1) {
 		fatalp("Cannot set IP_RECVIF\n");
-		close(s);
-		return -1;
+		goto chs_error;
 	}
+#ifdef INET6
+	if (setsockopt(s6, IPPROTO_IPV6, IPV6_RECVPKTINFO, &(uint32_t){1}, sizeof(uint32_t)) == -1)
+		goto chs_error;
+#endif
+	
 	hello_socket = s;
-	return hello_socket;
+#ifdef INET6
+	hello6_socket = s6;
+#endif
+
+	return 0;
+chs_error:
+	close(s);
+#ifdef INET6
+	close(s6);
+#endif
+	return -1;
 }
 
 /* Sets the TTL to 1 as we don't want to transmit outside this subnet */
-int 
+int
 set_ttl(int s)
 {
 	int             ret;
@@ -148,18 +222,21 @@ set_ttl(int s)
 }
 
 /* Sets multicast TTL to 1 */
-int
-set_mcast_ttl(int s)
+static int
+set_mcast_ttl(int s, int stype)
 {
 	int	ret;
-	if ((ret = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &(int){1},
+
+	assert(stype == 4 || stype == 6);
+	if ((ret = setsockopt(s, stype == 4 ? IPPROTO_IP : IPPROTO_IPV6,
+	    stype == 4 ? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS, &(int){1},
 	    sizeof(int))) == -1)
 		fatalp("set_mcast_ttl: %s", strerror(errno));
 	return ret;
 }
 
 /* Sets TOS to 0xc0 aka IP Precedence 6 */
-int 
+static int
 set_tos(int s)
 {
 	int             ret;
@@ -169,10 +246,10 @@ set_tos(int s)
 	return ret;
 }
 
-int 
+static int
 socket_reuse_port(int s)
 {
-	int             ret;
+	int ret;
 	if ((ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &(int){1},
 	    sizeof(int))) == -1)
 		fatalp("socket_reuse_port: %s", strerror(errno));
@@ -180,24 +257,38 @@ socket_reuse_port(int s)
 }
 
 /* binds an UDP socket */
-int 
-bind_socket(int s, uint32_t addr)
+static int
+bind_socket(int s, uint8_t stype)
 {
-	struct sockaddr_in sa;
+	struct sockaddr sa;
 
-	sa.sin_len = sizeof(sa);
-	sa.sin_family = AF_INET;
-	sa.sin_port = htons(LDP_PORT);
-	sa.sin_addr.s_addr = addr;
-	if (bind(s, (struct sockaddr *) (&sa), sizeof(sa))) {
-		fatalp("bind_socket: %s", strerror(errno));
+	assert (stype == 4 || stype == 6);
+
+	if (stype == 4) {
+		struct sockaddr_in *sa_inet = (struct sockaddr_in *)(&sa);
+		sa_inet->sin_len = sizeof(*sa_inet);
+		sa_inet->sin_family = AF_INET;
+		sa_inet->sin_addr.s_addr = INADDR_ANY;
+		sa_inet->sin_port = htons(LDP_PORT);
+	}
+#ifdef INET6
+	else if (stype == 6) {
+		struct sockaddr_in6 *sa_inet6 = (struct sockaddr_in6 *)(&sa);
+		sa_inet6->sin6_len = sizeof(*sa_inet6);
+		sa_inet6->sin6_family = AF_INET6;
+		sa_inet6->sin6_addr = in6addr_any;
+		sa_inet6->sin6_port = htons(LDP_PORT);
+	}
+#endif
+	if (bind(s, &sa, sa.sa_len)) {
+		fatalp("bind_socket: %s\n", strerror(errno));
 		return -1;
 	}
 	return 0;
 }
 
 /* Create / bind the TCP socket */
-int 
+int
 create_listening_socket(void)
 {
 	struct sockaddr_in sa;
@@ -208,7 +299,7 @@ create_listening_socket(void)
 	sa.sin_port = htons(LDP_PORT);
 	sa.sin_addr.s_addr = htonl(INADDR_ANY);
 
-	s = socket(PF_INET, SOCK_STREAM, 6);
+	s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
 	if (s < 0)
 		return s;
 	if (bind(s, (struct sockaddr *) & sa, sizeof(sa))) {
@@ -242,20 +333,27 @@ send_hello(void)
 	struct transport_address_tlv *trtlv;
 	void *v;
 	struct sockaddr_in sadest;	/* Destination ALL_ROUTERS */
-	int sb = 0;			/* sent bytes */
+	ssize_t sb = 0;			/* sent bytes */
 	struct ifaddrs *ifa, *ifb;
 	struct sockaddr_in *if_sa;
+#ifdef INET6
+	struct sockaddr_in6 sadest6;
+	struct sockaddr_in6 *if_sa6;
+#endif
 	char lastifname[20];
 
-#define HELLO_MSG_SIZE (sizeof(struct ldp_pdu) + 	/* PDU */	\
+#define BASIC_HELLO_MSG_SIZE (sizeof(struct ldp_pdu) + 	/* PDU */	\
 			TLV_TYPE_LENGTH + MSGID_SIZE +	/* Hello TLV */	\
 			/* Common Hello TLV */				\
-			sizeof(struct common_hello_tlv) +		\
-			/* IPv4 Transport Address */			\
-			sizeof(struct transport_address_tlv))
+			sizeof(struct common_hello_tlv))
+#define GENERAL_HELLO_MSG_SIZE BASIC_HELLO_MSG_SIZE + 			\
+			/* Transport Address */				\
+			sizeof(struct transport_address_tlv)
+#define IPV4_HELLO_MSG_SIZE BASIC_HELLO_MSG_SIZE + 4 + sizeof(struct in_addr)
+#define IPV6_HELLO_MSG_SIZE BASIC_HELLO_MSG_SIZE + 4 + sizeof(struct in6_addr)
 
-	if ((v = calloc(1, HELLO_MSG_SIZE)) == NULL) {
-		fatalp("malloc problem in send_hello()\n");
+	if ((v = calloc(1, GENERAL_HELLO_MSG_SIZE)) == NULL) {
+		fatalp("alloc problem in send_hello()\n");
 		return;
 	}
 
@@ -266,17 +364,18 @@ send_hello(void)
 
 	/* Prepare PDU envelope */
 	spdu->version = htons(LDP_VERSION);
-	spdu->length = htons(HELLO_MSG_SIZE - PDU_VER_LENGTH);
+	spdu->length = htons(IPV4_HELLO_MSG_SIZE - PDU_VER_LENGTH);
 	inet_aton(LDP_ID, &spdu->ldp_id);
 
 	/* Prepare Hello TLV */
 	t->type = htons(LDP_HELLO);
 	t->length = htons(MSGID_SIZE +
 			sizeof(struct common_hello_tlv) +
-			sizeof(struct transport_address_tlv));
+			IPV4_HELLO_MSG_SIZE - BASIC_HELLO_MSG_SIZE);
 	/*
+	 * kefren:
 	 * I used ID 0 instead of htonl(get_message_id()) because I've
-	 * seen hellos from a cisco router doing the same thing
+	 * seen hellos from Cisco routers doing the same thing
 	 */
 	t->messageid = 0;
 
@@ -287,7 +386,7 @@ send_hello(void)
 	cht->res = 0;
 
 	/*
-	 * Prepare Transport Address TLV RFC3036 says: "If this optional TLV
+	 * Prepare Transport Address TLV RFC5036 says: "If this optional TLV
 	 * is not present the IPv4 source address for the UDP packet carrying
 	 * the Hello should be used." But we send it because everybody seems
 	 * to do so
@@ -309,6 +408,7 @@ send_hello(void)
 	}
 	
 	lastifname[0] = '\0';
+	/* Loop all interfaces in order to send IPv4 hellos */
 	for (ifb = ifa; ifb; ifb = ifb->ifa_next) {
 		if_sa = (struct sockaddr_in *) ifb->ifa_addr;
 		if (if_sa->sin_family != AF_INET)
@@ -316,7 +416,8 @@ send_hello(void)
 		if (ntohl(if_sa->sin_addr.s_addr) >> 24 == IN_LOOPBACKNET ||
 		    ntohl(if_sa->sin_addr.s_addr) >> 24 == 0)
 			continue;
-		/* Send only once per interface, using master address */
+
+		/* Send only once per interface, using primary address */
 		if (strcmp(ifb->ifa_name, lastifname) == 0)
 			continue;
 		debugp("Sending hello on %s\n", ifb->ifa_name);
@@ -325,22 +426,80 @@ send_hello(void)
 			warnp("setsockopt failed: %s\n", strerror(errno));
 			continue;
 		}
-		trtlv->address.s_addr = if_sa->sin_addr.s_addr;
+		trtlv->address.ip4addr.s_addr = if_sa->sin_addr.s_addr;
 
 		strlcpy(lastifname, ifb->ifa_name, sizeof(lastifname));
 
 		/* Send to the wire */
-		sb = sendto(hello_socket, v, HELLO_MSG_SIZE,
+		sb = sendto(hello_socket, v, IPV4_HELLO_MSG_SIZE,
 			    0, (struct sockaddr *) & sadest, sizeof(sadest));
-		if (sb < (int)HELLO_MSG_SIZE)
+		if (sb < (ssize_t)(IPV4_HELLO_MSG_SIZE))
 		    fatalp("send: %s", strerror(errno));
 		else
-		    debugp("Send %d bytes (PDU: %d, Hello TLV: %d, CH: %d)\n",
-			sb, (int) (sizeof(struct ldp_pdu) - PDU_VER_LENGTH),
-		       (int) (TLV_TYPE_LENGTH + MSGID_SIZE),
-		       (int) (sizeof(struct common_hello_tlv)));
+		    debugp("Sent (IP4) %lu bytes on %s"
+			"(PDU: %d, Hello TLV: %d, CH: %d, TR: %d)\n",
+			sb, ifb->ifa_name,
+			ntohs(spdu->length), ntohs(t->length),
+			ntohs(cht->length), ntohs(trtlv->length));
+	}
+#ifdef INET6
+	/* Let's do the same thing for IPv6 */
+	lastifname[0]='\0';
+
+	/* Adjust lengths */
+	spdu->length = htons(IPV6_HELLO_MSG_SIZE - PDU_VER_LENGTH);
+	t->length = htons(MSGID_SIZE +
+			sizeof(struct common_hello_tlv) +
+			IPV6_HELLO_MSG_SIZE - BASIC_HELLO_MSG_SIZE);
+	trtlv->length = htons(sizeof(struct in6_addr));
+	trtlv->type = htons(TLV_IPV6_TRANSPORT);
+
+	/* Prepare destination sockaddr */
+	memset(&sadest6, 0, sizeof(sadest6));
+	sadest6.sin6_len = sizeof(sadest6);
+	sadest6.sin6_family = AF_INET6;
+	sadest6.sin6_port = htons(LDP_PORT);
+	assert(inet_pton(AF_INET6, ALL_ROUTERS6, &sadest6.sin6_addr) == 1);
+
+	for (ifb = ifa; ifb; ifb = ifb->ifa_next) {
+		unsigned int if_index;
+		if_sa6 = (struct sockaddr_in6 *) ifb->ifa_addr;
+		if (if_sa6->sin6_family != AF_INET6)
+			continue;
+		if (IN6_IS_ADDR_LOOPBACK(&if_sa6->sin6_addr))
+			continue;
+
+		/* Send only once per interface, using primary address */
+		if (strcmp(ifb->ifa_name, lastifname) == 0)
+			continue;
+		if_index = if_nametoindex(ifb->ifa_name);
+		if (if_index == 0)
+			continue;
+		if (setsockopt(hello6_socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+		    &if_index, sizeof(int)) == -1) {
+			warnp("setsockopt6 failed in sendhello(): %s\n",
+			    strerror(errno));
+			continue;
+		}
+		memcpy(&trtlv->address.ip6addr, &if_sa6->sin6_addr,
+		    sizeof(struct in6_addr));
+
+		strlcpy(lastifname, ifb->ifa_name, sizeof(lastifname));
+
+		/* Put it on the wire */
+		sb = sendto(hello6_socket, v, IPV6_HELLO_MSG_SIZE,
+			    0, (struct sockaddr *)&sadest6, sizeof(sadest6));
+		if (sb < (ssize_t)(IPV6_HELLO_MSG_SIZE))
+		    fatalp("send6 on %s: %s", ifb->ifa_name, strerror(errno));
+		else
+		    debugp("Sent (IPv6) %lu bytes on %s"
+			"(PDU: %d, Hello TLV: %d, CH: %d TR: %d)\n",
+			sb, ifb->ifa_name,
+			htons(spdu->length), htons(t->length),
+			htons(cht->length), htons(trtlv->length));
 
 	}
+#endif
 	freeifaddrs(ifa);
 	free(v);
 }
@@ -714,8 +873,8 @@ new_peer_connection()
 		close(s);
 		return;
 	}
-	/* XXX: sa.sin_addr ain't peer LDP ID ... */
-	ldp_peer_new(&sa.sin_addr, &sa.sin_addr, NULL, ldp_holddown_time, s);
+	/* XXX: sa.sin_addr is not peer LDP ID ... */
+	ldp_peer_new(&sa.sin_addr, &sa.sin_addr, NULL, NULL, ldp_holddown_time, s);
 
 }
 
@@ -940,7 +1099,7 @@ recv_session_pdu(struct ldp_peer * p)
 			break;
 		case LDP_LABEL_ABORT:
 		/* XXX: For now I pretend I can process everything
-		 * RFC 3036, Section 3.5.9.1
+		 * RFC 5036, Section 3.5.9.1
 		 * If an LSR receives a Label Abort Request Message after it
 		 * has responded to the Label Request in question with a Label
 		 * Mapping message or a Notification message, it ignores the

Index: src/usr.sbin/ldpd/socketops.h
diff -u src/usr.sbin/ldpd/socketops.h:1.2 src/usr.sbin/ldpd/socketops.h:1.3
--- src/usr.sbin/ldpd/socketops.h:1.2	Tue Jun 14 11:28:51 2011
+++ src/usr.sbin/ldpd/socketops.h	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: socketops.h,v 1.2 2011/06/14 11:28:51 kefren Exp $ */
+/* $NetBSD: socketops.h,v 1.3 2012/11/12 18:39:00 kefren Exp $ */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -42,11 +42,7 @@
 #define	LDP_AF_INET6	2
 
 int	set_ttl(int);
-int	set_mcast_ttl(int);
-int	set_tos(int);
-int	socket_reuse_port(int);
-int	bind_socket(int, uint32_t);
-int	create_hello_socket(void);
+int	create_hello_sockets(void);
 int	create_listening_socket(void);
 void	send_hello(void);
 int	get_message_id(void);

Index: src/usr.sbin/ldpd/tlv_stack.c
diff -u src/usr.sbin/ldpd/tlv_stack.c:1.4 src/usr.sbin/ldpd/tlv_stack.c:1.5
--- src/usr.sbin/ldpd/tlv_stack.c:1.4	Wed Jun 15 18:16:48 2011
+++ src/usr.sbin/ldpd/tlv_stack.c	Mon Nov 12 18:39:00 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: tlv_stack.c,v 1.4 2011/06/15 18:16:48 kefren Exp $ */
+/* $NetBSD: tlv_stack.c,v 1.5 2012/11/12 18:39:00 kefren Exp $ */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -253,8 +253,8 @@ send_label_tlv(struct ldp_peer * peer, s
 
 	/* Now let's do the even a dirtier job: PREFIX TLV */
 	p = (struct prefix_tlv *) & fec[1];
-	/* Cisco and Juniper don't support FEC type HOST
-	 * so everything is FEC_PREFIX..
+	/*
+	 * RFC5036 obsoletes FEC_HOST
 	 *
 	 * if (prefixlen == 32) p->type = FEC_HOST; else
 	 */
@@ -344,7 +344,8 @@ send_withdraw_tlv(struct ldp_peer * peer
 
 	/* Now the even dirtier job: PREFIX TLV */
 	p = (struct prefix_tlv *) & fec[1];
-	/* See above comment
+	/*
+	 * RFC5036 obsoletes FEC_HOST
 	 *
 	 * if (prefixlen == 32) p->type = FEC_HOST; else
 	 */

Reply via email to