[U-Boot] [RFC PATCH v4 21/23] sandbox: eth: Add a bridge to a real network for sandbox

Joe Hershberger joe.hershberger at ni.com
Wed Feb 25 01:02:30 CET 2015


Implement a bridge between u-boot's network stack and Linux's raw packet
API allowing the sandbox to send and receive packets using the host
machine's network interface.

This raw Ethernet API requires elevated privileges.  You can either run
as root, or you can add the capability needed like so:

sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot

Signed-off-by: Joe Hershberger <joe.hershberger at ni.com>

---

Changes in v4:
-Added comments to README.sandbox
-Use accessors for platdata and priv
-Add comments to priv struct definition
-Move os file to arch
-Cleanup var definition order
-Moved config to Kconfig
-Clean up the interface to sandbox's eth-raw-os by passing priv to raw-os
-Fixed the MAC address limitation (now all traffic uses MAC address from env)

Changes in v3:
-Made the os raw packet support for sandbox eth build and work.

Changes in v2:
-Added the raw packet proof-of-concept patch.

 arch/sandbox/Kconfig                  |   3 +
 arch/sandbox/cpu/Makefile             |  10 ++++
 arch/sandbox/cpu/eth-raw-os.c         | 102 +++++++++++++++++++++++++++++++++
 arch/sandbox/dts/sandbox.dts          |   6 ++
 arch/sandbox/include/asm/eth-raw-os.h |  32 +++++++++++
 board/sandbox/README.sandbox          |  13 +++++
 drivers/net/Kconfig                   |   5 ++
 drivers/net/Makefile                  |   1 +
 drivers/net/sandbox-raw.c             | 105 ++++++++++++++++++++++++++++++++++
 9 files changed, 277 insertions(+)
 create mode 100644 arch/sandbox/cpu/eth-raw-os.c
 create mode 100644 arch/sandbox/include/asm/eth-raw-os.h
 create mode 100644 drivers/net/sandbox-raw.c

diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index 186b58d..f84b3fc 100644
--- a/arch/sandbox/Kconfig
+++ b/arch/sandbox/Kconfig
@@ -43,4 +43,7 @@ config NETDEVICES
 config DM_ETH
 	default y
 
+config ETH_SANDBOX_RAW
+	default y
+
 endmenu
diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile
index 7d4410c..1b42fee 100644
--- a/arch/sandbox/cpu/Makefile
+++ b/arch/sandbox/cpu/Makefile
@@ -8,6 +8,7 @@
 #
 
 obj-y	:= cpu.o os.o start.o state.o
+obj-$(CONFIG_ETH_SANDBOX_RAW)	+= eth-raw-os.o
 obj-$(CONFIG_SANDBOX_SDL)	+= sdl.o
 
 # os.c is build in the system environment, so needs standard includes
@@ -20,3 +21,12 @@ $(obj)/os.o: $(src)/os.c FORCE
 	$(call if_changed_dep,cc_os.o)
 $(obj)/sdl.o: $(src)/sdl.c FORCE
 	$(call if_changed_dep,cc_os.o)
