On 24 February 2015 at 17:02, Joe Hershberger <joe.hershber...@ni.com> wrote: > 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.hershber...@ni.com>
Reviewed-by: Simon Glass <s...@chromium.org> A few nits below. > > --- > > 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.hershber...@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)); This calls U-Boot's malloc() and it can return NULL, so you should return -ENOMEM in that case. > + 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 -errno here? > + 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; return -errno here? At present you are returning -1 I think, which is -EPERM. > +} > + > +void sandbox_eth_raw_os_halt(struct eth_sandbox_raw_priv *priv) > +{ > + free((struct sockaddr_ll *)priv->device); Don't need that cast? > + 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@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.hershber...@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 This is so cool. Can you give some examples here? For me, ping seems to work, but I can't use bootp. Is that what the raw mode is for? How do I enable it? I tried setting ethact but am not sure what I am doing. Useful examples would be: - ping - bootp - tftpboot and how to use raw/normal device. > + > + > 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" This needs some help. > + > 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.hershber...@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); This can return NULL, so you should return -EINVAL in that case. > + > + 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; > +} You can drop this function. > + > +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 > Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot