From 4e8030a11a0e0b2d38ff07076461ce4bbfd9d7c4 Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 12 Sep 2012 18:42:07 +0000 Subject: Network discover utility from Max Holtzberg git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@5137 7fd9a85b-ad96-42d3-883c-3090e2eb8679 --- apps/ChangeLog.txt | 4 + apps/examples/README.txt | 22 ++ apps/examples/discover/Kconfig | 42 ++++ apps/examples/discover/Makefile | 106 +++++++++ apps/examples/discover/main.c | 183 +++++++++++++++ apps/include/netutils/discover.h | 58 +++++ apps/netutils/Kconfig | 4 + apps/netutils/Make.defs | 6 +- apps/netutils/Makefile | 3 +- apps/netutils/README.txt | 10 +- apps/netutils/discover/Kconfig | 39 ++++ apps/netutils/discover/Makefile | 100 +++++++++ apps/netutils/discover/README.txt | 9 + apps/netutils/discover/discover.c | 456 ++++++++++++++++++++++++++++++++++++++ nuttx/Documentation/README.html | 1 + nuttx/README.txt | 2 + 16 files changed, 1041 insertions(+), 4 deletions(-) create mode 100644 apps/examples/discover/Kconfig create mode 100644 apps/examples/discover/Makefile create mode 100644 apps/examples/discover/main.c create mode 100644 apps/include/netutils/discover.h create mode 100644 apps/netutils/discover/Kconfig create mode 100644 apps/netutils/discover/Makefile create mode 100644 apps/netutils/discover/README.txt create mode 100644 apps/netutils/discover/discover.c diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index 833a62cd1..6df66b95f 100755 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -319,3 +319,7 @@ * apps/netutils/webserver/httpd_sendfile.c: Add and option, CONFIG_NETUTILS_HTTPD_SENDFILE to transfer files using the NuttX sendfile() interface. + * apps/netutils/discover: A UDP network discovery utility contributed + by Max Holtzberg. + * apps/examples/discover: A test example for the UDP network discovery + utility (also contribed by Max Holtzberg). diff --git a/apps/examples/README.txt b/apps/examples/README.txt index 52d7279da..0d327ebfb 100644 --- a/apps/examples/README.txt +++ b/apps/examples/README.txt @@ -275,6 +275,28 @@ examples/dhcpd CONFIGURED_APPS += uiplib +examples/discover +^^^^^^^^^^^^^^^^^ + + This example execises netutils/discover utility. This example initializes + and starts the UDP discover daemon. This daemon is useful for discovering + devices in local networks, especially with DHCP configured devices. It + listens for UDP broadcasts which also can include a device class so that + groups of devices can be discovered. It is also possible to address all + classes with a kind of broadcast discover. + + This example will automatically be built as an NSH built-in if + CONFIG_NSH_BUILTIN_APPS is selected. Otherwise, it will be a standalone + program with entry point "discover_main". + + NuttX configuration settings: + + CONFIG_EXAMPLE_DISCOVER_DHCPC - DHCP Client + CONFIG_EXAMPLE_DISCOVER_NOMAC - Use canned MAC address + CONFIG_EXAMPLE_DISCOVER_IPADDR - Target IP address + CONFIG_EXAMPLE_DISCOVER_DRIPADDR - Router IP address + CONFIG_EXAMPLE_DISCOVER_NETMASK - Network Mask + examples/ftpc ^^^^^^^^^^^^^ diff --git a/apps/examples/discover/Kconfig b/apps/examples/discover/Kconfig new file mode 100644 index 000000000..afdb9ff82 --- /dev/null +++ b/apps/examples/discover/Kconfig @@ -0,0 +1,42 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +config EXAMPLES_DISCOVER + bool "UDP Discovery Example" + default n + depends on NET_UDP + select NETUTILS_DISCOVER + ---help--- + Enable the netutils/discover utility. This example initializes and + starts the UDP discover daemon. This daemon is useful for + discovering devices in local networks, especially with DHCP + configured devices. It listens for UDP broadcasts which also can + include a device class so that groups of devices can be discovered. + It is also possible to address all classes with a kind of broadcast + discover. + +if EXAMPLES_DISCOVER + +config EXAMPLE_DISCOVER_DHCPC + bool "DHCP Client" + default n + +config EXAMPLE_DISCOVER_NOMAC + bool "Use canned MAC address" + default n + +config EXAMPLE_DISCOVER_IPADDR + hex "Target IP address" + default 0x0a000002 + +config EXAMPLE_DISCOVER_DRIPADDR + hex "Router IP address" + default 0x0a000001 + +config EXAMPLE_DISCOVER_NETMASK + hex "Network Mask" + default 0xffffff00 + +endif diff --git a/apps/examples/discover/Makefile b/apps/examples/discover/Makefile new file mode 100644 index 000000000..f42f310a1 --- /dev/null +++ b/apps/examples/discover/Makefile @@ -0,0 +1,106 @@ +############################################################################ +# apps/examples/discover/Makefile +# +# Copyright (C) 2012 Max Holtzberg. All rights reserved. +# Copyright (C) 2008, 2010-2012 Gregory Nutt. All rights reserved. +# +# Authors: Max Holtzberg +# Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Discover built-in application info + +APPNAME = discover +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +ASRCS = +CSRCS = main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/discover/main.c b/apps/examples/discover/main.c new file mode 100644 index 000000000..b857e4f68 --- /dev/null +++ b/apps/examples/discover/main.c @@ -0,0 +1,183 @@ +/**************************************************************************** + * examples/discover/main.c + * + * Copyright (C) 2012 Max Holtzberg. All rights reserved. + * Copyright (C) 2008, 2011-2012 Gregory Nutt. All rights reserved. + * + * Authors: Max Holtzberg + * Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef CONFIG_EXAMPLE_DISCOVER_DHCPC +# include +#endif + +/* Here we include the header file for the application(s) we use in + * our project as defined in the config//defconfig file + */ + +/* DHCPC may be used in conjunction with any other feature (or not) */ + +#ifdef CONFIG_EXAMPLE_DISCOVER_DHCPC +# include +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * discover_main + ****************************************************************************/ + +int discover_main(int argc, char *argv[]) +{ +#ifndef CONFIG_NSH_BUILTIN_APPS + struct in_addr addr; +#if defined(CONFIG_EXAMPLE_DISCOVER_DHCPC) || defined(CONFIG_EXAMPLE_DISCOVER_NOMAC) + uint8_t mac[IFHWADDRLEN]; +#endif +#ifdef CONFIG_EXAMPLE_DISCOVER_DHCPC + void *handle; +#endif + +/* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_EXAMPLE_DISCOVER_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xde; + mac[3] = 0xad; + mac[4] = 0xbe; + mac[5] = 0xef; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up our host address */ + +#ifdef CONFIG_EXAMPLE_DISCOVER_DHCPC + addr.s_addr = 0; +#else + addr.s_addr = HTONL(CONFIG_EXAMPLE_DISCOVER_IPADDR); +#endif + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_DISCOVER_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_DISCOVER_NETMASK); + uip_setnetmask("eth0", &addr); + +#ifdef CONFIG_EXAMPLE_DISCOVER_DHCPC + /* Set up the resolver */ + + resolv_init(); + + /* Get the MAC address of the NIC */ + + uip_getmacaddr("eth0", mac); + + /* Set up the DHCPC modules */ + + handle = dhcpc_open(&mac, IFHWADDRLEN); + + /* Get an IP address. Note: there is no logic here for renewing the address in this + * example. The address should be renewed in ds.lease_time/2 seconds. + */ + + printf("Getting IP address\n"); + if (handle) + { + struct dhcpc_state ds; + (void)dhcpc_request(handle, &ds); + uip_sethostaddr("eth1", &ds.ipaddr); + + if (ds.netmask.s_addr != 0) + { + uip_setnetmask("eth0", &ds.netmask); + } + + if (ds.default_router.s_addr != 0) + { + uip_setdraddr("eth0", &ds.default_router); + } + + if (ds.dnsaddr.s_addr != 0) + { + resolv_conf(&ds.dnsaddr); + } + + dhcpc_close(handle); + printf("IP: %s\n", inet_ntoa(ds.ipaddr)); + } +#endif +#endif /* CONFIG_NSH_BUILTIN_APPS */ + + if (discover_start() < 0) + { + ndbg("Could not start discover daemon.\n"); + return ERROR; + } + + return OK; +} + diff --git a/apps/include/netutils/discover.h b/apps/include/netutils/discover.h new file mode 100644 index 000000000..c2226918d --- /dev/null +++ b/apps/include/netutils/discover.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * apps/include/netutils/discover.h + * + * Copyright (C) 2012 Max Holtzberg. All rights reserved. + * Author: Max Holtzberg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_INCLUDE_NETUTILS_DISCOVER_H +#define __APPS_INCLUDE_NETUTILS_DISCOVER_H + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: discover_start + * + * Description: + * Start the discover daemon. + * + * Return: + * The process ID (pid) of the new discover daemon is returned on + * success; A negated errno is returned if the daemon was not successfully + * started. + * + ****************************************************************************/ + +int discover_start(void); + +#endif /* __APPS_INCLUDE_NETUTILS_DISCOVER_H */ diff --git a/apps/netutils/Kconfig b/apps/netutils/Kconfig index cd0cb84dd..aa0f14963 100644 --- a/apps/netutils/Kconfig +++ b/apps/netutils/Kconfig @@ -52,3 +52,7 @@ endmenu menu "uIP web server" source "$APPSDIR/netutils/webserver/Kconfig" endmenu + +menu "UDP Discovery Utility" +source "$APPSDIR/netutils/discover/Kconfig" +endmenu diff --git a/apps/netutils/Make.defs b/apps/netutils/Make.defs index 04accf5d2..f957009b5 100644 --- a/apps/netutils/Make.defs +++ b/apps/netutils/Make.defs @@ -78,6 +78,10 @@ ifeq ($(CONFIG_NETUTILS_WEBCLIENT),y) CONFIGURED_APPS += netutils/webclient endif -ifeq ($(CONFIGNETUTILS_WEBSERVER),y) +ifeq ($(CONFIG_NETUTILS_WEBSERVER),y) CONFIGURED_APPS += netutils/webserver endif + +ifeq ($(CONFIG_NETUTILS_DISCOVER),y) +CONFIGURED_APPS += netutils/discover +endif diff --git a/apps/netutils/Makefile b/apps/netutils/Makefile index 1313c223d..03261c7a3 100644 --- a/apps/netutils/Makefile +++ b/apps/netutils/Makefile @@ -38,7 +38,8 @@ # Sub-directories ifeq ($(CONFIG_NET),y) -SUBDIRS = uiplib dhcpc dhcpd ftpc ftpd resolv smtp telnetd webclient webserver tftpc thttpd +SUBDIRS = uiplib dhcpc dhcpd discover ftpc ftpd resolv smtp telnetd +SUBDIRS += webclient webserver tftpc thttpd endif all: nothing diff --git a/apps/netutils/README.txt b/apps/netutils/README.txt index 26f11b7ce..231cf62c1 100644 --- a/apps/netutils/README.txt +++ b/apps/netutils/README.txt @@ -1,5 +1,5 @@ -netutils -^^^^^^^^ +netutils README.txt +^^^^^^^^^^^^^^^^^^^ Contents -------- @@ -39,6 +39,12 @@ highly influenced by uIP) include: dhcpd - Dynamic Host Configuration Protocol (DHCP) server. See apps/include/netutils/dhcpd.h for interface information. + discover - This daemon is useful for discovering devices in local + networks, especially with DHCP configured devices. It + listens for UDP broadcasts which also can include a + device class so that groups of devices can be discovered. + It is also possible to address all classes with a kind of + broadcast discover. (Contributed by Max Holtzberg). tftpc - TFTP client. See apps/include/netutils/tftp.h for interface information. telnetd - TELNET server. This is the Telnet logic adapted from diff --git a/apps/netutils/discover/Kconfig b/apps/netutils/discover/Kconfig new file mode 100644 index 000000000..336550511 --- /dev/null +++ b/apps/netutils/discover/Kconfig @@ -0,0 +1,39 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +config NETUTILS_DISCOVER + bool "Network Discovery Utility" + default n + depends on NET_UDP + ---help--- + Tool for discovering devices on the local network per UDP broadcast. + +if NETUTILS_DISCOVER + +DISCOVER_STACK_SIZE + int "Discover Daemon Stack Size" + default 1024 + +DISCOVER_PRIORITY + int "Discover Daemon Priority" + default 50 + +DISCOVER_PORT + int "Discover Daemon Port Number" + default 96 + +DISCOVER_INTERFACE + int "Network Interface Name" + default "eth0" + +DISCOVER_DEVICE_CLASS + hex "Network Discovery Class" + default 0xff + +CONFIG_DISCOVER_DESCR + string "Discoverer Description" + default "NuttX" + +endif diff --git a/apps/netutils/discover/Makefile b/apps/netutils/discover/Makefile new file mode 100644 index 000000000..52099b439 --- /dev/null +++ b/apps/netutils/discover/Makefile @@ -0,0 +1,100 @@ +############################################################################ +# apps/netutils/discover/Makefile +# +# Copyright (C) 2012 Max Holtzberg. All rights reserved. +# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. +# +# Authors: Max Holtzberg +# Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Telnet daemon + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_UDP),y) +CSRCS += discover.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/discover/README.txt b/apps/netutils/discover/README.txt new file mode 100644 index 000000000..11aab8bf3 --- /dev/null +++ b/apps/netutils/discover/README.txt @@ -0,0 +1,9 @@ +apps/netutils/discover README.txt +================================= + +This daemon is useful for discovering devices in local networks, especially +with DHCP configured devices. It listens for UDP broadcasts which also can +include a device class so that groups of devices can be discovered. It is +also possible to address all classes with a kind of broadcast discover. + +See nuttx/tools/discover.py for a client example. diff --git a/apps/netutils/discover/discover.c b/apps/netutils/discover/discover.c new file mode 100644 index 000000000..67df02b3f --- /dev/null +++ b/apps/netutils/discover/discover.c @@ -0,0 +1,456 @@ +/**************************************************************************** + * examples/discover/main.c + * + * Copyright (C) 2012 Max Holtzberg. All rights reserved. + * Copyright (C) 2008, 2011-2012 Gregory Nutt. All rights reserved. + * + * Authors: Max Holtzberg + * Gregory Nutt + * + * This code is derived from the netutils/dhcpd code. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_DISCOVER_STACK_SIZE +# define CONFIG_DISCOVER_STACK_SIZE 1024 +#endif + +#ifndef CONFIG_DISCOVER_PRIORITY +# define CONFIG_DISCOVER_PRIORITY SCHED_PRIORITY_DEFAULT +#endif + +#ifndef CONFIG_DISCOVER_PORT +# define CONFIG_DISCOVER_PORT 96 +#endif + +#ifndef CONFIG_DISCOVER_INTERFACE +# define CONFIG_DISCOVER_INTERFACE "eth0" +#endif + +#ifndef CONFIG_DISCOVER_DEVICE_CLASS +# define CONFIG_DISCOVER_DEVICE_CLASS DISCOVER_ALL +#endif + +#ifndef CONFIG_DISCOVER_DESCR +# define CONFIG_DISCOVER_DESCR CONFIG_ARCH_BOARD +#endif + +/* Internal Definitions *****************************************************/ +/* Discover request packet format: + * Byte Description + * 0 Protocol indentifier (0x99) + * 1 Request command 0x01 + * 2 Destination device class (For querying subsets of available devices) + * 0xff for all devices + * 3 Checksum (Byte 0 - Byte 1 - Byte n) & 0xff + */ + +/* Discover response packet format: + * Byte Description + * 0 Protocol indentifier (0x99) + * 1 Reponse command (0x02) + * 2-33 Device description string with 0 bytes filled + * 34 Checksum (Byte 0 - Byte 1 - Byte n) & 0xff + */ + +#define DISCOVER_PROTO_ID 0x99 +#define DISCOVER_REQUEST 0x01 +#define DISCOVER_RESPONSE 0x02 +#define DISCOVER_ALL 0xff +#define DISCOVER_REQUEST_SIZE 4 +#define DISCOVER_RESPONSE_SIZE 35 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef uint8_t request_t[DISCOVER_REQUEST_SIZE]; +typedef uint8_t response_t[DISCOVER_RESPONSE_SIZE]; + +struct discover_state_s +{ + in_addr_t serverip; + request_t request; + response_t response; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +struct discover_state_s g_state; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int discover_daemon(int argc, char *argv[]); +static inline int discover_socket(void); +static inline int discover_openlistener(void); +static inline int discover_openresponder(void); +static inline int discover_parse(request_t packet); +static inline int discover_respond(in_addr_t *ipaddr); +static inline void discover_initresponse(void); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline void discover_initresponse() +{ + int chk = 0; + int i; + + g_state.response[0] = DISCOVER_PROTO_ID; + g_state.response[1] = DISCOVER_RESPONSE; + + strncpy((char*) &g_state.response[2], CONFIG_DISCOVER_DESCR, + DISCOVER_RESPONSE_SIZE-3); + + for (i = 0; i < DISCOVER_RESPONSE_SIZE-1; i++) + { + chk -= g_state.response[i]; + } + + /* Append check sum */ + + g_state.response[DISCOVER_RESPONSE_SIZE-1] = chk & 0xff; +} + +static int discover_daemon(int argc, char *argv[]) +{ + int sockfd = -1; + int nbytes; + int addrlen = sizeof(struct sockaddr_in); + struct sockaddr_in srcaddr; + + memset(&g_state, 0, sizeof(struct discover_state_s)); + discover_initresponse(); + + nvdbg("Started\n"); + + for (;;) + { + /* Create a socket to listen for requests from DHCP clients */ + + if (sockfd < 0) + { + sockfd = discover_openlistener(); + if (sockfd < 0) + { + ndbg("Failed to create socket\n"); + break; + } + } + + /* Read the next packet */ + + nbytes = recvfrom(sockfd, &g_state.request, sizeof(g_state.request), 0, + (struct sockaddr*) &srcaddr, + (socklen_t *) &addrlen); + if (nbytes < 0) + { + /* On errors (other EINTR), close the socket and try again */ + + ndbg("recv failed: %d\n", errno); + if (errno != EINTR) + { + close(sockfd); + sockfd = -1; + } + continue; + } + + if (discover_parse(g_state.request) != OK) + { + continue; + } + + ndbg("Received discover from %08lx'\n", srcaddr.sin_addr.s_addr); + + discover_respond(&srcaddr.sin_addr.s_addr); + } + + return OK; +} + +static inline int discover_parse(request_t packet) +{ + int i; + uint8_t chk = 0; + + if (packet[0] != DISCOVER_PROTO_ID) + { + ndbg("Wrong protocol id: %d\n", packet[0]); + return ERROR; + } + + if (packet[1] != DISCOVER_REQUEST) + { + ndbg("Wrong command: %d\n", packet[1]); + return ERROR; + } + + if (packet[2] == 0xff || packet[2] == CONFIG_DISCOVER_DEVICE_CLASS) + { + for (i = 0; i < DISCOVER_REQUEST_SIZE-1; i++) + chk -= packet[i]; + + if ((chk & 0xff) != packet[3]) + { + ndbg("Checksum does not match: %d\n", packet[3]); + return ERROR; + } + else + { + return OK; + } + } + return ERROR; +} + +static inline int discover_respond(in_addr_t *ipaddr) +{ + struct sockaddr_in addr; + int sockfd; + int ret; + + sockfd = discover_openresponder(); + if (sockfd >= 0) + { + /* Then send the reponse to the DHCP client port at that address */ + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = HTONS(CONFIG_DISCOVER_PORT); + addr.sin_addr.s_addr = *ipaddr; + + ret = sendto(sockfd, &g_state.response, sizeof(g_state.response), 0, + (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + if (ret < 0) + { + ndbg("Could not send discovery response: %d\n", errno); + } + + close(sockfd); + } + + return ret; +} + +static inline int discover_socket() +{ + int sockfd; +#if defined(HAVE_SO_REUSEADDR) || defined(HAVE_SO_BROADCAST) + int optval; + int ret; +#endif + + /* Create a socket to listen for requests from DHCP clients */ + + sockfd = socket(PF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + ndbg("socket failed: %d\n", errno); + return ERROR; + } + + /* Configure the socket */ + +#ifdef HAVE_SO_REUSEADDR + optval = 1; + ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)); + if (ret < 0) + { + ndbg("setsockopt SO_REUSEADDR failed: %d\n", errno); + close(sockfd); + return ERROR; + } +#endif + +#ifdef HAVE_SO_BROADCAST + optval = 1; + ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (void*)&optval, sizeof(int)); + if (ret < 0) + { + ndbg("setsockopt SO_BROADCAST failed: %d\n", errno); + close(sockfd); + return ERROR; + } +#endif + + return sockfd; +} + +static inline int discover_openlistener() +{ + struct sockaddr_in addr; + struct ifreq req; + int sockfd; + int ret; + + /* Create a socket to listen for requests from DHCP clients */ + + sockfd = discover_socket(); + if (sockfd < 0) + { + ndbg("socket failed: %d\n", errno); + return ERROR; + } + + /* Get the IP address of the selected device */ + + strncpy(req.ifr_name, CONFIG_DISCOVER_INTERFACE, IFNAMSIZ); + ret = ioctl(sockfd, SIOCGIFADDR, (unsigned long)&req); + if (ret < 0) + { + ndbg("setsockopt SIOCGIFADDR failed: %d\n", errno); + close(sockfd); + return ERROR; + } + g_state.serverip = ((struct sockaddr_in*)&req.ifr_addr)->sin_addr.s_addr; + nvdbg("serverip: %08lx\n", ntohl(g_state.serverip)); + + /* Bind the socket to a local port. We have to bind to INADDRY_ANY to + * receive broadcast messages. + */ + + addr.sin_family = AF_INET; + addr.sin_port = htons(CONFIG_DISCOVER_PORT); + addr.sin_addr.s_addr = INADDR_ANY; + + ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + if (ret < 0) + { + ndbg("bind failed, port=%d addr=%08lx: %d\n", + addr.sin_port, (long)addr.sin_addr.s_addr, errno); + close(sockfd); + return ERROR; + } + + return sockfd; +} + +static inline int discover_openresponder(void) +{ + struct sockaddr_in addr; + int sockfd; + int ret; + + /* Create a socket for responding to discovery message */ + + sockfd = discover_socket(); + if (sockfd < 0) + { + ndbg("socket failed: %d\n", errno); + return ERROR; + } + + /* Bind the socket to a local port.*/ + + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = g_state.serverip; + + ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + if (ret < 0) + { + ndbg("bind failed, port=%d addr=%08lx: %d\n", + addr.sin_port, (long)addr.sin_addr.s_addr, errno); + close(sockfd); + return ERROR; + } + + return sockfd; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: discover_start + * + * Description: + * Start the discover daemon. + * + * Return: + * The process ID (pid) of the new discover daemon is returned on + * success; A negated errno is returned if the daemon was not successfully + * started. + * + ****************************************************************************/ + +int discover_start() +{ + pid_t pid; + + /* Then start the new daemon */ + + pid = TASK_CREATE("Discover daemon", CONFIG_DISCOVER_PRIORITY, + CONFIG_DISCOVER_STACK_SIZE, discover_daemon, NULL); + if (pid < 0) + { + int errval = errno; + ndbg("Failed to start the discover daemon: %d\n", errval); + return -errval; + } + + /* Return success */ + + return pid; +} diff --git a/nuttx/Documentation/README.html b/nuttx/Documentation/README.html index 135c4f359..5bc3d1d96 100644 --- a/nuttx/Documentation/README.html +++ b/nuttx/Documentation/README.html @@ -254,6 +254,7 @@ |- modbus/ | `- README.txt |- netutils/ + | | |- discover/README.txt | | |- ftpc/README.txt | | |- telnetd/README.txt | `- README diff --git a/nuttx/README.txt b/nuttx/README.txt index b0aa5384c..ae33a6e9c 100644 --- a/nuttx/README.txt +++ b/nuttx/README.txt @@ -824,6 +824,8 @@ apps |- modbus/ | `- README.txt |- netutils/ + | |- discover + | | `- README.txt | |- ftpc | | `- README.txt | |- telnetd -- cgit v1.2.3