+
+# eth-raw-os.c is built in the system env, so needs standard includes
+# CFLAGS_REMOVE_eth-raw-os.o cannot be used to drop header include path
+quiet_cmd_cc_eth-raw-os.o = CC $(quiet_modtag)  $@
+cmd_cc_eth-raw-os.o = $(CC) $(filter-out -nostdinc, \
+	$(patsubst -I%,-idirafter%,$(c_flags))) -c -o $@ $<
+
+$(obj)/eth-raw-os.o: $(src)/eth-raw-os.c FORCE
+	$(call if_changed_dep,cc_eth-raw-os.o)
diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c
new file mode 100644
index 0000000..9218f94
--- /dev/null
+++ b/arch/sandbox/cpu/eth-raw-os.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015 National Instruments
+ *
+ * (C) Copyright 2015
+ * Joe Hershberger <joe.hershberger at ni.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <asm/eth-raw-os.h>
+#include <errno.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+
+int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac,
+			    struct eth_sandbox_raw_priv *priv)
+{
+	struct sockaddr_ll *device;
+	struct packet_mreq mr;
+
+	/* Prepare device struct */
+	priv->device = malloc(sizeof(struct sockaddr_ll));
+	device = priv->device;
+	memset(device, 0, sizeof(struct sockaddr_ll));
+	device->sll_ifindex = if_nametoindex(ifname);
+	device->sll_family = AF_PACKET;
+	memcpy(device->sll_addr, ethmac, 6);
+	device->sll_halen = htons(6);
+
+	/* Open socket */
+	priv->sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+	if (priv->sd < 0) {
+		printf("Failed to open socket: %d %s\n", errno,
+		       strerror(errno));
+		return -errno;
+	}
+	/* Bind to the specified interface */
+	setsockopt(priv->sd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
+		   strlen(ifname) + 1);
+
+	/* Enable promiscuous mode to receive responses meant for us */
+	mr.mr_ifindex = device->sll_ifindex;
+	mr.mr_type = PACKET_MR_PROMISC;
+	setsockopt(priv->sd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
+		   &mr, sizeof(mr));
+	return 0;
+}
+
+int sandbox_eth_raw_os_send(void *packet, int length,
+			    const struct eth_sandbox_raw_priv *priv)
+{
+	int retval;
+
+	if (!priv->sd || !priv->device)
+		return -EINVAL;
+
+	retval = sendto(priv->sd, packet, length, 0,
+			(struct sockaddr *)priv->device,
+			sizeof(struct sockaddr_ll));
+	if (retval < 0)
+		printf("Failed to send packet: %d %s\n", errno,
+		       strerror(errno));
+	return retval;
+}
+
+int sandbox_eth_raw_os_recv(void *packet, int *length,
+			    const struct eth_sandbox_raw_priv *priv)
+{
+	int retval;
+	int saddr_size;
+
+	if (!priv->sd || !priv->device)
+		return -EINVAL;
+	saddr_size = sizeof(struct sockaddr);
+	retval = recvfrom(priv->sd, packet, 1536, 0,
+			  (struct sockaddr *)priv->device,
+			  (socklen_t *)&saddr_size);
+	*length = 0;
+	if (retval > 0) {
+		*length = retval;
+		return 0;
+	}
+	return retval;
+}
+
+void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv)
+{
+	free((struct sockaddr_ll *)priv->device);
+	priv->device = NULL;
+	close(priv->sd);
+	priv->sd = -1;
+}
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 235dcc0..b6762f4 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -186,4 +186,10 @@
 		reg = <0x10002000 0x1000>;
 		fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>;
 	};
+
+	eth at 80000000 {
+		compatible = "sandbox,eth-raw";
+		reg = <0x80000000 0x1000>;
+		host-raw-interface = "eth0";
+	};
 };
diff --git a/arch/sandbox/include/asm/eth-raw-os.h b/arch/sandbox/include/asm/eth-raw-os.h
new file mode 100644
index 0000000..d92b72c
--- /dev/null
+++ b/arch/sandbox/include/asm/eth-raw-os.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015 National Instruments
+ *
+ * (C) Copyright 2015
+ * Joe Hershberger <joe.hershberger at ni.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __ETH_RAW_OS_H
+#define __ETH_RAW_OS_H
+
+/**
+ * struct eth_sandbox_raw_priv - raw socket session
+ *
+ * sd: socket descriptor - the open socket during a session
+ * device: struct sockaddr_ll - the host interface packets move to/from
+ */
+struct eth_sandbox_raw_priv {
+	int sd;
+	void *device;
+};
+
+int sandbox_eth_raw_os_init(const char *ifname, unsigned char *ethmac,
+			    struct eth_sandbox_raw_priv *priv);
+int sandbox_eth_raw_os_send(void *packet, int length,
+			    const struct eth_sandbox_raw_priv *priv);
+int sandbox_eth_raw_os_recv(void *packet, int *length,
+			    const struct eth_sandbox_raw_priv *priv);
+void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv);
+
+#endif /* __ETH_RAW_OS_H */
diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox
index c1f5f7e..c4c3139 100644
--- a/board/sandbox/README.sandbox
+++ b/board/sandbox/README.sandbox
@@ -190,6 +190,19 @@ Also sandbox uses generic board (CONFIG_SYS_GENERIC_BOARD) and supports
 driver model (CONFIG_DM) and associated commands.
 
 
