dynamic loading of network stack no longer needed
This commit is contained in:
22
Makefile
Normal file
22
Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Common makefile -- loads make rules for each platform
|
||||
|
||||
BUILD=build
|
||||
INT=integrations
|
||||
ZTO=zto
|
||||
|
||||
OSTYPE=$(shell uname -s)
|
||||
|
||||
ifeq ($(OSTYPE),Darwin)
|
||||
include make-mac.mk
|
||||
endif
|
||||
|
||||
ifeq ($(OSTYPE),Linux)
|
||||
include make-linux.mk
|
||||
endif
|
||||
|
||||
ifeq ($(OSTYPE),FreeBSD)
|
||||
include make-freebsd.mk
|
||||
endif
|
||||
ifeq ($(OSTYPE),OpenBSD)
|
||||
include make-freebsd.mk
|
||||
endif
|
||||
15
README.md
Normal file
15
README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
ZeroTier SDK
|
||||
======
|
||||
|
||||
|
||||
***
|
||||
|
||||
## Build Targets
|
||||
### Static Library
|
||||
`static_lib`
|
||||
|
||||
## Using Language Bindings
|
||||
`SDK_LANG_JAVA=1`
|
||||
`SDK_LANG_CSHARP=1`
|
||||
`SDK_LANG_PYTHON=1`
|
||||
`SDK_LANG_=1`
|
||||
1
api/README.md
Normal file
1
api/README.md
Normal file
@@ -0,0 +1 @@
|
||||
Language bindings
|
||||
3
api/cpp/README.md
Normal file
3
api/cpp/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
C\C++ Language Binding API for the ZeroTier SDK
|
||||
======
|
||||
|
||||
3
api/csharp/README.md
Normal file
3
api/csharp/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
C# Language Binding API for the ZeroTier SDK
|
||||
======
|
||||
|
||||
3
api/java/README.md
Normal file
3
api/java/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Java Language Binding API for the ZeroTier SDK
|
||||
======
|
||||
|
||||
3
api/python/README.md
Normal file
3
api/python/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Python Language Binding API for the ZeroTier SDK
|
||||
======
|
||||
|
||||
3
api/swift/README.md
Normal file
3
api/swift/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Swift Language Binding API for the ZeroTier SDK
|
||||
======
|
||||
|
||||
16
check.sh
Executable file
16
check.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
red=`tput setaf 1`
|
||||
green=`tput setaf 2`
|
||||
reset=`tput sgr0`
|
||||
|
||||
FILE="$1"
|
||||
|
||||
if ([ -f "$FILE" ] && [ -s "$FILE" ]) || ([ -d "$FILE" ] && [ "$(ls -A "$FILE")" ]);
|
||||
then
|
||||
echo "${green}[OK ]${reset} $FILE"
|
||||
exit 0
|
||||
else
|
||||
echo "${red}[FAIL]${reset} $FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
1
ext/README.md
Normal file
1
ext/README.md
Normal file
@@ -0,0 +1 @@
|
||||
The ext/ folder contains third party code, drivers, installation support files, etc.
|
||||
24
ext/picotcp/.gitignore
vendored
Normal file
24
ext/picotcp/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
*.d
|
||||
*.o
|
||||
*.a
|
||||
*.out
|
||||
*.swp
|
||||
tags
|
||||
build
|
||||
UNIT_*
|
||||
core
|
||||
core.*
|
||||
.DS_Store
|
||||
cscope.files
|
||||
cscope.out
|
||||
*.so
|
||||
*.aux
|
||||
*.pdf
|
||||
*.toc
|
||||
*.gz
|
||||
*.log
|
||||
*.pyc
|
||||
*.elf
|
||||
*.gcov
|
||||
*.gcda
|
||||
*.gcno
|
||||
13
ext/picotcp/.travis.yml
Normal file
13
ext/picotcp/.travis.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y vde2 check libvdeplug2-dev libpcap-dev psmisc
|
||||
- sudo pip install cpp-coveralls
|
||||
- make clean
|
||||
- rm -f *.gc*
|
||||
|
||||
install: make GCOV=1 && make units ARCH=faulty GCOV=1 && make test GCOV=1
|
||||
language: c
|
||||
script:
|
||||
- ./test/coverage.sh
|
||||
after_success:
|
||||
- coveralls --exclude test/ --exclude modules/ptsocket --exclude build --exclude modules/pico_dev_mock.c --exclude modules/pico_dev_null.c --exclude modules/pico_dev_pcap.c --exclude modules/pico_dev_tap_windows.c --exclude modules/pico_dev_tun.c --gcov-options='\-lp'
|
||||
8
ext/picotcp/COPYING
Normal file
8
ext/picotcp/COPYING
Normal file
@@ -0,0 +1,8 @@
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems.
|
||||
|
||||
Released under the GNU General Public License, version 2.
|
||||
See LICENSE for details.
|
||||
|
||||
Different licensing models may exist, at the sole discretion of
|
||||
the Copyright holders.
|
||||
|
||||
339
ext/picotcp/LICENSE
Normal file
339
ext/picotcp/LICENSE
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
23
ext/picotcp/MODTREE
Normal file
23
ext/picotcp/MODTREE
Normal file
@@ -0,0 +1,23 @@
|
||||
RTOS:
|
||||
IPV4:
|
||||
IPV6:
|
||||
DEVLOOP:
|
||||
CRC:
|
||||
ETH: IPV4
|
||||
TCP: IPV4
|
||||
UDP: IPV4
|
||||
IPV4FRAG: IPV4
|
||||
NAT: IPV4 UDP
|
||||
ICMP4: IPV4
|
||||
MCAST: UDP
|
||||
PING: ICMP4
|
||||
DHCP_CLIENT: UDP
|
||||
DHCP_SERVER: UDP
|
||||
DNS_CLIENT: UDP
|
||||
IPFILTER: IPV4
|
||||
OLSR: MCAST
|
||||
SLAACV4: IPV4
|
||||
SNTP_CLIENT: DNS_CLIENT
|
||||
TFTP: UDP
|
||||
MDNS: MCAST
|
||||
DNS_SD: MDNS
|
||||
416
ext/picotcp/Makefile
Normal file
416
ext/picotcp/Makefile
Normal file
@@ -0,0 +1,416 @@
|
||||
-include ../../config.mk
|
||||
-include ../../tools/kconfig/.config
|
||||
|
||||
CC:=$(CROSS_COMPILE)gcc
|
||||
LD:=$(CROSS_COMPILE)ld
|
||||
AR:=$(CROSS_COMPILE)ar
|
||||
RANLIB:=$(CROSS_COMPILE)ranlib
|
||||
SIZE:=$(CROSS_COMPILE)size
|
||||
STRIP_BIN:=$(CROSS_COMPILE)strip
|
||||
TEST_LDFLAGS=-pthread $(PREFIX)/modules/*.o $(PREFIX)/lib/*.o -lvdeplug
|
||||
LIBNAME:="libpicotcp.a"
|
||||
|
||||
PREFIX?=$(PWD)/build
|
||||
DEBUG?=1
|
||||
PROFILE?=0
|
||||
PERF?=0
|
||||
ENDIAN?=little
|
||||
STRIP?=0
|
||||
RTOS?=0
|
||||
GENERIC?=0
|
||||
PTHREAD?=0
|
||||
ADDRESS_SANITIZER?=1
|
||||
|
||||
# Default compiled-in protocols
|
||||
#
|
||||
TCP?=1
|
||||
UDP?=1
|
||||
ETH?=1
|
||||
IPV4?=1
|
||||
IPV4FRAG?=1
|
||||
IPV6FRAG?=0
|
||||
NAT?=1
|
||||
ICMP4?=1
|
||||
MCAST?=1
|
||||
DEVLOOP?=1
|
||||
PING?=1
|
||||
DHCP_CLIENT?=1
|
||||
DHCP_SERVER?=1
|
||||
DNS_CLIENT?=1
|
||||
MDNS?=1
|
||||
DNS_SD?=1
|
||||
SNTP_CLIENT?=1
|
||||
IPFILTER?=1
|
||||
CRC?=1
|
||||
OLSR?=0
|
||||
SLAACV4?=1
|
||||
TFTP?=1
|
||||
AODV?=1
|
||||
MEMORY_MANAGER?=0
|
||||
MEMORY_MANAGER_PROFILING?=0
|
||||
TUN?=0
|
||||
TAP?=0
|
||||
PCAP?=0
|
||||
PPP?=1
|
||||
CYASSL?=0
|
||||
WOLFSSL?=0
|
||||
POLARSSL?=0
|
||||
|
||||
#IPv6 related
|
||||
IPV6?=1
|
||||
|
||||
EXTRA_CFLAGS+=-DPICO_COMPILE_TIME=`date +%s`
|
||||
EXTRA_CFLAGS+=$(PLATFORM_CFLAGS)
|
||||
|
||||
CFLAGS=-I$(PREFIX)/include -Iinclude -Imodules -Wall -Wdeclaration-after-statement -W -Wextra -Wshadow -Wcast-qual -Wwrite-strings -Wunused-variable -Wundef -Wunused-function $(EXTRA_CFLAGS)
|
||||
# extra flags recommanded by TIOBE TICS framework to score an A on compiler warnings
|
||||
CFLAGS+= -Wconversion
|
||||
# request from Toon
|
||||
CFLAGS+= -Wcast-align
|
||||
CFLAGS+= -Wmissing-prototypes
|
||||
CFLAGS+= -Wno-missing-field-initializers
|
||||
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS+=-ggdb
|
||||
else
|
||||
ifeq ($(PERF), 1)
|
||||
CFLAGS+=-O3
|
||||
else
|
||||
CFLAGS+=-Os
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(PROFILE),1)
|
||||
CFLAGS+=-pg
|
||||
endif
|
||||
|
||||
ifeq ($(TFTP),1)
|
||||
MOD_OBJ+=$(LIBBASE)modules/pico_strings.o $(LIBBASE)modules/pico_tftp.o
|
||||
OPTIONS+=-DPICO_SUPPORT_TFTP
|
||||
endif
|
||||
|
||||
ifeq ($(AODV),1)
|
||||
MOD_OBJ+=$(LIBBASE)modules/pico_aodv.o
|
||||
OPTIONS+=-DPICO_SUPPORT_AODV
|
||||
endif
|
||||
|
||||
ifeq ($(GENERIC),1)
|
||||
CFLAGS+=-DGENERIC
|
||||
endif
|
||||
|
||||
ifeq ($(PTHREAD),1)
|
||||
CFLAGS+=-DPICO_SUPPORT_PTHREAD
|
||||
endif
|
||||
|
||||
|
||||
ifneq ($(ENDIAN),little)
|
||||
CFLAGS+=-DPICO_BIGENDIAN
|
||||
endif
|
||||
|
||||
ifneq ($(RTOS),0)
|
||||
OPTIONS+=-DPICO_SUPPORT_RTOS
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),cortexm4-hardfloat)
|
||||
CFLAGS+=-DCORTEX_M4_HARDFLOAT -mcpu=cortex-m4 -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork -fsingle-precision-constant
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),cortexm4-softfloat)
|
||||
CFLAGS+=-DCORTEX_M4_SOFTFLOAT -mcpu=cortex-m4 -mthumb -mlittle-endian -mfloat-abi=soft -mthumb-interwork
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),cortexm3)
|
||||
CFLAGS+=-DCORTEX_M3 -mcpu=cortex-m3 -mthumb -mlittle-endian -mthumb-interwork
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm9)
|
||||
CFLAGS+=-DARM9 -mcpu=arm9e -march=armv5te -gdwarf-2 -Wall -marm -mthumb-interwork -fpack-struct
|
||||
endif
|
||||
|
||||
ifeq ($(ADDRESS_SANITIZER),1)
|
||||
TEST_LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),faulty)
|
||||
CFLAGS+=-DFAULTY -DUNIT_TEST
|
||||
ifeq ($(ADDRESS_SANITIZER),1)
|
||||
CFLAGS+=-fsanitize=address
|
||||
endif
|
||||
CFLAGS+=-fno-omit-frame-pointer
|
||||
UNITS_OBJ+=test/pico_faulty.o
|
||||
TEST_OBJ+=test/pico_faulty.o
|
||||
DUMMY_EXTRA+=test/pico_faulty.o
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),msp430)
|
||||
CFLAGS+=-DMSP430
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),esp8266)
|
||||
CFLAGS+=-DESP8266 -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),mt7681)
|
||||
CFLAGS+=-DMT7681 -fno-builtin -ffunction-sections -fno-strict-aliasing -m16bit -mabi=2 -mbaseline=V2 -mcpu=n9 -mno-div -mel -mmw-count=8 -mno-ext-mac -mno-dx-regs
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),pic24)
|
||||
CFLAGS+=-DPIC24 -c -mcpu=24FJ256GA106 -MMD -MF -g -omf=elf \
|
||||
-mlarge-code -mlarge-data -msmart-io=1 -msfr-warn=off
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),atmega128)
|
||||
CFLAGS+=-Wall -mmcu=atmega128 -DAVR
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),none)
|
||||
CFLAGS+=-DARCHNONE
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),shared)
|
||||
CFLAGS+=-fPIC
|
||||
endif
|
||||
|
||||
%.o:%.c deps
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
CORE_OBJ= stack/pico_stack.o \
|
||||
stack/pico_frame.o \
|
||||
stack/pico_device.o \
|
||||
stack/pico_protocol.o \
|
||||
stack/pico_socket.o \
|
||||
stack/pico_socket_multicast.o \
|
||||
stack/pico_tree.o \
|
||||
stack/pico_md5.o
|
||||
|
||||
POSIX_OBJ+= modules/pico_dev_vde.o \
|
||||
modules/pico_dev_tun.o \
|
||||
modules/pico_dev_tap.o \
|
||||
modules/pico_dev_mock.o
|
||||
|
||||
ifneq ($(ETH),0)
|
||||
include rules/eth.mk
|
||||
endif
|
||||
ifneq ($(IPV4),0)
|
||||
include rules/ipv4.mk
|
||||
endif
|
||||
ifneq ($(IPV4FRAG),0)
|
||||
include rules/ipv4frag.mk
|
||||
endif
|
||||
ifneq ($(ICMP4),0)
|
||||
include rules/icmp4.mk
|
||||
endif
|
||||
ifneq ($(TCP),0)
|
||||
include rules/tcp.mk
|
||||
endif
|
||||
ifneq ($(UDP),0)
|
||||
include rules/udp.mk
|
||||
endif
|
||||
ifneq ($(MCAST),0)
|
||||
include rules/mcast.mk
|
||||
include rules/igmp.mk
|
||||
include rules/mld.mk
|
||||
endif
|
||||
ifneq ($(NAT),0)
|
||||
include rules/nat.mk
|
||||
endif
|
||||
ifneq ($(DEVLOOP),0)
|
||||
include rules/devloop.mk
|
||||
endif
|
||||
ifneq ($(DHCP_CLIENT),0)
|
||||
include rules/dhcp_client.mk
|
||||
endif
|
||||
ifneq ($(DHCP_SERVER),0)
|
||||
include rules/dhcp_server.mk
|
||||
endif
|
||||
ifneq ($(DNS_CLIENT),0)
|
||||
include rules/dns_client.mk
|
||||
endif
|
||||
ifneq ($(MDNS),0)
|
||||
include rules/mdns.mk
|
||||
endif
|
||||
ifneq ($(DNS_SD),0)
|
||||
include rules/dns_sd.mk
|
||||
endif
|
||||
ifneq ($(IPFILTER),0)
|
||||
include rules/ipfilter.mk
|
||||
endif
|
||||
ifneq ($(CRC),0)
|
||||
include rules/crc.mk
|
||||
endif
|
||||
ifneq ($(OLSR),0)
|
||||
include rules/olsr.mk
|
||||
endif
|
||||
ifneq ($(SLAACV4),0)
|
||||
include rules/slaacv4.mk
|
||||
endif
|
||||
ifneq ($(IPV6),0)
|
||||
include rules/ipv6.mk
|
||||
endif
|
||||
ifneq ($(MEMORY_MANAGER),0)
|
||||
include rules/memory_manager.mk
|
||||
endif
|
||||
ifneq ($(MEMORY_MANAGER_PROFILING),0)
|
||||
OPTIONS+=-DPICO_SUPPORT_MM_PROFILING
|
||||
endif
|
||||
ifneq ($(SNTP_CLIENT),0)
|
||||
include rules/sntp_client.mk
|
||||
endif
|
||||
ifneq ($(TUN),0)
|
||||
include rules/tun.mk
|
||||
endif
|
||||
ifneq ($(TAP),0)
|
||||
include rules/tap.mk
|
||||
endif
|
||||
ifneq ($(PCAP),0)
|
||||
include rules/pcap.mk
|
||||
endif
|
||||
ifneq ($(PPP),0)
|
||||
include rules/ppp.mk
|
||||
endif
|
||||
ifneq ($(CYASSL),0)
|
||||
include rules/cyassl.mk
|
||||
endif
|
||||
ifneq ($(WOLFSSL),0)
|
||||
include rules/wolfssl.mk
|
||||
endif
|
||||
ifneq ($(POLARSSL),0)
|
||||
include rules/polarssl.mk
|
||||
endif
|
||||
|
||||
all: mod core lib
|
||||
|
||||
core: $(CORE_OBJ)
|
||||
@mkdir -p $(PREFIX)/lib
|
||||
@mv stack/*.o $(PREFIX)/lib
|
||||
|
||||
mod: $(MOD_OBJ)
|
||||
@mkdir -p $(PREFIX)/modules
|
||||
@mv modules/*.o $(PREFIX)/modules || echo
|
||||
|
||||
posix: all $(POSIX_OBJ)
|
||||
@mv modules/*.o $(PREFIX)/modules || echo
|
||||
|
||||
|
||||
TEST_ELF= test/picoapp.elf
|
||||
TEST6_ELF= test/picoapp6.elf
|
||||
|
||||
|
||||
test: posix
|
||||
@mkdir -p $(PREFIX)/test/
|
||||
@make -C test/examples PREFIX=$(PREFIX)
|
||||
@echo -e "\t[CC] picoapp.o"
|
||||
@$(CC) -c -o $(PREFIX)/examples/picoapp.o test/picoapp.c $(CFLAGS) -Itest/examples
|
||||
@echo -e "\t[LD] $@"
|
||||
@$(CC) -g -o $(TEST_ELF) -I include -I modules -I $(PREFIX)/include -Wl,--start-group $(TEST_LDFLAGS) $(TEST_OBJ) $(PREFIX)/examples/*.o -Wl,--end-group
|
||||
@mv test/*.elf $(PREFIX)/test
|
||||
@install $(PREFIX)/$(TEST_ELF) $(PREFIX)/$(TEST6_ELF)
|
||||
|
||||
tst: test
|
||||
|
||||
$(PREFIX)/include/pico_defines.h:
|
||||
@mkdir -p $(PREFIX)/lib
|
||||
@mkdir -p $(PREFIX)/include
|
||||
@bash ./mkdeps.sh $(PREFIX) $(OPTIONS)
|
||||
|
||||
|
||||
deps: $(PREFIX)/include/pico_defines.h
|
||||
|
||||
|
||||
|
||||
lib: mod core
|
||||
@cp -f include/*.h $(PREFIX)/include
|
||||
@cp -fa include/arch $(PREFIX)/include
|
||||
@cp -f modules/*.h $(PREFIX)/include
|
||||
@$(AR) cru $(PREFIX)/lib/$(LIBNAME) $(PREFIX)/modules/*.o $(PREFIX)/lib/*.o \
|
||||
|| $(AR) cru $(PREFIX)/lib/$(LIBNAME) $(PREFIX)/lib/*.o
|
||||
@$(RANLIB) $(PREFIX)/lib/$(LIBNAME)
|
||||
|
||||
loop: mod core
|
||||
mkdir -p $(PREFIX)/test
|
||||
@$(CC) -c -o $(PREFIX)/modules/pico_dev_loop.o modules/pico_dev_loop.c $(CFLAGS)
|
||||
@$(CC) -c -o $(PREFIX)/loop_ping.o test/loop_ping.c $(CFLAGS) -ggdb
|
||||
|
||||
units: mod core lib $(UNITS_OBJ) $(MOD_OBJ)
|
||||
@echo -e "\n\t[UNIT TESTS SUITE]"
|
||||
@mkdir -p $(PREFIX)/test
|
||||
@echo -e "\t[CC] units.o"
|
||||
@$(CC) -g -c -o $(PREFIX)/test/units.o test/units.c $(CFLAGS) -I stack -I modules -I includes -I test/unit -DUNIT_TEST
|
||||
@echo -e "\t[LD] $(PREFIX)/test/units"
|
||||
@$(CC) -o $(PREFIX)/test/units $(CFLAGS) $(PREFIX)/test/units.o -lcheck -lm -pthread -lrt \
|
||||
$(UNITS_OBJ) $(PREFIX)/modules/pico_aodv.o \
|
||||
$(PREFIX)/modules/pico_fragments.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
|
||||
@$(CC) -o $(PREFIX)/test/modunit_tcp.elf $(CFLAGS) -I. test/unit/modunit_pico_tcp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_dns_client.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_client.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_dns_common.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_common.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_mdns.elf $(CFLAGS) -I. test/unit/modunit_pico_mdns.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_dns_sd.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_sd.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_dev_loop.elf $(CFLAGS) -I. test/unit/modunit_pico_dev_loop.c -lcheck -lm -pthread -lrt $(UNITS_OBJ)
|
||||
@$(CC) -o $(PREFIX)/test/modunit_ipv6_nd.elf $(CFLAGS) -I. test/unit/modunit_pico_ipv6_nd.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_pico_stack.elf $(CFLAGS) -I. test/unit/modunit_pico_stack.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_tftp.elf $(CFLAGS) -I. test/unit/modunit_pico_tftp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_sntp_client.elf $(CFLAGS) -I. test/unit/modunit_pico_sntp_client.c -lcheck -lm -pthread -lrt $(UNITS_OBJ)
|
||||
@$(CC) -o $(PREFIX)/test/modunit_ipfilter.elf $(CFLAGS) -I. test/unit/modunit_pico_ipfilter.c stack/pico_tree.c -lcheck -lm -pthread -lrt $(UNITS_OBJ)
|
||||
@$(CC) -o $(PREFIX)/test/modunit_aodv.elf $(CFLAGS) -I. test/unit/modunit_pico_aodv.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_fragments.elf $(CFLAGS) -I. test/unit/modunit_pico_fragments.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)
|
||||
@$(CC) -o $(PREFIX)/test/modunit_dev_ppp.elf $(CFLAGS) -I. test/unit/modunit_pico_dev_ppp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_mld.elf $(CFLAGS) -I. test/unit/modunit_pico_mld.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_igmp.elf $(CFLAGS) -I. test/unit/modunit_pico_igmp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_hotplug_detection.elf $(CFLAGS) -I. test/unit/modunit_pico_hotplug_detection.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
|
||||
devunits: mod core lib
|
||||
@echo -e "\n\t[UNIT TESTS SUITE: device drivers]"
|
||||
@mkdir -p $(PREFIX)/test/unit/device/
|
||||
@echo -e "\t[CC] picotcp_mock.o"
|
||||
@$(CC) -c -o $(PREFIX)/test/unit/device/picotcp_mock.o $(CFLAGS) -I stack -I modules -I includes -I test/unit test/unit/device/picotcp_mock.c
|
||||
@$(CC) -c -o $(PREFIX)/test/unit/device/unit_dev_vde.o $(CFLAGS) -I stack -I modules -I includes -I test/unit test/unit/device/unit_dev_vde.c
|
||||
@echo -e "\t[LD] $(PREFIX)/test/devunits"
|
||||
@$(CC) -o $(PREFIX)/test/devunits $(CFLAGS) -I stack $(PREFIX)/test/unit/device/*.o -lcheck -lm -pthread -lrt
|
||||
|
||||
units_mm: mod core lib
|
||||
@echo -e "\n\t[UNIT TESTS SUITE]"
|
||||
@mkdir -p $(PREFIX)/test
|
||||
@echo -e "\t[CC] units_mm.o"
|
||||
@$(CC) -c -o $(PREFIX)/test/units_mm.o test/unit/unit_mem_manager.c $(CFLAGS) -I stack -I modules -I includes -I test/unit
|
||||
@echo -e "\t[LD] $(PREFIX)/test/units"
|
||||
@$(CC) -o $(PREFIX)/test/units_mm $(CFLAGS) $(PREFIX)/test/units_mm.o -lcheck -lm -pthread -lrt
|
||||
|
||||
|
||||
clean:
|
||||
@echo -e "\t[CLEAN] $(PREFIX)/"
|
||||
@rm -rf $(PREFIX) tags
|
||||
|
||||
mbed:
|
||||
@echo -e "\t[Creating PicoTCP.zip]"
|
||||
@rm -f PicoTCP.zip
|
||||
@cp include/pico_socket.h include/socket.tmp
|
||||
@echo "#define MBED\n" > include/mbed.tmp
|
||||
@cat include/mbed.tmp include/socket.tmp > include/pico_socket.h
|
||||
@zip -0 PicoTCP.zip -r include modules stack -x include/arch/ include/arch/* include/pico_config.h include/*.tmp modules/pico_dev_*
|
||||
@rm include/pico_socket.h include/mbed.tmp
|
||||
@mv include/socket.tmp include/pico_socket.h
|
||||
|
||||
|
||||
style:
|
||||
@find . -iname "*.[c|h]" | xargs -x uncrustify --replace -l C -c uncrustify.cfg || true
|
||||
@find . -iname "*unc-backup*" |xargs -x rm || true
|
||||
|
||||
dummy: mod core lib $(DUMMY_EXTRA)
|
||||
@echo testing configuration...
|
||||
@$(CC) -c -o test/dummy.o test/dummy.c $(CFLAGS)
|
||||
@$(CC) -o dummy test/dummy.o $(DUMMY_EXTRA) $(PREFIX)/lib/libpicotcp.a $(LDFLAGS) $(CFLAGS)
|
||||
@echo done.
|
||||
@rm -f test/dummy.o dummy
|
||||
|
||||
ppptest: test/ppp.c lib
|
||||
gcc -ggdb -c -o ppp.o test/ppp.c -I build/include/ -I build/modules/ $(CFLAGS)
|
||||
gcc -o ppp ppp.o build/lib/libpicotcp.a $(LDFLAGS) $(CFLAGS)
|
||||
rm -f ppp.o
|
||||
|
||||
|
||||
FORCE:
|
||||
403
ext/picotcp/Makefile.watcom
Normal file
403
ext/picotcp/Makefile.watcom
Normal file
@@ -0,0 +1,403 @@
|
||||
-include ../../config.mk
|
||||
-include ../../tools/kconfig/.config
|
||||
|
||||
WATCOM_PATH:=/opt/watcom
|
||||
CC:=$(WATCOM_PATH)/binl/$(CROSS_COMPILE)wcc386
|
||||
LD:=$(WATCOM_PATH)/binl/$(CROSS_COMPILE)wcl386
|
||||
AR:=$(WATCOM_PATH)/binl/$(CROSS_COMPILE)wlib
|
||||
RANLIB:=$(WATCOM_PATH)/binl/$(CROSS_COMPILE)ranlib
|
||||
SIZE:=$(CROSS_COMPILE)size
|
||||
STRIP_BIN:=$(CROSS_COMPILE)strip
|
||||
TEST_LDFLAGS=-pthread $(PREFIX)/modules/*.o $(PREFIX)/lib/*.o -lvdeplug
|
||||
LIBNAME:=libpicotcp.a
|
||||
|
||||
PREFIX?=$(PWD)/build
|
||||
DEBUG?=1
|
||||
PROFILE?=0
|
||||
PERF?=0
|
||||
ENDIAN?=little
|
||||
STRIP?=0
|
||||
RTOS?=0
|
||||
GENERIC?=0
|
||||
PTHREAD?=0
|
||||
ADDRESS_SANITIZER?=1
|
||||
|
||||
# Default compiled-in protocols
|
||||
#
|
||||
TCP?=1
|
||||
UDP?=1
|
||||
ETH?=1
|
||||
IPV4?=1
|
||||
IPV4FRAG?=1
|
||||
IPV6FRAG?=0
|
||||
NAT?=1
|
||||
ICMP4?=1
|
||||
MCAST?=1
|
||||
DEVLOOP?=1
|
||||
PING?=1
|
||||
DHCP_CLIENT?=1
|
||||
DHCP_SERVER?=1
|
||||
DNS_CLIENT?=1
|
||||
MDNS?=1
|
||||
DNS_SD?=1
|
||||
SNTP_CLIENT?=1
|
||||
IPFILTER?=1
|
||||
CRC?=1
|
||||
OLSR?=0
|
||||
SLAACV4?=1
|
||||
TFTP?=1
|
||||
AODV?=1
|
||||
MEMORY_MANAGER?=0
|
||||
MEMORY_MANAGER_PROFILING?=0
|
||||
TUN?=0
|
||||
TAP?=0
|
||||
PCAP?=0
|
||||
PPP?=0
|
||||
CYASSL?=0
|
||||
WOLFSSL?=0
|
||||
POLARSSL?=0
|
||||
|
||||
#IPv6 related
|
||||
IPV6?=1
|
||||
|
||||
EXTRA_CFLAGS+=-dPICO_COMPILE_TIME=`date +%s`
|
||||
EXTRA_CFLAGS+=$(PLATFORM_CFLAGS)
|
||||
|
||||
CFLAGS=-i=$(WATCOM_PATH)/h -i=$(PREFIX)/include -i=include -i=modules $(EXTRA_CFLAGS) -q
|
||||
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS+=-od -of -d9
|
||||
else
|
||||
ifeq ($(PERF), 1)
|
||||
CFLAGS+=
|
||||
else
|
||||
CFLAGS+=
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(TFTP),1)
|
||||
MOD_OBJ+=$(LIBBASE)modules/pico_strings.o $(LIBBASE)modules/pico_tftp.o
|
||||
OPTIONS+=-dPICO_SUPPORT_TFTP
|
||||
endif
|
||||
|
||||
ifeq ($(AODV),1)
|
||||
MOD_OBJ+=$(LIBBASE)modules/pico_aodv.o
|
||||
OPTIONS+=-dPICO_SUPPORT_AODV
|
||||
endif
|
||||
|
||||
ifeq ($(GENERIC),1)
|
||||
CFLAGS+=-dGENERIC
|
||||
endif
|
||||
|
||||
ifeq ($(PTHREAD),1)
|
||||
CFLAGS+=-dPICO_SUPPORT_PTHREAD
|
||||
endif
|
||||
|
||||
|
||||
ifneq ($(ENDIAN),little)
|
||||
CFLAGS+=-dPICO_BIGENDIAN
|
||||
endif
|
||||
|
||||
ifneq ($(RTOS),0)
|
||||
OPTIONS+=-dPICO_SUPPORT_RTOS
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),cortexm4-hardfloat)
|
||||
CFLAGS+=-dCORTEX_M4_HARDFLOAT -mcpu=cortex-m4 -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork -fsingle-precision-constant
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),cortexm4-softfloat)
|
||||
CFLAGS+=-dCORTEX_M4_SOFTFLOAT -mcpu=cortex-m4 -mthumb -mlittle-endian -mfloat-abi=soft -mthumb-interwork
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),cortexm3)
|
||||
CFLAGS+=-dCORTEX_M3 -mcpu=cortex-m3 -mthumb -mlittle-endian -mthumb-interwork
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm9)
|
||||
CFLAGS+=-dARM9 -mcpu=arm9e -march=armv5te -gdwarf-2 -Wall -marm -mthumb-interwork -fpack-struct
|
||||
endif
|
||||
|
||||
ifeq ($(ADDRESS_SANITIZER),1)
|
||||
TEST_LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),faulty)
|
||||
CFLAGS+=-dFAULTY -dUNIT_TEST
|
||||
CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
UNITS_OBJ+=test/pico_faulty.o
|
||||
TEST_OBJ+=test/pico_faulty.o
|
||||
DUMMY_EXTRA+=test/pico_faulty.o
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),msp430)
|
||||
CFLAGS+=-dMSP430
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),esp8266)
|
||||
CFLAGS+=-dESP8266 -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),mt7681)
|
||||
CFLAGS+=-dMT7681 -fno-builtin -ffunction-sections -fno-strict-aliasing -m16bit -mabi=2 -mbaseline=V2 -mcpu=n9 -mno-div -mel -mmw-count=8 -mno-ext-mac -mno-dx-regs
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),pic24)
|
||||
CFLAGS+=-dPIC24 -mcpu=24FJ256GA106 -MMD -MF -g -omf=elf \
|
||||
-mlarge-code -mlarge-data -msmart-io=1 -msfr-warn=off
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),atmega128)
|
||||
CFLAGS+=-Wall -mmcu=atmega128 -dAVR
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),none)
|
||||
CFLAGS+=-dARCHNONE
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),shared)
|
||||
CFLAGS+=-fPIC
|
||||
endif
|
||||
|
||||
%.o:%.c deps
|
||||
$(CC) $(CFLAGS) -fo=$@ $<
|
||||
|
||||
CORE_OBJ= stack/pico_stack.o \
|
||||
stack/pico_frame.o \
|
||||
stack/pico_device.o \
|
||||
stack/pico_protocol.o \
|
||||
stack/pico_socket.o \
|
||||
stack/pico_socket_multicast.o \
|
||||
stack/pico_tree.o \
|
||||
stack/pico_md5.o
|
||||
|
||||
POSIX_OBJ+= modules/pico_dev_vde.o \
|
||||
modules/pico_dev_tun.o \
|
||||
modules/pico_dev_tap.o \
|
||||
modules/pico_dev_mock.o
|
||||
|
||||
ifneq ($(ETH),0)
|
||||
include rules/eth.mk
|
||||
endif
|
||||
ifneq ($(IPV4),0)
|
||||
include rules/ipv4.mk
|
||||
endif
|
||||
ifneq ($(IPV4FRAG),0)
|
||||
include rules/ipv4frag.mk
|
||||
endif
|
||||
ifneq ($(ICMP4),0)
|
||||
include rules/icmp4.mk
|
||||
endif
|
||||
ifneq ($(TCP),0)
|
||||
include rules/tcp.mk
|
||||
endif
|
||||
ifneq ($(UDP),0)
|
||||
include rules/udp.mk
|
||||
endif
|
||||
ifneq ($(MCAST),0)
|
||||
include rules/mcast.mk
|
||||
include rules/igmp.mk
|
||||
endif
|
||||
ifneq ($(NAT),0)
|
||||
include rules/nat.mk
|
||||
endif
|
||||
ifneq ($(DEVLOOP),0)
|
||||
include rules/devloop.mk
|
||||
endif
|
||||
ifneq ($(DHCP_CLIENT),0)
|
||||
include rules/dhcp_client.mk
|
||||
endif
|
||||
ifneq ($(DHCP_SERVER),0)
|
||||
include rules/dhcp_server.mk
|
||||
endif
|
||||
ifneq ($(DNS_CLIENT),0)
|
||||
include rules/dns_client.mk
|
||||
endif
|
||||
ifneq ($(MDNS),0)
|
||||
include rules/mdns.mk
|
||||
endif
|
||||
ifneq ($(DNS_SD),0)
|
||||
include rules/dns_sd.mk
|
||||
endif
|
||||
ifneq ($(IPFILTER),0)
|
||||
include rules/ipfilter.mk
|
||||
endif
|
||||
ifneq ($(CRC),0)
|
||||
include rules/crc.mk
|
||||
endif
|
||||
ifneq ($(OLSR),0)
|
||||
include rules/olsr.mk
|
||||
endif
|
||||
ifneq ($(SLAACV4),0)
|
||||
include rules/slaacv4.mk
|
||||
endif
|
||||
ifneq ($(IPV6),0)
|
||||
include rules/ipv6.mk
|
||||
endif
|
||||
ifneq ($(MEMORY_MANAGER),0)
|
||||
include rules/memory_manager.mk
|
||||
endif
|
||||
ifneq ($(MEMORY_MANAGER_PROFILING),0)
|
||||
OPTIONS+=-dPICO_SUPPORT_MM_PROFILING
|
||||
endif
|
||||
ifneq ($(SNTP_CLIENT),0)
|
||||
include rules/sntp_client.mk
|
||||
endif
|
||||
ifneq ($(TUN),0)
|
||||
include rules/tun.mk
|
||||
endif
|
||||
ifneq ($(TAP),0)
|
||||
include rules/tap.mk
|
||||
endif
|
||||
ifneq ($(PCAP),0)
|
||||
include rules/pcap.mk
|
||||
endif
|
||||
ifneq ($(PPP),0)
|
||||
include rules/ppp.mk
|
||||
endif
|
||||
ifneq ($(CYASSL),0)
|
||||
include rules/cyassl.mk
|
||||
endif
|
||||
ifneq ($(WOLFSSL),0)
|
||||
include rules/wolfssl.mk
|
||||
endif
|
||||
ifneq ($(POLARSSL),0)
|
||||
include rules/polarssl.mk
|
||||
endif
|
||||
|
||||
all: mod core lib
|
||||
|
||||
core: $(CORE_OBJ)
|
||||
@mkdir -p $(PREFIX)/lib
|
||||
@mv stack/*.o $(PREFIX)/lib
|
||||
|
||||
mod: $(MOD_OBJ)
|
||||
@mkdir -p $(PREFIX)/modules
|
||||
@mv modules/*.o $(PREFIX)/modules || echo
|
||||
|
||||
posix: all $(POSIX_OBJ)
|
||||
@mv modules/*.o $(PREFIX)/modules || echo
|
||||
|
||||
|
||||
TEST_ELF= test/picoapp.elf
|
||||
TEST6_ELF= test/picoapp6.elf
|
||||
|
||||
|
||||
test: posix
|
||||
@mkdir -p $(PREFIX)/test/
|
||||
@make -C test/examples PREFIX=$(PREFIX)
|
||||
@echo -e "\t[CC] picoapp.o"
|
||||
@$(CC) -c -o $(PREFIX)/examples/picoapp.o test/picoapp.c $(CFLAGS) -Itest/examples
|
||||
@echo -e "\t[LD] $@"
|
||||
@$(CC) -g -o $(TEST_ELF) -I include -I modules -I $(PREFIX)/include -Wl,--start-group $(TEST_LDFLAGS) $(TEST_OBJ) $(PREFIX)/examples/*.o -Wl,--end-group
|
||||
@mv test/*.elf $(PREFIX)/test
|
||||
@install $(PREFIX)/$(TEST_ELF) $(PREFIX)/$(TEST6_ELF)
|
||||
|
||||
tst: test
|
||||
|
||||
$(PREFIX)/include/pico_defines.h:
|
||||
@mkdir -p $(PREFIX)/lib
|
||||
@mkdir -p $(PREFIX)/include
|
||||
@bash ./mkdeps.sh $(PREFIX) $(OPTIONS)
|
||||
|
||||
|
||||
deps: $(PREFIX)/include/pico_defines.h
|
||||
|
||||
|
||||
|
||||
lib: mod core
|
||||
@cp -f include/*.h $(PREFIX)/include
|
||||
@cp -fa include/arch $(PREFIX)/include
|
||||
@cp -f modules/*.h $(PREFIX)/include
|
||||
@echo -e "\t[AR] $(PREFIX)/lib/$(LIBNAME)"
|
||||
$(AR) -q -b -n -fag -o=$(PREFIX)/lib/$(LIBNAME) $(PREFIX)/modules/*.o $(PREFIX)/lib/*.o
|
||||
@echo || $(AR) cru $(PREFIX)/lib/$(LIBNAME) $(PREFIX)/lib/*.o
|
||||
@echo -e "\t[RANLIB] $(PREFIX)/lib/$(LIBNAME)"
|
||||
@$(RANLIB) $(PREFIX)/lib/$(LIBNAME)
|
||||
@echo -e "\t[LIBSIZE] `du -b $(PREFIX)/lib/$(LIBNAME)`"
|
||||
|
||||
loop: mod core
|
||||
mkdir -p $(PREFIX)/test
|
||||
@$(CC) -c -o $(PREFIX)/modules/pico_dev_loop.o modules/pico_dev_loop.c $(CFLAGS)
|
||||
@$(CC) -c -o $(PREFIX)/loop_ping.o test/loop_ping.c $(CFLAGS) -ggdb
|
||||
|
||||
units: mod core lib $(UNITS_OBJ) $(MOD_OBJ)
|
||||
@echo -e "\n\t[UNIT TESTS SUITE]"
|
||||
@mkdir -p $(PREFIX)/test
|
||||
@echo -e "\t[CC] units.o"
|
||||
@$(CC) -c -o $(PREFIX)/test/units.o test/units.c $(CFLAGS) -I stack -I modules -I includes -I test/unit -dUNIT_TEST
|
||||
@echo -e "\t[LD] $(PREFIX)/test/units"
|
||||
@$(CC) -o $(PREFIX)/test/units $(CFLAGS) $(PREFIX)/test/units.o -lcheck -lm -pthread -lrt \
|
||||
$(UNITS_OBJ) $(PREFIX)/modules/pico_aodv.o \
|
||||
$(PREFIX)/modules/pico_fragments.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
|
||||
@$(CC) -o $(PREFIX)/test/modunit_tcp.elf $(CFLAGS) -I. test/unit/modunit_pico_tcp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_dns_client.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_client.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_dns_common.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_common.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_mdns.elf $(CFLAGS) -I. test/unit/modunit_pico_mdns.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_dns_sd.elf $(CFLAGS) -I. test/unit/modunit_pico_dns_sd.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_dev_loop.elf $(CFLAGS) -I. test/unit/modunit_pico_dev_loop.c -lcheck -lm -pthread -lrt $(UNITS_OBJ)
|
||||
@$(CC) -o $(PREFIX)/test/modunit_ipv6_nd.elf $(CFLAGS) -I. test/unit/modunit_pico_ipv6_nd.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_pico_stack.elf $(CFLAGS) -I. test/unit/modunit_pico_stack.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_tftp.elf $(CFLAGS) -I. test/unit/modunit_pico_tftp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_sntp_client.elf $(CFLAGS) -I. test/unit/modunit_pico_sntp_client.c -lcheck -lm -pthread -lrt $(UNITS_OBJ)
|
||||
@$(CC) -o $(PREFIX)/test/modunit_ipfilter.elf $(CFLAGS) -I. test/unit/modunit_pico_ipfilter.c stack/pico_tree.c -lcheck -lm -pthread -lrt $(UNITS_OBJ)
|
||||
@$(CC) -o $(PREFIX)/test/modunit_aodv.elf $(CFLAGS) -I. test/unit/modunit_pico_aodv.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
@$(CC) -o $(PREFIX)/test/modunit_fragments.elf $(CFLAGS) -I. test/unit/modunit_pico_fragments.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)
|
||||
@$(CC) -o $(PREFIX)/test/modunit_dev_ppp.elf $(CFLAGS) -I. test/unit/modunit_pico_dev_ppp.c -lcheck -lm -pthread -lrt $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
|
||||
|
||||
devunits: mod core lib
|
||||
@echo -e "\n\t[UNIT TESTS SUITE: device drivers]"
|
||||
@mkdir -p $(PREFIX)/test/unit/device/
|
||||
@echo -e "\t[CC] picotcp_mock.o"
|
||||
@$(CC) -c -o $(PREFIX)/test/unit/device/picotcp_mock.o $(CFLAGS) -I stack -I modules -I includes -I test/unit test/unit/device/picotcp_mock.c
|
||||
@$(CC) -c -o $(PREFIX)/test/unit/device/unit_dev_vde.o $(CFLAGS) -I stack -I modules -I includes -I test/unit test/unit/device/unit_dev_vde.c
|
||||
@echo -e "\t[LD] $(PREFIX)/test/devunits"
|
||||
@$(CC) -o $(PREFIX)/test/devunits $(CFLAGS) -I stack $(PREFIX)/test/unit/device/*.o -lcheck -lm -pthread -lrt
|
||||
|
||||
units_mm: mod core lib
|
||||
@echo -e "\n\t[UNIT TESTS SUITE]"
|
||||
@mkdir -p $(PREFIX)/test
|
||||
@echo -e "\t[CC] units_mm.o"
|
||||
@$(CC) -c -o $(PREFIX)/test/units_mm.o test/unit/unit_mem_manager.c $(CFLAGS) -I stack -I modules -I includes -I test/unit
|
||||
@echo -e "\t[LD] $(PREFIX)/test/units"
|
||||
@$(CC) -o $(PREFIX)/test/units_mm $(CFLAGS) $(PREFIX)/test/units_mm.o -lcheck -lm -pthread -lrt
|
||||
|
||||
|
||||
clean:
|
||||
@echo -e "\t[CLEAN] $(PREFIX)/"
|
||||
@rm -rf $(PREFIX) tags
|
||||
|
||||
mbed:
|
||||
@echo -e "\t[Creating PicoTCP.zip]"
|
||||
@rm -f PicoTCP.zip
|
||||
@cp include/pico_socket.h include/socket.tmp
|
||||
@echo "#define MBED\n" > include/mbed.tmp
|
||||
@cat include/mbed.tmp include/socket.tmp > include/pico_socket.h
|
||||
@zip -0 PicoTCP.zip -r include modules stack -x include/arch/ include/arch/* include/pico_config.h include/*.tmp modules/pico_dev_*
|
||||
@rm include/pico_socket.h include/mbed.tmp
|
||||
@mv include/socket.tmp include/pico_socket.h
|
||||
|
||||
|
||||
style:
|
||||
@find . -iname "*.[c|h]" | xargs -x uncrustify --replace -l C -c uncrustify.cfg || true
|
||||
@find . -iname "*unc-backup*" |xargs -x rm || true
|
||||
|
||||
dummy: mod core lib $(DUMMY_EXTRA)
|
||||
@echo testing configuration...
|
||||
@$(CC) -c -o test/dummy.o test/dummy.c $(CFLAGS)
|
||||
@$(CC) -o dummy test/dummy.o $(DUMMY_EXTRA) $(PREFIX)/lib/libpicotcp.a $(LDFLAGS) $(CFLAGS)
|
||||
@echo done.
|
||||
@rm -f test/dummy.o dummy
|
||||
|
||||
ppptest: test/ppp.c lib
|
||||
gcc -ggdb -c -o ppp.o test/ppp.c -I build/include/ -I build/modules/ $(CFLAGS)
|
||||
gcc -o ppp ppp.o build/lib/libpicotcp.a $(LDFLAGS) $(CFLAGS)
|
||||
rm -f ppp.o
|
||||
|
||||
|
||||
FORCE:
|
||||
103
ext/picotcp/README.md
Normal file
103
ext/picotcp/README.md
Normal file
@@ -0,0 +1,103 @@
|
||||
picoTCP
|
||||
|
||||
---------------
|
||||
|
||||
Welcome to the one and only <font color=ff00f0>picoTCP repository</font>.
|
||||
|
||||
picoTCP is a small-footprint, modular TCP/IP stack designed for embedded systems and the Internet of Things. It's actively being developed by *[Altran Intelligent Systems](http://intelligent-systems.altran.com/)*. Textual information about picoTCP, you can find on the [about page of our website](http://picotcp.com/about).
|
||||
|
||||
This code is released under the terms of GNU GPL v2 only. Some rights reserved.
|
||||
Other licenses may apply at the sole discretion of the copyright holders.
|
||||
|
||||
Learn how to use picoTCP in your project by going through the **Getting Started guide** on our [GitHub wiki](https://github.com/tass-belgium/picotcp/wiki).
|
||||
|
||||
For more information visit the [picoTCP website](http://www.picotcp.com), send us an email or contact us on [Twitter](https://twitter.com/picotcp), [Facebook](https://www.facebook.com/picoTCP) or [Reddit](http://www.reddit.com/r/picotcp/).
|
||||
|
||||
Wondering about picoTCP's code quality? Check [our TiCS score](http://tics.picotcp.com:42506/tiobeweb/TICS/TqiDashboard.html#axes=Project%28%29&metric=tqi&sel=Project%28PicoTCP_rel%29)
|
||||
|
||||
|
||||
---------------
|
||||
|
||||
Continuous integration
|
||||
|
||||
Jenkins Functional tests:
|
||||
[](http://jenkins.picotcp.com:8080/job/picoTCP_Rel/job/PicoTCP_rel_autotest)
|
||||
|
||||
Jenkins Unit tests :
|
||||
[](http://jenkins.picotcp.com:8080/job/picoTCP_Rel/job/PicoTCP_rel_unit_tests)
|
||||
|
||||
Jenkins RFC compliance :
|
||||
[](http://jenkins.picotcp.com:8080/job/picoTCP_Rel/job/PicoTCP_rel_RF_mbed)
|
||||
|
||||
Jenkins TICS quality :
|
||||
[](http://jenkins.picotcp.com:8080/job/picoTCP_Rel/job/PicoTCP_rel_TICS/)
|
||||
|
||||
Coverity Scan Build status:
|
||||
[](https://scan.coverity.com/projects/7944)
|
||||
|
||||
---------------
|
||||
|
||||
Works with ...
|
||||
## Platforms
|
||||
* ARM Cortex-M series
|
||||
* ST Micro STM
|
||||
* NXP LPC
|
||||
* TI Stellaris
|
||||
* Freescale K64F
|
||||
* ARM ARM9-series
|
||||
* ST Micro STR9
|
||||
* Texas Instruments
|
||||
* MSP430
|
||||
* Microchip
|
||||
* PIC24
|
||||
* Atmel
|
||||
* AVR 8bit
|
||||
* Linux
|
||||
* User space (TUN/TAP)
|
||||
* Kernel space
|
||||
* Windows
|
||||
* User space (TAP)
|
||||
|
||||
## Network drivers
|
||||
* BCM43362 (IEEE 802.11)
|
||||
* MRF24WG (IEEE 802.11)
|
||||
* LPC Ethernet ENET/EMAC (IEEE 802.3)
|
||||
* Stellaris Ethernet (IEEE 802.3)
|
||||
* STM32 Ethernet (IEEE 802.3)
|
||||
* Wiznet W5100 (IEEE 802.3)
|
||||
* USB CDC-ECM (CDC1.2)
|
||||
* PPP
|
||||
* Virtual drivers
|
||||
* TUN/TAP
|
||||
* VDE
|
||||
* Libpcap
|
||||
|
||||
## (RT)OSes
|
||||
* No OS / Bare metal
|
||||
* FreeRTOS
|
||||
* mbed-RTOS
|
||||
* Frosted
|
||||
* linux / POSIX
|
||||
* MS DOS
|
||||
* MS Windows
|
||||
|
||||
## Libraries
|
||||
* wolfSSL
|
||||
* mbedTLS
|
||||
* Mongoose RESTful library
|
||||
* MicroPython
|
||||
* HTTP library
|
||||
* ZeroMQ (WIP)
|
||||
* MQTT
|
||||
|
||||
## Compilers
|
||||
* GCC
|
||||
* Clang
|
||||
* TCC
|
||||
* ARM-RCVT
|
||||
* IAR
|
||||
* XC-16
|
||||
* MSP-GCC
|
||||
* AVR-GCC
|
||||
|
||||
Your favorite not in the list? Check out the wiki for information and examples on how to port picoTCP to a new platform!
|
||||
35
ext/picotcp/include/arch/pico_arm9.h
Normal file
35
ext/picotcp/include/arch/pico_arm9.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
*********************************************************************/
|
||||
#define dbg(...) do {} while(0)
|
||||
|
||||
/******************/
|
||||
|
||||
/*** MACHINE CONFIGURATION ***/
|
||||
/* Temporary (POSIX) stuff. */
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern volatile uint32_t __str9_tick;
|
||||
|
||||
#define pico_native_malloc(x) calloc(x, 1)
|
||||
#define pico_native_free(x) free(x)
|
||||
|
||||
static inline unsigned long PICO_TIME(void)
|
||||
{
|
||||
register uint32_t tick = __str9_tick;
|
||||
return tick / 1000;
|
||||
}
|
||||
|
||||
static inline unsigned long PICO_TIME_MS(void)
|
||||
{
|
||||
return __str9_tick;
|
||||
}
|
||||
|
||||
static inline void PICO_IDLE(void)
|
||||
{
|
||||
unsigned long tick_now = __str9_tick;
|
||||
while(tick_now == __str9_tick) ;
|
||||
}
|
||||
|
||||
39
ext/picotcp/include/arch/pico_avr.h
Normal file
39
ext/picotcp/include/arch/pico_avr.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#define dbg(...) do {} while(0)
|
||||
/* #define dbg printf */
|
||||
|
||||
/*************************/
|
||||
|
||||
/*** MACHINE CONFIGURATION ***/
|
||||
/* Temporary (POSIX) stuff. */
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "pico_mm.h"
|
||||
|
||||
extern volatile uint32_t __avr_tick;
|
||||
|
||||
#define pico_zalloc(x) calloc(x, 1)
|
||||
#define pico_free(x) free(x)
|
||||
|
||||
static inline unsigned long PICO_TIME(void)
|
||||
{
|
||||
register uint32_t tick = __avr_tick;
|
||||
return tick / 1000;
|
||||
}
|
||||
|
||||
static inline unsigned long PICO_TIME_MS(void)
|
||||
{
|
||||
return __avr_tick;
|
||||
}
|
||||
|
||||
static inline void PICO_IDLE(void)
|
||||
{
|
||||
unsigned long tick_now = __avr_tick;
|
||||
while(tick_now == __avr_tick) ;
|
||||
}
|
||||
|
||||
12
ext/picotcp/include/arch/pico_cortex_m.h
Normal file
12
ext/picotcp/include/arch/pico_cortex_m.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef _INCLUDE_PICO_CORTEX_M
|
||||
#define _INCLUDE_PICO_CORTEX_M
|
||||
|
||||
#include "pico_generic_gcc.h"
|
||||
|
||||
#endif /* PICO_CORTEX_M */
|
||||
|
||||
55
ext/picotcp/include/arch/pico_esp8266.h
Normal file
55
ext/picotcp/include/arch/pico_esp8266.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef _INCLUDE_PICO_ESP8266
|
||||
#define _INCLUDE_PICO_ESP8266
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "pico_constants.h"
|
||||
|
||||
/* -------------- DEBUG ------------- */
|
||||
|
||||
/* #define dbg(...) */
|
||||
#define dbg printf
|
||||
|
||||
/* -------------- MEMORY ------------- */
|
||||
extern void *pvPortMalloc( size_t xWantedSize );
|
||||
extern void vPortFree( void *pv );
|
||||
|
||||
#define pico_free vPortFree
|
||||
|
||||
static inline void *pico_zalloc(size_t size)
|
||||
{
|
||||
void *ptr = (void *)pvPortMalloc(size);
|
||||
|
||||
if(ptr)
|
||||
memset(ptr, 0u, size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* -------------- TIME ------------- */
|
||||
|
||||
extern volatile uint32_t esp_tick;
|
||||
|
||||
static inline pico_time PICO_TIME_MS(void) {
|
||||
return (pico_time) esp_tick;
|
||||
}
|
||||
|
||||
static inline pico_time PICO_TIME(void) {
|
||||
return PICO_TIME_MS() / 1000;
|
||||
}
|
||||
|
||||
static inline void PICO_IDLE(void) {
|
||||
uint32_t now = esp_tick;
|
||||
while (now == esp_tick)
|
||||
;
|
||||
}
|
||||
|
||||
#endif
|
||||
102
ext/picotcp/include/arch/pico_generic_gcc.h
Normal file
102
ext/picotcp/include/arch/pico_generic_gcc.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef _INCLUDE_PICO_GCC
|
||||
#define _INCLUDE_PICO_GCC
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "pico_constants.h"
|
||||
|
||||
/* monotonically increasing tick,
|
||||
* typically incremented every millisecond in a systick interrupt */
|
||||
extern volatile unsigned int pico_ms_tick;
|
||||
|
||||
#define dbg(...)
|
||||
|
||||
#ifdef PICO_SUPPORT_PTHREAD
|
||||
#define PICO_SUPPORT_MUTEX
|
||||
#endif
|
||||
|
||||
#ifdef PICO_SUPPORT_RTOS
|
||||
#define PICO_SUPPORT_MUTEX
|
||||
|
||||
extern void *pico_mutex_init(void);
|
||||
extern void pico_mutex_lock(void*);
|
||||
extern void pico_mutex_unlock(void*);
|
||||
extern void *pvPortMalloc( size_t xSize );
|
||||
extern void vPortFree( void *pv );
|
||||
|
||||
#define pico_free(x) vPortFree(x)
|
||||
#define free(x) vPortFree(x)
|
||||
|
||||
static inline void *pico_zalloc(size_t size)
|
||||
{
|
||||
void *ptr = pvPortMalloc(size);
|
||||
|
||||
if(ptr)
|
||||
memset(ptr, 0u, size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline pico_time PICO_TIME_MS()
|
||||
{
|
||||
return pico_ms_tick;
|
||||
}
|
||||
|
||||
static inline pico_time PICO_TIME()
|
||||
{
|
||||
return pico_ms_tick / 1000;
|
||||
}
|
||||
|
||||
static inline void PICO_IDLE(void)
|
||||
{
|
||||
pico_time now = PICO_TIME_MS();
|
||||
while(now == PICO_TIME_MS()) ;
|
||||
}
|
||||
|
||||
#else /* NO RTOS SUPPORT */
|
||||
|
||||
#ifdef MEM_MEAS
|
||||
/* These functions should be implemented elsewhere */
|
||||
extern void *memmeas_zalloc(size_t size);
|
||||
extern void memmeas_free(void *);
|
||||
#define pico_free(x) memmeas_free(x)
|
||||
#define pico_zalloc(x) memmeas_zalloc(x)
|
||||
#else
|
||||
/* Use plain C-lib malloc and free */
|
||||
#define pico_free(x) free(x)
|
||||
static inline void *pico_zalloc(size_t size)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
if(ptr)
|
||||
memset(ptr, 0u, size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline pico_time PICO_TIME_MS(void)
|
||||
{
|
||||
return (pico_time)pico_ms_tick;
|
||||
}
|
||||
|
||||
static inline pico_time PICO_TIME(void)
|
||||
{
|
||||
return (pico_time)(PICO_TIME_MS() / 1000);
|
||||
}
|
||||
|
||||
static inline void PICO_IDLE(void)
|
||||
{
|
||||
unsigned int now = pico_ms_tick;
|
||||
while(now == pico_ms_tick) ;
|
||||
}
|
||||
|
||||
#endif /* IFNDEF RTOS */
|
||||
|
||||
#endif /* PICO_GCC */
|
||||
|
||||
33
ext/picotcp/include/arch/pico_linux.h
Normal file
33
ext/picotcp/include/arch/pico_linux.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef PICO_SUPPORT_LINUX
|
||||
#define PICO_SUPPORT_LINUX
|
||||
|
||||
#include "linux/types.h"
|
||||
#include "linux/mm.h"
|
||||
#include "linux/slab.h"
|
||||
#include "linux/jiffies.h"
|
||||
|
||||
#define dbg printk
|
||||
|
||||
#define pico_zalloc(x) kcalloc(x, 1, GFP_ATOMIC) /* All allocations are GFP_ATOMIC for now */
|
||||
#define pico_free(x) kfree(x)
|
||||
|
||||
|
||||
static inline unsigned long PICO_TIME(void)
|
||||
{
|
||||
return (unsigned long)(jiffies_to_msecs(jiffies) / 1000);
|
||||
}
|
||||
|
||||
static inline unsigned long PICO_TIME_MS(void)
|
||||
{
|
||||
return (unsigned long)jiffies_to_msecs(jiffies);
|
||||
}
|
||||
|
||||
static inline void PICO_IDLE(void)
|
||||
{
|
||||
unsigned long now = jiffies;
|
||||
while (now == jiffies) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
185
ext/picotcp/include/arch/pico_mbed.h
Normal file
185
ext/picotcp/include/arch/pico_mbed.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
File: pico_mbed.h
|
||||
Author: Toon Peters
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef PICO_SUPPORT_MBED
|
||||
#define PICO_SUPPORT_MBED
|
||||
#include <stdio.h>
|
||||
#include <pico_queue.h>
|
||||
/* #include "mbed.h" */
|
||||
/* #include "serial_api.h" */
|
||||
|
||||
/* #define TIME_PRESCALE */
|
||||
/* #define PICO_MEASURE_STACK */
|
||||
/* #define MEMORY_MEASURE */
|
||||
/*
|
||||
Debug needs initialization:
|
||||
* void serial_init (serial_t *obj, PinName tx, PinName rx);
|
||||
* void serial_baud (serial_t *obj, int baudrate);
|
||||
* void serial_format (serial_t *obj, int data_bits, SerialParity parity, int stop_bits);
|
||||
*/
|
||||
|
||||
#define dbg(...)
|
||||
|
||||
/*
|
||||
#define MEMORY_MEASURE
|
||||
#define JENKINS_DEBUG
|
||||
*/
|
||||
|
||||
/* Intended for Mr. Jenkins endurance test loggings */
|
||||
#ifdef JENKINS_DEBUG
|
||||
#include "PicoTerm.h"
|
||||
#define jenkins_dbg ptm_dbg
|
||||
#endif
|
||||
|
||||
#ifdef PICO_MEASURE_STACK
|
||||
|
||||
extern int freeStack;
|
||||
#define STACK_TOTAL_WORDS 1000u
|
||||
#define STACK_PATTERN (0xC0CAC01Au)
|
||||
|
||||
void stack_fill_pattern(void *ptr);
|
||||
void stack_count_free_words(void *ptr);
|
||||
int stack_get_free_words(void);
|
||||
#else
|
||||
#define stack_fill_pattern(...) do {} while(0)
|
||||
#define stack_count_free_words(...) do {} while(0)
|
||||
#define stack_get_free_words() (0)
|
||||
#endif
|
||||
|
||||
#ifdef MEMORY_MEASURE /* in case, comment out the two defines above me. */
|
||||
extern uint32_t max_mem;
|
||||
extern uint32_t cur_mem;
|
||||
|
||||
struct mem_chunk_stats {
|
||||
#ifdef MEMORY_MEASURE_ADV
|
||||
uint32_t signature;
|
||||
void *mem;
|
||||
#endif
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
static inline void *pico_zalloc(int x)
|
||||
{
|
||||
struct mem_chunk_stats *stats;
|
||||
if ((cur_mem + x) > (10 * 1024))
|
||||
return NULL;
|
||||
|
||||
stats = (struct mem_chunk_stats *)calloc(x + sizeof(struct mem_chunk_stats), 1);
|
||||
#ifdef MEMORY_MEASURE_ADV
|
||||
stats->signature = 0xdeadbeef;
|
||||
stats->mem = ((uint8_t *)stats) + sizeof(struct mem_chunk_stats);
|
||||
#endif
|
||||
stats->size = x;
|
||||
|
||||
/* Intended for Mr. Jenkins endurance test loggings */
|
||||
#ifdef JENKINS_DEBUG
|
||||
if (!stats) {
|
||||
jenkins_dbg(">> OUT OF MEM\n");
|
||||
while(1) ;
|
||||
;
|
||||
}
|
||||
|
||||
#endif
|
||||
cur_mem += x;
|
||||
if (cur_mem > max_mem) {
|
||||
max_mem = cur_mem;
|
||||
/* printf("max mem: %lu\n", max_mem); */
|
||||
}
|
||||
|
||||
#ifdef MEMORY_MEASURE_ADV
|
||||
return (void*)(stats->mem);
|
||||
#else
|
||||
return (void*) (((uint8_t *)stats) + sizeof(struct mem_chunk_stats));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void pico_free(void *x)
|
||||
{
|
||||
struct mem_chunk_stats *stats = (struct mem_chunk_stats *) ((uint8_t *)x - sizeof(struct mem_chunk_stats));
|
||||
|
||||
#ifdef JENKINS_DEBUG
|
||||
#ifdef MEMORY_MEASURE_ADV
|
||||
if ((stats->signature != 0xdeadbeef) || (x != stats->mem)) {
|
||||
jenkins_dbg(">> FREE ERROR: caller is %p\n", __builtin_return_address(0));
|
||||
while(1) ;
|
||||
;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
cur_mem -= stats->size;
|
||||
memset(stats, 0, sizeof(struct mem_chunk_stats));
|
||||
free(stats);
|
||||
}
|
||||
#else
|
||||
|
||||
#define pico_zalloc(x) calloc(x, 1)
|
||||
#define pico_free(x) free(x)
|
||||
|
||||
#endif
|
||||
|
||||
#define PICO_SUPPORT_MUTEX
|
||||
extern void *pico_mutex_init(void);
|
||||
extern void pico_mutex_lock(void*);
|
||||
extern void pico_mutex_unlock(void*);
|
||||
extern void pico_mutex_deinit(void*);
|
||||
|
||||
extern uint32_t os_time;
|
||||
extern pico_time local_time;
|
||||
extern uint32_t last_os_time;
|
||||
|
||||
#ifdef TIME_PRESCALE
|
||||
extern int32_t prescale_time;
|
||||
#endif
|
||||
|
||||
#define UPDATE_LOCAL_TIME() do {local_time = local_time + ((pico_time)os_time - (pico_time)last_os_time);last_os_time = os_time;} while(0)
|
||||
|
||||
static inline pico_time PICO_TIME(void)
|
||||
{
|
||||
UPDATE_LOCAL_TIME();
|
||||
#ifdef TIME_PRESCALE
|
||||
return (prescale_time < 0) ? (pico_time)(local_time / 1000 << (-prescale_time)) : \
|
||||
(pico_time)(local_time / 1000 >> prescale_time);
|
||||
#else
|
||||
return (pico_time)(local_time / 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline pico_time PICO_TIME_MS(void)
|
||||
{
|
||||
UPDATE_LOCAL_TIME();
|
||||
#ifdef TIME_PRESCALE
|
||||
return (prescale_time < 0) ? (pico_time)(local_time << (-prescale_time)) : \
|
||||
(pico_time)(local_time >> prescale_time);
|
||||
#else
|
||||
return (pico_time)local_time;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void PICO_IDLE(void)
|
||||
{
|
||||
/* TODO needs implementation */
|
||||
}
|
||||
/*
|
||||
static inline void PICO_DEBUG(const char * formatter, ... )
|
||||
{
|
||||
char buffer[256];
|
||||
char *ptr;
|
||||
va_list args;
|
||||
va_start(args, formatter);
|
||||
vsnprintf(buffer, 256, formatter, args);
|
||||
ptr = buffer;
|
||||
while(*ptr != '\0')
|
||||
serial_putc(serial_t *obj, (int) (*(ptr++)));
|
||||
va_end(args);
|
||||
//TODO implement serial_t
|
||||
}*/
|
||||
|
||||
#endif
|
||||
38
ext/picotcp/include/arch/pico_msp430.h
Normal file
38
ext/picotcp/include/arch/pico_msp430.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef _INCLUDE_PICO_LPC
|
||||
#define _INCLUDE_PICO_LPC
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "pico_constants.h"
|
||||
|
||||
extern pico_time msp430_time_s(void);
|
||||
extern pico_time msp430_time_ms(void);
|
||||
extern void *malloc(size_t);
|
||||
extern void free(void *);
|
||||
|
||||
|
||||
#define PICO_TIME() msp430_time_s()
|
||||
#define PICO_TIME_MS() msp430_time_ms()
|
||||
#define PICO_IDLE() do {} while(0)
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#define dbg(...)
|
||||
|
||||
#endif
|
||||
22
ext/picotcp/include/arch/pico_none.h
Normal file
22
ext/picotcp/include/arch/pico_none.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef PICO_SUPPORT_ARCHNONE
|
||||
#define PICO_SUPPORT_ARCHNONE
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define dbg(...) do {} while(0)
|
||||
#define pico_zalloc(x) NULL
|
||||
#define pico_free(x) do {} while(0)
|
||||
#define PICO_TIME() 666
|
||||
#define PICO_TIME_MS() 666000
|
||||
#define PICO_IDLE() do {} while(0)
|
||||
|
||||
#endif /* PICO_SUPPORT_ARCHNONE */
|
||||
|
||||
100
ext/picotcp/include/arch/pico_pic24.h
Normal file
100
ext/picotcp/include/arch/pico_pic24.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
*********************************************************************/
|
||||
#ifndef PICO_SUPPORT_PIC24
|
||||
#define PICO_SUPPORT_PIC24
|
||||
#define dbg printf
|
||||
/* #define dbg(...) */
|
||||
|
||||
/*************************/
|
||||
|
||||
/*** MACHINE CONFIGURATION ***/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* #include "phalox_development_board.h" */
|
||||
|
||||
#ifndef __PIC24F__
|
||||
#define __PIC24F__
|
||||
#endif
|
||||
|
||||
/*
|
||||
#ifndef __PIC24FJ256GA106__
|
||||
#define __PIC24FJ256GA106__
|
||||
#endif
|
||||
*/
|
||||
|
||||
#ifndef PICO_MAX_SOCKET_FRAMES
|
||||
#define PICO_MAX_SOCKET_FRAMES 16
|
||||
#endif
|
||||
|
||||
/* Device header file */
|
||||
|
||||
#if defined(__PIC24E__)
|
||||
# include <p24Exxxx.h>
|
||||
#elif defined(__PIC24F__)
|
||||
# include <p24Fxxxx.h>
|
||||
#elif defined(__PIC24H__)
|
||||
# include <p24Hxxxx.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define TIMBASE_INT_E IEC0bits.T2IE
|
||||
|
||||
#ifdef PICO_SUPPORT_DEBUG_MEMORY
|
||||
static inline void *pico_zalloc(int len)
|
||||
{
|
||||
/* dbg("%s: Alloc object of len %d, caller: %p\n", __FUNCTION__, len, __builtin_return_address(0)); */
|
||||
return calloc(len, 1);
|
||||
}
|
||||
|
||||
static inline void pico_free(void *tgt)
|
||||
{
|
||||
/* dbg("%s: Discarded object @%p, caller: %p\n", __FUNCTION__, tgt, __builtin_return_address(0)); */
|
||||
free(tgt);
|
||||
}
|
||||
#else
|
||||
# define pico_zalloc(x) calloc(x, 1)
|
||||
# define pico_free(x) free(x)
|
||||
#endif
|
||||
|
||||
extern void *pvPortMalloc( size_t xWantedSize );
|
||||
extern volatile pico_time __pic24_tick;
|
||||
|
||||
static inline unsigned long PICO_TIME(void)
|
||||
{
|
||||
unsigned long tick;
|
||||
/* Disable timer interrupts */
|
||||
TIMBASE_INT_E = 0;
|
||||
tick = __pic24_tick;
|
||||
/* Enable timer interrupts */
|
||||
TIMBASE_INT_E = 1;
|
||||
return tick / 1000;
|
||||
}
|
||||
|
||||
static inline unsigned long PICO_TIME_MS(void)
|
||||
{
|
||||
unsigned long tick;
|
||||
/* Disable timer interrupts */
|
||||
TIMBASE_INT_E = 0;
|
||||
tick = __pic24_tick;
|
||||
/* Enable timer interrupts */
|
||||
TIMBASE_INT_E = 1;
|
||||
return tick;
|
||||
}
|
||||
|
||||
static inline void PICO_IDLE(void)
|
||||
{
|
||||
unsigned long tick_now;
|
||||
/* Disable timer interrupts */
|
||||
TIMBASE_INT_E = 0;
|
||||
tick_now = (unsigned long)pico_tick;
|
||||
/* Enable timer interrupts */
|
||||
TIMBASE_INT_E = 1;
|
||||
/* Doesn't matter that this call isn't interrupt safe, */
|
||||
/* we just check for the value to change */
|
||||
while(tick_now == __pic24_tick) ;
|
||||
}
|
||||
|
||||
#endif
|
||||
130
ext/picotcp/include/arch/pico_posix.h
Normal file
130
ext/picotcp/include/arch/pico_posix.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef PICO_SUPPORT_POSIX
|
||||
#define PICO_SUPPORT_POSIX
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/*
|
||||
#define MEMORY_MEASURE
|
||||
#define TIME_PRESCALE
|
||||
#define PICO_SUPPORT_THREADING
|
||||
*/
|
||||
#define dbg printf
|
||||
|
||||
#define stack_fill_pattern(...) do {} while(0)
|
||||
#define stack_count_free_words(...) do {} while(0)
|
||||
#define stack_get_free_words() (0)
|
||||
|
||||
/* measure allocated memory */
|
||||
#ifdef MEMORY_MEASURE
|
||||
extern uint32_t max_mem;
|
||||
extern uint32_t cur_mem;
|
||||
|
||||
static inline void *pico_zalloc(int x)
|
||||
{
|
||||
uint32_t *ptr;
|
||||
if ((cur_mem + x) > (10 * 1024))
|
||||
return NULL;
|
||||
|
||||
ptr = (uint32_t *)calloc(x + 4, 1);
|
||||
*ptr = (uint32_t)x;
|
||||
cur_mem += x;
|
||||
if (cur_mem > max_mem) {
|
||||
max_mem = cur_mem;
|
||||
}
|
||||
|
||||
return (void*)(ptr + 1);
|
||||
}
|
||||
|
||||
static inline void pico_free(void *x)
|
||||
{
|
||||
uint32_t *ptr = (uint32_t*)(((uint8_t *)x) - 4);
|
||||
cur_mem -= *ptr;
|
||||
free(ptr);
|
||||
}
|
||||
#else
|
||||
#define pico_zalloc(x) calloc(x, 1)
|
||||
#define pico_free(x) free(x)
|
||||
#endif
|
||||
|
||||
/* time prescaler */
|
||||
#ifdef TIME_PRESCALE
|
||||
extern int32_t prescale_time;
|
||||
#endif
|
||||
|
||||
#if defined(PICO_SUPPORT_RTOS) || defined (PICO_SUPPORT_PTHREAD)
|
||||
/* pico_ms_tick must be defined */
|
||||
extern volatile unsigned long int pico_ms_tick;
|
||||
|
||||
|
||||
static inline uint32_t PICO_TIME(void)
|
||||
{
|
||||
return pico_ms_tick / 1000;
|
||||
}
|
||||
|
||||
static inline uint32_t PICO_TIME_MS(void)
|
||||
{
|
||||
return pico_ms_tick;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline uint32_t PICO_TIME(void)
|
||||
{
|
||||
struct timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
#ifdef TIME_PRESCALE
|
||||
return (prescale_time < 0) ? (uint32_t)(t.tv_sec / 1000 << (-prescale_time)) : \
|
||||
(uint32_t)(t.tv_sec / 1000 >> prescale_time);
|
||||
#else
|
||||
return (uint32_t)t.tv_sec;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t PICO_TIME_MS(void)
|
||||
{
|
||||
struct timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
#ifdef TIME_PRESCALER
|
||||
uint32_t tmp = ((t.tv_sec * 1000) + (t.tv_usec / 1000));
|
||||
return (prescale_time < 0) ? (uint32_t)(tmp / 1000 << (-prescale_time)) : \
|
||||
(uint32_t)(tmp / 1000 >> prescale_time);
|
||||
#else
|
||||
return (uint32_t)((t.tv_sec * 1000) + (t.tv_usec / 1000));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PICO_SUPPORT_THREADING
|
||||
#define PICO_SUPPORT_MUTEX
|
||||
/* mutex implementations */
|
||||
extern void *pico_mutex_init(void);
|
||||
extern void pico_mutex_lock(void *mux);
|
||||
extern void pico_mutex_unlock(void *mux);
|
||||
|
||||
/* semaphore implementations (only used in wrapper code) */
|
||||
extern void *pico_sem_init(void);
|
||||
extern void pico_sem_destroy(void *sem);
|
||||
extern void pico_sem_post(void *sem);
|
||||
/* returns -1 on timeout (in ms), else returns 0 */
|
||||
/* if timeout < 0, the semaphore waits forever */
|
||||
extern int pico_sem_wait(void *sem, int timeout);
|
||||
|
||||
/* thread implementations */
|
||||
extern void *pico_thread_create(void *(*routine)(void *), void *arg);
|
||||
#endif /* PICO_SUPPORT_THREADING */
|
||||
|
||||
static inline void PICO_IDLE(void)
|
||||
{
|
||||
usleep(5000);
|
||||
}
|
||||
|
||||
#endif /* PICO_SUPPORT_POSIX */
|
||||
|
||||
83
ext/picotcp/include/heap.h
Normal file
83
ext/picotcp/include/heap.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#define DECLARE_HEAP(type, orderby) \
|
||||
struct heap_ ## type { \
|
||||
uint32_t size; \
|
||||
uint32_t n; \
|
||||
type *top; \
|
||||
}; \
|
||||
typedef struct heap_ ## type heap_ ## type; \
|
||||
static inline int heap_insert(struct heap_ ## type *heap, type * el) \
|
||||
{ \
|
||||
uint32_t i; \
|
||||
type *newTop; \
|
||||
if (++heap->n >= heap->size) { \
|
||||
newTop = PICO_ZALLOC((heap->n + 1) * sizeof(type)); \
|
||||
if(!newTop) { \
|
||||
heap->n--; \
|
||||
return -1; \
|
||||
} \
|
||||
if (heap->top) { \
|
||||
memcpy(newTop, heap->top, heap->n * sizeof(type)); \
|
||||
PICO_FREE(heap->top); \
|
||||
} \
|
||||
heap->top = newTop; \
|
||||
heap->size++; \
|
||||
} \
|
||||
if (heap->n == 1) { \
|
||||
memcpy(&heap->top[1], el, sizeof(type)); \
|
||||
return 0; \
|
||||
} \
|
||||
for (i = heap->n; ((i > 1) && (heap->top[i / 2].orderby > el->orderby)); i /= 2) { \
|
||||
memcpy(&heap->top[i], &heap->top[i / 2], sizeof(type)); \
|
||||
} \
|
||||
memcpy(&heap->top[i], el, sizeof(type)); \
|
||||
return 0; \
|
||||
} \
|
||||
static inline int heap_peek(struct heap_ ## type *heap, type * first) \
|
||||
{ \
|
||||
type *last; \
|
||||
uint32_t i, child; \
|
||||
if(heap->n == 0) { \
|
||||
return -1; \
|
||||
} \
|
||||
memcpy(first, &heap->top[1], sizeof(type)); \
|
||||
last = &heap->top[heap->n--]; \
|
||||
for(i = 1; (i * 2u) <= heap->n; i = child) { \
|
||||
child = 2u * i; \
|
||||
if ((child != heap->n) && \
|
||||
(heap->top[child + 1]).orderby \
|
||||
< (heap->top[child]).orderby) \
|
||||
child++; \
|
||||
if (last->orderby > \
|
||||
heap->top[child].orderby) \
|
||||
memcpy(&heap->top[i], &heap->top[child], \
|
||||
sizeof(type)); \
|
||||
else \
|
||||
break; \
|
||||
} \
|
||||
memcpy(&heap->top[i], last, sizeof(type)); \
|
||||
return 0; \
|
||||
} \
|
||||
static inline type *heap_first(heap_ ## type * heap) \
|
||||
{ \
|
||||
if (heap->n == 0) \
|
||||
return NULL; \
|
||||
return &heap->top[1]; \
|
||||
} \
|
||||
static inline heap_ ## type *heap_init(void) \
|
||||
{ \
|
||||
heap_ ## type * p = (heap_ ## type *)PICO_ZALLOC(sizeof(heap_ ## type)); \
|
||||
return p; \
|
||||
} \
|
||||
/*static inline void heap_destroy(heap_ ## type * h) \
|
||||
{ \
|
||||
PICO_FREE(h->top); \
|
||||
PICO_FREE(h); \
|
||||
} \*/
|
||||
|
||||
|
||||
52
ext/picotcp/include/pico_addressing.h
Normal file
52
ext/picotcp/include/pico_addressing.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_ADDRESSING
|
||||
#define INCLUDE_PICO_ADDRESSING
|
||||
|
||||
#include "pico_config.h"
|
||||
|
||||
PACKED_STRUCT_DEF pico_ip4
|
||||
{
|
||||
uint32_t addr;
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_ip6
|
||||
{
|
||||
uint8_t addr[16];
|
||||
};
|
||||
|
||||
union pico_address
|
||||
{
|
||||
struct pico_ip4 ip4;
|
||||
struct pico_ip6 ip6;
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_eth
|
||||
{
|
||||
uint8_t addr[6];
|
||||
uint8_t padding[2];
|
||||
};
|
||||
|
||||
extern const uint8_t PICO_ETHADDR_ALL[];
|
||||
|
||||
|
||||
PACKED_STRUCT_DEF pico_trans
|
||||
{
|
||||
uint16_t sport;
|
||||
uint16_t dport;
|
||||
|
||||
};
|
||||
|
||||
/* Here are some protocols. */
|
||||
#define PICO_PROTO_IPV4 0
|
||||
#define PICO_PROTO_ICMP4 1
|
||||
#define PICO_PROTO_IGMP 2
|
||||
#define PICO_PROTO_TCP 6
|
||||
#define PICO_PROTO_UDP 17
|
||||
#define PICO_PROTO_IPV6 41
|
||||
#define PICO_PROTO_ICMP6 58
|
||||
|
||||
#endif
|
||||
234
ext/picotcp/include/pico_config.h
Normal file
234
ext/picotcp/include/pico_config.h
Normal file
@@ -0,0 +1,234 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#include "pico_defines.h"
|
||||
#ifndef INCLUDE_PICO_CONFIG
|
||||
#define INCLUDE_PICO_CONFIG
|
||||
#ifndef __KERNEL__
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#else
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
|
||||
#if defined __IAR_SYSTEMS_ICC__ || defined ATOP
|
||||
# define PACKED_STRUCT_DEF __packed struct
|
||||
# define PEDANTIC_STRUCT_DEF __packed struct
|
||||
# define PACKED_UNION_DEF __packed union
|
||||
# define WEAK
|
||||
#elif defined __WATCOMC__
|
||||
# define PACKED_STRUCT_DEF _Packed struct
|
||||
# define PEDANTIC_STRUCT_DEF struct
|
||||
# define PACKED_UNION_DEF _Packed union
|
||||
# define WEAK
|
||||
#else
|
||||
# define PACKED_STRUCT_DEF struct __attribute__((packed))
|
||||
# define PEDANTIC_STRUCT_DEF struct
|
||||
# define PACKED_UNION_DEF union /* Sane compilers do not require packed unions */
|
||||
# define WEAK __attribute__((weak))
|
||||
# ifdef __GNUC__
|
||||
# define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||
# if ((GCC_VERSION >= 40800))
|
||||
# define BYTESWAP_GCC
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef PICO_BIGENDIAN
|
||||
|
||||
# define PICO_IDETH_IPV4 0x0800
|
||||
# define PICO_IDETH_ARP 0x0806
|
||||
# define PICO_IDETH_IPV6 0x86DD
|
||||
|
||||
# define PICO_ARP_REQUEST 0x0001
|
||||
# define PICO_ARP_REPLY 0x0002
|
||||
# define PICO_ARP_HTYPE_ETH 0x0001
|
||||
|
||||
#define short_be(x) (x)
|
||||
#define long_be(x) (x)
|
||||
#define long_long_be(x) (x)
|
||||
|
||||
static inline uint16_t short_from(void *_p)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)_p;
|
||||
uint16_t r, p0, p1;
|
||||
p0 = p[0];
|
||||
p1 = p[1];
|
||||
r = (p0 << 8) + p1;
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline uint32_t long_from(void *_p)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)_p;
|
||||
uint32_t r, p0, p1, p2, p3;
|
||||
p0 = p[0];
|
||||
p1 = p[1];
|
||||
p2 = p[2];
|
||||
p3 = p[3];
|
||||
r = (p0 << 24) + (p1 << 16) + (p2 << 8) + p3;
|
||||
return r;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline uint16_t short_from(void *_p)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)_p;
|
||||
uint16_t r, _p0, _p1;
|
||||
_p0 = p[0];
|
||||
_p1 = p[1];
|
||||
r = (uint16_t)((_p1 << 8u) + _p0);
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline uint32_t long_from(void *_p)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)_p;
|
||||
uint32_t r, _p0, _p1, _p2, _p3;
|
||||
_p0 = p[0];
|
||||
_p1 = p[1];
|
||||
_p2 = p[2];
|
||||
_p3 = p[3];
|
||||
r = (_p3 << 24) + (_p2 << 16) + (_p1 << 8) + _p0;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
# define PICO_IDETH_IPV4 0x0008
|
||||
# define PICO_IDETH_ARP 0x0608
|
||||
# define PICO_IDETH_IPV6 0xDD86
|
||||
|
||||
# define PICO_ARP_REQUEST 0x0100
|
||||
# define PICO_ARP_REPLY 0x0200
|
||||
# define PICO_ARP_HTYPE_ETH 0x0100
|
||||
|
||||
# ifndef BYTESWAP_GCC
|
||||
static inline uint16_t short_be(uint16_t le)
|
||||
{
|
||||
return (uint16_t)(((le & 0xFFu) << 8) | ((le >> 8u) & 0xFFu));
|
||||
}
|
||||
|
||||
static inline uint32_t long_be(uint32_t le)
|
||||
{
|
||||
uint8_t *b = (uint8_t *)≤
|
||||
uint32_t be = 0;
|
||||
uint32_t b0, b1, b2;
|
||||
b0 = b[0];
|
||||
b1 = b[1];
|
||||
b2 = b[2];
|
||||
be = b[3] + (b2 << 8) + (b1 << 16) + (b0 << 24);
|
||||
return be;
|
||||
}
|
||||
static inline uint64_t long_long_be(uint64_t le)
|
||||
{
|
||||
uint8_t *b = (uint8_t *)≤
|
||||
uint64_t be = 0;
|
||||
uint64_t b0, b1, b2, b3, b4, b5, b6;
|
||||
b0 = b[0];
|
||||
b1 = b[1];
|
||||
b2 = b[2];
|
||||
b3 = b[3];
|
||||
b4 = b[4];
|
||||
b5 = b[5];
|
||||
b6 = b[6];
|
||||
be = b[7] + (b6 << 8) + (b5 << 16) + (b4 << 24) + (b3 << 32) + (b2 << 40) + (b1 << 48) + (b0 << 56);
|
||||
return be;
|
||||
}
|
||||
# else
|
||||
/*
|
||||
extern uint32_t __builtin_bswap32(uint32_t);
|
||||
extern uint16_t __builtin_bswap16(uint16_t);
|
||||
extern uint64_t __builtin_bswap64(uint64_t);
|
||||
*/
|
||||
|
||||
static inline uint32_t long_be(uint32_t le)
|
||||
{
|
||||
return (uint32_t)__builtin_bswap32(le);
|
||||
}
|
||||
|
||||
static inline uint16_t short_be(uint16_t le)
|
||||
{
|
||||
return (uint16_t)__builtin_bswap16(le);
|
||||
}
|
||||
|
||||
static inline uint64_t long_long_be(uint64_t le)
|
||||
{
|
||||
return (uint64_t)__builtin_bswap64(le);
|
||||
}
|
||||
|
||||
# endif /* BYTESWAP_GCC */
|
||||
#endif
|
||||
|
||||
|
||||
/* Mockables */
|
||||
#if defined UNIT_TEST
|
||||
# define MOCKABLE __attribute__((weak))
|
||||
#else
|
||||
# define MOCKABLE
|
||||
#endif
|
||||
|
||||
#include "pico_constants.h"
|
||||
#include "pico_mm.h"
|
||||
|
||||
#define IGNORE_PARAMETER(x) ((void)x)
|
||||
|
||||
#define PICO_MEM_DEFAULT_SLAB_SIZE 1600
|
||||
#define PICO_MEM_PAGE_SIZE 4096
|
||||
#define PICO_MEM_PAGE_LIFETIME 100
|
||||
#define PICO_MIN_HEAP_SIZE 600
|
||||
#define PICO_MIN_SLAB_SIZE 1200
|
||||
#define PICO_MAX_SLAB_SIZE 1600
|
||||
#define PICO_MEM_MINIMUM_OBJECT_SIZE 4
|
||||
|
||||
|
||||
/*** *** *** *** *** *** ***
|
||||
*** PLATFORM SPECIFIC ***
|
||||
*** *** *** *** *** *** ***/
|
||||
#if defined PICO_PORT_CUSTOM
|
||||
# include "pico_port.h"
|
||||
#elif defined CORTEX_M4_HARDFLOAT
|
||||
# include "arch/pico_cortex_m.h"
|
||||
#elif defined CORTEX_M4_SOFTFLOAT
|
||||
# include "arch/pico_cortex_m.h"
|
||||
#elif defined CORTEX_M3
|
||||
# include "arch/pico_cortex_m.h"
|
||||
#elif defined PIC24
|
||||
# include "arch/pico_pic24.h"
|
||||
#elif defined MSP430
|
||||
# include "arch/pico_msp430.h"
|
||||
#elif defined MBED_TEST
|
||||
# include "arch/pico_mbed.h"
|
||||
#elif defined AVR
|
||||
# include "arch/pico_avr.h"
|
||||
#elif defined ARM9
|
||||
# include "arch/pico_arm9.h"
|
||||
#elif defined ESP8266
|
||||
# include "arch/pico_esp8266.h"
|
||||
#elif defined MT7681
|
||||
# include "arch/pico_generic_gcc.h"
|
||||
#elif defined FAULTY
|
||||
# include "../test/pico_faulty.h"
|
||||
#elif defined ARCHNONE
|
||||
# include "arch/pico_none.h"
|
||||
#elif defined GENERIC
|
||||
# include "arch/pico_generic_gcc.h"
|
||||
#elif defined __KERNEL__
|
||||
# include "arch/pico_linux.h"
|
||||
/* #elif defined ... */
|
||||
#else
|
||||
# include "arch/pico_posix.h"
|
||||
#endif
|
||||
|
||||
#ifdef PICO_SUPPORT_MM
|
||||
#define PICO_ZALLOC(x) pico_mem_zalloc(x)
|
||||
#define PICO_FREE(x) pico_mem_free(x)
|
||||
#else
|
||||
#define PICO_ZALLOC(x) pico_zalloc(x)
|
||||
#define PICO_FREE(x) pico_free(x)
|
||||
#endif /* PICO_SUPPORT_MM */
|
||||
|
||||
#endif
|
||||
54
ext/picotcp/include/pico_constants.h
Normal file
54
ext/picotcp/include/pico_constants.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_CONST
|
||||
#define INCLUDE_PICO_CONST
|
||||
/* Included from pico_config.h */
|
||||
|
||||
/** Non-endian dependant constants */
|
||||
#define PICO_SIZE_IP4 4
|
||||
#define PICO_SIZE_IP6 16
|
||||
#define PICO_SIZE_ETH 6
|
||||
#define PICO_SIZE_TRANS 8
|
||||
|
||||
/** Endian-dependant constants **/
|
||||
typedef uint64_t pico_time;
|
||||
extern volatile uint64_t pico_tick;
|
||||
|
||||
|
||||
/*** *** *** *** *** *** ***
|
||||
*** ARP CONFIG ***
|
||||
*** *** *** *** *** *** ***/
|
||||
|
||||
#include "pico_addressing.h"
|
||||
|
||||
/* Maximum amount of accepted ARP requests per burst interval */
|
||||
#define PICO_ARP_MAX_RATE 1
|
||||
/* Duration of the burst interval in milliseconds */
|
||||
#define PICO_ARP_INTERVAL 1000
|
||||
|
||||
/* Add well-known host numbers here. (bigendian constants only beyond this point) */
|
||||
#define PICO_IP4_ANY (0x00000000U)
|
||||
#define PICO_IP4_BCAST (0xffffffffU)
|
||||
|
||||
/* defined in modules/pico_ipv6.c */
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
extern const uint8_t PICO_IPV6_ANY[PICO_SIZE_IP6];
|
||||
#endif
|
||||
|
||||
static inline uint32_t pico_hash(const void *buf, uint32_t size)
|
||||
{
|
||||
uint32_t hash = 5381;
|
||||
uint32_t i;
|
||||
const uint8_t *ptr = (const uint8_t *)buf;
|
||||
for(i = 0; i < size; i++)
|
||||
hash = ((hash << 5) + hash) + ptr[i]; /* hash * 33 + char */
|
||||
return hash;
|
||||
}
|
||||
|
||||
/* Debug */
|
||||
/* #define PICO_SUPPORT_DEBUG_MEMORY */
|
||||
/* #define PICO_SUPPORT_DEBUG_TOOLS */
|
||||
#endif
|
||||
60
ext/picotcp/include/pico_device.h
Normal file
60
ext/picotcp/include/pico_device.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_DEVICE
|
||||
#define INCLUDE_PICO_DEVICE
|
||||
#include "pico_queue.h"
|
||||
#include "pico_frame.h"
|
||||
#include "pico_addressing.h"
|
||||
#include "pico_tree.h"
|
||||
extern struct pico_tree Device_tree;
|
||||
#include "pico_ipv6_nd.h"
|
||||
#define MAX_DEVICE_NAME 16
|
||||
|
||||
|
||||
struct pico_ethdev {
|
||||
struct pico_eth mac;
|
||||
};
|
||||
|
||||
struct pico_device {
|
||||
char name[MAX_DEVICE_NAME];
|
||||
uint32_t hash;
|
||||
uint32_t overhead;
|
||||
uint32_t mtu;
|
||||
struct pico_ethdev *eth; /* Null if non-ethernet */
|
||||
struct pico_queue *q_in;
|
||||
struct pico_queue *q_out;
|
||||
int (*link_state)(struct pico_device *self);
|
||||
int (*send)(struct pico_device *self, void *buf, int len); /* Send function. Return 0 if busy */
|
||||
int (*poll)(struct pico_device *self, int loop_score);
|
||||
void (*destroy)(struct pico_device *self);
|
||||
int (*dsr)(struct pico_device *self, int loop_score);
|
||||
int __serving_interrupt;
|
||||
/* used to signal the upper layer the number of events arrived since the last processing */
|
||||
volatile int eventCnt;
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
struct pico_nd_hostvars hostvars;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int pico_device_init(struct pico_device *dev, const char *name, uint8_t *mac);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
void pico_device_destroy(struct pico_device *dev);
|
||||
int pico_devices_loop(int loop_score, int direction);
|
||||
struct pico_device*pico_get_device(const char*name);
|
||||
int32_t pico_device_broadcast(struct pico_frame *f);
|
||||
int pico_device_link_state(struct pico_device *dev);
|
||||
int pico_device_ipv6_random_ll(struct pico_device *dev);
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
21
ext/picotcp/include/pico_eth.h
Normal file
21
ext/picotcp/include/pico_eth.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_ETH
|
||||
#define INCLUDE_PICO_ETH
|
||||
#include "pico_addressing.h"
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_ipv6.h"
|
||||
|
||||
|
||||
PACKED_STRUCT_DEF pico_eth_hdr {
|
||||
uint8_t daddr[6];
|
||||
uint8_t saddr[6];
|
||||
uint16_t proto;
|
||||
};
|
||||
|
||||
#define PICO_SIZE_ETHHDR 14
|
||||
|
||||
#endif
|
||||
122
ext/picotcp/include/pico_frame.h
Normal file
122
ext/picotcp/include/pico_frame.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_FRAME
|
||||
#define INCLUDE_PICO_FRAME
|
||||
#include "pico_config.h"
|
||||
|
||||
|
||||
#define PICO_FRAME_FLAG_BCAST (0x01)
|
||||
#define PICO_FRAME_FLAG_EXT_BUFFER (0x02)
|
||||
#define PICO_FRAME_FLAG_EXT_USAGE_COUNTER (0x04)
|
||||
#define PICO_FRAME_FLAG_SACKED (0x80)
|
||||
#define IS_BCAST(f) ((f->flags & PICO_FRAME_FLAG_BCAST) == PICO_FRAME_FLAG_BCAST)
|
||||
|
||||
|
||||
struct pico_socket;
|
||||
|
||||
|
||||
struct pico_frame {
|
||||
|
||||
/* Connector for queues */
|
||||
struct pico_frame *next;
|
||||
|
||||
/* Start of the whole buffer, total frame length. */
|
||||
unsigned char *buffer;
|
||||
uint32_t buffer_len;
|
||||
|
||||
/* For outgoing packets: this is the meaningful buffer. */
|
||||
unsigned char *start;
|
||||
uint32_t len;
|
||||
|
||||
/* Pointer to usage counter */
|
||||
uint32_t *usage_count;
|
||||
|
||||
/* Pointer to protocol headers */
|
||||
uint8_t *datalink_hdr;
|
||||
|
||||
uint8_t *net_hdr;
|
||||
uint16_t net_len;
|
||||
uint8_t *transport_hdr;
|
||||
uint16_t transport_len;
|
||||
uint8_t *app_hdr;
|
||||
uint16_t app_len;
|
||||
|
||||
/* Pointer to the phisical device this packet belongs to.
|
||||
* Should be valid in both routing directions
|
||||
*/
|
||||
struct pico_device *dev;
|
||||
|
||||
pico_time timestamp;
|
||||
|
||||
/* Failures due to bad datalink addressing. */
|
||||
uint16_t failure_count;
|
||||
|
||||
/* Protocol over IP */
|
||||
uint8_t proto;
|
||||
|
||||
/* PICO_FRAME_FLAG_* */
|
||||
uint8_t flags;
|
||||
|
||||
/* Pointer to payload */
|
||||
unsigned char *payload;
|
||||
uint16_t payload_len;
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV4FRAG) || defined(PICO_SUPPORT_IPV6FRAG)
|
||||
/* Payload fragmentation info */
|
||||
uint16_t frag;
|
||||
#endif
|
||||
|
||||
/* Pointer to socket */
|
||||
struct pico_socket *sock;
|
||||
|
||||
/* Pointer to transport info, used to store remote UDP endpoint (IP + port) */
|
||||
void *info;
|
||||
|
||||
/*Priority. "best-effort" priority, the default value is 0. Priority can be in between -10 and +10*/
|
||||
int8_t priority;
|
||||
uint8_t transport_flags_saved;
|
||||
|
||||
/* 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 **/
|
||||
void pico_frame_discard(struct pico_frame *f);
|
||||
struct pico_frame *pico_frame_copy(struct pico_frame *f);
|
||||
struct pico_frame *pico_frame_deepcopy(struct pico_frame *f);
|
||||
struct pico_frame *pico_frame_alloc(uint32_t size);
|
||||
int pico_frame_grow(struct pico_frame *f, uint32_t size);
|
||||
struct pico_frame *pico_frame_alloc_skeleton(uint32_t size, int ext_buffer);
|
||||
int pico_frame_skeleton_set_buffer(struct pico_frame *f, void *buf);
|
||||
uint16_t pico_checksum(void *inbuf, uint32_t len);
|
||||
uint16_t pico_dualbuffer_checksum(void *b1, uint32_t len1, void *b2, uint32_t len2);
|
||||
|
||||
static inline int pico_is_digit(char c)
|
||||
{
|
||||
if (c < '0' || c > '9')
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int pico_is_hex(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return 1;
|
||||
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return 1;
|
||||
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
17
ext/picotcp/include/pico_md5.h
Normal file
17
ext/picotcp/include/pico_md5.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*********************************************************************
|
||||
* PicoTCP. Copyright (c) 2015 Altran Intelligent Systems. Some rights reserved.
|
||||
* See LICENSE and COPYING for usage.
|
||||
*
|
||||
* Authors: Daniele Lacamera
|
||||
* *********************************************************************/
|
||||
|
||||
#ifndef PICO_MD5_INCLUDE
|
||||
#define PICO_MD5_INCLUDE
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void pico_md5sum(uint8_t *dst, const uint8_t *src, size_t len);
|
||||
void pico_register_md5sum(void (*md5)(uint8_t *, const uint8_t *, size_t));
|
||||
|
||||
#endif /* PICO_MD5_INCLUDE */
|
||||
33
ext/picotcp/include/pico_module_eth.h
Normal file
33
ext/picotcp/include/pico_module_eth.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef PICO_MODULE_IPV4_H
|
||||
#define PICO_MODULE_IPV4_H
|
||||
|
||||
struct pico_arp_entry {
|
||||
struct eth dest;
|
||||
#ifdef PICO_CONFIG_IPV4
|
||||
struct ipv4 addr_ipv4;
|
||||
#endif
|
||||
RB_ENTRY(pico_arp_entry) node;
|
||||
};
|
||||
|
||||
/* Configured device */
|
||||
struct pico_eth_link {
|
||||
struct pico_device *dev;
|
||||
struct eth address;
|
||||
struct eth netmask;
|
||||
RB_ENTRY(pico_eth_link) node;
|
||||
};
|
||||
|
||||
#ifndef IS_MODULE_ETH
|
||||
# define _mod extern
|
||||
#else
|
||||
# define _mod
|
||||
#endif
|
||||
_mod struct pico_module pico_module_eth;
|
||||
#undef _mod
|
||||
|
||||
#endif
|
||||
95
ext/picotcp/include/pico_protocol.h
Normal file
95
ext/picotcp/include/pico_protocol.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_PROTOCOL
|
||||
#define INCLUDE_PICO_PROTOCOL
|
||||
#include "pico_config.h"
|
||||
#include "pico_queue.h"
|
||||
|
||||
#define PICO_LOOP_DIR_IN 1
|
||||
#define PICO_LOOP_DIR_OUT 2
|
||||
|
||||
enum pico_layer {
|
||||
PICO_LAYER_DATALINK = 2, /* Ethernet only. */
|
||||
PICO_LAYER_NETWORK = 3, /* IPv4, IPv6, ARP. Arp is there because it communicates with L2 */
|
||||
PICO_LAYER_TRANSPORT = 4, /* UDP, TCP, ICMP */
|
||||
PICO_LAYER_SOCKET = 5 /* Socket management */
|
||||
};
|
||||
|
||||
enum pico_err_e {
|
||||
PICO_ERR_NOERR = 0,
|
||||
PICO_ERR_EPERM = 1,
|
||||
PICO_ERR_ENOENT = 2,
|
||||
/* ... */
|
||||
PICO_ERR_EINTR = 4,
|
||||
PICO_ERR_EIO = 5,
|
||||
PICO_ERR_ENXIO = 6,
|
||||
/* ... */
|
||||
PICO_ERR_EAGAIN = 11,
|
||||
PICO_ERR_ENOMEM = 12,
|
||||
PICO_ERR_EACCESS = 13,
|
||||
PICO_ERR_EFAULT = 14,
|
||||
/* ... */
|
||||
PICO_ERR_EBUSY = 16,
|
||||
PICO_ERR_EEXIST = 17,
|
||||
/* ... */
|
||||
PICO_ERR_EINVAL = 22,
|
||||
/* ... */
|
||||
PICO_ERR_ENONET = 64,
|
||||
/* ... */
|
||||
PICO_ERR_EPROTO = 71,
|
||||
/* ... */
|
||||
PICO_ERR_ENOPROTOOPT = 92,
|
||||
PICO_ERR_EPROTONOSUPPORT = 93,
|
||||
/* ... */
|
||||
PICO_ERR_EOPNOTSUPP = 95,
|
||||
PICO_ERR_EADDRINUSE = 98,
|
||||
PICO_ERR_EADDRNOTAVAIL = 99,
|
||||
PICO_ERR_ENETDOWN = 100,
|
||||
PICO_ERR_ENETUNREACH = 101,
|
||||
/* ... */
|
||||
PICO_ERR_ECONNRESET = 104,
|
||||
/* ... */
|
||||
PICO_ERR_EISCONN = 106,
|
||||
PICO_ERR_ENOTCONN = 107,
|
||||
PICO_ERR_ESHUTDOWN = 108,
|
||||
/* ... */
|
||||
PICO_ERR_ETIMEDOUT = 110,
|
||||
PICO_ERR_ECONNREFUSED = 111,
|
||||
PICO_ERR_EHOSTDOWN = 112,
|
||||
PICO_ERR_EHOSTUNREACH = 113,
|
||||
};
|
||||
|
||||
typedef enum pico_err_e pico_err_t;
|
||||
extern volatile pico_err_t pico_err;
|
||||
|
||||
#define IS_IPV6(f) (f && f->net_hdr && ((((uint8_t *)(f->net_hdr))[0] & 0xf0) == 0x60))
|
||||
#define IS_IPV4(f) (f && f->net_hdr && ((((uint8_t *)(f->net_hdr))[0] & 0xf0) == 0x40))
|
||||
|
||||
#define MAX_PROTOCOL_NAME 16
|
||||
|
||||
struct pico_protocol {
|
||||
char name[MAX_PROTOCOL_NAME];
|
||||
uint32_t hash;
|
||||
enum pico_layer layer;
|
||||
uint16_t proto_number;
|
||||
struct pico_queue *q_in;
|
||||
struct pico_queue *q_out;
|
||||
struct pico_frame *(*alloc)(struct pico_protocol *self, uint16_t size); /* Frame allocation. */
|
||||
int (*push)(struct pico_protocol *self, struct pico_frame *p); /* Push function, for active outgoing pkts from above */
|
||||
int (*process_out)(struct pico_protocol *self, struct pico_frame *p); /* Send loop. */
|
||||
int (*process_in)(struct pico_protocol *self, struct pico_frame *p); /* Recv loop. */
|
||||
uint16_t (*get_mtu)(struct pico_protocol *self);
|
||||
};
|
||||
|
||||
int pico_protocols_loop(int loop_score);
|
||||
void pico_protocol_init(struct pico_protocol *p);
|
||||
|
||||
int pico_protocol_datalink_loop(int loop_score, int direction);
|
||||
int pico_protocol_network_loop(int loop_score, int direction);
|
||||
int pico_protocol_transport_loop(int loop_score, int direction);
|
||||
int pico_protocol_socket_loop(int loop_score, int direction);
|
||||
|
||||
#endif
|
||||
166
ext/picotcp/include/pico_queue.h
Normal file
166
ext/picotcp/include/pico_queue.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_QUEUE
|
||||
#define INCLUDE_PICO_QUEUE
|
||||
#include "pico_config.h"
|
||||
#include "pico_frame.h"
|
||||
|
||||
#define Q_LIMIT 0
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
void *pico_mutex_init(void);
|
||||
void pico_mutex_deinit(void *mutex);
|
||||
void pico_mutex_lock(void *mutex);
|
||||
int pico_mutex_lock_timeout(void *mutex, int timeout);
|
||||
void pico_mutex_unlock(void *mutex);
|
||||
void pico_mutex_unlock_ISR(void *mutex);
|
||||
|
||||
struct pico_queue {
|
||||
uint32_t frames;
|
||||
uint32_t size;
|
||||
uint32_t max_frames;
|
||||
uint32_t max_size;
|
||||
struct pico_frame *head;
|
||||
struct pico_frame *tail;
|
||||
#ifdef PICO_SUPPORT_MUTEX
|
||||
void *mutex;
|
||||
#endif
|
||||
uint8_t shared;
|
||||
uint16_t overhead;
|
||||
};
|
||||
|
||||
#ifdef PICO_SUPPORT_MUTEX
|
||||
#define PICOTCP_MUTEX_LOCK(x) { \
|
||||
if (x == NULL) \
|
||||
x = pico_mutex_init(); \
|
||||
pico_mutex_lock(x); \
|
||||
}
|
||||
#define PICOTCP_MUTEX_UNLOCK(x) pico_mutex_unlock(x)
|
||||
#define PICOTCP_MUTEX_DEL(x) pico_mutex_deinit(x)
|
||||
|
||||
#else
|
||||
#define PICOTCP_MUTEX_LOCK(x) do {} while(0)
|
||||
#define PICOTCP_MUTEX_UNLOCK(x) do {} while(0)
|
||||
#define PICOTCP_MUTEX_DEL(x) do {} while(0)
|
||||
#endif
|
||||
|
||||
#ifdef PICO_SUPPORT_DEBUG_TOOLS
|
||||
static void debug_q(struct pico_queue *q)
|
||||
{
|
||||
struct pico_frame *p = q->head;
|
||||
dbg("%d: ", q->frames);
|
||||
while(p) {
|
||||
dbg("(%p)-->", p);
|
||||
p = p->next;
|
||||
}
|
||||
dbg("X\n");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define debug_q(x) do {} while(0)
|
||||
#endif
|
||||
|
||||
static inline int32_t pico_enqueue(struct pico_queue *q, struct pico_frame *p)
|
||||
{
|
||||
if ((q->max_frames) && (q->max_frames <= q->frames))
|
||||
return -1;
|
||||
|
||||
#if (Q_LIMIT != 0)
|
||||
if ((Q_LIMIT < p->buffer_len + q->size))
|
||||
return -1;
|
||||
|
||||
#endif
|
||||
|
||||
if ((q->max_size) && (q->max_size < (p->buffer_len + q->size)))
|
||||
return -1;
|
||||
|
||||
if (q->shared)
|
||||
PICOTCP_MUTEX_LOCK(q->mutex);
|
||||
|
||||
p->next = NULL;
|
||||
if (!q->head) {
|
||||
q->head = p;
|
||||
q->tail = p;
|
||||
q->size = 0;
|
||||
q->frames = 0;
|
||||
} else {
|
||||
q->tail->next = p;
|
||||
q->tail = p;
|
||||
}
|
||||
|
||||
q->size += p->buffer_len + q->overhead;
|
||||
q->frames++;
|
||||
debug_q(q);
|
||||
|
||||
if (q->shared)
|
||||
PICOTCP_MUTEX_UNLOCK(q->mutex);
|
||||
|
||||
return (int32_t)q->size;
|
||||
}
|
||||
|
||||
static inline struct pico_frame *pico_dequeue(struct pico_queue *q)
|
||||
{
|
||||
struct pico_frame *p = q->head;
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (q->frames < 1)
|
||||
return NULL;
|
||||
|
||||
if (q->shared)
|
||||
PICOTCP_MUTEX_LOCK(q->mutex);
|
||||
|
||||
q->head = p->next;
|
||||
q->frames--;
|
||||
q->size -= p->buffer_len - q->overhead;
|
||||
if (q->head == NULL)
|
||||
q->tail = NULL;
|
||||
|
||||
debug_q(q);
|
||||
|
||||
p->next = NULL;
|
||||
if (q->shared)
|
||||
PICOTCP_MUTEX_UNLOCK(q->mutex);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline struct pico_frame *pico_queue_peek(struct pico_queue *q)
|
||||
{
|
||||
struct pico_frame *p = q->head;
|
||||
if (q->frames < 1)
|
||||
return NULL;
|
||||
|
||||
debug_q(q);
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline void pico_queue_deinit(struct pico_queue *q)
|
||||
{
|
||||
if (q->shared) {
|
||||
PICOTCP_MUTEX_DEL(q->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pico_queue_empty(struct pico_queue *q)
|
||||
{
|
||||
struct pico_frame *p = pico_dequeue(q);
|
||||
while(p) {
|
||||
pico_frame_discard(p);
|
||||
p = pico_dequeue(q);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pico_queue_protect(struct pico_queue *q)
|
||||
{
|
||||
q->shared = 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
271
ext/picotcp/include/pico_socket.h
Normal file
271
ext/picotcp/include/pico_socket.h
Normal file
@@ -0,0 +1,271 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_SOCKET
|
||||
#define INCLUDE_PICO_SOCKET
|
||||
#include "pico_queue.h"
|
||||
#include "pico_addressing.h"
|
||||
#include "pico_config.h"
|
||||
#include "pico_protocol.h"
|
||||
#include "pico_tree.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#define PICO_DEFAULT_SOCKETQ (16 * 1024) /* Linux host, so we want full throttle */
|
||||
#else
|
||||
#define PICO_DEFAULT_SOCKETQ (6 * 1024) /* seems like an acceptable default for small embedded systems */
|
||||
#endif
|
||||
|
||||
#define PICO_SHUT_RD 1
|
||||
#define PICO_SHUT_WR 2
|
||||
#define PICO_SHUT_RDWR 3
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV4
|
||||
# define IS_SOCK_IPV4(s) ((s->net == &pico_proto_ipv4))
|
||||
#else
|
||||
# define IS_SOCK_IPV4(s) (0)
|
||||
#endif
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
# define IS_SOCK_IPV6(s) ((s->net == &pico_proto_ipv6))
|
||||
#else
|
||||
# define IS_SOCK_IPV6(s) (0)
|
||||
#endif
|
||||
|
||||
|
||||
struct pico_sockport
|
||||
{
|
||||
struct pico_tree socks; /* how you make the connection ? */
|
||||
uint16_t number;
|
||||
uint16_t proto;
|
||||
};
|
||||
|
||||
|
||||
struct pico_socket {
|
||||
struct pico_protocol *proto;
|
||||
struct pico_protocol *net;
|
||||
|
||||
union pico_address local_addr;
|
||||
union pico_address remote_addr;
|
||||
|
||||
uint16_t local_port;
|
||||
uint16_t remote_port;
|
||||
|
||||
struct pico_queue q_in;
|
||||
struct pico_queue q_out;
|
||||
|
||||
void (*wakeup)(uint16_t ev, struct pico_socket *s);
|
||||
|
||||
|
||||
#ifdef PICO_SUPPORT_TCP
|
||||
/* For the TCP backlog queue */
|
||||
struct pico_socket *backlog;
|
||||
struct pico_socket *next;
|
||||
struct pico_socket *parent;
|
||||
uint16_t max_backlog;
|
||||
uint16_t number_of_pending_conn;
|
||||
#endif
|
||||
#ifdef PICO_SUPPORT_MCAST
|
||||
struct pico_tree *MCASTListen;
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
struct pico_tree *MCASTListen_ipv6;
|
||||
#endif
|
||||
#endif
|
||||
uint16_t ev_pending;
|
||||
|
||||
struct pico_device *dev;
|
||||
|
||||
/* Private field. */
|
||||
int id;
|
||||
uint16_t state;
|
||||
uint16_t opt_flags;
|
||||
pico_time timestamp;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct pico_remote_endpoint {
|
||||
union pico_address remote_addr;
|
||||
uint16_t remote_port;
|
||||
};
|
||||
|
||||
|
||||
struct pico_ip_mreq {
|
||||
union pico_address mcast_group_addr;
|
||||
union pico_address mcast_link_addr;
|
||||
};
|
||||
struct pico_ip_mreq_source {
|
||||
union pico_address mcast_group_addr;
|
||||
union pico_address mcast_source_addr;
|
||||
union pico_address mcast_link_addr;
|
||||
};
|
||||
|
||||
|
||||
#define PICO_SOCKET_STATE_UNDEFINED 0x0000u
|
||||
#define PICO_SOCKET_STATE_SHUT_LOCAL 0x0001u
|
||||
#define PICO_SOCKET_STATE_SHUT_REMOTE 0x0002u
|
||||
#define PICO_SOCKET_STATE_BOUND 0x0004u
|
||||
#define PICO_SOCKET_STATE_CONNECTED 0x0008u
|
||||
#define PICO_SOCKET_STATE_CLOSING 0x0010u
|
||||
#define PICO_SOCKET_STATE_CLOSED 0x0020u
|
||||
|
||||
# define PICO_SOCKET_STATE_TCP 0xFF00u
|
||||
# define PICO_SOCKET_STATE_TCP_UNDEF 0x00FFu
|
||||
# define PICO_SOCKET_STATE_TCP_CLOSED 0x0100u
|
||||
# define PICO_SOCKET_STATE_TCP_LISTEN 0x0200u
|
||||
# define PICO_SOCKET_STATE_TCP_SYN_SENT 0x0300u
|
||||
# define PICO_SOCKET_STATE_TCP_SYN_RECV 0x0400u
|
||||
# define PICO_SOCKET_STATE_TCP_ESTABLISHED 0x0500u
|
||||
# define PICO_SOCKET_STATE_TCP_CLOSE_WAIT 0x0600u
|
||||
# define PICO_SOCKET_STATE_TCP_LAST_ACK 0x0700u
|
||||
# define PICO_SOCKET_STATE_TCP_FIN_WAIT1 0x0800u
|
||||
# define PICO_SOCKET_STATE_TCP_FIN_WAIT2 0x0900u
|
||||
# define PICO_SOCKET_STATE_TCP_CLOSING 0x0a00u
|
||||
# define PICO_SOCKET_STATE_TCP_TIME_WAIT 0x0b00u
|
||||
# define PICO_SOCKET_STATE_TCP_ARRAYSIZ 0x0cu
|
||||
|
||||
|
||||
/* Socket options */
|
||||
# define PICO_TCP_NODELAY 1
|
||||
# define PICO_SOCKET_OPT_TCPNODELAY 0x0000u
|
||||
|
||||
# define PICO_IP_MULTICAST_EXCLUDE 0
|
||||
# define PICO_IP_MULTICAST_INCLUDE 1
|
||||
# define PICO_IP_MULTICAST_IF 32
|
||||
# define PICO_IP_MULTICAST_TTL 33
|
||||
# define PICO_IP_MULTICAST_LOOP 34
|
||||
# define PICO_IP_ADD_MEMBERSHIP 35
|
||||
# define PICO_IP_DROP_MEMBERSHIP 36
|
||||
# define PICO_IP_UNBLOCK_SOURCE 37
|
||||
# define PICO_IP_BLOCK_SOURCE 38
|
||||
# define PICO_IP_ADD_SOURCE_MEMBERSHIP 39
|
||||
# define PICO_IP_DROP_SOURCE_MEMBERSHIP 40
|
||||
|
||||
# define PICO_SOCKET_OPT_MULTICAST_LOOP 1
|
||||
# define PICO_SOCKET_OPT_KEEPIDLE 4
|
||||
# define PICO_SOCKET_OPT_KEEPINTVL 5
|
||||
# define PICO_SOCKET_OPT_KEEPCNT 6
|
||||
|
||||
#define PICO_SOCKET_OPT_LINGER 13
|
||||
|
||||
# define PICO_SOCKET_OPT_RCVBUF 52
|
||||
# define PICO_SOCKET_OPT_SNDBUF 53
|
||||
|
||||
|
||||
/* Constants */
|
||||
# define PICO_IP_DEFAULT_MULTICAST_TTL 1
|
||||
# define PICO_IP_DEFAULT_MULTICAST_LOOP 1
|
||||
|
||||
#define PICO_SOCKET_TIMEOUT 5000u /* 5 seconds */
|
||||
#define PICO_SOCKET_LINGER_TIMEOUT 3000u /* 3 seconds */
|
||||
#define PICO_SOCKET_BOUND_TIMEOUT 30000u /* 30 seconds */
|
||||
|
||||
#define PICO_SOCKET_SHUTDOWN_WRITE 0x01u
|
||||
#define PICO_SOCKET_SHUTDOWN_READ 0x02u
|
||||
#define TCPSTATE(s) ((s)->state & PICO_SOCKET_STATE_TCP)
|
||||
|
||||
#define PICO_SOCK_EV_RD 1u
|
||||
#define PICO_SOCK_EV_WR 2u
|
||||
#define PICO_SOCK_EV_CONN 4u
|
||||
#define PICO_SOCK_EV_CLOSE 8u
|
||||
#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;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *s));
|
||||
|
||||
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);
|
||||
|
||||
struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port);
|
||||
int8_t pico_socket_del(struct pico_socket *s);
|
||||
|
||||
int pico_socket_setoption(struct pico_socket *s, int option, void *value);
|
||||
int pico_socket_getoption(struct pico_socket *s, int option, void *value);
|
||||
|
||||
int pico_socket_shutdown(struct pico_socket *s, int mode);
|
||||
int pico_socket_close(struct pico_socket *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, uint16_t len);
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV4
|
||||
# define is_sock_ipv4(x) (x->net == &pico_proto_ipv4)
|
||||
#else
|
||||
# define is_sock_ipv4(x) (0)
|
||||
#endif
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
# define is_sock_ipv6(x) (x->net == &pico_proto_ipv6)
|
||||
#else
|
||||
# define is_sock_ipv6(x) (0)
|
||||
#endif
|
||||
|
||||
#ifdef PICO_SUPPORT_UDP
|
||||
# define is_sock_udp(x) (x->proto == &pico_proto_udp)
|
||||
#else
|
||||
# define is_sock_udp(x) (0)
|
||||
#endif
|
||||
|
||||
#ifdef PICO_SUPPORT_TCP
|
||||
# define is_sock_tcp(x) (x->proto == &pico_proto_tcp)
|
||||
#else
|
||||
# define is_sock_tcp(x) (0)
|
||||
#endif
|
||||
|
||||
/* Interface towards transport protocol */
|
||||
int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f);
|
||||
struct pico_socket *pico_socket_clone(struct pico_socket *facsimile);
|
||||
int8_t pico_socket_add(struct pico_socket *s);
|
||||
int pico_transport_error(struct pico_frame *f, uint8_t proto, int code);
|
||||
|
||||
/* Socket loop */
|
||||
int pico_sockets_loop(int loop_score);
|
||||
struct pico_socket*pico_sockets_find(uint16_t local, uint16_t remote);
|
||||
/* Port check */
|
||||
int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net);
|
||||
|
||||
struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port);
|
||||
|
||||
uint32_t pico_socket_get_mss(struct pico_socket *s);
|
||||
int pico_socket_set_family(struct pico_socket *s, uint16_t family);
|
||||
|
||||
int pico_count_sockets(uint8_t proto);
|
||||
|
||||
#define PICO_SOCKET_SETOPT_EN(socket, index) (socket->opt_flags |= (1 << index))
|
||||
#define PICO_SOCKET_SETOPT_DIS(socket, index) (socket->opt_flags &= (uint16_t) ~(1 << index))
|
||||
#define PICO_SOCKET_GETOPT(socket, index) ((socket->opt_flags & (1u << index)) != 0)
|
||||
|
||||
|
||||
#endif
|
||||
10
ext/picotcp/include/pico_socket_multicast.h
Normal file
10
ext/picotcp/include/pico_socket_multicast.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef PICO_SOCKET_MULTICAST_H
|
||||
#define PICO_SOCKET_MULTICAST_H
|
||||
int pico_socket_mcast_filter(struct pico_socket *s, union pico_address *mcast_group, union pico_address *src);
|
||||
void pico_multicast_delete(struct pico_socket *s);
|
||||
int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value);
|
||||
int pico_getsockopt_mcast(struct pico_socket *s, int option, void *value);
|
||||
int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl);
|
||||
int pico_udp_set_mc_ttl(struct pico_socket *s, void *_ttl);
|
||||
|
||||
#endif
|
||||
93
ext/picotcp/include/pico_stack.h
Normal file
93
ext/picotcp/include/pico_stack.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_STACK
|
||||
#define INCLUDE_PICO_STACK
|
||||
|
||||
#include "pico_config.h"
|
||||
#include "pico_frame.h"
|
||||
|
||||
#define PICO_MAX_TIMERS 20
|
||||
|
||||
#define PICO_ETH_MRU (1514u)
|
||||
#define PICO_IP_MRU (1500u)
|
||||
|
||||
/* ===== RECEIVING FUNCTIONS (from dev up to socket) ===== */
|
||||
|
||||
/* TRANSPORT LEVEL */
|
||||
/* interface towards network */
|
||||
int32_t pico_transport_receive(struct pico_frame *f, uint8_t proto);
|
||||
|
||||
/* NETWORK LEVEL */
|
||||
/* interface towards ethernet */
|
||||
int32_t pico_network_receive(struct pico_frame *f);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* LOWEST LEVEL: interface towards devices. */
|
||||
/* Device driver will call this function which returns immediately.
|
||||
* Incoming packet will be processed later on in the dev loop.
|
||||
* The zerocopy version will associate the current buffer to the newly created frame.
|
||||
* Warning: the buffer used in the zerocopy version MUST have been allocated using PICO_ZALLOC()
|
||||
*/
|
||||
int32_t pico_stack_recv(struct pico_device *dev, uint8_t *buffer, uint32_t len);
|
||||
int32_t pico_stack_recv_zerocopy(struct pico_device *dev, uint8_t *buffer, uint32_t len);
|
||||
int32_t pico_stack_recv_zerocopy_ext_buffer(struct pico_device *dev, uint8_t *buffer, uint32_t len);
|
||||
int32_t pico_stack_recv_zerocopy_ext_buffer_notify(struct pico_device *dev, uint8_t *buffer, uint32_t len, void (*notify_free)(uint8_t *buffer));
|
||||
|
||||
/* ===== SENDING FUNCTIONS (from socket down to dev) ===== */
|
||||
|
||||
int32_t pico_network_send(struct pico_frame *f);
|
||||
int32_t pico_sendto_dev(struct pico_frame *f);
|
||||
|
||||
#ifdef PICO_SUPPORT_ETH
|
||||
int32_t pico_ethernet_send(struct pico_frame *f);
|
||||
|
||||
/* The pico_ethernet_receive() function is used by
|
||||
* those devices supporting ETH in order to push packets up
|
||||
* into the stack.
|
||||
*/
|
||||
/* DATALINK LEVEL */
|
||||
int32_t pico_ethernet_receive(struct pico_frame *f);
|
||||
#else
|
||||
/* When ETH is not supported by the stack... */
|
||||
# define pico_ethernet_send(f) (-1)
|
||||
# define pico_ethernet_receive(f) (-1)
|
||||
#endif
|
||||
|
||||
/* ----- Initialization ----- */
|
||||
int pico_stack_init(void);
|
||||
|
||||
/* ----- Loop Function. ----- */
|
||||
void pico_stack_tick(void);
|
||||
void pico_stack_loop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ---- Notifications for stack errors */
|
||||
int pico_notify_socket_unreachable(struct pico_frame *f);
|
||||
int pico_notify_proto_unreachable(struct pico_frame *f);
|
||||
int pico_notify_dest_unreachable(struct pico_frame *f);
|
||||
int pico_notify_ttl_expired(struct pico_frame *f);
|
||||
int pico_notify_frag_expired(struct pico_frame *f);
|
||||
int pico_notify_pkt_too_big(struct pico_frame *f);
|
||||
|
||||
/* Various. */
|
||||
int pico_source_is_local(struct pico_frame *f);
|
||||
int pico_frame_dst_is_unicast(struct pico_frame *f);
|
||||
void pico_store_network_origin(void *src, struct pico_frame *f);
|
||||
uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg);
|
||||
void pico_timer_cancel(uint32_t id);
|
||||
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
|
||||
93
ext/picotcp/include/pico_tree.h
Normal file
93
ext/picotcp/include/pico_tree.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Author: Andrei Carp <andrei.carp@tass.be>
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef PICO_RBTREE_H
|
||||
#define PICO_RBTREE_H
|
||||
|
||||
#include "pico_config.h"
|
||||
|
||||
/* This is used to declare a new tree, leaf root by default */
|
||||
#define PICO_TREE_DECLARE(name, compareFunction) \
|
||||
struct pico_tree name = \
|
||||
{ \
|
||||
&LEAF, \
|
||||
compareFunction \
|
||||
}
|
||||
|
||||
#define USE_PICO_PAGE0_ZALLOC (1)
|
||||
#define USE_PICO_ZALLOC (2)
|
||||
|
||||
struct pico_tree_node
|
||||
{
|
||||
void*keyValue; /* generic key */
|
||||
struct pico_tree_node*parent;
|
||||
struct pico_tree_node*leftChild;
|
||||
struct pico_tree_node*rightChild;
|
||||
uint8_t color;
|
||||
};
|
||||
|
||||
struct pico_tree
|
||||
{
|
||||
struct pico_tree_node *root; /* root of the tree */
|
||||
|
||||
/* this function directly provides the keys as parameters not the nodes. */
|
||||
int (*compare)(void*keyA, void*keyB);
|
||||
};
|
||||
|
||||
extern struct pico_tree_node LEAF; /* generic leaf node */
|
||||
|
||||
#ifdef PICO_SUPPORT_MM
|
||||
void *pico_tree_insert_implementation(struct pico_tree *tree, void *key, uint8_t allocator);
|
||||
void *pico_tree_delete_implementation(struct pico_tree *tree, void *key, uint8_t allocator);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Manipulation functions
|
||||
*/
|
||||
void *pico_tree_insert(struct pico_tree *tree, void *key);
|
||||
void *pico_tree_delete(struct pico_tree *tree, void *key);
|
||||
void *pico_tree_findKey(struct pico_tree *tree, void *key);
|
||||
void pico_tree_drop(struct pico_tree *tree);
|
||||
int pico_tree_empty(struct pico_tree *tree);
|
||||
struct pico_tree_node *pico_tree_findNode(struct pico_tree *tree, void *key);
|
||||
|
||||
void *pico_tree_first(struct pico_tree *tree);
|
||||
void *pico_tree_last(struct pico_tree *tree);
|
||||
/*
|
||||
* Traverse functions
|
||||
*/
|
||||
struct pico_tree_node *pico_tree_lastNode(struct pico_tree_node *node);
|
||||
struct pico_tree_node *pico_tree_firstNode(struct pico_tree_node *node);
|
||||
struct pico_tree_node *pico_tree_next(struct pico_tree_node *node);
|
||||
struct pico_tree_node *pico_tree_prev(struct pico_tree_node *node);
|
||||
|
||||
/*
|
||||
* For each macros
|
||||
*/
|
||||
|
||||
#define pico_tree_foreach(idx, tree) \
|
||||
for ((idx) = pico_tree_firstNode((tree)->root); \
|
||||
(idx) != &LEAF; \
|
||||
(idx) = pico_tree_next(idx))
|
||||
|
||||
#define pico_tree_foreach_reverse(idx, tree) \
|
||||
for ((idx) = pico_tree_lastNode((tree)->root); \
|
||||
(idx) != &LEAF; \
|
||||
(idx) = pico_tree_prev(idx))
|
||||
|
||||
#define pico_tree_foreach_safe(idx, tree, idx2) \
|
||||
for ((idx) = pico_tree_firstNode((tree)->root); \
|
||||
((idx) != &LEAF) && ((idx2) = pico_tree_next(idx), 1); \
|
||||
(idx) = (idx2))
|
||||
|
||||
#define pico_tree_foreach_reverse_safe(idx, tree, idx2) \
|
||||
for ((idx) = pico_tree_lastNode((tree)->root); \
|
||||
((idx) != &LEAF) && ((idx2) = pico_tree_prev(idx), 1); \
|
||||
(idx) = (idx2))
|
||||
|
||||
#endif
|
||||
16
ext/picotcp/mkdeps.sh
Executable file
16
ext/picotcp/mkdeps.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
PREFIX=$1
|
||||
shift
|
||||
echo "/* PicoTCP - Definition file - DO NOT EDIT */" >$PREFIX/include/pico_defines.h
|
||||
echo "/* This file is automatically generated at compile time */" >>$PREFIX/include/pico_defines.h
|
||||
echo "#ifndef PICO_DEFINES_H" >>$PREFIX/include/pico_defines.h
|
||||
echo "#define PICO_DEFINES_H" >>$PREFIX/include/pico_defines.h
|
||||
echo >>$PREFIX/include/pico_defines.h
|
||||
|
||||
for i in $@; do
|
||||
if (echo $i | grep "^-D" |grep PICO_SUPPORT >/dev/null); then
|
||||
my_def=`echo $i |sed -e "s/-D//g"`
|
||||
echo "#define $my_def" >> $PREFIX/include/pico_defines.h
|
||||
fi
|
||||
done
|
||||
echo "#endif" >>$PREFIX/include/pico_defines.h
|
||||
50
ext/picotcp/modcheck.py
Executable file
50
ext/picotcp/modcheck.py
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/python
|
||||
import os,sys
|
||||
import subprocess
|
||||
|
||||
f = open('MODTREE')
|
||||
mods = {}
|
||||
commands = []
|
||||
|
||||
def get_deps(mod):
|
||||
if not mod in mods.keys():
|
||||
return []
|
||||
deps = mods[mod]
|
||||
retlist = [mod]
|
||||
for i in deps.split(' '):
|
||||
retlist.append(i)
|
||||
for j in get_deps(i):
|
||||
retlist.append(j)
|
||||
return retlist
|
||||
|
||||
|
||||
while(True):
|
||||
r = f.readline()
|
||||
if r == '':
|
||||
break
|
||||
if r != '\n':
|
||||
strings = r.split(':')
|
||||
mod = strings[0]
|
||||
deps = strings[1].rstrip('\n')
|
||||
mods[mod] = deps.strip(' ')
|
||||
|
||||
for k,v in mods.iteritems():
|
||||
command = 'make dummy '
|
||||
deps = get_deps(k)
|
||||
for i in mods.keys():
|
||||
if i in deps:
|
||||
command += i + "=1 "
|
||||
else:
|
||||
command += i + "=0 "
|
||||
commands.append(command)
|
||||
|
||||
nul = open('/dev/null', 'w')
|
||||
for i in commands:
|
||||
print 'Checking config:\n\t%s' % i
|
||||
os.system('make clean >/dev/null')
|
||||
args = i.split(' ')
|
||||
subprocess.call(['make','clean'], shell=True, stdout=nul, stderr=nul)
|
||||
subprocess.call(args[-1], shell=True,stdout=nul, stderr=nul)==0 or sys.exit(1)
|
||||
print "CONFIG OK!"
|
||||
print
|
||||
sys.exit(0)
|
||||
674
ext/picotcp/modules/pico_aodv.c
Normal file
674
ext/picotcp/modules/pico_aodv.c
Normal file
@@ -0,0 +1,674 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
Author: Daniele Lacamera <daniele.lacamera@altran.com>
|
||||
*********************************************************************/
|
||||
#include <pico_stack.h>
|
||||
#include <pico_tree.h>
|
||||
#include <pico_socket.h>
|
||||
#include <pico_aodv.h>
|
||||
#include <pico_device.h>
|
||||
|
||||
#include <pico_ipv4.h>
|
||||
#ifdef PICO_SUPPORT_IPV4
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
static 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 != (int)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 != (int)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 != (int)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;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int pico_aodv_init(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pico_aodv_add(struct pico_device *dev)
|
||||
{
|
||||
(void)dev;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pico_aodv_lookup(const union pico_address *addr)
|
||||
{
|
||||
(void)addr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void pico_aodv_refresh(const union pico_address *addr)
|
||||
{
|
||||
(void)addr;
|
||||
}
|
||||
|
||||
#endif
|
||||
130
ext/picotcp/modules/pico_aodv.h
Normal file
130
ext/picotcp/modules/pico_aodv.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
Author: Daniele Lacamera <daniele.lacamera@altran.com>
|
||||
*********************************************************************/
|
||||
#ifndef PICO_AODV_H_
|
||||
#define PICO_AODV_H_
|
||||
|
||||
/* 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
|
||||
537
ext/picotcp/modules/pico_arp.c
Normal file
537
ext/picotcp/modules/pico_arp.c
Normal file
@@ -0,0 +1,537 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include "pico_config.h"
|
||||
#include "pico_arp.h"
|
||||
#include "pico_tree.h"
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_device.h"
|
||||
#include "pico_stack.h"
|
||||
|
||||
extern const uint8_t PICO_ETHADDR_ALL[6];
|
||||
#define PICO_ARP_TIMEOUT 600000llu
|
||||
#define PICO_ARP_RETRY 300lu
|
||||
#define PICO_ARP_MAX_PENDING 5
|
||||
|
||||
#ifdef DEBUG_ARP
|
||||
#define arp_dbg dbg
|
||||
#else
|
||||
#define arp_dbg(...) do {} while(0)
|
||||
#endif
|
||||
|
||||
static int max_arp_reqs = PICO_ARP_MAX_RATE;
|
||||
static struct pico_frame *frames_queued[PICO_ARP_MAX_PENDING] = { 0 };
|
||||
|
||||
static void pico_arp_queued_trigger(void)
|
||||
{
|
||||
int i;
|
||||
struct pico_frame *f;
|
||||
for (i = 0; i < PICO_ARP_MAX_PENDING; i++)
|
||||
{
|
||||
f = frames_queued[i];
|
||||
if (f) {
|
||||
if (!pico_ethernet_send(f))
|
||||
{
|
||||
pico_frame_discard(f);
|
||||
frames_queued[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void update_max_arp_reqs(pico_time now, void *unused)
|
||||
{
|
||||
IGNORE_PARAMETER(now);
|
||||
IGNORE_PARAMETER(unused);
|
||||
if (max_arp_reqs < PICO_ARP_MAX_RATE)
|
||||
max_arp_reqs++;
|
||||
|
||||
pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL);
|
||||
}
|
||||
|
||||
void pico_arp_init(void)
|
||||
{
|
||||
pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL);
|
||||
}
|
||||
|
||||
PACKED_STRUCT_DEF pico_arp_hdr
|
||||
{
|
||||
uint16_t htype;
|
||||
uint16_t ptype;
|
||||
uint8_t hsize;
|
||||
uint8_t psize;
|
||||
uint16_t opcode;
|
||||
uint8_t s_mac[PICO_SIZE_ETH];
|
||||
struct pico_ip4 src;
|
||||
uint8_t d_mac[PICO_SIZE_ETH];
|
||||
struct pico_ip4 dst;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Callback handler for ip conflict service (e.g. IPv4 SLAAC)
|
||||
* Whenever the IP address registered here is seen in the network,
|
||||
* the callback is awaken to take countermeasures against IP collisions.
|
||||
*
|
||||
*/
|
||||
|
||||
struct arp_service_ipconflict {
|
||||
struct pico_eth mac;
|
||||
struct pico_ip4 ip;
|
||||
void (*conflict)(int);
|
||||
};
|
||||
|
||||
static struct arp_service_ipconflict conflict_ipv4;
|
||||
|
||||
|
||||
|
||||
#define PICO_SIZE_ARPHDR ((sizeof(struct pico_arp_hdr)))
|
||||
|
||||
/* Arp Entries for the tables. */
|
||||
struct pico_arp {
|
||||
/* CAREFUL MAN! ARP entry MUST begin with a pico_eth structure,
|
||||
* due to in-place casting!!! */
|
||||
struct pico_eth eth;
|
||||
struct pico_ip4 ipv4;
|
||||
int arp_status;
|
||||
pico_time timestamp;
|
||||
struct pico_device *dev;
|
||||
uint32_t timer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************/
|
||||
/** ARP TREE **/
|
||||
/*****************/
|
||||
|
||||
/* Routing destination */
|
||||
|
||||
static int arp_compare(void *ka, void *kb)
|
||||
{
|
||||
struct pico_arp *a = ka, *b = kb;
|
||||
return pico_ipv4_compare(&a->ipv4, &b->ipv4);
|
||||
}
|
||||
|
||||
PICO_TREE_DECLARE(arp_tree, arp_compare);
|
||||
|
||||
/*********************/
|
||||
/** END ARP TREE **/
|
||||
/*********************/
|
||||
|
||||
struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst)
|
||||
{
|
||||
struct pico_arp search, *found;
|
||||
search.ipv4.addr = dst->addr;
|
||||
found = pico_tree_findKey(&arp_tree, &search);
|
||||
if (found && (found->arp_status != PICO_ARP_STATUS_STALE))
|
||||
return &found->eth;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst)
|
||||
{
|
||||
struct pico_arp*search;
|
||||
struct pico_tree_node *index;
|
||||
pico_tree_foreach(index, &arp_tree){
|
||||
search = index->keyValue;
|
||||
if(memcmp(&(search->eth.addr), &dst->addr, 6) == 0)
|
||||
return &search->ipv4;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void pico_arp_unreachable(struct pico_ip4 *a)
|
||||
{
|
||||
int i;
|
||||
struct pico_frame *f;
|
||||
struct pico_ipv4_hdr *hdr;
|
||||
struct pico_ip4 dst;
|
||||
for (i = 0; i < PICO_ARP_MAX_PENDING; i++)
|
||||
{
|
||||
f = frames_queued[i];
|
||||
if (f) {
|
||||
hdr = (struct pico_ipv4_hdr *) f->net_hdr;
|
||||
dst = pico_ipv4_route_get_gateway(&hdr->dst);
|
||||
if (!dst.addr)
|
||||
dst.addr = hdr->dst.addr;
|
||||
|
||||
if (dst.addr == a->addr) {
|
||||
if (!pico_source_is_local(f)) {
|
||||
pico_notify_dest_unreachable(f);
|
||||
}
|
||||
|
||||
pico_frame_discard(f);
|
||||
frames_queued[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pico_arp_retry(struct pico_frame *f, struct pico_ip4 *where)
|
||||
{
|
||||
if (++f->failure_count < 4) {
|
||||
arp_dbg ("================= ARP REQUIRED: %d =============\n\n", f->failure_count);
|
||||
/* check if dst is local (gateway = 0), or if to use gateway */
|
||||
pico_arp_request(f->dev, where, PICO_ARP_QUERY);
|
||||
} else {
|
||||
pico_arp_unreachable(where);
|
||||
}
|
||||
}
|
||||
|
||||
struct pico_eth *pico_arp_get(struct pico_frame *f)
|
||||
{
|
||||
struct pico_eth *a4;
|
||||
struct pico_ip4 gateway;
|
||||
struct pico_ip4 *where;
|
||||
struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
|
||||
struct pico_ipv4_link *l;
|
||||
if (!hdr)
|
||||
return NULL;
|
||||
|
||||
l = pico_ipv4_link_get(&hdr->dst);
|
||||
if(l) {
|
||||
/* address belongs to ourself */
|
||||
return &l->dev->eth->mac;
|
||||
}
|
||||
|
||||
gateway = pico_ipv4_route_get_gateway(&hdr->dst);
|
||||
/* check if dst is local (gateway = 0), or if to use gateway */
|
||||
if (gateway.addr != 0)
|
||||
where = &gateway;
|
||||
else
|
||||
where = &hdr->dst;
|
||||
|
||||
a4 = pico_arp_lookup(where); /* check if dst ip mac in cache */
|
||||
|
||||
if (!a4)
|
||||
pico_arp_retry(f, where);
|
||||
|
||||
return a4;
|
||||
}
|
||||
|
||||
|
||||
void pico_arp_postpone(struct pico_frame *f)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < PICO_ARP_MAX_PENDING; i++)
|
||||
{
|
||||
if (!frames_queued[i]) {
|
||||
frames_queued[i] = pico_frame_copy(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Not possible to enqueue: caller will discard packet */
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_ARP
|
||||
void dbg_arp(void)
|
||||
{
|
||||
struct pico_arp *a;
|
||||
struct pico_tree_node *index;
|
||||
|
||||
pico_tree_foreach(index, &arp_tree) {
|
||||
a = index->keyValue;
|
||||
arp_dbg("ARP to %08x, mac: %02x:%02x:%02x:%02x:%02x:%02x\n", a->ipv4.addr, a->eth.addr[0], a->eth.addr[1], a->eth.addr[2], a->eth.addr[3], a->eth.addr[4], a->eth.addr[5] );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void arp_expire(pico_time now, void *_stale)
|
||||
{
|
||||
struct pico_arp *stale = (struct pico_arp *) _stale;
|
||||
if (now >= (stale->timestamp + PICO_ARP_TIMEOUT)) {
|
||||
stale->arp_status = PICO_ARP_STATUS_STALE;
|
||||
arp_dbg("ARP: Setting arp_status to STALE\n");
|
||||
pico_arp_request(stale->dev, &stale->ipv4, PICO_ARP_QUERY);
|
||||
} else {
|
||||
/* Timer must be rescheduled, ARP entry has been renewed lately.
|
||||
* No action required to refresh the entry, will check on the next timeout */
|
||||
pico_timer_add(PICO_ARP_TIMEOUT + stale->timestamp - now, arp_expire, stale);
|
||||
}
|
||||
}
|
||||
|
||||
static void pico_arp_add_entry(struct pico_arp *entry)
|
||||
{
|
||||
entry->arp_status = PICO_ARP_STATUS_REACHABLE;
|
||||
entry->timestamp = PICO_TIME();
|
||||
|
||||
pico_tree_insert(&arp_tree, entry);
|
||||
arp_dbg("ARP ## reachable.\n");
|
||||
pico_arp_queued_trigger();
|
||||
pico_timer_add(PICO_ARP_TIMEOUT, arp_expire, entry);
|
||||
}
|
||||
|
||||
int pico_arp_create_entry(uint8_t *hwaddr, struct pico_ip4 ipv4, struct pico_device *dev)
|
||||
{
|
||||
struct pico_arp*arp = PICO_ZALLOC(sizeof(struct pico_arp));
|
||||
if(!arp) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(arp->eth.addr, hwaddr, 6);
|
||||
arp->ipv4.addr = ipv4.addr;
|
||||
arp->dev = dev;
|
||||
|
||||
pico_arp_add_entry(arp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pico_arp_check_conflict(struct pico_arp_hdr *hdr)
|
||||
{
|
||||
if (conflict_ipv4.conflict)
|
||||
{
|
||||
if((conflict_ipv4.ip.addr == hdr->src.addr) &&
|
||||
(memcmp(hdr->s_mac, conflict_ipv4.mac.addr, PICO_SIZE_ETH) != 0))
|
||||
conflict_ipv4.conflict(PICO_ARP_CONFLICT_REASON_CONFLICT );
|
||||
if((hdr->src.addr == 0) && (hdr->dst.addr == conflict_ipv4.ip.addr) )
|
||||
conflict_ipv4.conflict(PICO_ARP_CONFLICT_REASON_PROBE );
|
||||
}
|
||||
}
|
||||
|
||||
static struct pico_arp *pico_arp_lookup_entry(struct pico_frame *f)
|
||||
{
|
||||
struct pico_arp search;
|
||||
struct pico_arp *found = NULL;
|
||||
struct pico_arp_hdr *hdr = (struct pico_arp_hdr *) f->net_hdr;
|
||||
/* Populate a new arp entry */
|
||||
search.ipv4.addr = hdr->src.addr;
|
||||
|
||||
/* Search for already existing entry */
|
||||
found = pico_tree_findKey(&arp_tree, &search);
|
||||
if (found) {
|
||||
if (found->arp_status == PICO_ARP_STATUS_STALE) {
|
||||
/* Replace if stale */
|
||||
pico_tree_delete(&arp_tree, found);
|
||||
pico_arp_add_entry(found);
|
||||
} else {
|
||||
/* Update mac address */
|
||||
memcpy(found->eth.addr, hdr->s_mac, PICO_SIZE_ETH);
|
||||
arp_dbg("ARP entry updated!\n");
|
||||
|
||||
/* Refresh timestamp, this will force a reschedule on the next timeout*/
|
||||
found->timestamp = PICO_TIME();
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
static int pico_arp_check_incoming_hdr_type(struct pico_arp_hdr *h)
|
||||
{
|
||||
/* Check the hardware type and protocol */
|
||||
if ((h->htype != PICO_ARP_HTYPE_ETH) || (h->ptype != PICO_IDETH_IPV4))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_arp_check_incoming_hdr(struct pico_frame *f, struct pico_ip4 *dst_addr)
|
||||
{
|
||||
struct pico_arp_hdr *hdr = (struct pico_arp_hdr *) f->net_hdr;
|
||||
if (!hdr)
|
||||
return -1;
|
||||
|
||||
dst_addr->addr = hdr->dst.addr;
|
||||
if (pico_arp_check_incoming_hdr_type(hdr) < 0)
|
||||
return -1;
|
||||
|
||||
/* The source mac address must not be a multicast or broadcast address */
|
||||
if (hdr->s_mac[0] & 0x01)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pico_arp_reply_on_request(struct pico_frame *f, struct pico_ip4 me)
|
||||
{
|
||||
struct pico_arp_hdr *hdr;
|
||||
struct pico_eth_hdr *eh;
|
||||
|
||||
hdr = (struct pico_arp_hdr *) f->net_hdr;
|
||||
eh = (struct pico_eth_hdr *)f->datalink_hdr;
|
||||
if (hdr->opcode != PICO_ARP_REQUEST)
|
||||
return;
|
||||
|
||||
hdr->opcode = PICO_ARP_REPLY;
|
||||
memcpy(hdr->d_mac, hdr->s_mac, PICO_SIZE_ETH);
|
||||
memcpy(hdr->s_mac, f->dev->eth->mac.addr, PICO_SIZE_ETH);
|
||||
hdr->dst.addr = hdr->src.addr;
|
||||
hdr->src.addr = me.addr;
|
||||
|
||||
/* Prepare eth header for arp reply */
|
||||
memcpy(eh->daddr, eh->saddr, PICO_SIZE_ETH);
|
||||
memcpy(eh->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH);
|
||||
f->start = f->datalink_hdr;
|
||||
f->len = PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR;
|
||||
f->dev->send(f->dev, f->start, (int)f->len);
|
||||
}
|
||||
|
||||
static int pico_arp_check_flooding(struct pico_frame *f, struct pico_ip4 me)
|
||||
{
|
||||
struct pico_device *link_dev;
|
||||
struct pico_arp_hdr *hdr;
|
||||
hdr = (struct pico_arp_hdr *) f->net_hdr;
|
||||
|
||||
/* Prevent ARP flooding */
|
||||
link_dev = pico_ipv4_link_find(&me);
|
||||
if ((link_dev == f->dev) && (hdr->opcode == PICO_ARP_REQUEST)) {
|
||||
if (max_arp_reqs == 0)
|
||||
return -1;
|
||||
else
|
||||
max_arp_reqs--;
|
||||
}
|
||||
|
||||
/* Check if we are the target IP address */
|
||||
if (link_dev != f->dev)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_arp_process_in(struct pico_frame *f, struct pico_arp_hdr *hdr, struct pico_arp *found)
|
||||
{
|
||||
struct pico_ip4 me;
|
||||
if (pico_arp_check_incoming_hdr(f, &me) < 0) {
|
||||
pico_frame_discard(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pico_arp_check_flooding(f, me) < 0) {
|
||||
pico_frame_discard(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If no existing entry was found, create a new entry, or fail trying. */
|
||||
if ((!found) && (pico_arp_create_entry(hdr->s_mac, hdr->src, f->dev) < 0)) {
|
||||
pico_frame_discard(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If the packet is a request, send a reply */
|
||||
pico_arp_reply_on_request(f, me);
|
||||
|
||||
#ifdef DEBUG_ARP
|
||||
dbg_arp();
|
||||
#endif
|
||||
pico_frame_discard(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_arp_receive(struct pico_frame *f)
|
||||
{
|
||||
struct pico_arp_hdr *hdr;
|
||||
struct pico_arp *found = NULL;
|
||||
|
||||
hdr = (struct pico_arp_hdr *) f->net_hdr;
|
||||
if (!hdr)
|
||||
return -1;
|
||||
|
||||
pico_arp_check_conflict(hdr);
|
||||
found = pico_arp_lookup_entry(f);
|
||||
return pico_arp_process_in(f, hdr, found);
|
||||
|
||||
}
|
||||
|
||||
static int32_t pico_arp_request_xmit(struct pico_device *dev, struct pico_frame *f, struct pico_ip4 *src, struct pico_ip4 *dst, uint8_t type)
|
||||
{
|
||||
struct pico_arp_hdr *ah = (struct pico_arp_hdr *) (f->start + PICO_SIZE_ETHHDR);
|
||||
int ret;
|
||||
|
||||
/* Fill arp header */
|
||||
ah->htype = PICO_ARP_HTYPE_ETH;
|
||||
ah->ptype = PICO_IDETH_IPV4;
|
||||
ah->hsize = PICO_SIZE_ETH;
|
||||
ah->psize = PICO_SIZE_IP4;
|
||||
ah->opcode = PICO_ARP_REQUEST;
|
||||
memcpy(ah->s_mac, dev->eth->mac.addr, PICO_SIZE_ETH);
|
||||
|
||||
switch (type) {
|
||||
case PICO_ARP_ANNOUNCE:
|
||||
ah->src.addr = dst->addr;
|
||||
ah->dst.addr = dst->addr;
|
||||
break;
|
||||
case PICO_ARP_PROBE:
|
||||
ah->src.addr = 0;
|
||||
ah->dst.addr = dst->addr;
|
||||
break;
|
||||
case PICO_ARP_QUERY:
|
||||
ah->src.addr = src->addr;
|
||||
ah->dst.addr = dst->addr;
|
||||
break;
|
||||
default:
|
||||
pico_frame_discard(f);
|
||||
return -1;
|
||||
}
|
||||
arp_dbg("Sending arp request.\n");
|
||||
ret = dev->send(dev, f->start, (int) f->len);
|
||||
pico_frame_discard(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t pico_arp_request(struct pico_device *dev, struct pico_ip4 *dst, uint8_t type)
|
||||
{
|
||||
struct pico_frame *q = pico_frame_alloc(PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR);
|
||||
struct pico_eth_hdr *eh;
|
||||
struct pico_ip4 *src = NULL;
|
||||
|
||||
if (!q)
|
||||
return -1;
|
||||
|
||||
if (type == PICO_ARP_QUERY)
|
||||
{
|
||||
src = pico_ipv4_source_find(dst);
|
||||
if (!src) {
|
||||
pico_frame_discard(q);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
arp_dbg("QUERY: %08x\n", dst->addr);
|
||||
|
||||
eh = (struct pico_eth_hdr *)q->start;
|
||||
|
||||
/* Fill eth header */
|
||||
memcpy(eh->saddr, dev->eth->mac.addr, PICO_SIZE_ETH);
|
||||
memcpy(eh->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH);
|
||||
eh->proto = PICO_IDETH_ARP;
|
||||
|
||||
return pico_arp_request_xmit(dev, q, src, dst, type);
|
||||
}
|
||||
|
||||
int pico_arp_get_neighbors(struct pico_device *dev, struct pico_ip4 *neighbors, int maxlen)
|
||||
{
|
||||
struct pico_arp*search;
|
||||
struct pico_tree_node *index;
|
||||
int i = 0;
|
||||
pico_tree_foreach(index, &arp_tree){
|
||||
search = index->keyValue;
|
||||
if (search->dev == dev) {
|
||||
neighbors[i++].addr = search->ipv4.addr;
|
||||
if (i >= maxlen)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void pico_arp_register_ipconflict(struct pico_ip4 *ip, struct pico_eth *mac, void (*cb)(int reason))
|
||||
{
|
||||
conflict_ipv4.conflict = cb;
|
||||
conflict_ipv4.ip.addr = ip->addr;
|
||||
if (mac != NULL)
|
||||
memcpy(conflict_ipv4.mac.addr, mac, 6);
|
||||
}
|
||||
|
||||
35
ext/picotcp/modules/pico_arp.h
Normal file
35
ext/picotcp/modules/pico_arp.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_ARP
|
||||
#define INCLUDE_PICO_ARP
|
||||
#include "pico_eth.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
int pico_arp_receive(struct pico_frame *);
|
||||
|
||||
|
||||
struct pico_eth *pico_arp_get(struct pico_frame *f);
|
||||
int32_t pico_arp_request(struct pico_device *dev, struct pico_ip4 *dst, uint8_t type);
|
||||
|
||||
#define PICO_ARP_STATUS_REACHABLE 0x00
|
||||
#define PICO_ARP_STATUS_PERMANENT 0x01
|
||||
#define PICO_ARP_STATUS_STALE 0x02
|
||||
|
||||
#define PICO_ARP_QUERY 0x00
|
||||
#define PICO_ARP_PROBE 0x01
|
||||
#define PICO_ARP_ANNOUNCE 0x02
|
||||
|
||||
#define PICO_ARP_CONFLICT_REASON_CONFLICT 0
|
||||
#define PICO_ARP_CONFLICT_REASON_PROBE 1
|
||||
|
||||
struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst);
|
||||
struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst);
|
||||
int pico_arp_create_entry(uint8_t*hwaddr, struct pico_ip4 ipv4, struct pico_device*dev);
|
||||
int pico_arp_get_neighbors(struct pico_device *dev, struct pico_ip4 *neighbors, int maxlen);
|
||||
void pico_arp_register_ipconflict(struct pico_ip4 *ip, struct pico_eth *mac, void (*cb)(int reason));
|
||||
void pico_arp_postpone(struct pico_frame *f);
|
||||
void pico_arp_init(void);
|
||||
#endif
|
||||
66
ext/picotcp/modules/pico_dev_loop.c
Normal file
66
ext/picotcp/modules/pico_dev_loop.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include "pico_device.h"
|
||||
#include "pico_dev_loop.h"
|
||||
#include "pico_stack.h"
|
||||
|
||||
|
||||
#define LOOP_MTU 1500
|
||||
static uint8_t l_buf[LOOP_MTU];
|
||||
static int l_bufsize = 0;
|
||||
|
||||
|
||||
static int pico_loop_send(struct pico_device *dev, void *buf, int len)
|
||||
{
|
||||
IGNORE_PARAMETER(dev);
|
||||
if (len > LOOP_MTU)
|
||||
return 0;
|
||||
|
||||
if (l_bufsize == 0) {
|
||||
memcpy(l_buf, buf, (size_t)len);
|
||||
l_bufsize += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_loop_poll(struct pico_device *dev, int loop_score)
|
||||
{
|
||||
if (loop_score <= 0)
|
||||
return 0;
|
||||
|
||||
if (l_bufsize > 0) {
|
||||
pico_stack_recv(dev, l_buf, (uint32_t)l_bufsize);
|
||||
l_bufsize = 0;
|
||||
loop_score--;
|
||||
}
|
||||
|
||||
return loop_score;
|
||||
}
|
||||
|
||||
|
||||
struct pico_device *pico_loop_create(void)
|
||||
{
|
||||
struct pico_device *loop = PICO_ZALLOC(sizeof(struct pico_device));
|
||||
if (!loop)
|
||||
return NULL;
|
||||
|
||||
if( 0 != pico_device_init(loop, "loop", NULL)) {
|
||||
dbg ("Loop init failed.\n");
|
||||
pico_device_destroy(loop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
loop->send = pico_loop_send;
|
||||
loop->poll = pico_loop_poll;
|
||||
dbg("Device %s created.\n", loop->name);
|
||||
return loop;
|
||||
}
|
||||
|
||||
15
ext/picotcp/modules/pico_dev_loop.h
Normal file
15
ext/picotcp/modules/pico_dev_loop.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_LOOP
|
||||
#define INCLUDE_PICO_LOOP
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
void pico_loop_destroy(struct pico_device *loop);
|
||||
struct pico_device *pico_loop_create(void);
|
||||
|
||||
#endif
|
||||
|
||||
307
ext/picotcp/modules/pico_dev_mock.c
Normal file
307
ext/picotcp/modules/pico_dev_mock.c
Normal file
@@ -0,0 +1,307 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Frederik Van Slycken
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include "pico_device.h"
|
||||
#include "pico_dev_mock.h"
|
||||
#include "pico_stack.h"
|
||||
#include "pico_tree.h"
|
||||
|
||||
#define MOCK_MTU 1500
|
||||
|
||||
|
||||
|
||||
/* Tree for finding mock_device based on pico_device* */
|
||||
|
||||
|
||||
static int mock_dev_cmp(void *ka, void *kb)
|
||||
{
|
||||
struct mock_device *a = ka, *b = kb;
|
||||
if (a->dev < b->dev)
|
||||
return -1;
|
||||
|
||||
if (a->dev > b->dev)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PICO_TREE_DECLARE(mock_device_tree, mock_dev_cmp);
|
||||
|
||||
static int pico_mock_send(struct pico_device *dev, void *buf, int len)
|
||||
{
|
||||
struct mock_device search = {
|
||||
.dev = dev
|
||||
};
|
||||
struct mock_device*mock = pico_tree_findKey(&mock_device_tree, &search);
|
||||
struct mock_frame*frame;
|
||||
|
||||
if(!mock)
|
||||
return 0;
|
||||
|
||||
if (len > MOCK_MTU)
|
||||
return 0;
|
||||
|
||||
frame = PICO_ZALLOC(sizeof(struct mock_frame));
|
||||
if(!frame) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(mock->out_head == NULL)
|
||||
mock->out_head = frame;
|
||||
else
|
||||
mock->out_tail->next = frame;
|
||||
|
||||
mock->out_tail = frame;
|
||||
|
||||
mock->out_tail->buffer = PICO_ZALLOC((uint32_t)len);
|
||||
if(!mock->out_tail->buffer)
|
||||
return 0;
|
||||
|
||||
memcpy(mock->out_tail->buffer, buf, (uint32_t)len);
|
||||
mock->out_tail->len = len;
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
static int pico_mock_poll(struct pico_device *dev, int loop_score)
|
||||
{
|
||||
struct mock_device search = {
|
||||
.dev = dev
|
||||
};
|
||||
struct mock_device*mock = pico_tree_findKey(&mock_device_tree, &search);
|
||||
struct mock_frame*nxt;
|
||||
|
||||
if(!mock)
|
||||
return 0;
|
||||
|
||||
if (loop_score <= 0)
|
||||
return 0;
|
||||
|
||||
while(mock->in_head != NULL && loop_score > 0)
|
||||
{
|
||||
pico_stack_recv(dev, mock->in_head->buffer, (uint32_t)mock->in_head->len);
|
||||
loop_score--;
|
||||
|
||||
PICO_FREE(mock->in_head->buffer);
|
||||
|
||||
if(mock->in_tail == mock->in_head) {
|
||||
PICO_FREE(mock->in_head);
|
||||
mock->in_tail = mock->in_head = NULL;
|
||||
return loop_score;
|
||||
}
|
||||
|
||||
nxt = mock->in_head->next;
|
||||
PICO_FREE(mock->in_head);
|
||||
mock->in_head = nxt;
|
||||
}
|
||||
return loop_score;
|
||||
}
|
||||
|
||||
int pico_mock_network_read(struct mock_device*mock, void *buf, int len)
|
||||
{
|
||||
struct mock_frame*nxt;
|
||||
if(mock->out_head == NULL)
|
||||
return 0;
|
||||
|
||||
if(len > mock->out_head->len - mock->out_head->read)
|
||||
len = mock->out_head->len - mock->out_head->read;
|
||||
|
||||
memcpy(buf, mock->out_head->buffer, (uint32_t)len);
|
||||
|
||||
if(len + mock->out_head->read != mock->out_head->len) {
|
||||
mock->out_head->read += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
PICO_FREE(mock->out_head->buffer);
|
||||
|
||||
if(mock->out_tail == mock->out_head) {
|
||||
PICO_FREE(mock->out_head);
|
||||
mock->out_tail = mock->out_head = NULL;
|
||||
return len;
|
||||
}
|
||||
|
||||
nxt = mock->out_head->next;
|
||||
PICO_FREE(mock->out_head);
|
||||
mock->out_head = nxt;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int pico_mock_network_write(struct mock_device*mock, const void *buf, int len)
|
||||
{
|
||||
struct mock_frame*frame;
|
||||
if (len > MOCK_MTU)
|
||||
return 0;
|
||||
|
||||
frame = PICO_ZALLOC(sizeof(struct mock_frame));
|
||||
if(!frame) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(mock->in_head == NULL)
|
||||
mock->in_head = frame;
|
||||
else
|
||||
mock->in_tail->next = frame;
|
||||
|
||||
mock->in_tail = frame;
|
||||
|
||||
mock->in_tail->buffer = PICO_ZALLOC((uint32_t)len);
|
||||
if(!mock->in_tail->buffer)
|
||||
return 0;
|
||||
|
||||
memcpy(mock->in_tail->buffer, buf, (uint32_t)len);
|
||||
mock->in_tail->len = len;
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
/* Public interface: create/destroy. */
|
||||
|
||||
void pico_mock_destroy(struct pico_device *dev)
|
||||
{
|
||||
struct mock_device search = {
|
||||
.dev = dev
|
||||
};
|
||||
struct mock_device*mock = pico_tree_findKey(&mock_device_tree, &search);
|
||||
struct mock_frame*nxt;
|
||||
|
||||
if(!mock)
|
||||
return;
|
||||
|
||||
nxt = mock->in_head;
|
||||
while(nxt != NULL) {
|
||||
mock->in_head = mock->in_head->next;
|
||||
PICO_FREE(nxt);
|
||||
nxt = mock->in_head;
|
||||
}
|
||||
nxt = mock->out_head;
|
||||
while(nxt != NULL) {
|
||||
mock->out_head = mock->out_head->next;
|
||||
PICO_FREE(nxt);
|
||||
nxt = mock->out_head;
|
||||
}
|
||||
pico_tree_delete(&mock_device_tree, mock);
|
||||
}
|
||||
|
||||
struct mock_device *pico_mock_create(uint8_t*mac)
|
||||
{
|
||||
|
||||
struct mock_device*mock = PICO_ZALLOC(sizeof(struct mock_device));
|
||||
if(!mock)
|
||||
return NULL;
|
||||
|
||||
mock->dev = PICO_ZALLOC(sizeof(struct pico_device));
|
||||
if (!mock->dev) {
|
||||
PICO_FREE(mock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(mac != NULL) {
|
||||
mock->mac = PICO_ZALLOC(6 * sizeof(uint8_t));
|
||||
if(!mock->mac) {
|
||||
PICO_FREE(mock->mac);
|
||||
PICO_FREE(mock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(mock->mac, mac, 6);
|
||||
}
|
||||
|
||||
if( 0 != pico_device_init((struct pico_device *)mock->dev, "mock", mac)) {
|
||||
dbg ("Loop init failed.\n");
|
||||
pico_mock_destroy((struct pico_device *)mock->dev);
|
||||
if(mock->mac != NULL)
|
||||
PICO_FREE(mock->mac);
|
||||
|
||||
PICO_FREE(mock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mock->dev->send = pico_mock_send;
|
||||
mock->dev->poll = pico_mock_poll;
|
||||
mock->dev->destroy = pico_mock_destroy;
|
||||
dbg("Device %s created.\n", mock->dev->name);
|
||||
|
||||
pico_tree_insert(&mock_device_tree, mock);
|
||||
return mock;
|
||||
}
|
||||
|
||||
/*
|
||||
* a few utility functions that check certain fields
|
||||
*/
|
||||
|
||||
uint32_t mock_get_sender_ip4(struct mock_device*mock, void*buf, int len)
|
||||
{
|
||||
uint32_t ret;
|
||||
int start = mock->mac ? 14 : 0;
|
||||
if(start + 16 > len) {
|
||||
dbg("out of range!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&ret, buf + start + 12, 4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO
|
||||
* find a way to create ARP replies
|
||||
*
|
||||
* create the other utility functions, e.g.
|
||||
* -is_arp_request
|
||||
* -create_arp_reply
|
||||
* -get_destination_ip4
|
||||
* -get_ip4_total_length
|
||||
* -is_ip4_checksum_valid
|
||||
* -is_tcp_syn
|
||||
* -create_tcp_synack
|
||||
* -is_tcp_checksum_valid
|
||||
* etc.
|
||||
*
|
||||
*/
|
||||
|
||||
int mock_ip_protocol(struct mock_device*mock, void*buf, int len)
|
||||
{
|
||||
uint8_t type;
|
||||
int start = mock->mac ? 14 : 0;
|
||||
if(start + 10 > len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&type, buf + start + 9, 1);
|
||||
return type;
|
||||
}
|
||||
|
||||
/* note : this function doesn't check if the IP header has any options */
|
||||
int mock_icmp_type(struct mock_device*mock, void*buf, int len)
|
||||
{
|
||||
uint8_t type;
|
||||
int start = mock->mac ? 14 : 0;
|
||||
if(start + 21 > len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&type, buf + start + 20, 1);
|
||||
return type;
|
||||
}
|
||||
|
||||
/* note : this function doesn't check if the IP header has any options */
|
||||
int mock_icmp_code(struct mock_device*mock, void*buf, int len)
|
||||
{
|
||||
uint8_t type;
|
||||
int start = mock->mac ? 14 : 0;
|
||||
if(start + 22 > len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&type, buf + start + 21, 1);
|
||||
return type;
|
||||
}
|
||||
47
ext/picotcp/modules/pico_dev_mock.h
Normal file
47
ext/picotcp/modules/pico_dev_mock.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_MOCK
|
||||
#define INCLUDE_PICO_MOCK
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
|
||||
struct mock_frame {
|
||||
uint8_t*buffer;
|
||||
int len;
|
||||
int read;
|
||||
|
||||
struct mock_frame*next;
|
||||
};
|
||||
|
||||
struct mock_device {
|
||||
struct pico_device*dev;
|
||||
struct mock_frame*in_head;
|
||||
struct mock_frame*in_tail;
|
||||
struct mock_frame*out_head;
|
||||
struct mock_frame*out_tail;
|
||||
|
||||
uint8_t*mac;
|
||||
|
||||
};
|
||||
|
||||
struct mock_device;
|
||||
/* A mockup-device for the purpose of testing. It provides a couple of extra "network"-functions, which represent the network-side of the device. A network_send will result in mock_poll reading something, a network_read will see if the stack has sent anything through our mock-device. */
|
||||
void pico_mock_destroy(struct pico_device *dev);
|
||||
struct mock_device *pico_mock_create(uint8_t*mac);
|
||||
|
||||
int pico_mock_network_read(struct mock_device*mock, void *buf, int len);
|
||||
int pico_mock_network_write(struct mock_device*mock, const void *buf, int len);
|
||||
|
||||
/* TODO */
|
||||
/* we could use a few checking functions, e.g. one to see if it's a valid IP packet, if it's TCP, if the IP-address matches,... */
|
||||
/* That would be useful to avoid having to manually create buffers of what you expect, probably with masks for things that are random,... */
|
||||
uint32_t mock_get_sender_ip4(struct mock_device*mock, void*buf, int len);
|
||||
|
||||
int mock_ip_protocol(struct mock_device*mock, void*buf, int len);
|
||||
int mock_icmp_type(struct mock_device*mock, void*buf, int len);
|
||||
int mock_icmp_code(struct mock_device*mock, void*buf, int len);
|
||||
#endif
|
||||
60
ext/picotcp/modules/pico_dev_null.c
Normal file
60
ext/picotcp/modules/pico_dev_null.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include "pico_device.h"
|
||||
#include "pico_dev_null.h"
|
||||
#include "pico_stack.h"
|
||||
|
||||
struct pico_device_null {
|
||||
struct pico_device dev;
|
||||
int statistics_frames_out;
|
||||
};
|
||||
|
||||
#define NULL_MTU 0
|
||||
|
||||
static int pico_null_send(struct pico_device *dev, void *buf, int len)
|
||||
{
|
||||
struct pico_device_null *null = (struct pico_device_null *) dev;
|
||||
IGNORE_PARAMETER(buf);
|
||||
|
||||
/* Increase the statistic count */
|
||||
null->statistics_frames_out++;
|
||||
|
||||
/* Discard the frame content silently. */
|
||||
return len;
|
||||
}
|
||||
|
||||
static int pico_null_poll(struct pico_device *dev, int loop_score)
|
||||
{
|
||||
/* We never have packet to receive, no score is used. */
|
||||
IGNORE_PARAMETER(dev);
|
||||
return loop_score;
|
||||
}
|
||||
|
||||
/* Public interface: create/destroy. */
|
||||
|
||||
|
||||
struct pico_device *pico_null_create(char *name)
|
||||
{
|
||||
struct pico_device_null *null = PICO_ZALLOC(sizeof(struct pico_device_null));
|
||||
|
||||
if (!null)
|
||||
return NULL;
|
||||
|
||||
if( 0 != pico_device_init((struct pico_device *)null, name, NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
null->dev.overhead = 0;
|
||||
null->statistics_frames_out = 0;
|
||||
null->dev.send = pico_null_send;
|
||||
null->dev.poll = pico_null_poll;
|
||||
dbg("Device %s created.\n", null->dev.name);
|
||||
return (struct pico_device *)null;
|
||||
}
|
||||
|
||||
15
ext/picotcp/modules/pico_dev_null.h
Normal file
15
ext/picotcp/modules/pico_dev_null.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_NULL
|
||||
#define INCLUDE_PICO_NULL
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
void pico_null_destroy(struct pico_device *null);
|
||||
struct pico_device *pico_null_create(char *name);
|
||||
|
||||
#endif
|
||||
|
||||
96
ext/picotcp/modules/pico_dev_pcap.c
Normal file
96
ext/picotcp/modules/pico_dev_pcap.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include <pcap.h>
|
||||
#include "pico_device.h"
|
||||
#include "pico_dev_pcap.h"
|
||||
#include "pico_stack.h"
|
||||
|
||||
#include <sys/poll.h>
|
||||
|
||||
struct pico_device_pcap {
|
||||
struct pico_device dev;
|
||||
pcap_t *conn;
|
||||
};
|
||||
|
||||
#define VDE_MTU 2048
|
||||
|
||||
static int pico_pcap_send(struct pico_device *dev, void *buf, int len)
|
||||
{
|
||||
struct pico_device_pcap *pcap = (struct pico_device_pcap *) dev;
|
||||
/* dbg("[%s] send %d bytes.\n", dev->name, len); */
|
||||
return pcap_inject(pcap->conn, buf, (uint32_t)len);
|
||||
}
|
||||
|
||||
static void pico_dev_pcap_cb(u_char *u, const struct pcap_pkthdr *h, const u_char *data)
|
||||
{
|
||||
struct pico_device *dev = (struct pico_device *)u;
|
||||
const uint8_t *buf = (const uint8_t *)data;
|
||||
pico_stack_recv(dev, buf, (uint32_t)h->len);
|
||||
}
|
||||
|
||||
|
||||
static int pico_pcap_poll(struct pico_device *dev, int loop_score)
|
||||
{
|
||||
struct pico_device_pcap *pcap = (struct pico_device_pcap *) dev;
|
||||
loop_score -= pcap_dispatch(pcap->conn, loop_score, pico_dev_pcap_cb, (u_char *) pcap);
|
||||
return loop_score;
|
||||
}
|
||||
|
||||
/* Public interface: create/destroy. */
|
||||
|
||||
void pico_pcap_destroy(struct pico_device *dev)
|
||||
{
|
||||
struct pico_device_pcap *pcap = (struct pico_device_pcap *) dev;
|
||||
pcap_close(pcap->conn);
|
||||
}
|
||||
|
||||
#define PICO_PCAP_MODE_LIVE 0
|
||||
#define PICO_PCAP_MODE_STORED 1
|
||||
|
||||
static struct pico_device *pico_pcap_create(char *if_file_name, char *name, uint8_t *mac, int mode)
|
||||
{
|
||||
struct pico_device_pcap *pcap = PICO_ZALLOC(sizeof(struct pico_device_pcap));
|
||||
char errbuf[2000];
|
||||
if (!pcap)
|
||||
return NULL;
|
||||
|
||||
if( 0 != pico_device_init((struct pico_device *)pcap, name, mac)) {
|
||||
dbg ("Pcap init failed.\n");
|
||||
pico_pcap_destroy((struct pico_device *)pcap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pcap->dev.overhead = 0;
|
||||
|
||||
if (mode == PICO_PCAP_MODE_LIVE)
|
||||
pcap->conn = pcap_open_live(if_file_name, 2000, 100, 10, errbuf);
|
||||
else
|
||||
pcap->conn = pcap_open_offline(if_file_name, errbuf);
|
||||
|
||||
if (!pcap->conn) {
|
||||
pico_pcap_destroy((struct pico_device *)pcap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pcap->dev.send = pico_pcap_send;
|
||||
pcap->dev.poll = pico_pcap_poll;
|
||||
pcap->dev.destroy = pico_pcap_destroy;
|
||||
dbg("Device %s created.\n", pcap->dev.name);
|
||||
return (struct pico_device *)pcap;
|
||||
}
|
||||
|
||||
struct pico_device *pico_pcap_create_fromfile(char *filename, char *name, uint8_t *mac)
|
||||
{
|
||||
return pico_pcap_create(filename, name, mac, PICO_PCAP_MODE_STORED);
|
||||
}
|
||||
|
||||
struct pico_device *pico_pcap_create_live(char *ifname, char *name, uint8_t *mac)
|
||||
{
|
||||
return pico_pcap_create(ifname, name, mac, PICO_PCAP_MODE_LIVE);
|
||||
}
|
||||
19
ext/picotcp/modules/pico_dev_pcap.h
Normal file
19
ext/picotcp/modules/pico_dev_pcap.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
|
||||
Author: Daniele Lacamera <daniele.lacamera@altran.com>
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_PCAP
|
||||
#define INCLUDE_PICO_PCAP
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
#include <pcap.h>
|
||||
|
||||
void pico_pcap_destroy(struct pico_device *pcap);
|
||||
struct pico_device *pico_pcap_create_live(char *ifname, char *name, uint8_t *mac);
|
||||
struct pico_device *pico_pcap_create_fromfile(char *filename, char *name, uint8_t *mac);
|
||||
|
||||
#endif
|
||||
|
||||
2294
ext/picotcp/modules/pico_dev_ppp.c
Normal file
2294
ext/picotcp/modules/pico_dev_ppp.c
Normal file
File diff suppressed because it is too large
Load Diff
26
ext/picotcp/modules/pico_dev_ppp.h
Normal file
26
ext/picotcp/modules/pico_dev_ppp.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_PPP
|
||||
#define INCLUDE_PICO_PPP
|
||||
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
void pico_ppp_destroy(struct pico_device *ppp);
|
||||
struct pico_device *pico_ppp_create(void);
|
||||
|
||||
int pico_ppp_connect(struct pico_device *dev);
|
||||
int pico_ppp_disconnect(struct pico_device *dev);
|
||||
|
||||
int pico_ppp_set_serial_read(struct pico_device *dev, int (*sread)(struct pico_device *, void *, int));
|
||||
int pico_ppp_set_serial_write(struct pico_device *dev, int (*swrite)(struct pico_device *, const void *, int));
|
||||
int pico_ppp_set_serial_set_speed(struct pico_device *dev, int (*sspeed)(struct pico_device *, uint32_t));
|
||||
|
||||
int pico_ppp_set_apn(struct pico_device *dev, const char *apn);
|
||||
int pico_ppp_set_username(struct pico_device *dev, const char *username);
|
||||
int pico_ppp_set_password(struct pico_device *dev, const char *password);
|
||||
|
||||
#endif /* INCLUDE_PICO_PPP */
|
||||
220
ext/picotcp/modules/pico_dev_tap.c
Normal file
220
ext/picotcp/modules/pico_dev_tap.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <signal.h>
|
||||
#include "pico_device.h"
|
||||
#include "pico_dev_tap.h"
|
||||
#include "pico_stack.h"
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
#include <linux/if_tun.h>
|
||||
#endif
|
||||
|
||||
#include <sys/poll.h>
|
||||
|
||||
struct pico_device_tap {
|
||||
struct pico_device dev;
|
||||
int fd;
|
||||
};
|
||||
|
||||
#define TUN_MTU 2048
|
||||
|
||||
// We only support one global link state - we only have two USR signals, we
|
||||
// can't spread these out over an arbitrary amount of devices. When you unplug
|
||||
// one tap, you unplug all of them.
|
||||
|
||||
static int link_state = 0;
|
||||
|
||||
static void sig_handler(int signo)
|
||||
{
|
||||
if (signo == SIGUSR1)
|
||||
link_state = 0;
|
||||
if (signo == SIGUSR2)
|
||||
link_state = 1;
|
||||
}
|
||||
|
||||
static int tap_link_state(__attribute__((unused)) struct pico_device *self)
|
||||
{
|
||||
return link_state;
|
||||
}
|
||||
|
||||
|
||||
static int pico_tap_send(struct pico_device *dev, void *buf, int len)
|
||||
{
|
||||
struct pico_device_tap *tap = (struct pico_device_tap *) dev;
|
||||
return (int)write(tap->fd, buf, (uint32_t)len);
|
||||
}
|
||||
|
||||
static int pico_tap_poll(struct pico_device *dev, int loop_score)
|
||||
{
|
||||
struct pico_device_tap *tap = (struct pico_device_tap *) dev;
|
||||
struct pollfd pfd;
|
||||
unsigned char buf[TUN_MTU];
|
||||
int len;
|
||||
pfd.fd = tap->fd;
|
||||
pfd.events = POLLIN;
|
||||
do {
|
||||
if (poll(&pfd, 1, 0) <= 0)
|
||||
return loop_score;
|
||||
|
||||
len = (int)read(tap->fd, buf, TUN_MTU);
|
||||
if (len > 0) {
|
||||
loop_score--;
|
||||
pico_stack_recv(dev, buf, (uint32_t)len);
|
||||
}
|
||||
} while(loop_score > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Public interface: create/destroy. */
|
||||
|
||||
void pico_tap_destroy(struct pico_device *dev)
|
||||
{
|
||||
struct pico_device_tap *tap = (struct pico_device_tap *) dev;
|
||||
if(tap->fd > 0)
|
||||
close(tap->fd);
|
||||
}
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
static int tap_open(char *name)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int tap_fd;
|
||||
if((tap_fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, name, IFNAMSIZ);
|
||||
if(ioctl(tap_fd, TUNSETIFF, &ifr) < 0) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return tap_fd;
|
||||
}
|
||||
#else
|
||||
static int tap_open(char *name)
|
||||
{
|
||||
int tap_fd;
|
||||
(void)name;
|
||||
tap_fd = open("/dev/tap0", O_RDWR);
|
||||
return tap_fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
static int tap_get_mac(char *name, uint8_t *mac)
|
||||
{
|
||||
int sck;
|
||||
struct ifreq eth;
|
||||
int retval = -1;
|
||||
|
||||
|
||||
|
||||
|
||||
sck = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(sck < 0) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
memset(ð, 0, sizeof(struct ifreq));
|
||||
strcpy(eth.ifr_name, name);
|
||||
/* call the IOCTL */
|
||||
if (ioctl(sck, SIOCGIFHWADDR, ð) < 0) {
|
||||
perror("ioctl(SIOCGIFHWADDR)");
|
||||
return -1;
|
||||
;
|
||||
}
|
||||
|
||||
memcpy (mac, ð.ifr_hwaddr.sa_data, 6);
|
||||
|
||||
|
||||
close(sck);
|
||||
return 0;
|
||||
|
||||
}
|
||||
#else
|
||||
#include <net/if_dl.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if_types.h>
|
||||
static int tap_get_mac(char *name, uint8_t *mac)
|
||||
{
|
||||
struct sockaddr_dl *sdl;
|
||||
struct ifaddrs *ifap, *root;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return -1;
|
||||
|
||||
root = ifap;
|
||||
while(ifap) {
|
||||
if (strcmp(name, ifap->ifa_name) == 0)
|
||||
sdl = (struct sockaddr_dl *) ifap->ifa_addr;
|
||||
|
||||
if (sdl->sdl_type == IFT_ETHER) {
|
||||
memcpy(mac, LLADDR(sdl), 6);
|
||||
freeifaddrs(root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ifap = ifap->ifa_next;
|
||||
}
|
||||
freeifaddrs(root);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct pico_device *pico_tap_create(char *name)
|
||||
{
|
||||
struct pico_device_tap *tap = PICO_ZALLOC(sizeof(struct pico_device_tap));
|
||||
uint8_t mac[6] = {};
|
||||
struct sigaction sa;
|
||||
|
||||
if (!tap)
|
||||
return NULL;
|
||||
|
||||
sa.sa_flags = 0;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_handler = sig_handler;
|
||||
|
||||
if ((sigaction(SIGUSR1, &sa, NULL) == 0) &&
|
||||
(sigaction(SIGUSR2, &sa, NULL) == 0))
|
||||
tap->dev.link_state = &tap_link_state;
|
||||
|
||||
tap->dev.overhead = 0;
|
||||
tap->fd = tap_open(name);
|
||||
if (tap->fd < 0) {
|
||||
dbg("Tap creation failed.\n");
|
||||
pico_tap_destroy((struct pico_device *)tap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tap_get_mac(name, mac) < 0) {
|
||||
dbg("Tap mac query failed.\n");
|
||||
pico_tap_destroy((struct pico_device *)tap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mac[5]++;
|
||||
|
||||
if( 0 != pico_device_init((struct pico_device *)tap, name, mac)) {
|
||||
dbg("Tap init failed.\n");
|
||||
pico_tap_destroy((struct pico_device *)tap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tap->dev.send = pico_tap_send;
|
||||
tap->dev.poll = pico_tap_poll;
|
||||
tap->dev.destroy = pico_tap_destroy;
|
||||
dbg("Device %s created.\n", tap->dev.name);
|
||||
return (struct pico_device *)tap;
|
||||
}
|
||||
|
||||
15
ext/picotcp/modules/pico_dev_tap.h
Normal file
15
ext/picotcp/modules/pico_dev_tap.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_TAP
|
||||
#define INCLUDE_PICO_TAP
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
void pico_tap_destroy(struct pico_device *tap);
|
||||
struct pico_device *pico_tap_create(char *name);
|
||||
|
||||
#endif
|
||||
|
||||
1083
ext/picotcp/modules/pico_dev_tap_windows.c
Normal file
1083
ext/picotcp/modules/pico_dev_tap_windows.c
Normal file
File diff suppressed because it is too large
Load Diff
17
ext/picotcp/modules/pico_dev_tap_windows.h
Executable file
17
ext/picotcp/modules/pico_dev_tap_windows.h
Executable file
@@ -0,0 +1,17 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_TAP
|
||||
#define INCLUDE_PICO_TAP
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
/* will look for the first TAP device available, and use it */
|
||||
struct pico_device *pico_tap_create(char *name, uint8_t *mac);
|
||||
/* TODO: not implemented yet */
|
||||
/* void pico_tap_destroy(struct pico_device *null); */
|
||||
|
||||
#endif
|
||||
|
||||
89
ext/picotcp/modules/pico_dev_tap_windows_private.h
Normal file
89
ext/picotcp/modules/pico_dev_tap_windows_private.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Maxime Vincent
|
||||
Based on the OpenVPN tun.c driver, under GPL
|
||||
|
||||
NOTES: This is the Windows-only driver, a Linux-equivalent is available, too
|
||||
You need to have an OpenVPN TUN/TAP network adapter installed, first
|
||||
This driver is barely working:
|
||||
* Only TAP-mode is supported (TUN is not)
|
||||
* it will simply open the first TAP device it can find
|
||||
* there is memory being allocated that's never freed
|
||||
* there is no destroy function, yet
|
||||
* it has only been tested on a Windows 7 machine
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef __PICO_DEV_TAP_WINDOWS_PRIVATE_H
|
||||
#define __PICO_DEV_TAP_WINDOWS_PRIVATE_H
|
||||
|
||||
/* Extra defines (vnz) */
|
||||
#define TAP_WIN_COMPONENT_ID "tap0901"
|
||||
#define TAP_WIN_MIN_MAJOR 9
|
||||
#define TAP_WIN_MIN_MINOR 9
|
||||
#define PACKAGE_NAME "PicoTCP WinTAP"
|
||||
|
||||
/* Extra structs */
|
||||
struct tap_reg
|
||||
{
|
||||
const char *guid;
|
||||
struct tap_reg *next;
|
||||
};
|
||||
|
||||
struct panel_reg
|
||||
{
|
||||
const char *name;
|
||||
const char *guid;
|
||||
struct panel_reg *next;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* =============
|
||||
* TAP IOCTLs
|
||||
* =============
|
||||
*/
|
||||
|
||||
#define TAP_WIN_CONTROL_CODE(request, method) \
|
||||
CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
|
||||
|
||||
/* Present in 8.1 */
|
||||
|
||||
#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_INFO TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED)
|
||||
|
||||
/* Added in 8.2 */
|
||||
|
||||
/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */
|
||||
#define TAP_WIN_IOCTL_CONFIG_TUN TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED)
|
||||
|
||||
/*
|
||||
* =================
|
||||
* Registry keys
|
||||
* =================
|
||||
*/
|
||||
|
||||
#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
||||
|
||||
#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
||||
|
||||
/*
|
||||
* ======================
|
||||
* Filesystem prefixes
|
||||
* ======================
|
||||
*/
|
||||
|
||||
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
|
||||
#define SYSDEVICEDIR "\\Device\\"
|
||||
#define USERDEVICEDIR "\\DosDevices\\Global\\"
|
||||
#define TAP_WIN_SUFFIX ".tap"
|
||||
|
||||
#endif
|
||||
110
ext/picotcp/modules/pico_dev_tun.c
Normal file
110
ext/picotcp/modules/pico_dev_tun.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include "pico_device.h"
|
||||
#include "pico_dev_tun.h"
|
||||
#include "pico_stack.h"
|
||||
|
||||
#include <sys/poll.h>
|
||||
|
||||
struct pico_device_tun {
|
||||
struct pico_device dev;
|
||||
int fd;
|
||||
};
|
||||
|
||||
#define TUN_MTU 2048
|
||||
|
||||
static int pico_tun_send(struct pico_device *dev, void *buf, int len)
|
||||
{
|
||||
struct pico_device_tun *tun = (struct pico_device_tun *) dev;
|
||||
return (int)write(tun->fd, buf, (uint32_t)len);
|
||||
}
|
||||
|
||||
static int pico_tun_poll(struct pico_device *dev, int loop_score)
|
||||
{
|
||||
struct pico_device_tun *tun = (struct pico_device_tun *) dev;
|
||||
struct pollfd pfd;
|
||||
unsigned char buf[TUN_MTU];
|
||||
int len;
|
||||
pfd.fd = tun->fd;
|
||||
pfd.events = POLLIN;
|
||||
do {
|
||||
if (poll(&pfd, 1, 0) <= 0)
|
||||
return loop_score;
|
||||
|
||||
len = (int)read(tun->fd, buf, TUN_MTU);
|
||||
if (len > 0) {
|
||||
loop_score--;
|
||||
pico_stack_recv(dev, buf, (uint32_t)len);
|
||||
}
|
||||
} while(loop_score > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Public interface: create/destroy. */
|
||||
|
||||
void pico_tun_destroy(struct pico_device *dev)
|
||||
{
|
||||
struct pico_device_tun *tun = (struct pico_device_tun *) dev;
|
||||
if(tun->fd > 0)
|
||||
close(tun->fd);
|
||||
}
|
||||
|
||||
|
||||
static int tun_open(char *name)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int tun_fd;
|
||||
if((tun_fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, name, IFNAMSIZ);
|
||||
if(ioctl(tun_fd, TUNSETIFF, &ifr) < 0) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return tun_fd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct pico_device *pico_tun_create(char *name)
|
||||
{
|
||||
struct pico_device_tun *tun = PICO_ZALLOC(sizeof(struct pico_device_tun));
|
||||
|
||||
if (!tun)
|
||||
return NULL;
|
||||
|
||||
if( 0 != pico_device_init((struct pico_device *)tun, name, NULL)) {
|
||||
dbg("Tun init failed.\n");
|
||||
pico_tun_destroy((struct pico_device *)tun);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tun->dev.overhead = 0;
|
||||
tun->fd = tun_open(name);
|
||||
if (tun->fd < 0) {
|
||||
dbg("Tun creation failed.\n");
|
||||
pico_tun_destroy((struct pico_device *)tun);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tun->dev.send = pico_tun_send;
|
||||
tun->dev.poll = pico_tun_poll;
|
||||
tun->dev.destroy = pico_tun_destroy;
|
||||
dbg("Device %s created.\n", tun->dev.name);
|
||||
return (struct pico_device *)tun;
|
||||
}
|
||||
|
||||
15
ext/picotcp/modules/pico_dev_tun.h
Normal file
15
ext/picotcp/modules/pico_dev_tun.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_TUN
|
||||
#define INCLUDE_PICO_TUN
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
void pico_tun_destroy(struct pico_device *tun);
|
||||
struct pico_device *pico_tun_create(char *name);
|
||||
|
||||
#endif
|
||||
|
||||
115
ext/picotcp/modules/pico_dev_vde.c
Normal file
115
ext/picotcp/modules/pico_dev_vde.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef UNIT_TEST
|
||||
#include <libvdeplug.h>
|
||||
#endif
|
||||
#include "pico_device.h"
|
||||
#include "pico_dev_vde.h"
|
||||
#include "pico_stack.h"
|
||||
|
||||
#include <sys/poll.h>
|
||||
|
||||
struct pico_device_vde {
|
||||
struct pico_device dev;
|
||||
char *sock;
|
||||
VDECONN *conn;
|
||||
uint32_t counter_in;
|
||||
uint32_t counter_out;
|
||||
uint32_t lost_in;
|
||||
uint32_t lost_out;
|
||||
};
|
||||
|
||||
#define VDE_MTU 65536
|
||||
|
||||
static int pico_vde_send(struct pico_device *dev, void *buf, int len)
|
||||
{
|
||||
struct pico_device_vde *vde = (struct pico_device_vde *) dev;
|
||||
/* dbg("[%s] send %d bytes.\n", dev->name, len); */
|
||||
if ((vde->lost_out == 0) || ((pico_rand() % 100) > vde->lost_out))
|
||||
return (int)vde_send(vde->conn, buf, (uint32_t)len, 0);
|
||||
else
|
||||
return len; /* Silently discarded "on the wire" */
|
||||
|
||||
}
|
||||
|
||||
static int pico_vde_poll(struct pico_device *dev, int loop_score)
|
||||
{
|
||||
struct pico_device_vde *vde = (struct pico_device_vde *) dev;
|
||||
struct pollfd pfd;
|
||||
unsigned char buf[VDE_MTU];
|
||||
int len;
|
||||
pfd.fd = vde_datafd(vde->conn);
|
||||
pfd.events = POLLIN;
|
||||
do {
|
||||
if (poll(&pfd, 1, 0) <= 0)
|
||||
return loop_score;
|
||||
|
||||
len = (int)vde_recv(vde->conn, buf, VDE_MTU, 0);
|
||||
if (len > 0) {
|
||||
/* dbg("Received pkt.\n"); */
|
||||
if ((vde->lost_in == 0) || ((pico_rand() % 100) > vde->lost_in)) {
|
||||
loop_score--;
|
||||
pico_stack_recv(dev, buf, (uint32_t)len);
|
||||
}
|
||||
}
|
||||
} while(loop_score > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Public interface: create/destroy. */
|
||||
|
||||
void pico_vde_destroy(struct pico_device *dev)
|
||||
{
|
||||
struct pico_device_vde *vde = (struct pico_device_vde *) dev;
|
||||
vde_close(vde->conn);
|
||||
usleep(100000);
|
||||
sync();
|
||||
}
|
||||
|
||||
void pico_vde_set_packetloss(struct pico_device *dev, uint32_t in_pct, uint32_t out_pct)
|
||||
{
|
||||
struct pico_device_vde *vde = (struct pico_device_vde *) dev;
|
||||
vde->lost_in = in_pct;
|
||||
vde->lost_out = out_pct;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct pico_device *pico_vde_create(char *sock, char *name, uint8_t *mac)
|
||||
{
|
||||
struct pico_device_vde *vde = PICO_ZALLOC(sizeof(struct pico_device_vde));
|
||||
struct vde_open_args open_args = {
|
||||
.mode = 0700
|
||||
};
|
||||
char vdename[] = "picotcp";
|
||||
|
||||
if (!vde)
|
||||
return NULL;
|
||||
|
||||
if( 0 != pico_device_init((struct pico_device *)vde, name, mac)) {
|
||||
dbg ("Vde init failed.\n");
|
||||
pico_vde_destroy((struct pico_device *)vde);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vde->dev.overhead = 0;
|
||||
vde->sock = PICO_ZALLOC(strlen(sock) + 1);
|
||||
memcpy(vde->sock, sock, strlen(sock));
|
||||
vde->conn = vde_open(sock, vdename, &open_args);
|
||||
if (!vde->conn) {
|
||||
pico_vde_destroy((struct pico_device *)vde);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vde->dev.send = pico_vde_send;
|
||||
vde->dev.poll = pico_vde_poll;
|
||||
vde->dev.destroy = pico_vde_destroy;
|
||||
dbg("Device %s created.\n", vde->dev.name);
|
||||
return (struct pico_device *)vde;
|
||||
}
|
||||
|
||||
18
ext/picotcp/modules/pico_dev_vde.h
Normal file
18
ext/picotcp/modules/pico_dev_vde.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_VDE
|
||||
#define INCLUDE_PICO_VDE
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
#include <libvdeplug.h>
|
||||
|
||||
void pico_vde_destroy(struct pico_device *vde);
|
||||
struct pico_device *pico_vde_create(char *sock, char *name, uint8_t *mac);
|
||||
void pico_vde_set_packetloss(struct pico_device *dev, uint32_t in_pct, uint32_t out_pct);
|
||||
|
||||
#endif
|
||||
|
||||
990
ext/picotcp/modules/pico_dhcp_client.c
Normal file
990
ext/picotcp/modules/pico_dhcp_client.c
Normal file
@@ -0,0 +1,990 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Kristof Roelants, Frederik Van Slycken
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include "pico_dhcp_client.h"
|
||||
#include "pico_stack.h"
|
||||
#include "pico_config.h"
|
||||
#include "pico_device.h"
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_socket.h"
|
||||
#include "pico_eth.h"
|
||||
|
||||
#if (defined PICO_SUPPORT_DHCPC && defined PICO_SUPPORT_UDP)
|
||||
#define dhcpc_dbg(...) do {} while(0)
|
||||
/* #define dhcpc_dbg dbg */
|
||||
|
||||
/* timer values */
|
||||
#define DHCP_CLIENT_REINIT 6000 /* msec */
|
||||
#define DHCP_CLIENT_RETRANS 4 /* sec */
|
||||
#define DHCP_CLIENT_RETRIES 3
|
||||
|
||||
#define DHCP_CLIENT_TIMER_STOPPED 0
|
||||
#define DHCP_CLIENT_TIMER_STARTED 1
|
||||
|
||||
/* maximum size of a DHCP message */
|
||||
#define DHCP_CLIENT_MAXMSGZISE (PICO_IP_MRU - PICO_SIZE_IP4HDR)
|
||||
#define PICO_DHCP_HOSTNAME_MAXLEN 64U
|
||||
|
||||
static char dhcpc_host_name[PICO_DHCP_HOSTNAME_MAXLEN] = "";
|
||||
static char dhcpc_domain_name[PICO_DHCP_HOSTNAME_MAXLEN] = "";
|
||||
|
||||
|
||||
enum dhcp_client_state {
|
||||
DHCP_CLIENT_STATE_INIT_REBOOT = 0,
|
||||
DHCP_CLIENT_STATE_REBOOTING,
|
||||
DHCP_CLIENT_STATE_INIT,
|
||||
DHCP_CLIENT_STATE_SELECTING,
|
||||
DHCP_CLIENT_STATE_REQUESTING,
|
||||
DHCP_CLIENT_STATE_BOUND,
|
||||
DHCP_CLIENT_STATE_RENEWING,
|
||||
DHCP_CLIENT_STATE_REBINDING
|
||||
};
|
||||
|
||||
|
||||
#define PICO_DHCPC_TIMER_INIT 0
|
||||
#define PICO_DHCPC_TIMER_REQUEST 1
|
||||
#define PICO_DHCPC_TIMER_RENEW 2
|
||||
#define PICO_DHCPC_TIMER_REBIND 3
|
||||
#define PICO_DHCPC_TIMER_T1 4
|
||||
#define PICO_DHCPC_TIMER_T2 5
|
||||
#define PICO_DHCPC_TIMER_LEASE 6
|
||||
#define PICO_DHCPC_TIMER_ARRAY_SIZE 7
|
||||
|
||||
struct dhcp_client_timer
|
||||
{
|
||||
uint8_t state;
|
||||
unsigned int type;
|
||||
uint32_t xid;
|
||||
};
|
||||
|
||||
struct pico_dhcp_client_cookie
|
||||
{
|
||||
uint8_t event;
|
||||
uint8_t retry;
|
||||
uint32_t xid;
|
||||
uint32_t *uid;
|
||||
enum dhcp_client_state state;
|
||||
void (*cb)(void*dhcpc, int code);
|
||||
pico_time init_timestamp;
|
||||
struct pico_socket *s;
|
||||
struct pico_ip4 address;
|
||||
struct pico_ip4 netmask;
|
||||
struct pico_ip4 gateway;
|
||||
struct pico_ip4 nameserver[2];
|
||||
struct pico_ip4 server_id;
|
||||
struct pico_device *dev;
|
||||
struct dhcp_client_timer *timer[PICO_DHCPC_TIMER_ARRAY_SIZE];
|
||||
uint32_t t1_time;
|
||||
uint32_t t2_time;
|
||||
uint32_t lease_time;
|
||||
uint32_t renew_time;
|
||||
uint32_t rebind_time;
|
||||
};
|
||||
|
||||
static int pico_dhcp_client_init(struct pico_dhcp_client_cookie *dhcpc);
|
||||
static int reset(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
|
||||
static int8_t pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_t msg_type);
|
||||
static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s);
|
||||
static void pico_dhcp_state_machine(uint8_t event, struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
|
||||
|
||||
static const struct pico_ip4 bcast_netmask = {
|
||||
.addr = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
static struct pico_ip4 inaddr_any = {
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
static int dhcp_cookies_cmp(void *ka, void *kb)
|
||||
{
|
||||
struct pico_dhcp_client_cookie *a = ka, *b = kb;
|
||||
if (a->xid == b->xid)
|
||||
return 0;
|
||||
|
||||
return (a->xid < b->xid) ? (-1) : (1);
|
||||
}
|
||||
PICO_TREE_DECLARE(DHCPCookies, dhcp_cookies_cmp);
|
||||
|
||||
static struct pico_dhcp_client_cookie *pico_dhcp_client_add_cookie(uint32_t xid, struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid)
|
||||
{
|
||||
struct pico_dhcp_client_cookie *dhcpc = NULL, *found = NULL, test = {
|
||||
0
|
||||
};
|
||||
|
||||
test.xid = xid;
|
||||
found = pico_tree_findKey(&DHCPCookies, &test);
|
||||
if (found) {
|
||||
pico_err = PICO_ERR_EAGAIN;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dhcpc = PICO_ZALLOC(sizeof(struct pico_dhcp_client_cookie));
|
||||
if (!dhcpc) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dhcpc->state = DHCP_CLIENT_STATE_INIT;
|
||||
dhcpc->xid = xid;
|
||||
dhcpc->uid = uid;
|
||||
*(dhcpc->uid) = 0;
|
||||
dhcpc->cb = cb;
|
||||
dhcpc->dev = dev;
|
||||
|
||||
pico_tree_insert(&DHCPCookies, dhcpc);
|
||||
return dhcpc;
|
||||
}
|
||||
|
||||
static void pico_dhcp_client_stop_timers(struct pico_dhcp_client_cookie *dhcpc);
|
||||
static int pico_dhcp_client_del_cookie(uint32_t xid)
|
||||
{
|
||||
struct pico_dhcp_client_cookie test = {
|
||||
0
|
||||
}, *found = NULL;
|
||||
|
||||
test.xid = xid;
|
||||
found = pico_tree_findKey(&DHCPCookies, &test);
|
||||
if (!found)
|
||||
return -1;
|
||||
|
||||
pico_dhcp_client_stop_timers(found);
|
||||
pico_socket_close(found->s);
|
||||
found->s = NULL;
|
||||
pico_ipv4_link_del(found->dev, found->address);
|
||||
pico_tree_delete(&DHCPCookies, found);
|
||||
PICO_FREE(found);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pico_dhcp_client_cookie *pico_dhcp_client_find_cookie(uint32_t xid)
|
||||
{
|
||||
struct pico_dhcp_client_cookie test = {
|
||||
0
|
||||
}, *found = NULL;
|
||||
|
||||
test.xid = xid;
|
||||
found = pico_tree_findKey(&DHCPCookies, &test);
|
||||
if (found)
|
||||
return found;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void pico_dhcp_client_timer_handler(pico_time now, void *arg);
|
||||
static void pico_dhcp_client_reinit(pico_time now, void *arg);
|
||||
static struct dhcp_client_timer *pico_dhcp_timer_add(uint8_t type, uint32_t time, struct pico_dhcp_client_cookie *ck)
|
||||
{
|
||||
struct dhcp_client_timer *t;
|
||||
|
||||
t = PICO_ZALLOC(sizeof(struct dhcp_client_timer));
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
t->state = DHCP_CLIENT_TIMER_STARTED;
|
||||
t->xid = ck->xid;
|
||||
t->type = type;
|
||||
pico_timer_add(time, pico_dhcp_client_timer_handler, t);
|
||||
if (ck->timer[type]) {
|
||||
ck->timer[type]->state = DHCP_CLIENT_TIMER_STOPPED;
|
||||
}
|
||||
|
||||
ck->timer[type] = t;
|
||||
return t;
|
||||
}
|
||||
|
||||
static int dhcp_get_timer_event(struct pico_dhcp_client_cookie *dhcpc, unsigned int type)
|
||||
{
|
||||
const int events[PICO_DHCPC_TIMER_ARRAY_SIZE] =
|
||||
{
|
||||
PICO_DHCP_EVENT_RETRANSMIT,
|
||||
PICO_DHCP_EVENT_RETRANSMIT,
|
||||
PICO_DHCP_EVENT_RETRANSMIT,
|
||||
PICO_DHCP_EVENT_RETRANSMIT,
|
||||
PICO_DHCP_EVENT_T1,
|
||||
PICO_DHCP_EVENT_T2,
|
||||
PICO_DHCP_EVENT_LEASE
|
||||
};
|
||||
|
||||
if (type == PICO_DHCPC_TIMER_REQUEST) {
|
||||
if (++dhcpc->retry > DHCP_CLIENT_RETRIES) {
|
||||
reset(dhcpc, NULL);
|
||||
return PICO_DHCP_EVENT_NONE;
|
||||
}
|
||||
} else if (type < PICO_DHCPC_TIMER_T1) {
|
||||
dhcpc->retry++;
|
||||
}
|
||||
|
||||
return events[type];
|
||||
}
|
||||
|
||||
static void pico_dhcp_client_timer_handler(pico_time now, void *arg)
|
||||
{
|
||||
struct dhcp_client_timer *t = (struct dhcp_client_timer *)arg;
|
||||
struct pico_dhcp_client_cookie *dhcpc;
|
||||
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
(void) now;
|
||||
if (t->state != DHCP_CLIENT_TIMER_STOPPED) {
|
||||
dhcpc = pico_dhcp_client_find_cookie(t->xid);
|
||||
if (dhcpc && dhcpc->timer) {
|
||||
t->state = DHCP_CLIENT_TIMER_STOPPED;
|
||||
if ((t->type == PICO_DHCPC_TIMER_INIT) && (dhcpc->state < DHCP_CLIENT_STATE_SELECTING)) {
|
||||
pico_dhcp_client_reinit(now, dhcpc);
|
||||
} else if (t->type != PICO_DHCPC_TIMER_INIT) {
|
||||
dhcpc->event = (uint8_t)dhcp_get_timer_event(dhcpc, t->type);
|
||||
if (dhcpc->event != PICO_DHCP_EVENT_NONE)
|
||||
pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pico_dhcp_client_timer_stop(struct pico_dhcp_client_cookie *dhcpc, int type)
|
||||
{
|
||||
if (dhcpc->timer[type]) {
|
||||
dhcpc->timer[type]->state = DHCP_CLIENT_TIMER_STOPPED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void pico_dhcp_client_reinit(pico_time now, void *arg)
|
||||
{
|
||||
struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
|
||||
(void) now;
|
||||
|
||||
if (dhcpc->s) {
|
||||
pico_socket_close(dhcpc->s);
|
||||
dhcpc->s = NULL;
|
||||
}
|
||||
|
||||
if (++dhcpc->retry > DHCP_CLIENT_RETRIES) {
|
||||
pico_err = PICO_ERR_EAGAIN;
|
||||
if (dhcpc->cb)
|
||||
dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
|
||||
|
||||
pico_dhcp_client_del_cookie(dhcpc->xid);
|
||||
return;
|
||||
}
|
||||
|
||||
pico_dhcp_client_init(dhcpc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void pico_dhcp_client_stop_timers(struct pico_dhcp_client_cookie *dhcpc)
|
||||
{
|
||||
int i;
|
||||
dhcpc->retry = 0;
|
||||
for (i = 0; i < PICO_DHCPC_TIMER_ARRAY_SIZE; i++)
|
||||
pico_dhcp_client_timer_stop(dhcpc, i);
|
||||
}
|
||||
|
||||
static void pico_dhcp_client_start_init_timer(struct pico_dhcp_client_cookie *dhcpc)
|
||||
{
|
||||
uint32_t time = 0;
|
||||
/* timer value is doubled with every retry (exponential backoff) */
|
||||
time = (uint32_t) (DHCP_CLIENT_RETRANS << dhcpc->retry);
|
||||
pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, time * 1000, dhcpc);
|
||||
}
|
||||
|
||||
static void pico_dhcp_client_start_requesting_timer(struct pico_dhcp_client_cookie *dhcpc)
|
||||
{
|
||||
uint32_t time = 0;
|
||||
|
||||
/* timer value is doubled with every retry (exponential backoff) */
|
||||
time = (uint32_t)(DHCP_CLIENT_RETRANS << dhcpc->retry);
|
||||
pico_dhcp_timer_add(PICO_DHCPC_TIMER_REQUEST, time * 1000, dhcpc);
|
||||
}
|
||||
|
||||
static void pico_dhcp_client_start_renewing_timer(struct pico_dhcp_client_cookie *dhcpc)
|
||||
{
|
||||
uint32_t halftime = 0;
|
||||
|
||||
/* wait one-half of the remaining time until T2, down to a minimum of 60 seconds */
|
||||
/* (dhcpc->retry + 1): initial -> divide by 2, 1st retry -> divide by 4, 2nd retry -> divide by 8, etc */
|
||||
pico_dhcp_client_stop_timers(dhcpc);
|
||||
halftime = dhcpc->renew_time >> (dhcpc->retry + 1);
|
||||
if (halftime < 60)
|
||||
halftime = 60;
|
||||
|
||||
pico_dhcp_timer_add(PICO_DHCPC_TIMER_RENEW, halftime * 1000, dhcpc);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void pico_dhcp_client_start_rebinding_timer(struct pico_dhcp_client_cookie *dhcpc)
|
||||
{
|
||||
uint32_t halftime = 0;
|
||||
|
||||
pico_dhcp_client_stop_timers(dhcpc);
|
||||
halftime = dhcpc->rebind_time >> (dhcpc->retry + 1);
|
||||
if (halftime < 60)
|
||||
halftime = 60;
|
||||
|
||||
pico_dhcp_timer_add(PICO_DHCPC_TIMER_REBIND, halftime * 1000, dhcpc);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void pico_dhcp_client_start_reacquisition_timers(struct pico_dhcp_client_cookie *dhcpc)
|
||||
{
|
||||
|
||||
pico_dhcp_client_stop_timers(dhcpc);
|
||||
pico_dhcp_timer_add(PICO_DHCPC_TIMER_T1, dhcpc->t1_time * 1000, dhcpc);
|
||||
pico_dhcp_timer_add(PICO_DHCPC_TIMER_T2, dhcpc->t2_time * 1000, dhcpc);
|
||||
pico_dhcp_timer_add(PICO_DHCPC_TIMER_LEASE, dhcpc->lease_time * 1000, dhcpc);
|
||||
}
|
||||
|
||||
static int pico_dhcp_client_init(struct pico_dhcp_client_cookie *dhcpc)
|
||||
{
|
||||
uint16_t port = PICO_DHCP_CLIENT_PORT;
|
||||
if (!dhcpc)
|
||||
return -1;
|
||||
|
||||
/* adding a link with address 0.0.0.0 and netmask 0.0.0.0,
|
||||
* automatically adds a route for a global broadcast */
|
||||
pico_ipv4_link_add(dhcpc->dev, inaddr_any, bcast_netmask);
|
||||
if (!dhcpc->s)
|
||||
dhcpc->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_client_wakeup);
|
||||
|
||||
if (!dhcpc->s) {
|
||||
pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dhcpc->s->dev = dhcpc->dev;
|
||||
if (pico_socket_bind(dhcpc->s, &inaddr_any, &port) < 0) {
|
||||
pico_socket_close(dhcpc->s);
|
||||
dhcpc->s = NULL;
|
||||
pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER) < 0) {
|
||||
pico_socket_close(dhcpc->s);
|
||||
dhcpc->s = NULL;
|
||||
pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dhcpc->retry = 0;
|
||||
dhcpc->init_timestamp = PICO_TIME_MS();
|
||||
pico_dhcp_client_start_init_timer(dhcpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_dhcp_initiate_negotiation(struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid)
|
||||
{
|
||||
uint8_t retry = 32;
|
||||
uint32_t xid = 0;
|
||||
struct pico_dhcp_client_cookie *dhcpc = NULL;
|
||||
|
||||
if (!dev || !cb || !uid) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!dev->eth) {
|
||||
pico_err = PICO_ERR_EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* attempt to generate a correct xid, else fail */
|
||||
do {
|
||||
xid = pico_rand();
|
||||
} while (!xid && --retry);
|
||||
|
||||
if (!xid) {
|
||||
pico_err = PICO_ERR_EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dhcpc = pico_dhcp_client_add_cookie(xid, dev, cb, uid);
|
||||
if (!dhcpc)
|
||||
return -1;
|
||||
|
||||
dhcpc_dbg("DHCP client: cookie with xid %u\n", dhcpc->xid);
|
||||
*uid = xid;
|
||||
return pico_dhcp_client_init(dhcpc);
|
||||
}
|
||||
|
||||
static void pico_dhcp_client_recv_params(struct pico_dhcp_client_cookie *dhcpc, struct pico_dhcp_opt *opt)
|
||||
{
|
||||
do {
|
||||
switch (opt->code)
|
||||
{
|
||||
case PICO_DHCP_OPT_PAD:
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_END:
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_MSGTYPE:
|
||||
dhcpc->event = opt->ext.msg_type.type;
|
||||
dhcpc_dbg("DHCP client: message type %u\n", dhcpc->event);
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_LEASETIME:
|
||||
dhcpc->lease_time = long_be(opt->ext.lease_time.time);
|
||||
dhcpc_dbg("DHCP client: lease time %u\n", dhcpc->lease_time);
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_RENEWALTIME:
|
||||
dhcpc->t1_time = long_be(opt->ext.renewal_time.time);
|
||||
dhcpc_dbg("DHCP client: renewal time %u\n", dhcpc->t1_time);
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_REBINDINGTIME:
|
||||
dhcpc->t2_time = long_be(opt->ext.rebinding_time.time);
|
||||
dhcpc_dbg("DHCP client: rebinding time %u\n", dhcpc->t2_time);
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_ROUTER:
|
||||
dhcpc->gateway = opt->ext.router.ip;
|
||||
dhcpc_dbg("DHCP client: router %08X\n", dhcpc->gateway.addr);
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_DNS:
|
||||
dhcpc->nameserver[0] = opt->ext.dns1.ip;
|
||||
dhcpc_dbg("DHCP client: dns1 %08X\n", dhcpc->nameserver[0].addr);
|
||||
if (opt->len >= 8) {
|
||||
dhcpc->nameserver[1] = opt->ext.dns2.ip;
|
||||
dhcpc_dbg("DHCP client: dns1 %08X\n", dhcpc->nameserver[1].addr);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_NETMASK:
|
||||
dhcpc->netmask = opt->ext.netmask.ip;
|
||||
dhcpc_dbg("DHCP client: netmask %08X\n", dhcpc->netmask.addr);
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_SERVERID:
|
||||
dhcpc->server_id = opt->ext.server_id.ip;
|
||||
dhcpc_dbg("DHCP client: server ID %08X\n", dhcpc->server_id.addr);
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_OPTOVERLOAD:
|
||||
dhcpc_dbg("DHCP client: WARNING option overload present (not processed)");
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_HOSTNAME:
|
||||
{
|
||||
uint32_t maxlen = PICO_DHCP_HOSTNAME_MAXLEN;
|
||||
if (opt->len < maxlen)
|
||||
maxlen = opt->len;
|
||||
strncpy(dhcpc_host_name, opt->ext.string.txt, maxlen);
|
||||
}
|
||||
break;
|
||||
|
||||
case PICO_DHCP_OPT_DOMAINNAME:
|
||||
{
|
||||
uint32_t maxlen = PICO_DHCP_HOSTNAME_MAXLEN;
|
||||
if (opt->len < maxlen)
|
||||
maxlen = opt->len;
|
||||
strncpy(dhcpc_domain_name, opt->ext.string.txt, maxlen);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dhcpc_dbg("DHCP client: WARNING unsupported option %u\n", opt->code);
|
||||
break;
|
||||
}
|
||||
} while (pico_dhcp_next_option(&opt));
|
||||
|
||||
/* default values for T1 and T2 when not provided */
|
||||
if (!dhcpc->t1_time)
|
||||
dhcpc->t1_time = dhcpc->lease_time >> 1;
|
||||
|
||||
if (!dhcpc->t2_time)
|
||||
dhcpc->t2_time = (dhcpc->lease_time * 875) / 1000;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int recv_offer(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
|
||||
{
|
||||
struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
|
||||
struct pico_dhcp_opt *opt = DHCP_OPT(hdr,0);
|
||||
|
||||
pico_dhcp_client_recv_params(dhcpc, opt);
|
||||
if ((dhcpc->event != PICO_DHCP_MSG_OFFER) || !dhcpc->server_id.addr || !dhcpc->netmask.addr || !dhcpc->lease_time)
|
||||
return -1;
|
||||
|
||||
dhcpc->address.addr = hdr->yiaddr;
|
||||
|
||||
/* we skip state SELECTING, process first offer received */
|
||||
dhcpc->state = DHCP_CLIENT_STATE_REQUESTING;
|
||||
dhcpc->retry = 0;
|
||||
pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
|
||||
pico_dhcp_client_start_requesting_timer(dhcpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int recv_ack(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
|
||||
{
|
||||
struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
|
||||
struct pico_dhcp_opt *opt = DHCP_OPT(hdr,0);
|
||||
struct pico_ip4 address = {
|
||||
0
|
||||
};
|
||||
struct pico_ip4 any_address = {
|
||||
0
|
||||
};
|
||||
|
||||
struct pico_ipv4_link *l;
|
||||
|
||||
pico_dhcp_client_recv_params(dhcpc, opt);
|
||||
if ((dhcpc->event != PICO_DHCP_MSG_ACK) || !dhcpc->server_id.addr || !dhcpc->netmask.addr || !dhcpc->lease_time)
|
||||
return -1;
|
||||
|
||||
/* Issue #20 the server can transmit on ACK a different IP than the one in OFFER */
|
||||
/* RFC2131 ch 4.3.2 ... The client SHOULD use the parameters in the DHCPACK message for configuration */
|
||||
if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING)
|
||||
dhcpc->address.addr = hdr->yiaddr;
|
||||
|
||||
|
||||
/* close the socket used for address (re)acquisition */
|
||||
pico_socket_close(dhcpc->s);
|
||||
dhcpc->s = NULL;
|
||||
|
||||
/* Delete all the links before adding the address */
|
||||
pico_ipv4_link_del(dhcpc->dev, address);
|
||||
l = pico_ipv4_link_by_dev(dhcpc->dev);
|
||||
while(l) {
|
||||
pico_ipv4_link_del(dhcpc->dev, l->address);
|
||||
l = pico_ipv4_link_by_dev_next(dhcpc->dev, l);
|
||||
}
|
||||
pico_ipv4_link_add(dhcpc->dev, dhcpc->address, dhcpc->netmask);
|
||||
|
||||
dbg("DHCP client: renewal time (T1) %u\n", (unsigned int)dhcpc->t1_time);
|
||||
dbg("DHCP client: rebinding time (T2) %u\n", (unsigned int)dhcpc->t2_time);
|
||||
dbg("DHCP client: lease time %u\n", (unsigned int)dhcpc->lease_time);
|
||||
|
||||
/* If router option is received, use it as default gateway */
|
||||
if (dhcpc->gateway.addr != 0U) {
|
||||
pico_ipv4_route_add(any_address, any_address, dhcpc->gateway, 1, NULL);
|
||||
}
|
||||
|
||||
dhcpc->retry = 0;
|
||||
dhcpc->renew_time = dhcpc->t2_time - dhcpc->t1_time;
|
||||
dhcpc->rebind_time = dhcpc->lease_time - dhcpc->t2_time;
|
||||
pico_dhcp_client_start_reacquisition_timers(dhcpc);
|
||||
|
||||
*(dhcpc->uid) = dhcpc->xid;
|
||||
if (dhcpc->cb)
|
||||
dhcpc->cb(dhcpc, PICO_DHCP_SUCCESS);
|
||||
|
||||
dhcpc->state = DHCP_CLIENT_STATE_BOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int renew(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
|
||||
{
|
||||
uint16_t port = PICO_DHCP_CLIENT_PORT;
|
||||
(void) buf;
|
||||
dhcpc->state = DHCP_CLIENT_STATE_RENEWING;
|
||||
dhcpc->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_client_wakeup);
|
||||
if (!dhcpc->s) {
|
||||
dhcpc_dbg("DHCP client ERROR: failure opening socket on renew, aborting DHCP! (%s)\n", strerror(pico_err));
|
||||
if (dhcpc->cb)
|
||||
dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pico_socket_bind(dhcpc->s, &dhcpc->address, &port) != 0) {
|
||||
dhcpc_dbg("DHCP client ERROR: failure binding socket on renew, aborting DHCP! (%s)\n", strerror(pico_err));
|
||||
pico_socket_close(dhcpc->s);
|
||||
dhcpc->s = NULL;
|
||||
if (dhcpc->cb)
|
||||
dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
dhcpc->retry = 0;
|
||||
pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
|
||||
pico_dhcp_client_start_renewing_timer(dhcpc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rebind(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
|
||||
{
|
||||
(void) buf;
|
||||
|
||||
dhcpc->state = DHCP_CLIENT_STATE_REBINDING;
|
||||
dhcpc->retry = 0;
|
||||
pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
|
||||
pico_dhcp_client_start_rebinding_timer(dhcpc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reset(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
|
||||
{
|
||||
struct pico_ip4 address = {
|
||||
0
|
||||
};
|
||||
(void) buf;
|
||||
|
||||
if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING)
|
||||
address.addr = PICO_IP4_ANY;
|
||||
else
|
||||
address.addr = dhcpc->address.addr;
|
||||
|
||||
/* close the socket used for address (re)acquisition */
|
||||
pico_socket_close(dhcpc->s);
|
||||
dhcpc->s = NULL;
|
||||
/* delete the link with the currently in use address */
|
||||
pico_ipv4_link_del(dhcpc->dev, address);
|
||||
|
||||
if (dhcpc->cb)
|
||||
dhcpc->cb(dhcpc, PICO_DHCP_RESET);
|
||||
|
||||
if (dhcpc->state < DHCP_CLIENT_STATE_BOUND)
|
||||
{
|
||||
/* pico_dhcp_client_timer_stop(dhcpc, PICO_DHCPC_TIMER_INIT); */
|
||||
}
|
||||
|
||||
|
||||
dhcpc->state = DHCP_CLIENT_STATE_INIT;
|
||||
pico_dhcp_client_stop_timers(dhcpc);
|
||||
pico_dhcp_client_init(dhcpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int retransmit(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
|
||||
{
|
||||
(void) buf;
|
||||
switch (dhcpc->state)
|
||||
{
|
||||
case DHCP_CLIENT_STATE_INIT:
|
||||
pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER);
|
||||
pico_dhcp_client_start_init_timer(dhcpc);
|
||||
break;
|
||||
|
||||
case DHCP_CLIENT_STATE_REQUESTING:
|
||||
pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
|
||||
pico_dhcp_client_start_requesting_timer(dhcpc);
|
||||
break;
|
||||
|
||||
case DHCP_CLIENT_STATE_RENEWING:
|
||||
pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
|
||||
pico_dhcp_client_start_renewing_timer(dhcpc);
|
||||
break;
|
||||
|
||||
case DHCP_CLIENT_STATE_REBINDING:
|
||||
pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER);
|
||||
pico_dhcp_client_start_rebinding_timer(dhcpc);
|
||||
break;
|
||||
|
||||
default:
|
||||
dhcpc_dbg("DHCP client WARNING: retransmit in incorrect state (%u)!\n", dhcpc->state);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dhcp_action_entry {
|
||||
int (*offer)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
|
||||
int (*ack)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
|
||||
int (*nak)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
|
||||
int (*timer1)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
|
||||
int (*timer2)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
|
||||
int (*timer_lease)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
|
||||
int (*timer_retransmit)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
|
||||
};
|
||||
|
||||
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 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 },
|
||||
/* state requesting */ { NULL, recv_ack, reset, NULL, NULL, NULL, retransmit },
|
||||
/* state bound */ { NULL, NULL, NULL, renew, NULL, NULL, NULL },
|
||||
/* state renewing */ { NULL, recv_ack, reset, NULL, rebind, NULL, retransmit },
|
||||
/* state rebinding */ { NULL, recv_ack, reset, NULL, NULL, reset, retransmit },
|
||||
};
|
||||
|
||||
/* TIMERS REMARK:
|
||||
* In state bound we have T1, T2 and the lease timer running. If T1 goes off, we attempt to renew.
|
||||
* If the renew succeeds a new T1, T2 and lease timer is started. The former T2 and lease timer is
|
||||
* still running though. This poses no concerns as the T2 and lease event in state bound have a NULL
|
||||
* pointer in the fsm. If the former T2 or lease timer goes off, nothing happens. Same situation
|
||||
* applies for T2 and a succesfull rebind. */
|
||||
|
||||
static void pico_dhcp_state_machine(uint8_t event, struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case PICO_DHCP_MSG_OFFER:
|
||||
dhcpc_dbg("DHCP client: received OFFER\n");
|
||||
if (dhcp_fsm[dhcpc->state].offer)
|
||||
dhcp_fsm[dhcpc->state].offer(dhcpc, buf);
|
||||
|
||||
break;
|
||||
|
||||
case PICO_DHCP_MSG_ACK:
|
||||
dhcpc_dbg("DHCP client: received ACK\n");
|
||||
if (dhcp_fsm[dhcpc->state].ack)
|
||||
dhcp_fsm[dhcpc->state].ack(dhcpc, buf);
|
||||
|
||||
break;
|
||||
|
||||
case PICO_DHCP_MSG_NAK:
|
||||
dhcpc_dbg("DHCP client: received NAK\n");
|
||||
if (dhcp_fsm[dhcpc->state].nak)
|
||||
dhcp_fsm[dhcpc->state].nak(dhcpc, buf);
|
||||
|
||||
break;
|
||||
|
||||
case PICO_DHCP_EVENT_T1:
|
||||
dhcpc_dbg("DHCP client: received T1 timeout\n");
|
||||
if (dhcp_fsm[dhcpc->state].timer1)
|
||||
dhcp_fsm[dhcpc->state].timer1(dhcpc, NULL);
|
||||
|
||||
break;
|
||||
|
||||
case PICO_DHCP_EVENT_T2:
|
||||
dhcpc_dbg("DHCP client: received T2 timeout\n");
|
||||
if (dhcp_fsm[dhcpc->state].timer2)
|
||||
dhcp_fsm[dhcpc->state].timer2(dhcpc, NULL);
|
||||
|
||||
break;
|
||||
|
||||
case PICO_DHCP_EVENT_LEASE:
|
||||
dhcpc_dbg("DHCP client: received LEASE timeout\n");
|
||||
if (dhcp_fsm[dhcpc->state].timer_lease)
|
||||
dhcp_fsm[dhcpc->state].timer_lease(dhcpc, NULL);
|
||||
|
||||
break;
|
||||
|
||||
case PICO_DHCP_EVENT_RETRANSMIT:
|
||||
dhcpc_dbg("DHCP client: received RETRANSMIT timeout\n");
|
||||
if (dhcp_fsm[dhcpc->state].timer_retransmit)
|
||||
dhcp_fsm[dhcpc->state].timer_retransmit(dhcpc, NULL);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
dhcpc_dbg("DHCP client WARNING: unrecognized event (%u)!\n", dhcpc->event);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int16_t pico_dhcp_client_opt_parse(void *ptr, uint16_t len)
|
||||
{
|
||||
uint32_t optlen = len - (uint32_t)sizeof(struct pico_dhcp_hdr);
|
||||
struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)ptr;
|
||||
struct pico_dhcp_opt *opt = DHCP_OPT(hdr,0);
|
||||
|
||||
if (hdr->dhcp_magic != PICO_DHCPD_MAGIC_COOKIE)
|
||||
return -1;
|
||||
|
||||
if (!pico_dhcp_are_options_valid(opt, (int32_t)optlen))
|
||||
return -1;
|
||||
|
||||
do {
|
||||
if (opt->code == PICO_DHCP_OPT_MSGTYPE)
|
||||
return opt->ext.msg_type.type;
|
||||
} while (pico_dhcp_next_option(&opt));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int8_t pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_t msg_type)
|
||||
{
|
||||
int32_t r = 0;
|
||||
uint16_t optlen = 0, offset = 0;
|
||||
struct pico_ip4 destination = {
|
||||
.addr = 0xFFFFFFFF
|
||||
};
|
||||
struct pico_dhcp_hdr *hdr = NULL;
|
||||
|
||||
|
||||
/* RFC 2131 3.1.3: Request is always BROADCAST */
|
||||
|
||||
/* Set again default route for the bcast request */
|
||||
pico_ipv4_route_set_bcast_link(pico_ipv4_link_by_dev(dhcpc->dev));
|
||||
|
||||
switch (msg_type)
|
||||
{
|
||||
case PICO_DHCP_MSG_DISCOVER:
|
||||
dhcpc_dbg("DHCP client: sent DHCPDISCOVER\n");
|
||||
optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_MAXMSGSIZE + PICO_DHCP_OPTLEN_PARAMLIST + PICO_DHCP_OPTLEN_END;
|
||||
hdr = PICO_ZALLOC((size_t)(sizeof(struct pico_dhcp_hdr) + optlen));
|
||||
if (!hdr) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* specific options */
|
||||
offset = (uint16_t)(offset + pico_dhcp_opt_maxmsgsize(DHCP_OPT(hdr,offset), DHCP_CLIENT_MAXMSGZISE));
|
||||
break;
|
||||
|
||||
case PICO_DHCP_MSG_REQUEST:
|
||||
optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_MAXMSGSIZE + PICO_DHCP_OPTLEN_PARAMLIST + PICO_DHCP_OPTLEN_REQIP + PICO_DHCP_OPTLEN_SERVERID
|
||||
+ PICO_DHCP_OPTLEN_END;
|
||||
hdr = PICO_ZALLOC(sizeof(struct pico_dhcp_hdr) + optlen);
|
||||
if (!hdr) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* specific options */
|
||||
offset = (uint16_t)(offset + pico_dhcp_opt_maxmsgsize(DHCP_OPT(hdr,offset), DHCP_CLIENT_MAXMSGZISE));
|
||||
if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING) {
|
||||
offset = (uint16_t)(offset + pico_dhcp_opt_reqip(DHCP_OPT(hdr,offset), &dhcpc->address));
|
||||
offset = (uint16_t)(offset + pico_dhcp_opt_serverid(DHCP_OPT(hdr,offset), &dhcpc->server_id));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* common options */
|
||||
offset = (uint16_t)(offset + pico_dhcp_opt_msgtype(DHCP_OPT(hdr,offset), msg_type));
|
||||
offset = (uint16_t)(offset + pico_dhcp_opt_paramlist(DHCP_OPT(hdr,offset)));
|
||||
offset = (uint16_t)(offset + pico_dhcp_opt_end(DHCP_OPT(hdr,offset)));
|
||||
|
||||
switch (dhcpc->state)
|
||||
{
|
||||
case DHCP_CLIENT_STATE_BOUND:
|
||||
destination.addr = dhcpc->server_id.addr;
|
||||
hdr->ciaddr = dhcpc->address.addr;
|
||||
break;
|
||||
|
||||
case DHCP_CLIENT_STATE_RENEWING:
|
||||
destination.addr = dhcpc->server_id.addr;
|
||||
hdr->ciaddr = dhcpc->address.addr;
|
||||
break;
|
||||
|
||||
case DHCP_CLIENT_STATE_REBINDING:
|
||||
hdr->ciaddr = dhcpc->address.addr;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
/* header information */
|
||||
hdr->op = PICO_DHCP_OP_REQUEST;
|
||||
hdr->htype = PICO_DHCP_HTYPE_ETH;
|
||||
hdr->hlen = PICO_SIZE_ETH;
|
||||
hdr->xid = dhcpc->xid;
|
||||
/* hdr->flags = short_be(PICO_DHCP_FLAG_BROADCAST); / * Nope: see bug #96! * / */
|
||||
hdr->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
|
||||
/* copy client hardware address */
|
||||
memcpy(hdr->hwaddr, &dhcpc->dev->eth->mac, PICO_SIZE_ETH);
|
||||
|
||||
if (destination.addr == PICO_IP4_BCAST)
|
||||
pico_ipv4_route_set_bcast_link(pico_ipv4_link_get(&dhcpc->address));
|
||||
|
||||
r = pico_socket_sendto(dhcpc->s, hdr, (int)(sizeof(struct pico_dhcp_hdr) + optlen), &destination, PICO_DHCPD_PORT);
|
||||
PICO_FREE(hdr);
|
||||
if (r < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s)
|
||||
{
|
||||
|
||||
uint8_t *buf;
|
||||
int r = 0;
|
||||
struct pico_dhcp_hdr *hdr = NULL;
|
||||
struct pico_dhcp_client_cookie *dhcpc = NULL;
|
||||
|
||||
if ((ev & PICO_SOCK_EV_RD) == 0)
|
||||
return;
|
||||
|
||||
buf = PICO_ZALLOC(DHCP_CLIENT_MAXMSGZISE);
|
||||
if (!buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
r = pico_socket_recvfrom(s, buf, DHCP_CLIENT_MAXMSGZISE, NULL, NULL);
|
||||
if (r < 0)
|
||||
goto out_discard_buf;
|
||||
|
||||
/* If the 'xid' of an arriving message does not match the 'xid'
|
||||
* of the most recent transmitted message, the message must be
|
||||
* silently discarded. */
|
||||
hdr = (struct pico_dhcp_hdr *)buf;
|
||||
dhcpc = pico_dhcp_client_find_cookie(hdr->xid);
|
||||
if (!dhcpc)
|
||||
goto out_discard_buf;
|
||||
|
||||
dhcpc->event = (uint8_t)pico_dhcp_client_opt_parse(buf, (uint16_t)r);
|
||||
pico_dhcp_state_machine(dhcpc->event, dhcpc, buf);
|
||||
|
||||
out_discard_buf:
|
||||
PICO_FREE(buf);
|
||||
}
|
||||
|
||||
void *pico_dhcp_get_identifier(uint32_t xid)
|
||||
{
|
||||
return (void *)pico_dhcp_client_find_cookie(xid);
|
||||
}
|
||||
|
||||
struct pico_ip4 pico_dhcp_get_address(void*dhcpc)
|
||||
{
|
||||
return ((struct pico_dhcp_client_cookie*)dhcpc)->address;
|
||||
}
|
||||
|
||||
struct pico_ip4 pico_dhcp_get_gateway(void*dhcpc)
|
||||
{
|
||||
return ((struct pico_dhcp_client_cookie*)dhcpc)->gateway;
|
||||
}
|
||||
|
||||
struct pico_ip4 pico_dhcp_get_netmask(void *dhcpc)
|
||||
{
|
||||
return ((struct pico_dhcp_client_cookie*)dhcpc)->netmask;
|
||||
}
|
||||
|
||||
struct pico_ip4 pico_dhcp_get_nameserver(void*dhcpc, int index)
|
||||
{
|
||||
struct pico_ip4 fault = {
|
||||
.addr = 0xFFFFFFFFU
|
||||
};
|
||||
if ((index != 0) && (index != 1))
|
||||
return fault;
|
||||
|
||||
return ((struct pico_dhcp_client_cookie*)dhcpc)->nameserver[index];
|
||||
}
|
||||
|
||||
int pico_dhcp_client_abort(uint32_t xid)
|
||||
{
|
||||
return pico_dhcp_client_del_cookie(xid);
|
||||
}
|
||||
|
||||
|
||||
char *pico_dhcp_get_hostname(void)
|
||||
{
|
||||
return dhcpc_host_name;
|
||||
}
|
||||
|
||||
char *pico_dhcp_get_domain(void)
|
||||
{
|
||||
return dhcpc_domain_name;
|
||||
}
|
||||
|
||||
#endif
|
||||
32
ext/picotcp/modules/pico_dhcp_client.h
Normal file
32
ext/picotcp/modules/pico_dhcp_client.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_DHCP_CLIENT
|
||||
#define INCLUDE_PICO_DHCP_CLIENT
|
||||
#include "pico_defines.h"
|
||||
#ifdef PICO_SUPPORT_UDP
|
||||
#include "pico_dhcp_common.h"
|
||||
#include "pico_addressing.h"
|
||||
#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_get_identifier(uint32_t xid);
|
||||
struct pico_ip4 pico_dhcp_get_address(void *cli);
|
||||
struct pico_ip4 pico_dhcp_get_gateway(void *cli);
|
||||
struct pico_ip4 pico_dhcp_get_netmask(void *cli);
|
||||
struct pico_ip4 pico_dhcp_get_nameserver(void*cli, int index);
|
||||
int pico_dhcp_client_abort(uint32_t xid);
|
||||
char *pico_dhcp_get_hostname(void);
|
||||
char *pico_dhcp_get_domain(void);
|
||||
|
||||
/* possible codes for the callback */
|
||||
#define PICO_DHCP_SUCCESS 0
|
||||
#define PICO_DHCP_ERROR 1
|
||||
#define PICO_DHCP_RESET 2
|
||||
|
||||
#endif
|
||||
#endif
|
||||
190
ext/picotcp/modules/pico_dhcp_common.c
Normal file
190
ext/picotcp/modules/pico_dhcp_common.c
Normal file
@@ -0,0 +1,190 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
Authors: Frederik Van Slycken
|
||||
*********************************************************************/
|
||||
|
||||
#include "pico_config.h"
|
||||
#include "pico_stack.h"
|
||||
#include "pico_dhcp_common.h"
|
||||
|
||||
#if defined (PICO_SUPPORT_DHCPC) || defined (PICO_SUPPORT_DHCPD)
|
||||
/* pico_dhcp_are_options_valid needs to be called first to prevent illegal memory access */
|
||||
/* The argument pointer is moved forward to the next option */
|
||||
struct pico_dhcp_opt *pico_dhcp_next_option(struct pico_dhcp_opt **ptr)
|
||||
{
|
||||
uint8_t **p = (uint8_t **)ptr;
|
||||
struct pico_dhcp_opt *opt = *ptr;
|
||||
|
||||
if (opt->code == PICO_DHCP_OPT_END)
|
||||
return NULL;
|
||||
|
||||
if (opt->code == PICO_DHCP_OPT_PAD) {
|
||||
*p += 1;
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
*p += (opt->len + 2); /* (len + 2) to account for code and len octet */
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_are_options_valid(void *ptr, int32_t len)
|
||||
{
|
||||
uint8_t optlen = 0, *p = ptr;
|
||||
|
||||
while (len > 0) {
|
||||
switch (*p)
|
||||
{
|
||||
case PICO_DHCP_OPT_END:
|
||||
return 1;
|
||||
|
||||
case PICO_DHCP_OPT_PAD:
|
||||
p++;
|
||||
len--;
|
||||
break;
|
||||
|
||||
default:
|
||||
p++; /* move pointer from code octet to len octet */
|
||||
len--;
|
||||
if ((len <= 0) || (len - (*p + 1) < 0)) /* (*p + 1) to account for len octet */
|
||||
return 0;
|
||||
|
||||
optlen = *p;
|
||||
p += optlen + 1;
|
||||
len -= optlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_netmask(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: netmask */
|
||||
opt->code = PICO_DHCP_OPT_NETMASK;
|
||||
opt->len = PICO_DHCP_OPTLEN_NETMASK - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.netmask.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_NETMASK;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_router(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: router */
|
||||
opt->code = PICO_DHCP_OPT_ROUTER;
|
||||
opt->len = PICO_DHCP_OPTLEN_ROUTER - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.router.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_ROUTER;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_dns(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: dns */
|
||||
opt->code = PICO_DHCP_OPT_DNS;
|
||||
opt->len = PICO_DHCP_OPTLEN_DNS - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.dns1.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_DNS;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_broadcast(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: broadcast */
|
||||
opt->code = PICO_DHCP_OPT_BROADCAST;
|
||||
opt->len = PICO_DHCP_OPTLEN_BROADCAST - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.broadcast.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_BROADCAST;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_reqip(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: request IP address */
|
||||
opt->code = PICO_DHCP_OPT_REQIP;
|
||||
opt->len = PICO_DHCP_OPTLEN_REQIP - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.req_ip.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_REQIP;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_leasetime(void *ptr, uint32_t time)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: lease time */
|
||||
opt->code = PICO_DHCP_OPT_LEASETIME;
|
||||
opt->len = PICO_DHCP_OPTLEN_LEASETIME - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.lease_time.time = time;
|
||||
return PICO_DHCP_OPTLEN_LEASETIME;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_msgtype(void *ptr, uint8_t type)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: message type */
|
||||
opt->code = PICO_DHCP_OPT_MSGTYPE;
|
||||
opt->len = PICO_DHCP_OPTLEN_MSGTYPE - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.msg_type.type = type;
|
||||
return PICO_DHCP_OPTLEN_MSGTYPE;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_serverid(void *ptr, struct pico_ip4 *ip)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: server identifier */
|
||||
opt->code = PICO_DHCP_OPT_SERVERID;
|
||||
opt->len = PICO_DHCP_OPTLEN_SERVERID - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.server_id.ip = *ip;
|
||||
return PICO_DHCP_OPTLEN_SERVERID;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_paramlist(void *ptr)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
uint8_t *param_code = &(opt->ext.param_list.code[0]);
|
||||
|
||||
/* option: parameter list */
|
||||
opt->code = PICO_DHCP_OPT_PARAMLIST;
|
||||
opt->len = PICO_DHCP_OPTLEN_PARAMLIST - PICO_DHCP_OPTLEN_HDR;
|
||||
param_code[0] = PICO_DHCP_OPT_NETMASK;
|
||||
param_code[1] = PICO_DHCP_OPT_TIME;
|
||||
param_code[2] = PICO_DHCP_OPT_ROUTER;
|
||||
param_code[3] = PICO_DHCP_OPT_HOSTNAME;
|
||||
param_code[4] = PICO_DHCP_OPT_RENEWALTIME;
|
||||
param_code[5] = PICO_DHCP_OPT_REBINDINGTIME;
|
||||
param_code[6] = PICO_DHCP_OPT_DNS;
|
||||
return PICO_DHCP_OPTLEN_PARAMLIST;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_maxmsgsize(void *ptr, uint16_t size)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
|
||||
|
||||
/* option: maximum message size */
|
||||
opt->code = PICO_DHCP_OPT_MAXMSGSIZE;
|
||||
opt->len = PICO_DHCP_OPTLEN_MAXMSGSIZE - PICO_DHCP_OPTLEN_HDR;
|
||||
opt->ext.max_msg_size.size = short_be(size);
|
||||
return PICO_DHCP_OPTLEN_MAXMSGSIZE;
|
||||
}
|
||||
|
||||
uint8_t pico_dhcp_opt_end(void *ptr)
|
||||
{
|
||||
uint8_t *opt = (uint8_t *)ptr;
|
||||
|
||||
/* option: end of options */
|
||||
*opt = PICO_DHCP_OPT_END;
|
||||
return PICO_DHCP_OPTLEN_END;
|
||||
}
|
||||
|
||||
#endif
|
||||
191
ext/picotcp/modules/pico_dhcp_common.h
Normal file
191
ext/picotcp/modules/pico_dhcp_common.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_DHCP_COMMON
|
||||
#define INCLUDE_PICO_DHCP_COMMON
|
||||
#include "pico_config.h"
|
||||
#include "pico_addressing.h"
|
||||
|
||||
#define PICO_DHCPD_PORT (short_be(67))
|
||||
#define PICO_DHCP_CLIENT_PORT (short_be(68))
|
||||
#define PICO_DHCPD_MAGIC_COOKIE (long_be(0x63825363))
|
||||
#define PICO_DHCP_HTYPE_ETH 1
|
||||
|
||||
/* Macro to get DHCP option field */
|
||||
#define DHCP_OPT(hdr,off) ((struct pico_dhcp_opt *)(((uint8_t *)hdr)+sizeof(struct pico_dhcp_hdr) + off))
|
||||
|
||||
/* flags */
|
||||
#define PICO_DHCP_FLAG_BROADCAST 0x8000
|
||||
|
||||
/* options */
|
||||
#define PICO_DHCP_OPT_PAD 0x00
|
||||
#define PICO_DHCP_OPT_NETMASK 0x01
|
||||
#define PICO_DHCP_OPT_TIME 0x02
|
||||
#define PICO_DHCP_OPT_ROUTER 0x03
|
||||
#define PICO_DHCP_OPT_DNS 0x06
|
||||
#define PICO_DHCP_OPT_HOSTNAME 0x0c
|
||||
#define PICO_DHCP_OPT_DOMAINNAME 0x0f
|
||||
#define PICO_DHCP_OPT_MTU 0x1a
|
||||
#define PICO_DHCP_OPT_BROADCAST 0x1c
|
||||
#define PICO_DHCP_OPT_NETBIOSNS 0x2c
|
||||
#define PICO_DHCP_OPT_NETBIOSSCOPE 0x2f
|
||||
#define PICO_DHCP_OPT_REQIP 0x32
|
||||
#define PICO_DHCP_OPT_LEASETIME 0x33
|
||||
#define PICO_DHCP_OPT_OPTOVERLOAD 0x34
|
||||
#define PICO_DHCP_OPT_MSGTYPE 0x35
|
||||
#define PICO_DHCP_OPT_SERVERID 0x36
|
||||
#define PICO_DHCP_OPT_PARAMLIST 0x37
|
||||
#define PICO_DHCP_OPT_MESSAGE 0x38
|
||||
#define PICO_DHCP_OPT_MAXMSGSIZE 0x39
|
||||
#define PICO_DHCP_OPT_RENEWALTIME 0x3a
|
||||
#define PICO_DHCP_OPT_REBINDINGTIME 0x3b
|
||||
#define PICO_DHCP_OPT_VENDORID 0x3c
|
||||
#define PICO_DHCP_OPT_CLIENTID 0x3d
|
||||
#define PICO_DHCP_OPT_DOMAINSEARCH 0x77
|
||||
#define PICO_DHCP_OPT_STATICROUTE 0x79
|
||||
#define PICO_DHCP_OPT_END 0xFF
|
||||
|
||||
/* options len */
|
||||
#define PICO_DHCP_OPTLEN_HDR 2 /* account for code and len field */
|
||||
#define PICO_DHCP_OPTLEN_NETMASK 6
|
||||
#define PICO_DHCP_OPTLEN_ROUTER 6
|
||||
#define PICO_DHCP_OPTLEN_DNS 6
|
||||
#define PICO_DHCP_OPTLEN_BROADCAST 6
|
||||
#define PICO_DHCP_OPTLEN_REQIP 6
|
||||
#define PICO_DHCP_OPTLEN_LEASETIME 6
|
||||
#define PICO_DHCP_OPTLEN_OPTOVERLOAD 3
|
||||
#define PICO_DHCP_OPTLEN_MSGTYPE 3
|
||||
#define PICO_DHCP_OPTLEN_SERVERID 6
|
||||
#define PICO_DHCP_OPTLEN_PARAMLIST 9 /* PicoTCP specific */
|
||||
#define PICO_DHCP_OPTLEN_MAXMSGSIZE 4
|
||||
#define PICO_DHCP_OPTLEN_RENEWALTIME 6
|
||||
#define PICO_DHCP_OPTLEN_REBINDINGTIME 6
|
||||
#define PICO_DHCP_OPTLEN_END 1
|
||||
|
||||
/* op codes */
|
||||
#define PICO_DHCP_OP_REQUEST 1
|
||||
#define PICO_DHCP_OP_REPLY 2
|
||||
|
||||
/* rfc message types */
|
||||
#define PICO_DHCP_MSG_DISCOVER 1
|
||||
#define PICO_DHCP_MSG_OFFER 2
|
||||
#define PICO_DHCP_MSG_REQUEST 3
|
||||
#define PICO_DHCP_MSG_DECLINE 4
|
||||
#define PICO_DHCP_MSG_ACK 5
|
||||
#define PICO_DHCP_MSG_NAK 6
|
||||
#define PICO_DHCP_MSG_RELEASE 7
|
||||
#define PICO_DHCP_MSG_INFORM 8
|
||||
|
||||
/* custom message types */
|
||||
#define PICO_DHCP_EVENT_T1 9
|
||||
#define PICO_DHCP_EVENT_T2 10
|
||||
#define PICO_DHCP_EVENT_LEASE 11
|
||||
#define PICO_DHCP_EVENT_RETRANSMIT 12
|
||||
#define PICO_DHCP_EVENT_NONE 0xff
|
||||
|
||||
PACKED_STRUCT_DEF pico_dhcp_hdr
|
||||
{
|
||||
uint8_t op;
|
||||
uint8_t htype;
|
||||
uint8_t hlen;
|
||||
uint8_t hops; /* zero */
|
||||
uint32_t xid; /* store this in the request */
|
||||
uint16_t secs; /* ignore */
|
||||
uint16_t flags;
|
||||
uint32_t ciaddr; /* client address - if asking for renewal */
|
||||
uint32_t yiaddr; /* your address (client) */
|
||||
uint32_t siaddr; /* dhcp offered address */
|
||||
uint32_t giaddr; /* relay agent, bootp. */
|
||||
uint8_t hwaddr[6];
|
||||
uint8_t hwaddr_padding[10];
|
||||
char hostname[64];
|
||||
char bootp_filename[128];
|
||||
uint32_t dhcp_magic;
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_dhcp_opt
|
||||
{
|
||||
uint8_t code;
|
||||
uint8_t len;
|
||||
PACKED_UNION_DEF dhcp_opt_ext_u {
|
||||
PEDANTIC_STRUCT_DEF netmask_s {
|
||||
struct pico_ip4 ip;
|
||||
} netmask;
|
||||
PEDANTIC_STRUCT_DEF router_s {
|
||||
struct pico_ip4 ip;
|
||||
} router;
|
||||
PEDANTIC_STRUCT_DEF dns_s {
|
||||
struct pico_ip4 ip;
|
||||
} dns1;
|
||||
struct dns_s dns2;
|
||||
PEDANTIC_STRUCT_DEF broadcast_s {
|
||||
struct pico_ip4 ip;
|
||||
} broadcast;
|
||||
PEDANTIC_STRUCT_DEF req_ip_s {
|
||||
struct pico_ip4 ip;
|
||||
} req_ip;
|
||||
PEDANTIC_STRUCT_DEF lease_time_s {
|
||||
uint32_t time;
|
||||
} lease_time;
|
||||
PEDANTIC_STRUCT_DEF opt_overload_s {
|
||||
uint8_t value;
|
||||
} opt_overload;
|
||||
PEDANTIC_STRUCT_DEF tftp_server_s {
|
||||
char name[1];
|
||||
} tftp_server;
|
||||
PEDANTIC_STRUCT_DEF bootfile_s {
|
||||
char name[1];
|
||||
} bootfile;
|
||||
PEDANTIC_STRUCT_DEF msg_type_s {
|
||||
uint8_t type;
|
||||
} msg_type;
|
||||
PEDANTIC_STRUCT_DEF server_id_s {
|
||||
struct pico_ip4 ip;
|
||||
} server_id;
|
||||
PEDANTIC_STRUCT_DEF param_list_s {
|
||||
uint8_t code[1];
|
||||
} param_list;
|
||||
PEDANTIC_STRUCT_DEF message_s {
|
||||
char error[1];
|
||||
} message;
|
||||
PEDANTIC_STRUCT_DEF max_msg_size_s {
|
||||
uint16_t size;
|
||||
} max_msg_size;
|
||||
PEDANTIC_STRUCT_DEF renewal_time_s {
|
||||
uint32_t time;
|
||||
} renewal_time;
|
||||
PEDANTIC_STRUCT_DEF rebinding_time_s {
|
||||
uint32_t time;
|
||||
} rebinding_time;
|
||||
PEDANTIC_STRUCT_DEF vendor_id_s {
|
||||
uint8_t id[1];
|
||||
} vendor_id;
|
||||
PEDANTIC_STRUCT_DEF client_id_s {
|
||||
uint8_t id[1];
|
||||
} client_id;
|
||||
PEDANTIC_STRUCT_DEF text_s {
|
||||
char txt[1];
|
||||
} string;
|
||||
} ext;
|
||||
};
|
||||
|
||||
uint8_t dhcp_get_next_option(uint8_t *begin, uint8_t *data, int *len, uint8_t **nextopt);
|
||||
struct pico_dhcp_opt *pico_dhcp_next_option(struct pico_dhcp_opt **ptr);
|
||||
uint8_t pico_dhcp_are_options_valid(void *ptr, int32_t len);
|
||||
|
||||
uint8_t pico_dhcp_opt_netmask(void *ptr, struct pico_ip4 *ip);
|
||||
uint8_t pico_dhcp_opt_router(void *ptr, struct pico_ip4 *ip);
|
||||
uint8_t pico_dhcp_opt_dns(void *ptr, struct pico_ip4 *ip);
|
||||
uint8_t pico_dhcp_opt_broadcast(void *ptr, struct pico_ip4 *ip);
|
||||
uint8_t pico_dhcp_opt_reqip(void *ptr, struct pico_ip4 *ip);
|
||||
uint8_t pico_dhcp_opt_leasetime(void *ptr, uint32_t time);
|
||||
uint8_t pico_dhcp_opt_msgtype(void *ptr, uint8_t type);
|
||||
uint8_t pico_dhcp_opt_serverid(void *ptr, struct pico_ip4 *ip);
|
||||
uint8_t pico_dhcp_opt_paramlist(void *ptr);
|
||||
uint8_t pico_dhcp_opt_maxmsgsize(void *ptr, uint16_t size);
|
||||
uint8_t pico_dhcp_opt_end(void *ptr);
|
||||
#endif
|
||||
411
ext/picotcp/modules/pico_dhcp_server.c
Normal file
411
ext/picotcp/modules/pico_dhcp_server.c
Normal file
@@ -0,0 +1,411 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
|
||||
Authors: Frederik Van Slycken, Kristof Roelants
|
||||
*********************************************************************/
|
||||
|
||||
#include "pico_dhcp_server.h"
|
||||
#include "pico_config.h"
|
||||
#include "pico_addressing.h"
|
||||
#include "pico_socket.h"
|
||||
#include "pico_udp.h"
|
||||
#include "pico_stack.h"
|
||||
#include "pico_arp.h"
|
||||
|
||||
#if (defined PICO_SUPPORT_DHCPD && defined PICO_SUPPORT_UDP)
|
||||
|
||||
#define dhcps_dbg(...) do {} while(0)
|
||||
/* #define dhcps_dbg dbg */
|
||||
|
||||
/* default configurations */
|
||||
#define DHCP_SERVER_OPENDNS long_be(0xd043dede) /* OpenDNS DNS server 208.67.222.222 */
|
||||
#define DHCP_SERVER_POOL_START long_be(0x00000064)
|
||||
#define DHCP_SERVER_POOL_END long_be(0x000000fe)
|
||||
#define DHCP_SERVER_LEASE_TIME long_be(0x00000078)
|
||||
|
||||
/* maximum size of a DHCP message */
|
||||
#define DHCP_SERVER_MAXMSGSIZE (PICO_IP_MRU - sizeof(struct pico_ipv4_hdr) - sizeof(struct pico_udp_hdr))
|
||||
|
||||
enum dhcp_server_state {
|
||||
PICO_DHCP_STATE_DISCOVER = 0,
|
||||
PICO_DHCP_STATE_OFFER,
|
||||
PICO_DHCP_STATE_REQUEST,
|
||||
PICO_DHCP_STATE_BOUND,
|
||||
PICO_DHCP_STATE_RENEWING
|
||||
};
|
||||
|
||||
struct pico_dhcp_server_negotiation {
|
||||
uint32_t xid;
|
||||
enum dhcp_server_state state;
|
||||
struct pico_dhcp_server_setting *dhcps;
|
||||
struct pico_ip4 ciaddr;
|
||||
struct pico_eth hwaddr;
|
||||
uint8_t bcast;
|
||||
};
|
||||
|
||||
static inline int ip_address_is_in_dhcp_range(struct pico_dhcp_server_negotiation *n, uint32_t x)
|
||||
{
|
||||
uint32_t ip_hostendian = long_be(x);
|
||||
if (ip_hostendian < long_be(n->dhcps->pool_start))
|
||||
return 0;
|
||||
|
||||
if (ip_hostendian > long_be(n->dhcps->pool_end))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void pico_dhcpd_wakeup(uint16_t ev, struct pico_socket *s);
|
||||
|
||||
static int dhcp_settings_cmp(void *ka, void *kb)
|
||||
{
|
||||
struct pico_dhcp_server_setting *a = ka, *b = kb;
|
||||
if (a->dev == b->dev)
|
||||
return 0;
|
||||
|
||||
return (a->dev < b->dev) ? (-1) : (1);
|
||||
}
|
||||
PICO_TREE_DECLARE(DHCPSettings, dhcp_settings_cmp);
|
||||
|
||||
static int dhcp_negotiations_cmp(void *ka, void *kb)
|
||||
{
|
||||
struct pico_dhcp_server_negotiation *a = ka, *b = kb;
|
||||
if (a->xid == b->xid)
|
||||
return 0;
|
||||
|
||||
return (a->xid < b->xid) ? (-1) : (1);
|
||||
}
|
||||
PICO_TREE_DECLARE(DHCPNegotiations, dhcp_negotiations_cmp);
|
||||
|
||||
|
||||
static inline void dhcps_set_default_pool_start_if_not_provided(struct pico_dhcp_server_setting *dhcps)
|
||||
{
|
||||
if (!dhcps->pool_start)
|
||||
dhcps->pool_start = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_START;
|
||||
}
|
||||
|
||||
static inline void dhcps_set_default_pool_end_if_not_provided(struct pico_dhcp_server_setting *dhcps)
|
||||
{
|
||||
if (!dhcps->pool_end)
|
||||
dhcps->pool_end = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_END;
|
||||
}
|
||||
static inline void dhcps_set_default_lease_time_if_not_provided(struct pico_dhcp_server_setting *dhcps)
|
||||
{
|
||||
if (!dhcps->lease_time)
|
||||
dhcps->lease_time = DHCP_SERVER_LEASE_TIME;
|
||||
}
|
||||
|
||||
static inline struct pico_dhcp_server_setting *dhcps_try_open_socket(struct pico_dhcp_server_setting *dhcps)
|
||||
{
|
||||
uint16_t port = PICO_DHCPD_PORT;
|
||||
dhcps->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcpd_wakeup);
|
||||
if (!dhcps->s) {
|
||||
dhcps_dbg("DHCP server ERROR: failure opening socket (%s)\n", strerror(pico_err));
|
||||
PICO_FREE(dhcps);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pico_socket_bind(dhcps->s, &dhcps->server_ip, &port) < 0) {
|
||||
dhcps_dbg("DHCP server ERROR: failure binding socket (%s)\n", strerror(pico_err));
|
||||
PICO_FREE(dhcps);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pico_tree_insert(&DHCPSettings, dhcps);
|
||||
return dhcps;
|
||||
}
|
||||
|
||||
static struct pico_dhcp_server_setting *pico_dhcp_server_add_setting(struct pico_dhcp_server_setting *setting)
|
||||
{
|
||||
struct pico_dhcp_server_setting *dhcps = NULL, *found = NULL, test = {
|
||||
0
|
||||
};
|
||||
struct pico_ipv4_link *link = NULL;
|
||||
|
||||
link = pico_ipv4_link_get(&setting->server_ip);
|
||||
if (!link) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
test.dev = setting->dev;
|
||||
found = pico_tree_findKey(&DHCPSettings, &test);
|
||||
if (found) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dhcps = PICO_ZALLOC(sizeof(struct pico_dhcp_server_setting));
|
||||
if (!dhcps) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dhcps->lease_time = setting->lease_time;
|
||||
dhcps->pool_start = setting->pool_start;
|
||||
dhcps->pool_next = setting->pool_next;
|
||||
dhcps->pool_end = setting->pool_end;
|
||||
dhcps->dev = link->dev;
|
||||
dhcps->server_ip = link->address;
|
||||
dhcps->netmask = link->netmask;
|
||||
|
||||
/* default values if not provided */
|
||||
dhcps_set_default_lease_time_if_not_provided(dhcps);
|
||||
dhcps_set_default_pool_end_if_not_provided(dhcps);
|
||||
dhcps_set_default_pool_start_if_not_provided(dhcps);
|
||||
|
||||
dhcps->pool_next = dhcps->pool_start;
|
||||
|
||||
return dhcps_try_open_socket(dhcps);
|
||||
|
||||
}
|
||||
|
||||
static struct pico_dhcp_server_negotiation *pico_dhcp_server_find_negotiation(uint32_t xid)
|
||||
{
|
||||
struct pico_dhcp_server_negotiation test = {
|
||||
0
|
||||
}, *found = NULL;
|
||||
|
||||
test.xid = xid;
|
||||
found = pico_tree_findKey(&DHCPNegotiations, &test);
|
||||
if (found)
|
||||
return found;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void dhcp_negotiation_set_ciaddr(struct pico_dhcp_server_negotiation *dhcpn)
|
||||
{
|
||||
struct pico_ip4 *ciaddr = NULL;
|
||||
ciaddr = pico_arp_reverse_lookup(&dhcpn->hwaddr);
|
||||
if (!ciaddr) {
|
||||
dhcpn->ciaddr.addr = dhcpn->dhcps->pool_next;
|
||||
dhcpn->dhcps->pool_next = long_be(long_be(dhcpn->dhcps->pool_next) + 1);
|
||||
pico_arp_create_entry(dhcpn->hwaddr.addr, dhcpn->ciaddr, dhcpn->dhcps->dev);
|
||||
} else {
|
||||
dhcpn->ciaddr = *ciaddr;
|
||||
}
|
||||
}
|
||||
|
||||
static struct pico_dhcp_server_negotiation *pico_dhcp_server_add_negotiation(struct pico_device *dev, struct pico_dhcp_hdr *hdr)
|
||||
{
|
||||
struct pico_dhcp_server_negotiation *dhcpn = NULL;
|
||||
struct pico_dhcp_server_setting test = {
|
||||
0
|
||||
};
|
||||
|
||||
if (pico_dhcp_server_find_negotiation(hdr->xid))
|
||||
return NULL;
|
||||
|
||||
dhcpn = PICO_ZALLOC(sizeof(struct pico_dhcp_server_negotiation));
|
||||
if (!dhcpn) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dhcpn->xid = hdr->xid;
|
||||
dhcpn->state = PICO_DHCP_STATE_DISCOVER;
|
||||
dhcpn->bcast = ((short_be(hdr->flags) & PICO_DHCP_FLAG_BROADCAST) != 0) ? (1) : (0);
|
||||
memcpy(dhcpn->hwaddr.addr, hdr->hwaddr, PICO_SIZE_ETH);
|
||||
|
||||
test.dev = dev;
|
||||
dhcpn->dhcps = pico_tree_findKey(&DHCPSettings, &test);
|
||||
if (!dhcpn->dhcps) {
|
||||
dhcps_dbg("DHCP server WARNING: received DHCP message on unconfigured link %s\n", dev->name);
|
||||
PICO_FREE(dhcpn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dhcp_negotiation_set_ciaddr(dhcpn);
|
||||
pico_tree_insert(&DHCPNegotiations, dhcpn);
|
||||
return dhcpn;
|
||||
}
|
||||
|
||||
static void dhcpd_make_reply(struct pico_dhcp_server_negotiation *dhcpn, uint8_t msg_type)
|
||||
{
|
||||
int r = 0, optlen = 0, offset = 0;
|
||||
struct pico_ip4 broadcast = {
|
||||
0
|
||||
}, dns = {
|
||||
0
|
||||
}, destination = {
|
||||
.addr = 0xFFFFFFFF
|
||||
};
|
||||
struct pico_dhcp_hdr *hdr = NULL;
|
||||
|
||||
dns.addr = DHCP_SERVER_OPENDNS;
|
||||
broadcast.addr = dhcpn->dhcps->server_ip.addr | ~(dhcpn->dhcps->netmask.addr);
|
||||
|
||||
optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_SERVERID + PICO_DHCP_OPTLEN_LEASETIME + PICO_DHCP_OPTLEN_NETMASK + PICO_DHCP_OPTLEN_ROUTER
|
||||
+ PICO_DHCP_OPTLEN_BROADCAST + PICO_DHCP_OPTLEN_DNS + PICO_DHCP_OPTLEN_END;
|
||||
hdr = PICO_ZALLOC(sizeof(struct pico_dhcp_hdr) + (uint32_t)optlen);
|
||||
if (!hdr) {
|
||||
return;
|
||||
}
|
||||
|
||||
hdr->op = PICO_DHCP_OP_REPLY;
|
||||
hdr->htype = PICO_DHCP_HTYPE_ETH;
|
||||
hdr->hlen = PICO_SIZE_ETH;
|
||||
hdr->xid = dhcpn->xid;
|
||||
hdr->yiaddr = dhcpn->ciaddr.addr;
|
||||
hdr->siaddr = dhcpn->dhcps->server_ip.addr;
|
||||
hdr->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
|
||||
memcpy(hdr->hwaddr, dhcpn->hwaddr.addr, PICO_SIZE_ETH);
|
||||
|
||||
/* options */
|
||||
offset += pico_dhcp_opt_msgtype(DHCP_OPT(hdr,offset), msg_type);
|
||||
offset += pico_dhcp_opt_serverid(DHCP_OPT(hdr,offset), &dhcpn->dhcps->server_ip);
|
||||
offset += pico_dhcp_opt_leasetime(DHCP_OPT(hdr,offset), dhcpn->dhcps->lease_time);
|
||||
offset += pico_dhcp_opt_netmask(DHCP_OPT(hdr,offset), &dhcpn->dhcps->netmask);
|
||||
offset += pico_dhcp_opt_router(DHCP_OPT(hdr,offset), &dhcpn->dhcps->server_ip);
|
||||
offset += pico_dhcp_opt_broadcast(DHCP_OPT(hdr,offset), &broadcast);
|
||||
offset += pico_dhcp_opt_dns(DHCP_OPT(hdr,offset), &dns);
|
||||
offset += pico_dhcp_opt_end(DHCP_OPT(hdr,offset));
|
||||
|
||||
if (dhcpn->bcast == 0)
|
||||
destination.addr = hdr->yiaddr;
|
||||
else {
|
||||
hdr->flags |= short_be(PICO_DHCP_FLAG_BROADCAST);
|
||||
destination.addr = broadcast.addr;
|
||||
}
|
||||
|
||||
r = pico_socket_sendto(dhcpn->dhcps->s, hdr, (int)(sizeof(struct pico_dhcp_hdr) + (uint32_t)optlen), &destination, PICO_DHCP_CLIENT_PORT);
|
||||
if (r < 0)
|
||||
dhcps_dbg("DHCP server WARNING: failure sending: %s!\n", strerror(pico_err));
|
||||
|
||||
PICO_FREE(hdr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void parse_opt_msgtype(struct pico_dhcp_opt *opt, uint8_t *msgtype)
|
||||
{
|
||||
if (opt->code == PICO_DHCP_OPT_MSGTYPE) {
|
||||
*msgtype = opt->ext.msg_type.type;
|
||||
dhcps_dbg("DHCP server: message type %u\n", msgtype);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void parse_opt_reqip(struct pico_dhcp_opt *opt, struct pico_ip4 *reqip)
|
||||
{
|
||||
if (opt->code == PICO_DHCP_OPT_REQIP)
|
||||
reqip->addr = opt->ext.req_ip.ip.addr;
|
||||
}
|
||||
|
||||
static inline void parse_opt_serverid(struct pico_dhcp_opt *opt, struct pico_ip4 *serverid)
|
||||
{
|
||||
if (opt->code == PICO_DHCP_OPT_SERVERID)
|
||||
*serverid = opt->ext.server_id.ip;
|
||||
}
|
||||
|
||||
static inline void dhcps_make_reply_to_request_msg(struct pico_dhcp_server_negotiation *dhcpn, int bound_valid_flag)
|
||||
{
|
||||
if ((dhcpn->state == PICO_DHCP_STATE_BOUND) && bound_valid_flag)
|
||||
dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_ACK);
|
||||
|
||||
if (dhcpn->state == PICO_DHCP_STATE_OFFER) {
|
||||
dhcpn->state = PICO_DHCP_STATE_BOUND;
|
||||
dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_ACK);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dhcps_make_reply_to_discover_or_request(struct pico_dhcp_server_negotiation *dhcpn, uint8_t msgtype, int bound_valid_flag)
|
||||
{
|
||||
if (PICO_DHCP_MSG_DISCOVER == msgtype) {
|
||||
dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_OFFER);
|
||||
dhcpn->state = PICO_DHCP_STATE_OFFER;
|
||||
} else if (PICO_DHCP_MSG_REQUEST == msgtype) {
|
||||
dhcps_make_reply_to_request_msg(dhcpn, bound_valid_flag);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dhcps_parse_options_loop(struct pico_dhcp_server_negotiation *dhcpn, struct pico_dhcp_hdr *hdr)
|
||||
{
|
||||
struct pico_dhcp_opt *opt = DHCP_OPT(hdr,0);
|
||||
uint8_t msgtype = 0;
|
||||
struct pico_ip4 reqip = {
|
||||
0
|
||||
}, server_id = {
|
||||
0
|
||||
};
|
||||
|
||||
do {
|
||||
parse_opt_msgtype(opt, &msgtype);
|
||||
parse_opt_reqip(opt, &reqip);
|
||||
parse_opt_serverid(opt, &server_id);
|
||||
} while (pico_dhcp_next_option(&opt));
|
||||
dhcps_make_reply_to_discover_or_request(dhcpn, msgtype, (!reqip.addr) && (!server_id.addr) && (hdr->ciaddr == dhcpn->ciaddr.addr));
|
||||
}
|
||||
|
||||
static void pico_dhcp_server_recv(struct pico_socket *s, uint8_t *buf, uint32_t len)
|
||||
{
|
||||
int32_t optlen = (int32_t)(len - sizeof(struct pico_dhcp_hdr));
|
||||
struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
|
||||
struct pico_dhcp_server_negotiation *dhcpn = NULL;
|
||||
struct pico_device *dev = NULL;
|
||||
|
||||
if (!pico_dhcp_are_options_valid(DHCP_OPT(hdr,0), optlen))
|
||||
return;
|
||||
|
||||
dev = pico_ipv4_link_find(&s->local_addr.ip4);
|
||||
dhcpn = pico_dhcp_server_find_negotiation(hdr->xid);
|
||||
if (!dhcpn)
|
||||
dhcpn = pico_dhcp_server_add_negotiation(dev, hdr);
|
||||
|
||||
if (!ip_address_is_in_dhcp_range(dhcpn, dhcpn->ciaddr.addr))
|
||||
return;
|
||||
|
||||
dhcps_parse_options_loop(dhcpn, hdr);
|
||||
|
||||
}
|
||||
|
||||
static void pico_dhcpd_wakeup(uint16_t ev, struct pico_socket *s)
|
||||
{
|
||||
uint8_t buf[DHCP_SERVER_MAXMSGSIZE] = {
|
||||
0
|
||||
};
|
||||
int r = 0;
|
||||
|
||||
if (ev != PICO_SOCK_EV_RD)
|
||||
return;
|
||||
|
||||
r = pico_socket_recvfrom(s, buf, DHCP_SERVER_MAXMSGSIZE, NULL, NULL);
|
||||
if (r < 0)
|
||||
return;
|
||||
|
||||
pico_dhcp_server_recv(s, buf, (uint32_t)r);
|
||||
return;
|
||||
}
|
||||
|
||||
int pico_dhcp_server_initiate(struct pico_dhcp_server_setting *setting)
|
||||
{
|
||||
if (!setting || !setting->server_ip.addr) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pico_dhcp_server_add_setting(setting) == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_dhcp_server_destroy(struct pico_device *dev)
|
||||
{
|
||||
struct pico_dhcp_server_setting *found, test = { 0 };
|
||||
test.dev = dev;
|
||||
found = pico_tree_findKey(&DHCPSettings, &test);
|
||||
if (!found) {
|
||||
pico_err = PICO_ERR_ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pico_tree_delete(&DHCPSettings, found);
|
||||
PICO_FREE(found);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* PICO_SUPPORT_DHCP */
|
||||
34
ext/picotcp/modules/pico_dhcp_server.h
Normal file
34
ext/picotcp/modules/pico_dhcp_server.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_DHCP_SERVER
|
||||
#define INCLUDE_PICO_DHCP_SERVER
|
||||
#include "pico_defines.h"
|
||||
#ifdef PICO_SUPPORT_UDP
|
||||
|
||||
#include "pico_dhcp_common.h"
|
||||
#include "pico_addressing.h"
|
||||
|
||||
struct pico_dhcp_server_setting
|
||||
{
|
||||
uint32_t pool_start;
|
||||
uint32_t pool_next;
|
||||
uint32_t pool_end;
|
||||
uint32_t lease_time;
|
||||
struct pico_device *dev;
|
||||
struct pico_socket *s;
|
||||
struct pico_ip4 server_ip;
|
||||
struct pico_ip4 netmask;
|
||||
uint8_t flags; /* unused atm */
|
||||
};
|
||||
|
||||
/* required field: IP address of the interface to serve, only IPs of this network will be served. */
|
||||
int pico_dhcp_server_initiate(struct pico_dhcp_server_setting *dhcps);
|
||||
|
||||
/* To destroy an existing DHCP server configuration, running on a given interface */
|
||||
int pico_dhcp_server_destroy(struct pico_device *dev);
|
||||
|
||||
#endif /* _INCLUDE_PICO_DHCP_SERVER */
|
||||
#endif
|
||||
808
ext/picotcp/modules/pico_dns_client.c
Normal file
808
ext/picotcp/modules/pico_dns_client.c
Normal file
@@ -0,0 +1,808 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
.
|
||||
Authors: Kristof Roelants
|
||||
*********************************************************************/
|
||||
#include "pico_config.h"
|
||||
#include "pico_stack.h"
|
||||
#include "pico_addressing.h"
|
||||
#include "pico_socket.h"
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_ipv6.h"
|
||||
#include "pico_dns_client.h"
|
||||
#include "pico_dns_common.h"
|
||||
#include "pico_tree.h"
|
||||
|
||||
#ifdef PICO_SUPPORT_DNS_CLIENT
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV4
|
||||
|
||||
#define dns_dbg(...) do {} while(0)
|
||||
/* #define dns_dbg dbg */
|
||||
|
||||
/* DNS response length */
|
||||
#define PICO_DNS_MAX_QUERY_LEN 255
|
||||
#define PICO_DNS_MAX_QUERY_LABEL_LEN 63
|
||||
|
||||
/* DNS client retransmission time (msec) + frequency */
|
||||
#define PICO_DNS_CLIENT_RETRANS 4000
|
||||
#define PICO_DNS_CLIENT_MAX_RETRANS 3
|
||||
|
||||
static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s);
|
||||
static void pico_dns_client_retransmission(pico_time now, void *arg);
|
||||
static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg);
|
||||
|
||||
struct pico_dns_ns
|
||||
{
|
||||
struct pico_ip4 ns; /* nameserver */
|
||||
};
|
||||
|
||||
static int dns_ns_cmp(void *ka, void *kb)
|
||||
{
|
||||
struct pico_dns_ns *a = ka, *b = kb;
|
||||
return pico_ipv4_compare(&a->ns, &b->ns);
|
||||
}
|
||||
PICO_TREE_DECLARE(NSTable, dns_ns_cmp);
|
||||
|
||||
struct pico_dns_query
|
||||
{
|
||||
char *query;
|
||||
uint16_t len;
|
||||
uint16_t id;
|
||||
uint16_t qtype;
|
||||
uint16_t qclass;
|
||||
uint8_t retrans;
|
||||
struct pico_dns_ns q_ns;
|
||||
struct pico_socket *s;
|
||||
void (*callback)(char *, void *);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static int dns_query_cmp(void *ka, void *kb)
|
||||
{
|
||||
struct pico_dns_query *a = ka, *b = kb;
|
||||
if (a->id == b->id)
|
||||
return 0;
|
||||
|
||||
return (a->id < b->id) ? (-1) : (1);
|
||||
}
|
||||
PICO_TREE_DECLARE(DNSTable, dns_query_cmp);
|
||||
|
||||
static int pico_dns_client_del_ns(struct pico_ip4 *ns_addr)
|
||||
{
|
||||
struct pico_dns_ns test = {{0}}, *found = NULL;
|
||||
|
||||
test.ns = *ns_addr;
|
||||
found = pico_tree_findKey(&NSTable, &test);
|
||||
if (!found)
|
||||
return -1;
|
||||
|
||||
pico_tree_delete(&NSTable, found);
|
||||
PICO_FREE(found);
|
||||
|
||||
/* no NS left, add default NS */
|
||||
if (pico_tree_empty(&NSTable))
|
||||
pico_dns_client_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pico_dns_ns *pico_dns_client_add_ns(struct pico_ip4 *ns_addr)
|
||||
{
|
||||
struct pico_dns_ns *dns = NULL, *found = NULL, test = {{0}};
|
||||
struct pico_ip4 zero = {0}; /* 0.0.0.0 */
|
||||
|
||||
/* Do not add 0.0.0.0 addresses, which some DHCP servers might reply */
|
||||
if (!pico_ipv4_compare(ns_addr, &zero))
|
||||
{
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dns = PICO_ZALLOC(sizeof(struct pico_dns_ns));
|
||||
if (!dns) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dns->ns = *ns_addr;
|
||||
|
||||
found = pico_tree_insert(&NSTable, dns);
|
||||
if (found) { /* nameserver already present */
|
||||
PICO_FREE(dns);
|
||||
return found;
|
||||
}
|
||||
|
||||
/* default NS found, remove it */
|
||||
pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&test.ns.addr);
|
||||
found = pico_tree_findKey(&NSTable, &test);
|
||||
if (found && (found->ns.addr != ns_addr->addr))
|
||||
pico_dns_client_del_ns(&found->ns);
|
||||
|
||||
return dns;
|
||||
}
|
||||
|
||||
static struct pico_dns_ns pico_dns_client_next_ns(struct pico_ip4 *ns_addr)
|
||||
{
|
||||
struct pico_dns_ns dns = {{0}}, *nxtdns = NULL;
|
||||
struct pico_tree_node *node = NULL, *nxtnode = NULL;
|
||||
|
||||
dns.ns = *ns_addr;
|
||||
node = pico_tree_findNode(&NSTable, &dns);
|
||||
if (!node)
|
||||
return dns; /* keep using current NS */
|
||||
|
||||
nxtnode = pico_tree_next(node);
|
||||
nxtdns = nxtnode->keyValue;
|
||||
if (!nxtdns)
|
||||
nxtdns = (struct pico_dns_ns *)pico_tree_first(&NSTable);
|
||||
|
||||
return *nxtdns;
|
||||
}
|
||||
|
||||
static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_header *hdr, uint16_t len, struct pico_dns_question_suffix *suffix,
|
||||
void (*callback)(char *, void *), void *arg)
|
||||
{
|
||||
struct pico_dns_query *q = NULL, *found = NULL;
|
||||
|
||||
q = PICO_ZALLOC(sizeof(struct pico_dns_query));
|
||||
if (!q)
|
||||
return NULL;
|
||||
|
||||
q->query = (char *)hdr;
|
||||
q->len = len;
|
||||
q->id = short_be(hdr->id);
|
||||
q->qtype = short_be(suffix->qtype);
|
||||
q->qclass = short_be(suffix->qclass);
|
||||
q->retrans = 1;
|
||||
q->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
|
||||
q->callback = callback;
|
||||
q->arg = arg;
|
||||
q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback);
|
||||
if (!q->s) {
|
||||
PICO_FREE(q);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
found = pico_tree_insert(&DNSTable, q);
|
||||
if (found) {
|
||||
pico_err = PICO_ERR_EAGAIN;
|
||||
pico_socket_close(q->s);
|
||||
PICO_FREE(q);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
static int pico_dns_client_del_query(uint16_t id)
|
||||
{
|
||||
struct pico_dns_query test = {
|
||||
0
|
||||
}, *found = NULL;
|
||||
|
||||
test.id = id;
|
||||
found = pico_tree_findKey(&DNSTable, &test);
|
||||
if (!found)
|
||||
return -1;
|
||||
|
||||
PICO_FREE(found->query);
|
||||
pico_socket_close(found->s);
|
||||
pico_tree_delete(&DNSTable, found);
|
||||
PICO_FREE(found);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pico_dns_query *pico_dns_client_find_query(uint16_t id)
|
||||
{
|
||||
struct pico_dns_query test = {
|
||||
0
|
||||
}, *found = NULL;
|
||||
|
||||
test.id = id;
|
||||
found = pico_tree_findKey(&DNSTable, &test);
|
||||
if (found)
|
||||
return found;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* seek end of string */
|
||||
static char *pico_dns_client_seek(char *ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
while (*ptr != 0)
|
||||
ptr++;
|
||||
return ptr + 1;
|
||||
}
|
||||
|
||||
static struct pico_dns_query *pico_dns_client_idcheck(uint16_t id)
|
||||
{
|
||||
struct pico_dns_query test = {
|
||||
0
|
||||
};
|
||||
|
||||
test.id = id;
|
||||
return pico_tree_findKey(&DNSTable, &test);
|
||||
}
|
||||
|
||||
static int pico_dns_client_query_header(struct pico_dns_header *hdr)
|
||||
{
|
||||
uint16_t id = 0;
|
||||
uint8_t retry = 32;
|
||||
|
||||
do {
|
||||
id = (uint16_t)(pico_rand() & 0xFFFFU);
|
||||
dns_dbg("DNS: generated id %u\n", id);
|
||||
} while (retry-- && pico_dns_client_idcheck(id));
|
||||
if (!retry)
|
||||
return -1;
|
||||
|
||||
hdr->id = short_be(id);
|
||||
pico_dns_fill_packet_header(hdr, 1, 0, 0, 0); /* 1 question, 0 answers */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_dns_client_check_header(struct pico_dns_header *pre)
|
||||
{
|
||||
if (pre->qr != PICO_DNS_QR_RESPONSE || pre->opcode != PICO_DNS_OPCODE_QUERY || pre->rcode != PICO_DNS_RCODE_NO_ERROR) {
|
||||
dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", pre->opcode, pre->tc, pre->rcode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (short_be(pre->ancount) < 1) {
|
||||
dns_dbg("DNS ERROR: ancount < 1\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_dns_client_check_qsuffix(struct pico_dns_question_suffix *suf, struct pico_dns_query *q)
|
||||
{
|
||||
if (!suf)
|
||||
return -1;
|
||||
|
||||
if (short_be(suf->qtype) != q->qtype || short_be(suf->qclass) != q->qclass) {
|
||||
dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->qtype), short_be(suf->qclass));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_dns_client_check_url(struct pico_dns_header *resp, struct pico_dns_query *q)
|
||||
{
|
||||
char *recv_name = (char*)(resp) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL;
|
||||
char *exp_name = (char *)(q->query) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL;
|
||||
if (strcasecmp(recv_name, exp_name) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_dns_client_check_asuffix(struct pico_dns_record_suffix *suf, struct pico_dns_query *q)
|
||||
{
|
||||
if (!suf) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (short_be(suf->rtype) != q->qtype || short_be(suf->rclass) != q->qclass) {
|
||||
dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->rtype), short_be(suf->rclass));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (long_be(suf->rttl) > PICO_DNS_MAX_TTL) {
|
||||
dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(suf->rttl), PICO_DNS_MAX_TTL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *pico_dns_client_seek_suffix(char *suf, struct pico_dns_header *pre, struct pico_dns_query *q)
|
||||
{
|
||||
struct pico_dns_record_suffix *asuffix = NULL;
|
||||
uint16_t comp = 0, compression = 0;
|
||||
uint16_t i = 0;
|
||||
|
||||
if (!suf)
|
||||
return NULL;
|
||||
|
||||
while (i++ < short_be(pre->ancount)) {
|
||||
comp = short_from(suf);
|
||||
compression = short_be(comp);
|
||||
switch (compression >> 14)
|
||||
{
|
||||
case PICO_DNS_POINTER:
|
||||
while (compression >> 14 == PICO_DNS_POINTER) {
|
||||
dns_dbg("DNS: pointer\n");
|
||||
suf += sizeof(uint16_t);
|
||||
comp = short_from(suf);
|
||||
compression = short_be(comp);
|
||||
}
|
||||
break;
|
||||
|
||||
case PICO_DNS_LABEL:
|
||||
dns_dbg("DNS: label\n");
|
||||
suf = pico_dns_client_seek(suf);
|
||||
break;
|
||||
|
||||
default:
|
||||
dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
asuffix = (struct pico_dns_record_suffix *)suf;
|
||||
if (!asuffix)
|
||||
break;
|
||||
|
||||
if (pico_dns_client_check_asuffix(asuffix, q) < 0) {
|
||||
suf += (sizeof(struct pico_dns_record_suffix) + short_be(asuffix->rdlength));
|
||||
continue;
|
||||
}
|
||||
|
||||
return suf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int pico_dns_client_send(struct pico_dns_query *q)
|
||||
{
|
||||
uint16_t *paramID = PICO_ZALLOC(sizeof(uint16_t));
|
||||
if (!paramID) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_dbg("DNS: sending query to %08X\n", q->q_ns.ns.addr);
|
||||
if (!q->s)
|
||||
goto failure;
|
||||
|
||||
if (pico_socket_connect(q->s, &q->q_ns.ns, short_be(PICO_DNS_NS_PORT)) < 0)
|
||||
goto failure;
|
||||
|
||||
pico_socket_send(q->s, q->query, q->len);
|
||||
*paramID = q->id;
|
||||
pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, paramID);
|
||||
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
PICO_FREE(paramID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void pico_dns_client_retransmission(pico_time now, void *arg)
|
||||
{
|
||||
struct pico_dns_query *q = NULL;
|
||||
struct pico_dns_query dummy;
|
||||
IGNORE_PARAMETER(now);
|
||||
|
||||
if(!arg)
|
||||
return;
|
||||
|
||||
/* search for the dns query and free used space */
|
||||
dummy.id = *(uint16_t *)arg;
|
||||
q = (struct pico_dns_query *)pico_tree_findKey(&DNSTable, &dummy);
|
||||
PICO_FREE(arg);
|
||||
|
||||
/* dns query successful? */
|
||||
if (!q) {
|
||||
return;
|
||||
}
|
||||
|
||||
q->retrans++;
|
||||
if (q->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) {
|
||||
q->q_ns = pico_dns_client_next_ns(&q->q_ns.ns);
|
||||
pico_dns_client_send(q);
|
||||
} else {
|
||||
pico_err = PICO_ERR_EIO;
|
||||
q->callback(NULL, q->arg);
|
||||
pico_dns_client_del_query(q->id);
|
||||
}
|
||||
}
|
||||
|
||||
static int pico_dns_client_user_callback(struct pico_dns_record_suffix *asuffix, struct pico_dns_query *q)
|
||||
{
|
||||
uint32_t ip = 0;
|
||||
char *str = NULL;
|
||||
char *rdata = (char *) asuffix + sizeof(struct pico_dns_record_suffix);
|
||||
|
||||
switch (q->qtype)
|
||||
{
|
||||
case PICO_DNS_TYPE_A:
|
||||
ip = long_from(rdata);
|
||||
str = PICO_ZALLOC(PICO_DNS_IPV4_ADDR_LEN);
|
||||
pico_ipv4_to_string(str, ip);
|
||||
break;
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
case PICO_DNS_TYPE_AAAA:
|
||||
{
|
||||
struct pico_ip6 ip6;
|
||||
memcpy(&ip6.addr, rdata, sizeof(struct pico_ip6));
|
||||
str = PICO_ZALLOC(PICO_DNS_IPV6_ADDR_LEN);
|
||||
pico_ipv6_to_string(str, ip6.addr);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case PICO_DNS_TYPE_PTR:
|
||||
/* TODO: check for decompression / rdlength vs. decompressed length */
|
||||
pico_dns_notation_to_name(rdata, short_be(asuffix->rdlength));
|
||||
str = PICO_ZALLOC((size_t)(short_be(asuffix->rdlength) -
|
||||
PICO_DNS_LABEL_INITIAL));
|
||||
if (!str) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(str, rdata + PICO_DNS_LABEL_INITIAL, short_be(asuffix->rdlength) - PICO_DNS_LABEL_INITIAL);
|
||||
break;
|
||||
|
||||
default:
|
||||
dns_dbg("DNS ERROR: incorrect qtype (%u)\n", q->qtype);
|
||||
break;
|
||||
}
|
||||
|
||||
if (q->retrans) {
|
||||
q->callback(str, q->arg);
|
||||
q->retrans = 0;
|
||||
pico_dns_client_del_query(q->id);
|
||||
}
|
||||
|
||||
if (str)
|
||||
PICO_FREE(str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char dns_response[PICO_IP_MRU] = {
|
||||
0
|
||||
};
|
||||
|
||||
static void pico_dns_try_fallback_cname(struct pico_dns_query *q, struct pico_dns_header *h, struct pico_dns_question_suffix *qsuffix)
|
||||
{
|
||||
uint16_t type = q->qtype;
|
||||
uint16_t proto = PICO_PROTO_IPV4;
|
||||
struct pico_dns_record_suffix *asuffix = NULL;
|
||||
char *p_asuffix = NULL;
|
||||
char *cname_orig = NULL;
|
||||
char *cname = NULL;
|
||||
uint16_t cname_len;
|
||||
|
||||
/* Try to use CNAME only if A or AAAA query is ongoing */
|
||||
if (type != PICO_DNS_TYPE_A && type != PICO_DNS_TYPE_AAAA)
|
||||
return;
|
||||
|
||||
if (type == PICO_DNS_TYPE_AAAA)
|
||||
proto = PICO_PROTO_IPV6;
|
||||
|
||||
q->qtype = PICO_DNS_TYPE_CNAME;
|
||||
p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix);
|
||||
p_asuffix = pico_dns_client_seek_suffix(p_asuffix, h, q);
|
||||
if (!p_asuffix) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Found CNAME response. Re-initiating query. */
|
||||
asuffix = (struct pico_dns_record_suffix *)p_asuffix;
|
||||
cname = pico_dns_decompress_name((char *)asuffix + sizeof(struct pico_dns_record_suffix), (pico_dns_packet *)h); /* allocates memory! */
|
||||
cname_orig = cname; /* to free later */
|
||||
|
||||
if (cname == NULL)
|
||||
return;
|
||||
|
||||
cname_len = (uint16_t)(pico_dns_strlen(cname) + 1);
|
||||
|
||||
pico_dns_notation_to_name(cname, cname_len);
|
||||
if (cname[0] == '.')
|
||||
cname++;
|
||||
|
||||
dns_dbg("Restarting query for name '%s'\n", cname);
|
||||
pico_dns_client_getaddr_init(cname, proto, q->callback, q->arg);
|
||||
PICO_FREE(cname_orig);
|
||||
pico_dns_client_del_query(q->id);
|
||||
}
|
||||
|
||||
static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s)
|
||||
{
|
||||
struct pico_dns_header *header = NULL;
|
||||
char *domain;
|
||||
struct pico_dns_question_suffix *qsuffix = NULL;
|
||||
struct pico_dns_record_suffix *asuffix = NULL;
|
||||
struct pico_dns_query *q = NULL;
|
||||
char *p_asuffix = NULL;
|
||||
|
||||
if (ev == PICO_SOCK_EV_ERR) {
|
||||
dns_dbg("DNS: socket error received\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev & PICO_SOCK_EV_RD) {
|
||||
if (pico_socket_read(s, dns_response, PICO_IP_MRU) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
header = (struct pico_dns_header *)dns_response;
|
||||
domain = (char *)header + sizeof(struct pico_dns_header);
|
||||
qsuffix = (struct pico_dns_question_suffix *)pico_dns_client_seek(domain);
|
||||
/* valid asuffix is determined dynamically later on */
|
||||
|
||||
if (pico_dns_client_check_header(header) < 0)
|
||||
return;
|
||||
|
||||
q = pico_dns_client_find_query(short_be(header->id));
|
||||
if (!q)
|
||||
return;
|
||||
|
||||
if (pico_dns_client_check_qsuffix(qsuffix, q) < 0)
|
||||
return;
|
||||
|
||||
if (pico_dns_client_check_url(header, q) < 0)
|
||||
return;
|
||||
|
||||
p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix);
|
||||
p_asuffix = pico_dns_client_seek_suffix(p_asuffix, header, q);
|
||||
if (!p_asuffix) {
|
||||
pico_dns_try_fallback_cname(q, header, qsuffix);
|
||||
return;
|
||||
}
|
||||
|
||||
asuffix = (struct pico_dns_record_suffix *)p_asuffix;
|
||||
pico_dns_client_user_callback(asuffix, q);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int pico_dns_create_message(struct pico_dns_header **header, struct pico_dns_question_suffix **qsuffix, enum pico_dns_arpa arpa, const char *url, uint16_t *urlen, uint16_t *hdrlen)
|
||||
{
|
||||
char *domain;
|
||||
char inaddr_arpa[14];
|
||||
uint16_t strlen = 0, arpalen = 0;
|
||||
|
||||
if (!url) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(arpa == PICO_DNS_ARPA4) {
|
||||
strcpy(inaddr_arpa, ".in-addr.arpa");
|
||||
strlen = pico_dns_strlen(url);
|
||||
}
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
else if (arpa == PICO_DNS_ARPA6) {
|
||||
strcpy(inaddr_arpa, ".IP6.ARPA");
|
||||
strlen = STRLEN_PTR_IP6;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
strcpy(inaddr_arpa, "");
|
||||
strlen = pico_dns_strlen(url);
|
||||
}
|
||||
|
||||
arpalen = pico_dns_strlen(inaddr_arpa);
|
||||
*urlen = (uint16_t)(PICO_DNS_LABEL_INITIAL + strlen + arpalen + PICO_DNS_LABEL_ROOT);
|
||||
*hdrlen = (uint16_t)(sizeof(struct pico_dns_header) + *urlen + sizeof(struct pico_dns_question_suffix));
|
||||
*header = PICO_ZALLOC(*hdrlen);
|
||||
if (!*header) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*header = (struct pico_dns_header *)*header;
|
||||
domain = (char *) *header + sizeof(struct pico_dns_header);
|
||||
*qsuffix = (struct pico_dns_question_suffix *)(domain + *urlen);
|
||||
|
||||
if(arpa == PICO_DNS_ARPA4) {
|
||||
memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen);
|
||||
pico_dns_mirror_addr(domain + PICO_DNS_LABEL_INITIAL);
|
||||
memcpy(domain + PICO_DNS_LABEL_INITIAL + strlen, inaddr_arpa, arpalen);
|
||||
}
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
else if (arpa == PICO_DNS_ARPA6) {
|
||||
pico_dns_ipv6_set_ptr(url, domain + PICO_DNS_LABEL_INITIAL);
|
||||
memcpy(domain + PICO_DNS_LABEL_INITIAL + STRLEN_PTR_IP6, inaddr_arpa, arpalen);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen);
|
||||
}
|
||||
|
||||
/* assemble dns message */
|
||||
pico_dns_client_query_header(*header);
|
||||
pico_dns_name_to_dns_notation(domain, strlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_dns_client_addr_label_check_len(const char *url)
|
||||
{
|
||||
const char *p, *label;
|
||||
int count;
|
||||
label = url;
|
||||
p = label;
|
||||
|
||||
while(*p != (char) 0) {
|
||||
count = 0;
|
||||
while((*p != (char)0)) {
|
||||
if (*p == '.') {
|
||||
label = ++p;
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
p++;
|
||||
if (count > PICO_DNS_MAX_QUERY_LABEL_LEN)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_dns_client_getaddr_check(const char *url, void (*callback)(char *, void *))
|
||||
{
|
||||
if (!url || !callback) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(url) > PICO_DNS_MAX_QUERY_LEN) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pico_dns_client_addr_label_check_len(url) < 0) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg)
|
||||
{
|
||||
struct pico_dns_header *header = NULL;
|
||||
struct pico_dns_question_suffix *qsuffix = NULL;
|
||||
struct pico_dns_query *q = NULL;
|
||||
uint16_t len = 0, lblen = 0;
|
||||
(void)proto;
|
||||
|
||||
if (pico_dns_client_getaddr_check(url, callback) < 0)
|
||||
return -1;
|
||||
|
||||
if(pico_dns_create_message(&header, &qsuffix, PICO_DNS_NO_ARPA, url, &lblen, &len) != 0)
|
||||
return -1;
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
if (proto == PICO_PROTO_IPV6) {
|
||||
pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_AAAA, PICO_DNS_CLASS_IN);
|
||||
} else
|
||||
#endif
|
||||
pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN);
|
||||
|
||||
q = pico_dns_client_add_query(header, len, qsuffix, callback, arg);
|
||||
if (!q) {
|
||||
PICO_FREE(header);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pico_dns_client_send(q) < 0) {
|
||||
pico_dns_client_del_query(q->id); /* frees msg */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
|
||||
{
|
||||
return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV4, callback, arg);
|
||||
}
|
||||
|
||||
int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg)
|
||||
{
|
||||
return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV6, callback, arg);
|
||||
}
|
||||
|
||||
static int pico_dns_getname_univ(const char *ip, void (*callback)(char *, void *), void *arg, enum pico_dns_arpa arpa)
|
||||
{
|
||||
struct pico_dns_header *header = NULL;
|
||||
struct pico_dns_question_suffix *qsuffix = NULL;
|
||||
struct pico_dns_query *q = NULL;
|
||||
uint16_t len = 0, lblen = 0;
|
||||
|
||||
if (!ip || !callback) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pico_dns_create_message(&header, &qsuffix, arpa, ip, &lblen, &len) != 0)
|
||||
return -1;
|
||||
|
||||
pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN);
|
||||
q = pico_dns_client_add_query(header, len, qsuffix, callback, arg);
|
||||
if (!q) {
|
||||
PICO_FREE(header);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pico_dns_client_send(q) < 0) {
|
||||
pico_dns_client_del_query(q->id); /* frees header */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg)
|
||||
{
|
||||
return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA4);
|
||||
}
|
||||
|
||||
|
||||
int pico_dns_client_getname6(const char *ip, void (*callback)(char *, void *), void *arg)
|
||||
{
|
||||
return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA6);
|
||||
}
|
||||
|
||||
int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag)
|
||||
{
|
||||
if (!ns) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (flag)
|
||||
{
|
||||
case PICO_DNS_NS_ADD:
|
||||
if (!pico_dns_client_add_ns(ns))
|
||||
return -1;
|
||||
|
||||
break;
|
||||
|
||||
case PICO_DNS_NS_DEL:
|
||||
if (pico_dns_client_del_ns(ns) < 0) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_dns_client_init(void)
|
||||
{
|
||||
struct pico_ip4 default_ns = {
|
||||
0
|
||||
};
|
||||
|
||||
if (pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&default_ns.addr) < 0)
|
||||
return -1;
|
||||
|
||||
return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int pico_dns_client_init(void)
|
||||
{
|
||||
dbg("ERROR Trying to initialize DNS module: IPv4 not supported in this build.\n");
|
||||
return -1;
|
||||
}
|
||||
#endif /* PICO_SUPPORT_IPV4 */
|
||||
|
||||
|
||||
#endif /* PICO_SUPPORT_DNS_CLIENT */
|
||||
|
||||
46
ext/picotcp/modules/pico_dns_client.h
Normal file
46
ext/picotcp/modules/pico_dns_client.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
Authors: Kristof Roelants
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef INCLUDE_PICO_DNS_CLIENT
|
||||
#define INCLUDE_PICO_DNS_CLIENT
|
||||
|
||||
#define PICO_DNS_NS_DEL 0
|
||||
#define PICO_DNS_NS_ADD 1
|
||||
#include "pico_config.h"
|
||||
|
||||
/* Compression values */
|
||||
#define PICO_DNS_LABEL 0
|
||||
#define PICO_DNS_POINTER 3
|
||||
|
||||
/* Label len */
|
||||
#define PICO_DNS_LABEL_INITIAL 1u
|
||||
#define PICO_DNS_LABEL_ROOT 1
|
||||
|
||||
/* TTL values */
|
||||
#define PICO_DNS_MAX_TTL 604800 /* one week */
|
||||
|
||||
/* Len of an IPv4 address string */
|
||||
#define PICO_DNS_IPV4_ADDR_LEN 16
|
||||
#define PICO_DNS_IPV6_ADDR_LEN 54
|
||||
|
||||
/* Default nameservers + port */
|
||||
#define PICO_DNS_NS_DEFAULT "208.67.222.222"
|
||||
#define PICO_DNS_NS_PORT 53
|
||||
|
||||
int pico_dns_client_init(void);
|
||||
/* flag is PICO_DNS_NS_DEL or PICO_DNS_NS_ADD */
|
||||
int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag);
|
||||
int pico_dns_client_getaddr(const char *url, void (*callback)(char *ip, void *arg), void *arg);
|
||||
int pico_dns_client_getname(const char *ip, void (*callback)(char *url, void *arg), void *arg);
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg);
|
||||
int pico_dns_client_getname6(const char *url, void (*callback)(char *, void *), void *arg);
|
||||
#endif
|
||||
|
||||
#endif /* _INCLUDE_PICO_DNS_CLIENT */
|
||||
1773
ext/picotcp/modules/pico_dns_common.c
Normal file
1773
ext/picotcp/modules/pico_dns_common.c
Normal file
File diff suppressed because it is too large
Load Diff
523
ext/picotcp/modules/pico_dns_common.h
Normal file
523
ext/picotcp/modules/pico_dns_common.h
Normal file
@@ -0,0 +1,523 @@
|
||||
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
.
|
||||
Authors: Toon Stegen, Jelle De Vleeschouwer
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef INCLUDE_PICO_DNS_COMMON
|
||||
#define INCLUDE_PICO_DNS_COMMON
|
||||
|
||||
#include "pico_config.h"
|
||||
#include "pico_tree.h"
|
||||
|
||||
/* TYPE values */
|
||||
#define PICO_DNS_TYPE_A 1
|
||||
#define PICO_DNS_TYPE_CNAME 5
|
||||
#define PICO_DNS_TYPE_PTR 12
|
||||
#define PICO_DNS_TYPE_TXT 16
|
||||
#define PICO_DNS_TYPE_AAAA 28
|
||||
#define PICO_DNS_TYPE_SRV 33
|
||||
#define PICO_DNS_TYPE_NSEC 47
|
||||
#define PICO_DNS_TYPE_ANY 255
|
||||
|
||||
/* CLASS values */
|
||||
#define PICO_DNS_CLASS_IN 1
|
||||
|
||||
/* FLAG values */
|
||||
#define PICO_DNS_QR_QUERY 0
|
||||
#define PICO_DNS_QR_RESPONSE 1
|
||||
#define PICO_DNS_OPCODE_QUERY 0
|
||||
#define PICO_DNS_OPCODE_IQUERY 1
|
||||
#define PICO_DNS_OPCODE_STATUS 2
|
||||
#define PICO_DNS_AA_NO_AUTHORITY 0
|
||||
#define PICO_DNS_AA_IS_AUTHORITY 1
|
||||
#define PICO_DNS_TC_NO_TRUNCATION 0
|
||||
#define PICO_DNS_TC_IS_TRUNCATED 1
|
||||
#define PICO_DNS_RD_NO_DESIRE 0
|
||||
#define PICO_DNS_RD_IS_DESIRED 1
|
||||
#define PICO_DNS_RA_NO_SUPPORT 0
|
||||
#define PICO_DNS_RA_IS_SUPPORTED 1
|
||||
#define PICO_DNS_RCODE_NO_ERROR 0
|
||||
#define PICO_DNS_RCODE_EFORMAT 1
|
||||
#define PICO_DNS_RCODE_ESERVER 2
|
||||
#define PICO_DNS_RCODE_ENAME 3
|
||||
#define PICO_DNS_RCODE_ENOIMP 4
|
||||
#define PICO_DNS_RCODE_EREFUSED 5
|
||||
|
||||
#define PICO_ARPA_IPV4_SUFFIX ".in-addr.arpa"
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
#define STRLEN_PTR_IP6 63
|
||||
#define PICO_ARPA_IPV6_SUFFIX ".IP6.ARPA"
|
||||
#endif
|
||||
|
||||
#define PICO_DNS_NAMEBUF_SIZE (256)
|
||||
|
||||
enum pico_dns_arpa
|
||||
{
|
||||
PICO_DNS_ARPA4,
|
||||
PICO_DNS_ARPA6,
|
||||
PICO_DNS_NO_ARPA,
|
||||
};
|
||||
|
||||
/* flags split in 2x uint8 due to endianness */
|
||||
PACKED_STRUCT_DEF pico_dns_header
|
||||
{
|
||||
uint16_t id; /* Packet id */
|
||||
uint8_t rd : 1; /* Recursion Desired */
|
||||
uint8_t tc : 1; /* TrunCation */
|
||||
uint8_t aa : 1; /* Authoritative Answer */
|
||||
uint8_t opcode : 4; /* Opcode */
|
||||
uint8_t qr : 1; /* Query/Response */
|
||||
uint8_t rcode : 4; /* Response code */
|
||||
uint8_t z : 3; /* Zero */
|
||||
uint8_t ra : 1; /* Recursion Available */
|
||||
uint16_t qdcount; /* Question count */
|
||||
uint16_t ancount; /* Answer count */
|
||||
uint16_t nscount; /* Authority count */
|
||||
uint16_t arcount; /* Additional count */
|
||||
};
|
||||
typedef struct pico_dns_header pico_dns_packet;
|
||||
|
||||
/* Question fixed-sized fields */
|
||||
PACKED_STRUCT_DEF pico_dns_question_suffix
|
||||
{
|
||||
uint16_t qtype;
|
||||
uint16_t qclass;
|
||||
};
|
||||
|
||||
/* Resource record fixed-sized fields */
|
||||
PACKED_STRUCT_DEF pico_dns_record_suffix
|
||||
{
|
||||
uint16_t rtype;
|
||||
uint16_t rclass;
|
||||
uint32_t rttl;
|
||||
uint16_t rdlength;
|
||||
};
|
||||
|
||||
/* DNS QUESTION */
|
||||
struct pico_dns_question
|
||||
{
|
||||
char *qname;
|
||||
struct pico_dns_question_suffix *qsuffix;
|
||||
uint16_t qname_length;
|
||||
uint8_t proto;
|
||||
};
|
||||
|
||||
/* DNS RECORD */
|
||||
struct pico_dns_record
|
||||
{
|
||||
char *rname;
|
||||
struct pico_dns_record_suffix *rsuffix;
|
||||
uint8_t *rdata;
|
||||
uint16_t rname_length;
|
||||
};
|
||||
|
||||
/* MARK: v NAME & IP FUNCTIONS */
|
||||
|
||||
/* ****************************************************************************
|
||||
* Checks if the DNS name doesn't exceed 256 bytes including zero-byte.
|
||||
*
|
||||
* @param namelen Length of the DNS name-string including zero-byte
|
||||
* @return 0 when the length is correct
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_check_namelen( uint16_t namelen );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Returns the length of a name in a DNS-packet as if DNS name compression
|
||||
* would be applied to the packet. If there's no compression present this
|
||||
* returns the strlen. If there's compression present this returns the length
|
||||
* until the compression-pointer + 1.
|
||||
*
|
||||
* @param name Compressed name you want the calculate the strlen from
|
||||
* @return Returns strlen of a compressed name, takes the first byte of compr-
|
||||
* ession pointer into account but not the second byte, which acts
|
||||
* like a trailing zero-byte.
|
||||
* ****************************************************************************/
|
||||
uint16_t
|
||||
pico_dns_namelen_comp( char *name );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Returns the uncompressed name in DNS name format when DNS name compression
|
||||
* is applied to the packet-buffer.
|
||||
*
|
||||
* @param name Compressed name, should be in the bounds of the actual packet
|
||||
* @param packet Packet that contains the compressed name
|
||||
* @return Returns the decompressed name, NULL on failure.
|
||||
* ****************************************************************************/
|
||||
char *
|
||||
pico_dns_decompress_name( char *name, pico_dns_packet *packet );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Converts a DNS name in DNS name format to a name in URL format. Provides
|
||||
* space for the name in URL format as well. PICO_FREE() should be called on
|
||||
* the returned string buffer that contains the name in URL format.
|
||||
*
|
||||
* @param qname DNS name in DNS name format to convert
|
||||
* @return Returns a pointer to a string-buffer with the URL name on success.
|
||||
* ****************************************************************************/
|
||||
char *
|
||||
pico_dns_qname_to_url( const char *qname );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Converts a DNS name in URL format to name in DNS name format. Provides
|
||||
* space for the DNS name as well. PICO_FREE() should be called on the returned
|
||||
* string buffer that contains the DNS name.
|
||||
*
|
||||
* @param url DNS name in URL format to convert
|
||||
* @return Returns a pointer to a string-buffer with the DNS name on success.
|
||||
* ****************************************************************************/
|
||||
char *
|
||||
pico_dns_url_to_qname( const char *url );
|
||||
|
||||
/* ****************************************************************************
|
||||
* @param url String-buffer
|
||||
* @return Length of string-buffer in an uint16_t
|
||||
* ****************************************************************************/
|
||||
uint16_t
|
||||
pico_dns_strlen( const char *url );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Replaces .'s in a DNS name in URL format by the label lengths. So it
|
||||
* actually converts a name in URL format to a name in DNS name format.
|
||||
* f.e. "*www.google.be" => "3www6google2be0"
|
||||
*
|
||||
* @param url Location to buffer with name in URL format. The URL needs to
|
||||
* be +1 byte offset in the actual buffer. Size is should be
|
||||
* strlen(url) + 2.
|
||||
* @param maxlen Maximum length of buffer so it doesn't cause a buffer overflow
|
||||
* @return 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int pico_dns_name_to_dns_notation( char *url, unsigned int maxlen );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Replaces the label lengths in a DNS-name by .'s. So it actually converts a
|
||||
* name in DNS format to a name in URL format.
|
||||
* f.e. 3www6google2be0 => .www.google.be
|
||||
*
|
||||
* @param ptr Location to buffer with name in DNS name format
|
||||
* @param maxlen Maximum length of buffer so it doesn't cause a buffer overflow
|
||||
* @return 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int pico_dns_notation_to_name( char *ptr, unsigned int maxlen );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Determines the length of the first label of a DNS name in URL-format
|
||||
*
|
||||
* @param url DNS name in URL-format
|
||||
* @return Length of the first label of DNS name in URL-format
|
||||
* ****************************************************************************/
|
||||
uint16_t
|
||||
pico_dns_first_label_length( const char *url );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Mirrors a dotted IPv4-address string.
|
||||
* f.e. 192.168.0.1 => 1.0.168.192
|
||||
*
|
||||
* @param ptr
|
||||
* @return 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_mirror_addr( char *ptr );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Convert an IPv6-address in string-format to a IPv6-address in nibble-format.
|
||||
* Doesn't add a IPv6 ARPA-suffix though.
|
||||
*
|
||||
* @param ip IPv6-address stored as a string
|
||||
* @param dst Destination to store IPv6-address in nibble-format
|
||||
* ****************************************************************************/
|
||||
void
|
||||
pico_dns_ipv6_set_ptr( const char *ip, char *dst );
|
||||
|
||||
/* MARK: QUESTION FUNCTIONS */
|
||||
|
||||
/* ****************************************************************************
|
||||
* Deletes a single DNS Question.
|
||||
*
|
||||
* @param question Void-pointer to DNS Question. Can be used with pico_tree_-
|
||||
* destroy.
|
||||
* @return Returns 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_question_delete( void **question);
|
||||
|
||||
/* ****************************************************************************
|
||||
* Fills in the DNS question suffix-fields with the correct values.
|
||||
*
|
||||
* todo: Update pico_dns_client to make the same mechanism possible as with
|
||||
* filling DNS Resource Record-suffixes. This function shouldn't be an
|
||||
* API-function.
|
||||
*
|
||||
* @param suf Pointer to the suffix member of the DNS question.
|
||||
* @param qtype DNS type of the DNS question to be.
|
||||
* @param qclass DNS class of the DNS question to be.
|
||||
* @return Returns 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_question_fill_suffix( struct pico_dns_question_suffix *suf,
|
||||
uint16_t qtype,
|
||||
uint16_t qclass );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Creates a standalone DNS Question with a given name and type.
|
||||
*
|
||||
* @param url DNS question name in URL format. Will be converted to DNS
|
||||
* name notation format.
|
||||
* @param len Will be filled with the total length of the DNS question.
|
||||
* @param proto Protocol for which you want to create a question. Can be
|
||||
* either PICO_PROTO_IPV4 or PICO_PROTO_IPV6.
|
||||
* @param qtype DNS type of the question to be.
|
||||
* @param qclass DNS class of the question to be.
|
||||
* @param reverse When this is true, a reverse resolution name will be gene-
|
||||
* from the URL
|
||||
* @return Returns pointer to the created DNS Question on success, NULL on
|
||||
* failure.
|
||||
* ****************************************************************************/
|
||||
struct pico_dns_question *
|
||||
pico_dns_question_create( const char *url,
|
||||
uint16_t *len,
|
||||
uint8_t proto,
|
||||
uint16_t qtype,
|
||||
uint16_t qclass,
|
||||
uint8_t reverse );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Decompresses the name of a single DNS question.
|
||||
*
|
||||
* @param question Question you want to decompress the name of
|
||||
* @param packet Packet in which the DNS question is contained.
|
||||
* @return Pointer to original name of the DNS question before decompressing.
|
||||
* ****************************************************************************/
|
||||
char *
|
||||
pico_dns_question_decompress( struct pico_dns_question *question,
|
||||
pico_dns_packet *packet );
|
||||
|
||||
/* MARK: RESOURCE RECORD FUNCTIONS */
|
||||
|
||||
/* ****************************************************************************
|
||||
* Deletes a single DNS resource record.
|
||||
*
|
||||
* @param record Void-pointer to DNS record. Can be used with pico_tree_destroy
|
||||
* @return Returns 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_record_delete( void **record );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Just makes a hardcopy from a single DNS Resource Record
|
||||
*
|
||||
* @param record DNS record you want to copy
|
||||
* @return Pointer to copy of DNS record.
|
||||
* ****************************************************************************/
|
||||
struct pico_dns_record *
|
||||
pico_dns_record_copy( struct pico_dns_record *record );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Create a standalone DNS Resource Record with given name, type and data.
|
||||
*
|
||||
* @param url DNS rrecord name in URL format. Will be converted to DNS
|
||||
* name notation format.
|
||||
* @param _rdata Memory buffer with data to insert in the resource record. If
|
||||
* data of record should contain a DNS name, the name in the
|
||||
* databuffer needs to be in URL-format.
|
||||
* @param datalen The exact length in bytes of the _rdata-buffer. If data of
|
||||
* record should contain a DNS name, datalen needs to be
|
||||
* pico_dns_strlen(_rdata).
|
||||
* @param len Will be filled with the total length of the DNS rrecord.
|
||||
* @param rtype DNS type of the resource record to be.
|
||||
* @param rclass DNS class of the resource record to be.
|
||||
* @param rttl DNS ttl of the resource record to be.
|
||||
* @return Returns pointer to the created DNS Resource Record
|
||||
* ****************************************************************************/
|
||||
struct pico_dns_record *
|
||||
pico_dns_record_create( const char *url,
|
||||
void *_rdata,
|
||||
uint16_t datalen,
|
||||
uint16_t *len,
|
||||
uint16_t rtype,
|
||||
uint16_t rclass,
|
||||
uint32_t rttl );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Decompresses the name of single DNS record.
|
||||
*
|
||||
* @param record DNS record to decompress the name of.
|
||||
* @param packet Packet in which is DNS record is present
|
||||
* @return Pointer to original name of the DNS record before decompressing.
|
||||
* ****************************************************************************/
|
||||
char *
|
||||
pico_dns_record_decompress( struct pico_dns_record *record,
|
||||
pico_dns_packet *packet );
|
||||
|
||||
/* MARK: COMPARING */
|
||||
|
||||
/* ****************************************************************************
|
||||
* Compares two databuffers against each other.
|
||||
*
|
||||
* @param a 1st Memory buffer to compare
|
||||
* @param b 2nd Memory buffer to compare
|
||||
* @param rdlength_a Length of 1st memory buffer
|
||||
* @param rdlength_b Length of 2nd memory buffer
|
||||
* @param caseinsensitive Whether or not the bytes are compared
|
||||
* case-insensitive
|
||||
* @return 0 when the buffers are equal, returns difference when they're not.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_rdata_cmp( uint8_t *a, uint8_t *b,
|
||||
uint16_t rdlength_a, uint16_t rdlength_b, uint8_t caseinsensitive );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Compares 2 DNS questions
|
||||
*
|
||||
* @param qa DNS question A as a void-pointer (for pico_tree)
|
||||
* @param qb DNS question A as a void-pointer (for pico_tree)
|
||||
* @return 0 when questions are equal, returns difference when they're not.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_question_cmp( void *qa,
|
||||
void *qb );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Compares 2 DNS records by type and name only
|
||||
*
|
||||
* @param ra DNS record A as a void-pointer (for pico_tree)
|
||||
* @param rb DNS record B as a void-pointer (for pico_tree)
|
||||
* @return 0 when name and type of records are equal, returns difference when
|
||||
* they're not.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_record_cmp_name_type( void *ra,
|
||||
void *rb );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Compares 2 DNS records by type, name AND rdata for a truly unique result
|
||||
*
|
||||
* @param ra DNS record A as a void-pointer (for pico_tree)
|
||||
* @param rb DNS record B as a void-pointer (for pico_tree)
|
||||
* @return 0 when records are equal, returns difference when they're not
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_record_cmp( void *ra,
|
||||
void *rb );
|
||||
|
||||
/* MARK: PICO_TREE */
|
||||
|
||||
/* ****************************************************************************
|
||||
* Erases a pico_tree entirely.
|
||||
*
|
||||
* @param tree Pointer to a pico_tree-instance
|
||||
* @param node_delete Helper-function for type-specific deleting.
|
||||
* @return Returns 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_tree_destroy( struct pico_tree *tree, int (*node_delete)(void **));
|
||||
|
||||
/* ****************************************************************************
|
||||
* Determines the amount of nodes in a pico_tree
|
||||
*
|
||||
* @param tree Pointer to pico_tree-instance
|
||||
* @return Amount of items in the tree.
|
||||
* ****************************************************************************/
|
||||
uint16_t
|
||||
pico_tree_count( struct pico_tree *tree );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Definition of DNS question tree
|
||||
* ****************************************************************************/
|
||||
typedef struct pico_tree pico_dns_qtree;
|
||||
#define PICO_DNS_QTREE_DECLARE(name) \
|
||||
pico_dns_qtree (name) = {&LEAF, pico_dns_question_cmp}
|
||||
#define PICO_DNS_QTREE_DESTROY(qtree) \
|
||||
pico_tree_destroy(qtree, pico_dns_question_delete)
|
||||
|
||||
/* ****************************************************************************
|
||||
* Deletes all the questions with given DNS name from a pico_tree
|
||||
*
|
||||
* @param qtree Pointer to pico_tree-instance which contains DNS questions
|
||||
* @param name Name of the questions you want to delete
|
||||
* @return Returns 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_qtree_del_name( struct pico_tree *qtree,
|
||||
const char *name );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Checks whether a question with given name is in the tree or not.
|
||||
*
|
||||
* @param qtree Pointer to pico_tree-instance which contains DNS questions
|
||||
* @param name Name you want to check for
|
||||
* @return 1 when the name is present in the qtree, 0 when it's not.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_qtree_find_name( struct pico_tree *qtree,
|
||||
const char *name );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Definition of DNS record tree
|
||||
* ****************************************************************************/
|
||||
typedef struct pico_tree pico_dns_rtree;
|
||||
#define PICO_DNS_RTREE_DECLARE(name) \
|
||||
pico_dns_rtree (name) = {&LEAF, pico_dns_record_cmp}
|
||||
#define PICO_DNS_RTREE_DESTROY(rtree) \
|
||||
pico_tree_destroy((rtree), pico_dns_record_delete)
|
||||
|
||||
/* MARK: DNS PACKET FUNCTIONS */
|
||||
|
||||
/* ****************************************************************************
|
||||
* Fills the header section of a DNS packet with the correct flags and section
|
||||
* -counts.
|
||||
*
|
||||
* @param hdr Header to fill in.
|
||||
* @param qdcount Amount of questions added to the packet
|
||||
* @param ancount Amount of answer records added to the packet
|
||||
* @param nscount Amount of authority records added to the packet
|
||||
* @param arcount Amount of additional records added to the packet
|
||||
* ****************************************************************************/
|
||||
void
|
||||
pico_dns_fill_packet_header( struct pico_dns_header *hdr,
|
||||
uint16_t qdcount,
|
||||
uint16_t ancount,
|
||||
uint16_t authcount,
|
||||
uint16_t addcount );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Creates a DNS Query packet with given question and resource records to put
|
||||
* the Resource Record Sections. If a NULL-pointer is provided for a certain
|
||||
* tree, no records will be added to that particular section of the packet.
|
||||
*
|
||||
* @param qtree DNS Questions to put in the Question Section
|
||||
* @param antree DNS Records to put in the Answer Section
|
||||
* @param nstree DNS Records to put in the Authority Section
|
||||
* @param artree DNS Records to put in the Additional Section
|
||||
* @param len Will get filled with the entire size of the packet
|
||||
* @return Pointer to created DNS packet
|
||||
* ****************************************************************************/
|
||||
pico_dns_packet *
|
||||
pico_dns_query_create( struct pico_tree *qtree,
|
||||
struct pico_tree *antree,
|
||||
struct pico_tree *nstree,
|
||||
struct pico_tree *artree,
|
||||
uint16_t *len );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Creates a DNS Answer packet with given resource records to put in the
|
||||
* Resource Record Sections. If a NULL-pointer is provided for a certain tree,
|
||||
* no records will be added to that particular section of the packet.
|
||||
*
|
||||
* @param antree DNS Records to put in the Answer Section
|
||||
* @param nstree DNS Records to put in the Authority Section
|
||||
* @param artree DNS Records to put in the Additional Section
|
||||
* @param len Will get filled with the entire size of the packet
|
||||
* @return Pointer to created DNS packet.
|
||||
* ****************************************************************************/
|
||||
pico_dns_packet *
|
||||
pico_dns_answer_create( struct pico_tree *antree,
|
||||
struct pico_tree *nstree,
|
||||
struct pico_tree *artree,
|
||||
uint16_t *len );
|
||||
|
||||
#endif /* _INCLUDE_PICO_DNS_COMMON */
|
||||
549
ext/picotcp/modules/pico_dns_sd.c
Normal file
549
ext/picotcp/modules/pico_dns_sd.c
Normal file
@@ -0,0 +1,549 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2014-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
.
|
||||
Author: Jelle De Vleeschouwer
|
||||
*********************************************************************/
|
||||
|
||||
#include "pico_dns_sd.h"
|
||||
|
||||
#ifdef PICO_SUPPORT_DNS_SD
|
||||
|
||||
/* --- Debugging --- */
|
||||
#define dns_sd_dbg(...) do {} while(0)
|
||||
//#define dns_sd_dbg dbg
|
||||
|
||||
/* --- PROTOTYPES --- */
|
||||
key_value_pair_t *
|
||||
pico_dns_sd_kv_vector_get( kv_vector *vector, uint16_t index );
|
||||
int
|
||||
pico_dns_sd_kv_vector_erase( kv_vector *vector );
|
||||
/* ------------------- */
|
||||
|
||||
typedef PACKED_STRUCT_DEF pico_dns_srv_record_prefix
|
||||
{
|
||||
uint16_t priority;
|
||||
uint16_t weight;
|
||||
uint16_t port;
|
||||
} pico_dns_srv_record;
|
||||
|
||||
/* ****************************************************************************
|
||||
* Determines the length of the resulting string when a string would be
|
||||
* created from a key-value pair vector.
|
||||
*
|
||||
* @param vector Key-Value pair vector to determine the length of.
|
||||
* @return The length of the key-value pair vector in bytes as if it would be
|
||||
* converted to a string.
|
||||
* ****************************************************************************/
|
||||
static uint16_t
|
||||
pico_dns_sd_kv_vector_strlen( kv_vector *vector )
|
||||
{
|
||||
key_value_pair_t *iterator = NULL;
|
||||
uint16_t i = 0, len = 0;
|
||||
|
||||
/* Check params */
|
||||
if (!vector) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Iterate over the key-value pairs */
|
||||
for (i = 0; i < vector->count; i++) {
|
||||
iterator = pico_dns_sd_kv_vector_get(vector, i);
|
||||
len = (uint16_t) (len + 1u + /* Length byte */
|
||||
strlen(iterator->key) /* Length of the key */);
|
||||
if (iterator->value)
|
||||
len = (uint16_t) (len + 1u /* '=' char */ +
|
||||
strlen(iterator->value) /* Length of value */);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Creates an mDNS record with the SRV record format.
|
||||
*
|
||||
* @param url Name of the SRV record in URL format.
|
||||
* @param priority Priority, should be 0.
|
||||
* @param weight Weight, should be 0.
|
||||
* @param port Port to register the service on.
|
||||
* @param target_url Hostname of the service-target, in URL-format
|
||||
* @param ttl TTL of the SRV Record
|
||||
* @param flags mDNS record flags to set specifications of the record.
|
||||
* @return Pointer to newly created record on success, NULL on failure.
|
||||
* ****************************************************************************/
|
||||
static struct pico_mdns_record *
|
||||
pico_dns_sd_srv_record_create( const char *url,
|
||||
uint16_t priority,
|
||||
uint16_t weight,
|
||||
uint16_t port,
|
||||
const char *target_url,
|
||||
uint32_t ttl,
|
||||
uint8_t flags )
|
||||
{
|
||||
struct pico_mdns_record *record = NULL;
|
||||
pico_dns_srv_record *srv_data = NULL;
|
||||
char *target_rname = NULL;
|
||||
uint16_t srv_length = 0;
|
||||
|
||||
/* Check params */
|
||||
if (!url || !target_url) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Determine the length the rdata buf needs to be */
|
||||
srv_length = (uint16_t) (6u + strlen(target_url) + 2u);
|
||||
|
||||
/* Provide space for the data-buf */
|
||||
if (!(srv_data = (pico_dns_srv_record *) PICO_ZALLOC(srv_length))) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set the fields */
|
||||
srv_data->priority = short_be(priority);
|
||||
srv_data->weight = short_be(weight);
|
||||
srv_data->port = short_be(port);
|
||||
|
||||
/* Copy in the URL and convert to DNS notation */
|
||||
if (!(target_rname = pico_dns_url_to_qname(target_url))) {
|
||||
dns_sd_dbg("Could not convert URL to qname!\n");
|
||||
PICO_FREE(srv_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy((char *)srv_data + 6u, target_rname);
|
||||
PICO_FREE(target_rname);
|
||||
|
||||
/* Create and return new mDNS record */
|
||||
record = pico_mdns_record_create(url, srv_data, srv_length,
|
||||
PICO_DNS_TYPE_SRV,
|
||||
ttl, flags);
|
||||
PICO_FREE(srv_data);
|
||||
return record;
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Creates an mDNS record with the TXT record format.
|
||||
*
|
||||
* @param url Name of the TXT record in URL format.
|
||||
* @param key_value_pairs Key-Value pair vector to generate the data from.
|
||||
* @param ttl TTL of the TXT record.
|
||||
* @param flags mDNS record flags to set specifications of the record
|
||||
* @return Pointer to newly created record on success, NULL on failure.
|
||||
* ****************************************************************************/
|
||||
static struct pico_mdns_record *
|
||||
pico_dns_sd_txt_record_create( const char *url,
|
||||
kv_vector key_value_pairs,
|
||||
uint32_t ttl,
|
||||
uint8_t flags )
|
||||
{
|
||||
struct pico_mdns_record *record = NULL;
|
||||
key_value_pair_t *iterator = NULL;
|
||||
char *txt = NULL;
|
||||
uint16_t i = 0, txt_i = 0, pair_len = 0, key_len = 0, value_len = 0;
|
||||
|
||||
/* Determine the length of the string to fit in all pairs */
|
||||
uint16_t len = (uint16_t)(pico_dns_sd_kv_vector_strlen(&key_value_pairs) + 1u);
|
||||
|
||||
/* If kv-vector is empty don't bother to create a TXT record */
|
||||
if (len <= 1)
|
||||
return NULL;
|
||||
|
||||
/* Provide space for the txt buf */
|
||||
if (!(txt = (char *)PICO_ZALLOC(len))) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Iterate over all the key-value pairs */
|
||||
for (i = 0; i < key_value_pairs.count; i++) {
|
||||
iterator = pico_dns_sd_kv_vector_get(&key_value_pairs, i);
|
||||
|
||||
/* Determine the length of the key */
|
||||
key_len = (uint16_t) strlen(iterator->key);
|
||||
pair_len = key_len;
|
||||
|
||||
/* If value is not a NULL-ptr */
|
||||
if (iterator->value) {
|
||||
value_len = (uint16_t) strlen(iterator->value);
|
||||
pair_len = (uint16_t) (pair_len + 1u + value_len);
|
||||
}
|
||||
|
||||
/* Set the pair length label */
|
||||
txt[txt_i] = (char)pair_len;
|
||||
|
||||
/* Copy the key */
|
||||
strcpy(txt + txt_i + 1u, iterator->key);
|
||||
|
||||
/* Copy the value if it is not a NULL-ptr */
|
||||
if (iterator->value) {
|
||||
strcpy(txt + txt_i + 1u + key_len, "=");
|
||||
strcpy(txt + txt_i + 2u + key_len, iterator->value);
|
||||
txt_i = (uint16_t) (txt_i + 2u + key_len + value_len);
|
||||
} else {
|
||||
txt_i = (uint16_t) (txt_i + 1u + key_len);
|
||||
}
|
||||
}
|
||||
record = pico_mdns_record_create(url, txt, (uint16_t)(len - 1u), PICO_DNS_TYPE_TXT, ttl, flags);
|
||||
PICO_FREE(txt);
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Deletes a single key-value pair instance
|
||||
*
|
||||
* @param kv_pair Pointer-pointer to to delete instance
|
||||
* @return Returns 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
static int
|
||||
pico_dns_sd_kv_delete( key_value_pair_t **kv_pair )
|
||||
{
|
||||
/* Check params */
|
||||
if (!kv_pair || !(*kv_pair)) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Delete the fields */
|
||||
if ((*kv_pair)->key)
|
||||
PICO_FREE((*kv_pair)->key);
|
||||
|
||||
if ((*kv_pair)->value)
|
||||
PICO_FREE((*kv_pair)->value);
|
||||
|
||||
PICO_FREE(*kv_pair);
|
||||
*kv_pair = NULL;
|
||||
kv_pair = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Creates a single key-value pair-instance
|
||||
*
|
||||
* @param key Key of the pair, cannot be NULL.
|
||||
* @param value Value of the pair, can be NULL, empty ("") or filled ("qkejq")
|
||||
* @return Pointer to newly created KV-instance on success, NULL on failure.
|
||||
* ****************************************************************************/
|
||||
static key_value_pair_t *
|
||||
pico_dns_sd_kv_create( const char *key, const char *value )
|
||||
{
|
||||
key_value_pair_t *kv_pair = NULL;
|
||||
|
||||
/* Check params */
|
||||
if (!key || !(kv_pair = PICO_ZALLOC(sizeof(key_value_pair_t)))) {
|
||||
pico_dns_sd_kv_delete(&kv_pair);
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Provide space to copy the values */
|
||||
if (!(kv_pair->key = PICO_ZALLOC((size_t)(strlen(key) + 1)))) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
pico_dns_sd_kv_delete(&kv_pair);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(kv_pair->key, key);
|
||||
|
||||
if (value) {
|
||||
if (!(kv_pair->value = PICO_ZALLOC((size_t)(strlen(value) + 1)))) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
pico_dns_sd_kv_delete(&kv_pair);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(kv_pair->value, value);
|
||||
} else
|
||||
kv_pair->value = NULL;
|
||||
|
||||
return kv_pair;
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Checks whether the type is correctly formatted ant it's label length are
|
||||
* between the allowed boundaries.
|
||||
*
|
||||
* @param type Servicetype to check the format of.
|
||||
* @return Returns 0 when the type is correctly formatted, something else when
|
||||
* it's not.
|
||||
* ****************************************************************************/
|
||||
static int
|
||||
pico_dns_sd_check_type_format( const char *type )
|
||||
{
|
||||
uint16_t first_lbl = 0;
|
||||
int8_t subtype_present = 0;
|
||||
|
||||
/* Check params */
|
||||
if (!(first_lbl = pico_dns_first_label_length(type)))
|
||||
return -1;
|
||||
|
||||
subtype_present = !memcmp(type + first_lbl + 1, "_sub", 4);
|
||||
|
||||
/* Check if there is a subtype present */
|
||||
if (subtype_present && (first_lbl > 63))
|
||||
return -1;
|
||||
else if (subtype_present)
|
||||
/* Get the length of the service name */
|
||||
first_lbl = pico_dns_first_label_length(type + first_lbl + 6);
|
||||
else {
|
||||
/* Check if type is not greater then 21 bytes (22 - 1, since the length
|
||||
byte of the service name isn't included yet) */
|
||||
if (strlen(type) > (size_t) 21)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if the service name is not greater then 16 bytes (17 - 1) */
|
||||
return (first_lbl > ((uint16_t) 16u));
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Checks whether the service instance name is correctly formatted and it's
|
||||
* label length falls between the allowed boundaries.
|
||||
*
|
||||
* @param name Instance name to check the format of.
|
||||
* @return Returns 0 when the name is correctly formatted, something else when
|
||||
* it's not.
|
||||
* ****************************************************************************/
|
||||
static int
|
||||
pico_dns_sd_check_instance_name_format( const char *name )
|
||||
{
|
||||
/* First of all check if the total length is larger than 63 bytes */
|
||||
if (pico_dns_strlen(name) > 63 || !pico_dns_strlen(name))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Append the instance name adn service type to create a '.local' service SIN.
|
||||
*
|
||||
* @param name Instance Name of the service, f.e. "Printer 2nd Floor".
|
||||
* @param type ServiceType of the service, f.e. "_http._tcp".
|
||||
* @return Pointer to newly created SIN on success, NULL on failure.
|
||||
* ****************************************************************************/
|
||||
static char *
|
||||
pico_dns_sd_create_service_url( const char *name,
|
||||
const char *type )
|
||||
{
|
||||
char *url = NULL;
|
||||
uint16_t len = 0, namelen = 0, typelen = 0;
|
||||
|
||||
if (pico_dns_sd_check_type_format(type)) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pico_dns_sd_check_instance_name_format(name)) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
namelen = (uint16_t)strlen(name);
|
||||
typelen = (uint16_t)strlen(type);
|
||||
|
||||
/* Determine the length that the URL needs to be */
|
||||
len = (uint16_t)(namelen + 1u /* for '.'*/ +
|
||||
typelen + 7u /* for '.local\0' */);
|
||||
url = (char *)PICO_ZALLOC(len);
|
||||
if (!url) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Append the parts together */
|
||||
strcpy(url, name);
|
||||
strcpy(url + namelen, ".");
|
||||
strcpy(url + namelen + 1, type);
|
||||
strcpy(url + namelen + 1 + typelen, ".local");
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* This function actually does exactly the same as pico_mdns_init();
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_sd_init( const char *_hostname,
|
||||
struct pico_ip4 address,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg )
|
||||
{
|
||||
return pico_mdns_init(_hostname, address, callback, arg);
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Just calls pico_mdns_init in it's turn to initialise the mDNS-module.
|
||||
* See pico_mdns.h for description.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_sd_register_service( const char *name,
|
||||
const char *type,
|
||||
uint16_t port,
|
||||
kv_vector *txt_data,
|
||||
uint16_t ttl,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg)
|
||||
{
|
||||
PICO_MDNS_RTREE_DECLARE(rtree);
|
||||
struct pico_mdns_record *srv_record = NULL;
|
||||
struct pico_mdns_record *txt_record = NULL;
|
||||
const char *hostname = pico_mdns_get_hostname();
|
||||
char *url = NULL;
|
||||
|
||||
/* Try to create a service URL to create records with */
|
||||
if (!(url = pico_dns_sd_create_service_url(name, type)) || !txt_data || !hostname) {
|
||||
if (url)
|
||||
PICO_FREE(url);
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_sd_dbg("\n>>>>>>>>>> Target: %s <<<<<<<<<<\n\n", hostname);
|
||||
|
||||
/* Create the SRV record */
|
||||
srv_record = pico_dns_sd_srv_record_create(url, 0, 0, port, hostname, ttl, PICO_MDNS_RECORD_UNIQUE);
|
||||
if (!srv_record) {
|
||||
PICO_FREE(url);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create the TXT record */
|
||||
txt_record = pico_dns_sd_txt_record_create(url, *txt_data, ttl, PICO_MDNS_RECORD_UNIQUE);
|
||||
PICO_FREE(url);
|
||||
|
||||
/* Erase the key-value pair vector, it's no longer needed */
|
||||
pico_dns_sd_kv_vector_erase(txt_data);
|
||||
|
||||
if (txt_record)
|
||||
pico_tree_insert(&rtree, txt_record);
|
||||
|
||||
pico_tree_insert(&rtree, srv_record);
|
||||
|
||||
if (pico_mdns_claim(rtree, callback, arg)) {
|
||||
PICO_MDNS_RTREE_DESTROY(&rtree);
|
||||
return -1;
|
||||
}
|
||||
pico_tree_destroy(&rtree, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Does nothing for now.
|
||||
*
|
||||
* @param type Type to browse for.
|
||||
* @param callback Callback to call when something particular happens.
|
||||
* @return When the module successfully started browsing the servicetype.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_sd_browse_service( const char *type,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg )
|
||||
{
|
||||
IGNORE_PARAMETER(type);
|
||||
IGNORE_PARAMETER(callback);
|
||||
IGNORE_PARAMETER(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Add a key-value pair the a key-value pair vector.
|
||||
*
|
||||
* @param vector Vector to add the pair to.
|
||||
* @param key Key of the pair, cannot be NULL.
|
||||
* @param value Value of the pair, can be NULL, empty ("") or filled ("qkejq")
|
||||
* @return Returns 0 when the pair is added successfully, something else on
|
||||
* failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_sd_kv_vector_add( kv_vector *vector, char *key, char *value )
|
||||
{
|
||||
key_value_pair_t *kv_pair = NULL;
|
||||
key_value_pair_t **new_pairs = NULL;
|
||||
uint16_t i = 0;
|
||||
|
||||
/* Check params */
|
||||
if (!vector || !key || !(kv_pair = pico_dns_sd_kv_create(key, value))) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
pico_dns_sd_kv_delete(&kv_pair);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Provide enough space for the new pair pointers */
|
||||
if (!(new_pairs = PICO_ZALLOC(sizeof(key_value_pair_t *) *
|
||||
(vector->count + 1u)))) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
pico_dns_sd_kv_delete(&kv_pair);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy previous pairs and add new one */
|
||||
for (i = 0; i < vector->count; i++)
|
||||
new_pairs[i] = vector->pairs[i];
|
||||
new_pairs[i] = kv_pair;
|
||||
|
||||
/* Free the previous array */
|
||||
if (vector->pairs)
|
||||
PICO_FREE(vector->pairs);
|
||||
|
||||
vector->pairs = new_pairs;
|
||||
vector->count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Gets a single key-value pair form a Key-Value pair vector @ certain index.
|
||||
*
|
||||
* @param vector Vector to get KV-pair from.
|
||||
* @param index Index of the KV-pair.
|
||||
* @return key_value_pair_t* on success, NULL on failure.
|
||||
* ****************************************************************************/
|
||||
key_value_pair_t *
|
||||
pico_dns_sd_kv_vector_get( kv_vector *vector, uint16_t index )
|
||||
{
|
||||
/* Check params */
|
||||
if (!vector)
|
||||
return NULL;
|
||||
|
||||
/* Return record with conditioned index */
|
||||
if (index < vector->count)
|
||||
return vector->pairs[index];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Erase all the contents of a key-value pair vector.
|
||||
*
|
||||
* @param vector Key-Value pair vector.
|
||||
* @return 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_sd_kv_vector_erase( kv_vector *vector )
|
||||
{
|
||||
uint16_t i = 0;
|
||||
|
||||
/* Iterate over each key-value pair */
|
||||
for (i = 0; i < vector->count; i++) {
|
||||
if (pico_dns_sd_kv_delete(&(vector->pairs[i])) < 0) {
|
||||
dns_sd_dbg("Could not delete key-value pairs from vector");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
PICO_FREE(vector->pairs);
|
||||
vector->pairs = NULL;
|
||||
vector->count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
91
ext/picotcp/modules/pico_dns_sd.h
Normal file
91
ext/picotcp/modules/pico_dns_sd.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/* ****************************************************************************
|
||||
* PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved.
|
||||
* See LICENSE and COPYING for usage.
|
||||
* .
|
||||
* Author: Jelle De Vleeschouwer
|
||||
* ****************************************************************************/
|
||||
#ifndef INCLUDE_PICO_DNS_SD
|
||||
#define INCLUDE_PICO_DNS_SD
|
||||
|
||||
#include "pico_mdns.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *key;
|
||||
char *value;
|
||||
} key_value_pair_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
key_value_pair_t **pairs;
|
||||
uint16_t count;
|
||||
} kv_vector;
|
||||
|
||||
#define PICO_DNS_SD_KV_VECTOR_DECLARE(name) \
|
||||
kv_vector (name) = {0}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Just calls pico_mdns_init in it's turn to initialise the mDNS-module.
|
||||
* See pico_mdns.h for description.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_sd_init( const char *_hostname,
|
||||
struct pico_ip4 address,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Register a DNS-SD service via Multicast DNS on the local network.
|
||||
*
|
||||
* @param name Instance Name of the service, f.e. "Printer 2nd Floor".
|
||||
* @param type ServiceType of the service, f.e. "_http._tcp".
|
||||
* @param port Port number on which the service runs.
|
||||
* @param txt_data TXT data to create TXT record with, need kv_vector-type,
|
||||
* Declare such a type with PICO_DNS_SD_KV_VECTOR_DECLARE(*) &
|
||||
* add key-value pairs with pico_dns_sd_kv_vector_add().
|
||||
* @param ttl TTL
|
||||
* @param callback Callback-function to call when the service is registered.
|
||||
* @return
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_sd_register_service( const char *name,
|
||||
const char *type,
|
||||
uint16_t port,
|
||||
kv_vector *txt_data,
|
||||
uint16_t ttl,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg);
|
||||
|
||||
/* ****************************************************************************
|
||||
* Does nothing for now.
|
||||
*
|
||||
* @param type Type to browse for.
|
||||
* @param callback Callback to call when something particular happens.
|
||||
* @return When the module successfully started browsing the servicetype.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_sd_browse_service( const char *type,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Add a key-value pair the a key-value pair vector.
|
||||
*
|
||||
* @param vector Vector to add the pair to.
|
||||
* @param key Key of the pair, cannot be NULL.
|
||||
* @param value Value of the pair, can be NULL, empty ("") or filled ("qkejq")
|
||||
* @return Returns 0 when the pair is added successfully, something else on
|
||||
* failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_dns_sd_kv_vector_add( kv_vector *vector, char *key, char *value );
|
||||
|
||||
|
||||
#endif /* _INCLUDE_PICO_DNS_SD */
|
||||
|
||||
391
ext/picotcp/modules/pico_fragments.c
Normal file
391
ext/picotcp/modules/pico_fragments.c
Normal file
@@ -0,0 +1,391 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Laurens Miers, Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include "pico_config.h"
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
#include "pico_ipv6.h"
|
||||
#include "pico_icmp6.h"
|
||||
#endif
|
||||
#ifdef PICO_SUPPORT_IPV4
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_icmp4.h"
|
||||
#endif
|
||||
#include "pico_stack.h"
|
||||
#include "pico_eth.h"
|
||||
#include "pico_udp.h"
|
||||
#include "pico_tcp.h"
|
||||
#include "pico_socket.h"
|
||||
#include "pico_device.h"
|
||||
#include "pico_tree.h"
|
||||
#include "pico_constants.h"
|
||||
#include "pico_fragments.h"
|
||||
|
||||
#define frag_dbg(...) do {} while(0)
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
#define IP6_FRAG_OFF(x) ((x & 0xFFF8u))
|
||||
#define IP6_FRAG_MORE(x) ((x & 0x0001))
|
||||
#define IP6_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]))
|
||||
#else
|
||||
#define IP6_FRAG_OFF(x) (0)
|
||||
#define IP6_FRAG_MORE(x) (0)
|
||||
#define IP6_FRAG_ID(x) (0)
|
||||
#endif
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
#define IP4_FRAG_OFF(frag) (((uint32_t)frag & PICO_IPV4_FRAG_MASK) << 3ul)
|
||||
#define IP4_FRAG_MORE(frag) ((frag & PICO_IPV4_MOREFRAG) ? 1 : 0)
|
||||
#define IP4_FRAG_ID(hdr) (hdr->id)
|
||||
#else
|
||||
#define IP4_FRAG_OFF(frag) (0)
|
||||
#define IP4_FRAG_MORE(frag) (0)
|
||||
#define IP4_FRAG_ID(hdr) (0)
|
||||
#endif
|
||||
|
||||
#define FRAG_OFF(net, frag) ((net == PICO_PROTO_IPV4) ? (IP4_FRAG_OFF(frag)) : (IP6_FRAG_OFF(frag)))
|
||||
#define FRAG_MORE(net, frag) ((net == PICO_PROTO_IPV4) ? (IP4_FRAG_MORE(frag)) : (IP6_FRAG_MORE(frag)))
|
||||
|
||||
#define PICO_IPV6_FRAG_TIMEOUT 60000
|
||||
#define PICO_IPV4_FRAG_TIMEOUT 15000
|
||||
|
||||
static void pico_frag_expire(pico_time now, void *arg);
|
||||
static void pico_fragments_complete(unsigned int bookmark, uint8_t proto, uint8_t net);
|
||||
static int pico_fragments_check_complete(uint8_t proto, uint8_t net);
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
static uint32_t ipv6_cur_frag_id = 0u;
|
||||
uint32_t ipv6_fragments_timer = 0u;
|
||||
|
||||
static int pico_ipv6_frag_compare(void *ka, void *kb)
|
||||
{
|
||||
struct pico_frame *a = ka, *b = kb;
|
||||
if (IP6_FRAG_OFF(a->frag) > IP6_FRAG_OFF(b->frag))
|
||||
return 1;
|
||||
|
||||
if (IP6_FRAG_OFF(a->frag) < IP6_FRAG_OFF(b->frag))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
PICO_TREE_DECLARE(ipv6_fragments, pico_ipv6_frag_compare);
|
||||
|
||||
static void pico_ipv6_fragments_complete(unsigned int len, uint8_t proto)
|
||||
{
|
||||
struct pico_tree_node *index, *tmp;
|
||||
struct pico_frame *f;
|
||||
unsigned int bookmark = 0;
|
||||
struct pico_frame *full = NULL;
|
||||
struct pico_frame *first = pico_tree_first(&ipv6_fragments);
|
||||
|
||||
full = pico_frame_alloc((uint16_t)(PICO_SIZE_IP6HDR + len));
|
||||
if (full) {
|
||||
full->net_hdr = full->buffer;
|
||||
full->net_len = PICO_SIZE_IP6HDR;
|
||||
memcpy(full->net_hdr, first->net_hdr, full->net_len);
|
||||
full->transport_hdr = full->net_hdr + full->net_len;
|
||||
full->transport_len = (uint16_t)len;
|
||||
full->dev = first->dev;
|
||||
pico_tree_foreach_safe(index, &ipv6_fragments, tmp) {
|
||||
f = index->keyValue;
|
||||
memcpy(full->transport_hdr + bookmark, f->transport_hdr, f->transport_len);
|
||||
bookmark += f->transport_len;
|
||||
pico_tree_delete(&ipv6_fragments, f);
|
||||
pico_frame_discard(f);
|
||||
}
|
||||
if (pico_transport_receive(full, proto) == -1)
|
||||
{
|
||||
pico_frame_discard(full);
|
||||
}
|
||||
pico_timer_cancel(ipv6_fragments_timer);
|
||||
ipv6_fragments_timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pico_ipv6_frag_timer_on(void)
|
||||
{
|
||||
ipv6_fragments_timer = pico_timer_add(PICO_IPV6_FRAG_TIMEOUT, pico_frag_expire, &ipv6_fragments);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
static uint32_t ipv4_cur_frag_id = 0u;
|
||||
uint32_t ipv4_fragments_timer = 0u;
|
||||
|
||||
static int pico_ipv4_frag_compare(void *ka, void *kb)
|
||||
{
|
||||
struct pico_frame *a = ka, *b = kb;
|
||||
if (IP4_FRAG_OFF(a->frag) > IP4_FRAG_OFF(b->frag))
|
||||
return 1;
|
||||
|
||||
if (IP4_FRAG_OFF(a->frag) < IP4_FRAG_OFF(b->frag))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
PICO_TREE_DECLARE(ipv4_fragments, pico_ipv4_frag_compare);
|
||||
|
||||
static void pico_ipv4_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(&ipv4_fragments);
|
||||
|
||||
full = pico_frame_alloc((uint16_t)(PICO_SIZE_IP4HDR + len));
|
||||
if (full) {
|
||||
full->net_hdr = full->buffer;
|
||||
full->net_len = PICO_SIZE_IP4HDR;
|
||||
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, &ipv4_fragments, tmp) {
|
||||
f = index->keyValue;
|
||||
memcpy(full->transport_hdr + bookmark, f->transport_hdr, f->transport_len);
|
||||
bookmark += f->transport_len;
|
||||
pico_tree_delete(&ipv4_fragments, f);
|
||||
pico_frame_discard(f);
|
||||
}
|
||||
ipv4_cur_frag_id = 0;
|
||||
if (pico_transport_receive(full, proto) == -1)
|
||||
{
|
||||
pico_frame_discard(full);
|
||||
}
|
||||
pico_timer_cancel(ipv4_fragments_timer);
|
||||
ipv4_fragments_timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pico_ipv4_frag_timer_on(void)
|
||||
{
|
||||
ipv4_fragments_timer = pico_timer_add( PICO_IPV4_FRAG_TIMEOUT, pico_frag_expire, &ipv4_fragments);
|
||||
}
|
||||
|
||||
static int pico_ipv4_frag_match(struct pico_frame *a, struct pico_frame *b)
|
||||
{
|
||||
struct pico_ipv4_hdr *ha, *hb;
|
||||
if (!a || !b)
|
||||
return 0;
|
||||
|
||||
ha = (struct pico_ipv4_hdr *)a->net_hdr;
|
||||
hb = (struct pico_ipv4_hdr *)b->net_hdr;
|
||||
if (!ha || !hb)
|
||||
return 0;
|
||||
|
||||
if (memcmp(&(ha->src.addr), &(hb->src.addr), PICO_SIZE_IP4) != 0)
|
||||
return 0;
|
||||
|
||||
if (memcmp(&(ha->dst.addr), &(hb->dst.addr), PICO_SIZE_IP4) != 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void pico_fragments_complete(unsigned int bookmark, uint8_t proto, uint8_t net)
|
||||
{
|
||||
if (0) {}
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
else if (net == PICO_PROTO_IPV4)
|
||||
{
|
||||
pico_ipv4_fragments_complete(bookmark, proto);
|
||||
}
|
||||
#endif
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
else if (net == PICO_PROTO_IPV6)
|
||||
{
|
||||
pico_ipv6_fragments_complete(bookmark, proto);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int pico_fragments_check_complete(uint8_t proto, uint8_t net)
|
||||
{
|
||||
struct pico_tree_node *index, *temp;
|
||||
struct pico_frame *cur;
|
||||
unsigned int bookmark = 0;
|
||||
struct pico_tree *tree = NULL;
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
if (net == PICO_PROTO_IPV4)
|
||||
{
|
||||
tree = &ipv4_fragments;
|
||||
}
|
||||
#endif
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
if (net == PICO_PROTO_IPV6)
|
||||
{
|
||||
tree = &ipv6_fragments;
|
||||
}
|
||||
#endif
|
||||
|
||||
pico_tree_foreach_safe(index, tree, temp) {
|
||||
cur = index->keyValue;
|
||||
if (FRAG_OFF(net, cur->frag) != bookmark)
|
||||
return 0;
|
||||
|
||||
bookmark += cur->transport_len;
|
||||
if (!FRAG_MORE(net, cur->frag)) {
|
||||
pico_fragments_complete(bookmark, proto, net);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pico_frag_expire(pico_time now, void *arg)
|
||||
{
|
||||
struct pico_tree_node *index, *tmp;
|
||||
struct pico_frame *f = NULL;
|
||||
struct pico_tree *tree = (struct pico_tree *) arg;
|
||||
struct pico_frame *first = NULL;
|
||||
uint8_t net = 0;
|
||||
(void)now;
|
||||
|
||||
if (!tree)
|
||||
{
|
||||
frag_dbg("Expired packet but no tree supplied!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
first = pico_tree_first(tree);
|
||||
|
||||
if (!first) {
|
||||
frag_dbg("not first - not sending notify\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
if (IS_IPV4(first))
|
||||
{
|
||||
net = PICO_PROTO_IPV4;
|
||||
frag_dbg("Packet expired! ID:%hu\n", ipv4_cur_frag_id);
|
||||
}
|
||||
#endif
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
if (IS_IPV6(first))
|
||||
{
|
||||
net = PICO_PROTO_IPV6;
|
||||
frag_dbg("Packet expired! ID:%hu\n", ipv6_cur_frag_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Empty the tree */
|
||||
pico_tree_foreach_safe(index, tree, tmp) {
|
||||
f = index->keyValue;
|
||||
pico_tree_delete(tree, f);
|
||||
if (f != first)
|
||||
pico_frame_discard(f); /* Later, after ICMP notification...*/
|
||||
|
||||
}
|
||||
|
||||
if (((FRAG_OFF(net, first->frag) == 0) && (pico_frame_dst_is_unicast(first))))
|
||||
{
|
||||
frag_dbg("sending notify\n");
|
||||
pico_notify_frag_expired(first);
|
||||
}
|
||||
|
||||
if (f)
|
||||
pico_tree_delete(tree, f);
|
||||
|
||||
pico_frame_discard(first);
|
||||
}
|
||||
|
||||
void pico_ipv6_process_frag(struct pico_ipv6_exthdr *frag, struct pico_frame *f, uint8_t proto)
|
||||
{
|
||||
#if defined(PICO_SUPPORT_IPV6) && defined(PICO_SUPPORT_IPV6FRAG)
|
||||
struct pico_frame *first = pico_tree_first(&ipv6_fragments);
|
||||
|
||||
if (!first) {
|
||||
if (ipv6_cur_frag_id && (IP6_FRAG_ID(frag) == ipv6_cur_frag_id)) {
|
||||
/* Discard late arrivals, without firing the timer. */
|
||||
frag_dbg("discarded late arrival, exp:%hu found:%hu\n", ipv6_cur_frag_id, IP6_FRAG_ID(frag));
|
||||
return;
|
||||
}
|
||||
|
||||
pico_ipv6_frag_timer_on();
|
||||
ipv6_cur_frag_id = IP6_FRAG_ID(frag);
|
||||
frag_dbg("Started new reassembly, ID:%hu\n", ipv6_cur_frag_id);
|
||||
}
|
||||
|
||||
if (!first || (pico_ipv6_frag_match(f, first) && (IP6_FRAG_ID(frag) == ipv6_cur_frag_id))) {
|
||||
pico_tree_insert(&ipv6_fragments, pico_frame_copy(f));
|
||||
}
|
||||
|
||||
pico_fragments_check_complete(proto, PICO_PROTO_IPV6);
|
||||
#else
|
||||
IGNORE_PARAMETER(frag);
|
||||
IGNORE_PARAMETER(f);
|
||||
IGNORE_PARAMETER(proto);
|
||||
#endif
|
||||
}
|
||||
|
||||
void pico_ipv4_process_frag(struct pico_ipv4_hdr *hdr, struct pico_frame *f, uint8_t proto)
|
||||
{
|
||||
#if defined(PICO_SUPPORT_IPV4) && defined(PICO_SUPPORT_IPV4FRAG)
|
||||
struct pico_frame *first = pico_tree_first(&ipv4_fragments);
|
||||
|
||||
/* fragments from old packets still in tree, and new first fragment ? */
|
||||
if (first && (IP4_FRAG_ID(hdr) != ipv4_cur_frag_id) && (IP4_FRAG_OFF(f->frag) == 0))
|
||||
{
|
||||
/* Empty the tree */
|
||||
struct pico_tree_node *index, *tmp;
|
||||
pico_tree_foreach_safe(index, &ipv4_fragments, tmp) {
|
||||
struct pico_frame * old = index->keyValue;
|
||||
pico_tree_delete(&ipv4_fragments, old);
|
||||
pico_frame_discard(old);
|
||||
}
|
||||
first = NULL;
|
||||
ipv4_cur_frag_id = 0;
|
||||
}
|
||||
|
||||
f->frag = short_be(hdr->frag);
|
||||
if (!first) {
|
||||
if (ipv4_cur_frag_id && (IP4_FRAG_ID(hdr) == ipv4_cur_frag_id)) {
|
||||
/* Discard late arrivals, without firing the timer */
|
||||
return;
|
||||
}
|
||||
|
||||
pico_ipv4_frag_timer_on();
|
||||
ipv4_cur_frag_id = IP4_FRAG_ID(hdr);
|
||||
}
|
||||
|
||||
if (!first || (pico_ipv4_frag_match(f, first) && (IP4_FRAG_ID(hdr) == ipv4_cur_frag_id))) {
|
||||
pico_tree_insert(&ipv4_fragments, pico_frame_copy(f));
|
||||
}
|
||||
|
||||
pico_fragments_check_complete(proto, PICO_PROTO_IPV4);
|
||||
#else
|
||||
IGNORE_PARAMETER(hdr);
|
||||
IGNORE_PARAMETER(f);
|
||||
IGNORE_PARAMETER(proto);
|
||||
#endif
|
||||
}
|
||||
11
ext/picotcp/modules/pico_fragments.h
Normal file
11
ext/picotcp/modules/pico_fragments.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef PICO_FRAGMENTS_H
|
||||
#define PICO_FRAGMENTS_H
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_ipv6.h"
|
||||
#include "pico_addressing.h"
|
||||
#include "pico_frame.h"
|
||||
|
||||
void pico_ipv6_process_frag(struct pico_ipv6_exthdr *frag, struct pico_frame *f, uint8_t proto);
|
||||
void pico_ipv4_process_frag(struct pico_ipv4_hdr *hdr, struct pico_frame *f, uint8_t proto);
|
||||
|
||||
#endif
|
||||
134
ext/picotcp/modules/pico_hotplug_detection.c
Normal file
134
ext/picotcp/modules/pico_hotplug_detection.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Frederik Van Slycken
|
||||
*********************************************************************/
|
||||
#include "pico_protocol.h"
|
||||
#include "pico_hotplug_detection.h"
|
||||
#include "pico_tree.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
struct pico_hotplug_device{
|
||||
struct pico_device *dev;
|
||||
int prev_state;
|
||||
struct pico_tree callbacks;
|
||||
};
|
||||
|
||||
uint32_t timer_id = 0;
|
||||
|
||||
static int pico_hotplug_dev_cmp(void *ka, void *kb)
|
||||
{
|
||||
struct pico_hotplug_device *a = ka, *b = kb;
|
||||
if (a->dev->hash < b->dev->hash)
|
||||
return -1;
|
||||
|
||||
if (a->dev->hash > b->dev->hash)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int callback_compare(void *ka, void *kb)
|
||||
{
|
||||
if (ka < kb)
|
||||
return -1;
|
||||
if (ka > kb)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PICO_TREE_DECLARE(Hotplug_device_tree, pico_hotplug_dev_cmp);
|
||||
|
||||
static void timer_cb(__attribute__((unused)) pico_time t, __attribute__((unused)) void* v)
|
||||
{
|
||||
struct pico_tree_node *node = NULL, *safe = NULL, *cb_node = NULL, *cb_safe = NULL;
|
||||
int new_state, event;
|
||||
struct pico_hotplug_device *hpdev = NULL;
|
||||
void (*cb)(struct pico_device *dev, int event);
|
||||
|
||||
//we don't know if one of the callbacks might deregister, so be safe
|
||||
pico_tree_foreach_safe(node, &Hotplug_device_tree, safe)
|
||||
{
|
||||
hpdev = node->keyValue;
|
||||
new_state = hpdev->dev->link_state(hpdev->dev);
|
||||
if (new_state != hpdev->prev_state)
|
||||
{
|
||||
if (new_state == 1){
|
||||
event = PICO_HOTPLUG_EVENT_UP;
|
||||
} else {
|
||||
event = PICO_HOTPLUG_EVENT_DOWN;
|
||||
}
|
||||
//we don't know if one of the callbacks might deregister, so be safe
|
||||
pico_tree_foreach_safe(cb_node, &(hpdev->callbacks), cb_safe)
|
||||
{
|
||||
cb = cb_node->keyValue;
|
||||
cb(hpdev->dev, event);
|
||||
}
|
||||
hpdev->prev_state = new_state;
|
||||
}
|
||||
}
|
||||
|
||||
timer_id = pico_timer_add(PICO_HOTPLUG_INTERVAL, &timer_cb, NULL);
|
||||
}
|
||||
|
||||
|
||||
int pico_hotplug_register(struct pico_device *dev, void (*cb)(struct pico_device *dev, int event))
|
||||
{
|
||||
struct pico_hotplug_device *hotplug_dev;
|
||||
struct pico_hotplug_device search = {.dev = dev};
|
||||
|
||||
if (dev->link_state == NULL){
|
||||
pico_err = PICO_ERR_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
hotplug_dev = (struct pico_hotplug_device*)pico_tree_findKey(&Hotplug_device_tree, &search);
|
||||
if (! hotplug_dev )
|
||||
{
|
||||
hotplug_dev = PICO_ZALLOC(sizeof(struct pico_hotplug_device));
|
||||
if (!hotplug_dev)
|
||||
{
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
hotplug_dev->dev = dev;
|
||||
hotplug_dev->prev_state = dev->link_state(hotplug_dev->dev);
|
||||
hotplug_dev->callbacks.root = &LEAF;
|
||||
hotplug_dev->callbacks.compare = &callback_compare;
|
||||
pico_tree_insert(&Hotplug_device_tree, hotplug_dev);
|
||||
}
|
||||
pico_tree_insert(&(hotplug_dev->callbacks), cb);
|
||||
|
||||
if (timer_id == 0)
|
||||
{
|
||||
timer_id = pico_timer_add(PICO_HOTPLUG_INTERVAL, &timer_cb, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_hotplug_deregister(struct pico_device *dev, void (*cb)(struct pico_device *dev, int event))
|
||||
{
|
||||
struct pico_hotplug_device* hotplug_dev;
|
||||
struct pico_hotplug_device search = {.dev = dev};
|
||||
|
||||
hotplug_dev = (struct pico_hotplug_device*)pico_tree_findKey(&Hotplug_device_tree, &search);
|
||||
if (!hotplug_dev)
|
||||
//wasn't registered
|
||||
return 0;
|
||||
pico_tree_delete(&hotplug_dev->callbacks, cb);
|
||||
if (pico_tree_empty(&hotplug_dev->callbacks))
|
||||
{
|
||||
pico_tree_delete(&Hotplug_device_tree, hotplug_dev);
|
||||
PICO_FREE(hotplug_dev);
|
||||
}
|
||||
|
||||
if (pico_tree_empty(&Hotplug_device_tree) && timer_id != 0)
|
||||
{
|
||||
pico_timer_cancel(timer_id);
|
||||
timer_id = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
20
ext/picotcp/modules/pico_hotplug_detection.h
Normal file
20
ext/picotcp/modules/pico_hotplug_detection.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Frederik Van Slycken
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_SUPPORT_HOTPLUG
|
||||
#define INCLUDE_PICO_SUPPORT_HOTPLUG
|
||||
#include "pico_stack.h"
|
||||
|
||||
#define PICO_HOTPLUG_EVENT_UP 1 /* link went up */
|
||||
#define PICO_HOTPLUG_EVENT_DOWN 2 /* link went down */
|
||||
|
||||
#define PICO_HOTPLUG_INTERVAL 100
|
||||
|
||||
int pico_hotplug_register(struct pico_device *dev, void (*cb)(struct pico_device *dev, int event));
|
||||
int pico_hotplug_deregister(struct pico_device *dev, void (*cb)(struct pico_device *dev, int event));
|
||||
|
||||
#endif /* _INCLUDE_PICO_SUPPORT_HOTPLUG */
|
||||
|
||||
395
ext/picotcp/modules/pico_icmp4.c
Normal file
395
ext/picotcp/modules/pico_icmp4.c
Normal file
@@ -0,0 +1,395 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#include "pico_icmp4.h"
|
||||
#include "pico_config.h"
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_eth.h"
|
||||
#include "pico_device.h"
|
||||
#include "pico_stack.h"
|
||||
#include "pico_tree.h"
|
||||
|
||||
/* Queues */
|
||||
static struct pico_queue icmp_in = {
|
||||
0
|
||||
};
|
||||
static struct pico_queue icmp_out = {
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/* Functions */
|
||||
|
||||
static int pico_icmp4_checksum(struct pico_frame *f)
|
||||
{
|
||||
struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
|
||||
if (!hdr) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr->crc = 0;
|
||||
hdr->crc = short_be(pico_checksum(hdr, f->transport_len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef PICO_SUPPORT_PING
|
||||
static void ping_recv_reply(struct pico_frame *f);
|
||||
#endif
|
||||
|
||||
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) {
|
||||
hdr->type = PICO_ICMP_ECHOREPLY;
|
||||
/* outgoing frames require a f->len without the ethernet header len */
|
||||
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) {
|
||||
f->net_hdr = f->transport_hdr + PICO_ICMPHDR_UN_SIZE;
|
||||
pico_ipv4_unreachable(f, hdr->code);
|
||||
} else if (hdr->type == PICO_ICMP_ECHOREPLY) {
|
||||
#ifdef PICO_SUPPORT_PING
|
||||
ping_recv_reply(f);
|
||||
#endif
|
||||
pico_frame_discard(f);
|
||||
} else {
|
||||
pico_frame_discard(f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_icmp4_process_out(struct pico_protocol *self, struct pico_frame *f)
|
||||
{
|
||||
IGNORE_PARAMETER(self);
|
||||
IGNORE_PARAMETER(f);
|
||||
dbg("Called %s\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Interface: protocol definition */
|
||||
struct pico_protocol pico_proto_icmp4 = {
|
||||
.name = "icmp4",
|
||||
.proto_number = PICO_PROTO_ICMP4,
|
||||
.layer = PICO_LAYER_TRANSPORT,
|
||||
.process_in = pico_icmp4_process_in,
|
||||
.process_out = pico_icmp4_process_out,
|
||||
.q_in = &icmp_in,
|
||||
.q_out = &icmp_out,
|
||||
};
|
||||
|
||||
static int pico_icmp4_notify(struct pico_frame *f, uint8_t type, uint8_t code)
|
||||
{
|
||||
struct pico_frame *reply;
|
||||
struct pico_icmp4_hdr *hdr;
|
||||
struct pico_ipv4_hdr *info;
|
||||
uint16_t f_tot_len;
|
||||
|
||||
f_tot_len = short_be(((struct pico_ipv4_hdr *)f->net_hdr)->len);
|
||||
|
||||
if (f_tot_len < (sizeof(struct pico_ipv4_hdr)))
|
||||
return -1;
|
||||
|
||||
/* Truncate tot len to be at most 8 bytes + iphdr */
|
||||
if (f_tot_len > (sizeof(struct pico_ipv4_hdr) + 8u)) {
|
||||
f_tot_len = (sizeof(struct pico_ipv4_hdr) + 8u);
|
||||
}
|
||||
|
||||
if (f == NULL) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
reply = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t) (f_tot_len + PICO_ICMPHDR_UN_SIZE));
|
||||
info = (struct pico_ipv4_hdr*)(f->net_hdr);
|
||||
hdr = (struct pico_icmp4_hdr *) reply->transport_hdr;
|
||||
hdr->type = type;
|
||||
hdr->code = code;
|
||||
hdr->hun.ih_pmtu.ipm_nmtu = short_be(1500);
|
||||
hdr->hun.ih_pmtu.ipm_void = 0;
|
||||
reply->transport_len = (uint16_t)(f_tot_len + PICO_ICMPHDR_UN_SIZE);
|
||||
reply->payload = reply->transport_hdr + PICO_ICMPHDR_UN_SIZE;
|
||||
memcpy(reply->payload, f->net_hdr, f_tot_len);
|
||||
pico_icmp4_checksum(reply);
|
||||
pico_ipv4_frame_push(reply, &info->src, PICO_PROTO_ICMP4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_icmp4_port_unreachable(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PORT);
|
||||
}
|
||||
|
||||
int pico_icmp4_proto_unreachable(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PROTOCOL);
|
||||
}
|
||||
|
||||
int pico_icmp4_dest_unreachable(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_HOST);
|
||||
}
|
||||
|
||||
int pico_icmp4_ttl_expired(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_INTRANS);
|
||||
}
|
||||
|
||||
MOCKABLE int pico_icmp4_frag_expired(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_REASS);
|
||||
}
|
||||
|
||||
int pico_icmp4_mtu_exceeded(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_NEEDFRAG);
|
||||
}
|
||||
|
||||
int pico_icmp4_packet_filtered(struct pico_frame *f)
|
||||
{
|
||||
/*Parameter check executed in pico_icmp4_notify*/
|
||||
/*Packet Filtered: type 3, code 13 (Communication Administratively Prohibited)*/
|
||||
return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_FILTER_PROHIB);
|
||||
}
|
||||
|
||||
int pico_icmp4_param_problem(struct pico_frame *f, uint8_t code)
|
||||
{
|
||||
return pico_icmp4_notify(f, PICO_ICMP_PARAMPROB, code);
|
||||
}
|
||||
|
||||
/***********************/
|
||||
/* Ping implementation */
|
||||
/***********************/
|
||||
/***********************/
|
||||
/***********************/
|
||||
/***********************/
|
||||
|
||||
|
||||
#ifdef PICO_SUPPORT_PING
|
||||
|
||||
|
||||
struct pico_icmp4_ping_cookie
|
||||
{
|
||||
struct pico_ip4 dst;
|
||||
uint16_t err;
|
||||
uint16_t id;
|
||||
uint16_t seq;
|
||||
uint16_t size;
|
||||
int count;
|
||||
pico_time timestamp;
|
||||
int interval;
|
||||
int timeout;
|
||||
void (*cb)(struct pico_icmp4_stats*);
|
||||
};
|
||||
|
||||
static int cookie_compare(void *ka, void *kb)
|
||||
{
|
||||
struct pico_icmp4_ping_cookie *a = ka, *b = kb;
|
||||
if (a->id < b->id)
|
||||
return -1;
|
||||
|
||||
if (a->id > b->id)
|
||||
return 1;
|
||||
|
||||
return (a->seq - b->seq);
|
||||
}
|
||||
|
||||
PICO_TREE_DECLARE(Pings, cookie_compare);
|
||||
|
||||
static int8_t pico_icmp4_send_echo(struct pico_icmp4_ping_cookie *cookie)
|
||||
{
|
||||
struct pico_frame *echo = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t)(PICO_ICMPHDR_UN_SIZE + cookie->size));
|
||||
struct pico_icmp4_hdr *hdr;
|
||||
if (!echo) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr = (struct pico_icmp4_hdr *) echo->transport_hdr;
|
||||
|
||||
hdr->type = PICO_ICMP_ECHO;
|
||||
hdr->code = 0;
|
||||
hdr->hun.ih_idseq.idseq_id = short_be(cookie->id);
|
||||
hdr->hun.ih_idseq.idseq_seq = short_be(cookie->seq);
|
||||
echo->transport_len = (uint16_t)(PICO_ICMPHDR_UN_SIZE + cookie->size);
|
||||
echo->payload = echo->transport_hdr + PICO_ICMPHDR_UN_SIZE;
|
||||
echo->payload_len = cookie->size;
|
||||
/* XXX: Fill payload */
|
||||
pico_icmp4_checksum(echo);
|
||||
pico_ipv4_frame_push(echo, &cookie->dst, PICO_PROTO_ICMP4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ping_timeout(pico_time now, void *arg)
|
||||
{
|
||||
struct pico_icmp4_ping_cookie *cookie = (struct pico_icmp4_ping_cookie *)arg;
|
||||
IGNORE_PARAMETER(now);
|
||||
|
||||
if(pico_tree_findKey(&Pings, cookie)) {
|
||||
if (cookie->err == PICO_PING_ERR_PENDING) {
|
||||
struct pico_icmp4_stats stats;
|
||||
stats.dst = cookie->dst;
|
||||
stats.seq = cookie->seq;
|
||||
stats.time = 0;
|
||||
stats.size = cookie->size;
|
||||
stats.err = PICO_PING_ERR_TIMEOUT;
|
||||
dbg(" ---- Ping timeout!!!\n");
|
||||
cookie->cb(&stats);
|
||||
}
|
||||
|
||||
pico_tree_delete(&Pings, cookie);
|
||||
PICO_FREE(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
static void next_ping(pico_time now, void *arg);
|
||||
static inline void send_ping(struct pico_icmp4_ping_cookie *cookie)
|
||||
{
|
||||
pico_icmp4_send_echo(cookie);
|
||||
cookie->timestamp = pico_tick;
|
||||
pico_timer_add((uint32_t)cookie->timeout, ping_timeout, cookie);
|
||||
if (cookie->seq < (uint16_t)cookie->count)
|
||||
pico_timer_add((uint32_t)cookie->interval, next_ping, cookie);
|
||||
}
|
||||
|
||||
static void next_ping(pico_time now, void *arg)
|
||||
{
|
||||
struct pico_icmp4_ping_cookie *newcookie, *cookie = (struct pico_icmp4_ping_cookie *)arg;
|
||||
IGNORE_PARAMETER(now);
|
||||
|
||||
if(pico_tree_findKey(&Pings, cookie)) {
|
||||
if (cookie->err == PICO_PING_ERR_ABORTED)
|
||||
return;
|
||||
|
||||
if (cookie->seq < (uint16_t)cookie->count) {
|
||||
newcookie = PICO_ZALLOC(sizeof(struct pico_icmp4_ping_cookie));
|
||||
if (!newcookie)
|
||||
return;
|
||||
|
||||
memcpy(newcookie, cookie, sizeof(struct pico_icmp4_ping_cookie));
|
||||
newcookie->seq++;
|
||||
|
||||
pico_tree_insert(&Pings, newcookie);
|
||||
send_ping(newcookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ping_recv_reply(struct pico_frame *f)
|
||||
{
|
||||
struct pico_icmp4_ping_cookie test, *cookie;
|
||||
struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
|
||||
test.id = short_be(hdr->hun.ih_idseq.idseq_id );
|
||||
test.seq = short_be(hdr->hun.ih_idseq.idseq_seq);
|
||||
|
||||
cookie = pico_tree_findKey(&Pings, &test);
|
||||
if (cookie) {
|
||||
struct pico_icmp4_stats stats;
|
||||
if (cookie->err == PICO_PING_ERR_ABORTED)
|
||||
return;
|
||||
|
||||
cookie->err = PICO_PING_ERR_REPLIED;
|
||||
stats.dst = ((struct pico_ipv4_hdr *)f->net_hdr)->src;
|
||||
stats.seq = cookie->seq;
|
||||
stats.size = cookie->size;
|
||||
stats.time = pico_tick - cookie->timestamp;
|
||||
stats.err = cookie->err;
|
||||
stats.ttl = ((struct pico_ipv4_hdr *)f->net_hdr)->ttl;
|
||||
if(cookie->cb != NULL)
|
||||
cookie->cb(&stats);
|
||||
} else {
|
||||
dbg("Reply for seq=%d, not found.\n", test.seq);
|
||||
}
|
||||
}
|
||||
|
||||
int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *))
|
||||
{
|
||||
static uint16_t next_id = 0x91c0;
|
||||
struct pico_icmp4_ping_cookie *cookie;
|
||||
|
||||
if((dst == NULL) || (interval == 0) || (timeout == 0) || (count == 0)) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cookie = PICO_ZALLOC(sizeof(struct pico_icmp4_ping_cookie));
|
||||
if (!cookie) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pico_string_to_ipv4(dst, (uint32_t *)&cookie->dst.addr) < 0) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
PICO_FREE(cookie);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cookie->seq = 1;
|
||||
cookie->id = next_id++;
|
||||
cookie->err = PICO_PING_ERR_PENDING;
|
||||
cookie->size = (uint16_t)size;
|
||||
cookie->interval = interval;
|
||||
cookie->timeout = timeout;
|
||||
cookie->cb = cb;
|
||||
cookie->count = count;
|
||||
|
||||
pico_tree_insert(&Pings, cookie);
|
||||
send_ping(cookie);
|
||||
|
||||
return cookie->id;
|
||||
|
||||
}
|
||||
|
||||
int pico_icmp4_ping_abort(int id)
|
||||
{
|
||||
struct pico_tree_node *node;
|
||||
int found = 0;
|
||||
pico_tree_foreach(node, &Pings)
|
||||
{
|
||||
struct pico_icmp4_ping_cookie *ck =
|
||||
(struct pico_icmp4_ping_cookie *) node->keyValue;
|
||||
if (ck->id == (uint16_t)id) {
|
||||
ck->err = PICO_PING_ERR_ABORTED;
|
||||
found++;
|
||||
}
|
||||
}
|
||||
if (found > 0)
|
||||
return 0; /* OK if at least one pending ping has been canceled */
|
||||
|
||||
pico_err = PICO_ERR_ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
162
ext/picotcp/modules/pico_icmp4.h
Normal file
162
ext/picotcp/modules/pico_icmp4.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_ICMP4
|
||||
#define INCLUDE_PICO_ICMP4
|
||||
#include "pico_defines.h"
|
||||
#include "pico_addressing.h"
|
||||
#include "pico_protocol.h"
|
||||
|
||||
|
||||
extern struct pico_protocol pico_proto_icmp4;
|
||||
|
||||
PACKED_STRUCT_DEF pico_icmp4_hdr {
|
||||
uint8_t type;
|
||||
uint8_t code;
|
||||
uint16_t crc;
|
||||
|
||||
/* hun */
|
||||
PACKED_UNION_DEF hun_u {
|
||||
uint8_t ih_pptr;
|
||||
struct pico_ip4 ih_gwaddr;
|
||||
PEDANTIC_STRUCT_DEF ih_idseq_s {
|
||||
uint16_t idseq_id;
|
||||
uint16_t idseq_seq;
|
||||
} ih_idseq;
|
||||
uint32_t ih_void;
|
||||
PEDANTIC_STRUCT_DEF ih_pmtu_s {
|
||||
uint16_t ipm_void;
|
||||
uint16_t ipm_nmtu;
|
||||
} ih_pmtu;
|
||||
PEDANTIC_STRUCT_DEF ih_rta_s {
|
||||
uint8_t rta_numgw;
|
||||
uint8_t rta_wpa;
|
||||
uint16_t rta_lifetime;
|
||||
} ih_rta;
|
||||
} hun;
|
||||
|
||||
/* dun */
|
||||
PACKED_UNION_DEF dun_u {
|
||||
PEDANTIC_STRUCT_DEF id_ts_s {
|
||||
uint32_t ts_otime;
|
||||
uint32_t ts_rtime;
|
||||
uint32_t ts_ttime;
|
||||
} id_ts;
|
||||
PEDANTIC_STRUCT_DEF id_ip_s {
|
||||
uint32_t ip_options;
|
||||
uint32_t ip_data_hi;
|
||||
uint32_t ip_data_lo;
|
||||
} id_ip;
|
||||
PEDANTIC_STRUCT_DEF id_ra_s {
|
||||
uint32_t ira_addr;
|
||||
uint32_t ira_pref;
|
||||
} id_ra;
|
||||
uint32_t id_mask;
|
||||
uint8_t id_data[1];
|
||||
} dun;
|
||||
};
|
||||
|
||||
#define PICO_ICMPHDR_DRY_SIZE 4
|
||||
#define PICO_ICMPHDR_UN_SIZE 8u
|
||||
|
||||
#define PICO_ICMP_ECHOREPLY 0
|
||||
#define PICO_ICMP_DEST_UNREACH 3
|
||||
#define PICO_ICMP_SOURCE_QUENCH 4
|
||||
#define PICO_ICMP_REDIRECT 5
|
||||
#define PICO_ICMP_ECHO 8
|
||||
#define PICO_ICMP_TIME_EXCEEDED 11
|
||||
#define PICO_ICMP_PARAMETERPROB 12
|
||||
#define PICO_ICMP_TIMESTAMP 13
|
||||
#define PICO_ICMP_TIMESTAMPREPLY 14
|
||||
#define PICO_ICMP_INFO_REQUEST 15
|
||||
#define PICO_ICMP_INFO_REPLY 16
|
||||
#define PICO_ICMP_ADDRESS 17
|
||||
#define PICO_ICMP_ADDRESSREPLY 18
|
||||
|
||||
|
||||
#define PICO_ICMP_UNREACH 3
|
||||
#define PICO_ICMP_SOURCEQUENCH 4
|
||||
#define PICO_ICMP_ROUTERADVERT 9
|
||||
#define PICO_ICMP_ROUTERSOLICIT 10
|
||||
#define PICO_ICMP_TIMXCEED 11
|
||||
#define PICO_ICMP_PARAMPROB 12
|
||||
#define PICO_ICMP_TSTAMP 13
|
||||
#define PICO_ICMP_TSTAMPREPLY 14
|
||||
#define PICO_ICMP_IREQ 15
|
||||
#define PICO_ICMP_IREQREPLY 16
|
||||
#define PICO_ICMP_MASKREQ 17
|
||||
#define PICO_ICMP_MASKREPLY 18
|
||||
|
||||
#define PICO_ICMP_MAXTYPE 18
|
||||
|
||||
|
||||
#define PICO_ICMP_UNREACH_NET 0
|
||||
#define PICO_ICMP_UNREACH_HOST 1
|
||||
#define PICO_ICMP_UNREACH_PROTOCOL 2
|
||||
#define PICO_ICMP_UNREACH_PORT 3
|
||||
#define PICO_ICMP_UNREACH_NEEDFRAG 4
|
||||
#define PICO_ICMP_UNREACH_SRCFAIL 5
|
||||
#define PICO_ICMP_UNREACH_NET_UNKNOWN 6
|
||||
#define PICO_ICMP_UNREACH_HOST_UNKNOWN 7
|
||||
#define PICO_ICMP_UNREACH_ISOLATED 8
|
||||
#define PICO_ICMP_UNREACH_NET_PROHIB 9
|
||||
#define PICO_ICMP_UNREACH_HOST_PROHIB 10
|
||||
#define PICO_ICMP_UNREACH_TOSNET 11
|
||||
#define PICO_ICMP_UNREACH_TOSHOST 12
|
||||
#define PICO_ICMP_UNREACH_FILTER_PROHIB 13
|
||||
#define PICO_ICMP_UNREACH_HOST_PRECEDENCE 14
|
||||
#define PICO_ICMP_UNREACH_PRECEDENCE_CUTOFF 15
|
||||
|
||||
|
||||
#define PICO_ICMP_REDIRECT_NET 0
|
||||
#define PICO_ICMP_REDIRECT_HOST 1
|
||||
#define PICO_ICMP_REDIRECT_TOSNET 2
|
||||
#define PICO_ICMP_REDIRECT_TOSHOST 3
|
||||
|
||||
|
||||
#define PICO_ICMP_TIMXCEED_INTRANS 0
|
||||
#define PICO_ICMP_TIMXCEED_REASS 1
|
||||
|
||||
|
||||
#define PICO_ICMP_PARAMPROB_OPTABSENT 1
|
||||
|
||||
#define PICO_SIZE_ICMP4HDR ((sizeof(struct pico_icmp4_hdr)))
|
||||
|
||||
struct pico_icmp4_stats
|
||||
{
|
||||
struct pico_ip4 dst;
|
||||
unsigned long size;
|
||||
unsigned long seq;
|
||||
pico_time time;
|
||||
unsigned long ttl;
|
||||
int err;
|
||||
};
|
||||
|
||||
int pico_icmp4_port_unreachable(struct pico_frame *f);
|
||||
int pico_icmp4_proto_unreachable(struct pico_frame *f);
|
||||
int pico_icmp4_dest_unreachable(struct pico_frame *f);
|
||||
int pico_icmp4_mtu_exceeded(struct pico_frame *f);
|
||||
int pico_icmp4_ttl_expired(struct pico_frame *f);
|
||||
int pico_icmp4_frag_expired(struct pico_frame *f);
|
||||
int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *));
|
||||
int pico_icmp4_ping_abort(int id);
|
||||
|
||||
#ifdef PICO_SUPPORT_ICMP4
|
||||
int pico_icmp4_packet_filtered(struct pico_frame *f);
|
||||
int pico_icmp4_param_problem(struct pico_frame *f, uint8_t code);
|
||||
#else
|
||||
# define pico_icmp4_packet_filtered(f) (-1)
|
||||
# define pico_icmp4_param_problem(f, c) (-1)
|
||||
#endif /* PICO_SUPPORT_ICMP4 */
|
||||
|
||||
#define PICO_PING_ERR_REPLIED 0
|
||||
#define PICO_PING_ERR_TIMEOUT 1
|
||||
#define PICO_PING_ERR_UNREACH 2
|
||||
#define PICO_PING_ERR_ABORTED 3
|
||||
#define PICO_PING_ERR_PENDING 0xFFFF
|
||||
|
||||
#endif
|
||||
698
ext/picotcp/modules/pico_icmp6.c
Normal file
698
ext/picotcp/modules/pico_icmp6.c
Normal file
@@ -0,0 +1,698 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
Authors: Kristof Roelants, Daniele Lacamera
|
||||
*********************************************************************/
|
||||
|
||||
#include "pico_config.h"
|
||||
#include "pico_icmp6.h"
|
||||
#include "pico_ipv6_nd.h"
|
||||
#include "pico_eth.h"
|
||||
#include "pico_device.h"
|
||||
#include "pico_stack.h"
|
||||
#include "pico_tree.h"
|
||||
#include "pico_socket.h"
|
||||
#include "pico_mld.h"
|
||||
#define icmp6_dbg(...) do { }while(0);
|
||||
|
||||
static struct pico_queue icmp6_in;
|
||||
static struct pico_queue icmp6_out;
|
||||
|
||||
uint16_t pico_icmp6_checksum(struct pico_frame *f)
|
||||
{
|
||||
struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr;
|
||||
|
||||
struct pico_icmp6_hdr *icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
|
||||
struct pico_ipv6_pseudo_hdr pseudo;
|
||||
|
||||
pseudo.src = ipv6_hdr->src;
|
||||
pseudo.dst = ipv6_hdr->dst;
|
||||
pseudo.len = long_be(f->transport_len);
|
||||
pseudo.nxthdr = PICO_PROTO_ICMP6;
|
||||
|
||||
pseudo.zero[0] = 0;
|
||||
pseudo.zero[1] = 0;
|
||||
pseudo.zero[2] = 0;
|
||||
|
||||
return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv6_pseudo_hdr), icmp6_hdr, f->transport_len);
|
||||
}
|
||||
|
||||
#ifdef PICO_SUPPORT_PING
|
||||
static void pico_icmp6_ping_recv_reply(struct pico_frame *f);
|
||||
#endif
|
||||
|
||||
static int pico_icmp6_send_echoreply(struct pico_frame *echo)
|
||||
{
|
||||
struct pico_frame *reply = NULL;
|
||||
struct pico_icmp6_hdr *ehdr = NULL, *rhdr = NULL;
|
||||
struct pico_ip6 src;
|
||||
struct pico_ip6 dst;
|
||||
|
||||
reply = pico_proto_ipv6.alloc(&pico_proto_ipv6, (uint16_t)(echo->transport_len));
|
||||
if (!reply) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
|
||||
reply->payload = reply->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
|
||||
reply->payload_len = echo->transport_len;
|
||||
reply->dev = echo->dev;
|
||||
|
||||
ehdr = (struct pico_icmp6_hdr *)echo->transport_hdr;
|
||||
rhdr = (struct pico_icmp6_hdr *)reply->transport_hdr;
|
||||
rhdr->type = PICO_ICMP6_ECHO_REPLY;
|
||||
rhdr->code = 0;
|
||||
rhdr->msg.info.echo_reply.id = ehdr->msg.info.echo_reply.id;
|
||||
rhdr->msg.info.echo_reply.seq = ehdr->msg.info.echo_request.seq;
|
||||
memcpy(reply->payload, echo->payload, (uint32_t)(echo->transport_len - PICO_ICMP6HDR_ECHO_REQUEST_SIZE));
|
||||
rhdr->crc = 0;
|
||||
rhdr->crc = short_be(pico_icmp6_checksum(reply));
|
||||
/* Get destination and source swapped */
|
||||
memcpy(dst.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, PICO_SIZE_IP6);
|
||||
memcpy(src.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->dst.addr, PICO_SIZE_IP6);
|
||||
pico_ipv6_frame_push(reply, &src, &dst, PICO_PROTO_ICMP6, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pico_icmp6_process_in(struct pico_protocol *self, struct pico_frame *f)
|
||||
{
|
||||
struct pico_icmp6_hdr *hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
|
||||
|
||||
IGNORE_PARAMETER(self);
|
||||
|
||||
icmp6_dbg("Process IN, type = %d\n", hdr->type);
|
||||
|
||||
switch (hdr->type)
|
||||
{
|
||||
case PICO_ICMP6_DEST_UNREACH:
|
||||
pico_ipv6_unreachable(f, hdr->code);
|
||||
break;
|
||||
|
||||
case PICO_ICMP6_ECHO_REQUEST:
|
||||
icmp6_dbg("ICMP6: Received ECHO REQ\n");
|
||||
f->transport_len = (uint16_t)(f->len - f->net_len - (uint16_t)(f->net_hdr - f->buffer));
|
||||
pico_icmp6_send_echoreply(f);
|
||||
pico_frame_discard(f);
|
||||
break;
|
||||
|
||||
case PICO_ICMP6_ECHO_REPLY:
|
||||
#ifdef PICO_SUPPORT_PING
|
||||
pico_icmp6_ping_recv_reply(f);
|
||||
#endif
|
||||
pico_frame_discard(f);
|
||||
break;
|
||||
#ifdef PICO_SUPPORT_MCAST
|
||||
case PICO_MLD_QUERY:
|
||||
case PICO_MLD_REPORT:
|
||||
case PICO_MLD_DONE:
|
||||
case PICO_MLD_REPORTV2:
|
||||
pico_mld_process_in(f);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return pico_ipv6_nd_recv(f); /* CAUTION -- Implies: pico_frame_discard in any case, keep in the default! */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pico_icmp6_process_out(struct pico_protocol *self, struct pico_frame *f)
|
||||
{
|
||||
IGNORE_PARAMETER(self);
|
||||
IGNORE_PARAMETER(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Interface: protocol definition */
|
||||
struct pico_protocol pico_proto_icmp6 = {
|
||||
.name = "icmp6",
|
||||
.proto_number = PICO_PROTO_ICMP6,
|
||||
.layer = PICO_LAYER_TRANSPORT,
|
||||
.process_in = pico_icmp6_process_in,
|
||||
.process_out = pico_icmp6_process_out,
|
||||
.q_in = &icmp6_in,
|
||||
.q_out = &icmp6_out,
|
||||
};
|
||||
|
||||
static int pico_icmp6_notify(struct pico_frame *f, uint8_t type, uint8_t code, uint32_t ptr)
|
||||
{
|
||||
struct pico_frame *notice = NULL;
|
||||
struct pico_ipv6_hdr *ipv6_hdr = NULL;
|
||||
struct pico_icmp6_hdr *icmp6_hdr = NULL;
|
||||
uint16_t len = 0;
|
||||
|
||||
if (!f)
|
||||
return -1;
|
||||
|
||||
ipv6_hdr = (struct pico_ipv6_hdr *)(f->net_hdr);
|
||||
len = (uint16_t)(short_be(ipv6_hdr->len) + PICO_SIZE_IP6HDR);
|
||||
switch (type)
|
||||
{
|
||||
case PICO_ICMP6_DEST_UNREACH:
|
||||
/* as much of invoking packet as possible without exceeding the minimum IPv6 MTU */
|
||||
if (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_DEST_UNREACH_SIZE + len > PICO_IPV6_MIN_MTU)
|
||||
len = PICO_IPV6_MIN_MTU - (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_DEST_UNREACH_SIZE);
|
||||
|
||||
notice = pico_proto_ipv6.alloc(&pico_proto_ipv6, (uint16_t)(PICO_ICMP6HDR_DEST_UNREACH_SIZE + len));
|
||||
if (!notice) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
notice->payload = notice->transport_hdr + PICO_ICMP6HDR_DEST_UNREACH_SIZE;
|
||||
notice->payload_len = len;
|
||||
icmp6_hdr = (struct pico_icmp6_hdr *)notice->transport_hdr;
|
||||
icmp6_hdr->msg.err.dest_unreach.unused = 0;
|
||||
break;
|
||||
|
||||
case PICO_ICMP6_TIME_EXCEEDED:
|
||||
/* as much of invoking packet as possible without exceeding the minimum IPv6 MTU */
|
||||
if (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_TIME_XCEEDED_SIZE + len > PICO_IPV6_MIN_MTU)
|
||||
len = PICO_IPV6_MIN_MTU - (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_TIME_XCEEDED_SIZE);
|
||||
|
||||
notice = pico_proto_ipv6.alloc(&pico_proto_ipv6, (uint16_t)(PICO_ICMP6HDR_TIME_XCEEDED_SIZE + len));
|
||||
if (!notice) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
notice->payload = notice->transport_hdr + PICO_ICMP6HDR_TIME_XCEEDED_SIZE;
|
||||
notice->payload_len = len;
|
||||
icmp6_hdr = (struct pico_icmp6_hdr *)notice->transport_hdr;
|
||||
icmp6_hdr->msg.err.time_exceeded.unused = 0;
|
||||
break;
|
||||
|
||||
case PICO_ICMP6_PARAM_PROBLEM:
|
||||
if (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_PARAM_PROBLEM_SIZE + len > PICO_IPV6_MIN_MTU)
|
||||
len = PICO_IPV6_MIN_MTU - (PICO_SIZE_IP6HDR + PICO_ICMP6HDR_PARAM_PROBLEM_SIZE);
|
||||
|
||||
notice = pico_proto_ipv6.alloc(&pico_proto_ipv6, (uint16_t)(PICO_ICMP6HDR_PARAM_PROBLEM_SIZE + len));
|
||||
if (!notice) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
notice->payload = notice->transport_hdr + PICO_ICMP6HDR_PARAM_PROBLEM_SIZE;
|
||||
notice->payload_len = len;
|
||||
icmp6_hdr = (struct pico_icmp6_hdr *)notice->transport_hdr;
|
||||
icmp6_hdr->msg.err.param_problem.ptr = long_be(ptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
icmp6_hdr->type = type;
|
||||
icmp6_hdr->code = code;
|
||||
memcpy(notice->payload, f->net_hdr, notice->payload_len);
|
||||
notice->dev = f->dev;
|
||||
/* f->src is set in frame_push, checksum calculated there */
|
||||
pico_ipv6_frame_push(notice, NULL, &ipv6_hdr->src, PICO_PROTO_ICMP6, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_icmp6_port_unreachable(struct pico_frame *f)
|
||||
{
|
||||
struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
|
||||
if (pico_ipv6_is_multicast(hdr->dst.addr))
|
||||
return 0;
|
||||
|
||||
return pico_icmp6_notify(f, PICO_ICMP6_DEST_UNREACH, PICO_ICMP6_UNREACH_PORT, 0);
|
||||
}
|
||||
|
||||
int pico_icmp6_proto_unreachable(struct pico_frame *f)
|
||||
{
|
||||
struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
|
||||
if (pico_ipv6_is_multicast(hdr->dst.addr))
|
||||
return 0;
|
||||
|
||||
return pico_icmp6_notify(f, PICO_ICMP6_DEST_UNREACH, PICO_ICMP6_UNREACH_ADDR, 0);
|
||||
}
|
||||
|
||||
int pico_icmp6_dest_unreachable(struct pico_frame *f)
|
||||
{
|
||||
struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
|
||||
if (pico_ipv6_is_multicast(hdr->dst.addr))
|
||||
return 0;
|
||||
|
||||
return pico_icmp6_notify(f, PICO_ICMP6_DEST_UNREACH, PICO_ICMP6_UNREACH_ADDR, 0);
|
||||
}
|
||||
|
||||
int pico_icmp6_ttl_expired(struct pico_frame *f)
|
||||
{
|
||||
struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
|
||||
if (pico_ipv6_is_multicast(hdr->dst.addr))
|
||||
return 0;
|
||||
|
||||
return pico_icmp6_notify(f, PICO_ICMP6_TIME_EXCEEDED, PICO_ICMP6_TIMXCEED_INTRANS, 0);
|
||||
}
|
||||
|
||||
int pico_icmp6_pkt_too_big(struct pico_frame *f)
|
||||
{
|
||||
struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
|
||||
if (pico_ipv6_is_multicast(hdr->dst.addr))
|
||||
return 0;
|
||||
|
||||
return pico_icmp6_notify(f, PICO_ICMP6_PKT_TOO_BIG, 0, 0);
|
||||
}
|
||||
|
||||
#ifdef PICO_SUPPORT_IPFILTER
|
||||
int pico_icmp6_packet_filtered(struct pico_frame *f)
|
||||
{
|
||||
return pico_icmp6_notify(f, PICO_ICMP6_DEST_UNREACH, PICO_ICMP6_UNREACH_ADMIN, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
int pico_icmp6_parameter_problem(struct pico_frame *f, uint8_t problem, uint32_t ptr)
|
||||
{
|
||||
return pico_icmp6_notify(f, PICO_ICMP6_PARAM_PROBLEM, problem, ptr);
|
||||
}
|
||||
|
||||
MOCKABLE int pico_icmp6_frag_expired(struct pico_frame *f)
|
||||
{
|
||||
struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
|
||||
if (pico_ipv6_is_multicast(hdr->dst.addr))
|
||||
return 0;
|
||||
|
||||
return pico_icmp6_notify(f, PICO_ICMP6_TIME_EXCEEDED, PICO_ICMP6_TIMXCEED_REASS, 0);
|
||||
}
|
||||
|
||||
/* RFC 4861 $7.2.2: sending neighbor solicitations */
|
||||
int pico_icmp6_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *dst, uint8_t type)
|
||||
{
|
||||
struct pico_frame *sol = NULL;
|
||||
struct pico_icmp6_hdr *icmp6_hdr = NULL;
|
||||
struct pico_icmp6_opt_lladdr *opt = NULL;
|
||||
struct pico_ip6 daddr = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00 }};
|
||||
uint8_t i = 0;
|
||||
uint16_t len = 0;
|
||||
|
||||
if (pico_ipv6_is_multicast(dst->addr))
|
||||
return -1;
|
||||
|
||||
len = PICO_ICMP6HDR_NEIGH_SOL_SIZE;
|
||||
if (type != PICO_ICMP6_ND_DAD)
|
||||
len = (uint16_t)(len + 8);
|
||||
|
||||
sol = pico_proto_ipv6.alloc(&pico_proto_ipv6, len);
|
||||
if (!sol) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sol->payload = sol->transport_hdr + len;
|
||||
sol->payload_len = 0;
|
||||
|
||||
icmp6_hdr = (struct pico_icmp6_hdr *)sol->transport_hdr;
|
||||
icmp6_hdr->type = PICO_ICMP6_NEIGH_SOL;
|
||||
icmp6_hdr->code = 0;
|
||||
icmp6_hdr->msg.info.neigh_sol.unused = 0;
|
||||
icmp6_hdr->msg.info.neigh_sol.target = *dst;
|
||||
|
||||
if (type != PICO_ICMP6_ND_DAD) {
|
||||
opt = (struct pico_icmp6_opt_lladdr *)(((uint8_t *)&icmp6_hdr->msg.info.neigh_sol) + sizeof(struct neigh_sol_s));
|
||||
opt->type = PICO_ND_OPT_LLADDR_SRC;
|
||||
opt->len = 1;
|
||||
memcpy(opt->addr.mac.addr, dev->eth->mac.addr, PICO_SIZE_ETH);
|
||||
}
|
||||
|
||||
if (type == PICO_ICMP6_ND_SOLICITED || type == PICO_ICMP6_ND_DAD) {
|
||||
for (i = 1; i <= 3; ++i) {
|
||||
daddr.addr[PICO_SIZE_IP6 - i] = dst->addr[PICO_SIZE_IP6 - i];
|
||||
}
|
||||
} else {
|
||||
daddr = *dst;
|
||||
}
|
||||
|
||||
sol->dev = dev;
|
||||
|
||||
/* f->src is set in frame_push, checksum calculated there */
|
||||
pico_ipv6_frame_push(sol, NULL, &daddr, PICO_PROTO_ICMP6, (type == PICO_ICMP6_ND_DAD));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RFC 4861 $7.2.4: sending solicited neighbor advertisements */
|
||||
int pico_icmp6_neighbor_advertisement(struct pico_frame *f, struct pico_ip6 *target)
|
||||
{
|
||||
struct pico_frame *adv = NULL;
|
||||
struct pico_ipv6_hdr *ipv6_hdr = NULL;
|
||||
struct pico_icmp6_hdr *icmp6_hdr = NULL;
|
||||
struct pico_icmp6_opt_lladdr *opt = NULL;
|
||||
struct pico_ip6 dst = {{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}};
|
||||
|
||||
ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr;
|
||||
adv = pico_proto_ipv6.alloc(&pico_proto_ipv6, PICO_ICMP6HDR_NEIGH_ADV_SIZE + 8);
|
||||
if (!adv) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
adv->payload = adv->transport_hdr + PICO_ICMP6HDR_NEIGH_ADV_SIZE + 8;
|
||||
adv->payload_len = 0;
|
||||
|
||||
icmp6_hdr = (struct pico_icmp6_hdr *)adv->transport_hdr;
|
||||
icmp6_hdr->type = PICO_ICMP6_NEIGH_ADV;
|
||||
icmp6_hdr->code = 0;
|
||||
icmp6_hdr->msg.info.neigh_adv.target = *target;
|
||||
icmp6_hdr->msg.info.neigh_adv.rsor = long_be(0x60000000); /* !router && solicited && override */
|
||||
if (pico_ipv6_is_unspecified(ipv6_hdr->src.addr)) {
|
||||
/* solicited = clear && dst = all-nodes address (scope link-local) */
|
||||
icmp6_hdr->msg.info.neigh_adv.rsor ^= long_be(0x40000000);
|
||||
} else {
|
||||
/* solicited = set && dst = source of solicitation */
|
||||
dst = ipv6_hdr->src;
|
||||
}
|
||||
|
||||
/* XXX if the target address is either an anycast address or a unicast
|
||||
* address for which the node is providing proxy service, or the target
|
||||
* link-layer Address option is not included, the Override flag SHOULD
|
||||
* be set to zero.
|
||||
*/
|
||||
|
||||
/* XXX if the target address is an anycast address, the sender SHOULD delay
|
||||
* sending a response for a random time between 0 and MAX_ANYCAST_DELAY_TIME seconds.
|
||||
*/
|
||||
|
||||
opt = (struct pico_icmp6_opt_lladdr *)(((uint8_t *)&icmp6_hdr->msg.info.neigh_adv) + sizeof(struct neigh_adv_s));
|
||||
opt->type = PICO_ND_OPT_LLADDR_TGT;
|
||||
opt->len = 1;
|
||||
memcpy(opt->addr.mac.addr, f->dev->eth->mac.addr, PICO_SIZE_ETH);
|
||||
adv->dev = f->dev;
|
||||
|
||||
/* f->src is set in frame_push, checksum calculated there */
|
||||
pico_ipv6_frame_push(adv, NULL, &dst, PICO_PROTO_ICMP6, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RFC 4861 $6.3.7: sending router solicitations */
|
||||
int pico_icmp6_router_solicitation(struct pico_device *dev, struct pico_ip6 *src)
|
||||
{
|
||||
struct pico_frame *sol = NULL;
|
||||
struct pico_icmp6_hdr *icmp6_hdr = NULL;
|
||||
struct pico_icmp6_opt_lladdr *lladdr = NULL;
|
||||
uint16_t len = 0;
|
||||
struct pico_ip6 daddr = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }};
|
||||
|
||||
len = PICO_ICMP6HDR_ROUTER_SOL_SIZE;
|
||||
if (!pico_ipv6_is_unspecified(src->addr))
|
||||
len = (uint16_t)(len + 8);
|
||||
|
||||
sol = pico_proto_ipv6.alloc(&pico_proto_ipv6, len);
|
||||
if (!sol) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sol->payload = sol->transport_hdr + len;
|
||||
sol->payload_len = 0;
|
||||
|
||||
icmp6_hdr = (struct pico_icmp6_hdr *)sol->transport_hdr;
|
||||
icmp6_hdr->type = PICO_ICMP6_ROUTER_SOL;
|
||||
icmp6_hdr->code = 0;
|
||||
|
||||
if (!pico_ipv6_is_unspecified(src->addr)) {
|
||||
lladdr = (struct pico_icmp6_opt_lladdr *)(((uint8_t *)&icmp6_hdr->msg.info.router_sol) + sizeof(struct router_sol_s));
|
||||
lladdr->type = PICO_ND_OPT_LLADDR_SRC;
|
||||
lladdr->len = 1;
|
||||
memcpy(lladdr->addr.mac.addr, dev->eth->mac.addr, PICO_SIZE_ETH);
|
||||
}
|
||||
|
||||
sol->dev = dev;
|
||||
|
||||
/* f->src is set in frame_push, checksum calculated there */
|
||||
pico_ipv6_frame_push(sol, NULL, &daddr, PICO_PROTO_ICMP6, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PICO_RADV_VAL_LIFETIME (long_be(86400))
|
||||
#define PICO_RADV_PREF_LIFETIME (long_be(14400))
|
||||
|
||||
/* RFC 4861: sending router advertisements */
|
||||
int pico_icmp6_router_advertisement(struct pico_device *dev, struct pico_ip6 *dst)
|
||||
{
|
||||
struct pico_frame *adv = NULL;
|
||||
struct pico_icmp6_hdr *icmp6_hdr = NULL;
|
||||
struct pico_icmp6_opt_lladdr *lladdr;
|
||||
struct pico_icmp6_opt_prefix *prefix;
|
||||
uint16_t len = 0;
|
||||
struct pico_ip6 dst_mcast = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }};
|
||||
uint8_t *nxt_opt;
|
||||
|
||||
len = PICO_ICMP6HDR_ROUTER_ADV_SIZE + PICO_ICMP6_OPT_LLADDR_SIZE + sizeof(struct pico_icmp6_opt_prefix);
|
||||
|
||||
adv = pico_proto_ipv6.alloc(&pico_proto_ipv6, len);
|
||||
if (!adv) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
adv->payload = adv->transport_hdr + len;
|
||||
adv->payload_len = 0;
|
||||
adv->dev = dev;
|
||||
|
||||
icmp6_hdr = (struct pico_icmp6_hdr *)adv->transport_hdr;
|
||||
icmp6_hdr->type = PICO_ICMP6_ROUTER_ADV;
|
||||
icmp6_hdr->code = 0;
|
||||
icmp6_hdr->msg.info.router_adv.life_time = short_be(45);
|
||||
icmp6_hdr->msg.info.router_adv.hop = 64;
|
||||
nxt_opt = (uint8_t *)&icmp6_hdr->msg.info.router_adv + sizeof(struct router_adv_s);
|
||||
|
||||
prefix = (struct pico_icmp6_opt_prefix *)nxt_opt;
|
||||
prefix->type = PICO_ND_OPT_PREFIX;
|
||||
prefix->len = sizeof(struct pico_icmp6_opt_prefix) >> 3;
|
||||
prefix->prefix_len = 64; /* Only /64 are forwarded */
|
||||
prefix->aac = 1;
|
||||
prefix->onlink = 1;
|
||||
prefix->val_lifetime = PICO_RADV_VAL_LIFETIME;
|
||||
prefix->pref_lifetime = PICO_RADV_PREF_LIFETIME;
|
||||
memcpy(&prefix->prefix, dst, sizeof(struct pico_ip6));
|
||||
|
||||
nxt_opt += (sizeof (struct pico_icmp6_opt_prefix));
|
||||
lladdr = (struct pico_icmp6_opt_lladdr *)nxt_opt;
|
||||
lladdr->type = PICO_ND_OPT_LLADDR_SRC;
|
||||
lladdr->len = 1;
|
||||
memcpy(lladdr->addr.mac.addr, dev->eth->mac.addr, PICO_SIZE_ETH);
|
||||
icmp6_hdr->crc = 0;
|
||||
icmp6_hdr->crc = short_be(pico_icmp6_checksum(adv));
|
||||
/* f->src is set in frame_push, checksum calculated there */
|
||||
pico_ipv6_frame_push(adv, NULL, &dst_mcast, PICO_PROTO_ICMP6, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************/
|
||||
/* Ping implementation */
|
||||
/***********************/
|
||||
|
||||
#ifdef PICO_SUPPORT_PING
|
||||
struct pico_icmp6_ping_cookie
|
||||
{
|
||||
uint16_t id;
|
||||
uint16_t seq;
|
||||
uint16_t size;
|
||||
uint16_t err;
|
||||
int count;
|
||||
int interval;
|
||||
int timeout;
|
||||
pico_time timestamp;
|
||||
struct pico_ip6 dst;
|
||||
struct pico_device *dev;
|
||||
void (*cb)(struct pico_icmp6_stats*);
|
||||
};
|
||||
|
||||
static int icmp6_cookie_compare(void *ka, void *kb)
|
||||
{
|
||||
struct pico_icmp6_ping_cookie *a = ka, *b = kb;
|
||||
if (a->id < b->id)
|
||||
return -1;
|
||||
|
||||
if (a->id > b->id)
|
||||
return 1;
|
||||
|
||||
return (a->seq - b->seq);
|
||||
}
|
||||
PICO_TREE_DECLARE(IPV6Pings, icmp6_cookie_compare);
|
||||
|
||||
static int pico_icmp6_send_echo(struct pico_icmp6_ping_cookie *cookie)
|
||||
{
|
||||
struct pico_frame *echo = NULL;
|
||||
struct pico_icmp6_hdr *hdr = NULL;
|
||||
|
||||
echo = pico_proto_ipv6.alloc(&pico_proto_ipv6, (uint16_t)(PICO_ICMP6HDR_ECHO_REQUEST_SIZE + cookie->size));
|
||||
if (!echo) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
|
||||
echo->payload_len = cookie->size;
|
||||
|
||||
hdr = (struct pico_icmp6_hdr *)echo->transport_hdr;
|
||||
hdr->type = PICO_ICMP6_ECHO_REQUEST;
|
||||
hdr->code = 0;
|
||||
hdr->msg.info.echo_request.id = short_be(cookie->id);
|
||||
hdr->msg.info.echo_request.seq = short_be(cookie->seq);
|
||||
/* XXX: Fill payload */
|
||||
hdr->crc = 0;
|
||||
hdr->crc = short_be(pico_icmp6_checksum(echo));
|
||||
echo->dev = cookie->dev;
|
||||
pico_ipv6_frame_push(echo, NULL, &cookie->dst, PICO_PROTO_ICMP6, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void pico_icmp6_ping_timeout(pico_time now, void *arg)
|
||||
{
|
||||
struct pico_icmp6_ping_cookie *cookie = NULL;
|
||||
|
||||
IGNORE_PARAMETER(now);
|
||||
|
||||
cookie = (struct pico_icmp6_ping_cookie *)arg;
|
||||
if (pico_tree_findKey(&IPV6Pings, cookie)) {
|
||||
if (cookie->err == PICO_PING6_ERR_PENDING) {
|
||||
struct pico_icmp6_stats stats = {
|
||||
0
|
||||
};
|
||||
stats.dst = cookie->dst;
|
||||
stats.seq = cookie->seq;
|
||||
stats.time = 0;
|
||||
stats.size = cookie->size;
|
||||
stats.err = PICO_PING6_ERR_TIMEOUT;
|
||||
dbg(" ---- Ping6 timeout!!!\n");
|
||||
if (cookie->cb)
|
||||
cookie->cb(&stats);
|
||||
}
|
||||
|
||||
pico_tree_delete(&IPV6Pings, cookie);
|
||||
PICO_FREE(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
static void pico_icmp6_next_ping(pico_time now, void *arg);
|
||||
static inline void pico_icmp6_send_ping(struct pico_icmp6_ping_cookie *cookie)
|
||||
{
|
||||
pico_icmp6_send_echo(cookie);
|
||||
cookie->timestamp = pico_tick;
|
||||
pico_timer_add((pico_time)(cookie->interval), pico_icmp6_next_ping, cookie);
|
||||
pico_timer_add((pico_time)(cookie->timeout), pico_icmp6_ping_timeout, cookie);
|
||||
}
|
||||
|
||||
static void pico_icmp6_next_ping(pico_time now, void *arg)
|
||||
{
|
||||
struct pico_icmp6_ping_cookie *cookie = NULL, *new = NULL;
|
||||
|
||||
IGNORE_PARAMETER(now);
|
||||
|
||||
cookie = (struct pico_icmp6_ping_cookie *)arg;
|
||||
if (pico_tree_findKey(&IPV6Pings, cookie)) {
|
||||
if (cookie->err == PICO_PING6_ERR_ABORTED)
|
||||
return;
|
||||
|
||||
if (cookie->seq < (uint16_t)cookie->count) {
|
||||
new = PICO_ZALLOC(sizeof(struct pico_icmp6_ping_cookie));
|
||||
if (!new) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(new, cookie, sizeof(struct pico_icmp6_ping_cookie));
|
||||
new->seq++;
|
||||
|
||||
pico_tree_insert(&IPV6Pings, new);
|
||||
pico_icmp6_send_ping(new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pico_icmp6_ping_recv_reply(struct pico_frame *f)
|
||||
{
|
||||
struct pico_icmp6_ping_cookie *cookie = NULL, test = {
|
||||
0
|
||||
};
|
||||
struct pico_icmp6_hdr *hdr = NULL;
|
||||
|
||||
hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
|
||||
test.id = short_be(hdr->msg.info.echo_reply.id);
|
||||
test.seq = short_be(hdr->msg.info.echo_reply.seq);
|
||||
cookie = pico_tree_findKey(&IPV6Pings, &test);
|
||||
if (cookie) {
|
||||
struct pico_icmp6_stats stats = {
|
||||
0
|
||||
};
|
||||
if (cookie->err == PICO_PING6_ERR_ABORTED)
|
||||
return;
|
||||
|
||||
cookie->err = PICO_PING6_ERR_REPLIED;
|
||||
stats.dst = cookie->dst;
|
||||
stats.seq = cookie->seq;
|
||||
stats.size = cookie->size;
|
||||
stats.time = pico_tick - cookie->timestamp;
|
||||
stats.err = cookie->err;
|
||||
stats.ttl = ((struct pico_ipv6_hdr *)f->net_hdr)->hop;
|
||||
if(cookie->cb)
|
||||
cookie->cb(&stats);
|
||||
} else {
|
||||
dbg("Reply for seq=%d, not found.\n", test.seq);
|
||||
}
|
||||
}
|
||||
|
||||
int pico_icmp6_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp6_stats *), struct pico_device *dev)
|
||||
{
|
||||
static uint16_t next_id = 0x91c0;
|
||||
struct pico_icmp6_ping_cookie *cookie = NULL;
|
||||
|
||||
if(!dst || !count || !interval || !timeout) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cookie = PICO_ZALLOC(sizeof(struct pico_icmp6_ping_cookie));
|
||||
if (!cookie) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pico_string_to_ipv6(dst, cookie->dst.addr) < 0) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
PICO_FREE(cookie);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cookie->seq = 1;
|
||||
cookie->id = next_id++;
|
||||
cookie->err = PICO_PING6_ERR_PENDING;
|
||||
cookie->size = (uint16_t)size;
|
||||
cookie->interval = interval;
|
||||
cookie->timeout = timeout;
|
||||
cookie->cb = cb;
|
||||
cookie->count = count;
|
||||
cookie->dev = dev;
|
||||
|
||||
pico_tree_insert(&IPV6Pings, cookie);
|
||||
pico_icmp6_send_ping(cookie);
|
||||
return (int)cookie->id;
|
||||
}
|
||||
|
||||
int pico_icmp6_ping_abort(int id)
|
||||
{
|
||||
struct pico_tree_node *node;
|
||||
int found = 0;
|
||||
pico_tree_foreach(node, &IPV6Pings)
|
||||
{
|
||||
struct pico_icmp6_ping_cookie *ck =
|
||||
(struct pico_icmp6_ping_cookie *) node->keyValue;
|
||||
if (ck->id == (uint16_t)id) {
|
||||
ck->err = PICO_PING6_ERR_ABORTED;
|
||||
found++;
|
||||
}
|
||||
}
|
||||
if (found > 0)
|
||||
return 0; /* OK if at least one pending ping has been canceled */
|
||||
|
||||
pico_err = PICO_ERR_ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
256
ext/picotcp/modules/pico_icmp6.h
Normal file
256
ext/picotcp/modules/pico_icmp6.h
Normal file
@@ -0,0 +1,256 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef _INCLUDE_PICO_ICMP6
|
||||
#define _INCLUDE_PICO_ICMP6
|
||||
#include "pico_addressing.h"
|
||||
#include "pico_protocol.h"
|
||||
#include "pico_mld.h"
|
||||
/* ICMP header sizes */
|
||||
#define PICO_ICMP6HDR_DRY_SIZE 4
|
||||
#define PICO_ICMP6HDR_ECHO_REQUEST_SIZE 8
|
||||
#define PICO_ICMP6HDR_DEST_UNREACH_SIZE 8
|
||||
#define PICO_ICMP6HDR_TIME_XCEEDED_SIZE 8
|
||||
#define PICO_ICMP6HDR_PARAM_PROBLEM_SIZE 8
|
||||
#define PICO_ICMP6HDR_NEIGH_SOL_SIZE 24
|
||||
#define PICO_ICMP6HDR_NEIGH_ADV_SIZE 24
|
||||
#define PICO_ICMP6HDR_ROUTER_SOL_SIZE 8
|
||||
#define PICO_ICMP6HDR_ROUTER_ADV_SIZE 16
|
||||
#define PICO_ICMP6HDR_REDIRECT_SIZE 40
|
||||
|
||||
/* ICMP types */
|
||||
#define PICO_ICMP6_DEST_UNREACH 1
|
||||
#define PICO_ICMP6_PKT_TOO_BIG 2
|
||||
#define PICO_ICMP6_TIME_EXCEEDED 3
|
||||
#define PICO_ICMP6_PARAM_PROBLEM 4
|
||||
#define PICO_ICMP6_ECHO_REQUEST 128
|
||||
#define PICO_ICMP6_ECHO_REPLY 129
|
||||
#define PICO_ICMP6_ROUTER_SOL 133
|
||||
#define PICO_ICMP6_ROUTER_ADV 134
|
||||
#define PICO_ICMP6_NEIGH_SOL 135
|
||||
#define PICO_ICMP6_NEIGH_ADV 136
|
||||
#define PICO_ICMP6_REDIRECT 137
|
||||
|
||||
/* destination unreachable codes */
|
||||
#define PICO_ICMP6_UNREACH_NOROUTE 0
|
||||
#define PICO_ICMP6_UNREACH_ADMIN 1
|
||||
#define PICO_ICMP6_UNREACH_SRCSCOPE 2
|
||||
#define PICO_ICMP6_UNREACH_ADDR 3
|
||||
#define PICO_ICMP6_UNREACH_PORT 4
|
||||
#define PICO_ICMP6_UNREACH_SRCFILTER 5
|
||||
#define PICO_ICMP6_UNREACH_REJROUTE 6
|
||||
|
||||
/* time exceeded codes */
|
||||
#define PICO_ICMP6_TIMXCEED_INTRANS 0
|
||||
#define PICO_ICMP6_TIMXCEED_REASS 1
|
||||
|
||||
/* parameter problem codes */
|
||||
#define PICO_ICMP6_PARAMPROB_HDRFIELD 0
|
||||
#define PICO_ICMP6_PARAMPROB_NXTHDR 1
|
||||
#define PICO_ICMP6_PARAMPROB_IPV6OPT 2
|
||||
|
||||
/* ping error codes */
|
||||
#define PICO_PING6_ERR_REPLIED 0
|
||||
#define PICO_PING6_ERR_TIMEOUT 1
|
||||
#define PICO_PING6_ERR_UNREACH 2
|
||||
#define PICO_PING6_ERR_ABORTED 3
|
||||
#define PICO_PING6_ERR_PENDING 0xFFFF
|
||||
|
||||
/* ND configuration */
|
||||
#define PICO_ND_MAX_FRAMES_QUEUED 4 /* max frames queued while awaiting address resolution */
|
||||
|
||||
/* ND RFC constants */
|
||||
#define PICO_ND_MAX_SOLICIT 3
|
||||
#define PICO_ND_MAX_NEIGHBOR_ADVERT 3
|
||||
#define PICO_ND_DELAY_INCOMPLETE 1000 /* msec */
|
||||
#define PICO_ND_DELAY_FIRST_PROBE_TIME 5000 /* msec */
|
||||
|
||||
/* neighbor discovery options */
|
||||
#define PICO_ND_OPT_LLADDR_SRC 1
|
||||
#define PICO_ND_OPT_LLADDR_TGT 2
|
||||
#define PICO_ND_OPT_PREFIX 3
|
||||
#define PICO_ND_OPT_REDIRECT 4
|
||||
#define PICO_ND_OPT_MTU 5
|
||||
#define PICO_ND_OPT_RDNSS 25 /* RFC 5006 */
|
||||
|
||||
/* ND advertisement flags */
|
||||
#define PICO_ND_ROUTER 0x80000000
|
||||
#define PICO_ND_SOLICITED 0x40000000
|
||||
#define PICO_ND_OVERRIDE 0x20000000
|
||||
#define IS_ROUTER(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_ROUTER)) /* router flag set? */
|
||||
#define IS_SOLICITED(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_SOLICITED)) /* solicited flag set? */
|
||||
#define IS_OVERRIDE(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_OVERRIDE)) /* override flag set? */
|
||||
|
||||
#define PICO_ND_PREFIX_LIFETIME_INF 0xFFFFFFFFu
|
||||
/* #define PICO_ND_DESTINATION_LRU_TIME 600000u / * msecs (10min) * / */
|
||||
|
||||
/* custom defines */
|
||||
#define PICO_ICMP6_ND_UNICAST 0
|
||||
#define PICO_ICMP6_ND_ANYCAST 1
|
||||
#define PICO_ICMP6_ND_SOLICITED 2
|
||||
#define PICO_ICMP6_ND_DAD 3
|
||||
|
||||
#define PICO_ICMP6_MAX_RTR_SOL_DELAY 1000
|
||||
|
||||
#define PICO_SIZE_ICMP6HDR ((sizeof(struct pico_icmp6_hdr)))
|
||||
#define PICO_ICMP6_OPT_LLADDR_SIZE (8)
|
||||
|
||||
extern struct pico_protocol pico_proto_icmp6;
|
||||
|
||||
PACKED_STRUCT_DEF pico_icmp6_hdr {
|
||||
uint8_t type;
|
||||
uint8_t code;
|
||||
uint16_t crc;
|
||||
|
||||
PACKED_UNION_DEF icmp6_msg_u {
|
||||
/* error messages */
|
||||
PACKED_UNION_DEF icmp6_err_u {
|
||||
PEDANTIC_STRUCT_DEF dest_unreach_s {
|
||||
uint32_t unused;
|
||||
} dest_unreach;
|
||||
PEDANTIC_STRUCT_DEF pkt_too_big_s {
|
||||
uint32_t mtu;
|
||||
} pkt_too_big;
|
||||
PEDANTIC_STRUCT_DEF time_exceeded_s {
|
||||
uint32_t unused;
|
||||
} time_exceeded;
|
||||
PEDANTIC_STRUCT_DEF param_problem_s {
|
||||
uint32_t ptr;
|
||||
} param_problem;
|
||||
} err;
|
||||
|
||||
/* informational messages */
|
||||
PACKED_UNION_DEF icmp6_info_u {
|
||||
PEDANTIC_STRUCT_DEF echo_request_s {
|
||||
uint16_t id;
|
||||
uint16_t seq;
|
||||
} echo_request;
|
||||
PEDANTIC_STRUCT_DEF echo_reply_s {
|
||||
uint16_t id;
|
||||
uint16_t seq;
|
||||
} echo_reply;
|
||||
PEDANTIC_STRUCT_DEF router_sol_s {
|
||||
uint32_t unused;
|
||||
} router_sol;
|
||||
PEDANTIC_STRUCT_DEF router_adv_s {
|
||||
uint8_t hop;
|
||||
uint8_t mor;
|
||||
uint16_t life_time;
|
||||
uint32_t reachable_time;
|
||||
uint32_t retrans_time;
|
||||
} router_adv;
|
||||
PEDANTIC_STRUCT_DEF neigh_sol_s {
|
||||
uint32_t unused;
|
||||
struct pico_ip6 target;
|
||||
} neigh_sol;
|
||||
PEDANTIC_STRUCT_DEF neigh_adv_s {
|
||||
uint32_t rsor;
|
||||
struct pico_ip6 target;
|
||||
} neigh_adv;
|
||||
PEDANTIC_STRUCT_DEF redirect_s {
|
||||
uint32_t reserved;
|
||||
struct pico_ip6 target;
|
||||
struct pico_ip6 dest;
|
||||
} redirect;
|
||||
PEDANTIC_STRUCT_DEF mld_s {
|
||||
uint16_t max_resp_time;
|
||||
uint16_t reserved;
|
||||
struct pico_ip6 mmcast_group;
|
||||
/*MLDv2*/
|
||||
uint8_t reserverd; // With S and QRV
|
||||
uint8_t QQIC;
|
||||
uint16_t nbr_src;
|
||||
struct pico_ip6 src[0];
|
||||
} mld;
|
||||
} info;
|
||||
} msg;
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_icmp6_opt_lladdr
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
PACKED_UNION_DEF icmp6_opt_hw_addr_u {
|
||||
struct pico_eth mac;
|
||||
} addr;
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_icmp6_opt_prefix
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
uint8_t prefix_len;
|
||||
uint8_t res : 6;
|
||||
uint8_t aac : 1;
|
||||
uint8_t onlink : 1;
|
||||
uint32_t val_lifetime;
|
||||
uint32_t pref_lifetime;
|
||||
uint32_t reserved;
|
||||
struct pico_ip6 prefix;
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_icmp6_opt_mtu
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
uint16_t res;
|
||||
uint32_t mtu;
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_icmp6_opt_redirect
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
uint16_t res0;
|
||||
uint32_t res1;
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_icmp6_opt_rdnss
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
uint16_t res0;
|
||||
uint32_t lifetime;
|
||||
struct pico_ip6 *addr;
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_icmp6_opt_na
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
};
|
||||
|
||||
struct pico_icmp6_stats
|
||||
{
|
||||
unsigned long size;
|
||||
unsigned long seq;
|
||||
pico_time time;
|
||||
unsigned long ttl;
|
||||
int err;
|
||||
struct pico_ip6 dst;
|
||||
};
|
||||
|
||||
int pico_icmp6_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp6_stats *), struct pico_device *dev);
|
||||
int pico_icmp6_ping_abort(int id);
|
||||
|
||||
int pico_icmp6_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *dst, uint8_t type);
|
||||
int pico_icmp6_neighbor_advertisement(struct pico_frame *f, struct pico_ip6 *target);
|
||||
int pico_icmp6_router_solicitation(struct pico_device *dev, struct pico_ip6 *src);
|
||||
|
||||
int pico_icmp6_port_unreachable(struct pico_frame *f);
|
||||
int pico_icmp6_proto_unreachable(struct pico_frame *f);
|
||||
int pico_icmp6_dest_unreachable(struct pico_frame *f);
|
||||
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);
|
||||
|
||||
#endif
|
||||
1276
ext/picotcp/modules/pico_igmp.c
Normal file
1276
ext/picotcp/modules/pico_igmp.c
Normal file
File diff suppressed because it is too large
Load Diff
26
ext/picotcp/modules/pico_igmp.h
Normal file
26
ext/picotcp/modules/pico_igmp.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
Authors: Kristof Roelants, Simon Maes, Brecht Van Cauwenberghe
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef INCLUDE_PICO_IGMP
|
||||
#define INCLUDE_PICO_IGMP
|
||||
|
||||
#define PICO_IGMPV1 1
|
||||
#define PICO_IGMPV2 2
|
||||
#define PICO_IGMPV3 3
|
||||
|
||||
#define PICO_IGMP_STATE_CREATE 1
|
||||
#define PICO_IGMP_STATE_UPDATE 2
|
||||
#define PICO_IGMP_STATE_DELETE 3
|
||||
|
||||
#define PICO_IGMP_QUERY_INTERVAL 125
|
||||
|
||||
extern struct pico_protocol pico_proto_igmp;
|
||||
|
||||
int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state);
|
||||
#endif /* _INCLUDE_PICO_IGMP */
|
||||
458
ext/picotcp/modules/pico_ipfilter.c
Normal file
458
ext/picotcp/modules/pico_ipfilter.c
Normal file
@@ -0,0 +1,458 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Andrei Carp
|
||||
Simon Maes
|
||||
*********************************************************************/
|
||||
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_config.h"
|
||||
#include "pico_icmp4.h"
|
||||
#include "pico_stack.h"
|
||||
#include "pico_eth.h"
|
||||
#include "pico_socket.h"
|
||||
#include "pico_device.h"
|
||||
#include "pico_ipfilter.h"
|
||||
#include "pico_tcp.h"
|
||||
#include "pico_udp.h"
|
||||
#include "pico_tree.h"
|
||||
|
||||
/**************** LOCAL MACROS ****************/
|
||||
#define MAX_PRIORITY (10)
|
||||
#define MIN_PRIORITY (-10)
|
||||
|
||||
#define ipf_dbg(...) do {} while(0)
|
||||
|
||||
/**************** LOCAL DECLARATIONS ****************/
|
||||
struct filter_node;
|
||||
static int filter_compare(void *filterA, void *filterB);
|
||||
|
||||
/**************** FILTER TREE ****************/
|
||||
|
||||
struct filter_node {
|
||||
struct pico_device *fdev;
|
||||
/* output address */
|
||||
uint32_t out_addr;
|
||||
uint32_t out_addr_netmask;
|
||||
/* input address */
|
||||
uint32_t in_addr;
|
||||
uint32_t in_addr_netmask;
|
||||
/* transport */
|
||||
uint16_t out_port;
|
||||
uint16_t in_port;
|
||||
/* filter details */
|
||||
uint8_t proto;
|
||||
int8_t priority;
|
||||
uint8_t tos;
|
||||
uint32_t filter_id;
|
||||
int (*function_ptr)(struct filter_node *filter, struct pico_frame *f);
|
||||
};
|
||||
|
||||
PICO_TREE_DECLARE(filter_tree, &filter_compare);
|
||||
|
||||
static inline int ipfilter_uint32_cmp(uint32_t a, uint32_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return -1;
|
||||
|
||||
if (b < a)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ipfilter_uint16_cmp(uint16_t a, uint16_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return -1;
|
||||
|
||||
if (b < a)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ipfilter_uint8_cmp(uint8_t a, uint8_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return -1;
|
||||
|
||||
if (b < a)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ipfilter_ptr_cmp(void *a, void *b)
|
||||
{
|
||||
if (a < b)
|
||||
return -1;
|
||||
|
||||
if (b < a)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline int filter_compare_ports(struct filter_node *a, struct filter_node *b)
|
||||
{
|
||||
int cmp;
|
||||
cmp = ipfilter_uint16_cmp(a->in_port, b->in_port);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
cmp = ipfilter_uint16_cmp(a->out_port, b->out_port);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
static inline int filter_compare_addresses(struct filter_node *a, struct filter_node *b)
|
||||
{
|
||||
int cmp;
|
||||
/* Compare source address */
|
||||
cmp = ipfilter_uint32_cmp((a->in_addr & a->in_addr_netmask), (b->in_addr & b->in_addr_netmask));
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
/* Compare destination address */
|
||||
cmp = ipfilter_uint32_cmp((a->out_addr & a->out_addr_netmask), (b->out_addr & b->out_addr_netmask));
|
||||
return cmp;
|
||||
}
|
||||
|
||||
static inline int filter_compare_proto(struct filter_node *a, struct filter_node *b)
|
||||
{
|
||||
return ipfilter_uint8_cmp(a->proto, b->proto);
|
||||
}
|
||||
|
||||
static inline int filter_compare_address_port(struct filter_node *a, struct filter_node *b)
|
||||
{
|
||||
int cmp;
|
||||
cmp = filter_compare_addresses(a, b);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
return filter_compare_ports(a, b);
|
||||
}
|
||||
|
||||
static inline int filter_match_packet_dev(struct filter_node *a, struct filter_node *b, struct filter_node *rule)
|
||||
{
|
||||
int cmp;
|
||||
/* 1. Compare devices */
|
||||
if (rule->fdev) {
|
||||
cmp = ipfilter_ptr_cmp(a->fdev, b->fdev);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static inline int filter_match_packet_proto(struct filter_node *a, struct filter_node *b, struct filter_node *rule)
|
||||
{
|
||||
int cmp;
|
||||
/* 2. Compare protocol */
|
||||
if (rule->proto) {
|
||||
cmp = filter_compare_proto(a, b);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
static inline int filter_match_packet_addr_in(struct filter_node *a, struct filter_node *b, struct filter_node *rule)
|
||||
{
|
||||
int cmp;
|
||||
/* 3. Compare addresses order: in, out */
|
||||
if (rule->in_addr_netmask) {
|
||||
cmp = ipfilter_uint32_cmp(a->in_addr & rule->in_addr_netmask, b->in_addr & rule->in_addr_netmask);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static inline int filter_match_packet_addr_out(struct filter_node *a, struct filter_node *b, struct filter_node *rule)
|
||||
{
|
||||
int cmp;
|
||||
if (rule->out_addr_netmask) {
|
||||
cmp = ipfilter_uint32_cmp(a->out_addr & rule->out_addr_netmask, b->out_addr & rule->out_addr_netmask);
|
||||
if (cmp) {
|
||||
return cmp;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static inline int filter_match_packet_port_in(struct filter_node *a, struct filter_node *b, struct filter_node *rule)
|
||||
{
|
||||
int cmp;
|
||||
/* 4. Compare ports order: in, out */
|
||||
if (rule->in_port) {
|
||||
cmp = ipfilter_uint16_cmp(a->in_port, b->in_port);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static inline int filter_match_packet_port_out(struct filter_node *a, struct filter_node *b, struct filter_node *rule)
|
||||
{
|
||||
int cmp;
|
||||
if (rule->out_port) {
|
||||
cmp = ipfilter_uint16_cmp(a->out_port, b->out_port);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int filter_match_packet_dev_and_proto(struct filter_node *a, struct filter_node *b, struct filter_node *rule)
|
||||
{
|
||||
int cmp = filter_match_packet_dev(a, b, rule);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
return filter_match_packet_proto(a, b, rule);
|
||||
}
|
||||
|
||||
static inline int filter_match_packet_addr(struct filter_node *a, struct filter_node *b, struct filter_node *rule)
|
||||
{
|
||||
int cmp = filter_match_packet_addr_in(a, b, rule);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
return filter_match_packet_addr_out(a, b, rule);
|
||||
|
||||
}
|
||||
|
||||
static inline int filter_match_packet_port(struct filter_node *a, struct filter_node *b, struct filter_node *rule)
|
||||
{
|
||||
int cmp = filter_match_packet_port_in(a, b, rule);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
return filter_match_packet_port_out(a, b, rule);
|
||||
}
|
||||
|
||||
static inline struct filter_node *filter_match_packet_find_rule(struct filter_node *a, struct filter_node *b)
|
||||
{
|
||||
if (!a->filter_id)
|
||||
return b;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static inline int filter_match_packet(struct filter_node *a, struct filter_node *b)
|
||||
{
|
||||
struct filter_node *rule;
|
||||
int cmp = 0;
|
||||
rule = filter_match_packet_find_rule(a, b);
|
||||
|
||||
cmp = filter_match_packet_dev_and_proto(a, b, rule);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
cmp = filter_match_packet_addr(a, b, rule);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
cmp = filter_match_packet_port(a, b, rule);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int filter_compare(void *filterA, void *filterB)
|
||||
{
|
||||
|
||||
struct filter_node *a = (struct filter_node *)filterA;
|
||||
struct filter_node *b = (struct filter_node *)filterB;
|
||||
int cmp = 0;
|
||||
if (a->filter_id == 0 || b->filter_id == 0) {
|
||||
return filter_match_packet(a, b);
|
||||
}
|
||||
|
||||
/* improve the search */
|
||||
if(a->filter_id == b->filter_id)
|
||||
return 0;
|
||||
|
||||
/* 1. Compare devices */
|
||||
cmp = ipfilter_ptr_cmp(a->fdev, a->fdev);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
/* 2. Compare protocol */
|
||||
cmp = filter_compare_proto(a, b);
|
||||
if(cmp)
|
||||
return cmp;
|
||||
|
||||
/* 3. Compare addresses order: in, out */
|
||||
/* 4. Compare ports order: in, out */
|
||||
cmp = filter_compare_address_port(a, b);
|
||||
|
||||
return cmp;
|
||||
}
|
||||
|
||||
/**************** FILTER CALLBACKS ****************/
|
||||
|
||||
static int fp_priority(struct filter_node *filter, struct pico_frame *f)
|
||||
{
|
||||
/* TODO do priority-stuff */
|
||||
IGNORE_PARAMETER(filter);
|
||||
IGNORE_PARAMETER(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fp_reject(struct filter_node *filter, struct pico_frame *f)
|
||||
{
|
||||
/* TODO check first if sender is pico itself or not */
|
||||
IGNORE_PARAMETER(filter);
|
||||
ipf_dbg("ipfilter> reject\n");
|
||||
(void)pico_icmp4_packet_filtered(f);
|
||||
pico_frame_discard(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fp_drop(struct filter_node *filter, struct pico_frame *f)
|
||||
{
|
||||
IGNORE_PARAMETER(filter);
|
||||
ipf_dbg("ipfilter> drop\n");
|
||||
pico_frame_discard(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct fp_function {
|
||||
int (*fn)(struct filter_node *filter, struct pico_frame *f);
|
||||
};
|
||||
|
||||
|
||||
static const struct fp_function fp_function[FILTER_COUNT] =
|
||||
{
|
||||
{&fp_priority},
|
||||
{&fp_reject},
|
||||
{&fp_drop}
|
||||
};
|
||||
|
||||
static int pico_ipv4_filter_add_validate(int8_t priority, enum filter_action action)
|
||||
{
|
||||
if ( priority > MAX_PRIORITY || priority < MIN_PRIORITY) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (action >= FILTER_COUNT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**************** FILTER API's ****************/
|
||||
uint32_t pico_ipv4_filter_add(struct pico_device *dev, uint8_t proto,
|
||||
struct pico_ip4 *out_addr, struct pico_ip4 *out_addr_netmask,
|
||||
struct pico_ip4 *in_addr, struct pico_ip4 *in_addr_netmask,
|
||||
uint16_t out_port, uint16_t in_port, int8_t priority,
|
||||
uint8_t tos, enum filter_action action)
|
||||
{
|
||||
static uint32_t filter_id = 1u; /* 0 is a special value used in the binary-tree search for packets being processed */
|
||||
struct filter_node *new_filter;
|
||||
|
||||
if (pico_ipv4_filter_add_validate(priority, action) < 0) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_filter = PICO_ZALLOC(sizeof(struct filter_node));
|
||||
if (!new_filter) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_filter->fdev = dev;
|
||||
new_filter->proto = proto;
|
||||
new_filter->out_addr = (!out_addr) ? (0U) : (out_addr->addr);
|
||||
new_filter->out_addr_netmask = (!out_addr_netmask) ? (0U) : (out_addr_netmask->addr);
|
||||
new_filter->in_addr = (!in_addr) ? (0U) : (in_addr->addr);
|
||||
new_filter->in_addr_netmask = (!in_addr_netmask) ? (0U) : (in_addr_netmask->addr);
|
||||
new_filter->out_port = out_port;
|
||||
new_filter->in_port = in_port;
|
||||
new_filter->priority = priority;
|
||||
new_filter->tos = tos;
|
||||
new_filter->filter_id = filter_id++;
|
||||
new_filter->function_ptr = fp_function[action].fn;
|
||||
|
||||
if(pico_tree_insert(&filter_tree, new_filter))
|
||||
{
|
||||
PICO_FREE(new_filter);
|
||||
filter_id--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return new_filter->filter_id;
|
||||
}
|
||||
|
||||
int pico_ipv4_filter_del(uint32_t filter_id)
|
||||
{
|
||||
struct filter_node *node = NULL;
|
||||
struct filter_node dummy = { 0 };
|
||||
|
||||
dummy.filter_id = filter_id;
|
||||
if((node = pico_tree_delete(&filter_tree, &dummy)) == NULL)
|
||||
{
|
||||
ipf_dbg("ipfilter> failed to delete filter :%d\n", filter_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PICO_FREE(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipfilter_apply_filter(struct pico_frame *f, struct filter_node *pkt)
|
||||
{
|
||||
struct filter_node *filter_frame = NULL;
|
||||
filter_frame = pico_tree_findKey(&filter_tree, pkt);
|
||||
if(filter_frame)
|
||||
{
|
||||
filter_frame->function_ptr(filter_frame, f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipfilter(struct pico_frame *f)
|
||||
{
|
||||
struct filter_node temp;
|
||||
struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *) f->net_hdr;
|
||||
struct pico_trans *trans;
|
||||
struct pico_icmp4_hdr *icmp_hdr;
|
||||
|
||||
memset(&temp, 0u, sizeof(struct filter_node));
|
||||
|
||||
temp.fdev = f->dev;
|
||||
temp.out_addr = ipv4_hdr->dst.addr;
|
||||
temp.in_addr = ipv4_hdr->src.addr;
|
||||
if ((ipv4_hdr->proto == PICO_PROTO_TCP) || (ipv4_hdr->proto == PICO_PROTO_UDP)) {
|
||||
trans = (struct pico_trans *) f->transport_hdr;
|
||||
temp.out_port = short_be(trans->dport);
|
||||
temp.in_port = short_be(trans->sport);
|
||||
}
|
||||
else if(ipv4_hdr->proto == PICO_PROTO_ICMP4) {
|
||||
icmp_hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
|
||||
if(icmp_hdr->type == PICO_ICMP_UNREACH && icmp_hdr->type == PICO_ICMP_UNREACH_FILTER_PROHIB)
|
||||
return 0;
|
||||
}
|
||||
|
||||
temp.proto = ipv4_hdr->proto;
|
||||
temp.priority = f->priority;
|
||||
temp.tos = ipv4_hdr->tos;
|
||||
return ipfilter_apply_filter(f, &temp);
|
||||
}
|
||||
|
||||
29
ext/picotcp/modules/pico_ipfilter.h
Normal file
29
ext/picotcp/modules/pico_ipfilter.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Simon Maes
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_IPFILTER
|
||||
#define INCLUDE_PICO_IPFILTER
|
||||
|
||||
#include "pico_device.h"
|
||||
|
||||
enum filter_action {
|
||||
FILTER_PRIORITY = 0,
|
||||
FILTER_REJECT,
|
||||
FILTER_DROP,
|
||||
FILTER_COUNT
|
||||
};
|
||||
|
||||
uint32_t pico_ipv4_filter_add(struct pico_device *dev, uint8_t proto,
|
||||
struct pico_ip4 *out_addr, struct pico_ip4 *out_addr_netmask, struct pico_ip4 *in_addr,
|
||||
struct pico_ip4 *in_addr_netmask, uint16_t out_port, uint16_t in_port,
|
||||
int8_t priority, uint8_t tos, enum filter_action action);
|
||||
|
||||
int pico_ipv4_filter_del(uint32_t filter_id);
|
||||
|
||||
int ipfilter(struct pico_frame *f);
|
||||
|
||||
#endif /* _INCLUDE_PICO_IPFILTER */
|
||||
|
||||
1585
ext/picotcp/modules/pico_ipv4.c
Normal file
1585
ext/picotcp/modules/pico_ipv4.c
Normal file
File diff suppressed because it is too large
Load Diff
129
ext/picotcp/modules/pico_ipv4.h
Normal file
129
ext/picotcp/modules/pico_ipv4.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef INCLUDE_PICO_IPV4
|
||||
#define INCLUDE_PICO_IPV4
|
||||
#include "pico_addressing.h"
|
||||
#include "pico_protocol.h"
|
||||
#include "pico_tree.h"
|
||||
#include "pico_device.h"
|
||||
|
||||
#define PICO_IPV4_INADDR_ANY 0x00000000U
|
||||
|
||||
#define PICO_IPV4_MTU (1500u)
|
||||
#define PICO_SIZE_IP4HDR (uint32_t)((sizeof(struct pico_ipv4_hdr)))
|
||||
#define PICO_IPV4_MAXPAYLOAD (PICO_IPV4_MTU - PICO_SIZE_IP4HDR)
|
||||
#define PICO_IPV4_DONTFRAG 0x4000U
|
||||
#define PICO_IPV4_MOREFRAG 0x2000U
|
||||
#define PICO_IPV4_EVIL 0x8000U
|
||||
#define PICO_IPV4_FRAG_MASK 0x1FFFU
|
||||
#define PICO_IPV4_DEFAULT_TTL 64
|
||||
#ifndef MBED
|
||||
#define PICO_IPV4_FRAG_MAX_SIZE (uint32_t)(63 * 1024)
|
||||
#else
|
||||
#define PICO_IPV4_FRAG_MAX_SIZE PICO_DEFAULT_SOCKETQ
|
||||
#endif
|
||||
|
||||
extern struct pico_protocol pico_proto_ipv4;
|
||||
|
||||
PACKED_STRUCT_DEF pico_ipv4_hdr {
|
||||
uint8_t vhl;
|
||||
uint8_t tos;
|
||||
uint16_t len;
|
||||
uint16_t id;
|
||||
uint16_t frag;
|
||||
uint8_t ttl;
|
||||
uint8_t proto;
|
||||
uint16_t crc;
|
||||
struct pico_ip4 src;
|
||||
struct pico_ip4 dst;
|
||||
uint8_t options[];
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_ipv4_pseudo_hdr
|
||||
{
|
||||
struct pico_ip4 src;
|
||||
struct pico_ip4 dst;
|
||||
uint8_t zeros;
|
||||
uint8_t proto;
|
||||
uint16_t len;
|
||||
};
|
||||
|
||||
/* Interface: link to device */
|
||||
struct pico_mcast_list;
|
||||
|
||||
struct pico_ipv4_link
|
||||
{
|
||||
struct pico_device *dev;
|
||||
struct pico_ip4 address;
|
||||
struct pico_ip4 netmask;
|
||||
#ifdef PICO_SUPPORT_MCAST
|
||||
struct pico_tree *MCASTGroups;
|
||||
uint8_t mcast_compatibility;
|
||||
uint8_t mcast_last_query_interval;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef PICO_SUPPORT_MCAST
|
||||
struct pico_mcast_group {
|
||||
uint8_t filter_mode;
|
||||
uint16_t reference_count;
|
||||
struct pico_ip4 mcast_addr;
|
||||
struct pico_tree MCASTSources;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct pico_ipv4_route
|
||||
{
|
||||
struct pico_ip4 dest;
|
||||
struct pico_ip4 netmask;
|
||||
struct pico_ip4 gateway;
|
||||
struct pico_ipv4_link *link;
|
||||
uint32_t metric;
|
||||
};
|
||||
|
||||
extern struct pico_tree Routes;
|
||||
|
||||
int pico_ipv4_compare(struct pico_ip4 *a, struct pico_ip4 *b);
|
||||
int pico_ipv4_to_string(char *ipbuf, const uint32_t ip);
|
||||
int pico_ipv4_valid_netmask(uint32_t mask);
|
||||
int pico_ipv4_is_unicast(uint32_t address);
|
||||
int pico_ipv4_is_multicast(uint32_t address);
|
||||
int pico_ipv4_is_broadcast(uint32_t addr);
|
||||
int pico_ipv4_is_loopback(uint32_t addr);
|
||||
int pico_ipv4_is_valid_src(uint32_t addr, struct pico_device *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int pico_string_to_ipv4(const char *ipstr, uint32_t *ip);
|
||||
int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address);
|
||||
int pico_ipv4_rebound(struct pico_frame *f);
|
||||
|
||||
int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t proto);
|
||||
struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address);
|
||||
struct pico_ipv4_link *pico_ipv4_link_by_dev(struct pico_device *dev);
|
||||
struct pico_ipv4_link *pico_ipv4_link_by_dev_next(struct pico_device *dev, struct pico_ipv4_link *last);
|
||||
struct pico_device *pico_ipv4_link_find(struct pico_ip4 *address);
|
||||
struct pico_ip4 *pico_ipv4_source_find(const struct pico_ip4 *dst);
|
||||
struct pico_device *pico_ipv4_source_dev_find(const struct pico_ip4 *dst);
|
||||
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 pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, int metric);
|
||||
struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr);
|
||||
void pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link);
|
||||
void pico_ipv4_unreachable(struct pico_frame *f, int err);
|
||||
|
||||
int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter);
|
||||
int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter);
|
||||
struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void);
|
||||
int pico_ipv4_cleanup_links(struct pico_device *dev);
|
||||
|
||||
#endif /* _INCLUDE_PICO_IPV4 */
|
||||
1921
ext/picotcp/modules/pico_ipv6.c
Normal file
1921
ext/picotcp/modules/pico_ipv6.c
Normal file
File diff suppressed because it is too large
Load Diff
182
ext/picotcp/modules/pico_ipv6.h
Normal file
182
ext/picotcp/modules/pico_ipv6.h
Normal file
@@ -0,0 +1,182 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef _INCLUDE_PICO_IPV6
|
||||
#define _INCLUDE_PICO_IPV6
|
||||
#include "pico_addressing.h"
|
||||
#include "pico_protocol.h"
|
||||
#include "pico_ipv4.h"
|
||||
#define PICO_SIZE_IP6HDR ((uint32_t)(sizeof(struct pico_ipv6_hdr)))
|
||||
#define PICO_IPV6_DEFAULT_HOP 64
|
||||
#define PICO_IPV6_MIN_MTU 1280
|
||||
#define PICO_IPV6_STRING 46
|
||||
|
||||
#define PICO_IPV6_EXTHDR_HOPBYHOP 0
|
||||
#define PICO_IPV6_EXTHDR_ROUTING 43
|
||||
#define PICO_IPV6_EXTHDR_FRAG 44
|
||||
#define PICO_IPV6_EXTHDR_ESP 50
|
||||
#define PICO_IPV6_EXTHDR_AUTH 51
|
||||
#define PICO_IPV6_EXTHDR_NONE 59
|
||||
#define PICO_IPV6_EXTHDR_DESTOPT 60
|
||||
|
||||
|
||||
#define PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT 5
|
||||
#define PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT_DATALEN 2
|
||||
|
||||
#define HBH_LEN(hbh) ((((hbh->ext.hopbyhop.len + 1) << 3) - 2)) /* len in bytes, minus nxthdr and len byte */
|
||||
|
||||
extern const uint8_t PICO_IP6_ANY[PICO_SIZE_IP6];
|
||||
extern struct pico_protocol pico_proto_ipv6;
|
||||
extern struct pico_tree IPV6Routes;
|
||||
|
||||
PACKED_STRUCT_DEF pico_ipv6_hdr {
|
||||
uint32_t vtf;
|
||||
uint16_t len;
|
||||
uint8_t nxthdr;
|
||||
uint8_t hop;
|
||||
struct pico_ip6 src;
|
||||
struct pico_ip6 dst;
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_ipv6_pseudo_hdr
|
||||
{
|
||||
struct pico_ip6 src;
|
||||
struct pico_ip6 dst;
|
||||
uint32_t len;
|
||||
uint8_t zero[3];
|
||||
uint8_t nxthdr;
|
||||
};
|
||||
|
||||
struct pico_ipv6_link
|
||||
{
|
||||
struct pico_device *dev;
|
||||
struct pico_ip6 address;
|
||||
struct pico_ip6 netmask;
|
||||
uint8_t istentative : 1;
|
||||
uint8_t isduplicate : 1;
|
||||
uint32_t dad_timer;
|
||||
uint16_t dup_detect_retrans;
|
||||
pico_time expire_time;
|
||||
#ifdef PICO_SUPPORT_MCAST
|
||||
struct pico_tree *MCASTGroups;
|
||||
uint8_t mcast_compatibility;
|
||||
uint8_t mcast_last_query_interval;
|
||||
#endif
|
||||
|
||||
};
|
||||
union pico_link {
|
||||
struct pico_ipv4_link ipv4;
|
||||
struct pico_ipv6_link ipv6;
|
||||
};
|
||||
|
||||
struct pico_ipv6_hbhoption {
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
};
|
||||
#ifdef PICO_SUPPORT_MCAST
|
||||
struct pico_ipv6_mcast_group {
|
||||
uint8_t filter_mode;
|
||||
uint16_t reference_count;
|
||||
struct pico_ip6 mcast_addr;
|
||||
struct pico_tree MCASTSources;
|
||||
};
|
||||
#endif
|
||||
struct pico_ipv6_destoption {
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
};
|
||||
|
||||
struct pico_ipv6_route
|
||||
{
|
||||
struct pico_ip6 dest;
|
||||
struct pico_ip6 netmask;
|
||||
struct pico_ip6 gateway;
|
||||
struct pico_ipv6_link *link;
|
||||
uint32_t metric;
|
||||
};
|
||||
|
||||
PACKED_STRUCT_DEF pico_ipv6_exthdr {
|
||||
uint8_t nxthdr;
|
||||
|
||||
PACKED_UNION_DEF ipv6_ext_u {
|
||||
PEDANTIC_STRUCT_DEF hopbyhop_s {
|
||||
uint8_t len;
|
||||
} hopbyhop;
|
||||
|
||||
PEDANTIC_STRUCT_DEF destopt_s {
|
||||
uint8_t len;
|
||||
} destopt;
|
||||
|
||||
PEDANTIC_STRUCT_DEF routing_s {
|
||||
uint8_t len;
|
||||
uint8_t routtype;
|
||||
uint8_t segleft;
|
||||
} routing;
|
||||
|
||||
PEDANTIC_STRUCT_DEF fragmentation_s {
|
||||
uint8_t res;
|
||||
uint8_t om[2];
|
||||
uint8_t id[4];
|
||||
} frag;
|
||||
} ext;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask);
|
||||
int pico_string_to_ipv6(const char *ipstr, uint8_t *ip);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
int pico_ipv6_compare(struct pico_ip6 *a, struct pico_ip6 *b);
|
||||
int pico_ipv6_to_string(char *ipbuf, const uint8_t ip[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_unicast(struct pico_ip6 *a);
|
||||
int pico_ipv6_is_multicast(const uint8_t addr[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_allhosts_multicast(const uint8_t addr[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_solnode_multicast(const uint8_t addr[PICO_SIZE_IP6], struct pico_device *dev);
|
||||
int pico_ipv6_is_global(const uint8_t addr[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_uniquelocal(const uint8_t addr[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_sitelocal(const uint8_t addr[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_linklocal(const uint8_t addr[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_solicited(const uint8_t addr[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_unspecified(const uint8_t addr[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_localhost(const uint8_t addr[PICO_SIZE_IP6]);
|
||||
|
||||
int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *src, struct pico_ip6 *dst, uint8_t proto, int is_dad);
|
||||
int pico_ipv6_route_add(struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link);
|
||||
int pico_ipv6_route_del(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);
|
||||
|
||||
int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address);
|
||||
int pico_ipv6_cleanup_links(struct pico_device *dev);
|
||||
struct pico_ipv6_link *pico_ipv6_link_istentative(struct pico_ip6 *address);
|
||||
struct pico_ipv6_link *pico_ipv6_link_get(struct pico_ip6 *address);
|
||||
struct pico_device *pico_ipv6_link_find(struct pico_ip6 *address);
|
||||
struct pico_ip6 pico_ipv6_route_get_gateway(struct pico_ip6 *addr);
|
||||
struct pico_ip6 *pico_ipv6_source_find(const struct pico_ip6 *dst);
|
||||
struct pico_device *pico_ipv6_source_dev_find(const struct pico_ip6 *dst);
|
||||
struct pico_ipv6_link *pico_ipv6_link_by_dev(struct pico_device *dev);
|
||||
struct pico_ipv6_link *pico_ipv6_link_by_dev_next(struct pico_device *dev, struct pico_ipv6_link *last);
|
||||
struct pico_ipv6_link *pico_ipv6_global_get(struct pico_device *dev);
|
||||
struct pico_ipv6_link *pico_ipv6_linklocal_get(struct pico_device *dev);
|
||||
struct pico_ipv6_link *pico_ipv6_sitelocal_get(struct pico_device *dev);
|
||||
struct pico_ipv6_link *pico_ipv6_prefix_configured(struct pico_ip6 *prefix);
|
||||
int pico_ipv6_lifetime_set(struct pico_ipv6_link *l, pico_time expire);
|
||||
void pico_ipv6_check_lifetime_expired(pico_time now, void *arg);
|
||||
int pico_ipv6_dev_routing_enable(struct pico_device *dev);
|
||||
int pico_ipv6_dev_routing_disable(struct pico_device *dev);
|
||||
void pico_ipv6_router_down(struct pico_ip6 *address);
|
||||
|
||||
int pico_ipv6_mcast_join(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *_MCASTFilter);
|
||||
int pico_ipv6_mcast_leave(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *_MCASTFilter);
|
||||
|
||||
struct pico_ipv6_link *pico_ipv6_get_default_mcastlink(void);
|
||||
|
||||
int pico_ipv6_is_null_address(struct pico_ip6 * ip6);
|
||||
#endif
|
||||
1009
ext/picotcp/modules/pico_ipv6_nd.c
Normal file
1009
ext/picotcp/modules/pico_ipv6_nd.c
Normal file
File diff suppressed because it is too large
Load Diff
26
ext/picotcp/modules/pico_ipv6_nd.h
Normal file
26
ext/picotcp/modules/pico_ipv6_nd.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef _INCLUDE_PICO_ND
|
||||
#define _INCLUDE_PICO_ND
|
||||
#include "pico_frame.h"
|
||||
|
||||
/* RFC constants */
|
||||
#define PICO_ND_REACHABLE_TIME 30000 /* msec */
|
||||
#define PICO_ND_RETRANS_TIMER 1000 /* msec */
|
||||
|
||||
struct pico_nd_hostvars {
|
||||
uint8_t routing;
|
||||
uint8_t hoplimit;
|
||||
pico_time basetime;
|
||||
pico_time reachabletime;
|
||||
pico_time retranstime;
|
||||
};
|
||||
|
||||
void pico_ipv6_nd_init(void);
|
||||
struct pico_eth *pico_ipv6_get_neighbor(struct pico_frame *f);
|
||||
void pico_ipv6_nd_postpone(struct pico_frame *f);
|
||||
int pico_ipv6_nd_recv(struct pico_frame *f);
|
||||
#endif
|
||||
3417
ext/picotcp/modules/pico_mdns.c
Normal file
3417
ext/picotcp/modules/pico_mdns.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user