[U-Boot] [PATCH 2/3] Add sendnbc tool to broadcast NBC magic packet

tristan.lelong at blunderer.org tristan.lelong at blunderer.org
Tue Nov 16 19:04:32 CET 2010


From: Tristan Lelong <tristan.lelong at blunderer.org>

This tool send NBC packet filled with data provided on command line
It can be used in combination with netconsole by calling:
BOARD_IP=192.168.0.2 ./sendnbc -i $BOARD_IP && ./netconsole $BOARD_IP

Signed-off-by: Tristan Lelong <tristan.lelong at blunderer.org>
---
 tools/Makefile  |    6 ++
 tools/sendnbc.c |  219 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 225 insertions(+), 0 deletions(-)
 create mode 100644 tools/sendnbc.c

diff --git a/tools/Makefile b/tools/Makefile
index 619c9f2..e1719fc 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -45,6 +45,7 @@ CONFIG_CMD_LOADS = y
 CONFIG_CMD_NET = y
 CONFIG_INCA_IP = y
 CONFIG_NETCONSOLE = y
+CONFIG_CMD_NBC = y
 CONFIG_SHA1_CHECK_UB_IMG = y
 endif
 
@@ -64,6 +65,7 @@ BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX)
 BIN_FILES-$(CONFIG_INCA_IP) += inca-swap-bytes$(SFX)
 BIN_FILES-y += mkimage$(SFX)
 BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
+BIN_FILES-$(CONFIG_CMD_NBC) += sendnbc$(SFX)
 BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)
 
 # Source files which exist outside the tools directory
@@ -86,6 +88,7 @@ NOPED_OBJ_FILES-y += kwbimage.o
 NOPED_OBJ_FILES-y += imximage.o
 NOPED_OBJ_FILES-y += mkimage.o
 OBJ_FILES-$(CONFIG_NETCONSOLE) += ncb.o
+OBJ_FILES-$(CONFIG_CMD_NBC) += sendnbc.o
 NOPED_OBJ_FILES-y += os_support.o
 OBJ_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1.o
 
@@ -197,6 +200,9 @@ $(obj)ncb$(SFX):	$(obj)ncb.o
 	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
 	$(HOSTSTRIP) $@
 
+$(obj)sendnbc$(SFX):	$(obj)sendnbc.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+
 $(obj)ubsha1$(SFX):	$(obj)os_support.o $(obj)sha1.o $(obj)ubsha1.o
 	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
 
