diff --git a/COPYING b/COPYING index 8a5fe4b6c..a95d23a37 100644 --- a/COPYING +++ b/COPYING @@ -1,4 +1,4 @@ -PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. +PicoTCP. Copyright (c) 2013 TASS Belgium NV. Released under the GNU General Public License, version 2. See LICENSE for details. diff --git a/Makefile b/Makefile index f9fcc855d..790de64c0 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,3 @@ --include ../../config.mk --include ../../tools/kconfig/.config - CC:=$(CROSS_COMPILE)gcc LD:=$(CROSS_COMPILE)ld AR:=$(CROSS_COMPILE)ar @@ -18,7 +15,6 @@ ENDIAN?=little STRIP?=0 RTOS?=0 CHECKSUMFUN?=young -ADDRESS_SANITIZER?=0 # Default compiled-in protocols # @@ -36,13 +32,13 @@ DHCP_CLIENT?=1 DHCP_SERVER?=1 DNS_CLIENT?=1 MDNS?=1 +DNS_SD?=1 SNTP_CLIENT?=1 IPFILTER?=1 CRC?=1 OLSR?=0 SLAACV4?=1 TFTP?=1 -AODV?=1 MEMORY_MANAGER?=0 MEMORY_MANAGER_PROFILING?=0 TUN?=0 @@ -52,7 +48,6 @@ TAP?=0 IPV6?=1 EXTRA_CFLAGS+=-DPICO_COMPILE_TIME=`date +%s` -EXTRA_CFLAGS+=$(PLATFORM_CFLAGS) CFLAGS=-I$(PREFIX)/include -Iinclude -Imodules -Wall -Wdeclaration-after-statement -W -Wextra -Wshadow -Wcast-qual -Wwrite-strings -Wmissing-field-initializers -Wunused-variable -Wundef -Wunused-function $(EXTRA_CFLAGS) # extra flags recommanded by TIOBE TICS framework to score an A on compiler warnings @@ -63,11 +58,11 @@ CFLAGS+= -Wcast-align ifeq ($(DEBUG),1) CFLAGS+=-ggdb else - ifeq ($(PERF), 1) - CFLAGS+=-O3 - else - CFLAGS+=-Os - endif + ifeq ($(PERF), 1) + CFLAGS+=-O3 + else + CFLAGS+=-Os + endif endif ifeq ($(PROFILE),1) @@ -79,11 +74,6 @@ ifeq ($(TFTP),1) OPTIONS+=-DPICO_SUPPORT_TFTP endif -ifeq ($(AODV),1) - MOD_OBJ+=$(LIBBASE)modules/pico_aodv.o - OPTIONS+=-DPICO_SUPPORT_AODV -endif - ifneq ($(ENDIAN),little) CFLAGS+=-DPICO_BIGENDIAN @@ -97,25 +87,22 @@ ifneq ($(RTOS),0) OPTIONS+=-DPICO_SUPPORT_RTOS endif -ifeq ($(ARCH),cortexm4-hardfloat) - CFLAGS+=-DCORTEX_M4_HARDFLOAT -mcpu=cortex-m4 -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork -fsingle-precision-constant -endif - -ifeq ($(ARCH),cortexm4-softfloat) - CFLAGS+=-DCORTEX_M4_SOFTFLOAT -mcpu=cortex-m4 -mthumb -mlittle-endian -mfloat-abi=soft -mthumb-interwork -endif - -ifeq ($(ARCH),cortexm3) - CFLAGS+=-DCORTEX_M3 -mcpu=cortex-m3 -mthumb -mlittle-endian -mthumb-interwork +ifeq ($(ARCH),stm32f4xx) + CFLAGS+=-mcpu=cortex-m4 \ + -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 \ + -mfloat-abi=hard -mthumb-interwork -fsingle-precision-constant -DSTM32 endif -ifeq ($(ARCH),arm9) - CFLAGS+=-DARM9 -mcpu=arm9e -march=armv5te -gdwarf-2 -Wall -marm -mthumb-interwork -fpack-struct +ifeq ($(ARCH),stm32) + CFLAGS+=-mcpu=cortex-m4 \ + -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 \ + -mfloat-abi=hard -mthumb-interwork -fsingle-precision-constant -DSTM32 endif -ifeq ($(ADDRESS_SANITIZER),1) - CFLAGS+=-fsanitize=address -fno-omit-frame-pointer -m32 - TEST_LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer -m32 +ifeq ($(ARCH),stm32_gc) + CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 + CFLAGS_CORTEX_M4 += -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion + CFLAGS+= $(CFLAGS_CORTEX_M4) -mlittle-endian -DSTM32_GC endif ifeq ($(ARCH),faulty) @@ -125,12 +112,59 @@ ifeq ($(ARCH),faulty) DUMMY_EXTRA+=test/pico_faulty.o endif +ifeq ($(ARCH),stm32-softfloat) + CFLAGS+=-mcpu=cortex-m3 \ + -mthumb -mlittle-endian \ + -mfloat-abi=soft -mthumb-interwork \ + -DSTM32 +endif + + +ifeq ($(ARCH),stm32f1xx) + CFLAGS+=-mcpu=cortex-m3 \ + -mthumb -mlittle-endian \ + -mthumb-interwork \ + -DSTM32F1 +endif + + ifeq ($(ARCH),msp430) CFLAGS+=-DMSP430 endif ifeq ($(ARCH),esp8266) - CFLAGS+=-DESP8266 -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals + CFLAGS += -DESP8266 \ + -g \ + -Wpointer-arith \ + -Wundef \ + -Wl,-EL \ + -fno-inline-functions \ + -nostdlib \ + -mlongcalls \ + -mtext-section-literals +endif + +ifeq ($(ARCH),stellaris) + CFLAGS+=-mthumb -DSTELLARIS +endif + +ifeq ($(ARCH),lpc) + CFLAGS+=-fmessage-length=0 -fno-builtin \ + -ffunction-sections -fdata-sections -mlittle-endian \ + -mcpu=cortex-m3 -mthumb -MMD -MP -DLPC +endif + +ifeq ($(ARCH),lpc18xx) + CFLAGS+=-fmessage-length=0 -fno-builtin \ + -ffunction-sections -fdata-sections -mlittle-endian \ + -mcpu=cortex-m3 -mthumb -MMD -MP -DLPC18XX +endif + +ifeq ($(ARCH),lpc43xx) + CFLAGS+=-fmessage-length=0 -fno-builtin \ + -ffunction-sections -fdata-sections -mlittle-endian \ + -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 \ + -fsingle-precision-constant -mthumb -MMD -MP -DLPC43XX endif ifeq ($(ARCH),pic24) @@ -139,7 +173,11 @@ ifeq ($(ARCH),pic24) endif ifeq ($(ARCH),atmega128) - CFLAGS+=-Wall -mmcu=atmega128 -DAVR + CFLAGS+=-Wall -mmcu=atmega128 -DAVR +endif + +ifeq ($(ARCH),str9) + CFLAGS+=-DSTR9 -mcpu=arm9e -march=armv5te -gdwarf-2 -Wall -marm -mthumb-interwork -fpack-struct endif ifeq ($(ARCH),none) @@ -150,7 +188,7 @@ ifeq ($(ARCH),shared) CFLAGS+=-fPIC endif -%.o:%.c deps +.c.o: $(CC) -c $(CFLAGS) -o $@ $< CORE_OBJ= stack/pico_stack.o \ @@ -158,15 +196,15 @@ CORE_OBJ= stack/pico_stack.o \ stack/pico_device.o \ stack/pico_protocol.o \ stack/pico_socket.o \ - stack/pico_socket_multicast.o \ - stack/pico_tree.o + stack/pico_socket_multicast.o \ + stack/pico_tree.o -POSIX_OBJ+= modules/pico_dev_vde.o \ - modules/pico_dev_tun.o \ - modules/pico_dev_tap.o \ - modules/pico_dev_mock.o \ +POSIX_OBJ+= modules/pico_dev_vde.o \ + modules/pico_dev_tun.o \ + modules/pico_dev_tap.o \ + modules/pico_dev_mock.o \ modules/pico_dev_pcap.o \ - modules/ptsocket/pico_ptsocket.o + modules/ptsocket/pico_ptsocket.o ifneq ($(ETH),0) include rules/eth.mk @@ -208,6 +246,9 @@ endif ifneq ($(MDNS),0) include rules/mdns.mk endif +ifneq ($(DNS_SD),0) + include rules/dns_sd.mk +endif ifneq ($(IPFILTER),0) include rules/ipfilter.mk endif @@ -241,11 +282,11 @@ endif all: mod core lib -core: $(CORE_OBJ) +core: deps $(CORE_OBJ) @mkdir -p $(PREFIX)/lib @mv stack/*.o $(PREFIX)/lib -mod: $(MOD_OBJ) +mod: deps $(MOD_OBJ) @mkdir -p $(PREFIX)/modules @mv modules/*.o $(PREFIX)/modules || echo @@ -270,7 +311,7 @@ test: posix tst: test -$(PREFIX)/include/pico_defines.h: +$(PREFIX)/include/pico_defines.h: FORCE @mkdir -p $(PREFIX)/lib @mkdir -p $(PREFIX)/include @bash ./mkdeps.sh $(PREFIX) $(OPTIONS) @@ -306,20 +347,21 @@ units: mod core lib $(UNITS_OBJ) $(MOD_OBJ) @echo -e "\t[CC] units.o" @$(CC) -c -o $(PREFIX)/test/units.o test/units.c $(CFLAGS) -I stack -I modules -I includes -I test/unit -DUNIT_TEST @echo -e "\t[LD] $(PREFIX)/test/units" - @$(CC) -o $(PREFIX)/test/units $(CFLAGS) $(PREFIX)/test/units.o -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/modules/pico_aodv.o + @$(CC) -o $(PREFIX)/test/units $(CFLAGS) $(PREFIX)/test/units.o -lcheck -lm -pthread -lrt $(UNITS_OBJ) @$(CC) -o $(PREFIX)/test/modunit_pico_protocol.elf $(CFLAGS) -I. test/unit/modunit_pico_protocol.c stack/pico_tree.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) @$(CC) -o $(PREFIX)/test/modunit_pico_frame.elf $(CFLAGS) -I. test/unit/modunit_pico_frame.c stack/pico_tree.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) @$(CC) -o $(PREFIX)/test/modunit_seq.elf $(CFLAGS) -I. test/unit/modunit_seq.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a @$(CC) -o $(PREFIX)/test/modunit_tcp.elf $(CFLAGS) -I. test/unit/modunit_pico_tcp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a @$(CC) -o $(PREFIX)/test/modunit_dns_client.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_client.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a + @$(CC) -o $(PREFIX)/test/modunit_dns_common.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_common.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a @$(CC) -o $(PREFIX)/test/modunit_mdns.elf $(CFLAGS) -I. test/unit/modunit_pico_mdns.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a + @$(CC) -o $(PREFIX)/test/modunit_dns_sd.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_sd.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a @$(CC) -o $(PREFIX)/test/modunit_dev_loop.elf $(CFLAGS) -I. test/unit/modunit_pico_dev_loop.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) @$(CC) -o $(PREFIX)/test/modunit_ipv6_nd.elf $(CFLAGS) -I. test/unit/modunit_pico_ipv6_nd.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a @$(CC) -o $(PREFIX)/test/modunit_pico_stack.elf $(CFLAGS) -I. test/unit/modunit_pico_stack.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a @$(CC) -o $(PREFIX)/test/modunit_tftp.elf $(CFLAGS) -I. test/unit/modunit_pico_tftp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a @$(CC) -o $(PREFIX)/test/modunit_sntp_client.elf $(CFLAGS) -I. test/unit/modunit_pico_sntp_client.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) @$(CC) -o $(PREFIX)/test/modunit_ipfilter.elf $(CFLAGS) -I. test/unit/modunit_pico_ipfilter.c stack/pico_tree.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) - @$(CC) -o $(PREFIX)/test/modunit_aodv.elf $(CFLAGS) -I. test/unit/modunit_pico_aodv.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a @$(CC) -o $(PREFIX)/test/modunit_queue.elf $(CFLAGS) -I. test/unit/modunit_queue.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) devunits: mod core lib diff --git a/README.md b/README.md index 08f57cfb4..f6ad88384 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -picoTCP +picoTCP - dns-sd --------------- Welcome to the one and only picoTCP repository. -picoTCP is a TCP/IP stack designed for embedded systems developed by *[Altran Intelligent Systems](http://intelligent-systems.altran.com/)* +picoTCP is a TCP/IP stack designed for embedded systems developed by *[Altran ISY](http://intelligent-systems.altran.com/)* This code is released under the terms of GNU GPL v2 only. Some rights reserved. Other licenses may apply at the sole discretion of the copyright holders. @@ -13,7 +13,7 @@ The getting started guide can be found on the GitHub wiki (https://github.com/ta For more information, visit [the project's website](http://www.picotcp.com) -[Check our code quality](http://95.138.172.54:42506/TIOBEPortal/TICS/treeviewer?) +[Check our code quality](http://tics.picotcp.com:42506/TIOBEPortal/TICS/treeviewer?) --------------- @@ -21,16 +21,16 @@ For more information, visit [the project's website](http://www.picotcp.com) Continuous integration Jenkins Functional tests: -[![Jenkins autotest](http://162.13.84.104:8080/buildStatus/icon?job=PicoTCP_rel_autotest)](http://162.13.84.104:8080/job/PicoTCP_rel_autotest) +[![Jenkins autotest](http://jenkins.picotcp.com:8080/buildStatus/icon?job=PicoTCP_rel_autotest)](http://jenkins.picotcp.com:8080/job/PicoTCP_rel_autotest) Jenkins Unit tests : -[![Jenkins unit tests](http://162.13.84.104:8080/buildStatus/icon?job=PicoTCP_rel_unit_tests)](http://162.13.84.104:8080/job/PicoTCP_rel_unit_tests) +[![Jenkins unit tests](http://jenkins.picotcp.com:8080/buildStatus/icon?job=PicoTCP_rel_unit_tests)](http://jenkins.picotcp.com:8080/job/PicoTCP_rel_unit_tests) Jenkins RFC compliance : -[![Jenkins RFC Compliance](http://162.13.84.104:8080/buildStatus/icon?job=PicoTCP_rel_RF_mbed)](http://162.13.84.104:8080/job/PicoTCP_rel_RF_mbed) +[![Jenkins RFC Compliance](http://jenkins.picotcp.com:8080/buildStatus/icon?job=PicoTCP_rel_RF_mbed)](http://jenkins.picotcp.com:8080/job/PicoTCP_rel_RF_mbed) Jenkins TICS quality : -[![Jenkins TICS](http://162.13.84.104:8080/buildStatus/icon?job=PicoTCP_rel_TICS)](http://162.13.84.104:8080/job/PicoTCP_rel_TICS/) +[![Jenkins TICS](http://jenkins.picotcp.com:8080/buildStatus/icon?job=PicoTCP_rel_TICS)](http://jenkins.picotcp.com:8080/job/PicoTCP_rel_TICS/) Travis: [![Travis CI build status](https://api.travis-ci.org/tass-belgium/picotcp.svg)](https://travis-ci.org/tass-belgium/picotcp) diff --git a/docs/user_manual/chap_api_aodv.tex b/docs/user_manual/chap_api_aodv.tex deleted file mode 100644 index 02171ea20..000000000 --- a/docs/user_manual/chap_api_aodv.tex +++ /dev/null @@ -1,42 +0,0 @@ -\section{Ad-hoc On-Demand Distance Vector Routing (AODV)} - - -AODV is a reactive routing protocol for mobile ad-hoc networks -(MANETs). Its best fit are especially ultra-low power radio networks, -or those RF topologies where sporadic traffic between a small specific set -of nodes is foreseen. -In order to create a route, one node must explicitly start the communication -towards a remote node, and the route is created ad-hoc upon the demand -for a specific network path. -AODV guarantees that the traffic generated by each node in order to create -and maintain routes is kept as low as possible. - -\subsection{pico\_aodv\_add} - -\subsubsection*{Description} -This function will add the target device to the AODV mechanism on the machine, -meaning that it will be possible to advertise and collect routing information -using Ad-hoc On-Demand Distance Vector Routing, as described in RFC3561, through the -target device. - -In order to use multiple devices in the AODV system, this function needs to be called -multiple times, once per device. - -\subsubsection*{Function prototype} -\texttt{pico\_aodv\_add(struct pico\_device *dev);} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{dev} - a pointer to a struct \texttt{pico\_device} specifying the target interface. -\end{itemize} - -\subsubsection*{Return value} -0 returned if the device is successfully added. - -\subsubsection*{Example} -\begin{verbatim} - -ret = pico_aodv_add(dev); - -\end{verbatim} - diff --git a/docs/user_manual/chap_api_sock.tex b/docs/user_manual/chap_api_sock.tex index da43a1a30..d75309e57 100644 --- a/docs/user_manual/chap_api_sock.tex +++ b/docs/user_manual/chap_api_sock.tex @@ -8,7 +8,7 @@ \subsection{pico$\_$socket$\_$open} \subsubsection*{Description} This function will be called to open a socket from the application level. The created -socket will be unbound and not connected. +socket will be unbound. \subsubsection*{Function prototype} \begin{verbatim} @@ -57,7 +57,7 @@ \subsubsection*{Example} \subsection{pico$\_$socket$\_$read} \subsubsection*{Description} -This function will be called to read data from a connected socket. The function checks that the socket is bound and connected before attempting to receive data. +This function will be called to read a string from a socket from the application level. The function checks whether or not the socket is bound. \subsubsection*{Function prototype} \begin{verbatim} @@ -67,7 +67,7 @@ \subsubsection*{Function prototype} \subsubsection*{Parameters} \begin{itemize}[noitemsep] \item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer where the received data will be stored +\item \texttt{buf} - Void pointer to the start of a string buffer where the string will be stored \item \texttt{len} - Length of the buffer (in bytes), represents the maximum amount of bytes that can be read \end{itemize} @@ -92,9 +92,10 @@ \subsubsection*{Example} \subsection{pico$\_$socket$\_$write} \subsubsection*{Description} -This function will be called to write the content of a buffer to a socket that has been previously connected. -This function checks that the socket is bound, connected and that it is allowed to send data, i.e. there hasn't been a local shutdown. -This is the preferred function to use when writing data from the application to a connected stream. +This function will be called to write a string to a socket from the application level. +This function also checks if the socket is bound, connected and that it isn't shutdown +locally. This is the preferred function to use when writing strings from application +level. \subsubsection*{Function prototype} \begin{verbatim} @@ -104,8 +105,8 @@ \subsubsection*{Function prototype} \subsubsection*{Parameters} \begin{itemize}[noitemsep] \item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of a (constant) buffer where the data is stored -\item \texttt{len} - Length of the data buffer \texttt{buf} +\item \texttt{buf} - Void pointer to the start of a string buffer where the string is stored +\item \texttt{len} - Length of the string that is stored in the buffer (in bytes) \end{itemize} \subsubsection*{Return value} @@ -133,10 +134,9 @@ \subsubsection*{Example} \subsection{pico$\_$socket$\_$sendto} \subsubsection*{Description} -This function sends data from the local address to the remote address, without checking -whether the remote endpoint is connected. Specifying the destination is particularly useful while sending single datagrams -to different destinations upon consecutive calls. This is the preferred mechanism to send datagrams to a remote destination -using a UDP socket. +This function is be called by the \texttt{pico$\_$socket$\_$write} and \texttt{pico$\_$socket$\_$send} functions. +This function sends a string from the local address to the remote address, without checking +if the remote is connected or not. \subsubsection*{Function prototype} \begin{verbatim} @@ -147,8 +147,8 @@ \subsubsection*{Function prototype} \subsubsection*{Parameters} \begin{itemize}[noitemsep] \item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Length of the buffer \texttt{buf} +\item \texttt{buf} - Void pointer to the start of a string buffer where the string is stored +\item \texttt{len} - Length of the string that is stored in the buffer (in bytes) \item \texttt{dst} - Pointer to the origin of the IPv4/IPv6 frame header \item \texttt{remote$\_$port} - Portnumber of the receiving socket \end{itemize} @@ -176,7 +176,7 @@ \subsubsection*{Example} \subsection{pico$\_$socket$\_$recvfrom} \subsubsection*{Description} -This function is called to receive data from the specified socket. +This function is called to receive a string of data from the specified socket. It is useful when called in the context of a non-connected socket, to receive the information regarding the origin of the data, namely the origin address and the remote port number. @@ -190,8 +190,8 @@ \subsubsection*{Function prototype} \subsubsection*{Parameters} \begin{itemize}[noitemsep] \item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Maximum allowed length for the data to be stored in the buffer \texttt{buf} +\item \texttt{buf} - Void pointer to the start of a string buffer where the string will be stored +\item \texttt{len} - Length of the string that will be stored in the buffer (in bytes) \item \texttt{orig} - Pointer to the origin of the IPv4/IPv6 frame header, can be NULL \item \texttt{remote$\_$port} - Pointer to the port number of the sender socket, can be NULL \end{itemize} @@ -216,119 +216,12 @@ \subsubsection*{Example} bytesRcvd = pico_socket_recvfrom(sk_tcp, buf, bufLen, &peer, &port); \end{verbatim} -\subsection{Extended Socket operations} -The interface provided by sendto/recvfrom can be extended to include more information about the network communication. -This is especially useful in UDP communication, and whenever extended information is needed about the single datagram and its encapsulation in the networking layer. - -PicoTCP offers an extra structure that can be used to set and retrieve message information while transmitting and receiving datagrams, respectively. The structure \texttt{pico$\_$msginfo} is defined as follows: -\begin{verbatim} -struct pico_msginfo { - struct pico_device *dev; - uint8_t ttl; - uint8_t tos; -}; -\end{verbatim} - - - -\subsection{pico$\_$socket$\_$sendto$\_$extended} - -\subsubsection*{Description} -This function is an extension of the \texttt{pico$\_$socket$\_$sendto} function described above. It's exactly the same but it adds up an additional argument to set TTL and QOS information on the outgoing packet which contains the datagram. - -The usage of the extended argument makes sense in UDP context only, as the information is set at packet level, and only with UDP there is a 1:1 correspondence between datagrams and IP packets. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_sendto_extended(struct pico_socket *s, const void *buf, int len, -void *dst, uint16_t remote_port, struct pico_msginfo *info); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Length of the data that is stored in the buffer (in bytes) -\item \texttt{dst} - Pointer to the origin of the IPv4/IPv6 frame header -\item \texttt{remote$\_$port} - Port number of the receiving socket at the remote endpoint -\item \texttt{info} - Extended information about the packet containing this datagram. Only the fields "ttl" and "tos" are taken into consideeration, while "dev" is ignored. - -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns an integer representing the number of bytes written to the socket. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EADDRNOTAVAIL} - address not available -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$EHOSTUNREACH} - host is unreachable -\item \texttt{PICO$\_$ERR$\_$ENOMEM} - not enough space -\item \texttt{PICO$\_$ERR$\_$EAGAIN} - resource temporarily unavailable -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -struct pico_msginfo info = { }; -info.ttl = 5; -bytesWritten = pico_socket_sendto_extended(sk_tcp, buf, len, &sk_tcp->remote_addr, -sk_tcp->remote_port, &info); -\end{verbatim} - - -\subsection{pico$\_$socket$\_$recvfrom$\_$extended} - -\subsubsection*{Description} -This function is an extension to the normal \texttt{pico$\_$socket$\_$recvfrom} function, which allows to retrieve additional information about the networking layer that has been involved in the delivery of the datagram. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_recvfrom_extended(struct pico_socket *s, void *buf, int len, -void *orig, uint16_t *remote_port, struct pico_msginfo *info); -\end{verbatim} - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Maximum allowed length for the data to be stored in the buffer \texttt{buf} -\item \texttt{orig} - Pointer to the origin of the IPv4/IPv6 frame header, can be NULL -\item \texttt{remote$\_$port} - Pointer to the port number of the sender socket, can be NULL -\item \texttt{info} - Extended information about the incoming packet containing this datagram. The device where the packet was received is pointed by info->dev, the maximum TTL for the packet is stored in info->ttl, and finally the field info->tos keeps track of the flags in IP header's QoS. -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns an integer representing the number of bytes read from the socket. On success, if \texttt{orig} -is not NULL, The address of the remote endpoint is stored in the memory area pointed by \texttt{orig}. -In the same way, \texttt{remote$\_$port} will contain the portnumber of the sending socket, unless a NULL is passed -from the caller. - -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument -\item \texttt{PICO$\_$ERR$\_$ESHUTDOWN} - cannot read after transport endpoint shutdown -\item \texttt{PICO$\_$ERR$\_$EADDRNOTAVAIL} - address not available -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -struct pico_msginfo info; -bytesRcvd = pico_socket_recvfrom_extended(sk_tcp, buf, bufLen, &peer, &port, &info); -if (info && info->dev) { - printf("Socket received a datagram via device %s, ttl:%d, tos: %08x\n", - info->dev->name, info->ttl, info->tos); -} -\end{verbatim} - \subsection{pico$\_$socket$\_$send} \subsubsection*{Description} -This function is called to send data to the specified socket. -It checks if the socket is connected and then calls the +This function is called to send a string of data to the specified socket. +This function also checks if the socket is connected and then calls the \texttt{pico$\_$socket$\_$sendto} function. \subsubsection*{Function prototype} @@ -340,8 +233,8 @@ \subsubsection*{Function prototype} \subsubsection*{Parameters} \begin{itemize}[noitemsep] \item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Length of the buffer \texttt{buf} +\item \texttt{buf} - Void pointer to the start of a string buffer where the string is stored +\item \texttt{len} - Length of the string that is stored in the buffer (in bytes) \end{itemize} \subsubsection*{Return value} @@ -377,8 +270,8 @@ \subsubsection*{Function prototype} \subsubsection*{Parameters} \begin{itemize}[noitemsep] \item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{buf} - Void pointer to the start of the buffer -\item \texttt{len} - Maximum allowed length for the data to be stored in the buffer \texttt{buf} +\item \texttt{buf} - Void pointer to the start of a string buffer where the string will be stored +\item \texttt{len} - Length of the string in the socket buffer (in bytes) \end{itemize} \subsubsection*{Return value} @@ -472,47 +365,6 @@ \subsubsection*{Example} } \end{verbatim} -\subsection{pico$\_$socket$\_$getpeername} - -\subsubsection*{Description} -This function returns the IP-address of the remote peer connected to the specified socket. - -\subsubsection*{Function prototype} -\begin{verbatim} -int pico_socket_getpeername(struct pico_socket *s, void *remote_addr, uint16_t *port, - uint16_t *proto); -\end{verbatim} - - -\subsubsection*{Parameters} -\begin{itemize}[noitemsep] -\item \texttt{s} - Pointer to socket of type \texttt{struct pico$\_$socket} -\item \texttt{remote$\_$addr} - Address (IPv4 or IPv6) associated to the socket remote endpoint -\item \texttt{port} - Local portnumber associated to the socket -\item \texttt{proto} - Proto of the address returned in the \texttt{local$\_$addr} field. Can be either \texttt{PICO$\_$PROTO$\_$IPV4} or \texttt{PICO$\_$PROTO$\_$IPV6} -\end{itemize} - -\subsubsection*{Return value} -On success, this call returns 0 and populates the three fields {local$\_$addr} \texttt{port} and \texttt{proto} accordingly. -On error, -1 is returned, and \texttt{pico$\_$err} is set appropriately. - -\subsubsection*{Errors} -\begin{itemize}[noitemsep] -\item \texttt{PICO$\_$ERR$\_$EINVAL} - invalid argument(s) provided -\item \texttt{PICO$\_$ERR$\_$ENOTCONN} - the socket is not connected to any peer -\end{itemize} - -\subsubsection*{Example} -\begin{verbatim} -errMsg = pico_socket_getpeername(sk_tcp, address, &port, &proto); -if (errMsg == 0) { - if (proto == PICO_PROTO_IPV4) - addr4 = (struct pico_ip4 *)address; - else - addr6 = (struct pico_ip6 *)address; -} -\end{verbatim} - \subsection{pico$\_$socket$\_$connect} diff --git a/docs/user_manual/chap_rfcs.tex b/docs/user_manual/chap_rfcs.tex index dfb53a84c..934f935ba 100644 --- a/docs/user_manual/chap_rfcs.tex +++ b/docs/user_manual/chap_rfcs.tex @@ -62,7 +62,7 @@ Requirements for Internet Hosts - Application and Support (\textsuperscript{1}) \\ \hline RFC 1191 & -Path MTU Discovery (\textsuperscript{1})\\ \hline +Path MTU Discovery \\ \hline RFC 1323 & TCP Extensions for High Performance \\ \hline @@ -127,9 +127,6 @@ RFC 3517 & A Conservative Selective Acknowledgment (SACK)-based Loss Recovery Algorithm for TCP \\ \hline -RFC 3561 & -Ad-hoc On-Demand Distance Vector (AODV) Routing \\ \hline - RFC 3626 & Optimized Link State Routing Protocol (OLSR) \\ \hline @@ -142,9 +139,6 @@ RFC 4291 & IP Version 6 Addressing Architecture \\ \hline -RFC 4443 & -Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification \\ \hline - RFC 4861 & Neighbor Discovery for IP version 6 (IPv6) \\ \hline diff --git a/docs/user_manual/layout1.tex b/docs/user_manual/layout1.tex index 946b6bac7..0d451d221 100644 --- a/docs/user_manual/layout1.tex +++ b/docs/user_manual/layout1.tex @@ -1,4 +1,4 @@ -% Altran Intelligent Systems +% TASS Belgium NV % % LAYOUT TEXT % =========== @@ -24,4 +24,4 @@ {\setlength{\parindent}{0pt} \raggedright \normalfont \bfseries\Huge\thechapter.\ #1 \par\nobreak\vspace{40 pt}}} -\makeatother +\makeatother \ No newline at end of file diff --git a/docs/user_manual/user_doc.tex b/docs/user_manual/user_doc.tex index 6c8c5d1d6..6464b7dc9 100644 --- a/docs/user_manual/user_doc.tex +++ b/docs/user_manual/user_doc.tex @@ -27,7 +27,7 @@ %% to print watermark % \usepackage{draftwatermark} -% \SetWatermarkText{Altran ISY Confidential} +% \SetWatermarkText{TASS Confidential} % \SetWatermarkScale{3} % \SetWatermarkLightness{0.9} @@ -49,7 +49,7 @@ \begin{document} \title{picoTCP User Documentation} -\author{Copyright \copyright 2013-2015 Altran NV. All right reserved.} +\author{Copyright \copyright 2013-2014 Altran NV. All right reserved.} \maketitle \date{\today} \maketitle @@ -98,7 +98,6 @@ \chapter{API Documentation} \input{chap_api_slaacv4} \input{chap_api_tftp} \input{chap_api_olsr} -\input{chap_api_aodv} \chapter{Examples} \label{chap:examples} diff --git a/include/arch/pico_avr.h b/include/arch/pico_avr.h index cd7e4aba8..ec81e4525 100644 --- a/include/arch/pico_avr.h +++ b/include/arch/pico_avr.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/include/arch/pico_cortex_m.h b/include/arch/pico_cortex_m.h deleted file mode 100644 index cfd12f30f..000000000 --- a/include/arch/pico_cortex_m.h +++ /dev/null @@ -1,12 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - *********************************************************************/ -#ifndef _INCLUDE_PICO_CORTEX_M -#define _INCLUDE_PICO_CORTEX_M - -#include "pico_generic_gcc.h" - -#endif /* PICO_CORTEX_M */ - diff --git a/include/arch/pico_esp8266.h b/include/arch/pico_esp8266.h index a2bd42819..b35661e4d 100644 --- a/include/arch/pico_esp8266.h +++ b/include/arch/pico_esp8266.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ @@ -14,7 +14,7 @@ /* -------------- DEBUG ------------- */ -/* #define dbg(...) */ +//#define dbg(...) #define dbg os_printf @@ -27,7 +27,6 @@ static inline void *pico_zalloc(size_t size) void *ptr = (void *)os_malloc(size); if(ptr) memset(ptr, 0u, size); - return ptr; } diff --git a/include/arch/pico_lpc1768.h b/include/arch/pico_lpc1768.h new file mode 100644 index 000000000..d8c8f3fbf --- /dev/null +++ b/include/arch/pico_lpc1768.h @@ -0,0 +1,83 @@ +/********************************************************************* + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. + See LICENSE and COPYING for usage. + + *********************************************************************/ +#ifndef _INCLUDE_PICO_LPC +#define _INCLUDE_PICO_LPC + +#include +#include +#include +#include "pico_constants.h" + +#ifdef PICO_SUPPORT_RTOS +# define PICO_SUPPORT_MUTEX +extern void *pico_mutex_init(void); +extern void pico_mutex_lock(void*); +extern void pico_mutex_unlock(void*); +extern void *pvPortMalloc( size_t xSize ); +extern void vPortFree( void *pv ); + +#define pico_free(x) vPortFree(x) +#define free(x) vPortFree(x) + +static inline void *pico_zalloc(size_t size) +{ + void *ptr = pvPortMalloc(size); + + if(ptr) + memset(ptr, 0u, size); + + return ptr; +} + +#define PICO_TIME() (Time_ElapsedSec()) +#define PICO_TIME_MS() (Time_ElapsedMili()) +#define PICO_IDLE() +extern uint32_t Time_ElapsedSec(void); +extern uint32_t Time_ElapsedMili(void); + + +#else +# define pico_free(x) free(x) + +static inline void *pico_zalloc(size_t size) +{ + void *ptr = malloc(size); + + if(ptr) + memset(ptr, 0u, size); + + return ptr; +} + +extern volatile uint32_t lpc_tick; +extern volatile pico_time full_tick; + +static inline pico_time PICO_TIME_MS(void) +{ + if ((full_tick & 0xFFFFFFFF) > lpc_tick) { + full_tick += 0x100000000ULL; + } + + full_tick = (full_tick & 0xFFFFFFFF00000000ULL) + lpc_tick; + return full_tick; +} + +static inline pico_time PICO_TIME(void) +{ + return PICO_TIME_MS() / 1000; +} + +static inline void PICO_IDLE(void) +{ + uint32_t now = lpc_tick; + while(now == lpc_tick) ; +} + +#endif /* IFNDEF RTOS */ + +#define dbg(...) + +#endif diff --git a/include/arch/pico_lpc18xx.h b/include/arch/pico_lpc18xx.h new file mode 100644 index 000000000..c038c956d --- /dev/null +++ b/include/arch/pico_lpc18xx.h @@ -0,0 +1,121 @@ +/********************************************************************* + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. + See LICENSE and COPYING for usage. + + *********************************************************************/ +#ifndef _INCLUDE_PICO_LPC +#define _INCLUDE_PICO_LPC + +#include +#include +#include +#include "pico_constants.h" + +#define dbg(...) + + +extern volatile uint32_t tassTick; + +#ifdef PICO_SUPPORT_RTOS + #define PICO_SUPPORT_MUTEX +extern void *pico_mutex_init(void); +extern void pico_mutex_lock(void*); +extern void pico_mutex_unlock(void*); +extern void *pvPortMalloc( size_t xSize ); +extern void vPortFree( void *pv ); + + #define pico_free(x) vPortFree(x) + #define free(x) vPortFree(x) + +static inline void *pico_zalloc(size_t size) +{ + void *ptr = pvPortMalloc(size); + + if(ptr) + memset(ptr, 0u, size); + + return ptr; +} + +static inline pico_time PICO_TIME_MS() +{ + return tassTick; +} + +static inline pico_time PICO_TIME() +{ + return tassTick / 1000; +} + +static inline void PICO_IDLE(void) +{ + uint32_t now = PICO_TIME_MS(); + while(now == PICO_TIME_MS()) ; +} + +#else /* NO RTOS SUPPORT */ + +#ifdef MEM_MEASURE +void *pico_zzalloc(size_t x); +void pico_ffree(void *x); + +extern uint32_t max_mem; +extern uint32_t cur_mem; + +struct mem_chunk_stats { + uint32_t signature; + void *mem; + uint32_t size; +}; + +static inline void *pico_zalloc(size_t size) +{ + return pico_zzalloc(size); +} +static inline void pico_free(void *x) +{ + return pico_ffree(x); +} + +#else + #define pico_free(x) free(x) + +static inline void *pico_zalloc(size_t size) +{ + void *ptr = malloc(size); + + if(ptr) + memset(ptr, 0u, size); + + return ptr; +} + +#endif + +extern volatile uint32_t lpc_tick; +extern volatile pico_time full_tick; + +static inline pico_time PICO_TIME_MS(void) +{ + if ((full_tick & 0xFFFFFFFF) > lpc_tick) { + full_tick += 0x100000000ULL; + } + + full_tick = (full_tick & 0xFFFFFFFF00000000ULL) + lpc_tick; + return full_tick; +} + +static inline pico_time PICO_TIME(void) +{ + return PICO_TIME_MS() / 1000; +} + +static inline void PICO_IDLE(void) +{ + uint32_t now = lpc_tick; + while(now == lpc_tick) ; +} + +#endif /* IFNDEF RTOS */ + +#endif diff --git a/include/arch/pico_generic_gcc.h b/include/arch/pico_lpc43xx.h similarity index 58% rename from include/arch/pico_generic_gcc.h rename to include/arch/pico_lpc43xx.h index a26fcf12e..ae2bd25a1 100644 --- a/include/arch/pico_generic_gcc.h +++ b/include/arch/pico_lpc43xx.h @@ -1,25 +1,23 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ -#ifndef _INCLUDE_PICO_GCC -#define _INCLUDE_PICO_GCC +#ifndef _INCLUDE_PICO_LPC43XX +#define _INCLUDE_PICO_LPC43XX #include #include #include #include "pico_constants.h" -/* monotonically increasing tick, - * typically incremented every millisecond in a systick interrupt */ -extern volatile unsigned int pico_ms_tick; +extern volatile uint32_t tassTick; -#define dbg(...) +#define dbg #ifdef PICO_SUPPORT_RTOS - #define PICO_SUPPORT_MUTEX + #define PICO_SUPPORT_MUTEX extern void *pico_mutex_init(void); extern void pico_mutex_lock(void*); extern void pico_mutex_unlock(void*); @@ -41,44 +39,38 @@ static inline void *pico_zalloc(size_t size) static inline pico_time PICO_TIME_MS() { - return pico_ms_tick; + return tassTick; } static inline pico_time PICO_TIME() { - return pico_ms_tick / 1000; + return tassTick / 1000; } static inline void PICO_IDLE(void) { - pico_time now = PICO_TIME_MS(); + uint32_t now = PICO_TIME_MS(); while(now == PICO_TIME_MS()) ; } -#else /* NO RTOS SUPPORT */ - - #ifdef MEM_MEAS -/* These functions should be implemented elsewhere */ -extern void *memmeas_zalloc(size_t size); -extern void memmeas_free(void *); - #define pico_free(x) memmeas_free(x) - #define pico_zalloc(x) memmeas_zalloc(x) - #else -/* Use plain C-lib malloc and free */ - #define pico_free(x) free(x) +#else + + #define pico_free(x) free(x) static inline void *pico_zalloc(size_t size) { void *ptr = malloc(size); + if(ptr) memset(ptr, 0u, size); return ptr; } - #endif + +extern volatile pico_time lpc_tick; static inline pico_time PICO_TIME_MS(void) { - return pico_ms_tick; + return lpc_tick; } static inline pico_time PICO_TIME(void) @@ -88,11 +80,10 @@ static inline pico_time PICO_TIME(void) static inline void PICO_IDLE(void) { - unsigned int now = pico_ms_tick; - while(now == pico_ms_tick) ; + uint32_t now = lpc_tick; + while(now == lpc_tick) ; } #endif /* IFNDEF RTOS */ -#endif /* PICO_GCC */ - +#endif diff --git a/include/arch/pico_mbed.h b/include/arch/pico_mbed.h index 3c3a2722b..f3e2bf494 100644 --- a/include/arch/pico_mbed.h +++ b/include/arch/pico_mbed.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. File: pico_mbed.h @@ -9,7 +9,6 @@ #ifndef PICO_SUPPORT_MBED #define PICO_SUPPORT_MBED #include -#include /* #include "mbed.h" */ /* #include "serial_api.h" */ diff --git a/include/arch/pico_msp430.h b/include/arch/pico_msp430.h index 27e3e5afe..ba90895d7 100644 --- a/include/arch/pico_msp430.h +++ b/include/arch/pico_msp430.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/include/arch/pico_none.h b/include/arch/pico_none.h index fee74f995..30c4186e1 100644 --- a/include/arch/pico_none.h +++ b/include/arch/pico_none.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/include/arch/pico_pic24.h b/include/arch/pico_pic24.h index 27ff39ef6..fc7e5a690 100644 --- a/include/arch/pico_pic24.h +++ b/include/arch/pico_pic24.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ #ifndef PICO_SUPPORT_PIC24 diff --git a/include/arch/pico_posix.h b/include/arch/pico_posix.h index 6283b89ad..86193553a 100644 --- a/include/arch/pico_posix.h +++ b/include/arch/pico_posix.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/include/arch/pico_stellaris.h b/include/arch/pico_stellaris.h new file mode 100644 index 000000000..ce8ce3749 --- /dev/null +++ b/include/arch/pico_stellaris.h @@ -0,0 +1,58 @@ +/********************************************************************* + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. + See LICENSE and COPYING for usage. + *********************************************************************/ +#ifndef PICO_SUPPORT_STELLARIS +#define PICO_SUPPORT_STELLARIS + +/* #define dbg printf */ +#define dbg(...) do {} while(0) + +/*************************/ + +/*** MACHINE CONFIGURATION ***/ +/* Temporary (POSIX) stuff. */ +#include +#include +#include + +extern volatile uint32_t stellaris_tick; + +#ifdef PICO_SUPPORT_DEBUG_MEMORY +static inline void *pico_zalloc(int len) +{ + /* dbg("%s: Alloc object of len %d, caller: %p\n", __FUNCTION__, len, __builtin_return_address(0)); */ + return calloc(len, 1); +} + +static inline void pico_free(void *tgt) +{ + /* dbg("%s: Discarded object @%p, caller: %p\n", __FUNCTION__, tgt, __builtin_return_address(0)); */ + free(tgt); +} +#else +# define pico_zalloc(x) calloc(x, 1) +# define pico_free(x) free(x) +#endif + + + +static inline unsigned long PICO_TIME(void) +{ + register uint32_t tick = stellaris_tick; + return tick / 1000; +} + +static inline unsigned long PICO_TIME_MS(void) +{ + return stellaris_tick; +} + +static inline void PICO_IDLE(void) +{ + unsigned long tick_now = stellaris_tick; + while(tick_now == stellaris_tick) ; +} + +#endif + diff --git a/include/arch/pico_stm32.h b/include/arch/pico_stm32.h new file mode 100644 index 000000000..7318f1b6d --- /dev/null +++ b/include/arch/pico_stm32.h @@ -0,0 +1,78 @@ +/********************************************************************* + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. + See LICENSE and COPYING for usage. + *********************************************************************/ +#define dbg(...) do {} while(0) +/* #define dbg printf */ + +extern volatile uint32_t tassTick; + +#ifdef PICO_SUPPORT_RTOS + #define PICO_SUPPORT_MUTEX +extern void *pico_mutex_init(void); +extern void pico_mutex_lock(void*); +extern void pico_mutex_unlock(void*); +extern void *pvPortMalloc( size_t xSize ); +extern void vPortFree( void *pv ); + + #define pico_free(x) vPortFree(x) + #define free(x) vPortFree(x) + +static inline void *pico_zalloc(size_t size) +{ + void *ptr = pvPortMalloc(size); + + if(ptr) + memset(ptr, 0u, size); + + return ptr; +} + +static inline pico_time PICO_TIME_MS() +{ + return tassTick; +} + +static inline pico_time PICO_TIME() +{ + return tassTick / 1000; +} + +static inline void PICO_IDLE(void) +{ + uint32_t now = PICO_TIME_MS(); + while(now == PICO_TIME_MS()) ; +} + +#else /* NO RTOS SUPPORT */ + #define pico_free(x) free(x) + +static inline void *pico_zalloc(size_t size) +{ + void *ptr = malloc(size); + + if(ptr) + memset(ptr, 0u, size); + + return ptr; +} + +static inline unsigned long PICO_TIME(void) +{ + register uint32_t tick = tassTick; + return tick / 1000; +} + +static inline unsigned long PICO_TIME_MS(void) +{ + return tassTick; +} + +static inline void PICO_IDLE(void) +{ + uint32_t now = PICO_TIME_MS(); + while(now == PICO_TIME_MS()) ; +} + +#endif /* IFNDEF RTOS */ + diff --git a/include/arch/pico_stm32_gc.h b/include/arch/pico_stm32_gc.h new file mode 100644 index 000000000..bb0ee620c --- /dev/null +++ b/include/arch/pico_stm32_gc.h @@ -0,0 +1,64 @@ +/********************************************************************* + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. + See LICENSE and COPYING for usage. + *********************************************************************/ + + #define dbg(...) do {} while(0) +/* #define dbg printf */ + +extern volatile pico_time full_tick; + +/* Enable me if you are running stmhal */ +#if 0 +extern volatile uint32_t uwTick; +#else +extern volatile uint32_t sys_tick_counter; +#define uwTick sys_tick_counter +#endif +extern volatile uint32_t __stm32_tick; + +#ifdef PICO_SUPPORT_RTOS + #define PICO_SUPPORT_MUTEX +extern void *pico_mutex_init(void); +extern void pico_mutex_lock(void*); +extern void pico_mutex_unlock(void*); +extern void *pvPortMalloc( size_t xSize ); +extern void vPortFree( void *pv ); + + #define pico_free(x) vPortFree(x) + +static inline void *pico_zalloc(size_t size) +{ + void *ptr = pvPortMalloc(size); + + if(ptr) + memset(ptr, 0u, size); + + return ptr; +} + +static inline pico_time PICO_TIME_MS(void) +{ + if ((full_tick & 0xFFFFFFFF) > uwTick) { + full_tick += 0x100000000ULL; + } + + full_tick = (full_tick & 0xFFFFFFFF00000000ULL) + uwTick; + return full_tick; +} + +static inline pico_time PICO_TIME() +{ + return PICO_TIME_MS() >> 10; /* TODO: quick-hack bc no c-lib avail */ +} + +static inline void PICO_IDLE(void) +{ + pico_time now = PICO_TIME_MS(); + while(now == PICO_TIME_MS()) ; +} + +#else /* NO RTOS SUPPORT */ + #error Not implemented for STM32_GC +#endif /* IFNDEF RTOS */ + diff --git a/include/arch/pico_arm9.h b/include/arch/pico_str9.h similarity index 89% rename from include/arch/pico_arm9.h rename to include/arch/pico_str9.h index 0d2d2e311..78e047564 100644 --- a/include/arch/pico_arm9.h +++ b/include/arch/pico_str9.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ #define dbg(...) do {} while(0) diff --git a/include/heap.h b/include/heap.h index 868d275be..7624b14ba 100644 --- a/include/heap.h +++ b/include/heap.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/include/pico_addressing.h b/include/pico_addressing.h index de622813a..c352409dc 100644 --- a/include/pico_addressing.h +++ b/include/pico_addressing.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/include/pico_config.h b/include/pico_config.h index bd9232f03..bcd2c6b04 100644 --- a/include/pico_config.h +++ b/include/pico_config.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ @@ -18,7 +18,7 @@ # define PACKED_STRUCT_DEF __packed struct # define PEDANTIC_STRUCT_DEF __packed struct # define PACKED_UNION_DEF __packed union -# define WEAK +# define WEAK #else # define PACKED_STRUCT_DEF struct __attribute__((packed)) # define PEDANTIC_STRUCT_DEF struct @@ -133,26 +133,27 @@ static inline uint64_t long_long_be(uint64_t le) be = b[7] + (b6 << 8) + (b5 << 16) + (b4 << 24) + (b3 << 32) + (b2 << 40) + (b1 << 48) + (b0 << 56); return be; } +#warning "Not using GCC Optimizations!" # else /* - extern uint32_t __builtin_bswap32(uint32_t); - extern uint16_t __builtin_bswap16(uint16_t); - extern uint64_t __builtin_bswap64(uint64_t); - */ +extern uint32_t __builtin_bswap32(uint32_t); +extern uint16_t __builtin_bswap16(uint16_t); +extern uint64_t __builtin_bswap64(uint64_t); +*/ -static inline uint32_t long_be(uint32_t le) +static inline uint32_t long_be(uint32_t le) { - return (uint32_t)__builtin_bswap32(le); + return (uint32_t)__builtin_bswap32(le); } -static inline uint16_t short_be(uint16_t le) +static inline uint16_t short_be(uint16_t le) { - return (uint16_t)__builtin_bswap16(le); + return (uint16_t)__builtin_bswap16(le); } static inline uint64_t long_long_be(uint64_t le) { - return (uint64_t)__builtin_bswap64(le); + return (uint64_t)__builtin_bswap64(le); } # endif /* BYTESWAP_GCC */ @@ -183,14 +184,18 @@ static inline uint64_t long_long_be(uint64_t le) /*** *** *** *** *** *** *** *** PLATFORM SPECIFIC *** *** *** *** *** *** *** ***/ -#if defined PICO_PORT_CUSTOM -# include "pico_port.h" -#elif defined CORTEX_M4_HARDFLOAT -# include "arch/pico_cortex_m.h" -#elif defined CORTEX_M4_SOFTFLOAT -# include "arch/pico_cortex_m.h" -#elif defined CORTEX_M3 -# include "arch/pico_cortex_m.h" +#if defined STM32 +# include "arch/pico_stm32.h" +#elif defined STM32_GC +# include "arch/pico_stm32_gc.h" +#elif defined STELLARIS +# include "arch/pico_stellaris.h" +#elif defined LPC +# include "arch/pico_lpc1768.h" +#elif defined LPC43XX +# include "arch/pico_lpc43xx.h" +#elif defined LPC18XX +# include "arch/pico_lpc18xx.h" #elif defined PIC24 # include "arch/pico_pic24.h" #elif defined MSP430 @@ -199,8 +204,8 @@ static inline uint64_t long_long_be(uint64_t le) # include "arch/pico_mbed.h" #elif defined AVR # include "arch/pico_avr.h" -#elif defined ARM9 -# include "arch/pico_arm9.h" +#elif defined STR9 +# include "arch/pico_str9.h" #elif defined ESP8266 # include "arch/pico_esp8266.h" #elif defined FAULTY @@ -209,7 +214,10 @@ static inline uint64_t long_long_be(uint64_t le) # include "arch/pico_none.h" #elif defined __KERNEL__ # include "arch/pico_linux.h" + + /* #elif defined ... */ + #else # include "arch/pico_posix.h" #endif diff --git a/include/pico_constants.h b/include/pico_constants.h index f04340887..e4a7fdbdb 100644 --- a/include/pico_constants.h +++ b/include/pico_constants.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ @@ -25,7 +25,7 @@ extern volatile uint64_t pico_tick; #include "pico_addressing.h" /* Maximum amount of accepted ARP requests per burst interval */ -#define PICO_ARP_MAX_RATE 1 +#define PICO_ARP_MAX_RATE 25 /* Duration of the burst interval in milliseconds */ #define PICO_ARP_INTERVAL 1000 diff --git a/include/pico_device.h b/include/pico_device.h index a2d03ecb6..89a8f22ac 100644 --- a/include/pico_device.h +++ b/include/pico_device.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ @@ -46,9 +46,5 @@ int pico_devices_loop(int loop_score, int direction); struct pico_device*pico_get_device(const char*name); int32_t pico_device_broadcast(struct pico_frame *f); int pico_device_link_state(struct pico_device *dev); -int pico_device_ipv6_random_ll(struct pico_device *dev); -#ifdef PICO_SUPPORT_IPV6 -struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix); -#endif #endif diff --git a/include/pico_eth.h b/include/pico_eth.h index 89846c721..c7f71b37e 100644 --- a/include/pico_eth.h +++ b/include/pico_eth.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/include/pico_frame.h b/include/pico_frame.h index dc5a3c3f0..87833719f 100644 --- a/include/pico_frame.h +++ b/include/pico_frame.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ @@ -80,9 +80,6 @@ struct pico_frame { /* Callback to notify listener when the buffer has been discarded */ void (*notify_free)(uint8_t *); - - uint8_t send_ttl; /* Special TTL/HOPS value, 0 = auto assign */ - uint8_t send_tos; /* Type of service */ }; /** frame alloc/dealloc/copy **/ diff --git a/include/pico_module_eth.h b/include/pico_module_eth.h index c86680d01..8216dfb54 100644 --- a/include/pico_module_eth.h +++ b/include/pico_module_eth.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/include/pico_protocol.h b/include/pico_protocol.h index fd7c12210..67f8c5270 100644 --- a/include/pico_protocol.h +++ b/include/pico_protocol.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/include/pico_queue.h b/include/pico_queue.h index ad7b9e3e6..78cafd6f1 100644 --- a/include/pico_queue.h +++ b/include/pico_queue.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ @@ -14,13 +14,6 @@ #define NULL ((void *)0) #endif -void *pico_mutex_init(void); -void pico_mutex_deinit(void *mutex); -void pico_mutex_lock(void *mutex); -int pico_mutex_lock_timeout(void *mutex, int timeout); -void pico_mutex_unlock(void *mutex); -void pico_mutex_unlock_ISR(void *mutex); - struct pico_queue { uint32_t frames; uint32_t size; diff --git a/include/pico_socket.h b/include/pico_socket.h index a07665423..9e8beafac 100644 --- a/include/pico_socket.h +++ b/include/pico_socket.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ @@ -178,11 +178,6 @@ struct pico_ipv6_mreq_source { #define PICO_SOCK_EV_FIN 0x10u #define PICO_SOCK_EV_ERR 0x80u -struct pico_msginfo { - struct pico_device *dev; - uint8_t ttl; - uint8_t tos; -}; struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *s)); @@ -190,19 +185,13 @@ int pico_socket_read(struct pico_socket *s, void *buf, int len); int pico_socket_write(struct pico_socket *s, const void *buf, int len); int pico_socket_sendto(struct pico_socket *s, const void *buf, int len, void *dst, uint16_t remote_port); -int pico_socket_sendto_extended(struct pico_socket *s, const void *buf, const int len, - void *dst, uint16_t remote_port, struct pico_msginfo *msginfo); - int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *local_port); -int pico_socket_recvfrom_extended(struct pico_socket *s, void *buf, int len, void *orig, - uint16_t *remote_port, struct pico_msginfo *msginfo); int pico_socket_send(struct pico_socket *s, const void *buf, int len); int pico_socket_recv(struct pico_socket *s, void *buf, int len); int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port); int pico_socket_getname(struct pico_socket *s, void *local_addr, uint16_t *port, uint16_t *proto); -int pico_socket_getpeername(struct pico_socket *s, void *remote_addr, uint16_t *port, uint16_t *proto); int pico_socket_connect(struct pico_socket *s, const void *srv_addr, uint16_t remote_port); int pico_socket_listen(struct pico_socket *s, const int backlog); @@ -230,13 +219,13 @@ struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, uint16_t len); #endif #ifdef PICO_SUPPORT_UDP -# define is_sock_udp(x) (x->proto == &pico_proto_udp) +# define is_sock_udp(x) (x->net == &pico_proto_udp) #else # define is_sock_udp(x) (0) #endif #ifdef PICO_SUPPORT_TCP -# define is_sock_tcp(x) (x->proto == &pico_proto_tcp) +# define is_sock_tcp(x) (x->net == &pico_proto_tcp) #else # define is_sock_tcp(x) (0) #endif diff --git a/include/pico_stack.h b/include/pico_stack.h index e74616c74..8e1c696a9 100644 --- a/include/pico_stack.h +++ b/include/pico_stack.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ @@ -50,7 +50,7 @@ int32_t pico_ethernet_send(struct pico_frame *f); /* DATALINK LEVEL */ int32_t pico_ethernet_receive(struct pico_frame *f); #else -/* When ETH is not supported by the stack... */ + /* When ETH is not supported by the stack... */ # define pico_ethernet_send(f) (-1) # define pico_ethernet_receive(f) (-1) #endif @@ -80,6 +80,5 @@ uint32_t pico_rand(void); void pico_rand_feed(uint32_t feed); void pico_to_lowercase(char *str); int pico_address_compare(union pico_address *a, union pico_address *b, uint16_t proto); -int32_t pico_seq_compare(uint32_t a, uint32_t b); #endif diff --git a/include/pico_tree.h b/include/pico_tree.h index 8667a1f46..095eb5e95 100644 --- a/include/pico_tree.h +++ b/include/pico_tree.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Author: Andrei Carp diff --git a/modules/pico_aodv.c b/modules/pico_aodv.c deleted file mode 100644 index bc148c650..000000000 --- a/modules/pico_aodv.c +++ /dev/null @@ -1,648 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Author: Daniele Lacamera - *********************************************************************/ -#include -#include -#include -#include -#include - -#include - -#define pico_aodv_dbg(...) do {} while(0) -/* #define pico_aodv_dbg dbg */ - -#define AODV_MAX_PKT (64) -static const struct pico_ip4 HOST_NETMASK = { - 0xffffffff -}; -static struct pico_ip4 all_bcast = { - .addr = 0xFFFFFFFFu -}; - -static const struct pico_ip4 ANY_HOST = { - 0x0 -}; - -static uint32_t pico_aodv_local_id = 0; -static int aodv_node_compare(void *ka, void *kb) -{ - struct pico_aodv_node *a = ka, *b = kb; - if (a->dest.ip4.addr < b->dest.ip4.addr) - return -1; - - if (b->dest.ip4.addr < a->dest.ip4.addr) - return 1; - - return 0; -} - -static int aodv_dev_cmp(void *ka, void *kb) -{ - struct pico_device *a = ka, *b = kb; - if (a->hash < b->hash) - return -1; - - if (a->hash > b->hash) - return 1; - - return 0; -} - -PICO_TREE_DECLARE(aodv_nodes, aodv_node_compare); -PICO_TREE_DECLARE(aodv_devices, aodv_dev_cmp); - -static struct pico_socket *aodv_socket = NULL; - -static struct pico_aodv_node *get_node_by_addr(const union pico_address *addr) -{ - struct pico_aodv_node search; - memcpy(&search.dest, addr, sizeof(union pico_address)); - return pico_tree_findKey(&aodv_nodes, &search); - -} - -static void pico_aodv_set_dev(struct pico_device *dev) -{ - pico_ipv4_route_set_bcast_link(pico_ipv4_link_by_dev(dev)); -} - - -static int aodv_peer_refresh(struct pico_aodv_node *node, uint32_t seq) -{ - if ((0 == (node->flags & PICO_AODV_NODE_SYNC)) || (pico_seq_compare(seq, node->dseq) > 0)) { - node->dseq = seq; - node->flags |= PICO_AODV_NODE_SYNC; - node->last_seen = PICO_TIME_MS(); - return 0; - } - - return -1; -} - -static void aodv_elect_route(struct pico_aodv_node *node, union pico_address *gw, uint8_t metric, struct pico_device *dev) -{ - metric++; - if (!(PICO_AODV_ACTIVE(node)) || metric < node->metric) { - pico_ipv4_route_del(node->dest.ip4, HOST_NETMASK, node->metric); - if (!gw) { - pico_ipv4_route_add(node->dest.ip4, HOST_NETMASK, ANY_HOST, 1, pico_ipv4_link_by_dev(dev)); - node->metric = 1; - } else { - node->metric = metric; - pico_ipv4_route_add(node->dest.ip4, HOST_NETMASK, gw->ip4, metric, NULL); - } - } -} - -static struct pico_aodv_node *aodv_peer_new(const union pico_address *addr) -{ - struct pico_aodv_node *node = PICO_ZALLOC(sizeof(struct pico_aodv_node)); - if (!node) - return NULL; - - memcpy(&node->dest, addr, sizeof(union pico_address)); - pico_tree_insert(&aodv_nodes, node); - return node; -} - - -static struct pico_aodv_node *aodv_peer_eval(union pico_address *addr, uint32_t seq, int valid_seq) -{ - struct pico_aodv_node *node = NULL; - node = get_node_by_addr(addr); - if (!node) { - node = aodv_peer_new(addr); - } - - if (!valid_seq) - return node; - - if (node && (aodv_peer_refresh(node, long_be(seq)) == 0)) - return node; - - return NULL; -} - -void aodv_forward(void *pkt, struct pico_msginfo *info, int reply) -{ - struct pico_aodv_node *orig; - union pico_address orig_addr; - struct pico_tree_node *index; - struct pico_device *dev; - pico_time now; - int size; - - pico_aodv_dbg("Forwarding %s packet\n", reply ? "REPLY" : "REQUEST"); - - if (reply) { - struct pico_aodv_rrep *rep = (struct pico_aodv_rrep *)pkt; - orig_addr.ip4.addr = rep->dest; - rep->hop_count++; - pico_aodv_dbg("RREP hop count: %d\n", rep->hop_count); - size = sizeof(struct pico_aodv_rrep); - } else { - struct pico_aodv_rreq *req = (struct pico_aodv_rreq *)pkt; - orig_addr.ip4.addr = req->orig; - req->hop_count++; - size = sizeof(struct pico_aodv_rreq); - } - - orig = get_node_by_addr(&orig_addr); - if (!orig) - orig = aodv_peer_new(&orig_addr); - - if (!orig) - return; - - now = PICO_TIME_MS(); - - pico_aodv_dbg("Forwarding %s: last fwd_time: %llu now: %llu ttl: %d ==== \n", reply ? "REPLY" : "REQUEST", - orig->fwd_time, now, info->ttl); - if (((orig->fwd_time == 0) || ((now - orig->fwd_time) > AODV_NODE_TRAVERSAL_TIME)) && (--info->ttl > 0)) { - orig->fwd_time = now; - info->dev = NULL; - pico_tree_foreach(index, &aodv_devices){ - dev = index->keyValue; - pico_aodv_set_dev(dev); - pico_socket_sendto_extended(aodv_socket, pkt, size, &all_bcast, short_be(PICO_AODV_PORT), info); - pico_aodv_dbg("Forwarding %s: complete! ==== \n", reply ? "REPLY" : "REQUEST"); - } - } -} - -static uint32_t aodv_lifetime(struct pico_aodv_node *node) -{ - uint32_t lifetime; - pico_time now = PICO_TIME_MS(); - if (!node->last_seen) - node->last_seen = now; - - if ((now - node->last_seen) > AODV_ACTIVE_ROUTE_TIMEOUT) - return 0; - - lifetime = AODV_ACTIVE_ROUTE_TIMEOUT - (uint32_t)(now - node->last_seen); - return lifetime; -} - -static void aodv_send_reply(struct pico_aodv_node *node, struct pico_aodv_rreq *req, int node_is_local, struct pico_msginfo *info) -{ - struct pico_aodv_rrep reply; - union pico_address dest; - union pico_address oaddr; - struct pico_aodv_node *orig; - oaddr.ip4.addr = req->orig; - orig = get_node_by_addr(&oaddr); - reply.type = AODV_TYPE_RREP; - reply.dest = req->dest; - reply.dseq = req->dseq; - reply.orig = req->orig; - if (!orig) - return; - - reply.hop_count = (uint8_t)(orig->metric - 1u); - - - dest.ip4.addr = 0xFFFFFFFF; /* wide broadcast */ - - if (short_be(req->req_flags) & AODV_RREQ_FLAG_G) { - dest.ip4.addr = req->orig; - } else { - pico_aodv_set_dev(info->dev); - } - - if (node_is_local) { - reply.lifetime = long_be(AODV_MY_ROUTE_TIMEOUT); - reply.dseq = long_be(++pico_aodv_local_id); - pico_socket_sendto(aodv_socket, &reply, sizeof(reply), &dest, short_be(PICO_AODV_PORT)); - } else if (((short_be(req->req_flags) & AODV_RREQ_FLAG_D) == 0) && (node->flags & PICO_AODV_NODE_SYNC)) { - reply.lifetime = long_be(aodv_lifetime(node)); - reply.dseq = long_be(node->dseq); - pico_aodv_dbg("Generating RREP for node %x, id=%x\n", reply.dest, reply.dseq); - pico_socket_sendto(aodv_socket, &reply, sizeof(reply), &dest, short_be(PICO_AODV_PORT)); - } - - pico_aodv_dbg("no rrep generated.\n"); -} - -/* Parser functions */ - -static int aodv_send_req(struct pico_aodv_node *node); - -static void aodv_reverse_path_discover(pico_time now, void *arg) -{ - struct pico_aodv_node *origin = (struct pico_aodv_node *)arg; - (void)now; - pico_aodv_dbg("Sending G RREQ to ORIGIN (metric = %d).\n", origin->metric); - origin->ring_ttl = origin->metric; - aodv_send_req(origin); -} - -static void aodv_recv_valid_rreq(struct pico_aodv_node *node, struct pico_aodv_rreq *req, struct pico_msginfo *info) -{ - struct pico_device *dev; - dev = pico_ipv4_link_find(&node->dest.ip4); - pico_aodv_dbg("Valid req.\n"); - if (dev || PICO_AODV_ACTIVE(node)) { - /* if destination is ourselves, or we have a possible route: Send reply. */ - aodv_send_reply(node, req, dev != NULL, info); - if (dev) { - /* if really for us, we need to build the return route. Initiate a gratuitous request. */ - union pico_address origin_addr; - struct pico_aodv_node *origin; - origin_addr.ip4.addr = req->orig; - origin = get_node_by_addr(&origin_addr); - if (origin) { - origin->flags |= PICO_AODV_NODE_ROUTE_DOWN; - pico_timer_add(AODV_PATH_DISCOVERY_TIME, aodv_reverse_path_discover, origin); - } - } - - pico_aodv_dbg("Replied.\n"); - } else { - /* destination unknown. Evaluate forwarding. */ - pico_aodv_dbg(" == Forwarding == .\n"); - aodv_forward(req, info, 0); - } -} - - -static void aodv_parse_rreq(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) -{ - struct pico_aodv_rreq *req = (struct pico_aodv_rreq *) buf; - struct pico_aodv_node *node = NULL; - struct pico_device *dev; - union pico_address orig, dest; - (void)from; - if (len != sizeof(struct pico_aodv_rreq)) - return; - - orig.ip4.addr = req->orig; - dev = pico_ipv4_link_find(&orig.ip4); - if (dev) { - pico_aodv_dbg("RREQ <-- myself\n"); - return; - } - - node = aodv_peer_eval(&orig, req->oseq, 1); - if (!node) { - pico_aodv_dbg("RREQ: Neighbor is not valid. oseq=%d\n", long_be(req->oseq)); - return; - } - - if (req->hop_count > 0) - aodv_elect_route(node, from, req->hop_count, msginfo->dev); - else - aodv_elect_route(node, NULL, 0, msginfo->dev); - - dest.ip4.addr = req->dest; - node = aodv_peer_eval(&dest, req->dseq, !(req->req_flags & short_be(AODV_RREQ_FLAG_U))); - if (!node) { - node = aodv_peer_new(&dest); - pico_aodv_dbg("RREQ: New peer! %08x\n", dest.ip4.addr); - } - - if (!node) - return; - - aodv_recv_valid_rreq(node, req, msginfo); -} - -static void aodv_parse_rrep(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) -{ - struct pico_aodv_rrep *rep = (struct pico_aodv_rrep *) buf; - struct pico_aodv_node *node = NULL; - union pico_address dest; - union pico_address orig; - struct pico_device *dev = NULL; - if (len != sizeof(struct pico_aodv_rrep)) - return; - - dest.ip4.addr = rep->dest; - orig.ip4.addr = rep->orig; - dev = pico_ipv4_link_find(&dest.ip4); - - if (dev) /* Our reply packet got rebounced, no useful information here, no need to fwd. */ - return; - - pico_aodv_dbg("::::::::::::: Parsing RREP for node %08x\n", rep->dest); - node = aodv_peer_eval(&dest, rep->dseq, 1); - if (node) { - pico_aodv_dbg("::::::::::::: Node found. Electing route and forwarding.\n"); - dest.ip4.addr = node->dest.ip4.addr; - if (rep->hop_count > 0) - aodv_elect_route(node, from, rep->hop_count, msginfo->dev); - else - aodv_elect_route(node, NULL, 0, msginfo->dev); - - /* If we are the final destination for the reply (orig), no need to forward. */ - if (pico_ipv4_link_find(&orig.ip4)) { - node->flags |= PICO_AODV_NODE_ROUTE_UP; - } else { - aodv_forward(rep, msginfo, 1); - } - } -} - -static void aodv_parse_rerr(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) -{ - if ((uint32_t)len < sizeof(struct pico_aodv_rerr) || - (((uint32_t)len - sizeof(struct pico_aodv_rerr)) % sizeof(struct pico_aodv_unreachable)) > 0) - return; - - (void)from; - (void)buf; - (void)len; - (void)msginfo; - /* TODO: invalidate routes. This only makes sense if we are using HELLO messages. */ -} - -static void aodv_parse_rack(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) -{ - if (len != sizeof(struct pico_aodv_rack)) - return; - - (void)from; - (void)buf; - (void)len; - (void)msginfo; -} - -struct aodv_parser_s { - void (*call)(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo); -}; - -struct aodv_parser_s aodv_parser[5] = { - {.call = NULL}, - {.call = aodv_parse_rreq }, - {.call = aodv_parse_rrep }, - {.call = aodv_parse_rerr }, - {.call = aodv_parse_rack } -}; - - -static void pico_aodv_parse(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) -{ - struct pico_aodv_node *node; - uint8_t hopcount = 0; - if ((buf[0] < 1) || (buf[0] > 4)) { - /* Type is invalid. Discard silently. */ - return; - } - - if (buf[0] == AODV_TYPE_RREQ) { - hopcount = ((struct pico_aodv_rreq *)buf)->hop_count; - } - - if (buf[0] == AODV_TYPE_RREP) { - hopcount = ((struct pico_aodv_rrep *)buf)->hop_count; - } - - node = aodv_peer_eval(from, 0, 0); - if (!node) - node = aodv_peer_new(from); - - if (node && (hopcount == 0)) { - aodv_elect_route(node, NULL, hopcount, msginfo->dev); - } - - pico_aodv_dbg("Received AODV packet, ttl = %d\n", msginfo->ttl); - aodv_parser[buf[0]].call(from, buf, len, msginfo); -} - -static void pico_aodv_socket_callback(uint16_t ev, struct pico_socket *s) -{ - static uint8_t aodv_pkt[AODV_MAX_PKT]; - static union pico_address from; - static struct pico_msginfo msginfo; - uint16_t sport; - int r; - if (s != aodv_socket) - return; - - if (ev & PICO_SOCK_EV_RD) { - r = pico_socket_recvfrom_extended(s, aodv_pkt, AODV_MAX_PKT, &from, &sport, &msginfo); - if (r <= 0) - return; - - pico_aodv_dbg("Received AODV packet: %d bytes \n", r); - - pico_aodv_parse(&from, aodv_pkt, r, &msginfo); - } -} - -static void aodv_make_rreq(struct pico_aodv_node *node, struct pico_aodv_rreq *req) -{ - memset(req, 0, sizeof(struct pico_aodv_rreq)); - req->type = AODV_TYPE_RREQ; - - if (0 == (node->flags & PICO_AODV_NODE_SYNC)) { - req->req_flags |= short_be(AODV_RREQ_FLAG_U); /* no known dseq, mark as U */ - req->dseq = 0; /* Unknown */ - } else { - req->dseq = long_be(node->dseq); - req->req_flags |= short_be(AODV_RREQ_FLAG_G); /* RFC3561 $6.3: we SHOULD set G flag as originators */ - } - - /* Hop count = 0; */ - req->rreq_id = long_be(++pico_aodv_local_id); - req->dest = node->dest.ip4.addr; - req->oseq = long_be(pico_aodv_local_id); -} - -static void aodv_retrans_rreq(pico_time now, void *arg) -{ - struct pico_aodv_node *node = (struct pico_aodv_node *)arg; - struct pico_device *dev; - struct pico_tree_node *index; - static struct pico_aodv_rreq rreq; - struct pico_ipv4_link *ip4l = NULL; - struct pico_msginfo info = { - .dev = NULL, .tos = 0, .ttl = AODV_TTL_START - }; - (void)now; - - memset(&rreq, 0, sizeof(rreq)); - - if (node->flags & PICO_AODV_NODE_ROUTE_UP) { - pico_aodv_dbg("------------------------------------------------------ Node %08x already active.\n", node->dest.ip4.addr); - return; - } - - if (node->ring_ttl > AODV_TTL_THRESHOLD) { - node->ring_ttl = AODV_NET_DIAMETER; - pico_aodv_dbg("----------- DIAMETER reached.\n"); - } - - - if (node->rreq_retry > AODV_RREQ_RETRIES) { - node->rreq_retry = 0; - node->ring_ttl = 0; - pico_aodv_dbg("Node is unreachable.\n"); - node->flags &= (uint16_t)(~PICO_AODV_NODE_ROUTE_DOWN); - return; - } - - if (node->ring_ttl == AODV_NET_DIAMETER) { - node->rreq_retry++; - pico_aodv_dbg("Retry #%d\n", node->rreq_retry); - } - - aodv_make_rreq(node, &rreq); - info.ttl = (uint8_t)node->ring_ttl; - pico_tree_foreach(index, &aodv_devices){ - dev = index->keyValue; - pico_aodv_set_dev(dev); - ip4l = pico_ipv4_link_by_dev(dev); - if (ip4l) { - rreq.orig = ip4l->address.addr; - pico_socket_sendto_extended(aodv_socket, &rreq, sizeof(rreq), &all_bcast, short_be(PICO_AODV_PORT), &info); - } - } - if (node->ring_ttl < AODV_NET_DIAMETER) - node->ring_ttl = (uint8_t)(node->ring_ttl + AODV_TTL_INCREMENT); - - pico_timer_add((pico_time)AODV_RING_TRAVERSAL_TIME(node->ring_ttl), aodv_retrans_rreq, node); -} - -static int aodv_send_req(struct pico_aodv_node *node) -{ - struct pico_device *dev; - struct pico_tree_node *index; - static struct pico_aodv_rreq rreq; - int n = 0; - struct pico_ipv4_link *ip4l = NULL; - struct pico_msginfo info = { - .dev = NULL, .tos = 0, .ttl = AODV_TTL_START - }; - memset(&rreq, 0, sizeof(rreq)); - - if (PICO_AODV_ACTIVE(node)) - return 0; - - node->flags |= PICO_AODV_NODE_REQUESTING; - - if (pico_tree_empty(&aodv_devices)) - return n; - - if (!aodv_socket) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (node->flags & PICO_AODV_NODE_ROUTE_DOWN) { - info.ttl = node->metric; - } - - aodv_make_rreq(node, &rreq); - pico_tree_foreach(index, &aodv_devices) { - dev = index->keyValue; - pico_aodv_set_dev(dev); - ip4l = pico_ipv4_link_by_dev(dev); - if (ip4l) { - rreq.orig = ip4l->address.addr; - pico_socket_sendto_extended(aodv_socket, &rreq, sizeof(rreq), &all_bcast, short_be(PICO_AODV_PORT), &info); - n++; - } - } - pico_timer_add((pico_time)AODV_RING_TRAVERSAL_TIME(1), aodv_retrans_rreq, node); - return n; -} - -static void pico_aodv_expired(struct pico_aodv_node *node) -{ - node->flags |= PICO_AODV_NODE_UNREACH; - node->flags &= (uint8_t)(~PICO_AODV_NODE_ROUTE_UP); - node->flags &= (uint8_t)(~PICO_AODV_NODE_ROUTE_DOWN); - pico_ipv4_route_del(node->dest.ip4, HOST_NETMASK, node->metric); - node->ring_ttl = 0; - /* TODO: send err */ - -} - -static void pico_aodv_collector(pico_time now, void *arg) -{ - struct pico_tree_node *index; - struct pico_aodv_node *node; - (void)arg; - (void)now; - pico_tree_foreach(index, &aodv_nodes){ - node = index->keyValue; - if (PICO_AODV_ACTIVE(node)) { - uint32_t lifetime = aodv_lifetime(node); - if (lifetime == 0) - pico_aodv_expired(node); - } - } - pico_timer_add(AODV_HELLO_INTERVAL, pico_aodv_collector, NULL); -} - -MOCKABLE int pico_aodv_init(void) -{ - struct pico_ip4 any = { - 0 - }; - uint16_t port = short_be(PICO_AODV_PORT); - if (aodv_socket) { - pico_err = PICO_ERR_EADDRINUSE; - return -1; - } - - aodv_socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, pico_aodv_socket_callback); - if (!aodv_socket) - return -1; - - if (pico_socket_bind(aodv_socket, &any, &port) != 0) { - uint16_t err = pico_err; - pico_socket_close(aodv_socket); - pico_err = err; - aodv_socket = NULL; - return -1; - } - - pico_aodv_local_id = pico_rand(); - pico_timer_add(AODV_HELLO_INTERVAL, pico_aodv_collector, NULL); - return 0; -} - - -int pico_aodv_add(struct pico_device *dev) -{ - return (pico_tree_insert(&aodv_devices, dev)) ? (0) : (-1); -} - -void pico_aodv_refresh(const union pico_address *addr) -{ - struct pico_aodv_node *node = get_node_by_addr(addr); - if (node) { - node->last_seen = PICO_TIME_MS(); - } -} - -int pico_aodv_lookup(const union pico_address *addr) -{ - struct pico_aodv_node *node = get_node_by_addr(addr); - if (!node) - node = aodv_peer_new(addr); - - if (!node) - return -1; - - if ((node->flags & PICO_AODV_NODE_ROUTE_UP) || (node->flags & PICO_AODV_NODE_ROUTE_DOWN)) - return 0; - - if (node->ring_ttl < AODV_TTL_START) { - node->ring_ttl = AODV_TTL_START; - aodv_send_req(node); - return 0; - } - - pico_err = PICO_ERR_EINVAL; - return -1; -} - diff --git a/modules/pico_aodv.h b/modules/pico_aodv.h deleted file mode 100644 index a3e9b66bd..000000000 --- a/modules/pico_aodv.h +++ /dev/null @@ -1,131 +0,0 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Author: Daniele Lacamera - *********************************************************************/ -#ifndef PICO_AODV_H_ -#define PICO_AODV_H_ -#include - -/* RFC3561 */ -#define PICO_AODV_PORT (654) - -/* RFC3561 $10 */ -#define AODV_ACTIVE_ROUTE_TIMEOUT (8000u) /* Conservative value for link breakage detection */ -#define AODV_DELETE_PERIOD (5 * AODV_ACTIVE_ROUTE_TIMEOUT) /* Recommended value K = 5 */ -#define AODV_ALLOWED_HELLO_LOSS (4) /* conservative */ -#define AODV_NET_DIAMETER ((uint8_t)(35)) -#define AODV_RREQ_RETRIES (2) -#define AODV_NODE_TRAVERSAL_TIME (40) -#define AODV_HELLO_INTERVAL (1000) -#define AODV_LOCAL_ADD_TTL 2 -#define AODV_RREQ_RATELIMIT (10) -#define AODV_TIMEOUT_BUFFER (2) -#define AODV_TTL_START ((uint8_t)(1)) -#define AODV_TTL_INCREMENT 2 -#define AODV_TTL_THRESHOLD ((uint8_t)(7)) -#define AODV_RERR_RATELIMIT (10) -#define AODV_MAX_REPAIR_TTL ((uint8_t)(AODV_NET_DIAMETER / 3)) -#define AODV_MY_ROUTE_TIMEOUT (2 * AODV_ACTIVE_ROUTE_TIMEOUT) -#define AODV_NET_TRAVERSAL_TIME (2 * AODV_NODE_TRAVERSAL_TIME * AODV_NET_DIAMETER) -#define AODV_BLACKLIST_TIMEOUT (AODV_RREQ_RETRIES * AODV_NET_TRAVERSAL_TIME) -#define AODV_NEXT_HOP_WAIT (AODV_NODE_TRAVERSAL_TIME + 10) -#define AODV_PATH_DISCOVERY_TIME (2 * AODV_NET_TRAVERSAL_TIME) -#define AODV_RING_TRAVERSAL_TIME(ttl) (2 * AODV_NODE_TRAVERSAL_TIME * (ttl + AODV_TIMEOUT_BUFFER)) -/* End section RFC3561 $10 */ - - -#define AODV_TYPE_RREQ 1 -#define AODV_TYPE_RREP 2 -#define AODV_TYPE_RERR 3 -#define AODV_TYPE_RACK 4 - -PACKED_STRUCT_DEF pico_aodv_rreq -{ - uint8_t type; - uint16_t req_flags; - uint8_t hop_count; - uint32_t rreq_id; - uint32_t dest; - uint32_t dseq; - uint32_t orig; - uint32_t oseq; -}; - -#define AODV_RREQ_FLAG_J 0x8000 -#define AODV_RREQ_FLAG_R 0x4000 -#define AODV_RREQ_FLAG_G 0x2000 -#define AODV_RREQ_FLAG_D 0x1000 -#define AODV_RREQ_FLAG_U 0x0800 -#define AODV_RREQ_FLAG_RESERVED 0x07FF - -PACKED_STRUCT_DEF pico_aodv_rrep -{ - uint8_t type; - uint8_t rep_flags; - uint8_t prefix_sz; - uint8_t hop_count; - uint32_t dest; - uint32_t dseq; - uint32_t orig; - uint32_t lifetime; -}; - -#define AODV_RREP_MAX_PREFIX 0x1F -#define AODV_RREP_FLAG_R 0x80 -#define AODV_RREP_FLAG_A 0x40 -#define AODV_RREP_FLAG_RESERVED 0x3F - -#define PICO_AODV_NODE_NEW 0x0000 -#define PICO_AODV_NODE_SYNC 0x0001 -#define PICO_AODV_NODE_REQUESTING 0x0002 -#define PICO_AODV_NODE_ROUTE_UP 0x0004 -#define PICO_AODV_NODE_ROUTE_DOWN 0x0008 -#define PICO_AODV_NODE_IDLING 0x0010 -#define PICO_AODV_NODE_UNREACH 0x0020 - -#define PICO_AODV_ACTIVE(node) ((node->flags & PICO_AODV_NODE_ROUTE_UP) && (node->flags & PICO_AODV_NODE_ROUTE_DOWN)) - - -struct pico_aodv_node -{ - union pico_address dest; - pico_time last_seen; - pico_time fwd_time; - uint32_t dseq; - uint16_t flags; - uint8_t metric; - uint8_t ring_ttl; - uint8_t rreq_retry; -}; - -PACKED_STRUCT_DEF pico_aodv_unreachable -{ - uint32_t addr; - uint32_t dseq; -}; - -PACKED_STRUCT_DEF pico_aodv_rerr -{ - uint8_t type; - uint16_t rerr_flags; - uint8_t dst_count; - uint32_t unreach_addr; - uint32_t unreach_dseq; - struct pico_aodv_unreachable unreach[1]; /* unrechable nodes: must be at least 1. See dst_count field above */ -}; - -PACKED_STRUCT_DEF pico_aodv_rack -{ - uint8_t type; - uint8_t reserved; -}; - -int pico_aodv_init(void); -int pico_aodv_add(struct pico_device *dev); -int pico_aodv_lookup(const union pico_address *addr); -void pico_aodv_refresh(const union pico_address *addr); -#endif diff --git a/modules/pico_arp.c b/modules/pico_arp.c index de8b61155..32808729b 100644 --- a/modules/pico_arp.c +++ b/modules/pico_arp.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -398,11 +398,12 @@ static int pico_arp_check_flooding(struct pico_frame *f, struct pico_ip4 me) static int pico_arp_process_in(struct pico_frame *f, struct pico_arp_hdr *hdr, struct pico_arp *found) { struct pico_ip4 me; + if (pico_arp_check_incoming_hdr(f, &me) < 0) { pico_frame_discard(f); return -1; } - + if (pico_arp_check_flooding(f, me) < 0) { pico_frame_discard(f); return -1; @@ -416,7 +417,7 @@ static int pico_arp_process_in(struct pico_frame *f, struct pico_arp_hdr *hdr, s /* If the packet is a request, send a reply */ pico_arp_reply_on_request(f, me); - + #ifdef DEBUG_ARP dbg_arp(); #endif diff --git a/modules/pico_arp.h b/modules/pico_arp.h index 18e1f6967..dcf6cf269 100644 --- a/modules/pico_arp.h +++ b/modules/pico_arp.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/modules/pico_dev_loop.c b/modules/pico_dev_loop.c index 4416d0bb1..34a53a267 100644 --- a/modules/pico_dev_loop.c +++ b/modules/pico_dev_loop.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Daniele Lacamera diff --git a/modules/pico_dev_loop.h b/modules/pico_dev_loop.h index 6cb8de1fb..2e3019938 100644 --- a/modules/pico_dev_loop.h +++ b/modules/pico_dev_loop.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/modules/pico_dev_mock.c b/modules/pico_dev_mock.c index 59fae0174..c0301ab70 100644 --- a/modules/pico_dev_mock.c +++ b/modules/pico_dev_mock.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Frederik Van Slycken diff --git a/modules/pico_dev_mock.h b/modules/pico_dev_mock.h index dfc2cfcb5..e53d3a95f 100644 --- a/modules/pico_dev_mock.h +++ b/modules/pico_dev_mock.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/modules/pico_dev_null.c b/modules/pico_dev_null.c index 5fed494e6..47d68b03d 100644 --- a/modules/pico_dev_null.c +++ b/modules/pico_dev_null.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Daniele Lacamera diff --git a/modules/pico_dev_null.h b/modules/pico_dev_null.h index a0eb98e2f..5bab257e7 100644 --- a/modules/pico_dev_null.h +++ b/modules/pico_dev_null.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/modules/pico_dev_pcap.c b/modules/pico_dev_pcap.c index f62fb146c..d7f82ad3e 100644 --- a/modules/pico_dev_pcap.c +++ b/modules/pico_dev_pcap.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Daniele Lacamera diff --git a/modules/pico_dev_pcap.h b/modules/pico_dev_pcap.h index 887be2786..febc6e45a 100644 --- a/modules/pico_dev_pcap.h +++ b/modules/pico_dev_pcap.h @@ -1,9 +1,9 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. - Author: Daniele Lacamera + Author: Daniele Lacamera *********************************************************************/ #ifndef INCLUDE_PICO_PCAP #define INCLUDE_PICO_PCAP diff --git a/modules/pico_dev_tap.c b/modules/pico_dev_tap.c index b1425c219..224b378c1 100644 --- a/modules/pico_dev_tap.c +++ b/modules/pico_dev_tap.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Daniele Lacamera @@ -86,21 +86,18 @@ static int tap_get_mac(char *name, uint8_t *mac) int retval = -1; sck = socket(AF_INET, SOCK_DGRAM, 0); - if(sck < 0) { + if(sck < 0){ return retval; } - memset(ð, 0, sizeof(struct ifreq)); - strcpy(eth.ifr_name, name); + strcpy(eth.ifr_name,name); /* call the IOCTL */ if (ioctl(sck, SIOCGIFHWADDR, ð) < 0) { perror("ioctl(SIOCGIFHWADDR)"); - return -1; - ; + return -1;; } - memcpy (mac, ð.ifr_hwaddr.sa_data, 6); close(sck); @@ -125,12 +122,12 @@ struct pico_device *pico_tap_create(char *name) return NULL; } - if (tap_get_mac(name, mac) < 0) { + if (tap_get_mac(name, mac) < 0) { dbg("Tap mac query failed.\n"); pico_tap_destroy((struct pico_device *)tap); return NULL; } - + mac[5]++; if( 0 != pico_device_init((struct pico_device *)tap, name, mac)) { diff --git a/modules/pico_dev_tap.h b/modules/pico_dev_tap.h index ebc21fe0f..d1a379978 100644 --- a/modules/pico_dev_tap.h +++ b/modules/pico_dev_tap.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/modules/pico_dev_tap_windows.c b/modules/pico_dev_tap_windows.c old mode 100644 new mode 100755 index 2e003f887..ac80ffa75 --- a/modules/pico_dev_tap_windows.c +++ b/modules/pico_dev_tap_windows.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Maxime Vincent @@ -8,11 +8,11 @@ NOTES: This is the Windows-only driver, a Linux-equivalent is available, too You need to have an OpenVPN TUN/TAP network adapter installed, first This driver is barely working: - * Only TAP-mode is supported (TUN is not) - * it will simply open the first TAP device it can find - * there is memory being allocated that's never freed - * there is no destroy function, yet - * it has only been tested on a Windows 7 machine + * Only TAP-mode is supported (TUN is not) + * it will simply open the first TAP device it can find + * there is memory being allocated that's never freed + * there is no destroy function, yet + * it has only been tested on a Windows 7 machine *********************************************************************/ #include "pico_device.h" @@ -22,16 +22,16 @@ #include #include -#include +#include #include "pico_dev_tap_windows_private.h" /* * Debugging info */ -#define dbg_tap_info(...) /* tap info messages */ -#define dbg_tap(...) /* first level debug */ -#define dbg_win32(...) /* second level detailed win32 debug */ -#define dbg_reg(...) /* third level: registry debug */ +#define dbg_tap_info(...) // tap info messages +#define dbg_tap(...) // first level debug +#define dbg_win32(...) // second level detailed win32 debug +#define dbg_reg(...) // third level: registry debug /* * Tunnel types @@ -42,7 +42,7 @@ #define DEV_TYPE_TAP 3 /* ethernet (802.3) tunnel */ -/* +/* * We try to do all Win32 I/O using overlapped * (i.e. asynchronous) I/O for a performance win. */ @@ -50,38 +50,38 @@ struct overlapped_io { # define IOSTATE_INITIAL 0 # define IOSTATE_QUEUED 1 /* overlapped I/O has been queued */ # define IOSTATE_IMMEDIATE_RETURN 2 /* I/O function returned immediately without queueing */ - int iostate; - OVERLAPPED overlapped; - DWORD size; - DWORD flags; - int status; - int addr_defined; - uint8_t *buf_init; - uint32_t buf_init_len; - uint8_t *buf; - uint32_t buf_len; + int iostate; + OVERLAPPED overlapped; + DWORD size; + DWORD flags; + int status; + int addr_defined; + uint8_t * buf_init; + uint32_t buf_init_len; + uint8_t * buf; + uint32_t buf_len; }; struct rw_handle { - HANDLE read; - HANDLE write; + HANDLE read; + HANDLE write; }; struct tuntap { - int type; /* DEV_TYPE_x as defined in proto.h */ - int ipv6; - int persistent_if; /* if existed before, keep on program end */ - char *actual_name; /* actual name of TUN/TAP dev, usually including unit number */ - int post_open_mtu; - uint8_t mac[6]; - - /* Windows stuff */ - DWORD adapter_index; /*adapter index for TAP-Windows adapter, ~0 if undefined */ - HANDLE hand; - struct overlapped_io reads; /* for overlapped IO */ - struct overlapped_io writes; - struct rw_handle rw_handle; + int type; /* DEV_TYPE_x as defined in proto.h */ + int ipv6; + int persistent_if; /* if existed before, keep on program end */ + char *actual_name; /* actual name of TUN/TAP dev, usually including unit number */ + int post_open_mtu; + uint8_t mac[6]; + + /* Windows stuff */ + DWORD adapter_index; /*adapter index for TAP-Windows adapter, ~0 if undefined */ + HANDLE hand; + struct overlapped_io reads; /* for overlapped IO */ + struct overlapped_io writes; + struct rw_handle rw_handle; }; @@ -89,15 +89,15 @@ struct tuntap struct pico_device_tap { struct pico_device dev; int statistics_frames_out; - struct tuntap *tt; + struct tuntap * tt; }; /* * Private function prototypes */ -const struct tap_reg *get_tap_reg (void); -const struct panel_reg *get_panel_reg (void); +const struct tap_reg * get_tap_reg (void); +const struct panel_reg * get_panel_reg (void); /* @@ -105,347 +105,338 @@ const struct panel_reg *get_panel_reg (void); */ /* Get TAP info from Windows registry */ -const struct tap_reg *get_tap_reg (void) +const struct tap_reg * get_tap_reg (void) { - HKEY adapter_key; - LONG status; - DWORD len; - struct tap_reg *first = NULL; - struct tap_reg *last = NULL; - int i = 0; + HKEY adapter_key; + LONG status; + DWORD len; + struct tap_reg *first = NULL; + struct tap_reg *last = NULL; + int i = 0; + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + ADAPTER_KEY, + 0, + KEY_READ, + &adapter_key); + + if (status != ERROR_SUCCESS) + { + dbg_reg("Error opening registry key: %s\n", ADAPTER_KEY); + return NULL; + } + + while (1) + { + char enum_name[256]; + char unit_string[256]; + HKEY unit_key; + char component_id_string[] = "ComponentId"; + char component_id[256]; + char net_cfg_instance_id_string[] = "NetCfgInstanceId"; + char net_cfg_instance_id[256]; + DWORD data_type; + + len = sizeof (enum_name); + status = RegEnumKeyEx( + adapter_key, + i, + enum_name, + &len, + NULL, + NULL, + NULL, + NULL); + if (status == ERROR_NO_MORE_ITEMS) + break; + else if (status != ERROR_SUCCESS) + dbg_reg("Error enumerating registry subkeys of key: %s.\n", ADAPTER_KEY); + + snprintf (unit_string, sizeof(unit_string), "%s\\%s", + ADAPTER_KEY, enum_name); status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, - ADAPTER_KEY, + unit_string, 0, KEY_READ, - &adapter_key); + &unit_key); if (status != ERROR_SUCCESS) { - dbg_reg("Error opening registry key: %s\n", ADAPTER_KEY); - return NULL; + dbg_reg("Error opening registry key: %s\n", unit_string); } - - while (1) + else { - char enum_name[256]; - char unit_string[256]; - HKEY unit_key; - char component_id_string[] = "ComponentId"; - char component_id[256]; - char net_cfg_instance_id_string[] = "NetCfgInstanceId"; - char net_cfg_instance_id[256]; - DWORD data_type; - - len = sizeof (enum_name); - status = RegEnumKeyEx( - adapter_key, - i, - enum_name, - &len, - NULL, + len = sizeof (component_id); + status = RegQueryValueEx( + unit_key, + component_id_string, + NULL, + &data_type, + (LPBYTE)component_id, + &len); + + if (status != ERROR_SUCCESS || data_type != REG_SZ) + { + dbg_reg("Error opening registry key: %s\\%s\n", unit_string, component_id_string); + } + else + { + len = sizeof (net_cfg_instance_id); + status = RegQueryValueEx( + unit_key, + net_cfg_instance_id_string, NULL, - NULL, - NULL); - if (status == ERROR_NO_MORE_ITEMS) - break; - else if (status != ERROR_SUCCESS) - dbg_reg("Error enumerating registry subkeys of key: %s.\n", ADAPTER_KEY); + &data_type, + (LPBYTE)net_cfg_instance_id, + &len); - snprintf (unit_string, sizeof(unit_string), "%s\\%s", - ADAPTER_KEY, enum_name); - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - unit_string, - 0, - KEY_READ, - &unit_key); - - if (status != ERROR_SUCCESS) - { - dbg_reg("Error opening registry key: %s\n", unit_string); - } - else + if (status == ERROR_SUCCESS && data_type == REG_SZ) { - len = sizeof (component_id); - status = RegQueryValueEx( - unit_key, - component_id_string, - NULL, - &data_type, - (LPBYTE)component_id, - &len); - - if (status != ERROR_SUCCESS || data_type != REG_SZ) + if (!strcmp (component_id, TAP_WIN_COMPONENT_ID)) + { + struct tap_reg *reg; + reg = PICO_ZALLOC(sizeof(struct tap_reg), 1); + //ALLOC_OBJ_CLEAR_GC (reg, struct tap_reg, gc); + if (!reg) + return NULL; + //reg->guid = string_alloc (net_cfg_instance_id, gc); + reg->guid = PICO_ZALLOC (strlen(net_cfg_instance_id)+1, 1); + if (!(reg->guid)) { - dbg_reg("Error opening registry key: %s\\%s\n", unit_string, component_id_string); + PICO_FREE(reg); + return NULL; } - else - { - len = sizeof (net_cfg_instance_id); - status = RegQueryValueEx( - unit_key, - net_cfg_instance_id_string, - NULL, - &data_type, - (LPBYTE)net_cfg_instance_id, - &len); - - if (status == ERROR_SUCCESS && data_type == REG_SZ) - { - if (!strcmp (component_id, TAP_WIN_COMPONENT_ID)) - { - struct tap_reg *reg; - reg = PICO_ZALLOC(sizeof(struct tap_reg), 1); - /* ALLOC_OBJ_CLEAR_GC (reg, struct tap_reg, gc); */ - if (!reg) - return NULL; - - /* reg->guid = string_alloc (net_cfg_instance_id, gc); */ - reg->guid = PICO_ZALLOC (strlen(net_cfg_instance_id) + 1, 1); - if (!(reg->guid)) - { - PICO_FREE(reg); - return NULL; - } - - strcpy((char *)reg->guid, net_cfg_instance_id); - /* link into return list */ - if (!first) - first = reg; - - if (last) - last->next = reg; - - last = reg; - } - } - } - - RegCloseKey (unit_key); + strcpy((char *)reg->guid, net_cfg_instance_id); + /* link into return list */ + if (!first) + first = reg; + if (last) + last->next = reg; + last = reg; + } } - - ++i; + } + RegCloseKey (unit_key); } - RegCloseKey (adapter_key); - return first; + ++i; + } + + RegCloseKey (adapter_key); + return first; } /* Get Panel info from Windows registry */ -const struct panel_reg *get_panel_reg (void) +const struct panel_reg * get_panel_reg (void) { - LONG status; - HKEY network_connections_key; - DWORD len; - struct panel_reg *first = NULL; - struct panel_reg *last = NULL; - int i = 0; + LONG status; + HKEY network_connections_key; + DWORD len; + struct panel_reg *first = NULL; + struct panel_reg *last = NULL; + int i = 0; + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + NETWORK_CONNECTIONS_KEY, + 0, + KEY_READ, + &network_connections_key); + + if (status != ERROR_SUCCESS) + { + dbg_reg("Error opening registry key: %s\n", NETWORK_CONNECTIONS_KEY); + return NULL; + } + + while (1) + { + char enum_name[256]; + char connection_string[256]; + HKEY connection_key; + WCHAR name_data[256]; + DWORD name_type; + const WCHAR name_string[] = L"Name"; + + len = sizeof (enum_name); + status = RegEnumKeyEx( + network_connections_key, + i, + enum_name, + &len, + NULL, + NULL, + NULL, + NULL); + if (status == ERROR_NO_MORE_ITEMS) + break; + else if (status != ERROR_SUCCESS) + dbg_reg("Error enumerating registry subkeys of key: %s.\n", NETWORK_CONNECTIONS_KEY); + + snprintf (connection_string, sizeof(connection_string), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, enum_name); status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, - NETWORK_CONNECTIONS_KEY, + connection_string, 0, KEY_READ, - &network_connections_key); - + &connection_key); if (status != ERROR_SUCCESS) + dbg_reg("Error opening registry key: %s\n", connection_string); + else { - dbg_reg("Error opening registry key: %s\n", NETWORK_CONNECTIONS_KEY); - return NULL; - } - - while (1) - { - char enum_name[256]; - char connection_string[256]; - HKEY connection_key; - WCHAR name_data[256]; - DWORD name_type; - const WCHAR name_string[] = L"Name"; - - len = sizeof (enum_name); - status = RegEnumKeyEx( - network_connections_key, - i, - enum_name, - &len, - NULL, - NULL, - NULL, - NULL); - if (status == ERROR_NO_MORE_ITEMS) - break; - else if (status != ERROR_SUCCESS) - dbg_reg("Error enumerating registry subkeys of key: %s.\n", NETWORK_CONNECTIONS_KEY); - - snprintf (connection_string, sizeof(connection_string), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, enum_name); - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - connection_string, - 0, - KEY_READ, - &connection_key); - if (status != ERROR_SUCCESS) - dbg_reg("Error opening registry key: %s\n", connection_string); - else + len = sizeof (name_data); + status = RegQueryValueExW( + connection_key, + name_string, + NULL, + &name_type, + (LPBYTE) name_data, + &len); + + if (status != ERROR_SUCCESS || name_type != REG_SZ) + dbg_reg("Error opening registry key: %s\\%s\\%S\n", NETWORK_CONNECTIONS_KEY, connection_string, name_string); + else + { + int n; + LPSTR name; + struct panel_reg *reg; + + //ALLOC_OBJ_CLEAR_GC (reg, struct panel_reg, gc); + reg = PICO_ZALLOC(sizeof(struct panel_reg), 1); + if (!reg) + return NULL; + n = WideCharToMultiByte (CP_UTF8, 0, name_data, -1, NULL, 0, NULL, NULL); + //name = gc_malloc (n, false, gc); + name = PICO_ZALLOC(n, 1); + if (!name) { - len = sizeof (name_data); - status = RegQueryValueExW( - connection_key, - name_string, - NULL, - &name_type, - (LPBYTE) name_data, - &len); - - if (status != ERROR_SUCCESS || name_type != REG_SZ) - dbg_reg("Error opening registry key: %s\\%s\\%S\n", NETWORK_CONNECTIONS_KEY, connection_string, name_string); - else - { - int n; - LPSTR name; - struct panel_reg *reg; - - /* ALLOC_OBJ_CLEAR_GC (reg, struct panel_reg, gc); */ - reg = PICO_ZALLOC(sizeof(struct panel_reg), 1); - if (!reg) - return NULL; - - n = WideCharToMultiByte (CP_UTF8, 0, name_data, -1, NULL, 0, NULL, NULL); - /* name = gc_malloc (n, false, gc); */ - name = PICO_ZALLOC(n, 1); - if (!name) - { - PICO_FREE(reg); - return NULL; - } - - WideCharToMultiByte (CP_UTF8, 0, name_data, -1, name, n, NULL, NULL); - reg->name = name; - /* reg->guid = string_alloc (enum_name, gc); */ - reg->guid = PICO_ZALLOC(strlen(enum_name) + 1, 1); - if (!reg->guid) - { - PICO_FREE((void *)reg->name); - PICO_FREE((void *)reg); - return NULL; - } - - strcpy((char *)reg->guid, enum_name); - - /* link into return list */ - if (!first) - first = reg; - - if (last) - last->next = reg; - - last = reg; - } - - RegCloseKey (connection_key); + PICO_FREE(reg); + return NULL; } - - ++i; + WideCharToMultiByte (CP_UTF8, 0, name_data, -1, name, n, NULL, NULL); + reg->name = name; + //reg->guid = string_alloc (enum_name, gc); + reg->guid = PICO_ZALLOC(strlen(enum_name)+1, 1); + if (!reg->guid) + { + PICO_FREE((void *)reg->name); + PICO_FREE((void *)reg); + return NULL; + } + strcpy((char *)reg->guid, enum_name); + + /* link into return list */ + if (!first) + first = reg; + if (last) + last->next = reg; + last = reg; + } + RegCloseKey (connection_key); } - RegCloseKey (network_connections_key); + ++i; + } + + RegCloseKey (network_connections_key); - return first; + return first; } void show_tap_win_adapters (void) { - int warn_panel_null = 0; - int warn_panel_dup = 0; - int warn_tap_dup = 0; + int warn_panel_null = 0; + int warn_panel_dup = 0; + int warn_tap_dup = 0; - int links; + int links; - const struct tap_reg *tr; - const struct tap_reg *tr1; - const struct panel_reg *pr; + const struct tap_reg *tr; + const struct tap_reg *tr1; + const struct panel_reg *pr; - const struct tap_reg *tap_reg = get_tap_reg (); - const struct panel_reg *panel_reg = get_panel_reg (); + const struct tap_reg *tap_reg = get_tap_reg (); + const struct panel_reg *panel_reg = get_panel_reg (); - if (!(tap_reg && panel_reg)) - return; + if (!(tap_reg && panel_reg)) + return; - dbg_tap_info("Available TAP-WIN32 adapters [name, GUID]:\n"); + dbg_tap_info("Available TAP-WIN32 adapters [name, GUID]:\n"); - /* loop through each TAP-Windows adapter registry entry */ - for (tr = tap_reg; tr != NULL; tr = tr->next) + /* loop through each TAP-Windows adapter registry entry */ + for (tr = tap_reg; tr != NULL; tr = tr->next) + { + links = 0; + + /* loop through each network connections entry in the control panel */ + for (pr = panel_reg; pr != NULL; pr = pr->next) { - links = 0; + if (!strcmp (tr->guid, pr->guid)) + { + dbg_tap_info("\t>> '%s' %s\n", pr->name, tr->guid); + ++links; + } + } - /* loop through each network connections entry in the control panel */ - for (pr = panel_reg; pr != NULL; pr = pr->next) - { - if (!strcmp (tr->guid, pr->guid)) - { - dbg_tap_info("\t>> '%s' %s\n", pr->name, tr->guid); - ++links; - } - } - if (links > 1) - { - warn_panel_dup = 1; - } - else if (links == 0) - { - /* a TAP adapter exists without a link from the network - connections control panel */ - warn_panel_null = 1; - dbg_tap_info("\t>> [NULL] %s\n", tr->guid); - } + if (links > 1) + { + warn_panel_dup = 1; } - /* check for TAP-Windows adapter duplicated GUIDs */ - for (tr = tap_reg; tr != NULL; tr = tr->next) + else if (links == 0) { - for (tr1 = tap_reg; tr1 != NULL; tr1 = tr1->next) - { - if (tr != tr1 && !strcmp (tr->guid, tr1->guid)) - warn_tap_dup = 1; - } + /* a TAP adapter exists without a link from the network + connections control panel */ + warn_panel_null = 1; + dbg_tap_info("\t>> [NULL] %s\n", tr->guid); + } + } + + /* check for TAP-Windows adapter duplicated GUIDs */ + for (tr = tap_reg; tr != NULL; tr = tr->next) + { + for (tr1 = tap_reg; tr1 != NULL; tr1 = tr1->next) + { + if (tr != tr1 && !strcmp (tr->guid, tr1->guid)) + warn_tap_dup = 1; } - /* warn on registry inconsistencies */ - if (warn_tap_dup) - dbg_tap_info("WARNING: Some TAP-Windows adapters have duplicate GUIDs\n"); + } + + /* warn on registry inconsistencies */ + if (warn_tap_dup) + dbg_tap_info("WARNING: Some TAP-Windows adapters have duplicate GUIDs\n"); - if (warn_panel_dup) - dbg_tap_info("WARNING: Some TAP-Windows adapters have duplicate links from the Network Connections control panel\n"); + if (warn_panel_dup) + dbg_tap_info("WARNING: Some TAP-Windows adapters have duplicate links from the Network Connections control panel\n"); - if (warn_panel_null) - dbg_tap_info("WARNING: Some TAP-Windows adapters have no link from the Network Connections control panel\n"); + if (warn_panel_null) + dbg_tap_info("WARNING: Some TAP-Windows adapters have no link from the Network Connections control panel\n"); } /* Get the GUID of the first TAP device found */ -const char *get_first_device_guid(const struct tap_reg *tap_reg, const struct panel_reg *panel_reg, char *name) +const char * get_first_device_guid(const struct tap_reg *tap_reg, const struct panel_reg *panel_reg, char * name) { - const struct tap_reg *tr; - const struct panel_reg *pr; - /* loop through each TAP-Windows adapter registry entry */ - for (tr = tap_reg; tr != NULL; tr = tr->next) + const struct tap_reg *tr; + const struct panel_reg *pr; + /* loop through each TAP-Windows adapter registry entry */ + for (tr = tap_reg; tr != NULL; tr = tr->next) + { + /* loop through each network connections entry in the control panel */ + for (pr = panel_reg; pr != NULL; pr = pr->next) { - /* loop through each network connections entry in the control panel */ - for (pr = panel_reg; pr != NULL; pr = pr->next) - { - if (!strcmp (tr->guid, pr->guid)) - { - dbg_tap_info("Using first TAP device: '%s' %s\n", pr->name, tr->guid); - if (name) - strcpy(name, pr->name); - - return tr->guid; - } - } + if (!strcmp (tr->guid, pr->guid)) + { + dbg_tap_info("Using first TAP device: '%s' %s\n", pr->name, tr->guid); + if (name) + strcpy(name, pr->name); + return tr->guid; + } } - return NULL; + } + return NULL; } @@ -486,45 +477,45 @@ int open_tun (const char *dev, const char *dev_type, const char *dev_node, struc /* Open Windows TAP-Windows adapter */ snprintf (device_path, sizeof(device_path), "%s%s%s", - USERMODEDEVICEDIR, - device_guid, - TAP_WIN_SUFFIX); + USERMODEDEVICEDIR, + device_guid, + TAP_WIN_SUFFIX); tt->hand = CreateFile ( - device_path, - GENERIC_READ | GENERIC_WRITE, - 0, /* was: FILE_SHARE_READ */ - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, - 0 - ); + device_path, + GENERIC_READ | GENERIC_WRITE, + 0, /* was: FILE_SHARE_READ */ + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, + 0 + ); if (tt->hand == INVALID_HANDLE_VALUE) dbg_tap_info("CreateFile failed on TAP device: %s\n", device_path); /* translate high-level device name into a device instance GUID using the registry */ - tt->actual_name = PICO_ZALLOC(strlen(name) + 1); + tt->actual_name = PICO_ZALLOC(strlen(name)+1); if (tt->actual_name) strcpy(tt->actual_name, name); } dbg_tap_info("TAP-WIN32 device [%s] opened: %s\n", tt->actual_name, device_path); - /* TODO TODO TODO */ - /* tt->adapter_index = get_adapter_index (device_guid); */ + // TODO TODO TODO + //tt->adapter_index = get_adapter_index (device_guid); /* get driver version info */ { ULONG info[3]; - /* TODO TODO TODO */ - /* CLEAR (info); */ + // TODO TODO TODO + //CLEAR (info); if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_VERSION, &info, sizeof (info), &info, sizeof (info), &len, NULL)) { dbg_tap_info ("TAP-Windows Driver Version %d.%d %s\n", - (int) info[0], - (int) info[1], - (info[2] ? "(DEBUG)" : "")); + (int) info[0], + (int) info[1], + (info[2] ? "(DEBUG)" : "")); } @@ -532,8 +523,8 @@ int open_tun (const char *dev, const char *dev_type, const char *dev_node, struc dbg_tap_info ("ERROR: This version of " PACKAGE_NAME " requires a TAP-Windows driver that is at least version %d.%d \ -- If you recently upgraded your " PACKAGE_NAME " distribution, \ a reboot is probably required at this point to get Windows to see the new driver.\n", - TAP_WIN_MIN_MAJOR, - TAP_WIN_MIN_MINOR); + TAP_WIN_MIN_MAJOR, + TAP_WIN_MIN_MINOR); /* usage of numeric constants is ugly, but this is really tied to * *this* version of the driver @@ -546,7 +537,7 @@ int open_tun (const char *dev, const char *dev_type, const char *dev_node, struc } /* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy - */ + */ if ( tt->type == DEV_TYPE_TUN && info[0] == 9 && info[1] == 8) { dbg_tap_info("ERROR: Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode. Upgrade to Tap-Win32 9.9 (2.2.2 release or later) or use TAP mode\n", (int) info[0], (int) info[1] ); @@ -557,8 +548,8 @@ int open_tun (const char *dev, const char *dev_type, const char *dev_node, struc { ULONG mtu; if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_MTU, - &mtu, sizeof (mtu), - &mtu, sizeof (mtu), &len, NULL)) + &mtu, sizeof (mtu), + &mtu, sizeof (mtu), &len, NULL)) { tt->post_open_mtu = (int) mtu; dbg_tap_info("TAP-Windows MTU=%d\n", (int) mtu); @@ -568,15 +559,13 @@ int open_tun (const char *dev, const char *dev_type, const char *dev_node, struc /* get driver MAC */ { - uint8_t mac[6] = { - 0, 0, 0, 0, 0, 0 - }; + uint8_t mac[6] = {0,0,0,0,0,0}; if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_MAC, - mac, sizeof (mac), - mac, sizeof (mac), &len, NULL)) + mac, sizeof (mac), + mac, sizeof (mac), &len, NULL)) { dbg_tap_info("TAP-Windows MAC=[%x,%x,%x,%x,%x,%x]\n", mac[0], mac[1], mac[2], - mac[2], mac[4], mac[5]); + mac[2], mac[4], mac[5]); memcpy(tt->mac, mac, sizeof(mac)); } } @@ -597,8 +586,8 @@ int open_tun (const char *dev, const char *dev_type, const char *dev_node, struc { ULONG status = TRUE; if (!DeviceIoControl (tt->hand, TAP_WIN_IOCTL_SET_MEDIA_STATUS, - &status, sizeof (status), - &status, sizeof (status), &len, NULL)) + &status, sizeof (status), + &status, sizeof (status), &len, NULL)) dbg_tap_info("WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call."); } @@ -610,39 +599,38 @@ int open_tun (const char *dev, const char *dev_type, const char *dev_node, struc /* TODO: Closing a TUN device is currently not implemented */ /* - void close_tun (struct tuntap *tt) - { +void close_tun (struct tuntap *tt) +{ (void)tt; - } - */ +} +*/ -int tap_win_getinfo (const struct tuntap *tt, char *buf, int bufsize) +int tap_win_getinfo (const struct tuntap *tt, char * buf, int bufsize) { if (tt && tt->hand != NULL && buf != NULL) { DWORD len; if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_INFO, - buf, bufsize, - buf, bufsize, - &len, NULL)) + buf, bufsize, + buf, bufsize, + &len, NULL)) { return 0; } } - return -1; } -void tun_show_debug (struct tuntap *tt, char *buf, int bufsize) +void tun_show_debug (struct tuntap *tt, char * buf, int bufsize) { if (tt && tt->hand != NULL && buf != NULL) { DWORD len; while (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_LOG_LINE, - buf, bufsize, - buf, bufsize, - &len, NULL)) + buf, bufsize, + buf, bufsize, + &len, NULL)) { dbg_tap_info("TAP-Windows: %s\n", buf); } @@ -651,7 +639,7 @@ void tun_show_debug (struct tuntap *tt, char *buf, int bufsize) /* returns the state */ -int tun_read_queue (struct tuntap *tt, uint8_t *buffer, int maxsize) +int tun_read_queue (struct tuntap *tt, uint8_t * buffer, int maxsize) { if (tt->reads.iostate == IOSTATE_INITIAL) { @@ -664,25 +652,25 @@ int tun_read_queue (struct tuntap *tt, uint8_t *buffer, int maxsize) tt->reads.buf_len = tt->reads.buf_init_len; len = maxsize ? maxsize : (tt->reads.buf_len); - if (len > (tt->reads.buf_len)) /* clip to buffer len */ + if (len > (tt->reads.buf_len)) // clip to buffer len len = tt->reads.buf_len; /* the overlapped read will signal this event on I/O completion */ - if (!ResetEvent (tt->reads.overlapped.hEvent)) + if (! ResetEvent (tt->reads.overlapped.hEvent)) dbg_tap("ResetEvent failed\n"); status = ReadFile( - tt->hand, - buffer, - len, - &tt->reads.size, - &tt->reads.overlapped - ); + tt->hand, + buffer, + len, + &tt->reads.size, + &tt->reads.overlapped + ); if (status) /* operation completed immediately? */ { /* since we got an immediate return, we must signal the event object ourselves */ - /* ASSERT (SetEvent (tt->reads.overlapped.hEvent)); */ + //ASSERT (SetEvent (tt->reads.overlapped.hEvent)); if (!SetEvent (tt->reads.overlapped.hEvent)) dbg_tap("SetEvent failed\n"); @@ -690,12 +678,12 @@ int tun_read_queue (struct tuntap *tt, uint8_t *buffer, int maxsize) tt->reads.status = 0; dbg_win32 ("WIN32 I/O: TAP Read immediate return [%d,%d]\n", - (int) len, - (int) tt->reads.size); + (int) len, + (int) tt->reads.size); } else { - err = GetLastError (); + err = GetLastError (); if (err == ERROR_IO_PENDING) /* operation queued? */ { tt->reads.iostate = IOSTATE_QUEUED; @@ -706,106 +694,96 @@ int tun_read_queue (struct tuntap *tt, uint8_t *buffer, int maxsize) { if (!SetEvent (tt->reads.overlapped.hEvent)) dbg_tap("SetEvent failed\n"); - tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN; tt->reads.status = err; dbg_tap ("WIN32 I/O: TAP Read error [%d] : %d\n", (int) len, (int) err); } } } - return tt->reads.iostate; } /* Finalize any pending overlapped IO's */ -int tun_finalize(HANDLE h, struct overlapped_io *io, uint8_t **buf, uint32_t *buf_len) +int tun_finalize(HANDLE h, struct overlapped_io *io, uint8_t ** buf, uint32_t * buf_len) { int ret = -1; BOOL status; switch (io->iostate) { - case IOSTATE_QUEUED: - status = GetOverlappedResult( - h, - &io->overlapped, - &io->size, - 0u - ); - if (status) - { - /* successful return for a queued operation */ - if (buf) + case IOSTATE_QUEUED: + status = GetOverlappedResult( + h, + &io->overlapped, + &io->size, + 0u + ); + if (status) + { + /* successful return for a queued operation */ + if (buf) + { + *buf = io->buf; + *buf_len = io->buf_len; + } + ret = io->size; + io->iostate = IOSTATE_INITIAL; + + if (!ResetEvent (io->overlapped.hEvent)) + dbg_tap("ResetEvent in finalize failed!\n"); + dbg_win32 ("WIN32 I/O: TAP Completion success: QUEUED! [%d]\n", ret); + } + else { - *buf = io->buf; - *buf_len = io->buf_len; + /* error during a queued operation */ + // error, or just not completed? + ret = 0; + if (GetLastError() != ERROR_IO_INCOMPLETE) + { + /* if no error (i.e. just not finished yet), + then DON'T execute this code */ + io->iostate = IOSTATE_INITIAL; + if (!ResetEvent (io->overlapped.hEvent)) + dbg_tap("ResetEvent in finalize failed!\n"); + dbg_tap("WIN32 I/O: TAP Completion error\n"); + ret = -1; // There actually was an error + } } + break; - ret = io->size; + case IOSTATE_IMMEDIATE_RETURN: io->iostate = IOSTATE_INITIAL; - if (!ResetEvent (io->overlapped.hEvent)) dbg_tap("ResetEvent in finalize failed!\n"); - - dbg_win32 ("WIN32 I/O: TAP Completion success: QUEUED! [%d]\n", ret); - } - else - { - /* error during a queued operation */ - /* error, or just not completed? */ - ret = 0; - if (GetLastError() != ERROR_IO_INCOMPLETE) + if (io->status) { - /* if no error (i.e. just not finished yet), - then DON'T execute this code */ - io->iostate = IOSTATE_INITIAL; - if (!ResetEvent (io->overlapped.hEvent)) - dbg_tap("ResetEvent in finalize failed!\n"); - - dbg_tap("WIN32 I/O: TAP Completion error\n"); - ret = -1; /* There actually was an error */ + /* error return for a non-queued operation */ + SetLastError (io->status); + ret = -1; + dbg_tap("WIN32 I/O: TAP Completion non-queued error\n"); } - } - - break; - - case IOSTATE_IMMEDIATE_RETURN: - io->iostate = IOSTATE_INITIAL; - if (!ResetEvent (io->overlapped.hEvent)) - dbg_tap("ResetEvent in finalize failed!\n"); + else + { + /* successful return for a non-queued operation */ + if (buf) + *buf = io->buf; + ret = io->size; + dbg_win32 ("WIN32 I/O: TAP Completion non-queued success [%d]\n", ret); + } + break; - if (io->status) - { - /* error return for a non-queued operation */ - SetLastError (io->status); + case IOSTATE_INITIAL: /* were we called without proper queueing? */ + SetLastError (ERROR_INVALID_FUNCTION); ret = -1; - dbg_tap("WIN32 I/O: TAP Completion non-queued error\n"); - } - else - { - /* successful return for a non-queued operation */ - if (buf) - *buf = io->buf; - - ret = io->size; - dbg_win32 ("WIN32 I/O: TAP Completion non-queued success [%d]\n", ret); - } - - break; - - case IOSTATE_INITIAL: /* were we called without proper queueing? */ - SetLastError (ERROR_INVALID_FUNCTION); - ret = -1; - dbg_tap ("WIN32 I/O: TAP Completion BAD STATE\n"); - break; + dbg_tap ("WIN32 I/O: TAP Completion BAD STATE\n"); + break; - default: - dbg_tap ("Some weird case happened..\n"); + default: + dbg_tap ("Some weird case happened..\n"); } if (buf) *buf_len = ret; - return ret; } @@ -829,12 +807,12 @@ int tun_write_queue (struct tuntap *tt, uint8_t *buf, uint32_t buf_len) dbg_tap("ResetEvent in write_queue failed!\n"); status = WriteFile( - tt->hand, - tt->writes.buf, - tt->writes.buf_len, - &tt->writes.size, - &tt->writes.overlapped - ); + tt->hand, + tt->writes.buf, + tt->writes.buf_len, + &tt->writes.size, + &tt->writes.overlapped + ); if (status) /* operation completed immediately? */ { @@ -847,18 +825,18 @@ int tun_write_queue (struct tuntap *tt, uint8_t *buf, uint32_t buf_len) tt->writes.status = 0; dbg_win32 ("WIN32 I/O: TAP Write immediate return [%d,%d]\n", - (int)(tt->writes.buf_len), - (int)tt->writes.size); + (int)(tt->writes.buf_len), + (int)tt->writes.size); } else { - err = GetLastError (); + err = GetLastError (); if (err == ERROR_IO_PENDING) /* operation queued? */ { tt->writes.iostate = IOSTATE_QUEUED; tt->writes.status = err; dbg_win32("WIN32 I/O: TAP Write queued [%d]\n", - (tt->writes.buf_len)); + (tt->writes.buf_len)); } else /* error occurred */ { @@ -871,16 +849,15 @@ int tun_write_queue (struct tuntap *tt, uint8_t *buf, uint32_t buf_len) } } } - return tt->writes.iostate; } static inline int overlapped_io_active (struct overlapped_io *o) { - return o->iostate == IOSTATE_QUEUED || o->iostate == IOSTATE_IMMEDIATE_RETURN; + return o->iostate == IOSTATE_QUEUED || o->iostate == IOSTATE_IMMEDIATE_RETURN; } -/* if >= 0: returns the amount of bytes read, otherwise error! */ +// if >= 0: returns the amount of bytes read, otherwise error! static int tun_write_win32 (struct tuntap *tt, uint8_t *buf, uint32_t buf_len) { int err = 0; @@ -890,15 +867,13 @@ static int tun_write_win32 (struct tuntap *tt, uint8_t *buf, uint32_t buf_len) status = tun_finalize (tt->hand, &tt->writes, NULL, 0); if (status == 0) { - /* busy, just wait, do not schedule a new write */ + // busy, just wait, do not schedule a new write return 0; } - if (status < 0) err = GetLastError (); } - - /* the overlapped IO is done, now we can schedule a new write */ + // the overlapped IO is done, now we can schedule a new write tun_write_queue (tt, buf, buf_len); if (status < 0) { @@ -910,43 +885,40 @@ static int tun_write_win32 (struct tuntap *tt, uint8_t *buf, uint32_t buf_len) } -/* if >= 0: returns the amount of bytes read, otherwise error! */ +// if >= 0: returns the amount of bytes read, otherwise error! static int tun_read_win32 (struct tuntap *tt, uint8_t *buf, uint32_t buf_len) { int err = 0; int status = 0; - /* First, finish possible pending IOs */ + // First, finish possible pending IOs if (overlapped_io_active (&tt->reads)) { status = tun_finalize (tt->hand, &tt->reads, &buf, &buf_len); if (status == 0) { - /* busy, just wait, do not schedule a new read */ + // busy, just wait, do not schedule a new read return 0; } - if (status < 0) { dbg_tap ("tun_finalize status < 0: %d\n", status); err = GetLastError (); } - if (status > 0) { return buf_len; } } - /* If no pending IOs, schedule a new read */ - /* queue, or immediate return */ + // If no pending IOs, schedule a new read + // queue, or immediate return if (IOSTATE_IMMEDIATE_RETURN == tun_read_queue(tt, buf, buf_len)) { return tt->reads.size; } - - /* If the pending IOs gave an error, report it */ + // If the pending IOs gave an error, report it if (status < 0) { SetLastError (err); @@ -954,20 +926,20 @@ static int tun_read_win32 (struct tuntap *tt, uint8_t *buf, uint32_t buf_len) } else { - /* no errors, but the newly scheduled read is now pending */ + // no errors, but the newly scheduled read is now pending return 0; } } -static int read_tun_buffered(struct tuntap *tt, uint8_t *buf, uint32_t buf_len) +static int read_tun_buffered(struct tuntap *tt, uint8_t * buf, uint32_t buf_len) { - return tun_read_win32 (tt, buf, buf_len); + return tun_read_win32 (tt, buf, buf_len); } -static int write_tun_buffered(struct tuntap *tt, uint8_t *buf, uint32_t buf_len) +static int write_tun_buffered(struct tuntap *tt, uint8_t * buf, uint32_t buf_len) { - return tun_write_win32 (tt, buf, buf_len); + return tun_write_win32 (tt, buf, buf_len); } @@ -999,7 +971,7 @@ static int pico_tap_poll(struct pico_device *dev, int loop_score) { dbg_tap("RX< recvd: %d bytes\n", bytes_read); pico_stack_recv(dev, recv_buffer, bytes_read); - /* break; */ + //break; } else break; @@ -1013,20 +985,20 @@ static int pico_tap_poll(struct pico_device *dev, int loop_score) void overlapped_io_init (struct overlapped_io *o, int event_state) { - CLEAR (*o); - - /* manual reset event, initially set according to event_state */ - o->overlapped.hEvent = CreateEvent (NULL, TRUE, event_state, NULL); - if (o->overlapped.hEvent == NULL) - dbg_tap ("Error: overlapped_io_init: CreateEvent failed\n"); - - /* allocate buffer for overlapped I/O */ - o->buf_init = PICO_ZALLOC(1500); /* XXX: MTU */ - o->buf_init_len = 1500; /* XXX: MTU */ - if (!(o->buf_init)) - dbg_tap("buffer alloc failed!\n"); /* XXX: return -1 or so? */ - else - dbg_tap("overlapped_io_init buffer allocated!\n"); + CLEAR (*o); + + /* manual reset event, initially set according to event_state */ + o->overlapped.hEvent = CreateEvent (NULL, TRUE, event_state, NULL); + if (o->overlapped.hEvent == NULL) + dbg_tap ("Error: overlapped_io_init: CreateEvent failed\n"); + + /* allocate buffer for overlapped I/O */ + o->buf_init = PICO_ZALLOC(1500); // XXX: MTU + o->buf_init_len = 1500; // XXX: MTU + if (!(o->buf_init)) + dbg_tap("buffer alloc failed!\n"); // XXX: return -1 or so? + else + dbg_tap("overlapped_io_init buffer allocated!\n"); } void init_tun_post (struct tuntap *tt) @@ -1042,12 +1014,12 @@ void init_tun_post (struct tuntap *tt) /* * Public interface: pico_tap_create * TODO: pico_tap_destroy - */ + */ struct pico_device *pico_tap_create(char *name, uint8_t *mac) { struct pico_device_tap *tap = PICO_ZALLOC(sizeof(struct pico_device_tap)); - struct tuntap *tt = PICO_ZALLOC(sizeof(struct tuntap), 1); + struct tuntap *tt = PICO_ZALLOC(sizeof(struct tuntap),1); if (!(tap) || !(tt)) return NULL; @@ -1067,14 +1039,13 @@ struct pico_device *pico_tap_create(char *name, uint8_t *mac) PICO_FREE(tap); return NULL; } - tap->tt = tt; if( 0 != pico_device_init((struct pico_device *)tap, name, mac)) { return NULL; } - init_tun_post(tt); /* init overlapped io */ + init_tun_post(tt); // init overlapped io dbg_tap("Device %s created.\n", tap->dev.name); diff --git a/modules/pico_dev_tap_windows.h b/modules/pico_dev_tap_windows.h index 25bd4fc13..0c5750493 100755 --- a/modules/pico_dev_tap_windows.h +++ b/modules/pico_dev_tap_windows.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/modules/pico_dev_tap_windows_private.h b/modules/pico_dev_tap_windows_private.h old mode 100644 new mode 100755 index 8f3b19234..4363fbbbb --- a/modules/pico_dev_tap_windows_private.h +++ b/modules/pico_dev_tap_windows_private.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Maxime Vincent @@ -8,11 +8,11 @@ NOTES: This is the Windows-only driver, a Linux-equivalent is available, too You need to have an OpenVPN TUN/TAP network adapter installed, first This driver is barely working: - * Only TAP-mode is supported (TUN is not) - * it will simply open the first TAP device it can find - * there is memory being allocated that's never freed - * there is no destroy function, yet - * it has only been tested on a Windows 7 machine + * Only TAP-mode is supported (TUN is not) + * it will simply open the first TAP device it can find + * there is memory being allocated that's never freed + * there is no destroy function, yet + * it has only been tested on a Windows 7 machine *********************************************************************/ #ifndef __PICO_DEV_TAP_WINDOWS_PRIVATE_H @@ -27,15 +27,15 @@ /* Extra structs */ struct tap_reg { - const char *guid; - struct tap_reg *next; + const char *guid; + struct tap_reg *next; }; struct panel_reg { - const char *name; - const char *guid; - struct panel_reg *next; + const char *name; + const char *guid; + struct panel_reg *next; }; @@ -45,8 +45,8 @@ struct panel_reg * ============= */ -#define TAP_WIN_CONTROL_CODE(request, method) \ - CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) +#define TAP_WIN_CONTROL_CODE(request,method) \ + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) /* Present in 8.1 */ diff --git a/modules/pico_dev_tun.c b/modules/pico_dev_tun.c index f5b76c3bb..4065a725d 100644 --- a/modules/pico_dev_tun.c +++ b/modules/pico_dev_tun.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Daniele Lacamera diff --git a/modules/pico_dev_tun.h b/modules/pico_dev_tun.h index 4dd477eb9..6bb3fc164 100644 --- a/modules/pico_dev_tun.h +++ b/modules/pico_dev_tun.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/modules/pico_dev_vde.c b/modules/pico_dev_vde.c index c21a61915..f9011b6f5 100644 --- a/modules/pico_dev_vde.c +++ b/modules/pico_dev_vde.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Daniele Lacamera @@ -51,7 +51,6 @@ static int pico_vde_poll(struct pico_device *dev, int loop_score) len = vde_recv(vde->conn, buf, VDE_MTU, 0); if (len > 0) { - /* dbg("Received pkt.\n"); */ if ((vde->lost_in == 0) || ((pico_rand() % 100) > vde->lost_in)) { loop_score--; pico_stack_recv(dev, buf, (uint32_t)len); @@ -67,8 +66,6 @@ void pico_vde_destroy(struct pico_device *dev) { struct pico_device_vde *vde = (struct pico_device_vde *) dev; vde_close(vde->conn); - usleep(100000); - sync(); } void pico_vde_set_packetloss(struct pico_device *dev, uint32_t in_pct, uint32_t out_pct) @@ -78,8 +75,6 @@ void pico_vde_set_packetloss(struct pico_device *dev, uint32_t in_pct, uint32_t vde->lost_out = out_pct; } - - struct pico_device *pico_vde_create(char *sock, char *name, uint8_t *mac) { struct pico_device_vde *vde = PICO_ZALLOC(sizeof(struct pico_device_vde)); diff --git a/modules/pico_dev_vde.h b/modules/pico_dev_vde.h index c6c999e60..7e9b5443b 100644 --- a/modules/pico_dev_vde.h +++ b/modules/pico_dev_vde.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. diff --git a/modules/pico_dhcp_client.c b/modules/pico_dhcp_client.c index 4db92f964..42a87e8f7 100644 --- a/modules/pico_dhcp_client.c +++ b/modules/pico_dhcp_client.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Kristof Roelants, Frederik Van Slycken @@ -229,9 +229,9 @@ static void pico_dhcp_client_timer_handler(pico_time now, void *arg) (void) now; - if (t->state != DHCP_CLIENT_TIMER_STOPPED) { - dhcpc = pico_dhcp_client_find_cookie(t->xid); - if (dhcpc && dhcpc->timer) { + dhcpc = pico_dhcp_client_find_cookie(t->xid); + if (dhcpc && dhcpc->timer) { + if (t->state != DHCP_CLIENT_TIMER_STOPPED) { t->state = DHCP_CLIENT_TIMER_STOPPED; if (t->type == PICO_DHCPC_TIMER_INIT) { pico_dhcp_client_reinit(now, dhcpc); @@ -342,9 +342,6 @@ static void pico_dhcp_client_start_reacquisition_timers(struct pico_dhcp_client_ static int pico_dhcp_client_init(struct pico_dhcp_client_cookie *dhcpc) { uint16_t port = PICO_DHCP_CLIENT_PORT; - if (!dhcpc) - return -1; - /* adding a link with address 0.0.0.0 and netmask 0.0.0.0, * automatically adds a route for a global broadcast */ pico_ipv4_link_add(dhcpc->dev, inaddr_any, bcast_netmask); @@ -879,23 +876,19 @@ static int8_t pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_ static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s) { - - uint8_t *buf; + uint8_t buf[DHCP_CLIENT_MAXMSGZISE] = { + 0 + }; int r = 0; struct pico_dhcp_hdr *hdr = NULL; struct pico_dhcp_client_cookie *dhcpc = NULL; - - if (ev != PICO_SOCK_EV_RD) - return; - buf = PICO_ZALLOC(DHCP_CLIENT_MAXMSGZISE); - if (!buf) { + if (ev != PICO_SOCK_EV_RD) return; - } r = pico_socket_recvfrom(s, buf, DHCP_CLIENT_MAXMSGZISE, NULL, NULL); if (r < 0) - goto out_discard_buf; + return; /* If the 'xid' of an arriving message does not match the 'xid' * of the most recent transmitted message, the message must be @@ -903,13 +896,10 @@ static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s) hdr = (struct pico_dhcp_hdr *)buf; dhcpc = pico_dhcp_client_find_cookie(hdr->xid); if (!dhcpc) - goto out_discard_buf; + return; dhcpc->event = (uint8_t)pico_dhcp_client_opt_parse(buf, (uint16_t)r); pico_dhcp_state_machine(dhcpc->event, dhcpc, buf); - -out_discard_buf: - PICO_FREE(buf); } void *pico_dhcp_get_identifier(uint32_t xid) diff --git a/modules/pico_dhcp_client.h b/modules/pico_dhcp_client.h index 09f027087..bf493ae72 100644 --- a/modules/pico_dhcp_client.h +++ b/modules/pico_dhcp_client.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -14,6 +14,7 @@ #include "pico_protocol.h" int pico_dhcp_initiate_negotiation(struct pico_device *device, void (*callback)(void*cli, int code), uint32_t *xid); +void pico_dhcp_process_incoming_message(uint8_t *data, int len); void *pico_dhcp_get_identifier(uint32_t xid); struct pico_ip4 pico_dhcp_get_address(void *cli); struct pico_ip4 pico_dhcp_get_gateway(void *cli); diff --git a/modules/pico_dhcp_common.c b/modules/pico_dhcp_common.c index 2eb10b165..f353024f1 100644 --- a/modules/pico_dhcp_common.c +++ b/modules/pico_dhcp_common.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . diff --git a/modules/pico_dhcp_common.h b/modules/pico_dhcp_common.h index e9f304a9e..66de1c08d 100644 --- a/modules/pico_dhcp_common.h +++ b/modules/pico_dhcp_common.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . diff --git a/modules/pico_dhcp_server.c b/modules/pico_dhcp_server.c index 48725d150..3436be980 100644 --- a/modules/pico_dhcp_server.c +++ b/modules/pico_dhcp_server.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. diff --git a/modules/pico_dhcp_server.h b/modules/pico_dhcp_server.h index d5df8203c..0b9be61e7 100644 --- a/modules/pico_dhcp_server.h +++ b/modules/pico_dhcp_server.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/modules/pico_dns_client.c b/modules/pico_dns_client.c index 6989bdc86..15b5206f8 100644 --- a/modules/pico_dns_client.c +++ b/modules/pico_dns_client.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -133,7 +133,7 @@ static struct pico_dns_ns pico_dns_client_next_ns(struct pico_ip4 *ns_addr) return *nxtdns; } -static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_header *hdr, uint16_t len, struct pico_dns_query_suffix *suffix, +static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_header *hdr, uint16_t len, struct pico_dns_question_suffix *suffix, void (*callback)(char *, void *), void *arg) { struct pico_dns_query *q = NULL, *found = NULL; @@ -234,7 +234,7 @@ static int pico_dns_client_query_header(struct pico_dns_header *hdr) return -1; hdr->id = short_be(id); - pico_dns_fill_header(hdr, 1, 0); /* 1 question, 0 answers */ + pico_dns_fill_packet_header(hdr, 1, 0, 0, 0); /* 1 question, 0 answers */ return 0; } @@ -254,7 +254,7 @@ static int pico_dns_client_check_header(struct pico_dns_header *pre) return 0; } -static int pico_dns_client_check_qsuffix(struct pico_dns_query_suffix *suf, struct pico_dns_query *q) +static int pico_dns_client_check_qsuffix(struct pico_dns_question_suffix *suf, struct pico_dns_query *q) { if (!suf) return -1; @@ -267,20 +267,20 @@ static int pico_dns_client_check_qsuffix(struct pico_dns_query_suffix *suf, stru return 0; } -static int pico_dns_client_check_asuffix(struct pico_dns_answer_suffix *suf, struct pico_dns_query *q) +static int pico_dns_client_check_asuffix(struct pico_dns_record_suffix *suf, struct pico_dns_query *q) { if (!suf) { pico_err = PICO_ERR_EINVAL; return -1; } - if (short_be(suf->qtype) != q->qtype || short_be(suf->qclass) != q->qclass) { - dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->qtype), short_be(suf->qclass)); + if (short_be(suf->rtype) != q->qtype || short_be(suf->rclass) != q->qclass) { + dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->rtype), short_be(suf->rclass)); return -1; } - if (long_be(suf->ttl) > PICO_DNS_MAX_TTL) { - dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(suf->ttl), PICO_DNS_MAX_TTL); + if (long_be(suf->rttl) > PICO_DNS_MAX_TTL) { + dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(suf->rttl), PICO_DNS_MAX_TTL); return -1; } @@ -289,7 +289,7 @@ static int pico_dns_client_check_asuffix(struct pico_dns_answer_suffix *suf, str static char *pico_dns_client_seek_suffix(char *suf, struct pico_dns_header *pre, struct pico_dns_query *q) { - struct pico_dns_answer_suffix *asuffix = NULL; + struct pico_dns_record_suffix *asuffix = NULL; uint16_t comp = 0, compression = 0; uint16_t i = 0; @@ -320,12 +320,12 @@ static char *pico_dns_client_seek_suffix(char *suf, struct pico_dns_header *pre, return NULL; } - asuffix = (struct pico_dns_answer_suffix *)suf; + asuffix = (struct pico_dns_record_suffix *)suf; if (!asuffix) break; if (pico_dns_client_check_asuffix(asuffix, q) < 0) { - suf += (sizeof(struct pico_dns_answer_suffix) + short_be(asuffix->rdlength)); + suf += (sizeof(struct pico_dns_record_suffix) + short_be(asuffix->rdlength)); continue; } @@ -390,11 +390,11 @@ static void pico_dns_client_retransmission(pico_time now, void *arg) } } -static int pico_dns_client_user_callback(struct pico_dns_answer_suffix *asuffix, struct pico_dns_query *q) +static int pico_dns_client_user_callback(struct pico_dns_record_suffix *asuffix, struct pico_dns_query *q) { uint32_t ip = 0; char *str = NULL; - char *rdata = (char *) asuffix + sizeof(struct pico_dns_answer_suffix); + char *rdata = (char *) asuffix + sizeof(struct pico_dns_record_suffix); switch (q->qtype) { @@ -442,14 +442,14 @@ static int pico_dns_client_user_callback(struct pico_dns_answer_suffix *asuffix, } static char dns_response[PICO_IP_MRU] = { - 0 + 0 }; -static void pico_dns_try_fallback_cname(struct pico_dns_query *q, struct pico_dns_header *h, struct pico_dns_query_suffix *qsuffix) +static void pico_dns_try_fallback_cname(struct pico_dns_query *q, struct pico_dns_header *h, struct pico_dns_question_suffix *qsuffix) { uint16_t type = q->qtype; uint16_t proto = PICO_PROTO_IPV4; - struct pico_dns_answer_suffix *asuffix = NULL; + struct pico_dns_record_suffix *asuffix = NULL; char *p_asuffix = NULL; char *cname = NULL; @@ -461,30 +461,28 @@ static void pico_dns_try_fallback_cname(struct pico_dns_query *q, struct pico_dn proto = PICO_PROTO_IPV6; q->qtype = PICO_DNS_TYPE_CNAME; - p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_query_suffix); + p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix); p_asuffix = pico_dns_client_seek_suffix(p_asuffix, h, q); if (!p_asuffix) { return; } - /* Found CNAME response. Re-initiating query. */ - asuffix = (struct pico_dns_answer_suffix *)p_asuffix; - cname = (char *) asuffix + sizeof(struct pico_dns_answer_suffix); + asuffix = (struct pico_dns_record_suffix *)p_asuffix; + cname = (char *) asuffix + sizeof(struct pico_dns_record_suffix); pico_dns_notation_to_name(cname); if (cname[0] == '.') - cname++; - + cname++; dns_dbg("Restarting query for name '%s'\n", cname); pico_dns_client_getaddr_init(cname, proto, q->callback, q->arg); pico_dns_client_del_query(q->id); } - + static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s) { struct pico_dns_header *header = NULL; char *domain; - struct pico_dns_query_suffix *qsuffix = NULL; - struct pico_dns_answer_suffix *asuffix = NULL; + struct pico_dns_question_suffix *qsuffix = NULL; + struct pico_dns_record_suffix *asuffix = NULL; struct pico_dns_query *q = NULL; char *p_asuffix = NULL; @@ -500,7 +498,7 @@ static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s) header = (struct pico_dns_header *)dns_response; domain = (char *)header + sizeof(struct pico_dns_header); - qsuffix = (struct pico_dns_query_suffix *)pico_dns_client_seek(domain); + qsuffix = (struct pico_dns_question_suffix *)pico_dns_client_seek(domain); /* valid asuffix is determined dynamically later on */ if (pico_dns_client_check_header(header) < 0) @@ -513,20 +511,20 @@ static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s) if (pico_dns_client_check_qsuffix(qsuffix, q) < 0) return; - p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_query_suffix); + p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix); p_asuffix = pico_dns_client_seek_suffix(p_asuffix, header, q); if (!p_asuffix) { pico_dns_try_fallback_cname(q, header, qsuffix); return; } - asuffix = (struct pico_dns_answer_suffix *)p_asuffix; + asuffix = (struct pico_dns_record_suffix *)p_asuffix; pico_dns_client_user_callback(asuffix, q); return; } -static int pico_dns_create_message(struct pico_dns_header **header, struct pico_dns_query_suffix **qsuffix, enum pico_dns_arpa arpa, const char *url, uint16_t *urlen, uint16_t *hdrlen) +static int pico_dns_create_message(struct pico_dns_header **header, struct pico_dns_question_suffix **qsuffix, enum pico_dns_arpa arpa, const char *url, uint16_t *urlen, uint16_t *hdrlen) { char *domain; char inaddr_arpa[14]; @@ -555,7 +553,7 @@ static int pico_dns_create_message(struct pico_dns_header **header, struct pico_ arpalen = pico_dns_client_strlen(inaddr_arpa); *urlen = (uint16_t)(PICO_DNS_LABEL_INITIAL + strlen + arpalen + PICO_DNS_LABEL_ROOT); - *hdrlen = (uint16_t)(sizeof(struct pico_dns_header) + *urlen + sizeof(struct pico_dns_query_suffix)); + *hdrlen = (uint16_t)(sizeof(struct pico_dns_header) + *urlen + sizeof(struct pico_dns_question_suffix)); *header = PICO_ZALLOC(*hdrlen); if (!*header) { pico_err = PICO_ERR_ENOMEM; @@ -564,7 +562,7 @@ static int pico_dns_create_message(struct pico_dns_header **header, struct pico_ *header = (struct pico_dns_header *)*header; domain = (char *) *header + sizeof(struct pico_dns_header); - *qsuffix = (struct pico_dns_query_suffix *)(domain + *urlen); + *qsuffix = (struct pico_dns_question_suffix *)(domain + *urlen); if(arpa == PICO_DNS_ARPA4) { memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen); @@ -599,11 +597,10 @@ static int pico_dns_client_addr_label_check_len(const char *url) while(*p != (char) 0) { count = 0; while((*p != (char)0)) { - if (*p == '.') { + if (*p == '.'){ label = ++p; break; } - count++; p++; if (count > PICO_DNS_MAX_QUERY_LABEL_LEN) @@ -619,24 +616,21 @@ static int pico_dns_client_getaddr_check(const char *url, void (*callback)(char pico_err = PICO_ERR_EINVAL; return -1; } - if (strlen(url) > PICO_DNS_MAX_QUERY_LEN) { pico_err = PICO_ERR_EINVAL; return -1; } - if (pico_dns_client_addr_label_check_len(url) < 0) { pico_err = PICO_ERR_EINVAL; return -1; } - return 0; } static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg) { struct pico_dns_header *header = NULL; - struct pico_dns_query_suffix *qsuffix = NULL; + struct pico_dns_question_suffix *qsuffix = NULL; struct pico_dns_query *q = NULL; uint16_t len = 0, lblen = 0; (void)proto; @@ -649,10 +643,10 @@ static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (* #ifdef PICO_SUPPORT_IPV6 if (proto == PICO_PROTO_IPV6) { - pico_dns_fill_query_suffix(qsuffix, PICO_DNS_TYPE_AAAA, PICO_DNS_CLASS_IN); + pico_dns_question_fill_qsuffix(qsuffix, PICO_DNS_TYPE_AAAA, PICO_DNS_CLASS_IN); } else #endif - pico_dns_fill_query_suffix(qsuffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN); + pico_dns_question_fill_qsuffix(qsuffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN); q = pico_dns_client_add_query(header, len, qsuffix, callback, arg); if (!q) { @@ -681,7 +675,7 @@ int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), static int pico_dns_getname_univ(const char *ip, void (*callback)(char *, void *), void *arg, enum pico_dns_arpa arpa) { struct pico_dns_header *header = NULL; - struct pico_dns_query_suffix *qsuffix = NULL; + struct pico_dns_question_suffix *qsuffix = NULL; struct pico_dns_query *q = NULL; uint16_t len = 0, lblen = 0; @@ -693,7 +687,7 @@ static int pico_dns_getname_univ(const char *ip, void (*callback)(char *, void * if(pico_dns_create_message(&header, &qsuffix, arpa, ip, &lblen, &len) != 0) return -1; - pico_dns_fill_query_suffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN); + pico_dns_question_fill_qsuffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN); q = pico_dns_client_add_query(header, len, qsuffix, callback, arg); if (!q) { PICO_FREE(header); diff --git a/modules/pico_dns_client.h b/modules/pico_dns_client.h index dcf970a6c..910cc92e1 100644 --- a/modules/pico_dns_client.h +++ b/modules/pico_dns_client.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . diff --git a/modules/pico_dns_common.c b/modules/pico_dns_common.c index ed1d9b7f0..0ca41c739 100644 --- a/modules/pico_dns_common.c +++ b/modules/pico_dns_common.c @@ -1,11 +1,11 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - - . - - Authors: Toon Stegen - *********************************************************************/ +/* **************************************************************************** + * PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. + * See LICENSE and COPYING for usage. + * + * . + * + * Authors: Toon Stegen, Jelle De Vleeschouwer + * ****************************************************************************/ #include "pico_config.h" #include "pico_stack.h" #include "pico_addressing.h" @@ -16,56 +16,1596 @@ #include "pico_dns_client.h" #include "pico_tree.h" -void pico_dns_fill_header(struct pico_dns_header *hdr, uint16_t qdcount, uint16_t ancount) -{ +#define dns_dbg(...) do {} while(0) +//#define dns_dbg dbg - /* hdr->id should be filled by caller */ +// MARK: PROTOTYPES +static int +pico_dns_record_copy_flat( struct pico_dns_record *record, + uint8_t **destination ); +static char * +pico_dns_url_to_reverse_qname( const char *url, uint8_t proto ); + +// MARK: DNS PACKET FUNCTIONS +/* **************************************************************************** + * Fills the header section of a DNS packet with correct flags and section- + * counts. + * ****************************************************************************/ +void +pico_dns_fill_packet_header( struct pico_dns_header *hdr, + uint16_t qdcount, + uint16_t ancount, + uint16_t nscount, + uint16_t arcount ) +{ + /* hdr->id should be filled by caller */ + + /* If there are questions in the packet, make it a Query */ if(qdcount > 0) { hdr->qr = PICO_DNS_QR_QUERY; hdr->aa = PICO_DNS_AA_NO_AUTHORITY; - } - else { + } else { + /* If there are questions in the packet, make it a Response */ hdr->qr = PICO_DNS_QR_RESPONSE; hdr->aa = PICO_DNS_AA_IS_AUTHORITY; } - + + /* Fill in the flags and the fields */ hdr->opcode = PICO_DNS_OPCODE_QUERY; hdr->tc = PICO_DNS_TC_NO_TRUNCATION; - hdr->rd = PICO_DNS_RD_IS_DESIRED; + hdr->rd = PICO_DNS_RD_NO_DESIRE; hdr->ra = PICO_DNS_RA_NO_SUPPORT; hdr->z = 0; /* Z, AD, CD are 0 */ hdr->rcode = PICO_DNS_RCODE_NO_ERROR; hdr->qdcount = short_be(qdcount); hdr->ancount = short_be(ancount); - hdr->nscount = short_be(0); - hdr->arcount = short_be(0); + hdr->nscount = short_be(nscount); + hdr->arcount = short_be(arcount); } -/* determine len of string */ -uint16_t pico_dns_client_strlen(const char *url) +/* **************************************************************************** + * Fills the resource record section of a DNS packet with provided record- + * vectors. + * ****************************************************************************/ +static int +pico_dns_fill_packet_rr_sections( pico_dns_packet *packet, + pico_dns_question_vector *qvector, + pico_dns_record_vector *anvector, + pico_dns_record_vector *nsvector, + pico_dns_record_vector *arvector ) { - if (!url) + struct pico_dns_record *record = NULL; + uint16_t i = 0; + uint8_t *destination = NULL; + + /* Check params */ + if (!packet || !qvector || !anvector || !nsvector || !arvector) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Initialise the destination pointers before iterating */ + destination = (uint8_t *)packet + sizeof(struct pico_dns_header); + destination += pico_dns_question_vector_size(qvector); + + /* iterate over ANSWER vector */ + for (i = 0; i < pico_dns_record_vector_count(anvector); i++) { + record = pico_dns_record_vector_get(anvector, i); + if (pico_dns_record_copy_flat(record, &destination)) { + dns_dbg("Could not copy record into Answer Section!\n"); + return -1; + } + } + + /* iterate over AUTHORITY vector */ + for (i = 0; i < pico_dns_record_vector_count(nsvector); i++) { + record = pico_dns_record_vector_get(nsvector, i); + if (pico_dns_record_copy_flat(record, &destination)) { + dns_dbg("Could not copy record into Authority Section!\n"); + return -1; + } + } + + /* iterate over ADDITIONAL vector */ + for (i = 0; i < pico_dns_record_vector_count(arvector); i++) { + record = pico_dns_record_vector_get(nsvector, i); + if (pico_dns_record_copy_flat(record, &destination)) { + dns_dbg("Could not copy record into Authority Section!\n"); + return -1; + } + } + + return 0; +} + +/* **************************************************************************** + * Fills the question section of a DNS packet with provided questions in + * question_list + * ****************************************************************************/ +static int +pico_dns_fill_packet_question_section( pico_dns_packet *packet, + pico_dns_question_vector *vector) +{ + struct pico_dns_question *question = NULL; + struct pico_dns_question_suffix *destination_qsuffix = NULL; + char *destination_qname = NULL; + uint16_t i = 0; + + /* Check params */ + if (!packet || !vector) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Get the first question in the vector */ + question = pico_dns_question_vector_get(vector, 0); + if (!question) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + destination_qname = (char *)((uint8_t *)packet + + sizeof(struct pico_dns_header)); + + for (i = 0; i < pico_dns_question_vector_count(vector); i++) { + question = pico_dns_question_vector_get(vector, i); + + /* Copy the qname of the question into the packet */ + strcpy(destination_qname, question->qname); + + destination_qsuffix = (struct pico_dns_question_suffix *) + (destination_qname + question->qname_length); + + /* Copy the qtype and qclass fields */ + destination_qsuffix->qtype = question->qsuffix->qtype; + destination_qsuffix->qclass = question->qsuffix->qclass; + + /* Set the destination pointers correctly */ + destination_qname = (char *)((uint8_t *) destination_qsuffix + + sizeof(struct pico_dns_question_suffix)); + } + + return 0; +} + +/* **************************************************************************** + * Looks for a name somewhere else in packet, more specifically between the + * beginning of the data buffer and the name itself. + * ****************************************************************************/ +static uint8_t * +pico_dns_packet_compress_find_ptr( uint8_t *name, + uint8_t *data, + uint16_t len ) +{ + uint8_t *iterator = NULL; + + /* Check params */ + if (!name || !data || !len) { + return NULL; + } + if ((name < data) || (name > (data + len))) { + return NULL; + } + + iterator = data; + + /* Iterate from the beginning of data up until the name-ptr */ + while (iterator < name) { + /* Compare in each iteration of current name is equal to a section of + the DNS packet and if so return the pointer to that section */ + if (memcmp((void *)iterator++, + (void *)name, + strlen((char *)name) + 1u) == 0) + return (iterator - 1); + } + + return NULL; +} + +/* **************************************************************************** + * Compresses a single name by looking for the same name somewhere else in the + * packet-buffer. + * ****************************************************************************/ +static int +pico_dns_packet_compress_name( uint8_t *name, + uint8_t *packet, + uint16_t *len) +{ + uint8_t *lbl_iterator = NULL; // To iterate over labels + uint8_t *compression_ptr = NULL; // PTR to somewhere else in the packet + uint8_t *offset = NULL; // PTR after compression pointer + uint8_t *ptr_after_str = NULL; + uint8_t *last_byte = NULL; + uint8_t *i = NULL; + uint16_t ptr = 0; + uint16_t difference = 0; + + /* Check params */ + if (!name || !packet || !len) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + if ((name < packet) || (name > (packet + *len))) { + dns_dbg("Name ptr OOB. name: %p max: %p\n", name, packet + *len); + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Try to compress name */ + lbl_iterator = name; + while (lbl_iterator != '\0') { + /* Try to find a compression pointer with current name */ + compression_ptr = pico_dns_packet_compress_find_ptr(lbl_iterator, + packet + 12, *len); + /* If name can be compressed */ + if (compression_ptr) { + /* Point to place after current string */ + ptr_after_str = lbl_iterator + strlen((char *)lbl_iterator) + 1u; + + /* Calculate the compression pointer value */ + ptr = (uint16_t)(compression_ptr - packet); + + /* Set the compression pointer in the packet */ + *lbl_iterator = (uint8_t)(0xC0 | (uint8_t)(ptr >> 8)); + *(lbl_iterator + 1) = (uint8_t)(ptr & 0xFF); + + /* Move up the rest of the packet data to right after the pointer */ + offset = lbl_iterator + 2; + + /* Move up left over data */ + difference = (uint16_t)(ptr_after_str - offset); + last_byte = packet + *len; + for (i = ptr_after_str; i <= last_byte; i++) + *(i - difference) = *i; + + /* Update length */ + *len = (uint16_t)(*len - difference); + break; + } + + /* Move to next length label */ + lbl_iterator = lbl_iterator + *(lbl_iterator) + 1; + } + + return 0; +} + +/* **************************************************************************** + * Utility function compress a record section + * ****************************************************************************/ +static int +pico_dns_compress_record_section( int expression, uint16_t count, + uint8_t *buf, uint8_t **iterator, + uint16_t *len ) +{ + struct pico_dns_record_suffix *rsuffix = NULL; + uint8_t *_iterator = *iterator; + uint16_t i = 0; + + /* Check params */ + if (!buf || !iterator || !len) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + if (!(*iterator)) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + for (i = 0; i < count; i++) { + if (expression || i) + pico_dns_packet_compress_name(_iterator, buf, len); + + /* To get rdlength */ + rsuffix = (struct pico_dns_record_suffix *) + (_iterator + pico_dns_namelen_comp((char *)_iterator) + 1u); + + /* Move to next res record */ + _iterator = ((uint8_t *)rsuffix + + sizeof(struct pico_dns_record_suffix) + + short_be(rsuffix->rdlength)); + } + + *iterator = _iterator; + return 0; +} + +/* **************************************************************************** + * Applies DNS name compression to an entire DNS packet + * ****************************************************************************/ +static int +pico_dns_packet_compress( pico_dns_packet *packet, uint16_t *len ) +{ + uint8_t *packet_buf = NULL; + uint8_t *iterator = NULL; + uint16_t qdcount = 0, ancount = 0, nscount = 0, arcount = 0, i = 0; + + /* Check params */ + if (!packet || !len) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + packet_buf = (uint8_t *)packet; + + /* Temporarily store the question & record counts */ + qdcount = short_be(packet->qdcount); + ancount = short_be(packet->ancount); + nscount = short_be(packet->nscount); + arcount = short_be(packet->arcount); + + /* Move past the DNS packet header */ + iterator = (uint8_t *)((uint8_t *) packet + 12u); + + /* Start with the questions */ + for (i = 0; i < qdcount; i++) { + if (i) /* First question can't be compressed */ + pico_dns_packet_compress_name(iterator, packet_buf, len); + + /* Move to next question */ + iterator = (uint8_t *)(iterator + + pico_dns_namelen_comp((char *)iterator) + + sizeof(struct pico_dns_question_suffix) + 1u); + } + + /* Then onto the answers */ + pico_dns_compress_record_section(qdcount, ancount, + packet_buf, &iterator, + len); + + /* Then onto the authorities */ + pico_dns_compress_record_section((qdcount || ancount), nscount, + packet_buf, &iterator, + len); + + /* Then onto the additionals */ + pico_dns_compress_record_section((qdcount || ancount || nscount), arcount, + packet_buf, &iterator, + len); + return 0; +} + +// MARK: QUESTION FUNCTIONS + +/* **************************************************************************** + * Fills the question fixed-sized flags & fields accordingly. + * ****************************************************************************/ +void +pico_dns_question_fill_qsuffix( struct pico_dns_question_suffix *suf, + uint16_t type, + uint16_t qclass ) +{ + suf->qtype = short_be(type); + suf->qclass = short_be(qclass); +} + +/* **************************************************************************** + * Just copies a question provided in [questio] + * ****************************************************************************/ +struct pico_dns_question * +pico_dns_question_copy( struct pico_dns_question *question ) +{ + struct pico_dns_question *copy = NULL; + + /* Check params */ + if (!question) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + /* Provide space for the copy and copy */ + copy = (struct pico_dns_question *) + PICO_ZALLOC(sizeof(struct pico_dns_question)); + if (!copy) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + copy->qname = PICO_ZALLOC((size_t)question->qname_length); + if (!(copy->qname)) { + pico_err = PICO_ERR_ENOMEM; + PICO_FREE(copy); + return NULL; + } + strcpy(copy->qname, question->qname); + copy->qname_length = question->qname_length; + copy->qsuffix = PICO_ZALLOC(sizeof(struct pico_dns_question_suffix)); + if (!(copy->qsuffix)) { + pico_err = PICO_ERR_ENOMEM; + PICO_FREE(copy->qname); + PICO_FREE(copy); + return NULL; + } + copy->qsuffix->qtype = question->qsuffix->qtype; + copy->qsuffix->qclass = question->qsuffix->qclass; + copy->proto = question->proto; + return copy; +} + +/* **************************************************************************** + * Deletes & free's the memory for a certain dns resource record. Doesn't take + * lists into account so if applied to a list, most probably, gaps will arisee. + * ****************************************************************************/ +int +pico_dns_question_delete( struct pico_dns_question **question) +{ + if (!question || !(*question)) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + if ((*question)->qname) + PICO_FREE((*question)->qname); + (*question)->qname = NULL; + + if ((*question)->qsuffix) + PICO_FREE((*question)->qsuffix); + (*question)->qsuffix = NULL; + + PICO_FREE(*question); + *question = NULL; + + return 0; +} + +/* **************************************************************************** + * Creates a standalone DNS question for given 'url'. Fills the 'len'-argument + * with the total length of the question. + * ****************************************************************************/ +struct pico_dns_question * +pico_dns_question_create( const char *url, + uint16_t *len, + uint8_t proto, + uint16_t qtype, + uint16_t qclass, + uint8_t reverse ) +{ + struct pico_dns_question *question = NULL; + uint16_t slen = 0; + + /* Check if valid arguments are provided */ + if (!url || !len) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + /* Allocate space for the question and the subfields */ + question = PICO_ZALLOC(sizeof(struct pico_dns_question)); + if (!question) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + + /* Create a qname from the URL */ + if (reverse && qtype == PICO_DNS_TYPE_PTR) { + question->qname = pico_dns_url_to_reverse_qname(url, proto); + } else { + question->qname = pico_dns_url_to_qname(url); + } + + /* Provide space for the question suffix */ + question->qsuffix = PICO_ZALLOC(sizeof(struct pico_dns_question_suffix)); + if (!(question->qsuffix) || !(question->qname)) { + pico_err = PICO_ERR_ENOMEM; + pico_dns_question_delete(&question); + return NULL; + } + + /* Determine the entire length of the question */ + slen = (uint16_t)(strlen(question->qname) + 1u); + *len = (uint16_t)(slen + (uint16_t)sizeof(struct pico_dns_question_suffix)); + + /* Set the length of the question */ + question->qname_length = (uint8_t)(slen); + + /* Fill in the question suffix */ + pico_dns_question_fill_qsuffix(question->qsuffix, qtype, qclass); + + /* Fill in the proto */ + question->proto = proto; + return question; +} + +/* **************************************************************************** + * Initialise a DNS question vector + * ****************************************************************************/ +int +pico_dns_question_vector_init( pico_dns_question_vector *vector ) +{ + /* Check params */ + if (!vector) return -1; + vector->questions = NULL; + vector->count = 0; + return 0; +} + +/* **************************************************************************** + * Returns the amount of questions contained in the DNS question vector + * ****************************************************************************/ +uint16_t +pico_dns_question_vector_count( pico_dns_question_vector *vector ) +{ + /* Check params */ + if (!vector) return 0; + return vector->count; +} + +/* **************************************************************************** + * Adds a DNS question to a DNS question vector + * ****************************************************************************/ +int +pico_dns_question_vector_add( pico_dns_question_vector *vector, + struct pico_dns_question *question ) +{ + struct pico_dns_question **new_questions = NULL; + uint16_t i = 0; + + /* Check params */ + if (!vector || !question) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Create a new array with larger size */ + new_questions = PICO_ZALLOC(sizeof(struct pico_dns_question *) * + (vector->count + 1u)); + if (!new_questions) + return -1; + + /* Copy all the record-pointers from the previous array to the new one */ + for (i = 0; i < vector->count; i++) + new_questions[i] = vector->questions[i]; + new_questions[i] = question; + + /* Free the previous array */ + if (vector->questions) + PICO_FREE(vector->questions); + + /* Set the records array to the new one and update count */ + vector->questions = new_questions; + vector->count++; + return 0; +} + +/* **************************************************************************** + * Adds a copy of a DNS question to a DNS question vector + * ****************************************************************************/ +int +pico_dns_question_vector_add_copy( pico_dns_question_vector *vector, + struct pico_dns_question *question ) +{ + struct pico_dns_question *copy = NULL; + + /* Check params */ + if (!vector || !question) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Create copy */ + copy = pico_dns_question_copy(question); + return pico_dns_question_vector_add(vector, copy); +} + +/* **************************************************************************** + * Returns a DNS question from a DNS question vector at a certain index + * ****************************************************************************/ +struct pico_dns_question * +pico_dns_question_vector_get( pico_dns_question_vector *vector, + uint16_t index) +{ + /* Check params */ + if (!vector) + return NULL; + + /* Return record with conditioned index */ + if (index < vector->count) + return vector->questions[index]; + + return NULL; +} + +static int +pico_dns_question_vector_del_generic( pico_dns_question_vector *vector, + uint16_t index, + uint8_t delete ) +{ + struct pico_dns_question **new_questions = NULL; + uint16_t i = 0; + + /* Check params */ + if (!vector) return -1; + if (index >= vector->count) return -1; + + /* Delete record */ + if (delete) { + if (pico_dns_question_delete(&(vector->questions[index])) < 0) + return -1; + } + + vector->count--; + if (vector->count) { + new_questions = PICO_ZALLOC(sizeof(struct pico_dns_question *) * + vector->count); + if (!new_questions) { + pico_err = PICO_ERR_ENOMEM; + return -1; + } + } + + /* Move up subsequent questions */ + for (i = index; i < vector->count; i++) { + vector->questions[i] = vector->questions[i + 1]; + vector->questions[i + 1] = NULL; + } + + /* Copy records */ + for (i = 0; i < vector->count; i++) + new_questions[i] = vector->questions[i]; + + /* Free the previous array */ + PICO_FREE(vector->questions); + + /* Set the records array to the new one */ + vector->questions = new_questions; + return 0; +} + +/* **************************************************************************** + * Removes a DNS question from a DNS question vector at a certain index + * ****************************************************************************/ +int +pico_dns_question_vector_remove( pico_dns_question_vector *vector, + uint16_t index ) +{ + return pico_dns_question_vector_del_generic(vector, index, 0); +} + +/* **************************************************************************** + * Deletes a DNS question from a DNS question vector at a certain index + * ****************************************************************************/ +int +pico_dns_question_vector_delete( pico_dns_question_vector *vector, + uint16_t index) +{ + return pico_dns_question_vector_del_generic(vector, index, 1); +} + +/* **************************************************************************** + * Deletes every DNS question from a DNS question vector + * ****************************************************************************/ +int +pico_dns_question_vector_destroy( pico_dns_question_vector *vector ) +{ + uint16_t i = 0; + + /* Check params */ + if (!vector) return -1; + + /* Delete every record in the vector */ + for (i = 0; i < vector->count; i++) { + if (pico_dns_question_delete(&(vector->questions[i])) < 0) { + dns_dbg("Could not delete record from vector!\n"); + return -1; + } + } + + /* Update the fields */ + vector->questions = NULL; + vector->count = 0; + return 0; +} + +/* **************************************************************************** + * Finds a DNS question in a DNS question vector + * ****************************************************************************/ +struct pico_dns_question * +pico_dns_question_vector_find_name( pico_dns_question_vector *vector, + const char *name ) +{ + struct pico_dns_question *question = NULL; + uint16_t i = 0; + + /* Check params */ + if (!vector || !name) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + /* Iterate over the vector an compare names */ + for (i = 0; i < pico_dns_question_vector_count(vector); i++) { + question = pico_dns_question_vector_get(vector, i); + if (strcmp(question->qname, name) == 0) + return question; + } + + return NULL; +} + +/* **************************************************************************** + * Deletes a DNS question from a DNS question vector + * ****************************************************************************/ +int +pico_dns_question_vector_del_name( pico_dns_question_vector *vector, + const char *name ) +{ + struct pico_dns_question *question = NULL; + uint16_t i = 0; + + /* Check params */ + if (!vector || !name) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Iterate over the vector an compare names */ + for (i = 0; i < pico_dns_question_vector_count(vector); i++) { + question = pico_dns_question_vector_get(vector, i); + if (strcmp(question->qname, name) == 0) { + if (pico_dns_question_vector_delete(vector, i) < 0) { + dns_dbg("Could not delete question from probe cookie!\n"); + return -1; + } + } + } + + return 0; +} + +/* **************************************************************************** + * Returns the size in bytes of all the DNS questions contained in a DNS + * question-vector. + * ****************************************************************************/ +uint16_t +pico_dns_question_vector_size( pico_dns_question_vector *vector ) +{ + struct pico_dns_question *question = NULL; + uint16_t i = 0; + size_t size = 0; + + /* Check params */ + if (!vector) { + pico_err = PICO_ERR_EINVAL; return 0; + } + + /* Add up the sizes */ + for (i = 0; i < pico_dns_question_vector_count(vector); i++) { + question = pico_dns_question_vector_get(vector, i); + size += (size_t)question->qname_length + + sizeof(struct pico_dns_question_suffix); + } + return (uint16_t)size; +} + +// MARK: QUERY FUNCTIONS - return (uint16_t)strlen(url); +static uint16_t +pico_dns_packet_len( pico_dns_question_vector *qvector, + pico_dns_record_vector *anvector, + pico_dns_record_vector *nsvector, + pico_dns_record_vector *arvector, + uint8_t *qdcount, uint8_t *ancount, + uint8_t *nscount, uint8_t *arcount ) +{ + uint16_t len = (uint16_t) sizeof(pico_dns_packet); + + /* Check params */ + if (!qvector || !anvector || !nsvector || !arvector) { + pico_err = PICO_ERR_EINVAL; + return 0; + } + + len = (uint16_t)(len + pico_dns_question_vector_size(qvector)); + *qdcount = (uint8_t)(qvector->count); + len = (uint16_t)(len + pico_dns_record_vector_size(anvector)); + *ancount = (uint8_t)(anvector->count); + len = (uint16_t)(len + pico_dns_record_vector_size(nsvector)); + *nscount = (uint8_t)(nsvector->count); + len = (uint16_t)(len + pico_dns_record_vector_size(arvector)); + *arcount = (uint8_t)(arvector->count); + + return len; +} + +/* **************************************************************************** + * Generic packet creation utility + * ****************************************************************************/ +pico_dns_packet * +pico_dns_packet_create( pico_dns_question_vector *qvector, + pico_dns_record_vector *anvector, + pico_dns_record_vector *nsvector, + pico_dns_record_vector *arvector, + uint16_t *len ) +{ + pico_dns_packet *packet = NULL; + pico_dns_question_vector _qvector = {0}; + pico_dns_record_vector _anvector = {0}, _nsvector = {0}, _arvector = {0}; + uint8_t qdcount = 0, ancount = 0, nscount = 0, arcount = 0; + + /* Set default vector, if arguments are NULL-pointers */ + _qvector = qvector ? *qvector : _qvector; + _anvector = anvector ? *anvector : _anvector; + _nsvector = nsvector ? *nsvector : _nsvector; + _arvector = arvector ? *arvector : _arvector; + + /* Get the size of the entire packet and determine the header counters */ + *len = pico_dns_packet_len(&_qvector, &_anvector, &_nsvector, &_arvector, + &qdcount, &ancount, &nscount, &arcount); + + /* Provide space for the entire packet */ + packet = PICO_ZALLOC(*len); + if (!packet) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + + /* Fill the Question Section with questions */ + if (qvector && _qvector.count != 0) { + if (pico_dns_fill_packet_question_section(packet, &_qvector)) { + dns_dbg("Could not fill Question Section correctly!\n"); + return NULL; + } + } + + /* Fill the Resource Record Sections with resource records */ + if (pico_dns_fill_packet_rr_sections(packet, &_qvector, &_anvector, + &_nsvector, &_arvector)) { + dns_dbg("Could not fill Resource Record Sections correctly!\n"); + return NULL; + } + + /* Fill the DNS packet header */ + pico_dns_fill_packet_header(packet, qdcount, ancount, nscount, arcount); + + /* Apply DNS name compression */ + pico_dns_packet_compress(packet, len); + + return packet; +} + +/* **************************************************************************** + * Creates a DNS packet meant for querying. Currently only questions can be + * inserted in the packet. + * ****************************************************************************/ +pico_dns_packet * +pico_dns_query_create( pico_dns_question_vector *qvector, + pico_dns_record_vector *anvector, + pico_dns_record_vector *nsvector, + pico_dns_record_vector *arvector, + uint16_t *len ) +{ + return pico_dns_packet_create(qvector, anvector, nsvector, arvector, len); +} + +// MARK: RESOURCE RECORD FUNCTIONS + +/* **************************************************************************** + * Fills the resource record fixed-sized flags & fields accordingly. + * ****************************************************************************/ +static void +pico_dns_record_fill_suffix( struct pico_dns_record_suffix *suf, + uint16_t rtype, + uint16_t rclass, + uint32_t rttl, + uint16_t rdlength ) +{ + suf->rtype = short_be(rtype); + suf->rclass = short_be(rclass); + suf->rttl = long_be(rttl); + suf->rdlength = short_be(rdlength); +} + +/* **************************************************************************** + * Copies the contents a resource record [record] to a single flat + * location in [destination]. [destination] pointer will point to address + * right after this flat resource record on success. + * ****************************************************************************/ +static int +pico_dns_record_copy_flat( struct pico_dns_record *record, + uint8_t **destination ) +{ + char *dest_rname = NULL; // rname destination location + struct pico_dns_record_suffix *dest_rsuffix = NULL; // rsuffix destin. + uint8_t *dest_rdata = NULL; // rdata destination location + + /* Check if there are no NULL-pointers given */ + if (!record || !destination || !(*destination)) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Initialise the destiation pointers to the right locations */ + dest_rname = (char *) *destination; + dest_rsuffix = (struct pico_dns_record_suffix *) + (dest_rname + record->rname_length); + dest_rdata = ((uint8_t *)dest_rsuffix + + sizeof(struct pico_dns_record_suffix)); + + /* Copy the rname of the resource record into the flat location */ + strcpy(dest_rname, record->rname); + + /* Copy the question suffix fields */ + dest_rsuffix->rtype = record->rsuffix->rtype; + dest_rsuffix->rclass = record->rsuffix->rclass; + dest_rsuffix->rttl = record->rsuffix->rttl; + dest_rsuffix->rdlength = record->rsuffix->rdlength; + + /* Copy the rdata of the resource */ + memcpy(dest_rdata, + record->rdata, + short_be(dest_rsuffix->rdlength)); + + /* Point to location right after flat resource record */ + *destination = (uint8_t *)(dest_rdata + + short_be(record->rsuffix->rdlength)); + + return 0; +} + +/* **************************************************************************** + * Deletes & free's the memory for a certain dns resource record + * ****************************************************************************/ +int +pico_dns_record_delete( struct pico_dns_record **rr ) +{ + if (!rr) + return 0; + if (!(*rr)) + return 0; + + if ((*rr)->rname) + PICO_FREE((*rr)->rname); + + if ((*rr)->rsuffix) + PICO_FREE((*rr)->rsuffix); + + if ((*rr)->rdata) + PICO_FREE((*rr)->rdata); + + PICO_FREE((*rr)); + *rr = NULL; + + return 0; +} + +/* **************************************************************************** + * Just copies a resource record provided in [record] + * ****************************************************************************/ +struct pico_dns_record * +pico_dns_record_copy( struct pico_dns_record *record ) +{ + struct pico_dns_record *copy = NULL; + + /* Check params */ + if (!record) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + if (!(record->rname) || !(record->rsuffix) || !(record->rdata)) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + /* Provide place the copy */ + copy = PICO_ZALLOC(sizeof(struct pico_dns_record)); + if (!copy) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + + /* Provide space for the subfields */ + copy->rname = PICO_ZALLOC((size_t)record->rname_length); + copy->rsuffix = PICO_ZALLOC(sizeof(struct pico_dns_record_suffix)); + copy->rdata = PICO_ZALLOC((size_t)short_be(record->rsuffix->rdlength)); + if (!(copy->rname) || !(copy->rsuffix) || !(copy->rdata)) { + pico_dns_record_delete(©); + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + + /* Fill in the rname field */ + strcpy(copy->rname, record->rname); + copy->rname_length = record->rname_length; + + /* Fill in the rsuffix fields */ + copy->rsuffix->rtype = record->rsuffix->rtype; + copy->rsuffix->rclass = record->rsuffix->rclass; + copy->rsuffix->rttl = record->rsuffix->rttl; + copy->rsuffix->rdlength = record->rsuffix->rdlength; + + /* Fill in the rdata field */ + memcpy(copy->rdata, record->rdata, short_be(record->rsuffix->rdlength)); + + return copy; +} + + + +/* **************************************************************************** + * Creates a standalone DNS resource record for given 'url'. Fills the + * 'len'-argument with the total length of the record. + * ****************************************************************************/ +struct pico_dns_record * +pico_dns_record_create( const char *url, + void *_rdata, + uint16_t datalen, + uint16_t *len, + uint16_t rtype, + uint16_t rclass, + uint32_t rttl ) +{ + struct pico_dns_record *record = NULL; + uint16_t slen; + + /* Cast the void pointer to a char pointer */ + char *rdata = (char *)_rdata; + + /* Get length + 2 for .-prefix en trailing zero-byte */ + slen = (uint16_t)(pico_dns_client_strlen(url) + 2u); + + /* We want DNS notation with PTR records */ + if (rtype == PICO_DNS_TYPE_PTR) + datalen = (uint16_t)(datalen + 2u); + + /* Allocate space for the record and subfields */ + record = PICO_ZALLOC(sizeof(struct pico_dns_record)); + if (!record) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + record->rname = PICO_ZALLOC(slen); + record->rsuffix = PICO_ZALLOC(sizeof(struct pico_dns_record_suffix)); + record->rdata = PICO_ZALLOC(datalen); + if (!(record->rname) || !(record->rsuffix) || !(record->rdata)) { + pico_dns_record_delete(&record); + return NULL; + } + + /* Determine the complete length of resource record */ + *len = (uint16_t)(slen + sizeof(struct pico_dns_record_suffix) + datalen); + + /* Fill in the rname_length field */ + record->rname_length = (uint8_t)slen; + + /* Copy url into rname in DNS notation */ + strcpy(record->rname + 1u, url); + pico_dns_name_to_dns_notation(record->rname); + + /* Fill in the resource record suffix */ + pico_dns_record_fill_suffix(record->rsuffix, rtype, rclass, rttl, datalen); + + /* Fill in rdata */ + if (rtype == PICO_DNS_TYPE_PTR) { + memcpy(record->rdata + 1, rdata, datalen - 2u); + pico_dns_name_to_dns_notation((char *)(record->rdata)); + } else + memcpy(record->rdata, rdata, datalen); + + return record; +} + +/* **************************************************************************** + * Initialise an DNS record vector + * ****************************************************************************/ +int +pico_dns_record_vector_init( pico_dns_record_vector *vector ) +{ + /* Check params */ + if (!vector) return -1; + vector->records = NULL; + vector->count = 0; + return 0; } -/* replace '.' in the domain name by the label length - * f.e. www.google.be => 3www6google2be0 */ -int pico_dns_name_to_dns_notation(char *ptr) +/* **************************************************************************** + * Returns the amount of records contained in the DNS record vector + * ****************************************************************************/ +uint16_t +pico_dns_record_vector_count( pico_dns_record_vector *vector ) +{ + /* Check params */ + if (!vector) return 0; + return vector->count; +} + +/* **************************************************************************** + * Adds a DNS record to a DNS record vector + * ****************************************************************************/ +int +pico_dns_record_vector_add( pico_dns_record_vector *vector, + struct pico_dns_record *record ) +{ + struct pico_dns_record **new_records = NULL; + uint16_t i = 0; + + /* Check params */ + if (!vector || !record) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Create a new array with larger size */ + new_records = PICO_ZALLOC(sizeof(struct pico_dns_record *) * + (vector->count + 1u)); + if (!new_records) + return -1; + + /* Copy all the record-pointers from the previous array to the new one */ + for (i = 0; i < vector->count; i++) + new_records[i] = vector->records[i]; + new_records[i] = record; + + /* Free the previous array */ + if (vector->records) + PICO_FREE(vector->records); + + /* Set the records array to the new one and update count */ + vector->records = new_records; + vector->count++; + return 0; +} + +/* **************************************************************************** + * Adds a copy of a DNS record to a DNS record vector + * ****************************************************************************/ +int +pico_dns_record_vector_add_copy( pico_dns_record_vector *vector, + struct pico_dns_record *record ) +{ + struct pico_dns_record *copy = NULL; + + /* Check params */ + if (!vector || !record) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Create copy */ + copy = pico_dns_record_copy(record); + return pico_dns_record_vector_add(vector, copy); +} + +/* **************************************************************************** + * Returns a DNS record from a DNS record vector at a certain index + * ****************************************************************************/ +struct pico_dns_record * +pico_dns_record_vector_get( pico_dns_record_vector *vector, uint16_t index) +{ + /* Check params */ + if (!vector) + return NULL; + + /* Return record with conditioned index */ + if (index < vector->count) + return vector->records[index]; + + return NULL; +} + +/* **************************************************************************** + * Deletes a DNS record from a DNS record vector at a certain index + * ****************************************************************************/ +int +pico_dns_record_vector_delete( pico_dns_record_vector *vector, uint16_t index) +{ + struct pico_dns_record **new_records = NULL; + uint16_t i = 0; + + /* Check params */ + if (!vector) return -1; + if (index >= vector->count) return -1; + + /* Delete record */ + if (pico_dns_record_delete(&(vector->records[index])) < 0) + return -1; + + vector->count--; + if (vector->count) { + new_records = PICO_ZALLOC(sizeof(struct pico_dns_record *) * + vector->count); + if (!new_records) { + pico_err = PICO_ERR_ENOMEM; + return -1; + } + } + + /* Move up subsequent records */ + for (i = index; i < vector->count; i++) { + vector->records[i] = vector->records[i + 1]; + vector->records[i + 1] = NULL; + } + + /* Copy records */ + for (i = 0; i < vector->count; i++) + new_records[i] = vector->records[i]; + + /* Free the previous array */ + PICO_FREE(vector->records); + + /* Set the records array to the new one */ + vector->records = new_records; + return 0; +} + +/* **************************************************************************** + * Deletes every DNS record from a DNS record vector + * ****************************************************************************/ +int +pico_dns_record_vector_destroy( pico_dns_record_vector *vector ) +{ + uint16_t i = 0; + + /* Check params */ + if (!vector) return -1; + + /* Delete every record in the vector */ + for (i = 0; i < vector->count; i++) { + if (pico_dns_record_delete(&(vector->records[i])) < 0) { + dns_dbg("Could not delete record from vector!\n"); + return -1; + } + } + + /* Update the fields */ + vector->records = NULL; + vector->count = 0; + return 0; +} + +/* **************************************************************************** + * Returns the size in bytes of all the DNS records contained in a DNS + * record-vector. + * ****************************************************************************/ +uint16_t +pico_dns_record_vector_size( pico_dns_record_vector *vector ) +{ + struct pico_dns_record *record = NULL; + uint16_t i = 0; + size_t size = 0; + + /* Check params */ + if (!vector) { + pico_err = PICO_ERR_EINVAL; + return 0; + } + + /* Add up the sizes */ + for (i = 0; i < pico_dns_record_vector_count(vector); i++) { + record = pico_dns_record_vector_get(vector, i); + size = size + (size_t)record->rname_length + + sizeof(struct pico_dns_record_suffix) + + short_be(record->rsuffix->rdlength); + } + return (uint16_t)size; +} + +// MARK: ANSWER FUNCTIONS + +/* **************************************************************************** + * Creates a DNS Answer packet with given resource records to put in the + * Resource Record Sections. If a NULL-pointer is provided for a certain + * list, no records will be added to the packet for that section. + * ****************************************************************************/ +pico_dns_packet * +pico_dns_answer_create( pico_dns_record_vector *anvector, + pico_dns_record_vector *nsvector, + pico_dns_record_vector *arvector, + uint16_t *len ) +{ + return pico_dns_packet_create(NULL, anvector, nsvector, arvector, len); +} + +// MARK: NAME & IP FUNCTIONS + +/* **************************************************************************** + * Returns the length of an FQDN in a DNS-packet as if DNS name compression + * would be applied to the packet + * ****************************************************************************/ +uint16_t +pico_dns_namelen_comp( char *name ) +{ + uint8_t *ptr = (uint8_t *)name; // Pointer to work with + uint16_t len = 0; // Length to return + + if (!ptr) { + pico_err = PICO_ERR_EINVAL; + return 0; + } + + /* Just count until the zero-byte */ + while (*ptr != '\0' && !(*ptr & 0xC0)) { + ptr += (uint8_t) *ptr + 1; + } + + len = (uint16_t)(ptr - (uint8_t *)name); + if(*ptr != '\0') + len++; + + return len; +} + +/* **************************************************************************** + * Returns the length of an FQDN. If DNS name compression is applied in the + * DNS packet, this will be the length as if the compressed name would be + * decompressed. + * ****************************************************************************/ +uint16_t +pico_dns_namelen_uncomp( char *name, pico_dns_packet *packet ) +{ + uint8_t *begin = (uint8_t *)name; // Stores the beginning of the name + uint8_t *ptr = begin; // Pointer to work with + uint8_t *buf = NULL; // DNS packet, byte addressable + uint16_t comp_ptr = 0; // Pointer in DNS packet index + uint16_t len = 0; // Length to return + + /* Cast the DNS packet to a byte-addressable buffer */ + buf = (uint8_t *)packet; + + /* While we are not at the end of the name */ + while (*ptr != '\0') { + /* Check if the first bit of the data is set - '|1|1|P|P|...|P|P|' */ + if(*ptr & 0xC0) { + /* Move ptr to the pointer location */ + comp_ptr = (uint16_t)((uint16_t)((((uint16_t)*ptr) << 8) & 0x3F00) | + ((uint16_t)*(ptr + 1))); + ptr = buf + comp_ptr; + } else { + /* Add the label length to the total length */ + len = (uint16_t)(len + (uint16_t)(*ptr & 0x3F) + 1); + + /* Move 'ptr' to the next length label */ + ptr += (*ptr + 1); + } + } + return len; +} + +/* **************************************************************************** + * Returns the uncompressed FQDN when DNS name compression is applied in the + * DNS packet. + * ****************************************************************************/ +char * +pico_dns_decompress_name( char *name, pico_dns_packet *packet ) +{ + char *decompressed_name = NULL; + uint8_t *dest_iterator = NULL; + uint8_t *iterator = NULL; + uint16_t ptr = 0; + + /* Provide storage for the uncompressed name */ + decompressed_name = PICO_ZALLOC((size_t) (pico_dns_namelen_uncomp(name, + packet))); + if(!decompressed_name) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + + /* Initialise iterators */ + iterator = (uint8_t *) name; + dest_iterator = (uint8_t *) decompressed_name; + while (*iterator != '\0') { + if ((*iterator) & 0xC0) { + /* We have a pointer */ + ptr = (uint16_t)((((uint16_t) *iterator) & 0x003F) << 8); + ptr = (uint16_t)(ptr | (uint16_t) *(iterator + 1)); + iterator = (uint8_t *)((uint8_t *)packet + ptr); + } else { + /* We want to keep the label lengths */ + *dest_iterator = (uint8_t) *iterator; + /* Copy the label */ + memcpy(dest_iterator + 1, iterator + 1, *iterator); + /* Move to next length label */ + dest_iterator += (*iterator) + 1; + iterator += (*iterator) + 1; + } + } + + /* Append final zero-byte */ + *dest_iterator = (uint8_t) '\0'; + + return decompressed_name; +} + +/* **************************************************************************** + * Gets the length of a given 'url' as if it where a qname for given qtype and + * protocol. Fills arpalen with the length of the arpa-suffix when qtype is + * PICO_DNS_TYPE_PTR, depending on [proto]. + * ****************************************************************************/ +static uint16_t +pico_dns_url_get_reverse_len( const char *url, + uint16_t *arpalen, + uint16_t proto) +{ + uint16_t slen = 0; + + /* Check if pointers given are not NULL */ + if (!url && !arpalen) { + pico_err = PICO_ERR_EINVAL; + return 0; + } + /* Get length + 2 for .-prefix en trailing zero-byte by default */ + slen = (uint16_t)(pico_dns_client_strlen(url) + 2u); + *arpalen = 0; + + /* Get the length of arpa-suffix if needed */ + if (proto == PICO_PROTO_IPV4) + *arpalen = (uint16_t) strlen(PICO_ARPA_IPV4_SUFFIX); +#ifdef PICO_SUPPORT_IPV6 + else if (proto == PICO_PROTO_IPV6) + { + *arpalen = (uint16_t) strlen(PICO_ARPA_IPV6_SUFFIX); + slen = STRLEN_PTR_IP6 + 2u; + } +#endif + return slen; +} + +/* **************************************************************************** + * Returns the qname with [url] in DNS-format, with reverse resolving + * f.e.: www.google.com => 3www6google3com0 + * ****************************************************************************/ +static char * +pico_dns_url_to_reverse_qname( const char *url, uint8_t proto ) +{ + char *reverse_qname = NULL; + uint16_t slen = 0, arpalen = 0; + + slen = pico_dns_url_get_reverse_len(url, &arpalen, proto); + reverse_qname = PICO_ZALLOC((size_t)(slen + arpalen)); + if (!reverse_qname || !url) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + + /* If reverse IPv4 address resolving, convert to IPv4 arpa-format */ + if (proto == PICO_PROTO_IPV4) { + memcpy(reverse_qname + 1u, url, strlen(url)); + pico_dns_mirror_addr(reverse_qname + 1u); + memcpy(reverse_qname + (uint16_t)(strlen(url) + 2u) - 1, + PICO_ARPA_IPV4_SUFFIX, + strlen(PICO_ARPA_IPV4_SUFFIX)); + /* If reverse IPv6 address resolving, convert to IPv6 arpa-format */ + } +#ifdef PICO_SUPPORT_IPV6 + else if (proto == PICO_PROTO_IPV6) { + pico_dns_ipv6_set_ptr(url, reverse_qname + 1u); + memcpy(reverse_qname + 1u + STRLEN_PTR_IP6, + PICO_ARPA_IPV6_SUFFIX, + strlen(PICO_ARPA_IPV6_SUFFIX)); + } +#endif + else { + /* If you call this function you want a reverse qname */ + } + pico_dns_name_to_dns_notation(reverse_qname); + return reverse_qname; +} + +/* **************************************************************************** + * Create an URL in *[url_addr] from any qname given in [qname]. [url_addr] + * needs to be an addres to a NULL-pointer. Returns a string + * 1 byte smaller in size than [qname] or 2 bytes smaller than the + * string-length. Use PICO_FREE() to deallocate the memory for this pointer. + * + * f.e. * 4tass5local0 -> tass.local + * * 11112102107in-addr4arpa0 -> 1.1.10.10.in-addr.arpa + * ****************************************************************************/ +char * +pico_dns_qname_to_url( const char *qname ) +{ + char *url = NULL; // URL-string to return + char *temp = NULL; // Temporary string + + /* Check if qname or url_addr is not a NULL-pointer */ + if (!qname) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + /* Provide space for the url */ + url = PICO_ZALLOC(strlen(qname) - 2u); + if (!url) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + + /* Provide space for a temporary string to work with */ + temp = PICO_ZALLOC(strlen(qname) + 1u); + if (!temp) { + pico_err = PICO_ERR_ENOMEM; + PICO_FREE(url); + return NULL; + } + + /* Convert qname to an URL*/ + strcpy(temp, qname); + pico_dns_notation_to_name(temp); + strcpy(url, temp + 1); + + /* We don't need temp anymore, free memory */ + PICO_FREE(temp); + + return url; +} + +/* **************************************************************************** + * Create a qname in *[qname_addr] from any url given in [url]. [qname_addr] + * needs to be an address to a NULL-pointer. Returns a string + * 1 byte larger in size than [url] or 2 bytes larger than the + * string-length. use PICO_FREE() to deallocate the memory for this pointer. + * + * f.e. - tass.local -> 4tass5local0 + * - 1.1.10.10.in-addr.arpa -> 11112102107in-addr4arpa0 + * ****************************************************************************/ +char * +pico_dns_url_to_qname( const char *url ) +{ + char *qname = NULL; // qname-string to return + char *temp = NULL; // temp string to work with + + /* Check if url or qname_addr is not a NULL-pointer */ + if (!url) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + /* Provide space for the temporary string */ + temp = PICO_ZALLOC(strlen(url) + 1u); + if (!temp) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + strcpy(temp, url); + + /* Provide space for the qname */ + qname = PICO_ZALLOC(strlen(url) + 2u); + if (!qname) { + pico_err = PICO_ERR_ENOMEM; + PICO_FREE(temp); + return NULL; + } + + /* Copy in the URL (+1 to leave space for leading '.') */ + strcpy(qname + 1, temp); + PICO_FREE(temp); + + /* Change to DNS notation */ + pico_dns_name_to_dns_notation(qname); + + return qname; +} + +/* **************************************************************************** + * Determines the length of a string + * ****************************************************************************/ +uint16_t +pico_dns_client_strlen(const char *url) +{ + if (!url) + return 0; + return (uint16_t) strlen(url); +} + +/* **************************************************************************** + * Converts a URL at location url + 1 to a FQDN in the form 3www6google3com0 + * f.e. www.google.be => 3www6google2be0 + * Size of ptr[] has to +2u more than the URL itself. + * ****************************************************************************/ +int +pico_dns_name_to_dns_notation(char *url) { char p = 0, *label = NULL; uint8_t len = 0; - if (!ptr) + if (!url) return -1; - label = ptr++; - while ((p = *ptr++) != 0) { + label = url++; + while ((p = *url++) != 0) { if (p == '.') { *label = (char)len; - label = ptr - 1; + label = url - 1; len = 0; } else { len++; @@ -75,41 +1615,33 @@ int pico_dns_name_to_dns_notation(char *ptr) return 0; } -/* replace the label length in the domain name by '.' - * f.e. 3www6google2be0 => .www.google.be */ -int pico_dns_notation_to_name(char *ptr) +/* **************************************************************************** + * Converts a FQDN at location fqdn to an URL in the form .www.google.com + * f.e. 3www6google2be0 => .www.google.be + * ****************************************************************************/ +int +pico_dns_notation_to_name(char *fqdn) { char p = 0, *label = NULL; - if (!ptr) + if (!fqdn) return -1; - label = ptr; - while ((p = *ptr++) != 0) { - ptr += p; + label = fqdn; + while ((p = *fqdn++) != 0) { + fqdn += p; *label = '.'; - label = ptr; + label = fqdn; } return 0; } -void pico_dns_fill_query_suffix(struct pico_dns_query_suffix *suf, uint16_t type, uint16_t qclass) -{ - suf->qtype = short_be(type); - suf->qclass = short_be(qclass); -} - -void pico_dns_fill_rr_suffix(struct pico_dns_answer_suffix *suf, uint16_t qtype, uint16_t qclass, uint32_t ttl, uint16_t rdlength) -{ - suf->qtype = short_be(qtype); - suf->qclass = short_be(qclass); - suf->ttl = long_be(ttl); - suf->rdlength = short_be(rdlength); -} - -/* mirror ip address numbers - * f.e. 192.168.0.1 => 1.0.168.192 */ -int8_t pico_dns_mirror_addr(char *ptr) +/* **************************************************************************** + * mirror ip address numbers + * f.e. 192.168.0.1 => 1.0.168.192 + * ****************************************************************************/ +int8_t +pico_dns_mirror_addr(char *ptr) { const unsigned char *addr = NULL; char *m = ptr; @@ -144,7 +1676,8 @@ int8_t pico_dns_mirror_addr(char *ptr) #ifdef PICO_SUPPORT_IPV6 #define STRLEN_PTR_IP6 63 -static inline char dns_ptr_ip6_nibble_lo(uint8_t byte) +static inline char +dns_ptr_ip6_nibble_lo(uint8_t byte) { uint8_t nibble = byte & 0x0f; if (nibble < 10) @@ -153,7 +1686,8 @@ static inline char dns_ptr_ip6_nibble_lo(uint8_t byte) return (char)(nibble - 0xa + 'a'); } -static inline char dns_ptr_ip6_nibble_hi(uint8_t byte) +static inline char +dns_ptr_ip6_nibble_hi(uint8_t byte) { uint8_t nibble = (byte & 0xf0u) >> 4u; if (nibble < 10u) @@ -162,11 +1696,11 @@ static inline char dns_ptr_ip6_nibble_hi(uint8_t byte) return (char)(nibble - 0xa + 'a'); } -void pico_dns_ipv6_set_ptr(const char *ip, char *dst) +void +pico_dns_ipv6_set_ptr(const char *ip, char *dst) { - struct pico_ip6 ip6 = { - .addr = {} - }; + /* Wow, initiasing struct fields, cool */ + struct pico_ip6 ip6 = {.addr = {}}; int i, j = 0; pico_string_to_ipv6(ip, ip6.addr); for (i = 15; i >= 0; i--) { @@ -176,4 +1710,4 @@ void pico_dns_ipv6_set_ptr(const char *ip, char *dst) dst[j++] = '.'; } } -#endif +#endif \ No newline at end of file diff --git a/modules/pico_dns_common.h b/modules/pico_dns_common.h index 183c977b3..fb35a1044 100644 --- a/modules/pico_dns_common.h +++ b/modules/pico_dns_common.h @@ -1,11 +1,11 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . - Authors: Toon Stegen + Authors: Toon Stegen, Jelle De Vleeschouwer *********************************************************************/ #ifndef INCLUDE_PICO_DNS_COMMON @@ -16,11 +16,12 @@ /* QTYPE values */ #define PICO_DNS_TYPE_A 1 #define PICO_DNS_TYPE_CNAME 5 -#define PICO_DNS_TYPE_AAAA 28 #define PICO_DNS_TYPE_PTR 12 +#define PICO_DNS_TYPE_TXT 16 +#define PICO_DNS_TYPE_AAAA 28 +#define PICO_DNS_TYPE_SRV 33 #define PICO_DNS_TYPE_ANY 255 - /* QCLASS values */ #define PICO_DNS_CLASS_IN 1 @@ -45,56 +46,392 @@ #define PICO_DNS_RCODE_ENOIMP 4 #define PICO_DNS_RCODE_EREFUSED 5 +#define PICO_ARPA_IPV4_SUFFIX ".in-addr.arpa" + #ifdef PICO_SUPPORT_IPV6 #define STRLEN_PTR_IP6 63 +#define PICO_ARPA_IPV6_SUFFIX ".IP6.ARPA" #endif +enum pico_dns_arpa +{ + PICO_DNS_ARPA4, + PICO_DNS_ARPA6, + PICO_DNS_NO_ARPA, +}; + /* flags split in 2x uint8 due to endianness */ PACKED_STRUCT_DEF pico_dns_header { - uint16_t id; - uint8_t rd : 1; /* recursion desired */ - uint8_t tc : 1; /* truncation */ - uint8_t aa : 1; /* authoritative answer */ - uint8_t opcode : 4; /* opcode */ - uint8_t qr : 1; /* query */ - uint8_t rcode : 4; /* response code */ - uint8_t z : 3; /* zero */ - uint8_t ra : 1; /* recursion available */ - uint16_t qdcount; - uint16_t ancount; - uint16_t nscount; - uint16_t arcount; + uint16_t id; // Packet id + uint8_t rd : 1; // Recursion Desired + uint8_t tc : 1; // TrunCation + uint8_t aa : 1; // Authoritative Answer + uint8_t opcode : 4; // Opcode + uint8_t qr : 1; // Query/Response + uint8_t rcode : 4; // Response code + uint8_t z : 3; // Zero + uint8_t ra : 1; // Recursion Available + uint16_t qdcount; // Question count + uint16_t ancount; // Answer count + uint16_t nscount; // Authority count + uint16_t arcount; // Additional count }; -PACKED_STRUCT_DEF pico_dns_query_suffix +typedef struct pico_dns_header pico_dns_packet; + +/* Question fixed-sized fields */ +PACKED_STRUCT_DEF pico_dns_question_suffix { uint16_t qtype; uint16_t qclass; }; -PACKED_STRUCT_DEF pico_dns_answer_suffix +/* Resource record fixed-sized fields */ +PACKED_STRUCT_DEF pico_dns_record_suffix { - uint16_t qtype; - uint16_t qclass; - uint32_t ttl; + uint16_t rtype; + uint16_t rclass; + uint32_t rttl; uint16_t rdlength; }; -enum pico_dns_arpa +/* DNS QUESTION */ +struct pico_dns_question { - PICO_DNS_ARPA4, - PICO_DNS_ARPA6, - PICO_DNS_NO_ARPA, + char *qname; + struct pico_dns_question_suffix *qsuffix; + uint16_t qname_length; + uint8_t proto; }; -void pico_dns_fill_header(struct pico_dns_header *hdr, uint16_t qdcount, uint16_t ancount); -uint16_t pico_dns_client_strlen(const char *url); -int pico_dns_name_to_dns_notation(char *ptr); -int pico_dns_notation_to_name(char *ptr); -void pico_dns_fill_query_suffix(struct pico_dns_query_suffix *suf, uint16_t type, uint16_t qclass); -void pico_dns_fill_rr_suffix(struct pico_dns_answer_suffix *suf, uint16_t qtype, uint16_t qclass, uint32_t ttl, uint16_t rdlength); -int8_t pico_dns_mirror_addr(char *ptr); -void pico_dns_ipv6_set_ptr(const char *ip, char *dst); +/* DNS RECORD */ +struct pico_dns_record +{ + char *rname; + struct pico_dns_record_suffix *rsuffix; + uint8_t *rdata; + uint16_t rname_length; +}; + +/* DNS QUESTION VECTOR */ +typedef struct +{ + struct pico_dns_question **questions; + uint16_t count; +} pico_dns_question_vector; + +/* DNS RECORD VECTOR */ +typedef struct +{ + struct pico_dns_record **records; + uint16_t count; +} pico_dns_record_vector; + +// MARK: DNS PACKET FUNCTIONS + +/* **************************************************************************** + * Fills the header section of a DNS packet with correct flags and section- + * counts. + * ****************************************************************************/ +void +pico_dns_fill_packet_header( struct pico_dns_header *hdr, + uint16_t qdcount, + uint16_t ancount, + uint16_t authcount, + uint16_t addcount ); + +// MARK: QUESTION FUNCTIONS + +/* **************************************************************************** + * Fills the question fixed-sized flags & fields accordingly. + * ****************************************************************************/ +void +pico_dns_question_fill_qsuffix( struct pico_dns_question_suffix *suf, + uint16_t type, + uint16_t qclass ); + +/* **************************************************************************** + * Just copies a question provided in [questio] + * ****************************************************************************/ +struct pico_dns_question * +pico_dns_question_copy( struct pico_dns_question *question ); + +/* **************************************************************************** + * Deletes & free's the memory for a certain dns resource record. Doesn't take + * lists into account so if applied to a list, most probaebly, gaps will arise. + * ****************************************************************************/ +int +pico_dns_question_delete( struct pico_dns_question **question); + +/* **************************************************************************** + * Creates a standalone DNS question for given 'url'. Fills the 'len'-argument + * with the total length of the question. + * ****************************************************************************/ +struct pico_dns_question * +pico_dns_question_create( const char *url, + uint16_t *len, + uint8_t proto, + uint16_t qtype, + uint16_t qclass, + uint8_t reverse ); + +/* **************************************************************************** + * Initialise an mDNS record vector + * ****************************************************************************/ +int +pico_dns_question_vector_init( pico_dns_question_vector *vector ); + +/* **************************************************************************** + * Returns the amount of questions contained in the DNS question vector + * ****************************************************************************/ +uint16_t +pico_dns_question_vector_count( pico_dns_question_vector *vector ); + +/* **************************************************************************** + * Adds a DNS question to a DNS question vector + * ****************************************************************************/ +int +pico_dns_question_vector_add( pico_dns_question_vector *vector, + struct pico_dns_question *question ); + +/* **************************************************************************** + * Adds a copy of a DNS question to a DNS question vector + * ****************************************************************************/ +int +pico_dns_question_vector_add_copy( pico_dns_question_vector *vector, + struct pico_dns_question *question ); + +/* **************************************************************************** + * Returns a DNS question from a DNS question vector at a certain index + * ****************************************************************************/ +struct pico_dns_question * +pico_dns_question_vector_get( pico_dns_question_vector *vector, uint16_t index); + +/* **************************************************************************** + * Removes a DNS question from a DNS question vector at a certain index + * ****************************************************************************/ +int +pico_dns_question_vector_remove( pico_dns_question_vector *vector, + uint16_t index); + +/* **************************************************************************** + * Deletes a DNS question a DNS question vector at a certain index + * ****************************************************************************/ +int +pico_dns_question_vector_delete( pico_dns_question_vector *vector, + uint16_t index); + +/* **************************************************************************** + * Deletes every DNS question from a DNS question vector + * ****************************************************************************/ +int +pico_dns_question_vector_destroy( pico_dns_question_vector *vector ); + +/* **************************************************************************** + * Finds a DNS question in a DNS question + * ****************************************************************************/ +struct pico_dns_question * +pico_dns_question_vector_find_name( pico_dns_question_vector *vector, + const char *qname ); + +/* **************************************************************************** + * Deletes a DNS question from a DNS question vector + * ****************************************************************************/ +int +pico_dns_question_vector_del_name( pico_dns_question_vector *vector, + const char *name ); + +/* **************************************************************************** + * Returns the size in bytes of all the DNS questions contained in a DNS + * question-vector. + * ****************************************************************************/ +uint16_t +pico_dns_question_vector_size( pico_dns_question_vector *vector ); + +// MARK: QUERY FUNCTIONS + +/* **************************************************************************** + * Creates a DNS packet meant for querying. Currently only questions can be + * inserted in the packet. + * ****************************************************************************/ +pico_dns_packet * +pico_dns_query_create( pico_dns_question_vector *qvector, + pico_dns_record_vector *anvector, + pico_dns_record_vector *nsvector, + pico_dns_record_vector *arvector, + uint16_t *len ); + +// MARK: RESOURCE RECORD FUNCTIONS + +/* **************************************************************************** + * Just copies a resource record provided in [record] + * ****************************************************************************/ +struct pico_dns_record * +pico_dns_record_copy( struct pico_dns_record *record ); + +/* **************************************************************************** + * Deletes & free's the memory for a certain dns resource record + * ****************************************************************************/ +int +pico_dns_record_delete( struct pico_dns_record **rr ); + +/* **************************************************************************** + * Creates a standalone DNS resource record for given 'url'. Fills the + * 'len'-argument with the total length of the record. + * ****************************************************************************/ +struct pico_dns_record * +pico_dns_record_create( const char *url, + void *_rdata, + uint16_t datalen, + uint16_t *len, + uint16_t rtype, + uint16_t rclass, + uint32_t rttl ); + +/* **************************************************************************** + * Initialise an DNS record vector + * ****************************************************************************/ +int +pico_dns_record_vector_init( pico_dns_record_vector *vector ); + +/* **************************************************************************** + * Returns the amount of records contained in the DNS record vector + * ****************************************************************************/ +uint16_t +pico_dns_record_vector_count( pico_dns_record_vector *vector ); + +/* **************************************************************************** + * Adds a DNS record to a DNS record vector + * ****************************************************************************/ +int +pico_dns_record_vector_add( pico_dns_record_vector *vector, + struct pico_dns_record *record ); + +/* **************************************************************************** + * Adds a copy of a DNS record to a DNS record vector + * ****************************************************************************/ +int +pico_dns_record_vector_add_copy( pico_dns_record_vector *vector, + struct pico_dns_record *record ); + +/* **************************************************************************** + * Returns a DNS record from a DNS record vector at a certain index + * ****************************************************************************/ +struct pico_dns_record * +pico_dns_record_vector_get( pico_dns_record_vector *vector, uint16_t index); + +/* **************************************************************************** + * Deletes a DNS record from a DNS record vector at a certain index + * ****************************************************************************/ +int +pico_dns_record_vector_delete( pico_dns_record_vector *vector, uint16_t index); + +/* **************************************************************************** + * Deletes every DNS record from a DNS record vector + * ****************************************************************************/ +int +pico_dns_record_vector_destroy( pico_dns_record_vector *vector ); + +/* **************************************************************************** + * Returns the size in bytes of all the DNS records contained in a DNS + * record-vector. + * ****************************************************************************/ +uint16_t +pico_dns_record_vector_size( pico_dns_record_vector *vector ); + +// MARK: ANSWER FUNCTIONS + +/* **************************************************************************** + * Creates a DNS Answer packet with given resource records to put in the + * Resource Record Sections. If a NULL-pointer is provided for a certain + * list, no records will be added to the packet for that section. + * ****************************************************************************/ +pico_dns_packet * +pico_dns_answer_create( pico_dns_record_vector *anvector, + pico_dns_record_vector *nsvector, + pico_dns_record_vector *arvector, + uint16_t *len ); + +// MARK: NAME & IP FUNCTIONS + +/* **************************************************************************** + * Returns the length of an FQDN in a DNS-packet as if DNS name compression + * would be applied to the packet + * ****************************************************************************/ +uint16_t pico_dns_namelen_comp( char *name ); + +/* **************************************************************************** + * Returns the length of an FQDN. If DNS name compression is applied in the + * DNS packet, this will be the length as if the compressed name would be + * decompressed. + * ****************************************************************************/ +uint16_t +pico_dns_namelen_uncomp( char *name, pico_dns_packet *packet ); + +/* **************************************************************************** + * Returns the uncompressed FQDN when DNS name compression is applied in the + * DNS packet. + * ****************************************************************************/ +char * +pico_dns_decompress_name( char *name, pico_dns_packet *packet ); + +/* **************************************************************************** + * Create an URL in *[url_addr] from any qname given in [qname]. [url_addr] + * needs to be an addres to a NULL-pointer. Returns a string + * 1 byte smaller in size than [qname] or 2 bytes smaller than the + * string-length. Use PICO_FREE() to deallocate the memory for this pointer. + * + * f.e. * 4tass5local0 -> tass.local + * * 11112102107in-addr4arpa0 -> 1.1.10.10.in-addr.arpa + * ****************************************************************************/ +char * +pico_dns_qname_to_url( const char *qname ); + +/* **************************************************************************** + * Create a qname in *[qname_addr] from any url given in [url]. [qname_addr] + * needs to be an address to a NULL-pointer. Returns a string + * 1 byte larger in size than [url] or 2 bytes larger than the + * string-length. use PICO_FREE() to deallocate the memory for this pointer. + * + * f.e. - tass.local -> 4tass5local0 + * - 1.1.10.10.in-addr.arpa -> 11112102107in-addr4arpa0 + * ****************************************************************************/ +char * +pico_dns_url_to_qname( const char *url ); + +/* **************************************************************************** + * Determines the length of a string + * ****************************************************************************/ +uint16_t +pico_dns_client_strlen( const char *url ); + +/* **************************************************************************** + * Converts a URL at location url + 1 to a FQDN in the form 3www6google3com0 + * f.e. www.google.be => 3www6google2be0 + * Size of ptr[] has to +2u more than the URL itself. + * ****************************************************************************/ +int +pico_dns_name_to_dns_notation( char *url ); + +/* **************************************************************************** + * Converts a FQDN at location fqdn to an URL in the form .www.google.com + * f.e. 3www6google2be0 => .www.google.be + * ****************************************************************************/ +int +pico_dns_notation_to_name( char *fqdn ); + +/* **************************************************************************** + * Mirrors and IP-address in ptr to an ARPA-format + * f.e. 192.168.0.1 => 1.0.168.192 + * ****************************************************************************/ +int8_t +pico_dns_mirror_addr( char *ptr ); + +/* **************************************************************************** + * + * ****************************************************************************/ +void +pico_dns_ipv6_set_ptr( const char *ip, char *dst ); #endif /* _INCLUDE_PICO_DNS_COMMON */ diff --git a/modules/pico_dns_sd.c b/modules/pico_dns_sd.c new file mode 100644 index 000000000..33ae4b751 --- /dev/null +++ b/modules/pico_dns_sd.c @@ -0,0 +1,650 @@ +/********************************************************************* + PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. + See LICENSE and COPYING for usage. + . + Author: Jelle De Vleeschouwer + *********************************************************************/ + +#include "pico_dns_sd.h" + +/* --- Debugging --- */ +#define DEBUG 1 + +#if DEBUG == 0 +#define dns_sd_dbg(...) do {} while(0) +#else +#define dns_sd_dbg dbg +#endif + +/* --- PROTOTYPES --- */ +key_value_pair_t * +pico_dns_sd_kv_vector_get( kv_vector *vector, uint16_t index ); +int +pico_dns_sd_kv_vector_erase( kv_vector *vector ); +/* ------------------- */ + +typedef PACKED_STRUCT_DEF pico_dns_srv_record_prefix +{ + uint16_t priority; + uint16_t weight; + uint16_t port; +} pico_dns_srv_record; + +struct register_argument { + struct pico_mdns_record *ptr_record; + void (*callback)(pico_mdns_record_vector *, + char *, + void *); + void *arg; +}; + +/* **************************************************************************** + * Determines resulting string length of a key-value pair vector + * ****************************************************************************/ +static uint16_t +pico_dns_sd_kv_vector_strlen( kv_vector *vector ) +{ + key_value_pair_t *iterator = NULL; + uint16_t i = 0, len = 0; + + /* Check params */ + if (!vector) { + pico_err = PICO_ERR_EINVAL; + return 0; + } + + /* Iterate over the key-value pairs */ + for (i = 0; i < vector->count; i++) { + iterator = pico_dns_sd_kv_vector_get(vector, i); + len = (uint16_t) (len + 1u /* Length byte */ + + strlen(iterator->key) /* Length of the key */); + if (iterator->value) + len = (uint16_t) (len + 1u /* '=' char */ + + strlen(iterator->value) /* Lenght of value */); + } + + return len; +} + +/* **************************************************************************** + * Creates an mDNS record with the SRV record format + * ****************************************************************************/ +static struct pico_mdns_record * +pico_dns_sd_srv_record_create( const char *url, + uint16_t priority, + uint16_t weight, + uint16_t port, + const char *target_url, + uint32_t ttl, + uint8_t flags ) +{ + struct pico_mdns_record *record = NULL; + pico_dns_srv_record *srv_data = NULL; + char *target_rname = NULL; + uint16_t srv_length = 0; + + /* Check params */ + if (!url || !target_url) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + /* Determine the length the rdata buf needs to be */ + srv_length = (uint16_t) (6u + strlen(target_url) + 2u); + + /* Provide space for the data-buf */ + srv_data = (pico_dns_srv_record *) PICO_ZALLOC(srv_length); + if (!srv_data) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + + /* TODO: Check for Endianess */ + srv_data->priority = short_be(priority); + srv_data->weight = short_be(weight); + srv_data->port = short_be(port); + + /* Copy in the URL and convert to DNS notation */ + target_rname = pico_dns_url_to_qname(target_url); + if (!target_rname) { + dns_sd_dbg("Could not convert URL to qname!\n"); + PICO_FREE(srv_data); + return NULL; + } + strcpy((char *)srv_data + 6u, target_rname); + PICO_FREE(target_rname); + + /* Create and return new mDNS record */ + record = pico_mdns_record_create(url, srv_data, srv_length, + PICO_DNS_TYPE_SRV, + ttl, flags); + PICO_FREE(srv_data); + + return record; +} + +/* **************************************************************************** + * Creates an mDNS record with the TXT record format + * ****************************************************************************/ +static struct pico_mdns_record * +pico_dns_sd_txt_record_create( const char *url, + kv_vector key_value_pairs, + uint32_t ttl, + uint8_t flags ) +{ + struct pico_mdns_record *record = NULL; + key_value_pair_t *iterator = NULL; + char *txt = NULL; + uint16_t i = 0, txt_i = 0, pair_len = 0, key_len = 0, value_len = 0; + + /* Determine the length of the string to fit in all pairs */ + uint16_t len = pico_dns_sd_kv_vector_strlen(&key_value_pairs); + + /* Provide space for the txt buf */ + txt = (char *)PICO_ZALLOC(len); + if (!txt) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + + /* Iterate over all the key-value pairs */ + for (i = 0; i < key_value_pairs.count; i++) { + iterator = pico_dns_sd_kv_vector_get(&key_value_pairs, i); + + /* Determine the length of the key */ + key_len = (uint16_t) strlen(iterator->key); + pair_len = key_len; + + /* If value is not a NULL-ptr */ + if (iterator->value) { + value_len = (uint16_t) strlen(iterator->value); + pair_len = (uint16_t) (pair_len + 1u + value_len); + } + + /* Set the pair length label */ + txt[txt_i] = (char)pair_len; + + /* Copy the key */ + strcpy(txt + txt_i + 1u, iterator->key); + + /* Copy the value if it is not a NULL-ptr */ + if (iterator->value) { + strcpy(txt + txt_i + 1u + key_len, "="); + strcpy(txt + txt_i + 2u + key_len, iterator->value); + txt_i = (uint16_t) (txt_i + 2u + key_len + value_len); + } else { + txt_i = (uint16_t) (txt_i + 1u + key_len); + } + } + + record = pico_mdns_record_create(url, txt, len, PICO_DNS_TYPE_TXT, + ttl, flags); + PICO_FREE(txt); + + return record; +} + +/* **************************************************************************** + * Creates a single key-value pair struct + * ****************************************************************************/ +static key_value_pair_t * +pico_dns_sd_kv_create( const char *key, const char *value ) +{ + key_value_pair_t *kv_pair = NULL; + + /* Chekc params */ + if (!key) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + /* Provide space for the new pair */ + kv_pair = (key_value_pair_t *)PICO_ZALLOC(sizeof(key_value_pair_t)); + if (!kv_pair) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + + /* Provide space to copy the values */ + kv_pair->key = (char *)PICO_ZALLOC((size_t)(strlen(key) + 1)); + if (!(kv_pair->key)) { + pico_err = PICO_ERR_ENOMEM; + PICO_FREE(kv_pair); + return NULL; + } + strcpy(kv_pair->key, key); + + if (!value) + kv_pair->value = NULL; + else { + kv_pair->value = (char *)PICO_ZALLOC((size_t)(strlen(value) + 1)); + if (!(kv_pair->value)) { + pico_err = PICO_ERR_ENOMEM; + PICO_FREE(kv_pair->key); + PICO_FREE(kv_pair); + return NULL; + } + strcpy(kv_pair->value, value); + } + + return kv_pair; +} + +/* **************************************************************************** + * Deletes a single key-value pair struct + * ****************************************************************************/ +static int +pico_dns_sd_kv_delete( key_value_pair_t **kv_pair ) +{ + /* Check params */ + if (!kv_pair || !(*kv_pair)) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Delete the fields */ + if ((*kv_pair)->key) + PICO_FREE((*kv_pair)->key); + if ((*kv_pair)->value) + PICO_FREE((*kv_pair)->value); + + PICO_FREE(*kv_pair); + *kv_pair = NULL; + kv_pair = NULL; + + return 0; +} + +/* **************************************************************************** + * Returns the length of the first label in an URL + * ****************************************************************************/ +static uint16_t +pico_dns_sd_first_label_length( const char *url ) +{ + const char *i = NULL; + uint16_t len = 0; + + if (!url) + return 0; + + i = url; + while (*i != '.' && *i != '\0') { + ++i; + ++len; + } + + return len; +} + +/* **************************************************************************** + * Returns 0 when the type is correctly formatted and it's label lengths are + * in the allowed boundaries + * ****************************************************************************/ +static int +pico_dns_sd_check_type_format( const char *type ) +{ + uint16_t first_lbl_length = 0; + + /* Check params */ + if (!type) + return -1; + + /* Then check if the first label is larger than 17 bytes */ + first_lbl_length = pico_dns_sd_first_label_length(type); + + /* Check if there is a subtype present */ + if (memcmp(type + first_lbl_length + 1, "_sub", 4) == 0) { + /* Check the subtype's length */ + if (first_lbl_length > 63) + return -1; + + /* Get the length of the service name */ + first_lbl_length = pico_dns_sd_first_label_length(type + + first_lbl_length + 6); + } else { + /* Check if type is not greater then 21 bytes (22 - 1, since the length + byte of the service name isn't included yet) */ + if (strlen(type) > (size_t) 21) + return -1; + } + + /* Check if the service name is not greater then 16 bytes (17 - 1) */ + if (first_lbl_length > (uint16_t) 16u) + return -1; + + return 0; +} + +/* **************************************************************************** + * Returns 0 when the instance name is of the correct length + * ****************************************************************************/ +static int +pico_dns_sd_check_instance_name_format( const char *name ) +{ + /* First of all check if the total length is larger than 63 bytes */ + if (strlen(name) > 63) + return -1; + return 0; +} + +/* **************************************************************************** + * Append the instance name and service type to create a .local service url. + * ****************************************************************************/ +static char * +pico_dns_sd_create_service_url( const char *name, + const char *type ) +{ + char *url = NULL; + uint16_t len = 0, namelen = 0, typelen = 0; + + /* Check params */ + if (!name || !type) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + if (pico_dns_sd_check_type_format(type)) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + if (pico_dns_sd_check_instance_name_format(name)) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + namelen = (uint16_t)strlen(name); + typelen = (uint16_t)strlen(type); + + /* Determine the length that the URL needs to be */ + len = (uint16_t)(namelen + 1u /* for '.'*/ + + typelen + 7u /* for '.local\0' */ ); + url = (char *)PICO_ZALLOC(len); + if (!url) { + pico_err = PICO_ERR_ENOMEM; + return NULL; + } + + /* Append the parts together */ + strcpy(url, name); + strcpy(url + namelen, "."); + strcpy(url + namelen + 1, type); + strcpy(url + namelen + 1 + typelen, ".local"); + + return url; +} + +static void +pico_dns_sd_claimed_callback( pico_mdns_record_vector *records, + char *str, + void *arg ) +{ + pico_mdns_record_vector rvector = {0}; + struct pico_mdns_record *record = NULL; + struct register_argument *arguments = NULL; + struct pico_mdns_record *ptr_record = NULL; + char *rname = NULL; + + IGNORE_PARAMETER(str); + + /* Parse in the PTR record */ + if (!arg || !records) { + pico_err = PICO_ERR_EINVAL; + return; + } + arguments = (struct register_argument *)arg; + ptr_record = arguments->ptr_record; + + /* Get the rname of the claimed records */ + if (!(record = pico_mdns_record_vector_get(records, 0))) { + dns_sd_dbg("Error occured with claiming!\n"); + return; + } + rname = record->record->rname; + if (strcmp(rname, (char*)(ptr_record->record->rdata)) != 0) { + /* Update rdata */ + PICO_FREE(ptr_record->record->rdata); + ptr_record->record->rdata = NULL; + + /* Provide space for the updated name */ + ptr_record->record->rdata = (uint8_t *)PICO_ZALLOC(strlen(rname) + 1); + if (!(ptr_record->record->rdata)) { + pico_err = PICO_ERR_ENOMEM; + pico_mdns_record_delete(&ptr_record); + return; + } + /* Copy in the the updated name */ + strcpy((char *)(ptr_record->record->rdata), rname); + /* Update rdlength */ + ptr_record->record->rsuffix->rdlength = short_be((uint16_t) + (strlen(rname) + 1u)); + } + + /* Claim the PTR record */ + pico_mdns_record_vector_add(&rvector, ptr_record); + if (pico_mdns_claim(rvector, arguments->callback, arguments->arg) < 0) { + dns_sd_dbg("Trying to claim PTR record failed!\n"); + pico_mdns_record_vector_destroy(&rvector); + } + + PICO_FREE(arguments); +} + +/* **************************************************************************** + * This function actually does exactly the same as pico_mdns_init(); + * ****************************************************************************/ +int +pico_dns_sd_init( const char *_hostname, + struct pico_ipv4_link *link, + uint8_t flags, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ) +{ + return pico_mdns_init(_hostname, link, flags, callback, arg); +} + +/* **************************************************************************** + * Register a service on in the '.local'-domain of a certain type. Port number + * Needs to be provided and can't be 0. + * ****************************************************************************/ +int +pico_dns_sd_register_service( const char *name, + const char *type, + uint16_t port, + kv_vector *txt_data, + uint16_t ttl, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg) +{ + pico_mdns_record_vector rvector = {0}; + struct pico_mdns_record *srv_record = NULL; + struct pico_mdns_record *txt_record = NULL; + struct pico_mdns_record *ptr_record = NULL; + struct register_argument *arguments = NULL; + const char *hostname = pico_mdns_get_hostname(); + + /* Try to create a service URL to create records with */ + char *url = pico_dns_sd_create_service_url(name, type); + if (!url) { + dns_sd_dbg("Could not create service URL!\n"); + return -1; + } + + /* Check other params */ + if (!txt_data) { + dns_sd_dbg("No key-value pair vector passed!\n"); + PICO_FREE(url); + return -1; + } + + dns_sd_dbg("Target: %s\n", hostname); + + /* Create the SRV record */ + srv_record = pico_dns_sd_srv_record_create(url, 0, 0, port, hostname, + ttl, PICO_MDNS_RECORD_UNIQUE); + /* Create the TXT record */ + txt_record = pico_dns_sd_txt_record_create(url, *txt_data, ttl, + PICO_MDNS_RECORD_UNIQUE); + + /* Erase the key-value pair vector, it's no longer needed */ + if (pico_dns_sd_kv_vector_erase(txt_data) < 0) { + dns_sd_dbg("Could not erase key-value pair vector!\n"); + PICO_FREE(url); + return -1; + } + + /* Create the shared PTR record */ + ptr_record = pico_mdns_record_create((char *)(url + strlen(name) + 1u), + (void *)url, (uint16_t)strlen(url), + PICO_DNS_TYPE_PTR, + ttl, PICO_MDNS_RECORD_SHARED); + PICO_FREE(url); + + pico_mdns_record_vector_add(&rvector, srv_record); + pico_mdns_record_vector_add(&rvector, txt_record); + + /* Provide space for argument struct */ + arguments = PICO_ZALLOC(sizeof(struct register_argument)); + if (!arguments) { + pico_err = PICO_ERR_ENOMEM; + return -1; + } + + arguments->ptr_record = ptr_record; + arguments->callback = callback; + arguments->arg = arg; + + if (pico_mdns_claim(rvector, pico_dns_sd_claimed_callback, + (void *)arguments) < 0) { + dns_sd_dbg("Trying to claim SRV and TXT records failed!\n"); + return -1; + } + + return 0; +} + +/* **************************************************************************** + * Browse for a service of a certain type on the '.local' domain. Calls + * callback when any changes happen to found service, as in as they come and + * go. + * + * MARK: Probably this function will be updated in the near future. + * ****************************************************************************/ +int +pico_dns_sd_browse_service( const char *type, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ) +{ + /* TODO: (Implement this) */ + IGNORE_PARAMETER(type); + IGNORE_PARAMETER(callback); + IGNORE_PARAMETER(arg); + return 0; +} + +/* **************************************************************************** + * Initialise a key-value pair vector + * ****************************************************************************/ +int +pico_dns_sd_kv_vector_init( kv_vector *vector ) +{ + /* Check params */ + if (!vector) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + vector->pairs = NULL; + vector->count = 0; + return 0; +} + +/* **************************************************************************** + * Add a key-value pair to the key-value pair vector + * ****************************************************************************/ +int +pico_dns_sd_kv_vector_add( kv_vector *vector, char *key, char *value ) +{ + key_value_pair_t *kv_pair = NULL; + key_value_pair_t **new_pairs = NULL; + uint16_t i = 0; + + /* Check params */ + if (!vector || !key) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Try to create a new key value pair */ + kv_pair = pico_dns_sd_kv_create(key, value); + if (!kv_pair) + return -1; + + /* Provide enough space for the new pair pointers */ + new_pairs = PICO_ZALLOC(sizeof(key_value_pair_t *) * + (vector->count +1u)); + if (!new_pairs) { + pico_err = PICO_ERR_ENOMEM; + pico_dns_sd_kv_delete(&kv_pair); + return -1; + } + + /* Copy previous pairs and add new one */ + for (i = 0; i < vector->count; i++) + new_pairs[i] = vector->pairs[i]; + new_pairs[i] = kv_pair; + + /* Free the previous array */ + if (vector->pairs) + PICO_FREE(vector->pairs); + + vector->pairs = new_pairs; + vector->count++; + + return 0; +} + +/* **************************************************************************** + * Gets a key-value pair from the key-value pair vector + * ****************************************************************************/ +key_value_pair_t * +pico_dns_sd_kv_vector_get( kv_vector *vector, uint16_t index ) +{ + /* Check params */ + if (!vector) + return NULL; + + /* Return record with conditioned index */ + if (index < vector->count) + return vector->pairs[index]; + + return NULL; +} + +/* **************************************************************************** + * Erase all the contents of a key + * ****************************************************************************/ +int +pico_dns_sd_kv_vector_erase( kv_vector *vector ) +{ + uint16_t i = 0; + + /* Iterate over each key-value pair */ + for (i = 0; i < vector->count; i++) { + if (pico_dns_sd_kv_delete(&(vector->pairs[i])) < 0) { + dns_sd_dbg("Could not delete key-value pairs from vector"); + return -1; + } + } + + vector->pairs = NULL; + vector->count = 0; + + return 0; +} \ No newline at end of file diff --git a/modules/pico_dns_sd.h b/modules/pico_dns_sd.h new file mode 100644 index 000000000..e2b8bbf08 --- /dev/null +++ b/modules/pico_dns_sd.h @@ -0,0 +1,79 @@ +/* **************************************************************************** + * PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved. + * See LICENSE and COPYING for usage. + * . + * Author: Jelle De Vleeschouwer + * ****************************************************************************/ +#ifndef INCLUDE_PICO_DNS_SD +#define INCLUDE_PICO_DNS_SD + +#include "pico_mdns.h" + +typedef struct +{ + char *key; + char *value; +} key_value_pair_t; + +typedef struct +{ + key_value_pair_t **pairs; + uint16_t count; +} kv_vector; + +/* **************************************************************************** + * This function actually does exactly the same as pico_mdns_init(); + * ****************************************************************************/ +int +pico_dns_sd_init( const char *_hostname, + struct pico_ipv4_link *link, + uint8_t flags, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ); + +/* **************************************************************************** + * Register a service on in the '.local'-domain of a certain type. Port number + * Needs to be provided and can't be 0. The key-value pair vector passed in + * will be erased so you can no longer use it after registering the service. + * ****************************************************************************/ +int +pico_dns_sd_register_service( const char *name, + const char *type, + uint16_t port, + kv_vector *txt_data, + uint16_t ttl, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ); + +/* **************************************************************************** + * Browse for a service of a certain type on the '.local' domain. Calls + * callback when any changes happen to found service, as in as they come and + * go. + * + * MARK: Probably this function will be updated in the near future. + * ****************************************************************************/ +int +pico_dns_sd_browse_service( const char *type, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ); + +/* **************************************************************************** + * Initialise a key-value pair vector + * ****************************************************************************/ +int +pico_dns_sd_kv_vector_init( kv_vector *vector ); + +/* **************************************************************************** + * Add a key-value pair to the key-value pair vector + * ****************************************************************************/ +int +pico_dns_sd_kv_vector_add( kv_vector *vector, char *key, char *value ); + + +#endif /* _INCLUDE_PICO_DNS_SD */ diff --git a/modules/pico_icmp4.c b/modules/pico_icmp4.c index 3c2b9ccdd..0cd7f585c 100644 --- a/modules/pico_icmp4.c +++ b/modules/pico_icmp4.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -47,9 +47,6 @@ static void ping_recv_reply(struct pico_frame *f); static int pico_icmp4_process_in(struct pico_protocol *self, struct pico_frame *f) { struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr; - static int firstpkt = 1; - static uint16_t last_id = 0; - static uint16_t last_seq = 0; IGNORE_PARAMETER(self); if (hdr->type == PICO_ICMP_ECHO) { @@ -58,15 +55,6 @@ static int pico_icmp4_process_in(struct pico_protocol *self, struct pico_frame * if (f->dev && f->dev->eth) f->len -= PICO_SIZE_ETHHDR; - if (!firstpkt && (hdr->hun.ih_idseq.idseq_id == last_id) && (last_seq == hdr->hun.ih_idseq.idseq_seq)) { - /* The network duplicated the echo. Do not reply. */ - pico_frame_discard(f); - return 0; - } - - firstpkt = 0; - last_id = hdr->hun.ih_idseq.idseq_id; - last_seq = hdr->hun.ih_idseq.idseq_seq; pico_icmp4_checksum(f); pico_ipv4_rebound(f); } else if (hdr->type == PICO_ICMP_UNREACH) { diff --git a/modules/pico_icmp4.h b/modules/pico_icmp4.h index 90dd6f4a3..f125986cd 100644 --- a/modules/pico_icmp4.h +++ b/modules/pico_icmp4.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . diff --git a/modules/pico_icmp6.c b/modules/pico_icmp6.c index 2c84c2460..a0c8bf3a2 100644 --- a/modules/pico_icmp6.c +++ b/modules/pico_icmp6.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -44,40 +44,6 @@ uint16_t pico_icmp6_checksum(struct pico_frame *f) static void pico_icmp6_ping_recv_reply(struct pico_frame *f); #endif -static int pico_icmp6_send_echoreply(struct pico_frame *echo) -{ - struct pico_frame *reply = NULL; - struct pico_icmp6_hdr *ehdr = NULL, *rhdr = NULL; - struct pico_ip6 src; - struct pico_ip6 dst; - - reply = pico_proto_ipv6.alloc(&pico_proto_ipv6, (uint16_t)(echo->transport_len)); - if (!reply) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE; - reply->payload = reply->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE; - reply->payload_len = echo->transport_len; - reply->dev = echo->dev; - - ehdr = (struct pico_icmp6_hdr *)echo->transport_hdr; - rhdr = (struct pico_icmp6_hdr *)reply->transport_hdr; - rhdr->type = PICO_ICMP6_ECHO_REPLY; - rhdr->code = 0; - rhdr->msg.info.echo_reply.id = ehdr->msg.info.echo_reply.id; - rhdr->msg.info.echo_reply.seq = ehdr->msg.info.echo_request.seq; - memcpy(reply->payload, echo->payload, (uint32_t)(echo->transport_len - PICO_ICMP6HDR_ECHO_REQUEST_SIZE)); - rhdr->crc = 0; - rhdr->crc = short_be(pico_icmp6_checksum(reply)); - /* Get destination and source swapped */ - memcpy(dst.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, PICO_SIZE_IP6); - memcpy(src.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->dst.addr, PICO_SIZE_IP6); - pico_ipv6_frame_push(reply, &src, &dst, PICO_PROTO_ICMP6, 0); - return 0; -} - static int pico_icmp6_process_in(struct pico_protocol *self, struct pico_frame *f) { struct pico_icmp6_hdr *hdr = (struct pico_icmp6_hdr *)f->transport_hdr; @@ -94,9 +60,23 @@ static int pico_icmp6_process_in(struct pico_protocol *self, struct pico_frame * case PICO_ICMP6_ECHO_REQUEST: icmp6_dbg("ICMP6: Received ECHO REQ\n"); - f->transport_len = (uint16_t)(f->len - f->net_len - (uint16_t)(f->net_hdr - f->buffer)); - pico_icmp6_send_echoreply(f); - pico_frame_discard(f); + hdr->type = PICO_ICMP6_ECHO_REPLY; + /* XXX these pointers and len should already be set correctly in pico_ipv6_process_in */ + /* Ugly, but the best way to get ICMP data size here. */ + f->transport_len = (uint16_t)(f->buffer_len - PICO_SIZE_IP6HDR); + if (f->dev->eth) + f->transport_len = (uint16_t)(f->transport_len - PICO_SIZE_ETHHDR); + + hdr->crc = 0; + hdr->crc = short_be(pico_icmp6_checksum(f)); + + f->net_hdr = f->transport_hdr - PICO_SIZE_IP6HDR; + f->start = f->net_hdr; + f->len = f->buffer_len; + if (f->dev->eth) + f->len -= PICO_SIZE_ETHHDR; + + pico_ipv6_rebound(f); break; case PICO_ICMP6_ECHO_REPLY: @@ -194,6 +174,7 @@ static int pico_icmp6_notify(struct pico_frame *f, uint8_t type, uint8_t code, u icmp6_hdr->msg.err.param_problem.ptr = long_be(ptr); break; + default: return -1; } @@ -201,55 +182,34 @@ static int pico_icmp6_notify(struct pico_frame *f, uint8_t type, uint8_t code, u icmp6_hdr->type = type; icmp6_hdr->code = code; memcpy(notice->payload, f->net_hdr, notice->payload_len); - notice->dev = f->dev; /* f->src is set in frame_push, checksum calculated there */ - pico_ipv6_frame_push(notice, NULL, &ipv6_hdr->src, PICO_PROTO_ICMP6, 0); + pico_ipv6_frame_push(notice, &ipv6_hdr->src, PICO_PROTO_ICMP6); return 0; } int pico_icmp6_port_unreachable(struct pico_frame *f) { - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - return pico_icmp6_notify(f, PICO_ICMP6_DEST_UNREACH, PICO_ICMP6_UNREACH_PORT, 0); } int pico_icmp6_proto_unreachable(struct pico_frame *f) { - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - return pico_icmp6_notify(f, PICO_ICMP6_DEST_UNREACH, PICO_ICMP6_UNREACH_ADDR, 0); } int pico_icmp6_dest_unreachable(struct pico_frame *f) { - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - return pico_icmp6_notify(f, PICO_ICMP6_DEST_UNREACH, PICO_ICMP6_UNREACH_ADDR, 0); } int pico_icmp6_ttl_expired(struct pico_frame *f) { - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - return pico_icmp6_notify(f, PICO_ICMP6_TIME_EXCEEDED, PICO_ICMP6_TIMXCEED_INTRANS, 0); } int pico_icmp6_pkt_too_big(struct pico_frame *f) { - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - - return pico_icmp6_notify(f, PICO_ICMP6_PKT_TOO_BIG, 0, 0); + return pico_icmp6_notify(f, PICO_ICMP6_PKT_TOO_BIG, 0, 0); } #ifdef PICO_SUPPORT_IPFILTER @@ -264,15 +224,6 @@ int pico_icmp6_parameter_problem(struct pico_frame *f, uint8_t problem, uint32_t return pico_icmp6_notify(f, PICO_ICMP6_PARAM_PROBLEM, problem, ptr); } -int pico_icmp6_frag_expired(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if (pico_ipv6_is_multicast(hdr->dst.addr)) - return 0; - - return pico_icmp6_notify(f, PICO_ICMP6_TIME_EXCEEDED, PICO_ICMP6_TIMXCEED_REASS, 0); -} - /* RFC 4861 $7.2.2: sending neighbor solicitations */ int pico_icmp6_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *dst, uint8_t type) { @@ -319,11 +270,10 @@ int pico_icmp6_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *d } else { daddr = *dst; } - sol->dev = dev; /* f->src is set in frame_push, checksum calculated there */ - pico_ipv6_frame_push(sol, NULL, &daddr, PICO_PROTO_ICMP6, (type == PICO_ICMP6_ND_DAD)); + pico_ipv6_frame_push(sol, &daddr, PICO_PROTO_ICMP6); return 0; } @@ -376,7 +326,7 @@ int pico_icmp6_neighbor_advertisement(struct pico_frame *f, struct pico_ip6 *tar adv->dev = f->dev; /* f->src is set in frame_push, checksum calculated there */ - pico_ipv6_frame_push(adv, NULL, &dst, PICO_PROTO_ICMP6, 0); + pico_ipv6_frame_push(adv, &dst, PICO_PROTO_ICMP6); return 0; } @@ -412,11 +362,10 @@ int pico_icmp6_router_solicitation(struct pico_device *dev, struct pico_ip6 *src lladdr->len = 1; memcpy(lladdr->addr.mac.addr, dev->eth->mac.addr, PICO_SIZE_ETH); } - sol->dev = dev; /* f->src is set in frame_push, checksum calculated there */ - pico_ipv6_frame_push(sol, NULL, &daddr, PICO_PROTO_ICMP6, 0); + pico_ipv6_frame_push(sol, &daddr, PICO_PROTO_ICMP6); return 0; } @@ -471,7 +420,7 @@ int pico_icmp6_router_advertisement(struct pico_device *dev, struct pico_ip6 *ds icmp6_hdr->crc = 0; icmp6_hdr->crc = short_be(pico_icmp6_checksum(adv)); /* f->src is set in frame_push, checksum calculated there */ - pico_ipv6_frame_push(adv, NULL, &dst_mcast, PICO_PROTO_ICMP6, 0); + pico_ipv6_frame_push(adv, &dst_mcast, PICO_PROTO_ICMP6); return 0; } @@ -491,7 +440,6 @@ struct pico_icmp6_ping_cookie int timeout; pico_time timestamp; struct pico_ip6 dst; - struct pico_device *dev; void (*cb)(struct pico_icmp6_stats*); }; @@ -530,12 +478,10 @@ static int pico_icmp6_send_echo(struct pico_icmp6_ping_cookie *cookie) /* XXX: Fill payload */ hdr->crc = 0; hdr->crc = short_be(pico_icmp6_checksum(echo)); - echo->dev = cookie->dev; - pico_ipv6_frame_push(echo, NULL, &cookie->dst, PICO_PROTO_ICMP6, 0); + pico_ipv6_frame_push(echo, &cookie->dst, PICO_PROTO_ICMP6); return 0; } - static void pico_icmp6_ping_timeout(pico_time now, void *arg) { struct pico_icmp6_ping_cookie *cookie = NULL; @@ -631,7 +577,7 @@ static void pico_icmp6_ping_recv_reply(struct pico_frame *f) } } -int pico_icmp6_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp6_stats *), struct pico_device *dev) +int pico_icmp6_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp6_stats *)) { static uint16_t next_id = 0x91c0; struct pico_icmp6_ping_cookie *cookie = NULL; @@ -661,7 +607,6 @@ int pico_icmp6_ping(char *dst, int count, int interval, int timeout, int size, v cookie->timeout = timeout; cookie->cb = cb; cookie->count = count; - cookie->dev = dev; pico_tree_insert(&IPV6Pings, cookie); pico_icmp6_send_ping(cookie); diff --git a/modules/pico_icmp6.h b/modules/pico_icmp6.h index 90e82235c..37de5acb3 100644 --- a/modules/pico_icmp6.h +++ b/modules/pico_icmp6.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -61,7 +61,7 @@ #define PICO_PING6_ERR_PENDING 0xFFFF /* ND configuration */ -#define PICO_ND_MAX_FRAMES_QUEUED 4 /* max frames queued while awaiting address resolution */ +#define PICO_ND_MAX_FRAMES_QUEUED 3 /* max frames queued while awaiting address resolution */ /* ND RFC constants */ #define PICO_ND_MAX_SOLICIT 3 @@ -86,7 +86,7 @@ #define IS_OVERRIDE(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_OVERRIDE)) /* override flag set? */ #define PICO_ND_PREFIX_LIFETIME_INF 0xFFFFFFFFu -/* #define PICO_ND_DESTINATION_LRU_TIME 600000u / * msecs (10min) * / */ +#define PICO_ND_DESTINATION_LRU_TIME 600000u /* msecs (10min) */ /* custom defines */ #define PICO_ICMP6_ND_UNICAST 0 @@ -237,7 +237,7 @@ struct pico_icmp6_stats struct pico_ip6 dst; }; -int pico_icmp6_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp6_stats *), struct pico_device *dev); +int pico_icmp6_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp6_stats *)); int pico_icmp6_ping_abort(int id); int pico_icmp6_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *dst, uint8_t type); @@ -251,7 +251,6 @@ int pico_icmp6_ttl_expired(struct pico_frame *f); int pico_icmp6_packet_filtered(struct pico_frame *f); int pico_icmp6_parameter_problem(struct pico_frame *f, uint8_t problem, uint32_t ptr); int pico_icmp6_pkt_too_big(struct pico_frame *f); -int pico_icmp6_frag_expired(struct pico_frame *f); uint16_t pico_icmp6_checksum(struct pico_frame *f); int pico_icmp6_router_advertisement(struct pico_device *dev, struct pico_ip6 *dst); diff --git a/modules/pico_igmp.c b/modules/pico_igmp.c index 0316f992d..cf588eba8 100644 --- a/modules/pico_igmp.c +++ b/modules/pico_igmp.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. RFC 1112, 2236, 3376, 3569, 3678, 4607 @@ -19,7 +19,7 @@ #include "pico_socket.h" #define igmp_dbg(...) do {} while(0) -/* #define igmp_dbg dbg */ +//#define igmp_dbg dbg /* membership states */ #define IGMP_STATE_NON_MEMBER (0x0) diff --git a/modules/pico_igmp.h b/modules/pico_igmp.h index 03d610259..576210184 100644 --- a/modules/pico_igmp.h +++ b/modules/pico_igmp.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . diff --git a/modules/pico_ipfilter.c b/modules/pico_ipfilter.c index 906251000..460eca2e4 100644 --- a/modules/pico_ipfilter.c +++ b/modules/pico_ipfilter.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Andrei Carp diff --git a/modules/pico_ipfilter.h b/modules/pico_ipfilter.h index fb92e6791..d85c1fb17 100644 --- a/modules/pico_ipfilter.h +++ b/modules/pico_ipfilter.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Simon Maes diff --git a/modules/pico_ipv4.c b/modules/pico_ipv4.c index 6577f6075..77b7f1962 100644 --- a/modules/pico_ipv4.c +++ b/modules/pico_ipv4.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Daniele Lacamera, Markian Yskout @@ -19,7 +19,6 @@ #include "pico_nat.h" #include "pico_igmp.h" #include "pico_tree.h" -#include "pico_aodv.h" #include "pico_socket_multicast.h" #ifdef PICO_SUPPORT_IPV4 @@ -72,18 +71,18 @@ int pico_ipv4_to_string(char *ipbuf, const uint32_t ip) for(i = 0; i < 4; i++) { - if (addr[i] > 99) { + if(addr[i] > 99) { *ipbuf++ = (char)('0' + (addr[i] / 100)); *ipbuf++ = (char)('0' + ((addr[i] % 100) / 10)); *ipbuf++ = (char)('0' + ((addr[i] % 100) % 10)); - } else if (addr[i] > 9) { + }else if(addr[i] > 9) { *ipbuf++ = (char)('0' + (addr[i] / 10)); *ipbuf++ = (char)('0' + (addr[i] % 10)); - } else { + }else{ *ipbuf++ = (char)('0' + addr[i]); } - if (i < 3) + if(i < 3) *ipbuf++ = '.'; } *ipbuf = '\0'; @@ -94,7 +93,7 @@ int pico_ipv4_to_string(char *ipbuf, const uint32_t ip) static int pico_string_check_null_args(const char *ipstr, uint32_t *ip) { - if (!ipstr || !ip) { + if(!ipstr || !ip) { pico_err = PICO_ERR_EINVAL; return -1; } @@ -105,7 +104,7 @@ static int pico_string_check_null_args(const char *ipstr, uint32_t *ip) int pico_string_to_ipv4(const char *ipstr, uint32_t *ip) { - unsigned char buf[PICO_SIZE_IP4] = { + unsigned char buf[4] = { 0 }; int cnt = 0; @@ -114,25 +113,26 @@ int pico_string_to_ipv4(const char *ipstr, uint32_t *ip) if (pico_string_check_null_args(ipstr, ip) < 0) return -1; - while((p = *ipstr++) != 0 && cnt < PICO_SIZE_IP4) + + while((p = *ipstr++) != 0) { - if (pico_is_digit(p)) { + if(pico_is_digit(p)) { buf[cnt] = (uint8_t)((10 * buf[cnt]) + (p - '0')); - } else if (p == '.') { + }else if(p == '.') { cnt++; - } else { + }else{ return -1; } } /* Handle short notation */ - if (cnt == 1) { + if(cnt == 1) { buf[3] = buf[1]; buf[1] = 0; buf[2] = 0; - } else if (cnt == 2) { + }else if (cnt == 2) { buf[3] = buf[2]; buf[2] = 0; - } else if (cnt != 3) { + }else if(cnt != 3) { /* String could not be parsed, return error */ return -1; } @@ -140,6 +140,7 @@ int pico_string_to_ipv4(const char *ipstr, uint32_t *ip) *ip = long_from(buf); return 0; + } int pico_ipv4_valid_netmask(uint32_t mask) @@ -157,14 +158,14 @@ int pico_ipv4_valid_netmask(uint32_t mask) * */ for(i = 0; i < 32; i++) { - if ((mask_swap << i) & 0x80000000) { - if (end) { + if((mask_swap << i) & 0x80000000) { + if(end) { pico_err = PICO_ERR_EINVAL; return -1; } cnt++; - } else { + }else{ end = 1; } } @@ -174,7 +175,7 @@ int pico_ipv4_valid_netmask(uint32_t mask) int pico_ipv4_is_unicast(uint32_t address) { const unsigned char *addr = (unsigned char *) &address; - if ((addr[0] & 0xe0) == 0xe0) + if((addr[0] & 0xe0) == 0xe0) return 0; /* multicast */ return 1; @@ -183,7 +184,7 @@ int pico_ipv4_is_unicast(uint32_t address) int pico_ipv4_is_multicast(uint32_t address) { const unsigned char *addr = (unsigned char *) &address; - if ((addr[0] != 0xff) && ((addr[0] & 0xe0) == 0xe0)) + if((addr[0] != 0xff) && ((addr[0] & 0xe0) == 0xe0)) return 1; /* multicast */ return 0; @@ -192,7 +193,7 @@ int pico_ipv4_is_multicast(uint32_t address) int pico_ipv4_is_loopback(uint32_t address) { const unsigned char *addr = (unsigned char *) &address; - if (addr[0] == 0x7f) + if(addr[0] == 0x7f) return 1; return 0; @@ -208,18 +209,16 @@ int pico_ipv4_is_valid_src(uint32_t address, struct pico_device *dev) if (pico_ipv4_is_broadcast(address)) { dbg("Source is a broadcast address, discard packet\n"); return 0; - } else if ( pico_ipv4_is_multicast(address)) { + } + else if( pico_ipv4_is_multicast(address)) { dbg("Source is a multicast address, discard packet\n"); return 0; - } else if (pico_ipv4_is_invalid_loopback(address, dev)) { + } + else if (pico_ipv4_is_invalid_loopback(address, dev)) { dbg("Source is a loopback address, discard packet\n"); return 0; - } else { -#ifdef PICO_SUPPORT_AODV - union pico_address src; - src.ip4.addr = address; - pico_aodv_refresh(&src); -#endif + } + else { return 1; } } @@ -382,7 +381,8 @@ static inline int8_t fragmented_check_has_morefrags(struct pico_frame **f) pico_tree_insert(pfrag->t, *f); pico_tree_insert(&pico_ipv4_fragmented_tree, pfrag); return 0; - } else { + } + else { reassembly_dbg("REASSEMBLY: intermediate element of a fragmented packet with id %X and offset %u\n", short_be(hdr->id), offset); pfrag = fragment_find_by_hdr(hdr); if (pfrag) { @@ -411,7 +411,6 @@ static inline int8_t fragmented_check_is_lastfrag(struct pico_frame **f) uint16_t running_offset = 0; uint16_t offset = 0; uint16_t data_len = 0; - uint16_t frag_len = 0; struct pico_ipv4_hdr *f_frag_hdr = NULL, *hdr = (struct pico_ipv4_hdr *) (*f)->net_hdr; struct pico_ipv4_fragmented_packet *pfrag = NULL; struct pico_frame *f_new = NULL, *f_frag = NULL; @@ -433,7 +432,7 @@ static inline int8_t fragmented_check_is_lastfrag(struct pico_frame **f) } f_new = pico_proto_ipv4.alloc(&pico_proto_ipv4, pfrag->total_len); - if (!f_new) { + if (!f_new){ pico_ipv4_fragmented_cleanup(pfrag); pico_frame_discard(*f); return -1; @@ -453,7 +452,8 @@ static inline int8_t fragmented_check_is_lastfrag(struct pico_frame **f) pico_frame_discard(f_frag); reassembly_dbg("REASSEMBLY: reassembled first packet of %u data bytes, offset = %u next expected offset = %u\n", data_len, offset, running_offset); - pico_tree_foreach_safe(index, pfrag->t, _tmp) { + pico_tree_foreach_safe(index, pfrag->t, _tmp) + { f_frag = index->keyValue; f_frag_hdr = (struct pico_ipv4_hdr *)f_frag->net_hdr; data_len = (uint16_t)(short_be(f_frag_hdr->len) - f_frag->net_len); @@ -471,7 +471,6 @@ static inline int8_t fragmented_check_is_lastfrag(struct pico_frame **f) pico_frame_discard(f_frag); reassembly_dbg("REASSEMBLY: reassembled intermediate packet of %u data bytes, offset = %u next expected offset = %u\n", data_len, offset, running_offset); } - frag_len = pfrag->total_len; pico_tree_delete(&pico_ipv4_fragmented_tree, pfrag); PICO_FREE(pfrag); @@ -482,7 +481,7 @@ static inline int8_t fragmented_check_is_lastfrag(struct pico_frame **f) reassembly_dbg("REASSEMBLY: reassembled last packet of %u data bytes, offset = %u\n", data_len, offset); hdr = (struct pico_ipv4_hdr *)f_new->net_hdr; - hdr->len = frag_len; + hdr->len = pfrag->total_len; hdr->frag = 0; /* flags cleared and no offset */ hdr->crc = 0; hdr->crc = short_be(pico_checksum(hdr, f_new->net_len)); @@ -596,7 +595,6 @@ static int pico_ipv4_process_bcast_in(struct pico_frame *f) pico_enqueue(pico_proto_udp.q_in, f); return 1; } - #endif #ifdef PICO_SUPPORT_ICMP4 @@ -606,7 +604,6 @@ static int pico_ipv4_process_bcast_in(struct pico_frame *f) pico_enqueue(pico_proto_icmp4.q_in, f); return 1; } - #endif return 0; } @@ -664,7 +661,8 @@ static int pico_ipv4_process_local_unicast_in(struct pico_frame *f) static void pico_ipv4_process_finally_try_forward(struct pico_frame *f) { struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - if ((pico_ipv4_is_broadcast(hdr->dst.addr))) { + if((pico_ipv4_is_broadcast(hdr->dst.addr))) + { /* don't forward broadcast frame, discard! */ pico_frame_discard(f); } else if (pico_ipv4_forward(f) != 0) { @@ -682,7 +680,7 @@ static int pico_ipv4_process_in(struct pico_protocol *self, struct pico_frame *f struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; /* NAT needs transport header information */ - if (((hdr->vhl) & 0x0F) > 5) { + if(((hdr->vhl) & 0x0F) > 5) { option_len = (uint8_t)(4 * (((hdr->vhl) & 0x0F) - 5)); } @@ -698,7 +696,6 @@ static int pico_ipv4_process_in(struct pico_protocol *self, struct pico_frame *f #endif - /* ret == 1 indicates to continue the function */ ret = pico_ipv4_crc_check(f); if (ret < 1) @@ -748,13 +745,13 @@ static int pico_ipv4_process_out(struct pico_protocol *self, struct pico_frame * { IGNORE_PARAMETER(self); f->start = (uint8_t*) f->net_hdr; -#ifdef PICO_SUPPORT_IPFILTER + #ifdef PICO_SUPPORT_IPFILTER if (ipfilter(f)) { /*pico_frame is discarded as result of the filtering*/ return 0; } -#endif + #endif return pico_sendto_dev(f); } @@ -841,7 +838,8 @@ static struct pico_ipv4_route *route_find(const struct pico_ip4 *addr) struct pico_ipv4_route *r; struct pico_tree_node *index; - if (addr->addr != PICO_IP4_BCAST) { + if(addr->addr != PICO_IP4_BCAST) + { pico_tree_foreach_reverse(index, &Routes) { r = index->keyValue; if ((addr->addr & (r->netmask.addr)) == (r->dest.addr)) { @@ -860,7 +858,7 @@ struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr) struct pico_ipv4_route *route; nullip.addr = 0U; - if (!addr) { + if(!addr) { pico_err = PICO_ERR_EINVAL; return nullip; } @@ -878,15 +876,8 @@ struct pico_ip4 *pico_ipv4_source_find(const struct pico_ip4 *dst) { struct pico_ip4 *myself = NULL; struct pico_ipv4_route *rt; -#ifdef PICO_SUPPORT_AODV - union pico_address node_address; - node_address.ip4.addr = dst->addr; - if (dst->addr && pico_ipv4_is_unicast(dst->addr)) - pico_aodv_lookup(&node_address); -#endif - - if (!dst) { + if(!dst) { pico_err = PICO_ERR_EINVAL; return NULL; } @@ -894,9 +885,8 @@ struct pico_ip4 *pico_ipv4_source_find(const struct pico_ip4 *dst) rt = route_find(dst); if (rt && rt->link) { myself = &rt->link->address; - } else { + } else pico_err = PICO_ERR_EHOSTUNREACH; - } return myself; } @@ -906,7 +896,7 @@ struct pico_device *pico_ipv4_source_dev_find(const struct pico_ip4 *dst) struct pico_device *dev = NULL; struct pico_ipv4_route *rt; - if (!dst) { + if(!dst) { pico_err = PICO_ERR_EINVAL; return NULL; } @@ -962,10 +952,12 @@ static void pico_ipv4_mcast_print_groups(struct pico_ipv4_link *mcast_link) ip_mcast_dbg("+ nr | interface | host group | reference count | filter mode | source +\n"); ip_mcast_dbg("+---------------------------------------------------------------------------------+\n"); - pico_tree_foreach(index, mcast_link->MCASTGroups) { + pico_tree_foreach(index, mcast_link->MCASTGroups) + { g = index->keyValue; ip_mcast_dbg("+ %04d | %16s | %08X | %05u | %u | %8s +\n", i, mcast_link->dev->name, g->mcast_addr.addr, g->reference_count, g->filter_mode, ""); - pico_tree_foreach(index2, &g->MCASTSources) { + pico_tree_foreach(index2, &g->MCASTSources) + { source = index2->keyValue; ip_mcast_dbg("+ %4s | %16s | %8s | %5s | %s | %08X +\n", "", "", "", "", "", source->addr); } @@ -979,14 +971,16 @@ static int mcast_group_update(struct pico_mcast_group *g, struct pico_tree *MCAS struct pico_tree_node *index = NULL, *_tmp = NULL; struct pico_ip4 *source = NULL; /* cleanup filter */ - pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) { + pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) + { source = index->keyValue; pico_tree_delete(&g->MCASTSources, source); PICO_FREE(source); } /* insert new filter */ if (MCASTFilter) { - pico_tree_foreach(index, MCASTFilter) { + pico_tree_foreach(index, MCASTFilter) + { if (index->keyValue) { source = PICO_ZALLOC(sizeof(struct pico_ip4)); if (!source) { @@ -1013,8 +1007,8 @@ int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_gro if (mcast_link) link = pico_ipv4_link_get(mcast_link); - - if (!link) + + if(!link) link = mcast_default_link; test.mcast_addr = *mcast_group; @@ -1062,8 +1056,8 @@ int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_gr if (mcast_link) link = pico_ipv4_link_get(mcast_link); - - if (!link) + + if(!link) link = mcast_default_link; test.mcast_addr = *mcast_group; @@ -1075,7 +1069,8 @@ int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_gr if (reference_count && (--(g->reference_count) < 1)) { pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_DELETE); /* cleanup filter */ - pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) { + pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) + { source = index->keyValue; pico_tree_delete(&g->MCASTSources, source); PICO_FREE(source); @@ -1109,16 +1104,19 @@ static int pico_ipv4_mcast_filter(struct pico_frame *f) test.mcast_addr = hdr->dst; - pico_tree_foreach(index, &Tree_dev_link) { + pico_tree_foreach(index, &Tree_dev_link) + { link = index->keyValue; g = pico_tree_findKey(link->MCASTGroups, &test); if (g) { if (f->dev == link->dev) { ip_mcast_dbg("MCAST: IP %08X is group member of current link %s\n", hdr->dst.addr, f->dev->name); /* perform source filtering */ - switch (g->filter_mode) { + switch (g->filter_mode) + { case PICO_IP_MULTICAST_INCLUDE: - pico_tree_foreach(index2, &g->MCASTSources) { + pico_tree_foreach(index2, &g->MCASTSources) + { if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) { ip_mcast_dbg("MCAST: IP %08X in included interface source list\n", hdr->src.addr); return 0; @@ -1128,7 +1126,8 @@ static int pico_ipv4_mcast_filter(struct pico_frame *f) return -1; case PICO_IP_MULTICAST_EXCLUDE: - pico_tree_foreach(index2, &g->MCASTSources) { + pico_tree_foreach(index2, &g->MCASTSources) + { if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) { ip_mcast_dbg("MCAST: IP %08X in excluded interface source list\n", hdr->src.addr); return -1; @@ -1157,20 +1156,17 @@ int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_gro pico_err = PICO_ERR_EPROTONOSUPPORT; return -1; } - int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) { pico_err = PICO_ERR_EPROTONOSUPPORT; return -1; } - struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void) { pico_err = PICO_ERR_EPROTONOSUPPORT; return NULL; } #endif /* PICO_SUPPORT_MCAST */ - /* #define DEBUG_ROUTE */ #ifdef DEBUG_ROUTE void dbg_route(void) @@ -1179,7 +1175,7 @@ void dbg_route(void) struct pico_tree_node *index; int count_hosts = 0; dbg("==== ROUTING TABLE =====\n"); - pico_tree_foreach(index, &Routes) { + pico_tree_foreach(index, &Routes){ r = index->keyValue; dbg("Route to %08x/%08x, gw %08x, dev: %s, metric: %d\n", r->dest.addr, r->netmask.addr, r->gateway.addr, r->link->dev->name, r->metric); if (r->netmask.addr == 0xFFFFFFFF) @@ -1204,12 +1200,11 @@ int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t pro struct pico_tree_node *index; #endif - if (!f || !dst) { + if(!f || !dst) { pico_err = PICO_ERR_EINVAL; return -1; } - hdr = (struct pico_ipv4_hdr *) f->net_hdr; if (!hdr) { dbg("IP header error\n"); @@ -1236,7 +1231,7 @@ int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t pro if (pico_ipv4_is_multicast(dst->addr)) { /* if multicast */ switch (proto) { case PICO_PROTO_UDP: - if (pico_udp_get_mc_ttl(f->sock, &ttl) < 0) + if(pico_udp_get_mc_ttl(f->sock, &ttl) < 0) ttl = PICO_IP_DEFAULT_MULTICAST_TTL; break; @@ -1274,15 +1269,10 @@ int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t pro 1 ) ipv4_progressive_id++; - if (f->send_ttl > 0) { - ttl = f->send_ttl; - } - hdr->id = short_be(ipv4_progressive_id); hdr->dst.addr = dst->addr; hdr->src.addr = link->address.addr; hdr->ttl = ttl; - hdr->tos = f->send_tos; hdr->proto = proto; hdr->frag = short_be(PICO_IPV4_DONTFRAG); #ifdef PICO_SUPPORT_IPFRAG @@ -1308,7 +1298,7 @@ int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t pro f->dev = f->sock->dev; } else { f->dev = link->dev; - if (f->sock) + if (f->sock) f->sock->dev = f->dev; } @@ -1325,20 +1315,10 @@ int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t pro #endif -/* #ifdef PICO_SUPPORT_AODV */ -#if 0 - { - union pico_address node_address; - node_address.ip4.addr = hdr->dst.addr; - if(hdr->dst.addr && pico_ipv4_is_unicast(hdr->dst.addr)) - pico_aodv_lookup(&node_address); - } -#endif - - if (pico_ipv4_link_get(&hdr->dst)) { + if(pico_ipv4_link_get(&hdr->dst)) { /* it's our own IP */ return pico_enqueue(&in, f); - } else{ + }else{ /* TODO: Check if there are members subscribed here */ return pico_enqueue(&out, f); } @@ -1370,14 +1350,14 @@ static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_fra } -int MOCKABLE pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) +int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) { struct pico_ipv4_route test, *new; test.dest.addr = address.addr; test.netmask.addr = netmask.addr; test.metric = (uint32_t)metric; - if (pico_tree_findKey(&Routes, &test)) { + if(pico_tree_findKey(&Routes, &test)) { pico_err = PICO_ERR_EINVAL; return -1; } @@ -1452,7 +1432,7 @@ int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct struct pico_ip4 network, gateway; char ipstr[30]; - if (!dev) { + if(!dev) { pico_err = PICO_ERR_EINVAL; return -1; } @@ -1462,7 +1442,7 @@ int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct test.dev = dev; /** XXX: Valid netmask / unicast address test **/ - if (pico_tree_findKey(&Tree_dev_link, &test)) { + if(pico_tree_findKey(&Tree_dev_link, &test)) { pico_err = PICO_ERR_EADDRINUSE; return -1; } @@ -1525,7 +1505,8 @@ static int pico_ipv4_cleanup_routes(struct pico_ipv4_link *link) struct pico_tree_node *index = NULL, *tmp = NULL; struct pico_ipv4_route *route = NULL; - pico_tree_foreach_safe(index, &Routes, tmp) { + pico_tree_foreach_safe(index, &Routes, tmp) + { route = index->keyValue; if (link == route->link) pico_ipv4_route_del(route->dest, route->netmask, (int)route->metric); @@ -1533,7 +1514,7 @@ static int pico_ipv4_cleanup_routes(struct pico_ipv4_link *link) return 0; } -void MOCKABLE pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link) +void pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link) { if (link) default_bcast_route.link = link; @@ -1543,7 +1524,7 @@ int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address) { struct pico_ipv4_link test, *found; - if (!dev) { + if(!dev) { pico_err = PICO_ERR_EINVAL; return -1; } @@ -1570,7 +1551,8 @@ int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address) mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS; pico_ipv4_mcast_leave(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL); - pico_tree_foreach_safe(index, found->MCASTGroups, _tmp) { + pico_tree_foreach_safe(index, found->MCASTGroups, _tmp) + { g = index->keyValue; pico_tree_delete(found->MCASTGroups, g); PICO_FREE(g); @@ -1602,12 +1584,13 @@ struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address) return found; } -struct pico_ipv4_link *MOCKABLE pico_ipv4_link_by_dev(struct pico_device *dev) +struct pico_ipv4_link *pico_ipv4_link_by_dev(struct pico_device *dev) { struct pico_tree_node *index = NULL; struct pico_ipv4_link *link = NULL; - pico_tree_foreach(index, &Tree_dev_link) { + pico_tree_foreach(index, &Tree_dev_link) + { link = index->keyValue; if (link->dev == dev) return link; @@ -1624,7 +1607,8 @@ struct pico_ipv4_link *pico_ipv4_link_by_dev_next(struct pico_device *dev, struc if (last == NULL) valid = 1; - pico_tree_foreach(index, &Tree_dev_link) { + pico_tree_foreach(index, &Tree_dev_link) + { link = index->keyValue; if (link->dev == dev) { if (last == link) @@ -1636,10 +1620,10 @@ struct pico_ipv4_link *pico_ipv4_link_by_dev_next(struct pico_device *dev, struc return NULL; } -struct pico_device *MOCKABLE pico_ipv4_link_find(struct pico_ip4 *address) +struct pico_device *pico_ipv4_link_find(struct pico_ip4 *address) { struct pico_ipv4_link test, *found; - if (!address) { + if(!address) { pico_err = PICO_ERR_EINVAL; return NULL; } @@ -1704,7 +1688,7 @@ int pico_ipv4_rebound(struct pico_frame *f) { struct pico_ip4 dst; struct pico_ipv4_hdr *hdr; - if (!f) { + if(!f) { pico_err = PICO_ERR_EINVAL; return -1; } @@ -1727,15 +1711,11 @@ static int pico_ipv4_pre_forward_checks(struct pico_frame *f) { static uint16_t last_id = 0; static uint16_t last_proto = 0; - static struct pico_ip4 last_src = { - 0 - }; - static struct pico_ip4 last_dst = { - 0 - }; + static struct pico_ip4 last_src = {0}; + static struct pico_ip4 last_dst = {0}; struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; - - /* Decrease TTL, check if expired */ + + /* Decrease TTL, check if expired */ hdr->ttl = (uint8_t)(hdr->ttl - 1); if (hdr->ttl < 1) { pico_notify_ttl_expired(f); @@ -1752,7 +1732,7 @@ static int pico_ipv4_pre_forward_checks(struct pico_frame *f) /* If this was the last forwarded packet, silently discard to prevent duplications */ if ((last_src.addr == hdr->src.addr) && (last_id == hdr->id) - && (last_dst.addr == hdr->dst.addr) && (last_proto == hdr->proto)) { + && (last_dst.addr == hdr->dst.addr) && (last_proto == hdr->proto)) { return -1; } else { last_src.addr = hdr->src.addr; @@ -1760,20 +1740,18 @@ static int pico_ipv4_pre_forward_checks(struct pico_frame *f) last_id = hdr->id; last_proto = hdr->proto; } - return 0; } static int pico_ipv4_forward_check_dev(struct pico_frame *f) { - if (f->dev->eth != NULL) + if(f->dev->eth != NULL) f->len -= PICO_SIZE_ETHHDR; - if (f->len > f->dev->mtu) { + if(f->len > f->dev->mtu) { pico_notify_pkt_too_big(f); return -1; } - return 0; } @@ -1837,7 +1815,8 @@ int pico_ipv4_cleanup_links(struct pico_device *dev) struct pico_tree_node *index = NULL, *_tmp = NULL; struct pico_ipv4_link *link = NULL; - pico_tree_foreach_safe(index, &Tree_dev_link, _tmp) { + pico_tree_foreach_safe(index, &Tree_dev_link, _tmp) + { link = index->keyValue; if (dev == link->dev) pico_ipv4_link_del(dev, link->address); diff --git a/modules/pico_ipv4.h b/modules/pico_ipv4.h index 906bdd127..6fe006570 100644 --- a/modules/pico_ipv4.h +++ b/modules/pico_ipv4.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . diff --git a/modules/pico_ipv6.c b/modules/pico_ipv6.c index fffc49b1d..e5fd1e7dc 100644 --- a/modules/pico_ipv6.c +++ b/modules/pico_ipv6.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Daniele Lacamera, Kristof Roelants @@ -250,8 +250,7 @@ int pico_string_to_ipv6(const char *ipstr, uint8_t *ip) shift = PICO_SIZE_IP6 - zeros - doublecolon; for (i = shift; i >= 0; --i) { /* (i-1) as arrays are indexed from 0 onwards */ - if ((doublecolon + (i - 1)) >= 0) - buf[doublecolon + zeros + (i - 1)] = buf[doublecolon + (i - 1)]; + buf[doublecolon + zeros + (i - 1)] = buf[doublecolon + (i - 1)]; } memset(&buf[doublecolon], 0, (size_t)zeros); } @@ -336,12 +335,6 @@ int pico_ipv6_is_multicast(const uint8_t addr[PICO_SIZE_IP6]) return 0; } -int pico_ipv6_is_allhosts_multicast(const uint8_t addr[PICO_SIZE_IP6]) -{ - struct pico_ip6 allhosts = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}; - return !memcmp(allhosts.addr, addr, PICO_SIZE_IP6); -} - int pico_ipv6_is_solicited(const uint8_t addr[PICO_SIZE_IP6]) { struct pico_ip6 solicited_node = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00 }}; @@ -353,15 +346,29 @@ int pico_ipv6_is_unspecified(const uint8_t addr[PICO_SIZE_IP6]) return !memcmp(PICO_IP6_ANY, addr, PICO_SIZE_IP6); } +int pico_ipv6_rebound(struct pico_frame *f) +{ + struct pico_ip6 dst = {{0}}; + struct pico_ipv6_hdr *hdr = NULL; + + if(!f) + return -1; + + hdr = (struct pico_ipv6_hdr *)f->net_hdr; + if (!hdr) + return -1; + + dst = hdr->src; + + return pico_ipv6_frame_push(f, &dst, hdr->nxthdr); +} + static struct pico_ipv6_route *pico_ipv6_route_find(const struct pico_ip6 *addr) { struct pico_ipv6_route *r = NULL; struct pico_tree_node *index = NULL; int i = 0; - if (!pico_ipv6_is_localhost(addr->addr) && (pico_ipv6_is_linklocal(addr->addr) || pico_ipv6_is_multicast(addr->addr) || pico_ipv6_is_sitelocal(addr->addr))) - return NULL; - pico_tree_foreach_reverse(index, &IPV6Routes) { r = index->keyValue; @@ -412,7 +419,6 @@ struct pico_device *pico_ipv6_source_dev_find(const struct pico_ip6 *dst) dev = rt->link->dev; } else pico_err = PICO_ERR_EHOSTUNREACH; - return dev; } @@ -425,15 +431,14 @@ static int pico_ipv6_forward_check_dev(struct pico_frame *f) pico_notify_pkt_too_big(f); return -1; } - return 0; } static int pico_ipv6_pre_forward_checks(struct pico_frame *f) { struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - - /* Decrease HOP count, check if expired */ + + /* Decrease HOP count, check if expired */ hdr->hop = (uint8_t)(hdr->hop - 1); if (hdr->hop < 1) { pico_notify_ttl_expired(f); @@ -448,6 +453,7 @@ static int pico_ipv6_pre_forward_checks(struct pico_frame *f) if (pico_ipv6_forward_check_dev(f) < 0) return -1; + pico_sendto_dev(f); return 0; } @@ -472,10 +478,12 @@ static int pico_ipv6_forward(struct pico_frame *f) f->start = f->net_hdr; - return pico_sendto_dev(f); -} + if (pico_ipv6_forward_check_dev(f) < 0) + return -1; -#define HBH_LEN(hbh) ((((hbh->ext.hopbyhop.len + 1) << 3) - 2)) /* len in bytes, minus nxthdr and len byte */ + pico_sendto_dev(f); + return 0; +} int pico_ipv6_process_hopbyhop(struct pico_ipv6_exthdr *hbh, struct pico_frame *f) { @@ -487,7 +495,7 @@ int pico_ipv6_process_hopbyhop(struct pico_ipv6_exthdr *hbh, struct pico_frame * IGNORE_PARAMETER(f); option = hbh->ext.hopbyhop.options; - len = (uint8_t)HBH_LEN(hbh); + len = (uint8_t)(((hbh->ext.hopbyhop.len + 1) << 3) - 2); /* len in bytes, minus nxthdr and len byte */ ipv6_dbg("IPv6: hop by hop extension header length %u\n", len + 2); while (len) { switch (*option) @@ -515,9 +523,8 @@ int pico_ipv6_process_hopbyhop(struct pico_ipv6_exthdr *hbh, struct pico_frame * pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, ptr + (uint32_t)(option - extensions_start)); return -1; case PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD_SINM: - if (!pico_ipv6_is_multicast(((struct pico_ipv6_hdr *)(f->net_hdr))->dst.addr)) - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, ptr + (uint32_t)(option - extensions_start)); - + /* TODO DLA: check if not multicast */ + pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, ptr + (uint32_t)(option - extensions_start)); return -1; } ipv6_dbg("IPv6: option with type %u and length %u\n", *option, optlen); @@ -529,271 +536,87 @@ int pico_ipv6_process_hopbyhop(struct pico_ipv6_exthdr *hbh, struct pico_frame * } -int pico_ipv6_process_routing(struct pico_ipv6_exthdr *routing, struct pico_frame *f, uint32_t ptr) +int pico_ipv6_process_routing(struct pico_ipv6_exthdr *routing, struct pico_frame *f) { IGNORE_PARAMETER(f); - if (routing->ext.routing.segleft == 0) - return 0; - ipv6_dbg("IPv6: routing extension header with len %u\n", routing->ext.routing.len + 2); switch (routing->ext.routing.routtype) { case 0x00: /* deprecated */ - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_HDRFIELD, ptr + 2); - return -1; + break; case 0x02: /* routing type for MIPv6: not supported yet */ break; default: - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_HDRFIELD, ptr + 2); + /* XXX: ICMP parameter problem (code 0) */ return -1; } return 0; } - -#define IP6FRAG_OFF(x) ((x & 0xFFF8)) -#define IP6FRAG_MORE(x) ((x & 0x0001)) - -static int pico_ipv6_frag_compare(void *ka, void *kb) +int pico_ipv6_process_frag(struct pico_ipv6_exthdr *fragm, struct pico_frame *f) { - struct pico_frame *a = ka, *b = kb; - if (IP6FRAG_OFF(a->frag) > IP6FRAG_OFF(b->frag)) - return 1; - - if (IP6FRAG_OFF(a->frag) < IP6FRAG_OFF(b->frag)) + IGNORE_PARAMETER(fragm); + if (!f) { + pico_err = PICO_ERR_EINVAL; return -1; - - return 0; -} -PICO_TREE_DECLARE(ipv6_fragments, pico_ipv6_frag_compare); -struct pico_timer *ipv6_fragments_timer = NULL; - -static void pico_ipv6_fragments_complete(unsigned int len, uint8_t proto) -{ - struct pico_tree_node *index, *tmp; - struct pico_frame *f; - unsigned int bookmark = 0; - struct pico_frame *full = NULL; - struct pico_frame *first = pico_tree_first(&ipv6_fragments); - - full = pico_frame_alloc((uint16_t)(PICO_SIZE_IP6HDR + len)); - if (full) { - full->net_hdr = full->buffer; - full->net_len = PICO_SIZE_IP6HDR; - memcpy(full->net_hdr, first->net_hdr, full->net_len); - full->transport_hdr = full->net_hdr + full->net_len; - full->transport_len = (uint16_t)len; - full->dev = first->dev; - pico_tree_foreach_safe(index, &ipv6_fragments, tmp) { - f = index->keyValue; - memcpy(full->transport_hdr + bookmark, f->transport_hdr, f->transport_len); - bookmark += f->transport_len; - pico_tree_delete(&ipv6_fragments, f); - pico_frame_discard(f); - } - pico_transport_receive(full, proto); - if (ipv6_fragments_timer) { - pico_timer_cancel(ipv6_fragments_timer); - ipv6_fragments_timer = NULL; - } - } -} - -static void pico_ipv6_fragments_check_complete(uint8_t proto) -{ - struct pico_tree_node *index, *temp; - struct pico_frame *cur; - unsigned int bookmark = 0; - pico_tree_foreach_safe(index, &ipv6_fragments, temp) { - cur = index->keyValue; - if (IP6FRAG_OFF(cur->frag) != bookmark) - return; - - bookmark += cur->transport_len; - if (!IP6FRAG_MORE(cur->frag)) { - pico_ipv6_fragments_complete(bookmark, proto); - } - } -} - -static void pico_ipv6_frag_expire(pico_time now, void *arg) -{ - struct pico_tree_node *index, *tmp; - struct pico_frame *f; - struct pico_frame *first = pico_tree_first(&ipv6_fragments); - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)first->net_hdr; - (void)arg; - (void)now; - if (!first) { - return; - } - - /* Empty the tree */ - pico_tree_foreach_safe(index, &ipv6_fragments, tmp) { - f = index->keyValue; - pico_tree_delete(&ipv6_fragments, f); - if (f != first) - pico_frame_discard(f); /* Later, after ICMP notification...*/ - - } - if ((IP6FRAG_OFF(first->frag) == 0) && (!pico_ipv6_is_multicast(hdr->dst.addr))) - pico_icmp6_frag_expired(first); - - pico_frame_discard(first); -} - -#define PICO_IPV6_FRAG_TIMEOUT 60000 - -#define FRAG_ID(x) ((uint32_t)((x->ext.frag.id[0] << 24) + (x->ext.frag.id[1] << 16) + \ - (x->ext.frag.id[2] << 8) + x->ext.frag.id[3])) -static void pico_ipv6_frag_timer_on(void) -{ - ipv6_fragments_timer = pico_timer_add(PICO_IPV6_FRAG_TIMEOUT, pico_ipv6_frag_expire, NULL); -} - -static int pico_ipv6_frag_match(struct pico_frame *a, struct pico_frame *b) -{ - struct pico_ipv6_hdr *ha, *hb; - if (!a || !b) - return 0; - - ha = (struct pico_ipv6_hdr *)a->net_hdr; - hb = (struct pico_ipv6_hdr *)b->net_hdr; - if (!ha || !hb) - return 0; - - if (memcmp(ha->src.addr, hb->src.addr, PICO_SIZE_IP6) != 0) - return 0; - - if (memcmp(ha->dst.addr, hb->dst.addr, PICO_SIZE_IP6) != 0) - return 0; - - return 1; -} - -static void pico_ipv6_process_frag(struct pico_ipv6_exthdr *frag, struct pico_frame *f, uint8_t proto) -{ - struct pico_frame *first = pico_tree_first(&ipv6_fragments); - static uint32_t ipv6_cur_frag_id = 0u; - - - if (!first) { - if (ipv6_cur_frag_id && (FRAG_ID(frag) == ipv6_cur_frag_id)) { - /* Discard late arrivals, without firing the timer, - * just to make TAHI happy in-between two consecutive tests - */ - return; - } - - pico_ipv6_frag_timer_on(); - ipv6_cur_frag_id = FRAG_ID(frag); - } - - if (!first || (pico_ipv6_frag_match(f, first) && (FRAG_ID(frag) == ipv6_cur_frag_id))) { - pico_tree_insert(&ipv6_fragments, pico_frame_copy(f)); } - - pico_ipv6_fragments_check_complete(proto); + ipv6_dbg("IPv6: fragmentation extension header\n"); + return 0; } -static int pico_ipv6_process_destopt(struct pico_ipv6_exthdr *destopt, struct pico_frame *f, uint32_t opt_ptr) +int pico_ipv6_process_destopt(struct pico_ipv6_exthdr *destopt, struct pico_frame *f) { uint8_t *option = NULL; uint8_t len = 0, optlen = 0; - opt_ptr += (uint32_t)(2u); /* Skip Dest_opts header */ + IGNORE_PARAMETER(f); option = destopt->ext.destopt.options; len = (uint8_t)(((destopt->ext.destopt.len + 1) << 3) - 2); /* len in bytes, minus nxthdr and len byte */ ipv6_dbg("IPv6: destination option extension header length %u\n", len + 2); while (len) { - optlen = (uint8_t)(*(option + 1) + 2); switch (*option) { case PICO_IPV6_EXTHDR_OPT_PAD1: + ++option; + --len; break; case PICO_IPV6_EXTHDR_OPT_PADN: + optlen = (uint8_t)(*(option + 1) + 2); /* plus type and len byte */ + option += optlen; + len = (uint8_t)(len - optlen); break; case PICO_IPV6_EXTHDR_OPT_SRCADDR: + optlen = (uint8_t)(*(option + 1) + 2); /* plus type and len byte */ + option += optlen; + len = (uint8_t)(len - optlen); /* 2 = 1 byte for option type and 1 byte for option length */ ipv6_dbg("IPv6: home address option with length %u\n", optlen); break; default: - ipv6_dbg("IPv6: option with type %u and length %u\n", *option, optlen); - switch (*option & PICO_IPV6_EXTHDR_OPT_ACTION_MASK) { + optlen = *(option + 1); + ipv6_dbg("IPv6: option with type %u and length %u\n", *option, optlen + 2); + switch ((*option) & PICO_IPV6_EXTHDR_OPT_ACTION_MASK) { case PICO_IPV6_EXTHDR_OPT_ACTION_SKIP: break; case PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD: return -1; case PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD_SI: - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, opt_ptr); + /* XXX: send ICMP parameter problem (code 2), pointing to the unrecognized option type */ return -1; case PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD_SINM: - if (!pico_ipv6_is_multicast(((struct pico_ipv6_hdr *)(f->net_hdr))->dst.addr)) - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, opt_ptr); - + /* XXX: if destination address was not a multicast address, send an ICMP parameter problem (code 2) */ return -1; } + option += optlen + 2; + len = (uint8_t)(len - optlen + 2); /* 2 = 1 byte for option type and 1 byte for option length */ break; } - opt_ptr += optlen; - option += optlen; - len = (uint8_t)(len - optlen); - } - return 0; -} - -#define IPV6_OPTLEN(x) ((uint16_t)(((x + 1) << 3))) - -static int pico_ipv6_check_headers_sequence(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - int ptr = sizeof(struct pico_ipv6_hdr); - int cur_nexthdr = 6; /* Starts with nexthdr field in ipv6 pkt */ - uint8_t nxthdr = hdr->nxthdr; - for (;; ) { - uint8_t optlen = *(f->net_hdr + ptr + 1); - switch (nxthdr) { - case PICO_IPV6_EXTHDR_DESTOPT: - case PICO_IPV6_EXTHDR_ROUTING: - case PICO_IPV6_EXTHDR_HOPBYHOP: - case PICO_IPV6_EXTHDR_ESP: - case PICO_IPV6_EXTHDR_AUTH: - optlen = (uint8_t)IPV6_OPTLEN(optlen); - break; - case PICO_IPV6_EXTHDR_FRAG: - optlen = 8; - break; - case PICO_IPV6_EXTHDR_NONE: - return 0; - - case PICO_PROTO_TCP: - case PICO_PROTO_UDP: - case PICO_PROTO_ICMP6: - return 0; - default: - /* Invalid next header */ - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_NXTHDR, (uint32_t)cur_nexthdr); - return -1; - } - cur_nexthdr = ptr; - nxthdr = *(f->net_hdr + ptr); - ptr += optlen; - } -} - -static int pico_ipv6_check_aligned(struct pico_frame *f) -{ - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - if ((short_be(hdr->len) % 8) != 0) { - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_HDRFIELD, 4); - return -1; } - return 0; } @@ -801,62 +624,45 @@ static int pico_ipv6_extension_headers(struct pico_frame *f) { struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; uint8_t nxthdr = hdr->nxthdr; - struct pico_ipv6_exthdr *exthdr = NULL, *frag_hdr = NULL; + struct pico_ipv6_exthdr *exthdr = NULL; uint32_t ptr = sizeof(struct pico_ipv6_hdr); - uint16_t cur_optlen; - uint32_t cur_nexthdr = 6; - int must_align = 0; + int is_ipv6_hdr = 1; /* ==1 indicates that the option being parsed is in the header, + * rather than in an extension. + */ f->net_len = sizeof(struct pico_ipv6_hdr); - - if (pico_ipv6_check_headers_sequence(f) < 0) - return -1; - for (;; ) { exthdr = (struct pico_ipv6_exthdr *)(f->net_hdr + f->net_len); - cur_optlen = 0; - switch (nxthdr) { case PICO_IPV6_EXTHDR_HOPBYHOP: - if (cur_nexthdr != 6) { - /* The Hop-by-Hop Options header, - * when present, must immediately follow the IPv6 header. - */ - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_NXTHDR, cur_nexthdr); + /* The Hop-by-Hop Options header, + * when present, must immediately follow the IPv6 header. + */ + if (!is_ipv6_hdr) { + pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_NXTHDR, ptr); return -1; } - cur_optlen = IPV6_OPTLEN(exthdr->ext.hopbyhop.len); - f->net_len = (uint16_t) (f->net_len + cur_optlen); - must_align = 1; + f->net_len = (uint16_t)(f->net_len + ((exthdr->ext.hopbyhop.len + 1) << 3)); if (pico_ipv6_process_hopbyhop(exthdr, f) < 0) return -1; break; case PICO_IPV6_EXTHDR_ROUTING: - cur_optlen = IPV6_OPTLEN(exthdr->ext.routing.len); - f->net_len = (uint16_t) (f->net_len + cur_optlen); - if (pico_ipv6_process_routing(exthdr, f, ptr) < 0) + f->net_len = (uint16_t)(f->net_len + ((exthdr->ext.routing.len + 1) << 3)); + if (pico_ipv6_process_routing(exthdr, f) < 0) return -1; break; case PICO_IPV6_EXTHDR_FRAG: - cur_optlen = 8u; - f->net_len = (uint16_t) (f->net_len + cur_optlen); - frag_hdr = exthdr; - f->frag = (uint16_t)((frag_hdr->ext.frag.om[0] << 8) + frag_hdr->ext.frag.om[1]); - /* If M-Flag is set, and packet is not 8B aligned, discard and alert */ - if (IP6FRAG_MORE(f->frag) && ((short_be(hdr->len) % 8) != 0)) { - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_HDRFIELD, 4); + f->net_len = (uint16_t)(f->net_len + 8); /* fixed length */ + if (pico_ipv6_process_frag(exthdr, f) < 0) return -1; - } break; case PICO_IPV6_EXTHDR_DESTOPT: - cur_optlen = IPV6_OPTLEN(exthdr->ext.destopt.len); - f->net_len = (uint16_t) (f->net_len + cur_optlen); - must_align = 1; - if (pico_ipv6_process_destopt(exthdr, f, ptr) < 0) + f->net_len = (uint16_t)(f->net_len + ((exthdr->ext.destopt.len + 1) << 3)); + if (pico_ipv6_process_destopt(exthdr, f) < 0) return -1; break; @@ -868,35 +674,27 @@ static int pico_ipv6_extension_headers(struct pico_frame *f) return 0; case PICO_IPV6_EXTHDR_NONE: /* no next header */ - if (must_align && (pico_ipv6_check_aligned(f) < 0)) - return -1; - return 0; case PICO_PROTO_TCP: case PICO_PROTO_UDP: case PICO_PROTO_ICMP6: - if (must_align && (pico_ipv6_check_aligned(f) < 0)) - return -1; - f->transport_hdr = f->net_hdr + f->net_len; f->transport_len = (uint16_t)(short_be(hdr->len) - (f->net_len - sizeof(struct pico_ipv6_hdr))); - if (frag_hdr) { - pico_ipv6_process_frag(frag_hdr, f, nxthdr); - return -1; - } else { - return nxthdr; - } - - break; + return nxthdr; default: - /* Invalid next header */ - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_NXTHDR, cur_nexthdr); + if (is_ipv6_hdr) + pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_NXTHDR, 6); /* 6 is the pos of next hdr field */ + else + pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_NXTHDR, ptr); + return -1; } nxthdr = exthdr->nxthdr; - cur_nexthdr = ptr; - ptr += cur_optlen; + if (!is_ipv6_hdr) + ptr += (uint32_t)sizeof(struct pico_ipv6_exthdr); + + is_ipv6_hdr = 0; } } @@ -906,12 +704,6 @@ int pico_ipv6_process_in(struct pico_protocol *self, struct pico_frame *f) struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; IGNORE_PARAMETER(self); - /* TODO: Check hop-by-hop hdr before forwarding */ - - if (pico_ipv6_is_unicast(&hdr->dst) && !pico_ipv6_link_get(&hdr->dst)) { - /* not local, try to forward. */ - return pico_ipv6_forward(f); - } proto = pico_ipv6_extension_headers(f); if (proto <= 0) { @@ -922,11 +714,16 @@ int pico_ipv6_process_in(struct pico_protocol *self, struct pico_frame *f) f->proto = (uint8_t)proto; ipv6_dbg("IPv6: payload %u net_len %u nxthdr %u\n", short_be(hdr->len), f->net_len, proto); - if (pico_ipv6_is_unicast(&hdr->dst)) { + + if (0) { + } else if (pico_ipv6_is_unicast(&hdr->dst)) { pico_transport_receive(f, f->proto); } else if (pico_ipv6_is_multicast(hdr->dst.addr)) { /* XXX perform multicast filtering: solicited-node multicast address MUST BE allowed! */ pico_transport_receive(f, f->proto); + } else { + /* not local, try to forward. */ + pico_ipv6_forward(f); } return 0; @@ -992,7 +789,7 @@ static inline struct pico_ipv6_route *ipv6_pushed_frame_checks(struct pico_frame } route = pico_ipv6_route_find(dst); - if (!route && !f->dev) { + if (!route) { dbg("IPv6: route not found.\n"); pico_err = PICO_ERR_EHOSTUNREACH; return NULL; @@ -1001,7 +798,7 @@ static inline struct pico_ipv6_route *ipv6_pushed_frame_checks(struct pico_frame return route; } -static inline void ipv6_push_hdr_adjust(struct pico_frame *f, struct pico_ipv6_link *link, struct pico_ip6 *src, struct pico_ip6 *dst, uint8_t proto, int is_dad) +static inline void ipv6_push_hdr_adjust(struct pico_frame *f, struct pico_ipv6_link *link, struct pico_ip6 *dst, uint8_t proto) { struct pico_icmp6_hdr *icmp6_hdr = NULL; struct pico_ipv6_hdr *hdr = NULL; @@ -1012,24 +809,9 @@ static inline void ipv6_push_hdr_adjust(struct pico_frame *f, struct pico_ipv6_l hdr->len = short_be((uint16_t)(f->transport_len + f->net_len - (uint16_t)sizeof(struct pico_ipv6_hdr))); hdr->nxthdr = proto; hdr->hop = f->dev->hostvars.hoplimit; + hdr->src = link->address; hdr->dst = *dst; - if (!src) - /* Address defaults to the link information: src address selection is done via link */ - hdr->src = link->address; - else { - /* Sender protocol is forcing an IPv6 address */ - memcpy(hdr->src.addr, src->addr, PICO_SIZE_IP6); - } - - if (f->send_ttl) { - hdr->hop = f->send_ttl; - } - - if (f->send_tos) { - hdr->vtf |= ((uint32_t)f->send_tos << 20u); - } - /* make adjustments to defaults according to proto */ switch (proto) { @@ -1039,21 +821,19 @@ static inline void ipv6_push_hdr_adjust(struct pico_frame *f, struct pico_ipv6_l if (icmp6_hdr->type == PICO_ICMP6_NEIGH_SOL || icmp6_hdr->type == PICO_ICMP6_NEIGH_ADV) hdr->hop = 255; - if ((is_dad || link->istentative) && icmp6_hdr->type == PICO_ICMP6_NEIGH_SOL) + if (icmp6_hdr->type == PICO_ICMP6_NEIGH_SOL && link->istentative) memcpy(hdr->src.addr, PICO_IP6_ANY, PICO_SIZE_IP6); icmp6_hdr->crc = 0; icmp6_hdr->crc = short_be(pico_icmp6_checksum(f)); break; } -#ifdef PICO_SUPPORT_UDP case PICO_PROTO_UDP: { struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - udp_hdr->crc = short_be(pico_udp_checksum_ipv6(f)); + udp_hdr->crc = pico_udp_checksum_ipv6(f); break; } -#endif default: break; @@ -1065,17 +845,20 @@ static int ipv6_frame_push_final(struct pico_frame *f) { struct pico_ipv6_hdr *hdr = NULL; hdr = (struct pico_ipv6_hdr *)f->net_hdr; + if(pico_ipv6_link_get(&hdr->dst)) { return pico_enqueue(&ipv6_in, f); } else { return pico_enqueue(&ipv6_out, f); } + + } struct pico_ipv6_link *pico_ipv6_linklocal_get(struct pico_device *dev); -int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *src, struct pico_ip6 *dst, uint8_t proto, int is_dad) +int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *dst, uint8_t proto) { struct pico_ipv6_route *route = NULL; struct pico_ipv6_link *link = NULL; @@ -1085,20 +868,11 @@ int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *src, struct pico pico_frame_discard(f); return -1; } - - if (pico_ipv6_is_sitelocal(dst->addr)) - link = pico_ipv6_sitelocal_get(f->dev); - else - link = pico_ipv6_linklocal_get(f->dev); - + link = pico_ipv6_linklocal_get(f->dev); if (link) goto push_final; } - if (pico_ipv6_is_localhost(dst->addr)) { - f->dev = pico_get_device("loop"); - } - route = ipv6_pushed_frame_checks(f, dst); if (!route) { pico_frame_discard(f); @@ -1124,8 +898,10 @@ int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *src, struct pico #endif push_final: - ipv6_push_hdr_adjust(f, link, src, dst, proto, is_dad); + ipv6_push_hdr_adjust(f, link, dst, proto); + return ipv6_frame_push_final(f); + } static int pico_ipv6_frame_sock_push(struct pico_protocol *self, struct pico_frame *f) @@ -1147,7 +923,7 @@ static int pico_ipv6_frame_sock_push(struct pico_protocol *self, struct pico_fra dst = &f->sock->remote_addr.ip6; } - return pico_ipv6_frame_push(f, NULL, dst, (uint8_t)f->sock->proto->proto_number, 0); + return pico_ipv6_frame_push(f, dst, (uint8_t)f->sock->proto->proto_number); } /* interface: protocol definition */ @@ -1191,7 +967,6 @@ static inline struct pico_ipv6_route *ipv6_route_add_link(struct pico_ip6 gatewa return NULL; } - return r; } @@ -1227,19 +1002,11 @@ int pico_ipv6_route_add(struct pico_ip6 address, struct pico_ip6 netmask, struct } else { struct pico_ipv6_route *r = ipv6_route_add_link(gateway); if (!r) { - if (link) - new->link = link; - else { - PICO_FREE(new); - return -1; - } - } else { - new->link = r->link; + PICO_FREE(new); + return -1; } - } - if (new->link && (pico_ipv6_is_global(address.addr)) && (!pico_ipv6_is_global(new->link->address.addr))) { - new->link = pico_ipv6_global_get(new->link->dev); + new->link = r->link; } if (!new->link) { @@ -1248,7 +1015,6 @@ int pico_ipv6_route_add(struct pico_ip6 address, struct pico_ip6 netmask, struct return -1; } - pico_tree_insert(&IPV6Routes, new); pico_ipv6_dbg_route(); return 0; @@ -1294,7 +1060,6 @@ void pico_ipv6_nd_dad(pico_time now, void *arg) l = pico_ipv6_link_istentative(address); if (!l) return; - if (l->isduplicate) { dbg("IPv6: duplicate address.\n"); old_address = *address; @@ -1319,7 +1084,7 @@ void pico_ipv6_nd_dad(pico_time now, void *arg) } -struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask) +int pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask) { struct pico_ipv6_link test = { 0 @@ -1335,7 +1100,7 @@ struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_i if (!dev) { pico_err = PICO_ERR_EINVAL; - return NULL; + return -1; } test.address = address; @@ -1345,7 +1110,7 @@ struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_i if (pico_tree_findKey(&IPV6Links, &test)) { dbg("IPv6: trying to assign an invalid address (in use)\n"); pico_err = PICO_ERR_EADDRINUSE; - return NULL; + return -1; } /** XXX: Check for network already in use (e.g. trying to assign 10.0.0.1/24 where 10.1.0.1/8 is in use) **/ @@ -1353,13 +1118,13 @@ struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_i if (!new) { dbg("IPv6: out of memory!\n"); pico_err = PICO_ERR_ENOMEM; - return NULL; + return -1; } new->address = address; new->netmask = netmask; new->dev = dev; - new->istentative = 1; + new->istentative = 0; new->isduplicate = 0; pico_tree_insert(&IPV6Links, new); @@ -1376,15 +1141,16 @@ struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_i #ifndef UNIT_TEST /* Duplicate Address Detection */ - pico_icmp6_neighbor_solicitation(dev, &address, PICO_ICMP6_ND_DAD); - new->dad_timer = pico_timer_add(pico_rand() % PICO_ICMP6_MAX_RTR_SOL_DELAY, &pico_ipv6_nd_dad, &new->address); -#else - new->istentative = 0; + if (!pico_ipv6_is_unspecified(address.addr)) { + new->istentative = 1; + pico_icmp6_neighbor_solicitation(dev, &address, PICO_ICMP6_ND_DAD); + pico_timer_add(pico_rand() % PICO_ICMP6_MAX_RTR_SOL_DELAY, &pico_ipv6_nd_dad, &new->address); + } #endif pico_ipv6_to_string(ipstr, new->address.addr); dbg("Assigned ipv6 %s to device %s\n", ipstr, new->dev->name); - return new; + return 0; } int pico_ipv6_cleanup_routes(struct pico_ipv6_link *link) @@ -1435,9 +1201,6 @@ int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address) } pico_ipv6_cleanup_routes(found); - if (found->dad_timer) - pico_timer_cancel(found->dad_timer); - pico_tree_delete(&IPV6Links, found); /* XXX MUST leave the solicited-node multicast address corresponding to the address (RFC 4861 $7.2.1) */ PICO_FREE(found); @@ -1558,19 +1321,6 @@ struct pico_ipv6_link *pico_ipv6_link_by_dev_next(struct pico_device *dev, struc return NULL; } -struct pico_ipv6_link *pico_ipv6_prefix_configured(struct pico_ip6 *prefix) -{ - unsigned int nm64_len = 8; - struct pico_tree_node *index = NULL; - struct pico_ipv6_link *link = NULL; - pico_tree_foreach(index, &IPV6Links) { - link = index->keyValue; - if (memcmp(link->address.addr, prefix->addr, nm64_len) == 0) - return link; - } - return NULL; -} - struct pico_ipv6_link *pico_ipv6_linklocal_get(struct pico_device *dev) { struct pico_ipv6_link *link = pico_ipv6_link_by_dev(dev); @@ -1580,58 +1330,6 @@ struct pico_ipv6_link *pico_ipv6_linklocal_get(struct pico_device *dev) return link; } -struct pico_ipv6_link *pico_ipv6_sitelocal_get(struct pico_device *dev) -{ - struct pico_ipv6_link *link = pico_ipv6_link_by_dev(dev); - while (link && !pico_ipv6_is_sitelocal(link->address.addr)) { - link = pico_ipv6_link_by_dev_next(dev, link); - } - return link; -} - -struct pico_ipv6_link *pico_ipv6_global_get(struct pico_device *dev) -{ - struct pico_ipv6_link *link = pico_ipv6_link_by_dev(dev); - while (link && !pico_ipv6_is_global(link->address.addr)) { - link = pico_ipv6_link_by_dev_next(dev, link); - } - return link; -} - -#define TWO_HOURS ((pico_time)(1000 * 60 * 60 * 2)) - -void pico_ipv6_check_lifetime_expired(pico_time now, void *arg) -{ - struct pico_tree_node *index = NULL, *temp; - struct pico_ipv6_link *link = NULL; - (void)arg; - pico_tree_foreach_safe(index, &IPV6Links, temp) { - link = index->keyValue; - if ((link->expire_time > 0) && (link->expire_time < now)) { - dbg("Warning: IPv6 address has expired.\n"); - pico_ipv6_link_del(link->dev, link->address); - } - } - pico_timer_add(1000, pico_ipv6_check_lifetime_expired, NULL); -} - -int pico_ipv6_lifetime_set(struct pico_ipv6_link *l, pico_time expire) -{ - pico_time now = PICO_TIME_MS(); - if (expire <= now) { - return -1; - } - - if (expire > 0xFFFFFFFE) { - l->expire_time = 0u; - }else if ((expire > (now + TWO_HOURS)) || (expire > l->expire_time)) { - l->expire_time = expire; - } else { - l->expire_time = now + TWO_HOURS; - } - - return 0; -} int pico_ipv6_dev_routing_enable(struct pico_device *dev) { diff --git a/modules/pico_ipv6.h b/modules/pico_ipv6.h index 0bc3fdcb3..a6b1f92e3 100644 --- a/modules/pico_ipv6.h +++ b/modules/pico_ipv6.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -44,8 +44,6 @@ struct pico_ipv6_link struct pico_ip6 netmask; uint8_t istentative : 1; uint8_t isduplicate : 1; - struct pico_timer *dad_timer; - pico_time expire_time; }; struct pico_ipv6_hbhoption { @@ -89,11 +87,11 @@ PACKED_STRUCT_DEF pico_ipv6_exthdr { uint8_t segleft; } routing; - PEDANTIC_STRUCT_DEF fragmentation_s { + PEDANTIC_STRUCT_DEF fragm_s { uint8_t res; - uint8_t om[2]; + uint8_t frm[2]; uint8_t id[4]; - } frag; + } fragm; } ext; }; @@ -102,7 +100,6 @@ int pico_string_to_ipv6(const char *ipstr, uint8_t *ip); int pico_ipv6_to_string(char *ipbuf, const uint8_t ip[PICO_SIZE_IP6]); int pico_ipv6_is_unicast(struct pico_ip6 *a); int pico_ipv6_is_multicast(const uint8_t addr[PICO_SIZE_IP6]); -int pico_ipv6_is_allhosts_multicast(const uint8_t addr[PICO_SIZE_IP6]); int pico_ipv6_is_global(const uint8_t addr[PICO_SIZE_IP6]); int pico_ipv6_is_uniquelocal(const uint8_t addr[PICO_SIZE_IP6]); int pico_ipv6_is_sitelocal(const uint8_t addr[PICO_SIZE_IP6]); @@ -110,11 +107,12 @@ int pico_ipv6_is_linklocal(const uint8_t addr[PICO_SIZE_IP6]); int pico_ipv6_is_solicited(const uint8_t addr[PICO_SIZE_IP6]); int pico_ipv6_is_unspecified(const uint8_t addr[PICO_SIZE_IP6]); -int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *src, struct pico_ip6 *dst, uint8_t proto, int is_dad); +int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *dst, uint8_t proto); +int pico_ipv6_rebound(struct pico_frame *f); int pico_ipv6_route_add(struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link); void pico_ipv6_unreachable(struct pico_frame *f, uint8_t code); -struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask); +int pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask); int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address); int pico_ipv6_cleanup_links(struct pico_device *dev); struct pico_ipv6_link *pico_ipv6_link_istentative(struct pico_ip6 *address); @@ -125,12 +123,6 @@ struct pico_ip6 *pico_ipv6_source_find(const struct pico_ip6 *dst); struct pico_device *pico_ipv6_source_dev_find(const struct pico_ip6 *dst); struct pico_ipv6_link *pico_ipv6_link_by_dev(struct pico_device *dev); struct pico_ipv6_link *pico_ipv6_link_by_dev_next(struct pico_device *dev, struct pico_ipv6_link *last); -struct pico_ipv6_link *pico_ipv6_global_get(struct pico_device *dev); -struct pico_ipv6_link *pico_ipv6_linklocal_get(struct pico_device *dev); -struct pico_ipv6_link *pico_ipv6_sitelocal_get(struct pico_device *dev); -struct pico_ipv6_link *pico_ipv6_prefix_configured(struct pico_ip6 *prefix); -int pico_ipv6_lifetime_set(struct pico_ipv6_link *l, pico_time expire); -void pico_ipv6_check_lifetime_expired(pico_time now, void *arg); int pico_ipv6_dev_routing_enable(struct pico_device *dev); int pico_ipv6_dev_routing_disable(struct pico_device *dev); #endif diff --git a/modules/pico_ipv6_nd.c b/modules/pico_ipv6_nd.c index eb6438655..d359116e0 100644 --- a/modules/pico_ipv6_nd.c +++ b/modules/pico_ipv6_nd.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -76,17 +76,6 @@ static void pico_ipv6_nd_queued_trigger(void) } } -static void ipv6_duplicate_detected(struct pico_ipv6_link *l) -{ - struct pico_device *dev; - int is_ll = pico_ipv6_is_linklocal(l->address.addr); - dev = l->dev; - dbg("IPV6: Duplicate address detected. Removing link.\n"); - pico_ipv6_link_del(l->dev, l->address); - if (is_ll) - pico_device_ipv6_random_ll(dev); -} - static struct pico_ipv6_neighbor *pico_nd_add(struct pico_ip6 *addr, struct pico_device *dev) { struct pico_ipv6_neighbor *n = PICO_ZALLOC(sizeof(struct pico_ipv6_neighbor)); @@ -132,25 +121,34 @@ static void pico_ipv6_nd_unreachable(struct pico_ip6 *a) static void pico_nd_new_expire_time(struct pico_ipv6_neighbor *n) { - if (n->state == PICO_ND_STATE_REACHABLE) - n->expire = PICO_TIME_MS() + PICO_ND_REACHABLE_TIME; - else if (n->state == PICO_ND_STATE_DELAY) + if (n->state == PICO_ND_STATE_INCOMPLETE) + n->expire = PICO_TIME_MS() + PICO_ND_DELAY_INCOMPLETE; + else if (n->state == PICO_ND_STATE_REACHABLE) + n->expire = PICO_TIME_MS() + PICO_ND_DESTINATION_LRU_TIME; + else if (n->state == PICO_ND_STATE_STALE) n->expire = PICO_TIME_MS() + PICO_ND_DELAY_FIRST_PROBE_TIME; - else { + else n->expire = n->dev->hostvars.retranstime + PICO_TIME_MS(); - } + + nd_dbg("Expiring in %lu ms \n", n->expire - PICO_TIME_MS()); +} + +static void pico_nd_new_expire_state(struct pico_ipv6_neighbor *n) +{ + if (n->state > PICO_ND_STATE_INCOMPLETE && n->state < PICO_ND_STATE_PROBE) + n->state++; } static void pico_nd_discover(struct pico_ipv6_neighbor *n) { - char IPADDR[64]; - if (n->expire != (pico_time)0) + if (n->expire != 0ull) return; - pico_ipv6_to_string(IPADDR, n->address.addr); - /* dbg("Sending NS for %s\n", IPADDR); */ - if (++n->failure_count > PICO_ND_MAX_SOLICIT) + if (++n->failure_count > PICO_ND_MAX_SOLICIT) { + pico_ipv6_nd_unreachable(&n->address); + pico_tree_delete(&NCache, n); return; + } if (n->state == PICO_ND_STATE_INCOMPLETE) { pico_icmp6_neighbor_solicitation(n->dev, &n->address, PICO_ICMP6_ND_SOLICITED); @@ -158,13 +156,12 @@ static void pico_nd_discover(struct pico_ipv6_neighbor *n) pico_icmp6_neighbor_solicitation(n->dev, &n->address, PICO_ICMP6_ND_UNICAST); } + pico_nd_new_expire_state(n); pico_nd_new_expire_time(n); } static struct pico_eth *pico_nd_get_neighbor(struct pico_ip6 *addr, struct pico_ipv6_neighbor *n, struct pico_device *dev) { - /* dbg("Finding neighbor %02x:...:%02x, state = %d\n", addr->addr[0], addr->addr[15], n?n->state:-1); */ - if (!n) { n = pico_nd_add(addr, dev); pico_nd_discover(n); @@ -175,14 +172,6 @@ static struct pico_eth *pico_nd_get_neighbor(struct pico_ip6 *addr, struct pico_ return NULL; } - if (n->state == PICO_ND_STATE_STALE) { - n->state = PICO_ND_STATE_DELAY; - pico_nd_new_expire_time(n); - } - - if (n->state != PICO_ND_STATE_REACHABLE) - pico_nd_discover(n); - return &n->mac; } @@ -214,45 +203,41 @@ static int neigh_options(struct pico_frame *f, struct pico_icmp6_opt_lladdr *opt struct pico_icmp6_hdr *icmp6_hdr = NULL; int len; uint8_t type; - int found = 0; icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; optlen = f->transport_len - PICO_ICMP6HDR_NEIGH_ADV_SIZE; if (optlen) option = icmp6_hdr->msg.info.neigh_adv.options; + while (optlen > 0) { type = ((struct pico_icmp6_opt_lladdr *)option)->type; len = ((struct pico_icmp6_opt_lladdr *)option)->len; - optlen -= len << 3; /* len in units of 8 octets */ + optlen -= len * 8; /* len in units of 8 octets */ if (len <= 0) - return -1; /* malformed option. */ + return -1; if (type == expected_opt) { - if (found > 0) - return -1; /* malformed option: option is there twice. */ - - memcpy(opt, (struct pico_icmp6_opt_lladdr *)option, (size_t)(len << 3)); - found++; - } - - if (optlen > 0) { - option += len << 3; - } else { /* parsing options: terminated. */ - return found; + memcpy(opt, (struct pico_icmp6_opt_lladdr *)option, sizeof(struct pico_icmp6_opt_lladdr)); + break; + } else if (optlen > 0) { + option += len * 8; + } else { /* no target link-layer address option */ + return -1; } } - return found; + return 0; } -static void pico_ipv6_neighbor_update(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt) +static int neigh_adv_complete(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt) { - memcpy(n->mac.addr, opt->addr.mac.addr, PICO_SIZE_ETH); -} + if (!opt) + return -1; -static int pico_ipv6_neighbor_compare_stored(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt) -{ - return memcmp(n->mac.addr, opt->addr.mac.addr, PICO_SIZE_ETH); + memcpy(n->mac.addr, opt->addr.mac.addr, PICO_SIZE_ETH); + n->state = PICO_ND_STATE_REACHABLE; + pico_ipv6_nd_queued_trigger(); + return 0; } static void neigh_adv_reconfirm_router_option(struct pico_ipv6_neighbor *n, unsigned int isRouter) @@ -265,65 +250,30 @@ static void neigh_adv_reconfirm_router_option(struct pico_ipv6_neighbor *n, unsi static int neigh_adv_reconfirm(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt, struct pico_icmp6_hdr *hdr) { - if (IS_SOLICITED(hdr) && !IS_OVERRIDE(hdr) && (pico_ipv6_neighbor_compare_stored(n, opt) == 0)) { - n->state = PICO_ND_STATE_REACHABLE; - n->failure_count = 0; - pico_ipv6_nd_queued_trigger(); - pico_nd_new_expire_time(n); - return 0; - } - - - if ((n->state == PICO_ND_STATE_REACHABLE) && IS_SOLICITED(hdr) && !IS_OVERRIDE(hdr)) { - n->state = PICO_ND_STATE_STALE; - return 0; - } - - if (IS_SOLICITED(hdr) && IS_OVERRIDE(hdr)) { - pico_ipv6_neighbor_update(n, opt); - n->state = PICO_ND_STATE_REACHABLE; - n->failure_count = 0; - pico_ipv6_nd_queued_trigger(); - pico_nd_new_expire_time(n); - return 0; - } - - if (!IS_SOLICITED(hdr) && IS_OVERRIDE(hdr) && (pico_ipv6_neighbor_compare_stored(n, opt) != 0)) { - pico_ipv6_neighbor_update(n, opt); - n->state = PICO_ND_STATE_STALE; - pico_ipv6_nd_queued_trigger(); - return 0; + if (!IS_OVERRIDE(hdr)) { + if (memcmp(opt->addr.mac.addr, n->mac.addr, PICO_SIZE_ETH) != 0) + n->state = PICO_ND_STATE_STALE; + } else { + n->mac = opt->addr.mac; } - return -1; + neigh_adv_reconfirm_router_option(n, IS_ROUTER(hdr)); + return 0; } -static void neigh_adv_process_incomplete(struct pico_ipv6_neighbor *n, struct pico_frame *f, struct pico_icmp6_opt_lladdr *opt) +static void neigh_adv_check_solicited(struct pico_icmp6_hdr *ic6, struct pico_ipv6_neighbor *n) { - struct pico_icmp6_hdr *icmp6_hdr = NULL; - if (!n || !f) - return; - - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - - if (!icmp6_hdr) - return; - - if (IS_SOLICITED(icmp6_hdr)) { + /* is a response to a solicitation? */ + if (IS_SOLICITED(ic6)) { n->state = PICO_ND_STATE_REACHABLE; n->failure_count = 0; - pico_nd_new_expire_time(n); } else { n->state = PICO_ND_STATE_STALE; } - if (opt) - pico_ipv6_neighbor_update(n, opt); - - pico_ipv6_nd_queued_trigger(); + pico_nd_new_expire_time(n); } - static int neigh_adv_process(struct pico_frame *f) { struct pico_icmp6_hdr *icmp6_hdr = NULL; @@ -331,34 +281,29 @@ static int neigh_adv_process(struct pico_frame *f) struct pico_icmp6_opt_lladdr opt = { 0 }; - int optres = neigh_options(f, &opt, PICO_ND_OPT_LLADDR_TGT); + icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - if (optres < 0) { /* Malformed packet: option field cannot be processed. */ - return -1; - } n = pico_nd_find_neighbor(&icmp6_hdr->msg.info.neigh_adv.target); - if (!n) { - return 0; - } + if (!n) + return -1; - if (optres == 0) { - neigh_adv_reconfirm_router_option(n, IS_ROUTER(icmp6_hdr)); - return 0; - } + if (neigh_options(f, &opt, PICO_ND_OPT_LLADDR_TGT) < 0) + return -1; - if (n->state == PICO_ND_STATE_INCOMPLETE) { - neigh_adv_process_incomplete(n, f, &opt); - return 0; - } + if (n->state == PICO_ND_STATE_INCOMPLETE) + neigh_adv_complete(n, &opt); + else + neigh_adv_reconfirm(n, &opt, icmp6_hdr); - return neigh_adv_reconfirm(n, &opt, icmp6_hdr); + neigh_adv_check_solicited(icmp6_hdr, n); + return 0; } -static struct pico_ipv6_neighbor *pico_ipv6_neighbor_from_sol_new(struct pico_ip6 *ip, struct pico_icmp6_opt_lladdr *opt, struct pico_device *dev) +static struct pico_ipv6_neighbor *neighbor_from_sol_new(struct pico_ip6 *ip, struct pico_icmp6_opt_lladdr *opt, struct pico_device *dev) { struct pico_ipv6_neighbor *n = NULL; n = pico_nd_add(ip, dev); @@ -366,90 +311,42 @@ static struct pico_ipv6_neighbor *pico_ipv6_neighbor_from_sol_new(struct pico_ip return NULL; memcpy(n->mac.addr, opt->addr.mac.addr, PICO_SIZE_ETH); - n->state = PICO_ND_STATE_STALE; - pico_ipv6_nd_queued_trigger(); + n->state = PICO_ND_STATE_REACHABLE; return n; } -static void pico_ipv6_neighbor_from_unsolicited(struct pico_frame *f) +static void neighbor_from_sol(struct pico_ip6 *ip, struct pico_icmp6_opt_lladdr *opt, struct pico_device *dev) { struct pico_ipv6_neighbor *n = NULL; - struct pico_icmp6_opt_lladdr opt = { - 0 - }; - struct pico_ipv6_hdr *ip = (struct pico_ipv6_hdr *)f->net_hdr; - int valid_lladdr = neigh_options(f, &opt, PICO_ND_OPT_LLADDR_SRC); - - if (!pico_ipv6_is_unspecified(ip->src.addr) && (valid_lladdr > 0)) { - n = pico_nd_find_neighbor(&ip->src); + /* Hello, neighbor! */ + if (!pico_ipv6_is_unspecified(ip->addr) && opt) { + n = pico_nd_find_neighbor(ip); if (!n) { - n = pico_ipv6_neighbor_from_sol_new(&ip->src, &opt, f->dev); - } else if (memcmp(opt.addr.mac.addr, n->mac.addr, PICO_SIZE_ETH)) { - pico_ipv6_neighbor_update(n, &opt); - if (n->state != PICO_ND_STATE_INCOMPLETE) { - n->state = PICO_ND_STATE_STALE; - } - - pico_ipv6_nd_queued_trigger(); + n = neighbor_from_sol_new(ip, opt, dev); + } else if (memcmp(opt->addr.mac.addr, n->mac.addr, PICO_SIZE_ETH)) { + memcpy(n->mac.addr, opt->addr.mac.addr, PICO_SIZE_ETH); + n->state = PICO_ND_STATE_STALE; } if (!n) return; - } -} -static int neigh_sol_detect_dad(struct pico_frame *f) -{ - struct pico_ipv6_hdr *ipv6_hdr = NULL; - struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_ipv6_link *link = NULL; - ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - link = pico_ipv6_link_istentative(&icmp6_hdr->msg.info.neigh_adv.target); - if (link) { - if (pico_ipv6_is_unicast(&ipv6_hdr->src)) - { - /* RFC4862 5.4.3 : sender is performing address resolution, - * our address is not yet valid, discard silently. - */ - dbg("DAD:Sender performing AR\n"); - } - - else if (pico_ipv6_is_unspecified(ipv6_hdr->src.addr) && - !pico_ipv6_is_allhosts_multicast(ipv6_hdr->dst.addr)) - { - /* RFC4862 5.4.3 : sender is performing DaD */ - dbg("DAD:Sender performing DaD\n"); - ipv6_duplicate_detected(link); - } - - return 0; + pico_nd_new_expire_time(n); } - - return -1; /* Current link is not tentative */ } static int neigh_sol_process(struct pico_frame *f) { + struct pico_ipv6_hdr *ipv6_hdr = NULL; struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_ipv6_link *link = NULL; - int valid_lladdr; struct pico_icmp6_opt_lladdr opt = { 0 }; + ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - - valid_lladdr = neigh_options(f, &opt, PICO_ND_OPT_LLADDR_SRC); - pico_ipv6_neighbor_from_unsolicited(f); - - if ((valid_lladdr == 0) && (neigh_sol_detect_dad(f) == 0)) - return 0; - - if (valid_lladdr < 0) - return -1; /* Malformed packet. */ - - link = pico_ipv6_link_get(&icmp6_hdr->msg.info.neigh_adv.target); - if (!link) { /* Not for us. */ + neigh_options(f, &opt, PICO_ND_OPT_LLADDR_SRC); + neighbor_from_sol(&ipv6_hdr->src, &opt, f->dev); + if (!pico_ipv6_link_get(&icmp6_hdr->msg.info.neigh_adv.target)) { /* Not for us. */ return -1; } @@ -466,65 +363,30 @@ static int icmp6_initial_checks(struct pico_frame *f) ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - /* RFC4861 - 7.1.2 : - * - The IP Hop Limit field has a value of 255, i.e., the packet - * could not possibly have been forwarded by a router. - * - ICMP Checksum is valid. - * - ICMP Code is 0. - */ if (ipv6_hdr->hop != 255 || pico_icmp6_checksum(f) != 0 || icmp6_hdr->code != 0) return -1; return 0; } -static int neigh_adv_option_len_validity_check(struct pico_frame *f) -{ - /* Step 4 validation */ - struct pico_icmp6_hdr *icmp6_hdr = NULL; - uint8_t *opt; - int optlen = f->transport_len - PICO_ICMP6HDR_NEIGH_ADV_SIZE; - /* RFC4861 - 7.1.2 : - * - All included options have a length that is greater than zero. - */ - icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; - opt = icmp6_hdr->msg.info.neigh_adv.options; - - while(optlen > 0) { - int opt_size = (opt[1] << 3); - if (opt_size == 0) - return -1; - - opt = opt + opt_size; - optlen -= opt_size; - } - return 0; -} - static int neigh_adv_mcast_validity_check(struct pico_frame *f) { /* Step 3 validation */ struct pico_ipv6_hdr *ipv6_hdr = NULL; struct pico_icmp6_hdr *icmp6_hdr = NULL; - /* RFC4861 - 7.1.2 : - * - If the IP Destination Address is a multicast address the - * Solicited flag is zero. - */ + ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; if (pico_ipv6_is_multicast(ipv6_hdr->dst.addr) && IS_SOLICITED(icmp6_hdr)) return -1; - return neigh_adv_option_len_validity_check(f); + return 0; } static int neigh_adv_validity_checks(struct pico_frame *f) { /* Step 2 validation */ - /* RFC4861 - 7.1.2: - * - ICMP length (derived from the IP length) is 24 or more octets. - */ - if (f->transport_len < PICO_ICMP6HDR_NEIGH_ADV_SIZE) + if (f->transport_len < PICO_ICMP6HDR_NEIGH_SOL_SIZE) return -1; return neigh_adv_mcast_validity_check(f); @@ -557,13 +419,6 @@ static int neigh_sol_unicast_validity_check(struct pico_frame *f) { struct pico_ipv6_link *link; struct pico_icmp6_hdr *icmp6_hdr = NULL; - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr; - - if (pico_ipv6_is_unspecified(hdr->src.addr)) { - dbg("Warning: Received unicast NS with unspecified source address!\n"); - return -1; - } - link = pico_ipv6_link_by_dev(f->dev); icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; while(link) { @@ -595,7 +450,6 @@ static int router_adv_validity_checks(struct pico_frame *f) /* Step 2 validation */ if (f->transport_len < PICO_ICMP6HDR_ROUTER_ADV_SIZE) return -1; - return 0; } @@ -611,24 +465,21 @@ static int neigh_adv_checks(struct pico_frame *f) static int pico_nd_router_sol_recv(struct pico_frame *f) { - pico_ipv6_neighbor_from_unsolicited(f); /* Host only: router solicitation is discarded. */ + (void)f; return 0; } static int radv_process(struct pico_frame *f) { struct pico_icmp6_hdr *icmp6_hdr = NULL; + struct pico_ipv6_hdr *ipv6_hdr = NULL; + struct pico_ip6 netmask = {{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0,0,0,0,0,0,0,0}}; uint8_t *nxtopt, *opt_start; - struct pico_ipv6_link *link; - struct pico_ipv6_hdr *hdr; - struct pico_ip6 zero = { - .addr = {0} - }; int optlen; - hdr = (struct pico_ipv6_hdr *)f->net_hdr; icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr; + ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; optlen = f->transport_len - PICO_ICMP6HDR_ROUTER_ADV_SIZE; opt_start = (uint8_t *)icmp6_hdr->msg.info.router_adv.options; nxtopt = opt_start; @@ -636,114 +487,74 @@ static int radv_process(struct pico_frame *f) while (optlen > 0) { uint8_t *type = (uint8_t *)nxtopt; switch (*type) { - case PICO_ND_OPT_PREFIX: - { - pico_time now = PICO_TIME_MS(); - struct pico_icmp6_opt_prefix *prefix = - (struct pico_icmp6_opt_prefix *) nxtopt; - /* RFC4862 5.5.3 */ - /* a) If the Autonomous flag is not set, silently ignore the Prefix - * Information option. - */ - if (prefix->aac == 0) - goto ignore_opt_prefix; - - /* b) If the prefix is the link-local prefix, silently ignore the - * Prefix Information option - */ - if (pico_ipv6_is_linklocal(prefix->prefix.addr)) - goto ignore_opt_prefix; - - /* c) If the preferred lifetime is greater than the valid lifetime, - * silently ignore the Prefix Information option - */ - if (long_be(prefix->pref_lifetime) > long_be(prefix->val_lifetime)) - goto ignore_opt_prefix; - - if (prefix->val_lifetime <= 0) - goto ignore_opt_prefix; - - - if (prefix->prefix_len != 64) { - return -1; - } - - link = pico_ipv6_prefix_configured(&prefix->prefix); - if (link) { - pico_ipv6_lifetime_set(link, now + (pico_time)(1000 * (long_be(prefix->val_lifetime)))); - goto ignore_opt_prefix; - } - - link = pico_ipv6_link_add_local(f->dev, &prefix->prefix); - if (link) { - pico_ipv6_lifetime_set(link, now + (pico_time)(1000 * (long_be(prefix->val_lifetime)))); - pico_ipv6_route_add(zero, zero, hdr->src, 10, link); - } - -ignore_opt_prefix: - optlen -= (prefix->len << 3); - nxtopt += (prefix->len << 3); - } - break; - case PICO_ND_OPT_LLADDR_SRC: - { - struct pico_icmp6_opt_lladdr *lladdr_src = - (struct pico_icmp6_opt_lladdr *) nxtopt; - optlen -= (lladdr_src->len << 3); - nxtopt += (lladdr_src->len << 3); - } - break; - case PICO_ND_OPT_MTU: - { - struct pico_icmp6_opt_mtu *mtu = - (struct pico_icmp6_opt_mtu *) nxtopt; - /* Skip this */ - optlen -= (mtu->len << 3); - nxtopt += (mtu->len << 3); - } - break; - case PICO_ND_OPT_REDIRECT: - { - struct pico_icmp6_opt_redirect *redirect = - (struct pico_icmp6_opt_redirect *) nxtopt; - /* Skip this */ - optlen -= (redirect->len << 3); - nxtopt += (redirect->len << 3); + case PICO_ND_OPT_PREFIX: + { + struct pico_icmp6_opt_prefix *prefix = + (struct pico_icmp6_opt_prefix *) nxtopt; + if (prefix->val_lifetime > 0) { + if (prefix->prefix_len == 64) { + pico_ipv6_route_add(prefix->prefix, netmask, ipv6_hdr->src, 1, NULL); + } else { + pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, + (uint32_t)sizeof(struct pico_ipv6_hdr) + (uint32_t)PICO_ICMP6HDR_ROUTER_ADV_SIZE + (uint32_t)(nxtopt - opt_start)); + return -1; + } + } + optlen -= (prefix->len << 3); + nxtopt += (prefix->len << 3); + } + break; + case PICO_ND_OPT_LLADDR_SRC: + { + struct pico_icmp6_opt_lladdr *lladdr_src = + (struct pico_icmp6_opt_lladdr *) nxtopt; + optlen -= (lladdr_src->len << 3); + nxtopt += (lladdr_src->len << 3); + } + break; + case PICO_ND_OPT_MTU: + { + struct pico_icmp6_opt_mtu *mtu = + (struct pico_icmp6_opt_mtu *) nxtopt; + /* Skip this */ + optlen -= (mtu->len << 3); + nxtopt += (mtu->len << 3); + } + break; + case PICO_ND_OPT_REDIRECT: + { + struct pico_icmp6_opt_redirect *redirect = + (struct pico_icmp6_opt_redirect *) nxtopt; + /* Skip this */ + optlen -= (redirect->len << 3); + nxtopt += (redirect->len << 3); - } - break; - case PICO_ND_OPT_RDNSS: - { - struct pico_icmp6_opt_rdnss *rdnss = - (struct pico_icmp6_opt_rdnss *) nxtopt; - /* Skip this */ - optlen -= (rdnss->len << 3); - nxtopt += (rdnss->len << 3); - } - break; - default: - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, - (uint32_t)sizeof(struct pico_ipv6_hdr) + (uint32_t)PICO_ICMP6HDR_ROUTER_ADV_SIZE + (uint32_t)(nxtopt - opt_start)); - return -1; + } + break; + case PICO_ND_OPT_RDNSS: + { + struct pico_icmp6_opt_rdnss *rdnss = + (struct pico_icmp6_opt_rdnss *) nxtopt; + /* Skip this */ + optlen -= (rdnss->len << 3); + nxtopt += (rdnss->len << 3); + } + break; + default: + pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, + (uint32_t)sizeof(struct pico_ipv6_hdr) + (uint32_t)PICO_ICMP6HDR_ROUTER_ADV_SIZE + (uint32_t)(nxtopt - opt_start)); + return -1; } } - if (icmp6_hdr->msg.info.router_adv.retrans_time != 0u) { - f->dev->hostvars.retranstime = long_be(icmp6_hdr->msg.info.router_adv.retrans_time); - } - return 0; } - static int pico_nd_router_adv_recv(struct pico_frame *f) { if (icmp6_initial_checks(f) < 0) return -1; - if (router_adv_validity_checks(f) < 0) return -1; - - pico_ipv6_neighbor_from_unsolicited(f); return radv_process(f); } @@ -770,53 +581,18 @@ static int pico_nd_neigh_adv_recv(struct pico_frame *f) link = pico_ipv6_link_istentative(&icmp6_hdr->msg.info.neigh_adv.target); if (link) - ipv6_duplicate_detected(link); + link->isduplicate = 1; return neigh_adv_process(f); } static int pico_nd_redirect_recv(struct pico_frame *f) { - pico_ipv6_neighbor_from_unsolicited(f); + (void)f; /* TODO */ return 0; } -static void pico_ipv6_nd_timer_elapsed(pico_time now, struct pico_ipv6_neighbor *n) -{ - (void)now; - switch(n->state) { - case PICO_ND_STATE_INCOMPLETE: - /* intentional fall through */ - case PICO_ND_STATE_PROBE: - if (n->failure_count > PICO_ND_MAX_SOLICIT) { - pico_ipv6_nd_unreachable(&n->address); - pico_tree_delete(&NCache, n); - return; - } - - n->expire = 0ull; - pico_nd_discover(n); - break; - - case PICO_ND_STATE_REACHABLE: - n->state = PICO_ND_STATE_STALE; - /* dbg("IPv6_ND: neighbor expired!\n"); */ - return; - - case PICO_ND_STATE_STALE: - break; - - case PICO_ND_STATE_DELAY: - n->expire = 0ull; - n->state = PICO_ND_STATE_PROBE; - break; - default: - dbg("IPv6_ND: neighbor in wrong state!\n"); - } - pico_nd_new_expire_time(n); -} - static void pico_ipv6_nd_timer_callback(pico_time now, void *arg) { struct pico_tree_node *index = NULL, *_tmp = NULL; @@ -827,7 +603,8 @@ static void pico_ipv6_nd_timer_callback(pico_time now, void *arg) { n = index->keyValue; if ( now > n->expire) { - pico_ipv6_nd_timer_elapsed(now, n); + n->expire = 0ull; + pico_nd_discover(n); } } pico_timer_add(200, pico_ipv6_nd_timer_callback, NULL); @@ -888,25 +665,14 @@ struct pico_eth *pico_ipv6_get_neighbor(struct pico_frame *f) void pico_ipv6_nd_postpone(struct pico_frame *f) { int i; - static int last_enq = -1; - struct pico_frame *cp = pico_frame_copy(f); for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++) { if (!frames_queued_v6[i]) { - frames_queued_v6[i] = cp; - last_enq = i; + frames_queued_v6[i] = pico_frame_copy(f); return; } } - /* Overwrite the oldest frame in the buffer */ - if (++last_enq >= PICO_ND_MAX_FRAMES_QUEUED) { - last_enq = 0; - } - - if (frames_queued_v6[last_enq]) - pico_frame_discard(frames_queued_v6[last_enq]); - - frames_queued_v6[last_enq] = cp; + /* Not possible to enqueue: caller will discard */ } @@ -947,7 +713,6 @@ void pico_ipv6_nd_init(void) { pico_timer_add(200, pico_ipv6_nd_timer_callback, NULL); pico_timer_add(200, pico_ipv6_nd_ra_timer_callback, NULL); - pico_timer_add(1000, pico_ipv6_check_lifetime_expired, NULL); } #endif diff --git a/modules/pico_ipv6_nd.h b/modules/pico_ipv6_nd.h index f709b1eaa..29bd50e40 100644 --- a/modules/pico_ipv6_nd.h +++ b/modules/pico_ipv6_nd.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. *********************************************************************/ diff --git a/modules/pico_mdns b/modules/pico_mdns new file mode 100644 index 000000000..f09e17167 --- /dev/null +++ b/modules/pico_mdns @@ -0,0 +1,1410 @@ +/********************************************************************* + PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved. + See LICENSE and COPYING for usage. + . + Author: Toon Stegen + *********************************************************************/ + +/* picoTCP */ +#include "pico_config.h" +#include "pico_stack.h" +#include "pico_addressing.h" +#include "pico_socket.h" +#include "pico_ipv4.h" +#include "pico_ipv6.h" +#include "pico_mdns.h" +#include "pico_dns_common.h" +#include "pico_tree.h" + +#ifdef PICO_SUPPORT_MDNS + +/* Debugging */ +//#define mdns_dbg(...) do {} while(0) +#define mdns_dbg dbg + +#define PICO_MDNS_QUERY_TIMEOUT (10000) /* Ten seconds */ +#define PICO_MDNS_RR_TTL_TICK (1000) /* One second */ + +/* mDNS MTU size */ +#define PICO_MDNS_MTU 1400u + +/* Constant strings */ +#define PICO_ARPA_IPV4_SUFFIX ".in-addr.arpa" +#define PICO_ARPA_IPV6_SUFFIX ".IP6.ARPA" +#define PICO_OK_STRING "OK" +#define PICO_NOK_STRING "NOK" +#define PICO_SOK_STRING "SOK" + +/* Question flags */ +#define PICO_MDNS_QUESTION_FLAG_PROBE 0x01u +#define PICO_MDNS_QUESTION_FLAG_NO_PROBE 0x00u +#define PICO_MDNS_QUESTION_FLAG_UNICAST_RES 0x02u +#define PICO_MDNS_QUESTION_FLAG_MULTICAST_RES 0x00u + +#define IS_QUESTION_PROBE_FLAG_SET(x) (((x) & PICO_MDNS_QUESTION_FLAG_UNICAST_RES) ? 1 : 0 ) +#define IS_QUESTION_UNICAST_FLAG_SET(x) (((x) & PICO_MDNS_QUESTION_FLAG_PROBE) ? 1 : 0 ) +#define IS_QUESTION_MULTICAST_FLAG_SET(x) (((x) & PICO_MDNS_QUESTION_FLAG_PROBE) ? 0 : 1 ) + +/* Resource Record flags */ +#define PICO_MDNS_RES_RECORD_PROBED 0x40u +#define PICO_MDNS_RES_RECORD_CLAIMED 0x80u + +#define IS_RES_RECORD_FLAG_CLAIM_SHARED_SET(x) (((x) & PICO_MDNS_RES_RECORD_SHARED) ? 1 : 0) +#define IS_RES_RECORD_FLAG_CLAIM_UNIQUE_SET(x) (((x) & PICO_MDNS_RES_RECORD_SHARED) ? 0 : 1) +#define IS_RES_RECORD_FLAG_PROBED_SET(x) (((x) & PICO_MDNS_RES_RECORD_PROBING_STATE) ? 1 : 0) + +#define PICO_MDNS_RES_RECORD_SET_PROBED(x) (x = ((x) | (uint8_t)PICO_MDNS_RES_RECORD_PROBED)) +#define PICO_MDNS_RES_RECORD_CLR_PROBED(x) (x = ((x) & (~((uint8_t)PICO_MDNS_RES_RECORD_PROBED)) + +static struct pico_ip4 inaddr_any = { 0 }; + +/* Global socket and port for all mdns communication */ +static struct pico_socket *mdns_sock_ipv4 = NULL; + +/* RFC: + * fully compliant mDNS Querier MUST send its Multicast DNS queries from + * UDP source port 5353, and MUST listen for Multicast DNS replies sent + * to UDP destination port 5353 at the mDNS link-local multicast address + * (224.0.0.251 and/or its IPv6 equivalent FF02::FB) + */ +static uint16_t mdns_port = 5353u; + +/* struct containing status of a query */ +struct pico_mdns_cookie +{ + pico_dns_packet *packet; // Pointer to DNS packet + char *qname; // Hostname being queried + uint16_t qtype; // qtype + uint16_t qclass; // qclass + uint8_t count; // Number of packets to send + uint8_t flags; // Flags: ... | uni/multi | probe | + uint16_t len; // Length of packet + struct pico_timer *timer; // For Timer events + void (*callback)(char *, void *); // MARK: Callback + void *arg; // Argument to pass to callback +}; + +/* struct containing the information about a cache record */ +struct pico_mdns_cache_rr +{ + char *url; // Hostname + struct pico_dns_res_record_suffix *suf; // Type, Class, TTL and rdata length + char *rdata; // Resource Record Data + struct pico_timer *timer; // For Timer events +}; + +/* ************************************************************************** + * Compare-function for two cache entries to give to the tree + * **************************************************************************/ +static int mdns_cache_cmp(void *ka, void *kb) +{ + struct pico_mdns_cache_rr *a = ka, *b = kb; + uint32_t ha = 0, hb = 0; + + /* Cache is sorted by qtype, name */ + if(a->suf->rtype < b->suf->rtype) + return -1; + if(b->suf->rtype < a->suf->rtype) + return 1; + + /* Hash strings to compare */ + ha = pico_hash(a->url, (uint32_t)strlen(a->url)); + hb = pico_hash(b->url, (uint32_t)strlen(b->url)); + + if(ha < hb) + return -1; + if(hb < ha) + return 1; + + return 0; +} + +/* ************************************************************************** + * Compare-function for two query-cookies to give to the tree + * **************************************************************************/ +static int mdns_cmp(void *ka, void *kb) +{ + struct pico_mdns_cookie *a = ka, *b = kb; + uint32_t ha = 0, hb = 0; + + /* Cookie is sorted by qtype, name */ + if(a->qtype < b->qtype) + return -1; + if(b->qtype < a->qtype) + return 1; + + /* Hash strings to compare */ + ha = pico_hash(a->qname, (uint32_t)strlen(a->qname)); + hb = pico_hash(b->qname, (uint32_t)strlen(b->qname)); + + if(ha < hb) + return -1; + if(hb < ha) + return 1; + + return 0; +} + +/* ************************************************************************** + * Compare-function for two mDNS resource records to give to a tree + * **************************************************************************/ +static int mdns_res_record_cmp( void *rra, void *rrb ) +{ + struct pico_mdns_res_record *a = (struct pico_mdns_res_record *)rra; + struct pico_mdns_res_record *b = (struct pico_mdns_res_record *)rrb; + uint32_t ha = 0, hb = 0; + + /* Lexicraphically qtype first */ + if (a->record->rsuffix->rtype < b->record->rsuffix->rtype) + return -1; + if (a->record->rsuffix->rtype > b->record->rsuffix->rtype) + return 1; + + /* Then hash strings to compare */ + ha = pico_hash(a->record->rname, (uint32_t)strlen(a->record->rname)); + hb = pico_hash(b->record->rname, (uint32_t)strlen(b->record->rname)); + + /* Compare hashes */ + if (ha < hb) + return -1; + if (hb < ha) + return 1; + + return 0; +} + +/* Cache records for the mDNS hosts in the network */ +PICO_TREE_DECLARE(CacheTable, mdns_cache_cmp); + +/* Tree containing query-cookies */ +PICO_TREE_DECLARE(QTable, mdns_cmp); + +/* Tree contain records I want to claim */ +PICO_TREE_DECLARE(MyRecordsTable, mdns_res_record_cmp); + +// MARK: MDNS PACKET UTILITIES + +/* Sends an mdns packet on the global socket*/ +static int pico_mdns_send_packet(pico_dns_packet *packet, uint16_t len) +{ + struct pico_ip4 dst4; + + /* Send packet to IPv4 socket */ + pico_string_to_ipv4(PICO_MDNS_DEST_ADDR4, &dst4.addr); + return pico_socket_sendto(mdns_sock_ipv4, packet, (int)len, &dst4, short_be(mdns_port)); +} + +#ifdef PICO_SUPPORT_IPV6 +static struct pico_ip6 *pico_get_ip6_from_ip4(struct pico_ip4 *ipv4_addr) +{ + struct pico_device *dev = NULL; + struct pico_ipv6_link *link = NULL; + if((dev = pico_ipv4_link_find(ipv4_addr)) == NULL) { + mdns_dbg("Could not find device!\n"); + return NULL; + } + + if((link = pico_ipv6_link_by_dev(dev)) == NULL) { + mdns_dbg("Could not find link!\n"); + return NULL; + } + + return &link->address; +} +#endif + +// MARK: QUESTION UTILITIES + +static struct pico_dns_question *pico_mdns_question_create( const char *url, uint16_t *len, uint8_t proto, uint16_t qtype, uint8_t flags ) +{ + /* Some variables */ + uint16_t _qtype = 0; + uint16_t qclass = 0; + uint16_t qclass_MSB = 0; + + /* Set the MSB of the qclass field according to the mDNS format */ + if (IS_QUESTION_UNICAST_FLAG_SET(flags)) + qclass_MSB = (uint16_t) 0x8000; + else + qclass_MSB = (uint16_t) 0x0000; + + /* Set the bit */ + qclass = (uint16_t) PICO_DNS_CLASS_IN; + qclass |= qclass_MSB; + + /* Fill in the question suffix */ + if (IS_QUESTION_PROBE_FLAG_SET(flags)) { + /* RFC: + * All probe queries SHOULD be done using the desired resource + * record name and class (usually class 1, "Internet"), and + * query type "ANY" (255), to elicit answers for all + * types of records with that name. + */ + _qtype = PICO_DNS_TYPE_ANY; + } else { + _qtype = qtype; + } + + /* Create a question as you would with plain DNS */ + return pico_dns_question_create(url, len, proto, _qtype, qclass); +} + +// MARK: MDNS QUERY UTILITIES + +/* ************************************************************************** + * Creates a DNS packet meant for querying. Currently only questions can be + * inserted in the packet. + * + * TODO: Allow resource records to be added to Authority & Answer Section + * - Answer Section: To implement Known-Answer Suppression + * - Authority Section: To implement probe queries and tiebreaking + * **************************************************************************/ +static pico_dns_packet *pico_mdns_query_create( struct pico_dns_question *question_list, struct pico_dns_res_record *answer_list, struct pico_dns_res_record *authority_list, struct pico_dns_res_record *additional_list, uint16_t *len ) +{ + pico_dns_packet *packet = NULL; + + /* Create an answer as you would with plain DNS */ + packet = pico_dns_query_create(question_list, answer_list, authority_list, additional_list, len); + if (!packet) { + mdns_dbg("Could not create DNS query!\n"); + return NULL; + } + + /* Set the id of the DNS packet to 0 */ + packet->id = 0; + + return packet; +} + +// MARK: RRECORD UTILITIES + +/* ************************************************************************** + * Create a resource record for the mDNS resource record format, that is + * with the MSB of the rclass field being set accordingly. + * **************************************************************************/ +static struct pico_dns_res_record *pico_mdns_rr_create( const char *url, + void *_rdata, + uint16_t *len, + uint16_t rtype, + uint16_t rttl, + uint8_t flags ) +{ + uint16_t rclass_MSB; + uint16_t rclass; + + /* Set the MSB of the rclass field according to the mDNS format */ + if (IS_RES_RECORD_FLAG_CLAIM_UNIQUE_SET(flags)) + rclass_MSB = (uint16_t) 0x8000; + else + rclass_MSB = (uint16_t) 0x0000; + + /* Set the bit */ + rclass = (uint16_t) PICO_DNS_CLASS_IN; + rclass |= rclass_MSB; + + /* Create a resource record as you would with plain DNS */ + return pico_dns_rr_create(url, _rdata, len, rtype, rclass, rttl); +} + +/* ************************************************************************** + * Creates a new mDNS resource record for which you want to have the + * authority, and adds it to the end of the [records] list. If a NULL- + * pointer is provided a new list will be created. Fills up len with the + * size of the DNS record + * **************************************************************************/ +int pico_mdns_res_record_create( pico_mdns_res_record_list *records, + const char *url, + void *_rdata, + uint16_t *len, + uint16_t rtype, + uint16_t rttl, + uint8_t flags ) +{ + pico_mdns_res_record *iterator = NULL; // Iterator for the list + + /* Put iterator at beginning of list */ + iterator = records; + + /* Move to the end of the list */ + while (iterator != NULL) { + iterator = iterator->next; + } + + /* Provide space for the new mDNS resource record */ + iterator = PICO_ZALLOC(sizeof(struct pico_mdns_res_record)); + if (!iterator) { + pico_err = PICO_ERR_ENOMEM; + return -1; + } + + /* Create a new record at the end of the lisst*/ + iterator->record = pico_mdns_rr_create(url, _rdata, len, rtype, rttl, flags); + + /* Initialise fields */ + iterator->timer = NULL; + iterator->next = NULL; + iterator->flags = flags; +} + +// MARK: ANSWER UTILITIES + +/* ************************************************************************** + * Create a resource record for the mDNS answer message format, that is + * with the identifier of the DNS packet being 0. + * **************************************************************************/ +static pico_dns_packet *pico_mdns_answer_create( struct pico_dns_res_record *answer_list, struct pico_dns_res_record *authority_list, struct pico_dns_res_record *additional_list, uint16_t *len ) +{ + pico_dns_packet *packet = NULL; + + /* Create an answer as you would with plain DNS */ + packet = pico_dns_answer_create(answer_list, authority_list, additional_list, len); + if (!packet) { + mdns_dbg("Could not create DNS answer!\n"); + return NULL; + } + + /* Set the id of the DNS packet to 0 */ + packet->id = 0; + + return packet; +} + +// MARK: CACHE UTILITIES + +static int pico_mdns_cache_del_rr(char *url, uint16_t qtype, char *rdata) +{ + struct pico_mdns_cache_rr test, *found = NULL; + + test.suf = PICO_ZALLOC(sizeof(struct pico_dns_res_record_suffix)); + if(!test.suf) + return -1; + + test.url = url; + test.suf->rclass = PICO_DNS_CLASS_IN; /* We only support IN */ + test.suf->rtype = qtype; + test.rdata = rdata; + + found = pico_tree_findKey(&CacheTable, &test); + PICO_FREE(test.suf); + + if(!found) { + mdns_dbg("Couldn't find cache RR to delete\n"); + return -1; + } + + mdns_dbg("Removing RR: qtype '%d' url '%s'\n", qtype, url); + + pico_tree_delete(&CacheTable, found); + PICO_FREE(found->url); + PICO_FREE(found->suf); + PICO_FREE(found->rdata); + PICO_FREE(found); + return 0; +} + +static void pico_mdns_cache_tick(pico_time now, void *_arg) +{ + struct pico_mdns_cache_rr *rr = (struct pico_mdns_cache_rr *)_arg; + IGNORE_PARAMETER(now); + + rr->suf->rttl--; + mdns_dbg("TTL UPDATE: '%s' - qtype: %d - TTL: %d\n", rr->url, rr->suf->rtype, rr->suf->rttl); + if(rr->suf->rttl < 1) + pico_mdns_cache_del_rr(rr->url, rr->suf->rtype, rr->rdata); + else + rr->timer = pico_timer_add(PICO_MDNS_RR_TTL_TICK, pico_mdns_cache_tick, rr); + + /* TODO: continuous querying: cache refresh at 80 or 85/90/95/100 % of TTL + 2% rnd */ +} + +/* Look for a RR in cache matching hostname and qtype */ +static struct pico_mdns_cache_rr *pico_mdns_cache_find_rr(const char *url, uint16_t rtype) +{ + struct pico_mdns_cache_rr test; /* Create a test-rr for the tree_findKey-function */ + struct pico_mdns_cache_rr *found = NULL; /* Resource Record pointer to return */ + struct pico_dns_res_record_suffix *suf = NULL; /* Create a test rsuffix for the test-rr */ + + /* Provide space for the test-suffix */ + suf = PICO_ZALLOC(sizeof(struct pico_dns_res_record_suffix)); + if(!suf) + return NULL; + + /* Set the rsuffix pointer of the test-rr */ + test.suf = suf; + + /* Set the rtype of the rsuffix */ + test.suf->rtype = rtype; + + /* Set the url of the test-rr in DNS name format */ + test.url = pico_dns_url_to_qname(url); + + /* Find the Resource Record in the tree */ + found = pico_tree_findKey(&CacheTable, &test); + + /* Free allocated space */ + PICO_FREE(test.url); + PICO_FREE(suf); + + return found; +} + +static int pico_mdns_cache_add_rr(char *url, struct pico_dns_res_record_suffix *suf, char *rdata) +{ + struct pico_mdns_cache_rr *rr = NULL; + struct pico_mdns_cache_rr *found = NULL; + struct pico_dns_res_record_suffix *rr_suf = NULL; + char *rr_url = NULL; + char *rr_rdata = NULL; + + if(!url || !suf || !rdata) + return -1; + + /* Don't cache PTR answers */ + if(short_be(suf->rtype) == PICO_DNS_TYPE_PTR ) { + mdns_dbg("Not caching PTR answer\n"); + return 0; + } + + /* Provide space for the cache RR */ + rr = PICO_ZALLOC(sizeof(struct pico_mdns_cache_rr)); + rr_suf = PICO_ZALLOC(sizeof(struct pico_dns_res_record_suffix)); + rr_url = pico_dns_url_to_qname(url); + rr_rdata = PICO_ZALLOC(short_be(suf->rdlength)); + if(!rr || !rr_suf || !rr_url || !rr_rdata) { + PICO_FREE(rr); + PICO_FREE(rr_suf); + PICO_FREE(rr_url); + PICO_FREE(rr_rdata); + pico_err = PICO_ERR_ENOMEM; + return -1; + } + + /* Set the rname of the cache rr */ + rr->url = rr_url; + + memcpy(rr_suf, suf, sizeof(struct pico_dns_res_record_suffix)); + rr->suf = rr_suf; + rr->suf->rtype = short_be(rr->suf->rtype); + rr->suf->rclass = short_be(rr->suf->rclass); + rr->suf->rttl = long_be(suf->rttl); + rr->suf->rdlength = short_be(suf->rdlength); + memcpy(rr_rdata, rdata, rr->suf->rdlength); + rr->rdata = rr_rdata; + + found = pico_mdns_cache_find_rr(url, rr->suf->rtype); + if(found) { + if(rr->suf->rttl > 0) { + mdns_dbg("RR already in cache, updating TTL (was %ds now %ds)\n", found->suf->rttl, rr->suf->rttl); + found->suf->rttl = rr->suf->rttl; + } + else { + mdns_dbg("RR scheduled for deletion\n"); + found->suf->rttl = 1; /* TTL 0 means delete from cache but we need to wait one second */ + } + } + else { + if(rr->suf->rttl > 0) { + pico_tree_insert(&CacheTable, rr); + mdns_dbg("RR cached. Starting TTL counter, TICK TACK TICK TACK..\n"); + rr->timer = pico_timer_add(PICO_MDNS_RR_TTL_TICK, pico_mdns_cache_tick, rr); + return 0; + } + else { + mdns_dbg("RR not in cache but TTL = 0\n"); + } + } + PICO_FREE(rr->suf); + PICO_FREE(rr->url); + PICO_FREE(rr->rdata); + PICO_FREE(rr); + return 0; +} + +/* ************************************************************************** + * Looks for a certain query-cookie in the global cookie-tree given an [url] + * and [qtype]. Qclass does not apply since all we use is qclass 'IN' or 1, + * anyway. + * **************************************************************************/ +static struct pico_mdns_cookie *pico_mdns_find_cookie( char *qname, uint16_t qtype ) +{ + struct pico_mdns_cookie test; /* Create a test-cookie for the tree_findKey-function */ + struct pico_mdns_cookie *found = NULL; /* Pointer to return */ + + /* Set qname & qtype of the test-cookie*/ + test.qname = qname; + test.qtype = qtype; + + /* Find the cookie in the tree */ + found = pico_tree_findKey(&QTable, &test); + + return found; +} + +/* ************************************************************************** + * Deletes for a certain query-cookie in the global cookie-tree given an [url] + * and [qtype]. Qclass does not apply since all we use is qclass 'IN' or 1, + * anyway. + * **************************************************************************/ +static int pico_mdns_del_cookie( char *qname, uint16_t qtype ) +{ + /* First, find the cookie in the global tree */ + struct pico_mdns_cookie *found = pico_mdns_find_cookie(qname, qtype); + if (!found) { + mdns_dbg("Could not find cookie '%s' to delete\n", qname); + return -1; + } + + /* Delete and free memory for the cookie */ + pico_tree_delete(&QTable, found); + PICO_FREE(found->packet); + PICO_FREE(found); + + mdns_dbg("Cookie deleted succesfully!\n"); + + return 0; +} + +/* Callback for the timeout timer of a query cookie */ +static void pico_mdns_timeout(pico_time now, void *_arg) +{ + struct pico_mdns_cookie *ck = NULL; + + IGNORE_PARAMETER(now); + + /* Cast the _arg pointer to a cookie */ + ck = (struct pico_mdns_cookie *)_arg; + + /* Call the callback */ + if(ck->callback) + ck->callback(NULL, ck->arg); + + /* Delete the cookie */ + pico_mdns_del_cookie(ck->qname, ck->qtype); + + /* TODO: If the request was for a reconfirmation of a record, flush the corresponding record after the timeout */ +} + +/* ************************************************************************** + * + * Creates and fills in a cookie with a certain query [dns_packet] and add it + * to the global cookie-tree. [len] is the length of the DNS packet in bytes. + * [flags] are the MDNS-flags given for a certain query, like probing-flag, + * unicast-response-flags. [callback] is callback that gets called when events + * happen, [arg] is and argument passed to the callback-function + * + * **************************************************************************/ +static struct pico_mdns_cookie *pico_mdns_add_cookie( pico_dns_packet *dns_packet, uint16_t len, uint8_t flags, uint8_t count, void (*callback)(char *str, void *arg), void *arg ) +{ + /* Query cookie structs */ + struct pico_mdns_cookie *ck = NULL; + struct pico_mdns_cookie *found = NULL; + + /* Provide space for such a cookie */ + ck = PICO_ZALLOC(sizeof(struct pico_mdns_cookie)); + if (!ck) + return NULL; + + /* Fill in the form */ + ck->packet = dns_packet; + ck->len = len; + ck->qname = (char *)dns_packet + sizeof(struct pico_dns_header); + pico_to_lowercase(ck->qname); + ck->qtype = short_be(*(uint16_t *)((char *)dns_packet + len - 4)); + ck->qclass = short_be(*(uint16_t *)((char *)dns_packet + len - 2)); + ck->flags = flags; + ck->count = count; + ck->callback = callback; + ck->arg = arg; + + /* Insert the cookie into a tree */ + found = pico_tree_insert(&QTable, ck); + + /* If cookie is already in tree */ + if (found) { + pico_err = PICO_ERR_EAGAIN; + PICO_FREE(ck); + PICO_FREE(dns_packet); + return NULL; + } + + mdns_dbg("Cookie '%s' with qtype '%x' added to QTable\n", ck->qname, ck->qtype); + + /* RFC: + * When no response is received within ten seconds, then, even though + * its TTL may indicate that it is not yet due to expire, that record + * SHOULD be promptly flushed from cache. + */ + if(IS_QUESTION_PROBE_FLAG_SET(flags)) + ck->timer = pico_timer_add(PICO_MDNS_QUERY_TIMEOUT, pico_mdns_timeout, ck); + + return ck; +} + +// MARK: ASYNCHRONOUS MDNS RECEPTION + +/* handle a single incoming answer */ +static int pico_mdns_handle_answer(char *url, struct pico_dns_res_record_suffix *suf, char *data) +{ + struct pico_mdns_cookie *ck = NULL; // Temporary storage of query cookie + + /* Remove cache flush bit if set MARK: But why? */ + suf->rclass &= short_be((uint16_t) ~0x8000); + + /* Print some context */ + mdns_dbg("Answer for record %s was received:\n", url); + mdns_dbg("rrtype: %u, rrclass: %u, ttl: %lu, rdlen: %u\n", short_be(suf->rtype), short_be(suf->rclass), (unsigned long)long_be(suf->rttl), short_be(suf->rdlength)); + + /* Add a resource record to cache */ + pico_mdns_cache_add_rr(url, suf, data); + + mdns_dbg("Searching for a corresponding query cookie for url: %s and qtype: %d...\n", url, short_be(suf->rtype)); + + /* Check in the query tree whether a request was sent to elicit this answer */ + ck = pico_mdns_find_cookie(url, short_be(suf->rtype)); + if(!ck) { + /* MARK: Of course no cookie will be found if the responder doesn't sent the same qtype with probes*/ + mdns_dbg("Found NO corresponding cookie!\n"); + return 0; + } + + mdns_dbg("Found a corresponding cookie!\n"); + + /* if we are probing, set probe to zero so the probe timer stops the next time it goes off */ + if (IS_QUESTION_PROBE_FLAG_SET(ck->flags)) { + mdns_dbg("Probe set to zero\n"); + ck->flags &= PICO_MDNS_QUESTION_FLAG_NO_PROBE; + return 0; + } + + /* If this was aan API request return answer passed in callback */ + if(short_be(suf->rtype) == PICO_DNS_TYPE_A) { + uint32_t rdata = long_from(data); + char peer_addr[46]; + pico_ipv4_to_string(peer_addr, long_from(&rdata)); + ck->callback(peer_addr, ck->arg); + } + +#ifdef PICO_SUPPORT_IPV6 + else if(short_be(suf->rtype) == PICO_DNS_TYPE_AAAA) { + uint8_t *rdata = (uint8_t *) data; + char peer_addr[46]; + pico_ipv6_to_string(peer_addr, rdata); + ck->callback(peer_addr, ck->arg); + } +#endif + else if(short_be(suf->rtype) == PICO_DNS_TYPE_PTR) { + pico_dns_notation_to_name(data); + ck->callback(data + 1, ck->arg); /* +1 to discard the beginning dot */ + } else { + mdns_dbg("Unrecognised record type\n"); + ck->callback(NULL, ck->arg); + } + + /* Remove the timer from the cookie and delete it */ + pico_timer_cancel(ck->timer); + pico_mdns_del_cookie(url, ck->qtype); + + return 0; +} + +/* Create a query answer according to the qtype (ANY, A, AAAA or PTR) of a certain IP address */ +//static struct pico_dns_header *pico_mdns_query_create_answer(union pico_address *local_addr, uint16_t qtype, uint16_t *len, char *name) +//{ +// // TODO: If type is ANY include all records corresponding to the name +// // TODO: Include negative responses for records this hosts knows they don't exist +// +// IGNORE_PARAMETER(local_addr); +// IGNORE_PARAMETER(qtype); +// IGNORE_PARAMETER(len); +// IGNORE_PARAMETER(name); +// +// if(qtype == PICO_DNS_TYPE_A || qtype == PICO_DNS_TYPE_ANY) { +// return pico_mdns_answer_create(mdns_global_host, len, PICO_DNS_TYPE_A, local_addr); +// } +//#ifdef PICO_SUPPORT_IPV6 +// if(qtype == PICO_DNS_TYPE_AAAA || qtype == PICO_DNS_TYPE_ANY) { +// struct pico_ip6 *ip6 = pico_get_ip6_from_ip4(&local_addr->ip4); +// return pico_mdns_answer_create(mdns_global_host, len, PICO_DNS_TYPE_AAAA, ip6); +// } +//#endif +// /* reply to PTR records */ +// if(qtype == PICO_DNS_TYPE_PTR) { +// char host_conv[255] = { 0 }; +// mdns_dbg("Replying on PTR query...\n"); +// strcpy(host_conv + 1, mdns_global_host); +// pico_dns_name_to_dns_notation(host_conv); +// return pico_mdns_answer_create(name, len, qtype, host_conv); +// } +// +// mdns_dbg("Unknown qtype!\n"); +// +// return NULL; +//} + +/* Reply on a single query */ +static int pico_mdns_reply_query(uint16_t qtype, struct pico_ip4 peer, char *name) +{ + IGNORE_PARAMETER(qtype); + IGNORE_PARAMETER(peer); + IGNORE_PARAMETER(name); + +// /* Pointer to DNS packet */ +// struct pico_dns_header *header = NULL; +// +// /* To store either an IPv4 or an IPv6 */ +// union pico_address *local_addr = NULL; +// +// uint16_t len; // Temporary storage of the length of the reply +// +// // TODO: Check for authority sections / probing queries +// // TODO: Check for unicast response bit +// +// /* RFC: +// * If a responder receives a query addressed to the mDNS IPv4 link-local multicast address, +// * from a source address not apparently on the same subnet as the +// * responder, then, even if the query indicates that a unicast +// * response is preferred, the responder SHOULD elect to respond by multicast +// * anyway, since it can reasonably predict that a unicast response with +// * an apparently non-local source address will probably be ignored. +// */ +// local_addr = (union pico_address *) pico_ipv4_source_find(&peer); +// if (!local_addr) { +// // TODO: Forced Response via multicast +// pico_err = PICO_ERR_EHOSTUNREACH; +// mdns_dbg("Peer not on same subnet!\n"); +// return -1; +// } +// +// /* Creates an answer for the host's IP, depending on the qtype */ +// // MARK: MUST contain all records for qtype ANY +// header = pico_mdns_query_create_answer(local_addr, qtype, &len, name); +// if (!header) { +// mdns_dbg("Error occured while creating an answer (pico_err:%d)!\n", pico_err); +// return -1; +// } +// +// /* Send a response on the wire */ +// if(pico_mdns_send_packet(header, len) != (int)len) { +// mdns_dbg("Send error occurred!\n"); +// return -1; +// } + + return 0; +} + +/* Compare if the received query name is the same as the name currently assigned to this host */ +static int pico_check_query_name(char *url) +{ + char addr[29] = { 0 }; + + /* Check if query is a normal query for this hostname*/ + if(strcmp(url, mdns_global_host) == 0) + return 1; + + /* Convert 192.168.1.1 decimal to '192.168.1.1'-string */ + pico_ipv4_to_string(addr, mdns_sock_ipv4->local_addr.ip4.addr); + + /* Mirror 192.168.1.1 to 1.1.168.192 */ + pico_dns_mirror_addr(addr); + + /* Add a arpa-suffix */ + memcpy(addr + strlen(addr), ".in-addr.arpa", 13); + + /* Check if request name is reverse query for this hostname */ + if(strcmp(url, addr) == 0) + return 1; + + return 0; +} + +/* Handle a single incoming query */ +static int pico_mdns_handle_query(char *name, struct pico_dns_question_suffix *suf, struct pico_ip4 peer) +{ + struct pico_mdns_cookie *ck = NULL; // Temporary storage of query cookie + + /* Remove cache flush bit if set MARK: but why? */ + suf->qclass &= short_be((uint16_t) ~0x8000); + + mdns_dbg("Query type: %u, class: %u\n", short_be(suf->qtype), short_be(suf->qclass)); + + /* Check if host has assigned itself a name already */ + if(mdns_global_host) { + + /* Check if queried name is the same as currently assigned name */ + // TODO: Check for all the records with that name and for wich this host has authority (Not only A and PTR) + if(pico_check_query_name(name)) { + /* Query is either a normal query or a reverse resolution query for this host */ + pico_mdns_reply_query(short_be(suf->qtype), peer, name); + } else { + /* Query is not meant for this host */ + /* TODO: Passive Observation Of Failures (POOF) */ + mdns_dbg("Received request for unknown hostname %s (my hostname: %s)\n", name, mdns_global_host); + } + } else { + /* Find a corresponding query currently being queried */ + ck = pico_mdns_find_cookie(name, short_be(suf->qtype)); + if(ck && ck->count < 3) { + /* TODO: Simultaneous Probe Tiebreaking */ + } else { + mdns_dbg("Received query before init\n"); + } + } + + return 0; +} + +/* Parses an incoming packet */ +static int pico_mdns_recv(void *buf, int buflen, struct pico_ip4 peer) +{ + /* Point to the DNS packet in the buffer */ + struct pico_dns_header *header = (struct pico_dns_header *) buf; + + /* Point to right after the header */ + char *ptr = (char *)header + sizeof(struct pico_dns_header); + + /* Depending on the header, we need to provide a query or answer struct */ + struct pico_dns_question_suffix *qsuf; + struct pico_dns_res_record_suffix *asuf; + + /* Count of questions and answers in the packet */ + uint16_t i, qcount, acount; + + /* Pointer to the data field of the questions or answers */ + char *data; + + /* Determine the count of questions and answers */ + // TODO: Authority Count and Additional count should be implemented + qcount = short_be(header->qdcount); + acount = short_be(header->ancount); + mdns_dbg("\n>>>>>>> QDcount: %u, ANcount: %u\n", qcount, acount); + if(qcount == 0 && acount == 0) { + mdns_dbg("Query and answer count is 0!\n"); + return -1; + } + + /* Handle queries */ + for(i = 0; i < qcount; i++) { + /* Point to the qtype & qclass fields */ + qsuf = (struct pico_dns_question_suffix*) (ptr + pico_dns_namelen_comp(ptr) + 1); + + /* Convert 3www6google3com0 to .www.google.com */ + pico_dns_notation_to_name(ptr); + if (!ptr) + return -1; + + /* Handle the query accordingly (+1 to skip the first '.') */ + pico_mdns_handle_query(ptr + 1, qsuf, peer); + + /* Point to the next question */ + ptr = (char *)qsuf + sizeof(struct pico_dns_question_suffix); + if(ptr - (char *)header > buflen) { + mdns_dbg("buffer is too short! ptr offset=%ld buflen=%d\n", ptr - (char*)header, buflen); + return -1; + } + } + + /* Handle answers */ + for(i = 0; i < acount; i++) { + char *name; + + /* Point to the suffix of the answer contain in the answer section */ + asuf = (struct pico_dns_res_record_suffix*) (ptr + pico_dns_namelen_comp(ptr) + 1); + + /* Get the uncompressed name of the possibly compressed name contained in de rrname-field */ + if((name = pico_dns_expand_name_comp(ptr, header)) == NULL) { + mdns_dbg("Received a zero name pointer\n"); + return -1; + } + + /* Point to the data-field of the answer contained in the answer section */ + data = (char *)asuf + sizeof(struct pico_dns_res_record_suffix); + + /* Handle the answer accordingly (+1 to skip the first '.') */ + pico_mdns_handle_answer(name + 1, asuf, data); + + /* Free memory */ + PICO_FREE(name); + + /* Move to the next answer */ + ptr = data + short_be(asuf->rdlength); + if(ptr - (char *)header > buflen) { + mdns_dbg("buffer is too short! ptr offset=%ld buflen=%d\n", ptr - (char*)header, buflen); + return -1; + } + } + + return 0; +} + +/* Callback for UDP IPv4 socket events */ +static void pico_mdns_event4( uint16_t ev, struct pico_socket *s ) +{ + // MARK: Why MTU 1400 and not 1500? + char recvbuf[PICO_MDNS_MTU] = { 0 }; // MTU of 1400 + struct pico_ip4 peer = { 0 }; // Peer who sent the data + int pico_read = 0; // Count of readed bytes + uint16_t port = 0; // Source port + char host[30]; // IP-address string + + /* process read event, data available */ + if (ev == PICO_SOCK_EV_RD) { + mdns_dbg("READ EVENT!\n"); + /* Receive while data is available in socket buffer */ + while((pico_read = pico_socket_recvfrom(s, recvbuf, PICO_MDNS_MTU, &peer, &port)) > 0) { + pico_ipv4_to_string(host, peer.addr); + mdns_dbg("Received data from %s:%u\n", host, short_be(port)); + /* Handle the MDNS data received */ + pico_mdns_recv(recvbuf, pico_read, peer); + } + } else if (ev == PICO_SOCK_EV_CLOSE) { + mdns_dbg("Socket is closed. Bailing out.\n"); + return; + } else { + mdns_dbg("Socket Error received. Bailing out.\n"); + return; + } +} + +// MARK: CACHE FUNCTIONS + +int pico_mdns_flush_cache(void) +{ + struct pico_mdns_cache_rr *rr = NULL; + struct pico_tree_node *index = NULL; + + mdns_dbg("Flushing mDNS RR cache\n"); + pico_tree_foreach(index, &CacheTable) { + rr = index->keyValue; + mdns_dbg("Deleting '%s' (%d)\n", rr->url, rr->suf->rtype); + pico_tree_delete(&CacheTable, rr); + pico_timer_cancel(rr->timer); + PICO_FREE(rr->url); + PICO_FREE(rr->suf); + PICO_FREE(rr->rdata); + PICO_FREE(rr); + } + return 0; +} + +// MARK: ADDRESS RESOLUTION + +static int pico_mdns_getaddr_generic(const char *url, void (*callback)(char *ip, void *arg), void *arg, uint16_t proto) +{ + struct pico_dns_header *header = NULL; + uint16_t len = 0; + + IGNORE_PARAMETER(callback); + IGNORE_PARAMETER(arg); + IGNORE_PARAMETER(proto); + + if (!url) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + if(!mdns_sock_ipv4) { + mdns_dbg("mDNS socket not yet populated. Did you call pico_mdns_init()?\n"); + return -1; + } + + //header = pico_mdns_create_query(url, &len, proto, PICO_DNS_TYPE_PTR, PICO_MDNS_QUESTION_FLAG_NO_PROBE); + if(!header || !len) { + mdns_dbg("ERROR: mdns_create_query returned NULL\n"); + return -1; + } + + if(pico_mdns_send_packet(header, len) != (int)len) { + mdns_dbg("Send error!\n"); + return -1; + } + + return 0; +} + +static int pico_mdns_getname_generic(const char *ip, void (*callback)(char *url, void *arg), void *arg, uint16_t proto) +{ + struct pico_dns_header *header = NULL; + uint16_t len = 0; + + IGNORE_PARAMETER(callback); + IGNORE_PARAMETER(arg); + IGNORE_PARAMETER(proto); + + if (!ip) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + if(!mdns_sock_ipv4) { + mdns_dbg("Mdns socket not yet populated. Did you call pico_mdns_init()?\n"); + return -1; + } + + //header = pico_mdns_create_query(ip, &len, proto, PICO_DNS_TYPE_PTR, PICO_MDNS_QUESTION_FLAG_NO_PROBE); + if(!header || !len) { + mdns_dbg("ERROR: mdns_create_query returned NULL\n"); + return -1; + } + + if(pico_mdns_send_packet(header, len) != (int)len) { + mdns_dbg("Send error!\n"); + return -1; + } + + return 0; +} + +int pico_mdns_getaddr(const char *url, void (*callback)(char *ip, void *arg), void *arg) +{ + struct pico_mdns_cache_rr *rr = NULL; + char addr[46]; + rr = pico_mdns_cache_find_rr(url, PICO_DNS_TYPE_A); + + if(rr && rr->rdata) { + pico_ipv4_to_string(addr, long_from(rr->rdata)); + mdns_dbg("Cache hit! Found A record for '%s' with addr '%s'\n", url, addr); + callback(addr, arg); + return 0; + } + else { + mdns_dbg("Cache miss for A record - url '%s'\n", url); + return pico_mdns_getaddr_generic(url, callback, arg, PICO_PROTO_IPV4); + } +} + +int pico_mdns_getname(const char *ip, void (*callback)(char *url, void *arg), void *arg) +{ + return pico_mdns_getname_generic(ip, callback, arg, PICO_PROTO_IPV4); +} + +#ifdef PICO_SUPPORT_IPV6 +int pico_mdns_getaddr6(const char *url, void (*callback)(char *ip, void *arg), void *arg) +{ + struct pico_mdns_cache_rr *rr = NULL; + char addr[46]; + rr = pico_mdns_cache_find_rr(url, PICO_DNS_TYPE_AAAA); + + if(rr && rr->rdata) { + pico_ipv6_to_string(addr, (uint8_t *)rr->rdata); + mdns_dbg("Cache hit! Found AAAA record for '%s' with addr '%s'\n", url, addr); + callback(addr, arg); + return 0; + } + else { + mdns_dbg("Cache miss for AAAA record - url '%s'\n", url); + return pico_mdns_getaddr_generic(url, callback, arg, PICO_PROTO_IPV6); + } +} + +int pico_mdns_getname6(const char *ip, void (*callback)(char *url, void *arg), void *arg) +{ + return pico_mdns_getname_generic(ip, callback, arg, PICO_PROTO_IPV6); +} +#endif + +// MARK: ANNOUNCEMENT + +/* Utility function to send an announcement on the wire */ +static int pico_mdns_send_packet_announcement(void) +{ + /* mDNS headers are just the same as plain legacy DNS headers */ + struct pico_dns_header *packet = NULL; + struct pico_dns_res_record *announcement = NULL; + + uint16_t len = 0; // Temporary storage of packet length + + /* If global hostname isn't set */ + if(!mdns_global_host) + return -1; + + /* Create an resource record to put in the announcement */ + announcement = pico_mdns_rr_create(mdns_global_host, &mdns_sock_ipv4->local_addr, &len, PICO_DNS_TYPE_A, 120, (PICO_MDNS_RES_RECORD_UNIQUE)); + if (!announcement) { + mdns_dbg("ERROR: mdns_create_query returned NULL\n"); + return -1; + } + + /* Create an mDNS answer */ + packet = pico_mdns_answer_create(announcement, NULL, NULL, &len); + if(!packet) { + mdns_dbg("Could not create answer!\n"); + return -1; + } + + /* Send the mDNS answer unsollicited via multicast */ + if(pico_mdns_send_packet(packet, len) != (int)len) { + mdns_dbg("send error occured!\n"); + return -1; + } + + return 0; +} + +/* Callback function for the announcement timer */ +static void pico_mdns_announce_timer(pico_time now, void *arg) +{ + IGNORE_PARAMETER(now); + IGNORE_PARAMETER(arg); + + /* Send a second unsollicited announcement */ + pico_mdns_send_packet_announcement(); +} + +/* announce the local hostname to the network */ +static int pico_mdns_announce(void) +{ + /* Send a first unsollicited announcement */ + if (pico_mdns_send_packet_announcement() < 0) + return -1; + + /* RFC: + * The Multicast DNS responder MUST send at least two unsolicited + * responses, one second apart. + */ + pico_timer_add(1000, pico_mdns_announce_timer, NULL); + + return 0; +} + +// MARK: PROBING + +/* Callback function for the probe timer */ +static void pico_mdns_probe_timer(pico_time now, void *arg) +{ + struct pico_mdns_cookie *ck = NULL; + char ok[] = "OK"; + char temp[255] = { 0 }; + + /* Cast the argument given in [arg] to a mDNS-cookie */ + if (!arg) + return; + ck = (struct pico_mdns_cookie *) arg; + + IGNORE_PARAMETER(now); + + if(!ck) { + mdns_dbg("Cookie does not exist! This shouldn't happen\n"); + return; + } + + /* If probe flag is reset */ + if(!IS_QUESTION_PROBE_FLAG_SET(ck->flags)) { + mdns_dbg("Hostname already in use!\n"); + ck->callback(NULL, ck->arg); + return; + } + + /* After 3 successful probing attempts */ + if(ck->count == 0) { + mdns_global_host = PICO_ZALLOC(strlen(ck->qname) - 1); + if (!mdns_global_host) { + pico_err = PICO_ERR_ENOMEM; + return; + } + strcpy(temp, ck->qname); + pico_dns_notation_to_name(temp); + strcpy(mdns_global_host, temp + 1); + mdns_dbg("Count is zero! Claimed %s\n", mdns_global_host); + pico_mdns_announce(); + + ck->callback(ok, ck->arg); + pico_mdns_del_cookie(ck->qname, ck->qtype); + + return; + } + + /* Send Probing query */ + if(pico_mdns_send_packet(ck->packet, ck->len) != (int)ck->len) { + mdns_dbg("Send error occurred!\n"); + PICO_FREE(arg); + ck->callback(NULL, ck->arg); + return; + } + + mdns_dbg("Probed!\n"); + + /* Decrement probe count */ + ck->count--; + + /* Schedule the next probe after 250 ms */ + pico_timer_add(250, pico_mdns_probe_timer, ck); +} + +/* Checks whether the given name is in use */ +static int pico_mdns_probe(char *hostname, void (*cb_initialised)(char *str, void *arg), void *arg) +{ + pico_dns_packet *packet = NULL; /* mDNS headers are just the same as plain legacy DNS headers */ + struct pico_mdns_cookie *cookie = NULL; /* Query cookie to pass to the time callback */ + uint16_t qlen = 0; /* Temporary storage of question length */ + uint16_t len = 0; /* Temporary storage of packet length */ + + /* RFC: + * Probe querys SHOULD be sent with as "QU" questions with the unicast-response bit set. + * To a defending host to respond immediately via unicast, instead of potentially + * having to wait before replying via multicast. + */ + struct pico_dns_question *probe_question = pico_mdns_question_create(hostname, &qlen, PICO_PROTO_IPV4, PICO_DNS_TYPE_ANY, (PICO_MDNS_QUESTION_FLAG_PROBE | PICO_MDNS_QUESTION_FLAG_UNICAST_RES)); + + /* Fill a DNS packet with the probe question */ + packet = pico_mdns_query_create(probe_question, NULL, NULL, NULL, &len); + if (!packet) { + mdns_dbg("ERROR: mdns_create_query returned NULL\n"); + return -1; + } + + /* Add a cookie to the global tree so we don't have to create the query everytime */ + cookie = pico_mdns_add_cookie(packet, len, (PICO_MDNS_QUESTION_FLAG_PROBE | PICO_MDNS_QUESTION_FLAG_UNICAST_RES), 3, cb_initialised, arg); + if (!cookie) { + mdns_dbg("ERROR: mdns_add_cookie returned NULL\n"); + return 1; + } + + /* RFC: + * When the host is ready to send his probe query he SHOULD delay it's + * transmission with a randomly chosen time between 0 and 250 ms. + */ + pico_timer_add(pico_rand() % 250, pico_mdns_probe_timer, cookie); + + return 0; +} + +static pico_dns_question *pico_mdns_probe_list_create( pico_mdns_res_record_list *records ); +{ + struct pico_mdns_res_record *iterator = NULL; + struct pico_dns_question *probe_list = NULL; + struct pico_dns_question *qiterator = NULL; + char *url = NULL; + uint16_t qlen = 0; + + iterator = records; + + while (iterator != NULL) { + if (IS_RES_RECORD_FLAG_CLAIM_UNIQUE_SET(iterator->flags)) { + /* Put question iterator at beginning of question list */ + qiterator = probe_list; + + /* Iterate until the end of question list */ + while (qiterator != NULL) { + qiterator = qiterator->next; + } + + /* Convert the rname in the mDNS record to an url */ + url = pico_dns_qname_to_url(iterator->record->rname); + + /* Create a new question at the end of the list */ + qiterator = pico_mdns_question_create(url, &qlen, PICO_PROTO_IPV4, PICO_DNS_TYPE_ANY, (PICO_MDNS_QUESTION_FLAG_PROBE | PICO_MDNS_QUESTION_FLAG_UNICAST_RES)); + + /* Free the url */ + PICO_FREE(url); + } else { + /* You don't need to probe Shared Records */ + PICO_MDNS_RES_RECORD_SET_PROBED(iterator->flags); + } + } +} + +/* ************************************************************************** + * Claim several mDNS resource records at once. + * **************************************************************************/ +int pico_mdns_claim( pico_mdns_res_record_list *records, + void (*cb_claimed)(char *str, void *arg), + void *arg ) +{ + struct pico_mdns_res_record *iterator = NULL; + struct pico_dns_question *probe_list = NULL; + char *OK = PICO_OK_STRING, *NOK = PICO_NOK_STRING, *SOK = PICO_SOK_STRING; + + /* Check if arguments are passed correctly */ + if (!records || !cb_claimed || !arg) { + mdns_dbg("NULL pointers passed to 'pico_mdns_claim()'!\n"); + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Check if module is initialised */ + if (!mdns_sock_ipv4) { + mdns_dbg("mDNS socket not initialised, did you call 'pico_mdns_init()'?\n"); + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Update the rr's and create a probe list */ + probe_list = pico_mdns_probe_list_create(records); + + + + return 0; +} + +int pico_mdns_init( uint8_t flags, void (*cb_initialised)(char *str, void *arg), void *arg ) +{ + struct pico_ip_mreq mreq4; + char *OK = PICO_OK_STRING, *NOK = PICO_NOK_STRING, *SOK = PICO_SOK_STRING; + uint16_t proto4 = PICO_PROTO_IPV4; + uint16_t port = 0; + uint16_t loop = 0; // Loopback = 0 + uint16_t ttl = 255; // IP TTL SHOULD = 255 + + /* For now */ + IGNORE_PARAMETER(flags); + + /* Initialise port */ + port = short_be(mdns_port); + + /* Check callbcak parameter */ + if(!cb_initialised) { + mdns_dbg("No callback function suplied!\n"); + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Open global IPv4 mDNS socket */ + mdns_sock_ipv4 = pico_socket_open(proto4, PICO_PROTO_UDP, &pico_mdns_event4); + if(!mdns_sock_ipv4) { + mdns_dbg("Open returned empty IPv4 socket\n"); + return -1; + } + + /* Convert the mDNS IPv4 destination address to struct */ + if(pico_string_to_ipv4(PICO_MDNS_DEST_ADDR4, &mreq4.mcast_group_addr.addr) != 0) { + mdns_dbg("String to IPv4 error\n"); + return -1; + } + + /* Receive data on any network interface */ + mreq4.mcast_link_addr = inaddr_any; + + /* Don't want the multicast data to be looped back to the host */ + if(pico_socket_setoption(mdns_sock_ipv4, PICO_IP_MULTICAST_LOOP, &loop) < 0) { + mdns_dbg("socket_setoption PICO_IP_MULTICAST_LOOP failed\n"); + return -1; + } + + /* Tell the kernel we're interested in this particular multicast group */ + if(pico_socket_setoption(mdns_sock_ipv4, PICO_IP_ADD_MEMBERSHIP, &mreq4) < 0) { + mdns_dbg("socket_setoption PICO_IP_ADD_MEMBERSHIP failed\n"); + return -1; + } + + /* RFC: + * All multicast responses (including answers sent via unicast) SHOULD + * be send with IP TTL set to 255 for backward-compatibility reasons + */ + if(pico_socket_setoption(mdns_sock_ipv4, PICO_IP_MULTICAST_TTL, &ttl) < 0) { + mdns_dbg("socket_setoption PICO_IP_MULTICAST_TTL failed\n"); + return -1; + } + + /* Bind to mDNS port */ + if (pico_socket_bind(mdns_sock_ipv4, &inaddr_any, &port) != 0) { + mdns_dbg("Bind error!\n"); + return -1; + } + + /* Call callback */ + cb_initialised(OK, arg); + + return 0; +} + +#endif /* PICO_SUPPORT_MDNS */ diff --git a/modules/pico_mdns.c b/modules/pico_mdns.c index 977902284..ad6eda520 100644 --- a/modules/pico_mdns.c +++ b/modules/pico_mdns.c @@ -2,7 +2,7 @@ PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved. See LICENSE and COPYING for usage. . - Author: Toon Stegen + Author: Toon Stegen, Jelle De Vleeschouwer *********************************************************************/ #include "pico_config.h" #include "pico_stack.h" @@ -11,1209 +11,3626 @@ #include "pico_ipv4.h" #include "pico_ipv6.h" #include "pico_mdns.h" -#include "pico_dns_common.h" #include "pico_tree.h" #ifdef PICO_SUPPORT_MDNS -#define PICO_MDNS_QUERY_TIMEOUT (10000) /* Ten seconds */ -#define PICO_MDNS_RR_TTL_TICK (1000) /* One second */ -#define PICO_MDNS_MAXBUF (1400) +/* --- Debugging --- */ +#define DEBUG 0 +#if DEBUG == 0 #define mdns_dbg(...) do {} while(0) -/*#define mdns_dbg dbg*/ - -#define PICO_MDNS_PROBE 1 -#define PICO_MDNS_NO_PROBE 0 -#define PICO_MDNS_INVERT 1 -#define PICO_MDNS_NO_INVERT 0 -#define PICO_MDNS_CACHE_FLUSH_BIT 0x8000u -static struct pico_ip4 inaddr_any = { - 0 -}; - -/* struct containing status of a query */ -struct pico_mdns_cookie { - struct pico_dns_header *header; /* packet header */ - char *url; /* hostname being queried */ - unsigned int count; /* number of packets to send */ - uint16_t len; /* length of header */ - uint16_t qtype; - uint16_t qclass; - unsigned int probe; /* indicator for probing */ - void (*callback)(char *, void *); - void *arg; - struct pico_timer *timer; -}; +#else +#define mdns_dbg dbg +#endif -struct pico_mdns_cache_rr { - char *url; - struct pico_dns_answer_suffix *suf; - char *rdata; - struct pico_timer *timer; +#define PICO_MDNS_QUERY_TIMEOUT (10000) /* Ten seconds */ +#define PICO_MDNS_RR_TTL_TICK (1000) /* One second */ + +/* mDNS MTU size */ +#define PICO_MDNS_MTU 1400u + +/* Cookie flags */ +#define PICO_MDNS_COOKIE_TYPE_ANNOUNCEMENT 0x01u +#define PICO_MDNS_COOKIE_TYPE_ANSWER 0x02u +#define PICO_MDNS_COOKIE_TYPE_QUERY 0x04u +#define PICO_MDNS_COOKIE_TYPE_PROBE 0x08u +/* Cookie status */ +#define PICO_MDNS_COOKIE_STATUS_ACTIVE 0xffu +#define PICO_MDNS_COOKIE_STATUS_INACTIVE 0x00u +#define PICO_MDNS_COOKIE_STATUS_CANCELLED 0x77u + +/* Question flags */ +#define PICO_MDNS_QUESTION_FLAG_PROBE 0x01u +#define PICO_MDNS_QUESTION_FLAG_NO_PROBE 0x00u +#define PICO_MDNS_QUESTION_FLAG_UNICAST_RES 0x02u +#define PICO_MDNS_QUESTION_FLAG_MULTICAST_RES 0x00u + +#define IS_QUESTION_PROBE_FLAG_SET(x) \ +(((x) & PICO_MDNS_QUESTION_FLAG_PROBE) ? 1 : 0 ) +#define IS_QUESTION_UNICAST_FLAG_SET(x) \ +(((x) & PICO_MDNS_QUESTION_FLAG_UNICAST_RES) ? 1 : 0 ) +#define IS_QUESTION_MULTICAST_FLAG_SET(x) \ +(((x) & PICO_MDNS_QUESTION_FLAG_UNICAST_RES) ? 0 : 1 ) + +/* Resource Record flags */ +#define PICO_MDNS_RECORD_HOSTNAME 0x02u +#define PICO_MDNS_RECORD_ADDITIONAL 0x08u +#define PICO_MDNS_RECORD_SEND_UNICAST 0x10u +#define PICO_MDNS_RECORD_CURRENTLY_PROBING 0x20u +#define PICO_MDNS_RECORD_PROBED 0x40u +#define PICO_MDNS_RECORD_CLAIMED 0x80u + +#define IS_RES_RECORD_FLAG_CLAIM_SHARED_SET(x) \ +(((x) & PICO_MDNS_RECORD_SHARED) ? 1 : 0) +#define IS_RES_RECORD_FLAG_CLAIM_UNIQUE_SET(x) \ +(((x) & PICO_MDNS_RECORD_SHARED) ? 0 : 1) +#define IS_RES_RECORD_FLAG_HOSTNAME_SET(x) \ +(((x) & PICO_MDNS_RECORD_HOSTNAME) ? 1 : 0) +#define IS_RES_RECORD_FLAG_CURRENTLY_PROBING(x) \ +(((x) & PICO_MDNS_RECORD_CURRENTLY_PROBING) ? 1 : 0) +#define IS_RES_RECORD_FLAG_PROBED_SET(x) \ +(((x) & PICO_MDNS_RECORD_PROBED) ? 1 : 0) +#define IS_RES_RECORD_FLAG_CLAIMED_SET(x) \ +(((x) & PICO_MDNS_RECORD_CLAIMED) ? 1 : 0) +#define IS_RES_RECORD_FLAG_ADDITIONAL_SET(x) \ +(((x) & PICO_MDNS_RECORD_ADDITIONAL) ? 1 : 0) +#define IS_RES_RECORD_FLAG_SEND_UNICAST_SET(x) \ +(((x) & PICO_MDNS_RECORD_SEND_UNICAST) ? 1 : 0) + +/* Set and clear flags */ +#define PICO_MDNS_SET_FLAG(x, b) (x = ((x) | (uint8_t)(b))) +#define PICO_MDNS_CLR_FLAG(x, b) (x = ((x) & (~((uint8_t)(b))))) + +/* Set and clear MSB of BE short */ +#define PICO_MDNS_SET_MSB_BE(x) (x = x | (uint16_t)(0x0080u)) +#define PICO_MDNS_CLR_MSB_BE(x) (x = x & (uint16_t)(0xff7fu)) +#define PICO_MDNS_IS_MSB_SET(x) (((x & 0x8000u) >> 15u) ? 1 : 0) + +/* **************************************************************************** + * mDNS cookie + * ****************************************************************************/ +struct pico_mdns_cookie +{ + pico_dns_question_vector qvector; // Question vector + pico_mdns_record_vector rvector; // Record vector + uint8_t count; // Times to send the query + uint8_t type; // QUERY/ANNOUNCE/PROBE/ANSWER + uint8_t status; // Active status + uint8_t timeout; // Timeout counter + struct pico_timer *send_timer; // For sending events + void (*callback)(pico_mdns_record_vector *, + char *, + void *); // Callback + void *arg; // Argument to pass to callback }; -/* Global socket and port for all mdns communication */ -static struct pico_socket *mdns_sock = NULL; -static uint16_t mdns_port = 5353u; - -/* only one hostname can be claimed at the time */ -static char *mdns_global_host; - -static int mdns_cache_cmp(void *ka, void *kb) +/* **************************************************************************** + * MARK: PROTOTYPES */ +static int +pico_mdns_record_am_i_lexi_later( struct pico_mdns_record *my_record, + struct pico_mdns_record *peer_record); + +static struct pico_mdns_record * +pico_mdns_record_copy_with_new_name( struct pico_mdns_record *record, + const char *new_rname ); + +static struct pico_mdns_record * +pico_mdns_record_copy( struct pico_mdns_record *record ); + +static int +pico_mdns_record_vector_delete( pico_mdns_record_vector *vector, + uint16_t index ); + +static int +pico_mdns_record_tree_del_url( const char *url, struct pico_tree *tree ); + +static int +pico_mdns_record_tree_del_record( struct pico_mdns_record *record, + struct pico_tree *tree ); + +static int +pico_mdns_getrecord_generic( const char *url, uint16_t type, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg); + +static void +pico_mdns_send_probe_packet( pico_time now, void *arg ); + +static int +pico_mdns_reclaim( pico_mdns_record_vector record_vector, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ); +/* EOF PROTOTYPES + * ****************************************************************************/ + +// MARK: TREES & GLOBAL VARIABLES + +/* **************************************************************************** + * Compares two data buffers + * ****************************************************************************/ +static int +pico_mdns_rdata_cmp( uint8_t *a, uint8_t *b, + uint16_t rdlength_a, uint16_t rdlength_b ) { - struct pico_mdns_cache_rr *a = ka, *b = kb; - uint32_t ha = 0, hb = 0; - - /* Cache is sorted by qtype, name */ - if(a->suf->qtype < b->suf->qtype) - return -1; - - if(b->suf->qtype < a->suf->qtype) - return 1; - - ha = pico_hash(a->url, (uint32_t)strlen(a->url)); - hb = pico_hash(b->url, (uint32_t)strlen(b->url)); + uint16_t i = 0; + uint16_t longest_rdlength = 0; - if(ha < hb) + /* Check params */ + if (!a || !b) { + pico_err = PICO_ERR_EINVAL; return -1; + } - if(hb < ha) - return 1; + if (rdlength_a >= rdlength_b) + longest_rdlength = rdlength_a; + else + longest_rdlength = rdlength_b; + + for (i = 0; i < longest_rdlength; i++) { + if (i < rdlength_a && i < rdlength_b) { + if ((uint8_t)a[i] == (uint8_t)b[i]) + continue; + else + return (((uint8_t)a[i] < (uint8_t)b[i]) ? -1 : 1); + } else if (rdlength_a == rdlength_b) + return 0; + else if (rdlength_a == longest_rdlength) + return 1; + else + return -1; + } return 0; } -/* Function for comparing two queries in a tree */ -static int mdns_cmp(void *ka, void *kb) +/* **************************************************************************** + * Compares two mDNS record by name and type + * ****************************************************************************/ +static int +pico_mdns_cmp_name_type( struct pico_mdns_record *a, + struct pico_mdns_record *b ) { - struct pico_mdns_cookie *a = ka, *b = kb; - uint32_t ha = 0, hb = 0; + uint16_t a_type = 0, b_type = 0; + + /* Check params */ + if (!a || !b) + return -2; - /* Cookie is sorted by qtype, name */ - if(a->qtype < b->qtype) + if (!(a->record) || !(b->record)) + return -2; + if (a->record && !(b->record)) + return 1; + if (!(a->record) && b->record) return -1; - if(b->qtype < a->qtype) + if (!(a->record->rsuffix) || !(b->record->rsuffix)) + return -2; + if (a->record->rsuffix && !(b->record->rsuffix)) return 1; + if (!(a->record->rsuffix) && b->record->rsuffix) + return -1; - ha = pico_hash(a->url, (uint32_t)strlen(a->url)); - hb = pico_hash(b->url, (uint32_t)strlen(b->url)); + a_type = short_be(a->record->rsuffix->rtype); + b_type = short_be(b->record->rsuffix->rtype); - if(ha < hb) + /* First, compare the rrtypes */ + if(a_type < b_type) return -1; - - if(hb < ha) + if(b_type < a_type) return 1; - return 0; + /* Then, compare the rrnames */ + return pico_mdns_rdata_cmp((uint8_t *)a->record->rname, + (uint8_t *)b->record->rname, + (uint16_t)strlen(a->record->rname), + (uint16_t)strlen(b->record->rname)); } -/* cache records for the mDNS hosts in the network */ -PICO_TREE_DECLARE(CacheTable, mdns_cache_cmp); - -/* tree containing queries */ -PICO_TREE_DECLARE(QTable, mdns_cmp); - -/* sends an mdns packet on the global socket*/ -static int pico_mdns_send(struct pico_dns_header *hdr, unsigned int len) +/* **************************************************************************** + * Function for comparing 2 resource records in the tree. + * ****************************************************************************/ +static int +pico_mdns_cmp( void *ka, void *kb ) { - struct pico_ip4 dst; - pico_string_to_ipv4(PICO_MDNS_DEST_ADDR4, &dst.addr); - return pico_socket_sendto(mdns_sock, hdr, (int)len, &dst, short_be(mdns_port)); + struct pico_mdns_record *a = NULL; + struct pico_mdns_record *b = NULL; + int ret = 0; + + /* Parse in the records */ + a = (struct pico_mdns_record *)ka; + b = (struct pico_mdns_record *)kb; + + /* First compare name and type */ + ret = pico_mdns_cmp_name_type(a, b); + if(ret) + return ret; + + /* Finally compare rdata for unique comparising */ + return pico_mdns_rdata_cmp((uint8_t *)a->record->rdata, + (uint8_t *)b->record->rdata, + short_be(a->record->rsuffix->rdlength), + short_be(b->record->rsuffix->rdlength)); } -static int pico_mdns_cache_del_rr(char *url, uint16_t qtype, char *rdata) +/* **************************************************************************** + * Function for comparing 2 cookies in the tree. + * ****************************************************************************/ +static int +pico_mdns_cookie_cmp( void *ka, void *kb ) { - struct pico_mdns_cache_rr test, *found = NULL; + struct pico_mdns_cookie *a = NULL; + struct pico_mdns_cookie *b = NULL; - test.suf = PICO_ZALLOC(sizeof(struct pico_dns_answer_suffix)); - if(!test.suf) - return -1; + /* To compare questions */ + struct pico_dns_question *qa = NULL; + struct pico_dns_question *qb = NULL; - test.url = url; - test.suf->qclass = PICO_DNS_CLASS_IN; /* We only support IN */ - test.suf->qtype = qtype; - test.rdata = rdata; + /* To compare records */ + struct pico_mdns_record *ra = NULL; + struct pico_mdns_record *rb = NULL; + int ret = 0; + uint16_t i = 0, j = 0, a_type = 0, b_type = 0; - found = pico_tree_findKey(&CacheTable, &test); - PICO_FREE(test.suf); + /* Parse in the cookies */ + a = (struct pico_mdns_cookie *)ka; + b = (struct pico_mdns_cookie *)kb; - if(!found) { - mdns_dbg("Couldn't find cache RR to delete\n"); - return -1; - } + /* Start comparing the questions */ - mdns_dbg("Removing RR: qtype '%d' url '%s'\n", qtype, url); + for (i = 0, j = 0; ((i < a->qvector.count) && (j < b->qvector.count)); + i++, j++) { + /* Get questions at current index */ + qa = pico_dns_question_vector_get(&(a->qvector), i); + qb = pico_dns_question_vector_get(&(b->qvector), j); - pico_tree_delete(&CacheTable, found); - PICO_FREE(found->url); - PICO_FREE(found->suf); - PICO_FREE(found->rdata); - PICO_FREE(found); - return 0; -} + a_type = short_be(qa->qsuffix->qtype); + b_type = short_be(qb->qsuffix->qtype); -/* delete a cookie from the tree*/ -static int pico_mdns_del_cookie(char *url, uint16_t qtype) -{ - struct pico_mdns_cookie test, *found = NULL; - char temp[256] = { - 0 - }; - if(!url) - return -1; + /* First, compare the qtypes */ + if(a_type < b_type) + return -1; + if(b_type < a_type) + return 1; - strcpy(temp + 1, url); + /* Then compare qnames */ + ret = pico_mdns_rdata_cmp((uint8_t *)qa->qname, + (uint8_t *)qb->qname, + (uint16_t)strlen(qa->qname), + (uint16_t)strlen(qb->qname)); - test.url = temp; - pico_dns_name_to_dns_notation(test.url); - test.qtype = qtype; - found = pico_tree_findKey(&QTable, &test); + if (ret) + return ret; + } - if (!found) { - mdns_dbg("Could not find cookie '%s' to delete\n", url); + /* All the questions currently compared are the same. Check which has the + most questions, if they have the same amount, move on */ + if (a->qvector.count < b->qvector.count) return -1; + if (b->qvector.count < a->qvector.count) + return 1; + + for (i = 0, j = 0; + ((i < a->rvector.count) && (j < b->rvector.count)); + i++, j++) { + /* Get records at current index */ + ra = pico_mdns_record_vector_get(&(a->rvector), i); + rb = pico_mdns_record_vector_get(&(b->rvector), j); + + /* Compare records */ + ret = pico_mdns_cmp((void *)ra, (void *)rb); + + /* If records differ, return return-value */ + if (ret) + return ret; } - pico_tree_delete(&QTable, found); - PICO_FREE(found->header); - PICO_FREE(found); + /* All the records currently compared are the same. Check Which has the most + records, if they have the same amount, move on */ + if (a->rvector.count < b->rvector.count) + return -1; + if (b->rvector.count < a->rvector.count) + return 1; + /* Cookies contain exactly the same questions and records */ return 0; } -static void pico_mdns_cache_tick(pico_time now, void *_arg) -{ - struct pico_mdns_cache_rr *rr = (struct pico_mdns_cache_rr *)_arg; - IGNORE_PARAMETER(now); +/* Cache records for the mDNS hosts in the network */ +PICO_TREE_DECLARE(Cache, pico_mdns_cmp); - rr->suf->ttl--; - mdns_dbg("TTL UPDATE: '%s' - qtype: %d - TTL: %d\n", rr->url, rr->suf->qtype, rr->suf->ttl); - if(rr->suf->ttl < 1) { - pico_mdns_cache_del_rr(rr->url, rr->suf->qtype, rr->rdata); - } - else - rr->timer = pico_timer_add(PICO_MDNS_RR_TTL_TICK, pico_mdns_cache_tick, rr); +/* My records for which I want to have the authority */ +PICO_TREE_DECLARE(MyRecords, pico_mdns_cmp); - /* TODO continuous querying: cache refresh at 80 or 85/90/95/100 percent + 2% rnd */ -} +/* Cookie-tree */ +PICO_TREE_DECLARE(Cookies, pico_mdns_cookie_cmp); -static void pico_mdns_timeout(pico_time now, void *_arg) -{ - struct pico_mdns_cookie *ck = (struct pico_mdns_cookie *)_arg; - char url[256] = { - 0 - }; - IGNORE_PARAMETER(now); +/* Global socket and port for all mdns communication */ +static struct pico_socket *mdns_sock_ipv4 = NULL; +static uint16_t mdns_port = 5353u; +static struct pico_ip4 inaddr_any = { 0 }; +static void (*init_callback)(pico_mdns_record_vector *, char *, void *) = 0; + +/* **************************************************************************** + * Hostname for this machine, only 1 hostname can be set. + * ****************************************************************************/ +static char *hostname = NULL; - if(ck->callback) - ck->callback(NULL, ck->arg); +// MARK: MDNS PACKET UTILITIES - strcpy(url, ck->url); +/* **************************************************************************** + * Sends an mdns packet on the global socket + * ****************************************************************************/ +static int +pico_mdns_send_packet(pico_dns_packet *packet, uint16_t len) +{ + struct pico_ip4 dst4; + + /* Set the destination address to the mDNS multicast-address */ + pico_string_to_ipv4(PICO_MDNS_DEST_ADDR4, &dst4.addr); - pico_dns_notation_to_name(url); - pico_mdns_del_cookie(url + 1, ck->qtype); + /* Send packet to IPv4 socket */ + return pico_socket_sendto(mdns_sock_ipv4, + packet, + (int)len, + &dst4, + short_be(mdns_port)); } -/* populate and add cookie to the tree */ -static struct pico_dns_header *pico_mdns_add_cookie(struct pico_dns_header *hdr, uint16_t len, struct pico_dns_query_suffix *suffix, unsigned int probe, void (*callback)(char *str, void *arg), void *arg) +/* **************************************************************************** + * Sends an mdns packet on the global socket via unicast + * ****************************************************************************/ +static int +pico_mdns_send_packet_unicast(pico_dns_packet *packet, + uint16_t len, + struct pico_ip4 peer) { - struct pico_mdns_cookie *ck = NULL, *found = NULL; + /* Send packet to IPv4 socket */ + return pico_socket_sendto(mdns_sock_ipv4, + packet, + (int)len, + &peer, + short_be(mdns_port)); +} - ck = PICO_ZALLOC(sizeof(struct pico_mdns_cookie)); - if (!ck) - return NULL; +// MARK: COOKIE UTILITIES - ck->header = hdr; - ck->url = (char *)hdr + sizeof(struct pico_dns_header); - pico_to_lowercase(ck->url); - ck->len = len; - ck->qtype = short_be(suffix->qtype); - if (short_be(suffix->qtype) == PICO_DNS_TYPE_PTR) - mdns_dbg("PTR\n"); - - ck->qclass = short_be(suffix->qclass); - ck->count = 3; - ck->probe = probe; - ck->callback = callback; - ck->arg = arg; - - found = pico_tree_insert(&QTable, ck); - /* cookie already in tree */ - if (found) { - pico_err = PICO_ERR_EAGAIN; - PICO_FREE(ck); - PICO_FREE(hdr); - return NULL; +/* **************************************************************************** + * Deletes a mDNS packet cookie and free's memory. + * ****************************************************************************/ +static int +pico_mdns_cookie_delete( struct pico_mdns_cookie **cookie ) +{ + /* Check params */ + if (!cookie || !(*cookie)) { + pico_err = PICO_ERR_EINVAL; + return -1; } - mdns_dbg("Cookie '%s' qtype '%d' added to QTable\n", ck->url, ck->qtype); - - if(probe == 0) - ck->timer = pico_timer_add(PICO_MDNS_QUERY_TIMEOUT, pico_mdns_timeout, ck); + /* Destroy the vectors contained */ + pico_dns_question_vector_destroy(&((*cookie)->qvector)); + pico_mdns_record_vector_destroy(&((*cookie)->rvector)); - return hdr; -} + /* Delete the cookie itself */ + PICO_FREE(*cookie); + *cookie = NULL; + cookie = NULL; -static void pico_mdns_fill_header(struct pico_dns_header *hdr, uint16_t qdcount, uint16_t ancount) -{ - hdr->id = short_be(0); - pico_dns_fill_header(hdr, qdcount, ancount); + return 0; } -static uint16_t mdns_get_len(uint16_t qtype, char *rdata) +/* **************************************************************************** + * Creates a mDNS cookie + * ****************************************************************************/ +static struct pico_mdns_cookie * +pico_mdns_cookie_create( pico_dns_question_vector qvector, + pico_mdns_record_vector rvector, + uint8_t count, + uint8_t type, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ) { - uint16_t len = 0; - switch(qtype) - { - case PICO_DNS_TYPE_A: - len = PICO_SIZE_IP4; - break; - #ifdef PICO_SUPPORT_IPV6 - case PICO_DNS_TYPE_AAAA: - len = PICO_SIZE_IP6; - break; - #endif - case PICO_DNS_TYPE_PTR: - len = (uint16_t)(strlen(rdata) + 1u); /* +1 for null termination */ - break; - } - return len; -} - -/* create an mdns answer */ -static struct pico_dns_header *pico_mdns_create_answer(char *url, unsigned int *len, uint16_t qtype, void *_rdata) -{ - struct pico_dns_header *header = NULL; - char *domain = NULL; - uint8_t *answer = NULL; - struct pico_dns_answer_suffix *asuffix = NULL; - uint32_t ttl = 224; - uint16_t slen, datalen; - char *rdata = (char*)_rdata; - - datalen = mdns_get_len(qtype, rdata); - if (!datalen) - return NULL; - - slen = (uint16_t)(pico_dns_client_strlen(url) + 2u); - *len = (unsigned int)(sizeof(struct pico_dns_header) + slen + sizeof(struct pico_dns_answer_suffix) + datalen); + struct pico_mdns_cookie *cookie = NULL; // Packet cookie to send - header = PICO_ZALLOC(*len); - if(!header) { + /* Provide space for the mDNS packet cookie */ + cookie = PICO_ZALLOC(sizeof(struct pico_mdns_cookie)); + if (!cookie) { pico_err = PICO_ERR_ENOMEM; return NULL; } - domain = (char *)header + sizeof(struct pico_dns_header); - memcpy(domain + 1u, url, strlen(url)); - asuffix = (struct pico_dns_answer_suffix *)(domain + slen); - answer = ((uint8_t *)asuffix + sizeof(struct pico_dns_answer_suffix)); - memcpy(answer, rdata, datalen); + /* Fill in the fields */ + cookie->qvector = qvector; + cookie->rvector = rvector; + cookie->count = count; + cookie->type = type; + cookie->status = PICO_MDNS_COOKIE_STATUS_INACTIVE; + cookie->timeout = 10u; + cookie->send_timer = NULL; + cookie->callback = callback; + cookie->arg = arg; + return cookie; +} + +/* **************************************************************************** + * Find a query cookie that contains a questions for a specific name + * ****************************************************************************/ +static struct pico_mdns_cookie * +pico_mdns_cookie_tree_find_query_cookie( const char *name ) +{ + struct pico_mdns_cookie *cookie = NULL; + struct pico_tree_node *node = NULL; + struct pico_dns_question *found = NULL; - /* assemble dns message */ - pico_mdns_fill_header(header, 0, 1); /* 0 questions, 1 answer */ - pico_dns_name_to_dns_notation(domain); + /* Check params */ + if (!name) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } - pico_dns_fill_rr_suffix(asuffix, qtype, PICO_DNS_CLASS_IN, ttl, datalen); + /* Iterate over the cookie-tree to find a cookie that contains a question + for this name */ + pico_tree_foreach(node, &Cookies) { + cookie = node->keyValue; + found = pico_dns_question_vector_find_name(&(cookie->qvector), name); + if (found) + return cookie; + } - return header; + return NULL; } -static int pico_mdns_perform_name_query(struct pico_dns_query_suffix *qsuffix, uint16_t proto) +/* **************************************************************************** + * Delete a specific cookie from the cookie-tree + * ****************************************************************************/ +static int +pico_mdns_cookie_tree_del_cookie( struct pico_mdns_cookie *cookie ) { -#ifdef PICO_SUPPORT_IPV6 - if(proto == PICO_PROTO_IPV6) { - pico_dns_fill_query_suffix(qsuffix, PICO_DNS_TYPE_AAAA, PICO_DNS_CLASS_IN); - return 0; + /* Check params */ + if (!cookie) { + pico_err = PICO_ERR_EINVAL; + return -1; } -#endif - if(proto == PICO_PROTO_IPV4) { - pico_dns_fill_query_suffix(qsuffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN); - return 0; + /* Delete cookie */ + pico_tree_delete(&Cookies, cookie); + if (pico_mdns_cookie_delete(&cookie)) { + mdns_dbg("Could not delete cookie from Cookie tree!\n"); + return -1; } - return -1; + return 0; } - -static int pico_mdns_perform_query(struct pico_dns_query_suffix *qsuffix, uint16_t proto, unsigned int probe, unsigned int inv) +/* **************************************************************************** + * Add a cookie to the cookie-tree + * ****************************************************************************/ +static int +pico_mdns_cookie_tree_add_cookie( struct pico_mdns_cookie *cookie ) { - if(probe == 1) - pico_dns_fill_query_suffix(qsuffix, PICO_DNS_TYPE_ANY, PICO_DNS_CLASS_IN); - else if(inv) - pico_dns_fill_query_suffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN); - else - return pico_mdns_perform_name_query(qsuffix, proto); - + if (pico_tree_insert(&Cookies, cookie)) { + return -1; + } return 0; } -static unsigned int pico_mdns_prepare_query_string(const char *url, char *inaddr_arpa, unsigned int inverse, uint16_t proto) +/* **************************************************************************** + * Finds an mDNS record in a cookie by comparing name and type. There can only + * be 1 record in a PROBE! cookie with a unique name and type combination, + * so this function only returns 1 record. + * ****************************************************************************/ +static struct pico_mdns_record * +pico_mdns_cookie_find_record( struct pico_mdns_cookie *cookie, + struct pico_dns_record *dns_record ) { - unsigned int slen = 0; - if(inverse && proto == PICO_PROTO_IPV4) { - strcpy(inaddr_arpa, ".in-addr.arpa"); - slen = (uint16_t)(pico_dns_client_strlen(url) + 2u); - } + /* In a cookie only one */ + struct pico_mdns_record *node_record = NULL; + struct pico_mdns_record record = {0}; + uint16_t i = 0; -#ifdef PICO_SUPPORT_IPV6 - else if (inverse && proto == PICO_PROTO_IPV6) { - strcpy(inaddr_arpa, ".IP6.ARPA"); - slen = STRLEN_PTR_IP6 + 2u; + /* Check params */ + if (!cookie || !dns_record) { + pico_err = PICO_ERR_EINVAL; + return NULL; } -#endif - else { - strcpy(inaddr_arpa, ""); - slen = (uint16_t)(pico_dns_client_strlen(url) + 2u); + if (cookie->type != PICO_MDNS_COOKIE_TYPE_PROBE) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + /* Create test record */ + record.record = dns_record; + + /* Iterate over record vector */ + for (i = 0; i < pico_mdns_record_vector_count(&(cookie->rvector)); i++) { + node_record = pico_mdns_record_vector_get(&(cookie->rvector), i); + if (node_record) { + if (pico_mdns_cmp_name_type(node_record, &record) == 0) { + return node_record; + } + } } - return slen; + return NULL; } -static int pico_mdns_create_query_valid_args(const char *url, uint16_t *len, uint16_t proto, void (*callback)(char *str, void *arg)) +/* **************************************************************************** + * Apply simultaneous probe tiebreaking on a probe cookie + * ****************************************************************************/ +static int +pico_mdns_cookie_apply_spt( struct pico_mdns_cookie *cookie, + struct pico_dns_record *answer) { - if (!url || !len || !callback) + struct pico_mdns_record *my_record = NULL; + struct pico_mdns_record peer_record; + int ret = 0; + + /* Check params */ + if (!cookie || !answer) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + if (cookie->type != PICO_MDNS_COOKIE_TYPE_PROBE) { + pico_err = PICO_ERR_EINVAL; return -1; + } + + cookie->status = PICO_MDNS_COOKIE_STATUS_INACTIVE; - if (proto != PICO_PROTO_IPV6 && proto != PICO_PROTO_IPV4) + /* Implement Simultaneous Probe Tiebreaking */ + my_record = pico_mdns_cookie_find_record(cookie, answer); + if (!my_record) { + mdns_dbg("This is weird! Record magically removed from cookie...\n"); return -1; + } + + peer_record.record = answer; + ret = pico_mdns_record_am_i_lexi_later(my_record, &peer_record); + if (ret > 0) { + mdns_dbg("My record is lexographically later! Yay!\n"); + cookie->status = PICO_MDNS_COOKIE_STATUS_ACTIVE; + } else { + pico_timer_cancel(cookie->send_timer); + cookie->timeout = 10u; + cookie->count = 3; + cookie->send_timer = pico_timer_add(1000, pico_mdns_send_probe_packet, + (void *)cookie); + mdns_dbg("Probing postponed with 1s because of S.P.T.\n"); + } return 0; } - -static void pico_mdns_populate_query_domain(const char *url, char *domain, char *inaddr_arpa, unsigned int arpalen, unsigned int inverse, unsigned int proto, unsigned int slen) +/* **************************************************************************** + * Checks whether there is a conflict-suffix already present in the first lbl + * of a name or not. If there is a conflict-suffix present, the + * opening-bracket and the closing-bracket pointer will be set accordingly an + * the suffix-string will be filled in. + * ****************************************************************************/ +static uint8_t +pico_mdns_is_suffix_present( char rname[], + char **opening_bracket_index, + char **closing_bracket_index, + char suffix[][5]) { + uint8_t suffix_is_present = 0, s_i = 0; + char temp[5] = {0}; + char *i = 0; + + /* Check params */ + if (!opening_bracket_index || !closing_bracket_index || !suffix) { + pico_err = PICO_ERR_EINVAL; + return 0; + } + + /* First clean out those pointers */ + *opening_bracket_index = NULL; + *closing_bracket_index = NULL; - if(inverse && proto == PICO_PROTO_IPV4) { - memcpy(domain + 1u, url, strlen(url)); - pico_dns_mirror_addr(domain + 1u); - memcpy(domain + slen - 1, inaddr_arpa, arpalen); + for (i = rname + 1; i < ((rname + 1) + *rname); i++) { + /* Find the first opening bracket */ + if (*i == '(') { + *opening_bracket_index = i; + suffix_is_present = 1; + } else { + /* Check if what follows is numeric and copy if so */ + if (*opening_bracket_index && i > *opening_bracket_index) { + if (*i < '0' || *i > '9') { + if (*i == ')') { + *closing_bracket_index = i; + } else { + suffix_is_present = 0; + } + } else { + if (s_i < 5) + (*suffix)[s_i++] = *i; + } + } + } } -#ifdef PICO_SUPPORT_IPV6 - else if (inverse && proto == PICO_PROTO_IPV6) { - pico_dns_ipv6_set_ptr(url, domain + 1u); - memcpy(domain + 1u + STRLEN_PTR_IP6, inaddr_arpa, arpalen); + if (!suffix_is_present) { + *opening_bracket_index = NULL; + *closing_bracket_index = NULL; + memcpy(suffix[0], temp, 5); } -#endif - else - memcpy(domain + 1u, url, strlen(url)); + + return suffix_is_present; } -/* create an mdns query */ -static struct pico_dns_header *pico_mdns_create_query(const char *url, uint16_t *len, uint16_t proto, unsigned int probe, unsigned int inverse, void (*callback)(char *str, void *arg), void *arg) +/* **************************************************************************** + * Utility function to append a conflict resolution suffix to the first label + * of a FQDN. + * ****************************************************************************/ +static char * +pico_mdns_resolve_name_conflict( char rname[] ) { - struct pico_dns_header *header = NULL; - char *domain = NULL; - struct pico_dns_query_suffix *qsuffix = NULL; - char inaddr_arpa[14]; - unsigned int slen, arpalen; - - if (pico_mdns_create_query_valid_args(url, len, proto, callback) < 0) { - pico_err = PICO_ERR_EINVAL; + char *new_rname = NULL; + uint16_t new_rlen = 0; + char *opening_bracket_index = NULL; + char *closing_bracket_index = NULL; + char suffix[5] = { 0 }; + char new_suffix[5] = { 0 }; + char *str = NULL; + uint16_t temp = 0; + + /* Check params */ + if (!rname) { return NULL; } - slen = pico_mdns_prepare_query_string(url, inaddr_arpa, inverse, proto); - - arpalen = (unsigned int)strlen(inaddr_arpa); - *len = (uint16_t)(sizeof(struct pico_dns_header) + slen + arpalen + sizeof(struct pico_dns_query_suffix)); + /* Check whether a conflict-suffix is already present in the first label + of the name */ + if (pico_mdns_is_suffix_present(rname, &opening_bracket_index, + &closing_bracket_index,&suffix)){ + /* If suffix is '()' */ + if (strlen(suffix) == 0) { + new_rlen = (uint16_t)(strlen(rname) + 1); + strcpy(new_suffix, "2"); + } else { + /* If suffix is numeric update the number & generate new suffix */ + str = suffix; + while (*str >= '0' && *str <= '9') + temp = (uint16_t)(temp * 10 + *str++ - '0'); + temp++; + sprintf(new_suffix, "%u", temp); + new_rlen = (uint16_t)(strlen(rname) + (strlen(new_suffix) - + strlen(suffix))); + } + } else { + /* If no suffix is present at all */ + opening_bracket_index = rname + rname[0]; + closing_bracket_index = opening_bracket_index + 1; + new_rlen = (uint16_t)(strlen(rname) + 4u); + strcpy(new_suffix, " (2)"); + } - header = PICO_ZALLOC(*len); - if(!header) { + /* Provide space for the new name */ + new_rname = (char *)PICO_ZALLOC(new_rlen + 1u); + if (!new_rname) { pico_err = PICO_ERR_ENOMEM; return NULL; } - domain = (char *)header + sizeof(struct pico_dns_header); - qsuffix = (struct pico_dns_query_suffix *)(domain + slen + arpalen); - - pico_mdns_populate_query_domain(url, domain, inaddr_arpa, arpalen, inverse, proto, slen); - - /* assemble dns message */ - pico_mdns_fill_header(header, 1, 0); - pico_dns_name_to_dns_notation(domain); + /* Assemble the new name again */ + memcpy(new_rname, rname, (size_t)(opening_bracket_index - rname + 1)); + strcpy(new_rname + (opening_bracket_index - rname) + 1, new_suffix); + strcpy(new_rname + (opening_bracket_index - rname) + + strlen(new_suffix) + 1, closing_bracket_index); + new_rname[0] = (char)(new_rname[0] + (char)(strlen(new_rname) - + strlen(rname))); + return new_rname; +} - if (pico_mdns_perform_query(qsuffix, proto, probe, inverse) < 0) - return NULL; +/* **************************************************************************** + * Utility function to generate new records from conflicting ones (copy) with + * another name. + * ****************************************************************************/ +static int +pico_mdns_generate_new_records( pico_mdns_record_vector *conflict_vector, + char *conflict_name, + pico_mdns_record_vector *new_vector, + char *new_name ) +{ + struct pico_mdns_record *record = NULL, *new_record = NULL; + uint16_t i = 0; + + for (i = 0; i < pico_mdns_record_vector_count(conflict_vector); i++) { + record = pico_mdns_record_vector_get(conflict_vector, i); + if (strcmp(record->record->rname, conflict_name) == 0) { + /* Create a new record */ + new_record = pico_mdns_record_copy_with_new_name(record, new_name); + if (!new_record) { + mdns_dbg("Could not create new non-conflicting record!\n"); + return -1; + } + /* Reset status bits */ + new_record->flags &= 0x1F; + /* Add the record to a vector */ + if (pico_mdns_record_vector_add(new_vector, new_record) < 0) { + mdns_dbg("Could not add record to vector!\n"); + pico_mdns_record_delete(&new_record); + return -1; + } + /* Remove current conflicting record */ + if (pico_mdns_record_vector_delete(conflict_vector, i) < 0) { + mdns_dbg("Could not delete conflicting record from vector!\n"); + pico_mdns_record_delete(&new_record); + return -1; + } + /* Because the record is deleted from the vector, when the next + iteration occurs count may be OOB, so decrement i. */ + --i; + } + } - return pico_mdns_add_cookie(header, *len, qsuffix, probe, callback, arg); + return 0; } -/* Look for a RR in cache matching hostname and qtype */ -static struct pico_mdns_cache_rr *pico_mdns_cache_find_rr(const char *url, uint16_t qtype) +/* **************************************************************************** + * Apply conflict resolution for a certain name on a probe cookie. + * ****************************************************************************/ +static int +pico_mdns_cookie_resolve_conflict( struct pico_mdns_cookie *cookie, + char *rname ) { - struct pico_mdns_cache_rr *rr = NULL; - struct pico_dns_answer_suffix *suf = NULL; - struct pico_mdns_cache_rr test; - char temp[256] = { - 0 - }; + pico_mdns_record_vector rvector = { 0 }; + char *new_name = NULL, *url = NULL; - suf = PICO_ZALLOC(sizeof(struct pico_dns_answer_suffix)); - if(!suf) - return NULL; - - test.suf = suf; - suf->qtype = qtype; + /* Check params */ + if (!cookie || !rname) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + if (cookie->type != PICO_MDNS_COOKIE_TYPE_PROBE) { + pico_err = PICO_ERR_EINVAL; + return -1; + } - strcpy(temp + 1, url); - pico_to_lowercase(temp); - test.url = temp; - pico_dns_name_to_dns_notation(test.url); + /* Convert rname to url */ + url = pico_dns_qname_to_url(rname); + mdns_dbg("CONFLICT for probe query with name '%s' occured!\n", url); - mdns_dbg("Looking for '%s' with qtype '%d' in cache\n", url, qtype); + /* Prerequisite step: delete all conflicting records from my records */ + if (pico_mdns_record_tree_del_url(url, &MyRecords) < 0) + mdns_dbg("Could not delete my conflicting records!\n"); + PICO_FREE(url); - rr = pico_tree_findKey(&CacheTable, &test); - PICO_FREE(suf); - return rr; -} + /* Step 1: Remove question with that name from cookie */ + if (pico_dns_question_vector_del_name(&(cookie->qvector), rname) < 0) { + mdns_dbg("Could not delete question with nameconflict from cookie!\n"); + return -1; + } -static int pico_mdns_cache_add_rr(char *url, struct pico_dns_answer_suffix *suf, char *rdata) -{ - struct pico_mdns_cache_rr *rr = NULL, *found = NULL; - struct pico_dns_answer_suffix *rr_suf = NULL; - char *rr_url = NULL; - char *rr_rdata = NULL; + /* Step 1b: Stop timer events if cookie contains no other questions */ + if (pico_dns_question_vector_count(&(cookie->qvector)) == 0) { + pico_timer_cancel(cookie->send_timer); + cookie->send_timer = NULL; + mdns_dbg("Stopped timer events for conflicting cookie.\n"); + } - if(!url || !suf || !rdata) + /* Step 2: Create a new name depending on current name */ + if (!(new_name = pico_mdns_resolve_name_conflict(rname))) { + mdns_dbg("Resolving name conflict returned NULL!\n"); return -1; - - /* Don't cache PTR answers */ - if(short_be(suf->qtype) == PICO_DNS_TYPE_PTR ) { - mdns_dbg("Not caching PTR answer\n"); - return 0; } - rr = PICO_ZALLOC(sizeof(struct pico_mdns_cache_rr)); - rr_suf = PICO_ZALLOC(sizeof(struct pico_dns_answer_suffix)); - rr_url = PICO_ZALLOC(strlen(url) + 1); - rr_rdata = PICO_ZALLOC(short_be(suf->rdlength)); - - if(!rr || !rr_suf || !rr_url || !rr_rdata) { - PICO_FREE(rr); - PICO_FREE(rr_suf); - PICO_FREE(rr_url); - PICO_FREE(rr_rdata); - return -1; - } - - memcpy(rr_url + 1, url, strlen(url)); - rr->url = rr_url; - pico_dns_name_to_dns_notation(rr->url); - memcpy(rr_suf, suf, sizeof(struct pico_dns_answer_suffix)); - rr->suf = rr_suf; - rr->suf->qtype = short_be(rr->suf->qtype); - rr->suf->qclass = short_be(rr->suf->qclass); - rr->suf->ttl = long_be(suf->ttl); - rr->suf->rdlength = short_be(suf->rdlength); - memcpy(rr_rdata, rdata, rr->suf->rdlength); - rr->rdata = rr_rdata; - - found = pico_mdns_cache_find_rr(url, rr->suf->qtype); - if(found) { - if(rr->suf->ttl > 0) { - mdns_dbg("RR already in cache, updating TTL (was %ds now %ds)\n", found->suf->ttl, rr->suf->ttl); - found->suf->ttl = rr->suf->ttl; - } - else { - mdns_dbg("RR scheduled for deletion\n"); - found->suf->ttl = 1; /* TTL 0 means delete from cache but we need to wait one second */ - } + /* Step 3: Create records with new name for the records with that name */ + if (pico_mdns_generate_new_records(&(cookie->rvector), rname, + &rvector, new_name) < 0) { + mdns_dbg("Could not generate new records from conflicting ones!\n"); + PICO_FREE(new_name); + return -1; } - else { - if(rr->suf->ttl > 0) { - pico_tree_insert(&CacheTable, rr); - mdns_dbg("RR cached. Starting TTL counter, TICK TACK TICK TACK..\n"); - rr->timer = pico_timer_add(PICO_MDNS_RR_TTL_TICK, pico_mdns_cache_tick, rr); - return 0; - } - else { - mdns_dbg("RR not in cache but TTL = 0\n"); - } + PICO_FREE(new_name); + + /* Step 5: Try to reclaim the newly created records */ + if (pico_mdns_reclaim(rvector, cookie->callback, cookie->arg) < 0) { + mdns_dbg("Could not claim new records!\n"); + return -1; } - PICO_FREE(rr->suf); - PICO_FREE(rr->url); - PICO_FREE(rr->rdata); - PICO_FREE(rr); + /* Step 6: Check if cookie is not empty now */ + if (cookie->qvector.count == 0 && cookie->rvector.count == 0) { + mdns_dbg("Deleting empty cookie..."); + if (pico_mdns_cookie_tree_del_cookie(cookie) < 0) + mdns_dbg("could not delete empty cookie!\n"); + else + mdns_dbg("done\n"); + } else + mdns_dbg("Leftover records are still being probed..\n"); + return 0; } -/* look for a cookie in the tree */ -static struct pico_mdns_cookie *pico_mdns_find_cookie(const char *url, uint16_t qtype) -{ - struct pico_mdns_cookie test; - char temp[256] = { - 0 - }; +// MARK: MDNS QUESTION UTILITIES - if(!url) - return NULL; +static struct pico_dns_question * +pico_mdns_question_create( const char *url, + uint16_t *len, + uint8_t proto, + uint16_t qtype, + uint8_t flags, + uint8_t reverse ) +{ + uint16_t _qtype = 0; // qtype + uint16_t qclass = short_be(PICO_DNS_CLASS_IN); // qclass + + /* Set the MSB of the qclass field according to the mDNS format */ + if (IS_QUESTION_UNICAST_FLAG_SET(flags)) { + PICO_MDNS_SET_MSB_BE(qclass); + } else + PICO_MDNS_CLR_MSB_BE(qclass); + + /* Make the class LE again */ + qclass = short_be(qclass); + + /* Fill in the question suffix */ + if (IS_QUESTION_PROBE_FLAG_SET(flags)) { + /* RFC: + * All probe queries SHOULD be done using the desired resource + * record name and class (usually class 1, "Internet"), and + * query type "ANY" (255), to elicit answers for all + * types of records with that name. + */ + _qtype = PICO_DNS_TYPE_ANY; + } else { + _qtype = qtype; + } - strcpy(temp + 1, url); - pico_to_lowercase(temp); - test.url = temp; - pico_dns_name_to_dns_notation(test.url); - test.qtype = qtype; - return pico_tree_findKey(&QTable, &test); + /* Create a question as you would with plain DNS */ + return pico_dns_question_create(url, len, proto, _qtype, qclass, reverse); } - -#ifdef PICO_SUPPORT_IPV6 -static struct pico_ip6 *pico_get_ip6_from_ip4(struct pico_ip4 *ipv4_addr) +// MARK: MDNS RR UTILITIES + +/* **************************************************************************** + * Create a resource record for the mDNS resource record format, that is + * with the MSB of the rclass field being set accordingly. + * ****************************************************************************/ +static struct pico_dns_record * +pico_mdns_dns_record_create( const char *url, + void *_rdata, + uint16_t datalen, + uint16_t *len, + uint16_t rtype, + uint32_t rttl, + uint8_t flags ) { - struct pico_device *dev = NULL; - struct pico_ipv6_link *link = NULL; - if((dev = pico_ipv4_link_find(ipv4_addr)) == NULL) { - mdns_dbg("Could not find device!\n"); - return NULL; - } + uint16_t rclass = short_be(PICO_DNS_CLASS_IN); // rclass - if((link = pico_ipv6_link_by_dev(dev)) == NULL) { - mdns_dbg("Could not find link!\n"); - return NULL; - } + /* Set the MSB of the rclass field according to the mDNS format */ + if (IS_RES_RECORD_FLAG_CLAIM_UNIQUE_SET(flags)) + PICO_MDNS_SET_MSB_BE(rclass); + else + PICO_MDNS_CLR_MSB_BE(rclass); + + /* Make the class LE again */ + rclass = short_be(rclass); - return &link->address; + /* Create a resource record as you would with plain DNS */ + return pico_dns_record_create(url, _rdata, datalen, len, + rtype, rclass, rttl); } -#endif -static struct pico_dns_header *pico_mdns_query_create_answer(union pico_address *local_addr, uint16_t qtype, - unsigned int *len, char *name) +static int +pico_mdns_record_resolve_conflict( struct pico_mdns_record *record, + char *rname ) { - if(qtype == PICO_DNS_TYPE_A || qtype == PICO_DNS_TYPE_ANY) { - return pico_mdns_create_answer(mdns_global_host, len, qtype, local_addr); - } - -#ifdef PICO_SUPPORT_IPV6 - if(qtype == PICO_DNS_TYPE_AAAA || qtype == PICO_DNS_TYPE_ANY) { - struct pico_ip6 *ip6 = pico_get_ip6_from_ip4(&local_addr->ip4); - return pico_mdns_create_answer(mdns_global_host, len, qtype, ip6); - } + pico_mdns_record_vector rvector = { 0 }; + struct pico_mdns_record *new_record = NULL; + char *new_name = NULL; -#endif - /* reply to PTR records */ - if(qtype == PICO_DNS_TYPE_PTR) { - char host_conv[255] = { - 0 - }; - mdns_dbg("Replying on PTR query...\n"); - strcpy(host_conv + 1, mdns_global_host); - pico_dns_name_to_dns_notation(host_conv); - return pico_mdns_create_answer(name, len, qtype, host_conv); + /* Check params */ + if (!record || !rname) { + pico_err = PICO_ERR_EINVAL; + return -1; } + /* There is no problem if my record is a shared record */ + if (IS_RES_RECORD_FLAG_CLAIM_SHARED_SET(record->flags)) + return 0; - return NULL; -} - + mdns_dbg("Record conflict occured for %s\n", rname); -/* reply on a single query */ -static int pico_mdns_reply_query(uint16_t qtype, struct pico_ip4 peer, char *name) -{ - struct pico_dns_header *header = NULL; - union pico_address *local_addr = NULL; - unsigned int len; + /* Step 2: Create a new name depending on current name */ + new_name = pico_mdns_resolve_name_conflict(rname); + if (!new_name) { + mdns_dbg("Resolving name conflict returned NULL!\n"); + return -1; + } - local_addr = (union pico_address *) pico_ipv4_source_find(&peer); - if (!local_addr) { - pico_err = PICO_ERR_EHOSTUNREACH; + /* Try to create new record */ + new_record = pico_mdns_record_copy_with_new_name(record, new_name); + if (!new_record) { + mdns_dbg("Could not create new non-conflicting record!\n"); + PICO_FREE(new_name); return -1; } + new_record->flags = new_record->flags & 0x1F; + PICO_FREE(new_name); - header = pico_mdns_query_create_answer(local_addr, qtype, &len, name); + /* Step 3: delete conflicting record from my records */ + if (pico_mdns_record_tree_del_record(record, &MyRecords) < 0) + mdns_dbg("Could not delete my conflicting records!\n"); - if (!header) + /* Add the record to a vector */ + if (pico_mdns_record_vector_add(&rvector, new_record) < 0) { + mdns_dbg("Could not add record to vector!\n"); return -1; + } - if(pico_mdns_send(header, len) != (int)len) { - mdns_dbg("Send error occurred!\n"); + /* Step 4: Try to reclaim the newly created record */ + if (pico_mdns_reclaim(rvector, init_callback, NULL) < 0) { + mdns_dbg("Could not claim new records!\n"); return -1; } return 0; } -static int pico_check_query_name(char *url) +/* **************************************************************************** + * Determines if my_record is lexographically later than peer_record, returns + * 1 when this is the case. + * ****************************************************************************/ +static int +pico_mdns_record_am_i_lexi_later( struct pico_mdns_record *my_record, + struct pico_mdns_record *peer_record) { - char addr[29] = { - 0 - }; - if(strcmp(url, mdns_global_host) == 0) + uint16_t my_type = 0, peer_type = 0, my_class = 0, peer_class = 0; + + /* Check params */ + if (!my_record || !peer_record) { + pico_err = PICO_ERR_EINVAL; + return -2; + } + + /* First, check class */ + my_class = short_be(my_record->record->rsuffix->rclass); + peer_class = short_be(peer_record->record->rsuffix->rclass); + if (my_class > peer_class) return 1; - pico_ipv4_to_string(addr, mdns_sock->local_addr.ip4.addr); - pico_dns_mirror_addr(addr); - memcpy(addr + strlen(addr), ".in-addr.arpa", 13); - if(strcmp(url, addr) == 0) + + /* Then, check type */ + my_type = short_be(my_record->record->rsuffix->rtype); + peer_type = short_be(peer_record->record->rsuffix->rtype); + if (my_type > peer_type) return 1; - return 0; + /* At last, check rdata */ + return pico_mdns_rdata_cmp(my_record->record->rdata, + peer_record->record->rdata, + short_be(my_record->record->rsuffix->rdlength), + short_be(peer_record->record->rsuffix->rdlength)); } - -/* handle a single incoming query */ -static int pico_mdns_handle_query(char *name, struct pico_dns_query_suffix *suf, struct pico_ip4 peer) +/* **************************************************************************** + * Creates a new mDNS resource record from an already existing DNS record + * ****************************************************************************/ +static struct pico_mdns_record * +pico_mdns_record_create_from_dns( struct pico_dns_record *dns_record ) { - struct pico_mdns_cookie *ck = NULL; - - /* remove cache flush bit if set */ - suf->qclass &= short_be((uint16_t) ~PICO_MDNS_CACHE_FLUSH_BIT); + struct pico_mdns_record *record = NULL; // Address to set afterwards - mdns_dbg("Query type: %u, class: %u\n", short_be(suf->qtype), short_be(suf->qclass)); - - if(mdns_global_host) { - if(pico_check_query_name(name)) { - pico_mdns_reply_query(short_be(suf->qtype), peer, name); - } else { - mdns_dbg("Received request for unknown hostname\n"); - } - } else { - ck = pico_mdns_find_cookie(name, short_be(suf->qtype)); - if(ck && ck->count < 3) { - /* we are probing, go probe tiebreaking */ - } else { - mdns_dbg("Received query before init\n"); - } + /* Provide space for the new mDNS resource record */ + record = PICO_ZALLOC(sizeof(struct pico_mdns_record)); + if (!record) { + mdns_dbg("Could not provide space for the mDNS resource record"); + pico_err = PICO_ERR_ENOMEM; + return NULL; } - return 0; + /* Set the DNS record */ + record->record = dns_record; + record->current_ttl = long_be(dns_record->rsuffix->rttl); + record->flags = 0; + record->claim_id = 0; + + return record; } -/* handle a single incoming answer */ -static int pico_mdns_handle_answer(char *url, struct pico_dns_answer_suffix *suf, char *data) +/* **************************************************************************** + * Copies an mDNS resource record with another name + * ****************************************************************************/ +static struct pico_mdns_record * +pico_mdns_record_copy_with_new_name( struct pico_mdns_record *record, + const char *new_rname ) { - struct pico_mdns_cookie *ck = NULL; - - /* remove cache flush bit if set */ - suf->qclass &= short_be((uint16_t) ~PICO_MDNS_CACHE_FLUSH_BIT); - - mdns_dbg("Answer for record %s was received:\n", url); - mdns_dbg("type: %u, class: %u, ttl: %lu, rdlen: %u\n", short_be(suf->qtype), - short_be(suf->qclass), (unsigned long)long_be(suf->ttl), short_be(suf->rdlength)); + struct pico_mdns_record *copy = NULL; - pico_mdns_cache_add_rr(url, suf, data); - - /* Check in the query tree whether a request was sent */ - ck = pico_mdns_find_cookie(url, short_be(suf->qtype)); - if(!ck) { - return 0; + /* Check params */ + if (!record && !new_rname) { + pico_err = PICO_ERR_EINVAL; + return NULL; } - mdns_dbg("Found a corresponding cookie!\n"); - /* if we are probing, set probe to zero so the probe timer stops the next time it goes off */ - if (ck->probe) { - mdns_dbg("Probe set to zero\n"); - ck->probe = 0; - return 0; + /* Copy the record */ + copy = pico_mdns_record_copy(record); + if (!copy) { + mdns_dbg("Could not copy record!\n"); + return NULL; } - if(short_be(suf->qtype) == PICO_DNS_TYPE_A) { - uint32_t rdata = long_from(data); - char peer_addr[46]; - pico_ipv4_to_string(peer_addr, long_from(&rdata)); - ck->callback(peer_addr, ck->arg); - } + /* Free the copied rname */ + PICO_FREE(copy->record->rname); -#ifdef PICO_SUPPORT_IPV6 - else if(short_be(suf->qtype) == PICO_DNS_TYPE_AAAA) { - uint8_t *rdata = (uint8_t *) data; - char peer_addr[46]; - pico_ipv6_to_string(peer_addr, rdata); - ck->callback(peer_addr, ck->arg); - } -#endif - else if(short_be(suf->qtype) == PICO_DNS_TYPE_PTR) { - pico_dns_notation_to_name(data); - ck->callback(data + 1, ck->arg); /* +1 to discard the beginning dot */ - } - else { - mdns_dbg("Unrecognised record type\n"); - ck->callback(NULL, ck->arg); + /* Provide a new string */ + copy->record->rname = PICO_ZALLOC(strlen(new_rname) + 1); + if (!(copy->record->rname)) { + pico_err = PICO_ERR_ENOMEM; + pico_mdns_record_delete(©); + return NULL; } - pico_timer_cancel(ck->timer); - pico_mdns_del_cookie(url, ck->qtype); + strcpy(copy->record->rname, new_rname); + copy->record->rname_length = (uint16_t)(strlen(new_rname) + 1); - return 0; + return copy; } -/* returns the compressed length of the compressed name without NULL terminator */ -static unsigned int pico_mdns_namelen_comp(char *name) +/* **************************************************************************** + * Just copies an mDNS resource record + * ****************************************************************************/ +static struct pico_mdns_record * +pico_mdns_record_copy( struct pico_mdns_record *record ) { - unsigned int len; - char *ptr; + struct pico_mdns_record *copy = NULL; - ptr = name; - while (*ptr != '\0' && !(*ptr & 0x80)) { - ptr += (uint8_t) *ptr + 1; + /* Check params */ + if (!record) { + pico_err = PICO_ERR_EINVAL; + return NULL; } - len = (unsigned int) (ptr - name); - if(*ptr != '\0') { - len++; + + /* Provide space for the copy */ + copy = PICO_ZALLOC(sizeof(struct pico_mdns_record)); + if (!copy) { + pico_err = PICO_ERR_ENOMEM; + return NULL; } - return len; -} + /* Copy the DNS record */ + copy->record = pico_dns_record_copy(record->record); + if (!(copy->record)) { + PICO_FREE(copy); + return NULL; + } -/* returns the uncompressed length of the compressed name without NULL terminator */ -static unsigned int pico_mdns_namelen_uncomp(char *name, char *buf) -{ - unsigned int len; - char *ptr, *begin_comp; + /* Copy the fields */ + copy->current_ttl = record->current_ttl; + copy->flags = record->flags; + copy->claim_id = record->claim_id; - len = 0; - begin_comp = name; - ptr = begin_comp; - while(*ptr != '\0') { - ptr += (uint8_t)*ptr + 1; - if(*ptr & 0x80) { - len += (unsigned int) (ptr - begin_comp); - begin_comp = buf + *(ptr + 1); /* set at beginning of compstring*/ - ptr = begin_comp; - } - } - len += (unsigned int) (ptr - begin_comp); - return len; + return copy; } -/* replace the label length in the domain name by '.' - * f.e. 3www6google2be0 => .www.google.be - * AND expand compressed names */ -static char *pico_mdns_expand_name_comp(char *url, char *buf) +/* **************************************************************************** + * Creates a new mDNS resource record. The address of a mDNS res record-struct + * needs to be given in record_out to return the created record in. If passed + * in record is an element of a list, the record will be appended to the end + * of the list. So you will have to iterate until the end of the list to + * access the newly created record. + * ****************************************************************************/ +struct pico_mdns_record * +pico_mdns_record_create( const char *url, + void *_rdata, + uint16_t datalen, + uint16_t rtype, + uint32_t rttl, + uint8_t flags ) { - unsigned int len; - char *ptr, *begin_comp, *str = NULL, *sp; + struct pico_mdns_record *record = NULL; + uint16_t len = 0; - len = pico_mdns_namelen_uncomp(url, buf); - mdns_dbg("Uncomp len:%u, comp len:%u.\n", len, pico_mdns_namelen_comp(url)); - if(len < pico_mdns_namelen_comp(url)) { - mdns_dbg("BOOM compressed longer than uncompressed!\n"); + /* Check params */ + if (!url || !_rdata) { + pico_err = PICO_ERR_EINVAL; return NULL; } - str = PICO_ZALLOC(len + 1); /* + 1 for null terminator */ - if(!str) { + /* Provide space for the new mDNS resource record */ + record = PICO_ZALLOC(sizeof(struct pico_mdns_record)); + if (!record) { + mdns_dbg("Could not provide space for the mDNS resource record"); pico_err = PICO_ERR_ENOMEM; return NULL; } - begin_comp = url; - ptr = begin_comp; - sp = str; - *sp = '.'; - sp++; - while(*ptr != '\0') { - memcpy(sp, ptr + 1, *(uint8_t*)ptr); - sp += (uint8_t)*ptr; - *sp = '.'; - sp++; - ptr += (uint8_t)*ptr + 1; /* jump to next occurring dot */ - if(*ptr & 0x80) { - len += (unsigned int) (ptr - begin_comp) + 1; /* +1 for the dot at the end of the label */ - begin_comp = buf + *(ptr + 1); /* set at beginning of compstring*/ - ptr = begin_comp; - } + /* Create a new record at the end of the list */ + record->record = pico_mdns_dns_record_create(url, _rdata, datalen, &len, + rtype, rttl, flags); + if (!((record)->record)) { + mdns_dbg("Creating mDNS resource record failed!\n"); + PICO_FREE(record); + return NULL; } - sp--; - *sp = '\0'; - return str; + /* Initialise fields */ + record->current_ttl = rttl; + record->flags = flags; + record->claim_id = 0; + + return record; } -/* parses an incoming packet */ -static int pico_mdns_recv(void *buf, int buflen, struct pico_ip4 peer) +/* **************************************************************************** + * Deletes a mDNS resource record. + * ****************************************************************************/ +int +pico_mdns_record_delete( struct pico_mdns_record **record ) { - struct pico_dns_header *header = (struct pico_dns_header *) buf; - char *ptr = (char *)header + sizeof(struct pico_dns_header); - struct pico_dns_query_suffix *qsuf; - struct pico_dns_answer_suffix *asuf; - uint16_t i, qcount, acount; - char *data; - - qcount = short_be(header->qdcount); - acount = short_be(header->ancount); - mdns_dbg("\n>>>>>>> QDcount: %u, ANcount: %u\n", qcount, acount); - - if(qcount == 0 && acount == 0) { - mdns_dbg("Query and answer count is 0!\n"); + /* Check params */ + if (!record || !(*record)) { + pico_err = PICO_ERR_EINVAL; return -1; } - /* handle queries */ - for(i = 0; i < qcount; i++) { - qsuf = (struct pico_dns_query_suffix*) (ptr + pico_mdns_namelen_comp(ptr) + 1); - pico_dns_notation_to_name(ptr); - if (!ptr) - return -1; + /* Delete DNS record contained */ + if ((*record)->record) + pico_dns_record_delete(&((*record)->record)); - pico_mdns_handle_query(ptr + 1, qsuf, peer); - ptr = (char *)qsuf + sizeof(struct pico_dns_query_suffix); - if(ptr - (char *)header > buflen) { - mdns_dbg("buffer is too short! ptr offset=%d buflen=%d\n", ptr - (char*)header, buflen); - return -1; - } - } - /* handle answers */ - for(i = 0; i < acount; i++) { - char *name; - asuf = (struct pico_dns_answer_suffix*) (ptr + pico_mdns_namelen_comp(ptr) + 1); - if((name = pico_mdns_expand_name_comp(ptr, buf)) == NULL) { - mdns_dbg("Received a zero name pointer\n"); - return -1; - } + /* Delete the record itself */ + PICO_FREE(*record); + *record = NULL; + record = NULL; - data = (char *)asuf + sizeof(struct pico_dns_answer_suffix); - pico_mdns_handle_answer(name + 1, asuf, data); /* +1 for starting . */ - PICO_FREE(name); - ptr = data + short_be(asuf->rdlength); - if(ptr - (char *)header > buflen) { - mdns_dbg("buffer is too short! ptr offset=%d buflen=%d\n", ptr - (char*)header, buflen); - return -1; - } - } return 0; } -/* callback for UDP socket events */ -static void pico_mdns_wakeup(uint16_t ev, struct pico_socket *s) +/* **************************************************************************** + * Initialise an mDNS record vector + * ****************************************************************************/ +int +pico_mdns_record_vector_init( pico_mdns_record_vector *vector ) { - char *recvbuf; - int pico_read = 0; - struct pico_ip4 peer = { - 0 - }; - uint16_t port = 0; - char host[30]; + /* Check params */ + if (!vector) + return -1; + + vector->records = NULL; + vector->count = 0; + return 0; +} + +/* **************************************************************************** + * Returns the amount of records contained in an mDNS record vector + * ****************************************************************************/ +uint16_t +pico_mdns_record_vector_count( pico_mdns_record_vector *vector ) +{ + /* Check params */ + if (!vector) + return 0; + return vector->count; +} + +/* **************************************************************************** + * Adds an mDNS record to an mDNS record vector + * ****************************************************************************/ +int +pico_mdns_record_vector_add( pico_mdns_record_vector *vector, + struct pico_mdns_record *record ) +{ + struct pico_mdns_record **new_records = NULL; + uint16_t i = 0; + + /* Check params */ + if (!vector || !record) + return -1; + + /* Create a new array with larger size */ + new_records = PICO_ZALLOC(sizeof(struct pico_mdns_record *) * + (vector->count + 1u)); + if (!new_records) + return -1; + + /* Copy all the record-pointers from the previous array to the new one */ + for (i = 0; i < vector->count; i++) + new_records[i] = vector->records[i]; + new_records[i] = record; + + /* Free the previous array */ + if (vector->records) + PICO_FREE(vector->records); + + /* Set the records array to the new one and update count */ + vector->records = new_records; + vector->count++; + return 0; +} + +/* **************************************************************************** + * Gets an mDNS record from an mDNS record vector at a certain index + * ****************************************************************************/ +struct pico_mdns_record * +pico_mdns_record_vector_get( pico_mdns_record_vector *vector, + uint16_t index ) +{ + /* Check params */ + if (!vector) + return NULL; + + /* Return record with conditioned index */ + if (index < vector->count) + return vector->records[index]; + + return NULL; +} + +static int +pico_mdns_record_vector_del_generic( pico_mdns_record_vector *vector, + uint16_t index, + uint8_t delete ) +{ + struct pico_mdns_record **new_records = NULL; + uint16_t i = 0; + + /* Check params */ + if (!vector) return -1; + if (index >= vector->count) return 0; + + if (delete) { + /* Delete record */ + if (pico_mdns_record_delete(&(vector->records[index])) < 0) + return -1; + } + + vector->count--; + if (vector->count) { + new_records = PICO_ZALLOC(sizeof(struct pico_mdns_record *) * + vector->count); + if (!new_records) { + pico_err = PICO_ERR_ENOMEM; + return -1; + } + } + + /* Move up subsequent records */ + for (i = index; i < vector->count; i++) { + vector->records[i] = vector->records[i + 1]; + vector->records[i + 1] = NULL; + } + + /* Copy records */ + for (i = 0; i < vector->count; i++) + new_records[i] = vector->records[i]; + + /* Free the previous array */ + PICO_FREE(vector->records); + + /* Set the records array to the new one */ + vector->records = new_records; + return 0; +} + +/* **************************************************************************** + * Removes an mDNS record from an mDNS record vector at a certain index + * ****************************************************************************/ +static int +pico_mdns_record_vector_remove( pico_mdns_record_vector *vector, + uint16_t index ) +{ + return pico_mdns_record_vector_del_generic(vector, index, 0); +} + +/* **************************************************************************** + * Deletes an mDNS record an mDNS record vector at a certain index + * ****************************************************************************/ +static int +pico_mdns_record_vector_delete( pico_mdns_record_vector *vector, + uint16_t index ) +{ + return pico_mdns_record_vector_del_generic(vector, index, 1); +} + +/* **************************************************************************** + * Deletes every mDNS record from an mDNS record vector + * ****************************************************************************/ +int +pico_mdns_record_vector_destroy( pico_mdns_record_vector *vector ) +{ + uint16_t i = 0; + + /* Check params */ + if (!vector) return -1; + + /* Delete every record in the vector */ + for (i = 0; i < vector->count; i++) { + if (pico_mdns_record_delete(&(vector->records[i])) < 0) { + mdns_dbg("Could not delete record from vector!\n"); + return -1; + } + } + + /* Update the fields */ + vector->records = NULL; + vector->count = 0; + return 0; +} + +/* **************************************************************************** + * Append two mDNS record vectors to each other + * ****************************************************************************/ +static int +pico_mdns_record_vector_append( pico_mdns_record_vector *vector, + pico_mdns_record_vector *vector_b ) +{ + struct pico_mdns_record **new_records = NULL; + uint16_t i = 0, offset = 0; + + /* Check params */ + if (!vector || !vector_b) + return -1; + + /* Create a new array with larger size */ + new_records = PICO_ZALLOC(sizeof(struct pico_mdns_record *) * + (size_t)(vector->count + vector_b->count)); + if (!new_records) + return -1; + + /* Copy all the record-pointers from the previous array to the new one */ + for (i = 0; i < vector->count; i++) + new_records[i] = vector->records[i]; + offset = i; + + for (i = offset; i < (offset + vector_b->count); i++) + new_records[i] = vector_b->records[i - offset]; + + /* Free the previous array */ + if (vector->records) + PICO_FREE(vector->records); + + /* Set the records array to the new one and update count */ + vector->records = new_records; + vector->count = (uint16_t)(vector->count + vector_b->count); + + /* Remove all the records from the second vector */ + for (i = 0; i < vector_b->count; i++) + pico_mdns_record_vector_remove(vector_b, i); + + return 0; +} + +/* **************************************************************************** + * Find multiple mDNS res records in a record tree by URL + * ****************************************************************************/ +static pico_mdns_record_vector +pico_mdns_record_tree_find_url( const char *url, + struct pico_tree *tree ) +{ + pico_mdns_record_vector cache_hits = { 0 }; + struct pico_mdns_record *node_record = NULL; + struct pico_tree_node *node = NULL; + char *rname = NULL; + + /* Check params */ + if (!url) { + pico_err = PICO_ERR_EINVAL; + return cache_hits; + } + + /* We need the FQDN to compare */ + rname = pico_dns_url_to_qname(url); + if (!rname) + return cache_hits; + + /* Iterate over the Cache-tree */ + pico_tree_foreach(node, tree) { + node_record = node->keyValue; + if (strcmp(node_record->record->rname, rname) == 0) { + /* Add the record to the an mDNS res record vector */ + if (pico_mdns_record_vector_add(&cache_hits, node_record) < 0) { + mdns_dbg("Could not add copy of cache record to vector!\n"); + return cache_hits; + } + } + } + PICO_FREE(rname); + return cache_hits; +} + +/* **************************************************************************** + * Find multiple mDNS res records in a record tree by URL and rtype + * ****************************************************************************/ +static pico_mdns_record_vector +pico_mdns_record_tree_find_url_type( const char *url, + uint16_t rtype, + struct pico_tree *tree ) +{ + pico_mdns_record_vector cache_hits = { 0 }; + struct pico_mdns_record test_record; + struct pico_mdns_record *node_record = NULL; + struct pico_mdns_record *copy = NULL; + struct pico_tree_node *node = NULL; + uint16_t len = 0; + uint8_t rdata = 0; + + /* Check params */ + if (!url) { + pico_err = PICO_ERR_EINVAL; + return cache_hits; + } + /* Create a test record */ + test_record.record = pico_dns_record_create(url, &rdata, 1, &len, rtype, + PICO_DNS_CLASS_IN, 0); + /* Iterate over the Cache-tree */ + pico_tree_foreach(node, tree) { + node_record = node->keyValue; + if (pico_mdns_cmp_name_type(node_record, &test_record) == 0) { + /* Make a copy of found record */ + copy = pico_mdns_record_copy(node_record); + if (copy) { + /* Add the copy to an mDNS record vector */ + if (pico_mdns_record_vector_add(&cache_hits, copy) < 0) { + mdns_dbg("Could not add copy of cache record to vector!\n"); + return cache_hits; + } + } + } + } + + /* Delete the test DNS record */ + if (pico_dns_record_delete(&(test_record.record)) < 0) { + mdns_dbg("Could not delete DNS test record!\n"); + return cache_hits; + } + + return cache_hits; +} + +/* **************************************************************************** + * Find a unique mDNS res record in a record tree by rname, rtype and rdata + * ****************************************************************************/ +static struct pico_mdns_record * +pico_mdns_record_tree_find_record( struct pico_mdns_record *record, + struct pico_tree *tree ) +{ + struct pico_mdns_record *node_record = NULL; + struct pico_tree_node *node = NULL; + + /* Check params */ + if (!record) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + /* Iterate over the Cache-tree */ + pico_tree_foreach(node, tree) { + node_record = node->keyValue; + if ((*tree).compare(node_record, record) == 0) + return node_record; + } + + return NULL; +} + +/* **************************************************************************** + * Delete multiple mDNS res records in a record tree by URL and rtype + * ****************************************************************************/ +static int +pico_mdns_record_tree_del_url( const char *url, + struct pico_tree *tree ) +{ + pico_mdns_record_vector cache_hits = { 0 }; + struct pico_mdns_record *record = NULL; + uint16_t i = 0; + + /* Check params */ + if (!url) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Find all the records by name in the tree */ + cache_hits = pico_mdns_record_tree_find_url(url, tree); + + /* Iterate over the results and remove them from the cache tree */ + for (i = 0; i < pico_mdns_record_vector_count(&cache_hits); i++) { + record = pico_mdns_record_vector_get(&cache_hits, i); + pico_tree_delete(tree, record); + } + + /* Delete all the cache records */ + if (pico_mdns_record_vector_destroy(&cache_hits) < 0) { + mdns_dbg("Could not delete mDNS cache records!\n"); + return -1; + } + + return 0; +} + +/* **************************************************************************** + * Delete multiple mDNS res records in a record tree by URL and rtype + * ****************************************************************************/ +static int +pico_mdns_record_tree_del_url_type( const char *url, + uint16_t type, + struct pico_tree *tree ) +{ + struct pico_mdns_record test_record; + struct pico_mdns_record *node_record = NULL; + struct pico_tree_node *node = NULL; + struct pico_tree_node *next = NULL; + + uint8_t rdata = 0; + uint16_t len = 0; + + /* Check params */ + if (!url) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Create a test record */ + test_record.record = pico_dns_record_create(url, &rdata, 1, &len, type, + PICO_DNS_CLASS_IN, 0); + + /* Iterate over the tree */ + pico_tree_foreach_safe(node, tree, next) { + node_record = node->keyValue; + if (pico_mdns_cmp_name_type(node_record, &test_record) == 0) { + /* Move the node to the next */ + node = pico_tree_next(node); + /* Delete from the tree */ + pico_tree_delete(tree, node_record); + if (pico_mdns_record_delete(&node_record) < 0) { + mdns_dbg("Could not delete mDNS res record from tree!\n"); + return -1; + } + /* Move the node to the previous, otherwise, a node will be + skipped in the next iteration */ + node = pico_tree_prev(node); + } + } + + /* Delete the test DNS record */ + if (pico_dns_record_delete(&(test_record.record)) < 0) { + mdns_dbg("Could not delete DNS test record!\n"); + return -1; + } + + return 0; +} + +/* **************************************************************************** + * Delete a unique res record in a record tree by rname, rtype and rdata + * ****************************************************************************/ +static int +pico_mdns_record_tree_del_record( struct pico_mdns_record *record, + struct pico_tree *tree ) +{ + struct pico_mdns_record *found = NULL; + + /* Check params */ + if (!record) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Try to find a unique record in the tree */ + found = pico_mdns_record_tree_find_record(record, tree); + + /* If found, delete unique record */ + if (found) { + pico_tree_delete(tree, found); + if (pico_mdns_record_delete(&found) < 0) { + mdns_dbg("Could not delete mDNS res record from tree!\n"); + } + } + + return 0; +} + +/* **************************************************************************** + * Adds a record to the tree if a same record is not already found in the tree + * ****************************************************************************/ +static int +pico_mdns_record_tree_add_record( struct pico_mdns_record *record, + struct pico_tree *tree) +{ + /* Check params */ + if (!record || !tree) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + if (!(record->record)) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + pico_tree_insert(tree, record); + return 0; +} + +// MARK: MY RECORDS UTILS + +/* **************************************************************************** + * Finds a mDNS record in my records by url and type + * ****************************************************************************/ +static struct pico_mdns_record * +pico_mdns_my_records_find_url_type( const char *url, + uint16_t type ) +{ + struct pico_mdns_record *node_record = NULL; + struct pico_tree_node *node = NULL; + struct pico_mdns_record test_record; + uint16_t len = 0; + uint8_t rdata = 0; + + /* Check params */ + if (!url) { + pico_err = PICO_ERR_EINVAL; + return NULL; + } + + /* Create a test record */ + test_record.record = pico_dns_record_create(url, &rdata, 1, &len, type, + PICO_DNS_CLASS_IN, 0); + /* Iterate over the Cache-tree */ + pico_tree_foreach(node, &MyRecords) { + node_record = node->keyValue; + if (pico_mdns_cmp_name_type(node_record, &test_record) == 0) + return node_record; + } + + /* Delete the test DNS record */ + if (pico_dns_record_delete(&(test_record.record)) < 0) { + mdns_dbg("Could not delete DNS test record!\n"); + return NULL; + } + + return NULL; +} + +/* **************************************************************************** + * Adds records contained in mdns_record_vector to my records, returns a + * mdns_record_vector with all the records who are added to my records, since, + * when a unique comination of name and type is already present in my records, + * the duplicate record will be removed from the vector and not added again. + * ****************************************************************************/ +static pico_mdns_record_vector +pico_mdns_my_records_add( pico_mdns_record_vector vector, uint8_t reclaim ) +{ + struct pico_mdns_record *record = NULL, *found = NULL; + static uint8_t claim_id_count = 0; + char *url = NULL; + uint16_t i = 0, j = 0; + + if (!reclaim) + ++claim_id_count; + + /* Iterate over record vector */ + for (i = 0; i < pico_mdns_record_vector_count(&vector); i++) { + record = pico_mdns_record_vector_get(&vector, i); + + /* Check if record with this combination of name and type is already + contained in my records and if so, skip adding */ + url = pico_dns_qname_to_url(record->record->rname); + found = pico_mdns_my_records_find_url_type(url, + short_be(record->record->rsuffix->rtype)); + PICO_FREE(url); + if (found) { + /* Remove duplicate record from the vector */ + pico_mdns_record_vector_remove(&vector, i); + continue; + } + + /* Set probed flag if shared record */ + if (IS_RES_RECORD_FLAG_CLAIM_SHARED_SET(record->flags)) + PICO_MDNS_SET_FLAG(record->flags, PICO_MDNS_RECORD_PROBED); + if (!reclaim) + record->claim_id = claim_id_count; + + /* If unique combination is not found, add record */ + if (pico_mdns_record_tree_add_record(record, &MyRecords) < 0) { + mdns_dbg("Could not add record to My Records! \n"); + /* Remove the leftover records from the vector */ + for (j = i; j < pico_mdns_record_vector_count(&vector); j++) + pico_mdns_record_vector_remove(&vector, i); + break; + } + } + return vector; +} + +/* **************************************************************************** + * Generates a list of all my records for which the probe flag already has + * been set and for which the claimed flag hasn't been set yet. Copies the + * records from my records, so you have to manually delete them. + * ****************************************************************************/ +static pico_mdns_record_vector +pico_mdns_my_records_find_probed( void ) +{ + pico_mdns_record_vector vector = { 0 }; + struct pico_mdns_record *node_record = NULL; + struct pico_mdns_record *copy = NULL; + struct pico_tree_node *node = NULL; + + pico_tree_foreach(node, &MyRecords) { + node_record = node->keyValue; + if (IS_RES_RECORD_FLAG_PROBED_SET(node_record->flags) && + !IS_RES_RECORD_FLAG_CLAIMED_SET(node_record->flags)) { + copy = pico_mdns_record_copy(node_record); + if (copy) { + if (pico_mdns_record_vector_add(&vector, copy) < 0) { + mdns_dbg("Could not add copy of mDNS record to vector!\n"); + pico_mdns_record_delete(©); + return vector; + } + } + } + } + return vector; +} + +/* **************************************************************************** + * Generates a list of all my records for which the probe flag and the + * the claimed flag has not yet been set. Copies the records from my records, + * so you have to manually delete them. + * ****************************************************************************/ +static pico_mdns_record_vector +pico_mdns_my_records_find_to_probe( void ) +{ + pico_mdns_record_vector vector = { 0 }; + struct pico_mdns_record *node_record = NULL; + struct pico_mdns_record *copy = NULL; + struct pico_tree_node *node = NULL; + + pico_tree_foreach(node, &MyRecords) { + node_record = node->keyValue; + /* Check if probed flag is not set of a record */ + if (!IS_RES_RECORD_FLAG_PROBED_SET(node_record->flags) && + !IS_RES_RECORD_FLAG_CLAIMED_SET(node_record->flags) && + IS_RES_RECORD_FLAG_CLAIM_UNIQUE_SET(node_record->flags) && + !IS_RES_RECORD_FLAG_CURRENTLY_PROBING(node_record->flags)) { + node_record->flags |= PICO_MDNS_RECORD_CURRENTLY_PROBING; + copy = pico_mdns_record_copy(node_record); + if (copy) { + if (pico_mdns_record_vector_add(&vector, copy) < 0) { + mdns_dbg("Could not add copy of mDNS record to vector!\n"); + pico_mdns_record_delete(©); + break; + } + } + } + } + return vector; +} + +/* **************************************************************************** + * Checks for all my records with a certain claim id if they've been claimed, + * returns 1 if this is the case, returns 0 otherwise. + * Adds all claimed records to the vector passed in. + * ****************************************************************************/ +static uint8_t +pico_mdns_my_records_claimed_id( uint8_t claim_id, + pico_mdns_record_vector *vector ) +{ + struct pico_mdns_record *record = NULL; + struct pico_tree_node *node = NULL; + + /* Initialise the iterator for iterating over my records */ + pico_tree_foreach(node, &MyRecords) { + record = node->keyValue; + if (record->claim_id == claim_id) { + /* Check if records are claimed for a certain claim ID */ + if (!IS_RES_RECORD_FLAG_CLAIMED_SET(record->flags)) { + return 0; + } else { + if (pico_mdns_record_vector_add(vector, record) < 0) { + mdns_dbg("Could not add record to vector!\n"); + return 0; + } + } + } + } + + return 1; +} + +/* **************************************************************************** + * Marks mDNS resource records contained in [records]-list as claimed. + * Checks 'my records' for other records that are claimed with the same + * claim ID and if all records with the same claim ID as these recordes are + * marked as claimed, the [cb_claimed]-callback will be called. Deletes the + * records contained in the list, because after a specific record has been + * claimed, there is no use in keeping it. + * ****************************************************************************/ +static int +pico_mdns_my_records_claimed( pico_mdns_record_vector rvector, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ) +{ + pico_mdns_record_vector vector = { 0 }; + struct pico_mdns_record *record = NULL; + struct pico_mdns_record *found = NULL; + char *url = NULL; + uint16_t i = 0; + uint8_t all_claimed = 1; + uint8_t claim_id = 0; + + /* Get the claim ID of the first claimed record */ + if (pico_mdns_record_vector_count(&rvector) > 0) { + claim_id = pico_mdns_record_vector_get(&rvector, 0)->claim_id; + } else { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Iterate over records and set the CLAIMED flag */ + for (i = 0; i < pico_mdns_record_vector_count(&rvector); i++) { + record = pico_mdns_record_vector_get(&rvector, i); + found = pico_mdns_record_tree_find_record(record, &MyRecords); + if (found) { + /* Set the flags of my records */ + PICO_MDNS_SET_FLAG(found->flags, PICO_MDNS_RECORD_CLAIMED); + PICO_MDNS_SET_FLAG(found->flags, PICO_MDNS_RECORD_PROBED); + + /* If the record is for the hostname, update it */ + if (IS_RES_RECORD_FLAG_HOSTNAME_SET(found->flags)) { + url = pico_dns_qname_to_url(found->record->rname); + PICO_FREE(hostname); + hostname = url; + } + } + } + + /* Check if all records with saim */ + all_claimed = pico_mdns_my_records_claimed_id(claim_id, &vector); + + /* If all_claimed is still true */ + if (all_claimed) { + mdns_dbg("%d records with claim ID '%d' are claimed!\n", + vector.count, claim_id); + callback(&vector, NULL, arg); + } + + return 0; +} + +// MARK: MDNS QUERY UTILITIES + +/* **************************************************************************** + * Creates a DNS packet meant for querying. Resource records can be added + * to query to allow: + * - Answer Section: To implement Known-Answer Suppression + * - Authority Section: To implement probe queries and tiebreaking + * ****************************************************************************/ +static pico_dns_packet * +pico_mdns_query_create( pico_dns_question_vector *qvector, + pico_dns_record_vector *anvector, + pico_dns_record_vector *nsvector, + pico_dns_record_vector *arvector, + uint16_t *len ) +{ + pico_dns_packet *packet = NULL; + + /* Create an answer as you would with plain DNS */ + packet = pico_dns_query_create(qvector, anvector, nsvector, arvector, len); + if (!packet) { + mdns_dbg("Could not create DNS query!\n"); + return NULL; + } + + /* Set the id of the DNS packet to 0 */ + packet->id = 0; + + return packet; +} + +// MARK: MDNS ANSWER UTILITIES + +/* **************************************************************************** + * Create a resource record for the mDNS answer message format, that is + * with the identifier of the DNS packet being 0. + * ****************************************************************************/ +static pico_dns_packet * +pico_mdns_answer_create( pico_dns_record_vector *anvector, + pico_dns_record_vector *nsvector, + pico_dns_record_vector *arvector, + uint16_t *len ) +{ + pico_dns_packet *packet = NULL; + + /* Create an answer as you would with plain DNS */ + packet = pico_dns_answer_create(anvector, nsvector, arvector, len); + if (!packet) { + mdns_dbg("Could not create DNS answer!\n"); + return NULL; + } + + /* Set the id of the DNS packet to 0 */ + packet->id = 0; + + return packet; +} + +// MARK: CACHE UTILITIES + +/* **************************************************************************** + * Utility function to update the TTL of a cache entry + * ****************************************************************************/ +static void +pico_mdns_cache_update_ttl( struct pico_mdns_record *record, + uint32_t ttl ) +{ + /* Check params */ + if (!record) + return; + + /* Update the TTL and timer */ + if(ttl > 0) { + mdns_dbg("RR already in cache, updating TTL (was %ds, now %ds)\n", + long_be(record->record->rsuffix->rttl), ttl); + + /* Update the TTL's */ + record->record->rsuffix->rttl = long_be(ttl); + record->current_ttl = ttl; + } else { + mdns_dbg("RR scheduled for deletion\n"); + /* TTL 0 means delete from cache but we need to wait one second */ + record->record->rsuffix->rttl = long_be(1u); + record->current_ttl = 1u; + } +} + +/* **************************************************************************** + * Utility function to add a cache entry + * ****************************************************************************/ +static int +pico_mdns_cache_add( struct pico_mdns_record *record, char *url ) +{ + struct pico_dns_record_suffix *suffix = NULL; + + /* Check param */ + if (!record || !url) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + /* Check if cache flush bit is set */ + suffix = record->record->rsuffix; + if (PICO_MDNS_IS_MSB_SET(short_be(suffix->rclass))) { + mdns_dbg("FLUSH - Cache flush bit was set, triggered flush.\n"); + if (pico_mdns_record_tree_del_url_type(url, short_be(suffix->rtype), + &Cache) < 0) { + mdns_dbg("Could not flush records from cache!\n"); + return -1; + } + } + + /* Add copy to cache */ + if (long_be(suffix->rttl) > 0) { + /* If the record is not a Goodbye Record, add it to the cache */ + pico_tree_insert(&Cache, record); + mdns_dbg("RR cached. TICK TACK TICK TACK...\n"); + } else { + mdns_dbg("RR is Goodbye Record.\n"); + } + + return 0; +} + +/* **************************************************************************** + * Add a copy of an mDNS resource record to the cache tree. + * ****************************************************************************/ +static int +pico_mdns_cache_add_record( struct pico_mdns_record *record ) +{ + struct pico_mdns_record *found = NULL; + char *url = NULL; + + /* Check params */ + if (!record) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + + /* See if the record is already contained in the cache */ + found = pico_mdns_record_tree_find_record(record, &Cache); + if (found) { + pico_mdns_cache_update_ttl(found, + long_be(record->record->rsuffix->rttl)); + return 1; + } else { + /* Convert the rname to an URL */ + url = pico_dns_qname_to_url(record->record->rname); + if (!url) { + mdns_dbg("Could not convert rname to url!\n"); + return -1; + } + if (pico_mdns_cache_add(record, url) < 0) { + mdns_dbg("Could not add cache entry!\n"); + return -1; + } + /* Free the url created */ + PICO_FREE(url); + } + + return 0; +} + +/* **************************************************************************** + * Flush all the records in the cache + * ****************************************************************************/ +int pico_mdns_flush_cache(void) +{ + struct pico_mdns_record *record = NULL; + struct pico_tree_node *node = NULL; + + mdns_dbg("FLUSH - Flushing *ALL* cache records...\n"); + + /* Iterate over all the cache-entries and delete them */ + pico_tree_foreach(node, &Cache) { + record = node->keyValue; + if (record) { + node = pico_tree_next(node); + pico_tree_delete(&Cache, record); + if (pico_mdns_record_delete(&record) < 0) { + mdns_dbg("Could not flush record from cache!\n"); + return -1; + } + node = pico_tree_prev(node); + } + } + + return 0; +} + +#if PICO_MDNS_CONTINUOUS_REFRESH == 1 +/* **************************************************************************** + * Determine if the current TTL is at a refresh point + * ****************************************************************************/ +static int +pico_mdns_ttl_at_refresh_time( uint32_t original, + uint32_t current ) +{ + uint32_t rnd = 0; + rnd = pico_rand() % 3; + + if (((original - current == + ((original * (80 + rnd)) / 100)) ? 1 : 0) || + ((original - current == + ((original * (85 + rnd)) / 100)) ? 1 : 0) || + ((original - current == + ((original * (90 + rnd)) / 100)) ? 1 : 0) || + ((original - current == + ((original * (95 + rnd)) / 100)) ? 1 : 0)) + return 1; + else + return 0; +} +#endif + +/* **************************************************************************** + * Utility function to update the TTL of cache entries and check for expired + * ones. + * ****************************************************************************/ +static void +pico_mdns_cache_check_expiries( void ) +{ + struct pico_mdns_record *node_record = NULL; + struct pico_tree_node *node = NULL; +#if PICO_MDNS_CONTINUOUS_REFRESH == 1 + uint32_t current = 0; + uint32_t original = 0; + char *url = NULL; +#endif + + /* Check for expired cache records */ + pico_tree_foreach(node, &Cache) { + node_record = node->keyValue; + if (node_record) { + /* Update current ttl */ + node_record->current_ttl--; + if (node_record->current_ttl < 1) { + /* Move the node to the next for a second */ + node = pico_tree_next(node); + pico_tree_delete(&Cache, node_record); + /* Move the node back to the previous, otherwise a record will + be skipped in the next iteration */ + node = pico_tree_prev(node); + } +#if PICO_MDNS_CONTINUOUS_REFRESH == 1 + /* Determine original and current ttl */ + original = long_be(node_record->record->rsuffix->rttl); + current = node_record->current_ttl; + + /* Cache refresh at 80 or 85/90/95% of TTL + 2% rnd */ + if (pico_mdns_ttl_at_refresh_time(original, current)) { + /* Parse the rname to an url */ + url = pico_dns_qname_to_url(node_record->record->rname); + /* Reconfirm record */ + if (pico_mdns_getrecord_generic(url, + short_be(node_record->record->rsuffix->rtype), + NULL, NULL) < 0) + mdns_dbg("Could not reconfirm record '%s'!\n", url); + PICO_FREE(url); + } +#endif + } + } +} + +/* **************************************************************************** + * Utility function to update the TTL of cookies and check for expired + * ones. + * ****************************************************************************/ +static void +pico_mdns_cookies_check_timeouts( void ) +{ + struct pico_mdns_cookie *node_cookie = NULL; + struct pico_tree_node *node = NULL; + + pico_tree_foreach(node, &Cookies) { + node_cookie = node->keyValue; + + /* Update the timeout counter */ + node_cookie->timeout--; + + if (node_cookie->timeout == 0) { + /* Call callback */ + if (node_cookie->callback) { + node_cookie->callback(NULL, NULL, node_cookie->arg); + } + + /* Move to the next node for a second */ + node = pico_tree_next(node); + + /* Delete cookie */ + if (pico_mdns_cookie_tree_del_cookie(node_cookie) < 0) { + mdns_dbg("Could not delete cookie after timeout!\n"); + return; + } + + /* Move back to the previous node, otherwise a node will be skipped + in the next iteration */ + node = pico_tree_prev(node); + + mdns_dbg("Query cookie timed out, deleted!\n"); + + /* If the request was for a reconfirmation of a record, + flush the corresponding record after the timeout */ + } + } +} + +/* **************************************************************************** + * mDNS module-tick function, central point where all the timing occurs. + * ****************************************************************************/ +static void +pico_mdns_tick( pico_time now, void *_arg ) +{ + IGNORE_PARAMETER(now); + IGNORE_PARAMETER(_arg); + + /* Update the cache */ + pico_mdns_cache_check_expiries(); + + /* Update the cookies */ + pico_mdns_cookies_check_timeouts(); + + /* Schedule new tick */ + pico_timer_add(PICO_MDNS_RR_TTL_TICK, pico_mdns_tick, NULL); +} + +// MARK: ASYNCHRONOUS MDNS RECEPTION + +/* **************************************************************************** + * Utility function to populate an answer vector depending on url, qtype and + * qclass. + * ****************************************************************************/ +static pico_mdns_record_vector +pico_mdns_populate_answer_vector( char *url, uint16_t qtype, uint16_t qclass ) +{ + pico_mdns_record_vector anvector = {0}; + struct pico_mdns_record *record = NULL; + uint16_t i = 0; + + /* Check params */ + if (!url) + return anvector; + + /* Create an answer record vector */ + if (qtype == PICO_DNS_TYPE_ANY) + anvector = pico_mdns_record_tree_find_url(url, &MyRecords); + else + anvector = pico_mdns_record_tree_find_url_type(url, qtype, &MyRecords); + + /* Check if question is a QU-question */ + if (PICO_MDNS_IS_MSB_SET(qclass)) { + mdns_dbg("Question requests for Unicast response...\n"); + + /* Set the SEND_UNICAST flag of all the answer records */ + for (i = 0; i < anvector.count; i++) { + record = pico_mdns_record_vector_get(&anvector, i); + if (!IS_RES_RECORD_FLAG_PROBED_SET(record->flags)) { + pico_mdns_record_vector_delete(&anvector, i); + continue; + } + PICO_MDNS_SET_FLAG(record->flags, PICO_MDNS_RECORD_SEND_UNICAST); + } + } + + return anvector; +} + +/* **************************************************************************** + * Handle a single received question + * ****************************************************************************/ +static pico_mdns_record_vector +pico_mdns_handle_single_question( struct pico_dns_question *question, + pico_dns_packet *packet ) +{ + pico_mdns_record_vector anvector = { 0 }; + struct pico_mdns_cookie *found_cookie = NULL; + char *qname_original = NULL, *url = NULL; + uint16_t qtype = 0, qclass = 0; + + /* Check params */ + if (!question || !packet) { + pico_err = PICO_ERR_EINVAL; + return anvector; + } + + /* Decompress qname and convert to URL */ + qname_original = question->qname; + question->qname = pico_dns_decompress_name(question->qname, packet); + if (!question->qname) { + mdns_dbg("Could not decompress name correctly!\n"); + return anvector; + } + url = pico_dns_qname_to_url(question->qname); + mdns_dbg("Question RCVD for '%s'\n", url); + + /* Find currently active query cookie */ + found_cookie = pico_mdns_cookie_tree_find_query_cookie(question->qname); + if (found_cookie) { + /* Cancel the planned query-cookie */ + mdns_dbg("Query cookie found for question, suppress duplicate.\n"); + found_cookie->status = PICO_MDNS_COOKIE_STATUS_CANCELLED; + } else { + /* Popoluate answer vector depending on url, qtype and qclass */ + qtype = short_be(question->qsuffix->qtype); + qclass = short_be(question->qsuffix->qclass); + anvector = pico_mdns_populate_answer_vector(url, qtype, qclass); + } + + /* Free the qname, with the decompression, memory was allocated */ + PICO_FREE(url); + PICO_FREE(question->qname); + question->qname = qname_original; + return anvector; +} + +/* **************************************************************************** + * Handle a single received answer + * ****************************************************************************/ +static int +pico_mdns_handle_cookie_with_answer( struct pico_mdns_cookie *cookie, + struct pico_mdns_record *answer ) +{ + pico_mdns_record_vector anvector = {0}; + uint8_t type = 0, status = 0; + + /* Check params */ + if (!cookie || !answer) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + type = cookie->type; + status = cookie->status; + + if (PICO_MDNS_COOKIE_TYPE_PROBE == type && + PICO_MDNS_COOKIE_STATUS_ACTIVE == status) { + /* Found cookie is a probe cookie, apply conflict resolution */ + if (pico_mdns_cookie_resolve_conflict(cookie, answer->record->rname) + < 0) + mdns_dbg("Could not resolve conflict correctly!\n"); + } else if (PICO_MDNS_COOKIE_TYPE_QUERY == type && + PICO_MDNS_COOKIE_STATUS_ACTIVE == status) { + /* Call callback if any */ + if (cookie->callback) { + if (pico_mdns_record_vector_add(&anvector, answer) < 0) { + mdns_dbg("Could not create vector to pass to callback!\n"); + return -1; + } + + /* Callback is responsible for aggregating all the records */ + cookie->callback(&anvector, NULL, cookie->arg); + } + } + + return 0; +} + +/* **************************************************************************** + * Handle a single received answer + * ****************************************************************************/ +static int +pico_mdns_handle_single_answer( struct pico_mdns_record *answer ) +{ + struct pico_mdns_record *found_record = NULL; + struct pico_mdns_cookie *found = NULL; + char *url = NULL; + uint16_t type = 0; + + /* Check params */ + if (!answer) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + mdns_dbg("Answer RCVD for '%s'\n", answer->record->rname); + + /* Find currently active query cookie */ + found = pico_mdns_cookie_tree_find_query_cookie(answer->record->rname); + if (found) { + if (pico_mdns_handle_cookie_with_answer(found, answer) < 0) { + mdns_dbg("Could not handle found cookie correctly!\n"); + return -1; + } + } else { + /* Received unsolicited answer, see if */ + mdns_dbg("RCVD an unsolicited record!\n"); + + /* Check for conflicting 'my record' */ + url = pico_dns_qname_to_url(answer->record->rname); + if (!url) return -1; + type = short_be(answer->record->rsuffix->rtype); + found_record = pico_mdns_my_records_find_url_type(url, type); + PICO_FREE(url); + + /* Resolve conflict if found */ + if (found_record) + pico_mdns_record_resolve_conflict(found_record, + answer->record->rname); + } + + return 0; +} + +/* **************************************************************************** + * Handle a single received authority + * ****************************************************************************/ +static int +pico_mdns_handle_single_authority( struct pico_mdns_record *answer ) +{ + struct pico_mdns_cookie *found = NULL; + + /* Check params */ + if (!answer) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + mdns_dbg("Authority RCVD for '%s'\n", answer->record->rname); + + /* Find currently active probe cookie */ + found = pico_mdns_cookie_tree_find_query_cookie(answer->record->rname); + if (found) { + if (found->type == PICO_MDNS_COOKIE_TYPE_PROBE && + found->status == PICO_MDNS_COOKIE_STATUS_ACTIVE) { + mdns_dbg("Simultaneous Probing occured, went tiebreaking...\n"); + if (pico_mdns_cookie_apply_spt(found, answer->record) < 0) { + mdns_dbg("Could not apply S.P.T. to cookie!\n"); + return -1; + } + } + } + + return 0; +} + +/* **************************************************************************** + * Handle a single received additional + * ****************************************************************************/ +static int +pico_mdns_handle_single_additional( struct pico_mdns_record *answer ) +{ + /* Don't need this for now ... */ + IGNORE_PARAMETER(answer); + return 0; +} + +/* **************************************************************************** + * Handles a flat chunk of memory as if it were all questions in it. + * Generates record vector with responses if there are any questions for + * records for which this module has the authority to answer. + * ****************************************************************************/ +static pico_mdns_record_vector +pico_mdns_handle_data_as_questions ( uint8_t **ptr, + uint16_t qdcount, + pico_dns_packet *packet ) +{ + pico_mdns_record_vector anvector = { 0 }; + pico_mdns_record_vector rvector = { 0 }; + struct pico_dns_question question; // Temporary store question + uint16_t i = 0; + + /* Check params */ + if (!ptr) { + pico_err = PICO_ERR_EINVAL; + return anvector; + } + if (!(*ptr) || !packet) { + pico_err = PICO_ERR_EINVAL; + return anvector; + } + + for (i = 0; i < qdcount; i++) { + /* Set qname of the question to the correct location */ + question.qname = (char *)(*ptr); + + /* Set qsuffix of the question to the correct location */ + question.qsuffix = (struct pico_dns_question_suffix *) + (question.qname + pico_dns_namelen_comp(question.qname) + 1); + + /* Handle a single question and append the returend vector */ + rvector = pico_mdns_handle_single_question(&question, packet); + + pico_mdns_record_vector_append(&anvector, &rvector); + + /* Move to next question */ + *ptr = (uint8_t *)question.qsuffix + + sizeof(struct pico_dns_question_suffix); + } + + return anvector; +} + +int +pico_mdns_handle_data_as_answers_generic( uint8_t **ptr, + uint16_t count, + pico_dns_packet *packet, + uint8_t type ) +{ + struct pico_mdns_record *mdns_answer = NULL; + struct pico_dns_record answer, *copy = NULL; + uint16_t i = 0; + + /* Check params */ + if (!ptr) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + if (!(*ptr) || !packet) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + for (i = 0; i < count; i++) { + /* Set rname of the record to the correct location */ + answer.rname = (char *)(*ptr); + + /* Set rsuffix of the record to the correct location */ + answer.rsuffix = (struct pico_dns_record_suffix *) + (answer.rname + pico_dns_namelen_comp(answer.rname) + 1u); + + /* Set rdata of the record to the correct location */ + answer.rdata = (uint8_t *) answer.rsuffix + + sizeof(struct pico_dns_record_suffix); + + answer.rname_length = short_be((uint16_t)(strlen(answer.rname) + 1u)); + + /* Make an mDNS record copy from the answer */ + copy = pico_dns_record_copy(&answer); + if (!copy) + return -1; + PICO_FREE(copy->rname); + copy->rname = pico_dns_decompress_name(answer.rname, packet); + mdns_answer = pico_mdns_record_create_from_dns(copy); + if (!mdns_answer) { + pico_dns_record_delete(©); + return -1; + } + + /* Handle a single aswer */ + switch (type) { + case 1: + pico_mdns_handle_single_authority(mdns_answer); + pico_mdns_record_delete(&mdns_answer); + break; + case 2: + pico_mdns_handle_single_additional(mdns_answer); + pico_mdns_record_delete(&mdns_answer); + break; + default: + pico_mdns_handle_single_answer(mdns_answer); + if (pico_mdns_cache_add_record(mdns_answer)) { + pico_mdns_record_delete(&mdns_answer); + } + break; + } + + /* Move to next record */ + *ptr = (uint8_t *) answer.rdata + short_be(answer.rsuffix->rdlength); + } + + return 0; +} + +int +pico_mdns_handle_data_as_answers( uint8_t **ptr, + uint16_t count, + pico_dns_packet *packet ) +{ + return pico_mdns_handle_data_as_answers_generic(ptr, count, packet, 0); +} + +int +pico_mdns_handle_data_as_authorities( uint8_t **ptr, + uint16_t count, + pico_dns_packet *packet ) +{ + return pico_mdns_handle_data_as_answers_generic(ptr, count, packet, 1); +} + +int +pico_mdns_handle_data_as_additionals( uint8_t **ptr, + uint16_t count, + pico_dns_packet *packet ) +{ + return pico_mdns_handle_data_as_answers_generic(ptr, count, packet, 2); +} + +/* **************************************************************************** + * Splits a mDNS record vector in two DNS record vectors, one for unicast + * responses, one for multicast responses + * ****************************************************************************/ +static int +pico_mdns_sort_unicast_multicast( pico_mdns_record_vector *answers, + pico_dns_record_vector *unicast_vector, + pico_dns_record_vector *multicast_vector ) +{ + struct pico_mdns_record *record = NULL; + uint16_t i = 0; + + /* Check params */ + if (!answers || !unicast_vector || !multicast_vector) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + for (i = 0; i < answers->count; i++) { + record = pico_mdns_record_vector_get(answers, i); + if (IS_RES_RECORD_FLAG_SEND_UNICAST_SET(record->flags)) + pico_dns_record_vector_add(unicast_vector, record->record); + else + pico_dns_record_vector_add(multicast_vector, record->record); + } + + return 0; +} + +/* **************************************************************************** + * Send DNS records as answers to a peer via unicast + * ****************************************************************************/ +static int +pico_mdns_unicast_reply( pico_dns_record_vector *unicast_vector, + struct pico_ip4 peer ) +{ + pico_dns_packet *packet = NULL; + union pico_address *local_addr = NULL; + uint16_t len = 0; + + if (pico_dns_record_vector_count(unicast_vector) > 0) { + /* Create response DNS packet */ + packet = pico_mdns_answer_create(unicast_vector, NULL, NULL, &len); + if (!packet || len == 0) { + pico_err = PICO_ERR_ENOMEM; + return -1; + } + + /* Check if source address is on the local link */ + local_addr = (union pico_address *) pico_ipv4_source_find(&peer); + if (!local_addr) { + mdns_dbg("Peer not on same link!\n"); + /* Forced response via multicast */ + if (pico_mdns_send_packet(packet, len) < 0) { + mdns_dbg("Could not send multicast response!\n"); + return -1; + } + } else { + /* Send the packet via unicast */ + if (pico_mdns_send_packet_unicast(packet, len, peer) < 0) { + mdns_dbg("Could not send unicast response!\n"); + return -1; + } + mdns_dbg("Unicast response sent succesfully!\n"); + } + } + + return 0; +} + +/* **************************************************************************** + * Send DNS records as answers to peers via multicast + * ****************************************************************************/ +static int +pico_mdns_multicast_reply( pico_dns_record_vector *multicast_vector ) +{ + pico_dns_packet *packet = NULL; + uint16_t len = 0; + + /* If there are any unicast records */ + if (pico_dns_record_vector_count(multicast_vector) > 0) { + /* Create response DNS packet */ + packet = pico_mdns_answer_create(multicast_vector, NULL, NULL, &len); + if (!packet || len == 0) { + pico_err = PICO_ERR_ENOMEM; + return -1; + } + + /* Send the packet via multicast */ + if (pico_mdns_send_packet(packet, len) < 0) { + mdns_dbg("Could not send multicast response!\n"); + return -1; + } + mdns_dbg("Multicast response sent succesfully!\n"); + } + + return 0; +} + +/* **************************************************************************** + * Parses DNS records from a plain chunk of data and looks for them in the + * vector. If they're found, they will be removed from the vector. + * ****************************************************************************/ +static int +pico_mdns_apply_known_answer_suppression( pico_mdns_record_vector *vector, + pico_dns_packet *packet, + uint16_t ancount, + uint8_t **data ) +{ + struct pico_dns_record answer = {0}, *copy = NULL; + struct pico_mdns_record *record = NULL; + struct pico_mdns_record ka = {0}; + uint16_t i = 0, j = 0; + + /* Check params */ + if (!data) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + if (!(*data) || !vector || !packet) { + pico_err = PICO_ERR_EINVAL; + return -1; + } + + for (i = 0; i < ancount; i++) { + /* Set rname of the record to the correct location */ + answer.rname = (char *)(*data); + + /* Set rsuffix of the record to the correct location */ + answer.rsuffix = (struct pico_dns_record_suffix *) + (answer.rname + pico_dns_namelen_comp(answer.rname) + 1u); + + /* Set rdata of the record to the correct location */ + answer.rdata = (uint8_t *) answer.rsuffix + + sizeof(struct pico_dns_record_suffix); + + copy = pico_dns_record_copy(&answer); + if (!copy) + return -1; + PICO_FREE(copy->rname); + copy->rname = pico_dns_decompress_name(answer.rname, packet); + ka.record = &answer; + + /* If the answer is in the record vector */ + for (j = 0; j < vector->count; j++) { + record = pico_mdns_record_vector_get(vector, j); + if (pico_mdns_cmp(record, &ka) == 0) { + if (pico_mdns_record_vector_delete(vector, i) < 0) { + mdns_dbg("Could not delete record from vector!\n"); + return -1; + } + } + } + + pico_dns_record_delete(©); + ka.record = NULL; + + /* Move to next record */ + *data = (uint8_t *) answer.rdata + short_be(answer.rsuffix->rdlength); + } + + return 0; +} + +/* **************************************************************************** + * Handle a single incoming query packet without Known Answer Suppression + * ****************************************************************************/ +static int +pico_mdns_handle_query_packet( pico_dns_packet *packet, struct pico_ip4 peer ) +{ + pico_mdns_record_vector anvector = { 0 }; + pico_dns_record_vector anvector_m = { 0 }; + pico_dns_record_vector anvector_u = { 0 }; + uint8_t *data = NULL; + uint16_t qdcount = 0, ancount = 0; + + /* Move to the data section of the packet */ + data = (uint8_t *)packet + sizeof(struct pico_dns_header); + + /* Generate a list of answers */ + qdcount = short_be(packet->qdcount); + anvector = pico_mdns_handle_data_as_questions(&data, qdcount, packet); + if (pico_mdns_record_vector_count(&anvector) == 0) { + mdns_dbg("No records found that correspond with this query!\n"); + return 0; + } + + /* Apply Known Answer Suppression */ + ancount = short_be(packet->ancount); + if (pico_mdns_apply_known_answer_suppression(&anvector, + packet, + ancount, + &data) < 0){ + mdns_dbg("Could not apply known answer suppression!\n"); + return -1; + } + + /* Sort the records in 2 two vectors by unicast or multicast */ + if (pico_mdns_sort_unicast_multicast(&anvector, + &anvector_u, + &anvector_m) < 0) { + mdns_dbg("Could not sort answers into unicast/multicast vector!\n"); + return -1; + } + + if (pico_mdns_unicast_reply(&anvector_u, peer) < 0) + mdns_dbg("Could not sent reply via unicast!\n"); + + if (pico_mdns_multicast_reply(&anvector_m) < 0) + mdns_dbg("Could not sent reply via multicast!\n"); + + return 0; +} + +/* **************************************************************************** + * Handle a probe packet + * ****************************************************************************/ +static int +pico_mdns_handle_probe_packet( pico_dns_packet *packet, struct pico_ip4 peer ) +{ + pico_mdns_record_vector anvector = { 0 }; + pico_dns_record_vector anvector_m = { 0 }; + pico_dns_record_vector anvector_u = { 0 }; + uint8_t *data = NULL; + + /* Move to the data section of the packet */ + data = (uint8_t *)packet + sizeof(struct pico_dns_header); + + /* Generate a list of answers */ + anvector = pico_mdns_handle_data_as_questions(&data, + short_be(packet->qdcount), + packet); + + /* Check if we need to tiebreak simultaneous probing */ + if (pico_mdns_handle_data_as_authorities(&data, short_be(packet->nscount), + packet) < 0) + mdns_dbg("No Simultaneous Probe Tiebreaking needed!\n"); + + if (pico_mdns_record_vector_count(&anvector) == 0) { + mdns_dbg("No records found that correspond with this query!\n"); + return 0; + } + + /* Sort the records in 2 two vectors by unicast or multicast */ + if (pico_mdns_sort_unicast_multicast(&anvector, + &anvector_u, + &anvector_m) < 0) { + mdns_dbg("Could not sort answers into unicast/multicast vector!\n"); + return -1; + } + + + if (pico_mdns_unicast_reply(&anvector_u, peer) < 0) + mdns_dbg("Could not sent reply via unicast!\n"); + + if (pico_mdns_multicast_reply(&anvector_m) < 0) + mdns_dbg("Could not sent reply via multicast!\n"); + + return 0; +} + +/* **************************************************************************** + * Handle a DNS response packet + * ****************************************************************************/ +static int +pico_mdns_handle_response_packet( pico_dns_packet *packet, + struct pico_ip4 peer ) +{ + uint8_t *data = NULL; + + /* We can't do anything with the peer in a response */ + IGNORE_PARAMETER(peer); + + /* Move to the data section of the packet */ + data = (uint8_t *)packet + sizeof(struct pico_dns_header); + + /* Generate a list of answers */ + if (pico_mdns_handle_data_as_answers(&data, short_be(packet->ancount), + packet) < 0) { + mdns_dbg("Could not handle data as answers\n"); + return -1; + } + + return 0; +} + +/* **************************************************************************** + * Parses an incoming packet and handles it according to the type of packet + * ****************************************************************************/ +static int +pico_mdns_recv(void *buf, int buflen, struct pico_ip4 peer) +{ + pico_dns_packet *packet = NULL; // DNS packet received + uint16_t qdcount = 0, ancount = 0, authcount = 0, addcount = 0; + + IGNORE_PARAMETER(buflen); + + /* Parse buf into packet */ + packet = (pico_dns_packet *) buf; + + /* Determine the count of questions and answers */ + qdcount = short_be(packet->qdcount); + ancount = short_be(packet->ancount); + authcount = short_be(packet->nscount); + addcount = short_be(packet->arcount); + mdns_dbg(">>>>>>> QDcount: %u, ANcount: %u, NScount: %u, ARcount: %u\n", + qdcount, ancount, authcount, addcount); + + IGNORE_PARAMETER(addcount); + + /* Determine what kind of DNS packet we have to deal with */ + if ((qdcount > 0)) { + if (authcount > 0) { + mdns_dbg(">>>>>>> RCVD a mDNS probe query:\n"); + /* Packet is probe query */ + if (pico_mdns_handle_probe_packet(packet, peer) < 0) { + mdns_dbg("Could not handle mDNS probe query!\n"); + return -1; + } + } else { + mdns_dbg(">>>>>>> RCVD a plain mDNS query:\n"); + /* Packet is a plain query */ + if (pico_mdns_handle_query_packet(packet, peer) < 0) { + mdns_dbg("Could not handle plain DNS query!\n"); + return -1; + } + } + } else { + if (ancount > 0) { + mdns_dbg(">>>>>>> RCVD a mDNS response:\n"); + /* Packet is a response */ + if (pico_mdns_handle_response_packet(packet, peer) < 0) { + mdns_dbg("Could not handle DNS response!\n"); + return -1; + } + } else { + /* Here went something wrong... */ + mdns_dbg("RCVD Packet contains no questions or answers...\n"); + return -1; + } + } + + return 0; +} + +/* **************************************************************************** + * Callback for UDP IPv4 socket events + * ****************************************************************************/ +static void +pico_mdns_event4( uint16_t ev, struct pico_socket *s ) +{ + char recvbuf[PICO_MDNS_MTU] = { 0 }; + struct pico_ip4 peer = { 0 }; + int pico_read = 0; + uint16_t port = 0; + char host[30]; /* process read event, data available */ if (ev == PICO_SOCK_EV_RD) { - recvbuf = PICO_ZALLOC(PICO_MDNS_MAXBUF); - if (!recvbuf) - return; - mdns_dbg("READ EVENT!\n"); - /* receive while data available in socket buffer */ - while((pico_read = pico_socket_recvfrom(s, recvbuf, PICO_MDNS_MAXBUF, &peer, &port)) > 0) { - /* if pico_socket_setoption is implemented, this check is not needed */ + mdns_dbg("\n>>>>>>> READ EVENT! <<<<<<<\n"); + /* Receive while data is available in socket buffer */ + while((pico_read = pico_socket_recvfrom(s, recvbuf, PICO_MDNS_MTU, + &peer, &port)) > 0) { pico_ipv4_to_string(host, peer.addr); mdns_dbg("Received data from %s:%u\n", host, short_be(port)); + /* Handle the MDNS data received */ pico_mdns_recv(recvbuf, pico_read, peer); } - PICO_FREE(recvbuf); - } - /* socket is closed */ - else if(ev == PICO_SOCK_EV_CLOSE) { + } else if (ev == PICO_SOCK_EV_CLOSE) { mdns_dbg("Socket is closed. Bailing out.\n"); return; - } - /* process error event, socket error occured */ - else if(ev == PICO_SOCK_EV_ERR) { + } else { mdns_dbg("Socket Error received. Bailing out.\n"); return; } } -static void pico_mdns_announce_timer(pico_time now, void *arg) +// MARK: ADDRESS RESOLUTION + +static void +pico_mdns_send_query_packet( pico_time now, void *arg ) { - struct pico_dns_header *header = NULL; - unsigned int len; + struct pico_mdns_cookie *query_cookie = NULL; + pico_dns_packet *packet = NULL; + uint16_t len = 0; + IGNORE_PARAMETER(now); - IGNORE_PARAMETER(arg); - if(!mdns_global_host) + /* Check params */ + if (!arg) { + pico_err = PICO_ERR_EINVAL; return; + } - header = pico_mdns_create_answer(mdns_global_host, &len, PICO_DNS_TYPE_A, &mdns_sock->local_addr); - if(!header) { - mdns_dbg("Could not create answer header!\n"); + /* Parse in the cookie */ + query_cookie = (struct pico_mdns_cookie *)arg; + if (query_cookie->type != PICO_MDNS_COOKIE_TYPE_QUERY) return; + + /* Create an mDNS answer */ + packet = pico_mdns_query_create(&(query_cookie->qvector), NULL, + NULL, NULL, &len); + if (!packet) { + mdns_dbg("Could not create query packet!\n"); } - if(pico_mdns_send(header, len) != (int)len) { - mdns_dbg("send error occured!\n"); - return; + /* Send the mDNS answer unsollicited via multicast */ + if (query_cookie->status != PICO_MDNS_COOKIE_STATUS_CANCELLED) { + query_cookie->status = PICO_MDNS_COOKIE_STATUS_ACTIVE; + if(pico_mdns_send_packet(packet, len) != (int)len) { + mdns_dbg("Send error occured!\n"); + return; + } + mdns_dbg("DONE - Sent query.\n"); + } else { + mdns_dbg("DONE - Duplicate query suppressed.\n"); + if (query_cookie->send_timer) + pico_timer_cancel(query_cookie->send_timer); + pico_mdns_cookie_tree_del_cookie(query_cookie); } } -/* announce the local hostname to the network */ -static int pico_mdns_announce(void) +static int +pico_mdns_getrecord_generic( const char *url, uint16_t type, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg) { - struct pico_dns_header *header = NULL; - unsigned int len; + struct pico_mdns_cookie *query_cookie = NULL; + pico_dns_question_vector qvector = { 0 }; + pico_mdns_record_vector anvector = { 0 }; + struct pico_dns_question *question = NULL; + uint16_t qlen = 0; + + /* Create a single question */ + question = pico_mdns_question_create(url, &qlen, PICO_PROTO_IPV4, type, + PICO_MDNS_QUESTION_FLAG_NO_PROBE, 0); + if (!question) { + mdns_dbg("question_create returned NULL!\n"); + return -1; + } + + /* Add the question to a vector */ + if (pico_dns_question_vector_add(&qvector, question) < 0) { + mdns_dbg("Could not add question to vector!\n"); + return -1; + } - if(!mdns_global_host) + /* Create a mDNS cookie to send */ + query_cookie = pico_mdns_cookie_create(qvector, anvector, 1, + PICO_MDNS_COOKIE_TYPE_QUERY, + callback, arg); + if (!query_cookie) { + mdns_dbg("cookie_create returned NULL!\n"); return -1; + } - header = pico_mdns_create_answer(mdns_global_host, &len, PICO_DNS_TYPE_A, &mdns_sock->local_addr); - if(!header) { - mdns_dbg("Could not create answer header!\n"); + /* Add the query cookie to the end of Cookies + to be able to find it afterwards */ + if (pico_mdns_cookie_tree_add_cookie(query_cookie) < 0) { + mdns_dbg("Could not append cookie to Cookies!\n"); return -1; } - if(pico_mdns_send(header, len) != (int)len) { - mdns_dbg("send error occured!\n"); + pico_timer_add((pico_rand() % 120) + 20, pico_mdns_send_query_packet, + (void *)query_cookie); + + return 0; +} + +int +pico_mdns_getrecord( const char *url, uint16_t type, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ) +{ + pico_mdns_record_vector cache_hits = { 0 }; + + /* Check params */ + if (!url) { + pico_err = PICO_ERR_EINVAL; return -1; } - pico_timer_add(1000, pico_mdns_announce_timer, NULL); + /* First, try to find records in the cache */ + cache_hits = pico_mdns_record_tree_find_url_type(url, type, &Cache); + if (pico_mdns_record_vector_count(&cache_hits) > 0) { + mdns_dbg("CACHE HIT! Passed copies of cache records to callback.\n"); + callback(&cache_hits, NULL, arg); + } else { + mdns_dbg("CACHE MISS! Trying to resolve URL '%s'...\n", url); + return pico_mdns_getrecord_generic(url, type, callback, arg); + } + return 0; } -/* callback function for the probe timer */ -static void pico_mdns_probe_timer(pico_time now, void *arg) +// MARK: PROBING & ANNOUNCING + +/* **************************************************************************** + * Utility function to create an announcement packet from an mDNS packet + * cookie passed in [arg] and send it on the wire. + * ****************************************************************************/ +static void +pico_mdns_send_announcement_packet( pico_time now, void *arg ) { - char *url = (char *)arg; - struct pico_mdns_cookie *ck; - char ok[] = "OK"; + pico_dns_packet *packet = NULL; + struct pico_mdns_cookie *cookie = NULL; + struct pico_mdns_record *record = NULL; + pico_dns_record_vector anvector = { 0 }; + uint16_t i = 0, len = 0; + IGNORE_PARAMETER(now); - if(!arg) + /* Parse argument */ + cookie = (struct pico_mdns_cookie *)arg; + + if (cookie->type != PICO_MDNS_COOKIE_TYPE_ANNOUNCEMENT) return; - ck = pico_mdns_find_cookie(url, PICO_DNS_TYPE_ANY); + if (cookie->count > 0) { + cookie->status = PICO_MDNS_COOKIE_STATUS_ACTIVE; + /* Iterate over records in cookie */ + for (i = 0; i < cookie->rvector.count; i++) { + record = pico_mdns_record_vector_get(&(cookie->rvector), i); + /* Add DNS records to announcement records */ + if (pico_dns_record_vector_add(&anvector, record->record) < 0) { + mdns_dbg("Could not append DNS resource record to list\n"); + } + } - if(!ck) { - mdns_dbg("Corresponding cookie not found!\n"); - PICO_FREE(arg); - return; - } + /* Create an mDNS answer */ + packet = pico_mdns_answer_create(&anvector, NULL, NULL, &len); + if (!packet) { + mdns_dbg("Could not create announcement packet!\n"); + return; + } - if(ck->probe == 0) { - mdns_dbg("Hostname already in use!\n"); - PICO_FREE(arg); - ck->callback(NULL, ck->arg); - return; - } + /* Send the mDNS answer unsollicited via multicast */ + if(pico_mdns_send_packet(packet, len) != (int)len) { + mdns_dbg("Send error occured!\n"); + return; + } - if(ck->count == 0) { - mdns_global_host = url; - mdns_dbg("count is zero! Claimed %s\n", mdns_global_host); - pico_mdns_announce(); - ck->callback(ok, ck->arg); - pico_mdns_del_cookie(url, ck->qtype); - return; - } + /* Decrement the count */ + cookie->count--; + mdns_dbg("DONE - Sent announcement!\n"); + + /* The Multicast DNS responder MUST send at least two unsolicited + * responses, one second apart. */ + if (cookie->count > 0) + cookie->send_timer = pico_timer_add(1000, + pico_mdns_send_announcement_packet, + (void *)cookie); + else + pico_mdns_send_announcement_packet(0, (void *)cookie); + } else { + cookie->status = PICO_MDNS_COOKIE_STATUS_INACTIVE; + pico_mdns_my_records_claimed(cookie->rvector, cookie->callback, + cookie->arg); + /* Try to delete the cookie */ + if (pico_mdns_cookie_tree_del_cookie(cookie) < 0) { + mdns_dbg("Could not delete cookie after initialisation!\n"); + return; + } - if(pico_mdns_send(ck->header, ck->len) != (int)ck->len) { - mdns_dbg("Send error occurred!\n"); - PICO_FREE(arg); - ck->callback(NULL, ck->arg); - return; + mdns_dbg("DONE - Announcing.\n"); } - - ck->count--; - pico_timer_add(250, pico_mdns_probe_timer, url); } -/* checks whether the given name is in use */ -static int pico_mdns_probe(char *hostname, void (*cb_initialised)(char *str, void *arg), void *arg) +/* **************************************************************************** + * Utility function to announce all 'my records' which passed the probed- + * state. When all the records are announced for a particular claim ID, + * the callback passed in this function will be called. + * ****************************************************************************/ +static int +pico_mdns_announce( void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ) { - struct pico_dns_header *header = NULL; - uint16_t len = 0; - char *host; - /* QU question with unicast response bit set */ - header = pico_mdns_create_query(hostname, &len, 0, PICO_MDNS_PROBE, PICO_MDNS_NO_INVERT, cb_initialised, arg); - if(!header || !len) { - mdns_dbg("ERROR: mdns_create_query returned NULL\n"); + struct pico_mdns_cookie *announcement_cookie = NULL; + pico_mdns_record_vector rvector = { 0 }; + pico_dns_question_vector qvector = { 0 }; + + /* Check params */ + if (!callback) { + pico_err = PICO_ERR_EINVAL; return -1; } - host = PICO_ZALLOC(strlen(hostname) + 1); - if(!host) { - pico_err = PICO_ERR_ENOMEM; + IGNORE_PARAMETER(arg); + + /* Find out which resource records can be announced */ + rvector = pico_mdns_my_records_find_probed(); + if (pico_mdns_record_vector_count(&rvector) == 0) + return 0; + + /* Create a mDNS packet cookie */ + announcement_cookie = pico_mdns_cookie_create(qvector, rvector, 2, + PICO_MDNS_COOKIE_TYPE_ANNOUNCEMENT, + callback, arg); + if (!announcement_cookie) { + mdns_dbg("cookie_create returned NULL!\n"); return -1; } - strcpy(host, hostname); - pico_timer_add(pico_rand() % 250, pico_mdns_probe_timer, host); + /* Send a first unsollicited announcement */ + pico_mdns_send_announcement_packet(0, announcement_cookie); + mdns_dbg("DONE - Started announcing.\n"); + return 0; } -/* Opens the socket, probes for the usename and calls back the user when a host name is set up */ -int pico_mdns_init(char *hostname, void (*cb_initialised)(char *str, void *arg), void *arg) +/* **************************************************************************** + * Utility functions to create an probe packet from an mDNS packet + * cookie passed in [arg] and send it on the wire. + * ****************************************************************************/ +static void +pico_mdns_send_probe_packet( pico_time now, void *arg ) { - struct pico_ip_mreq mreq; - uint16_t proto = PICO_PROTO_IPV4, port; - int loop = 0; - int ttl = 255; + pico_dns_packet *packet = NULL; // DNS packet we need to create + struct pico_mdns_cookie *cookie = NULL; // To parse argument in arg + struct pico_mdns_record *record = NULL; + struct pico_mdns_record *found = NULL; + pico_dns_record_vector nsvector = { 0 }; + uint16_t i = 0, len = 0; - if(!hostname) { - mdns_dbg("No hostname given!\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } + IGNORE_PARAMETER(now); - if(!cb_initialised) { - mdns_dbg("No callback function suplied!\n"); + /* Check params */ + if (!arg || !mdns_sock_ipv4) { + mdns_dbg("Socket not initialised, did you call pico_mdns_init()?\n"); pico_err = PICO_ERR_EINVAL; - return -1; + return; } - mdns_sock = pico_socket_open(proto, PICO_PROTO_UDP, &pico_mdns_wakeup); - if(!mdns_sock) { - mdns_dbg("Open returned empty socket\n"); - return -1; - } + /* Parse argument */ + cookie = (struct pico_mdns_cookie *)arg; + cookie->status = PICO_MDNS_COOKIE_STATUS_ACTIVE; + if (cookie->type != PICO_MDNS_COOKIE_TYPE_PROBE) + return; - if(pico_string_to_ipv4(PICO_MDNS_DEST_ADDR4, &mreq.mcast_group_addr.addr) != 0) { - mdns_dbg("String to ipv4 error\n"); - return -1; + if (cookie->count > 0) { + for (i = 0; i < cookie->rvector.count; i++) { + record = pico_mdns_record_vector_get(&(cookie->rvector), i); + /* We don't want the cache flush bit set here */ + PICO_MDNS_CLR_MSB_BE(record->record->rsuffix->rclass); + pico_dns_record_vector_add(&nsvector, record->record); + } + + /* Create an mDNS answer */ + packet = pico_mdns_query_create(&(cookie->qvector), NULL, &nsvector, + NULL, &len); + if (!packet) { + mdns_dbg("Could not create probe packet!\n"); + return; + } + + /* Send the mDNS answer unsollicited via multicast */ + if(pico_mdns_send_packet(packet, len) != (int)len) { + mdns_dbg("Send error occured!\n"); + return; + } + cookie->count--; + mdns_dbg("DONE - Sent probe!\n"); + + /* 250 ms after the first query, the host should send a second; + * then, 250 ms after that, a third. */ + cookie->send_timer = pico_timer_add(250, pico_mdns_send_probe_packet, + (void *)cookie); + } else { + mdns_dbg("DONE - Probing.\n"); + for (i = 0; i < cookie->rvector.count; i++) { + record = pico_mdns_record_vector_get(&(cookie->rvector), i); + /* Set the cache flush bit again */ + PICO_MDNS_SET_MSB_BE(record->record->rsuffix->rclass); + found = pico_mdns_record_tree_find_record(record, &MyRecords); + if (found) /* Set probed flag of corresponding my record */ + PICO_MDNS_SET_FLAG(found->flags, PICO_MDNS_RECORD_PROBED); + } + + /* Delete all the question in the cookie */ + if (pico_dns_question_vector_destroy(&(cookie->qvector)) < 0) { + mdns_dbg("Could not delete all probe questions!\n"); + } + + /* Start announcing the records */ + cookie->count = 2; + cookie->type = PICO_MDNS_COOKIE_TYPE_ANNOUNCEMENT; + pico_mdns_send_announcement_packet(0, (void*) cookie); } - mreq.mcast_link_addr = inaddr_any; + return; +} - if(pico_socket_setoption(mdns_sock, PICO_IP_MULTICAST_LOOP, &loop) < 0) { - mdns_dbg("socket_setoption PICO_IP_MULTICAST_LOOP failed\n"); - return -1; +/* **************************************************************************** + * Utility functions to add a new probe question to the question vector, if a + * name is already in the vector, it will not be appended again. + * ****************************************************************************/ +static int +pico_mdns_add_probe_question( pico_dns_question_vector *vector, + char *name ) +{ + struct pico_dns_question *found = NULL, *new = NULL; + char *url = NULL; + uint16_t qlen = 0; + uint8_t flags = 0; + + /* Try to find an existing question in the vector */ + found = pico_dns_question_vector_find_name(vector, name); + if (!found) { + /* Set the flags */ + if (PICO_MDNS_PROBE_UNICAST) + flags = (PICO_MDNS_QUESTION_FLAG_PROBE | + PICO_MDNS_QUESTION_FLAG_UNICAST_RES); + else + flags = PICO_MDNS_QUESTION_FLAG_PROBE; + + /* Convert name to URL */ + url = pico_dns_qname_to_url(name); + if (!url) + return -1; + + /* Create a new probe question */ + new = pico_mdns_question_create(url, &qlen, PICO_PROTO_IPV4, + PICO_DNS_TYPE_ANY, flags, 0); + + /* Free memory */ + PICO_FREE(url); + url = NULL; + + /* Append probe question to question list */ + if (pico_dns_question_vector_add(vector, new) < 0) { + mdns_dbg("Could not add question to question vector!\n"); + return -1; + } } - if(pico_socket_setoption(mdns_sock, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) { - mdns_dbg("socket_setoption PICO_IP_ADD_MEMBERSHIP failed\n"); + return 0; +} + +/* **************************************************************************** + * Try to find any of my records that need to be probed, and probe them + * ****************************************************************************/ +static int pico_mdns_probe( void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ) +{ + struct pico_mdns_cookie *probe_cookie = NULL; + struct pico_mdns_record *record = NULL; + pico_dns_question_vector qvector = { 0 }; + pico_mdns_record_vector rvector = { 0 }; + uint16_t i = 0; + + /* Check params */ + if (!callback) { + pico_err = PICO_ERR_EINVAL; return -1; } - if(pico_socket_setoption(mdns_sock, PICO_IP_MULTICAST_TTL, &ttl) < 0) { - mdns_dbg("socket_setoption PICO_IP_MULTICAST_TTL failed\n"); - return -1; + /* Find my records that need to pass the probing step first */ + rvector = pico_mdns_my_records_find_to_probe(); + + if (pico_mdns_record_vector_count(&rvector)) { + /* Iterate over the found records */ + for (i = 0; i < pico_mdns_record_vector_count(&rvector); i++) { + record = pico_mdns_record_vector_get(&rvector, i); + /* Find a probe question for the record name */ + + if (pico_mdns_add_probe_question(&qvector, record->record->rname) + < 0) { + mdns_dbg("Could not add probe question to vector!\n"); + return -1; + } + } + + /* Create a mDNS packet to send */ + probe_cookie = pico_mdns_cookie_create(qvector, rvector, 3, + PICO_MDNS_COOKIE_TYPE_PROBE, + callback, arg); + if (!probe_cookie) { + mdns_dbg("Cookie_create returned NULL @ probe()!\n"); + return -1; + } + + if (pico_mdns_cookie_tree_add_cookie(probe_cookie) < 0) { + mdns_dbg("Could not append cookie to Cookies!\n"); + return -1; + } + + /* When the host is ready to send his probe query he SHOULD delay it's + transmission with a randomly chosen time between 0 and 250 ms. */ + probe_cookie->send_timer = pico_timer_add(pico_rand() % 250, + pico_mdns_send_probe_packet, + (void *)probe_cookie); + mdns_dbg("DONE - Started probing.\n"); } - port = short_be(mdns_port); - if (pico_socket_bind(mdns_sock, &inaddr_any, &port) != 0) { - mdns_dbg("Bind error!\n"); + return 0; +} + +// MARK: API functions + +/* **************************************************************************** + * Claim or reclaim all the mDNS records contained in an mDNS record vector + * at once. + * ****************************************************************************/ +static int +pico_mdns_claim_generic( pico_mdns_record_vector vector, + uint8_t reclaim, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ) +{ + /* Check if arguments are passed correctly */ + if (!callback) { + mdns_dbg("NULL pointers passed to 'pico_mdns_claim()'!\n"); + pico_err = PICO_ERR_EINVAL; return -1; } - if(pico_mdns_probe(hostname, cb_initialised, arg) != 0) { - mdns_dbg("Probe error\n"); + /* Check if module is initialised */ + if (!mdns_sock_ipv4) { + mdns_dbg("Socket not initialised, did you call 'pico_mdns_init()'?\n"); + pico_err = PICO_ERR_EINVAL; return -1; } + /* 1.) Appending records to 'my records' */ + vector = pico_mdns_my_records_add(vector, reclaim); + + /* 2a.) Try to probe any records */ + pico_mdns_probe(callback, arg); + + /* 2b.) Try to announce any records */ + pico_mdns_announce(callback, arg); + return 0; } -int pico_mdns_flush_cache(void) +/* **************************************************************************** + * Claim all the mDNS records contained in an mDNS record vector at once. + * ****************************************************************************/ +int +pico_mdns_claim( pico_mdns_record_vector record_vector, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ) { - struct pico_mdns_cache_rr *rr = NULL; - struct pico_tree_node *index = NULL; + return pico_mdns_claim_generic(record_vector, 0, callback, arg); +} - mdns_dbg("Flushing mDNS RR cache\n"); - pico_tree_foreach(index, &CacheTable) { - rr = index->keyValue; - mdns_dbg("Deleting '%s' (%d)\n", rr->url, rr->suf->qtype); - pico_tree_delete(&CacheTable, rr); - pico_timer_cancel(rr->timer); - PICO_FREE(rr->url); - PICO_FREE(rr->suf); - PICO_FREE(rr->rdata); - PICO_FREE(rr); - } - return 0; +/* **************************************************************************** + * Reclaim all the mDNS records contained in an mDNS record vector at once. + * ****************************************************************************/ +static int +pico_mdns_reclaim( pico_mdns_record_vector record_vector, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ) +{ + return pico_mdns_claim_generic(record_vector, 1, callback, arg); } -static int pico_mdns_getaddr_generic(const char *url, void (*callback)(char *ip, void *arg), void *arg, uint16_t proto) +/* **************************************************************************** + * Set the hostname for this machine. Claims it automatically as a unique + * 'A' record for the local address of the bound socket. + * ****************************************************************************/ +int +pico_mdns_set_hostname( const char *url, void *arg ) { - struct pico_dns_header *header = NULL; - uint16_t len = 0; + pico_mdns_record_vector vector = { 0 }; + struct pico_mdns_record *record = NULL; + + /* Check params */ if (!url) { pico_err = PICO_ERR_EINVAL; return -1; } - if(!mdns_sock) { - mdns_dbg("Mdns socket not yet populated. Did you call pico_mdns_init()?\n"); + /* Check if module is initialised */ + if (!mdns_sock_ipv4) { + mdns_dbg("mDNS socket not initialised, did you call 'pico_mdns_init()'?\n"); + pico_err = PICO_ERR_EINVAL; return -1; } - header = pico_mdns_create_query(url, &len, proto, PICO_MDNS_NO_PROBE, PICO_MDNS_NO_INVERT, callback, arg); - if(!header || !len) { - mdns_dbg("ERROR: mdns_create_query returned NULL\n"); + /* Check if hostname is already set */ + if (hostname) + PICO_FREE(hostname); + + hostname = PICO_ZALLOC(strlen(url) + 1); + if (!hostname) { + pico_err = PICO_ERR_ENOMEM; return -1; } + strcpy(hostname, url); - if(pico_mdns_send(header, len) != (int)len) { - mdns_dbg("Send error!\n"); + /* Create an A record for hostname */ + record = pico_mdns_record_create(hostname, + (void*)&(mdns_sock_ipv4->local_addr.ip4.addr), + 4, PICO_DNS_TYPE_A, PICO_MDNS_DEFAULT_TTL, + (PICO_MDNS_RECORD_UNIQUE | + PICO_MDNS_RECORD_HOSTNAME)); + if (!record) { + mdns_dbg("Could not create A record for hostname!\n"); return -1; } - return 0; -} + /* TODO: Create a reverse resolution record */ -static int pico_mdns_getname_generic(const char *ip, void (*callback)(char *url, void *arg), void *arg, uint16_t proto) -{ - struct pico_dns_header *header = NULL; - uint16_t len = 0; - if (!ip) { - pico_err = PICO_ERR_EINVAL; + /* Add the record a vector */ + if (pico_mdns_record_vector_add(&vector, record) < 0) { + mdns_dbg("Could not add hostname record to vector!\n"); + pico_mdns_record_delete(&record); return -1; } - if(!mdns_sock) { - mdns_dbg("Mdns socket not yet populated. Did you call pico_mdns_init()?\n"); + /* Try to claim the record */ + if (pico_mdns_claim(vector, init_callback, arg) < 0) { + mdns_dbg("Could not claim record for hostname %s!\n", url); + pico_mdns_record_vector_destroy(&vector); return -1; } - header = pico_mdns_create_query(ip, &len, proto, PICO_MDNS_NO_PROBE, PICO_MDNS_INVERT, callback, arg); - if(!header || !len) { - mdns_dbg("ERROR: mdns_create_query returned NULL\n"); - return -1; - } + return 0; +} - if(pico_mdns_send(header, len) != (int)len) { - mdns_dbg("Send error!\n"); - return -1; +/* **************************************************************************** + * Returns the hostname for this machine + * ****************************************************************************/ +const char * +pico_mdns_get_hostname( void ) +{ + /* Check if module is initialised */ + if (!mdns_sock_ipv4) { + mdns_dbg("mDNS socket not initialised, did you call 'pico_mdns_init()'?\n"); + pico_err = PICO_ERR_EINVAL; + return NULL; } - return 0; + return (const char *)hostname; } -int pico_mdns_getaddr(const char *url, void (*callback)(char *ip, void *arg), void *arg) +/* **************************************************************************** + * Initialises the global mDNS socket and sets the hostname for this machine. + * Calls cb_initialised when succeeded. + * [flags] is for future use. f.e. Opening a IPv4 multicast socket or an + * IPv6 one or both. + * ****************************************************************************/ +int +pico_mdns_init( const char *_hostname, + struct pico_ipv4_link *link, + uint8_t flags, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ) { - struct pico_mdns_cache_rr *rr = NULL; - char addr[46]; - rr = pico_mdns_cache_find_rr(url, PICO_DNS_TYPE_A); + struct pico_ip_mreq mreq4; + uint16_t proto4 = PICO_PROTO_IPV4; + uint16_t port = 0; + uint16_t loop = 0; // Loopback = 0 + uint16_t ttl = 255; // IP TTL SHOULD = 255 - if(rr && rr->rdata) { - pico_ipv4_to_string(addr, long_from(rr->rdata)); - mdns_dbg("Cache hit! Found A record for '%s' with addr '%s'\n", url, addr); - callback(addr, arg); - return 0; + /* For now */ + IGNORE_PARAMETER(flags); + + /* Initialise port */ + port = short_be(mdns_port); + + /* Check callbcak parameter */ + if(!callback || !_hostname || !link) { + mdns_dbg("No callback function suplied!\n"); + pico_err = PICO_ERR_EINVAL; + return -1; } - else { - mdns_dbg("Cache miss for A record - url '%s'\n", url); - return pico_mdns_getaddr_generic(url, callback, arg, PICO_PROTO_IPV4); + + /* Open global IPv4 mDNS socket */ + mdns_sock_ipv4 = pico_socket_open(proto4, + PICO_PROTO_UDP, + &pico_mdns_event4); + if(!mdns_sock_ipv4) { + mdns_dbg("Open returned empty IPv4 socket\n"); + return -1; } -} -int pico_mdns_getname(const char *ip, void (*callback)(char *url, void *arg), void *arg) -{ - return pico_mdns_getname_generic(ip, callback, arg, PICO_PROTO_IPV4); -} + /* Convert the mDNS IPv4 destination address to struct */ + if(pico_string_to_ipv4(PICO_MDNS_DEST_ADDR4, + &mreq4.mcast_group_addr.addr) != 0) { + mdns_dbg("String to IPv4 error\n"); + return -1; + } -#ifdef PICO_SUPPORT_IPV6 -int pico_mdns_getaddr6(const char *url, void (*callback)(char *ip, void *arg), void *arg) -{ - struct pico_mdns_cache_rr *rr = NULL; - char addr[46]; - rr = pico_mdns_cache_find_rr(url, PICO_DNS_TYPE_AAAA); + /* Receive data on any network interface */ + mreq4.mcast_link_addr = inaddr_any; - if(rr && rr->rdata) { - pico_ipv6_to_string(addr, (uint8_t *)rr->rdata); - mdns_dbg("Cache hit! Found AAAA record for '%s' with addr '%s'\n", url, addr); - callback(addr, arg); - return 0; + /* Don't want the multicast data to be looped back to the host */ + if(pico_socket_setoption(mdns_sock_ipv4, + PICO_IP_MULTICAST_LOOP, + &loop) < 0) { + mdns_dbg("socket_setoption PICO_IP_MULTICAST_LOOP failed\n"); + return -1; } - else { - mdns_dbg("Cache miss for AAAA record - url '%s'\n", url); - return pico_mdns_getaddr_generic(url, callback, arg, PICO_PROTO_IPV6); + + /* Tell the stack we're interested in this particular multicast group */ + if(pico_socket_setoption(mdns_sock_ipv4, + PICO_IP_ADD_MEMBERSHIP, + &mreq4) < 0) { + mdns_dbg("socket_setoption PICO_IP_ADD_MEMBERSHIP failed\n"); + return -1; } -} -int pico_mdns_getname6(const char *ip, void (*callback)(char *url, void *arg), void *arg) -{ - return pico_mdns_getname_generic(ip, callback, arg, PICO_PROTO_IPV6); + /* RFC: + * All multicast responses (including answers sent via unicast) SHOULD + * be send with IP TTL set to 255 for backward-compatibility reasons + */ + if(pico_socket_setoption(mdns_sock_ipv4, + PICO_IP_MULTICAST_TTL, + &ttl) < 0) { + mdns_dbg("socket_setoption PICO_IP_MULTICAST_TTL failed\n"); + return -1; + } + + /* Bind to mDNS port */ + if (pico_socket_bind(mdns_sock_ipv4, &(link->address), &port) != 0) { + mdns_dbg("Bind error!\n"); + return -1; + } + + /* Set the global init callback variable */ + init_callback = callback; + + /* Set the hostname for this machine */ + if (pico_mdns_set_hostname(_hostname, arg) < 0) { + mdns_dbg("Setting hostname returned error\n"); + return -1; + } + + pico_timer_add(PICO_MDNS_RR_TTL_TICK, pico_mdns_tick, NULL); + + return 0; } -#endif -#endif /* PICO_SUPPORT_MDNS */ +#endif /* PICO_SUPPORT_MDNS */ \ No newline at end of file diff --git a/modules/pico_mdns.h b/modules/pico_mdns.h index 4bb70cf97..525c3a8c8 100644 --- a/modules/pico_mdns.h +++ b/modules/pico_mdns.h @@ -1,23 +1,140 @@ -/********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. - See LICENSE and COPYING for usage. - . - Author: Toon Stegen - *********************************************************************/ +/* **************************************************************************** + * PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved. + * See LICENSE and COPYING for usage. + * . + * Author: Toon Stegen, Jelle De Vleeschouwer + * ****************************************************************************/ #ifndef INCLUDE_PICO_MDNS #define INCLUDE_PICO_MDNS +#include "pico_dns_common.h" +#include "pico_ipv4.h" + +/* ********************************* CONFIG ***********************************/ +#define PICO_MDNS_PROBE_UNICAST 0 /* Probe queries as QU-questions */ +#define PICO_MDNS_DEFAULT_TTL 60 /* Default TTL of mDNS records */ +#define PICO_MDNS_CONTINUOUS_REFRESH 0 /* Continuously update cache */ +/* ****************************************************************************/ + #define PICO_MDNS_DEST_ADDR4 "224.0.0.251" -int pico_mdns_init(char *hostname, void (*cb_initialised)(char *str, void *arg), void *arg); -int pico_mdns_getaddr(const char *url, void (*callback)(char *ip, void *arg), void *arg); -int pico_mdns_getname(const char *ip, void (*callback)(char *url, void *arg), void *arg); -int pico_mdns_flush_cache(void); +#define PICO_MDNS_RECORD_UNIQUE 0x00u +#define PICO_MDNS_RECORD_SHARED 0x01u + +/* MDNS resource record */ +struct pico_mdns_record +{ + struct pico_dns_record *record; // DNS Resource Record + uint32_t current_ttl; // Current TTL + uint8_t flags; // Resource Record flags + uint8_t claim_id; // Claim ID number +}; + +/* MDNS resource record vector */ +typedef struct +{ + struct pico_mdns_record **records; + uint16_t count; +} pico_mdns_record_vector; + +/* **************************************************************************** + * Creates a new mDNS resource record. The address of a mDNS res record-struct + * needs to be given in record_out to return the created record in. If passed + * in record is an element of a list, the record will be appended to the end + * of the list. So you will have to iterate until the end of the list to + * access the newly created record. + * ****************************************************************************/ +struct pico_mdns_record * +pico_mdns_record_create( const char *url, + void *_rdata, + uint16_t datalen, + uint16_t rtype, + uint32_t rttl, + uint8_t flags ); + +/* **************************************************************************** + * Deletes a mDNS resource record. + * ****************************************************************************/ +int +pico_mdns_record_delete( struct pico_mdns_record **record ); + +/* **************************************************************************** + * Initialise an mDNS record vector + * ****************************************************************************/ +int +pico_mdns_record_vector_init( pico_mdns_record_vector *vector ); + +/* **************************************************************************** + * Returns the amount of records contained in an mDNS record vector + * ****************************************************************************/ +uint16_t +pico_mdns_record_vector_count( pico_mdns_record_vector *vector ); + +/* **************************************************************************** + * Adds an mDNS record to an mDNS record vector + * ****************************************************************************/ +int +pico_mdns_record_vector_add( pico_mdns_record_vector *vector, + struct pico_mdns_record *record ); + +/* **************************************************************************** + * Gets an mDNS record from an mDNS record vector at a certain index + * ****************************************************************************/ +struct pico_mdns_record * +pico_mdns_record_vector_get( pico_mdns_record_vector *vector, + uint16_t index ); + +/* **************************************************************************** + * Deletes every mDNS record from an mDNS record vector + * ****************************************************************************/ +int +pico_mdns_record_vector_destroy( pico_mdns_record_vector *vector ); + +/* **************************************************************************** + * API functions + * ****************************************************************************/ +int +pico_mdns_getrecord( const char *url, uint16_t type, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ); + +/* **************************************************************************** + * Claim all the mDNS records contained in an mDNS record vector at once. + * ****************************************************************************/ +int +pico_mdns_claim( pico_mdns_record_vector record_vector, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ); + +/* **************************************************************************** + * Set the hostname for this machine. Claims it automatically as a unique + * A record for the local address of the bound socket. + * ****************************************************************************/ +int +pico_mdns_set_hostname( const char *url, void *arg ); + +/* **************************************************************************** + * Returns the hostname for this machine + * ****************************************************************************/ +const char * +pico_mdns_get_hostname( void ); -#ifdef PICO_SUPPORT_IPV6 -#define PICO_MDNS_DEST_ADDR6 "FF02::FB" -int pico_mdns_getaddr6(const char *url, void (*callback)(char *ip, void *arg), void *arg); -int pico_mdns_getname6(const char *ip, void (*callback)(char *url, void *arg), void *arg); -#endif +/* **************************************************************************** + * Initialises the global mDNS socket. Calls cb_initialised when succeeded. + * [flags] is for future use. f.e. Opening a IPv4 multicast socket or an + * IPv6 one or both. + * ****************************************************************************/ +int +pico_mdns_init( const char *_hostname, + struct pico_ipv4_link *link, + uint8_t flags, + void (*callback)(pico_mdns_record_vector *, + char *, + void *), + void *arg ); -#endif /* _INCLUDE_PICO_MDNS */ +#endif /* _INCLUDE_PICO_MDNS */ \ No newline at end of file diff --git a/modules/pico_mm.c b/modules/pico_mm.c index 357f8ac53..93d5cc8a6 100644 --- a/modules/pico_mm.c +++ b/modules/pico_mm.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Gustav Janssens, Jonas Van Nieuwenberg, Sam Van Den Berge diff --git a/modules/pico_mm.h b/modules/pico_mm.h index 29366d0a7..a341d32b5 100644 --- a/modules/pico_mm.h +++ b/modules/pico_mm.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Gustav Janssens, Jonas Van Nieuwenberg, Sam Van Den Berge diff --git a/modules/pico_nat.c b/modules/pico_nat.c index 19f85e067..a4ee112a1 100644 --- a/modules/pico_nat.c +++ b/modules/pico_nat.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . diff --git a/modules/pico_nat.h b/modules/pico_nat.h index 523750161..f201ae4bd 100644 --- a/modules/pico_nat.h +++ b/modules/pico_nat.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -29,23 +29,18 @@ int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr); #define pico_ipv4_nat_print_table() do {} while(0) static inline int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr) { - (void)f; - (void)link_addr; pico_err = PICO_ERR_EPROTONOSUPPORT; return -1; } static inline int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr) { - (void)f; - (void)link_addr; pico_err = PICO_ERR_EPROTONOSUPPORT; return -1; } static inline int pico_ipv4_nat_enable(struct pico_ipv4_link *link) { - (void)link; pico_err = PICO_ERR_EPROTONOSUPPORT; return -1; } @@ -58,29 +53,18 @@ static inline int pico_ipv4_nat_disable(void) static inline int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr) { - (void)link_addr; pico_err = PICO_ERR_EPROTONOSUPPORT; return -1; } static inline int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto) { - (void)nat_port; - (void)src_addr; - (void)src_port; - (void)proto; pico_err = PICO_ERR_EPROTONOSUPPORT; return -1; } static inline int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag) { - (void)nat_addr; - (void)nat_port; - (void)src_addr; - (void)src_port; - (void)proto; - (void)flag; pico_err = PICO_ERR_EPROTONOSUPPORT; return -1; } diff --git a/modules/pico_olsr.c b/modules/pico_olsr.c index 0edc186d6..dc1bd6ece 100644 --- a/modules/pico_olsr.c +++ b/modules/pico_olsr.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Daniele Lacamera @@ -15,7 +15,6 @@ #ifdef PICO_SUPPORT_OLSR #define DGRAM_MAX_SIZE (100 - 28) #define MAX_OLSR_MEM (4 * DGRAM_MAX_SIZE) -#define olsr_dbg(...) do {} while(0) int OOM(void); @@ -141,7 +140,7 @@ static struct olsr_route_entry *get_next_hop(struct olsr_route_entry *dst) { struct olsr_route_entry *hop = dst; while(hop) { - /* olsr_dbg("Finding next hop to %08x m=%d\n", hop->destination.addr, hop->metric); */ + /* dbg("Finding next hop to %08x m=%d\n", hop->destination.addr, hop->metric); */ if(hop->metric <= 1) return hop; @@ -166,7 +165,7 @@ static inline void olsr_route_add(struct olsr_route_entry *el) el->next = el->gateway->children; el->gateway->children = el; el->link_type = OLSRLINK_MPR; - olsr_dbg("[OLSR] ----------Adding route to %08x via %08x metric %d\n", el->destination.addr, nexthop->destination.addr, el->metric); + dbg("[OLSR] ----------Adding route to %08x via %08x metric %d\n", el->destination.addr, nexthop->destination.addr, el->metric); pico_ipv4_route_add(el->destination, HOST_NETMASK, nexthop->destination, (int) el->metric, NULL); } else if (el->iface) { /* neighbor */ @@ -182,7 +181,7 @@ static inline void olsr_route_add(struct olsr_route_entry *el) ei->children = el; } - olsr_dbg("[OLSR] ----------Adding neighbor %08x iface %s\n", el->destination.addr, el->iface->name); + dbg("[OLSR] ----------Adding neighbor %08x iface %s\n", el->destination.addr, el->iface->name); pico_ipv4_route_add(el->destination, HOST_NETMASK, no_gw, 1, pico_ipv4_link_by_dev(el->iface)); } @@ -191,7 +190,7 @@ static inline void olsr_route_add(struct olsr_route_entry *el) static inline void olsr_route_del(struct olsr_route_entry *r) { struct olsr_route_entry *cur, *prev = NULL, *lst; - /* olsr_dbg("[OLSR] DELETING route..................\n"); */ + /* dbg("[OLSR] DELETING route..................\n"); */ my_ansn++; if (r->gateway) { lst = r->gateway->children; @@ -207,7 +206,7 @@ static inline void olsr_route_del(struct olsr_route_entry *r) /* found */ if (r->gateway) { pico_ipv4_route_del(r->destination, HOST_NETMASK, r->metric); - olsr_dbg("[OLSR] Deleting route to %08x \n", r->destination.addr); + dbg("[OLSR] Deleting route to %08x \n", r->destination.addr); if (!prev) r->gateway->children = r->next; else @@ -254,7 +253,7 @@ static struct olsr_route_entry *get_route_by_address(struct olsr_route_entry *ls uint8_t seconds2olsr(uint32_t seconds) { uint16_t a, b; - /* olsr_dbg("seconds=%u\n", (uint16_t)seconds); */ + /* dbg("seconds=%u\n", (uint16_t)seconds); */ if (seconds > 32767) seconds = 32767; @@ -266,16 +265,16 @@ uint8_t seconds2olsr(uint32_t seconds) break; } } - /* olsr_dbg("b=%u", b); */ + /* dbg("b=%u", b); */ /* compute the expression 16*(T/(C*(2^b))-1), which may not be a integer, and round it up. This results in the value for 'a' */ /* a = (T / ( C * (1u << b) ) ) - 1u; */ { uint16_t den = ((uint16_t)(1u << b) >> 4u); - /* olsr_dbg(" den=%u ", den); */ + /* dbg(" den=%u ", den); */ if (den == 0) { - /* olsr_dbg("div by 0!\n"); */ + /* dbg("div by 0!\n"); */ den = 1u; } @@ -283,7 +282,7 @@ uint8_t seconds2olsr(uint32_t seconds) } /* a = a & 0x0Fu; */ - /* olsr_dbg(" a=%u\n", a); */ + /* dbg(" a=%u\n", a); */ /* if 'a' is equal to 16: increment 'b' by one, and set 'a' to 0 */ if (16u == a) { @@ -298,16 +297,16 @@ uint32_t olsr2seconds(uint8_t olsr) { uint8_t a, b; uint16_t seconds; - /* olsr_dbg("olsr format: %u -- ", olsr); */ + /* dbg("olsr format: %u -- ", olsr); */ a = (olsr >> 4) & 0xFu; b = olsr & 0x0f; - /* olsr_dbg("o2s: a=%u, b=%u\n", a,b); */ + /* dbg("o2s: a=%u, b=%u\n", a,b); */ if (b < 4) seconds = (uint16_t)(((1u << b) + (uint16_t)(((uint16_t)(a << b) >> 4u) & 0xFu)) >> OLSR_C_SHIFT); else seconds = (uint16_t)(((1u << b) + (uint16_t)(((uint16_t)(a << (b - 4))) & 0xFu)) >> OLSR_C_SHIFT); - /* olsr_dbg("o2s: seconds: %u\n", seconds); */ + /* dbg("o2s: seconds: %u\n", seconds); */ return seconds; } @@ -364,7 +363,7 @@ void olsr_process_out(pico_time now, void *arg) ohdr->seq = short_be((uint16_t)(odev->pkt_counter)++); bcast.addr = (addr->netmask.addr & addr->address.addr) | (~addr->netmask.addr); if ( 0 > pico_socket_sendto(udpsock, p->buf, p->len, &bcast, OLSR_PORT)) { - olsr_dbg("olsr send\n"); + dbg("olsr send\n"); } } else { while(pdev) { @@ -375,7 +374,7 @@ void olsr_process_out(pico_time now, void *arg) bcast.addr = (addr->netmask.addr & addr->address.addr) | (~addr->netmask.addr); if ( 0 > pico_socket_sendto(udpsock, p->buf, p->len, &bcast, OLSR_PORT)) { - olsr_dbg("olsr send\n"); + dbg("olsr send\n"); } pdev = pdev->next; @@ -391,7 +390,7 @@ void olsr_process_out(pico_time now, void *arg) static void olsr_scheduled_output(uint32_t when, void *buffer, uint16_t size, struct pico_device *pdev) { struct olsr_fwd_pkt *p; - /* olsr_dbg("Scheduling olsr packet, type:%s, size: %x\n", when == OLSR_HELLO_INTERVAL?"HELLO":"TC", size); */ + /* dbg("Scheduling olsr packet, type:%s, size: %x\n", when == OLSR_HELLO_INTERVAL?"HELLO":"TC", size); */ if ((buffer_mem_used + DGRAM_MAX_SIZE) > MAX_OLSR_MEM) { PICO_FREE(buffer); return; @@ -438,7 +437,7 @@ static void refresh_routes(void) } else if (lnk) { struct olsr_route_entry *e = PICO_ZALLOC(sizeof (struct olsr_route_entry)); if (!e) { - olsr_dbg("olsr: adding local route entry\n"); + dbg("olsr: adding local route entry\n"); OOM(); return; } @@ -658,7 +657,7 @@ static void olsr_compose_hello_dgram(struct pico_device *pdev, struct pico_ipv4_ if (DGRAM_MAX_SIZE > size) { r = olsr_build_hello_neighbors(dgram + size, DGRAM_MAX_SIZE - size, &last_neighbor); if (r == 0) { - /* olsr_dbg("Building hello message\n"); */ + /* dbg("Building hello message\n"); */ PICO_FREE(dgram); return; } @@ -704,7 +703,7 @@ void recv_mid(uint8_t *buffer, uint32_t len, struct olsr_route_entry *origin) if (!e) { e = PICO_ZALLOC(sizeof(struct olsr_route_entry)); if (!e) { - olsr_dbg("olsr allocating route\n"); + dbg("olsr allocating route\n"); OOM(); return; } @@ -758,7 +757,7 @@ void recv_hello(uint8_t *buffer, uint32_t len, struct olsr_route_entry *origin, if (!e) { e = PICO_ZALLOC(sizeof(struct olsr_route_entry)); if (!e) { - olsr_dbg("olsr allocating route\n"); + dbg("olsr allocating route\n"); OOM(); return; } @@ -813,7 +812,7 @@ uint32_t reconsider_topology(uint8_t *buf, uint32_t size, struct olsr_route_entr e->advertised_tc = PICO_ZALLOC(size); if (!e->advertised_tc) { OOM(); - olsr_dbg("Allocating forward packet\n"); + dbg("Allocating forward packet\n"); return 0; } @@ -849,7 +848,7 @@ uint32_t reconsider_topology(uint8_t *buf, uint32_t size, struct olsr_route_entr olsr_route_add(rt); } } - /* olsr_dbg("Routes changed...\n"); */ + /* dbg("Routes changed...\n"); */ } return retval; @@ -890,7 +889,7 @@ static void olsr_recv(uint8_t *buffer, uint32_t len) origin = get_route_by_address(Local_interfaces, msg->orig.addr); if(pico_ipv4_link_find(&msg->orig) != NULL) { - /* olsr_dbg("rebound\n"); */ + /* dbg("rebound\n"); */ parsed += short_be(msg->size); continue; } @@ -948,7 +947,7 @@ static void olsr_recv(uint8_t *buffer, uint32_t len) msg->ttl = 0; } else { recv_mid(buffer + parsed + sizeof(struct olsrmsg), (uint32_t)(short_be(msg->size) - (sizeof(struct olsrmsg))), origin); - /* olsr_dbg("MID forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */ + /* dbg("MID forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */ origin->seq = short_be(msg->seq); } @@ -959,7 +958,7 @@ static void olsr_recv(uint8_t *buffer, uint32_t len) if ((origin->seq != 0) && (!fresher(short_be(msg->seq), origin->seq))) { msg->ttl = 0; } else { - /* olsr_dbg("TC forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */ + /* dbg("TC forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */ origin->seq = short_be(msg->seq); } } @@ -1056,7 +1055,7 @@ void pico_olsr_init(void) 0 }; uint16_t port = OLSR_PORT; - olsr_dbg("OLSR initialized.\n"); + dbg("OLSR initialized.\n"); if (!udpsock) { udpsock = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &wakeup); if (udpsock) @@ -1097,7 +1096,7 @@ int pico_olsr_add(struct pico_device *dev) return -1; } - /* olsr_dbg("OLSR: Adding device %s\n", dev->name); */ + /* dbg("OLSR: Adding device %s\n", dev->name); */ od = PICO_ZALLOC(sizeof(struct olsr_dev_entry)); if (!od) { pico_err = PICO_ERR_ENOMEM; @@ -1114,11 +1113,11 @@ int pico_olsr_add(struct pico_device *dev) lnk = pico_ipv4_link_by_dev_next(dev, lnk); if (lnk) { struct olsr_route_entry *e = PICO_ZALLOC(sizeof(struct olsr_route_entry)); - /* olsr_dbg("OLSR: Found IP address %08x\n", long_be(lnk->address.addr)); */ + /* dbg("OLSR: Found IP address %08x\n", long_be(lnk->address.addr)); */ pico_ipv4_to_string(ipaddr, (lnk->address.addr)); - /* olsr_dbg("OLSR: Found IP address %s\n", ipaddr); */ + /* dbg("OLSR: Found IP address %s\n", ipaddr); */ if (!e) { - olsr_dbg("olsr allocating route\n"); + dbg("olsr allocating route\n"); pico_err = PICO_ERR_ENOMEM; return -1; } diff --git a/modules/pico_olsr.h b/modules/pico_olsr.h index 11c3bf0ca..baef60d1d 100644 --- a/modules/pico_olsr.h +++ b/modules/pico_olsr.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Daniele Lacamera diff --git a/modules/pico_posix.c b/modules/pico_posix.c index 4820b12e0..606ec32ca 100644 --- a/modules/pico_posix.c +++ b/modules/pico_posix.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Andrei Carp, Maarten Vandersteegen diff --git a/modules/pico_slaacv4.c b/modules/pico_slaacv4.c index 5c5af9537..2b1e68506 100644 --- a/modules/pico_slaacv4.c +++ b/modules/pico_slaacv4.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Bogdan Lupu diff --git a/modules/pico_slaacv4.h b/modules/pico_slaacv4.h index d90ef65b2..18104483a 100644 --- a/modules/pico_slaacv4.h +++ b/modules/pico_slaacv4.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Authors: Bogdan Lupu diff --git a/modules/pico_sntp_client.h b/modules/pico_sntp_client.h index 79b02b8c1..cd4dcb74d 100644 --- a/modules/pico_sntp_client.h +++ b/modules/pico_sntp_client.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Author: Toon Stegen diff --git a/modules/pico_socket_tcp.c b/modules/pico_socket_tcp.c index 2d8c5fcbd..e623b0478 100644 --- a/modules/pico_socket_tcp.c +++ b/modules/pico_socket_tcp.c @@ -85,7 +85,7 @@ void pico_socket_tcp_cleanup(struct pico_socket *sock) { #ifdef PICO_SUPPORT_TCP /* for tcp sockets go further and clean the sockets inside queue */ - if(is_sock_tcp(sock)) + if(sock->proto == &pico_proto_tcp) pico_tcp_cleanup_queues(sock); #endif @@ -239,8 +239,6 @@ int pico_socket_tcp_read(struct pico_socket *s, void *buf, uint32_t len) void transport_flags_update(struct pico_frame *f, struct pico_socket *s) { #ifdef PICO_SUPPORT_TCP - if(is_sock_tcp(s)) - pico_tcp_flags_update(f, s); - + pico_tcp_flags_update(f, s); #endif } diff --git a/modules/pico_socket_udp.h b/modules/pico_socket_udp.h index 6b3a4c9a3..fd7783a92 100644 --- a/modules/pico_socket_udp.h +++ b/modules/pico_socket_udp.h @@ -8,7 +8,7 @@ int pico_socket_udp_deliver(struct pico_sockport *sp, struct pico_frame *f); #ifdef PICO_SUPPORT_UDP int pico_setsockopt_udp(struct pico_socket *s, int option, void *value); int pico_getsockopt_udp(struct pico_socket *s, int option, void *value); -# define pico_socket_udp_recv(s, buf, len, addr, port) pico_udp_recv(s, buf, len, addr, port, NULL) +# define pico_socket_udp_recv(s, buf, len, addr, port) pico_udp_recv(s, buf, len, addr, port) #else # define pico_socket_udp_recv(...) (0) # define pico_getsockopt_udp(...) (-1) diff --git a/modules/pico_strings.c b/modules/pico_strings.c index 974126fa5..5fc18a837 100644 --- a/modules/pico_strings.c +++ b/modules/pico_strings.c @@ -11,14 +11,14 @@ #include #include "pico_strings.h" -char *get_string_terminator_position(char *const block, size_t len) +char *get_string_terminator_position(char * const block, size_t len) { size_t length = pico_strnlen(block, len); - return (len != length) ? (block + length) : 0; + return (len != length)? (block + length): 0; } -int pico_strncasecmp(const char *const str1, const char *const str2, size_t n) +int pico_strncasecmp(const char * const str1, const char * const str2, size_t n) { int ch1; int ch2; @@ -29,13 +29,12 @@ int pico_strncasecmp(const char *const str1, const char *const str2, size_t n) ch2 = toupper(*(str2 + i)); if (ch1 < ch2) return -1; - if (ch1 > ch2) return 1; - if ((!ch1) && (!ch2)) return 0; } + return 1; } @@ -73,6 +72,7 @@ static inline int revert_and_shift(char *buf, int len, int pos) len -= pos; for (i = 0; i < len; ++i) buf[i] = buf[i + pos]; + return len; } @@ -92,7 +92,6 @@ int num2string(int32_t num, char *buf, int len) do { if (!pos) return -3; - res = ldiv(res.quot, 10); buf[--pos] = (char)((res.rem + '0') & 0xFF); } while (res.quot); diff --git a/modules/pico_strings.h b/modules/pico_strings.h index 9a6209db5..23d113e37 100644 --- a/modules/pico_strings.h +++ b/modules/pico_strings.h @@ -12,8 +12,8 @@ #include #include -char *get_string_terminator_position(char *const block, size_t len); -int pico_strncasecmp(const char *const str1, const char *const str2, size_t n); +char *get_string_terminator_position(char * const block, size_t len); +int pico_strncasecmp(const char * const str1, const char * const str2, size_t n); size_t pico_strnlen(const char *str, size_t n); int num2string(int32_t num, char *buf, int len); diff --git a/modules/pico_tcp.c b/modules/pico_tcp.c index 83aef2b27..6af530255 100644 --- a/modules/pico_tcp.c +++ b/modules/pico_tcp.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -66,6 +66,30 @@ static void *Mutex = NULL; #endif +static /* inline*/ int32_t seq_compare(uint32_t a, uint32_t b) +{ + uint32_t thresh = ((uint32_t)(-1)) >> 1; + + if (a > b) /* return positive number, if not wrapped */ + { + if ((a - b) > thresh) /* b wrapped */ + return -(int32_t)(b - a); /* b = very small, a = very big */ + else + return (int32_t)(a - b); /* a = biggest, b = a bit smaller */ + + } + + if (a < b) /* return negative number, if not wrapped */ + { + if ((b - a) > thresh) /* a wrapped */ + return (int32_t)(a - b); /* a = very small, b = very big */ + else + return -(int32_t)(b - a); /* b = biggest, a = a bit smaller */ + + } + + return 0; +} /* Input segment, used to keep only needed data, not the full frame */ struct tcp_input_segment @@ -80,7 +104,7 @@ struct tcp_input_segment static int input_segment_compare(void *ka, void *kb) { struct tcp_input_segment *a = ka, *b = kb; - return pico_seq_compare(a->seq, b->seq); + return seq_compare(a->seq, b->seq); } static struct tcp_input_segment *segment_from_frame(struct pico_frame *f) @@ -105,7 +129,7 @@ static struct tcp_input_segment *segment_from_frame(struct pico_frame *f) static int segment_compare(void *ka, void *kb) { struct pico_frame *a = ka, *b = kb; - return pico_seq_compare(SEQN(a), SEQN(b)); + return seq_compare(SEQN(a), SEQN(b)); } struct pico_tcp_queue @@ -338,9 +362,9 @@ static int release_until(struct pico_tcp_queue *q, uint32_t seq) void *cur = head; if (IS_INPUT_QUEUE(q)) - seq_result = pico_seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq); + seq_result = seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq); else - seq_result = pico_seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq); + seq_result = seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq); if (seq_result <= 0) { @@ -369,9 +393,9 @@ static int release_all_until(struct pico_tcp_queue *q, uint32_t seq, pico_time * f = idx->keyValue; if (IS_INPUT_QUEUE(q)) - seq_result = pico_seq_compare(((struct tcp_input_segment *)f)->seq + ((struct tcp_input_segment *)f)->payload_len, seq); + seq_result = seq_compare(((struct tcp_input_segment *)f)->seq + ((struct tcp_input_segment *)f)->payload_len, seq); else - seq_result = pico_seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq); + seq_result = seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq); if (seq_result <= 0) { tcp_dbg("Releasing %p\n", f); @@ -493,7 +517,7 @@ static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f } if (f->payload_len > 0) { - if (pico_seq_compare(SEQN(f) + f->payload_len, t->snd_nxt) > 0) { + if (seq_compare(SEQN(f) + f->payload_len, t->snd_nxt) > 0) { t->snd_nxt = SEQN(f) + f->payload_len; tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt); } @@ -713,12 +737,12 @@ uint16_t pico_tcp_overhead(struct pico_socket *s) static inline int tcp_sack_marker(struct pico_frame *f, uint32_t start, uint32_t end, uint16_t *count) { int cmp; - cmp = pico_seq_compare(SEQN(f), start); + cmp = seq_compare(SEQN(f), start); if (cmp > 0) return 0; if (cmp == 0) { - cmp = pico_seq_compare(SEQN(f) + f->payload_len, end); + cmp = seq_compare(SEQN(f) + f->payload_len, end); if (cmp > 0) { tcp_dbg("Invalid SACK: ignoring.\n"); } @@ -889,7 +913,7 @@ static inline void tcp_send_add_tcpflags(struct pico_socket_tcp *ts, struct pico { struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; if (ts->rcv_nxt != 0) { - if ((ts->rcv_ackd == 0) || (pico_seq_compare(ts->rcv_ackd, ts->rcv_nxt) != 0) || (hdr->flags & PICO_TCP_ACK)) { + if ((ts->rcv_ackd == 0) || (seq_compare(ts->rcv_ackd, ts->rcv_nxt) != 0) || (hdr->flags & PICO_TCP_ACK)) { hdr->flags |= PICO_TCP_ACK; hdr->ack = long_be(ts->rcv_nxt); ts->rcv_ackd = ts->rcv_nxt; @@ -1060,7 +1084,7 @@ uint32_t pico_tcp_read(struct pico_socket *s, void *buf, uint32_t len) if (!f) return tcp_read_finish(s, tot_rd_len); - in_frame_off = pico_seq_compare(t->rcv_processed, f->seq); + in_frame_off = seq_compare(t->rcv_processed, f->seq); /* Check for hole at the beginning of data, awaiting retransmissions. */ if (in_frame_off < 0) { tcp_dbg("TCP> read hole beginning of data, %08x - %08x. rcv_nxt is %08x\n", t->rcv_processed, f->seq, t->rcv_nxt); @@ -1362,14 +1386,14 @@ int pico_tcp_reply_rst(struct pico_frame *fr) tcp_fill_rst_header(fr, hdr1, f, hdr); if (0) { -#ifdef PICO_SUPPORT_IPV4 +#ifdef PICO_SUPPORT_IPV4 } else if (IS_IPV4(f)) { tcp_dbg("Pushing IPv4 reset frame...\n"); pico_ipv4_frame_push(f, &(((struct pico_ipv4_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP); #endif #ifdef PICO_SUPPORT_IPV6 } else { - pico_ipv6_frame_push(f, NULL, &(((struct pico_ipv6_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP, 0); + pico_ipv6_frame_push(f, &(((struct pico_ipv6_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP); #endif } @@ -1535,7 +1559,7 @@ static void tcp_sack_prepare(struct pico_socket_tcp *t) static inline int tcp_data_in_expected(struct pico_socket_tcp *t, struct pico_frame *f) { struct tcp_input_segment *nxt; - if (pico_seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */ + if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */ /* Create new segment and enqueue it */ struct tcp_input_segment *input = segment_from_frame(f); if (!input) { @@ -1614,7 +1638,7 @@ static int tcp_data_in(struct pico_socket *s, struct pico_frame *f) f->payload_len = payload_len; tcp_dbg("TCP> Received segment. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); - if (pico_seq_compare(SEQN(f), t->rcv_nxt) <= 0) { + if (seq_compare(SEQN(f), t->rcv_nxt) <= 0) { ret = tcp_data_in_expected(t, f); } else { ret = tcp_data_in_high_segment(t, f); @@ -2035,7 +2059,6 @@ static int tcp_ack(struct pico_socket *s, struct pico_frame *f) t->cwnd = (uint16_t)t->in_flight; else t->cwnd = PICO_TCP_IW; - t->snd_retry = SEQN((struct pico_frame *)first_segment(&t->tcpq_out)); if (t->ssthresh > t->cwnd) t->ssthresh >>= 2; @@ -2056,10 +2079,10 @@ static int tcp_ack(struct pico_socket *s, struct pico_frame *f) tcp_dbg("Skipping %08x because it is sacked.\n", SEQN(nxt)); nxt = next_segment(&t->tcpq_out, nxt); } - if (nxt && (pico_seq_compare(SEQN(nxt), t->snd_nxt)) > 0) + if (nxt && (seq_compare(SEQN(nxt), t->snd_nxt)) > 0) nxt = NULL; - if (nxt && (pico_seq_compare(SEQN(nxt), SEQN((struct pico_frame *)first_segment(&t->tcpq_out))) > (int)(t->recv_wnd << t->recv_wnd_scale))) + if (nxt && (seq_compare(SEQN(nxt), SEQN((struct pico_frame *)first_segment(&t->tcpq_out))) > (int)(t->recv_wnd << t->recv_wnd_scale))) nxt = NULL; if(!nxt) @@ -2087,7 +2110,7 @@ static int tcp_ack(struct pico_socket *s, struct pico_frame *f) /* Linux very special zero-window probe detection (see bug #107) */ if ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) && /* This is a pure ack, and... */ (ACKN(f) == t->snd_nxt) && /* it's acking our snd_nxt, and... */ - (pico_seq_compare(SEQN(f), t->rcv_nxt) < 0)) /* Has an old seq number */ + (seq_compare(SEQN(f), t->rcv_nxt) < 0)) /* Has an old seq number */ { tcp_send_ack(t); } @@ -2393,10 +2416,10 @@ static void tcp_attempt_closewait(struct pico_socket *s, struct pico_frame *f) { struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); - if (pico_seq_compare(SEQN(f), t->rcv_nxt) == 0) { + if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* received FIN, increase ACK nr */ t->rcv_nxt = long_be(hdr->seq) + 1; - if (pico_seq_compare(SEQN(f), t->rcv_processed) == 0) { + if (seq_compare(SEQN(f), t->rcv_processed) == 0) { if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) { tcp_dbg("Changing state to CLOSE_WAIT\n"); s->state &= 0x00FFU; @@ -2512,6 +2535,7 @@ static int tcp_rst(struct pico_socket *s, struct pico_frame *f) tcp_force_closed(s); pico_err = PICO_ERR_ECONNRESET; tcp_wakeup_pending(s, PICO_SOCK_EV_ERR); + pico_socket_del(&t->sock); /* delete socket */ } else { /* not valid, ignore */ tcp_dbg("TCP RST> IGNORE\n"); return 0; @@ -2556,7 +2580,7 @@ static int tcp_closeconn(struct pico_socket *s, struct pico_frame *fr) struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (fr->transport_hdr); - if (pico_seq_compare(SEQN(fr), t->rcv_nxt) == 0) { + if (seq_compare(SEQN(fr), t->rcv_nxt) == 0) { /* received FIN, increase ACK nr */ t->rcv_nxt = long_be(hdr->seq) + 1; s->state &= 0x00FFU; @@ -2779,7 +2803,7 @@ int pico_tcp_output(struct pico_socket *s, int loop_score) f->timestamp = TCP_TIME; add_retransmission_timer(t, t->rto + TCP_TIME); tcp_add_options_frame(t, f); - seq_diff = pico_seq_compare(SEQN(f), SEQN(una)); + seq_diff = seq_compare(SEQN(f), SEQN(una)); if (seq_diff < 0) { dbg(">>> FATAL: seq diff is negative!\n"); break; diff --git a/modules/pico_tcp.h b/modules/pico_tcp.h index d5003a843..cd529cbe7 100644 --- a/modules/pico_tcp.h +++ b/modules/pico_tcp.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . diff --git a/modules/pico_tftp.c b/modules/pico_tftp.c index 47e2edb04..143be22ff 100644 --- a/modules/pico_tftp.c +++ b/modules/pico_tftp.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -29,7 +29,7 @@ #define AUTOMA_STATES (TFTP_STATE_CLOSING + 1) -/* MAX_OPTIONS_SIZE: "timeout" 255 "tsize" filesize => 8 + 4 + 6 + 11 */ +//MAX_OPTIONS_SIZE: "timeout" 255 "tsize" filesize => 8 + 4 + 6 + 11 #define MAX_OPTIONS_SIZE 29 /* RRQ and WRQ packets (opcodes 1 and 2 respectively) */ @@ -104,24 +104,24 @@ static struct server_t server; static struct pico_tftp_session *tftp_sessions = NULL; -static inline int session_status_get(struct pico_tftp_session *session, int status) +static inline int session_status_get(struct pico_tftp_session * session, int status) { return session->status & status; } -static inline void session_status_set(struct pico_tftp_session *session, int status) +static inline void session_status_set(struct pico_tftp_session * session, int status) { session->status |= status; } -static inline void session_status_clear(struct pico_tftp_session *session, int status) +static inline void session_status_clear(struct pico_tftp_session * session, int status) { session->status &= ~status; } -static char *extract_arg_pointer(char *arg, char *end_arg, char **value) +static char * extract_arg_pointer(char * arg, char * end_arg, char **value) { - char *pos; + char * pos; pos = get_string_terminator_position(arg, (size_t)(end_arg - arg)); if (!pos) @@ -139,7 +139,7 @@ static char *extract_arg_pointer(char *arg, char *end_arg, char **value) return arg + 1; } -static int extract_value(char *str, uint32_t *value, uint32_t max) +static int extract_value(char * str, uint32_t * value, uint32_t max) { char *endptr; unsigned long num; @@ -168,12 +168,10 @@ static int parse_optional_arguments(char *option_string, int32_t len, int *optio option_string = extract_arg_pointer(option_string, end_args, &pos); if (!option_string) return 0; - if (!pico_strncasecmp("timeout", current_option, (size_t)(pos - current_option))) { ret = extract_value(pos, &value, PICO_TFTP_MAX_TIMEOUT); if (ret) return -1; - *timeout = (uint8_t)value; *options |= PICO_TFTP_OPTION_TIME; } else { @@ -181,10 +179,8 @@ static int parse_optional_arguments(char *option_string, int32_t len, int *optio ret = extract_value(pos, (uint32_t *)filesize, PICO_TFTP_MAX_FILESIZE); if (ret) return -1; - if (*filesize < 0) return -1; - *options |= PICO_TFTP_OPTION_FILE; } } @@ -192,7 +188,7 @@ static int parse_optional_arguments(char *option_string, int32_t len, int *optio return 0; } -static inline struct pico_tftp_session *pico_tftp_session_create(struct pico_socket *sock, union pico_address *remote_addr) +static inline struct pico_tftp_session * pico_tftp_session_create(struct pico_socket *sock, union pico_address *remote_addr) { struct pico_tftp_session *session; @@ -221,11 +217,11 @@ static inline struct pico_tftp_session *pico_tftp_session_create(struct pico_soc return session; } -static struct pico_tftp_session *find_session_by_socket(struct pico_socket *tftp_socket) +static struct pico_tftp_session * find_session_by_socket(struct pico_socket *tftp_socket) { struct pico_tftp_session *pos = tftp_sessions; - for (; pos; pos = pos->next) + for (; pos ; pos = pos->next) if (pos->socket == tftp_socket) return pos; @@ -233,8 +229,8 @@ static struct pico_tftp_session *find_session_by_socket(struct pico_socket *tftp } /* **************** for future use... - static struct pico_tftp_session * find_session_by_localport(uint16_t localport) - { +static struct pico_tftp_session * find_session_by_localport(uint16_t localport) +{ struct pico_tftp_session *idx = tftp_sessions; for (; idx; idx = idx->next) @@ -242,7 +238,7 @@ static struct pico_tftp_session *find_session_by_socket(struct pico_socket *tftp return idx; return NULL; - } *********************/ +} *********************/ static void add_session(struct pico_tftp_session *idx) { @@ -265,22 +261,22 @@ static void add_session(struct pico_tftp_session *idx) /* Returns 0 if OK and -1 in case of errors */ static int del_session(struct pico_tftp_session *idx) { - struct pico_tftp_session *prev = NULL; + struct pico_tftp_session *prev; struct pico_tftp_session *pos; for (pos = tftp_sessions; pos; pos = pos->next) { if (pos == idx) { if (pos == tftp_sessions) tftp_sessions = tftp_sessions->next; - else if (prev) + else prev->next = pos->next; PICO_FREE(idx); return 0; } - prev = pos; } + return -1; } @@ -324,7 +320,6 @@ static void tftp_finish(struct pico_tftp_session *session) pico_timer_cancel(session->timer); --session->active_timers; } - session->wallclock_timeout = 0; tftp_schedule_timeout(session, 5); } @@ -405,7 +400,6 @@ static void tftp_send_oack(struct pico_tftp_session *session) tftp_finish(session); return; } - hdr = (struct pico_tftp_hdr *)buf; hdr->opcode = short_be(PICO_TFTP_OACK); memcpy(buf + options_pos, str_options, options_size); @@ -432,7 +426,7 @@ static void tftp_send_req(struct pico_tftp_session *session, union pico_address len = strlen(filename); - options_size = prepare_options_string(session, str_options, (opcode == PICO_TFTP_WRQ) ? session->file_size : 0); + options_size = prepare_options_string(session, str_options, (opcode == PICO_TFTP_WRQ)? session->file_size: 0); options_pos = sizeof(struct pico_tftp_hdr) + OCTET_STRSIZ + len; buf = PICO_ZALLOC(options_pos + options_size); @@ -488,7 +482,7 @@ static int send_error(uint8_t *buf, struct pico_socket *sock, union pico_address tftp_payload(eh)[len++] = (char)0; - return pico_socket_sendto(sock, eh, (int)(len + (int32_t)sizeof(struct pico_tftp_err_hdr)), a, port); + return pico_socket_sendto(sock, eh,(int)(len + (int32_t)sizeof(struct pico_tftp_err_hdr)), a, port); } static void tftp_send_error(struct pico_tftp_session *session, union pico_address *a, uint16_t port, uint16_t errcode, const char *errmsg) @@ -507,7 +501,7 @@ static void tftp_send_error(struct pico_tftp_session *session, union pico_addres port = session->remote_port; } - eh = (struct pico_tftp_err_hdr *) (session ? session->tftp_block : server.tftp_block); + eh = (struct pico_tftp_err_hdr *) (session? session->tftp_block: server.tftp_block); eh->opcode = short_be(PICO_TFTP_ERROR); eh->error_code = short_be(errcode); if (len + 1 > maxlen) @@ -567,9 +561,9 @@ static inline int tftp_data_prepare(struct pico_tftp_session *session, union pic static void tftp_req(uint8_t *block, int32_t len, union pico_address *a, uint16_t port) { struct pico_tftp_hdr *hdr = (struct pico_tftp_hdr *)block; - char *filename; - char *pos; - char *mode; + char * filename; + char * pos; + char * mode; int ret; switch (short_be(hdr->opcode)) { @@ -589,17 +583,15 @@ static void tftp_req(uint8_t *block, int32_t len, union pico_address *a, uint16_ send_error(block, server.listen_socket, a, port, TFTP_ERR_EILL, "Unsupported mode"); return; } - /*ret = parse_optional_arguments((char *)(block + sizeof(struct pico_tftp_hdr)), len - sizeof(struct pico_tftp_hdr), &new_options, &new_timeout, &new_filesize); - if (ret) { + if (ret) { tftp_send_error(NULL, a, port, TFTP_ERR_EILL, "Bad request"); return; - } */ + } */ if (server.listen_callback) { server.listen_callback(a, port, short_be(hdr->opcode), filename, len); } - break; default: send_error(block, server.listen_socket, a, port, TFTP_ERR_EILL, "Illegal opcode"); @@ -742,7 +734,7 @@ static void event_err(struct pico_tftp_session *session, int32_t len, union pico static inline void event_oack(struct pico_tftp_session *session, int32_t len, union pico_address *a, uint16_t port) { - char *option_string = (char *)session->tftp_block + sizeof(struct pico_tftp_hdr); + char * option_string = (char *)session->tftp_block + sizeof(struct pico_tftp_hdr); int ret; int proposed_options = session->options; @@ -794,7 +786,6 @@ static void event_timeout(struct pico_tftp_session *session, pico_time t) for (factor = session->retry; factor; --factor) new_timeout *= 2; } - tftp_schedule_timeout(session, new_timeout); } @@ -885,7 +876,6 @@ static void tftp_cb(uint16_t ev, struct pico_socket *s) tftp_finish(session); return; } - r = pico_socket_recvfrom(s, session->tftp_block, PICO_TFTP_TOTAL_BLOCK_SIZE, &ep, &port); if (r < (int)sizeof(struct pico_tftp_hdr)) return; @@ -895,11 +885,9 @@ static void tftp_cb(uint16_t ev, struct pico_socket *s) if (!server.listen_socket || s != server.listen_socket) { return; } - r = pico_socket_recvfrom(s, server.tftp_block, PICO_TFTP_TOTAL_BLOCK_SIZE, &ep, &port); - if (r < (int)sizeof(struct pico_tftp_hdr)) - return; - + if (r < (int)sizeof(struct pico_tftp_hdr)) + return; tftp_req(server.tftp_block, r, &ep, port); } } @@ -931,7 +919,7 @@ static int application_tx_cb(struct pico_tftp_session *session, uint16_t event, (void)block; (void)len; - *(int*)arg = ((event == PICO_TFTP_EV_OK) || (event == PICO_TFTP_EV_OPT)) ? 1 : -event; + *(int*)arg = ((event == PICO_TFTP_EV_OK) || (event == PICO_TFTP_EV_OPT))? 1 : -event; return 0; } @@ -953,7 +941,7 @@ static void timer_callback(pico_time now, void *arg) } } -static struct pico_socket *tftp_socket_open(uint16_t family, uint16_t localport) +static struct pico_socket * tftp_socket_open(uint16_t family, uint16_t localport) { struct pico_socket *sock; union pico_address local_address; @@ -974,7 +962,7 @@ static struct pico_socket *tftp_socket_open(uint16_t family, uint16_t localport) } static inline int tftp_start_check(struct pico_tftp_session *session, uint16_t port, const char *filename, - int (*user_cb)(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg)) + int (*user_cb)(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg)) { if (!session) { pico_err = PICO_ERR_EINVAL; @@ -1001,7 +989,7 @@ static inline int tftp_start_check(struct pico_tftp_session *session, uint16_t p /* *** EXPORTED FUNCTIONS *** */ -struct pico_tftp_session *pico_tftp_session_setup(union pico_address *a, uint16_t family) +struct pico_tftp_session * pico_tftp_session_setup(union pico_address *a, uint16_t family) { struct pico_socket *sock; @@ -1027,7 +1015,6 @@ int pico_tftp_get_option(struct pico_tftp_session *session, uint8_t type, int32_ pico_err = PICO_ERR_ENOENT; return -1; } - break; case PICO_TFTP_OPTION_TIME: if (session->options & PICO_TFTP_OPTION_TIME) @@ -1036,7 +1023,6 @@ int pico_tftp_get_option(struct pico_tftp_session *session, uint8_t type, int32_ pico_err = PICO_ERR_ENOENT; return -1; } - break; default: pico_err = PICO_ERR_EINVAL; @@ -1059,7 +1045,6 @@ int pico_tftp_set_option(struct pico_tftp_session *session, uint8_t type, int32_ pico_err = PICO_ERR_EINVAL; return -1; } - session->file_size = value; session->options |= PICO_TFTP_OPTION_FILE; break; @@ -1068,14 +1053,12 @@ int pico_tftp_set_option(struct pico_tftp_session *session, uint8_t type, int32_ pico_err = PICO_ERR_EINVAL; return -1; } - session->option_timeout = (uint8_t)value & 0xFF; if (value) { session->options |= PICO_TFTP_OPTION_TIME; } else { session->options &= ~PICO_TFTP_OPTION_TIME; } - break; default: pico_err = PICO_ERR_EINVAL; @@ -1087,7 +1070,7 @@ int pico_tftp_set_option(struct pico_tftp_session *session, uint8_t type, int32_ /* Active RX request from PicoTCP */ int pico_tftp_start_rx(struct pico_tftp_session *session, uint16_t port, const char *filename, - int (*user_cb)(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg), void *arg) + int (*user_cb)(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg), void *arg) { if (tftp_start_check(session, port, filename, user_cb)) return -1; @@ -1113,7 +1096,7 @@ int pico_tftp_start_rx(struct pico_tftp_session *session, uint16_t port, const c } int pico_tftp_start_tx(struct pico_tftp_session *session, uint16_t port, const char *filename, - int (*user_cb)(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg), void *arg) + int (*user_cb)(struct pico_tftp_session *session, uint16_t event, uint8_t *block, int32_t len, void *arg), void *arg) { if (tftp_start_check(session, port, filename, user_cb)) return -1; @@ -1138,7 +1121,7 @@ int pico_tftp_start_tx(struct pico_tftp_session *session, uint16_t port, const c return 0; } -int pico_tftp_reject_request(union pico_address*addr, uint16_t port, uint16_t error_code, const char*error_message) +int pico_tftp_reject_request(union pico_address* addr, uint16_t port, uint16_t error_code, const char* error_message) { return send_error(server.tftp_block, server.listen_socket, addr, port, error_code, error_message); } @@ -1184,7 +1167,7 @@ int pico_tftp_listen(uint16_t family, void (*cb)(union pico_address *addr, uint1 return 0; } -int pico_tftp_parse_request_args(char *args, int32_t len, int *options, uint8_t *timeout, int32_t *filesize) +int pico_tftp_parse_request_args(char * args, int32_t len, int * options, uint8_t * timeout, int32_t * filesize) { char *pos; char *end_args = args + len; @@ -1217,7 +1200,6 @@ int pico_tftp_close_server(void) pico_err = PICO_ERR_EINVAL; return -1; } - pico_socket_close(server.listen_socket); server.listen_socket = NULL; return 0; @@ -1228,7 +1210,7 @@ int pico_tftp_get_file_size(struct pico_tftp_session *session, int32_t *file_siz return pico_tftp_get_option(session, PICO_TFTP_OPTION_FILE, file_size); } -struct pico_tftp_session *pico_tftp_app_setup(union pico_address *a, uint16_t port, uint16_t family, int *synchro) +struct pico_tftp_session * pico_tftp_app_setup(union pico_address *a, uint16_t port, uint16_t family, int *synchro) { struct pico_tftp_session *session; @@ -1277,7 +1259,7 @@ int32_t pico_tftp_get(struct pico_tftp_session *session, uint8_t *data, int32_t if (synchro < 0) return synchro; - memcpy(data, tftp_payload(session->tftp_block), (size_t)session->len); + memcpy(data, session->tftp_block, (size_t)session->len); len = session->len; tftp_send_ack(session); diff --git a/modules/pico_tftp.h b/modules/pico_tftp.h index bcbb64892..35802310c 100644 --- a/modules/pico_tftp.h +++ b/modules/pico_tftp.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -50,7 +50,7 @@ struct pico_tftp_session; -struct pico_tftp_session *pico_tftp_session_setup(union pico_address *a, uint16_t family); +struct pico_tftp_session * pico_tftp_session_setup(union pico_address *a, uint16_t family); int pico_tftp_set_option(struct pico_tftp_session *session, uint8_t type, int32_t value); int pico_tftp_get_option(struct pico_tftp_session *session, uint8_t type, int32_t *value); @@ -72,7 +72,7 @@ int pico_tftp_close_server(void); int pico_tftp_get_file_size(struct pico_tftp_session *session, int32_t *file_size); /* SPECIFIC APPLICATION DRIVEN FUNCTIONS */ -struct pico_tftp_session *pico_tftp_app_setup(union pico_address *a, uint16_t port, uint16_t family, int *synchro); +struct pico_tftp_session * pico_tftp_app_setup(union pico_address *a, uint16_t port, uint16_t family, int *synchro); int pico_tftp_app_start_rx(struct pico_tftp_session *session, const char *filename); int pico_tftp_app_start_tx(struct pico_tftp_session *session, const char *filename); diff --git a/modules/pico_udp.c b/modules/pico_udp.c index b7c61e4c6..882d37894 100644 --- a/modules/pico_udp.c +++ b/modules/pico_udp.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -16,6 +16,7 @@ #define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame)) #define udp_dbg(...) do {} while(0) +//#define udp_dbg dbg /* Queues */ static struct pico_queue udp_in = { @@ -59,9 +60,7 @@ uint16_t pico_udp_checksum_ipv6(struct pico_frame *f) { struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *)f->transport_hdr; - struct pico_ipv6_pseudo_hdr pseudo = { - .src = {{0}}, .dst = {{0}}, .len = 0, .zero = {0}, .nxthdr = 0 - }; + struct pico_ipv6_pseudo_hdr pseudo; struct pico_socket *s = f->sock; struct pico_remote_endpoint *remote_endpoint = (struct pico_remote_endpoint *)f->info; @@ -156,28 +155,7 @@ struct pico_socket *pico_udp_open(void) return &u->sock; } -static void pico_udp_get_msginfo(struct pico_frame *f, struct pico_msginfo *msginfo) -{ - msginfo->dev = f->dev; - if (!msginfo || !f->net_hdr) - return; - - if (IS_IPV4(f)) { /* IPV4 */ -#ifdef PICO_SUPPORT_IPV4 - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)(f->net_hdr); - msginfo->ttl = hdr->ttl; - msginfo->tos = hdr->tos; -#endif - } else { -#ifdef PICO_SUPPORT_IPV6 - struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)(f->net_hdr); - msginfo->ttl = hdr->hop; - msginfo->tos = (hdr->vtf >> 20) & 0xFF; /* IPv6 traffic class */ -#endif - } -} - -uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src, uint16_t *port, struct pico_msginfo *msginfo) +uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src, uint16_t *port) { struct pico_frame *f = pico_queue_peek(&s->q_in); if (f) { @@ -195,10 +173,6 @@ uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src *port = hdr->sport; } - if (msginfo) { - pico_udp_get_msginfo(f, msginfo); - } - if (f->payload_len > len) { memcpy(buf, f->payload, len); f->payload += len; diff --git a/modules/pico_udp.h b/modules/pico_udp.h index 80b97a929..f85b607d2 100644 --- a/modules/pico_udp.h +++ b/modules/pico_udp.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -32,7 +32,7 @@ PACKED_STRUCT_DEF pico_udp_hdr { #define PICO_UDPHDR_SIZE 8 struct pico_socket *pico_udp_open(void); -uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src, uint16_t *port, struct pico_msginfo *msginfo); +uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src, uint16_t *port); uint16_t pico_udp_checksum_ipv4(struct pico_frame *f); #ifdef PICO_SUPPORT_IPV6 diff --git a/modules/ptsocket/pico_ptsocket.c b/modules/ptsocket/pico_ptsocket.c index ba12b069e..45791cf11 100644 --- a/modules/ptsocket/pico_ptsocket.c +++ b/modules/ptsocket/pico_ptsocket.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . diff --git a/modules/ptsocket/pico_ptsocket.h b/modules/ptsocket/pico_ptsocket.h index 6280011b1..a38e1f2c0 100644 --- a/modules/ptsocket/pico_ptsocket.h +++ b/modules/ptsocket/pico_ptsocket.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . diff --git a/rules/dns_sd.mk b/rules/dns_sd.mk new file mode 100644 index 000000000..62d05cc5d --- /dev/null +++ b/rules/dns_sd.mk @@ -0,0 +1,2 @@ +OPTIONS+=-DPICO_SUPPORT_DNS_SD +MOD_OBJ+=$(LIBBASE)modules/pico_dns_sd.o $(LIBBASE)modules/pico_mdns.o $(LIBBASE)modules/pico_dns_common.o \ No newline at end of file diff --git a/stack/pico_device.c b/stack/pico_device.c index 224b37f58..98b42c420 100644 --- a/stack/pico_device.c +++ b/stack/pico_device.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -50,47 +50,33 @@ static void device_init_ipv6_final(struct pico_device *dev, struct pico_ip6 *lin pico_icmp6_router_solicitation(dev, linklocal); dev->hostvars.hoplimit = PICO_IPV6_DEFAULT_HOP; } - -struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix) -{ - struct pico_ip6 newaddr; - struct pico_ip6 netmask64 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - struct pico_ipv6_link *link; - memcpy(newaddr.addr, prefix->addr, PICO_SIZE_IP6); - /* modified EUI-64 + invert universal/local bit */ - newaddr.addr[8] = (dev->eth->mac.addr[0] ^ 0x02); - newaddr.addr[9] = dev->eth->mac.addr[1]; - newaddr.addr[10] = dev->eth->mac.addr[2]; - newaddr.addr[11] = 0xff; - newaddr.addr[12] = 0xfe; - newaddr.addr[13] = dev->eth->mac.addr[3]; - newaddr.addr[14] = dev->eth->mac.addr[4]; - newaddr.addr[15] = dev->eth->mac.addr[5]; - link = pico_ipv6_link_add(dev, newaddr, netmask64); - if (link) { - device_init_ipv6_final(dev, &newaddr); - } - - return link; -} #endif static int device_init_mac(struct pico_device *dev, uint8_t *mac) { #ifdef PICO_SUPPORT_IPV6 struct pico_ip6 linklocal = {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xff, 0xfe, 0xaa, 0xaa, 0xaa}}; + struct pico_ip6 netmask6 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; #endif dev->eth = PICO_ZALLOC(sizeof(struct pico_ethdev)); if (dev->eth) { memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH); #ifdef PICO_SUPPORT_IPV6 - if (pico_ipv6_link_add_local(dev, &linklocal) == NULL) { + /* modified EUI-64 + invert universal/local bit */ + linklocal.addr[8] = (mac[0] ^ 0x02); + linklocal.addr[9] = mac[1]; + linklocal.addr[10] = mac[2]; + linklocal.addr[13] = mac[3]; + linklocal.addr[14] = mac[4]; + linklocal.addr[15] = mac[5]; + if (pico_ipv6_link_add(dev, linklocal, netmask6)) { PICO_FREE(dev->q_in); PICO_FREE(dev->q_out); PICO_FREE(dev->eth); return -1; } + device_init_ipv6_final(dev, &linklocal); #endif } else { pico_err = PICO_ERR_ENOMEM; @@ -100,7 +86,7 @@ static int device_init_mac(struct pico_device *dev, uint8_t *mac) return 0; } -int pico_device_ipv6_random_ll(struct pico_device *dev) +static int device_init_nomac(struct pico_device *dev) { #ifdef PICO_SUPPORT_IPV6 struct pico_ip6 linklocal = {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xff, 0xfe, 0xaa, 0xaa, 0xaa}}; @@ -122,23 +108,14 @@ int pico_device_ipv6_random_ll(struct pico_device *dev) pico_rand_feed(dev->hash); } while (pico_ipv6_link_get(&linklocal)); - if (pico_ipv6_link_add(dev, linklocal, netmask6) == NULL) { + if (pico_ipv6_link_add(dev, linklocal, netmask6)) { + PICO_FREE(dev->q_in); + PICO_FREE(dev->q_out); return -1; } } #endif - return 0; -} - -static int device_init_nomac(struct pico_device *dev) -{ - if (pico_device_ipv6_random_ll(dev) < 0) { - PICO_FREE(dev->q_in); - PICO_FREE(dev->q_out); - return -1; - } - dev->eth = NULL; return 0; } @@ -157,25 +134,18 @@ int pico_device_init(struct pico_device *dev, const char *name, uint8_t *mac) Devices_rr_info.node_in = NULL; Devices_rr_info.node_out = NULL; dev->q_in = PICO_ZALLOC(sizeof(struct pico_queue)); - if (!dev->q_in) - return -1; - dev->q_out = PICO_ZALLOC(sizeof(struct pico_queue)); - if (!dev->q_out) { - PICO_FREE(dev->q_in); + if (!dev->q_in || !dev->q_out) return -1; - } pico_tree_insert(&Device_tree, dev); if (!dev->mtu) dev->mtu = PICO_DEVICE_DEFAULT_MTU; - if (mac) { ret = device_init_mac(dev, mac); } else { ret = device_init_nomac(dev); } - return ret; } @@ -206,6 +176,8 @@ void pico_device_destroy(struct pico_device *dev) #endif pico_tree_delete(&Device_tree, dev); + + pico_tree_delete(&Device_tree, dev); Devices_rr_info.node_in = NULL; Devices_rr_info.node_out = NULL; PICO_FREE(dev); @@ -282,9 +254,8 @@ static int devloop_out(struct pico_device *dev, int loop_score) f = pico_dequeue(dev->q_out); pico_frame_discard(f); /* SINGLE POINT OF DISCARD for OUTGOING FRAMES */ loop_score--; - } else + } else break; /* Don't discard */ - } return loop_score; } @@ -403,6 +374,5 @@ int pico_device_link_state(struct pico_device *dev) { if (!dev->link_state) return 1; /* Not supported, assuming link is always up */ - return dev->link_state(dev); } diff --git a/stack/pico_frame.c b/stack/pico_frame.c index bb17b6055..efc8553c5 100644 --- a/stack/pico_frame.c +++ b/stack/pico_frame.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -79,7 +79,7 @@ static struct pico_frame *pico_frame_do_alloc(uint32_t size, int zerocopy, int e p->usage_count = PICO_ZALLOC(sizeof(uint32_t)); if (!p->usage_count) { - if (p->buffer) + if (p->buffer && !ext_buffer) PICO_FREE(p->buffer); PICO_FREE(p); @@ -88,6 +88,7 @@ static struct pico_frame *pico_frame_do_alloc(uint32_t size, int zerocopy, int e p->buffer_len = size; + /* By default, frame content is the full buffer. */ p->start = p->buffer; p->len = p->buffer_len; @@ -180,6 +181,7 @@ static inline uint32_t pico_checksum_adder(uint32_t sum, void *data, uint32_t le while (buf < stop) { sum += *buf++; } + return sum; } @@ -188,7 +190,7 @@ static inline uint16_t pico_checksum_finalize(uint32_t sum) while (sum >> 16) { /* a second carry is possible! */ sum = (sum & 0x0000FFFF) + (sum >> 16); } - return short_be((uint16_t) ~sum); + return short_be((uint16_t)~sum); } #else @@ -206,6 +208,7 @@ static inline uint32_t pico_checksum_adder(uint32_t sum, void *data, uint32_t le if (len > (i + 1u)) sum += buf[i + 1]; } + return sum; } diff --git a/stack/pico_protocol.c b/stack/pico_protocol.c index 98d2a205c..af9368c8b 100644 --- a/stack/pico_protocol.c +++ b/stack/pico_protocol.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -123,8 +123,8 @@ static int pico_protocol_generic_loop(struct pico_proto_rr *rr, int loop_score, if (!next_node) return loop_score; - - next = next_node->keyValue; + else + next = next_node->keyValue; /* init start node */ start = next; diff --git a/stack/pico_socket.c b/stack/pico_socket.c index 39343fd6e..4743f5fdc 100644 --- a/stack/pico_socket.c +++ b/stack/pico_socket.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. @@ -263,9 +263,9 @@ static int pico_port_in_use_ipv6(struct pico_sockport *sp, void *addr) struct pico_ip6 ip; /* IPv6 */ if (addr) - memcpy(ip.addr, ((struct pico_ip6 *)addr)->addr, sizeof(struct pico_ip6)); + memcpy(&ip.addr, ((struct pico_ip6 *)addr)->addr, sizeof(struct pico_ip6)); else - memcpy(ip.addr, PICO_IP6_ANY, sizeof(struct pico_ip6)); + memcpy(&ip.addr, PICO_IP6_ANY, sizeof(struct pico_ip6)); if (memcmp(ip.addr, PICO_IP6_ANY, sizeof(struct pico_ip6)) == 0) { if (!sp) @@ -282,28 +282,22 @@ static int pico_port_in_use_ipv6(struct pico_sockport *sp, void *addr) -static int pico_generic_port_in_use(uint16_t proto, uint16_t port, struct pico_sockport *sp, void *addr, void *net) +static int pico_generic_port_in_use(uint16_t proto, uint16_t port, struct pico_sockport *sp, void *addr) { #ifdef PICO_SUPPORT_IPV4 - if (net == &pico_proto_ipv4) - { - if (pico_port_in_use_by_nat(proto, port)) { - return 1; - } + if (pico_port_in_use_by_nat(proto, port)) { + return 1; + } - if (pico_port_in_use_ipv4(sp, addr)) { - return 1; - } + if (pico_port_in_use_ipv4(sp, addr)) { + return 1; } #endif #ifdef PICO_SUPPORT_IPV6 - if (net == &pico_proto_ipv6) - { - if (pico_port_in_use_ipv6(sp, addr)) { - return 1; - } + if (pico_port_in_use_ipv6(sp, addr)) { + return 1; } #endif @@ -314,9 +308,10 @@ static int pico_generic_port_in_use(uint16_t proto, uint16_t port, struct pico_s int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net) { struct pico_sockport *sp; + (void) net; sp = pico_get_sockport(proto, port); - if (pico_generic_port_in_use(proto, port, sp, addr, net)) + if (pico_generic_port_in_use(proto, port, sp, addr)) return 0; return 1; @@ -523,13 +518,11 @@ static int pico_socket_transport_deliver(struct pico_protocol *p, struct pico_so #ifdef PICO_SUPPORT_TCP if (p->proto_number == PICO_PROTO_TCP) return pico_socket_tcp_deliver(sp, f); - #endif #ifdef PICO_SUPPORT_UDP if (p->proto_number == PICO_PROTO_UDP) return pico_socket_udp_deliver(sp, f); - #endif return -1; @@ -582,13 +575,11 @@ static struct pico_socket *pico_socket_transport_open(uint16_t proto, uint16_t f #ifdef PICO_SUPPORT_UDP if (proto == PICO_PROTO_UDP) s = pico_socket_udp_open(); - #endif #ifdef PICO_SUPPORT_TCP if (proto == PICO_PROTO_TCP) s = pico_socket_tcp_open(family); - #endif return s; @@ -972,7 +963,6 @@ static int32_t pico_socket_sendto_set_localport(struct pico_socket *s) pico_err = PICO_ERR_EINVAL; return -1; } - s->state |= PICO_SOCKET_STATE_BOUND; } @@ -1029,8 +1019,7 @@ static int pico_socket_final_xmit(struct pico_socket *s, struct pico_frame *f) } } -static int pico_socket_xmit_one(struct pico_socket *s, const void *buf, const int len, void *src, - struct pico_remote_endpoint *ep, struct pico_msginfo *msginfo) +static int pico_socket_xmit_one(struct pico_socket *s, const void *buf, const int len, void *src, struct pico_remote_endpoint *ep) { struct pico_frame *f; uint16_t hdr_offset = (uint16_t)pico_socket_sendto_transport_offset(s); @@ -1056,12 +1045,6 @@ static int pico_socket_xmit_one(struct pico_socket *s, const void *buf, const in } } - if (msginfo) { - f->send_ttl = (uint8_t)msginfo->ttl; - f->send_tos = (uint8_t)msginfo->tos; - f->dev = msginfo->dev; - } - memcpy(f->payload, (const uint8_t *)buf, f->payload_len); /* dbg("Pushing segment, hdr len: %d, payload_len: %d\n", header_offset, f->payload_len); */ ret = pico_socket_final_xmit(s, f); @@ -1098,8 +1081,7 @@ static void pico_socket_xmit_next_fragment_setup(struct pico_frame *f, int hdr_o } #endif -static int pico_socket_xmit_fragments(struct pico_socket *s, const void *buf, const int len, - void *src, struct pico_remote_endpoint *ep, struct pico_msginfo *msginfo) +static int pico_socket_xmit_fragments(struct pico_socket *s, const void *buf, const int len, void *src, struct pico_remote_endpoint *ep) { int space = pico_socket_xmit_avail_space(s); int hdr_offset = pico_socket_sendto_transport_offset(s); @@ -1107,15 +1089,14 @@ static int pico_socket_xmit_fragments(struct pico_socket *s, const void *buf, co struct pico_frame *f = NULL; if (space > len) { - return pico_socket_xmit_one(s, buf, len, src, ep, msginfo); + return pico_socket_xmit_one(s, buf, len, src, ep); } #ifdef PICO_SUPPORT_IPV6 /* Can't fragment IPv6 */ if (is_sock_ipv6(s)) { - return pico_socket_xmit_one(s, buf, space, src, ep, msginfo); + return pico_socket_xmit_one(s, buf, space, src, ep); } - #endif #ifdef PICO_SUPPORT_IPFRAG @@ -1172,7 +1153,7 @@ static int pico_socket_xmit_fragments(struct pico_socket *s, const void *buf, co (void) f; (void) hdr_offset; (void) total_payload_written; - return pico_socket_xmit_one(s, buf, space, src, ep, msginfo); + return pico_socket_xmit_one(s, buf, space, src, ep); #endif } @@ -1184,7 +1165,7 @@ static void get_sock_dev(struct pico_socket *s) s->dev = pico_ipv6_source_dev_find(&s->remote_addr.ip6); else #endif - s->dev = pico_ipv4_source_dev_find(&s->remote_addr.ip4); + s->dev = pico_ipv4_source_dev_find(&s->remote_addr.ip4); } @@ -1195,7 +1176,7 @@ static uint32_t pico_socket_adapt_mss_to_proto(struct pico_socket *s, uint32_t m mss -= PICO_SIZE_IP6HDR; else #endif - mss -= PICO_SIZE_IP4HDR; + mss -= PICO_SIZE_IP4HDR; return mss; } @@ -1204,16 +1185,13 @@ uint32_t pico_socket_get_mss(struct pico_socket *s) uint32_t mss = PICO_MIN_MSS; if (!s) return mss; - if (!s->dev) get_sock_dev(s); - if (!s->dev) { mss = PICO_MIN_MSS; } else { mss = s->dev->mtu; } - return pico_socket_adapt_mss_to_proto(s, mss); } @@ -1240,8 +1218,7 @@ static int pico_socket_xmit_avail_space(struct pico_socket *s) } -static int pico_socket_xmit(struct pico_socket *s, const void *buf, const int len, void *src, - struct pico_remote_endpoint *ep, struct pico_msginfo *msginfo) +static int pico_socket_xmit(struct pico_socket *s, const void *buf, const int len, void *src, struct pico_remote_endpoint *ep) { int space = pico_socket_xmit_avail_space(s); int total_payload_written = 0; @@ -1252,7 +1229,7 @@ static int pico_socket_xmit(struct pico_socket *s, const void *buf, const int le } if ((PROTO(s) == PICO_PROTO_UDP) && (len > space)) { - return pico_socket_xmit_fragments(s, buf, len, src, ep, msginfo); + return pico_socket_xmit_fragments(s, buf, len, src, ep); } while (total_payload_written < len) { @@ -1260,7 +1237,7 @@ static int pico_socket_xmit(struct pico_socket *s, const void *buf, const int le if (chunk_len > space) chunk_len = space; - w = pico_socket_xmit_one(s, (const void *)((const uint8_t *)buf + total_payload_written), chunk_len, src, ep, msginfo); + w = pico_socket_xmit_one(s, (const void *)((const uint8_t *)buf + total_payload_written), chunk_len, src, ep); if (w <= 0) { break; } @@ -1283,8 +1260,7 @@ static void pico_socket_sendto_set_dport(struct pico_socket *s, uint16_t port) } -int MOCKABLE pico_socket_sendto_extended(struct pico_socket *s, const void *buf, const int len, - void *dst, uint16_t remote_port, struct pico_msginfo *msginfo) +int MOCKABLE pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port) { struct pico_remote_endpoint *remote_endpoint = NULL; void *src = NULL; @@ -1298,17 +1274,6 @@ int MOCKABLE pico_socket_sendto_extended(struct pico_socket *s, const void *buf, src = pico_socket_sendto_get_src(s, dst); if (!src) { -#ifdef PICO_SUPPORT_IPV6 - if((s->net->proto_number == PICO_PROTO_IPV6) - && msginfo && msginfo->dev - && pico_ipv6_is_linklocal(((struct pico_ip6 *)dst)->addr)) - { - src = &(pico_ipv6_linklocal_get(msginfo->dev)->address); - if(!src) - return -1; - } - else -#endif return -1; } @@ -1318,12 +1283,7 @@ int MOCKABLE pico_socket_sendto_extended(struct pico_socket *s, const void *buf, pico_socket_sendto_set_dport(s, remote_port); - return pico_socket_xmit(s, buf, len, src, remote_endpoint, msginfo); -} - -int MOCKABLE pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port) -{ - return pico_socket_sendto_extended(s, buf, len, dst, remote_port, NULL); + return pico_socket_xmit(s, buf, len, src, remote_endpoint); } int pico_socket_send(struct pico_socket *s, const void *buf, int len) @@ -1348,8 +1308,7 @@ int pico_socket_send(struct pico_socket *s, const void *buf, int len) return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port); } -int pico_socket_recvfrom_extended(struct pico_socket *s, void *buf, int len, void *orig, - uint16_t *remote_port, struct pico_msginfo *msginfo) +int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port) { if (!s || buf == NULL) { /* / || orig == NULL || remote_port == NULL) { */ pico_err = PICO_ERR_EINVAL; @@ -1376,7 +1335,7 @@ int pico_socket_recvfrom_extended(struct pico_socket *s, void *buf, int len, voi return -1; } - return pico_udp_recv(s, buf, (uint16_t)len, orig, remote_port, msginfo); + return pico_udp_recv(s, buf, (uint16_t)len, orig, remote_port); } #endif @@ -1397,13 +1356,6 @@ int pico_socket_recvfrom_extended(struct pico_socket *s, void *buf, int len, voi return 0; } -int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, - uint16_t *remote_port) -{ - return pico_socket_recvfrom_extended(s, buf, len, orig, remote_port, NULL); - -} - int pico_socket_recv(struct pico_socket *s, void *buf, int len) { return pico_socket_recvfrom(s, buf, len, NULL, NULL); @@ -1439,40 +1391,6 @@ int pico_socket_getname(struct pico_socket *s, void *local_addr, uint16_t *port, return 0; } -int pico_socket_getpeername(struct pico_socket *s, void *remote_addr, uint16_t *port, uint16_t *proto) -{ - if (!s || !remote_addr || !port || !proto) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) { - pico_err = PICO_ERR_ENOTCONN; - return -1; - } - - if (is_sock_ipv4(s)) { - #ifdef PICO_SUPPORT_IPV4 - struct pico_ip4 *ip = (struct pico_ip4 *)remote_addr; - ip->addr = s->remote_addr.ip4.addr; - *proto = PICO_PROTO_IPV4; - #endif - } else if (is_sock_ipv6(s)) { - #ifdef PICO_SUPPORT_IPV6 - struct pico_ip6 *ip = (struct pico_ip6 *)remote_addr; - memcpy(ip->addr, s->remote_addr.ip6.addr, PICO_SIZE_IP6); - *proto = PICO_PROTO_IPV6; - #endif - } else { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - *port = s->remote_port; - return 0; - -} - int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port) { if (!s || !local_addr || !port) { @@ -1611,7 +1529,7 @@ int pico_socket_connect(struct pico_socket *s, const void *remote_addr, uint16_t #ifdef PICO_SUPPORT_TCP if (PROTO(s) == PICO_PROTO_TCP) { if (pico_tcp_initconn(s) == 0) { - pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_SENT, PICO_SOCKET_STATE_CLOSED, 0); + pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_SENT, 0, 0); pico_err = PICO_ERR_NOERR; ret = 0; } else { @@ -1739,7 +1657,6 @@ int pico_socket_setoption(struct pico_socket *s, int option, void *value) return -1; } - if (PROTO(s) == PICO_PROTO_TCP) return pico_setsockopt_tcp(s, option, value); @@ -1834,7 +1751,6 @@ static inline int pico_transport_crc_check(struct pico_frame *f) switch (net_hdr->proto) { -#ifdef PICO_SUPPORT_TCP case PICO_PROTO_TCP: checksum_invalid = short_be(pico_tcp_checksum(f)); /* dbg("TCP CRC validation == %u\n", checksum_invalid); */ @@ -1845,9 +1761,7 @@ static inline int pico_transport_crc_check(struct pico_frame *f) } break; -#endif /* PICO_SUPPORT_TCP */ -#ifdef PICO_SUPPORT_UDP case PICO_PROTO_UDP: udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; if (short_be(udp_hdr->crc)) { @@ -1870,7 +1784,6 @@ static inline int pico_transport_crc_check(struct pico_frame *f) } break; -#endif /* PICO_SUPPORT_UDP */ default: /* Do nothing */ diff --git a/stack/pico_socket_multicast.c b/stack/pico_socket_multicast.c index f23327d6f..f57d048bb 100644 --- a/stack/pico_socket_multicast.c +++ b/stack/pico_socket_multicast.c @@ -34,7 +34,6 @@ struct pico_mcast_listen static int mcast_listen_link_cmp(struct pico_mcast_listen *a, struct pico_mcast_listen *b) { - if (a->proto < b->proto) return -1; @@ -570,7 +569,7 @@ static int mcast_so_addm(struct pico_socket *s, void *value) listen->proto = s->net->proto_number; pico_tree_insert(s->MCASTListen, listen); } - + pico_tree_insert(&MCASTSockets, s); filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr); if (filter_mode < 0) @@ -601,6 +600,7 @@ static int mcast_so_dropm(struct pico_socket *s, void *value) { source = index->keyValue; pico_tree_delete(&listen->MCASTSources, source); + PICO_FREE(source); } pico_tree_delete(s->MCASTListen, listen); PICO_FREE(listen); @@ -651,6 +651,7 @@ static int mcast_so_unblock_src(struct pico_socket *s, void *value) return -1; } else { pico_tree_delete(&listen->MCASTSources, source); + PICO_FREE(source); } } @@ -811,6 +812,7 @@ static int mcast_so_dropsrcm(struct pico_socket *s, void *value) return -1; } else { pico_tree_delete(&listen->MCASTSources, source); + PICO_FREE(source); if (pico_tree_empty(&listen->MCASTSources)) { /* 1 if empty, 0 otherwise */ reference_count = 1; pico_tree_delete(s->MCASTListen, listen); @@ -856,13 +858,13 @@ static int mcast_so_check_socket(struct pico_socket *s) pico_err = PICO_ERR_EINVAL; if (!s) return -1; - + if (!s->proto) return -1; if (s->proto->proto_number != PICO_PROTO_UDP) return -1; - + pico_err = PICO_ERR_NOERR; return 0; } @@ -874,7 +876,6 @@ int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value) pico_err = PICO_ERR_EOPNOTSUPP; return -1; } - if (mcast_so_check_socket(s) < 0) return -1; @@ -882,7 +883,7 @@ int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value) pico_err = PICO_ERR_EOPNOTSUPP; return -1; } - + return (mcast_so_calls[arrayn].call(s, value)); } @@ -911,6 +912,7 @@ int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl) return 0; } #else +/* IF MCAST build flag is not set */ int pico_udp_set_mc_ttl(struct pico_socket *s, void *_ttl) { pico_err = PICO_ERR_EPROTONOSUPPORT; @@ -950,7 +952,6 @@ int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value) (void)value; pico_err = PICO_ERR_EPROTONOSUPPORT; return -1; - } #endif /* PICO_SUPPORT_MCAST */ diff --git a/stack/pico_stack.c b/stack/pico_stack.c index 6048a238f..d17a187c0 100644 --- a/stack/pico_stack.c +++ b/stack/pico_stack.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . @@ -17,7 +17,6 @@ #include "pico_dns_client.h" #include "pico_olsr.h" -#include "pico_aodv.h" #include "pico_eth.h" #include "pico_arp.h" #include "pico_ipv4.h" @@ -54,7 +53,7 @@ volatile pico_err_t pico_err; static uint32_t _rand_seed; -void WEAK pico_rand_feed(uint32_t feed) +void pico_rand_feed(uint32_t feed) { if (!feed) return; @@ -174,6 +173,7 @@ int pico_notify_pkt_too_big(struct pico_frame *f) } + /* Transport layer */ int32_t pico_transport_receive(struct pico_frame *f, uint8_t proto) { @@ -339,7 +339,6 @@ static int32_t pico_ipv4_ethernet_receive(struct pico_frame *f) pico_frame_discard(f); return -1; } - return (int32_t)f->buffer_len; } #endif @@ -351,10 +350,10 @@ static int32_t pico_ipv6_ethernet_receive(struct pico_frame *f) pico_enqueue(pico_proto_ipv6.q_in, f); } else { /* Wrong version for link layer type */ + (void)pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_HDRFIELD, 0); pico_frame_discard(f); return -1; } - return (int32_t)f->buffer_len; } #endif @@ -365,21 +364,21 @@ static int32_t pico_ll_receive(struct pico_frame *f) f->net_hdr = f->datalink_hdr + sizeof(struct pico_eth_hdr); #if (defined PICO_SUPPORT_IPV4) && (defined PICO_SUPPORT_ETH) - if (hdr->proto == PICO_IDETH_ARP) + if (hdr->proto == PICO_IDETH_ARP) { return pico_arp_receive(f); - + } #endif #if defined (PICO_SUPPORT_IPV4) - if (hdr->proto == PICO_IDETH_IPV4) + if (hdr->proto == PICO_IDETH_IPV4) { return pico_ipv4_ethernet_receive(f); - + } #endif - + #if defined (PICO_SUPPORT_IPV6) - if (hdr->proto == PICO_IDETH_IPV6) + if (hdr->proto == PICO_IDETH_IPV6) { return pico_ipv6_ethernet_receive(f); - + } #endif pico_frame_discard(f); @@ -447,34 +446,24 @@ struct pico_eth *pico_ethernet_mcast6_translate(struct pico_frame *f, uint8_t *p } #endif -int pico_ethernet_ipv6_dst(struct pico_frame *f, struct pico_eth *const dstmac) +struct pico_eth *pico_ethernet_ipv6_dst(struct pico_frame *f) { - int retval = -1; - if (!dstmac) - return -1; - + struct pico_eth *dstmac = NULL; #ifdef PICO_SUPPORT_IPV6 if (destination_is_mcast(f)) { uint8_t pico_mcast6_mac[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; - pico_ethernet_mcast6_translate(f, pico_mcast6_mac); - memcpy(dstmac, pico_mcast6_mac, PICO_SIZE_ETH); - retval = 0; + dstmac = pico_ethernet_mcast6_translate(f, pico_mcast6_mac); } else { - struct pico_eth *neighbor = pico_ipv6_get_neighbor(f); - if (neighbor) - { - memcpy(dstmac, neighbor, PICO_SIZE_ETH); - retval = 0; - } + dstmac = pico_ipv6_get_neighbor(f); } #else (void)f; pico_err = PICO_ERR_EPROTONOSUPPORT; #endif - return retval; + return dstmac; } @@ -508,7 +497,6 @@ static int32_t pico_ethsend_bcast(struct pico_frame *f) (void)pico_device_broadcast(f); /* We can discard broadcast even if it's not sent. */ return 1; } - return 0; } @@ -535,8 +523,7 @@ static int32_t pico_ethsend_dispatch(struct pico_frame *f) int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f) { - struct pico_eth dstmac; - uint8_t dstmac_valid = 0; + const struct pico_eth *dstmac = NULL; uint16_t proto = PICO_IDETH_IPV4; #ifdef PICO_SUPPORT_IPV6 @@ -544,13 +531,11 @@ int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f) * destination address is taken from the ND tables */ if (IS_IPV6(f)) { - if (pico_ethernet_ipv6_dst(f, &dstmac) < 0) - { + dstmac = pico_ethernet_ipv6_dst(f); + if (!dstmac) { pico_ipv6_nd_postpone(f); return 0; /* I don't care if frame was actually postponed. If there is no room in the ND table, discard safely. */ } - - dstmac_valid = 1; proto = PICO_IDETH_IPV6; } else @@ -558,42 +543,32 @@ int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f) /* In case of broadcast (IPV4 only), dst mac is FF:FF:... */ if (IS_BCAST(f) || destination_is_bcast(f)) - { - memcpy(&dstmac, PICO_ETHADDR_ALL, PICO_SIZE_ETH); - dstmac_valid = 1; - } + dstmac = (const struct pico_eth *) PICO_ETHADDR_ALL; /* In case of multicast, dst mac is translated from the group address */ else if (destination_is_mcast(f)) { uint8_t pico_mcast_mac[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; - pico_ethernet_mcast_translate(f, pico_mcast_mac); - memcpy(&dstmac, pico_mcast_mac, PICO_SIZE_ETH); - dstmac_valid = 1; + dstmac = pico_ethernet_mcast_translate(f, pico_mcast_mac); } #if (defined PICO_SUPPORT_IPV4) else { - struct pico_eth *arp_get; - arp_get = pico_arp_get(f); - if (arp_get) { - memcpy(&dstmac, arp_get, PICO_SIZE_ETH); - dstmac_valid = 1; - } else { - /* At this point, ARP will discard the frame in any case. - * It is safe to return without discarding. - */ + dstmac = pico_arp_get(f); + /* At this point, ARP will discard the frame in any case. + * It is safe to return without discarding. + */ + if (!dstmac) { pico_arp_postpone(f); return 0; /* Same case as for IPv6 ... */ } - } #endif /* This sets destination and source address, then pushes the packet to the device. */ - if (dstmac_valid) { + if (dstmac) { struct pico_eth_hdr *hdr; hdr = (struct pico_eth_hdr *) f->datalink_hdr; if ((f->start > f->buffer) && ((f->start - f->buffer) >= PICO_SIZE_ETHHDR)) @@ -603,10 +578,9 @@ int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f) f->datalink_hdr = f->start; hdr = (struct pico_eth_hdr *) f->datalink_hdr; memcpy(hdr->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH); - memcpy(hdr->daddr, &dstmac, PICO_SIZE_ETH); + memcpy(hdr->daddr, dstmac, PICO_SIZE_ETH); hdr->proto = proto; } - if (pico_ethsend_local(f, hdr) || pico_ethsend_bcast(f) || pico_ethsend_dispatch(f)) { /* one of the above functions has delivered the frame accordingly. (returned != 0) * It is safe to directly return success. @@ -614,7 +588,6 @@ int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f) return 0; } } - /* Failure: do not dequeue the frame, keep it for later. */ return -1; } @@ -796,31 +769,6 @@ DECLARE_HEAP(pico_timer_ref, expire); static heap_pico_timer_ref *Timers; -int32_t pico_seq_compare(uint32_t a, uint32_t b) -{ - uint32_t thresh = ((uint32_t)(-1)) >> 1; - - if (a > b) /* return positive number, if not wrapped */ - { - if ((a - b) > thresh) /* b wrapped */ - return -(int32_t)(b - a); /* b = very small, a = very big */ - else - return (int32_t)(a - b); /* a = biggest, b = a bit smaller */ - - } - - if (a < b) /* return negative number, if not wrapped */ - { - if ((b - a) > thresh) /* a wrapped */ - return (int32_t)(a - b); /* a = very small, b = very big */ - else - return -(int32_t)(b - a); /* b = biggest, a = a bit smaller */ - - } - - return 0; -} - void pico_check_timers(void) { struct pico_timer *t; @@ -949,6 +897,41 @@ static int calc_score(int *score, int *index, int avg[][PROTO_DEF_AVG_NR], int * return 0; } + + +/* + + . + .vS. + . :iXXZUZXXe= + )2SS2SS2S2S2I =oS2S2S2S2X22;. _vuXS22S2S2S22i ._wZZXZZZXZZXZX= + )22S2S2S2S2Sl |S2S2S22S2SSSXc: .S2SS2S2S22S2SS= .]#XZZZXZXZZZZZZ: + )oSS2SS2S2Sol |2}!"""!32S22S(. uS2S2Se**12oS2e ]dXZZXX2?YYXXXZ* + .:2S2So:..-. . :]S2S2e;=X2SS2o .)oc ]XZZXZ( =nX: + .S2S22. ___s_i,.)oS2So(;2SS2So, ` 3XZZZZc, - + .S2SSo. =oXXXSSS2XoS2S2o( XS2S2XSos;. ]ZZZZXXXX|= + .S2S22. .)S2S2S22S2S2S2S2o( "X2SS2S2S2Sus,, +3XZZZZZXZZoos_ + .S2S22. .]2S2SS22S222S2SS2o( ]S22S2S2S222So :3XXZZZZZZZZXXv + .S2S22. =u2SS2e"~---"{2S2So( -"12S2S2SSS2Su. "?SXXXZXZZZZXo + .S2SSo. )SS22z; :S2S2o( ={vS2S2S22v .;:S2S2o( . + + + */ + void pico_stack_tick(void) { static int score[PROTO_DEF_NR] = { @@ -1096,9 +1079,6 @@ int pico_stack_init(void) #ifdef PICO_SUPPORT_OLSR pico_olsr_init(); #endif -#ifdef PICO_SUPPORT_AODV - pico_aodv_init(); -#endif pico_stack_tick(); pico_stack_tick(); diff --git a/stack/pico_tree.c b/stack/pico_tree.c index 76eaf2fd0..95edb75e2 100644 --- a/stack/pico_tree.c +++ b/stack/pico_tree.c @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Author: Andrei Carp diff --git a/test/autotest.sh b/test/autotest.sh index b1820084c..1b71fe544 100755 --- a/test/autotest.sh +++ b/test/autotest.sh @@ -65,23 +65,12 @@ wait || exit 1 wait killall picoapp6.elf -echo -echo -echo -echo "IPV6 FWD TCP TEST" -(./build/test/picoapp6.elf --vde pic0,/tmp/pic1.ctl,2001:aabb::2,ffff:ffff::,2001:aabb::ff,, -a tcpbench,r,6667,,) & -(./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,2001:aaaa::ff,ffff:ffff::,,, --vde pic1,/tmp/pic1.ctl,2001:aabb::ff,ffff:ffff::,,, -a noop,) & -./build/test/picoapp6.elf --vde pic0,/tmp/pic0.ctl,2001:aaaa::1,ffff:ffff::,2001:aaaa::ff,, -a tcpbench,t,2001:aabb::2,6667,, || exit 1 -sleep 2 -killall picoapp6.elf - - echo "MULTICAST TEST" -(./build/test/picoapp.elf --vde pic1:/tmp/pic0.ctl:10.40.0.3:255.255.0.0: -a mcastreceive:10.40.0.3:224.7.7.7:6667:6667:) & -(./build/test/picoapp.elf --vde pic2:/tmp/pic0.ctl:10.40.0.4:255.255.0.0: -a mcastreceive:10.40.0.4:224.7.7.7:6667:6667:) & -(./build/test/picoapp.elf --vde pic3:/tmp/pic0.ctl:10.40.0.5:255.255.0.0: -a mcastreceive:10.40.0.5:224.7.7.7:6667:6667:) & +(./build/test/picoapp.elf --vde pic1:/tmp/pic0.ctl:10.40.0.3:255.255.0.0: -a mcastreceive:10.40.0.3:224.7.7.7:6667:6667) & +(./build/test/picoapp.elf --vde pic2:/tmp/pic0.ctl:10.40.0.4:255.255.0.0: -a mcastreceive:10.40.0.4:224.7.7.7:6667:6667) & +(./build/test/picoapp.elf --vde pic3:/tmp/pic0.ctl:10.40.0.5:255.255.0.0: -a mcastreceive:10.40.0.5:224.7.7.7:6667:6667) & sleep 2 -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0: -a mcastsend:10.40.0.2:224.7.7.7:6667:6667: || exit 1 +./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0: -a mcastsend:10.40.0.2:224.7.7.7:6667:6667 || exit 1 (wait && wait && wait) || exit 1 echo @@ -122,40 +111,40 @@ time (./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: killall picoapp.elf echo "UDP TEST" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0::: -a udpecho:10.40.0.8:6667:) & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a udpclient:10.40.0.8:6667:6667:1400:100:10: || exit 1 +(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0::: -a udpecho:10.40.0.8:6667) & +./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a udpclient:10.40.0.8:6667:6667:1400:100:10 || exit 1 wait || exit 1 wait echo "UDP TEST with fragmentation" -(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0::: -a udpecho:10.40.0.8:6667:) & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a udpclient:10.40.0.8:6667:6667:4500:100:10: || exit 1 +(./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.8:255.255.0.0::: -a udpecho:10.40.0.8:6667) & +./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0::: -a udpclient:10.40.0.8:6667:6667:4500:100:10 || exit 1 wait || exit 1 wait echo "NAT TCP TEST" (./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.10:255.255.0.0::: --vde pic1:/tmp/pic1.ctl:10.50.0.10:255.255.0.0: -a natbox:10.50.0.10) & sleep 2 -(./build/test/picoapp.elf --vde pic0:/tmp/pic1.ctl:10.50.0.8:255.255.0.0::: -a tcpbench:r:6667:) & +(./build/test/picoapp.elf --vde pic0:/tmp/pic1.ctl:10.50.0.8:255.255.0.0::: -a tcpbench:r:6667) & sleep 2 ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0:10.40.0.10::: -a tcpbench:t:10.50.0.8:6667: || exit 1 killall picoapp.elf echo "NAT UDP TEST" (./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.10:255.255.0.0::: --vde pic1:/tmp/pic1.ctl:10.50.0.10:255.255.0.0::: -a natbox:10.50.0.10) & -(./build/test/picoapp.elf --vde pic0:/tmp/pic1.ctl:10.50.0.8:255.255.0.0::: -a udpecho:10.50.0.8:6667:) & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0:10.40.0.10::: -a udpclient:10.50.0.8:6667:6667:1400:100:10: || exit 1 +(./build/test/picoapp.elf --vde pic0:/tmp/pic1.ctl:10.50.0.8:255.255.0.0::: -a udpecho:10.50.0.8:6667) & +./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.9:255.255.0.0:10.40.0.10::: -a udpclient:10.50.0.8:6667:6667:1400:100:10 || exit 1 #sometimes udpecho finishes before reaching wait %2 #wait %2 killall picoapp.elf echo "MULTICAST TEST" -(./build/test/picoapp.elf --vde pic1:/tmp/pic0.ctl:10.40.0.3:255.255.0.0::: -a mcastreceive:10.40.0.3:224.7.7.7:6667:6667:) & -(./build/test/picoapp.elf --vde pic2:/tmp/pic0.ctl:10.40.0.4:255.255.0.0::: -a mcastreceive:10.40.0.4:224.7.7.7:6667:6667:) & -(./build/test/picoapp.elf --vde pic3:/tmp/pic0.ctl:10.40.0.5:255.255.0.0::: -a mcastreceive:10.40.0.5:224.7.7.7:6667:6667:) & +(./build/test/picoapp.elf --vde pic1:/tmp/pic0.ctl:10.40.0.3:255.255.0.0::: -a mcastreceive:10.40.0.3:224.7.7.7:6667:6667) & +(./build/test/picoapp.elf --vde pic2:/tmp/pic0.ctl:10.40.0.4:255.255.0.0::: -a mcastreceive:10.40.0.4:224.7.7.7:6667:6667) & +(./build/test/picoapp.elf --vde pic3:/tmp/pic0.ctl:10.40.0.5:255.255.0.0::: -a mcastreceive:10.40.0.5:224.7.7.7:6667:6667) & sleep 2 -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0::: -a mcastsend:10.40.0.2:224.7.7.7:6667:6667: || exit 1 +./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0::: -a mcastsend:10.40.0.2:224.7.7.7:6667:6667 || exit 1 (wait && wait && wait) || exit 1 killall picoapp.elf @@ -168,7 +157,7 @@ killall picoapp.elf echo "DHCP DUAL TEST" (./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0::: -a dhcpserver:pic0:10.40.0.2:255.255.255.0:64:128:) & (./build/test/picoapp.elf --vde pic1:/tmp/pic1.ctl:10.50.0.2:255.255.0.0::: -a dhcpserver:pic1:10.50.0.2:255.255.255.0:64:128:) & -./build/test/picoapp.elf --barevde pic0:/tmp/pic0.ctl: --barevde pic1:/tmp/pic1.ctl: -a dhcpclient:pic0:pic1: || exit 1 +./build/test/picoapp.elf --barevde pic0:/tmp/pic0.ctl: --barevde pic1:/tmp/pic1.ctl: -a dhcpclient:pic0:pic1 || exit 1 killall picoapp.elf #TO DO: the ping address 169.254.22.5 is hardcoded in the slaacv4 test. Nice to pass that by parameter @@ -180,7 +169,7 @@ killall picoapp.elf ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0:10.40.0.1::: -a udpdnsclient:www.google.be:173.194.67.94:: & ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.0.0:10.40.0.1::: -a udpdnsclient:ipv6.google.be:doesntmatter:ipv6: & -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.0.0:10.50.0.1::: -a sntp:ntp.nasa.gov: & +./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.0.0:10.50.0.1::: -a sntp:ntp.nasa.gov & sleep 20 killall picoapp.elf @@ -210,10 +199,10 @@ pushd $TFTP_WORK_DIR echo "TFTP GET TEST" tftp_setup $TFTP_WORK_DIR -(${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.255.0:10.50.0.1: --app tftp:S:) & +(${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.255.0:10.50.0.1: --app tftp:S) & cd $TFTP_WORK_SUBDIR sleep 2 -${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.3:255.255.255.0:10.50.0.1: --app tftp:R:${TFTP_WORK_FILE}:10.50.0.2: || tftp_cleanup 1 +${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.3:255.255.255.0:10.50.0.1: --app tftp:R:${TFTP_WORK_FILE}:10.50.0.2 || tftp_cleanup 1 sleep 3 killall picoapp.elf @@ -222,11 +211,11 @@ sleep 1 rm $TFTP_WORK_FILE echo "TFTP PUT TEST" -(${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.255.0:10.50.0.1: --app tftp:S:) & +(${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.255.0:10.50.0.1: --app tftp:S) & cd $TFTP_WORK_DIR tftp_setup $TFTP_WORK_DIR sleep 2 -${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.3:255.255.255.0:10.50.0.1: --app tftp:T:${TFTP_WORK_FILE}:10.50.0.2: || tftp_cleanup 1 +${TFTP_EXEC_DIR}/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.3:255.255.255.0:10.50.0.1: --app tftp:T:${TFTP_WORK_FILE}:10.50.0.2 || tftp_cleanup 1 sleep 3 tftp_cleanup diff --git a/test/examples/Makefile b/test/examples/Makefile index 597ca9495..72f1fb3d5 100644 --- a/test/examples/Makefile +++ b/test/examples/Makefile @@ -10,6 +10,7 @@ $(PREFIX)/examples/%.o: %.c OBJS:= \ $(PREFIX)/examples/dhcp_client.o \ $(PREFIX)/examples/dhcp_server.o \ +$(PREFIX)/examples/dns_sd.o \ $(PREFIX)/examples/dnsclient.o \ $(PREFIX)/examples/mdns.o \ $(PREFIX)/examples/multicast_recv.o \ @@ -27,7 +28,6 @@ $(PREFIX)/examples/udp_client.o \ $(PREFIX)/examples/udp_echo.o \ $(PREFIX)/examples/udpnat.o \ $(PREFIX)/examples/udp_sendto_test.o \ -$(PREFIX)/examples/iperfc.o \ all: $(OBJS) diff --git a/test/examples/dhcp_client.c b/test/examples/dhcp_client.c index dbce4dd4a..e4d6a5029 100644 --- a/test/examples/dhcp_client.c +++ b/test/examples/dhcp_client.c @@ -15,8 +15,8 @@ void ping_callback_dhcpclient(struct pico_icmp4_stats *s) pico_ipv4_to_string(host, s->dst.addr); if (s->err == 0) { - dbg("DHCP client: %lu bytes from %s: icmp_req=%lu ttl=64 time=%lu ms\n", - s->size, host, s->seq, (long unsigned int)s->time); + dbg("DHCP client: %lu bytes from %s: icmp_req=%lu ttl=64 time=%lu ms\n", + s->size, host, s->seq, (long unsigned int)s->time); if (s->seq >= 3) { dbg("DHCP client: TEST SUCCESS!\n"); if (--dhcpclient_devices <= 0) diff --git a/test/examples/dns_sd.c b/test/examples/dns_sd.c new file mode 100644 index 000000000..3e8479a8a --- /dev/null +++ b/test/examples/dns_sd.c @@ -0,0 +1,110 @@ +#include "utils.h" +#include +#include +#include + +/*** START DNS_SD ***/ +#ifdef PICO_SUPPORT_DNS_SD + +#define TTL 30 + +static char *service_name = NULL; + +void dns_sd_claimed_callback( pico_mdns_record_vector *vector, + char *str, + void *arg ) +{ + struct pico_mdns_record *record = NULL; + char *service_url = NULL; + char *service_name = NULL; + + IGNORE_PARAMETER(str); + IGNORE_PARAMETER(arg); + + /* Get the registered service name from the first claimed record */ + record = pico_mdns_record_vector_get(vector, 0); + service_name= (char*)(record->record->rdata); + + /* Provide some space for the service instance name */ + service_url = PICO_ZALLOC((size_t)(*service_name + 1)); + if (!service_url) { + pico_err = PICO_ERR_ENOMEM; + return; + } + + /* Copy the service instance name */ + memcpy(service_url, service_name + 1, (size_t) *service_name); + + /* Append zero byte */ + service_url[(int)*service_name] = '\0'; + + printf("Service registered: %s\n", service_url); +} + +void dns_sd_init_callback( pico_mdns_record_vector *vector, + char *str, + void *arg ) +{ + kv_vector key_value_pair_vector = {0}; + + IGNORE_PARAMETER(str); + IGNORE_PARAMETER(arg); + IGNORE_PARAMETER(vector); + + printf("DONE - Initialising DNS Service Discovery module.\n"); + + pico_dns_sd_kv_vector_add(&key_value_pair_vector, "textvers", "1"); + pico_dns_sd_kv_vector_add(&key_value_pair_vector, "auth", NULL); + pico_dns_sd_kv_vector_add(&key_value_pair_vector, "pass", ""); + + if (pico_dns_sd_register_service(service_name, + "_http._tcp", 80, + &key_value_pair_vector, + TTL, dns_sd_claimed_callback, NULL) < 0) { + printf("Registering service failed!\n"); + } +} + +void app_dns_sd(char *arg, struct pico_ipv4_link *link) +{ + char *hostname, *service_type, *service_port; + char *nxt = arg; + struct pico_ip6 ipaddr6 = {{0}}; + + if (!nxt) + exit(255); + + nxt = cpy_arg(&hostname, nxt); + if(!hostname) { + exit(255); + } + + if(!nxt) { + printf("Not enough args supplied!\n"); + exit(255); + } + + nxt = cpy_arg(&service_name, nxt); + if(!service_name) { + exit(255); + } + + if (!link) { + printf("Link not found!\n"); + exit(255); + } + + printf("\nStarting DNS Service Discovery module...\n"); + if (pico_dns_sd_init(hostname, link, 0, &dns_sd_init_callback, NULL) != 0) { + printf("Initialisation returned with Error!\n"); + exit(255); + } + + while(1) { + pico_stack_tick(); + usleep(2000); + } +} + +#endif +/*** END DNS_SD ***/ \ No newline at end of file diff --git a/test/examples/iperfc.c b/test/examples/iperfc.c deleted file mode 100644 index 7fce7ebb2..000000000 --- a/test/examples/iperfc.c +++ /dev/null @@ -1,135 +0,0 @@ -#include -#include -#include -#include "pico_stack.h" -#include "pico_socket.h" - -#define DURATION 30 - -struct iperf_hdr { - int32_t flags; /* 0 */ - int32_t numThreads; /* 1 */ - int32_t mPort; /* 5001 */ - int32_t bufferlen; /* 0 */ - int32_t mWinBand; /* 0 */ - int32_t mAmount; /* 0xfffffc18 */ -}; - -#define IPERF_PORT 5001 -#define MTU 1444 -#define SEND_BUF_SIZ (1024 * 2048) - -char *cpy_arg(char **dst, char *str); -extern int IPV6_MODE; -void deferred_exit(pico_time now, void *arg); - -static pico_time deadline; - -static void panic(void) -{ - for(;; ) ; -} - -static char buf[MTU] = {}; - -static void buf_paint(void) -{ - char paint[11] = "0123456789"; - int i; - for (i = 0; i < MTU; i++) { - buf[i] = paint[i % 10]; - } -} - -static void send_hdr(struct pico_socket *s) -{ - struct iperf_hdr hdr = {}; - hdr.numThreads = long_be(1); - hdr.mPort = long_be(5001); - hdr.mAmount = long_be(0xfffffc18); - pico_socket_write(s, &hdr, sizeof(hdr)); - deadline = PICO_TIME_MS() + DURATION * 1000; -} - -static void iperf_cb(uint16_t ev, struct pico_socket *s) -{ - int r; - static int end = 0; - if (ev & PICO_SOCK_EV_CONN) { - send_hdr(s); - return; - } - - if ((!end) && (ev & PICO_SOCK_EV_WR)) { - if (PICO_TIME_MS() > deadline) { - pico_socket_close(s); - pico_timer_add(2000, deferred_exit, NULL); - end++; - } - - pico_socket_write(s, buf, MTU); - } - - if (!(end) && (ev & (PICO_SOCK_EV_FIN | PICO_SOCK_EV_CLOSE))) { - pico_timer_add(2000, deferred_exit, NULL); - end++; - } -} - -static void iperfc_socket_setup(union pico_address *addr, uint16_t family) -{ - int yes = 1; - uint16_t send_port = 0; - struct pico_socket *s = NULL; - uint32_t bufsize = SEND_BUF_SIZ; - send_port = short_be(5001); - s = pico_socket_open(family, PICO_PROTO_TCP, &iperf_cb); - pico_socket_setoption(s, PICO_SOCKET_OPT_SNDBUF, &bufsize); - pico_socket_connect(s, addr, send_port); -} - -void app_iperfc(char *arg) -{ - struct pico_ip4 my_eth_addr, netmask; - struct pico_device *pico_dev_eth; - char *daddr = NULL, *dport = NULL; - char *nxt = arg; - uint16_t send_port = 0, listen_port = short_be(5001); - int i = 0, ret = 0, yes = 1; - struct pico_socket *s = NULL; - uint16_t family = PICO_PROTO_IPV4; - union pico_address dst = { - .ip4 = {0}, .ip6 = {{0}} - }; - union pico_address inaddr_any = { - .ip4 = {0}, .ip6 = {{0}} - }; - - /* start of argument parsing */ - if (nxt) { - nxt = cpy_arg(&daddr, arg); - if (daddr) { - if (!IPV6_MODE) - pico_string_to_ipv4(daddr, &dst.ip4.addr); - - #ifdef PICO_SUPPORT_IPV6 - else { - pico_string_to_ipv6(daddr, dst.ip6.addr); - family = PICO_PROTO_IPV6; - } - #endif - } else { - goto out; - } - } else { - /* missing dest_addr */ - goto out; - } - - iperfc_socket_setup(&dst, family); - return; -out: - dbg("Error parsing options!\n"); - exit(1); -} - diff --git a/test/examples/mdns.c b/test/examples/mdns.c index d59c534cb..acac67891 100644 --- a/test/examples/mdns.c +++ b/test/examples/mdns.c @@ -1,79 +1,74 @@ #include "utils.h" +#include #include +#include +#include /*** START MDNS ***/ #ifdef PICO_SUPPORT_MDNS -void mdns_getname6_callback(char *str, void *arg) +void mdns_getrecord_callback( pico_mdns_record_vector *vector, + char *str, + void *arg ) { - (void) arg; - if (!str) - printf("Getname6: timeout occurred!\n"); - else - printf("Getname6 callback called, str: %s\n", str); - - exit(0); + if (!vector) { + printf("Returned NULL-ptr!\n"); + return; + } + if (pico_mdns_record_vector_count(vector) > 0) { + printf("Get record succeeded!\n"); + } else { + printf("No records found!\n"); + } } -void mdns_getaddr6_callback(char *str, void *arg) +void mdns_claimed_callback( pico_mdns_record_vector *vector, + char *str, + void *arg ) { - (void) arg; - if (!str) - printf("Getaddr6: timeout occurred!\n"); - else - printf("Getaddr6 callback called, str: %s\n", str); - - if(pico_mdns_getname6(str, &mdns_getname6_callback, NULL) != 0) - printf("Getname6 returned with error!\n"); + printf("Claimed records\n"); } -void mdns_getname_callback(char *str, void *arg) +void mdns_init_callback( pico_mdns_record_vector *vector, + char *str, + void *arg ) { - char *peername = (char *)arg; - if(!peername) { - printf("No system name supplied!\n"); - exit(-1); - } + pico_mdns_record_vector rvector = { 0 }; + struct pico_mdns_record *hostname_record = NULL; + struct pico_mdns_record *test = NULL; + char *hostname = NULL; + char *name = "_http._tcp.local"; + char *pointer = "jelle._http._tcp.local"; + struct pico_ip4 ip = {0xFFFF00FF}; - if (!str) - printf("Getname: timeout occurred!\n"); - else - printf("Getname callback called, str: %s\n", str); + /* Get the first record in the vector */ + hostname_record = pico_mdns_record_vector_get(vector, 0); - if(pico_mdns_getaddr6(peername, &mdns_getaddr6_callback, NULL) != 0) - printf("Getaddr6 returned with error!\n"); -} + /* Convert the rname to an URL */ + hostname = pico_dns_qname_to_url(hostname_record->record->rname); -void mdns_getaddr_callback(char *str, void *arg) -{ - if (!str) - printf("Getaddr: timeout occurred!\n"); - else - printf("Getaddr callback called, str: %s\n", str); + printf("Initialised with hostname: %s\n", hostname); - if(pico_mdns_getname(str, &mdns_getname_callback, arg) != 0) - printf("Getname returned with error!\n"); -} + test = pico_mdns_record_create(name, pointer, strlen(pointer), + PICO_DNS_TYPE_PTR, 120, + PICO_MDNS_RECORD_SHARED); -void mdns_init_callback(char *str, void *arg) -{ - char *peername = (char *)arg; - printf("Init callback called, str: %s\n", str); - if(!peername) { - printf("No system name supplied!\n"); - exit(-1); - } + pico_mdns_record_vector_add(&rvector, test); + pico_mdns_claim(rvector, mdns_claimed_callback, NULL); + + pico_mdns_getrecord("_http._tcp.local", PICO_DNS_TYPE_PTR, + mdns_getrecord_callback, NULL); - if(pico_mdns_getaddr(peername, &mdns_getaddr_callback, peername) != 0) - printf("Getaddr returned with error!\n"); + PICO_FREE(hostname); } -void app_mdns(char *arg) +void app_mdns(char *arg, struct pico_ipv4_link *link) { char *hostname, *peername; char *nxt = arg; - + struct pico_ip6 ipaddr6 = {{0}}; + if (!nxt) exit(255); @@ -91,11 +86,19 @@ void app_mdns(char *arg) if(!peername) { exit(255); } - - printf("Starting to claim name: %s, system name: %s\n", hostname, peername); - if(pico_mdns_init(hostname, &mdns_init_callback, peername) != 0) - printf("Init returned with error\n"); - + + if (!link) { + printf("Link not found!\n"); + exit(255); + } + + printf("\nStarting mDNS module...\n"); + if (pico_mdns_init(hostname, link, 0, &mdns_init_callback, peername) != 0) { + printf("Initialisation returned with Error!\n"); + exit(255); + } + printf("DONE - Initialising mDNS module.\n"); + while(1) { pico_stack_tick(); usleep(2000); diff --git a/test/examples/multicast_recv.c b/test/examples/multicast_recv.c index 2d97badde..c6dcf8f4d 100644 --- a/test/examples/multicast_recv.c +++ b/test/examples/multicast_recv.c @@ -83,13 +83,13 @@ void app_mcastreceive(char *arg) printf("\n%s: multicast receive started. Receiving packets on %s:%d\n\n", __FUNCTION__, maddr, short_be(listen_port)); /* udpecho:bind_addr:listen_port[:sendto_port:datasize] */ - new_arg = calloc(1, strlen(laddr) + 1 + strlen(lport) + 1 + strlen(sport) + strlen(":64:") + 1); + new_arg = calloc(1, strlen(laddr) + 1 + strlen(lport) + 1 + strlen(sport) + strlen(":64") + 1); p = strcat(new_arg, laddr); p = strcat(p + strlen(laddr), ":"); p = strcat(p + 1, lport); p = strcat(p + strlen(lport), ":"); p = strcat(p + 1, sport); - p = strcat(p + strlen(sport), ":64:"); + p = strcat(p + strlen(sport), ":64"); app_udpecho(new_arg); diff --git a/test/examples/multicast_send.c b/test/examples/multicast_send.c index a703823c4..0d2ce7c34 100644 --- a/test/examples/multicast_send.c +++ b/test/examples/multicast_send.c @@ -80,13 +80,13 @@ void app_mcastsend(char *arg) picoapp_dbg("\n%s: mcastsend started. Sending packets to %08X:%u\n\n", __FUNCTION__, long_be(inaddr_mcast.addr), short_be(sendto_port)); /* udpclient:dest_addr:sendto_port[:listen_port:datasize:loops:subloops] */ - new_arg = calloc(1, strlen(maddr) + 1 + strlen(sport) + 1 + strlen(lport) + strlen(":64:10:5:") + 1); + new_arg = calloc(1, strlen(maddr) + 1 + strlen(sport) + 1 + strlen(lport) + strlen(":64:10:5") + 1); p = strcat(new_arg, maddr); p = strcat(p + strlen(maddr), ":"); p = strcat(p + 1, sport); p = strcat(p + strlen(sport), ":"); p = strcat(p + 1, lport); - p = strcat(p + strlen(lport), ":64:10:5:"); + p = strcat(p + strlen(lport), ":64:10:5"); app_udpclient(new_arg); diff --git a/test/examples/ping.c b/test/examples/ping.c index 793104cb4..4608e8de4 100644 --- a/test/examples/ping.c +++ b/test/examples/ping.c @@ -11,7 +11,7 @@ void cb_ping(struct pico_icmp4_stats *s) pico_ipv4_to_string(host, s->dst.addr); if (s->err == 0) { dbg("%lu bytes from %s: icmp_req=%lu ttl=%lu time=%lu ms\n", s->size, host, s->seq, - s->ttl, (long unsigned int)s->time); + s->ttl, (long unsigned int)s->time); if (s->seq >= NUM_PING) exit(0); } else { @@ -27,7 +27,7 @@ void cb_ping6(struct pico_icmp6_stats *s) pico_ipv6_to_string(host, s->dst.addr); if (s->err == 0) { dbg("%lu bytes from %s: icmp_req=%lu ttl=%lu time=%lu ms\n", s->size, host, s->seq, - s->ttl, (long unsigned int)s->time); + s->ttl, (long unsigned int)s->time); if (s->seq >= NUM_PING) exit(0); } else { @@ -81,7 +81,7 @@ void app_ping(char *arg) #ifdef PICO_SUPPORT_IPV6 else - id = pico_icmp6_ping(dest, NUM_PING, 1000, 10000, 64, cb_ping6, NULL); + id = pico_icmp6_ping(dest, NUM_PING, 1000, 10000, 64, cb_ping6); #endif if (timeout > 0) { printf("Adding abort timer after %d seconds for id %d\n", timeout, id); diff --git a/test/examples/slaacv4.c b/test/examples/slaacv4.c index 8a7c64db9..dbad01cc0 100644 --- a/test/examples/slaacv4.c +++ b/test/examples/slaacv4.c @@ -10,7 +10,7 @@ void ping_callback_slaacv4(struct pico_icmp4_stats *s) pico_ipv4_to_string(host, s->dst.addr); if (s->err == 0) { dbg("SLAACV4: %lu bytes from %s: icmp_req=%lu ttl=64 time=%lu ms\n", s->size, host, - s->seq, (long unsigned int)s->time); + s->seq, (long unsigned int)s->time); if (s->seq >= 3) { dbg("SLAACV4: TEST SUCCESS!\n"); pico_slaacv4_unregisterip(); diff --git a/test/examples/tftp.c b/test/examples/tftp.c index abadedc49..c4603dc9a 100644 --- a/test/examples/tftp.c +++ b/test/examples/tftp.c @@ -11,7 +11,7 @@ /* Let's use linux fs */ #include -#include +#include /*** START TFTP ***/ #ifdef PICO_SUPPORT_TFTP @@ -40,7 +40,7 @@ struct note_t { struct note_t *clipboard = NULL; -struct note_t *add_note(const char *filename, int fd, char direction) +struct note_t * add_note(const char *filename, int fd, char direction) { struct note_t *note = PICO_ZALLOC(sizeof(struct note_t)); @@ -65,12 +65,13 @@ void del_note(struct note_t *note) prev->next = note->next; break; } - - } + } + free(note->filename); + free(note); } -struct command_t *add_command(struct command_t *commands, char operation, - char *filename, union pico_address *server_address) +struct command_t * add_command(struct command_t * commands, char operation, + char *filename, union pico_address *server_address) { struct command_t *command = PICO_ZALLOC(sizeof(struct command_t)); @@ -89,22 +90,20 @@ int32_t get_filesize(const char *filename) ret = stat(filename, &buf); if (ret) return -1; - return buf.st_size; } -struct note_t *setup_transfer(char operation, const char *filename) +struct note_t * setup_transfer(char operation, const char *filename) { int fd; printf("operation %c\n", operation); - fd = open(filename, (toupper(operation) == 'T') ? O_RDONLY : O_WRONLY | O_EXCL | O_CREAT, 0666); + fd = open(filename, (toupper(operation) == 'T')? O_RDONLY: O_WRONLY | O_EXCL | O_CREAT, 0666); if (fd < 0) { perror("open"); fprintf(stderr, "Unable to handle file %s\n", filename); return NULL; } - return add_note(filename, fd, operation); } @@ -151,7 +150,6 @@ int cb_tftp_tx_opt(struct pico_tftp_session *session, uint16_t event, uint8_t *b printf("TFTP: Option filesize is not used\n"); else printf("TFTP: We expect to transmit %" PRId32 " bytes\n", filesize); - event = PICO_TFTP_EV_OK; } @@ -168,9 +166,6 @@ int cb_tftp_rx(struct pico_tftp_session *session, uint16_t event, uint8_t *block exit(1); } - if (!note) - return 0; - note->filesize += len; if (write(note->fd, block, len) < 0) { perror("write"); @@ -209,20 +204,19 @@ int cb_tftp_rx_opt(struct pico_tftp_session *session, uint16_t event, uint8_t *b return cb_tftp_rx(session, event, block, len, arg); } -struct pico_tftp_session *make_session_or_die(union pico_address *addr, uint16_t family) +struct pico_tftp_session * make_session_or_die(union pico_address *addr, uint16_t family) { - struct pico_tftp_session *session; + struct pico_tftp_session * session; session = pico_tftp_session_setup(addr, family); if (!session) { fprintf(stderr, "TFTP: Error in session setup\n"); exit(3); } - return session; } -struct note_t *transfer_prepare(struct pico_tftp_session **psession, char operation, const char *filename, union pico_address *addr, uint16_t family) +struct note_t * transfer_prepare(struct pico_tftp_session ** psession, char operation, const char *filename, union pico_address *addr, uint16_t family) { struct note_t *note; @@ -232,8 +226,8 @@ struct note_t *transfer_prepare(struct pico_tftp_session **psession, char operat } void start_rx(struct pico_tftp_session *session, const char *filename, uint16_t port, - int (*rx_callback)(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg), - struct note_t *note) + int (*rx_callback)(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg), + struct note_t *note) { if (pico_tftp_start_rx(session, port, filename, rx_callback, note)) { fprintf(stderr, "TFTP: Error in initialization\n"); @@ -242,8 +236,8 @@ void start_rx(struct pico_tftp_session *session, const char *filename, uint16_t } void start_tx(struct pico_tftp_session *session, const char *filename, uint16_t port, - int (*tx_callback)(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg), - struct note_t *note) + int (*tx_callback)(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg), + struct note_t *note) { if (pico_tftp_start_tx(session, port, filename, tx_callback, note)) { fprintf(stderr, "TFTP: Error in initialization\n"); @@ -289,14 +283,12 @@ void tftp_listen_cb_opt(union pico_address *addr, uint16_t port, uint16_t opcode if (options & PICO_TFTP_OPTION_TIME) pico_tftp_set_option(session, PICO_TFTP_OPTION_TIME, timeout); - if (options & PICO_TFTP_OPTION_FILE) { ret = get_filesize(filename); if (ret < 0) { pico_tftp_reject_request(addr, port, TFTP_ERR_ENOENT, "File not found"); return; } - pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, ret); } @@ -307,7 +299,6 @@ void tftp_listen_cb_opt(union pico_address *addr, uint16_t port, uint16_t opcode note = transfer_prepare(&session, 'R', filename, addr, family); if (options & PICO_TFTP_OPTION_TIME) pico_tftp_set_option(session, PICO_TFTP_OPTION_TIME, timeout); - if (options & PICO_TFTP_OPTION_FILE) pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, filesize); @@ -318,19 +309,19 @@ void tftp_listen_cb_opt(union pico_address *addr, uint16_t port, uint16_t opcode void print_usage(int exit_code) { printf("\nUsage: tftp:OPTION:[OPTION]...\n" - "\nOtions can be repeated. Every option may be one of the following:\n" - "\ts\t\t\t starts the basic server (RFC1350)\n" - "\tS\t\t\t starts the server with option handling capability\n" - "\tt:file:ip\t\t PUT request (without options) for file to server ip\n" - "\tT:file:ip\t\t PUT request for file to server ip\n" - "\tr:file:ip\t\t GET request (without options) for file to server ip\n" - "\tR:file:ip\t\t GET request for file to server ip\n" - "Example:\n" - "\t\t tftp:S:T:firstFile:10.40.0.2:R:another.file:10.40.0.5:T:secondFile:10.40.0.2\n\n"); + "\nOtions can be repeated. Every option may be one of the following:\n" + "\ts\t\t\t starts the basic server (RFC1350)\n" + "\tS\t\t\t starts the server with option handling capability\n" + "\tt:file:ip\t\t PUT request (without options) for file to server ip\n" + "\tT:file:ip\t\t PUT request for file to server ip\n" + "\tr:file:ip\t\t GET request (without options) for file to server ip\n" + "\tR:file:ip\t\t GET request for file to server ip\n" + "Example:\n" + "\t\t tftp:S:T:firstFile:10.40.0.2:R:another.file:10.40.0.5:T:secondFile:10.40.0.2\n\n"); exit(exit_code); } -struct command_t *parse_arguments_recursive(struct command_t *commands, char *arg) +struct command_t * parse_arguments_recursive(struct command_t *commands, char *arg) { char *next; char *operation; @@ -356,13 +347,11 @@ struct command_t *parse_arguments_recursive(struct command_t *commands, char *ar fprintf(stderr, "Incomplete client command %s (filename componet is missing)\n", arg); return NULL; } - next = cpy_arg(&filename, next); if (!next) { fprintf(stderr, "Incomplete client command %s (address component is missing)\n", arg); return NULL; } - next = cpy_arg(&address, next); if (!IPV6_MODE) ret = pico_string_to_ipv4(address, &remote_address.ip4.addr); @@ -370,10 +359,9 @@ struct command_t *parse_arguments_recursive(struct command_t *commands, char *ar ret = pico_string_to_ipv6(address, remote_address.ip6.addr); if (ret < 0) { - fprintf(stderr, "Invalid IP address %s\n", address); - print_usage(2); - } - + fprintf(stderr, "Invalid IP address %s\n", address); + print_usage(2); + } break; default: fprintf(stderr, "Invalid command %s\n", operation); @@ -383,7 +371,7 @@ struct command_t *parse_arguments_recursive(struct command_t *commands, char *ar return parse_arguments_recursive(add_command(commands, *operation, filename, &remote_address), next); } -struct command_t *parse_arguments(char *arg) +struct command_t * parse_arguments(char *arg) { struct command_t *reversed = parse_arguments_recursive(NULL, arg); struct command_t *commands = NULL; @@ -400,6 +388,7 @@ struct command_t *parse_arguments(char *arg) current->next = commands; commands = current; } + return commands; } @@ -411,7 +400,7 @@ void app_tftp(char *arg) int is_server_enabled = 0; int filesize; - family = IPV6_MODE ? PICO_PROTO_IPV6 : PICO_PROTO_IPV4; + family = IPV6_MODE? PICO_PROTO_IPV6: PICO_PROTO_IPV4; commands = parse_arguments(arg); while (commands) { @@ -426,7 +415,6 @@ void app_tftp(char *arg) pico_tftp_listen(PICO_PROTO_IPV4, (commands->operation == 'S') ? tftp_listen_cb_opt : tftp_listen_cb); is_server_enabled = 1; } - break; case 'T': filesize = get_filesize(commands->filename); @@ -434,7 +422,6 @@ void app_tftp(char *arg) fprintf(stderr, "TFTP: unable to read size of file %s\n", commands->filename); exit(3); } - pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, filesize); start_tx(session, commands->filename, short_be(PICO_TFTP_PORT), cb_tftp_tx_opt, note); break; diff --git a/test/examples/udp_sendto_test.c b/test/examples/udp_sendto_test.c index 78471e68a..5ed1a9fd5 100644 --- a/test/examples/udp_sendto_test.c +++ b/test/examples/udp_sendto_test.c @@ -29,7 +29,7 @@ void app_sendto_test(char *arg) uint16_t dport; struct pico_socket *sock; int ret; - + /* start of argument parsing */ if (nxt) { nxt = cpy_arg(&dstaddr, nxt); @@ -48,7 +48,7 @@ void app_sendto_test(char *arg) /* missing bind_addr */ goto out; } - + if (nxt) { nxt = cpy_arg(&dstport, nxt); if (dstport && atoi(dstport)) { @@ -60,27 +60,27 @@ void app_sendto_test(char *arg) /* missing listen_port */ goto out; } - + if (!IPV6_MODE) sock = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &dummy_cb); else sock = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_UDP, &dummy_cb); - - ret = pico_socket_sendto(sock, "Testing", 7u, ((IPV6_MODE) ? (void *)(&inaddr_dst6) : (void *)(&inaddr_dst)), dport); + + ret = pico_socket_sendto(sock, "Testing", 7u, IPV6_MODE? &inaddr_dst6: &inaddr_dst, dport); if (ret < 0) printf("Failure in first pico_socket_send\n"); - - ret = pico_socket_sendto(sock, "Testing", 7u, ((IPV6_MODE) ? (void *)(&inaddr_dst6) : (void *)(&inaddr_dst)), dport); + + ret = pico_socket_sendto(sock, "Testing", 7u, IPV6_MODE? &inaddr_dst6: &inaddr_dst, dport); if (ret < 0) printf("Failure in second pico_socket_send\n"); - + ret = pico_socket_close(sock); if (ret) printf("Failure in pico_socket_close\n"); - + printf("\n%s: UDP sendto test launched. Sending packets to ip %s port %u\n\n", __FUNCTION__, dstaddr, short_be(dport)); return; - + out: fprintf(stderr, "udp_sendto_test expects the following format: udp_sendto_test:dest_addr:[dest_por]t\n"); exit(255); diff --git a/test/perf.sh b/test/perf.sh deleted file mode 100755 index c9debbea7..000000000 --- a/test/perf.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -THRESHOLD=300 -sh ./test/vde_sock_start_user.sh -sleep 2 - -(iperf -s >/tmp/iperf.log)& -./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.50.0.2:255.255.255.0:10.50.0.1: --app iperfc:10.50.0.1: &>/dev/null -killall iperf -RES=`cat /tmp/iperf.log |grep Mbits |sed -e "s/.*Bytes//g" |sed -e "s/^[ ]*//g"` -SPEED=`echo $RES | cut -d " " -f 1` -UNITS=`echo $RES | cut -d " " -f 2` - -if [ ["$UNITS"] != ["Mbits/sec"] ]; then - echo "Wrong test result units: expected Mbits/sec, got $UNITS" - exit 1 -fi - -if (test $SPEED -lt $THRESHOLD); then - echo "Speed too low: expected $THRESHOLD MBits/s, got $SPEED $UNITS" - exit 2 -fi - -echo Test result: $SPEED $UNITS - -rm -f /tmp/iperf.log -exit 0 diff --git a/test/pico_faulty.h b/test/pico_faulty.h index abbee5dcf..1554610bf 100644 --- a/test/pico_faulty.h +++ b/test/pico_faulty.h @@ -1,5 +1,5 @@ /********************************************************************* - PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. + PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Do not redistribute without a written permission by the Copyright holders. diff --git a/test/picoapp.c b/test/picoapp.c index 427786376..1eb2fed28 100644 --- a/test/picoapp.c +++ b/test/picoapp.c @@ -28,7 +28,6 @@ #include "pico_dhcp_server.h" #include "pico_ipfilter.h" #include "pico_olsr.h" -#include "pico_aodv.h" #include "pico_sntp_client.h" #include "pico_mdns.h" #include "pico_tftp.h" @@ -56,14 +55,14 @@ void app_mcastreceive(char *args); void app_ping(char *args); void app_dhcp_server(char *args); void app_dhcp_client(char *args); -void app_mdns(char *args); +void app_dns_sd(char *arg, struct pico_ipv4_link *link); +void app_mdns(char *arg, struct pico_ipv4_link *link); void app_sntp(char *args); void app_tftp(char *args); void app_slaacv4(char *args); void app_udpecho(char *args); void app_sendto_test(char *args); void app_noop(void); -void app_iperfc(char *args); struct pico_ip4 ZERO_IP4 = { @@ -255,7 +254,6 @@ int main(int argc, char **argv) pico_string_to_ipv6(gw, gateway6.addr); pico_ipv6_route_add(zero6, zero6, gateway6, 1, NULL); } - pico_ipv6_dev_routing_enable(dev); } @@ -309,7 +307,6 @@ int main(int argc, char **argv) pico_string_to_ipv6(gw, gateway6.addr); pico_ipv6_route_add(zero6, zero6, gateway6, 1, NULL); } - pico_ipv6_dev_routing_enable(dev); } @@ -345,9 +342,10 @@ int main(int argc, char **argv) nxt = cpy_arg(&loss_out, nxt); if (!nxt) break; } else { - nxt = cpy_arg(&addr6, nxt); if (!nxt) break; + + printf("addr6: %s\n", addr6); nxt = cpy_arg(&nm6, nxt); if (!nxt) break; @@ -379,7 +377,6 @@ int main(int argc, char **argv) printf("Vde created.\n"); if (!IPV6_MODE) { - pico_string_to_ipv4(addr, &ipaddr.addr); pico_string_to_ipv4(nm, &netmask.addr); pico_ipv4_link_add(dev, ipaddr, netmask); @@ -401,10 +398,8 @@ int main(int argc, char **argv) pico_string_to_ipv6(gw6, gateway6.addr); pico_ipv6_route_add(zero6, zero6, gateway6, 1, NULL); } - pico_ipv6_dev_routing_enable(dev); } - #endif if (loss_in && (strlen(loss_in) > 0)) { i_pc = (uint32_t)atoi(loss_in); @@ -470,8 +465,8 @@ int main(int argc, char **argv) pico_string_to_ipv6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", netmask6.addr); pico_ipv6_link_add(dev, ipaddr6, netmask6); } - pico_ipv6_dev_routing_enable(dev); + #endif } break; @@ -568,15 +563,21 @@ int main(int argc, char **argv) return 0; #else app_dhcp_client(args); +#endif + } else IF_APPNAME("dns_sd") { +#ifndef PICO_SUPPORT_DNS_SD + return 0; +#else + app_dns_sd(args, pico_ipv4_link_by_dev(dev)); #endif } else IF_APPNAME("mdns") { #ifndef PICO_SUPPORT_MDNS return 0; #else - app_mdns(args); + app_mdns(args, pico_ipv4_link_by_dev(dev)); #endif #ifdef PICO_SUPPORT_SNTP_CLIENT - }else IF_APPNAME("sntp") { + } else IF_APPNAME("sntp") { app_sntp(args); #endif } else IF_APPNAME("bcast") { @@ -606,23 +607,6 @@ int main(int argc, char **argv) pico_olsr_add(dev); } - app_noop(); -#endif -#ifdef PICO_SUPPORT_AODV - } else IF_APPNAME("aodv") { - union pico_address aaa; - pico_string_to_ipv4("10.10.10.10", &aaa.ip4.addr); - dev = pico_get_device("pic0"); - if(dev) { - pico_aodv_add(dev); - } - - dev = pico_get_device("pic1"); - if(dev) { - pico_aodv_add(dev); - } - - app_noop(); #endif } else IF_APPNAME("slaacv4") { @@ -633,8 +617,6 @@ int main(int argc, char **argv) #endif } else IF_APPNAME("udp_sendto_test") { app_sendto_test(args); - } else IF_APPNAME("iperfc") { - app_iperfc(args); } else { fprintf(stderr, "Unknown application %s\n", name); usage(argv[0]); diff --git a/test/python/topology.py b/test/python/topology.py index 3caef6612..dd8de0f7b 100755 --- a/test/python/topology.py +++ b/test/python/topology.py @@ -2,7 +2,7 @@ # Python classes definition for the picoTCP # topology test environment # -# Copyright (c) 2013-2015 Altran Intelligent Systems. See LICENSE for usage. +# Copyright (c) 2013 TASS Belgium. See LICENSE for usage. import sys, os, subprocess, time, re diff --git a/test/test_tftp_app_client b/test/test_tftp_app_client new file mode 100755 index 000000000..495ca8357 Binary files /dev/null and b/test/test_tftp_app_client differ diff --git a/test/test_tftp_app_client.c b/test/test_tftp_app_client.c deleted file mode 100644 index dd5ece38a..000000000 --- a/test/test_tftp_app_client.c +++ /dev/null @@ -1,244 +0,0 @@ -#include -#include -#include -#include -#include -#include "pico_stack.h" -#include "pico_config.h" -#include "pico_ipv4.h" -#include "pico_icmp4.h" -#include "pico_socket.h" -#include "pico_stack.h" -#include "pico_device.h" -#include "pico_dev_vde.h" -#include "pico_tftp.h" - -static struct pico_device *pico_dev; - -int32_t get_filesize(const char *filename) -{ - int ret; - struct stat buf; - - ret = stat(filename, &buf); - if (ret) - return -1; - - return buf.st_size; -} - -void start_rx(struct pico_tftp_session *session, int *synchro, const char *filename, int options) -{ - int ret; - int fd; - int32_t len; - uint8_t buf[PICO_TFTP_PAYLOAD_SIZE]; - int left = 1000; - int countdown = 0; - - printf("Start receiving file %s with options set to %d\n", filename, options); - - if (options) { - ret = pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, 0); - if (ret) { - fprintf(stderr, "Error in pico_tftp_set_option\n"); - exit(1); - } - } - - ret = pico_tftp_app_start_rx(session, filename); - if (ret) { - fprintf(stderr, "Error in pico_tftp_app_start_rx\n"); - exit(1); - } - - fd = open(filename, O_WRONLY | O_EXCL | O_CREAT, 0664); - if (!fd) { - fprintf(stderr, "Error in open\n"); - countdown = 1; - } - - for(; left; left -= countdown) { - usleep(2000); /* PICO_IDLE(); */ - pico_stack_tick(); - if (countdown) - continue; - - if (*synchro) { - len = pico_tftp_get(session, buf, PICO_TFTP_PAYLOAD_SIZE); - if (len < 0) { - fprintf(stderr, "Failure in pico_tftp_get\n"); - close(fd); - countdown = 1; - continue; - } - - ret = write(fd, buf, len); - if (ret < 0) { - fprintf(stderr, "Error in write\n"); - pico_tftp_abort(session, TFTP_ERR_EXCEEDED, "File write error"); - close(fd); - countdown = 1; - continue; - } - - printf("Written %" PRId32 " bytes to file (synchro=%d)\n", len, *synchro); - - if (len != PICO_TFTP_PAYLOAD_SIZE) { - close(fd); - printf("Transfer complete!\n"); - countdown = 1; - } - } - } -} - -void start_tx(struct pico_tftp_session *session, int *synchro, const char *filename, int options) -{ - int ret; - int fd; - int32_t len; - uint8_t buf[PICO_TFTP_PAYLOAD_SIZE]; - int left = 1000; - int countdown = 0; - - printf("Start sending file %s with options set to %d\n", filename, options); - - if (options) { - ret = get_filesize(filename); - if (ret < 0) { - fprintf(stderr, "Error in get_filesize\n"); - exit(1); - } - - ret = pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, ret); - if (ret) { - fprintf(stderr, "Error in pico_tftp_set_option\n"); - exit(1); - } - } - - ret = pico_tftp_app_start_tx(session, filename); - if (ret) { - fprintf(stderr, "Error in pico_tftp_app_start_rx\n"); - exit(1); - } - - fd = open(filename, O_RDONLY, 0444); - if (!fd) { - fprintf(stderr, "Error in open\n"); - pico_tftp_abort(session, TFTP_ERR_EACC, "Error opening file"); - countdown = 1; - } - - for(; left; left -= countdown) { - usleep(2000); /* PICO_IDLE(); */ - pico_stack_tick(); - if (countdown) - continue; - - if (*synchro) { - ret = read(fd, buf, PICO_TFTP_PAYLOAD_SIZE); - if (ret < 0) { - fprintf(stderr, "Error in read\n"); - pico_tftp_abort(session, TFTP_ERR_EACC, "File read error"); - close(fd); - countdown = 1; - continue; - } - - printf("Read %" PRId32 " bytes from file (synchro=%d)\n", len, *synchro); - - len = pico_tftp_put(session, buf, ret); - if (len < 0) { - fprintf(stderr, "Failure in pico_tftp_put\n"); - close(fd); - countdown = 1; - continue; - } - - if (len != PICO_TFTP_PAYLOAD_SIZE) { - close(fd); - printf("Transfer complete!\n"); - countdown = 1; - } - } - } -} - -void usage(const char *text) -{ - fprintf(stderr, "%s\nArguments must be \n" - " can be:\n" - "\tg => GET request without options\n" - "\tG => GET request WITH options\n" - "\tp => PUT request without options\n" - "\tP => PUT request WITH options\n\n", - text); - exit(1); -} - -int main(int argc, char**argv) -{ - struct pico_ip4 my_ip; - union pico_address server_address; - struct pico_ip4 netmask; - struct pico_tftp_session *session; - int synchro; - int options = 0; - void (*operation)(struct pico_tftp_session *session, int *synchro, const char *filename, int options); - - unsigned char macaddr[6] = { - 0, 0, 0, 0xa, 0xb, 0x0 - }; - - uint16_t *macaddr_low = (uint16_t *) (macaddr + 2); - *macaddr_low = *macaddr_low ^ (uint16_t)((uint16_t)getpid() & (uint16_t)0xFFFFU); - macaddr[4] ^= (uint8_t)(getpid() >> 8); - macaddr[5] ^= (uint8_t) (getpid() & 0xFF); - - pico_string_to_ipv4("10.40.0.10", &my_ip.addr); - pico_string_to_ipv4("255.255.255.0", &netmask.addr); - pico_string_to_ipv4("10.40.0.2", &server_address.ip4.addr); - - if (argc != 3) { - usage("Invalid number or arguments"); - } - - switch (argv[2][0]) { - case 'G': - options = 1; - case 'g': - operation = start_rx; - break; - case 'P': - options = 1; - case 'p': - operation = start_tx; - break; - default: - usage("Invalid mode"); - } - - printf("%s start!\n", argv[0]); - pico_stack_init(); - pico_dev = (struct pico_device *) pico_vde_create("/tmp/vde_switch", "tap0", macaddr); - - if(!pico_dev) { - fprintf(stderr, "Error creating pico device, got enough privileges? Exiting...\n"); - exit(1); - } - - pico_ipv4_link_add(pico_dev, my_ip, netmask); - printf("Starting picoTCP loop\n"); - - session = pico_tftp_app_setup(&server_address, short_be(PICO_TFTP_PORT), PICO_PROTO_IPV4, &synchro); - if (!session) { - fprintf(stderr, "Error in pico_tftp_app_setup\n"); - exit(1); - } - - printf("synchro %d\n", synchro); - - operation(session, &synchro, argv[1], options); -} diff --git a/test/unit/modunit_pico_aodv.c b/test/unit/modunit_pico_aodv.c deleted file mode 100644 index 387b3cccd..000000000 --- a/test/unit/modunit_pico_aodv.c +++ /dev/null @@ -1,533 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "modules/pico_aodv.c" -#include "check.h" - - -START_TEST(tc_aodv_node_compare) -{ - struct pico_aodv_node a, b; - a.dest.ip4.addr = long_be(1); - b.dest.ip4.addr = long_be(2); - - fail_if(aodv_node_compare(&a, &b) >= 0); - a.dest.ip4.addr = long_be(3); - fail_if(aodv_node_compare(&a, &b) <= 0); - b.dest.ip4.addr = long_be(3); - fail_if(aodv_node_compare(&a, &b) != 0); -} -END_TEST - -START_TEST(tc_aodv_dev_cmp) -{ - struct pico_device a, b; - a.hash = 1; - b.hash = 2; - fail_if(aodv_dev_cmp(&a, &b) >= 0); - a.hash = 3; - fail_if(aodv_dev_cmp(&a, &b) <= 0); - b.hash = 3; - fail_if(aodv_dev_cmp(&a, &b) != 0); - -} -END_TEST - -START_TEST(tc_get_node_by_addr) -{ - struct pico_aodv_node a; - union pico_address test; - a.dest.ip4.addr = long_be(10); - test.ip4.addr = long_be(10); - - pico_tree_insert(&aodv_nodes, &a); - - fail_if(get_node_by_addr(&test) != &a); - pico_tree_delete(&aodv_nodes, &a); - fail_if(get_node_by_addr(&test) != NULL); - -} -END_TEST - -static int set_bcast_link_called = 0; -void pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link) -{ - set_bcast_link_called++; -} - -START_TEST(tc_pico_aodv_set_dev) -{ - struct pico_device *dev = NULL; - pico_aodv_set_dev(dev); - fail_if(set_bcast_link_called != 1); -} -END_TEST - -START_TEST(tc_aodv_peer_refresh) -{ - /* TODO: test this: static int aodv_peer_refresh(struct pico_aodv_node *node, uint32_t seq) */ - struct pico_aodv_node node; - memset(&node, 0, sizeof(node)); - node.dseq = 0xFFFF; - fail_if(aodv_peer_refresh(&node, 10) != 0); /* should succeed, because SYNC flag is not yet set... */ - fail_if(node.flags & PICO_AODV_NODE_SYNC == 0); /* Flag should be set after last call... */ - fail_if(aodv_peer_refresh(&node, 5) == 0); /* should FAIL, because seq number is lower... */ - fail_if(aodv_peer_refresh(&node, 10) == 0); /* should FAIL, because seq number is still the same... */ - fail_if(aodv_peer_refresh(&node, 15) != 0); /* should succeed, because seq number is now bigger... */ - fail_if(node.dseq != 15); -} -END_TEST - -static int called_route_add = 0; -static uint32_t route_add_gw = 0u; -static int route_add_metric = 0; -int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) -{ - called_route_add++; - route_add_gw = gateway.addr; - route_add_metric = metric; - return 0; -} - -START_TEST(tc_aodv_elect_route) -{ - struct pico_aodv_node node; - union pico_address gateway; - memset(&node, 0, sizeof(node)); - gateway.ip4.addr = 0x55555555; - - called_route_add = 0; - aodv_elect_route(&node, NULL, 150, NULL); - fail_if(called_route_add != 1); /* Not active, should succeed */ - fail_if(route_add_gw != 0u); - fail_if(route_add_metric != 1); - - called_route_add = 0; - route_add_metric = 0; - route_add_gw = 0u; - node.flags = PICO_AODV_NODE_ROUTE_DOWN | PICO_AODV_NODE_ROUTE_UP; - aodv_elect_route(&node, &gateway, 150, NULL); - fail_if(called_route_add != 0); /* Already active, existing metric is lower */ - - called_route_add = 0; - route_add_metric = 0; - route_add_gw = 0u; - node.metric = 22; - aodv_elect_route(&node, &gateway, 15, NULL); - fail_if(called_route_add != 1); /* Already active, existing metric is higher */ - fail_if(route_add_metric != 16); - fail_if(route_add_gw != 0x55555555); - -} -END_TEST - -START_TEST(tc_aodv_peer_new) -{ - union pico_address addr; - struct pico_aodv_node *new; - addr.ip4.addr = 0x44444444; - new = aodv_peer_new(&addr); - fail_if(!new); - fail_if(!get_node_by_addr(&addr)); - pico_set_mm_failure(1); - new = aodv_peer_new(&addr); - fail_if(new); -} -END_TEST -START_TEST(tc_aodv_peer_eval) -{ - union pico_address addr; - struct pico_aodv_node *node = NULL; - /* Case 0: Creation */ - addr.ip4.addr = 0x11224433; - node = aodv_peer_eval(&addr, 0, 0); - fail_if(!node); - fail_if((node->flags & PICO_AODV_NODE_SYNC) != 0); /* Not synced! */ - - /* Case 1: retrieve, unsynced */ - node->metric = 42; - node = aodv_peer_eval(&addr, 0, 0); /* Should get existing node! */ - fail_if(!node); - fail_if(node->metric != 42); - fail_if((node->flags & PICO_AODV_NODE_SYNC) != 0); /* Not synced! */ - - - /* Case 2: new node, invalid allocation */ - addr.ip4.addr = 0x11224455; - pico_set_mm_failure(1); - node = aodv_peer_eval(&addr, long_be(10), 1); - fail_if(node); - - /* Case 3: existing node, setting the new sequence */ - addr.ip4.addr = 0x11224433; - node = aodv_peer_eval(&addr, long_be(10), 1); /* Should get existing node! */ - fail_if(node->metric != 42); - fail_if((node->flags & PICO_AODV_NODE_SYNC) == 0); - fail_if(node->dseq != 10); -} -END_TEST - -START_TEST(tc_aodv_lifetime) -{ - struct pico_aodv_node node; - pico_time now = PICO_TIME_MS(); - memset(&node, 0, sizeof(node)); - fail_if(aodv_lifetime(&node) == 0); - fail_if(node.last_seen < now); - node.last_seen = now - AODV_ACTIVE_ROUTE_TIMEOUT; - fail_if(aodv_lifetime(&node) != 0); -} -END_TEST - -static uint8_t sent_pkt_type = 0xFF; -static uint32_t dest_addr = 0; -static int pico_socket_sendto_called = 0; -static int pico_socket_sendto_extended_called = 0; -uint32_t expected_dseq = 0; -int pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port) -{ - uint8_t *pkt = (uint8_t *)buf; - printf("Sendto called!\n"); - pico_socket_sendto_called++; - fail_if(remote_port != short_be(PICO_AODV_PORT)); - fail_if (s != aodv_socket); - fail_if(pkt[0] > 4); - fail_if(pkt[0] < 1); - sent_pkt_type = pkt[0]; - dest_addr = ((union pico_address *)dst)->ip4.addr; - if (sent_pkt_type == AODV_TYPE_RREQ) { - struct pico_aodv_rreq *req = (struct pico_aodv_rreq *)buf; - fail_if(len != sizeof(struct pico_aodv_rreq)); - } - else if (sent_pkt_type == AODV_TYPE_RREP) { - struct pico_aodv_rrep *rep = (struct pico_aodv_rrep *)buf; - fail_if(len != sizeof(struct pico_aodv_rrep)); - fail_if(rep->dest != 0x11111111); - fail_if(rep->orig != 0x22222222); - printf("rep->dseq= %08x, exp: %08x\n", rep->dseq, expected_dseq); - fail_if(rep->dseq != expected_dseq); - } - - return len; -} - -int pico_socket_sendto_extended(struct pico_socket *s, const void *buf, const int len, - void *dst, uint16_t remote_port, struct pico_msginfo *msginfo) -{ - pico_socket_sendto_extended_called++; - return pico_socket_sendto(s, buf, len, dst, remote_port); -} - -START_TEST(tc_aodv_send_reply) -{ - struct pico_aodv_node node; - struct pico_aodv_rreq req; - struct pico_msginfo info; - union pico_address addr; - addr.ip4.addr = 0x22222222; - memset(&node, 0, sizeof(node)); - memset(&req, 0, sizeof(req)); - memset(&info, 0, sizeof(info)); - - req.dest = 0x11111111; - req.orig = addr.ip4.addr; - req.dseq = 99; - - aodv_send_reply(&node, &req, 1, &info); - fail_if(pico_socket_sendto_called != 0); /* Call should have no effect, due to non-existing origin node */ - - /* Creating origin... */ - fail_if(aodv_peer_new(&addr) == NULL); - aodv_send_reply(&node, &req, 0, &info); - fail_if(pico_socket_sendto_called != 0); /* Call should have no effect, node non-local, non sync'd */ - - expected_dseq = long_be(pico_aodv_local_id + 1); - aodv_send_reply(&node, &req, 1, &info); - fail_if(pico_socket_sendto_called != 1); /* Call should succeed */ - pico_socket_sendto_called = 0; - - node.flags = PICO_AODV_NODE_SYNC; - node.dseq = 42; - expected_dseq = long_be(42); - aodv_send_reply(&node, &req, 0, &info); - fail_if(pico_socket_sendto_called != 1); /* Call should succeed */ - pico_socket_sendto_called = 0; -} -END_TEST - -static struct pico_ipv4_link global_link; -struct pico_ipv4_link *pico_ipv4_link_by_dev(struct pico_device *dev) -{ - if (!global_link.address.addr) - return NULL; - - printf("Setting link!\n"); - return &global_link; -} - -static struct pico_device global_dev; -static int link_find_success = 0; -struct pico_device *pico_ipv4_link_find(struct pico_ip4 *ip4) -{ - if (link_find_success) - return &global_dev; - - return NULL; -} - -static int timer_set = 0; -struct pico_timer *pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) -{ - printf("Timer set!\n"); - timer_set++; - return (struct pico_timer *) 0x99999999; - -} - -START_TEST(tc_aodv_send_req) -{ - struct pico_aodv_node node; - struct pico_device d; - aodv_socket = NULL; - - memset(&node, 0, sizeof(node)); - node.flags = PICO_AODV_NODE_ROUTE_DOWN | PICO_AODV_NODE_ROUTE_UP; - fail_if(aodv_send_req(&node) != 0); /* Should fail: node already active */ - fail_if(pico_socket_sendto_called != 0); - fail_if(pico_socket_sendto_extended_called != 0); - - node.flags = 0; - fail_if(aodv_send_req(&node) != 0); /* Should fail: no devices in tree */ - fail_if(pico_socket_sendto_called != 0); - fail_if(pico_socket_sendto_extended_called != 0); - - pico_tree_insert(&aodv_devices, &d); - fail_if(aodv_send_req(&node) != -1); /* Should fail: aodv_socket == NULL */ - fail_if(pico_err != PICO_ERR_EINVAL); - fail_if(pico_socket_sendto_called != 0); - fail_if(pico_socket_sendto_extended_called != 0); - - - /* No valid link, timer is set, call does not send packets */ - aodv_socket = 1; - global_link.address.addr = 0; - fail_if(aodv_send_req(&node) != 0); - fail_if(pico_socket_sendto_called != 0); - fail_if(pico_socket_sendto_extended_called != 0); - fail_if(timer_set != 1); - timer_set = 0; - - - /* One valid link, timer is set, one packet is sent */ - global_link.address.addr = 0xFEFEFEFE; - fail_if(aodv_send_req(&node) != 1); - fail_if(pico_socket_sendto_called != 1); - fail_if(pico_socket_sendto_extended_called != 1); - fail_if(timer_set != 1); - pico_socket_sendto_called = 0; - pico_socket_sendto_extended_called = 0; - timer_set = 0; - -} -END_TEST - -START_TEST(tc_aodv_reverse_path_discover) -{ - struct pico_aodv_node node; - memset(&node, 0, sizeof(node)); - aodv_reverse_path_discover(0, &node); -} -END_TEST - -START_TEST(tc_aodv_recv_valid_rreq) -{ - struct pico_aodv_node node; - struct pico_aodv_rreq req; - struct pico_msginfo info; - union pico_address addr; - memset(&node, 0, sizeof(node)); - memset(&req, 0, sizeof(req)); - memset(&info, 0, sizeof(info)); - - addr.ip4.addr = 0x22222222; - - link_find_success = 0; - aodv_recv_valid_rreq(&node, &req, &info); - fail_if(pico_socket_sendto_called > 0); - - /* link not local, but active node, set to send reply, no timer */ - link_find_success = 0; - fail_if(aodv_peer_new(&addr) == NULL); - global_link.address.addr = 0x44444444; - req.orig = addr.ip4.addr; - req.dest = 0x11111111; - node.flags = PICO_AODV_NODE_SYNC | PICO_AODV_NODE_ROUTE_UP | PICO_AODV_NODE_ROUTE_DOWN; - node.dseq = 42; - expected_dseq = long_be(42); - aodv_recv_valid_rreq(&node, &req, &info); - fail_if(pico_socket_sendto_called < 1); - fail_if(timer_set > 0); - pico_socket_sendto_called = 0; - - /* link local, active node. Full send + set timer. */ - link_find_success = 1; - expected_dseq = long_be(pico_aodv_local_id + 1); - aodv_peer_new(&addr); - aodv_recv_valid_rreq(&node, &req, &info); - fail_if(pico_socket_sendto_called < 1); - fail_if(timer_set < 1); - -} -END_TEST - -START_TEST(tc_aodv_parse_rreq) -{ - /* TODO: test this: static void aodv_parse_rreq(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) */ -} -END_TEST - -START_TEST(tc_aodv_parse_rrep) -{ - /* TODO: test this: static void aodv_parse_rrep(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) */ -} -END_TEST - -START_TEST(tc_aodv_parse_rerr) -{ - /* TODO: test this: static void aodv_parse_rerr(union pico_address *from, uint8_t *buf, int len, struct pico_msginfo *msginfo) */ -} -END_TEST - -START_TEST(tc_aodv_parse_rack) -{ - aodv_parse_rack(NULL, NULL, 0, NULL); -} -END_TEST - -START_TEST(tc_pico_aodv_parse) -{ -} -END_TEST - -START_TEST(tc_pico_aodv_socket_callback) -{ - /* TODO: test this: static void pico_aodv_socket_callback(uint16_t ev, struct pico_socket *s) */ -} -END_TEST - -START_TEST(tc_aodv_make_rreq) -{ - /* TODO: test this: static void aodv_make_rreq(struct pico_aodv_node *node, struct pico_aodv_rreq *req) */ -} -END_TEST - -START_TEST(tc_aodv_retrans_rreq) -{ - /* TODO: test this: static void aodv_retrans_rreq(pico_time now, void *arg) */ -} -END_TEST - -START_TEST(tc_pico_aodv_expired) -{ - /* TODO: test this: static void pico_aodv_expired(struct pico_aodv_node *node) */ -} -END_TEST - -START_TEST(tc_pico_aodv_collector) -{ - /* TODO: test this: static void pico_aodv_collector(pico_time now, void *arg) */ -} -END_TEST - - -Suite *pico_suite(void) -{ - Suite *s = suite_create("PicoTCP"); - - TCase *TCase_aodv_node_compare = tcase_create("Unit test for aodv_node_compare"); - TCase *TCase_aodv_dev_cmp = tcase_create("Unit test for aodv_dev_cmp"); - TCase *TCase_get_node_by_addr = tcase_create("Unit test for get_node_by_addr"); - TCase *TCase_pico_aodv_set_dev = tcase_create("Unit test for pico_aodv_set_dev"); - TCase *TCase_aodv_peer_refresh = tcase_create("Unit test for aodv_peer_refresh"); - TCase *TCase_aodv_elect_route = tcase_create("Unit test for aodv_elect_route"); - TCase *TCase_aodv_peer_new = tcase_create("Unit test for aodv_peer_new"); - TCase *TCase_aodv_peer_eval = tcase_create("Unit test for aodv_peer_eval"); - TCase *TCase_aodv_lifetime = tcase_create("Unit test for aodv_lifetime"); - TCase *TCase_aodv_send_reply = tcase_create("Unit test for aodv_send_reply"); - TCase *TCase_aodv_send_req = tcase_create("Unit test for aodv_send_req"); - TCase *TCase_aodv_reverse_path_discover = tcase_create("Unit test for aodv_reverse_path_discover"); - TCase *TCase_aodv_recv_valid_rreq = tcase_create("Unit test for aodv_recv_valid_rreq"); - TCase *TCase_aodv_parse_rreq = tcase_create("Unit test for aodv_parse_rreq"); - TCase *TCase_aodv_parse_rrep = tcase_create("Unit test for aodv_parse_rrep"); - TCase *TCase_aodv_parse_rerr = tcase_create("Unit test for aodv_parse_rerr"); - TCase *TCase_aodv_parse_rack = tcase_create("Unit test for aodv_parse_rack"); - TCase *TCase_pico_aodv_parse = tcase_create("Unit test for pico_aodv_parse"); - TCase *TCase_pico_aodv_socket_callback = tcase_create("Unit test for pico_aodv_socket_callback"); - TCase *TCase_aodv_make_rreq = tcase_create("Unit test for aodv_make_rreq"); - TCase *TCase_aodv_retrans_rreq = tcase_create("Unit test for aodv_retrans_rreq"); - TCase *TCase_pico_aodv_expired = tcase_create("Unit test for pico_aodv_expired"); - TCase *TCase_pico_aodv_collector = tcase_create("Unit test for pico_aodv_collector"); - - - tcase_add_test(TCase_aodv_node_compare, tc_aodv_node_compare); - suite_add_tcase(s, TCase_aodv_node_compare); - tcase_add_test(TCase_aodv_dev_cmp, tc_aodv_dev_cmp); - suite_add_tcase(s, TCase_aodv_dev_cmp); - tcase_add_test(TCase_get_node_by_addr, tc_get_node_by_addr); - suite_add_tcase(s, TCase_get_node_by_addr); - tcase_add_test(TCase_pico_aodv_set_dev, tc_pico_aodv_set_dev); - suite_add_tcase(s, TCase_pico_aodv_set_dev); - tcase_add_test(TCase_aodv_peer_refresh, tc_aodv_peer_refresh); - suite_add_tcase(s, TCase_aodv_peer_refresh); - tcase_add_test(TCase_aodv_elect_route, tc_aodv_elect_route); - suite_add_tcase(s, TCase_aodv_elect_route); - tcase_add_test(TCase_aodv_peer_new, tc_aodv_peer_new); - suite_add_tcase(s, TCase_aodv_peer_new); - tcase_add_test(TCase_aodv_peer_eval, tc_aodv_peer_eval); - suite_add_tcase(s, TCase_aodv_peer_eval); - tcase_add_test(TCase_aodv_lifetime, tc_aodv_lifetime); - suite_add_tcase(s, TCase_aodv_lifetime); - tcase_add_test(TCase_aodv_send_reply, tc_aodv_send_reply); - suite_add_tcase(s, TCase_aodv_send_reply); - tcase_add_test(TCase_aodv_send_req, tc_aodv_send_req); - suite_add_tcase(s, TCase_aodv_send_req); - tcase_add_test(TCase_aodv_reverse_path_discover, tc_aodv_reverse_path_discover); - suite_add_tcase(s, TCase_aodv_reverse_path_discover); - tcase_add_test(TCase_aodv_recv_valid_rreq, tc_aodv_recv_valid_rreq); - suite_add_tcase(s, TCase_aodv_recv_valid_rreq); - tcase_add_test(TCase_aodv_parse_rreq, tc_aodv_parse_rreq); - suite_add_tcase(s, TCase_aodv_parse_rreq); - tcase_add_test(TCase_aodv_parse_rrep, tc_aodv_parse_rrep); - suite_add_tcase(s, TCase_aodv_parse_rrep); - tcase_add_test(TCase_aodv_parse_rerr, tc_aodv_parse_rerr); - suite_add_tcase(s, TCase_aodv_parse_rerr); - tcase_add_test(TCase_aodv_parse_rack, tc_aodv_parse_rack); - suite_add_tcase(s, TCase_aodv_parse_rack); - tcase_add_test(TCase_pico_aodv_parse, tc_pico_aodv_parse); - suite_add_tcase(s, TCase_pico_aodv_parse); - tcase_add_test(TCase_pico_aodv_socket_callback, tc_pico_aodv_socket_callback); - suite_add_tcase(s, TCase_pico_aodv_socket_callback); - tcase_add_test(TCase_aodv_make_rreq, tc_aodv_make_rreq); - suite_add_tcase(s, TCase_aodv_make_rreq); - tcase_add_test(TCase_aodv_retrans_rreq, tc_aodv_retrans_rreq); - suite_add_tcase(s, TCase_aodv_retrans_rreq); - tcase_add_test(TCase_pico_aodv_expired, tc_pico_aodv_expired); - suite_add_tcase(s, TCase_pico_aodv_expired); - tcase_add_test(TCase_pico_aodv_collector, tc_pico_aodv_collector); - suite_add_tcase(s, TCase_pico_aodv_collector); - return s; -} - -int main(void) -{ - int fails; - Suite *s = pico_suite(); - SRunner *sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); - fails = srunner_ntests_failed(sr); - srunner_free(sr); - return fails; -} diff --git a/test/unit/modunit_pico_dev_loop.c b/test/unit/modunit_pico_dev_loop.c index 830436f7c..ebd089daf 100644 --- a/test/unit/modunit_pico_dev_loop.c +++ b/test/unit/modunit_pico_dev_loop.c @@ -14,7 +14,7 @@ int pico_device_init(struct pico_device __attribute__((unused)) *dev, const char void pico_device_destroy(struct pico_device *dev) { - dev = dev; + dev=dev; } int32_t pico_stack_recv(struct pico_device __attribute__((unused)) *dev, uint8_t __attribute__((unused)) *buffer, uint32_t __attribute__((unused)) len) diff --git a/test/unit/modunit_pico_dns_common.c b/test/unit/modunit_pico_dns_common.c new file mode 100644 index 000000000..b084e525a --- /dev/null +++ b/test/unit/modunit_pico_dns_common.c @@ -0,0 +1,1472 @@ +#include "pico_config.h" +#include "pico_stack.h" +#include "pico_addressing.h" +#include "pico_socket.h" +#include "pico_ipv4.h" +#include "pico_ipv6.h" +#include "pico_dns_common.h" +#include "pico_tree.h" +#include "modules/pico_dns_common.c" +#include "check.h" + +/* MARK: DNS packet section filling */ +START_TEST(tc_pico_dns_fill_packet_header) +{ + struct pico_dns_header *header = NULL; + uint8_t answer_buf[12] = { 0x00, 0x00, + 0x84, 0x00, + 0x00, 0x00, + 0x00, 0x01, + 0x00, 0x01, + 0x00, 0x01 }; + uint8_t query_buf[12] = { 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x01, + 0x00, 0x01, + 0x00, 0x01, + 0x00, 0x01 }; + + header = (struct pico_dns_header *) + PICO_ZALLOC(sizeof(struct pico_dns_header)); + + fail_if(NULL == header, "Not enough space!\n"); + + /* Create a query header */ + pico_dns_fill_packet_header(header, 1, 1, 1, 1); + + fail_unless(0 == memcmp((void *)header, (void *)query_buf, 12), + "Comparing query header failed!\n"); + + /* Create a answer header */ + pico_dns_fill_packet_header(header, 0, 1, 1, 1); + + fail_unless(0 == memcmp((void *)header, (void *)answer_buf, 12), + "Comparing answer header failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_fill_packet_rr_sections) +{ + pico_dns_packet *packet = NULL; + pico_dns_question_vector qvector = {0}; + pico_dns_record_vector anvector = {0}, nsvector = {0}, arvector = {0}; + struct pico_dns_record *record = NULL; + const char *rname = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint8_t cmp_buf[39] = { 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x00u, 0x00u, 0x00u, 0x78u, + 0x00u, 0x04u, + 10u, 10u, 0u, 1u}; + uint16_t len = 0; + int ret = 0; + + /* Create a new A record */ + record = pico_dns_record_create(rname, rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!record, "dns_record_create failed!\n"); + + pico_dns_record_vector_add(&anvector, record); + + /* Try to fill the rr sections with packet as a NULL-pointer */ + ret = pico_dns_fill_packet_rr_sections(packet, &qvector, &anvector, + &nsvector, &arvector); + fail_unless(ret, "Checking of params failed!\n"); + + len = (uint16_t)sizeof(struct pico_dns_header); + len = (uint16_t)(len + pico_dns_question_vector_size(&qvector)); + len = (uint16_t)(len + pico_dns_record_vector_size(&anvector)); + len = (uint16_t)(len + pico_dns_record_vector_size(&nsvector)); + len = (uint16_t)(len + pico_dns_record_vector_size(&arvector)); + + /* Allocate the packet with the right size */ + packet = (pico_dns_packet *)PICO_ZALLOC((size_t)len); + fail_if(NULL == packet, "Allocating packet failed!\n"); + fail_if(pico_dns_fill_packet_rr_sections(packet, &qvector, &anvector, + &nsvector, &arvector), + "Filling of rr sections failed!\n"); + + fail_unless(memcmp((void *)packet, (void *)cmp_buf, 39) == 0, + "Filling of rr sections went wrong!\n"); + PICO_FREE(packet); +} +END_TEST +START_TEST(tc_pico_dns_fill_packet_question_section) +{ + pico_dns_packet *packet = NULL; + pico_dns_question_vector qvector = {0}; + struct pico_dns_question *a = NULL, *b = NULL; + const char *qurl = "picotcp.com"; + uint8_t cmp_buf[45] = { 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x06u, 'g','o','o','g','l','e', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u}; + uint16_t len = 0; + + /* Create DNS questions and a vector of them */ + a = pico_dns_question_create(qurl, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(NULL == a, "dns_question_create failed!\n"); + pico_dns_question_vector_add(&qvector, a); + b = pico_dns_question_create("google.com", &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(NULL == b, "dns_question_create failed!\n"); + pico_dns_question_vector_add(&qvector, b); + + /* Determine the length of the packet and provide space */ + len = (uint16_t)sizeof(struct pico_dns_header); + len = (uint16_t)(len + pico_dns_question_vector_size(&qvector)); + packet = (pico_dns_packet *)PICO_ZALLOC((size_t)len); + + fail_if(NULL == packet, "Allocating packet failed!\n"); + fail_if(pico_dns_fill_packet_question_section(packet, &qvector), + "Filling of rr sections failed!\n"); + + fail_unless(memcmp((void *)packet, (void *)cmp_buf, 45) == 0, + "Filling of question section went wrong!\n"); + PICO_FREE(packet); +} +END_TEST +/* MARK: DNS packet compression */ +START_TEST(tc_pico_dns_packet_compress_find_ptr) +{ + uint8_t *data = (uint8_t *)"abcdef\5local\0abcdef\4test\5local"; + uint8_t *name = (uint8_t *)"\5local"; + uint16_t len = 31; + uint8_t *ptr = NULL; + + ptr = pico_dns_packet_compress_find_ptr(name, data, len); + fail_unless(ptr == (data + 6), "Finding compression ptr failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_packet_compress_name) +{ + uint8_t buf[46] = { 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u}; + + uint8_t *name = buf + 29u; + uint16_t len = 46; + int ret = 0; + ret = pico_dns_packet_compress_name(name, buf, &len); + fail_unless(ret == 0, "dns_packet_compress_name returned error!\n"); + fail_unless(len == (46 - 11), "packet_compress_name return wrong length!\n"); + fail_unless(memcmp(name, "\xc0\x0c", 2) == 0, "packet_compress_name failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_packet_compress) +{ + uint8_t buf[83] = { 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x01u, + 0x00u, 0x00u, + 0x00u, 0x02u, + 0x00u, 0x00u, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x00u, 0x00u, 0x00, 0x0A, + 0x00u, 0x04u, + 0x0Au, 0x0Au, 0x0A, 0x0A, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x00u, 0x00u, 0x00, 0x0A, + 0x00u, 0x04u, + 0x0Au, 0x0Au, 0x0A, 0x0A}; + uint8_t cmp_buf[61] = { 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x01u, + 0x00u, 0x00u, + 0x00u, 0x02u, + 0x00u, 0x00u, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0xC0u, 0x0Cu, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x00u, 0x00u, 0x00, 0x0A, + 0x00u, 0x04u, + 0x0Au, 0x0Au, 0x0A, 0x0A, + 0xC0u, 0x0Cu, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x00u, 0x00u, 0x00, 0x0A, + 0x00u, 0x04u, + 0x0Au, 0x0Au, 0x0A, 0x0A}; + pico_dns_packet *packet = (pico_dns_packet *)buf; + uint16_t len = 83; + int ret = 0; + + ret = pico_dns_packet_compress(packet, &len); + + fail_unless(ret == 0, "dns_packet_compress returned error!\n"); + fail_unless(len == (83 - 22), "packet_compress returned length %u!\n", len); + fail_unless(memcmp(packet, cmp_buf, 61) == 0, "packet_compress_name failed!\n"); +} +END_TEST +/* MARK: DNS question functions */ +START_TEST(tc_pico_dns_question_fill_qsuffix) +{ + struct pico_dns_question_suffix suffix; + pico_dns_question_fill_qsuffix(&suffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN); + + fail_unless((suffix.qtype == short_be(PICO_DNS_TYPE_A)) && + (suffix.qclass == short_be(PICO_DNS_CLASS_IN)), + "Filling qsuffix failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_question_copy) +{ + const char *qurl = "picotcp.com"; + uint16_t len = 0; + struct pico_dns_question *a = pico_dns_question_create(qurl, &len, + PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, + 0); + struct pico_dns_question *b = pico_dns_question_copy(a); + + fail_unless(strcmp(a->qname, b->qname) == 0, + "qname isn't copied correctly!\n"); + fail_unless(a->qsuffix->qtype == b->qsuffix->qtype, + "qtype isn't copied correctly!\n"); + fail_unless(a->qsuffix->qclass == b->qsuffix->qclass, + "qclass isn't copied correctly!\n"); + fail_if(a == b, "pointers point to same struct!\n"); +} +END_TEST +START_TEST(tc_pico_dns_question_delete) +{ + const char *qurl = "picotcp.com"; + uint16_t len = 0; + int ret = 0; + struct pico_dns_question *a = pico_dns_question_create(qurl, &len, + PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, + 0); + ret = pico_dns_question_delete(&a); + + fail_unless(ret == 0, "dns_question_delete returned error!\n"); + fail_unless(a == NULL, "dns_question_delete failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_question_create) +{ + const char *qurl = "picotcp.com"; + const char *qurl2 = "1.2.3.4"; + const char *qurl3 = "2001:0db8:0000:0000:0000:0000:0000:0000"; + char buf[13] = { 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u }; + char buf2[22] = { 0x01u, '4', + 0x01u, '3', + 0x01u, '2', + 0x01u, '1', + 0x07u, 'i','n','-','a','d','d','r', + 0x04u, 'a','r','p','a', + 0x00u }; + char buf3[74] = { 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '8', 0x01u, 'b', 0x01u, 'd', 0x01u, '0', + 0x01u, '1', 0x01u, '0', 0x01u, '0', 0x01u, '2', + 0x03u, 'I','P','6', + 0x04u, 'A','R','P','A', + 0x00u }; + uint16_t len = 0; + + /* First, plain A record */ + struct pico_dns_question *a = pico_dns_question_create(qurl, &len, + PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, + 0); + fail_if(a == NULL, "dns_question_created returned NULL!\n"); + fail_unless(strcmp(a->qname, buf) == 0, "url not converted correctly!\n"); + fail_unless(short_be(a->qsuffix->qtype) == PICO_DNS_TYPE_A, + "qtype not properly set!\n"); + fail_unless(short_be(a->qsuffix->qclass) == PICO_DNS_CLASS_IN, + "qclass not properly set!\n"); + pico_dns_question_delete(&a); + + /* Reverse PTR record for IPv4 address */ + a = pico_dns_question_create(qurl2, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN, 1); + fail_unless(strcmp(a->qname, buf2) == 0, "url2 not converted correctly!\n"); + fail_unless(short_be(a->qsuffix->qtype) == PICO_DNS_TYPE_PTR, + "qtype2 not properly set!\n"); + fail_unless(short_be(a->qsuffix->qclass) == PICO_DNS_CLASS_IN, + "qclass2 not properly set!\n"); + pico_dns_question_delete(&a); + + /* Reverse PTR record for IPv6 address */ + a = pico_dns_question_create(qurl3, &len, PICO_PROTO_IPV6, + PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN, 1); + fail_unless(strcmp(a->qname, buf3) == 0, "url3 not converted correctly!\n"); + fail_unless(short_be(a->qsuffix->qtype) == PICO_DNS_TYPE_PTR, + "qtype3 not properly set!\n"); + fail_unless(short_be(a->qsuffix->qclass) == PICO_DNS_CLASS_IN, + "qclass3 not properly set!\n"); + pico_dns_question_delete(&a); +} +END_TEST +/* MARK: DNS question vector functions */ +START_TEST(tc_pico_dns_question_vector_init) +{ + pico_dns_question_vector qvector; + + pico_dns_question_vector_init(&qvector); + fail_unless((qvector.questions == NULL && + qvector.count == 0), "dns_question_vector_init failed!\n"); + +} +END_TEST +START_TEST(tc_pico_dns_question_vector_count) +{ + pico_dns_question_vector qvector = { 0 }; + const char *qurl = "picotcp.com"; + uint16_t len = 0; + + struct pico_dns_question *a = pico_dns_question_create(qurl, &len, + PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, + 0); + fail_if(!a, "dns_question_create failed!\n"); + + fail_unless(pico_dns_question_vector_count(&qvector) == 0, + "question vector count should be 0\n"); + pico_dns_question_vector_add(&qvector, a); + fail_unless(pico_dns_question_vector_count(&qvector) == 1, + "question vector count should be 1\n"); + pico_dns_question_vector_delete(&qvector, 0); + fail_unless(pico_dns_question_vector_count(&qvector) == 0, + "question vector count should be 0\n"); +} +END_TEST +START_TEST(tc_pico_dns_question_vector_add) +{ + pico_dns_question_vector qvector = { 0 }; + const char *qurl = "picotcp.com"; + uint16_t len = 0; + int ret = 0; + + struct pico_dns_question *a = pico_dns_question_create(qurl, &len, + PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, + 0); + fail_if(!a, "dns_question_create failed!\n"); + + ret = pico_dns_question_vector_add(&qvector, a); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + fail_unless(a == pico_dns_question_vector_get(&qvector, 0), + "DNS question not added properly!\n"); +} +END_TEST +START_TEST(tc_pico_dns_question_vector_add_copy) +{ + pico_dns_question_vector qvector = { 0 }; + const char *qurl = "picotcp.com"; + uint16_t len = 0; + int ret = 0; + + struct pico_dns_question *b = NULL,*a = pico_dns_question_create(qurl, &len, + PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, + 0); + fail_if(!a, "dns_question_create failed!\n"); + + ret = pico_dns_question_vector_add_copy(&qvector, a); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + fail_unless(a != (b = pico_dns_question_vector_get(&qvector, 0)), + "Pointers point to same question struct!\n"); + fail_unless(strcmp(a->qname, b->qname) == 0, + "qname isn't copied correctly!\n"); + fail_unless(a->qsuffix->qtype == b->qsuffix->qtype, + "qtype isn't copied correctly!\n"); + fail_unless(a->qsuffix->qclass == b->qsuffix->qclass, + "qclass isn't copied correctly!\n"); +} +END_TEST +START_TEST(tc_pico_dns_question_vector_get) +{ + pico_dns_question_vector qvector = { 0 }; + const char *qurl = "picotcp.com"; + uint16_t len = 0; + int ret = 0; + struct pico_dns_question *b = NULL; + struct pico_dns_question *a = pico_dns_question_create(qurl, &len, + PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, + 0); + fail_if(!a, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, a); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + + b = pico_dns_question_vector_get(&qvector, 0); + fail_unless(b == a, "dns_question_vector_get failed!\n"); + + b = pico_dns_question_vector_get(&qvector, 1); + fail_unless(b == NULL, "dns_question_vector_get OOB failed!\n"); + + b = pico_dns_question_vector_get(NULL, 1); + fail_unless(b == NULL, "dns_question_vector_get NULL-ptr failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_question_vector_delete) +{ + pico_dns_question_vector qvector = { 0 }; + const char *qurl = "picotcp.com"; + uint16_t len = 0; + int ret = 0; + + struct pico_dns_question *a = pico_dns_question_create(qurl, &len, + PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, + 0); + fail_if(!a, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, a); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + + ret = pico_dns_question_vector_delete(&qvector, 1); + fail_unless(ret == -1, "dns_question_vector_delete OOB failed!\n"); + + ret = pico_dns_question_vector_delete(&qvector, 0); + fail_unless(ret == 0, "dns_question_vector_delete failed!\n"); + fail_unless(pico_dns_question_vector_count(&qvector) == 0, + "dns_question_vector_delete failed with updating the count!\n"); + + ret = pico_dns_question_vector_delete(NULL, 1); + fail_unless(ret == -1, "dns_question_vector_delete NULL-ptr failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_question_vector_destroy) +{ + pico_dns_question_vector qvector = { 0 }; + struct pico_dns_question *b = NULL; + const char *qurl = "picotcp.com"; + uint16_t len = 0; + int ret = 0; + + struct pico_dns_question *a = NULL; + + a = pico_dns_question_create(qurl, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!a, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, a); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + b = pico_dns_question_create(qurl, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!b, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, b); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + + ret = pico_dns_question_vector_destroy(&qvector); + fail_unless(pico_dns_question_vector_count(&qvector) == 0, + "dns_question_vector_destroy failed!\n"); + fail_unless(qvector.questions == NULL, + "dns_question_vector_destroy failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_question_vector_find_name) +{ + pico_dns_question_vector qvector = { 0 }; + const char *qurl = "picotcp.com"; + const char *qurl2 = "google.com"; + uint16_t len = 0; + int ret = 0; + struct pico_dns_question *a = NULL, *b = NULL, *c = NULL; + + a = pico_dns_question_create(qurl, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!a, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, a); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + b = pico_dns_question_create(qurl2, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!b, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, b); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + + c = pico_dns_question_vector_find_name(&qvector, "\6google\3com"); + fail_unless(c == b, "dns_question_vector_find_name failed!\n"); + + c = pico_dns_question_vector_find_name(&qvector, "\4test\5local"); + fail_unless(c == NULL, "question_vector_find_name unkown name failed!\n"); + + c = pico_dns_question_vector_find_name(&qvector, "\7picotcp\3com"); + fail_unless(c == a, "dns_question_vector_find_name failed!\n"); + + c = pico_dns_question_vector_find_name(NULL, "\4test\5local"); + fail_unless(c == NULL, "question_vector_find_name check params failed!\n"); + + c = pico_dns_question_vector_find_name(&qvector, NULL); + fail_unless(c == NULL, "question_vector_find_name check params failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_question_vector_size) +{ + pico_dns_question_vector qvector = { 0 }; + const char *qurl = "picotcp.com"; + const char *qurl2 = "google.com"; + uint16_t len = 0; + int ret = 0; + struct pico_dns_question *a = NULL, *b = NULL; + + a = pico_dns_question_create(qurl, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!a, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, a); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + b = pico_dns_question_create(qurl2, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!b, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, b); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + + len = pico_dns_question_vector_size(&qvector); + fail_unless(len == (17 + 16), + "dns_question_vector_size failed!\n"); + len = pico_dns_question_vector_size(NULL); + fail_unless(len == 0, + "dns_question_vector_size NULL-ptr failed!\n"); + + /* FREE memory */ + pico_dns_question_delete(&a); + pico_dns_question_delete(&b); +} +END_TEST +/* MARK: DNS query packet creation */ +START_TEST(tc_pico_dns_query_create) +{ + pico_dns_packet *packet = NULL; + pico_dns_question_vector qvector = { 0 }; + const char *qurl = "picotcp.com"; + const char *qurl2 = "google.com"; + uint8_t buf[42] = { 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x02u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x06u, 'g','o','o','g','l','e', + 0xc0u, 0x14u, + 0x00u, 0x01u, + 0x00u, 0x01u }; + uint16_t len = 0; + int ret = 0; + struct pico_dns_question *a = NULL, *b = NULL; + + a = pico_dns_question_create(qurl, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!a, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, a); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + b = pico_dns_question_create(qurl2, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!b, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, b); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + + packet = pico_dns_query_create(&qvector, NULL, NULL, NULL, &len); + fail_if(packet == NULL, "dns_query_create returned NULL!\n"); + fail_unless(0 == memcmp(buf, (void *)packet, 42), + "dns_query_created failed!\n"); +} +END_TEST +/* MARK: DNS resource record functions */ +START_TEST(tc_pico_dns_record_fill_suffix) +{ + struct pico_dns_record_suffix suffix; + pico_dns_record_fill_suffix(&suffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN, + 120, 4); + + fail_unless((suffix.rtype == short_be(PICO_DNS_TYPE_A) && + suffix.rclass == short_be(PICO_DNS_CLASS_IN) && + suffix.rttl == long_be(120) && + suffix.rdlength == short_be(4)), + "Filling rsuffix failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_record_copy_flat) +{ + struct pico_dns_record *record = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint8_t buf[128] = { 0 }; + uint8_t *ptr = NULL; + uint8_t cmp_buf[27] = { 0x07, 'p','i','c','o','t','c','p', + 0x03, 'c','o','m', + 0x00, + 0x00, 0x01, + 0x00, 0x01, + 0x00, 0x00, 0x00, 0x78, + 0x00, 0x04, + 0x0A, 0x0A, 0x00, 0x01}; + uint16_t len = 0; + int ret = 0; + + record = pico_dns_record_create(url, (void *)rdata, 4, + &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!record, "dns_record_create failed!\n"); + + *ptr = buf + 20; + + /* Try to copy the record to a flat buffer */ + ret = pico_dns_record_copy_flat(record, &ptr); + + fail_unless(ret == 0, "dns_record_copy_flat returned error!\n"); + fail_unless(memcmp(buf + 20, cmp_buf, 27) == 0, + "dns_record_copy_flat failed!\n"); + + /* FREE memory */ + pico_dns_record_delete(&record); +} +END_TEST +START_TEST(tc_pico_dns_record_copy) +{ + struct pico_dns_record *a = NULL, *b = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create failed!\n"); + + /* Try to copy the first DNS record */ + b = pico_dns_record_copy(a); + fail_unless(b != NULL, "dns_record_copy returned NULL!\n"); + fail_unless(a != b, "pointers point to same struct!\n"); + fail_unless(strcmp(a->rname, b->rname) == 0, + "dns_record_copy failed copying names!\n"); + fail_unless(a->rsuffix->rtype == b->rsuffix->rtype, + "dns_record_copy failed copying rtype!\n"); + fail_unless(a->rsuffix->rclass == b->rsuffix->rclass, + "dns_record_copy failed copying rclass!\n"); + fail_unless(a->rsuffix->rttl == b->rsuffix->rttl, + "dns_record_copy failed copying rttl!\n"); + fail_unless(a->rsuffix->rdlength == b->rsuffix->rdlength, + "dns_record_copy failed copying rdlenth!\n"); + fail_unless(memcmp(a->rdata, b->rdata, short_be(b->rsuffix->rdlength)) == 0, + "dns_record_copy failed copying rdata!\n"); + + /* FREE memory */ + pico_dns_record_delete(&a); + pico_dns_record_delete(&b); +} +END_TEST +START_TEST(tc_pico_dns_record_delete) +{ + struct pico_dns_record *a = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + int ret = 0; + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create failed!\n"); + + /* Try to delete the created record */ + ret = pico_dns_record_delete(&a); + fail_unless(ret == 0, "pico_dns_record_delete returned NULL!\n"); + fail_unless(a == NULL, "pico_dns_record_delete failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_record_create) +{ + struct pico_dns_record *a = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + fail_unless(strcmp(a->rname, "\x7picotcp\x3com"), + "dns_record_create didn't convert url %s properly!\n", + a->rname); + fail_unless(a->rsuffix->rtype == short_be(PICO_DNS_TYPE_A), + "dns_record_create failed setting rtype!\n"); + fail_unless(a->rsuffix->rclass == short_be(PICO_DNS_CLASS_IN), + "dns_record_create failed setting rclass!\n"); + fail_unless(a->rsuffix->rttl == long_be(120), + "dns_record_create failed setting rttl!\n"); + fail_unless(a->rsuffix->rdlength == short_be(4), + "dns_record_create failed setting rdlenth!\n"); + fail_unless(memcmp(a->rdata, rdata, 4) == 0, + "dns_record_create failed setting rdata!\n"); + + /* TODO: Test PTR records */ + + pico_dns_record_delete(&a); +} +END_TEST +/* MARK: DNS record vector functions */ +START_TEST(tc_pico_dns_record_vector_init) +{ + pico_dns_record_vector rvector; + + pico_dns_record_vector_init(&rvector); + fail_unless((rvector.records == NULL && + rvector.count == 0), "dns_record_vector_init failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_record_vector_count) +{ + pico_dns_record_vector rvector = { 0 }; + struct pico_dns_record *a = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + + fail_unless(pico_dns_record_vector_count(&rvector) == 0, + "question vector count should be 0\n"); + pico_dns_record_vector_add(&rvector, a); + fail_unless(pico_dns_record_vector_count(&rvector) == 1, + "question vector count should be 1\n"); + pico_dns_record_vector_delete(&rvector, 0); + fail_unless(pico_dns_record_vector_count(&rvector) == 0, + "question vector count should be 0\n"); +} +END_TEST +START_TEST(tc_pico_dns_record_vector_add) +{ + pico_dns_record_vector rvector = { 0 }; + struct pico_dns_record *a = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + int ret = 0; + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + + ret = pico_dns_record_vector_add(&rvector, a); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + fail_unless(a == pico_dns_record_vector_get(&rvector, 0), + "DNS record not added properly!\n"); +} +END_TEST +START_TEST(tc_pico_dns_record_vector_add_copy) +{ + pico_dns_record_vector rvector = { 0 }; + struct pico_dns_record *a = NULL, *b = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + int ret = 0; + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + + /* Try to add copy of record to vector */ + ret = pico_dns_record_vector_add_copy(&rvector, a); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + fail_unless(a != (b = pico_dns_record_vector_get(&rvector, 0)), + "Pointers point to same record struct!\n"); + fail_unless(strcmp(a->rname, b->rname) == 0, + "rname isn't copied correctly!\n"); + fail_unless(a->rsuffix->rtype == b->rsuffix->rtype, + "rtype isn't copied correctly!\n"); + fail_unless(a->rsuffix->rclass == b->rsuffix->rclass, + "rclass isn't copied correctly!\n"); + fail_unless(a->rsuffix->rttl == b->rsuffix->rttl, + "rttl isn't copied correctly!\n"); + fail_unless(a->rsuffix->rdlength == b->rsuffix->rdlength, + "rdlength isn't copied correctly!\n"); + fail_unless(memcmp(a->rdata, b->rdata, short_be(b->rsuffix->rdlength)) == 0, + "rdata isn't copied correctly!\n"); + + /* FREE memory */ + pico_dns_record_delete(&a); +} +END_TEST +START_TEST(tc_pico_dns_record_vector_get) +{ + pico_dns_record_vector rvector = { 0 }; + struct pico_dns_record *a = NULL, *b = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + int ret = 0; + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + + ret = pico_dns_record_vector_add(&rvector, a); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + + b = pico_dns_record_vector_get(&rvector, 0); + fail_unless(b == a, "dns_record_vector_get failed!\n"); + + b = pico_dns_record_vector_get(&rvector, 1); + fail_unless(b == NULL, "dns_record_vector_get OOB failed!\n"); + + b = pico_dns_record_vector_get(NULL, 1); + fail_unless(b == NULL, "dns_record_vector_get NULL-ptr failed!\n"); + + /* FREE memory */ + pico_dns_record_delete(&a); +} +END_TEST +START_TEST(tc_pico_dns_record_vector_delete) +{ + pico_dns_record_vector rvector = { 0 }; + struct pico_dns_record *a = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + int ret = 0; + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + + ret = pico_dns_record_vector_add(&rvector, a); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + + ret = pico_dns_record_vector_delete(&rvector, 1); + fail_unless(ret == -1, "dns_record_vector_delete OOB failed!\n"); + + ret = pico_dns_record_vector_delete(&rvector, 0); + fail_unless(ret == 0, "dns_record_vector_delete failed!\n"); + fail_unless(pico_dns_record_vector_count(&rvector) == 0, + "dns_record_vector_delete failed with updating the count!\n"); + + ret = pico_dns_record_vector_delete(NULL, 1); + fail_unless(ret == -1, "dns_record_vector_delete NULL-ptr failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_record_vector_destroy) +{ + pico_dns_record_vector rvector = { 0 }; + struct pico_dns_record *a = NULL, *b = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + int ret = 0; + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + b = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + ret = pico_dns_record_vector_add(&rvector, a); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + ret = pico_dns_record_vector_add(&rvector, b); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + + /* Try to destroy the entire contents of the vector */ + ret = pico_dns_record_vector_destroy(&rvector); + fail_unless(ret == 0, "dns_record_vector_destroy returned error!\n"); + fail_unless((rvector.records == NULL && + rvector.count == 0), "dns_record_vector_destroy failed!\n"); + + pico_dns_record_delete(&a); + pico_dns_record_delete(&b); +} +END_TEST +START_TEST(tc_pico_dns_record_vector_size) +{ + pico_dns_record_vector rvector = { 0 }; + struct pico_dns_record *a = NULL, *b = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + int ret = 0; + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + b = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + ret = pico_dns_record_vector_add(&rvector, a); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + ret = pico_dns_record_vector_add(&rvector, b); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + + len = pico_dns_record_vector_size(&rvector); + fail_unless(len == (27 + 27), + "dns_record_vector_size failed!\n"); + len = pico_dns_record_vector_size(NULL); + fail_unless(len == 0, + "dns_record_vector_size NULL-ptr failed!\n"); + + /* FREE memory */ + pico_dns_record_delete(&a); + pico_dns_record_delete(&b); +} +END_TEST +/* MARK: DNS answer packet creation */ +START_TEST(tc_pico_dns_answer_create) +{ + pico_dns_packet *packet = NULL; + pico_dns_record_vector rvector = { 0 }; + struct pico_dns_record *a = NULL, *b = NULL; + const char *url = "picotcp.com"; + const char *url2 = "google.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + int ret = 0; + uint8_t buf[62] = { 0x00u, 0x00u, + 0x84u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x02u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x00u, 0x00u, 0x00u, 0x78u, + 0x00u, 0x04u, + 0x0Au, 0x0Au, 0x00u, 0x01u, + 0x06u, 'g','o','o','g','l','e', + 0xc0u, 0x14u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x00u, 0x00u, 0x00u, 0x78u, + 0x00u, 0x04u, + 0x0Au, 0x0Au, 0x00u, 0x01u}; + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + b = pico_dns_record_create(url2, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + ret = pico_dns_record_vector_add(&rvector, a); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + ret = pico_dns_record_vector_add(&rvector, b); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + + /* Try to create an answer packet */ + packet = pico_dns_answer_create(&rvector, NULL, NULL, &len); + fail_if (packet == NULL, "dns_answer_create returned NULL!\n"); + fail_unless(0 == memcmp((void *)packet, (void *)buf, 62), + "dns_answer_create failed!\n"); +} +END_TEST +/* MARK: Name conversion and compression functions */ +START_TEST(tc_pico_dns_namelen_comp) +{ + char name[] = "\3www\4tass\2be\0"; + char name_comp[] = "\3www\4tass\2be\xc0\x02"; /* two bytes ofset from start of buf */ + unsigned int ret = 0; + + /* name without compression */ + ret = pico_dns_namelen_comp(name); + fail_unless(ret == 12, "Namelength is wrong!\n"); + + /* name with compression */ + ret = pico_dns_namelen_comp(name_comp); + fail_unless(ret == 13, "Namelength is wrong!\n"); +} +END_TEST +START_TEST(tc_pico_dns_namelen_uncomp) +{ + char name[] = "\3www\4tass\2be\0"; + char name_comp[] = "\3www\4tass\2be\xc0\x02"; /* two bytes ofset from start of buf */ + char name_comp2[] = "\xc0\x00"; + char buf[] = "00\5index\0"; + unsigned int ret = 0; + + /* name without compression */ + ret = pico_dns_namelen_uncomp(name, (pico_dns_packet *)buf); + fail_unless(ret == 12, "Namelength '%d' is wrong with no pointer!\n", ret); + /* name with compression */ + ret = pico_dns_namelen_uncomp(name_comp, (pico_dns_packet *)buf); + fail_unless(ret == 18, "Namelength '%d' is wrong with pointer!\n", ret); + + /* name with compression, but with name as 'buf' */ + ret = pico_dns_namelen_uncomp(name_comp2, (pico_dns_packet *)name); + fail_unless(ret == 12, "Namelength '%d' is wrong with only pointer!\n", ret); +} +END_TEST +START_TEST(tc_pico_dns_decompress_name) +{ + char name[] = "\4mail\xc0\x02"; + char name2[] = "\xc0\x02"; + char buf[] = "00\6google\3com"; + char *ret; + + /* Test normal DNS name compression */ + ret = pico_dns_decompress_name(name, (pico_dns_packet *)buf); + + /* Fail conditions */ + fail_unless(ret != NULL, "Name ptr returned is NULL"); + fail_unless(strcmp(ret, "\4mail\6google\3com") == 0, "Not correctly decompressed: '%s'!\n", ret); + + /* Free memory */ + PICO_FREE(ret); + ret = NULL; + + /* Test when there is only a pointer */ + ret = pico_dns_decompress_name(name2, (pico_dns_packet *)buf); + + /* Fail conditions */ + fail_unless(ret != NULL, "Name ptr returned is NULL"); + fail_unless(strcmp(ret, "\6google\3com") == 0, "Not correctly decompressed: '%s'!\n", ret); + + /* Free memory */ + PICO_FREE(ret); + ret = NULL; +} +END_TEST +START_TEST(tc_pico_dns_url_get_reverse_len) +{ + const char *url_ipv4 = "10.10.0.1"; + const char *url_ipv6 = "2001:0db8:0000:0000:0000:0000:0000:0000"; + uint16_t arpalen = 0; + uint16_t len = 0; + + /* Try to determine the reverse length of the IPv4 URL */ + len = pico_dns_url_get_reverse_len(url_ipv4, &arpalen, PICO_PROTO_IPV4); + fail_unless(len == (9 + 2) && arpalen == 13, + "dns_url_get_reverse_len failed with IPv4 URL!\n"); + + /* Try to determine the reverse length of the IPv6 URL */ + len = pico_dns_url_get_reverse_len(url_ipv6, &arpalen, PICO_PROTO_IPV6); + fail_unless(len == (63 + 2) && arpalen == 9, + "dns_url_get_reverse_len failed with IPv4 URL!\n"); + + len = pico_dns_url_get_reverse_len(NULL, NULL, PICO_PROTO_IPV4); + fail_unless(len == 0, "dns_url_get_reverse_len with NULL-ptrs failed!\n"); +} +END_TEST +START_TEST(tc_pico_dns_url_to_reverse_qname) +{ + const char *url_ipv4 = "10.10.0.1"; + const char *url_ipv6 = "2001:0db8:0000:0000:0000:0000:0000:0000"; + const char *qname = NULL; + char cmp_buf1[24] = { 0x01, '1', + 0x01, '0', + 0x02, '1','0', + 0x02, '1','0', + 0x07, 'i','n','-','a','d','d','r', + 0x04, 'a','r','p','a', + 0x00}; + char cmp_buf[74] = { 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '0', 0x01u, '0', 0x01u, '0', 0x01u, '0', + 0x01u, '8', 0x01u, 'b', 0x01u, 'd', 0x01u, '0', + 0x01u, '1', 0x01u, '0', 0x01u, '0', 0x01u, '2', + 0x03u, 'I','P','6', + 0x04u, 'A','R','P','A', + 0x00u }; + + /* Try to reverse IPv4 URL */ + qname = pico_dns_url_to_reverse_qname(url_ipv4, PICO_PROTO_IPV4); + fail_unless(qname != NULL, "dns_url_to_reverse_qname returned NULL!\n"); + fail_unless(strcmp(qname, cmp_buf1) == 0, + "dns_url_to_reverse_qname failed with IPv4!\n"); + PICO_FREE(qname); + + /* Try to reverse IPv6 URL */ + qname = pico_dns_url_to_reverse_qname(url_ipv6, PICO_PROTO_IPV6); + fail_unless(qname != NULL, "dns_url_to_reverse_qname returned NULL!\n"); + fail_unless(strcmp(qname, cmp_buf) == 0, + "dns_url_to_reverse_qname failed with IPv6!\n"); + PICO_FREE(qname); +} +END_TEST +START_TEST(tc_pico_dns_qname_to_url) +{ + char qname[24] = { 0x01, '1', + 0x01, '0', + 0x02, '1','0', + 0x02, '1','0', + 0x07, 'i','n','-','a','d','d','r', + 0x04, 'a','r','p','a', + 0x00 }; + char qname2[13] = { 0x07, 'p','i','c','o','t','c','p', + 0x03, 'c','o','m', + 0x00 }; + char qname3[14] = { 0x08, 'p','i','c','o', '\.','t','c','p', + 0x03, 'c','o','m', + 0x00 }; + char *url = NULL; + + /* Try to convert qname to url */ + url = pico_dns_qname_to_url(qname); + fail_unless(url != NULL, "dns_qname_to_url returned NULL!\n"); + fail_unless(strcmp(url, "1.0.10.10.in-addr.arpa") == 0, + "dns_qname_to_url failed %s!\n", url); + PICO_FREE(url); + + /* Try to convert qname2 to url */ + url = pico_dns_qname_to_url(qname2); + fail_unless(url != NULL, "dns_qname_to_url returned NULL!\n"); + fail_unless(strcmp(url, "picotcp.com") == 0, + "dns_qname_to_url failed %s!\n", url); + PICO_FREE(url); + + /* Try to convert qname2 to url */ + url = pico_dns_qname_to_url(qname3); + fail_unless(url != NULL, "dns_qname_to_url returned NULL!\n"); + fail_unless(strcmp(url, "pico.tcp.com") == 0, + "dns_qname_to_url failed %s!\n", url); + PICO_FREE(url); +} +END_TEST +START_TEST(tc_pico_dns_url_to_qname) +{ + char qname1[24] = { 0x01, '1', + 0x01, '0', + 0x02, '1','0', + 0x02, '1','0', + 0x07, 'i','n','-','a','d','d','r', + 0x04, 'a','r','p','a', + 0x00 }; + char qname2[13] = { 0x07, 'p','i','c','o','t','c','p', + 0x03, 'c','o','m', + 0x00 }; + char *qname = NULL; + + /* Try to convert url to qname1 */ + qname = pico_dns_url_to_qname("1.0.10.10.in-addr.arpa"); + fail_unless(qname != NULL, "dns_url_to_qname returned NULL!\n"); + fail_unless(strcmp(qname, qname1) == 0, + "dns_url_to_qname failed %s!\n", qname); + PICO_FREE(qname); + + /* Try to convert url to qname2 */ + qname = pico_dns_url_to_qname("picotcp.com"); + fail_unless(qname != NULL, "dns_url_to_qname returned NULL!\n"); + fail_unless(strcmp(qname, qname2) == 0, + "dns_url_to_qname failed %s!\n", qname); + PICO_FREE(qname); +} +END_TEST +START_TEST(tc_pico_dns_name_to_dns_notation) +{ + char qname1[13] = { 0x07, 'p','i','c','o','t','c','p', + 0x03, 'c','o','m', + 0x00 }; + char url1[13] = { 0x00,'p','i','c','o','t','c','p','.','c','o','m',0x00 }; + int ret = 0; + + ret = pico_dns_name_to_dns_notation(url1); + fail_unless(ret == 0, "dns_name_to_dns_notation returned error!\n"); + fail_unless(strcmp(url1, qname1) == 0, + "dns_name_to_dns_notation failed! %s\n", url1); +} +END_TEST +START_TEST(tc_pico_dns_notation_to_name) +{ + char qname1[13] = { 0x07, 'p','i','c','o','t','c','p', + 0x03, 'c','o','m', + 0x00 }; + char url1[13] = { '.','p','i','c','o','t','c','p','.','c','o','m',0x00 }; + int ret = 0; + + ret = pico_dns_notation_to_name(qname1); + fail_unless(ret == 0, "dns_notation_to_name returned error!\n"); + fail_unless(strcmp(url1, qname1) == 0, + "dns_notation_to_name failed! %s\n", qname1); +} +END_TEST +START_TEST(tc_pico_dns_mirror_addr) +{ + char url[12] = "192.168.0.1"; + int8_t ret = 0; + + ret = pico_dns_mirror_addr(url); + fail_unless(ret == 0, "dns_mirror_addr returned error!\n"); + fail_unless(strcmp(url, "1.0.168.192") == 0, + "dns_mirror_addr failed!\n"); +} +END_TEST +START_TEST(tc_dns_ptr_ip6_nibble_lo) +{ + uint8_t byte = 0x34; + char nibble_lo = 0; + + nibble_lo = dns_ptr_ip6_nibble_lo(byte); + fail_unless(nibble_lo == '4', "dns_ptr_ip6_nibble_lo failed!\n"); +} +END_TEST +START_TEST(tc_dns_ptr_ip6_nibble_hi) +{ + uint8_t byte = 0x34; + char nibble_hi = 0; + + nibble_hi = dns_ptr_ip6_nibble_hi(byte); + fail_unless(nibble_hi == '3', "dns_ptr_ip6_nibble_hi failed! '%c'\n", + nibble_hi); +} +END_TEST +START_TEST(tc_pico_dns_ipv6_set_ptr) +{ + const char *url_ipv6 = "2001:0db8:0000:0000:0000:0000:0000:0000"; + + char cmpbuf[65] = { '0', '.', '0', '.', '0', '.', '0', '.', + '0', '.', '0', '.', '0', '.', '0', '.', + '0', '.', '0', '.', '0', '.', '0', '.', + '0', '.', '0', '.', '0', '.', '0', '.', + '0', '.', '0', '.', '0', '.', '0', '.', + '0', '.', '0', '.', '0', '.', '0', '.', + '8', '.', 'b', '.', 'd', '.', '0', '.', + '1', '.', '0', '.', '0', '.', '2', '.', 0x00 }; + char buf[65] = {}; + + pico_dns_ipv6_set_ptr(url_ipv6, buf); + fail_unless(strcmp(buf, cmpbuf) == 0, + "dns_ipv6_set_ptr failed!\n"); +} +END_TEST + +Suite *pico_suite(void) +{ + Suite *s = suite_create("PicoTCP"); + + /* DNS packet section filling */ + TCase *TCase_pico_dns_fill_packet_header = tcase_create("Unit test for 'pico_dns_fill_packet_header'"); + TCase *TCase_pico_dns_fill_packet_rr_sections = tcase_create("Unit test for 'pico_dns_fill_packet_rr_sections'"); + TCase *TCase_pico_dns_fill_packet_question_section = tcase_create("Unit test for 'pico_dns_fill_packet_question_sections'"); + + /* DNS packet compression */ + TCase *TCase_pico_dns_packet_compress_find_ptr = tcase_create("Unit test for 'pico_dns_packet_compress_find_ptr'"); + TCase *TCase_pico_dns_packet_compress_name = tcase_create("Unit test for 'pico_dns_packet_compress_name'"); + TCase *TCase_pico_dns_packet_compress = tcase_create("Unit test for 'pico_dns_packet_compress'"); + + /* DNS question functions */ + TCase *TCase_pico_dns_question_fill_qsuffix = tcase_create("Unit test for 'pico_dns_question_fill_qsuffix'"); + TCase *TCase_pico_dns_question_copy = tcase_create("Unit test for 'pico_dns_question_copy'"); + TCase *TCase_pico_dns_question_delete = tcase_create("Unit test for 'pico_dns_question_delete'"); + TCase *TCase_pico_dns_question_create = tcase_create("Unit test for 'pico_dns_question_create'"); + + /* DNS question vector functions */ + TCase *TCase_pico_dns_question_vector_init = tcase_create("Unit test for 'pico_dns_question_vector_init'"); + TCase *TCase_pico_dns_question_vector_count = tcase_create("Unit test for 'pico_dns_question_vector_count'"); + TCase *TCase_pico_dns_question_vector_add = tcase_create("Unit test for 'pico_dns_question_vector_add'"); + TCase *TCase_pico_dns_question_vector_add_copy = tcase_create("Unit test for 'pico_dns_question_vector_add_copy'"); + TCase *TCase_pico_dns_question_vector_get = tcase_create("Unit test for 'pico_dns_question_vector_get'"); + TCase *TCase_pico_dns_question_vector_delete = tcase_create("Unit test for 'pico_dns_question_vector_delete'"); + TCase *TCase_pico_dns_question_vector_destroy = tcase_create("Unit test for 'pico_dns_question_vector_destroy'"); + TCase *TCase_pico_dns_question_vector_find_name = tcase_create("Unit test for 'pico_dns_question_vector_find_name'"); + TCase *TCase_pico_dns_question_vector_size = tcase_create("Unit test for 'pico_dns_question_vector_size'"); + + /* DNS query packet creation */ + TCase *TCase_pico_dns_query_create = tcase_create("Unit test for 'pico_dns_query_create'"); + + /* DNS resource record functions */ + TCase *TCase_pico_dns_record_fill_suffix = tcase_create("Unit test for 'pico_dns_record_fill_suffix'"); + TCase *TCase_pico_dns_record_copy_flat = tcase_create("Unit test for 'pico_dns_record_copy_flat'"); + TCase *TCase_pico_dns_record_copy = tcase_create("Unit test for 'pico_dns_record_copy'"); + TCase *TCase_pico_dns_record_delete = tcase_create("Unit test for 'pico_dns_record_delete'"); + TCase *TCAse_pico_dns_record_create = tcase_create("Unit test for 'pico_dns_record_create'"); + + /* DNS record vector funcitons */ + TCase *TCase_pico_dns_record_vector_init = tcase_create("Unit test for 'pico_dns_record_vector_init'"); + TCase *TCase_pico_dns_record_vector_count = tcase_create("Unit test for 'pico_dns_record_vector_count'"); + TCase *TCase_pico_dns_record_vector_add = tcase_create("Unit test for 'pico_dns_record_vector_add'"); + TCase *TCase_pico_dns_record_vector_add_copy = tcase_create("Unit test for 'pico_dns_record_vector_add_copy'"); + TCase *TCase_pico_dns_record_vector_get = tcase_create("Unit test for 'pico_dns_record_vector_get'"); + TCase *TCase_pico_dns_record_vector_delete = tcase_create("Unit test for 'pico_dns_record_vector_delete'"); + TCase *TCase_pico_dns_record_vector_destroy = tcase_create("Unit test for 'pico_dns_record_vector_destroy'"); + TCase *TCase_pico_dns_record_vector_size = tcase_create("Unit test for 'pico_dns_record_vector_size'"); + + /* DNS answer packet creation */ + TCase *TCase_pico_dns_answer_create = tcase_create("Unit test for 'pico_dns_answer_create'"); + + /* Name conversion and compression function */ + TCase *TCase_pico_dns_namelen_comp = tcase_create("Unit test for 'pico_dns_namelen_comp'"); + TCase *TCase_pico_dns_namelen_uncomp = tcase_create("Unit test for 'pico_dns_namelen_uncomp'"); + TCase *TCase_pico_dns_decompress_name = tcase_create("Unit test for 'pico_dns_decompress_name'"); + TCase *TCase_pico_dns_url_get_reverse_len = tcase_create("Unit test for 'pico_dns_url_get_reverse_len'"); + TCase *TCase_pico_dns_url_to_reverse_qname = tcase_create("Unit test for 'pico_dns_url_to_reverse_qname'"); + TCase *TCase_pico_dns_qname_to_url = tcase_create("Unit test for 'pico_dns_qname_to_url'"); + TCase *TCase_pico_dns_url_to_qname = tcase_create("Unit test for 'pico_dns_url_to_qname'"); + TCase *TCase_pico_dns_name_to_dns_notation = tcase_create("Unit test for 'pico_dns_name_to_dns_notation'"); + TCase *TCase_pico_dns_notation_to_name = tcase_create("Unit test for 'pico_dns_notation_to_name'"); + TCase *TCase_pico_dns_mirror_addr = tcase_create("Unit test for 'pico_dns_mirror_addr'"); + TCase *TCase_dns_ptr_ip6_nibble_lo = tcase_create("Unit test for 'dns_ptr_ip6_nibble_lo'"); + TCase *TCase_dns_ptr_ip6_nibble_hi = tcase_create("Unit test for 'dns_ptr_ip6_nibble_hi'"); + TCase *TCase_pico_dns_ipv6_set_ptr = tcase_create("Unit test for 'pico_dns_ipv6_set_ptr'"); + + tcase_add_test(TCase_pico_dns_fill_packet_header, tc_pico_dns_fill_packet_header); + tcase_add_test(TCase_pico_dns_fill_packet_rr_sections, tc_pico_dns_fill_packet_rr_sections); + tcase_add_test(TCase_pico_dns_fill_packet_question_section, tc_pico_dns_fill_packet_question_section); + tcase_add_test(TCase_pico_dns_packet_compress_find_ptr, tc_pico_dns_packet_compress_find_ptr); + tcase_add_test(TCase_pico_dns_packet_compress_name, tc_pico_dns_packet_compress_name); + tcase_add_test(TCase_pico_dns_packet_compress, tc_pico_dns_packet_compress); + tcase_add_test(TCase_pico_dns_question_fill_qsuffix, tc_pico_dns_question_fill_qsuffix); + tcase_add_test(TCase_pico_dns_question_copy, tc_pico_dns_question_copy); + tcase_add_test(TCase_pico_dns_question_delete, tc_pico_dns_question_delete); + tcase_add_test(TCase_pico_dns_question_create, tc_pico_dns_question_create); + tcase_add_test(TCase_pico_dns_question_vector_init, tc_pico_dns_question_vector_init); + tcase_add_test(TCase_pico_dns_question_vector_count, tc_pico_dns_question_vector_count); + tcase_add_test(TCase_pico_dns_question_vector_add, tc_pico_dns_question_vector_add); + tcase_add_test(TCase_pico_dns_question_vector_add_copy, tc_pico_dns_question_vector_add_copy); + tcase_add_test(TCase_pico_dns_question_vector_get, tc_pico_dns_question_vector_get); + tcase_add_test(TCase_pico_dns_question_vector_delete, tc_pico_dns_question_vector_delete); + tcase_add_test(TCase_pico_dns_question_vector_destroy, tc_pico_dns_question_vector_destroy); + tcase_add_test(TCase_pico_dns_question_vector_find_name, tc_pico_dns_question_vector_find_name); + tcase_add_test(TCase_pico_dns_question_vector_size, tc_pico_dns_question_vector_size); + tcase_add_test(TCase_pico_dns_query_create, tc_pico_dns_query_create); + tcase_add_test(TCase_pico_dns_record_fill_suffix, tc_pico_dns_record_fill_suffix); + tcase_add_test(TCase_pico_dns_record_copy_flat, tc_pico_dns_record_copy_flat); + tcase_add_test(TCase_pico_dns_record_copy, tc_pico_dns_record_copy); + tcase_add_test(TCase_pico_dns_record_delete, tc_pico_dns_record_delete); + tcase_add_test(TCAse_pico_dns_record_create, tc_pico_dns_record_create); + tcase_add_test(TCase_pico_dns_record_vector_init, tc_pico_dns_record_vector_init); + tcase_add_test(TCase_pico_dns_record_vector_count, tc_pico_dns_record_vector_count); + tcase_add_test(TCase_pico_dns_record_vector_add, tc_pico_dns_record_vector_add); + tcase_add_test(TCase_pico_dns_record_vector_add_copy, tc_pico_dns_record_vector_add_copy); + tcase_add_test(TCase_pico_dns_record_vector_get, tc_pico_dns_record_vector_get); + tcase_add_test(TCase_pico_dns_record_vector_delete, tc_pico_dns_record_vector_delete); + tcase_add_test(TCase_pico_dns_record_vector_destroy, tc_pico_dns_record_vector_destroy); + tcase_add_test(TCase_pico_dns_record_vector_size, tc_pico_dns_record_vector_size); + tcase_add_test(TCase_pico_dns_answer_create, tc_pico_dns_answer_create); + tcase_add_test(TCase_pico_dns_namelen_comp, tc_pico_dns_namelen_comp); + tcase_add_test(TCase_pico_dns_namelen_uncomp, tc_pico_dns_namelen_uncomp); + tcase_add_test(TCase_pico_dns_decompress_name, tc_pico_dns_decompress_name); + tcase_add_test(TCase_pico_dns_url_get_reverse_len, tc_pico_dns_url_get_reverse_len); + tcase_add_test(TCase_pico_dns_url_to_reverse_qname, tc_pico_dns_url_to_reverse_qname); + tcase_add_test(TCase_pico_dns_qname_to_url, tc_pico_dns_qname_to_url); + tcase_add_test(TCase_pico_dns_url_to_qname, tc_pico_dns_url_to_qname); + tcase_add_test(TCase_pico_dns_name_to_dns_notation, tc_pico_dns_name_to_dns_notation); + tcase_add_test(TCase_pico_dns_notation_to_name, tc_pico_dns_notation_to_name); + tcase_add_test(TCase_pico_dns_mirror_addr, tc_pico_dns_mirror_addr); + tcase_add_test(TCase_dns_ptr_ip6_nibble_lo, tc_dns_ptr_ip6_nibble_lo); + tcase_add_test(TCase_dns_ptr_ip6_nibble_hi, tc_dns_ptr_ip6_nibble_hi); + tcase_add_test(TCase_pico_dns_ipv6_set_ptr, tc_pico_dns_ipv6_set_ptr); + + suite_add_tcase(s, TCase_pico_dns_fill_packet_header); + suite_add_tcase(s, TCase_pico_dns_fill_packet_rr_sections); + suite_add_tcase(s, TCase_pico_dns_fill_packet_question_section); + suite_add_tcase(s, TCase_pico_dns_packet_compress_find_ptr); + suite_add_tcase(s, TCase_pico_dns_packet_compress_name); + suite_add_tcase(s, TCase_pico_dns_packet_compress); + suite_add_tcase(s, TCase_pico_dns_question_fill_qsuffix); + suite_add_tcase(s, TCase_pico_dns_question_copy); + suite_add_tcase(s, TCase_pico_dns_question_delete); + suite_add_tcase(s, TCase_pico_dns_question_create); + suite_add_tcase(s, TCase_pico_dns_question_vector_init); + suite_add_tcase(s, TCase_pico_dns_question_vector_count); + suite_add_tcase(s, TCase_pico_dns_question_vector_add); + suite_add_tcase(s, TCase_pico_dns_question_vector_add_copy); + suite_add_tcase(s, TCase_pico_dns_question_vector_get); + suite_add_tcase(s, TCase_pico_dns_question_vector_delete); + suite_add_tcase(s, TCase_pico_dns_question_vector_destroy); + suite_add_tcase(s, TCase_pico_dns_question_vector_find_name); + suite_add_tcase(s, TCase_pico_dns_question_vector_size); + suite_add_tcase(s, TCase_pico_dns_query_create); + suite_add_tcase(s, TCase_pico_dns_record_fill_suffix); + suite_add_tcase(s, TCase_pico_dns_record_copy); + suite_add_tcase(s, TCase_pico_dns_record_delete); + suite_add_tcase(s, TCAse_pico_dns_record_create); + suite_add_tcase(s, TCase_pico_dns_record_vector_init); + suite_add_tcase(s, TCase_pico_dns_record_vector_count); + suite_add_tcase(s, TCase_pico_dns_record_vector_add); + suite_add_tcase(s, TCase_pico_dns_record_vector_add_copy); + suite_add_tcase(s, TCase_pico_dns_record_vector_get); + suite_add_tcase(s, TCase_pico_dns_record_vector_delete); + suite_add_tcase(s, TCase_pico_dns_record_vector_destroy); + suite_add_tcase(s, TCase_pico_dns_record_vector_size); + suite_add_tcase(s, TCase_pico_dns_answer_create); + suite_add_tcase(s, TCase_pico_dns_namelen_comp); + suite_add_tcase(s, TCase_pico_dns_namelen_uncomp); + suite_add_tcase(s, TCase_pico_dns_decompress_name); + suite_add_tcase(s, TCase_pico_dns_url_get_reverse_len); + suite_add_tcase(s, TCase_pico_dns_url_to_reverse_qname); + suite_add_tcase(s, TCase_pico_dns_qname_to_url); + suite_add_tcase(s, TCase_pico_dns_url_to_qname); + suite_add_tcase(s, TCase_pico_dns_name_to_dns_notation); + suite_add_tcase(s, TCase_pico_dns_notation_to_name); + suite_add_tcase(s, TCase_pico_dns_mirror_addr); + suite_add_tcase(s, TCase_dns_ptr_ip6_nibble_lo); + suite_add_tcase(s, TCase_dns_ptr_ip6_nibble_hi); + suite_add_tcase(s, TCase_pico_dns_ipv6_set_ptr); + + return s; +} + +int main(void) +{ + int fails; + Suite *s = pico_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + fails = srunner_ntests_failed(sr); + srunner_free(sr); + return fails; +} + diff --git a/test/unit/modunit_pico_dns_sd.c b/test/unit/modunit_pico_dns_sd.c new file mode 100644 index 000000000..abef6059b --- /dev/null +++ b/test/unit/modunit_pico_dns_sd.c @@ -0,0 +1,438 @@ +#include "pico_config.h" +#include "pico_stack.h" +#include "pico_addressing.h" +#include "pico_socket.h" +#include "pico_ipv4.h" +#include "pico_ipv6.h" +#include "pico_dns_common.h" +#include "pico_tree.h" +#include "pico_dev_mock.c" +#include "pico_mdns.c" +#include "modules/pico_dns_sd.c" +#include "check.h" + +void callback( pico_mdns_record_vector *vector, + char *str, + void *arg ) +{ + /* This doesn't even gets called, tests exit before possible callback */ + IGNORE_PARAMETER(str); + IGNORE_PARAMETER(arg); + IGNORE_PARAMETER(vector); +} + +int dns_sd_init() +{ + struct mock_device *mock = NULL; + + struct pico_ip4 local = {.addr = long_be(0x0a280064)}; + struct pico_ip4 netmask = {.addr = long_be(0xffffff00)}; + + mock = pico_mock_create(NULL); + if (!mock) + return -1; + + pico_ipv4_link_add(mock->dev, local, netmask); + + /* Try to initialise the mDNS module right */ + return pico_dns_sd_init("host.local", pico_ipv4_link_by_dev(mock->dev), 0, + callback, NULL); +} + +START_TEST(tc_dns_sd_kv_vector_strlen) +{ + kv_vector pairs = {0}; + + pico_dns_sd_kv_vector_add(&pairs, "textvers", "1"); + pico_dns_sd_kv_vector_add(&pairs, "pass", NULL); + pico_dns_sd_kv_vector_add(&pairs, "color", ""); + + fail_unless(pico_dns_sd_kv_vector_strlen(&pairs) == 23, + "dns_sd_kv_vector_strlen returned wrong length!\n"); + + pico_dns_sd_kv_vector_erase(&pairs); +} +END_TEST +START_TEST(tc_dns_sd_srv_record_create) +{ + struct pico_mdns_record *record = NULL; + + uint8_t buf[19] = { 0,0, 0,0, 0,80, + 5,'h','i','t','e','x', + 5,'l','o','c','a','l', + 0 }; + + record = pico_dns_sd_srv_record_create("test.local", 0, 0, 80, + "hitex.local", 10, + PICO_MDNS_RECORD_UNIQUE); + + fail_unless(strcmp(record->record->rname, "\4test\5local") == 0, + "Name of SRV record not correct!\n"); + fail_unless(short_be(record->record->rsuffix->rtype) == 33, + "Type of SRV record not correctly set!\n"); + fail_unless(short_be(record->record->rsuffix->rclass) == 0x8001, + "Class of SRV record not correctly set!\n"); + fail_unless(short_be(record->record->rsuffix->rdlength) == 19, + "rdlength of SRV record not correctly set!\n"); + fail_unless(long_be(record->record->rsuffix->rttl) == 10, + "TTL of SRV record not correctly set!\n"); + fail_unless(memcmp(record->record->rdata, buf, 19) == 0, + "Rdata of TXT record not correctly set!\n"); + pico_mdns_record_delete(&record); +} +END_TEST +START_TEST(tc_dns_sd_txt_record_create) +{ + struct pico_mdns_record *record = NULL; + kv_vector pairs = {0}; + + uint8_t buf[23] = { 10,'t','e','x','t','v','e','r','s','=','1', + 4,'p','a','s','s', + 6,'c','o','l','o','r','=' }; + + pico_dns_sd_kv_vector_add(&pairs, "textvers", "1"); + pico_dns_sd_kv_vector_add(&pairs, "pass", NULL); + pico_dns_sd_kv_vector_add(&pairs, "color", ""); + + record = pico_dns_sd_txt_record_create("test.local", pairs, 10, + PICO_MDNS_RECORD_UNIQUE); + + fail_unless(strcmp(record->record->rname, "\4test\5local") == 0, + "Name of TXT record not correct!\n"); + fail_unless(short_be(record->record->rsuffix->rtype) == 16, + "Type of TXT record not correctly set!\n"); + fail_unless(short_be(record->record->rsuffix->rclass) == 0x8001, + "Class of TXT record not correctly set!\n"); + fail_unless(short_be(record->record->rsuffix->rdlength) == 23, + "rdlength of TXT record not correctly set!\n"); + fail_unless(long_be(record->record->rsuffix->rttl) == 10, + "TTL of TXT record not correctly set!\n"); + fail_unless(memcmp(record->record->rdata, buf, 23) == 0, + "Rdata of TXT record not correctly set!\n"); + pico_mdns_record_delete(&record); +} +END_TEST +START_TEST(tc_dns_sd_kv_create) +{ + key_value_pair_t *pair = NULL; + + pair = pico_dns_sd_kv_create("textvers", "1"); + fail_unless(strcmp(pair->key, "textvers") == 0, + "dns_sd_kv_create failed!\n"); + fail_unless(strcmp(pair->value, "1") == 0, + "dns_sd_kv_create failed!\n"); + PICO_FREE(pair->key); + PICO_FREE(pair->value); + PICO_FREE(pair); + + pair = pico_dns_sd_kv_create("textvers", NULL); + fail_unless(strcmp(pair->key, "textvers") == 0, + "dns_sd_kv_create failed!\n"); + fail_unless(pair->value == NULL, + "dns_sd_kv_create failed!\n"); + PICO_FREE(pair->key); + PICO_FREE(pair); + + pair = pico_dns_sd_kv_create("textvers", ""); + fail_unless(strcmp(pair->key, "textvers") == 0, + "dns_sd_kv_create failed!\n"); + fail_unless(strcmp(pair->value, "") == 0, + "dns_sd_kv_create failed!\n"); + PICO_FREE(pair->key); + PICO_FREE(pair->value); + PICO_FREE(pair); +} +END_TEST +START_TEST(tc_dns_sd_kv_delete) +{ + key_value_pair_t *pair = NULL; + + pair = pico_dns_sd_kv_create("textvers", "1"); + fail_unless(strcmp(pair->key, "textvers") == 0, + "dns_sd_kv_create failed!\n"); + fail_unless(strcmp(pair->value, "1") == 0, + "dns_sd_kv_create failed!\n"); + pico_dns_sd_kv_delete(&pair); + fail_unless(pair == NULL, + "dns_sd_kv_delete failed!\n"); + + pair = pico_dns_sd_kv_create("textvers", NULL); + fail_unless(strcmp(pair->key, "textvers") == 0, + "dns_sd_kv_create failed!\n"); + fail_unless(pair->value == NULL, + "dns_sd_kv_create failed!\n"); + pico_dns_sd_kv_delete(&pair); + fail_unless(pair == NULL, + "dns_sd_kv_delete failed!\n"); + + pair = pico_dns_sd_kv_create("textvers", ""); + fail_unless(strcmp(pair->key, "textvers") == 0, + "dns_sd_kv_create failed!\n"); + fail_unless(strcmp(pair->value, "") == 0, + "dns_sd_kv_create failed!\n"); + pico_dns_sd_kv_delete(&pair); + fail_unless(pair == NULL, + "dns_sd_kv_delete failed!\n"); +} +END_TEST +START_TEST(tc_dns_sd_first_label_length) +{ + fail_unless(pico_dns_sd_first_label_length("vlees..local") == 5, + "dns_sd_first_label_length failed!\n"); +} +END_TEST +START_TEST(tc_dns_sd_check_type_format) +{ + fail_unless(pico_dns_sd_check_type_format("_http._tcp") == 0, + "dns_sd_check_type_format failed with correct format!\n"); + fail_unless(pico_dns_sd_check_type_format("_printer._sub._http._tcp") + == 0, + "dns_sd_check_type_format failed with subtype!\n"); + + /* Test too long subtype */ + fail_unless(pico_dns_sd_check_type_format( +"1234567891123456789212345678931234567894123456789512345678961234._sub._http._tcp"), "dns_sd_check_type_format failed with too big subtype!\n"); + + /* Test too long service type with subtype */ + fail_unless(pico_dns_sd_check_type_format( + "printer._sub.0123456789112345678._tcp"), + "dns_sd_check_type_format failed with too big sn w/ sub!\n"); + + /* Test too long service type with subtype */ + fail_unless(pico_dns_sd_check_type_format("0123456789112345678._tcp"), + "dns_sd_check_type_format failed with too big sn!\n"); + +} +END_TEST +START_TEST(tc_dns_sd_check_instance_name_format) +{ + /* Test too long name */ + fail_unless(pico_dns_sd_check_instance_name_format( +"1234567891123456789212345678931234567894123456789512345678961234"), + "dns_sd_check_instance_name_format failed with too big name!\n"); + + fail_unless(pico_dns_sd_check_instance_name_format("Hello World!") == 0, + "dns_sd_check_instance_name_format failed!\n"); +} +END_TEST +START_TEST(tc_dns_sd_create_service_url) +{ + char *service_url = NULL; + + service_url = pico_dns_sd_create_service_url("Hello World!", "_http._tcp"); + + fail_unless(strcmp(service_url, "Hello World!._http._tcp.local") == 0, + "dns_sd_create_service_url failed!\n"); +} +END_TEST +START_TEST(tc_dns_sd_claimed_callback) +{ + pico_mdns_record_vector vector = {0}; + struct register_argument *test = NULL; + struct pico_mdns_record *ptr_record = NULL, *srv_record = NULL; + char *name = "Hello World!"; + char *url = "Hello World!._http._tcp.local"; + + pico_stack_init(); + dns_sd_init(); + + /* Create the shared PTR record */ + ptr_record = pico_mdns_record_create((char *)(url + strlen(name) + 1u), + (void *)url, (uint16_t)strlen(url), + PICO_DNS_TYPE_PTR, + 120, PICO_MDNS_RECORD_SHARED); + + /* Create a SRV record to pass in */ + srv_record = pico_dns_sd_srv_record_create(url, 0, 0, 80, "host.local", + 120, PICO_MDNS_RECORD_UNIQUE); + pico_mdns_record_vector_add(&vector, srv_record); + + test = PICO_ZALLOC(sizeof(struct register_argument)); + test->ptr_record = ptr_record; + test->callback = callback; + test->arg = NULL; + + /* Check if no errors occur */ + pico_dns_sd_claimed_callback(NULL, NULL, NULL); + pico_dns_sd_claimed_callback(NULL, NULL, test); + pico_dns_sd_claimed_callback(&vector, NULL, test); +} +END_TEST +START_TEST(tc_dns_sd_init) +{ + pico_stack_init(); + fail_unless(dns_sd_init() == 0, + "dns_sd_init failed!\n"); +} +END_TEST +START_TEST(tc_dns_sd_register_service) +{ + kv_vector vector = {0}; + + pico_stack_init(); + dns_sd_init(); + + fail_unless(pico_dns_sd_register_service("Hello World!", + "_kerberos._udp", + 88, &vector, 120, + callback, NULL) == 0, + "dns_sd_register_service failed!\n"); +} +END_TEST +START_TEST(tc_dns_sd_browse_service) +{ + /* Not implemented in code */ +} +END_TEST +START_TEST(tc_dns_sd_kv_vector_init) +{ + kv_vector test; + + pico_dns_sd_kv_vector_init(&test); + + fail_unless(test.pairs == NULL, + "dns_sd_kv_vector_init failed!\n"); + fail_unless(test.count == 0, + "dns_sd_kv_vector_init failed!\n"); +} +END_TEST +START_TEST(tc_dns_sd_kv_vector_add) +{ + kv_vector pairs = {0}; + char *key = NULL; + + pico_dns_sd_kv_vector_add(&pairs, "textvers", "1"); + pico_dns_sd_kv_vector_add(&pairs, "pass", NULL); + pico_dns_sd_kv_vector_add(&pairs, "color", ""); + + key = pico_dns_sd_kv_vector_get(&pairs, 2)->key; + fail_unless(strcmp("color", key) == 0, + "dns_sd_kv_vector_add failed!\n"); +} +END_TEST +START_TEST(tc_dns_sd_kv_vector_get) +{ + kv_vector pairs = {0}; + char *key = NULL; + + pico_dns_sd_kv_vector_add(&pairs, "textvers", "1"); + pico_dns_sd_kv_vector_add(&pairs, "pass", NULL); + pico_dns_sd_kv_vector_add(&pairs, "color", ""); + + key = pico_dns_sd_kv_vector_get(&pairs, 2)->key; + fail_unless(strcmp("color", key) == 0, + "dns_sd_kv_vector_get failed!\n"); + + fail_unless(pico_dns_sd_kv_vector_get(&pairs, 3) == NULL, + "dns_sd_kv_vector_get failed @ OOB!\n"); +} +END_TEST +START_TEST(tc_dns_sd_kv_vector_erase) +{ + kv_vector pairs = {0}; + + pico_dns_sd_kv_vector_add(&pairs, "textvers", "1"); + pico_dns_sd_kv_vector_add(&pairs, "pass", NULL); + pico_dns_sd_kv_vector_add(&pairs, "color", ""); + + pico_dns_sd_kv_vector_erase(&pairs); + + fail_unless(pairs.pairs == NULL, + "dns_sd_kv_vector_erase failed!\n"); + fail_unless(pairs.count == 0, + "dns_sd_kv_vector_erase failed!\n"); +} +END_TEST + +Suite *pico_suite(void) +{ + Suite *s = suite_create("PicoTCP"); + + /* Key-Value pair vector plain creation function */ + TCase *TCase_dns_sd_kv_vector_strlen = tcase_create("Unit test for dns_sd_kv_vector_strlen"); + + /* DNS utility functions */ + TCase *TCase_dns_sd_srv_record_create = tcase_create("Unit test for dns_sd_srv_record_create"); + TCase *TCase_dns_sd_txt_record_create = tcase_create("Unit test for dns_sd_txt_record_create"); + + /* Key-Value pair creation */ + TCase *TCase_dns_sd_kv_create = tcase_create("Unit test for dns_sd_kv_create"); + TCase *TCase_dns_sd_kv_delete = tcase_create("Unit test for dns_sd_kv_delete"); + + /* Utility functions */ + TCase *TCase_dns_sd_first_label_length = tcase_create("Unit test for dns_sd_first_label_length"); + TCase *TCase_dns_sd_check_type_format = tcase_create("Unit test for dns_sd_check_type_format"); + TCase *TCase_dns_sd_check_instance_name_format = tcase_create("Unit test for dns_sd_check_instance_name_format"); + TCase *TCase_dns_sd_create_service_url = tcase_create("Unit test for dns_sd_create_service_url"); + TCase *TCase_dns_sd_claimed_callback = tcase_create("Unit test for dns_sd_claimed_callback"); + + /* DNS SD API functions */ + TCase *TCase_dns_sd_init = tcase_create("Unit test for dns_sd_init"); + TCase *TCase_dns_sd_register_service = tcase_create("Unit test for dns_sd_register_service"); + TCase *TCase_dns_sd_browse_service = tcase_create("Unit test for dns_sd_browse_service"); + + /* Key-Value vector functions */ + TCase *TCase_dns_sd_kv_vector_init = tcase_create("Unit test for dns_sd_kv_vector_init"); + TCase *TCase_dns_sd_kv_vector_add = tcase_create("Unit test for dns_sd_kv_vector_add"); + TCase *TCase_dns_sd_kv_vector_get = tcase_create("Unit test for dns_sd_kv_vector_get"); + TCase *TCase_dns_sd_kv_vector_erase = tcase_create("Unit test for dns_sd_kv_vector_erase"); + + /* Key-Value pair vector plain creation function */ + tcase_add_test(TCase_dns_sd_kv_vector_strlen, tc_dns_sd_kv_vector_strlen); + suite_add_tcase(s, TCase_dns_sd_kv_vector_strlen); + + /* DNS utility functions */ + tcase_add_test(TCase_dns_sd_srv_record_create, tc_dns_sd_srv_record_create); + suite_add_tcase(s, TCase_dns_sd_srv_record_create); + tcase_add_test(TCase_dns_sd_txt_record_create, tc_dns_sd_txt_record_create); + suite_add_tcase(s, TCase_dns_sd_txt_record_create); + + /* Key-Value pair creation */ + tcase_add_test(TCase_dns_sd_kv_create, tc_dns_sd_kv_create); + suite_add_tcase(s, TCase_dns_sd_kv_create); + tcase_add_test(TCase_dns_sd_kv_delete, tc_dns_sd_kv_delete); + suite_add_tcase(s, TCase_dns_sd_kv_delete); + + /* Utility functions */ + tcase_add_test(TCase_dns_sd_first_label_length, tc_dns_sd_first_label_length); + suite_add_tcase(s, TCase_dns_sd_first_label_length); + tcase_add_test(TCase_dns_sd_check_type_format, tc_dns_sd_check_type_format); + suite_add_tcase(s, TCase_dns_sd_check_type_format); + tcase_add_test(TCase_dns_sd_check_instance_name_format, tc_dns_sd_check_instance_name_format); + suite_add_tcase(s, TCase_dns_sd_check_instance_name_format); + tcase_add_test(TCase_dns_sd_create_service_url, tc_dns_sd_create_service_url); + suite_add_tcase(s, TCase_dns_sd_create_service_url); + tcase_add_test(TCase_dns_sd_claimed_callback, tc_dns_sd_claimed_callback); + suite_add_tcase(s, TCase_dns_sd_claimed_callback); + + /* DNS SD API functions */ + tcase_add_test(TCase_dns_sd_init, tc_dns_sd_init); + suite_add_tcase(s, TCase_dns_sd_init); + tcase_add_test(TCase_dns_sd_register_service, tc_dns_sd_register_service); + suite_add_tcase(s, TCase_dns_sd_register_service); + tcase_add_test(TCase_dns_sd_browse_service, tc_dns_sd_browse_service); + suite_add_tcase(s, TCase_dns_sd_browse_service); + + /* Key-Value vector functions */ + tcase_add_test(TCase_dns_sd_kv_vector_init, tc_dns_sd_kv_vector_init); + suite_add_tcase(s, TCase_dns_sd_kv_vector_init); + tcase_add_test(TCase_dns_sd_kv_vector_add, tc_dns_sd_kv_vector_add); + suite_add_tcase(s, TCase_dns_sd_kv_vector_add); + tcase_add_test(TCase_dns_sd_kv_vector_get, tc_dns_sd_kv_vector_get); + suite_add_tcase(s, TCase_dns_sd_kv_vector_get); + tcase_add_test(TCase_dns_sd_kv_vector_erase, tc_dns_sd_kv_vector_erase); + suite_add_tcase(s, TCase_dns_sd_kv_vector_erase); + + return s; +} + +int main(void) +{ + int fails; + Suite *s = pico_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + fails = srunner_ntests_failed(sr); + srunner_free(sr); + return fails; +} \ No newline at end of file diff --git a/test/unit/modunit_pico_ipv6_nd.c b/test/unit/modunit_pico_ipv6_nd.c index eb3afe4df..62242d1d4 100644 --- a/test/unit/modunit_pico_ipv6_nd.c +++ b/test/unit/modunit_pico_ipv6_nd.c @@ -19,9 +19,7 @@ START_TEST(tc_pico_nd_new_expire_time) { - struct pico_ipv6_neighbor n = { - 0 - }; + struct pico_ipv6_neighbor n = { 0 }; struct pico_device d = { {0} }; /* TODO: how to test these time values */ @@ -76,6 +74,32 @@ START_TEST(tc_pico_nd_queue) } END_TEST +START_TEST(tc_pico_nd_new_expire_state) +{ + struct pico_ipv6_neighbor n = { + 0 + }; + unsigned int i; + + /* INCOMPLETE won't change */ + n.state = PICO_ND_STATE_INCOMPLETE; + pico_nd_new_expire_state(&n); + fail_unless(n.state == PICO_ND_STATE_INCOMPLETE); + + /* PROBE won't change */ + n.state = PICO_ND_STATE_PROBE; + pico_nd_new_expire_state(&n); + fail_unless(n.state == PICO_ND_STATE_PROBE); + + for (i = PICO_ND_STATE_INCOMPLETE + 1; i < PICO_ND_STATE_PROBE; ) + { + n.state = i; + pico_nd_new_expire_state(&n); + fail_unless(n.state == i + 1); + i = n.state; + } +} +END_TEST START_TEST(tc_pico_nd_discover) { /* TODO: test this: static void pico_nd_discover(struct pico_ipv6_neighbor *n) */ @@ -193,6 +217,7 @@ Suite *pico_suite(void) Suite *s = suite_create("PicoTCP"); TCase *TCase_pico_nd_new_expire_time = tcase_create("Unit test for pico_nd_new_expire_time"); + TCase *TCase_pico_nd_new_expire_state = tcase_create("Unit test for pico_nd_new_expire_state"); TCase *TCase_pico_nd_discover = tcase_create("Unit test for pico_nd_discover"); TCase *TCase_neigh_options = tcase_create("Unit test for neigh_options"); TCase *TCase_neigh_adv_complete = tcase_create("Unit test for neigh_adv_complete"); @@ -220,6 +245,8 @@ Suite *pico_suite(void) tcase_add_test(TCase_pico_nd_new_expire_time, tc_pico_nd_new_expire_time); suite_add_tcase(s, TCase_pico_nd_new_expire_time); + tcase_add_test(TCase_pico_nd_new_expire_state, tc_pico_nd_new_expire_state); + suite_add_tcase(s, TCase_pico_nd_new_expire_state); tcase_add_test(TCase_pico_nd_discover, tc_pico_nd_discover); suite_add_tcase(s, TCase_pico_nd_discover); tcase_add_test(TCase_neigh_options, tc_neigh_options); diff --git a/test/unit/modunit_pico_mdns.c b/test/unit/modunit_pico_mdns.c index c686fde03..85f06e0d9 100644 --- a/test/unit/modunit_pico_mdns.c +++ b/test/unit/modunit_pico_mdns.c @@ -5,537 +5,2762 @@ #include "pico_ipv4.h" #include "pico_ipv6.h" #include "pico_dns_client.h" +#include "pico_dns_common.h" #include "pico_tree.h" +#include "pico_dev_mock.c" #include "modules/pico_mdns.c" #include "check.h" -void callback(char *str, void *arg) +void callback( pico_mdns_record_vector *vector, + char *str, + void *arg ) { - (void) str; - (void) arg; + IGNORE_PARAMETER(vector); + IGNORE_PARAMETER(str); + IGNORE_PARAMETER(arg); + /* Do nothing, because fail_unless and fail_if don't work here */ } -START_TEST(tc_mdns_cache_cmp) + +int mdns_init() +{ + struct mock_device *mock = NULL; + + struct pico_ip4 local = {.addr = long_be(0x0a280064)}; + struct pico_ip4 netmask = {.addr = long_be(0xffffff00)}; + + mock = pico_mock_create(NULL); + if (!mock) + return -1; + + pico_ipv4_link_add(mock->dev, local, netmask); + + /* Try to initialise the mDNS module right */ + return pico_mdns_init("host.local", pico_ipv4_link_by_dev(mock->dev), 0, + callback, NULL); +} + +START_TEST(tc_mdns_init) +{ + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + pico_stack_init(); + + /* Try to initialise the mDNS module wrong */ + ret = pico_mdns_init(NULL, NULL, 0, callback, NULL); + fail_unless(-1 == ret, "mdns_init failed checking params!\n"); + + /* Try to initialise the mDNS module wrong */ + ret = pico_mdns_init(hostname, NULL, 0, callback, NULL); + fail_unless(-1 == ret, "mdns_init failed checking params!\n"); + + /* Try to initialise the mDNS module wrong */ + ret = pico_mdns_init(hostname, NULL, 0, NULL, NULL); + fail_unless(-1 == ret, "mdns_init failed checking params!\n"); + + ret = mdns_init(); + fail_unless(0 == ret, "mdns_init failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +/* MARK: Comparing functions */ +START_TEST(tc_mdns_rdata_cmp) { - struct pico_mdns_cache_rr ka; - struct pico_dns_answer_suffix sa; - struct pico_mdns_cache_rr kb; - struct pico_dns_answer_suffix sb; + uint8_t rdata1[10] = { 1,2,3,4,5,6,7,8,9,10 }; + uint8_t rdata2[10] = { 1,2,3,3,5,6,7,8,9,10 }; + uint8_t rdata3[1] = { 2 }; + uint8_t rdata4[1] = { 1 }; + uint8_t rdata5[11] = { 1,2,3,4,5,6,7,8,9,10,9 }; + uint8_t rdata6[12] = { 1,2,3,4,5,6,7,8,9,10,11 }; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Check equal data and size */ + ret = pico_mdns_rdata_cmp(rdata1, rdata1, 10, 10); + fail_unless(0 == ret, "mdns_rdata_cmp failed with equal data and size!\n"); + + /* Check smaller data and equal size */ + ret = pico_mdns_rdata_cmp(rdata1, rdata2, 10, 10); + fail_unless(1 == ret, "mdns_rdata_cmp failed with smaller data and equal size!\n"); + + /* Check larger data and smaller size */ + ret = pico_mdns_rdata_cmp(rdata1, rdata3, 10, 1); + fail_unless(-1 == ret, "mdns_rdata_cmp failed with larger data and smaller size!\n"); + + /* Check equal data and smaller size */ + ret = pico_mdns_rdata_cmp(rdata1, rdata4, 10, 1); + fail_unless(1 == ret, "mdns_rdata_cmp failed with equal data and smaller size!\n"); - char url1[] = "test_1"; - char url2[] = "test_2"; + /* Check smaller data and larger size */ + ret = pico_mdns_rdata_cmp(rdata1, rdata5, 10, 11); + fail_unless(-1 == ret, "mdns_rdata_cmp failed with smaller data and larger size!\n"); - ka.url = url1; - sa.qtype = PICO_DNS_TYPE_A; - ka.suf = &sa; - kb.url = url2; - sb.qtype = PICO_DNS_TYPE_A; - kb.suf = &sb; - fail_unless(mdns_cache_cmp(&ka, &kb) != 0, "RR cmp returned equal!"); + /* Check larger data and larger size */ + ret = pico_mdns_rdata_cmp(rdata1, rdata6, 10, 11); + fail_unless(-1 == ret, "mdns_rdata_cmp failed with larger data and larger size!\n"); - ka.url = url1; - kb.url = url1; - fail_unless(mdns_cache_cmp(&ka, &kb) == 0, "RR cmp returned different!"); + printf("*********************** ending %s * \n", __func__); } END_TEST START_TEST(tc_mdns_cmp) { - struct pico_mdns_cookie ka; - struct pico_mdns_cookie kb; + struct pico_mdns_record a = {0}; + struct pico_mdns_record b = {0}; + const char *url1 = "foo.local"; + const char *url3 = "a.local"; + struct pico_ip4 rdata = {0}; + uint16_t len = 0; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Create test records */ + a.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!a.record, "Record A could not be created!\n"); + b.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!b.record, "Record B could not be created!\n"); + + /* Try to compare equal records */ + ret = pico_mdns_cmp((void *) &a, (void *) &b); + fail_unless(0 == ret, "mdns_cmp failed with equal records!\n"); + pico_dns_record_delete(&(a.record)); + pico_dns_record_delete(&(b.record)); - char url1[] = "test_1"; - char url2[] = "test_2"; + /* Create different test records */ + a.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_PTR, + PICO_DNS_CLASS_IN, 0); + fail_if(!a.record, "Record A could not be created!\n"); + b.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!b.record, "Record B could not be created!\n"); - ka.url = url1; - ka.qtype = PICO_DNS_TYPE_A; - kb.url = url2; - kb.qtype = PICO_DNS_TYPE_A; - fail_unless(mdns_cmp(&ka, &kb) != 0, "cmp returned equal!"); + /* Try to compare records with equal rname but different type */ + ret = pico_mdns_cmp((void *) &a, (void *) &b); + fail_unless(1 == ret, "mdns_cmp failed with same name, different types!\n"); + pico_dns_record_delete(&(a.record)); + pico_dns_record_delete(&(b.record)); - ka.url = url1; - kb.url = url1; - fail_unless(mdns_cmp(&ka, &kb) == 0, "cmp returned different!"); + /* Create different test records */ + a.record = pico_dns_record_create(url3, &rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!a.record, "Record A could not be created!\n"); + b.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!b.record, "Record B could not be created!\n"); + + /* Try to compare records with different rname but equal type */ + ret = pico_mdns_cmp((void *) &a, (void *) &b); + fail_unless(-1 == ret, "mdns_cmp failed with different name, same types!\n"); + pico_dns_record_delete(&(a.record)); + pico_dns_record_delete(&(b.record)); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_send) +START_TEST(tc_mdns_cmp_name_type) { - struct pico_dns_header hdr = { - 0 - }; - int len = 0; - int sentlen = 0; - sentlen = pico_mdns_send(&hdr, (unsigned int)len); - fail_unless(sentlen == len, "Sent %d iso expected %d bytes!\n", sentlen, len); + struct pico_mdns_record a = {0}; + struct pico_mdns_record b = {0}; + const char *url1 = "foo.local"; + const char *url3 = "a.local"; + struct pico_ip4 rdata = {0}; + uint16_t len = 0; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Create different test records */ + a.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_PTR, + PICO_DNS_CLASS_IN, 0); + fail_if(!a.record, "Record A could not be created!\n"); + b.record = pico_dns_record_create(url1, &rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!b.record, "Record B could not be created!\n"); + + /* Try to compare records with equal rname but different type */ + ret = pico_mdns_cmp_name_type((void *) &a, (void *) &b); + fail_unless(1 == ret, "mdns_cmp_name_type failed with different types!\n"); + pico_dns_record_delete(&(a.record)); + pico_dns_record_delete(&(b.record)); + + /* Create different test records */ + a.record = pico_dns_record_create(url3, url1, strlen(url1), &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!a.record, "Record A could not be created!\n"); + b.record = pico_dns_record_create(url3, url1, strlen(url1), &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!b.record, "Record B could not be created!\n"); + + /* Try to compare records with different rname but equal type */ + ret = pico_mdns_cmp_name_type((void *) &a, (void *) &b); + fail_unless(0 == ret, "mdns_cmp_name_type failed!\n"); + pico_dns_record_delete(&(a.record)); + pico_dns_record_delete(&(b.record)); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_cache_del_rr) +START_TEST(tc_mdns_cookie_cmp) { - char url[] = "delrr.local"; - char *addr = NULL; - uint16_t qtype = PICO_DNS_TYPE_A; - struct pico_dns_answer_suffix suf = { - .qtype = short_be(qtype), - .ttl = long_be(100) - }; - char rdata[] = "somedata"; + struct pico_mdns_cookie a; + struct pico_mdns_cookie b; + struct pico_dns_question *question1 = NULL; + struct pico_dns_question *question2 = NULL; + struct pico_dns_question *question3 = NULL; + struct pico_dns_question *question4 = NULL; + struct pico_dns_question *question5 = NULL; + struct pico_mdns_record record1 = {0}, record2 = {0}, record3 = {0}, + record4 = {0}; + const char *url1 = "foo.local"; + const char *url2 = "bar.local"; + const char *url3 = "pi.local"; + const char *url4 = "ab.local"; + struct pico_ip4 rdata = {0}; + uint16_t len = 0; + int ret = 0; - pico_stack_init(); - fail_unless(pico_mdns_cache_del_rr(url, qtype, rdata) == -1, "Deleted a nonexisting RR from cache!\n"); - fail_unless(pico_mdns_cache_add_rr(url, &suf, rdata) == 0, "Failed to add RR to cache\n"); + printf("*********************** starting %s * \n", __func__); + + /* Create some questions */ + question1 = pico_dns_question_create(url1, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question1, "Could not create question 1!\n"); + question2 = pico_dns_question_create(url1, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_PTR, + PICO_DNS_CLASS_IN, 0); + fail_if(!question2, "Could not create question 2!\n"); + question3 = pico_dns_question_create(url3, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question2, "Could not create question 3!\n"); + question4 = pico_dns_question_create(url4, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_AAAA, + PICO_DNS_CLASS_IN, 0); + fail_if(!question2, "Could not create question 4!\n"); + question5 = pico_dns_question_create(url2, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_TYPE_AAAA, 0); + fail_if(!question2, "Could not create question 5!\n"); + + /* Create test records */ + record1.record = pico_dns_record_create(url1, &rdata, 4, &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!record1.record, "Record 1 could not be created!\n"); + record2.record = pico_dns_record_create(url1, &rdata, 4, &len, + PICO_DNS_TYPE_PTR, + PICO_DNS_CLASS_IN, 0); + fail_if(!record2.record, "Record 2 could not be created!\n"); + record3.record = pico_dns_record_create(url2, &rdata, 4, &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!record3.record, "Record 3 could not be created!\n"); + record4.record = pico_dns_record_create(url4, &rdata, 4, &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!record4.record, "Record 3 could not be created!\n"); + + /* Create 2 exactly the same cookies */ + pico_dns_question_vector_init(&(a.qvector)); + pico_dns_question_vector_add(&(a.qvector), question1); + pico_dns_question_vector_add(&(a.qvector), question2); + pico_dns_question_vector_add(&(a.qvector), question3); + pico_dns_question_vector_add(&(a.qvector), question4); + pico_dns_question_vector_add(&(a.qvector), question5); + pico_mdns_record_vector_init(&(a.rvector)); + pico_mdns_record_vector_add(&(a.rvector), &record1); + pico_mdns_record_vector_add(&(a.rvector), &record2); + pico_mdns_record_vector_add(&(a.rvector), &record3); + pico_mdns_record_vector_add(&(a.rvector), &record4); + + pico_dns_question_vector_init(&(b.qvector)); + pico_dns_question_vector_add(&(b.qvector), question1); + pico_dns_question_vector_add(&(b.qvector), question2); + pico_dns_question_vector_add(&(b.qvector), question3); + pico_dns_question_vector_add(&(b.qvector), question4); + pico_dns_question_vector_add(&(b.qvector), question5); + pico_mdns_record_vector_init(&(b.rvector)); + pico_mdns_record_vector_add(&(b.rvector), &record1); + pico_mdns_record_vector_add(&(b.rvector), &record2); + pico_mdns_record_vector_add(&(b.rvector), &record3); + pico_mdns_record_vector_add(&(b.rvector), &record4); + + /* Try to compare exactly the same cookies*/ + ret = pico_mdns_cookie_cmp((void *) &a, (void *) &b); + fail_unless(0 == ret, "mdns_cookie_cmp failed with equal cookies!\n"); + + /* Try to compare the same cookies but with A more records than B */ + pico_mdns_record_vector_remove(&(b.rvector), 3); + ret = pico_mdns_cookie_cmp((void *) &a, (void *) &b); + fail_unless(1 == ret, "mdns_cookie_cmp failed with different N records!\n"); + + /* Try to compare cookies but B a larger question than A*/ + pico_dns_question_vector_remove(&(a.qvector), 1); + ret = pico_mdns_cookie_cmp((void *) &a, (void *) &b); + fail_unless(-1 == ret, "mdns_cookie_cmp failed with larger question B!\n"); + + /* Insert more possibilities here.. */ + + pico_dns_record_delete(&(record1.record)); + pico_dns_record_delete(&(record2.record)); + pico_dns_record_delete(&(record3.record)); + pico_dns_record_delete(&(record4.record)); - addr = PICO_ZALLOC(strlen(url) + 1); - memcpy(addr + 1, url, strlen(url)); - pico_dns_name_to_dns_notation(addr); - fail_unless(pico_mdns_cache_del_rr(addr, qtype, rdata) == 0, "Unable to delete RR from cache!\n"); - PICO_FREE(addr); + pico_dns_question_delete(&question1); + pico_dns_question_delete(&question2); + pico_dns_question_delete(&question3); + pico_dns_question_delete(&question4); + pico_dns_question_delete(&question5); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_add_cookie) +/* MARK: Cookie functions */ +START_TEST(tc_mdns_cookie_delete) { - /* TODO: test this: static struct pico_mdns_cookie *pico_mdns_add_cookie(struct pico_dns_header *hdr, uint16_t len, struct pico_dns_query_suffix *suffix, unsigned int probe, void (*callback)(char *str, void *arg), void *arg) */ - /*char url[] = "addck.local"; - uint16_t qtype = PICO_DNS_TYPE_A; - uint16_t len = 0; - struct pico_dns_query_suffix suf = { - .qtype = short_be(qtype) - }; - unsigned int probe = 0; - void *arg = NULL; - struct pico_dns_header *hdr = PICO_ZALLOC(sizeof(struct pico_dns_header)+strlen(url)+1); - char *addr = (char *)hdr + sizeof(struct pico_dns_header); - pico_mdns_populate_query_domain(url, addr, NULL, 0, 0, PICO_PROTO_IPV4, 0); - pico_dns_client_query_domain(addr); + struct pico_mdns_cookie *a = NULL; + pico_dns_question_vector qvector = {0}; + pico_mdns_record_vector rvector = {0}; + + printf("*********************** starting %s * \n", __func__); - printf("First char %02x\n", addr[0]); + fail_unless(pico_mdns_cookie_delete(&a) == -1, + "mdns_cookie_delete failed checking params!\n"); + a = pico_mdns_cookie_create(qvector, rvector, 0, 0, NULL, NULL); + fail_unless(pico_mdns_cookie_delete(&a) == 0, + "mdns_cookie_delete failed!\n"); - pico_stack_init(); - fail_unless(pico_mdns_add_cookie(hdr, len, &suf, probe, callback, arg) != NULL, "Failed adding cookie!\n"); - fail_unless(pico_mdns_find_cookie(url, qtype) != NULL, "Cookie not found in table!\n"); - PICO_FREE(hdr);*/ + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_fill_header) +START_TEST(tc_mdns_cookie_create) { - /* TODO: test this: static void pico_mdns_fill_header(struct pico_dns_header *hdr, uint16_t qdcount, uint16_t ancount) */ - struct pico_dns_header hdr = { - 0 - }; - uint16_t qdcount = 0; - uint16_t ancount = 0; - pico_mdns_fill_header(&hdr, qdcount, ancount); + struct pico_mdns_cookie *a = NULL; + pico_dns_question_vector qvector = {0}; + pico_mdns_record_vector rvector = {0}; + + printf("*********************** starting %s * \n", __func__); + + a = pico_mdns_cookie_create(qvector, rvector, 0, 0, NULL, NULL); + fail_if(!a, "mdns_cookie_create failed!\n"); + + pico_mdns_cookie_delete(&a); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_create_answer) +START_TEST(tc_mdns_cookie_tree_find_query_cookie) { - char url[] = "cr-ans.local"; - unsigned int len = 0; - uint16_t qtype = PICO_DNS_TYPE_A; - char rdata[] = "somedata"; + struct pico_mdns_cookie *a = NULL, *b = NULL; + pico_dns_question_vector qvector_a = {0}, qvector_b = {0}; + pico_mdns_record_vector rvector = {0}; + struct pico_dns_question *question1 = NULL; + struct pico_dns_question *question2 = NULL; + struct pico_dns_question *question3 = NULL; + struct pico_dns_question *question4 = NULL; + struct pico_dns_question *question5 = NULL; + const char *url1 = "foo.local"; + const char *url2 = "bar.local"; + const char *url3 = "pi.local"; + const char *url4 = "ab.local"; + const char *url5 = "t.local"; + uint16_t len = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Create some questions */ + question1 = pico_dns_question_create(url1, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question1, "Could not create question 1!\n"); + question2 = pico_dns_question_create(url5, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_PTR, + PICO_DNS_CLASS_IN, 0); + fail_if(!question2, "Could not create question 2!\n"); + question3 = pico_dns_question_create(url3, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question3, "Could not create question 3!\n"); + question4 = pico_dns_question_create(url4, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_AAAA, + PICO_DNS_CLASS_IN, 0); + fail_if(!question4, "Could not create question 4!\n"); + question5 = pico_dns_question_create(url2, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question5, "Could not create question 5!\n"); + + pico_dns_question_vector_add(&qvector_a, question3); + pico_dns_question_vector_add(&qvector_a, question4); + + pico_dns_question_vector_add(&qvector_b, question1); + pico_dns_question_vector_add(&qvector_b, question2); + pico_dns_question_vector_add(&qvector_b, question5); + + a = pico_mdns_cookie_create(qvector_a, rvector, 1, + PICO_MDNS_COOKIE_TYPE_QUERY, NULL, NULL); + fail_if(!a, "mdns_cookie_create failed!\n"); + b = pico_mdns_cookie_create(qvector_b, rvector, 1, + PICO_MDNS_COOKIE_TYPE_QUERY, NULL, NULL); + fail_if(!b, "mdns_cookie_create failed!\n"); + + pico_mdns_cookie_tree_add_cookie(a); + pico_mdns_cookie_tree_add_cookie(b); + + fail_unless(b == pico_mdns_cookie_tree_find_query_cookie("\3foo\5local"), + "mdns_cookie_tree_find_query_cookie failed with foo.local\n"); + + fail_unless(a == pico_mdns_cookie_tree_find_query_cookie("\2pi\5local"), + "mdns_cookie_tree_find_query_cookie failed with pi.local\n"); + + fail_unless(NULL == pico_mdns_cookie_tree_find_query_cookie("bla.local"), + "mdns_cookie_tree_find_query_cookie failed with foo.local\n"); - fail_unless(pico_mdns_create_answer(url, &len, qtype, rdata) != NULL, "Header returned is NULL!\n"); - qtype = 0; - fail_unless(pico_mdns_create_answer(url, &len, qtype, rdata) == NULL, "Header returned is invalid!\n"); + pico_mdns_cookie_tree_del_cookie(a); + pico_mdns_cookie_tree_del_cookie(b); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_create_query) +START_TEST(tc_mdns_cookie_tree_del_cookie) { - /* TODO: test this: static struct pico_dns_header *pico_mdns_create_query(const char *url, uint16_t *len, uint16_t proto, unsigned int probe, unsigned int inverse, void (*callback)(char *str, void *arg), void *arg) */ - char url[256] = { - 0 - }; + struct pico_mdns_cookie *a = NULL, *b = NULL; + pico_dns_question_vector qvector_a = {0}, qvector_b = {0}; + pico_mdns_record_vector rvector = {0}; + struct pico_dns_question *question1 = NULL; + struct pico_dns_question *question2 = NULL; + struct pico_dns_question *question3 = NULL; + struct pico_dns_question *question4 = NULL; + struct pico_dns_question *question5 = NULL; + const char *url1 = "foo.local"; + const char *url2 = "bar.local"; + const char *url3 = "pi.local"; + const char *url4 = "ab.local"; + const char *url5 = "t.local"; uint16_t len = 0; - uint16_t proto = 0xFFFF; - unsigned int probe = 0; - unsigned int inverse = 0; - void *arg = NULL; - pico_stack_init(); - fail_if(pico_mdns_create_query(NULL, &len, proto, probe, inverse, callback, arg) != NULL); - fail_if(pico_err != PICO_ERR_EINVAL); - fail_if(pico_mdns_create_query(url, &len, proto, probe, inverse, callback, arg) != NULL); - fail_if(pico_err != PICO_ERR_EINVAL); - proto = PICO_PROTO_IPV4; - fail_if(pico_mdns_create_query(url, &len, proto, probe, inverse, NULL, arg) != NULL); - fail_if(pico_err != PICO_ERR_EINVAL); - fail_if(pico_mdns_create_query(url, NULL, proto, probe, inverse, callback, arg) != NULL); - fail_if(pico_err != PICO_ERR_EINVAL); + printf("*********************** starting %s * \n", __func__); + + /* Create some questions */ + question1 = pico_dns_question_create(url1, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question1, "Could not create question 1!\n"); + question2 = pico_dns_question_create(url5, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_PTR, + PICO_DNS_CLASS_IN, 0); + fail_if(!question2, "Could not create question 2!\n"); + question3 = pico_dns_question_create(url3, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question3, "Could not create question 3!\n"); + question4 = pico_dns_question_create(url4, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_AAAA, + PICO_DNS_CLASS_IN, 0); + fail_if(!question4, "Could not create question 4!\n"); + question5 = pico_dns_question_create(url2, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question5, "Could not create question 5!\n"); + + pico_dns_question_vector_add(&qvector_a, question3); + pico_dns_question_vector_add(&qvector_a, question4); + + pico_dns_question_vector_add(&qvector_b, question1); + pico_dns_question_vector_add(&qvector_b, question2); + pico_dns_question_vector_add(&qvector_b, question5); + + a = pico_mdns_cookie_create(qvector_a, rvector, 1, + PICO_MDNS_COOKIE_TYPE_QUERY, NULL, NULL); + fail_if(!a, "mdns_cookie_create failed!\n"); + b = pico_mdns_cookie_create(qvector_b, rvector, 1, + PICO_MDNS_COOKIE_TYPE_QUERY, NULL, NULL); + fail_if(!b, "mdns_cookie_create failed!\n"); + + pico_mdns_cookie_tree_add_cookie(a); + pico_mdns_cookie_tree_add_cookie(b); + + fail_unless(0 == pico_mdns_cookie_tree_del_cookie(b), + "mdns_cookie_tree_del_cookie failed deleting B!\n"); -#ifdef FAULTY - pico_set_mm_failure(1); - fail_if(pico_mdns_create_query(url, &len, proto, probe, inverse, callback, arg) != NULL); - fail_if(pico_err != PICO_ERR_ENOMEM); -#endif + fail_unless(NULL == pico_mdns_cookie_tree_find_query_cookie("\3foo\5local"), + "mdns_cookie_tree_del_cookie failed deleting B correctly!\n"); - fail_if(pico_mdns_create_query(url, &len, proto, probe, inverse, callback, arg) == NULL); + fail_unless(a == pico_mdns_cookie_tree_find_query_cookie("\2pi\5local"), + "mdns_cookie_tree_del_cookie delete the wrong cookie!\n"); + + fail_unless(0 == pico_mdns_cookie_tree_del_cookie(a), + "mdns_cookie_tree_del_cookie failed deleting A!\n"); + + fail_unless(NULL == pico_mdns_cookie_tree_find_query_cookie("\2pi\5local"), + "mdns_cookie_tree_del_cookie failed deleting A correctly!\n"); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_del_cookie) +START_TEST(tc_mdns_cookie_tree_add_cookie) { - char url[256] = { - 0 - }; - uint16_t qtype = PICO_DNS_TYPE_A; + struct pico_mdns_cookie *a = NULL, *b = NULL; + pico_dns_question_vector qvector_a = {0}, qvector_b = {0}; + pico_mdns_record_vector rvector = {0}; + struct pico_dns_question *question1 = NULL; + struct pico_dns_question *question2 = NULL; + struct pico_dns_question *question3 = NULL; + struct pico_dns_question *question4 = NULL; + struct pico_dns_question *question5 = NULL; + const char *url1 = "foo.local"; + const char *url2 = "bar.local"; + const char *url3 = "pi.local"; + const char *url4 = "ab.local"; + const char *url5 = "t.local"; + uint16_t len = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Create some questions */ + question1 = pico_dns_question_create(url1, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question1, "Could not create question 1!\n"); + question2 = pico_dns_question_create(url5, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_PTR, + PICO_DNS_CLASS_IN, 0); + fail_if(!question2, "Could not create question 2!\n"); + question3 = pico_dns_question_create(url3, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question3, "Could not create question 3!\n"); + question4 = pico_dns_question_create(url4, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_AAAA, + PICO_DNS_CLASS_IN, 0); + fail_if(!question4, "Could not create question 4!\n"); + question5 = pico_dns_question_create(url2, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question5, "Could not create question 5!\n"); + + pico_dns_question_vector_add(&qvector_a, question3); + pico_dns_question_vector_add(&qvector_a, question4); + + pico_dns_question_vector_add(&qvector_b, question1); + pico_dns_question_vector_add(&qvector_b, question2); + pico_dns_question_vector_add(&qvector_b, question5); - fail_unless(pico_mdns_del_cookie(url, qtype) == -1, "Deleted nonexisting cookie!\n"); - /* TODO - * Add cookie - * Try to delete cookie - * Look for cookie & see if it's deleted */ + a = pico_mdns_cookie_create(qvector_a, rvector, 1, + PICO_MDNS_COOKIE_TYPE_QUERY, NULL, NULL); + fail_if(!a, "mdns_cookie_create failed!\n"); + b = pico_mdns_cookie_create(qvector_b, rvector, 1, + PICO_MDNS_COOKIE_TYPE_QUERY, NULL, NULL); + fail_if(!b, "mdns_cookie_create failed!\n"); + + pico_mdns_cookie_tree_add_cookie(a); + pico_mdns_cookie_tree_add_cookie(b); + + fail_unless(b == pico_mdns_cookie_tree_find_query_cookie("\3foo\5local"), + "mdns_cookie_tree_del_cookie failed adding B to tree!\n"); + + fail_unless(a == pico_mdns_cookie_tree_find_query_cookie("\2pi\5local"), + "mdns_cookie_tree_del_cookie failed adding A to tree!\n"); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_cache_find_rr) +START_TEST(tc_mdns_cookie_find_record) { - char url[] = "findrr.local"; - uint16_t qtype = PICO_DNS_TYPE_A; - struct pico_mdns_cache_rr *rr = NULL; - struct pico_dns_answer_suffix suf = { - .qtype = short_be(qtype), - .ttl = long_be(100) - }; - char rdata[] = "somedata"; + pico_mdns_record_vector rvector = {0}; + pico_dns_question_vector qvector = {0}; + struct pico_mdns_cookie *cookie = NULL; + struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + const char *url = "foo.local"; + const char *url1 = "bar.local"; - pico_stack_init(); - rr = pico_mdns_cache_find_rr(url, qtype); - fail_unless(rr == NULL, "Found nonexistent RR in cache!\n"); + printf("*********************** starting %s * \n", __func__); + + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + record1 = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + + record2 = pico_mdns_record_create(url1, &rdata, 4, PICO_DNS_TYPE_AAAA, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Some test vectors */ + pico_mdns_record_vector_add(&rvector, record); + pico_mdns_record_vector_add(&rvector, record1); + pico_mdns_record_vector_add(&rvector, record2); - rr = NULL; - pico_mdns_cache_add_rr(url, &suf, rdata); - rr = pico_mdns_cache_find_rr(url, qtype); - fail_unless(rr != NULL, "RR not found in cache!\n"); + cookie = pico_mdns_cookie_create(qvector, rvector, 2, + PICO_MDNS_COOKIE_TYPE_PROBE, + NULL, NULL); + fail_if(!cookie, "Cookie could not be created!\n"); + + fail_unless(record == pico_mdns_cookie_find_record(cookie,record->record), + "mdns_cookie_find_record failed!\n"); + fail_unless(record1 == pico_mdns_cookie_find_record(cookie,record1->record), + "mdns_cookie_find_record failed!\n"); + fail_unless(record2 == pico_mdns_cookie_find_record(cookie,record2->record), + "mdns_cookie_find_record failed!\n"); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_cache_add_rr) +START_TEST(tc_mdns_cookie_apply_spt) { - char url[] = "addrr.local"; - uint16_t qtype = PICO_DNS_TYPE_A; - struct pico_dns_answer_suffix suf = { - .qtype = short_be(qtype), - .ttl = long_be(100) - }; - char rdata[] = "somedata"; + struct pico_mdns_cookie a; + struct pico_mdns_record record1 = {0}, record2 = {0}, record3 = {0}, + record4 = {0}; + const char *url1 = "foo.local"; + const char *url2 = "bar.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + struct pico_ip4 rdata2 = {long_be(0xFFFFFFFF)}; + int ret = 0; + uint16_t len = 0; + + printf("*********************** starting %s * \n", __func__); + /* Create test records */ + record1.record = pico_dns_record_create(url1, &rdata, 4, &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!record1.record, "Record 1 could not be created!\n"); + record2.record = pico_dns_record_create(url2, &rdata2, 4, &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!record2.record, "Record 2 could not be created!\n"); + record3.record = pico_dns_record_create(url1, &rdata2, 4, &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!record3.record, "Record 3 could not be created!\n"); + record4.record = pico_dns_record_create(url2, &rdata, 4, &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!record4.record, "Record 4 could not be created!\n"); + + /* Create 2 exactly the same cookies */ + pico_mdns_record_vector_init(&(a.rvector)); + pico_mdns_record_vector_add(&(a.rvector), &record1); + pico_mdns_record_vector_add(&(a.rvector), &record2); + + /* Make it a probe cookie otherwise it will just return -1 */ + a.type = PICO_MDNS_COOKIE_TYPE_PROBE; + + /* Need to initialise the stack to allow timer scheduling IMPORTANT! */ pico_stack_init(); - fail_unless(pico_mdns_cache_add_rr(url, &suf, rdata) == 0, "Failed to add RR to cache\n"); + + /* Check with peer record which is lexicographically later */ + ret = pico_mdns_cookie_apply_spt(&a, record3.record); + fail_unless(0 == ret, "mdns_cookie_apply_spt failed!\n"); + + /* Check with peer record which is lexicographically earlier */ + ret = pico_mdns_cookie_apply_spt(&a, record4.record); + fail_unless(0 == ret, "mdns_cookie_apply_spt failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_is_suffix_present) +{ + char name1[13] = {5,'v','l','e','e','s',5,'l','o','c','a','l',0}; + char name2[17] = {9,'v','l','e','e','s',' ','(','2',')',5,'l','o','c','a','l','\0'}; + char name6[17] = {12,'v','l','e','e','s',' ','(','a',')','(','2',')',5,'l','o','c','a','l','\0'}; + char name7[18] = {10,'v','l','e','e','s',' ','(','9','a',')',5,'l','o','c','a','l','\0'}; + char *o_index = NULL; + char *c_index = NULL; + char suffix[5] = {0}; + char new_suffix[5] = {0}; + uint8_t present = 0; + + printf("*********************** starting %s * \n", __func__); + present = pico_mdns_is_suffix_present(name1, &o_index, &c_index, &suffix); + fail_unless(0 == present, + "There is no suffix present!\n"); + fail_unless(NULL == o_index && NULL == c_index, + "There should be no indexes!\n"); + fail_unless(strcmp(suffix, "") == 0, "The should be no suffix!\n"); + + present = pico_mdns_is_suffix_present(name2, &o_index, &c_index, &suffix); + fail_unless(1 == present, + "is_suffix_present failed with suffix!\n"); + fail_unless((name2 + 7) == o_index && (name2 + 9) == c_index, + "is_suffix_pressent failed!\n"); + fail_unless(strcmp(suffix, "2") == 0, "Suffix should be 2!\n"); + + o_index = NULL; + c_index = NULL; + suffix[0] = '\0'; + + present = pico_mdns_is_suffix_present(name7, &o_index, &c_index, &suffix); + fail_unless(0 == present, + "There is no suffix present!\n"); + fail_unless(NULL == o_index && NULL == c_index, + "There should be no indexes!\n"); + fail_unless(strcmp(suffix, "") == 0, "The should be no suffix!\n"); + + present = pico_mdns_is_suffix_present(name6, &o_index, &c_index, &suffix); + fail_unless(1 == present, + "is_suffix_present failed with suffix!\n"); + fail_unless((name6 + 10) == o_index && (name6 + 12) == c_index, + "is_suffix_present failed!\n"); + fail_unless(strcmp(suffix, "2") == 0, "Suffix should be 2!\n"); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_flush_cache) +START_TEST(tc_mdns_resolve_name_conflict) { - char url[] = "flush.local"; - char url2[] = "flush2.local"; - uint16_t qtype = PICO_DNS_TYPE_A; - struct pico_mdns_cache_rr *rr = NULL; - struct pico_dns_answer_suffix suf = { - .qtype = short_be(qtype), - .ttl = long_be(100) - }; - char rdata[] = "somedata"; + char name1[13] = {5,'v','l','e','e','s',5,'l','o','c','a','l',0}; + char name2[17] = {9,'v','l','e','e','s',' ','(','2',')',5,'l','o','c','a','l','\0'}; + char name3[18] = {10,'v','l','e','e','s',' ','(','1','0',')',5,'l','o','c','a','l','\0'}; + char name4[17] = {9,'v','l','e','e','s',' ','(','9',')',5,'l','o','c','a','l','\0'}; + char name5[16] = {8,'v','l','e','e','s',' ','(',')',5,'l','o','c','a','l','\0'}; + char name6[17] = {9,'v','l','e','e','s',' ','(','a',')',5,'l','o','c','a','l','\0'}; + char name7[18] = {10,'v','l','e','e','s',' ','(','9','a',')',5,'l','o','c','a','l','\0'}; + char *ret = NULL; + + printf("*********************** starting %s * \n", __func__); + ret = pico_mdns_resolve_name_conflict(name1); + fail_unless(0 == strcmp(ret, "\x9vlees (2)\5local"), + "mdns_conflict_resolve_name failed 'vlees.local' to %s!\n", + ret); + PICO_FREE(ret); + ret = pico_mdns_resolve_name_conflict(name2); + fail_unless(0 == strcmp(ret, "\x9vlees (3)\5local"), + "mdns_conflict_resolve_name failed 'vlees (2).local' to %s!\n", + ret); + PICO_FREE(ret); + ret = pico_mdns_resolve_name_conflict(name3); + fail_unless(0 == strcmp(ret, "\xavlees (11)\5local"), + "mdns_conflict_resolve_name failed 'vlees (10).local' to %s!\n", + ret); + PICO_FREE(ret); + ret = pico_mdns_resolve_name_conflict(name4); + fail_unless(0 == strcmp(ret, "\xavlees (10)\5local"), + "mdns_conflict_resolve_name failed 'vlees (9).local' to %s!\n", + ret); + PICO_FREE(ret); + ret = pico_mdns_resolve_name_conflict(name5); + fail_unless(0 == strcmp(ret, "\x9vlees (2)\5local"), + "mdns_conflict_resolve_name failed 'vlees ().local' to %s!\n", + ret); + PICO_FREE(ret); + ret = pico_mdns_resolve_name_conflict(name6); + fail_unless(0 == strcmp(ret, "\xdvlees (a) (2)\5local"), + "mdns_conflict_resolve_name failed 'vlees (a) (2).local' to %s!\n", + ret); + PICO_FREE(ret); + ret = pico_mdns_resolve_name_conflict(name7); + fail_unless(0 == strcmp(ret, "\xevlees (9a) (2)\5local"), + "mdns_conflict_resolve_name failed 'vlees (9a).local' to %s!\n", + ret); + PICO_FREE(ret); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_generate_new_records) +{ + pico_mdns_record_vector conlfict_vector = {0}; + pico_mdns_record_vector new_vector = {0}; + struct pico_mdns_record *record = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!(record->record), "Record could not be created!\n"); + pico_mdns_record_vector_add(&conlfict_vector, record); + + ret = pico_mdns_generate_new_records(&conlfict_vector, "\3foo\5local", + &new_vector, "\7foo (2)\5local"); + fail_unless(0 == ret, "generate_new_records failed!\n"); + fail_unless(1 == new_vector.count, "new_vector has count of 0!\n"); + fail_unless(strcmp(new_vector.records[0]->record->rname, "\7foo (2)\5local") == 0, + "New name isn't correctly copied!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_cookie_resolve_conflict) +{ + struct pico_mdns_cookie *a = NULL; + pico_mdns_record_vector rvector = {0}; + pico_dns_question_vector qvector = {0}; + struct pico_dns_question *question = NULL; + struct pico_mdns_record *record = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + int ret = 0; + uint16_t len = 0; + + printf("*********************** starting %s * \n", __func__); + + question = pico_dns_question_create(url, &len, PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!question, "Question could not be created!\n"); + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!(record->record), "Record could not be created!\n"); + + + /* Create 2 exactly the same cookies */ + pico_mdns_record_vector_add(&rvector, record); + pico_dns_question_vector_add(&qvector, question); + + /* Make it a probe cookie otherwise it will just return -1 */ + a = pico_mdns_cookie_create(qvector, rvector, 1, + PICO_MDNS_COOKIE_TYPE_PROBE, + callback, NULL); + + /* Need to initialise the stack to allow timer scheduling IMPORTANT! */ pico_stack_init(); - /* Add RR and find it in the cache, then flush cache and look for it again */ - fail_unless(pico_mdns_cache_add_rr(url, &suf, rdata) == 0, "Failed to add RR to cache\n"); - fail_unless(pico_mdns_cache_add_rr(url2, &suf, rdata) == 0, "Failed to add RR to cache\n"); - rr = pico_mdns_cache_find_rr(url, qtype); - fail_unless(rr != NULL, "RR not found in cache!\n"); - fail_unless(pico_mdns_flush_cache() == 0, "RR cache flushing failure!\n"); + ret = mdns_init(); + fail_unless(0 == ret, "mdns_init failed!\n"); + + /* Cookie needs to be removed from cookie tree so we need to add it first */ + pico_mdns_cookie_tree_add_cookie(a); - rr = NULL; - rr = pico_mdns_cache_find_rr(url, qtype); - fail_unless(rr == NULL, "RR found in cache after flush!\n"); + ret = pico_mdns_cookie_resolve_conflict(a, "\3foo\5local"); + fail_unless(0 == ret, "mdns_cookie_resolve_conflict failed!\n"); - rr = NULL; - rr = pico_mdns_cache_find_rr(url2, qtype); - fail_unless(rr == NULL, "RR found in cache after flush!\n"); + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_find_cookie) +/* MARK: Question functions */ +START_TEST(tc_mdns_question_create) { - /* TODO Needs reworking! Cfr add_cookie */ - struct pico_mdns_cookie *ck = NULL; - char *addr = NULL; - char url[] = "findck.local"; - uint16_t qtype = PICO_DNS_TYPE_A; + struct pico_dns_question *question = NULL; + const char *url = "1.2.3.4"; + char cmpbuf[22] = { 0x01u, '4', + 0x01u, '3', + 0x01u, '2', + 0x01u, '1', + 0x07u, 'i','n','-','a','d','d','r', + 0x04u, 'a','r','p','a', + 0x00u }; uint16_t len = 0; - struct pico_dns_query_suffix suf = { - .qtype = short_be(qtype) - }; - unsigned int probe = 0; - void *arg = NULL; - struct pico_dns_header *hdr = PICO_ZALLOC(sizeof(struct pico_dns_header) + strlen(url) + 1); - addr = (char *)hdr + sizeof(struct pico_dns_header); - memcpy(addr + 1, url, strlen(url)); - pico_dns_name_to_dns_notation(addr); + printf("*********************** starting %s * \n", __func__); + + question = pico_mdns_question_create("foo.local", + &len, + PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_MDNS_QUESTION_FLAG_UNICAST_RES, + 0); + fail_if(!question, "mdns_question_create returned NULL!\n"); + fail_unless(0 == strcmp(question->qname, "\3foo\5local"), + "mdns_question_create failed!\n"); + fail_unless(0x8001 == short_be(question->qsuffix->qclass), + "mdns_quesiton_create failed setting QU bit!\n"); + pico_dns_question_delete(&question); + + question = pico_mdns_question_create("foo.local", + &len, + PICO_PROTO_IPV4, + PICO_DNS_TYPE_A, + PICO_MDNS_QUESTION_FLAG_PROBE, + 0); + fail_if(!question, "mdns_question_create returned NULL!\n"); + fail_unless(0 == strcmp(question->qname, "\3foo\5local"), + "mdns_question_create failed!\n"); + fail_unless(PICO_DNS_TYPE_ANY == short_be(question->qsuffix->qtype), + "mdns_quesiton_create failed setting type to ANY!\n"); + pico_dns_question_delete(&question); + + question = pico_mdns_question_create(url, + &len, + PICO_PROTO_IPV4, + PICO_DNS_TYPE_PTR, + 0, 1); + fail_if(!question, "mdns_question_create returned NULL!\n"); + fail_unless(0 == strcmp(question->qname, cmpbuf), + "mdns_question_create failed!\n"); + pico_dns_question_delete(&question); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +/* MARK: Record functions */ +START_TEST(tc_mdns_dns_record_create) +{ + struct pico_dns_record *a = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + + printf("*********************** starting %s * \n", __func__); + a = pico_mdns_dns_record_create(url, + (void *)rdata, 4, + &len, + PICO_DNS_TYPE_A, + 120, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!a, "mdns_dns_record_create returned NULL!\n"); + fail_unless(strcmp(a->rname, "\x7picotcp\x3com"), + "mdns_dns_record_create didn't convert url %s properly!\n", + a->rname); + fail_unless(a->rsuffix->rtype == short_be(PICO_DNS_TYPE_A), + "mdns_dns_record_create failed setting rtype!\n"); + fail_unless(0x8001 == short_be(a->rsuffix->rclass), + "mdns_dns_record_create failed setting rclass!\n"); + fail_unless(a->rsuffix->rttl == long_be(120), + "mdns_dns_record_create failed setting rttl!\n"); + fail_unless(a->rsuffix->rdlength == short_be(4), + "mdns_dns_record_create failed setting rdlenth!\n"); + fail_unless(memcmp(a->rdata, rdata, 4) == 0, + "mdns_dns_record_create failed setting rdata!\n"); + + pico_dns_record_delete(&a); + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_record_resolve_conflict) +{ + struct pico_mdns_record *record = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!(record->record), "Record could not be created!\n"); + /* Need to initialise the stack to allow timer scheduling IMPORTANT! */ pico_stack_init(); - ck = pico_mdns_find_cookie(url, qtype); - fail_unless(ck == NULL, "Found nonexisting cookie in table!\n"); - ck = NULL; - fail_unless(pico_mdns_add_cookie(hdr, len, &suf, probe, callback, arg) != NULL, "Failed adding cookie!\n"); - ck = pico_mdns_find_cookie(url, qtype); - fail_unless(ck != NULL, "Cookie not found in table!\n"); - PICO_FREE(hdr); + ret = mdns_init(); + fail_unless(0 == ret, "mdns_init failed!\n"); + + ret = pico_mdns_record_resolve_conflict(record, "\3foo\5local"); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_get_ip6_from_ip4) +START_TEST(tc_mdns_record_am_i_lexi_later) { - /* TODO: test this: static struct pico_ip6 *pico_get_ip6_from_ip4(struct pico_ip4 *ipv4_addr) */ - struct pico_ip4 *ipv4_addr = NULL; + struct pico_mdns_record record1 = {0}, record2 = {0}, record3 = {0}, + record4 = {0}; + const char *url1 = "foo.local"; + const char *url2 = "bar.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + struct pico_ip4 rdata2 = {long_be(0xFFFFFFFF)}; + uint16_t len = 0; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Create test records */ + record1.record = pico_dns_record_create(url1, &rdata, 4, &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!record1.record, "Record 1 could not be created!\n"); + record2.record = pico_dns_record_create(url2, &rdata2, 4, &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!record2.record, "Record 2 could not be created!\n"); + record3.record = pico_dns_record_create(url1, &rdata2, 4, &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!record3.record, "Record 3 could not be created!\n"); + record4.record = pico_dns_record_create(url2, &rdata, 4, &len, + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!record4.record, "Record 4 could not be created!\n"); + + ret = pico_mdns_record_am_i_lexi_later(&record1, &record3); + fail_if(-2 == ret, "mdns_record_am_i_lexi_later return error!\n"); + fail_unless(-1 == ret, "mdns_record_am_i_lexi_later failed!\n"); + + ret = pico_mdns_record_am_i_lexi_later(&record2, &record4); + fail_if(-2 == ret, "mdns_record_am_i_lexi_later return error!\n"); + fail_unless(1 == ret, "mdns_record_am_i_lexi_later failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_record_create_from_dns) +{ + struct pico_mdns_record *record = NULL; + struct pico_dns_record *a = NULL; + const char *url = "picotcp.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + + printf("*********************** starting %s * \n", __func__); + a = pico_mdns_dns_record_create(url, + (void *)rdata, 4, + &len, + PICO_DNS_TYPE_A, + 120, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!a, "mdns_dns_record_create returned NULL!\n"); + + /* Try to create an mDNS record from a DNS record */ + record = pico_mdns_record_create_from_dns(a); + fail_if(!record, "mdns_record_create_from_dns returned NULL!\n"); + fail_unless(strcmp(record->record->rname, "\x7picotcp\x3com"), + "mdns_record_create_from_dns failed!\n"); + fail_unless(record->record->rsuffix->rtype == short_be(PICO_DNS_TYPE_A), + "mdns_record_create_from_dns failed setting rtype!\n"); + fail_unless(0x8001 == short_be(record->record->rsuffix->rclass), + "mdns_record_create_from_dns failed setting rclass!\n"); + fail_unless(record->record->rsuffix->rttl == long_be(120), + "mdns_record_create_from_dns failed setting rttl!\n"); + fail_unless(record->record->rsuffix->rdlength == short_be(4), + "mdns_record_create_from_dns failed setting rdlenth!\n"); + fail_unless(memcmp(record->record->rdata, rdata, 4) == 0, + "mdns_record_create_from_dns failed setting rdata!\n"); - fail_unless(pico_get_ip6_from_ip4(ipv4_addr) == NULL, "Got an invalid IP!\n"); + pico_mdns_record_delete(&record); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_reply_query) +START_TEST(tc_mdns_record_copy_with_new_name) { - /* TODO: test this: static int pico_mdns_reply_query(uint16_t qtype, struct pico_ip4 peer) */ - uint16_t qtype = 0; - struct pico_ip4 peer = { - 0 - }; - char *name = NULL; + struct pico_mdns_record *record = NULL, *copy = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!(record->record), "Record could not be created!\n"); + + /* Try to create a copy with a new name */ + copy = pico_mdns_record_copy_with_new_name(record, "\4test\5local"); + fail_if(!copy, "mdns_record_copy_with_new_name returned NULL!\n"); + fail_unless(0 == strcmp(copy->record->rname, "\4test\5local"), + "mdns_record_copy_with_new_name didn't copy name right!\n"); + fail_unless(strlen("\4test\5local") + 1 == copy->record->rname_length, + "mdns_record_copy_with_new_name didn't update namelength!\n"); + + pico_mdns_record_delete(&record); + pico_mdns_record_delete(©); - fail_unless(pico_mdns_reply_query(qtype, peer, name) == -1, "Replied to query with invalid arg \n"); + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_handle_query) +START_TEST(tc_mdns_record_copy) { - /* TODO: test this: static int pico_mdns_handle_query(char *url, struct pico_dns_query_suffix *suf, struct pico_ip4 peer) */ - char url[256] = { - 0 - }; - struct pico_dns_query_suffix suf = { - 0 - }; - struct pico_ip4 peer = { - 0 - }; + struct pico_mdns_record *record = NULL, *copy = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; - pico_mdns_handle_query(url, &suf, peer); + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!(record->record), "Record could not be created!\n"); + + /* Try to copy */ + copy = pico_mdns_record_copy(record); + fail_if(!copy, "mdns_record_copy returned NULL!\n"); + fail_if(record == copy, "Pointers point to same struct!\n"); + fail_unless(0 == strcmp(copy->record->rname, record->record->rname), + "mdns_record_copy didn't copy names right!\n"); + fail_unless(copy->claim_id == record->claim_id, + "mdns_record_copy didn't copy claim_id right!\n"); + fail_unless(copy->current_ttl == record->current_ttl, + "mdns_record_copy didn't copy current_ttl right!\n"); + fail_unless(copy->flags == record->flags, + "mdns_record_copy didn't copy flags right!\n"); + + pico_mdns_record_delete(&record); + pico_mdns_record_delete(©); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_handle_answer) +START_TEST(tc_mdns_record_create) { - /* TODO: test this: static int pico_mdns_handle_answer(char *url, struct pico_dns_answer_suffix *suf, char *data) */ - char url[] = "han-ans.local"; - struct pico_dns_answer_suffix suf = { - 0 - }; - char data[] = "somedata"; - pico_mdns_handle_answer(url, &suf, data); + struct pico_mdns_record *record = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!(record->record), "Record could not be created!\n"); + fail_unless(0 == strcmp(record->record->rname, "\3foo\5local"), + "mdns_record_create didn't convert rname properly!\n"); + fail_unless(0x8001 == short_be(record->record->rsuffix->rclass), + "mdns_record_create didn't set QU flag correctly!\n"); + pico_mdns_record_delete(&record); + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_namelen_comp) +START_TEST(tc_mdns_record_delete) { - char name[] = "\3www\4tass\2be\0"; - char name_comp[] = "\3www\4tass\2be\xc0\x02"; /* two bytes ofset from start of buf */ - unsigned int ret = 0; + struct pico_mdns_record *record = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!(record->record), "Record could not be created!\n"); - /* name without compression */ - ret = pico_mdns_namelen_comp(name); - fail_unless(ret == 12, "Namelength is wrong!\n"); + /* Try to delete the record */ + ret = pico_mdns_record_delete(&record); + fail_unless(0 == ret, "mdns_record_delete returned error!\n"); + fail_unless(!record, "mdns_record_delete didn't delete properly"); - /* name with compression */ - ret = pico_mdns_namelen_comp(name_comp); - fail_unless(ret == 13, "Namelength is wrong!\n"); + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_namelen_uncomp) +/* MARK: Record Vector Functions */ +START_TEST(tc_mdns_record_vector_init) { - char name[] = "\3www\4tass\2be\0"; - char name_comp[] = "\3www\4tass\2be\xc0\x02"; /* two bytes ofset from start of buf */ - char buf[] = "00\5index\0"; - unsigned int ret = 0; + pico_mdns_record_vector rvector; - /* name without compression */ - ret = pico_mdns_namelen_uncomp(name, buf); - fail_unless(ret == 12, "Namelength is wrong!\n"); + printf("*********************** starting %s * \n", __func__); + rvector.count = 243; + rvector.records = (struct pico_mdns_record **)5; - /* name with compression */ - ret = pico_mdns_namelen_uncomp(name_comp, buf); - fail_unless(ret == 18, "Namelength is wrong!\n"); + /* Try to init the vector */ + pico_mdns_record_vector_init(&rvector); + + fail_unless(0 == rvector.count && NULL == rvector.records, + "mdns_record_vector_init failed!\n"); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_expand_name_comp) +START_TEST(tc_mdns_record_vector_count) { - char name[] = "\3www\4tass\2be\0"; - char buf[] = "00\5index\0"; - char *ret; - ret = pico_mdns_expand_name_comp(name, buf); - fail_unless(ret != NULL, "Name ptr returned is NULL"); + pico_mdns_record_vector rvector = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + record1 = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + + /* Some tests */ + fail_unless(0 == pico_mdns_record_vector_count(&rvector)); + pico_mdns_record_vector_add(&rvector, record); + fail_unless(1 == pico_mdns_record_vector_count(&rvector)); + pico_mdns_record_vector_add(&rvector, record1); + fail_unless(2 == pico_mdns_record_vector_count(&rvector)); + pico_mdns_record_vector_delete(&rvector, 0); + fail_unless(1 == pico_mdns_record_vector_count(&rvector)); + + pico_mdns_record_vector_destroy(&rvector); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_recv) +START_TEST(tc_mdns_record_vector_add) { - /* TODO: test this: static int pico_mdns_recv(void *buf, int buflen, struct pico_ip4 peer) */ - char buf[256] = { - 0 - }; - int buflen = 0; - struct pico_ip4 peer = { - 0 - }; + pico_mdns_record_vector rvector = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL; + const char *url = "foo.local"; + const char *url2 = "bar.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + record1 = pico_mdns_record_create(url2, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + + /* Some tests */ + fail_unless(0 == pico_mdns_record_vector_count(&rvector)); + pico_mdns_record_vector_add(&rvector, record); + fail_unless(1 == pico_mdns_record_vector_count(&rvector)); + pico_mdns_record_vector_add(&rvector, record1); + fail_unless(2 == pico_mdns_record_vector_count(&rvector)); + pico_mdns_record_vector_delete(&rvector, 0); + fail_unless(1 == pico_mdns_record_vector_count(&rvector)); - fail_unless(pico_mdns_recv(buf, buflen, peer) == -1, "No error with invalid args!\n"); + pico_mdns_record_vector_destroy(&rvector); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_wakeup) +START_TEST(tc_mdns_record_vector_get) { - /* TODO: test this: static void pico_mdns_wakeup(uint16_t ev, struct pico_socket *s) */ - uint16_t ev = 0; - struct pico_socket *s = NULL; + pico_mdns_record_vector rvector = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL, *ret = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + record1 = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + + /* Some tests */ + fail_unless(0 == pico_mdns_record_vector_count(&rvector)); + pico_mdns_record_vector_add(&rvector, record); + pico_mdns_record_vector_add(&rvector, record1); + ret = pico_mdns_record_vector_get(&rvector, 0); + fail_unless(ret == record, "mdns_record_vector_get failed!\n"); + ret = pico_mdns_record_vector_get(&rvector, 1); + fail_unless(ret == record1, "mdns_record_vector_get failed!\n"); + ret = pico_mdns_record_vector_get(&rvector, 2); + fail_unless(NULL == ret, "mdns_record_vector_get failed OOB!\n"); + + pico_mdns_record_vector_destroy(&rvector); - pico_mdns_wakeup(ev, s); + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_announce_timer) +START_TEST(tc_mdns_record_vector_delete) { - /* TODO: test this: static void pico_mdns_announce_timer(pico_time now, void *arg) */ - pico_time now = 0; - void *arg = NULL; + pico_mdns_record_vector rvector = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + int ret = 0; - pico_mdns_announce_timer(now, arg); + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + record1 = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + + /* Some tests */ + pico_mdns_record_vector_add(&rvector, record); + pico_mdns_record_vector_add(&rvector, record1); + ret = pico_mdns_record_vector_delete(&rvector, 0); + fail_unless(0 == ret, "mdns_record_vector_delete failed!\n"); + ret = pico_mdns_record_vector_delete(&rvector, 1); + fail_unless(0 == ret, "mdns_record_vector_delete failed OOB!\n"); + ret = pico_mdns_record_vector_delete(&rvector, 0); + fail_unless(0 == ret, "mdns_record_vector_delete failed!\n"); + ret = pico_mdns_record_vector_delete(&rvector, 2); + fail_unless(0 == ret, "mdns_record_vector_delete failed OOB!\n"); + fail_unless(0 == pico_mdns_record_vector_count(&rvector), + "mdns_record_vector_delete failed!\n"); + + pico_mdns_record_vector_destroy(&rvector); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_announce) +START_TEST(tc_mdns_record_vector_destroy) { - /* TODO: test this: static int pico_mdns_announce() */ - pico_mdns_announce(); + pico_mdns_record_vector rvector = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + record1 = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + + /* Some tests */ + pico_mdns_record_vector_add(&rvector, record); + pico_mdns_record_vector_add(&rvector, record1); + + /* Try to destroy the vector */ + pico_mdns_record_vector_destroy(&rvector); + fail_unless(NULL == rvector.records, + "Records not NULL!\n"); + fail_unless(0 == pico_mdns_record_vector_count(&rvector), + "mdns_record_vector_delete failed!\n"); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_probe_timer) +START_TEST(tc_mdns_record_vector_append) { - /* TODO: test this: static void pico_mdns_probe_timer(pico_time now, void *arg) */ - pico_time now = 0; - void *arg = NULL; + pico_mdns_record_vector rvector = {0}, rvector_b = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL; + const char *url = "foo.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + record1 = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); - pico_mdns_probe_timer(now, arg); + /* Some test vectors */ + pico_mdns_record_vector_add(&rvector, record); + pico_mdns_record_vector_add(&rvector_b, record1); + + ret = pico_mdns_record_vector_append(&rvector, &rvector_b); + fail_unless(0 == ret, "pico_mdns_record_vector_append returned NULL"); + fail_unless(0 == pico_mdns_record_vector_count(&rvector_b), + "pico_mdns_record_vector_append didn't remove vector B!\n"); + fail_unless(record1 == pico_mdns_record_vector_get(&rvector, 1), + "pico_mdns_record_vector_append failed!\n"); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_probe) +/* MARK: Record tree functions */ +void add_records( void ) { - /* TODO: test this: static int pico_mdns_probe(char *hostname, void (*cb_initialised)(char *str, void *arg), void *arg) */ - char hostname[256] = { - 0 - }; - void *arg = NULL; + struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, + *record3 = NULL; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + struct pico_ip4 rdata1 = {long_be(0xFFFFFFFF)}; + const char *url = "foo.local"; + const char *url1 = "bar.local"; + + /* Create an A record with URL */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + + /* Create 2 PTR records to URL */ + record1 = pico_mdns_record_create(url, url, strlen(url), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + + /* Simulate that this record is probed */ + record1->flags |= PICO_MDNS_RECORD_PROBED; + + record2 = pico_mdns_record_create(url, url1, strlen(url1), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Create a totally different record */ + record3 = pico_mdns_record_create(url1, &rdata1, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Add the records to the tree */ + pico_mdns_record_tree_add_record(record, &MyRecords); + pico_mdns_record_tree_add_record(record1, &MyRecords); + pico_mdns_record_tree_add_record(record2, &MyRecords); + pico_mdns_record_tree_add_record(record3, &MyRecords); +} +START_TEST(tc_mdns_record_tree_find_url) +{ + pico_mdns_record_vector hits = {0}; + int found = 1, i = 0; + + printf("*********************** starting %s * \n", __func__); + + add_records(); + + hits = pico_mdns_record_tree_find_url("foo.local", &MyRecords); + fail_unless(3 == hits.count, + "mdns_record_tree_find_url should find 3 records here!\n"); + for (i = 0; i < hits.count; i++) { + if (strcmp(pico_mdns_record_vector_get(&hits, + (uint16_t)i)->record->rname, + "\3foo\5local")) + found = 0; + } + fail_unless(1 == found, + "mdns_record_tree_find_url returned records with other name!\n"); + + hits = pico_mdns_record_tree_find_url("bar.local", &MyRecords); + fail_unless(1 == hits.count, + "mdns_record_tree_find_url should find 1 record here!\n"); + fail_unless(0 == strcmp(pico_mdns_record_vector_get(&hits, + 0)->record->rname, + "\3bar\5local"), + "mdns_record_tree_find_url returned record with other name!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_record_tree_find_url_type) +{ + pico_mdns_record_vector hits = {0}; + int found = 1, i = 0; + + printf("*********************** starting %s * \n", __func__); + + add_records(); + + /* Try to find the first A record */ + hits = pico_mdns_record_tree_find_url_type("foo.local", PICO_DNS_TYPE_A, + &MyRecords); + fail_unless(1 == hits.count, + "mdns_record_tree_find_url should find 1 record here!\n"); + fail_unless(0 == strcmp(pico_mdns_record_vector_get(&hits, + 0)->record->rname, + "\3foo\5local"), + "mdns_record_tree_find_url returned record with other name!\n"); + + /* Try to find the 2 PTR records */ + hits = pico_mdns_record_tree_find_url_type("foo.local", PICO_DNS_TYPE_PTR, + &MyRecords); + for (i = 0; i < hits.count; i++) { + if (strcmp(pico_mdns_record_vector_get(&hits, + (uint16_t)i)->record->rname, + "\3foo\5local")) + found = 0; + } + fail_unless(1 == found, + "mdns_record_tree_find_url returned records with other name!\n"); + + /* Try to find the last A record */ + hits = pico_mdns_record_tree_find_url_type("bar.local", PICO_DNS_TYPE_A, + &MyRecords); + fail_unless(1 == hits.count, + "mdns_record_tree_find_url should find 1 record here!\n"); + fail_unless(0 == strcmp(pico_mdns_record_vector_get(&hits, + 0)->record->rname, + "\3bar\5local"), + "mdns_record_tree_find_url returned record with other name!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_record_tree_find_record) +{ + struct pico_mdns_record *node_record = NULL; + struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, + *record3 = NULL; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + struct pico_ip4 rdata1 = {long_be(0xFFFFFFFF)}; + const char *url = "foo.local"; + const char *url1 = "bar.local"; + + printf("*********************** starting %s * \n", __func__); + + /* Create an A record with URL */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + + /* Create 2 PTR records to URL */ + record1 = pico_mdns_record_create(url, url, strlen(url), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + record2 = pico_mdns_record_create(url, url1, strlen(url1), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Create a totally different record */ + record3 = pico_mdns_record_create(url1, &rdata1, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Add the records to the tree */ + pico_mdns_record_tree_add_record(record, &MyRecords); + pico_mdns_record_tree_add_record(record1, &MyRecords); + pico_mdns_record_tree_add_record(record2, &MyRecords); + pico_mdns_record_tree_add_record(record3, &MyRecords); + + /* Try to find the first A record */ + node_record = pico_mdns_record_tree_find_record(record2, &MyRecords); + fail_unless(record2 == node_record, + "mdns_record_tree_find_record failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_record_tree_del_url) +{ + pico_mdns_record_vector hits = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, + *record3 = NULL; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + struct pico_ip4 rdata1 = {long_be(0xFFFFFFFF)}; + const char *url = "foo.local"; + const char *url1 = "bar.local"; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Create an A record with URL */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + + /* Create 2 PTR records to URL */ + record1 = pico_mdns_record_create(url, url, strlen(url), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + record2 = pico_mdns_record_create(url, url1, strlen(url1), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Create a totally different record */ + record3 = pico_mdns_record_create(url1, &rdata1, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Add the records to the tree */ + pico_mdns_record_tree_add_record(record, &MyRecords); + pico_mdns_record_tree_add_record(record1, &MyRecords); + pico_mdns_record_tree_add_record(record2, &MyRecords); + pico_mdns_record_tree_add_record(record3, &MyRecords); + + /* Try to del the first tree records */ + ret = pico_mdns_record_tree_del_url(url, &MyRecords); + fail_unless(0 == ret, + "mdns_record_tree_del_url failed!\n"); + hits = pico_mdns_record_tree_find_url(url, &MyRecords); + fail_unless(0 == hits.count, + "mdns_record_tree_find_url should find 3 records here!\n"); + + hits = pico_mdns_record_tree_find_url(url1, &MyRecords); + fail_unless(1 == hits.count, + "mdns_record_tree_find_url should find 1 record here!\n"); + fail_unless(0 == strcmp(pico_mdns_record_vector_get(&hits, + 0)->record->rname, + "\3bar\5local"), + "mdns_record_tree_del_url failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_record_tree_del_url_type) +{ + pico_mdns_record_vector hits = {0}; + const char *url = "foo.local"; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + add_records(); + + /* Try to del the two PTR records */ + ret = pico_mdns_record_tree_del_url_type(url, PICO_DNS_TYPE_PTR, + &MyRecords); + fail_unless(0 == ret, "mdns_record_tree_del_url_type returned error!\n"); + + /* Try to find the 2 PTR records */ + hits = pico_mdns_record_tree_find_url_type(url, PICO_DNS_TYPE_PTR, + &MyRecords); + fail_unless(0 == hits.count, + "mdns_record_tree_find_url_type returned PTR records!\n"); + + + /* Try to find the first A record */ + hits = pico_mdns_record_tree_find_url_type(url, PICO_DNS_TYPE_A, + &MyRecords); + fail_unless(1 == hits.count, + "mdns_record_tree_del_url_type failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_record_tree_del_record) +{ + struct pico_mdns_record *node_record = NULL; + struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, + *record3 = NULL; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + struct pico_ip4 rdata1 = {long_be(0xFFFFFFFF)}; + const char *url = "foo.local"; + const char *url1 = "bar.local"; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Create an A record with URL */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + + /* Create 2 PTR records to URL */ + record1 = pico_mdns_record_create(url, url, strlen(url), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + record2 = pico_mdns_record_create(url, url1, strlen(url1), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Create a totally different record */ + record3 = pico_mdns_record_create(url1, &rdata1, 4, + PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Add the records to the tree */ + pico_mdns_record_tree_add_record(record, &MyRecords); + pico_mdns_record_tree_add_record(record1, &MyRecords); + pico_mdns_record_tree_add_record(record2, &MyRecords); + pico_mdns_record_tree_add_record(record3, &MyRecords); + + /* Try to find the first A record */ + ret = pico_mdns_record_tree_del_record(record2, &MyRecords); + fail_unless(0 == ret, + "mdns_record_tree_del_record returned NULL!\n"); + node_record = pico_mdns_record_tree_find_record(record2, &MyRecords); + fail_unless(NULL == node_record, + "mdns_record_tree_del_record failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_record_tree_add_record) +{ + pico_mdns_record_vector hits = {0}; + int found = 1, i = 0; + + printf("*********************** starting %s * \n", __func__); + + add_records(); + + hits = pico_mdns_record_tree_find_url("foo.local", &MyRecords); + fail_unless(3 == hits.count, + "mdns_record_tree_find_url should find 3 records here!\n"); + for (i = 0; i < hits.count; i++) { + if (strcmp(pico_mdns_record_vector_get(&hits, + (uint16_t)i)->record->rname, + "\3foo\5local")) + found = 0; + } + fail_unless(1 == found, + "mdns_record_tree_find_url returned records with other name!\n"); + + hits = pico_mdns_record_tree_find_url("bar.local", &MyRecords); + fail_unless(1 == hits.count, + "mdns_record_tree_find_url should find 1 record here!\n"); + fail_unless(0 == strcmp(pico_mdns_record_vector_get(&hits, + 0)->record->rname, + "\3bar\5local"), + "mdns_record_tree_find_url returned record with other name!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +/* MARK: My records functions */ +START_TEST(tc_mdns_my_records_find_url_type) +{ + struct pico_mdns_record *hit = NULL; + + printf("*********************** starting %s * \n", __func__); + + add_records(); + + /* Try to find the first A record */ + hit = pico_mdns_my_records_find_url_type("foo.local", PICO_DNS_TYPE_A); + fail_unless(0 == strcmp(hit->record->rname, "\3foo\5local"), + "mdns_record_tree_find_url returned record with other name!\n"); + + /* Try to find the first PTR records */ + hit = pico_mdns_my_records_find_url_type("foo.local", PICO_DNS_TYPE_PTR); + fail_unless(0 == strcmp(hit->record->rname, "\3foo\5local"), + "mdns_record_tree_find_url returned record with other name!\n"); + + /* Try to find the last A record */ + hit = pico_mdns_my_records_find_url_type("bar.local", PICO_DNS_TYPE_A); + fail_unless(0 == strcmp(hit->record->rname, "\3bar\5local"), + "mdns_record_tree_find_url returned record with other name!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_my_records_add) +{ + pico_mdns_record_vector vector = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, + *record3 = NULL; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + struct pico_ip4 rdata1 = {long_be(0xFFFFFFFF)}; + const char *url = "foo.local"; + const char *url1 = "bar.local"; + + printf("*********************** starting %s * \n", __func__); + /* Create an A record with URL */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + + /* Create 2 PTR records to URL */ + record1 = pico_mdns_record_create(url, url, strlen(url), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + + /* Simulate that this record is not added again */ + record2 = pico_mdns_record_create(url, url1, strlen(url1), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Create a totally different record */ + record3 = pico_mdns_record_create(url1, &rdata1, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Add the records to the tree */ + pico_mdns_record_vector_add(&vector, record); + pico_mdns_record_vector_add(&vector, record1); + pico_mdns_record_vector_add(&vector, record2); + pico_mdns_record_vector_add(&vector, record3); + + vector = pico_mdns_my_records_add(vector, 0); + fail_unless(3 == vector.count, "mdns_my_records_add failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_my_records_find_probed) +{ + pico_mdns_record_vector hits = {0}; + + printf("*********************** starting %s * \n", __func__); + + add_records(); + + hits = pico_mdns_my_records_find_probed(); + fail_unless(1 == hits.count, + "mdns_my_records_find_probed failed!\n"); + + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_my_records_find_to_probe) +{ + pico_mdns_record_vector hits = {0}; + + printf("*********************** starting %s * \n", __func__); + + add_records(); + + hits = pico_mdns_my_records_find_to_probe(); + fail_unless(3 == hits.count, + "mdns_my_records_find_to_probe failed! %d\n", hits.count); + + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_my_records_claimed_id) +{ + pico_mdns_record_vector hits = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, + *record3 = NULL; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + struct pico_ip4 rdata1 = {long_be(0xFFFFFFFF)}; + const char *url = "foo.local"; + const char *url1 = "bar.local"; + + printf("*********************** starting %s * \n", __func__); + /* Create an A record with URL */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + record->claim_id = 1; + record->flags |= PICO_MDNS_RECORD_CLAIMED; + fail_if(!record, "Record could not be created!\n"); + + /* Create 2 PTR records to URL */ + record1 = pico_mdns_record_create(url, url, strlen(url), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + record1->claim_id = 1; + record1->flags |= PICO_MDNS_RECORD_CLAIMED; + fail_if(!record1, "Record could not be created!\n"); + + /* Simulate that this record is not added again */ + record2 = pico_mdns_record_create(url, url1, strlen(url1), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Create a totally different record */ + record3 = pico_mdns_record_create(url1, &rdata1, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Add the records to the tree */ + pico_mdns_record_tree_add_record(record, &MyRecords); + pico_mdns_record_tree_add_record(record1, &MyRecords); + pico_mdns_record_tree_add_record(record2, &MyRecords); + pico_mdns_record_tree_add_record(record3, &MyRecords); + + fail_unless(1 == pico_mdns_my_records_claimed_id(1, &hits), + "mdns_my_records_claimed_id_failed!\n"); + fail_unless(2 == hits.count, + "Vector count should be 2!\n"); + + fail_unless(0 == pico_mdns_my_records_claimed_id(0, &hits), + "Claim ID '0' isn't claimed yet.."); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_my_records_claimed) +{ + pico_mdns_record_vector rvector = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL, *record2 = NULL, + *record3 = NULL; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + struct pico_ip4 rdata1 = {long_be(0xFFFFFFFF)}; + const char *url = "foo.local"; + const char *url1 = "bar.local"; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Create an A record with URL */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + + /* Create 2 PTR records to URL */ + record1 = pico_mdns_record_create(url, url, strlen(url), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + record2 = pico_mdns_record_create(url, url1, strlen(url1), + PICO_DNS_TYPE_PTR, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Create a totally different record */ + record3 = pico_mdns_record_create(url1, &rdata1, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "Record could not be created!\n"); + + /* Add the records to the tree */ + pico_mdns_record_tree_add_record(record, &MyRecords); + pico_mdns_record_tree_add_record(record1, &MyRecords); + pico_mdns_record_tree_add_record(record2, &MyRecords); + pico_mdns_record_tree_add_record(record3, &MyRecords); + + pico_mdns_record_vector_add(&rvector, record); + pico_mdns_record_vector_add(&rvector, record1); + pico_mdns_record_vector_add(&rvector, record2); + pico_mdns_record_vector_add(&rvector, record3); + + ret = pico_mdns_my_records_claimed(rvector, callback, NULL); + fail_unless(0 == ret, "mdns_my_records_claimed failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +/* MARK: Query functions */ +START_TEST(tc_mdns_query_create) +{ + pico_dns_packet *packet = NULL; + pico_dns_question_vector qvector = { 0 }; + const char *qurl = "picotcp.com"; + const char *qurl2 = "google.com"; + uint8_t buf[42] = { 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x02u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x06u, 'g','o','o','g','l','e', + 0xc0u, 0x14u, + 0x00u, 0x01u, + 0x00u, 0x01u }; + uint16_t len = 0; + int ret = 0; + struct pico_dns_question *a = NULL, *b = NULL; + + printf("*********************** starting %s * \n", __func__); + + a = pico_dns_question_create(qurl, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!a, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, a); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + b = pico_dns_question_create(qurl2, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 0); + fail_if(!b, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, b); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + + packet = pico_dns_query_create(&qvector, NULL, NULL, NULL, &len); + fail_if(packet == NULL, "mdns_query_create returned NULL!\n"); + fail_unless(0 == memcmp(buf, (void *)packet, 42), + "mdns_query_create failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +/* MARK: Answer functions*/ +START_TEST(tc_mdns_answer_create) +{ + pico_dns_packet *packet = NULL; + pico_dns_record_vector rvector = { 0 }; + struct pico_dns_record *a = NULL, *b = NULL; + const char *url = "picotcp.com"; + const char *url2 = "google.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint16_t len = 0; + int ret = 0; + uint8_t buf[62] = { 0x00u, 0x00u, + 0x84u, 0x00u, + 0x00u, 0x00u, + 0x00u, 0x02u, + 0x00u, 0x00u, + 0x00u, 0x00u, + 0x07u, 'p','i','c','o','t','c','p', + 0x03u, 'c','o','m', + 0x00u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x00u, 0x00u, 0x00u, 0x78u, + 0x00u, 0x04u, + 0x0Au, 0x0Au, 0x00u, 0x01u, + 0x06u, 'g','o','o','g','l','e', + 0xc0u, 0x14u, + 0x00u, 0x01u, + 0x00u, 0x01u, + 0x00u, 0x00u, 0x00u, 0x78u, + 0x00u, 0x04u, + 0x0Au, 0x0Au, 0x00u, 0x01u}; + + printf("*********************** starting %s * \n", __func__); + + a = pico_dns_record_create(url, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + b = pico_dns_record_create(url2, (void *)rdata, 4, &len, PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN, 120); + fail_if(!a, "dns_record_create returned NULL!\n"); + ret = pico_dns_record_vector_add(&rvector, a); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + ret = pico_dns_record_vector_add(&rvector, b); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + + /* Try to create an answer packet */ + packet = pico_mdns_answer_create(&rvector, NULL, NULL, &len); + fail_if (packet == NULL, "mdns_answer_create returned NULL!\n"); + fail_unless(memcmp((void *)packet, (void *)buf, 62) == 0, + "mdns_answer_create failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +/* MARK: Cache functions */ +START_TEST(tc_mdns_cache_add_record) +{ + struct pico_mdns_record *record = NULL, *found = NULL; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + const char *url = "foo.local"; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Create an A record with URL */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 80, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + + ret = pico_mdns_cache_add_record(record); + fail_unless(0 == ret, + "mdns_cache_add_record returned error!\n"); + found = pico_mdns_record_tree_find_record(record, &Cache); + fail_unless((int)found, "mdns_cache_add_record failed!\n"); + ret = pico_mdns_cache_add_record(record); + fail_unless(1 == ret, + "mdns_cache_add_record returned error!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_cache_flush) +{ + struct pico_mdns_record *record = NULL, *found = NULL; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + const char *url = "foo.local"; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Create an A record with URL */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 80, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + + ret = pico_mdns_cache_add_record(record); + fail_unless(0 == ret, + "mdns_cache_add_record returned error!\n"); + ret = pico_mdns_flush_cache(); + fail_unless(0 == ret, + "mdns_cache_flush returned error!\n"); + found = pico_mdns_record_tree_find_record(record, &Cache); + fail_unless(!found, "mdns_cache_flush failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_populate_answer_vector) +{ + pico_mdns_record_vector vector = {0}; + + printf("*********************** starting %s * \n", __func__); + add_records(); + + vector = pico_mdns_populate_answer_vector("foo.local", + PICO_DNS_TYPE_A, + PICO_DNS_CLASS_IN); + + fail_unless(1 == vector.count, "mdns_populate_answer_vector failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +/* MARK: Handling receptions */ +START_TEST(tc_mdns_handle_data_as_questions) +{ + pico_dns_packet *packet = NULL; + pico_mdns_record_vector anvector = { 0 }; + pico_dns_question_vector qvector = { 0 }; + const char *qurl = "picotcp.com"; + const char *qurl2 = "google.com"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + struct pico_ip4 rdata1 = {long_be(0xFFFFFFFF)}; + uint16_t len = 0; + uint8_t *ptr = NULL; + int ret = 0; + struct pico_dns_question *a = NULL, *b = NULL; + struct pico_mdns_record *record1 = NULL, *record2 = NULL; + + printf("*********************** starting %s * \n", __func__); + + /* Create a DNS query packet */ + a = pico_mdns_question_create(qurl, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + PICO_MDNS_QUESTION_FLAG_UNICAST_RES, 0); + fail_if(!a, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, a); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + b = pico_mdns_question_create(qurl2, &len, PICO_PROTO_IPV4, PICO_DNS_TYPE_A, + 0, 0); + fail_if(!b, "dns_question_create failed!\n"); + ret = pico_dns_question_vector_add(&qvector, b); + fail_unless(ret == 0, "dns_question_vector_add returned error!\n"); + packet = pico_dns_query_create(&qvector, NULL, NULL, NULL, &len); + fail_if(packet == NULL, "mdns_query_create returned NULL!\n"); + + /* Create records for answers */ + record1 = pico_mdns_record_create(qurl, &rdata, 4, PICO_DNS_TYPE_A, 120, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "mdns_record_create returned NULL!\n"); + record1->flags |= 0xC0; + record2 = pico_mdns_record_create(qurl2, &rdata1, 4, PICO_DNS_TYPE_A, 120, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record2, "mdns_record_created returned NULL!\n"); + record2->flags |= 0xC0; + + /* Add them to my records */ + pico_mdns_record_tree_add_record(record1, &MyRecords); + pico_mdns_record_tree_add_record(record2, &MyRecords); + + ptr = ((uint8_t *)packet + 12); + + anvector = pico_mdns_handle_data_as_questions(&ptr, 2, packet); + fail_unless(2 == anvector.count, + "pico_mdns_handle_data_as_questions returned error!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_handle_data_as_answers) +{ + pico_dns_packet *packet = NULL; + pico_dns_record_vector rvector = { 0 }; + struct pico_mdns_record *a = NULL, *b = NULL; + const char *url = "picotcp.com"; + const char *url2 = "google.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint8_t *ptr = NULL;; + uint16_t len = 0; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + a = pico_mdns_record_create(url, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!a, "dns_record_create returned NULL!\n"); + b = pico_mdns_record_create(url2, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, + PICO_MDNS_RECORD_SHARED); + fail_if(!a, "dns_record_create returned NULL!\n"); + ret = pico_dns_record_vector_add(&rvector, a->record); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + ret = pico_dns_record_vector_add(&rvector, b->record); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + + /* Try to create an answer packet */ + packet = pico_mdns_answer_create(&rvector, NULL, NULL, &len); + fail_if (packet == NULL, "mdns_answer_create returned NULL!\n"); + + ptr = ((uint8_t *)packet + 12); + + ret = pico_mdns_handle_data_as_answers(&ptr, 2, packet); + fail_unless(0 == ret, "mdns_handle_data_as_answers failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_handle_data_as_authorities) +{ + pico_dns_packet *packet = NULL; + pico_dns_record_vector rvector = { 0 }; + struct pico_mdns_record *a = NULL, *b = NULL; + const char *url = "picotcp.com"; + const char *url2 = "google.com"; + uint16_t len = 0; + uint8_t *ptr = NULL; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + a = pico_mdns_record_create(url, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!a, "dns_record_create returned NULL!\n"); + b = pico_mdns_record_create(url2, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, + PICO_MDNS_RECORD_SHARED); + fail_if(!a, "dns_record_create returned NULL!\n"); + ret = pico_dns_record_vector_add(&rvector, a->record); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + ret = pico_dns_record_vector_add(&rvector, b->record); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + + /* Try to create an answer packet */ + packet = pico_mdns_answer_create(&rvector, NULL, NULL, &len); + fail_if (packet == NULL, "mdns_answer_create returned NULL!\n"); + + ptr = ((uint8_t *)packet + 12); + + ret = pico_mdns_handle_data_as_authorities(&ptr, 2, packet); + fail_unless(0 == ret, "mdns_handle_data_as_answers failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_handle_data_as_additionals) +{ + printf("*********************** starting %s * \n", __func__); + /* Insert code here... */ + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_sort_unicast_multicast) +{ + pico_mdns_record_vector rvector = { 0 }; + pico_dns_record_vector u_vector = {0}, m_vector = {0}; + struct pico_mdns_record *a = NULL, *b = NULL; + const char *url = "picotcp.com"; + const char *url2 = "google.com"; + uint16_t len = 0; + uint8_t *ptr = NULL; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + a = pico_mdns_record_create(url, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!a, "mdns_record_create returned NULL!\n"); + b = pico_mdns_record_create(url2, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, + (PICO_MDNS_RECORD_SHARED | PICO_MDNS_RECORD_SEND_UNICAST)); + fail_if(!a, "mdns_record_create returned NULL!\n"); + ret = pico_dns_record_vector_add(&rvector, a); + fail_unless(ret == 0, "mdns_record_vector_add returned error!\n"); + ret = pico_dns_record_vector_add(&rvector, b); + fail_unless(ret == 0, "mdns_record_vector_add returned error!\n"); + + ret = pico_mdns_sort_unicast_multicast(&rvector, &u_vector, &m_vector); + fail_unless(0 == ret, "mdns_sort_unicast_multicast returned error!\n"); + fail_unless(1 == u_vector.count, "mdns_sort_unicast_multicast failed!\n"); + fail_unless(1 == m_vector.count, "mdns_sort_unicast_multicast failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_apply_known_answer_suppression) +{ + pico_dns_packet *packet = NULL; + pico_dns_record_vector rvector = { 0 }; + pico_mdns_record_vector vector = {0}; + struct pico_mdns_record *a = NULL, *b = NULL; + const char *url = "picotcp.com"; + const char *url2 = "google.com"; + uint8_t rdata[4] = { 10, 10, 0, 1 }; + uint8_t *ptr = NULL;; + uint16_t len = 0; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + a = pico_mdns_record_create(url, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!a, "dns_record_create returned NULL!\n"); + b = pico_mdns_record_create(url2, (void *)rdata, 4, PICO_DNS_TYPE_A, 120, + PICO_MDNS_RECORD_SHARED); + fail_if(!a, "dns_record_create returned NULL!\n"); + ret = pico_dns_record_vector_add(&rvector, a->record); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + ret = pico_dns_record_vector_add(&rvector, b->record); + fail_unless(ret == 0, "dns_record_vector_add returned error!\n"); + ret = pico_mdns_record_vector_add(&vector, a); + fail_unless(ret == 0, "mdns_record_vector_add returned error!\n"); + ret = pico_mdns_record_vector_add(&vector, b); + fail_unless(ret == 0, "mdns_record_vector_add returned error!\n"); + + /* Try to create an answer packet */ + packet = pico_mdns_answer_create(&rvector, NULL, NULL, &len); + fail_if (packet == NULL, "mdns_answer_create returned NULL!\n"); + + ptr = ((uint8_t *)packet + 12); + + ret = pico_mdns_apply_known_answer_suppression(&vector, packet, 1, &ptr); + fail_unless(0 == ret, "mdns_apply_known_answer_suppression returned error!\n"); + + fail_unless(1 == vector.count, + "mdns_apply_known_answer_suppression failed %d!\n", rvector.count); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +/* MARK: Address resolving functions */ +START_TEST(tc_mdns_send_query_packet) +{ + struct pico_mdns_cookie cookie; + + printf("*********************** starting %s * \n", __func__); + + cookie.count = 2; + + pico_stack_init(); + mdns_init(); + + pico_mdns_send_query_packet(0, &cookie); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_getrecord) +{ + struct pico_mdns_record *record = NULL, *found = NULL; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + const char *url = "foo.local"; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + + /* Create an A record with URL */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 80, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + + ret = pico_mdns_cache_add_record(record); + fail_unless(0 == ret, + "mdns_cache_add_record returned error!\n"); + found = pico_mdns_record_tree_find_record(record, &Cache); + fail_unless((int)found, "mdns_cache_add_record failed!\n"); + ret = pico_mdns_cache_add_record(record); + fail_unless(1 == ret, + "mdns_cache_add_record returned error!\n"); + + /* Init */ + pico_stack_init(); + mdns_init(); + + ret = pico_mdns_getrecord("foo.local", PICO_DNS_TYPE_A, callback, NULL); + fail_unless(0 == ret, "mdns_getrecord failed!\n"); + + ret = pico_mdns_getrecord("bar.local", PICO_DNS_TYPE_A, callback, NULL); + fail_unless(0 == ret, "mdns_getrecord failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +/* MARK: Probe & Announcement functions */ +START_TEST(tc_mdns_send_announcement_packet) +{ + struct pico_mdns_cookie *cookie = NULL; + pico_dns_question_vector qvector = {0}; + pico_mdns_record_vector rvector = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL; + const char *url = "foo.local"; + const char *url2 = "bar.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + record1 = pico_mdns_record_create(url2, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + + cookie = pico_mdns_cookie_create(qvector, rvector, 2, + PICO_MDNS_COOKIE_TYPE_ANNOUNCEMENT, + callback, NULL); + + pico_stack_init(); + mdns_init(); + + pico_mdns_send_announcement_packet(0, cookie); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_announce) +{ + printf("*********************** starting %s * \n", __func__); + add_records(); + pico_stack_init(); + mdns_init(); + + fail_unless(0 == pico_mdns_announce(callback, NULL), + "mdns_announce failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_send_probe_packet) +{ + struct pico_mdns_cookie *cookie = NULL; + pico_dns_question_vector qvector = {0}; + pico_mdns_record_vector rvector = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL; + const char *url = "foo.local"; + const char *url2 = "bar.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + record1 = pico_mdns_record_create(url2, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + + cookie = pico_mdns_cookie_create(qvector, rvector, 2, + PICO_MDNS_COOKIE_TYPE_ANNOUNCEMENT, + callback, NULL); + pico_stack_init(); - pico_mdns_probe(hostname, callback, arg); + mdns_init(); + + pico_mdns_send_probe_packet(0, cookie); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +START_TEST(tc_mdns_add_probe_question) +{ + pico_dns_question_vector vector = {0}; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + ret = pico_mdns_add_probe_question(&vector, "\5vlees\5local"); + fail_unless(0 == ret, "mdns_add_probe_question returned error!\n"); + fail_unless(1 == vector.count, + "New probe question didn't create!\n"); + ret = pico_mdns_add_probe_question(&vector, "\5vlees\5local"); + fail_unless(0 == ret, "mdns_add_probe_question returned error!\n"); + fail_unless(1 == vector.count, + "mdns_add_probe_question failed!\n"); + + ret = pico_mdns_add_probe_question(&vector, "\4test\5local"); + fail_unless(0 == ret, "mdns_add_probe_question returned error!\n"); + fail_unless(2 == vector.count, + "mdns_add_probe_question failed!\n"); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_getaddr_generic) +START_TEST(tc_mdns_probe) { - /* TODO: test this: static int pico_mdns_getaddr_generic(const char *url, void (*callback)(char *ip, void *arg), void *arg, uint16_t proto) */ - const char *url = NULL; - void *arg = NULL; - uint16_t proto = 0; - pico_mdns_getaddr_generic(url, callback, arg, proto); + printf("*********************** starting %s * \n", __func__); + add_records(); + pico_stack_init(); + mdns_init(); + + fail_unless(0 == pico_mdns_probe(callback, NULL), + "mdns_announce failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST +/* MARK: Claiming functions */ +START_TEST(tc_mdns_claim) +{ + pico_mdns_record_vector rvector = {0}; + struct pico_mdns_record *record = NULL, *record1 = NULL; + const char *url = "foo.local"; + const char *url2 = "bar.local"; + struct pico_ip4 rdata = {long_be(0x00FFFFFF)}; + int ret = 0; + + printf("*********************** starting %s * \n", __func__); + /* Create a record */ + record = pico_mdns_record_create(url, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record, "Record could not be created!\n"); + record1 = pico_mdns_record_create(url2, &rdata, 4, PICO_DNS_TYPE_A, 0, + PICO_MDNS_RECORD_UNIQUE); + fail_if(!record1, "Record could not be created!\n"); + + /* Some tests */ + pico_mdns_record_vector_add(&rvector, record); + pico_mdns_record_vector_add(&rvector, record1); + + pico_stack_init(); + mdns_init(); + + ret = pico_mdns_claim(rvector, callback, NULL); + fail_unless(0 == ret, "mdns_claimed failed!\n"); + + printf("*********************** ending %s * \n", __func__); } END_TEST -START_TEST(tc_pico_mdns_getname_generic) +/* API functions */ +START_TEST(tc_mdns_set_hostname) { - /* TODO: test this: static int pico_mdns_getname_generic(const char *ip, void (*callback)(char *url, void *arg), void *arg, uint16_t proto) */ - const char *ip = NULL; - void *arg = NULL; - uint16_t proto = 0; + int ret = 0; - pico_mdns_getname_generic(ip, callback, arg, proto); + printf("*********************** starting %s * \n", __func__); + pico_stack_init(); + mdns_init(); + + ret = pico_mdns_set_hostname("test.local", NULL); + fail_unless(0 == ret, "mdns_set_hostname failed!\n"); + + printf("*********************** ending %s * \n", __func__); } END_TEST +START_TEST(tc_mdns_get_hostname) +{ + char *_hostname = NULL; + printf("*********************** starting %s * \n", __func__); + pico_stack_init(); + mdns_init(); + + _hostname = pico_mdns_get_hostname(); + fail_unless(0 == strcmp(_hostname, "host.local"), + "mdns_get_hostname failed!\n"); + + printf("*********************** ending %s * \n", __func__); +} +END_TEST Suite *pico_suite(void) { Suite *s = suite_create("PicoTCP"); + TCase *TCase_mdns_init = tcase_create("Unit test for mdns_init"); - TCase *TCase_mdns_cache_cmp = tcase_create("Unit test for mdns_cache_cmp"); + /* Comparing functions */ + TCase *TCase_mdns_rdata_cmp = tcase_create("Unit test for mdns_rdata_cmp"); TCase *TCase_mdns_cmp = tcase_create("Unit test for mdns_cmp"); - TCase *TCase_pico_mdns_send = tcase_create("Unit test for pico_mdns_send"); - TCase *TCase_pico_mdns_cache_del_rr = tcase_create("Unit test for pico_mdns_cache_del_rr"); - TCase *TCase_pico_mdns_add_cookie = tcase_create("Unit test for pico_mdns_add_cookie"); - TCase *TCase_pico_mdns_fill_header = tcase_create("Unit test for pico_mdns_fill_header"); - TCase *TCase_pico_mdns_create_answer = tcase_create("Unit test for pico_mdns_create_answer"); - TCase *TCase_pico_mdns_create_query = tcase_create("Unit test for pico_mdns_create_query"); - TCase *TCase_pico_mdns_del_cookie = tcase_create("Unit test for pico_mdns_del_cookie"); - TCase *TCase_pico_mdns_cache_find_rr = tcase_create("Unit test for pico_mdns_cache_find_rr"); - TCase *TCase_pico_mdns_cache_add_rr = tcase_create("Unit test for pico_mdns_cache_add_rr"); - TCase *TCase_pico_mdns_flush_cache = tcase_create("Unit test for pico_mdns_flush_cache"); - TCase *TCase_pico_mdns_find_cookie = tcase_create("Unit test for pico_mdns_find_cookie"); - TCase *TCase_pico_get_ip6_from_ip4 = tcase_create("Unit test for pico_get_ip6_from_ip4"); - TCase *TCase_pico_mdns_reply_query = tcase_create("Unit test for pico_mdns_reply_query"); - TCase *TCase_pico_mdns_handle_query = tcase_create("Unit test for pico_mdns_handle_query"); - TCase *TCase_pico_mdns_handle_answer = tcase_create("Unit test for pico_mdns_handle_answer"); - - TCase *TCase_pico_mdns_namelen_comp = tcase_create("Unit test for pico_mdns_namelen_comp"); - TCase *TCase_pico_mdns_namelen_uncomp = tcase_create("Unit test for pico_mdns_namelen_uncomp"); - TCase *TCase_pico_mdns_expand_name_comp = tcase_create("Unit test for pico_mdns_expand_name_comp"); - - TCase *TCase_pico_mdns_recv = tcase_create("Unit test for pico_mdns_recv"); - TCase *TCase_pico_mdns_wakeup = tcase_create("Unit test for pico_mdns_wakeup"); - TCase *TCase_pico_mdns_announce_timer = tcase_create("Unit test for pico_mdns_announce_timer"); - TCase *TCase_pico_mdns_announce = tcase_create("Unit test for pico_mdns_announce"); - TCase *TCase_pico_mdns_probe_timer = tcase_create("Unit test for pico_mdns_probe_timer"); - TCase *TCase_pico_mdns_probe = tcase_create("Unit test for pico_mdns_probe"); - TCase *TCase_pico_mdns_getaddr_generic = tcase_create("Unit test for pico_mdns_getaddr_generic"); - TCase *TCase_pico_mdns_getname_generic = tcase_create("Unit test for pico_mdns_getname_generic"); - - tcase_add_test(TCase_mdns_cache_cmp, tc_mdns_cache_cmp); - suite_add_tcase(s, TCase_mdns_cache_cmp); + TCase *TCase_mdns_cmp_name_type = tcase_create("Unit test for mdns_cmp_name_type"); + TCase *TCase_mdns_cookie_cmp = tcase_create("Unit test for mdns_cookie_cmp"); + + /* Cookie functions */ + TCase *TCase_mdns_cookie_delete = tcase_create("Unit test for mdns_cookie_delete"); + TCase *TCase_mdns_cookie_create = tcase_create("Unit test for mdns_cookie_create"); + TCase *TCase_mdns_cookie_tree_find_query_cookie = tcase_create("Unit test for mdns_cookie_tree_find_query_cookie"); + TCase *TCase_mdns_cookie_tree_del_cookie = tcase_create("Unit test for mdns_cookie_tree_del_cookie"); + TCase *TCase_mdns_cookie_tree_add_cookie = tcase_create("Unit test for mdns_cookie_tree_add_cookie"); + TCase *TCase_mdns_cookie_find_record = tcase_create("Unit test for mdns_cookie_find_record"); + TCase *TCase_mdns_cookie_apply_spt = tcase_create("Unit test for mdns_cookie_apply_spt"); + TCase *TCase_mdns_is_suffix_present = tcase_create("Unit test for mdns_is_suffix_present"); + TCase *TCase_mdns_resolve_name_conflict = tcase_create("Unit test for mdns_resolve_name_conflict"); + TCase *TCase_mdns_generate_new_records = tcase_create("Unit test for mdns_generate_new_records"); + TCase *TCase_mdns_cookie_resolve_conflict = tcase_create("Unit test for mdns_cookie_resolve_conflict"); + + /* Question functions */ + TCase *TCase_mdns_question_create = tcase_create("Unit test for mdns_question_create"); + + /* Record functions */ + TCase *TCase_mdns_dns_record_create = tcase_create("Unit test for mdns_dns_record_create"); + TCase *TCase_mdns_record_resolve_conflict = tcase_create("Unit test for mdns_record_resolve_conflict"); + TCase *TCase_mdns_record_am_i_lexi_later = tcase_create("Unit test for mdns_record_am_i_lexi_later"); + TCase *TCase_mdns_record_create_from_dns = tcase_create("Unit test for mdns_recod_create_from_dns"); + TCase *TCase_mdns_record_copy_with_new_name = tcase_create("Unit test for mdns_record_copy"); + TCase *TCase_mdns_record_copy = tcase_create("Unit test for mdns_record_copy"); + TCase *TCase_mdns_record_create = tcase_create("Unit test for mdns_record_create"); + TCase *TCase_mdns_record_delete = tcase_create("Unit test for mdns_record_delete"); + + /* Record vector functions */ + TCase *TCase_mdns_record_vector_init = tcase_create("Unit test for mdns_record_vector_init"); + TCase *TCase_mdns_record_vector_count = tcase_create("Unit test for mdns_record_vector_count"); + TCase *TCase_mdns_record_vector_add = tcase_create("Unit test for mdns_record_vector_add"); + TCase *TCase_mdns_record_vector_get = tcase_create("Unit test for mdns_record_vector_get"); + TCase *TCase_mdns_record_vector_delete = tcase_create("Unit test for mdns_record_vector_delete"); + TCase *TCase_mdns_record_vector_destroy = tcase_create("Unit test for mdns_record_vector_destroy"); + TCase *TCase_mdns_record_vector_append = tcase_create("Unit test for mdns_record_vector_append"); + + /* Record tree functions */ + TCase *TCase_mdns_record_tree_find_url = tcase_create("Unit test for mdns_record_tree_find_url"); + TCase *TCase_mdns_record_tree_find_url_type = tcase_create("Unit test for mdns_record_tree_find_url_type"); + TCase *TCase_mdns_record_tree_find_record = tcase_create("Unit test for mdns_record_tree_find_record"); + TCase *TCase_mdns_record_tree_del_url = tcase_create("Unit test for mdns_record_tree_del_url"); + TCase *TCase_mdns_record_tree_del_url_type = tcase_create("Unit test for mdns_record_tree_del_url_type"); + TCase *TCase_mdns_record_tree_del_record = tcase_create("Unit test for mdns_record_tree_del_record"); + TCase *TCase_mdns_record_tree_add_record = tcase_create("Unit test for mdns_record_tree_add_record"); + + /* My record functions */ + TCase *TCase_mdns_my_records_find_url_type = tcase_create("Unit test for mdns_my_records_find_url_type"); + TCase *TCase_mdns_my_records_add = tcase_create("Unit test for mdns_my_records_add"); + TCase *TCase_mdns_my_records_find_probed = tcase_create("Unit test for mdns_my_records_find_probed"); + TCase *TCase_mdns_my_records_find_to_probe = tcase_create("Unit test for mdns_my_records_find_to_probe"); + TCase *TCase_mdns_my_records_claimed_id = tcase_create("Unit test for mdns_my_records_claimed_id"); + TCase *TCase_mdns_my_records_claimed = tcase_create("Unit test for mdns_my_records_claimed"); + + /* Query functions */ + TCase *TCase_mdns_query_create = tcase_create("Unit test for mdns_query_create"); + + /* Answer functions */ + TCase *TCase_mdns_answer_create = tcase_create("Unit test for mdns_answer_create"); + + /* Cache functions */ + TCase *TCase_mdns_cache_add_record = tcase_create("Unit test for mdns_cache_add_record"); + TCase *TCase_mdns_cache_flush = tcase_create("Unit test for mdns_cache_flush"); + TCase *TCase_mdns_populate_answer_vector = tcase_create("Unit test for mdns_populate_answer_vector"); + + /* Handling receptions */ + TCase *TCase_mdns_handle_data_as_questions = tcase_create("Unit test for mdns_handle_data_as_questions"); + TCase *TCase_mdns_handle_data_as_answers = tcase_create("Unit test for mdns_handle_data_as_answers"); + TCase *TCase_mdns_handle_data_as_authorities = tcase_create("Unit test for mdns_handle_data_as_authorities"); + TCase *TCase_mdns_handle_data_as_additionals = tcase_create("Unit test for mdns_handle_data_as_additionals"); + + /* Handling query packets */ + TCase *TCase_mdns_sort_unicast_multicast = tcase_create("Unit test for mdns_sort_unicast_multicast"); + TCase *TCase_mdns_apply_known_answer_suppression = tcase_create("Unit test for mdns_apply_known_answer_suppression"); + + /* Address resolving functions */ + TCase *TCase_mdns_send_query_packet = tcase_create("Unit test for mdns_send_query_packet"); + TCase *TCase_mdns_getrecord = tcase_create("Unit test for mdns_getrecord"); + + /* Probe & Announcement functions */ + TCase *TCase_mdns_send_announcement_packet = tcase_create("Unit test for mdns_send_announcement_packet"); + TCase *TCase_mdns_announce = tcase_create("Unit test for mdns_announce"); + TCase *TCase_mdns_send_probe_packet = tcase_create("Unit test for mdns_send_probe_packet"); + TCase *TCase_mdns_add_probe_question = tcase_create("Unit test for mdns_add_probe_question"); + TCase *TCase_mdns_probe = tcase_create("Unit test for mdns_probe"); + + /* Claiming functions */ + TCase *TCase_mdns_claim = tcase_create("Unit test for mnds_claim"); + + /* API functions */ + TCase *TCase_mdns_set_hostname = tcase_create("Unit test for mdns_set_hostname"); + TCase *TCase_mdns_get_hostname = tcase_create("Unit test for mdns_get_hostname"); + + tcase_add_test(TCase_mdns_init, tc_mdns_init); + suite_add_tcase(s, TCase_mdns_init); + + /* Comparing functions */ + tcase_add_test(TCase_mdns_rdata_cmp, tc_mdns_rdata_cmp); + suite_add_tcase(s, TCase_mdns_rdata_cmp); tcase_add_test(TCase_mdns_cmp, tc_mdns_cmp); suite_add_tcase(s, TCase_mdns_cmp); - tcase_add_test(TCase_pico_mdns_send, tc_pico_mdns_send); - suite_add_tcase(s, TCase_pico_mdns_send); - tcase_add_test(TCase_pico_mdns_cache_del_rr, tc_pico_mdns_cache_del_rr); - suite_add_tcase(s, TCase_pico_mdns_cache_del_rr); - tcase_add_test(TCase_pico_mdns_add_cookie, tc_pico_mdns_add_cookie); - suite_add_tcase(s, TCase_pico_mdns_add_cookie); - tcase_add_test(TCase_pico_mdns_fill_header, tc_pico_mdns_fill_header); - suite_add_tcase(s, TCase_pico_mdns_fill_header); - tcase_add_test(TCase_pico_mdns_create_answer, tc_pico_mdns_create_answer); - suite_add_tcase(s, TCase_pico_mdns_create_answer); - tcase_add_test(TCase_pico_mdns_create_query, tc_pico_mdns_create_query); - suite_add_tcase(s, TCase_pico_mdns_create_query); - tcase_add_test(TCase_pico_mdns_del_cookie, tc_pico_mdns_del_cookie); - suite_add_tcase(s, TCase_pico_mdns_del_cookie); - tcase_add_test(TCase_pico_mdns_cache_find_rr, tc_pico_mdns_cache_find_rr); - suite_add_tcase(s, TCase_pico_mdns_cache_find_rr); - tcase_add_test(TCase_pico_mdns_cache_add_rr, tc_pico_mdns_cache_add_rr); - suite_add_tcase(s, TCase_pico_mdns_cache_add_rr); - tcase_add_test(TCase_pico_mdns_flush_cache, tc_pico_mdns_flush_cache); - suite_add_tcase(s, TCase_pico_mdns_flush_cache); - tcase_add_test(TCase_pico_mdns_find_cookie, tc_pico_mdns_find_cookie); - suite_add_tcase(s, TCase_pico_mdns_find_cookie); - tcase_add_test(TCase_pico_get_ip6_from_ip4, tc_pico_get_ip6_from_ip4); - suite_add_tcase(s, TCase_pico_get_ip6_from_ip4); - tcase_add_test(TCase_pico_mdns_reply_query, tc_pico_mdns_reply_query); - suite_add_tcase(s, TCase_pico_mdns_reply_query); - tcase_add_test(TCase_pico_mdns_handle_query, tc_pico_mdns_handle_query); - suite_add_tcase(s, TCase_pico_mdns_handle_query); - tcase_add_test(TCase_pico_mdns_handle_answer, tc_pico_mdns_handle_answer); - suite_add_tcase(s, TCase_pico_mdns_handle_answer); - - tcase_add_test(TCase_pico_mdns_namelen_comp, tc_pico_mdns_namelen_comp); - suite_add_tcase(s, TCase_pico_mdns_namelen_comp); - tcase_add_test(TCase_pico_mdns_namelen_uncomp, tc_pico_mdns_namelen_uncomp); - suite_add_tcase(s, TCase_pico_mdns_namelen_uncomp); - tcase_add_test(TCase_pico_mdns_expand_name_comp, tc_pico_mdns_expand_name_comp); - suite_add_tcase(s, TCase_pico_mdns_expand_name_comp); - - tcase_add_test(TCase_pico_mdns_recv, tc_pico_mdns_recv); - suite_add_tcase(s, TCase_pico_mdns_recv); - tcase_add_test(TCase_pico_mdns_wakeup, tc_pico_mdns_wakeup); - suite_add_tcase(s, TCase_pico_mdns_wakeup); - tcase_add_test(TCase_pico_mdns_announce_timer, tc_pico_mdns_announce_timer); - suite_add_tcase(s, TCase_pico_mdns_announce_timer); - tcase_add_test(TCase_pico_mdns_announce, tc_pico_mdns_announce); - suite_add_tcase(s, TCase_pico_mdns_announce); - tcase_add_test(TCase_pico_mdns_probe_timer, tc_pico_mdns_probe_timer); - suite_add_tcase(s, TCase_pico_mdns_probe_timer); - tcase_add_test(TCase_pico_mdns_probe, tc_pico_mdns_probe); - suite_add_tcase(s, TCase_pico_mdns_probe); - tcase_add_test(TCase_pico_mdns_getaddr_generic, tc_pico_mdns_getaddr_generic); - suite_add_tcase(s, TCase_pico_mdns_getaddr_generic); - tcase_add_test(TCase_pico_mdns_getname_generic, tc_pico_mdns_getname_generic); - suite_add_tcase(s, TCase_pico_mdns_getname_generic); + tcase_add_test(TCase_mdns_cmp_name_type, tc_mdns_cmp_name_type); + suite_add_tcase(s, TCase_mdns_cmp_name_type); + tcase_add_test(TCase_mdns_cookie_cmp, tc_mdns_cookie_cmp); + suite_add_tcase(s, TCase_mdns_cookie_cmp); + + /* Cookie functions */ + tcase_add_test(TCase_mdns_cookie_delete, tc_mdns_cookie_delete); + suite_add_tcase(s, TCase_mdns_cookie_delete); + tcase_add_test(TCase_mdns_cookie_create, tc_mdns_cookie_create); + suite_add_tcase(s, TCase_mdns_cookie_create); + tcase_add_test(TCase_mdns_cookie_tree_find_query_cookie, tc_mdns_cookie_tree_find_query_cookie); + suite_add_tcase(s, TCase_mdns_cookie_tree_find_query_cookie); + tcase_add_test(TCase_mdns_cookie_tree_del_cookie, tc_mdns_cookie_tree_del_cookie); + suite_add_tcase(s, TCase_mdns_cookie_tree_del_cookie); + tcase_add_test(TCase_mdns_cookie_tree_add_cookie, tc_mdns_cookie_tree_add_cookie); + suite_add_tcase(s, TCase_mdns_cookie_tree_add_cookie); + tcase_add_test(TCase_mdns_cookie_find_record, tc_mdns_cookie_find_record); + suite_add_tcase(s, TCase_mdns_cookie_find_record); + tcase_add_test(TCase_mdns_cookie_apply_spt, tc_mdns_cookie_apply_spt); + suite_add_tcase(s, TCase_mdns_cookie_apply_spt); + tcase_add_test(TCase_mdns_is_suffix_present, tc_mdns_is_suffix_present); + suite_add_tcase(s, TCase_mdns_is_suffix_present); + tcase_add_test(TCase_mdns_resolve_name_conflict, tc_mdns_resolve_name_conflict); + suite_add_tcase(s, TCase_mdns_resolve_name_conflict); + tcase_add_test(TCase_mdns_generate_new_records, tc_mdns_generate_new_records); + suite_add_tcase(s, TCase_mdns_generate_new_records); + tcase_add_test(TCase_mdns_cookie_resolve_conflict, tc_mdns_cookie_resolve_conflict); + suite_add_tcase(s, TCase_mdns_cookie_resolve_conflict); + + /* Question functions */ + tcase_add_test(TCase_mdns_question_create, tc_mdns_question_create); + suite_add_tcase(s, TCase_mdns_question_create); + + /* Record functions */ + tcase_add_test(TCase_mdns_dns_record_create, tc_mdns_dns_record_create); + suite_add_tcase(s, TCase_mdns_dns_record_create); + tcase_add_test(TCase_mdns_record_resolve_conflict, tc_mdns_record_resolve_conflict); + suite_add_tcase(s, TCase_mdns_record_resolve_conflict); + tcase_add_test(TCase_mdns_record_am_i_lexi_later, tc_mdns_record_am_i_lexi_later); + suite_add_tcase(s, TCase_mdns_record_am_i_lexi_later); + tcase_add_test(TCase_mdns_record_create_from_dns, tc_mdns_record_create_from_dns); + suite_add_tcase(s, TCase_mdns_record_create_from_dns); + tcase_add_test(TCase_mdns_record_copy_with_new_name, tc_mdns_record_copy_with_new_name); + suite_add_tcase(s, TCase_mdns_record_copy_with_new_name); + tcase_add_test(TCase_mdns_record_copy, tc_mdns_record_copy); + suite_add_tcase(s, TCase_mdns_record_copy); + tcase_add_test(TCase_mdns_record_create, tc_mdns_record_create); + suite_add_tcase(s, TCase_mdns_record_create); + tcase_add_test(TCase_mdns_record_delete, tc_mdns_record_delete); + suite_add_tcase(s, TCase_mdns_record_delete); + + /* Record Vector functions */ + tcase_add_test(TCase_mdns_record_vector_init, tc_mdns_record_vector_init); + suite_add_tcase(s, TCase_mdns_record_vector_init); + tcase_add_test(TCase_mdns_record_vector_count, tc_mdns_record_vector_count); + suite_add_tcase(s, TCase_mdns_record_vector_count); + tcase_add_test(TCase_mdns_record_vector_add, tc_mdns_record_vector_add); + suite_add_tcase(s, TCase_mdns_record_vector_add); + tcase_add_test(TCase_mdns_record_vector_get, tc_mdns_record_vector_get); + suite_add_tcase(s, TCase_mdns_record_vector_get); + tcase_add_test(TCase_mdns_record_vector_delete, tc_mdns_record_vector_delete); + suite_add_tcase(s, TCase_mdns_record_vector_delete); + tcase_add_test(TCase_mdns_record_vector_destroy, tc_mdns_record_vector_destroy); + suite_add_tcase(s, TCase_mdns_record_vector_destroy); + tcase_add_test(TCase_mdns_record_vector_append, tc_mdns_record_vector_append); + + /* Record tree functions */ + tcase_add_test(TCase_mdns_record_tree_find_url, tc_mdns_record_tree_find_url); + suite_add_tcase(s, TCase_mdns_record_tree_find_url); + tcase_add_test(TCase_mdns_record_tree_find_url_type, tc_mdns_record_tree_find_url_type); + suite_add_tcase(s, TCase_mdns_record_tree_find_url_type); + tcase_add_test(TCase_mdns_record_tree_find_record, tc_mdns_record_tree_find_record); + suite_add_tcase(s, TCase_mdns_record_tree_find_record); + tcase_add_test(TCase_mdns_record_tree_del_url, tc_mdns_record_tree_del_url); + suite_add_tcase(s, TCase_mdns_record_tree_del_url); + tcase_add_test(TCase_mdns_record_tree_del_url_type, tc_mdns_record_tree_del_url_type); + suite_add_tcase(s, TCase_mdns_record_tree_del_url_type); + tcase_add_test(TCase_mdns_record_tree_del_record, tc_mdns_record_tree_del_record); + suite_add_tcase(s, TCase_mdns_record_tree_del_record); + tcase_add_test(TCase_mdns_record_tree_add_record, tc_mdns_record_tree_add_record); + suite_add_tcase(s, TCase_mdns_record_tree_add_record); + + /* My records functions */ + tcase_add_test(TCase_mdns_my_records_find_url_type, tc_mdns_my_records_find_url_type); + suite_add_tcase(s, TCase_mdns_my_records_find_url_type); + tcase_add_test(TCase_mdns_my_records_add, tc_mdns_my_records_add); + suite_add_tcase(s, TCase_mdns_my_records_add); + tcase_add_test(TCase_mdns_my_records_find_probed, tc_mdns_my_records_find_probed); + suite_add_tcase(s, TCase_mdns_my_records_find_probed); + tcase_add_test(TCase_mdns_my_records_find_to_probe, tc_mdns_my_records_find_to_probe); + suite_add_tcase(s, TCase_mdns_my_records_find_to_probe); + tcase_add_test(TCase_mdns_my_records_claimed_id, tc_mdns_my_records_claimed_id); + suite_add_tcase(s, TCase_mdns_my_records_claimed_id); + tcase_add_test(TCase_mdns_my_records_claimed, tc_mdns_my_records_claimed); + suite_add_tcase(s, TCase_mdns_my_records_claimed); + + /* Query functions */ + tcase_add_test(TCase_mdns_query_create, tc_mdns_query_create); + suite_add_tcase(s, TCase_mdns_query_create); + + /* Answer functions */ + tcase_add_test(TCase_mdns_answer_create, tc_mdns_answer_create); + suite_add_tcase(s, TCase_mdns_answer_create); + + /* Cache functions */ + tcase_add_test(TCase_mdns_cache_add_record, tc_mdns_cache_add_record); + suite_add_tcase(s, TCase_mdns_cache_add_record); + tcase_add_test(TCase_mdns_cache_flush, tc_mdns_cache_flush); + suite_add_tcase(s, TCase_mdns_cache_flush); + tcase_add_test(TCase_mdns_populate_answer_vector, tc_mdns_populate_answer_vector); + suite_add_tcase(s, TCase_mdns_populate_answer_vector); + + /* Handling receptions */ + tcase_add_test(TCase_mdns_handle_data_as_questions, tc_mdns_handle_data_as_questions); + suite_add_tcase(s, TCase_mdns_handle_data_as_questions); + tcase_add_test(TCase_mdns_handle_data_as_answers, tc_mdns_handle_data_as_answers); + suite_add_tcase(s, TCase_mdns_handle_data_as_answers); + tcase_add_test(TCase_mdns_handle_data_as_authorities, tc_mdns_handle_data_as_authorities); + suite_add_tcase(s, TCase_mdns_handle_data_as_authorities); + tcase_add_test(TCase_mdns_handle_data_as_additionals, tc_mdns_handle_data_as_additionals); + suite_add_tcase(s, TCase_mdns_handle_data_as_additionals); + + /* Handling query packets */ + tcase_add_test(TCase_mdns_sort_unicast_multicast, tc_mdns_sort_unicast_multicast); + suite_add_tcase(s, TCase_mdns_sort_unicast_multicast); + tcase_add_test(TCase_mdns_apply_known_answer_suppression, tc_mdns_apply_known_answer_suppression); + suite_add_tcase(s, TCase_mdns_apply_known_answer_suppression); + + /* Address resolving functions */ + tcase_add_test(TCase_mdns_send_query_packet, tc_mdns_send_query_packet); + suite_add_tcase(s, TCase_mdns_send_query_packet); + tcase_add_test(TCase_mdns_getrecord, tc_mdns_getrecord); + suite_add_tcase(s, TCase_mdns_getrecord); + + /* Probe & Announcement functions */ + tcase_add_test(TCase_mdns_send_announcement_packet, tc_mdns_send_announcement_packet); + suite_add_tcase(s, TCase_mdns_send_announcement_packet); + tcase_add_test(TCase_mdns_announce, tc_mdns_announce); + suite_add_tcase(s, TCase_mdns_announce); + tcase_add_test(TCase_mdns_send_probe_packet, tc_mdns_send_probe_packet); + suite_add_tcase(s, TCase_mdns_send_probe_packet); + tcase_add_test(TCase_mdns_add_probe_question, tc_mdns_add_probe_question); + suite_add_tcase(s, TCase_mdns_add_probe_question); + tcase_add_test(TCase_mdns_probe, tc_mdns_probe); + suite_add_tcase(s, TCase_mdns_probe); + + /* Claiming functions */ + tcase_add_test(TCase_mdns_claim, tc_mdns_claim); + suite_add_tcase(s, TCase_mdns_claim); + + /* API functions */ + tcase_add_test(TCase_mdns_set_hostname, tc_mdns_set_hostname); + suite_add_tcase(s, TCase_mdns_set_hostname); + tcase_add_test(TCase_mdns_get_hostname, tc_mdns_get_hostname); + suite_add_tcase(s, TCase_mdns_get_hostname); + return s; } @@ -549,3 +2774,4 @@ int main(void) srunner_free(sr); return fails; } + diff --git a/test/unit/modunit_pico_stack.c b/test/unit/modunit_pico_stack.c index e48c0268c..ac48c1ea5 100644 --- a/test/unit/modunit_pico_stack.c +++ b/test/unit/modunit_pico_stack.c @@ -66,7 +66,7 @@ START_TEST(tc_calc_score) END_TEST #ifdef PICO_FAULTY -void fake_timer(pico_time __attribute__((unused)) now, void __attribute__((unused)) *n) +void fake_timer(pico_time __attribute__((unused)) now, void __attribute__((unused)) *n) { } diff --git a/test/unit/modunit_pico_tftp.c b/test/unit/modunit_pico_tftp.c index a863f9fc1..1077718fc 100644 --- a/test/unit/modunit_pico_tftp.c +++ b/test/unit/modunit_pico_tftp.c @@ -61,18 +61,18 @@ void pico_timer_cancel(struct pico_timer *t) /* TESTS */ -/* START_TEST(tc_check_opcode) */ -/* { */ -/* / * TODO: test this: static int check_opcode(struct pico_tftp_hdr *th) * / */ -/* struct pico_tftp_hdr th; */ -/* th.opcode = 0; */ -/* fail_unless(check_opcode(&th) == -1); */ -/* th.opcode = short_be(PICO_TFTP_RRQ); */ -/* fail_unless(check_opcode(&th) == 0); */ -/* th.opcode = short_be(0xFF); */ -/* fail_unless(check_opcode(&th) == -1); */ -/* } */ -/* END_TEST */ +//START_TEST(tc_check_opcode) +//{ +// /* TODO: test this: static int check_opcode(struct pico_tftp_hdr *th) */ +// struct pico_tftp_hdr th; +// th.opcode = 0; +// fail_unless(check_opcode(&th) == -1); +// th.opcode = short_be(PICO_TFTP_RRQ); +// fail_unless(check_opcode(&th) == 0); +// th.opcode = short_be(0xFF); +// fail_unless(check_opcode(&th) == -1); +//} +//END_TEST START_TEST(tc_find_session_by_socket) @@ -227,20 +227,20 @@ END_TEST START_TEST(tc_pico_tftp_abort) { -/* int ret; */ -/* */ -/* server.listen_socket = NULL; */ +// int ret; +// +// server.listen_socket = NULL; /*first case: no session and no listening socket*/ -/* ret = pico_tftp_abort(NULL, TFTP_ERR_EUSR, "test"); */ -/* fail_if(ret != -1); */ +// ret = pico_tftp_abort(NULL, TFTP_ERR_EUSR, "test"); +// fail_if(ret != -1); /*second case: no session but listening socket*/ -/* server.listen_socket = example_session.socket = &example_socket; */ -/* pico_tftp_abort(NULL, TFTP_ERR_EUSR, "test"); */ -/* fail_if(ret != -1); */ +// server.listen_socket = example_session.socket = &example_socket; +// pico_tftp_abort(NULL, TFTP_ERR_EUSR, "test"); +// fail_if(ret != -1); /*tirdh case: session non into list*/ -/* ret = pico_tftp_abort(&example_session, TFTP_ERR_EUSR, "test"); */ -/* fail_if(ret != -1); */ +// ret = pico_tftp_abort(&example_session, TFTP_ERR_EUSR, "test"); +// fail_if(ret != -1); } END_TEST @@ -297,7 +297,7 @@ Suite *pico_suite(void) { Suite *s = suite_create("PicoTCP"); -/* TCase *TCase_check_opcode = tcase_create("Unit test for check_opcode"); */ +// TCase *TCase_check_opcode = tcase_create("Unit test for check_opcode"); TCase *TCase_find_session_by_socket = tcase_create("Unit test for find_session_by_socket"); TCase *TCase_tftp_finish = tcase_create("Unit test for tftp_finish"); TCase *TCase_tftp_send_ack = tcase_create("Unit test for tftp_send_ack"); @@ -318,8 +318,8 @@ Suite *pico_suite(void) TCase *TCase_tftp_socket_open = tcase_create("Unit test for tftp_socket_open"); -/* tcase_add_test(TCase_check_opcode, tc_check_opcode); */ -/* suite_add_tcase(s, TCase_check_opcode); */ +// tcase_add_test(TCase_check_opcode, tc_check_opcode); +// suite_add_tcase(s, TCase_check_opcode); tcase_add_test(TCase_find_session_by_socket, tc_find_session_by_socket); suite_add_tcase(s, TCase_find_session_by_socket); tcase_add_test(TCase_tftp_finish, tc_tftp_finish); diff --git a/test/unit/modunit_seq.c b/test/unit/modunit_seq.c index 25264e86d..73b9fb4e4 100644 --- a/test/unit/modunit_seq.c +++ b/test/unit/modunit_seq.c @@ -10,26 +10,26 @@ START_TEST(tc_seq_compare) uint32_t over_thresh = 0x80000000lu; uint32_t zero = 0lu; - fail_if(pico_seq_compare(small_a, small_b) >= 0); - fail_if(pico_seq_compare(small_b, small_a) <= 0); + fail_if(seq_compare(small_a, small_b) >= 0); + fail_if(seq_compare(small_b, small_a) <= 0); - fail_if(pico_seq_compare(over_thresh, under_thresh) <= 0); - fail_if(pico_seq_compare(under_thresh, over_thresh) >= 0); + fail_if(seq_compare(over_thresh, under_thresh) <= 0); + fail_if(seq_compare(under_thresh, over_thresh) >= 0); - fail_if(pico_seq_compare(small_a, big_b) <= 0); - fail_if(pico_seq_compare(big_b, small_a) >= 0); + fail_if(seq_compare(small_a, big_b) <= 0); + fail_if(seq_compare(big_b, small_a) >= 0); - fail_if(pico_seq_compare(small_a, zero) <= 0); - fail_if(pico_seq_compare(zero, small_a) >= 0); + fail_if(seq_compare(small_a, zero) <= 0); + fail_if(seq_compare(zero, small_a) >= 0); - fail_if(pico_seq_compare(big_a, zero) >= 0); - fail_if(pico_seq_compare(zero, big_a) <= 0); + fail_if(seq_compare(big_a, zero) >= 0); + fail_if(seq_compare(zero, big_a) <= 0); - fail_if(pico_seq_compare(big_a, big_b) >= 0); - fail_if(pico_seq_compare(big_b, big_a) <= 0); + fail_if(seq_compare(big_a, big_b) >= 0); + fail_if(seq_compare(big_b, big_a) <= 0); - fail_if(pico_seq_compare(big_a, big_a) != 0); - fail_if(pico_seq_compare(zero, zero) != 0); + fail_if(seq_compare(big_a, big_a) != 0); + fail_if(seq_compare(zero, zero) != 0); } END_TEST @@ -37,7 +37,7 @@ END_TEST Suite *pico_suite(void) { Suite *s = suite_create("pico tcp sequence numbers"); - TCase *TCase_seq_compare = tcase_create("Unit test for pico_seq_compare"); + TCase *TCase_seq_compare = tcase_create("Unit test for seq_compare"); tcase_add_test(TCase_seq_compare, tc_seq_compare); suite_add_tcase(s, TCase_seq_compare); return s; diff --git a/test/unit/unit_ipv6.c b/test/unit/unit_ipv6.c index baec8594b..71aedd852 100644 --- a/test/unit/unit_ipv6.c +++ b/test/unit/unit_ipv6.c @@ -226,7 +226,7 @@ START_TEST (test_ipv6) dev[i] = pico_null_create(devname); a[i] = iphex_a; a[i].addr[4] += i; - fail_if(pico_ipv6_link_add(dev[i], a[i], nm64) == NULL, "Error adding link"); + fail_if(pico_ipv6_link_add(dev[i], a[i], nm64) != 0, "Error adding link"); } /*link_find + link_get + route_add*/ for (i = 0; i < 10; ++i) { @@ -252,10 +252,10 @@ START_TEST (test_ipv6) fail_if(pico_ipv6_link_del(dev[i], a[i]) != 0, "Error deleting link"); } /* add 2 links to dev[0] */ - _link = pico_ipv6_link_add(dev[0], a[0], nm64); - fail_if (!_link, "Error adding link"); - _link = pico_ipv6_link_add(dev[0], a[1], nm64); - fail_if (!_link, "Error adding link"); + ret = pico_ipv6_link_add(dev[0], a[0], nm64); + fail_if(ret != 0, "Error adding link"); + ret = pico_ipv6_link_add(dev[0], a[1], nm64); + fail_if(ret != 0, "Error adding link"); /* add 2 routes to each of the links */ ret = pico_ipv6_route_add(r[0], nm128, a[0], 1, l[0]); fail_if(ret != 0, "Error adding route"); @@ -267,10 +267,10 @@ START_TEST (test_ipv6) fail_if(ret != 0, "Error adding route"); /* add 2 links to dev[1] */ - _link = pico_ipv6_link_add(dev[1], a[8], nm64); - fail_if (!_link, "Error adding link"); - _link = pico_ipv6_link_add(dev[1], a[9], nm64); - fail_if (!_link, "Error adding link"); + ret = pico_ipv6_link_add(dev[1], a[8], nm64); + fail_if(ret != 0, "Error adding link"); + ret = pico_ipv6_link_add(dev[1], a[9], nm64); + fail_if(ret != 0, "Error adding link"); /* add 2 routes to each of the links */ ret = pico_ipv6_route_add(r[6], nm128, a[8], 1, l[8]); fail_if(ret != 0, "Error adding route"); diff --git a/test/unit/unit_socket.c b/test/unit/unit_socket.c index e3f26ccb4..b1e737cc4 100644 --- a/test/unit/unit_socket.c +++ b/test/unit/unit_socket.c @@ -1,8 +1,4 @@ -int pico_aodv_init(void) -{ - return 0; -} START_TEST (test_socket) { int ret = 0; diff --git a/test/unit/unit_timer.c b/test/unit/unit_timer.c index 35de8f209..ce8893dff 100644 --- a/test/unit/unit_timer.c +++ b/test/unit/unit_timer.c @@ -1,5 +1,4 @@ -#define EXISTING_TIMERS 5 - +#define EXISTING_TIMERS 4 START_TEST (test_timers) { diff --git a/test/units.sh b/test/units.sh index e8fbfbfe2..b7340a2f5 100755 --- a/test/units.sh +++ b/test/units.sh @@ -9,13 +9,13 @@ rm -f /tmp/pico-mem-report-* ./build/test/modunit_tcp.elf || exit 1 ./build/test/modunit_dev_loop.elf || exit 1 ./build/test/modunit_dns_client.elf || exit 1 +./build/test/modunit_dns_common.elf || exit 1 ./build/test/modunit_sntp_client.elf || exit 1 ./build/test/modunit_ipv6_nd.elf || exit 1 ./build/test/modunit_mdns.elf || exit 1 ./build/test/modunit_ipfilter.elf || exit 1 ./build/test/modunit_queue.elf || exit 1 ./build/test/modunit_tftp.elf || exit 1 -./build/test/modunit_aodv.elf || exit 1 MAXMEM=`cat /tmp/pico-mem-report-* | sort -r -n |head -1` echo