+Linux RAW Networking Bridge
+---------------------------
+
+The sandbox_eth_raw driver bridges traffic between the bottom of the network
+stack and the RAW sockets API in Linux. This allows much of the u-boot network
+functionality to be tested in sandbox against real network traffic.
+
+The RAW sockets Ethernet API requires elevated privileges in Linux. You can
+either run as root, or you can add the capability needed like so:
+
+sudo /sbin/setcap "CAP_NET_RAW+ep" u-boot
+
+
 SPI Emulation
 -------------
 
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index b08746a..dcbfa8a 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -20,4 +20,9 @@ config ETH_SANDBOX
 	default y
 	bool "Sandbox: Mocked Ethernet driver"
 
+config ETH_SANDBOX_RAW
+	depends on DM_ETH && SANDBOX
+	default y
+	bool "Sandbox: Bridge to Linux Raw Sockets"
+
 endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 15dc431..2659a8a 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_PCNET) += pcnet.o
 obj-$(CONFIG_RTL8139) += rtl8139.o
 obj-$(CONFIG_RTL8169) += rtl8169.o
 obj-$(CONFIG_ETH_SANDBOX) += sandbox.o
+obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o
 obj-$(CONFIG_SH_ETHER) += sh_eth.o
 obj-$(CONFIG_SMC91111) += smc91111.o
 obj-$(CONFIG_SMC911X) += smc911x.o
diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c
new file mode 100644
index 0000000..01b33a9
--- /dev/null
+++ b/drivers/net/sandbox-raw.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2015 National Instruments
+ *
+ * (C) Copyright 2015
+ * Joe Hershberger <joe.hershberger at ni.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <asm/eth-raw-os.h>
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <net.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+
+static int sb_eth_raw_start(struct udevice *dev)
+{
+	struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	int retval;
+	const char *interface;
+
+	debug("eth_sandbox_raw: Start\n");
+
+	interface = fdt_getprop(gd->fdt_blob, dev->of_offset,
+					    "host-raw-interface", NULL);
+
+	retval = sandbox_eth_raw_os_init(interface, pdata->enetaddr, priv);
+
+	return retval;
+}
+
+static int sb_eth_raw_send(struct udevice *dev, void *packet, int length)
+{
+	struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
+
+	debug("eth_sandbox_raw: Send packet %d\n", length);
+
+	return sandbox_eth_raw_os_send(packet, length, priv);
+}
+
+static int sb_eth_raw_recv(struct udevice *dev)
+{
+	struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
+	int retval;
+	uchar buffer[PKTSIZE];
+	int length;
+
+	retval = sandbox_eth_raw_os_recv(buffer, &length, priv);
+
+	if (!retval && length) {
+		debug("eth_sandbox_raw: received packet %d\n",
+		      length);
+		NetReceive(buffer, length);
+	}
+	return 0;
+}
+
+static void sb_eth_raw_stop(struct udevice *dev)
+{
+	struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
+
+	debug("eth_sandbox_raw: Stop\n");
+
+	sandbox_eth_raw_os_halt(priv);
+}
+
+static const struct eth_ops sb_eth_raw_ops = {
+	.start			= sb_eth_raw_start,
+	.send			= sb_eth_raw_send,
+	.recv			= sb_eth_raw_recv,
+	.stop			= sb_eth_raw_stop,
+};
+
+static int sb_eth_raw_remove(struct udevice *dev)
+{
+	return 0;
+}
+
+static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+
+	pdata->iobase = dev_get_addr(dev);
+	return 0;
+}
+
+static const struct udevice_id sb_eth_raw_ids[] = {
+	{ .compatible = "sandbox,eth-raw" },
+	{ }
+};
+
+U_BOOT_DRIVER(eth_sandbox_raw) = {
+	.name	= "eth_sandbox_raw",
+	.id	= UCLASS_ETH,
+	.of_match = sb_eth_raw_ids,
+	.ofdata_to_platdata = sb_eth_raw_ofdata_to_platdata,
+	.remove	= sb_eth_raw_remove,
+	.ops	= &sb_eth_raw_ops,
+	.priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
-- 
1.7.11.5



More information about the U-Boot mailing list