diff --git a/tools/sendnbc.c b/tools/sendnbc.c
new file mode 100644
index 0000000..03bf5af
--- /dev/null
+++ b/tools/sendnbc.c
@@ -0,0 +1,219 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/ether.h>
+
+static void usage (char *argv0)
+{
+	printf
+	    ("SENDNBC: sends a magic packet to u-boot board to interrupt the autoboot\n");
+	printf ("         and reconfigure u-boot in netconsole mode.\n");
+	printf
+	    ("         Use in combination with netconsole to connect and control\n");
+	printf ("	 your u-boot device\n");
+	printf
+	    ("	 Ex: BOARD_IP=192.168.0.2 ./sendnbc -i $BOARD_IP -d eth0 && ./netconsole $BOARD_IP\n");
+	printf ("\nusage: %s [options]\n", argv0);
+	printf (" -i <ip addr>: the ip addr to assign to u-boot board\n");
+	printf (" -m <mac addr>: the targeted board mac addr \n");
+	printf (" -n <hostname>: the targeted board hostname \n");
+	printf
+	    (" -d <device>: the net interface to use for broadcasting (ex: eth0). Must be root to use this option\n");
+	printf (" -h: display this help\n");
+}
+
+static int build_nbc_pkt (char *buf, int buf_len, char *ip, char *mac,
+			  char *hostname)
+{
+	int offset = 0;
+	char *size = NULL;
+	char *ip_size = NULL;
+	char *mac_size = NULL;
+	char *hostname_size = NULL;
+
+	struct in_addr binip;
+	struct ether_addr binmac;
+
+	memset (buf, 0, buf_len);
+
+	buf[0] = (char)0xD3;	/* magic number */
+	offset += 1;
+
+	strcpy (buf + offset, "NBC");	/* packet header */
+	offset += 3;
+
+	size = (char *)(buf + offset);	/* msg total size */
+	offset += 1;
+
+	strcpy (buf + offset, "IP");	/* IP chunk header */
+	offset += 4;
+
+	ip_size = (char *)(buf + offset);	/* IP chunk size */
+	offset += 1;
+
+	inet_pton (AF_INET, ip, &binip);
+	memcpy (buf + offset, &binip, sizeof (struct in_addr));	/* IP chunk data */
+	offset += sizeof (struct in_addr);
+	*ip_size = sizeof (struct in_addr);
+
+	if (mac) {
+		strcpy (buf + offset, "MAC");	/* MAC chunk header */
+		offset += 4;
+
+		mac_size = (char *)(buf + offset);	/* MAC chunk size */
+		offset += 1;
+
+		ether_aton_r (mac, &binmac);
+		memcpy (buf + offset, &binmac, sizeof (struct ether_addr));	/* MAC chunk data */
+		offset += sizeof (struct ether_addr);
+		*mac_size = sizeof (struct ether_addr);
+	}
+
+	if (hostname) {
+		strcpy (buf + offset, "HOST");	/* HOST chunk header */
+		offset += 4;
+
+		hostname_size = (char *)(buf + offset);	/* HOST chunk size */
+		offset += 1;
+
+		strcpy (buf + offset, hostname);	/* HOST chunk data */
+		offset += strlen (hostname);
+		*hostname_size = strlen (hostname);
+	}
+
+	*size = offset;
+
+	return offset;
+}
+
+int main (int argc, char *argv[])
+{
+	char buf[255];
+	int s, len, o, nbcport = 4446, netconsoleport = 6666;
+	int buf_len = sizeof (buf);
+	char option;
+	char *ip = NULL;
+	char *mac = NULL;
+	char *device = NULL;
+	char *hostname = NULL;
+	struct sockaddr_in addr;
+	struct sockaddr_in broadcast_addr;
+	socklen_t addr_len = sizeof (addr);
+	socklen_t broadcast_addr_len = sizeof (broadcast_addr);
+
+	s = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (s < 0) {
+		perror ("Error with socket creation");
+		return 1;
+	}
+	while ((option = getopt (argc, argv, "hn:m:i:d:")) >= 0) {
+		switch (option) {
+		case 'h':
+			usage (argv[0]);
+			exit (0);
+		case 'd':
+			device = optarg;
+			break;
+		case 'n':
+			hostname = optarg;
+			break;
+		case 'm':
+			mac = optarg;
+			break;
+		case 'i':
+			ip = optarg;
+			break;
+		default:
+			usage (argv[0]);
+			exit (0);
+		}
+	}
+
+	if (!ip) {
+		usage (argv[0]);
+		exit (0);
+	}
+
+	/* set sockoptions */
+	o = 1;
+	len = 4;
+	setsockopt (3, SOL_SOCKET, SO_REUSEADDR, &o, len);
+	o = 1;
+	len = 4;
+	setsockopt (3, SOL_SOCKET, SO_BROADCAST, &o, len);
+	if (device) {
+		len = strlen (device);
+		setsockopt (3, SOL_SOCKET, SO_BINDTODEVICE, device, len);
+	}
+
+	/* configure socket */
+	memset (&addr, 0, sizeof (struct sockaddr_in));
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons (netconsoleport);
+	addr.sin_addr.s_addr = INADDR_ANY;
+
+	memset (&broadcast_addr, 0, sizeof (struct sockaddr_in));
+	broadcast_addr.sin_family = AF_INET;
+	broadcast_addr.sin_port = htons (nbcport);
+	broadcast_addr.sin_addr.s_addr = INADDR_BROADCAST;
+
+	if (bind (s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
+		perror ("error with bind");
+		close (s);
+	}
+
+	/* build packets */
+	buf_len = build_nbc_pkt (buf, sizeof (buf), ip, mac, hostname);
+
+	for (;;) {
+		char recv_buf = '\n';
+		struct in_addr binip;
+		struct sockaddr_in board_addr;
+		socklen_t board_addr_len = sizeof (struct sockaddr_in);
+
+		memset (&addr, 0, sizeof (struct sockaddr_in));
+		inet_pton (AF_INET, ip, &binip);
+		board_addr.sin_family = AF_INET;
+		board_addr.sin_port = htons (netconsoleport);
+		memcpy (&board_addr.sin_addr.s_addr, &binip,
+			sizeof (struct in_addr));
+
+		/* send the magic packet */
+		len =
+		    sendto (s, buf, buf_len, 0,
+			    (struct sockaddr *)&broadcast_addr,
+			    broadcast_addr_len);
+		if (len < 0) {
+			perror ("error in send");
+			break;
+		}
+
+		usleep (100000);
+
+		/* check for u-boot in netconsole mode */
+		len =
+		    sendto (s, &recv_buf, 1, 0, (struct sockaddr *)&board_addr,
+			    board_addr_len);
+		len = recv (s, &recv_buf, 1, MSG_PEEK | MSG_DONTWAIT);
+		if (len < 0) {
+			if (errno != EAGAIN) {
+				perror ("error in recv");
+				break;
+			}
+		} else if (len > 0) {
+			break;
+		}
+	}
+	if (len < 0) {
+		return 1;
+	}
+
+	close (s);
+
+	return 0;
+}
-- 
1.7.2.3



More information about the U-Boot mailing list