partially-working picoTCP integration
This commit is contained in:
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
|
||||
423
ext/picotcp/Makefile
Normal file
423
ext/picotcp/Makefile
Normal file
@@ -0,0 +1,423 @@
|
||||
-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
|
||||
@echo -e "\t[AR] $(PREFIX)/lib/$(LIBNAME)"
|
||||
@$(AR) cru $(PREFIX)/lib/$(LIBNAME) $(PREFIX)/modules/*.o $(PREFIX)/lib/*.o \
|
||||
|| $(AR) cru $(PREFIX)/lib/$(LIBNAME) $(PREFIX)/lib/*.o
|
||||
@echo -e "\t[RANLIB] $(PREFIX)/lib/$(LIBNAME)"
|
||||
@$(RANLIB) $(PREFIX)/lib/$(LIBNAME)
|
||||
@test $(STRIP) -eq 1 && (echo -e "\t[STRIP] $(PREFIX)/lib/$(LIBNAME)" \
|
||||
&& $(STRIP_BIN) $(PREFIX)/lib/$(LIBNAME)) \
|
||||
|| echo -e "\t[KEEP SYMBOLS] $(PREFIX)/lib/$(LIBNAME)"
|
||||
@echo -e "\t[LIBSIZE] `du -b $(PREFIX)/lib/$(LIBNAME)`"
|
||||
@echo -e "`size -t $(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
|
||||
54
ext/picotcp/include/pico_device.h
Normal file
54
ext/picotcp/include/pico_device.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_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
|
||||
};
|
||||
|
||||
|
||||
int pico_device_init(struct pico_device *dev, const char *name, uint8_t *mac);
|
||||
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
|
||||
261
ext/picotcp/include/pico_socket.h
Normal file
261
ext/picotcp/include/pico_socket.h
Normal file
@@ -0,0 +1,261 @@
|
||||
/*********************************************************************
|
||||
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;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
85
ext/picotcp/include/pico_stack.h
Normal file
85
ext/picotcp/include/pico_stack.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*********************************************************************
|
||||
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);
|
||||
|
||||
|
||||
/* 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);
|
||||
|
||||
/* ---- 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
124
ext/picotcp/modules/pico_ipv4.h
Normal file
124
ext/picotcp/modules/pico_ipv4.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*********************************************************************
|
||||
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_string_to_ipv4(const char *ipstr, 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);
|
||||
|
||||
int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask);
|
||||
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
175
ext/picotcp/modules/pico_ipv6.h
Normal file
175
ext/picotcp/modules/pico_ipv6.h
Normal file
@@ -0,0 +1,175 @@
|
||||
/*********************************************************************
|
||||
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;
|
||||
};
|
||||
|
||||
int pico_ipv6_compare(struct pico_ip6 *a, struct pico_ip6 *b);
|
||||
int pico_string_to_ipv6(const char *ipstr, uint8_t *ip);
|
||||
int pico_ipv6_to_string(char *ipbuf, const uint8_t ip[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_unicast(struct pico_ip6 *a);
|
||||
int pico_ipv6_is_multicast(const uint8_t addr[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_allhosts_multicast(const uint8_t addr[PICO_SIZE_IP6]);
|
||||
int pico_ipv6_is_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);
|
||||
|
||||
struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask);
|
||||
int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address);
|
||||
int pico_ipv6_cleanup_links(struct pico_device *dev);
|
||||
struct pico_ipv6_link *pico_ipv6_link_istentative(struct pico_ip6 *address);
|
||||
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
185
ext/picotcp/modules/pico_mdns.h
Normal file
185
ext/picotcp/modules/pico_mdns.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/* ****************************************************************************
|
||||
* PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved.
|
||||
* See LICENSE and COPYING for usage.
|
||||
* .
|
||||
* Author: Toon Stegen, Jelle De Vleeschouwer
|
||||
* ****************************************************************************/
|
||||
#ifndef INCLUDE_PICO_MDNS
|
||||
#define INCLUDE_PICO_MDNS
|
||||
|
||||
#include "pico_dns_common.h"
|
||||
#include "pico_tree.h"
|
||||
#include "pico_ipv4.h"
|
||||
|
||||
/* ********************************* CONFIG ***********************************/
|
||||
#define PICO_MDNS_PROBE_UNICAST 1 /* Probe queries as QU-questions */
|
||||
#define PICO_MDNS_CONTINUOUS_REFRESH 0 /* Continuously update cache */
|
||||
#define PICO_MDNS_ALLOW_CACHING 1 /* Enable caching on this host */
|
||||
#define PICO_MDNS_DEFAULT_TTL 120 /* Default TTL of mDNS records */
|
||||
#define PICO_MDNS_SERVICE_TTL 120 /* Default TTL of SRV/TXT/PTR/NSEC */
|
||||
#define PICO_MDNS_PROBE_COUNT 4 /* Amount of probes to send */
|
||||
#define PICO_MDNS_ANNOUNCEMENT_COUNT 3 /* Amount of announcements to send */
|
||||
/* ****************************************************************************/
|
||||
|
||||
#define PICO_MDNS_DEST_ADDR4 "224.0.0.251"
|
||||
|
||||
/* To make mDNS records unique or shared records */
|
||||
#define PICO_MDNS_RECORD_UNIQUE 0x00u
|
||||
#define PICO_MDNS_RECORD_SHARED 0x01u
|
||||
|
||||
/* Flag to check for when records are returned, to determine the hostname */
|
||||
#define PICO_MDNS_RECORD_HOSTNAME 0x02u
|
||||
#define IS_HOSTNAME_RECORD(x) \
|
||||
(((x)->flags) & PICO_MDNS_RECORD_HOSTNAME) ? (1) : (0)
|
||||
|
||||
/* --- MDNS resource record --- */
|
||||
struct pico_mdns_record
|
||||
{
|
||||
struct pico_dns_record *record; /* DNS Resource Record */
|
||||
uint32_t current_ttl; /* Current TTL */
|
||||
uint8_t flags; /* Resource Record flags */
|
||||
uint8_t claim_id; /* Claim ID number */
|
||||
};
|
||||
|
||||
/* ****************************************************************************
|
||||
* Compares 2 mDNS records by type, name AND rdata for a truly unique result
|
||||
*
|
||||
* @param ra mDNS record A
|
||||
* @param rb mDNS record B
|
||||
* @return 0 when records are equal, returns difference when they're not.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_record_cmp( void *a, void *b );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Deletes a single mDNS resource record.
|
||||
*
|
||||
* @param record Void-pointer to mDNS Resource Record. Can be used with pico_-
|
||||
* tree-destroy.
|
||||
* @return Returns 0 on success, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_record_delete( void **record );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Creates a single standalone mDNS resource record with given name, type and
|
||||
* data to register on the network.
|
||||
*
|
||||
* @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 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.
|
||||
* @param flags You can specify if the mDNS record should be a shared record
|
||||
* rather than a unique record.
|
||||
* @return Pointer to newly created mDNS resource record.
|
||||
* ****************************************************************************/
|
||||
struct pico_mdns_record *
|
||||
pico_mdns_record_create( const char *url,
|
||||
void *_rdata,
|
||||
uint16_t datalen,
|
||||
uint16_t rtype,
|
||||
uint32_t rttl,
|
||||
uint8_t flags );
|
||||
|
||||
|
||||
|
||||
/* ****************************************************************************
|
||||
* Definition of DNS record tree
|
||||
* ****************************************************************************/
|
||||
typedef struct pico_tree pico_mdns_rtree;
|
||||
#define PICO_MDNS_RTREE_DECLARE(name) \
|
||||
pico_mdns_rtree (name) = {&LEAF, pico_mdns_record_cmp}
|
||||
#define PICO_MDNS_RTREE_DESTROY(rtree) \
|
||||
pico_tree_destroy((rtree), pico_mdns_record_delete)
|
||||
#define PICO_MDNS_RTREE_ADD(tree, record) \
|
||||
pico_tree_insert((tree), (record))
|
||||
|
||||
/* ****************************************************************************
|
||||
* API-call to query a record with a certain URL and type. First checks the
|
||||
* Cache for this record. If no cache-entry is found, a query will be sent on
|
||||
* the wire for this record.
|
||||
*
|
||||
* @param url URL to query for.
|
||||
* @param type DNS type top query for.
|
||||
* @param callback Callback to call when records are found for the query.
|
||||
* @return 0 when query is correctly parsed, something else on failure.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_getrecord( const char *url, uint16_t type,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Claim all different mDNS records in a tree in a single API-call. All records
|
||||
* in tree are called in a single new claim-session.
|
||||
*
|
||||
* @param rtree mDNS record tree with records to claim
|
||||
* @param callback Callback to call when all record are properly claimed.
|
||||
* @return 0 When claiming didn't horribly fail.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_claim( pico_mdns_rtree record_tree,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Sets the hostname for this machine. Claims automatically a unique A record
|
||||
* with the IPv4-address of this host. The hostname won't be set directly when
|
||||
* this functions returns, but only if the claiming of the unique record succ-
|
||||
* eeded. Init-callback will be called when the hostname-record is successfully
|
||||
* registered.
|
||||
*
|
||||
* @param url URL to set the hostname to.
|
||||
* @param arg Argument to pass to the init-callback.
|
||||
* @return 0 when the host started registering the hostname-record successfully,
|
||||
* Returns something else when it didn't succeeded.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_set_hostname( const char *url, void *arg );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Get the current hostname for this machine.
|
||||
*
|
||||
* @return Returns the hostname for this machine when the module is initialised
|
||||
* Returns NULL when the module is not initialised.
|
||||
* ****************************************************************************/
|
||||
const char *
|
||||
pico_mdns_get_hostname( void );
|
||||
|
||||
/* ****************************************************************************
|
||||
* Initialises the entire mDNS-module and sets the hostname for this machine.
|
||||
* Sets up the global mDNS socket properly and calls callback when succeeded.
|
||||
* Only when the module is properly initialised records can be registered on
|
||||
* the module.
|
||||
*
|
||||
* @param hostname URL to set the hostname to.
|
||||
* @param address IPv4-address of this host to bind to.
|
||||
* @param callback Callback to call when the hostname is registered and
|
||||
* also the global mDNS module callback. Gets called when
|
||||
* Passive conflicts occur, so changes in records can be
|
||||
* tracked in this callback.
|
||||
* @param arg Argument to pass to the init-callback.
|
||||
* @return 0 when the module is properly initialised and the host started regis-
|
||||
* tering the hostname. Returns something else went the host failed
|
||||
* initialising the module or registering the hostname.
|
||||
* ****************************************************************************/
|
||||
int
|
||||
pico_mdns_init( const char *hostname,
|
||||
struct pico_ip4 address,
|
||||
void (*callback)(pico_mdns_rtree *,
|
||||
char *,
|
||||
void *),
|
||||
void *arg );
|
||||
|
||||
#endif /* _INCLUDE_PICO_MDNS */
|
||||
1179
ext/picotcp/modules/pico_mld.c
Normal file
1179
ext/picotcp/modules/pico_mld.c
Normal file
File diff suppressed because it is too large
Load Diff
119
ext/picotcp/modules/pico_mld.h
Normal file
119
ext/picotcp/modules/pico_mld.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
Authors: Roel Postelmans
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef INCLUDE_PICO_MLD
|
||||
#define INCLUDE_PICO_MLD
|
||||
|
||||
#define PICO_MLDV1 1
|
||||
#define PICO_MLDV2 2
|
||||
|
||||
#define PICO_MLD_QUERY 130
|
||||
#define PICO_MLD_REPORT 131
|
||||
#define PICO_MLD_DONE 132
|
||||
#define PICO_MLD_REPORTV2 143
|
||||
|
||||
/*RFC 3810 $6.2 */
|
||||
#define MLD_HOP_LIMIT 1
|
||||
|
||||
/* states */
|
||||
#define MLD_STATE_NON_LISTENER (0x0)
|
||||
#define MLD_STATE_DELAYING_LISTENER (0x1)
|
||||
#define MLD_STATE_IDLE_LISTENER (0x2)
|
||||
|
||||
#define PICO_MLD_STATE_CREATE 1
|
||||
#define PICO_MLD_STATE_UPDATE 2
|
||||
#define PICO_MLD_STATE_DELETE 3
|
||||
/* group record types */
|
||||
#define MLD_MODE_IS_INCLUDE (1)
|
||||
#define MLD_MODE_IS_EXCLUDE (2)
|
||||
#define MLD_CHANGE_TO_INCLUDE_MODE (3)
|
||||
#define MLD_CHANGE_TO_EXCLUDE_MODE (4)
|
||||
#define MLD_ALLOW_NEW_SOURCES (5)
|
||||
#define MLD_BLOCK_OLD_SOURCES (6)
|
||||
/* events */
|
||||
|
||||
#define MLD_EVENT_START_LISTENING (0x1)
|
||||
#define MLD_EVENT_STOP_LISTENING (0x0)
|
||||
#define MLD_EVENT_QUERY_RECV (0x3)
|
||||
#define MLD_EVENT_REPORT_RECV (0x4)
|
||||
#define MLD_EVENT_TIMER_EXPIRED (0x5)
|
||||
/*Not needed?*/
|
||||
#define MLD_EVENT_DONE_RECV (0x1)
|
||||
|
||||
#define MLD_EVENT_DELETE_GROUP (0x0)
|
||||
#define MLD_EVENT_CREATE_GROUP (0x1)
|
||||
#define MLD_EVENT_UPDATE_GROUP (0x2)
|
||||
#define MLD_EVENT_QUERY_RECV (0x3)
|
||||
#define MLD_EVENT_REPORT_RECV (0x4)
|
||||
#define MLD_EVENT_TIMER_EXPIRED (0x5)
|
||||
/* (default) Variabels for times/counters */
|
||||
/* ALL IN SECONDS */
|
||||
#define MLD_ROBUSTNESS (2)
|
||||
#define MLD_QUERY_INTERVAL (125)
|
||||
#define MLD_QUERY_RESPONSE_INTERVAL (10)
|
||||
#define MLD_DEFAULT_MAX_RESPONSE_TIME (100)
|
||||
#define MLD_MULTICAST_LISTENER_INTERVAL (MLD_ROBUSTNESS * MLD_QUERY_INTERVAL) + MLD_QUERY_RESPONSE_INTERVAL
|
||||
#define MLD_OTHER_QUERIER_PRESENT_INTERVAL (MLD_ROBUSTNESS * MLD_QUERY_INTERVAL) + (0.5 * MLD_QUERY_RESPONSE_INTERVAL)
|
||||
#define MLD_STARTUP_QUERY_INTERVAL (0.25 * MLD_QUERY_INTERVAL)
|
||||
#define MLD_STARTUP_QUERY_COUNT MLD_ROBUSTNESS
|
||||
#define MLD_LAST_LISTENER_QUERY_INTERVAL 1
|
||||
#define MLD_LISTENER_QUERY_COUNT MLD_ROBUSTNESS
|
||||
#define MLD_UNSOLICITED_REPORT_INTERVAL 10
|
||||
|
||||
/* custom timers types */
|
||||
#define MLD_TIMER_GROUP_REPORT (1)
|
||||
#define MLD_TIMER_V1_QUERIER (2)
|
||||
#define MLD_TIMER_V2_QUERIER (2)
|
||||
|
||||
|
||||
/* Who has send the last report message */
|
||||
#define MLD_HOST_LAST (0x1)
|
||||
#define MLD_HOST_NOT_LAST (0x0)
|
||||
|
||||
|
||||
#define MLD_TIMER_STOPPED (1)
|
||||
#define MLD_MAX_SOURCES (89)
|
||||
extern struct pico_protocol pico_proto_mld;
|
||||
|
||||
struct mld_multicast_address_record {
|
||||
uint8_t type;
|
||||
uint8_t aux_len;
|
||||
uint16_t nbr_src;
|
||||
struct pico_ip6 multicast;
|
||||
struct pico_ip6 src[0];
|
||||
};
|
||||
|
||||
struct mld_parameters {
|
||||
uint8_t event;
|
||||
uint8_t state;
|
||||
uint8_t general_query;
|
||||
uint8_t filter_mode;
|
||||
uint8_t last_host;
|
||||
uint16_t max_resp_time;
|
||||
struct pico_ip6 mcast_link;
|
||||
struct pico_ip6 mcast_group;
|
||||
struct pico_tree *MCASTFilter;
|
||||
struct pico_frame *f;
|
||||
};
|
||||
|
||||
struct mld_timer {
|
||||
uint8_t type;
|
||||
uint8_t stopped;
|
||||
pico_time start;
|
||||
pico_time delay;
|
||||
struct pico_ip6 mcast_link;
|
||||
struct pico_ip6 mcast_group;
|
||||
struct pico_frame *f;
|
||||
void (*mld_callback)(struct mld_timer *t);
|
||||
};
|
||||
|
||||
uint16_t pico_mld_checksum(struct pico_frame *f);
|
||||
int pico_mld_process_in(struct pico_frame *f);
|
||||
int pico_mld_state_change(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state);
|
||||
#endif /* _INCLUDE_PICO_MLD */
|
||||
1605
ext/picotcp/modules/pico_mm.c
Normal file
1605
ext/picotcp/modules/pico_mm.c
Normal file
File diff suppressed because it is too large
Load Diff
98
ext/picotcp/modules/pico_mm.h
Normal file
98
ext/picotcp/modules/pico_mm.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Gustav Janssens, Jonas Van Nieuwenberg, Sam Van Den Berge
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#ifndef _INCLUDE_PICO_MM
|
||||
#define _INCLUDE_PICO_MM
|
||||
|
||||
#include "pico_config.h"
|
||||
|
||||
/*
|
||||
* Memory init function, this will create a memory manager instance
|
||||
* A memory_manager page will be created, along with one page of memory
|
||||
* Memory can be asked for via the pico_mem_zalloc function
|
||||
* More memory will be allocated to the memory manager according to its needs
|
||||
* A maximum amount of memory of uint32_t memsize can be allocated
|
||||
*/
|
||||
void pico_mem_init(uint32_t memsize);
|
||||
/*
|
||||
* Memory deinit function, this will free all memory occupied by the current
|
||||
* memory manager instance.
|
||||
*/
|
||||
void pico_mem_deinit(void);
|
||||
/*
|
||||
* Zero-initialized malloc function, will reserve a memory segment of length uint32_t len
|
||||
* This memory will be quickly allocated in a slab of fixed size if possible
|
||||
* or less optimally in the heap for a small variable size
|
||||
* The fixed size of the slabs can be changed dynamically via a statistics engine
|
||||
*/
|
||||
void*pico_mem_zalloc(size_t len);
|
||||
/*
|
||||
* Free function, free a block of memory pointed to by ptr.
|
||||
* Unused memory is only returned to the system's control by pico_mem_cleanup
|
||||
*/
|
||||
void pico_mem_free(void*ptr);
|
||||
/*
|
||||
* This cleanup function will be provided by the memory manager
|
||||
* It can be called during processor downtime
|
||||
* This function will return unused pages to the system's control
|
||||
* Pages are unused if they no longer contain slabs or heap, and they have been idle for a longer time
|
||||
*/
|
||||
void pico_mem_cleanup(uint32_t timestamp);
|
||||
|
||||
|
||||
|
||||
#ifdef PICO_SUPPORT_MM_PROFILING
|
||||
/***********************************************************************************************************************
|
||||
***********************************************************************************************************************
|
||||
MEMORY PROFILING FUNCTIONS
|
||||
***********************************************************************************************************************
|
||||
***********************************************************************************************************************/
|
||||
/* General info struct */
|
||||
struct profiling_data
|
||||
{
|
||||
uint32_t free_heap_space;
|
||||
uint32_t free_slab_space;
|
||||
uint32_t used_heap_space;
|
||||
uint32_t used_slab_space;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function fills up a struct with used and free slab and heap space in the memory manager
|
||||
* The user is responsible for resource managment
|
||||
*/
|
||||
void pico_mem_profile_collect_data(struct profiling_data*profiling_page_struct);
|
||||
|
||||
/*
|
||||
* This function prints the general structure of the memory manager
|
||||
* Printf in this function can be rerouted to send this data over a serial port, or to write it away to memory
|
||||
*/
|
||||
void pico_mem_profile_scan_data(void);
|
||||
|
||||
/*
|
||||
* This function returns the total size that the manager has received from the system
|
||||
* This can give an indication of the total system resource commitment, but keep in mind that
|
||||
* there can be many free blocks in this "used" size
|
||||
* Together with pico_mem_profile_collect_data, this can give a good estimation of the total
|
||||
* resource commitment
|
||||
*/
|
||||
uint32_t pico_mem_profile_used_size(void);
|
||||
|
||||
/*
|
||||
* This function returns a pointer to page 0, the main memory manager housekeeping (struct pico_mem_manager).
|
||||
* This can be used to collect data about the memory in user defined functions.
|
||||
* Use with care!
|
||||
*/
|
||||
void*pico_mem_profile_manager(void);
|
||||
|
||||
/*
|
||||
* paramter manager is a pointer to a struct pico_mem_manager
|
||||
*/
|
||||
void pico_mem_init_profiling(void*manager, uint32_t memsize);
|
||||
#endif /* PICO_SUPPORT_MM_PROFILING */
|
||||
|
||||
#endif /* _INCLUDE_PICO_MM */
|
||||
576
ext/picotcp/modules/pico_nat.c
Normal file
576
ext/picotcp/modules/pico_nat.c
Normal file
@@ -0,0 +1,576 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
.
|
||||
|
||||
Authors: Kristof Roelants, Brecht Van Cauwenberghe,
|
||||
Simon Maes, Philippe Mariman
|
||||
*********************************************************************/
|
||||
|
||||
#include "pico_stack.h"
|
||||
#include "pico_frame.h"
|
||||
#include "pico_tcp.h"
|
||||
#include "pico_udp.h"
|
||||
#include "pico_ipv4.h"
|
||||
#include "pico_addressing.h"
|
||||
#include "pico_nat.h"
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV4
|
||||
#ifdef PICO_SUPPORT_NAT
|
||||
|
||||
#define nat_dbg(...) do {} while(0)
|
||||
/* #define nat_dbg dbg */
|
||||
#define PICO_NAT_TIMEWAIT 240000 /* msec (4 mins) */
|
||||
|
||||
#define PICO_NAT_INBOUND 0
|
||||
#define PICO_NAT_OUTBOUND 1
|
||||
|
||||
struct pico_nat_tuple {
|
||||
uint8_t proto;
|
||||
uint16_t conn_active : 11;
|
||||
uint16_t portforward : 1;
|
||||
uint16_t rst : 1;
|
||||
uint16_t syn : 1;
|
||||
uint16_t fin_in : 1;
|
||||
uint16_t fin_out : 1;
|
||||
uint16_t src_port;
|
||||
uint16_t dst_port;
|
||||
uint16_t nat_port;
|
||||
struct pico_ip4 src_addr;
|
||||
struct pico_ip4 dst_addr;
|
||||
struct pico_ip4 nat_addr;
|
||||
};
|
||||
|
||||
static struct pico_ipv4_link *nat_link = NULL;
|
||||
|
||||
static int nat_cmp_natport(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
|
||||
{
|
||||
|
||||
if (a->nat_port < b->nat_port)
|
||||
return -1;
|
||||
|
||||
if (a->nat_port > b->nat_port)
|
||||
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int nat_cmp_srcport(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
|
||||
{
|
||||
|
||||
if (a->src_port < b->src_port)
|
||||
return -1;
|
||||
|
||||
if (a->src_port > b->src_port)
|
||||
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int nat_cmp_proto(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
|
||||
{
|
||||
if (a->proto < b->proto)
|
||||
return -1;
|
||||
|
||||
if (a->proto > b->proto)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nat_cmp_address(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
|
||||
{
|
||||
return pico_ipv4_compare(&a->src_addr, &b->src_addr);
|
||||
}
|
||||
|
||||
static int nat_cmp_inbound(void *ka, void *kb)
|
||||
{
|
||||
struct pico_nat_tuple *a = ka, *b = kb;
|
||||
int cport = nat_cmp_natport(a, b);
|
||||
if (cport)
|
||||
return cport;
|
||||
|
||||
return nat_cmp_proto(a, b);
|
||||
}
|
||||
|
||||
|
||||
static int nat_cmp_outbound(void *ka, void *kb)
|
||||
{
|
||||
struct pico_nat_tuple *a = ka, *b = kb;
|
||||
int caddr, cport;
|
||||
|
||||
caddr = nat_cmp_address(a, b);
|
||||
if (caddr)
|
||||
return caddr;
|
||||
|
||||
cport = nat_cmp_srcport(a, b);
|
||||
|
||||
if (cport)
|
||||
return cport;
|
||||
|
||||
return nat_cmp_proto(a, b);
|
||||
}
|
||||
|
||||
PICO_TREE_DECLARE(NATOutbound, nat_cmp_outbound);
|
||||
PICO_TREE_DECLARE(NATInbound, nat_cmp_inbound);
|
||||
|
||||
void pico_ipv4_nat_print_table(void)
|
||||
{
|
||||
struct pico_nat_tuple *t = NULL;
|
||||
struct pico_tree_node *index = NULL;
|
||||
(void)t;
|
||||
|
||||
nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
|
||||
nat_dbg("+ NAT table +\n");
|
||||
nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n");
|
||||
nat_dbg("+ src_addr | src_port | dst_addr | dst_port | nat_addr | nat_port | proto | conn active | FIN1 | FIN2 | SYN | RST | FORW +\n");
|
||||
nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n");
|
||||
|
||||
pico_tree_foreach(index, &NATOutbound)
|
||||
{
|
||||
t = index->keyValue;
|
||||
nat_dbg("+ %08X | %05u | %08X | %05u | %08X | %05u | %03u | %03u | %u | %u | %u | %u | %u +\n",
|
||||
long_be(t->src_addr.addr), t->src_port, long_be(t->dst_addr.addr), t->dst_port, long_be(t->nat_addr.addr), t->nat_port,
|
||||
t->proto, t->conn_active, t->fin_in, t->fin_out, t->syn, t->rst, t->portforward);
|
||||
}
|
||||
nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
|
||||
}
|
||||
|
||||
/*
|
||||
2 options:
|
||||
find on nat_port and proto
|
||||
find on src_addr, src_port and proto
|
||||
zero the unused parameters
|
||||
*/
|
||||
static struct pico_nat_tuple *pico_ipv4_nat_find_tuple(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
|
||||
{
|
||||
struct pico_nat_tuple *found = NULL, test = {
|
||||
0
|
||||
};
|
||||
|
||||
test.nat_port = nat_port;
|
||||
test.src_port = src_port;
|
||||
test.proto = proto;
|
||||
if (src_addr)
|
||||
test.src_addr = *src_addr;
|
||||
|
||||
if (nat_port)
|
||||
found = pico_tree_findKey(&NATInbound, &test);
|
||||
else
|
||||
found = pico_tree_findKey(&NATOutbound, &test);
|
||||
|
||||
if (found)
|
||||
return found;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
|
||||
{
|
||||
struct pico_nat_tuple *t = NULL;
|
||||
|
||||
t = pico_ipv4_nat_find_tuple(nat_port, src_addr, src_port, proto);
|
||||
if (t)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pico_nat_tuple *pico_ipv4_nat_add(struct pico_ip4 dst_addr, uint16_t dst_port, struct pico_ip4 src_addr, uint16_t src_port,
|
||||
struct pico_ip4 nat_addr, uint16_t nat_port, uint8_t proto)
|
||||
{
|
||||
struct pico_nat_tuple *t = PICO_ZALLOC(sizeof(struct pico_nat_tuple));
|
||||
if (!t) {
|
||||
pico_err = PICO_ERR_ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t->dst_addr = dst_addr;
|
||||
t->dst_port = dst_port;
|
||||
t->src_addr = src_addr;
|
||||
t->src_port = src_port;
|
||||
t->nat_addr = nat_addr;
|
||||
t->nat_port = nat_port;
|
||||
t->proto = proto;
|
||||
t->conn_active = 1;
|
||||
t->portforward = 0;
|
||||
t->rst = 0;
|
||||
t->syn = 0;
|
||||
t->fin_in = 0;
|
||||
t->fin_out = 0;
|
||||
|
||||
if (pico_tree_insert(&NATOutbound, t)) {
|
||||
PICO_FREE(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pico_tree_insert(&NATInbound, t)) {
|
||||
pico_tree_delete(&NATOutbound, t);
|
||||
PICO_FREE(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static int pico_ipv4_nat_del(uint16_t nat_port, uint8_t proto)
|
||||
{
|
||||
struct pico_nat_tuple *t = NULL;
|
||||
t = pico_ipv4_nat_find_tuple(nat_port, NULL, 0, proto);
|
||||
if (t) {
|
||||
pico_tree_delete(&NATOutbound, t);
|
||||
pico_tree_delete(&NATInbound, t);
|
||||
PICO_FREE(t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pico_trans *pico_nat_generate_tuple_trans(struct pico_ipv4_hdr *net, struct pico_frame *f)
|
||||
{
|
||||
struct pico_trans *trans = NULL;
|
||||
switch (net->proto) {
|
||||
case PICO_PROTO_TCP:
|
||||
{
|
||||
struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
|
||||
trans = (struct pico_trans *)&tcp->trans;
|
||||
break;
|
||||
}
|
||||
case PICO_PROTO_UDP:
|
||||
{
|
||||
struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
|
||||
trans = (struct pico_trans *)&udp->trans;
|
||||
break;
|
||||
}
|
||||
case PICO_PROTO_ICMP4:
|
||||
/* XXX: implement */
|
||||
break;
|
||||
}
|
||||
return trans;
|
||||
}
|
||||
|
||||
static struct pico_nat_tuple *pico_ipv4_nat_generate_tuple(struct pico_frame *f)
|
||||
{
|
||||
struct pico_trans *trans = NULL;
|
||||
struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
|
||||
uint16_t nport = 0;
|
||||
uint8_t retry = 32;
|
||||
|
||||
/* generate NAT port */
|
||||
do {
|
||||
uint32_t rand = pico_rand();
|
||||
nport = (uint16_t) (rand & 0xFFFFU);
|
||||
nport = (uint16_t)((nport % (65535 - 1024)) + 1024U);
|
||||
nport = short_be(nport);
|
||||
|
||||
if (pico_is_port_free(net->proto, nport, NULL, &pico_proto_ipv4))
|
||||
break;
|
||||
} while (--retry);
|
||||
|
||||
if (!retry)
|
||||
return NULL;
|
||||
|
||||
trans = pico_nat_generate_tuple_trans(net, f);
|
||||
if(!trans)
|
||||
return NULL;
|
||||
|
||||
return pico_ipv4_nat_add(net->dst, trans->dport, net->src, trans->sport, nat_link->address, nport, net->proto);
|
||||
/* XXX return pico_ipv4_nat_add(nat_link->address, port, net->src, trans->sport, net->proto); */
|
||||
}
|
||||
|
||||
static inline void pico_ipv4_nat_set_tcp_flags(struct pico_nat_tuple *t, struct pico_frame *f, uint8_t direction)
|
||||
{
|
||||
struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
|
||||
if (tcp->flags & PICO_TCP_SYN)
|
||||
t->syn = 1;
|
||||
|
||||
if (tcp->flags & PICO_TCP_RST)
|
||||
t->rst = 1;
|
||||
|
||||
if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_INBOUND))
|
||||
t->fin_in = 1;
|
||||
|
||||
if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_OUTBOUND))
|
||||
t->fin_out = 1;
|
||||
}
|
||||
|
||||
static int pico_ipv4_nat_sniff_session(struct pico_nat_tuple *t, struct pico_frame *f, uint8_t direction)
|
||||
{
|
||||
struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
|
||||
|
||||
switch (net->proto) {
|
||||
case PICO_PROTO_TCP:
|
||||
{
|
||||
pico_ipv4_nat_set_tcp_flags(t, f, direction);
|
||||
break;
|
||||
}
|
||||
|
||||
case PICO_PROTO_UDP:
|
||||
t->conn_active = 1;
|
||||
break;
|
||||
|
||||
case PICO_PROTO_ICMP4:
|
||||
/* XXX: implement */
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pico_ipv4_nat_table_cleanup(pico_time now, void *_unused)
|
||||
{
|
||||
struct pico_tree_node *index = NULL, *_tmp = NULL;
|
||||
struct pico_nat_tuple *t = NULL;
|
||||
IGNORE_PARAMETER(now);
|
||||
IGNORE_PARAMETER(_unused);
|
||||
nat_dbg("NAT: before table cleanup:\n");
|
||||
pico_ipv4_nat_print_table();
|
||||
|
||||
pico_tree_foreach_reverse_safe(index, &NATOutbound, _tmp)
|
||||
{
|
||||
t = index->keyValue;
|
||||
switch (t->proto)
|
||||
{
|
||||
case PICO_PROTO_TCP:
|
||||
if (t->portforward)
|
||||
break;
|
||||
else if (t->conn_active == 0 || t->conn_active > 360) /* conn active for > 24 hours */
|
||||
pico_ipv4_nat_del(t->nat_port, t->proto);
|
||||
else if (t->rst || (t->fin_in && t->fin_out))
|
||||
t->conn_active = 0;
|
||||
else
|
||||
t->conn_active++;
|
||||
|
||||
break;
|
||||
|
||||
case PICO_PROTO_UDP:
|
||||
if (t->portforward)
|
||||
break;
|
||||
else if (t->conn_active > 1)
|
||||
pico_ipv4_nat_del(t->nat_port, t->proto);
|
||||
else
|
||||
t->conn_active++;
|
||||
|
||||
break;
|
||||
|
||||
case PICO_PROTO_ICMP4:
|
||||
if (t->conn_active > 1)
|
||||
pico_ipv4_nat_del(t->nat_port, t->proto);
|
||||
else
|
||||
t->conn_active++;
|
||||
|
||||
default:
|
||||
/* unknown protocol in NAT table, delete when it has existed NAT_TIMEWAIT */
|
||||
if (t->conn_active > 1)
|
||||
pico_ipv4_nat_del(t->nat_port, t->proto);
|
||||
else
|
||||
t->conn_active++;
|
||||
}
|
||||
}
|
||||
|
||||
nat_dbg("NAT: after table cleanup:\n");
|
||||
pico_ipv4_nat_print_table();
|
||||
pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
|
||||
}
|
||||
|
||||
int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag)
|
||||
{
|
||||
struct pico_nat_tuple *t = NULL;
|
||||
struct pico_ip4 any_addr = {
|
||||
0
|
||||
};
|
||||
uint16_t any_port = 0;
|
||||
|
||||
switch (flag)
|
||||
{
|
||||
case PICO_NAT_PORT_FORWARD_ADD:
|
||||
t = pico_ipv4_nat_add(any_addr, any_port, src_addr, src_port, nat_addr, nat_port, proto);
|
||||
if (!t) {
|
||||
pico_err = PICO_ERR_EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
t->portforward = 1;
|
||||
break;
|
||||
|
||||
case PICO_NAT_PORT_FORWARD_DEL:
|
||||
return pico_ipv4_nat_del(nat_port, proto);
|
||||
|
||||
default:
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pico_ipv4_nat_print_table();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr)
|
||||
{
|
||||
struct pico_nat_tuple *tuple = NULL;
|
||||
struct pico_trans *trans = NULL;
|
||||
struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
|
||||
|
||||
if (!pico_ipv4_nat_is_enabled(link_addr))
|
||||
return -1;
|
||||
|
||||
switch (net->proto) {
|
||||
#ifdef PICO_SUPPORT_TCP
|
||||
case PICO_PROTO_TCP:
|
||||
{
|
||||
struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
|
||||
trans = (struct pico_trans *)&tcp->trans;
|
||||
tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
|
||||
if (!tuple)
|
||||
return -1;
|
||||
|
||||
/* replace dst IP and dst PORT */
|
||||
net->dst = tuple->src_addr;
|
||||
trans->dport = tuple->src_port;
|
||||
/* recalculate CRC */
|
||||
tcp->crc = 0;
|
||||
tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef PICO_SUPPORT_UDP
|
||||
case PICO_PROTO_UDP:
|
||||
{
|
||||
struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
|
||||
trans = (struct pico_trans *)&udp->trans;
|
||||
tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
|
||||
if (!tuple)
|
||||
return -1;
|
||||
|
||||
/* replace dst IP and dst PORT */
|
||||
net->dst = tuple->src_addr;
|
||||
trans->dport = tuple->src_port;
|
||||
/* recalculate CRC */
|
||||
udp->crc = 0;
|
||||
udp->crc = short_be(pico_udp_checksum_ipv4(f));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case PICO_PROTO_ICMP4:
|
||||
/* XXX reimplement */
|
||||
break;
|
||||
|
||||
default:
|
||||
nat_dbg("NAT ERROR: inbound NAT on erroneous protocol\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pico_ipv4_nat_sniff_session(tuple, f, PICO_NAT_INBOUND);
|
||||
net->crc = 0;
|
||||
net->crc = short_be(pico_checksum(net, f->net_len));
|
||||
|
||||
nat_dbg("NAT: inbound translation {dst.addr, dport}: {%08X,%u} -> {%08X,%u}\n",
|
||||
tuple->nat_addr.addr, short_be(tuple->nat_port), tuple->src_addr.addr, short_be(tuple->src_port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr)
|
||||
{
|
||||
struct pico_nat_tuple *tuple = NULL;
|
||||
struct pico_trans *trans = NULL;
|
||||
struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
|
||||
|
||||
if (!pico_ipv4_nat_is_enabled(link_addr))
|
||||
return -1;
|
||||
|
||||
switch (net->proto) {
|
||||
#ifdef PICO_SUPPORT_TCP
|
||||
case PICO_PROTO_TCP:
|
||||
{
|
||||
struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
|
||||
trans = (struct pico_trans *)&tcp->trans;
|
||||
tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto);
|
||||
if (!tuple)
|
||||
tuple = pico_ipv4_nat_generate_tuple(f);
|
||||
|
||||
/* replace src IP and src PORT */
|
||||
net->src = tuple->nat_addr;
|
||||
trans->sport = tuple->nat_port;
|
||||
/* recalculate CRC */
|
||||
tcp->crc = 0;
|
||||
tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef PICO_SUPPORT_UDP
|
||||
case PICO_PROTO_UDP:
|
||||
{
|
||||
struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
|
||||
trans = (struct pico_trans *)&udp->trans;
|
||||
tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto);
|
||||
if (!tuple)
|
||||
tuple = pico_ipv4_nat_generate_tuple(f);
|
||||
|
||||
/* replace src IP and src PORT */
|
||||
net->src = tuple->nat_addr;
|
||||
trans->sport = tuple->nat_port;
|
||||
/* recalculate CRC */
|
||||
udp->crc = 0;
|
||||
udp->crc = short_be(pico_udp_checksum_ipv4(f));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case PICO_PROTO_ICMP4:
|
||||
/* XXX reimplement */
|
||||
break;
|
||||
|
||||
default:
|
||||
nat_dbg("NAT ERROR: outbound NAT on erroneous protocol\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pico_ipv4_nat_sniff_session(tuple, f, PICO_NAT_OUTBOUND);
|
||||
net->crc = 0;
|
||||
net->crc = short_be(pico_checksum(net, f->net_len));
|
||||
|
||||
nat_dbg("NAT: outbound translation {src.addr, sport}: {%08X,%u} -> {%08X,%u}\n",
|
||||
tuple->src_addr.addr, short_be(tuple->src_port), tuple->nat_addr.addr, short_be(tuple->nat_port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_ipv4_nat_enable(struct pico_ipv4_link *link)
|
||||
{
|
||||
if (link == NULL) {
|
||||
pico_err = PICO_ERR_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
nat_link = link;
|
||||
pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_ipv4_nat_disable(void)
|
||||
{
|
||||
nat_link = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr)
|
||||
{
|
||||
if (!nat_link)
|
||||
return 0;
|
||||
|
||||
if (nat_link->address.addr != link_addr->addr)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
90
ext/picotcp/modules/pico_nat.h
Normal file
90
ext/picotcp/modules/pico_nat.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*********************************************************************
|
||||
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_NAT
|
||||
#define INCLUDE_PICO_NAT
|
||||
#include "pico_frame.h"
|
||||
|
||||
#define PICO_NAT_PORT_FORWARD_DEL 0
|
||||
#define PICO_NAT_PORT_FORWARD_ADD 1
|
||||
|
||||
#ifdef PICO_SUPPORT_NAT
|
||||
void pico_ipv4_nat_print_table(void);
|
||||
int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto);
|
||||
int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag);
|
||||
|
||||
int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr);
|
||||
int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr);
|
||||
int pico_ipv4_nat_enable(struct pico_ipv4_link *link);
|
||||
int pico_ipv4_nat_disable(void);
|
||||
int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr);
|
||||
#else
|
||||
|
||||
#define pico_ipv4_nat_print_table() do {} while(0)
|
||||
static inline int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr)
|
||||
{
|
||||
(void)f;
|
||||
(void)link_addr;
|
||||
pico_err = PICO_ERR_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr)
|
||||
{
|
||||
(void)f;
|
||||
(void)link_addr;
|
||||
pico_err = PICO_ERR_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int pico_ipv4_nat_enable(struct pico_ipv4_link *link)
|
||||
{
|
||||
(void)link;
|
||||
pico_err = PICO_ERR_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int pico_ipv4_nat_disable(void)
|
||||
{
|
||||
pico_err = PICO_ERR_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr)
|
||||
{
|
||||
(void)link_addr;
|
||||
pico_err = PICO_ERR_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
|
||||
{
|
||||
(void)nat_port;
|
||||
(void)src_addr;
|
||||
(void)src_port;
|
||||
(void)proto;
|
||||
pico_err = PICO_ERR_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag)
|
||||
{
|
||||
(void)nat_addr;
|
||||
(void)nat_port;
|
||||
(void)src_addr;
|
||||
(void)src_port;
|
||||
(void)proto;
|
||||
(void)flag;
|
||||
pico_err = PICO_ERR_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INCLUDE_PICO_NAT */
|
||||
|
||||
1143
ext/picotcp/modules/pico_olsr.c
Normal file
1143
ext/picotcp/modules/pico_olsr.c
Normal file
File diff suppressed because it is too large
Load Diff
32
ext/picotcp/modules/pico_olsr.h
Normal file
32
ext/picotcp/modules/pico_olsr.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Daniele Lacamera
|
||||
*********************************************************************/
|
||||
#ifndef PICO_OLSR_H
|
||||
#define PICO_OLSR_H
|
||||
|
||||
|
||||
/* Objects */
|
||||
struct olsr_route_entry
|
||||
{
|
||||
struct olsr_route_entry *next;
|
||||
uint32_t time_left;
|
||||
struct pico_ip4 destination;
|
||||
struct olsr_route_entry *gateway;
|
||||
struct pico_device *iface;
|
||||
uint16_t metric;
|
||||
uint8_t link_type;
|
||||
struct olsr_route_entry *children;
|
||||
uint16_t ansn;
|
||||
uint16_t seq;
|
||||
uint8_t lq, nlq;
|
||||
uint8_t *advertised_tc;
|
||||
};
|
||||
|
||||
|
||||
void pico_olsr_init(void);
|
||||
int pico_olsr_add(struct pico_device *dev);
|
||||
struct olsr_route_entry *olsr_get_ethentry(struct pico_device *vif);
|
||||
#endif
|
||||
99
ext/picotcp/modules/pico_posix.c
Normal file
99
ext/picotcp/modules/pico_posix.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/*********************************************************************
|
||||
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
|
||||
See LICENSE and COPYING for usage.
|
||||
|
||||
Authors: Andrei Carp, Maarten Vandersteegen
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef PICO_SUPPORT_THREADING
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include "pico_config.h"
|
||||
|
||||
/* POSIX mutex implementation */
|
||||
void *pico_mutex_init(void)
|
||||
{
|
||||
pthread_mutex_t *m;
|
||||
m = (pthread_mutex_t *)PICO_ZALLOC(sizeof(pthread_mutex_t));
|
||||
pthread_mutex_init(m, NULL);
|
||||
return m;
|
||||
}
|
||||
|
||||
void pico_mutex_destroy(void *mux)
|
||||
{
|
||||
PICO_FREE(mux);
|
||||
mux = NULL;
|
||||
}
|
||||
|
||||
void pico_mutex_lock(void *mux)
|
||||
{
|
||||
if (mux == NULL) return;
|
||||
|
||||
pthread_mutex_t *m = (pthread_mutex_t *)mux;
|
||||
pthread_mutex_lock(m);
|
||||
}
|
||||
|
||||
void pico_mutex_unlock(void *mux)
|
||||
{
|
||||
if (mux == NULL) return;
|
||||
|
||||
pthread_mutex_t *m = (pthread_mutex_t *)mux;
|
||||
pthread_mutex_unlock(m);
|
||||
}
|
||||
|
||||
/* POSIX semaphore implementation */
|
||||
void *pico_sem_init(void)
|
||||
{
|
||||
sem_t *s;
|
||||
s = (sem_t *)PICO_ZALLOC(sizeof(sem_t));
|
||||
sem_init(s, 0, 0);
|
||||
return s;
|
||||
}
|
||||
|
||||
void pico_sem_destroy(void *sem)
|
||||
{
|
||||
PICO_FREE(sem);
|
||||
sem = NULL;
|
||||
}
|
||||
|
||||
void pico_sem_post(void *sem)
|
||||
{
|
||||
if (sem == NULL) return;
|
||||
|
||||
sem_t *s = (sem_t *)sem;
|
||||
sem_post(s);
|
||||
}
|
||||
|
||||
int pico_sem_wait(void *sem, int timeout)
|
||||
{
|
||||
struct timespec t;
|
||||
if (sem == NULL) return 0;
|
||||
|
||||
sem_t *s = (sem_t *)sem;
|
||||
|
||||
if (timeout < 0) {
|
||||
sem_wait(s);
|
||||
} else {
|
||||
clock_gettime(CLOCK_REALTIME, &t);
|
||||
t.tv_sec += timeout / 1000;
|
||||
t.tv_nsec += (timeout % 1000) * 1000000;
|
||||
if (sem_timedwait(s, &t) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* POSIX thread implementation */
|
||||
void *pico_thread_create(void *(*routine)(void *), void *arg)
|
||||
{
|
||||
pthread_t *thread;
|
||||
thread = (pthread_t *)PICO_ZALLOC(sizeof(pthread_t));
|
||||
|
||||
if (pthread_create(thread, NULL, routine, arg) == -1)
|
||||
return NULL;
|
||||
|
||||
return thread;
|
||||
}
|
||||
#endif /* PICO_SUPPORT_THREADING */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user