diff --git a/Makefile b/Makefile index 5379a5547..df0c3fc12 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,7 @@ CRC?=1 OLSR?=0 SLAACV4?=1 TFTP?=1 +AODV?=1 MEMORY_MANAGER?=0 MEMORY_MANAGER_PROFILING?=0 TUN?=0 @@ -78,6 +79,11 @@ 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 @@ -164,6 +170,12 @@ ifeq ($(ARCH),lpc18xx) -mcpu=cortex-m3 -mthumb -MMD -MP -DLPC18XX endif +ifeq ($(ARCH),lpc17xx) + CFLAGS+=-fmessage-length=0 -fno-builtin \ + -ffunction-sections -fdata-sections -mlittle-endian \ + -mcpu=cortex-m3 -mthumb -MMD -MP -DLPC17XX +endif + ifeq ($(ARCH),lpc43xx) CFLAGS+=-fmessage-length=0 -fno-builtin \ -ffunction-sections -fdata-sections -mlittle-endian \ @@ -192,7 +204,7 @@ ifeq ($(ARCH),shared) CFLAGS+=-fPIC endif -.c.o: +%.o:%.c deps $(CC) -c $(CFLAGS) -o $@ $< CORE_OBJ= stack/pico_stack.o \ @@ -283,11 +295,11 @@ endif all: mod core lib -core: deps $(CORE_OBJ) +core: $(CORE_OBJ) @mkdir -p $(PREFIX)/lib @mv stack/*.o $(PREFIX)/lib -mod: deps $(MOD_OBJ) +mod: $(MOD_OBJ) @mkdir -p $(PREFIX)/modules @mv modules/*.o $(PREFIX)/modules || echo @@ -348,7 +360,7 @@ 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) + @$(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/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 @@ -361,6 +373,7 @@ units: mod core lib $(UNITS_OBJ) $(MOD_OBJ) @$(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/docs/user_manual/chap_api_aodv.tex b/docs/user_manual/chap_api_aodv.tex new file mode 100644 index 000000000..02171ea20 --- /dev/null +++ b/docs/user_manual/chap_api_aodv.tex @@ -0,0 +1,42 @@ +\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 d75309e57..da43a1a30 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. +socket will be unbound and not connected. \subsubsection*{Function prototype} \begin{verbatim} @@ -57,7 +57,7 @@ \subsubsection*{Example} \subsection{pico$\_$socket$\_$read} \subsubsection*{Description} -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. +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. \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 a string buffer where the string will be stored +\item \texttt{buf} - Void pointer to the start of the buffer where the received data 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,10 +92,9 @@ \subsubsection*{Example} \subsection{pico$\_$socket$\_$write} \subsubsection*{Description} -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. +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. \subsubsection*{Function prototype} \begin{verbatim} @@ -105,8 +104,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 string buffer where the string is stored -\item \texttt{len} - Length of the string that is stored in the buffer (in bytes) +\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} \end{itemize} \subsubsection*{Return value} @@ -134,9 +133,10 @@ \subsubsection*{Example} \subsection{pico$\_$socket$\_$sendto} \subsubsection*{Description} -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. +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. \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 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{buf} - Void pointer to the start of the buffer +\item \texttt{len} - Length of the buffer \texttt{buf} \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 a string of data from the specified socket. +This function is called to receive 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 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{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 \end{itemize} @@ -216,12 +216,119 @@ \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 a string of data to the specified socket. -This function also checks if the socket is connected and then calls the +This function is called to send data to the specified socket. +It checks if the socket is connected and then calls the \texttt{pico$\_$socket$\_$sendto} function. \subsubsection*{Function prototype} @@ -233,8 +340,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 string buffer where the string is stored -\item \texttt{len} - Length of the string that is stored in the buffer (in bytes) +\item \texttt{buf} - Void pointer to the start of the buffer +\item \texttt{len} - Length of the buffer \texttt{buf} \end{itemize} \subsubsection*{Return value} @@ -270,8 +377,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 string buffer where the string will be stored -\item \texttt{len} - Length of the string in the socket buffer (in bytes) +\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} \end{itemize} \subsubsection*{Return value} @@ -365,6 +472,47 @@ \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 934f935ba..d540126c6 100644 --- a/docs/user_manual/chap_rfcs.tex +++ b/docs/user_manual/chap_rfcs.tex @@ -127,6 +127,9 @@ 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 diff --git a/docs/user_manual/user_doc.tex b/docs/user_manual/user_doc.tex index 6464b7dc9..40d40c4a0 100644 --- a/docs/user_manual/user_doc.tex +++ b/docs/user_manual/user_doc.tex @@ -98,6 +98,7 @@ \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_lpc1768.h b/include/arch/pico_lpc17xx.h similarity index 100% rename from include/arch/pico_lpc1768.h rename to include/arch/pico_lpc17xx.h diff --git a/include/arch/pico_lpc18xx.h b/include/arch/pico_lpc18xx.h index c038c956d..849a01c2d 100644 --- a/include/arch/pico_lpc18xx.h +++ b/include/arch/pico_lpc18xx.h @@ -13,8 +13,7 @@ #define dbg(...) - -extern volatile uint32_t tassTick; +extern volatile unsigned int tassTick; #ifdef PICO_SUPPORT_RTOS #define PICO_SUPPORT_MUTEX @@ -77,19 +76,25 @@ static inline void pico_free(void *x) return pico_ffree(x); } +#else +//#define MEM_MEAS +#ifdef MEM_MEAS + 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 #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 void *pico_zalloc(size_t size) + { + void *ptr = malloc(size); + + if(ptr) + memset(ptr, 0u, size); + + return ptr; + } +#endif #endif extern volatile uint32_t lpc_tick; diff --git a/include/arch/pico_stm32.h b/include/arch/pico_stm32.h index 7318f1b6d..d576834dc 100644 --- a/include/arch/pico_stm32.h +++ b/include/arch/pico_stm32.h @@ -5,7 +5,7 @@ #define dbg(...) do {} while(0) /* #define dbg printf */ -extern volatile uint32_t tassTick; +extern volatile unsigned int tassTick; #ifdef PICO_SUPPORT_RTOS #define PICO_SUPPORT_MUTEX diff --git a/include/pico_config.h b/include/pico_config.h index bcd2c6b04..1df7f71d9 100644 --- a/include/pico_config.h +++ b/include/pico_config.h @@ -133,7 +133,6 @@ 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); @@ -191,9 +190,11 @@ static inline uint64_t long_long_be(uint64_t le) #elif defined STELLARIS # include "arch/pico_stellaris.h" #elif defined LPC -# include "arch/pico_lpc1768.h" +# include "arch/pico_lpc17xx.h" #elif defined LPC43XX # include "arch/pico_lpc43xx.h" +#elif defined LPC17XX +# include "arch/pico_lpc17xx.h" #elif defined LPC18XX # include "arch/pico_lpc18xx.h" #elif defined PIC24 diff --git a/include/pico_frame.h b/include/pico_frame.h index 87833719f..22a40026c 100644 --- a/include/pico_frame.h +++ b/include/pico_frame.h @@ -80,6 +80,9 @@ 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_socket.h b/include/pico_socket.h index 9e8beafac..4d27daf2b 100644 --- a/include/pico_socket.h +++ b/include/pico_socket.h @@ -178,6 +178,11 @@ 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)); @@ -185,13 +190,19 @@ 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); diff --git a/include/pico_stack.h b/include/pico_stack.h index 8e1c696a9..36e8b318c 100644 --- a/include/pico_stack.h +++ b/include/pico_stack.h @@ -80,5 +80,6 @@ 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/modules/pico_aodv.c b/modules/pico_aodv.c new file mode 100644 index 000000000..031abc073 --- /dev/null +++ b/modules/pico_aodv.c @@ -0,0 +1,619 @@ +/********************************************************************* + 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 new file mode 100644 index 000000000..e6c3fad7c --- /dev/null +++ b/modules/pico_aodv.h @@ -0,0 +1,131 @@ +/********************************************************************* + 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_dhcp_client.c b/modules/pico_dhcp_client.c index 948cbd83a..3f148150d 100644 --- a/modules/pico_dhcp_client.c +++ b/modules/pico_dhcp_client.c @@ -668,8 +668,7 @@ struct dhcp_action_entry { static struct dhcp_action_entry dhcp_fsm[] = { /* event |offer |ack |nak |T1 |T2 |lease |retransmit */ -/* state init-reboot */ - { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, +/* state init-reboot */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, /* state rebooting */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, /* state init */ { recv_offer, NULL, NULL, NULL, NULL, NULL, retransmit }, /* state selecting */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL }, diff --git a/modules/pico_dhcp_client.h b/modules/pico_dhcp_client.h index bf493ae72..02fe7e0f5 100644 --- a/modules/pico_dhcp_client.h +++ b/modules/pico_dhcp_client.h @@ -14,7 +14,6 @@ #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_icmp4.c b/modules/pico_icmp4.c index 0cd7f585c..9048d2ed4 100644 --- a/modules/pico_icmp4.c +++ b/modules/pico_icmp4.c @@ -47,6 +47,9 @@ 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) { @@ -55,6 +58,14 @@ 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_icmp6.c b/modules/pico_icmp6.c index a0c8bf3a2..9ca6129c6 100644 --- a/modules/pico_icmp6.c +++ b/modules/pico_icmp6.c @@ -44,6 +44,36 @@ 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; + + 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)); + memcpy(src.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, PICO_SIZE_IP6); + pico_ipv6_frame_push(reply, &src, PICO_PROTO_ICMP6); + 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; @@ -60,23 +90,9 @@ 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"); - 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); + 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); break; case PICO_ICMP6_ECHO_REPLY: @@ -174,7 +190,6 @@ 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; } @@ -182,6 +197,7 @@ 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, &ipv6_hdr->src, PICO_PROTO_ICMP6); return 0; @@ -224,6 +240,11 @@ 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) +{ + 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) { @@ -482,6 +503,7 @@ static int pico_icmp6_send_echo(struct pico_icmp6_ping_cookie *cookie) return 0; } + static void pico_icmp6_ping_timeout(pico_time now, void *arg) { struct pico_icmp6_ping_cookie *cookie = NULL; diff --git a/modules/pico_icmp6.h b/modules/pico_icmp6.h index 37de5acb3..0e5ce5d5a 100644 --- a/modules/pico_icmp6.h +++ b/modules/pico_icmp6.h @@ -251,6 +251,7 @@ 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_ipv4.c b/modules/pico_ipv4.c index d00544b0b..b0c65364b 100644 --- a/modules/pico_ipv4.c +++ b/modules/pico_ipv4.c @@ -19,6 +19,7 @@ #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 @@ -219,6 +220,11 @@ int pico_ipv4_is_valid_src(uint32_t address, struct pico_device *dev) return 0; } else { +#ifdef PICO_SUPPORT_AODV + union pico_address src; + src.ip4.addr = address; + pico_aodv_refresh(&src); +#endif return 1; } } @@ -696,6 +702,7 @@ 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) @@ -876,6 +883,12 @@ 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) { pico_err = PICO_ERR_EINVAL; @@ -885,9 +898,9 @@ 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; } @@ -1205,6 +1218,7 @@ int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t pro return -1; } + hdr = (struct pico_ipv4_hdr *) f->net_hdr; if (!hdr) { dbg("IP header error\n"); @@ -1269,10 +1283,15 @@ 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 @@ -1315,6 +1334,16 @@ 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)) { /* it's our own IP */ return pico_enqueue(&in, f); @@ -1350,7 +1379,7 @@ static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_fra } -int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) +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) { struct pico_ipv4_route test, *new; test.dest.addr = address.addr; @@ -1512,7 +1541,7 @@ static int pico_ipv4_cleanup_routes(struct pico_ipv4_link *link) return 0; } -void pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link) +void MOCKABLE pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link) { if (link) default_bcast_route.link = link; @@ -1580,7 +1609,7 @@ struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address) return found; } -struct pico_ipv4_link *pico_ipv4_link_by_dev(struct pico_device *dev) +struct pico_ipv4_link * MOCKABLE pico_ipv4_link_by_dev(struct pico_device *dev) { struct pico_tree_node *index = NULL; struct pico_ipv4_link *link = NULL; @@ -1616,7 +1645,7 @@ struct pico_ipv4_link *pico_ipv4_link_by_dev_next(struct pico_device *dev, struc return NULL; } -struct pico_device *pico_ipv4_link_find(struct pico_ip4 *address) +struct pico_device * MOCKABLE pico_ipv4_link_find(struct pico_ip4 *address) { struct pico_ipv4_link test, *found; if(!address) { diff --git a/modules/pico_ipv6.c b/modules/pico_ipv6.c index e5fd1e7dc..15ed37873 100644 --- a/modules/pico_ipv6.c +++ b/modules/pico_ipv6.c @@ -346,29 +346,15 @@ 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; @@ -453,7 +439,6 @@ 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; } @@ -478,13 +463,11 @@ static int pico_ipv6_forward(struct pico_frame *f) f->start = f->net_hdr; - if (pico_ipv6_forward_check_dev(f) < 0) - return -1; - - pico_sendto_dev(f); - return 0; + return pico_sendto_dev(f); } +#define HBH_LEN(hbh) ((((hbh->ext.hopbyhop.len + 1) << 3) - 2)) /* len in bytes, minus nxthdr and len byte */ + int pico_ipv6_process_hopbyhop(struct pico_ipv6_exthdr *hbh, struct pico_frame *f) { uint8_t *option = NULL; @@ -495,7 +478,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->ext.hopbyhop.len + 1) << 3) - 2); /* len in bytes, minus nxthdr and len byte */ + len = (uint8_t)HBH_LEN(hbh); ipv6_dbg("IPv6: hop by hop extension header length %u\n", len + 2); while (len) { switch (*option) @@ -523,8 +506,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: - /* TODO DLA: check if not multicast */ - pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, ptr + (uint32_t)(option - extensions_start)); + 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)); return -1; } ipv6_dbg("IPv6: option with type %u and length %u\n", *option, optlen); @@ -536,86 +519,258 @@ 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) +int pico_ipv6_process_routing(struct pico_ipv6_exthdr *routing, struct pico_frame *f, uint32_t ptr) { 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 */ - break; + pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_HDRFIELD, ptr + 2); + return -1; case 0x02: /* routing type for MIPv6: not supported yet */ break; default: - /* XXX: ICMP parameter problem (code 0) */ + pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_HDRFIELD, ptr + 2); return -1; } return 0; } -int pico_ipv6_process_frag(struct pico_ipv6_exthdr *fragm, struct pico_frame *f) + +#define IP6FRAG_OFF(x) ((x & 0xFFF8)) +#define IP6FRAG_MORE(x) ((x & 0x0001)) + +static int pico_ipv6_frag_compare(void *ka, void *kb) { - IGNORE_PARAMETER(fragm); - if (!f) { - pico_err = PICO_ERR_EINVAL; + 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)) return -1; - } - ipv6_dbg("IPv6: fragmentation extension header\n"); 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)); + full->net_hdr = full->buffer; + full->net_len = PICO_SIZE_IP6HDR; + if (full) { + 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; + struct pico_frame *cur; + unsigned int bookmark = 0; + pico_tree_foreach(index, &ipv6_fragments) { + 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); + } + } +} -int pico_ipv6_process_destopt(struct pico_ipv6_exthdr *destopt, struct pico_frame *f) +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); + (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_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); +} + +static int pico_ipv6_process_destopt(struct pico_ipv6_exthdr *destopt, struct pico_frame *f, uint32_t opt_ptr) { 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: - 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) { + ipv6_dbg("IPv6: option with type %u and length %u\n", *option, optlen); + 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: - /* XXX: send ICMP parameter problem (code 2), pointing to the unrecognized option type */ + pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT, opt_ptr); return -1; case PICO_IPV6_EXTHDR_OPT_ACTION_DISCARD_SINM: - /* XXX: if destination address was not a multicast address, send an ICMP parameter problem (code 2) */ + 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); 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; } @@ -624,47 +779,61 @@ 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; + struct pico_ipv6_exthdr *exthdr = NULL, *frag_hdr = NULL; uint32_t ptr = sizeof(struct pico_ipv6_hdr); - int is_ipv6_hdr = 1; /* ==1 indicates that the option being parsed is in the header, - * rather than in an extension. - */ - + uint16_t cur_optlen; + uint32_t cur_nexthdr = 6; + int must_align = 0; + f->net_len = sizeof(struct pico_ipv6_hdr); - for (;; ) { + + 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: - /* 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); + 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); return -1; } - - f->net_len = (uint16_t)(f->net_len + ((exthdr->ext.hopbyhop.len + 1) << 3)); + cur_optlen = IPV6_OPTLEN(exthdr->ext.hopbyhop.len); + f->net_len = (uint16_t) (f->net_len + cur_optlen); + must_align = 1; if (pico_ipv6_process_hopbyhop(exthdr, f) < 0) return -1; break; case PICO_IPV6_EXTHDR_ROUTING: - f->net_len = (uint16_t)(f->net_len + ((exthdr->ext.routing.len + 1) << 3)); - if (pico_ipv6_process_routing(exthdr, f) < 0) + 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) return -1; break; case PICO_IPV6_EXTHDR_FRAG: - f->net_len = (uint16_t)(f->net_len + 8); /* fixed length */ - if (pico_ipv6_process_frag(exthdr, f) < 0) + 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); return -1; - + } break; case PICO_IPV6_EXTHDR_DESTOPT: - f->net_len = (uint16_t)(f->net_len + ((exthdr->ext.destopt.len + 1) << 3)); - if (pico_ipv6_process_destopt(exthdr, f) < 0) + 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) return -1; - break; case PICO_IPV6_EXTHDR_ESP: /* not supported, ignored. */ @@ -674,27 +843,32 @@ 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))); - return nxthdr; + if (frag_hdr) { + pico_ipv6_process_frag(frag_hdr, f, nxthdr); + return -1; + } else { + return nxthdr; + } + break; default: - 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); - + /* Invalid next header */ + pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_NXTHDR, cur_nexthdr); return -1; } nxthdr = exthdr->nxthdr; - if (!is_ipv6_hdr) - ptr += (uint32_t)sizeof(struct pico_ipv6_exthdr); - - is_ipv6_hdr = 0; + cur_nexthdr = ptr; + ptr += cur_optlen; } } @@ -704,6 +878,12 @@ 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) { @@ -714,18 +894,12 @@ 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 (0) { - } else if (pico_ipv6_is_unicast(&hdr->dst)) { + 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; } @@ -789,7 +963,7 @@ static inline struct pico_ipv6_route *ipv6_pushed_frame_checks(struct pico_frame } route = pico_ipv6_route_find(dst); - if (!route) { + if (!route && !f->dev) { dbg("IPv6: route not found.\n"); pico_err = PICO_ERR_EHOSTUNREACH; return NULL; @@ -812,6 +986,14 @@ static inline void ipv6_push_hdr_adjust(struct pico_frame *f, struct pico_ipv6_l hdr->src = link->address; hdr->dst = *dst; + 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) { @@ -828,12 +1010,14 @@ static inline void ipv6_push_hdr_adjust(struct pico_frame *f, struct pico_ipv6_l 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 = pico_udp_checksum_ipv6(f); + udp_hdr->crc = short_be(pico_udp_checksum_ipv6(f)); break; } +#endif default: break; @@ -845,15 +1029,12 @@ 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); @@ -873,6 +1054,10 @@ int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *dst, uint8_t pro 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); @@ -899,9 +1084,7 @@ int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *dst, uint8_t pro push_final: 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) @@ -967,6 +1150,7 @@ static inline struct pico_ipv6_route *ipv6_route_add_link(struct pico_ip6 gatewa return NULL; } + return r; } @@ -1009,12 +1193,17 @@ int pico_ipv6_route_add(struct pico_ip6 address, struct pico_ip6 netmask, struct new->link = r->link; } + 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); + } + if (!new->link) { pico_err = PICO_ERR_EINVAL; PICO_FREE(new); return -1; } + pico_tree_insert(&IPV6Routes, new); pico_ipv6_dbg_route(); return 0; @@ -1330,6 +1519,16 @@ struct pico_ipv6_link *pico_ipv6_linklocal_get(struct pico_device *dev) 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; +} + + int pico_ipv6_dev_routing_enable(struct pico_device *dev) { diff --git a/modules/pico_ipv6.h b/modules/pico_ipv6.h index a6b1f92e3..d1f3d74a2 100644 --- a/modules/pico_ipv6.h +++ b/modules/pico_ipv6.h @@ -87,11 +87,11 @@ PACKED_STRUCT_DEF pico_ipv6_exthdr { uint8_t segleft; } routing; - PEDANTIC_STRUCT_DEF fragm_s { + PEDANTIC_STRUCT_DEF fragmentation_s { uint8_t res; - uint8_t frm[2]; + uint8_t om[2]; uint8_t id[4]; - } fragm; + } frag; } ext; }; @@ -108,7 +108,6 @@ 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 *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); @@ -123,6 +122,8 @@ 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); 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 d359116e0..e842df769 100644 --- a/modules/pico_ipv6_nd.c +++ b/modules/pico_ipv6_nd.c @@ -493,7 +493,7 @@ static int radv_process(struct pico_frame *f) (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); + pico_ipv6_route_add(prefix->prefix, netmask, ipv6_hdr->src, 10, 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)); diff --git a/modules/pico_olsr.c b/modules/pico_olsr.c index dc1bd6ece..6feae50a2 100644 --- a/modules/pico_olsr.c +++ b/modules/pico_olsr.c @@ -15,6 +15,7 @@ #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); @@ -140,7 +141,7 @@ static struct olsr_route_entry *get_next_hop(struct olsr_route_entry *dst) { struct olsr_route_entry *hop = dst; while(hop) { - /* dbg("Finding next hop to %08x m=%d\n", hop->destination.addr, hop->metric); */ + /* olsr_dbg("Finding next hop to %08x m=%d\n", hop->destination.addr, hop->metric); */ if(hop->metric <= 1) return hop; @@ -165,7 +166,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; - dbg("[OLSR] ----------Adding route to %08x via %08x metric %d\n", el->destination.addr, nexthop->destination.addr, el->metric); + olsr_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 */ @@ -181,7 +182,7 @@ static inline void olsr_route_add(struct olsr_route_entry *el) ei->children = el; } - dbg("[OLSR] ----------Adding neighbor %08x iface %s\n", el->destination.addr, el->iface->name); + olsr_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)); } @@ -190,7 +191,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; - /* dbg("[OLSR] DELETING route..................\n"); */ + /* olsr_dbg("[OLSR] DELETING route..................\n"); */ my_ansn++; if (r->gateway) { lst = r->gateway->children; @@ -206,7 +207,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); - dbg("[OLSR] Deleting route to %08x \n", r->destination.addr); + olsr_dbg("[OLSR] Deleting route to %08x \n", r->destination.addr); if (!prev) r->gateway->children = r->next; else @@ -253,7 +254,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; - /* dbg("seconds=%u\n", (uint16_t)seconds); */ + /* olsr_dbg("seconds=%u\n", (uint16_t)seconds); */ if (seconds > 32767) seconds = 32767; @@ -265,16 +266,16 @@ uint8_t seconds2olsr(uint32_t seconds) break; } } - /* dbg("b=%u", b); */ + /* olsr_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); - /* dbg(" den=%u ", den); */ + /* olsr_dbg(" den=%u ", den); */ if (den == 0) { - /* dbg("div by 0!\n"); */ + /* olsr_dbg("div by 0!\n"); */ den = 1u; } @@ -282,7 +283,7 @@ uint8_t seconds2olsr(uint32_t seconds) } /* a = a & 0x0Fu; */ - /* dbg(" a=%u\n", a); */ + /* olsr_dbg(" a=%u\n", a); */ /* if 'a' is equal to 16: increment 'b' by one, and set 'a' to 0 */ if (16u == a) { @@ -297,16 +298,16 @@ uint32_t olsr2seconds(uint8_t olsr) { uint8_t a, b; uint16_t seconds; - /* dbg("olsr format: %u -- ", olsr); */ + /* olsr_dbg("olsr format: %u -- ", olsr); */ a = (olsr >> 4) & 0xFu; b = olsr & 0x0f; - /* dbg("o2s: a=%u, b=%u\n", a,b); */ + /* olsr_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); - /* dbg("o2s: seconds: %u\n", seconds); */ + /* olsr_dbg("o2s: seconds: %u\n", seconds); */ return seconds; } @@ -363,7 +364,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)) { - dbg("olsr send\n"); + olsr_dbg("olsr send\n"); } } else { while(pdev) { @@ -374,7 +375,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)) { - dbg("olsr send\n"); + olsr_dbg("olsr send\n"); } pdev = pdev->next; @@ -390,7 +391,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; - /* dbg("Scheduling olsr packet, type:%s, size: %x\n", when == OLSR_HELLO_INTERVAL?"HELLO":"TC", size); */ + /* olsr_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; @@ -437,7 +438,7 @@ static void refresh_routes(void) } else if (lnk) { struct olsr_route_entry *e = PICO_ZALLOC(sizeof (struct olsr_route_entry)); if (!e) { - dbg("olsr: adding local route entry\n"); + olsr_dbg("olsr: adding local route entry\n"); OOM(); return; } @@ -657,7 +658,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) { - /* dbg("Building hello message\n"); */ + /* olsr_dbg("Building hello message\n"); */ PICO_FREE(dgram); return; } @@ -703,7 +704,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) { - dbg("olsr allocating route\n"); + olsr_dbg("olsr allocating route\n"); OOM(); return; } @@ -757,7 +758,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) { - dbg("olsr allocating route\n"); + olsr_dbg("olsr allocating route\n"); OOM(); return; } @@ -812,7 +813,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(); - dbg("Allocating forward packet\n"); + olsr_dbg("Allocating forward packet\n"); return 0; } @@ -848,7 +849,7 @@ uint32_t reconsider_topology(uint8_t *buf, uint32_t size, struct olsr_route_entr olsr_route_add(rt); } } - /* dbg("Routes changed...\n"); */ + /* olsr_dbg("Routes changed...\n"); */ } return retval; @@ -889,7 +890,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) { - /* dbg("rebound\n"); */ + /* olsr_dbg("rebound\n"); */ parsed += short_be(msg->size); continue; } @@ -947,7 +948,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); - /* dbg("MID forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */ + /* olsr_dbg("MID forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */ origin->seq = short_be(msg->seq); } @@ -958,7 +959,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 { - /* dbg("TC forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */ + /* olsr_dbg("TC forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */ origin->seq = short_be(msg->seq); } } @@ -1055,7 +1056,7 @@ void pico_olsr_init(void) 0 }; uint16_t port = OLSR_PORT; - dbg("OLSR initialized.\n"); + olsr_dbg("OLSR initialized.\n"); if (!udpsock) { udpsock = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &wakeup); if (udpsock) @@ -1096,7 +1097,7 @@ int pico_olsr_add(struct pico_device *dev) return -1; } - /* dbg("OLSR: Adding device %s\n", dev->name); */ + /* olsr_dbg("OLSR: Adding device %s\n", dev->name); */ od = PICO_ZALLOC(sizeof(struct olsr_dev_entry)); if (!od) { pico_err = PICO_ERR_ENOMEM; @@ -1113,11 +1114,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)); - /* dbg("OLSR: Found IP address %08x\n", long_be(lnk->address.addr)); */ + /* olsr_dbg("OLSR: Found IP address %08x\n", long_be(lnk->address.addr)); */ pico_ipv4_to_string(ipaddr, (lnk->address.addr)); - /* dbg("OLSR: Found IP address %s\n", ipaddr); */ + /* olsr_dbg("OLSR: Found IP address %s\n", ipaddr); */ if (!e) { - dbg("olsr allocating route\n"); + olsr_dbg("olsr allocating route\n"); pico_err = PICO_ERR_ENOMEM; return -1; } diff --git a/modules/pico_socket_udp.h b/modules/pico_socket_udp.h index fd7783a92..6b3a4c9a3 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) +# define pico_socket_udp_recv(s, buf, len, addr, port) pico_udp_recv(s, buf, len, addr, port, NULL) #else # define pico_socket_udp_recv(...) (0) # define pico_getsockopt_udp(...) (-1) diff --git a/modules/pico_tcp.c b/modules/pico_tcp.c index 6af530255..b20af6941 100644 --- a/modules/pico_tcp.c +++ b/modules/pico_tcp.c @@ -66,30 +66,6 @@ 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 @@ -104,7 +80,7 @@ struct tcp_input_segment static int input_segment_compare(void *ka, void *kb) { struct tcp_input_segment *a = ka, *b = kb; - return seq_compare(a->seq, b->seq); + return pico_seq_compare(a->seq, b->seq); } static struct tcp_input_segment *segment_from_frame(struct pico_frame *f) @@ -129,7 +105,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 seq_compare(SEQN(a), SEQN(b)); + return pico_seq_compare(SEQN(a), SEQN(b)); } struct pico_tcp_queue @@ -362,9 +338,9 @@ static int release_until(struct pico_tcp_queue *q, uint32_t seq) void *cur = head; if (IS_INPUT_QUEUE(q)) - seq_result = seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq); + seq_result = pico_seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq); else - seq_result = seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq); + seq_result = pico_seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq); if (seq_result <= 0) { @@ -393,9 +369,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 = seq_compare(((struct tcp_input_segment *)f)->seq + ((struct tcp_input_segment *)f)->payload_len, seq); + seq_result = pico_seq_compare(((struct tcp_input_segment *)f)->seq + ((struct tcp_input_segment *)f)->payload_len, seq); else - seq_result = seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq); + seq_result = pico_seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq); if (seq_result <= 0) { tcp_dbg("Releasing %p\n", f); @@ -517,7 +493,7 @@ static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f } if (f->payload_len > 0) { - if (seq_compare(SEQN(f) + f->payload_len, t->snd_nxt) > 0) { + if (pico_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); } @@ -737,12 +713,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 = seq_compare(SEQN(f), start); + cmp = pico_seq_compare(SEQN(f), start); if (cmp > 0) return 0; if (cmp == 0) { - cmp = seq_compare(SEQN(f) + f->payload_len, end); + cmp = pico_seq_compare(SEQN(f) + f->payload_len, end); if (cmp > 0) { tcp_dbg("Invalid SACK: ignoring.\n"); } @@ -913,7 +889,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) || (seq_compare(ts->rcv_ackd, ts->rcv_nxt) != 0) || (hdr->flags & PICO_TCP_ACK)) { + if ((ts->rcv_ackd == 0) || (pico_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; @@ -1084,7 +1060,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 = seq_compare(t->rcv_processed, f->seq); + in_frame_off = pico_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); @@ -1559,7 +1535,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 (seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */ + if (pico_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) { @@ -1638,7 +1614,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 (seq_compare(SEQN(f), t->rcv_nxt) <= 0) { + if (pico_seq_compare(SEQN(f), t->rcv_nxt) <= 0) { ret = tcp_data_in_expected(t, f); } else { ret = tcp_data_in_high_segment(t, f); @@ -2079,10 +2055,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 && (seq_compare(SEQN(nxt), t->snd_nxt)) > 0) + if (nxt && (pico_seq_compare(SEQN(nxt), t->snd_nxt)) > 0) nxt = NULL; - if (nxt && (seq_compare(SEQN(nxt), SEQN((struct pico_frame *)first_segment(&t->tcpq_out))) > (int)(t->recv_wnd << t->recv_wnd_scale))) + if (nxt && (pico_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) @@ -2110,7 +2086,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... */ - (seq_compare(SEQN(f), t->rcv_nxt) < 0)) /* Has an old seq number */ + (pico_seq_compare(SEQN(f), t->rcv_nxt) < 0)) /* Has an old seq number */ { tcp_send_ack(t); } @@ -2416,10 +2392,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 (seq_compare(SEQN(f), t->rcv_nxt) == 0) { + if (pico_seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* received FIN, increase ACK nr */ t->rcv_nxt = long_be(hdr->seq) + 1; - if (seq_compare(SEQN(f), t->rcv_processed) == 0) { + if (pico_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; @@ -2535,7 +2511,6 @@ 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; @@ -2580,7 +2555,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 (seq_compare(SEQN(fr), t->rcv_nxt) == 0) { + if (pico_seq_compare(SEQN(fr), t->rcv_nxt) == 0) { /* received FIN, increase ACK nr */ t->rcv_nxt = long_be(hdr->seq) + 1; s->state &= 0x00FFU; @@ -2803,7 +2778,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 = seq_compare(SEQN(f), SEQN(una)); + seq_diff = pico_seq_compare(SEQN(f), SEQN(una)); if (seq_diff < 0) { dbg(">>> FATAL: seq diff is negative!\n"); break; diff --git a/modules/pico_tftp.c b/modules/pico_tftp.c index 143be22ff..bb7098179 100644 --- a/modules/pico_tftp.c +++ b/modules/pico_tftp.c @@ -1259,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, session->tftp_block, (size_t)session->len); + memcpy(data, tftp_payload(session->tftp_block), (size_t)session->len); len = session->len; tftp_send_ack(session); diff --git a/modules/pico_udp.c b/modules/pico_udp.c index cdf62c5a9..678ed919d 100644 --- a/modules/pico_udp.c +++ b/modules/pico_udp.c @@ -154,7 +154,28 @@ struct pico_socket *pico_udp_open(void) return &u->sock; } -uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src, uint16_t *port) +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) { struct pico_frame *f = pico_queue_peek(&s->q_in); if (f) { @@ -172,6 +193,10 @@ 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 f85b607d2..3b38b6fcf 100644 --- a/modules/pico_udp.h +++ b/modules/pico_udp.h @@ -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); +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_checksum_ipv4(struct pico_frame *f); #ifdef PICO_SUPPORT_IPV6 diff --git a/stack/pico_socket.c b/stack/pico_socket.c index 425af012a..c97c40150 100644 --- a/stack/pico_socket.c +++ b/stack/pico_socket.c @@ -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,24 +282,28 @@ 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) +static int pico_generic_port_in_use(uint16_t proto, uint16_t port, struct pico_sockport *sp, void *addr, void *net) { #ifdef PICO_SUPPORT_IPV4 - if (pico_port_in_use_by_nat(proto, port)) { - return 1; - } + if (net == &pico_proto_ipv4) + { + 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 (pico_port_in_use_ipv6(sp, addr)) { - return 1; + if (net == &pico_proto_ipv6) + { + if (pico_port_in_use_ipv6(sp, addr)) { + return 1; + } } - #endif return 0; @@ -308,10 +312,9 @@ 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)) + if (pico_generic_port_in_use(proto, port, sp, addr, net)) return 0; return 1; @@ -1019,7 +1022,8 @@ 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) +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) { struct pico_frame *f; uint16_t hdr_offset = (uint16_t)pico_socket_sendto_transport_offset(s); @@ -1045,6 +1049,12 @@ 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); @@ -1081,7 +1091,8 @@ 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) +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) { int space = pico_socket_xmit_avail_space(s); int hdr_offset = pico_socket_sendto_transport_offset(s); @@ -1089,13 +1100,13 @@ 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); + return pico_socket_xmit_one(s, buf, len, src, ep, msginfo); } #ifdef PICO_SUPPORT_IPV6 /* Can't fragment IPv6 */ if (is_sock_ipv6(s)) { - return pico_socket_xmit_one(s, buf, space, src, ep); + return pico_socket_xmit_one(s, buf, space, src, ep, msginfo); } #endif @@ -1153,7 +1164,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); + return pico_socket_xmit_one(s, buf, space, src, ep, msginfo); #endif } @@ -1218,7 +1229,8 @@ 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) +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) { int space = pico_socket_xmit_avail_space(s); int total_payload_written = 0; @@ -1229,7 +1241,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); + return pico_socket_xmit_fragments(s, buf, len, src, ep, msginfo); } while (total_payload_written < len) { @@ -1237,7 +1249,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); + w = pico_socket_xmit_one(s, (const void *)((const uint8_t *)buf + total_payload_written), chunk_len, src, ep, msginfo); if (w <= 0) { break; } @@ -1260,7 +1272,8 @@ static void pico_socket_sendto_set_dport(struct pico_socket *s, uint16_t port) } -int MOCKABLE pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_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) { struct pico_remote_endpoint *remote_endpoint = NULL; void *src = NULL; @@ -1274,6 +1287,17 @@ int MOCKABLE pico_socket_sendto(struct pico_socket *s, const void *buf, const in 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; } @@ -1283,7 +1307,12 @@ int MOCKABLE pico_socket_sendto(struct pico_socket *s, const void *buf, const in pico_socket_sendto_set_dport(s, remote_port); - return pico_socket_xmit(s, buf, len, src, remote_endpoint); + 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); } int pico_socket_send(struct pico_socket *s, const void *buf, int len) @@ -1308,7 +1337,8 @@ 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(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *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) { if (!s || buf == NULL) { /* / || orig == NULL || remote_port == NULL) { */ pico_err = PICO_ERR_EINVAL; @@ -1335,7 +1365,7 @@ int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, return -1; } - return pico_udp_recv(s, buf, (uint16_t)len, orig, remote_port); + return pico_udp_recv(s, buf, (uint16_t)len, orig, remote_port, msginfo); } #endif @@ -1356,6 +1386,13 @@ int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, 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); @@ -1391,6 +1428,40 @@ 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) { @@ -1529,7 +1600,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, 0, 0); + pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_SENT, PICO_SOCKET_STATE_CLOSED, 0); pico_err = PICO_ERR_NOERR; ret = 0; } else { @@ -1752,6 +1823,7 @@ 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); */ @@ -1762,7 +1834,9 @@ 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)) { @@ -1785,6 +1859,7 @@ static inline int pico_transport_crc_check(struct pico_frame *f) } break; +#endif /* PICO_SUPPORT_UDP */ default: /* Do nothing */ diff --git a/stack/pico_stack.c b/stack/pico_stack.c index 3da8d7e62..25de63a22 100644 --- a/stack/pico_stack.c +++ b/stack/pico_stack.c @@ -17,6 +17,7 @@ #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" @@ -173,7 +174,6 @@ int pico_notify_pkt_too_big(struct pico_frame *f) } - /* Transport layer */ int32_t pico_transport_receive(struct pico_frame *f, uint8_t proto) { @@ -350,7 +350,6 @@ 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; } @@ -443,24 +442,34 @@ struct pico_eth *pico_ethernet_mcast6_translate(struct pico_frame *f, uint8_t *p } #endif -struct pico_eth *pico_ethernet_ipv6_dst(struct pico_frame *f) +int pico_ethernet_ipv6_dst(struct pico_frame *f, struct pico_eth * const dstmac) { - struct pico_eth *dstmac = NULL; + int retval = -1; + if (!dstmac) + return -1; + #ifdef PICO_SUPPORT_IPV6 if (destination_is_mcast(f)) { uint8_t pico_mcast6_mac[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; - dstmac = pico_ethernet_mcast6_translate(f, pico_mcast6_mac); + pico_ethernet_mcast6_translate(f, pico_mcast6_mac); + memcpy(dstmac, pico_mcast6_mac, PICO_SIZE_ETH); + retval = 0; } else { - dstmac = pico_ipv6_get_neighbor(f); + struct pico_eth * neighbor = pico_ipv6_get_neighbor(f); + if (neighbor) + { + memcpy(dstmac, neighbor, PICO_SIZE_ETH); + retval = 0; + } } #else (void)f; pico_err = PICO_ERR_EPROTONOSUPPORT; #endif - return dstmac; + return retval; } @@ -520,7 +529,8 @@ static int32_t pico_ethsend_dispatch(struct pico_frame *f) int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f) { - const struct pico_eth *dstmac = NULL; + struct pico_eth dstmac; + uint8_t dstmac_valid = 0; uint16_t proto = PICO_IDETH_IPV4; #ifdef PICO_SUPPORT_IPV6 @@ -528,11 +538,12 @@ int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f) * destination address is taken from the ND tables */ if (IS_IPV6(f)) { - dstmac = pico_ethernet_ipv6_dst(f); - if (!dstmac) { + if (pico_ethernet_ipv6_dst(f, &dstmac) < 0) + { 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 @@ -540,32 +551,42 @@ 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)) - dstmac = (const struct pico_eth *) PICO_ETHADDR_ALL; + { + memcpy(&dstmac, PICO_ETHADDR_ALL, PICO_SIZE_ETH); + dstmac_valid = 1; + } /* 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 }; - dstmac = pico_ethernet_mcast_translate(f, pico_mcast_mac); + pico_ethernet_mcast_translate(f, pico_mcast_mac); + memcpy(&dstmac, pico_mcast_mac, PICO_SIZE_ETH); + dstmac_valid = 1; } #if (defined PICO_SUPPORT_IPV4) else { - 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) { + 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. + */ 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) { + if (dstmac_valid) { 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)) @@ -575,7 +596,7 @@ 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)) { @@ -766,6 +787,31 @@ 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; @@ -894,41 +940,6 @@ 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] = { @@ -1076,6 +1087,9 @@ 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/test/autotest.sh b/test/autotest.sh index 1b71fe544..8ebeac5f9 100755 --- a/test/autotest.sh +++ b/test/autotest.sh @@ -65,6 +65,17 @@ 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) & diff --git a/test/examples/Makefile b/test/examples/Makefile index 09b67b54e..597ca9495 100644 --- a/test/examples/Makefile +++ b/test/examples/Makefile @@ -27,6 +27,7 @@ $(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/iperfc.c b/test/examples/iperfc.c new file mode 100644 index 000000000..eec2fd027 --- /dev/null +++ b/test/examples/iperfc.c @@ -0,0 +1,133 @@ +#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/perf.sh b/test/perf.sh new file mode 100755 index 000000000..c9debbea7 --- /dev/null +++ b/test/perf.sh @@ -0,0 +1,26 @@ +#!/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/picoapp.c b/test/picoapp.c index e11e8d5af..62306d2e2 100644 --- a/test/picoapp.c +++ b/test/picoapp.c @@ -28,6 +28,7 @@ #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" @@ -62,6 +63,7 @@ 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 = { @@ -466,7 +468,6 @@ int main(int argc, char **argv) pico_ipv6_link_add(dev, ipaddr6, netmask6); } pico_ipv6_dev_routing_enable(dev); - #endif } break; @@ -601,6 +602,23 @@ 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") { @@ -611,6 +629,8 @@ 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/test_tftp_app_client b/test/test_tftp_app_client deleted file mode 100755 index 495ca8357..000000000 Binary files a/test/test_tftp_app_client and /dev/null differ diff --git a/test/test_tftp_app_client.c b/test/test_tftp_app_client.c new file mode 100644 index 000000000..68efdb487 --- /dev/null +++ b/test/test_tftp_app_client.c @@ -0,0 +1,240 @@ +#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 new file mode 100644 index 000000000..d644ab862 --- /dev/null +++ b/test/unit/modunit_pico_aodv.c @@ -0,0 +1,530 @@ +#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_seq.c b/test/unit/modunit_seq.c index 73b9fb4e4..25264e86d 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(seq_compare(small_a, small_b) >= 0); - fail_if(seq_compare(small_b, small_a) <= 0); + fail_if(pico_seq_compare(small_a, small_b) >= 0); + fail_if(pico_seq_compare(small_b, small_a) <= 0); - fail_if(seq_compare(over_thresh, under_thresh) <= 0); - fail_if(seq_compare(under_thresh, over_thresh) >= 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(small_a, big_b) <= 0); - fail_if(seq_compare(big_b, small_a) >= 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, zero) <= 0); - fail_if(seq_compare(zero, 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(big_a, zero) >= 0); - fail_if(seq_compare(zero, big_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, big_b) >= 0); - fail_if(seq_compare(big_b, 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_a) != 0); - fail_if(seq_compare(zero, zero) != 0); + fail_if(pico_seq_compare(big_a, big_a) != 0); + fail_if(pico_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 seq_compare"); + TCase *TCase_seq_compare = tcase_create("Unit test for pico_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_socket.c b/test/unit/unit_socket.c index b1e737cc4..9f4cb77d8 100644 --- a/test/unit/unit_socket.c +++ b/test/unit/unit_socket.c @@ -1,4 +1,8 @@ +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 ce8893dff..24e3101f6 100644 --- a/test/unit/unit_timer.c +++ b/test/unit/unit_timer.c @@ -1,5 +1,6 @@ #define EXISTING_TIMERS 4 + START_TEST (test_timers) { struct pico_timer *T[128]; diff --git a/test/units.sh b/test/units.sh index 93e1e17c7..e8fbfbfe2 100755 --- a/test/units.sh +++ b/test/units.sh @@ -15,6 +15,7 @@ rm -f /tmp/pico-mem-report-* ./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