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