mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-21 10:26:06 +03:00
Merge pull request #1892 from me-no-dev/lwipsrc
Update and move lwIP headers, add options to use different lwIP build for generic device
This commit is contained in:
commit
18f66e9969
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,3 +5,6 @@ tools/esptool/
|
|||||||
tools/mkspiffs/
|
tools/mkspiffs/
|
||||||
package/versions/
|
package/versions/
|
||||||
exclude.txt
|
exclude.txt
|
||||||
|
tools/sdk/lib/liblwip_src.a
|
||||||
|
tools/sdk/lwip/src/build
|
||||||
|
tools/sdk/lwip/src/liblwip_src.a
|
||||||
|
251
boards.txt
251
boards.txt
@ -7,6 +7,7 @@ menu.ResetMethod=Reset Method
|
|||||||
menu.ESPModule=Module
|
menu.ESPModule=Module
|
||||||
menu.Debug=Debug port
|
menu.Debug=Debug port
|
||||||
menu.DebugLevel=Debug Level
|
menu.DebugLevel=Debug Level
|
||||||
|
menu.LwIPVariant=lwIP Variant
|
||||||
|
|
||||||
##############################################################
|
##############################################################
|
||||||
generic.name=Generic ESP8266 Module
|
generic.name=Generic ESP8266 Module
|
||||||
@ -29,6 +30,8 @@ generic.build.flash_mode=qio
|
|||||||
generic.build.spiffs_pagesize=256
|
generic.build.spiffs_pagesize=256
|
||||||
generic.build.debug_port=
|
generic.build.debug_port=
|
||||||
generic.build.debug_level=
|
generic.build.debug_level=
|
||||||
|
generic.build.lwip_lib=-llwip
|
||||||
|
generic.build.lwip_flags=
|
||||||
|
|
||||||
generic.menu.CpuFrequency.80=80 MHz
|
generic.menu.CpuFrequency.80=80 MHz
|
||||||
generic.menu.CpuFrequency.80.build.f_cpu=80000000L
|
generic.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -247,6 +250,8 @@ espduino.build.flash_size=4M
|
|||||||
espduino.build.flash_freq=40
|
espduino.build.flash_freq=40
|
||||||
espduino.build.debug_port=
|
espduino.build.debug_port=
|
||||||
espduino.build.debug_level=
|
espduino.build.debug_level=
|
||||||
|
espduino.build.lwip_lib=-llwip
|
||||||
|
espduino.build.lwip_flags=
|
||||||
|
|
||||||
espduino.menu.CpuFrequency.80=80 MHz
|
espduino.menu.CpuFrequency.80=80 MHz
|
||||||
espduino.menu.CpuFrequency.80.build.f_cpu=80000000L
|
espduino.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -310,6 +315,8 @@ huzzah.build.flash_size=4M
|
|||||||
huzzah.build.flash_freq=40
|
huzzah.build.flash_freq=40
|
||||||
huzzah.build.debug_port=
|
huzzah.build.debug_port=
|
||||||
huzzah.build.debug_level=
|
huzzah.build.debug_level=
|
||||||
|
huzzah.build.lwip_lib=-llwip
|
||||||
|
huzzah.build.lwip_flags=
|
||||||
|
|
||||||
huzzah.menu.CpuFrequency.80=80 MHz
|
huzzah.menu.CpuFrequency.80=80 MHz
|
||||||
huzzah.menu.CpuFrequency.80.build.f_cpu=80000000L
|
huzzah.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -359,6 +366,8 @@ espresso_lite_v1.build.variant=espresso_lite_v1
|
|||||||
espresso_lite_v1.build.flash_mode=dio
|
espresso_lite_v1.build.flash_mode=dio
|
||||||
espresso_lite_v1.build.flash_size=4M
|
espresso_lite_v1.build.flash_size=4M
|
||||||
espresso_lite_v1.build.flash_freq=40
|
espresso_lite_v1.build.flash_freq=40
|
||||||
|
espresso_lite_v1.build.lwip_lib=-llwip
|
||||||
|
espresso_lite_v1.build.lwip_flags=
|
||||||
|
|
||||||
espresso_lite_v1.menu.CpuFrequency.80=80 MHz
|
espresso_lite_v1.menu.CpuFrequency.80=80 MHz
|
||||||
espresso_lite_v1.menu.CpuFrequency.80.build.f_cpu=80000000L
|
espresso_lite_v1.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -464,6 +473,8 @@ espresso_lite_v2.build.variant=espresso_lite_v2
|
|||||||
espresso_lite_v2.build.flash_mode=dio
|
espresso_lite_v2.build.flash_mode=dio
|
||||||
espresso_lite_v2.build.flash_size=4M
|
espresso_lite_v2.build.flash_size=4M
|
||||||
espresso_lite_v2.build.flash_freq=40
|
espresso_lite_v2.build.flash_freq=40
|
||||||
|
espresso_lite_v2.build.lwip_lib=-llwip
|
||||||
|
espresso_lite_v2.build.lwip_flags=
|
||||||
|
|
||||||
espresso_lite_v2.menu.CpuFrequency.80=80 MHz
|
espresso_lite_v2.menu.CpuFrequency.80=80 MHz
|
||||||
espresso_lite_v2.menu.CpuFrequency.80.build.f_cpu=80000000L
|
espresso_lite_v2.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -575,6 +586,8 @@ nodemcu.build.flash_size=4M
|
|||||||
nodemcu.build.flash_freq=40
|
nodemcu.build.flash_freq=40
|
||||||
nodemcu.build.debug_port=
|
nodemcu.build.debug_port=
|
||||||
nodemcu.build.debug_level=
|
nodemcu.build.debug_level=
|
||||||
|
nodemcu.build.lwip_lib=-llwip
|
||||||
|
nodemcu.build.lwip_flags=
|
||||||
|
|
||||||
nodemcu.menu.CpuFrequency.80=80 MHz
|
nodemcu.menu.CpuFrequency.80=80 MHz
|
||||||
nodemcu.menu.CpuFrequency.80.build.f_cpu=80000000L
|
nodemcu.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -639,6 +652,8 @@ nodemcuv2.build.flash_size=4M
|
|||||||
nodemcuv2.build.flash_freq=40
|
nodemcuv2.build.flash_freq=40
|
||||||
nodemcuv2.build.debug_port=
|
nodemcuv2.build.debug_port=
|
||||||
nodemcuv2.build.debug_level=
|
nodemcuv2.build.debug_level=
|
||||||
|
nodemcuv2.build.lwip_lib=-llwip
|
||||||
|
nodemcuv2.build.lwip_flags=
|
||||||
|
|
||||||
nodemcuv2.menu.CpuFrequency.80=80 MHz
|
nodemcuv2.menu.CpuFrequency.80=80 MHz
|
||||||
nodemcuv2.menu.CpuFrequency.80.build.f_cpu=80000000L
|
nodemcuv2.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -710,6 +725,8 @@ modwifi.build.spiffs_pagesize=256
|
|||||||
modwifi.build.spiffs_blocksize=8192
|
modwifi.build.spiffs_blocksize=8192
|
||||||
modwifi.build.debug_port=
|
modwifi.build.debug_port=
|
||||||
modwifi.build.debug_level=
|
modwifi.build.debug_level=
|
||||||
|
modwifi.build.lwip_lib=-llwip
|
||||||
|
modwifi.build.lwip_flags=
|
||||||
|
|
||||||
modwifi.menu.CpuFrequency.80=80 MHz
|
modwifi.menu.CpuFrequency.80=80 MHz
|
||||||
modwifi.menu.CpuFrequency.80.build.f_cpu=80000000L
|
modwifi.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -764,6 +781,8 @@ thing.build.spiffs_blocksize=4096
|
|||||||
thing.build.spiffs_pagesize=256
|
thing.build.spiffs_pagesize=256
|
||||||
thing.build.debug_port=
|
thing.build.debug_port=
|
||||||
thing.build.debug_level=
|
thing.build.debug_level=
|
||||||
|
thing.build.lwip_lib=-llwip
|
||||||
|
thing.build.lwip_flags=
|
||||||
|
|
||||||
thing.menu.CpuFrequency.80=80 MHz
|
thing.menu.CpuFrequency.80=80 MHz
|
||||||
thing.menu.CpuFrequency.80.build.f_cpu=80000000L
|
thing.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -813,6 +832,8 @@ thingdev.build.flash_ld=eagle.flash.512k64.ld
|
|||||||
thingdev.build.flash_freq=40
|
thingdev.build.flash_freq=40
|
||||||
thingdev.build.debug_port=
|
thingdev.build.debug_port=
|
||||||
thingdev.build.debug_level=
|
thingdev.build.debug_level=
|
||||||
|
thingdev.build.lwip_lib=-llwip
|
||||||
|
thingdev.build.lwip_flags=
|
||||||
|
|
||||||
thingdev.menu.CpuFrequency.80=80 MHz
|
thingdev.menu.CpuFrequency.80=80 MHz
|
||||||
thingdev.menu.CpuFrequency.80.build.f_cpu=80000000L
|
thingdev.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -860,6 +881,8 @@ esp210.build.flash_size=4M
|
|||||||
esp210.build.flash_freq=40
|
esp210.build.flash_freq=40
|
||||||
esp210.build.debug_port=
|
esp210.build.debug_port=
|
||||||
esp210.build.debug_level=
|
esp210.build.debug_level=
|
||||||
|
esp210.build.lwip_lib=-llwip
|
||||||
|
esp210.build.lwip_flags=
|
||||||
|
|
||||||
esp210.menu.CpuFrequency.80=80 MHz
|
esp210.menu.CpuFrequency.80=80 MHz
|
||||||
esp210.menu.CpuFrequency.80.build.f_cpu=80000000L
|
esp210.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -951,6 +974,8 @@ d1_mini.build.flash_size=4M
|
|||||||
d1_mini.build.flash_freq=40
|
d1_mini.build.flash_freq=40
|
||||||
d1_mini.build.debug_port=
|
d1_mini.build.debug_port=
|
||||||
d1_mini.build.debug_level=
|
d1_mini.build.debug_level=
|
||||||
|
d1_mini.build.lwip_lib=-llwip
|
||||||
|
d1_mini.build.lwip_flags=
|
||||||
|
|
||||||
d1_mini.menu.CpuFrequency.80=80 MHz
|
d1_mini.menu.CpuFrequency.80=80 MHz
|
||||||
d1_mini.menu.CpuFrequency.80.build.f_cpu=80000000L
|
d1_mini.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -1017,6 +1042,8 @@ d1.build.flash_size=4M
|
|||||||
d1.build.flash_freq=40
|
d1.build.flash_freq=40
|
||||||
d1.build.debug_port=
|
d1.build.debug_port=
|
||||||
d1.build.debug_level=
|
d1.build.debug_level=
|
||||||
|
d1.build.lwip_lib=-llwip
|
||||||
|
d1.build.lwip_flags=
|
||||||
|
|
||||||
d1.menu.CpuFrequency.80=80 MHz
|
d1.menu.CpuFrequency.80=80 MHz
|
||||||
d1.menu.CpuFrequency.80.build.f_cpu=80000000L
|
d1.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -1085,6 +1112,8 @@ espino.build.flash_freq=40
|
|||||||
espino.build.spiffs_pagesize=256
|
espino.build.spiffs_pagesize=256
|
||||||
espino.build.debug_port=
|
espino.build.debug_port=
|
||||||
espino.build.debug_level=
|
espino.build.debug_level=
|
||||||
|
espino.build.lwip_lib=-llwip
|
||||||
|
espino.build.lwip_flags=
|
||||||
|
|
||||||
espino.menu.CpuFrequency.80=80 MHz
|
espino.menu.CpuFrequency.80=80 MHz
|
||||||
espino.menu.CpuFrequency.80.build.f_cpu=80000000L
|
espino.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -1159,6 +1188,8 @@ espinotee.build.flash_size=4M
|
|||||||
espinotee.build.flash_freq=40
|
espinotee.build.flash_freq=40
|
||||||
espinotee.build.debug_port=
|
espinotee.build.debug_port=
|
||||||
espinotee.build.debug_level=
|
espinotee.build.debug_level=
|
||||||
|
espinotee.build.lwip_lib=-llwip
|
||||||
|
espinotee.build.lwip_flags=
|
||||||
|
|
||||||
espinotee.menu.CpuFrequency.80=80 MHz
|
espinotee.menu.CpuFrequency.80=80 MHz
|
||||||
espinotee.menu.CpuFrequency.80.build.f_cpu=80000000L
|
espinotee.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
@ -1222,6 +1253,8 @@ wifinfo.build.board=ESP8266_ESP12
|
|||||||
wifinfo.build.spiffs_pagesize=256
|
wifinfo.build.spiffs_pagesize=256
|
||||||
wifinfo.build.debug_port=Serial1
|
wifinfo.build.debug_port=Serial1
|
||||||
wifinfo.build.debug_level=Wifinfo
|
wifinfo.build.debug_level=Wifinfo
|
||||||
|
wifinfo.build.lwip_lib=-llwip
|
||||||
|
wifinfo.build.lwip_flags=
|
||||||
|
|
||||||
wifinfo.menu.Debug.Disabled=Disabled
|
wifinfo.menu.Debug.Disabled=Disabled
|
||||||
wifinfo.menu.Debug.Disabled.build.debug_port=
|
wifinfo.menu.Debug.Disabled.build.debug_port=
|
||||||
@ -1332,3 +1365,221 @@ wifinfo.menu.UploadSpeed.512000.windows=512000
|
|||||||
wifinfo.menu.UploadSpeed.512000.upload.speed=512000
|
wifinfo.menu.UploadSpeed.512000.upload.speed=512000
|
||||||
wifinfo.menu.UploadSpeed.921600=921600
|
wifinfo.menu.UploadSpeed.921600=921600
|
||||||
wifinfo.menu.UploadSpeed.921600.upload.speed=921600
|
wifinfo.menu.UploadSpeed.921600.upload.speed=921600
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
coredev.name=Core Development Module
|
||||||
|
|
||||||
|
coredev.upload.tool=esptool
|
||||||
|
coredev.upload.speed=115200
|
||||||
|
coredev.upload.resetmethod=ck
|
||||||
|
coredev.upload.maximum_size=434160
|
||||||
|
coredev.upload.maximum_data_size=81920
|
||||||
|
coredev.upload.wait_for_upload_port=true
|
||||||
|
coredev.serial.disableDTR=true
|
||||||
|
coredev.serial.disableRTS=true
|
||||||
|
|
||||||
|
coredev.build.mcu=esp8266
|
||||||
|
coredev.build.f_cpu=80000000L
|
||||||
|
coredev.build.board=ESP8266_ESP01
|
||||||
|
coredev.build.core=esp8266
|
||||||
|
coredev.build.variant=generic
|
||||||
|
coredev.build.flash_mode=qio
|
||||||
|
coredev.build.spiffs_pagesize=256
|
||||||
|
coredev.build.debug_port=
|
||||||
|
coredev.build.debug_level=
|
||||||
|
coredev.build.lwip_lib=-llwip
|
||||||
|
coredev.build.lwip_flags=
|
||||||
|
|
||||||
|
|
||||||
|
coredev.menu.LwIPVariant.Espressif=Espressif (xcc)
|
||||||
|
coredev.menu.LwIPVariant.Espressif.build.lwip_lib=-llwip
|
||||||
|
coredev.menu.LwIPVariant.Espressif.build.lwip_flags=
|
||||||
|
coredev.menu.LwIPVariant.Prebuilt=Prebuilt Source (gcc)
|
||||||
|
coredev.menu.LwIPVariant.Prebuilt.build.lwip_lib=-llwip_gcc
|
||||||
|
coredev.menu.LwIPVariant.Prebuilt.build.lwip_flags=-DLWIP_OPEN_SRC
|
||||||
|
coredev.menu.LwIPVariant.OpenSource=Open Source (gcc)
|
||||||
|
coredev.menu.LwIPVariant.OpenSource.build.lwip_lib=-llwip_src
|
||||||
|
coredev.menu.LwIPVariant.OpenSource.build.lwip_flags=-DLWIP_OPEN_SRC
|
||||||
|
coredev.menu.LwIPVariant.OpenSource.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-"
|
||||||
|
|
||||||
|
coredev.menu.CpuFrequency.80=80 MHz
|
||||||
|
coredev.menu.CpuFrequency.80.build.f_cpu=80000000L
|
||||||
|
coredev.menu.CpuFrequency.160=160 MHz
|
||||||
|
coredev.menu.CpuFrequency.160.build.f_cpu=160000000L
|
||||||
|
|
||||||
|
coredev.menu.FlashFreq.40=40MHz
|
||||||
|
coredev.menu.FlashFreq.40.build.flash_freq=40
|
||||||
|
coredev.menu.FlashFreq.80=80MHz
|
||||||
|
coredev.menu.FlashFreq.80.build.flash_freq=80
|
||||||
|
|
||||||
|
coredev.menu.FlashMode.dio=DIO
|
||||||
|
coredev.menu.FlashMode.dio.build.flash_mode=dio
|
||||||
|
coredev.menu.FlashMode.qio=QIO
|
||||||
|
coredev.menu.FlashMode.qio.build.flash_mode=qio
|
||||||
|
|
||||||
|
coredev.menu.UploadSpeed.115200=115200
|
||||||
|
coredev.menu.UploadSpeed.115200.upload.speed=115200
|
||||||
|
coredev.menu.UploadSpeed.9600=9600
|
||||||
|
coredev.menu.UploadSpeed.9600.upload.speed=9600
|
||||||
|
coredev.menu.UploadSpeed.57600=57600
|
||||||
|
coredev.menu.UploadSpeed.57600.upload.speed=57600
|
||||||
|
coredev.menu.UploadSpeed.256000.windows=256000
|
||||||
|
coredev.menu.UploadSpeed.256000.upload.speed=256000
|
||||||
|
coredev.menu.UploadSpeed.230400.linux=230400
|
||||||
|
coredev.menu.UploadSpeed.230400.macosx=230400
|
||||||
|
coredev.menu.UploadSpeed.230400.upload.speed=230400
|
||||||
|
coredev.menu.UploadSpeed.460800.linux=460800
|
||||||
|
coredev.menu.UploadSpeed.460800.macosx=460800
|
||||||
|
coredev.menu.UploadSpeed.460800.upload.speed=460800
|
||||||
|
coredev.menu.UploadSpeed.512000.windows=512000
|
||||||
|
coredev.menu.UploadSpeed.512000.upload.speed=512000
|
||||||
|
coredev.menu.UploadSpeed.921600=921600
|
||||||
|
coredev.menu.UploadSpeed.921600.upload.speed=921600
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.512K64=512K (64K SPIFFS)
|
||||||
|
coredev.menu.FlashSize.512K64.build.flash_size=512K
|
||||||
|
coredev.menu.FlashSize.512K64.build.flash_ld=eagle.flash.512k64.ld
|
||||||
|
coredev.menu.FlashSize.512K64.build.spiffs_start=0x6B000
|
||||||
|
coredev.menu.FlashSize.512K64.build.spiffs_end=0x7B000
|
||||||
|
coredev.menu.FlashSize.512K64.build.spiffs_blocksize=4096
|
||||||
|
coredev.menu.FlashSize.512K64.upload.maximum_size=434160
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.512K128=512K (128K SPIFFS)
|
||||||
|
coredev.menu.FlashSize.512K128.build.flash_size=512K
|
||||||
|
coredev.menu.FlashSize.512K128.build.flash_ld=eagle.flash.512k128.ld
|
||||||
|
coredev.menu.FlashSize.512K128.build.spiffs_start=0x5B000
|
||||||
|
coredev.menu.FlashSize.512K128.build.spiffs_end=0x7B000
|
||||||
|
coredev.menu.FlashSize.512K128.build.spiffs_blocksize=4096
|
||||||
|
coredev.menu.FlashSize.512K128.upload.maximum_size=368624
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.512K0=512K (no SPIFFS)
|
||||||
|
coredev.menu.FlashSize.512K0.build.flash_size=512K
|
||||||
|
coredev.menu.FlashSize.512K0.build.flash_ld=eagle.flash.512k0.ld
|
||||||
|
coredev.menu.FlashSize.512K0.upload.maximum_size=499696
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.1M512=1M (512K SPIFFS)
|
||||||
|
coredev.menu.FlashSize.1M512.build.flash_size=1M
|
||||||
|
coredev.menu.FlashSize.1M512.build.flash_ld=eagle.flash.1m512.ld
|
||||||
|
coredev.menu.FlashSize.1M512.build.spiffs_start=0x7B000
|
||||||
|
coredev.menu.FlashSize.1M512.build.spiffs_end=0xFB000
|
||||||
|
coredev.menu.FlashSize.1M512.build.spiffs_blocksize=8192
|
||||||
|
coredev.menu.FlashSize.1M512.upload.maximum_size=499696
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.1M256=1M (256K SPIFFS)
|
||||||
|
coredev.menu.FlashSize.1M256.build.flash_size=1M
|
||||||
|
coredev.menu.FlashSize.1M256.build.flash_ld=eagle.flash.1m256.ld
|
||||||
|
coredev.menu.FlashSize.1M256.build.spiffs_start=0xBB000
|
||||||
|
coredev.menu.FlashSize.1M256.build.spiffs_end=0xFB000
|
||||||
|
coredev.menu.FlashSize.1M256.build.spiffs_blocksize=4096
|
||||||
|
coredev.menu.FlashSize.1M256.upload.maximum_size=761840
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.1M192=1M (192K SPIFFS)
|
||||||
|
coredev.menu.FlashSize.1M192.build.flash_size=1M
|
||||||
|
coredev.menu.FlashSize.1M192.build.flash_ld=eagle.flash.1m192.ld
|
||||||
|
coredev.menu.FlashSize.1M192.build.spiffs_start=0xCB000
|
||||||
|
coredev.menu.FlashSize.1M192.build.spiffs_end=0xFB000
|
||||||
|
coredev.menu.FlashSize.1M192.build.spiffs_blocksize=4096
|
||||||
|
coredev.menu.FlashSize.1M192.upload.maximum_size=827376
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.1M160=1M (160K SPIFFS)
|
||||||
|
coredev.menu.FlashSize.1M160.build.flash_size=1M
|
||||||
|
coredev.menu.FlashSize.1M160.build.flash_ld=eagle.flash.1m160.ld
|
||||||
|
coredev.menu.FlashSize.1M160.build.spiffs_start=0xD3000
|
||||||
|
coredev.menu.FlashSize.1M160.build.spiffs_end=0xFB000
|
||||||
|
coredev.menu.FlashSize.1M160.build.spiffs_blocksize=4096
|
||||||
|
coredev.menu.FlashSize.1M160.upload.maximum_size=860144
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.1M144=1M (144K SPIFFS)
|
||||||
|
coredev.menu.FlashSize.1M144.build.flash_size=1M
|
||||||
|
coredev.menu.FlashSize.1M144.build.flash_ld=eagle.flash.1m144.ld
|
||||||
|
coredev.menu.FlashSize.1M144.build.spiffs_start=0xD7000
|
||||||
|
coredev.menu.FlashSize.1M144.build.spiffs_end=0xFB000
|
||||||
|
coredev.menu.FlashSize.1M144.build.spiffs_blocksize=4096
|
||||||
|
coredev.menu.FlashSize.1M144.upload.maximum_size=876528
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.1M128=1M (128K SPIFFS)
|
||||||
|
coredev.menu.FlashSize.1M128.build.flash_size=1M
|
||||||
|
coredev.menu.FlashSize.1M128.build.flash_ld=eagle.flash.1m128.ld
|
||||||
|
coredev.menu.FlashSize.1M128.build.spiffs_start=0xDB000
|
||||||
|
coredev.menu.FlashSize.1M128.build.spiffs_end=0xFB000
|
||||||
|
coredev.menu.FlashSize.1M128.build.spiffs_blocksize=4096
|
||||||
|
coredev.menu.FlashSize.1M128.upload.maximum_size=892912
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.1M64=1M (64K SPIFFS)
|
||||||
|
coredev.menu.FlashSize.1M64.build.flash_size=1M
|
||||||
|
coredev.menu.FlashSize.1M64.build.flash_ld=eagle.flash.1m64.ld
|
||||||
|
coredev.menu.FlashSize.1M64.build.spiffs_start=0xEB000
|
||||||
|
coredev.menu.FlashSize.1M64.build.spiffs_end=0xFB000
|
||||||
|
coredev.menu.FlashSize.1M64.build.spiffs_blocksize=4096
|
||||||
|
coredev.menu.FlashSize.1M64.upload.maximum_size=958448
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.2M=2M (1M SPIFFS)
|
||||||
|
coredev.menu.FlashSize.2M.build.flash_size=2M
|
||||||
|
coredev.menu.FlashSize.2M.build.flash_ld=eagle.flash.2m.ld
|
||||||
|
coredev.menu.FlashSize.2M.build.spiffs_start=0x100000
|
||||||
|
coredev.menu.FlashSize.2M.build.spiffs_end=0x1FB000
|
||||||
|
coredev.menu.FlashSize.2M.build.spiffs_blocksize=8192
|
||||||
|
coredev.menu.FlashSize.2M.upload.maximum_size=1044464
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.4M1M=4M (1M SPIFFS)
|
||||||
|
coredev.menu.FlashSize.4M1M.build.flash_size=4M
|
||||||
|
coredev.menu.FlashSize.4M1M.build.flash_ld=eagle.flash.4m1m.ld
|
||||||
|
coredev.menu.FlashSize.4M1M.build.spiffs_start=0x300000
|
||||||
|
coredev.menu.FlashSize.4M1M.build.spiffs_end=0x3FB000
|
||||||
|
coredev.menu.FlashSize.4M1M.build.spiffs_blocksize=8192
|
||||||
|
coredev.menu.FlashSize.4M1M.build.spiffs_pagesize=256
|
||||||
|
coredev.menu.FlashSize.4M1M.upload.maximum_size=1044464
|
||||||
|
|
||||||
|
coredev.menu.FlashSize.4M3M=4M (3M SPIFFS)
|
||||||
|
coredev.menu.FlashSize.4M3M.build.flash_size=4M
|
||||||
|
coredev.menu.FlashSize.4M3M.build.flash_ld=eagle.flash.4m.ld
|
||||||
|
coredev.menu.FlashSize.4M3M.build.spiffs_start=0x100000
|
||||||
|
coredev.menu.FlashSize.4M3M.build.spiffs_end=0x3FB000
|
||||||
|
coredev.menu.FlashSize.4M3M.build.spiffs_blocksize=8192
|
||||||
|
coredev.menu.FlashSize.4M3M.upload.maximum_size=1044464
|
||||||
|
|
||||||
|
coredev.menu.ResetMethod.ck=ck
|
||||||
|
coredev.menu.ResetMethod.ck.upload.resetmethod=ck
|
||||||
|
coredev.menu.ResetMethod.nodemcu=nodemcu
|
||||||
|
coredev.menu.ResetMethod.nodemcu.upload.resetmethod=nodemcu
|
||||||
|
|
||||||
|
coredev.menu.Debug.Disabled=Disabled
|
||||||
|
coredev.menu.Debug.Disabled.build.debug_port=
|
||||||
|
coredev.menu.Debug.Serial=Serial
|
||||||
|
coredev.menu.Debug.Serial.build.debug_port=-DDEBUG_ESP_PORT=Serial
|
||||||
|
coredev.menu.Debug.Serial1=Serial1
|
||||||
|
coredev.menu.Debug.Serial1.build.debug_port=-DDEBUG_ESP_PORT=Serial1
|
||||||
|
|
||||||
|
coredev.menu.DebugLevel.None____=None
|
||||||
|
coredev.menu.DebugLevel.None____.build.debug_level=
|
||||||
|
coredev.menu.DebugLevel.Core____=Core
|
||||||
|
coredev.menu.DebugLevel.Core____.build.debug_level=-DDEBUG_ESP_CORE
|
||||||
|
coredev.menu.DebugLevel.SSL_____=Core + SSL
|
||||||
|
coredev.menu.DebugLevel.SSL_____.build.debug_level=-DDEBUG_ESP_CORE -DDEBUG_ESP_SSL
|
||||||
|
coredev.menu.DebugLevel.SSL_MEM_=Core + SSL + TLS Mem
|
||||||
|
coredev.menu.DebugLevel.SSL_MEM_.build.debug_level=-DDEBUG_ESP_CORE -DDEBUG_ESP_SSL -DDEBUG_TLS_MEM
|
||||||
|
coredev.menu.DebugLevel.WiFic___=Core + WiFi
|
||||||
|
coredev.menu.DebugLevel.WiFic___.build.debug_level=-DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI
|
||||||
|
coredev.menu.DebugLevel.WiFi____=WiFi
|
||||||
|
coredev.menu.DebugLevel.WiFi____.build.debug_level=-DDEBUG_ESP_WIFI
|
||||||
|
coredev.menu.DebugLevel.HTTPClient=HTTPClient
|
||||||
|
coredev.menu.DebugLevel.HTTPClient.build.debug_level=-DDEBUG_ESP_HTTP_CLIENT
|
||||||
|
coredev.menu.DebugLevel.HTTPClient2=HTTPClient + SSL
|
||||||
|
coredev.menu.DebugLevel.HTTPClient2.build.debug_level=-DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_SSL
|
||||||
|
coredev.menu.DebugLevel.HTTPUpdate=HTTPUpdate
|
||||||
|
coredev.menu.DebugLevel.HTTPUpdate.build.debug_level=-DDEBUG_ESP_HTTP_UPDATE
|
||||||
|
coredev.menu.DebugLevel.HTTPUpdate2=HTTPClient + HTTPUpdate
|
||||||
|
coredev.menu.DebugLevel.HTTPUpdate2.build.debug_level=-DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_UPDATE
|
||||||
|
coredev.menu.DebugLevel.HTTPUpdate3=HTTPClient + HTTPUpdate + Updater
|
||||||
|
coredev.menu.DebugLevel.HTTPUpdate3.build.debug_level=-DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_UPDATER
|
||||||
|
coredev.menu.DebugLevel.HTTPServer=HTTPServer
|
||||||
|
coredev.menu.DebugLevel.HTTPServer.build.debug_level=-DDEBUG_ESP_HTTP_SERVER
|
||||||
|
coredev.menu.DebugLevel.UPDATER=Updater
|
||||||
|
coredev.menu.DebugLevel.UPDATER.build.debug_level=-DDEBUG_ESP_UPDATER
|
||||||
|
coredev.menu.DebugLevel.OTA_____=OTA
|
||||||
|
coredev.menu.DebugLevel.OTA_____.build.debug_level=-DDEBUG_ESP_OTA
|
||||||
|
coredev.menu.DebugLevel.OTA2____=OTA + Updater
|
||||||
|
coredev.menu.DebugLevel.OTA2____.build.debug_level=-DDEBUG_ESP_OTA -DDEBUG_ESP_UPDATER
|
||||||
|
coredev.menu.DebugLevel.all_____=All
|
||||||
|
coredev.menu.DebugLevel.all_____.build.debug_level=-DDEBUG_ESP_CORE -DDEBUG_ESP_SSL -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
#ifndef LWIP_OPEN_SRC
|
||||||
#define LWIP_OPEN_SRC
|
#define LWIP_OPEN_SRC
|
||||||
|
#endif
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
#include "ArduinoOTA.h"
|
#include "ArduinoOTA.h"
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
#ifndef __MEM_MANAGER_H__
|
|
||||||
#define __MEM_MANAGER_H__
|
|
||||||
|
|
||||||
#include "c_types.h"
|
|
||||||
|
|
||||||
/*------------------------<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>------------------------*/
|
|
||||||
|
|
||||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
|
||||||
#ifndef IOT_SIP_MODE
|
|
||||||
//#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 0x3fffc000 - (uint32)&_heap_start ) )//fix 16000 to 24000 on 14.2.26
|
|
||||||
#else
|
|
||||||
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 8000 ) )
|
|
||||||
#endif
|
|
||||||
#define portBYTE_ALIGNMENT 8
|
|
||||||
#define pdFALSE 0
|
|
||||||
#define pdTRUE 1
|
|
||||||
|
|
||||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
|
||||||
#if portBYTE_ALIGNMENT == 8
|
|
||||||
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if portBYTE_ALIGNMENT == 4
|
|
||||||
#define portBYTE_ALIGNMENT_MASK ( 0x0003 )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if portBYTE_ALIGNMENT == 2
|
|
||||||
#define portBYTE_ALIGNMENT_MASK ( 0x0001 )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if portBYTE_ALIGNMENT == 1
|
|
||||||
#define portBYTE_ALIGNMENT_MASK ( 0x0000 )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef portBYTE_ALIGNMENT_MASK
|
|
||||||
#error "Invalid portBYTE_ALIGNMENT definition"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define configUSE_MALLOC_FAILED_HOOK 1
|
|
||||||
#define portPOINTER_SIZE_TYPE unsigned int
|
|
||||||
|
|
||||||
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )
|
|
||||||
|
|
||||||
//#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )
|
|
||||||
|
|
||||||
//static unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];
|
|
||||||
//static unsigned char *ucHeap;
|
|
||||||
|
|
||||||
typedef struct A_BLOCK_LINK
|
|
||||||
{
|
|
||||||
struct A_BLOCK_LINK *pxNextFreeBlock; //The next free block in the list.
|
|
||||||
size_t xBlockSize; //The size of the free block.
|
|
||||||
} xBlockLink;
|
|
||||||
|
|
||||||
static const unsigned short heapSTRUCT_SIZE = ( sizeof( xBlockLink ) + portBYTE_ALIGNMENT - ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) );
|
|
||||||
|
|
||||||
//static const size_t xTotalHeapSize = ( ( size_t ) configADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );
|
|
||||||
|
|
||||||
//static xBlockLink xStart, *pxEnd = NULL;
|
|
||||||
|
|
||||||
//static size_t xFreeBytesRemaining = ( ( size_t ) configADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-----------------------------------*/
|
|
||||||
|
|
||||||
//static void prvInsertBlockIntoFreeList( xBlockLink *pxBlockToInsert ) ;//ICACHE_FLASH_ATTR;
|
|
||||||
|
|
||||||
//static void prvHeapInit( void ) ;//ICACHE_FLASH_ATTR;
|
|
||||||
|
|
||||||
void vApplicationMallocFailedHook( void ) ;//ICACHE_FLASH_ATTR;
|
|
||||||
|
|
||||||
void *pvPortMalloc( size_t xWantedSize, const char* file, int line ) __attribute__((malloc, alloc_size(1)));//ICACHE_FLASH_ATTR;
|
|
||||||
|
|
||||||
void vPortFree( void *pv, const char* file, int line ) ;//ICACHE_FLASH_ATTR;
|
|
||||||
|
|
||||||
size_t xPortGetFreeHeapSize( void ) ;//ICACHE_FLASH_ATTR;
|
|
||||||
|
|
||||||
void vPortInitialiseBlocks( void ) ;//ICACHE_FLASH_ATTR;
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
#endif
|
|
@ -34,7 +34,9 @@ License (MIT license):
|
|||||||
// - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt
|
// - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt
|
||||||
// - MDNS-SD: https://tools.ietf.org/html/rfc6763
|
// - MDNS-SD: https://tools.ietf.org/html/rfc6763
|
||||||
|
|
||||||
|
#ifndef LWIP_OPEN_SRC
|
||||||
#define LWIP_OPEN_SRC
|
#define LWIP_OPEN_SRC
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "ESP8266mDNS.h"
|
#include "ESP8266mDNS.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
10
platform.txt
10
platform.txt
@ -19,7 +19,7 @@ compiler.warning_flags.all=-Wall -Wextra
|
|||||||
|
|
||||||
compiler.path={runtime.tools.xtensa-lx106-elf-gcc.path}/bin/
|
compiler.path={runtime.tools.xtensa-lx106-elf-gcc.path}/bin/
|
||||||
compiler.sdk.path={runtime.platform.path}/tools/sdk
|
compiler.sdk.path={runtime.platform.path}/tools/sdk
|
||||||
compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include"
|
compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include" "-I{compiler.sdk.path}/lwip/include"
|
||||||
|
|
||||||
compiler.c.cmd=xtensa-lx106-elf-gcc
|
compiler.c.cmd=xtensa-lx106-elf-gcc
|
||||||
compiler.c.flags=-c {compiler.warning_flags} -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections
|
compiler.c.flags=-c {compiler.warning_flags} -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections
|
||||||
@ -30,7 +30,7 @@ compiler.S.flags=-c -g -x assembler-with-cpp -MMD -mlongcalls
|
|||||||
compiler.c.elf.flags=-g {compiler.warning_flags} -Os -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-T{build.flash_ld}" -Wl,--gc-sections -Wl,-wrap,system_restart_local -Wl,-wrap,register_chipv6_phy
|
compiler.c.elf.flags=-g {compiler.warning_flags} -Os -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-T{build.flash_ld}" -Wl,--gc-sections -Wl,-wrap,system_restart_local -Wl,-wrap,register_chipv6_phy
|
||||||
|
|
||||||
compiler.c.elf.cmd=xtensa-lx106-elf-gcc
|
compiler.c.elf.cmd=xtensa-lx106-elf-gcc
|
||||||
compiler.c.elf.libs=-lm -lgcc -lhal -lphy -lpp -lnet80211 -llwip -lwpa -lcrypto -lmain -lwps -laxtls -lsmartconfig -lmesh -lwpa2
|
compiler.c.elf.libs=-lm -lgcc -lhal -lphy -lpp -lnet80211 -lwpa -lcrypto -lmain -lwps -laxtls -lsmartconfig -lmesh -lwpa2 {build.lwip_lib}
|
||||||
|
|
||||||
compiler.cpp.cmd=xtensa-lx106-elf-g++
|
compiler.cpp.cmd=xtensa-lx106-elf-g++
|
||||||
compiler.cpp.flags=-c {compiler.warning_flags} -Os -g -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD -ffunction-sections -fdata-sections
|
compiler.cpp.flags=-c {compiler.warning_flags} -Os -g -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD -ffunction-sections -fdata-sections
|
||||||
@ -61,13 +61,13 @@ compiler.objcopy.eep.extra_flags=
|
|||||||
compiler.elf2hex.extra_flags=
|
compiler.elf2hex.extra_flags=
|
||||||
|
|
||||||
## Compile c files
|
## Compile c files
|
||||||
recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.c.flags} -DF_CPU={build.f_cpu} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
|
recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.c.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
|
||||||
|
|
||||||
## Compile c++ files
|
## Compile c++ files
|
||||||
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} -DF_CPU={build.f_cpu} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
|
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
|
||||||
|
|
||||||
## Compile S files
|
## Compile S files
|
||||||
recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -DF_CPU={build.f_cpu} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
|
recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
|
||||||
|
|
||||||
## Create archives
|
## Create archives
|
||||||
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/arduino.ar" "{object_file}"
|
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/arduino.ar" "{object_file}"
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "c_types.h"
|
#include "c_types.h"
|
||||||
#include "eagle_soc.h"
|
#include "eagle_soc.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
typedef uint32_t ETSSignal;
|
typedef uint32_t ETSSignal;
|
||||||
typedef uint32_t ETSParam;
|
typedef uint32_t ETSParam;
|
||||||
|
101
tools/sdk/lwip/include/lwip/app/dhcpserver.h
Normal file
101
tools/sdk/lwip/include/lwip/app/dhcpserver.h
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#ifndef __DHCPS_H__
|
||||||
|
#define __DHCPS_H__
|
||||||
|
|
||||||
|
#define USE_DNS
|
||||||
|
|
||||||
|
typedef struct dhcps_state{
|
||||||
|
sint16_t state;
|
||||||
|
} dhcps_state;
|
||||||
|
|
||||||
|
typedef struct dhcps_msg {
|
||||||
|
uint8_t op, htype, hlen, hops;
|
||||||
|
uint8_t xid[4];
|
||||||
|
uint16_t secs, flags;
|
||||||
|
uint8_t ciaddr[4];
|
||||||
|
uint8_t yiaddr[4];
|
||||||
|
uint8_t siaddr[4];
|
||||||
|
uint8_t giaddr[4];
|
||||||
|
uint8_t chaddr[16];
|
||||||
|
uint8_t sname[64];
|
||||||
|
uint8_t file[128];
|
||||||
|
uint8_t options[312];
|
||||||
|
}dhcps_msg;
|
||||||
|
|
||||||
|
#ifndef LWIP_OPEN_SRC
|
||||||
|
struct dhcps_lease {
|
||||||
|
bool enable;
|
||||||
|
struct ip_addr start_ip;
|
||||||
|
struct ip_addr end_ip;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dhcps_offer_option{
|
||||||
|
OFFER_START = 0x00,
|
||||||
|
OFFER_ROUTER = 0x01,
|
||||||
|
OFFER_END
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct dhcps_pool{
|
||||||
|
struct ip_addr ip;
|
||||||
|
uint8 mac[6];
|
||||||
|
uint32 lease_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _list_node{
|
||||||
|
void *pnode;
|
||||||
|
struct _list_node *pnext;
|
||||||
|
}list_node;
|
||||||
|
|
||||||
|
extern uint32 dhcps_lease_time;
|
||||||
|
#define DHCPS_LEASE_TIMER dhcps_lease_time //0x05A0
|
||||||
|
#define DHCPS_MAX_LEASE 0x64
|
||||||
|
#define BOOTP_BROADCAST 0x8000
|
||||||
|
|
||||||
|
#define DHCP_REQUEST 1
|
||||||
|
#define DHCP_REPLY 2
|
||||||
|
#define DHCP_HTYPE_ETHERNET 1
|
||||||
|
#define DHCP_HLEN_ETHERNET 6
|
||||||
|
#define DHCP_MSG_LEN 236
|
||||||
|
|
||||||
|
#define DHCPS_SERVER_PORT 67
|
||||||
|
#define DHCPS_CLIENT_PORT 68
|
||||||
|
|
||||||
|
#define DHCPDISCOVER 1
|
||||||
|
#define DHCPOFFER 2
|
||||||
|
#define DHCPREQUEST 3
|
||||||
|
#define DHCPDECLINE 4
|
||||||
|
#define DHCPACK 5
|
||||||
|
#define DHCPNAK 6
|
||||||
|
#define DHCPRELEASE 7
|
||||||
|
|
||||||
|
#define DHCP_OPTION_SUBNET_MASK 1
|
||||||
|
#define DHCP_OPTION_ROUTER 3
|
||||||
|
#define DHCP_OPTION_DNS_SERVER 6
|
||||||
|
#define DHCP_OPTION_REQ_IPADDR 50
|
||||||
|
#define DHCP_OPTION_LEASE_TIME 51
|
||||||
|
#define DHCP_OPTION_MSG_TYPE 53
|
||||||
|
#define DHCP_OPTION_SERVER_ID 54
|
||||||
|
#define DHCP_OPTION_INTERFACE_MTU 26
|
||||||
|
#define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31
|
||||||
|
#define DHCP_OPTION_BROADCAST_ADDRESS 28
|
||||||
|
#define DHCP_OPTION_REQ_LIST 55
|
||||||
|
#define DHCP_OPTION_END 255
|
||||||
|
|
||||||
|
//#define USE_CLASS_B_NET 1
|
||||||
|
#define DHCPS_DEBUG 0
|
||||||
|
#define MAX_STATION_NUM 8
|
||||||
|
|
||||||
|
#define DHCPS_STATE_OFFER 1
|
||||||
|
#define DHCPS_STATE_DECLINE 2
|
||||||
|
#define DHCPS_STATE_ACK 3
|
||||||
|
#define DHCPS_STATE_NAK 4
|
||||||
|
#define DHCPS_STATE_IDLE 5
|
||||||
|
#define DHCPS_STATE_RELEASE 6
|
||||||
|
|
||||||
|
#define dhcps_router_enabled(offer) ((offer & OFFER_ROUTER) != 0)
|
||||||
|
|
||||||
|
void dhcps_start(struct ip_info *info);
|
||||||
|
void dhcps_stop(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
664
tools/sdk/lwip/include/lwip/app/espconn.h
Normal file
664
tools/sdk/lwip/include/lwip/app/espconn.h
Normal file
@ -0,0 +1,664 @@
|
|||||||
|
#ifndef __ESPCONN_H__
|
||||||
|
#define __ESPCONN_H__
|
||||||
|
|
||||||
|
#include "lwip/dns.h"
|
||||||
|
#include "os_type.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define espconn_printf(fmt, args...) os_printf(fmt,## args)
|
||||||
|
#else
|
||||||
|
#define espconn_printf(fmt, args...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef void *espconn_handle;
|
||||||
|
typedef void (* espconn_connect_callback)(void *arg);
|
||||||
|
typedef void (* espconn_reconnect_callback)(void *arg, sint8 err);
|
||||||
|
|
||||||
|
/* Definitions for error constants. */
|
||||||
|
|
||||||
|
#define ESPCONN_OK 0 /* No error, everything OK. */
|
||||||
|
#define ESPCONN_MEM -1 /* Out of memory error. */
|
||||||
|
#define ESPCONN_TIMEOUT -3 /* Timeout. */
|
||||||
|
#define ESPCONN_RTE -4 /* Routing problem. */
|
||||||
|
#define ESPCONN_INPROGRESS -5 /* Operation in progress */
|
||||||
|
#define ESPCONN_MAXNUM -7 /* Total number exceeds the set maximum*/
|
||||||
|
|
||||||
|
#define ESPCONN_ABRT -8 /* Connection aborted. */
|
||||||
|
#define ESPCONN_RST -9 /* Connection reset. */
|
||||||
|
#define ESPCONN_CLSD -10 /* Connection closed. */
|
||||||
|
#define ESPCONN_CONN -11 /* Not connected. */
|
||||||
|
|
||||||
|
#define ESPCONN_ARG -12 /* Illegal argument. */
|
||||||
|
#define ESPCONN_IF -14 /* Low_level error */
|
||||||
|
#define ESPCONN_ISCONN -15 /* Already connected. */
|
||||||
|
|
||||||
|
#define ESPCONN_HANDSHAKE -28 /* ssl handshake failed */
|
||||||
|
#define ESPCONN_RESP_TIMEOUT -29 /* ssl handshake no response*/
|
||||||
|
#define ESPCONN_PROTO_MSG -61 /* ssl application invalid */
|
||||||
|
|
||||||
|
#define ESPCONN_SSL 0x01
|
||||||
|
#define ESPCONN_NORM 0x00
|
||||||
|
|
||||||
|
#define ESPCONN_STA 0x01
|
||||||
|
#define ESPCONN_AP 0x02
|
||||||
|
#define ESPCONN_AP_STA 0x03
|
||||||
|
|
||||||
|
#define STA_NETIF 0x00
|
||||||
|
#define AP_NETIF 0x01
|
||||||
|
|
||||||
|
/** Protocol family and type of the espconn */
|
||||||
|
enum espconn_type {
|
||||||
|
ESPCONN_INVALID = 0,
|
||||||
|
/* ESPCONN_TCP Group */
|
||||||
|
ESPCONN_TCP = 0x10,
|
||||||
|
/* ESPCONN_UDP Group */
|
||||||
|
ESPCONN_UDP = 0x20,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Current state of the espconn. Non-TCP espconn are always in state ESPCONN_NONE! */
|
||||||
|
enum espconn_state {
|
||||||
|
ESPCONN_NONE,
|
||||||
|
ESPCONN_WAIT,
|
||||||
|
ESPCONN_LISTEN,
|
||||||
|
ESPCONN_CONNECT,
|
||||||
|
ESPCONN_WRITE,
|
||||||
|
ESPCONN_READ,
|
||||||
|
ESPCONN_CLOSE
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _esp_tcp {
|
||||||
|
int remote_port;
|
||||||
|
int local_port;
|
||||||
|
uint8 local_ip[4];
|
||||||
|
uint8 remote_ip[4];
|
||||||
|
espconn_connect_callback connect_callback;
|
||||||
|
espconn_reconnect_callback reconnect_callback;
|
||||||
|
espconn_connect_callback disconnect_callback;
|
||||||
|
espconn_connect_callback write_finish_fn;
|
||||||
|
} esp_tcp;
|
||||||
|
|
||||||
|
typedef struct _esp_udp {
|
||||||
|
int remote_port;
|
||||||
|
int local_port;
|
||||||
|
uint8 local_ip[4];
|
||||||
|
uint8 remote_ip[4];
|
||||||
|
} esp_udp;
|
||||||
|
|
||||||
|
typedef struct _remot_info{
|
||||||
|
enum espconn_state state;
|
||||||
|
int remote_port;
|
||||||
|
uint8 remote_ip[4];
|
||||||
|
}remot_info;
|
||||||
|
|
||||||
|
/** A callback prototype to inform about events for a espconn */
|
||||||
|
typedef void (* espconn_recv_callback)(void *arg, char *pdata, unsigned short len);
|
||||||
|
typedef void (* espconn_sent_callback)(void *arg);
|
||||||
|
|
||||||
|
/** A espconn descriptor */
|
||||||
|
struct espconn {
|
||||||
|
/** type of the espconn (TCP, UDP) */
|
||||||
|
enum espconn_type type;
|
||||||
|
/** current state of the espconn */
|
||||||
|
enum espconn_state state;
|
||||||
|
union {
|
||||||
|
esp_tcp *tcp;
|
||||||
|
esp_udp *udp;
|
||||||
|
} proto;
|
||||||
|
/** A callback function that is informed about events for this espconn */
|
||||||
|
espconn_recv_callback recv_callback;
|
||||||
|
espconn_sent_callback sent_callback;
|
||||||
|
uint8 link_cnt;
|
||||||
|
void *reverse;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum espconn_option{
|
||||||
|
ESPCONN_START = 0x00,
|
||||||
|
ESPCONN_REUSEADDR = 0x01,
|
||||||
|
ESPCONN_NODELAY = 0x02,
|
||||||
|
ESPCONN_COPY = 0x04,
|
||||||
|
ESPCONN_KEEPALIVE = 0x08,
|
||||||
|
ESPCONN_END
|
||||||
|
};
|
||||||
|
|
||||||
|
enum espconn_level{
|
||||||
|
ESPCONN_KEEPIDLE,
|
||||||
|
ESPCONN_KEEPINTVL,
|
||||||
|
ESPCONN_KEEPCNT
|
||||||
|
};
|
||||||
|
|
||||||
|
struct espconn_packet{
|
||||||
|
uint16 sent_length; /* sent length successful*/
|
||||||
|
uint16 snd_buf_size; /* Available buffer size for sending */
|
||||||
|
uint16 snd_queuelen; /* Available buffer space for sending */
|
||||||
|
uint16 total_queuelen; /* total Available buffer space for sending */
|
||||||
|
uint32 packseqno; /* seqno to be sent */
|
||||||
|
uint32 packseq_nxt; /* seqno expected */
|
||||||
|
uint32 packnum;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _espconn_buf{
|
||||||
|
uint8 *payload;
|
||||||
|
uint8 *punsent;
|
||||||
|
uint16 unsent;
|
||||||
|
uint16 len;
|
||||||
|
uint16 tot_len;
|
||||||
|
struct _espconn_buf *pnext;
|
||||||
|
} espconn_buf;
|
||||||
|
|
||||||
|
typedef struct _comon_pkt{
|
||||||
|
void *pcb;
|
||||||
|
int remote_port;
|
||||||
|
uint8 remote_ip[4];
|
||||||
|
uint32 local_port;
|
||||||
|
uint32 local_ip;
|
||||||
|
espconn_buf *pbuf;
|
||||||
|
espconn_buf *ptail;
|
||||||
|
uint8* ptrbuf;
|
||||||
|
uint16 cntr;
|
||||||
|
sint8 err;
|
||||||
|
uint32 timeout;
|
||||||
|
uint32 recv_check;
|
||||||
|
uint8 pbuf_num;
|
||||||
|
struct espconn_packet packet_info;
|
||||||
|
bool write_flag;
|
||||||
|
enum espconn_option espconn_opt;
|
||||||
|
}comon_pkt;
|
||||||
|
|
||||||
|
typedef struct _espconn_msg{
|
||||||
|
struct espconn *pespconn;
|
||||||
|
comon_pkt pcommon;
|
||||||
|
uint8 count_opt;
|
||||||
|
sint16_t hs_status; //the status of the handshake
|
||||||
|
void *preverse;
|
||||||
|
void *pssl;
|
||||||
|
struct _espconn_msg *pnext;
|
||||||
|
|
||||||
|
//***********Code for WIFI_BLOCK from upper**************
|
||||||
|
uint8 recv_hold_flag;
|
||||||
|
uint16 recv_holded_buf_Len;
|
||||||
|
}espconn_msg;
|
||||||
|
|
||||||
|
#ifndef _MDNS_INFO
|
||||||
|
#define _MDNS_INFO
|
||||||
|
struct mdns_info {
|
||||||
|
char *host_name;
|
||||||
|
char *server_name;
|
||||||
|
uint16 server_port;
|
||||||
|
unsigned long ipAddr;
|
||||||
|
char *txt_data[10];
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define linkMax 15
|
||||||
|
|
||||||
|
#define espconn_delay_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) != 0)
|
||||||
|
#define espconn_delay_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) == 0)
|
||||||
|
#define espconn_reuse_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_REUSEADDR) != 0)
|
||||||
|
#define espconn_copy_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) != 0)
|
||||||
|
#define espconn_copy_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) == 0)
|
||||||
|
#define espconn_keepalive_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) != 0)
|
||||||
|
#define espconn_keepalive_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) == 0)
|
||||||
|
|
||||||
|
#define espconn_TaskPrio 26
|
||||||
|
#define espconn_TaskQueueLen 15
|
||||||
|
|
||||||
|
enum espconn_sig {
|
||||||
|
SIG_ESPCONN_NONE,
|
||||||
|
SIG_ESPCONN_ERRER,
|
||||||
|
SIG_ESPCONN_LISTEN,
|
||||||
|
SIG_ESPCONN_CONNECT,
|
||||||
|
SIG_ESPCONN_WRITE,
|
||||||
|
SIG_ESPCONN_SEND,
|
||||||
|
SIG_ESPCONN_READ,
|
||||||
|
SIG_ESPCONN_CLOSE
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_copy_partial
|
||||||
|
* Description : reconnect with host
|
||||||
|
* Parameters : arg -- Additional argument to pass to the callback function
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
void espconn_copy_partial(struct espconn *pesp_dest, struct espconn *pesp_source);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_copy_partial
|
||||||
|
* Description : insert the node to the active connection list
|
||||||
|
* Parameters : arg -- Additional argument to pass to the callback function
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
void espconn_list_creat(espconn_msg **phead, espconn_msg* pinsert);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_list_delete
|
||||||
|
* Description : remove the node from the active connection list
|
||||||
|
* Parameters : arg -- Additional argument to pass to the callback function
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
void espconn_list_delete(espconn_msg **phead, espconn_msg* pdelete);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_find_connection
|
||||||
|
* Description : Initialize the server: set up a listening PCB and bind it to
|
||||||
|
* the defined port
|
||||||
|
* Parameters : espconn -- the espconn used to build server
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
bool espconn_find_connection(struct espconn *pespconn, espconn_msg **pnode);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_get_connection_info
|
||||||
|
* Description : used to specify the function that should be called when disconnect
|
||||||
|
* Parameters : espconn -- espconn to set the err callback
|
||||||
|
* discon_cb -- err callback function to call when err
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
sint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_get_packet_info
|
||||||
|
* Description : get the packet info with host
|
||||||
|
* Parameters : espconn -- the espconn used to disconnect the connection
|
||||||
|
* infoarg -- the packet info
|
||||||
|
* Returns : the errur code
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
sint8 espconn_get_packet_info(struct espconn *espconn, struct espconn_packet* infoarg);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_connect
|
||||||
|
* Description : The function given as the connect
|
||||||
|
* Parameters : espconn -- the espconn used to listen the connection
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_connect(struct espconn *espconn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_disconnect
|
||||||
|
* Description : disconnect with host
|
||||||
|
* Parameters : espconn -- the espconn used to disconnect the connection
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_disconnect(struct espconn *espconn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_delete
|
||||||
|
* Description : disconnect with host
|
||||||
|
* Parameters : espconn -- the espconn used to disconnect the connection
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_delete(struct espconn *espconn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_accept
|
||||||
|
* Description : The function given as the listen
|
||||||
|
* Parameters : espconn -- the espconn used to listen the connection
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_accept(struct espconn *espconn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_create
|
||||||
|
* Description : sent data for client or server
|
||||||
|
* Parameters : espconn -- espconn to the data transmission
|
||||||
|
* Returns : result
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_create(struct espconn *espconn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_get_wnd
|
||||||
|
* Description : get the window size of simulatenously active TCP connections
|
||||||
|
* Parameters : none
|
||||||
|
* Returns : the number of TCP_MSS active TCP connections
|
||||||
|
*******************************************************************************/
|
||||||
|
extern uint8 espconn_tcp_get_wnd(void);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_set_max_con
|
||||||
|
* Description : set the window size simulatenously active TCP connections
|
||||||
|
* Parameters : num -- the number of TCP_MSS
|
||||||
|
* Returns : ESPCONN_ARG -- Illegal argument
|
||||||
|
* ESPCONN_OK -- No error
|
||||||
|
*******************************************************************************/
|
||||||
|
extern sint8 espconn_tcp_set_wnd(uint8 num);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_get_max_con
|
||||||
|
* Description : get the number of simulatenously active TCP connections
|
||||||
|
* Parameters : none
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern uint8 espconn_tcp_get_max_con(void);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_set_max_con
|
||||||
|
* Description : set the number of simulatenously active TCP connections
|
||||||
|
* Parameters : num -- total number
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_tcp_set_max_con(uint8 num);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_get_max_retran
|
||||||
|
* Description : get the Maximum number of retransmissions of data active TCP connections
|
||||||
|
* Parameters : none
|
||||||
|
* Returns : the Maximum number of retransmissions
|
||||||
|
*******************************************************************************/
|
||||||
|
extern uint8 espconn_tcp_get_max_retran(void);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_set_max_retran
|
||||||
|
* Description : set the Maximum number of retransmissions of data active TCP connections
|
||||||
|
* Parameters : num -- the Maximum number of retransmissions
|
||||||
|
* Returns : result
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_tcp_set_max_retran(uint8 num);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_get_max_syn
|
||||||
|
* Description : get the Maximum number of retransmissions of SYN segments
|
||||||
|
* Parameters : none
|
||||||
|
* Returns : the Maximum number of retransmissions
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern uint8 espconn_tcp_get_max_syn(void);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_set_max_syn
|
||||||
|
* Description : set the Maximum number of retransmissions of SYN segments
|
||||||
|
* Parameters : num -- the Maximum number of retransmissions
|
||||||
|
* Returns : result
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_tcp_set_max_syn(uint8 num);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_get_max_con_allow
|
||||||
|
* Description : get the count of simulatenously active connections on the server
|
||||||
|
* Parameters : espconn -- espconn to get the count
|
||||||
|
* Returns : result
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_tcp_get_max_con_allow(struct espconn *espconn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_set_max_con_allow
|
||||||
|
* Description : set the count of simulatenously active connections on the server
|
||||||
|
* Parameters : espconn -- espconn to set the count
|
||||||
|
* Returns : result
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_set_buf_count
|
||||||
|
* Description : set the total number of espconn_buf on the unsent lists
|
||||||
|
* Parameters : espconn -- espconn to set the count
|
||||||
|
* num -- the total number of espconn_buf
|
||||||
|
* Returns : result
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_tcp_set_buf_count(struct espconn *espconn, uint8 num);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_regist_time
|
||||||
|
* Description : used to specify the time that should be called when don't recv data
|
||||||
|
* Parameters : espconn -- the espconn used to the connection
|
||||||
|
* interval -- the timer when don't recv data
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_regist_sentcb
|
||||||
|
* Description : Used to specify the function that should be called when data
|
||||||
|
* has been successfully delivered to the remote host.
|
||||||
|
* Parameters : struct espconn *espconn -- espconn to set the sent callback
|
||||||
|
* espconn_sent_callback sent_cb -- sent callback function to
|
||||||
|
* call for this espconn when data is successfully sent
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_regist_sentcb
|
||||||
|
* Description : Used to specify the function that should be called when data
|
||||||
|
* has been successfully delivered to the remote host.
|
||||||
|
* Parameters : espconn -- espconn to set the sent callback
|
||||||
|
* sent_cb -- sent callback function to call for this espconn
|
||||||
|
* when data is successfully sent
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern sint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_sent
|
||||||
|
* Description : sent data for client or server
|
||||||
|
* Parameters : espconn -- espconn to set for client or server
|
||||||
|
* psent -- data to send
|
||||||
|
* length -- length of data to send
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_regist_connectcb
|
||||||
|
* Description : used to specify the function that should be called when
|
||||||
|
* connects to host.
|
||||||
|
* Parameters : espconn -- espconn to set the connect callback
|
||||||
|
* connect_cb -- connected callback function to call when connected
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_regist_recvcb
|
||||||
|
* Description : used to specify the function that should be called when recv
|
||||||
|
* data from host.
|
||||||
|
* Parameters : espconn -- espconn to set the recv callback
|
||||||
|
* recv_cb -- recv callback function to call when recv data
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_regist_reconcb
|
||||||
|
* Description : used to specify the function that should be called when connection
|
||||||
|
* because of err disconnect.
|
||||||
|
* Parameters : espconn -- espconn to set the err callback
|
||||||
|
* recon_cb -- err callback function to call when err
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_regist_disconcb
|
||||||
|
* Description : used to specify the function that should be called when disconnect
|
||||||
|
* Parameters : espconn -- espconn to set the err callback
|
||||||
|
* discon_cb -- err callback function to call when err
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_port
|
||||||
|
* Description : access port value for client so that we don't end up bouncing
|
||||||
|
* all connections at the same time .
|
||||||
|
* Parameters : none
|
||||||
|
* Returns : access port value
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern uint32 espconn_port(void);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_set_opt
|
||||||
|
* Description : access port value for client so that we don't end up bouncing
|
||||||
|
* all connections at the same time .
|
||||||
|
* Parameters : none
|
||||||
|
* Returns : access port value
|
||||||
|
*******************************************************************************/
|
||||||
|
extern sint8 espconn_set_opt(struct espconn *espconn, uint8 opt);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_set_keepalive
|
||||||
|
* Description : access level value for connection so that we set the value for
|
||||||
|
* keep alive
|
||||||
|
* Parameters : espconn -- the espconn used to set the connection
|
||||||
|
* level -- the connection's level
|
||||||
|
* value -- the value of time(s)
|
||||||
|
* Returns : access port value
|
||||||
|
*******************************************************************************/
|
||||||
|
extern sint8 espconn_set_keepalive(struct espconn *espconn, uint8 level, void* optarg);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_get_keepalive
|
||||||
|
* Description : access level value for connection so that we get the value for
|
||||||
|
* keep alive
|
||||||
|
* Parameters : espconn -- the espconn used to get the connection
|
||||||
|
* level -- the connection's level
|
||||||
|
* Returns : access keep alive value
|
||||||
|
*******************************************************************************/
|
||||||
|
extern sint8 espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_gethostbyname
|
||||||
|
* Description : Resolve a hostname (string) into an IP address.
|
||||||
|
* Parameters : pespconn -- espconn to resolve a hostname
|
||||||
|
* hostname -- the hostname that is to be queried
|
||||||
|
* addr -- pointer to a ip_addr_t where to store the address if
|
||||||
|
* it is already cached in the dns_table (only valid if
|
||||||
|
* ESPCONN_OK is returned!)
|
||||||
|
* found -- a callback function to be called on success, failure
|
||||||
|
* or timeout (only if ERR_INPROGRESS is returned!)
|
||||||
|
* Returns : err_t return code
|
||||||
|
* - ESPCONN_OK if hostname is a valid IP address string or the host
|
||||||
|
* name is already in the local names table.
|
||||||
|
* - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server
|
||||||
|
* for resolution if no errors are present.
|
||||||
|
* - ESPCONN_ARG: dns client not initialized or invalid hostname
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_gethostbyname(struct espconn *pespconn, const char *name, ip_addr_t *addr, dns_found_callback found);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_igmp_join
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : host_ip -- the ip address of udp server
|
||||||
|
* multicast_ip -- multicast ip given by user
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_igmp_leave
|
||||||
|
* Description : leave a multicast group
|
||||||
|
* Parameters : host_ip -- the ip address of udp server
|
||||||
|
* multicast_ip -- multicast ip given by user
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_init
|
||||||
|
* Description : register a device with mdns
|
||||||
|
* Parameters : ipAddr -- the ip address of device
|
||||||
|
* hostname -- the hostname of device
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern void espconn_mdns_init(struct mdns_info *info);
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_init
|
||||||
|
* Description : close mdns socket
|
||||||
|
* Parameters : void
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern void espconn_mdns_close(void);
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : mdns_server_register
|
||||||
|
* Description : register a server and join a multicast group
|
||||||
|
* Parameters : none
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern void espconn_mdns_server_register(void);
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : mdns_server_register
|
||||||
|
* Description : unregister server and leave multicast group
|
||||||
|
* Parameters : none
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern void espconn_mdns_server_unregister(void);
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_get_servername
|
||||||
|
* Description : get server name
|
||||||
|
* Parameters : none
|
||||||
|
* Returns : server name
|
||||||
|
*******************************************************************************/
|
||||||
|
extern char* espconn_mdns_get_servername(void);
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_get_servername
|
||||||
|
* Description : set server name
|
||||||
|
* Parameters : server name
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern void espconn_mdns_set_servername(const char *name);
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_set_hostname
|
||||||
|
* Description : set host name
|
||||||
|
* Parameters : host name
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern void espconn_mdns_set_hostname(char *name);
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_init
|
||||||
|
* Description : get host name
|
||||||
|
* Parameters : void
|
||||||
|
* Returns : hostname
|
||||||
|
*******************************************************************************/
|
||||||
|
extern char* espconn_mdns_get_hostname(void);
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_disable
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : host_ip -- the ip address of udp server
|
||||||
|
* multicast_ip -- multicast ip given by user
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern void espconn_mdns_disable(void);
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_enable
|
||||||
|
* Description : enable mdns
|
||||||
|
* Parameters : void
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern void espconn_mdns_enable(void);
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_dns_setserver
|
||||||
|
* Description : Initialize one of the DNS servers.
|
||||||
|
* Parameters : numdns -- the index of the DNS server to set must
|
||||||
|
* be < DNS_MAX_SERVERS = 2
|
||||||
|
* dnsserver -- IP address of the DNS server to set
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
extern void espconn_dns_setserver(u8_t numdns, ip_addr_t *dnsserver);
|
||||||
|
#endif
|
||||||
|
|
55
tools/sdk/lwip/include/lwip/app/espconn_tcp.h
Normal file
55
tools/sdk/lwip/include/lwip/app/espconn_tcp.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef __ESPCONN_TCP_H__
|
||||||
|
#define __ESPCONN_TCP_H__
|
||||||
|
|
||||||
|
#ifndef ESPCONN_TCP_DEBUG
|
||||||
|
#define ESPCONN_TCP_DEBUG LWIP_DBG_OFF
|
||||||
|
#endif
|
||||||
|
#include "lwip/app/espconn.h"
|
||||||
|
|
||||||
|
#ifndef ESPCONN_TCP_TIMER
|
||||||
|
#define ESPCONN_TCP_TIMER 40
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define espconn_keepalive_enable(pcb) ((pcb)->so_options |= SOF_KEEPALIVE)
|
||||||
|
#define espconn_keepalive_disable(pcb) ((pcb)->so_options &= ~SOF_KEEPALIVE)
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_kill_oldest_pcb
|
||||||
|
* Description : A oldest incoming connection has been killed.
|
||||||
|
* Parameters : none
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern void espconn_kill_oldest_pcb(void);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_disconnect
|
||||||
|
* Description : A new incoming connection has been disconnected.
|
||||||
|
* Parameters : espconn -- the espconn used to disconnect with host
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern void espconn_tcp_disconnect(espconn_msg *pdiscon,u8 type);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_client
|
||||||
|
* Description : Initialize the client: set up a connect PCB and bind it to
|
||||||
|
* the defined port
|
||||||
|
* Parameters : espconn -- the espconn used to build client
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_tcp_client(struct espconn* espconn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_tcp_server
|
||||||
|
* Description : Initialize the server: set up a listening PCB and bind it to
|
||||||
|
* the defined port
|
||||||
|
* Parameters : espconn -- the espconn used to build server
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_tcp_server(struct espconn *espconn);
|
||||||
|
|
||||||
|
#endif /* __CLIENT_TCP_H__ */
|
||||||
|
|
64
tools/sdk/lwip/include/lwip/app/espconn_udp.h
Normal file
64
tools/sdk/lwip/include/lwip/app/espconn_udp.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#ifndef __ESPCONN_UDP_H__
|
||||||
|
#define __ESPCONN_UDP_H__
|
||||||
|
|
||||||
|
#ifndef ESPCONN_UDP_DEBUG
|
||||||
|
#define ESPCONN_UDP_DEBUG LWIP_DBG_OFF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "lwip/app/espconn.h"
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_udp_client
|
||||||
|
* Description : Initialize the client: set up a PCB and bind it to the port
|
||||||
|
* Parameters : pespconn -- the espconn used to build client
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_udp_client(struct espconn *pespconn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_udp_disconnect
|
||||||
|
* Description : A new incoming connection has been disconnected.
|
||||||
|
* Parameters : espconn -- the espconn used to disconnect with host
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern void espconn_udp_disconnect(espconn_msg *pdiscon);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_udp_server
|
||||||
|
* Description : Initialize the server: set up a PCB and bind it to the port
|
||||||
|
* Parameters : pespconn -- the espconn used to build server
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern sint8 espconn_udp_server(struct espconn *espconn);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_udp_sent
|
||||||
|
* Description : sent data for client or server
|
||||||
|
* Parameters : void *arg -- client or server to send
|
||||||
|
* uint8* psent -- Data to send
|
||||||
|
* uint16 length -- Length of data to send
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
extern err_t espconn_udp_sent(void *arg, uint8 *psent, uint16 length);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_udp_sendto
|
||||||
|
* Description : sent data for UDP
|
||||||
|
* Parameters : void *arg -- UDP to send
|
||||||
|
* uint8* psent -- Data to send
|
||||||
|
* uint16 length -- Length of data to send
|
||||||
|
* Returns : return espconn error code.
|
||||||
|
* - ESPCONN_OK. Successful. No error occured.
|
||||||
|
* - ESPCONN_MEM. Out of memory.
|
||||||
|
* - ESPCONN_RTE. Could not find route to destination address.
|
||||||
|
* - More errors could be returned by lower protocol layers.
|
||||||
|
*******************************************************************************/
|
||||||
|
extern err_t espconn_udp_sendto(void *arg, uint8 *psent, uint16 length);
|
||||||
|
|
||||||
|
#endif /* __ESPCONN_UDP_H__ */
|
||||||
|
|
||||||
|
|
85
tools/sdk/lwip/include/lwip/app/ping.h
Normal file
85
tools/sdk/lwip/include/lwip/app/ping.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#ifndef __PING_H__
|
||||||
|
#define __PING_H__
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
#include "lwip/icmp.h"
|
||||||
|
/**
|
||||||
|
* PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used
|
||||||
|
*/
|
||||||
|
#ifndef PING_USE_SOCKETS
|
||||||
|
#define PING_USE_SOCKETS LWIP_SOCKET
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PING_DEBUG: Enable debugging for PING.
|
||||||
|
*/
|
||||||
|
#ifndef PING_DEBUG
|
||||||
|
#define PING_DEBUG LWIP_DBG_OFF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** ping receive timeout - in milliseconds */
|
||||||
|
#ifndef PING_RCV_TIMEO
|
||||||
|
#define PING_RCV_TIMEO 1000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** ping delay - in milliseconds */
|
||||||
|
#ifndef PING_COARSE
|
||||||
|
#define PING_COARSE 1000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** ping identifier - must fit on a u16_t */
|
||||||
|
#ifndef PING_ID
|
||||||
|
#define PING_ID 0xAFAF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** ping additional data size to include in the packet */
|
||||||
|
#ifndef PING_DATA_SIZE
|
||||||
|
#define PING_DATA_SIZE 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** ping result action - no default action */
|
||||||
|
#ifndef PING_RESULT
|
||||||
|
#define PING_RESULT(ping_ok)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEFAULT_PING_MAX_COUNT 4
|
||||||
|
#define PING_TIMEOUT_MS 1000
|
||||||
|
|
||||||
|
typedef void (* ping_recv_function)(void* arg, void *pdata);
|
||||||
|
typedef void (* ping_sent_function)(void* arg, void *pdata);
|
||||||
|
|
||||||
|
struct ping_option{
|
||||||
|
uint32 count;
|
||||||
|
uint32 ip;
|
||||||
|
uint32 coarse_time;
|
||||||
|
ping_recv_function recv_function;
|
||||||
|
ping_sent_function sent_function;
|
||||||
|
void* reverse;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ping_msg{
|
||||||
|
struct ping_option *ping_opt;
|
||||||
|
struct raw_pcb *ping_pcb;
|
||||||
|
uint32 ping_start;
|
||||||
|
uint32 ping_sent;
|
||||||
|
uint32 timeout_count;
|
||||||
|
uint32 max_count;
|
||||||
|
uint32 sent_count;
|
||||||
|
uint32 coarse_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ping_resp{
|
||||||
|
uint32 total_count;
|
||||||
|
uint32 resp_time;
|
||||||
|
uint32 seqno;
|
||||||
|
uint32 timeout_count;
|
||||||
|
uint32 bytes;
|
||||||
|
uint32 total_bytes;
|
||||||
|
uint32 total_time;
|
||||||
|
sint8 ping_err;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ping_start(struct ping_option *ping_opt);
|
||||||
|
bool ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv);
|
||||||
|
bool ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent);
|
||||||
|
|
||||||
|
#endif /* __PING_H__ */
|
@ -207,6 +207,15 @@ void dhcp_fine_tmr(void);
|
|||||||
#define DHCP_OPTION_TCP_TTL 37
|
#define DHCP_OPTION_TCP_TTL 37
|
||||||
#define DHCP_OPTION_END 255
|
#define DHCP_OPTION_END 255
|
||||||
|
|
||||||
|
/**add options for support more router by liuHan**/
|
||||||
|
#define DHCP_OPTION_DOMAIN_NAME 15
|
||||||
|
#define DHCP_OPTION_PRD 31
|
||||||
|
#define DHCP_OPTION_STATIC_ROUTER 33
|
||||||
|
#define DHCP_OPTION_VSN 43
|
||||||
|
#define DHCP_OPTION_NB_TINS 44
|
||||||
|
#define DHCP_OPTION_NB_TINT 46
|
||||||
|
#define DHCP_OPTION_NB_TIS 47
|
||||||
|
#define DHCP_OPTION_CLASSLESS_STATIC_ROUTER 121
|
||||||
/** DHCP options */
|
/** DHCP options */
|
||||||
#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */
|
#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */
|
||||||
#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */
|
#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */
|
@ -96,7 +96,7 @@ void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)ICACHE_FLAS
|
|||||||
err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR;
|
err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR;
|
||||||
err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR;
|
err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR;
|
||||||
void igmp_tmr(void)ICACHE_FLASH_ATTR;
|
void igmp_tmr(void)ICACHE_FLASH_ATTR;
|
||||||
#define LWIP_RAND() rand()
|
#define LWIP_RAND() r_rand()
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
114
tools/sdk/lwip/include/lwip/mdns.h
Normal file
114
tools/sdk/lwip/include/lwip/mdns.h
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/**
|
||||||
|
* lwip MDNS resolver header file.
|
||||||
|
*
|
||||||
|
* Created on: Jul 29, 2010
|
||||||
|
* Author: Daniel Toma
|
||||||
|
|
||||||
|
|
||||||
|
* ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote
|
||||||
|
* products derived from this software without specific prior
|
||||||
|
* written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||||
|
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LWIP_DNS_H__
|
||||||
|
#define __LWIP_DNS_H__
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_MDNS /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
/** DNS timer period */
|
||||||
|
#define DNS_TMR_INTERVAL 1000
|
||||||
|
|
||||||
|
/** mDNS Address offset flag*/
|
||||||
|
#define DNS_OFFSET_FLAG 0xC0 /* the offset flag in the DNS message */
|
||||||
|
#define DNS_DEFAULT_OFFSET 0x0C /* the offset is set at the beginning of the DNS message */
|
||||||
|
|
||||||
|
#define DNS_IP_ADDR_LEN 4
|
||||||
|
|
||||||
|
|
||||||
|
/** DNS field TYPE used for "Resource Records" */
|
||||||
|
#define DNS_RRTYPE_A 1 /* a host address */
|
||||||
|
#define DNS_RRTYPE_NS 2 /* an authoritative name server */
|
||||||
|
#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */
|
||||||
|
#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */
|
||||||
|
#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */
|
||||||
|
#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */
|
||||||
|
#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */
|
||||||
|
#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */
|
||||||
|
#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */
|
||||||
|
#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */
|
||||||
|
#define DNS_RRTYPE_WKS 11 /* a well known service description */
|
||||||
|
#define DNS_RRTYPE_PTR 12 /* a domain name pointer */
|
||||||
|
#define DNS_RRTYPE_HINFO 13 /* host information */
|
||||||
|
#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */
|
||||||
|
#define DNS_RRTYPE_MX 15 /* mail exchange */
|
||||||
|
#define DNS_RRTYPE_TXT 16 /* text strings */
|
||||||
|
#define DNS_RRTYPE_SRV 33 /* Service record */
|
||||||
|
#define DNS_RRTYPE_OPT 41 /* EDNS0 OPT record */
|
||||||
|
#define DNS_RRTYPE_TSIG 250 /* Transaction Signature */
|
||||||
|
#define DNS_RRTYPE_ANY 255 /*Not a DNS type, but a DNS query type, meaning "all types"*/
|
||||||
|
|
||||||
|
/* DNS field CLASS used for "Resource Records" */
|
||||||
|
#define DNS_RRCLASS_IN 1 /* the Internet */
|
||||||
|
#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
|
||||||
|
#define DNS_RRCLASS_CH 3 /* the CHAOS class */
|
||||||
|
#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */
|
||||||
|
#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */
|
||||||
|
#define DNS_RRCLASS_FLUSH_IN 0x8001/* Flush bit and Internet*/
|
||||||
|
|
||||||
|
/** Callback which is invoked when a hostname is found.
|
||||||
|
* A function of this type must be implemented by the application using the DNS resolver.
|
||||||
|
* @param name pointer to the name that was looked up.
|
||||||
|
* @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname,
|
||||||
|
* or NULL if the name could not be found (or on any other error).
|
||||||
|
* @param callback_arg a user-specified callback argument passed to dns_gethostbyname
|
||||||
|
*/
|
||||||
|
#ifndef _MDNS_INFO
|
||||||
|
#define _MDNS_INFO
|
||||||
|
struct mdns_info {
|
||||||
|
char *host_name;
|
||||||
|
char *server_name;
|
||||||
|
uint16 server_port;
|
||||||
|
unsigned long ipAddr;
|
||||||
|
char *txt_data[10];
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
//void mdns_enable(void);
|
||||||
|
//void mdns_disable(void);
|
||||||
|
//void mdns_init(struct mdns_info *info);
|
||||||
|
//void mdns_close(void);
|
||||||
|
//char* mdns_get_hostname(void);
|
||||||
|
//void mdns_set_hostname(char *name);
|
||||||
|
//void mdns_set_servername(const char *name);
|
||||||
|
//char* mdns_get_servername(void);
|
||||||
|
//void mdns_server_unregister(void);
|
||||||
|
//void mdns_server_register(void) ;
|
||||||
|
//void mdns_tmr(void);
|
||||||
|
//void Delay(unsigned long ulSeconds);
|
||||||
|
|
||||||
|
#endif /* LWIP_DNS */
|
||||||
|
|
||||||
|
#endif /* __LWIP_DNS_H__ */
|
@ -33,7 +33,7 @@
|
|||||||
#define __LWIP_MEM_H__
|
#define __LWIP_MEM_H__
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
#include "lwip/opt.h"
|
||||||
#include "mem_manager.h"
|
//#include "mem_manager.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
@ -76,7 +76,7 @@ typedef enum {
|
|||||||
#endif /* MEM_USE_POOLS */
|
#endif /* MEM_USE_POOLS */
|
||||||
|
|
||||||
#if MEMP_MEM_MALLOC || MEM_USE_POOLS
|
#if MEMP_MEM_MALLOC || MEM_USE_POOLS
|
||||||
extern const u16_t memp_sizes[MEMP_MAX];
|
extern const u32_t memp_sizes[MEMP_MAX];
|
||||||
#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */
|
#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */
|
||||||
|
|
||||||
#if MEMP_MEM_MALLOC
|
#if MEMP_MEM_MALLOC
|
@ -130,6 +130,9 @@ typedef void (*netif_status_callback_fn)(struct netif *netif);
|
|||||||
typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,
|
typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,
|
||||||
ip_addr_t *group, u8_t action);
|
ip_addr_t *group, u8_t action);
|
||||||
|
|
||||||
|
/*add DHCP event processing by LiuHan*/
|
||||||
|
typedef void (*dhcp_event_fn)(void);
|
||||||
|
|
||||||
/** Generic data structure used for all lwIP network interfaces.
|
/** Generic data structure used for all lwIP network interfaces.
|
||||||
* The following fields should be filled in by the initialization
|
* The following fields should be filled in by the initialization
|
||||||
* function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
|
* function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
|
||||||
@ -169,6 +172,8 @@ struct netif {
|
|||||||
#if LWIP_DHCP
|
#if LWIP_DHCP
|
||||||
/** the DHCP client state information for this netif */
|
/** the DHCP client state information for this netif */
|
||||||
struct dhcp *dhcp;
|
struct dhcp *dhcp;
|
||||||
|
struct udp_pcb *dhcps_pcb; //dhcps
|
||||||
|
dhcp_event_fn dhcp_event;
|
||||||
#endif /* LWIP_DHCP */
|
#endif /* LWIP_DHCP */
|
||||||
#if LWIP_AUTOIP
|
#if LWIP_AUTOIP
|
||||||
/** the AutoIP client state information for this netif */
|
/** the AutoIP client state information for this netif */
|
@ -42,7 +42,7 @@
|
|||||||
* Include user defined options first. Anything not defined in these files
|
* Include user defined options first. Anything not defined in these files
|
||||||
* will be set to standard values. Override anything you dont like!
|
* will be set to standard values. Override anything you dont like!
|
||||||
*/
|
*/
|
||||||
#include "include/lwipopts.h"
|
#include "lwipopts.h"
|
||||||
#include "lwip/debug.h"
|
#include "lwip/debug.h"
|
||||||
|
|
||||||
/*
|
/*
|
44
tools/sdk/lwip/include/lwip/puck_def.h
Normal file
44
tools/sdk/lwip/include/lwip/puck_def.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* puck_def.h
|
||||||
|
*
|
||||||
|
* Created on: Jul 22, 2010
|
||||||
|
* Author: dtoma
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PUCK_DEF_H_
|
||||||
|
#define PUCK_DEF_H_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define INSTRUMENT_PORT 8760
|
||||||
|
|
||||||
|
#define INSTRUMENT_LENGTH 80
|
||||||
|
|
||||||
|
#define MDNS_NAME_LENGTH 68 //68
|
||||||
|
|
||||||
|
char* PUCK_SERVICE = NULL;
|
||||||
|
//#define PUCK_SERVICE "_Escpressif._tcp.local"
|
||||||
|
#define DNS_SD_SERVICE "_services._dns-sd._udp.local"
|
||||||
|
#define SERVICE_DESCRIPTION "PUCK PROTOCOL"
|
||||||
|
#define PUCK_SERVICE_LENGTH 30
|
||||||
|
|
||||||
|
#define UUID_LEN 16
|
||||||
|
#define DS_VERS_LEN 2
|
||||||
|
#define DS_SIZE_LEN 2
|
||||||
|
#define MAN_ID_LEN 4
|
||||||
|
#define MAN_MODEL_LEN 2
|
||||||
|
#define MAN_VERS_LEN 2
|
||||||
|
#define SER_NUM_LEN 4
|
||||||
|
#define NAME_LEN 64
|
||||||
|
#define PUCK_DATASHEET_SIZE 96
|
||||||
|
|
||||||
|
#define UUID_OFFSET 0
|
||||||
|
#define DS_VERS_OFFSET UUID_LEN + UUID_OFFSET
|
||||||
|
#define DS_SIZE_OFFSET DS_VERS_LEN + DS_VERS_OFFSET
|
||||||
|
#define MAN_ID_OFFSET DS_SIZE_LEN + DS_SIZE_OFFSET
|
||||||
|
#define MAN_MODEL_OFFSET MAN_ID_LEN + MAN_ID_OFFSET
|
||||||
|
#define MAN_VERS_OFFSET MAN_MODEL_LEN + MAN_MODEL_OFFSET
|
||||||
|
#define SER_NUM_OFFSET MAN_VERS_LEN + MAN_VERS_OFFSET
|
||||||
|
#define NAME_OFFSET SER_NUM_LEN + SER_NUM_OFFSET
|
||||||
|
|
||||||
|
#endif /* __PUCK_DEF_H__ */
|
56
tools/sdk/lwip/include/lwip/sntp.h
Normal file
56
tools/sdk/lwip/include/lwip/sntp.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#ifndef LWIP_SNTP_H
|
||||||
|
#define LWIP_SNTP_H
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** The maximum number of SNTP servers that can be set */
|
||||||
|
#ifndef SNTP_MAX_SERVERS
|
||||||
|
#define SNTP_MAX_SERVERS 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Set this to 1 to implement the callback function called by dhcp when
|
||||||
|
* NTP servers are received. */
|
||||||
|
#ifndef SNTP_GET_SERVERS_FROM_DHCP
|
||||||
|
#define SNTP_GET_SERVERS_FROM_DHCP 0//LWIP_DHCP_GET_NTP_SRV
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set this to 1 to support DNS names (or IP address strings) to set sntp servers */
|
||||||
|
#ifndef SNTP_SERVER_DNS
|
||||||
|
#define SNTP_SERVER_DNS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** One server address/name can be defined as default if SNTP_SERVER_DNS == 1:
|
||||||
|
* #define SNTP_SERVER_ADDRESS "pool.ntp.org"
|
||||||
|
*/
|
||||||
|
uint32 sntp_get_current_timestamp();
|
||||||
|
char* sntp_get_real_time(long t);
|
||||||
|
|
||||||
|
void sntp_init(void);
|
||||||
|
void sntp_stop(void);
|
||||||
|
|
||||||
|
sint8 sntp_get_timezone(void);
|
||||||
|
bool sntp_set_timezone(sint8 timezone);
|
||||||
|
void sntp_setserver(u8_t idx, ip_addr_t *addr);
|
||||||
|
ip_addr_t sntp_getserver(u8_t idx);
|
||||||
|
|
||||||
|
#if SNTP_SERVER_DNS
|
||||||
|
void sntp_setservername(u8_t idx, char *server);
|
||||||
|
char *sntp_getservername(u8_t idx);
|
||||||
|
#endif /* SNTP_SERVER_DNS */
|
||||||
|
|
||||||
|
#if SNTP_GET_SERVERS_FROM_DHCP
|
||||||
|
void sntp_servermode_dhcp(int set_servers_from_dhcp);
|
||||||
|
#else /* SNTP_GET_SERVERS_FROM_DHCP */
|
||||||
|
#define sntp_servermode_dhcp(x)
|
||||||
|
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* LWIP_SNTP_H */
|
@ -113,7 +113,7 @@ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;
|
|||||||
#define TCP_HLEN 20
|
#define TCP_HLEN 20
|
||||||
|
|
||||||
#ifndef TCP_TMR_INTERVAL
|
#ifndef TCP_TMR_INTERVAL
|
||||||
#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */
|
#define TCP_TMR_INTERVAL 125 /* The TCP timer interval in milliseconds. */
|
||||||
#endif /* TCP_TMR_INTERVAL */
|
#endif /* TCP_TMR_INTERVAL */
|
||||||
|
|
||||||
#ifndef TCP_FAST_INTERVAL
|
#ifndef TCP_FAST_INTERVAL
|
||||||
@ -135,15 +135,15 @@ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;
|
|||||||
|
|
||||||
/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */
|
/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */
|
||||||
#ifndef TCP_KEEPIDLE_DEFAULT
|
#ifndef TCP_KEEPIDLE_DEFAULT
|
||||||
#define TCP_KEEPIDLE_DEFAULT 3000UL /* Default KEEPALIVE timer in milliseconds */
|
#define TCP_KEEPIDLE_DEFAULT 120000UL /* Default KEEPALIVE timer in milliseconds */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TCP_KEEPINTVL_DEFAULT
|
#ifndef TCP_KEEPINTVL_DEFAULT
|
||||||
#define TCP_KEEPINTVL_DEFAULT 1000UL /* Default Time between KEEPALIVE probes in milliseconds */
|
#define TCP_KEEPINTVL_DEFAULT 10000UL /* Default Time between KEEPALIVE probes in milliseconds */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TCP_KEEPCNT_DEFAULT
|
#ifndef TCP_KEEPCNT_DEFAULT
|
||||||
#define TCP_KEEPCNT_DEFAULT 3U /* Default Counter for KEEPALIVE probes */
|
#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */
|
#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */
|
||||||
@ -156,14 +156,14 @@ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;
|
|||||||
#endif
|
#endif
|
||||||
PACK_STRUCT_BEGIN
|
PACK_STRUCT_BEGIN
|
||||||
struct tcp_hdr {
|
struct tcp_hdr {
|
||||||
PACK_STRUCT_FIELD(u16_t src); //源端口
|
PACK_STRUCT_FIELD(u16_t src); //Դ<EFBFBD>˿<EFBFBD>
|
||||||
PACK_STRUCT_FIELD(u16_t dest); //目的端口
|
PACK_STRUCT_FIELD(u16_t dest); //Ŀ<EFBFBD>Ķ˿<EFBFBD>
|
||||||
PACK_STRUCT_FIELD(u32_t seqno); //序号
|
PACK_STRUCT_FIELD(u32_t seqno); //<EFBFBD><EFBFBD><EFBFBD>
|
||||||
PACK_STRUCT_FIELD(u32_t ackno); //应答序号
|
PACK_STRUCT_FIELD(u32_t ackno); //Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);//首部长度+保留位+标志位
|
PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);//<EFBFBD>ײ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+<2B><><EFBFBD><EFBFBD>λ+<2B><>־λ
|
||||||
PACK_STRUCT_FIELD(u16_t wnd); //窗口大小
|
PACK_STRUCT_FIELD(u16_t wnd); //<EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>С
|
||||||
PACK_STRUCT_FIELD(u16_t chksum); //校验和
|
PACK_STRUCT_FIELD(u16_t chksum); //У<EFBFBD><EFBFBD><EFBFBD>
|
||||||
PACK_STRUCT_FIELD(u16_t urgp); //紧急指针
|
PACK_STRUCT_FIELD(u16_t urgp); //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>
|
||||||
} PACK_STRUCT_STRUCT;
|
} PACK_STRUCT_STRUCT;
|
||||||
PACK_STRUCT_END
|
PACK_STRUCT_END
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
@ -38,10 +38,9 @@
|
|||||||
#ifndef __LWIPOPTS_H__
|
#ifndef __LWIPOPTS_H__
|
||||||
#define __LWIPOPTS_H__
|
#define __LWIPOPTS_H__
|
||||||
|
|
||||||
|
#define PBUF_RSV_FOR_WLAN
|
||||||
|
#define EBUF_LWIP
|
||||||
|
|
||||||
#define EBUF_LWIP 1
|
|
||||||
#define LWIP_ESP 1
|
|
||||||
#define EP_OFFSET 36
|
|
||||||
/*
|
/*
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
---------- Platform specific locking ----------
|
---------- Platform specific locking ----------
|
||||||
@ -245,7 +244,7 @@
|
|||||||
* (requires the LWIP_TCP option)
|
* (requires the LWIP_TCP option)
|
||||||
*/
|
*/
|
||||||
#ifndef MEMP_NUM_TCP_PCB
|
#ifndef MEMP_NUM_TCP_PCB
|
||||||
#define MEMP_NUM_TCP_PCB (*((volatile uint32*)0x600011FC))
|
#define MEMP_NUM_TCP_PCB (*(volatile uint32*)0x600011FC)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -308,7 +307,7 @@
|
|||||||
* (requires NO_SYS==0)
|
* (requires NO_SYS==0)
|
||||||
*/
|
*/
|
||||||
#ifndef MEMP_NUM_SYS_TIMEOUT
|
#ifndef MEMP_NUM_SYS_TIMEOUT
|
||||||
#define MEMP_NUM_SYS_TIMEOUT 6
|
#define MEMP_NUM_SYS_TIMEOUT 8
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -534,7 +533,7 @@
|
|||||||
* in this time, the whole packet is discarded.
|
* in this time, the whole packet is discarded.
|
||||||
*/
|
*/
|
||||||
#ifndef IP_REASS_MAXAGE
|
#ifndef IP_REASS_MAXAGE
|
||||||
#define IP_REASS_MAXAGE 0
|
#define IP_REASS_MAXAGE 3
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -544,7 +543,7 @@
|
|||||||
* packets even if the maximum amount of fragments is enqueued for reassembly!
|
* packets even if the maximum amount of fragments is enqueued for reassembly!
|
||||||
*/
|
*/
|
||||||
#ifndef IP_REASS_MAX_PBUFS
|
#ifndef IP_REASS_MAX_PBUFS
|
||||||
#define IP_REASS_MAX_PBUFS 0
|
#define IP_REASS_MAX_PBUFS 10
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -633,7 +632,7 @@
|
|||||||
* LWIP_RAW==1: Enable application layer to hook into the IP layer itself.
|
* LWIP_RAW==1: Enable application layer to hook into the IP layer itself.
|
||||||
*/
|
*/
|
||||||
#ifndef LWIP_RAW
|
#ifndef LWIP_RAW
|
||||||
#define LWIP_RAW 0
|
#define LWIP_RAW 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -662,6 +661,13 @@
|
|||||||
#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP))
|
#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DHCP_MAXRTX: Maximum number of retries of current request.
|
||||||
|
*/
|
||||||
|
#ifndef DHCP_MAXRTX
|
||||||
|
#define DHCP_MAXRTX (*(volatile uint32*)0x600011E0)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
------------------------------------
|
------------------------------------
|
||||||
---------- AUTOIP options ----------
|
---------- AUTOIP options ----------
|
||||||
@ -774,6 +780,17 @@
|
|||||||
#ifndef LWIP_IGMP
|
#ifndef LWIP_IGMP
|
||||||
#define LWIP_IGMP 1
|
#define LWIP_IGMP 1
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
|
----------------------------------
|
||||||
|
---------- MDNS options ----------
|
||||||
|
----------------------------------
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* LWIP_MDNS==1: Turn on MDNS module.
|
||||||
|
*/
|
||||||
|
#ifndef LWIP_MDNS
|
||||||
|
#define LWIP_MDNS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
----------------------------------
|
----------------------------------
|
||||||
@ -890,21 +907,35 @@
|
|||||||
* (2 * TCP_MSS) for things to work well
|
* (2 * TCP_MSS) for things to work well
|
||||||
*/
|
*/
|
||||||
#ifndef TCP_WND
|
#ifndef TCP_WND
|
||||||
#define TCP_WND (4 * TCP_MSS)
|
#define TCP_WND (*(volatile uint32*)0x600011F0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TCP_MAXRTX: Maximum number of retransmissions of data segments.
|
* TCP_MAXRTX: Maximum number of retransmissions of data segments.
|
||||||
*/
|
*/
|
||||||
#ifndef TCP_MAXRTX
|
#ifndef TCP_MAXRTX
|
||||||
#define TCP_MAXRTX 5
|
#define TCP_MAXRTX (*(volatile uint32*)0x600011E8)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments.
|
* TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments.
|
||||||
*/
|
*/
|
||||||
#ifndef TCP_SYNMAXRTX
|
#ifndef TCP_SYNMAXRTX
|
||||||
#define TCP_SYNMAXRTX 5
|
#define TCP_SYNMAXRTX (*(volatile uint32*)0x600011E4)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TCP_MAXRTO: Maximum retransmission timeout of data segments.
|
||||||
|
*/
|
||||||
|
#ifndef TCP_MAXRTO
|
||||||
|
#define TCP_MAXRTO 10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TCP_MINRTO: Minimum retransmission timeout of data segments.
|
||||||
|
*/
|
||||||
|
#ifndef TCP_MINRTO
|
||||||
|
#define TCP_MINRTO 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -912,9 +943,10 @@
|
|||||||
* Define to 0 if your device is low on memory.
|
* Define to 0 if your device is low on memory.
|
||||||
*/
|
*/
|
||||||
#ifndef TCP_QUEUE_OOSEQ
|
#ifndef TCP_QUEUE_OOSEQ
|
||||||
#define TCP_QUEUE_OOSEQ 0
|
#define TCP_QUEUE_OOSEQ 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
/**
|
/**
|
||||||
* TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default,
|
* TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default,
|
||||||
* you might want to increase this.)
|
* you might want to increase this.)
|
||||||
@ -925,6 +957,7 @@
|
|||||||
#ifndef TCP_MSS
|
#ifndef TCP_MSS
|
||||||
#define TCP_MSS 1460
|
#define TCP_MSS 1460
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really
|
* TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really
|
||||||
@ -1070,7 +1103,7 @@
|
|||||||
* field.
|
* field.
|
||||||
*/
|
*/
|
||||||
#ifndef LWIP_NETIF_HOSTNAME
|
#ifndef LWIP_NETIF_HOSTNAME
|
||||||
#define LWIP_NETIF_HOSTNAME 0
|
#define LWIP_NETIF_HOSTNAME 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
254
tools/sdk/lwip/include/netif/etharp.h
Normal file
254
tools/sdk/lwip/include/netif/etharp.h
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||||
|
* Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
|
||||||
|
* Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NETIF_ETHARP_H__
|
||||||
|
#define __NETIF_ETHARP_H__
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/pbuf.h"
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
#include "lwip/ip.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ETHARP_HWADDR_LEN
|
||||||
|
#define ETHARP_HWADDR_LEN 6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/bpstruct.h"
|
||||||
|
#endif
|
||||||
|
PACK_STRUCT_BEGIN
|
||||||
|
struct eth_addr {
|
||||||
|
PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);
|
||||||
|
} PACK_STRUCT_STRUCT;
|
||||||
|
PACK_STRUCT_END
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/epstruct.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/bpstruct.h"
|
||||||
|
#endif
|
||||||
|
PACK_STRUCT_BEGIN
|
||||||
|
/** Ethernet header */
|
||||||
|
struct eth_hdr {
|
||||||
|
#if ETH_PAD_SIZE
|
||||||
|
PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
|
||||||
|
#endif
|
||||||
|
PACK_STRUCT_FIELD(struct eth_addr dest);
|
||||||
|
PACK_STRUCT_FIELD(struct eth_addr src);
|
||||||
|
PACK_STRUCT_FIELD(u16_t type);
|
||||||
|
} PACK_STRUCT_STRUCT;
|
||||||
|
PACK_STRUCT_END
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/epstruct.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
|
||||||
|
|
||||||
|
#if ETHARP_SUPPORT_VLAN
|
||||||
|
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/bpstruct.h"
|
||||||
|
#endif
|
||||||
|
PACK_STRUCT_BEGIN
|
||||||
|
/** VLAN header inserted between ethernet header and payload
|
||||||
|
* if 'type' in ethernet header is ETHTYPE_VLAN.
|
||||||
|
* See IEEE802.Q */
|
||||||
|
struct eth_vlan_hdr {
|
||||||
|
PACK_STRUCT_FIELD(u16_t tpid);
|
||||||
|
PACK_STRUCT_FIELD(u16_t prio_vid);
|
||||||
|
} PACK_STRUCT_STRUCT;
|
||||||
|
PACK_STRUCT_END
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/epstruct.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SIZEOF_VLAN_HDR 4
|
||||||
|
#define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF)
|
||||||
|
|
||||||
|
#endif /* ETHARP_SUPPORT_VLAN */
|
||||||
|
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/bpstruct.h"
|
||||||
|
#endif
|
||||||
|
PACK_STRUCT_BEGIN
|
||||||
|
/** the ARP message, see RFC 826 ("Packet format") */
|
||||||
|
struct etharp_hdr {
|
||||||
|
PACK_STRUCT_FIELD(u16_t hwtype);
|
||||||
|
PACK_STRUCT_FIELD(u16_t proto);
|
||||||
|
PACK_STRUCT_FIELD(u8_t hwlen);
|
||||||
|
PACK_STRUCT_FIELD(u8_t protolen);
|
||||||
|
PACK_STRUCT_FIELD(u16_t opcode);
|
||||||
|
PACK_STRUCT_FIELD(struct eth_addr shwaddr);
|
||||||
|
PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);
|
||||||
|
PACK_STRUCT_FIELD(struct eth_addr dhwaddr);
|
||||||
|
PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);
|
||||||
|
} PACK_STRUCT_STRUCT;
|
||||||
|
PACK_STRUCT_END
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/epstruct.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SIZEOF_ETHARP_HDR 28
|
||||||
|
#define SIZEOF_ETHARP_MINSIZE 46
|
||||||
|
#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR)
|
||||||
|
#define SIZEOF_ETHARP_WITHPAD (SIZEOF_ETH_HDR + SIZEOF_ETHARP_MINSIZE)
|
||||||
|
|
||||||
|
/** 5 seconds period */
|
||||||
|
#define ARP_TMR_INTERVAL 5000
|
||||||
|
|
||||||
|
#define ETHTYPE_ARP 0x0806
|
||||||
|
#define ETHTYPE_IP 0x0800
|
||||||
|
#define ETHTYPE_VLAN 0x8100
|
||||||
|
#define ETHTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */
|
||||||
|
#define ETHTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */
|
||||||
|
#define ETHTYPE_PAE 0x888e
|
||||||
|
|
||||||
|
/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables
|
||||||
|
* or known to be 32-bit aligned within the protocol header. */
|
||||||
|
#ifndef ETHADDR32_COPY
|
||||||
|
#define ETHADDR32_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local
|
||||||
|
* variables and known to be 16-bit aligned within the protocol header. */
|
||||||
|
#ifndef ETHADDR16_COPY
|
||||||
|
#define ETHADDR16_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
/** ARP message types (opcodes) */
|
||||||
|
#define ARP_REQUEST 1
|
||||||
|
#define ARP_REPLY 2
|
||||||
|
|
||||||
|
/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type)
|
||||||
|
* to a filter function that returns the correct netif when using multiple
|
||||||
|
* netifs on one hardware interface where the netif's low-level receive
|
||||||
|
* routine cannot decide for the correct netif (e.g. when mapping multiple
|
||||||
|
* IP addresses to one hardware interface).
|
||||||
|
*/
|
||||||
|
#ifndef LWIP_ARP_FILTER_NETIF
|
||||||
|
#define LWIP_ARP_FILTER_NETIF 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ARP_QUEUEING
|
||||||
|
/** struct for queueing outgoing packets for unknown address
|
||||||
|
* defined here to be accessed by memp.h
|
||||||
|
*/
|
||||||
|
struct etharp_q_entry {
|
||||||
|
struct etharp_q_entry *next;
|
||||||
|
struct pbuf *p;
|
||||||
|
};
|
||||||
|
#endif /* ARP_QUEUEING */
|
||||||
|
|
||||||
|
#define etharp_init() /* Compatibility define, not init needed. */
|
||||||
|
void etharp_tmr(void)ICACHE_FLASH_ATTR;
|
||||||
|
s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
|
||||||
|
struct eth_addr **eth_ret, ip_addr_t **ip_ret)ICACHE_FLASH_ATTR;
|
||||||
|
err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;
|
||||||
|
err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)ICACHE_FLASH_ATTR;
|
||||||
|
err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;
|
||||||
|
/** For Ethernet network interfaces, we might want to send "gratuitous ARP";
|
||||||
|
* this is an ARP packet sent by a node in order to spontaneously cause other
|
||||||
|
* nodes to update an entry in their ARP cache.
|
||||||
|
* From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */
|
||||||
|
#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr)
|
||||||
|
void etharp_cleanup_netif(struct netif *netif);
|
||||||
|
|
||||||
|
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||||
|
err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)ICACHE_FLASH_ATTR;
|
||||||
|
err_t etharp_remove_static_entry(ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;
|
||||||
|
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||||
|
|
||||||
|
#if LWIP_AUTOIP
|
||||||
|
err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
|
||||||
|
const struct eth_addr *ethdst_addr,
|
||||||
|
const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr,
|
||||||
|
const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr,
|
||||||
|
const u16_t opcode)ICACHE_FLASH_ATTR;
|
||||||
|
#endif /* LWIP_AUTOIP */
|
||||||
|
|
||||||
|
#endif /* LWIP_ARP */
|
||||||
|
|
||||||
|
err_t ethernet_input(struct pbuf *p, struct netif *netif)ICACHE_FLASH_ATTR;
|
||||||
|
|
||||||
|
#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0)
|
||||||
|
|
||||||
|
extern const struct eth_addr ethbroadcast, ethzero;
|
||||||
|
|
||||||
|
#endif /* LWIP_ARP || LWIP_ETHERNET */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/** Ethernet header */
|
||||||
|
#ifndef ETHARP_HWADDR_LEN
|
||||||
|
#define ETHARP_HWADDR_LEN 6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct eth_addr {
|
||||||
|
PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);
|
||||||
|
} PACK_STRUCT_STRUCT;
|
||||||
|
|
||||||
|
|
||||||
|
struct eth_hdr {
|
||||||
|
#if ETH_PAD_SIZE
|
||||||
|
PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
|
||||||
|
#endif
|
||||||
|
PACK_STRUCT_FIELD(struct eth_addr dest);
|
||||||
|
PACK_STRUCT_FIELD(struct eth_addr src);
|
||||||
|
PACK_STRUCT_FIELD(u16_t type);
|
||||||
|
} PACK_STRUCT_STRUCT;
|
||||||
|
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/epstruct.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __NETIF_ARP_H__ */
|
173
tools/sdk/lwip/include/netif/if_llc.h
Normal file
173
tools/sdk/lwip/include/netif/if_llc.h
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
/* $NetBSD: if_llc.h,v 1.12 1999/11/19 20:41:19 thorpej Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1988, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)if_llc.h 8.1 (Berkeley) 6/10/93
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NET_IF_LLC_H_
|
||||||
|
#define _NET_IF_LLC_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IEEE 802.2 Link Level Control headers, for use in conjunction with
|
||||||
|
* 802.{3,4,5} media access control methods.
|
||||||
|
*
|
||||||
|
* Headers here do not use bit fields due to shortcommings in many
|
||||||
|
* compilers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct llc {
|
||||||
|
uint8_t llc_dsap;
|
||||||
|
uint8_t llc_ssap;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint8_t control;
|
||||||
|
uint8_t format_id;
|
||||||
|
uint8_t class;
|
||||||
|
uint8_t window_x2;
|
||||||
|
} __packed type_u;
|
||||||
|
struct {
|
||||||
|
uint8_t num_snd_x2;
|
||||||
|
uint8_t num_rcv_x2;
|
||||||
|
} __packed type_i;
|
||||||
|
struct {
|
||||||
|
uint8_t control;
|
||||||
|
uint8_t num_rcv_x2;
|
||||||
|
} __packed type_s;
|
||||||
|
struct {
|
||||||
|
uint8_t control;
|
||||||
|
/*
|
||||||
|
* We cannot put the following fields in a structure because
|
||||||
|
* the structure rounding might cause padding.
|
||||||
|
*/
|
||||||
|
uint8_t frmr_rej_pdu0;
|
||||||
|
uint8_t frmr_rej_pdu1;
|
||||||
|
uint8_t frmr_control;
|
||||||
|
uint8_t frmr_control_ext;
|
||||||
|
uint8_t frmr_cause;
|
||||||
|
} __packed type_frmr;
|
||||||
|
struct {
|
||||||
|
uint8_t control;
|
||||||
|
uint8_t org_code[3];
|
||||||
|
uint16_t ether_type;
|
||||||
|
} __packed type_snap;
|
||||||
|
struct {
|
||||||
|
uint8_t control;
|
||||||
|
uint8_t control_ext;
|
||||||
|
} __packed type_raw;
|
||||||
|
} __packed llc_un;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct frmrinfo {
|
||||||
|
uint8_t frmr_rej_pdu0;
|
||||||
|
uint8_t frmr_rej_pdu1;
|
||||||
|
uint8_t frmr_control;
|
||||||
|
uint8_t frmr_control_ext;
|
||||||
|
uint8_t frmr_cause;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define llc_control llc_un.type_u.control
|
||||||
|
#define llc_control_ext llc_un.type_raw.control_ext
|
||||||
|
#define llc_fid llc_un.type_u.format_id
|
||||||
|
#define llc_class llc_un.type_u.class
|
||||||
|
#define llc_window llc_un.type_u.window_x2
|
||||||
|
#define llc_frmrinfo llc_un.type_frmr.frmr_rej_pdu0
|
||||||
|
#define llc_frmr_pdu0 llc_un.type_frmr.frmr_rej_pdu0
|
||||||
|
#define llc_frmr_pdu1 llc_un.type_frmr.frmr_rej_pdu1
|
||||||
|
#define llc_frmr_control llc_un.type_frmr.frmr_control
|
||||||
|
#define llc_frmr_control_ext llc_un.type_frmr.frmr_control_ext
|
||||||
|
#define llc_frmr_cause llc_un.type_frmr.frmr_cause
|
||||||
|
#define llc_snap llc_un.type_snap
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't use sizeof(struct llc_un) for LLC header sizes
|
||||||
|
*/
|
||||||
|
#define LLC_ISFRAMELEN 4
|
||||||
|
#define LLC_UFRAMELEN 3
|
||||||
|
#define LLC_FRMRLEN 7
|
||||||
|
#define LLC_SNAPFRAMELEN 8
|
||||||
|
|
||||||
|
#ifdef CTASSERT
|
||||||
|
CTASSERT(sizeof (struct llc) == LLC_SNAPFRAMELEN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unnumbered LLC format commands
|
||||||
|
*/
|
||||||
|
#define LLC_UI 0x3
|
||||||
|
#define LLC_UI_P 0x13
|
||||||
|
#define LLC_DISC 0x43
|
||||||
|
#define LLC_DISC_P 0x53
|
||||||
|
#define LLC_UA 0x63
|
||||||
|
#define LLC_UA_P 0x73
|
||||||
|
#define LLC_TEST 0xe3
|
||||||
|
#define LLC_TEST_P 0xf3
|
||||||
|
#define LLC_FRMR 0x87
|
||||||
|
#define LLC_FRMR_P 0x97
|
||||||
|
#define LLC_DM 0x0f
|
||||||
|
#define LLC_DM_P 0x1f
|
||||||
|
#define LLC_XID 0xaf
|
||||||
|
#define LLC_XID_P 0xbf
|
||||||
|
#define LLC_SABME 0x6f
|
||||||
|
#define LLC_SABME_P 0x7f
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Supervisory LLC commands
|
||||||
|
*/
|
||||||
|
#define LLC_RR 0x01
|
||||||
|
#define LLC_RNR 0x05
|
||||||
|
#define LLC_REJ 0x09
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Info format - dummy only
|
||||||
|
*/
|
||||||
|
#define LLC_INFO 0x00
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ISO PDTR 10178 contains among others
|
||||||
|
*/
|
||||||
|
#define LLC_8021D_LSAP 0x42
|
||||||
|
#define LLC_X25_LSAP 0x7e
|
||||||
|
#define LLC_SNAP_LSAP 0xaa
|
||||||
|
#define LLC_ISO_LSAP 0xfe
|
||||||
|
|
||||||
|
#define RFC1042_LEN 6
|
||||||
|
#define RFC1042 {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00}
|
||||||
|
#define ETHERNET_TUNNEL {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* copied from sys/net/ethernet.h
|
||||||
|
*/
|
||||||
|
#define ETHERTYPE_AARP 0x80F3 /* AppleTalk AARP */
|
||||||
|
#define ETHERTYPE_IPX 0x8137 /* Novell (old) NetWare IPX (ECONFIG E option) */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _NET_IF_LLC_H_ */
|
190
tools/sdk/lwip/include/netif/ppp_oe.h
Normal file
190
tools/sdk/lwip/include/netif/ppp_oe.h
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* ppp_oe.h - PPP Over Ethernet implementation for lwIP.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.
|
||||||
|
*
|
||||||
|
* The authors hereby grant permission to use, copy, modify, distribute,
|
||||||
|
* and license this software and its documentation for any purpose, provided
|
||||||
|
* that existing copyright notices are retained in all copies and that this
|
||||||
|
* notice and the following disclaimer are included verbatim in any
|
||||||
|
* distributions. No written agreement, license, or royalty fee is required
|
||||||
|
* for any of the authorized uses.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
* REVISION HISTORY
|
||||||
|
*
|
||||||
|
* 06-01-01 Marc Boucher <marc@mbsi.ca>
|
||||||
|
* Ported to lwIP.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
|
* by Martin Husemann <martin@NetBSD.org>.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the NetBSD
|
||||||
|
* Foundation, Inc. and its contributors.
|
||||||
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef PPP_OE_H
|
||||||
|
#define PPP_OE_H
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if PPPOE_SUPPORT > 0
|
||||||
|
|
||||||
|
#include "netif/etharp.h"
|
||||||
|
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/bpstruct.h"
|
||||||
|
#endif
|
||||||
|
PACK_STRUCT_BEGIN
|
||||||
|
struct pppoehdr {
|
||||||
|
PACK_STRUCT_FIELD(u8_t vertype);
|
||||||
|
PACK_STRUCT_FIELD(u8_t code);
|
||||||
|
PACK_STRUCT_FIELD(u16_t session);
|
||||||
|
PACK_STRUCT_FIELD(u16_t plen);
|
||||||
|
} PACK_STRUCT_STRUCT;
|
||||||
|
PACK_STRUCT_END
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/epstruct.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/bpstruct.h"
|
||||||
|
#endif
|
||||||
|
PACK_STRUCT_BEGIN
|
||||||
|
struct pppoetag {
|
||||||
|
PACK_STRUCT_FIELD(u16_t tag);
|
||||||
|
PACK_STRUCT_FIELD(u16_t len);
|
||||||
|
} PACK_STRUCT_STRUCT;
|
||||||
|
PACK_STRUCT_END
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/epstruct.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define PPPOE_STATE_INITIAL 0
|
||||||
|
#define PPPOE_STATE_PADI_SENT 1
|
||||||
|
#define PPPOE_STATE_PADR_SENT 2
|
||||||
|
#define PPPOE_STATE_SESSION 3
|
||||||
|
#define PPPOE_STATE_CLOSING 4
|
||||||
|
/* passive */
|
||||||
|
#define PPPOE_STATE_PADO_SENT 1
|
||||||
|
|
||||||
|
#define PPPOE_HEADERLEN sizeof(struct pppoehdr)
|
||||||
|
#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */
|
||||||
|
|
||||||
|
#define PPPOE_TAG_EOL 0x0000 /* end of list */
|
||||||
|
#define PPPOE_TAG_SNAME 0x0101 /* service name */
|
||||||
|
#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */
|
||||||
|
#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */
|
||||||
|
#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */
|
||||||
|
#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */
|
||||||
|
#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */
|
||||||
|
#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */
|
||||||
|
#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */
|
||||||
|
#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */
|
||||||
|
|
||||||
|
#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */
|
||||||
|
#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */
|
||||||
|
#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */
|
||||||
|
#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */
|
||||||
|
#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */
|
||||||
|
|
||||||
|
#ifndef ETHERMTU
|
||||||
|
#define ETHERMTU 1500
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* two byte PPP protocol discriminator, then IP data */
|
||||||
|
#define PPPOE_MAXMTU (ETHERMTU-PPPOE_HEADERLEN-2)
|
||||||
|
|
||||||
|
#ifndef PPPOE_MAX_AC_COOKIE_LEN
|
||||||
|
#define PPPOE_MAX_AC_COOKIE_LEN 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct pppoe_softc {
|
||||||
|
struct pppoe_softc *next;
|
||||||
|
struct netif *sc_ethif; /* ethernet interface we are using */
|
||||||
|
int sc_pd; /* ppp unit number */
|
||||||
|
void (*sc_linkStatusCB)(int pd, int up);
|
||||||
|
|
||||||
|
int sc_state; /* discovery phase or session connected */
|
||||||
|
struct eth_addr sc_dest; /* hardware address of concentrator */
|
||||||
|
u16_t sc_session; /* PPPoE session id */
|
||||||
|
|
||||||
|
#ifdef PPPOE_TODO
|
||||||
|
char *sc_service_name; /* if != NULL: requested name of service */
|
||||||
|
char *sc_concentrator_name; /* if != NULL: requested concentrator id */
|
||||||
|
#endif /* PPPOE_TODO */
|
||||||
|
u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */
|
||||||
|
size_t sc_ac_cookie_len; /* length of cookie data */
|
||||||
|
#ifdef PPPOE_SERVER
|
||||||
|
u8_t *sc_hunique; /* content of host unique we must echo back */
|
||||||
|
size_t sc_hunique_len; /* length of host unique */
|
||||||
|
#endif
|
||||||
|
int sc_padi_retried; /* number of PADI retries already done */
|
||||||
|
int sc_padr_retried; /* number of PADR retries already done */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define pppoe_init() /* compatibility define, no initialization needed */
|
||||||
|
|
||||||
|
err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr);
|
||||||
|
err_t pppoe_destroy(struct netif *ifp);
|
||||||
|
|
||||||
|
int pppoe_connect(struct pppoe_softc *sc);
|
||||||
|
void pppoe_disconnect(struct pppoe_softc *sc);
|
||||||
|
|
||||||
|
void pppoe_disc_input(struct netif *netif, struct pbuf *p);
|
||||||
|
void pppoe_data_input(struct netif *netif, struct pbuf *p);
|
||||||
|
|
||||||
|
err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb);
|
||||||
|
|
||||||
|
/** used in ppp.c */
|
||||||
|
#define PPPOE_HDRLEN (sizeof(struct eth_hdr) + PPPOE_HEADERLEN)
|
||||||
|
|
||||||
|
#endif /* PPPOE_SUPPORT */
|
||||||
|
|
||||||
|
#endif /* PPP_OE_H */
|
25
tools/sdk/lwip/include/netif/wlan_lwip_if.h
Normal file
25
tools/sdk/lwip/include/netif/wlan_lwip_if.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 Espressif System
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _WLAN_LWIP_IF_H_
|
||||||
|
#define _WLAN_LWIP_IF_H_
|
||||||
|
|
||||||
|
#define LWIP_IF0_PRIO 28
|
||||||
|
#define LWIP_IF1_PRIO 29
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SIG_LWIP_RX = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct netif * eagle_lwip_if_alloc(struct ieee80211_conn *conn, const uint8 *macaddr, struct ip_info *info);
|
||||||
|
struct netif * eagle_lwip_getif(uint8 index);
|
||||||
|
|
||||||
|
#ifndef IOT_SIP_MODE
|
||||||
|
sint8 ieee80211_output_pbuf(struct netif *ifp, struct pbuf* pb);
|
||||||
|
#else
|
||||||
|
sint8 ieee80211_output_pbuf(struct ieee80211_conn *conn, esf_buf *eb);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _WLAN_LWIP_IF_H_ */
|
32
tools/sdk/lwip/src/Makefile
Normal file
32
tools/sdk/lwip/src/Makefile
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
TOOLS_PATH ?= ../../../xtensa-lx106-elf/bin/xtensa-lx106-elf-
|
||||||
|
LWIP_LIB ?= liblwip_src.a
|
||||||
|
SDK_PATH ?= $(abspath ../../)
|
||||||
|
|
||||||
|
BUILD_PATH = build
|
||||||
|
LWIP_SRCS = $(patsubst %.c,$(BUILD_PATH)/%.o,$(wildcard */*.c)) $(patsubst %.c,$(BUILD_PATH)/%.o,$(wildcard */*/*.c))
|
||||||
|
|
||||||
|
LWIP_INCLUDE = -Ibuild -I$(SDK_PATH)/include -I$(SDK_PATH)/lwip/include
|
||||||
|
BUILD_FLAGS = -c -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections
|
||||||
|
BUILD_DEFINES = -D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ -DLWIP_OPEN_SRC
|
||||||
|
|
||||||
|
CC=$(TOOLS_PATH)gcc
|
||||||
|
AR=$(TOOLS_PATH)ar
|
||||||
|
|
||||||
|
$(BUILD_PATH)/%.h:
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
@touch $@
|
||||||
|
|
||||||
|
$(BUILD_PATH)/%.o: %.c
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
$(CC) $(BUILD_FLAGS) $(BUILD_DEFINES) $(LWIP_INCLUDE) $< -o $@
|
||||||
|
|
||||||
|
$(LWIP_LIB): $(BUILD_PATH)/user_config.h $(LWIP_SRCS)
|
||||||
|
$(AR) cru $(LWIP_LIB) $(LWIP_SRCS)
|
||||||
|
|
||||||
|
all: $(LWIP_LIB)
|
||||||
|
|
||||||
|
install: all
|
||||||
|
cp -f $(LWIP_LIB) $(SDK_PATH)/lib/$(LWIP_LIB)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -rf $(BUILD_PATH) $(LWIP_LIB)
|
740
tools/sdk/lwip/src/api/api_lib.c
Normal file
740
tools/sdk/lwip/src/api/api_lib.c
Normal file
@ -0,0 +1,740 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Sequential API External module
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This is the part of the API that is linked with
|
||||||
|
the application */
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/api.h"
|
||||||
|
#include "lwip/tcpip.h"
|
||||||
|
#include "lwip/memp.h"
|
||||||
|
|
||||||
|
#include "lwip/ip.h"
|
||||||
|
#include "lwip/raw.h"
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "lwip/tcp.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new netconn (of a specific type) that has a callback function.
|
||||||
|
* The corresponding pcb is also created.
|
||||||
|
*
|
||||||
|
* @param t the type of 'connection' to create (@see enum netconn_type)
|
||||||
|
* @param proto the IP protocol for RAW IP pcbs
|
||||||
|
* @param callback a function to call on status changes (RX available, TX'ed)
|
||||||
|
* @return a newly allocated struct netconn or
|
||||||
|
* NULL on memory error
|
||||||
|
*/
|
||||||
|
struct netconn*
|
||||||
|
netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
|
||||||
|
{
|
||||||
|
struct netconn *conn;
|
||||||
|
struct api_msg msg;
|
||||||
|
|
||||||
|
conn = netconn_alloc(t, callback);
|
||||||
|
if (conn != NULL) {
|
||||||
|
msg.function = do_newconn;
|
||||||
|
msg.msg.msg.n.proto = proto;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
if (TCPIP_APIMSG(&msg) != ERR_OK) {
|
||||||
|
LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
|
||||||
|
LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
|
||||||
|
LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
|
||||||
|
#if LWIP_TCP
|
||||||
|
LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
|
sys_sem_free(&conn->op_completed);
|
||||||
|
sys_mbox_free(&conn->recvmbox);
|
||||||
|
memp_free(MEMP_NETCONN, conn);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a netconn 'connection' and free its resources.
|
||||||
|
* UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
|
||||||
|
* after this returns.
|
||||||
|
*
|
||||||
|
* @param conn the netconn to delete
|
||||||
|
* @return ERR_OK if the connection was deleted
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_delete(struct netconn *conn)
|
||||||
|
{
|
||||||
|
struct api_msg msg;
|
||||||
|
|
||||||
|
/* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
|
||||||
|
if (conn == NULL) {
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.function = do_delconn;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
tcpip_apimsg(&msg);
|
||||||
|
|
||||||
|
netconn_free(conn);
|
||||||
|
|
||||||
|
/* don't care for return value of do_delconn since it only calls void functions */
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the local or remote IP address and port of a netconn.
|
||||||
|
* For RAW netconns, this returns the protocol instead of a port!
|
||||||
|
*
|
||||||
|
* @param conn the netconn to query
|
||||||
|
* @param addr a pointer to which to save the IP address
|
||||||
|
* @param port a pointer to which to save the port (or protocol for RAW)
|
||||||
|
* @param local 1 to get the local IP address, 0 to get the remote one
|
||||||
|
* @return ERR_CONN for invalid connections
|
||||||
|
* ERR_OK if the information was retrieved
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
|
||||||
|
{
|
||||||
|
struct api_msg msg;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
|
||||||
|
LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
|
||||||
|
|
||||||
|
msg.function = do_getaddr;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
msg.msg.msg.ad.ipaddr = addr;
|
||||||
|
msg.msg.msg.ad.port = port;
|
||||||
|
msg.msg.msg.ad.local = local;
|
||||||
|
err = TCPIP_APIMSG(&msg);
|
||||||
|
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a netconn to a specific local IP address and port.
|
||||||
|
* Binding one netconn twice might not always be checked correctly!
|
||||||
|
*
|
||||||
|
* @param conn the netconn to bind
|
||||||
|
* @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY
|
||||||
|
* to bind to all addresses)
|
||||||
|
* @param port the local port to bind the netconn to (not used for RAW)
|
||||||
|
* @return ERR_OK if bound, any other err_t on failure
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)
|
||||||
|
{
|
||||||
|
struct api_msg msg;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
|
||||||
|
msg.function = do_bind;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
msg.msg.msg.bc.ipaddr = addr;
|
||||||
|
msg.msg.msg.bc.port = port;
|
||||||
|
err = TCPIP_APIMSG(&msg);
|
||||||
|
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect a netconn to a specific remote IP address and port.
|
||||||
|
*
|
||||||
|
* @param conn the netconn to connect
|
||||||
|
* @param addr the remote IP address to connect to
|
||||||
|
* @param port the remote port to connect to (no used for RAW)
|
||||||
|
* @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)
|
||||||
|
{
|
||||||
|
struct api_msg msg;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
|
||||||
|
msg.function = do_connect;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
msg.msg.msg.bc.ipaddr = addr;
|
||||||
|
msg.msg.msg.bc.port = port;
|
||||||
|
/* This is the only function which need to not block tcpip_thread */
|
||||||
|
err = tcpip_apimsg(&msg);
|
||||||
|
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect a netconn from its current peer (only valid for UDP netconns).
|
||||||
|
*
|
||||||
|
* @param conn the netconn to disconnect
|
||||||
|
* @return TODO: return value is not set here...
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_disconnect(struct netconn *conn)
|
||||||
|
{
|
||||||
|
struct api_msg msg;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
|
||||||
|
msg.function = do_disconnect;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
err = TCPIP_APIMSG(&msg);
|
||||||
|
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a TCP netconn into listen mode
|
||||||
|
*
|
||||||
|
* @param conn the tcp netconn to set to listen mode
|
||||||
|
* @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
|
||||||
|
* @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
|
||||||
|
* don't return any error (yet?))
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
|
||||||
|
{
|
||||||
|
#if LWIP_TCP
|
||||||
|
struct api_msg msg;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
/* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
|
||||||
|
LWIP_UNUSED_ARG(backlog);
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
|
||||||
|
msg.function = do_listen;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
#if TCP_LISTEN_BACKLOG
|
||||||
|
msg.msg.msg.lb.backlog = backlog;
|
||||||
|
#endif /* TCP_LISTEN_BACKLOG */
|
||||||
|
err = TCPIP_APIMSG(&msg);
|
||||||
|
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, err);
|
||||||
|
return err;
|
||||||
|
#else /* LWIP_TCP */
|
||||||
|
LWIP_UNUSED_ARG(conn);
|
||||||
|
LWIP_UNUSED_ARG(backlog);
|
||||||
|
return ERR_ARG;
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accept a new connection on a TCP listening netconn.
|
||||||
|
*
|
||||||
|
* @param conn the TCP listen netconn
|
||||||
|
* @param new_conn pointer where the new connection is stored
|
||||||
|
* @return ERR_OK if a new connection has been received or an error
|
||||||
|
* code otherwise
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_accept(struct netconn *conn, struct netconn **new_conn)
|
||||||
|
{
|
||||||
|
#if LWIP_TCP
|
||||||
|
struct netconn *newconn;
|
||||||
|
err_t err;
|
||||||
|
#if TCP_LISTEN_BACKLOG
|
||||||
|
struct api_msg msg;
|
||||||
|
#endif /* TCP_LISTEN_BACKLOG */
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
|
||||||
|
*new_conn = NULL;
|
||||||
|
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;);
|
||||||
|
|
||||||
|
err = conn->last_err;
|
||||||
|
if (ERR_IS_FATAL(err)) {
|
||||||
|
/* don't recv on fatal errors: this might block the application task
|
||||||
|
waiting on acceptmbox forever! */
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_SO_RCVTIMEO
|
||||||
|
if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
|
||||||
|
return ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);
|
||||||
|
#endif /* LWIP_SO_RCVTIMEO*/
|
||||||
|
/* Register event with callback */
|
||||||
|
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
|
||||||
|
|
||||||
|
if (newconn == NULL) {
|
||||||
|
/* connection has been closed */
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
|
||||||
|
return ERR_CLSD;
|
||||||
|
}
|
||||||
|
#if TCP_LISTEN_BACKLOG
|
||||||
|
/* Let the stack know that we have accepted the connection. */
|
||||||
|
msg.function = do_recv;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
/* don't care for the return value of do_recv */
|
||||||
|
TCPIP_APIMSG(&msg);
|
||||||
|
#endif /* TCP_LISTEN_BACKLOG */
|
||||||
|
|
||||||
|
*new_conn = newconn;
|
||||||
|
/* don't set conn->last_err: it's only ERR_OK, anyway */
|
||||||
|
return ERR_OK;
|
||||||
|
#else /* LWIP_TCP */
|
||||||
|
LWIP_UNUSED_ARG(conn);
|
||||||
|
LWIP_UNUSED_ARG(new_conn);
|
||||||
|
return ERR_ARG;
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive data: actual implementation that doesn't care whether pbuf or netbuf
|
||||||
|
* is received
|
||||||
|
*
|
||||||
|
* @param conn the netconn from which to receive data
|
||||||
|
* @param new_buf pointer where a new pbuf/netbuf is stored when received data
|
||||||
|
* @return ERR_OK if data has been received, an error code otherwise (timeout,
|
||||||
|
* memory error or another error)
|
||||||
|
*/
|
||||||
|
static err_t
|
||||||
|
netconn_recv_data(struct netconn *conn, void **new_buf)
|
||||||
|
{
|
||||||
|
void *buf = NULL;
|
||||||
|
u16_t len;
|
||||||
|
err_t err;
|
||||||
|
#if LWIP_TCP
|
||||||
|
struct api_msg msg;
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
|
||||||
|
*new_buf = NULL;
|
||||||
|
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
|
||||||
|
|
||||||
|
err = conn->last_err;
|
||||||
|
if (ERR_IS_FATAL(err)) {
|
||||||
|
/* don't recv on fatal errors: this might block the application task
|
||||||
|
waiting on recvmbox forever! */
|
||||||
|
/* @todo: this does not allow us to fetch data that has been put into recvmbox
|
||||||
|
before the fatal error occurred - is that a problem? */
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_SO_RCVTIMEO
|
||||||
|
if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
|
||||||
|
return ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
|
||||||
|
#endif /* LWIP_SO_RCVTIMEO*/
|
||||||
|
|
||||||
|
#if LWIP_TCP
|
||||||
|
if (conn->type == NETCONN_TCP) {
|
||||||
|
if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
|
||||||
|
/* Let the stack know that we have taken the data. */
|
||||||
|
/* TODO: Speedup: Don't block and wait for the answer here
|
||||||
|
(to prevent multiple thread-switches). */
|
||||||
|
msg.function = do_recv;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
if (buf != NULL) {
|
||||||
|
msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;
|
||||||
|
} else {
|
||||||
|
msg.msg.msg.r.len = 1;
|
||||||
|
}
|
||||||
|
/* don't care for the return value of do_recv */
|
||||||
|
TCPIP_APIMSG(&msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we are closed, we indicate that we no longer wish to use the socket */
|
||||||
|
if (buf == NULL) {
|
||||||
|
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
|
||||||
|
/* Avoid to lose any previous error code */
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
|
||||||
|
return ERR_CLSD;
|
||||||
|
}
|
||||||
|
len = ((struct pbuf *)buf)->tot_len;
|
||||||
|
}
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
|
#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
|
||||||
|
else
|
||||||
|
#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
|
||||||
|
#if (LWIP_UDP || LWIP_RAW)
|
||||||
|
{
|
||||||
|
LWIP_ASSERT("buf != NULL", buf != NULL);
|
||||||
|
len = netbuf_len((struct netbuf *)buf);
|
||||||
|
}
|
||||||
|
#endif /* (LWIP_UDP || LWIP_RAW) */
|
||||||
|
|
||||||
|
#if LWIP_SO_RCVBUF
|
||||||
|
SYS_ARCH_DEC(conn->recv_avail, len);
|
||||||
|
#endif /* LWIP_SO_RCVBUF */
|
||||||
|
/* Register event with callback */
|
||||||
|
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
|
||||||
|
|
||||||
|
*new_buf = buf;
|
||||||
|
/* don't set conn->last_err: it's only ERR_OK, anyway */
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive data (in form of a pbuf) from a TCP netconn
|
||||||
|
*
|
||||||
|
* @param conn the netconn from which to receive data
|
||||||
|
* @param new_buf pointer where a new pbuf is stored when received data
|
||||||
|
* @return ERR_OK if data has been received, an error code otherwise (timeout,
|
||||||
|
* memory error or another error)
|
||||||
|
* ERR_ARG if conn is not a TCP netconn
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
|
||||||
|
{
|
||||||
|
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
|
||||||
|
netconn_type(conn) == NETCONN_TCP, return ERR_ARG;);
|
||||||
|
|
||||||
|
return netconn_recv_data(conn, (void **)new_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive data (in form of a netbuf containing a packet buffer) from a netconn
|
||||||
|
*
|
||||||
|
* @param conn the netconn from which to receive data
|
||||||
|
* @param new_buf pointer where a new netbuf is stored when received data
|
||||||
|
* @return ERR_OK if data has been received, an error code otherwise (timeout,
|
||||||
|
* memory error or another error)
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_recv(struct netconn *conn, struct netbuf **new_buf)
|
||||||
|
{
|
||||||
|
#if LWIP_TCP
|
||||||
|
struct netbuf *buf = NULL;
|
||||||
|
err_t err;
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
|
||||||
|
*new_buf = NULL;
|
||||||
|
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
|
||||||
|
|
||||||
|
#if LWIP_TCP
|
||||||
|
if (conn->type == NETCONN_TCP) {
|
||||||
|
struct pbuf *p = NULL;
|
||||||
|
/* This is not a listening netconn, since recvmbox is set */
|
||||||
|
|
||||||
|
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
|
||||||
|
if (buf == NULL) {
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = netconn_recv_data(conn, (void **)&p);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
memp_free(MEMP_NETBUF, buf);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
LWIP_ASSERT("p != NULL", p != NULL);
|
||||||
|
|
||||||
|
buf->p = p;
|
||||||
|
buf->ptr = p;
|
||||||
|
buf->port = 0;
|
||||||
|
ip_addr_set_any(&buf->addr);
|
||||||
|
*new_buf = buf;
|
||||||
|
/* don't set conn->last_err: it's only ERR_OK, anyway */
|
||||||
|
return ERR_OK;
|
||||||
|
} else
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
|
{
|
||||||
|
#if (LWIP_UDP || LWIP_RAW)
|
||||||
|
return netconn_recv_data(conn, (void **)new_buf);
|
||||||
|
#endif /* (LWIP_UDP || LWIP_RAW) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TCP: update the receive window: by calling this, the application
|
||||||
|
* tells the stack that it has processed data and is able to accept
|
||||||
|
* new data.
|
||||||
|
* ATTENTION: use with care, this is mainly used for sockets!
|
||||||
|
* Can only be used when calling netconn_set_noautorecved(conn, 1) before.
|
||||||
|
*
|
||||||
|
* @param conn the netconn for which to update the receive window
|
||||||
|
* @param length amount of data processed (ATTENTION: this must be accurate!)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netconn_recved(struct netconn *conn, u32_t length)
|
||||||
|
{
|
||||||
|
#if LWIP_TCP
|
||||||
|
if ((conn != NULL) && (conn->type == NETCONN_TCP) &&
|
||||||
|
(netconn_get_noautorecved(conn))) {
|
||||||
|
struct api_msg msg;
|
||||||
|
/* Let the stack know that we have taken the data. */
|
||||||
|
/* TODO: Speedup: Don't block and wait for the answer here
|
||||||
|
(to prevent multiple thread-switches). */
|
||||||
|
msg.function = do_recv;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
msg.msg.msg.r.len = length;
|
||||||
|
/* don't care for the return value of do_recv */
|
||||||
|
TCPIP_APIMSG(&msg);
|
||||||
|
}
|
||||||
|
#else /* LWIP_TCP */
|
||||||
|
LWIP_UNUSED_ARG(conn);
|
||||||
|
LWIP_UNUSED_ARG(length);
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send data (in form of a netbuf) to a specific remote IP address and port.
|
||||||
|
* Only to be used for UDP and RAW netconns (not TCP).
|
||||||
|
*
|
||||||
|
* @param conn the netconn over which to send data
|
||||||
|
* @param buf a netbuf containing the data to send
|
||||||
|
* @param addr the remote IP address to which to send the data
|
||||||
|
* @param port the remote port to which to send the data
|
||||||
|
* @return ERR_OK if data was sent, any other err_t on error
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)
|
||||||
|
{
|
||||||
|
if (buf != NULL) {
|
||||||
|
ip_addr_set(&buf->addr, addr);
|
||||||
|
buf->port = port;
|
||||||
|
return netconn_send(conn, buf);
|
||||||
|
}
|
||||||
|
return ERR_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send data over a UDP or RAW netconn (that is already connected).
|
||||||
|
*
|
||||||
|
* @param conn the UDP or RAW netconn over which to send data
|
||||||
|
* @param buf a netbuf containing the data to send
|
||||||
|
* @return ERR_OK if data was sent, any other err_t on error
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_send(struct netconn *conn, struct netbuf *buf)
|
||||||
|
{
|
||||||
|
struct api_msg msg;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
|
||||||
|
msg.function = do_send;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
msg.msg.msg.b = buf;
|
||||||
|
err = TCPIP_APIMSG(&msg);
|
||||||
|
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send data over a TCP netconn.
|
||||||
|
*
|
||||||
|
* @param conn the TCP netconn over which to send data
|
||||||
|
* @param dataptr pointer to the application buffer that contains the data to send
|
||||||
|
* @param size size of the application data to send
|
||||||
|
* @param apiflags combination of following flags :
|
||||||
|
* - NETCONN_COPY: data will be copied into memory belonging to the stack
|
||||||
|
* - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
|
||||||
|
* - NETCONN_DONTBLOCK: only write the data if all dat can be written at once
|
||||||
|
* @return ERR_OK if data was sent, any other err_t on error
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
|
||||||
|
{
|
||||||
|
struct api_msg msg;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
|
||||||
|
if (size == 0) {
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @todo: for non-blocking write, check if 'size' would ever fit into
|
||||||
|
snd_queue or snd_buf */
|
||||||
|
msg.function = do_write;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
msg.msg.msg.w.dataptr = dataptr;
|
||||||
|
msg.msg.msg.w.apiflags = apiflags;
|
||||||
|
msg.msg.msg.w.len = size;
|
||||||
|
/* For locking the core: this _can_ be delayed on low memory/low send buffer,
|
||||||
|
but if it is, this is done inside api_msg.c:do_write(), so we can use the
|
||||||
|
non-blocking version here. */
|
||||||
|
err = TCPIP_APIMSG(&msg);
|
||||||
|
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close ot shutdown a TCP netconn (doesn't delete it).
|
||||||
|
*
|
||||||
|
* @param conn the TCP netconn to close or shutdown
|
||||||
|
* @param how fully close or only shutdown one side?
|
||||||
|
* @return ERR_OK if the netconn was closed, any other err_t on error
|
||||||
|
*/
|
||||||
|
static err_t
|
||||||
|
netconn_close_shutdown(struct netconn *conn, u8_t how)
|
||||||
|
{
|
||||||
|
struct api_msg msg;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
|
||||||
|
msg.function = do_close;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
/* shutting down both ends is the same as closing */
|
||||||
|
msg.msg.msg.sd.shut = how;
|
||||||
|
/* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,
|
||||||
|
don't use TCPIP_APIMSG here */
|
||||||
|
err = tcpip_apimsg(&msg);
|
||||||
|
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a TCP netconn (doesn't delete it).
|
||||||
|
*
|
||||||
|
* @param conn the TCP netconn to close
|
||||||
|
* @return ERR_OK if the netconn was closed, any other err_t on error
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_close(struct netconn *conn)
|
||||||
|
{
|
||||||
|
/* shutting down both ends is the same as closing */
|
||||||
|
return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shut down one or both sides of a TCP netconn (doesn't delete it).
|
||||||
|
*
|
||||||
|
* @param conn the TCP netconn to shut down
|
||||||
|
* @return ERR_OK if the netconn was closed, any other err_t on error
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
|
||||||
|
{
|
||||||
|
return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_IGMP
|
||||||
|
/**
|
||||||
|
* Join multicast groups for UDP netconns.
|
||||||
|
*
|
||||||
|
* @param conn the UDP netconn for which to change multicast addresses
|
||||||
|
* @param multiaddr IP address of the multicast group to join or leave
|
||||||
|
* @param netif_addr the IP address of the network interface on which to send
|
||||||
|
* the igmp message
|
||||||
|
* @param join_or_leave flag whether to send a join- or leave-message
|
||||||
|
* @return ERR_OK if the action was taken, any err_t on error
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_join_leave_group(struct netconn *conn,
|
||||||
|
ip_addr_t *multiaddr,
|
||||||
|
ip_addr_t *netif_addr,
|
||||||
|
enum netconn_igmp join_or_leave)
|
||||||
|
{
|
||||||
|
struct api_msg msg;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||||
|
|
||||||
|
msg.function = do_join_leave_group;
|
||||||
|
msg.msg.conn = conn;
|
||||||
|
msg.msg.msg.jl.multiaddr = multiaddr;
|
||||||
|
msg.msg.msg.jl.netif_addr = netif_addr;
|
||||||
|
msg.msg.msg.jl.join_or_leave = join_or_leave;
|
||||||
|
err = TCPIP_APIMSG(&msg);
|
||||||
|
|
||||||
|
NETCONN_SET_SAFE_ERR(conn, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif /* LWIP_IGMP */
|
||||||
|
|
||||||
|
#if LWIP_DNS
|
||||||
|
/**
|
||||||
|
* Execute a DNS query, only one IP address is returned
|
||||||
|
*
|
||||||
|
* @param name a string representation of the DNS host name to query
|
||||||
|
* @param addr a preallocated ip_addr_t where to store the resolved IP address
|
||||||
|
* @return ERR_OK: resolving succeeded
|
||||||
|
* ERR_MEM: memory error, try again later
|
||||||
|
* ERR_ARG: dns client not initialized or invalid hostname
|
||||||
|
* ERR_VAL: dns server response was invalid
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netconn_gethostbyname(const char *name, ip_addr_t *addr)
|
||||||
|
{
|
||||||
|
struct dns_api_msg msg;
|
||||||
|
err_t err;
|
||||||
|
sys_sem_t sem;
|
||||||
|
|
||||||
|
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
|
||||||
|
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
|
||||||
|
|
||||||
|
err = sys_sem_new(&sem, 0);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.name = name;
|
||||||
|
msg.addr = addr;
|
||||||
|
msg.err = &err;
|
||||||
|
msg.sem = &sem;
|
||||||
|
|
||||||
|
tcpip_callback(do_gethostbyname, &msg);
|
||||||
|
sys_sem_wait(&sem);
|
||||||
|
sys_sem_free(&sem);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif /* LWIP_DNS*/
|
||||||
|
|
||||||
|
#endif /* LWIP_NETCONN */
|
1540
tools/sdk/lwip/src/api/api_msg.c
Normal file
1540
tools/sdk/lwip/src/api/api_msg.c
Normal file
File diff suppressed because it is too large
Load Diff
75
tools/sdk/lwip/src/api/err.c
Normal file
75
tools/sdk/lwip/src/api/err.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Error Management module
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/err.h"
|
||||||
|
|
||||||
|
#ifdef LWIP_DEBUG
|
||||||
|
|
||||||
|
static const char *err_strerr[] = {
|
||||||
|
"Ok.", /* ERR_OK 0 */
|
||||||
|
"Out of memory error.", /* ERR_MEM -1 */
|
||||||
|
"Buffer error.", /* ERR_BUF -2 */
|
||||||
|
"Timeout.", /* ERR_TIMEOUT -3 */
|
||||||
|
"Routing problem.", /* ERR_RTE -4 */
|
||||||
|
"Operation in progress.", /* ERR_INPROGRESS -5 */
|
||||||
|
"Illegal value.", /* ERR_VAL -6 */
|
||||||
|
"Operation would block.", /* ERR_WOULDBLOCK -7 */
|
||||||
|
"Connection aborted.", /* ERR_ABRT -8 */
|
||||||
|
"Connection reset.", /* ERR_RST -9 */
|
||||||
|
"Connection closed.", /* ERR_CLSD -10 */
|
||||||
|
"Not connected.", /* ERR_CONN -11 */
|
||||||
|
"Illegal argument.", /* ERR_ARG -12 */
|
||||||
|
"Address in use.", /* ERR_USE -13 */
|
||||||
|
"Low-level netif error.", /* ERR_IF -14 */
|
||||||
|
"Already connected.", /* ERR_ISCONN -15 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an lwip internal error to a string representation.
|
||||||
|
*
|
||||||
|
* @param err an lwip internal err_t
|
||||||
|
* @return a string representation for err
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
lwip_strerr(err_t err)
|
||||||
|
{
|
||||||
|
return err_strerr[-err];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_DEBUG */
|
245
tools/sdk/lwip/src/api/netbuf.c
Normal file
245
tools/sdk/lwip/src/api/netbuf.c
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Network buffer management
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/netbuf.h"
|
||||||
|
#include "lwip/memp.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create (allocate) and initialize a new netbuf.
|
||||||
|
* The netbuf doesn't yet contain a packet buffer!
|
||||||
|
* 申请一个新的netbuf空间,但不分配任何数据空间
|
||||||
|
* @return a pointer to a new netbuf
|
||||||
|
* NULL on lack of memory
|
||||||
|
*/
|
||||||
|
struct
|
||||||
|
netbuf *netbuf_new(void)
|
||||||
|
{
|
||||||
|
struct netbuf *buf;
|
||||||
|
|
||||||
|
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
|
||||||
|
if (buf != NULL) {
|
||||||
|
buf->p = NULL;
|
||||||
|
buf->ptr = NULL;
|
||||||
|
ip_addr_set_any(&buf->addr);
|
||||||
|
buf->port = 0;
|
||||||
|
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
|
||||||
|
#if LWIP_CHECKSUM_ON_COPY
|
||||||
|
buf->flags = 0;
|
||||||
|
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||||
|
buf->toport_chksum = 0;
|
||||||
|
#if LWIP_NETBUF_RECVINFO
|
||||||
|
ip_addr_set_any(&buf->toaddr);
|
||||||
|
#endif /* LWIP_NETBUF_RECVINFO */
|
||||||
|
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
|
||||||
|
return buf;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deallocate a netbuf allocated by netbuf_new().
|
||||||
|
* 释放一个netbuf空间
|
||||||
|
* @param buf pointer to a netbuf allocated by netbuf_new()
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netbuf_delete(struct netbuf *buf)
|
||||||
|
{
|
||||||
|
if (buf != NULL) {
|
||||||
|
if (buf->p != NULL) {
|
||||||
|
pbuf_free(buf->p);
|
||||||
|
buf->p = buf->ptr = NULL;
|
||||||
|
}
|
||||||
|
memp_free(MEMP_NETBUF, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate memory for a packet buffer for a given netbuf.
|
||||||
|
*为netbuf结构分配size大小的数据空间
|
||||||
|
* @param buf the netbuf for which to allocate a packet buffer
|
||||||
|
* @param size the size of the packet buffer to allocate
|
||||||
|
* @return pointer to the allocated memory
|
||||||
|
* NULL if no memory could be allocated
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
netbuf_alloc(struct netbuf *buf, u16_t size)
|
||||||
|
{
|
||||||
|
LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;);
|
||||||
|
|
||||||
|
/* Deallocate any previously allocated memory. */
|
||||||
|
if (buf->p != NULL) {
|
||||||
|
pbuf_free(buf->p);
|
||||||
|
}
|
||||||
|
buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
|
||||||
|
if (buf->p == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
LWIP_ASSERT("check that first pbuf can hold size",
|
||||||
|
(buf->p->len >= size));
|
||||||
|
buf->ptr = buf->p;
|
||||||
|
return buf->p->payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the packet buffer included in a netbuf
|
||||||
|
*释放netbuf结构指向的数据pbuf
|
||||||
|
* @param buf pointer to the netbuf which contains the packet buffer to free
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netbuf_free(struct netbuf *buf)
|
||||||
|
{
|
||||||
|
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
|
||||||
|
if (buf->p != NULL) {
|
||||||
|
pbuf_free(buf->p);
|
||||||
|
}
|
||||||
|
buf->p = buf->ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Let a netbuf reference existing (non-volatile) data.
|
||||||
|
*
|
||||||
|
* @param buf netbuf which should reference the data
|
||||||
|
* @param dataptr pointer to the data to reference
|
||||||
|
* @param size size of the data
|
||||||
|
* @return ERR_OK if data is referenced
|
||||||
|
* ERR_MEM if data couldn't be referenced due to lack of memory
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
|
||||||
|
{
|
||||||
|
LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;);
|
||||||
|
if (buf->p != NULL) {
|
||||||
|
pbuf_free(buf->p);
|
||||||
|
}
|
||||||
|
buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
|
||||||
|
if (buf->p == NULL) {
|
||||||
|
buf->ptr = NULL;
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
buf->p->payload = (void*)dataptr;
|
||||||
|
buf->p->len = buf->p->tot_len = size;
|
||||||
|
buf->ptr = buf->p;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chain one netbuf to another (@see pbuf_chain)
|
||||||
|
*
|
||||||
|
* @param head the first netbuf
|
||||||
|
* @param tail netbuf to chain after head, freed by this function, may not be reference after returning
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netbuf_chain(struct netbuf *head, struct netbuf *tail)
|
||||||
|
{
|
||||||
|
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
|
||||||
|
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
|
||||||
|
pbuf_cat(head->p, tail->p);
|
||||||
|
head->ptr = head->p;
|
||||||
|
memp_free(MEMP_NETBUF, tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data pointer and length of the data inside a netbuf.
|
||||||
|
*
|
||||||
|
* @param buf netbuf to get the data from
|
||||||
|
* @param dataptr pointer to a void pointer where to store the data pointer
|
||||||
|
* @param len pointer to an u16_t where the length of the data is stored
|
||||||
|
* @return ERR_OK if the information was retreived,
|
||||||
|
* ERR_BUF on error.
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
|
||||||
|
{
|
||||||
|
LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;);
|
||||||
|
LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;);
|
||||||
|
LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;);
|
||||||
|
|
||||||
|
if (buf->ptr == NULL) {
|
||||||
|
return ERR_BUF;
|
||||||
|
}
|
||||||
|
*dataptr = buf->ptr->payload;
|
||||||
|
*len = buf->ptr->len;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the current data pointer of a packet buffer contained in a netbuf
|
||||||
|
* to the next part.
|
||||||
|
* The packet buffer itself is not modified.
|
||||||
|
*
|
||||||
|
* @param buf the netbuf to modify
|
||||||
|
* @return -1 if there is no next part
|
||||||
|
* 1 if moved to the next part but now there is no next part
|
||||||
|
* 0 if moved to the next part and there are still more parts
|
||||||
|
*/
|
||||||
|
s8_t
|
||||||
|
netbuf_next(struct netbuf *buf)
|
||||||
|
{
|
||||||
|
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);
|
||||||
|
if (buf->ptr->next == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf->ptr = buf->ptr->next;
|
||||||
|
if (buf->ptr->next == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the current data pointer of a packet buffer contained in a netbuf
|
||||||
|
* to the beginning of the packet.
|
||||||
|
* The packet buffer itself is not modified.
|
||||||
|
*
|
||||||
|
* @param buf the netbuf to modify
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netbuf_first(struct netbuf *buf)
|
||||||
|
{
|
||||||
|
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
|
||||||
|
buf->ptr = buf->p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_NETCONN */
|
352
tools/sdk/lwip/src/api/netdb.c
Normal file
352
tools/sdk/lwip/src/api/netdb.c
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* API functions for name resolving
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Simon Goldschmidt
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/netdb.h"
|
||||||
|
|
||||||
|
#if LWIP_DNS && LWIP_SOCKET
|
||||||
|
|
||||||
|
#include "lwip/err.h"
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/memp.h"
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
#include "lwip/api.h"
|
||||||
|
#include "lwip/dns.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/** helper struct for gethostbyname_r to access the char* buffer */
|
||||||
|
struct gethostbyname_r_helper {
|
||||||
|
ip_addr_t *addrs;
|
||||||
|
ip_addr_t addr;
|
||||||
|
char *aliases;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** h_errno is exported in netdb.h for access by applications. */
|
||||||
|
#if LWIP_DNS_API_DECLARE_H_ERRNO
|
||||||
|
int h_errno;
|
||||||
|
#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */
|
||||||
|
|
||||||
|
/** define "hostent" variables storage: 0 if we use a static (but unprotected)
|
||||||
|
* set of variables for lwip_gethostbyname, 1 if we use a local storage */
|
||||||
|
#ifndef LWIP_DNS_API_HOSTENT_STORAGE
|
||||||
|
#define LWIP_DNS_API_HOSTENT_STORAGE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** define "hostent" variables storage */
|
||||||
|
#if LWIP_DNS_API_HOSTENT_STORAGE
|
||||||
|
#define HOSTENT_STORAGE
|
||||||
|
#else
|
||||||
|
#define HOSTENT_STORAGE static
|
||||||
|
#endif /* LWIP_DNS_API_STATIC_HOSTENT */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an entry containing addresses of address family AF_INET
|
||||||
|
* for the host with name name.
|
||||||
|
* Due to dns_gethostbyname limitations, only one address is returned.
|
||||||
|
*
|
||||||
|
* @param name the hostname to resolve
|
||||||
|
* @return an entry containing addresses of address family AF_INET
|
||||||
|
* for the host with name name
|
||||||
|
*/
|
||||||
|
struct hostent*
|
||||||
|
lwip_gethostbyname(const char *name)
|
||||||
|
{
|
||||||
|
err_t err;
|
||||||
|
ip_addr_t addr;
|
||||||
|
|
||||||
|
/* buffer variables for lwip_gethostbyname() */
|
||||||
|
HOSTENT_STORAGE struct hostent s_hostent;
|
||||||
|
HOSTENT_STORAGE char *s_aliases;
|
||||||
|
HOSTENT_STORAGE ip_addr_t s_hostent_addr;
|
||||||
|
HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
|
||||||
|
|
||||||
|
/* query host IP address */
|
||||||
|
err = netconn_gethostbyname(name, &addr);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
|
||||||
|
h_errno = HOST_NOT_FOUND;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill hostent */
|
||||||
|
s_hostent_addr = addr;
|
||||||
|
s_phostent_addr[0] = &s_hostent_addr;
|
||||||
|
s_phostent_addr[1] = NULL;
|
||||||
|
s_hostent.h_name = (char*)name;
|
||||||
|
s_hostent.h_aliases = &s_aliases;
|
||||||
|
s_hostent.h_addrtype = AF_INET;
|
||||||
|
s_hostent.h_length = sizeof(ip_addr_t);
|
||||||
|
s_hostent.h_addr_list = (char**)&s_phostent_addr;
|
||||||
|
|
||||||
|
#if DNS_DEBUG
|
||||||
|
/* dump hostent */
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases));
|
||||||
|
if (s_hostent.h_aliases != NULL) {
|
||||||
|
u8_t idx;
|
||||||
|
for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx]));
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype));
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length));
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list));
|
||||||
|
if (s_hostent.h_addr_list != NULL) {
|
||||||
|
u8_t idx;
|
||||||
|
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* DNS_DEBUG */
|
||||||
|
|
||||||
|
#if LWIP_DNS_API_HOSTENT_STORAGE
|
||||||
|
/* this function should return the "per-thread" hostent after copy from s_hostent */
|
||||||
|
return sys_thread_hostent(&s_hostent);
|
||||||
|
#else
|
||||||
|
return &s_hostent;
|
||||||
|
#endif /* LWIP_DNS_API_HOSTENT_STORAGE */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread-safe variant of lwip_gethostbyname: instead of using a static
|
||||||
|
* buffer, this function takes buffer and errno pointers as arguments
|
||||||
|
* and uses these for the result.
|
||||||
|
*
|
||||||
|
* @param name the hostname to resolve
|
||||||
|
* @param ret pre-allocated struct where to store the result
|
||||||
|
* @param buf pre-allocated buffer where to store additional data
|
||||||
|
* @param buflen the size of buf
|
||||||
|
* @param result pointer to a hostent pointer that is set to ret on success
|
||||||
|
* and set to zero on error
|
||||||
|
* @param h_errnop pointer to an int where to store errors (instead of modifying
|
||||||
|
* the global h_errno)
|
||||||
|
* @return 0 on success, non-zero on error, additional error information
|
||||||
|
* is stored in *h_errnop instead of h_errno to be thread-safe
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||||
|
size_t buflen, struct hostent **result, int *h_errnop)
|
||||||
|
{
|
||||||
|
err_t err;
|
||||||
|
struct gethostbyname_r_helper *h;
|
||||||
|
char *hostname;
|
||||||
|
size_t namelen;
|
||||||
|
int lh_errno;
|
||||||
|
|
||||||
|
if (h_errnop == NULL) {
|
||||||
|
/* ensure h_errnop is never NULL */
|
||||||
|
h_errnop = &lh_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == NULL) {
|
||||||
|
/* not all arguments given */
|
||||||
|
*h_errnop = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* first thing to do: set *result to nothing */
|
||||||
|
*result = NULL;
|
||||||
|
if ((name == NULL) || (ret == NULL) || (buf == 0)) {
|
||||||
|
/* not all arguments given */
|
||||||
|
*h_errnop = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
namelen = strlen(name);
|
||||||
|
if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {
|
||||||
|
/* buf can't hold the data needed + a copy of name */
|
||||||
|
*h_errnop = ERANGE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);
|
||||||
|
hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
|
||||||
|
|
||||||
|
/* query host IP address */
|
||||||
|
err = netconn_gethostbyname(name, &(h->addr));
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
|
||||||
|
*h_errnop = ENSRNOTFOUND;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy the hostname into buf */
|
||||||
|
MEMCPY(hostname, name, namelen);
|
||||||
|
hostname[namelen] = 0;
|
||||||
|
|
||||||
|
/* fill hostent */
|
||||||
|
h->addrs = &(h->addr);
|
||||||
|
h->aliases = NULL;
|
||||||
|
ret->h_name = (char*)hostname;
|
||||||
|
ret->h_aliases = &(h->aliases);
|
||||||
|
ret->h_addrtype = AF_INET;
|
||||||
|
ret->h_length = sizeof(ip_addr_t);
|
||||||
|
ret->h_addr_list = (char**)&(h->addrs);
|
||||||
|
|
||||||
|
/* set result != NULL */
|
||||||
|
*result = ret;
|
||||||
|
|
||||||
|
/* return success */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees one or more addrinfo structures returned by getaddrinfo(), along with
|
||||||
|
* any additional storage associated with those structures. If the ai_next field
|
||||||
|
* of the structure is not null, the entire list of structures is freed.
|
||||||
|
*
|
||||||
|
* @param ai struct addrinfo to free
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lwip_freeaddrinfo(struct addrinfo *ai)
|
||||||
|
{
|
||||||
|
struct addrinfo *next;
|
||||||
|
|
||||||
|
while (ai != NULL) {
|
||||||
|
next = ai->ai_next;
|
||||||
|
memp_free(MEMP_NETDB, ai);
|
||||||
|
ai = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates the name of a service location (for example, a host name) and/or
|
||||||
|
* a service name and returns a set of socket addresses and associated
|
||||||
|
* information to be used in creating a socket with which to address the
|
||||||
|
* specified service.
|
||||||
|
* Memory for the result is allocated internally and must be freed by calling
|
||||||
|
* lwip_freeaddrinfo()!
|
||||||
|
*
|
||||||
|
* Due to a limitation in dns_gethostbyname, only the first address of a
|
||||||
|
* host is returned.
|
||||||
|
* Also, service names are not supported (only port numbers)!
|
||||||
|
*
|
||||||
|
* @param nodename descriptive name or address string of the host
|
||||||
|
* (may be NULL -> local address)
|
||||||
|
* @param servname port number as string of NULL
|
||||||
|
* @param hints structure containing input values that set socktype and protocol
|
||||||
|
* @param res pointer to a pointer where to store the result (set to NULL on failure)
|
||||||
|
* @return 0 on success, non-zero on failure
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||||
|
const struct addrinfo *hints, struct addrinfo **res)
|
||||||
|
{
|
||||||
|
err_t err;
|
||||||
|
ip_addr_t addr;
|
||||||
|
struct addrinfo *ai;
|
||||||
|
struct sockaddr_in *sa = NULL;
|
||||||
|
int port_nr = 0;
|
||||||
|
size_t total_size;
|
||||||
|
size_t namelen = 0;
|
||||||
|
|
||||||
|
if (res == NULL) {
|
||||||
|
return EAI_FAIL;
|
||||||
|
}
|
||||||
|
*res = NULL;
|
||||||
|
if ((nodename == NULL) && (servname == NULL)) {
|
||||||
|
return EAI_NONAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (servname != NULL) {
|
||||||
|
/* service name specified: convert to port number
|
||||||
|
* @todo?: currently, only ASCII integers (port numbers) are supported! */
|
||||||
|
port_nr = atoi(servname);
|
||||||
|
if ((port_nr <= 0) || (port_nr > 0xffff)) {
|
||||||
|
return EAI_SERVICE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodename != NULL) {
|
||||||
|
/* service location specified, try to resolve */
|
||||||
|
err = netconn_gethostbyname(nodename, &addr);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
return EAI_FAIL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* service location specified, use loopback address */
|
||||||
|
ip_addr_set_loopback(&addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
|
||||||
|
if (nodename != NULL) {
|
||||||
|
namelen = strlen(nodename);
|
||||||
|
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
|
||||||
|
total_size += namelen + 1;
|
||||||
|
}
|
||||||
|
/* If this fails, please report to lwip-devel! :-) */
|
||||||
|
LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
|
||||||
|
total_size <= NETDB_ELEM_SIZE);
|
||||||
|
ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
|
||||||
|
if (ai == NULL) {
|
||||||
|
goto memerr;
|
||||||
|
}
|
||||||
|
memset(ai, 0, total_size);
|
||||||
|
sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
|
||||||
|
/* set up sockaddr */
|
||||||
|
inet_addr_from_ipaddr(&sa->sin_addr, &addr);
|
||||||
|
sa->sin_family = AF_INET;
|
||||||
|
sa->sin_len = sizeof(struct sockaddr_in);
|
||||||
|
sa->sin_port = htons((u16_t)port_nr);
|
||||||
|
|
||||||
|
/* set up addrinfo */
|
||||||
|
ai->ai_family = AF_INET;
|
||||||
|
if (hints != NULL) {
|
||||||
|
/* copy socktype & protocol from hints if specified */
|
||||||
|
ai->ai_socktype = hints->ai_socktype;
|
||||||
|
ai->ai_protocol = hints->ai_protocol;
|
||||||
|
}
|
||||||
|
if (nodename != NULL) {
|
||||||
|
/* copy nodename to canonname if specified */
|
||||||
|
ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
|
||||||
|
MEMCPY(ai->ai_canonname, nodename, namelen);
|
||||||
|
ai->ai_canonname[namelen] = 0;
|
||||||
|
}
|
||||||
|
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||||
|
ai->ai_addr = (struct sockaddr*)sa;
|
||||||
|
|
||||||
|
*res = ai;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
memerr:
|
||||||
|
if (ai != NULL) {
|
||||||
|
memp_free(MEMP_NETDB, ai);
|
||||||
|
}
|
||||||
|
return EAI_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_DNS && LWIP_SOCKET */
|
160
tools/sdk/lwip/src/api/netifapi.c
Normal file
160
tools/sdk/lwip/src/api/netifapi.c
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Network Interface Sequential API module
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/netifapi.h"
|
||||||
|
#include "lwip/tcpip.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call netif_add() inside the tcpip_thread context.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
do_netifapi_netif_add(struct netifapi_msg_msg *msg)
|
||||||
|
{
|
||||||
|
if (!netif_add( msg->netif,
|
||||||
|
msg->msg.add.ipaddr,
|
||||||
|
msg->msg.add.netmask,
|
||||||
|
msg->msg.add.gw,
|
||||||
|
msg->msg.add.state,
|
||||||
|
msg->msg.add.init,
|
||||||
|
msg->msg.add.input)) {
|
||||||
|
msg->err = ERR_IF;
|
||||||
|
} else {
|
||||||
|
msg->err = ERR_OK;
|
||||||
|
}
|
||||||
|
TCPIP_NETIFAPI_ACK(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call netif_set_addr() inside the tcpip_thread context.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
|
||||||
|
{
|
||||||
|
netif_set_addr( msg->netif,
|
||||||
|
msg->msg.add.ipaddr,
|
||||||
|
msg->msg.add.netmask,
|
||||||
|
msg->msg.add.gw);
|
||||||
|
msg->err = ERR_OK;
|
||||||
|
TCPIP_NETIFAPI_ACK(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
|
||||||
|
* tcpip_thread context.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
do_netifapi_netif_common(struct netifapi_msg_msg *msg)
|
||||||
|
{
|
||||||
|
if (msg->msg.common.errtfunc != NULL) {
|
||||||
|
msg->err = msg->msg.common.errtfunc(msg->netif);
|
||||||
|
} else {
|
||||||
|
msg->err = ERR_OK;
|
||||||
|
msg->msg.common.voidfunc(msg->netif);
|
||||||
|
}
|
||||||
|
TCPIP_NETIFAPI_ACK(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call netif_add() in a thread-safe way by running that function inside the
|
||||||
|
* tcpip_thread context.
|
||||||
|
*
|
||||||
|
* @note for params @see netif_add()
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netifapi_netif_add(struct netif *netif,
|
||||||
|
ip_addr_t *ipaddr,
|
||||||
|
ip_addr_t *netmask,
|
||||||
|
ip_addr_t *gw,
|
||||||
|
void *state,
|
||||||
|
netif_init_fn init,
|
||||||
|
netif_input_fn input)
|
||||||
|
{
|
||||||
|
struct netifapi_msg msg;
|
||||||
|
msg.function = do_netifapi_netif_add;
|
||||||
|
msg.msg.netif = netif;
|
||||||
|
msg.msg.msg.add.ipaddr = ipaddr;
|
||||||
|
msg.msg.msg.add.netmask = netmask;
|
||||||
|
msg.msg.msg.add.gw = gw;
|
||||||
|
msg.msg.msg.add.state = state;
|
||||||
|
msg.msg.msg.add.init = init;
|
||||||
|
msg.msg.msg.add.input = input;
|
||||||
|
TCPIP_NETIFAPI(&msg);
|
||||||
|
return msg.msg.err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call netif_set_addr() in a thread-safe way by running that function inside the
|
||||||
|
* tcpip_thread context.
|
||||||
|
*
|
||||||
|
* @note for params @see netif_set_addr()
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netifapi_netif_set_addr(struct netif *netif,
|
||||||
|
ip_addr_t *ipaddr,
|
||||||
|
ip_addr_t *netmask,
|
||||||
|
ip_addr_t *gw)
|
||||||
|
{
|
||||||
|
struct netifapi_msg msg;
|
||||||
|
msg.function = do_netifapi_netif_set_addr;
|
||||||
|
msg.msg.netif = netif;
|
||||||
|
msg.msg.msg.add.ipaddr = ipaddr;
|
||||||
|
msg.msg.msg.add.netmask = netmask;
|
||||||
|
msg.msg.msg.add.gw = gw;
|
||||||
|
TCPIP_NETIFAPI(&msg);
|
||||||
|
return msg.msg.err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
|
||||||
|
* way by running that function inside the tcpip_thread context.
|
||||||
|
*
|
||||||
|
* @note use only for functions where there is only "netif" parameter.
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
|
||||||
|
netifapi_errt_fn errtfunc)
|
||||||
|
{
|
||||||
|
struct netifapi_msg msg;
|
||||||
|
msg.function = do_netifapi_netif_common;
|
||||||
|
msg.msg.netif = netif;
|
||||||
|
msg.msg.msg.common.voidfunc = voidfunc;
|
||||||
|
msg.msg.msg.common.errtfunc = errtfunc;
|
||||||
|
TCPIP_NETIFAPI(&msg);
|
||||||
|
return msg.msg.err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_NETIF_API */
|
2343
tools/sdk/lwip/src/api/sockets.c
Normal file
2343
tools/sdk/lwip/src/api/sockets.c
Normal file
File diff suppressed because it is too large
Load Diff
460
tools/sdk/lwip/src/api/tcpip.c
Normal file
460
tools/sdk/lwip/src/api/tcpip.c
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Sequential API Main thread module
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
#include "lwip/memp.h"
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/pbuf.h"
|
||||||
|
#include "lwip/tcpip.h"
|
||||||
|
#include "lwip/init.h"
|
||||||
|
#include "netif/etharp.h"
|
||||||
|
#include "netif/ppp_oe.h"
|
||||||
|
|
||||||
|
/* global variables */
|
||||||
|
static tcpip_init_done_fn tcpip_init_done;
|
||||||
|
static void *tcpip_init_done_arg;
|
||||||
|
static sys_mbox_t mbox;
|
||||||
|
|
||||||
|
#if LWIP_TCPIP_CORE_LOCKING
|
||||||
|
/** The global semaphore to lock the stack. */
|
||||||
|
sys_mutex_t lock_tcpip_core;
|
||||||
|
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main lwIP thread. This thread has exclusive access to lwIP core functions
|
||||||
|
* (unless access to them is not locked). Other threads communicate with this
|
||||||
|
* thread using message boxes.
|
||||||
|
*
|
||||||
|
* It also starts all the timers to make sure they are running in the right
|
||||||
|
* thread context.
|
||||||
|
*
|
||||||
|
* @param arg unused argument
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
tcpip_thread(void *arg)
|
||||||
|
{
|
||||||
|
struct tcpip_msg *msg;
|
||||||
|
LWIP_UNUSED_ARG(arg);
|
||||||
|
|
||||||
|
if (tcpip_init_done != NULL) {//用户注册了自定义初始化函数
|
||||||
|
tcpip_init_done(tcpip_init_done_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK_TCPIP_CORE();
|
||||||
|
while (1) { /* MAIN Loop */
|
||||||
|
UNLOCK_TCPIP_CORE();
|
||||||
|
LWIP_TCPIP_THREAD_ALIVE();
|
||||||
|
/* wait for a message, timeouts are processed while waiting */
|
||||||
|
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
|
||||||
|
LOCK_TCPIP_CORE();
|
||||||
|
switch (msg->type) {
|
||||||
|
#if LWIP_NETCONN
|
||||||
|
case TCPIP_MSG_API://API调用
|
||||||
|
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
|
||||||
|
msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
|
||||||
|
break;
|
||||||
|
#endif /* LWIP_NETCONN */
|
||||||
|
|
||||||
|
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||||
|
case TCPIP_MSG_INPKT://底层数据包输入
|
||||||
|
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
|
||||||
|
#if LWIP_ETHERNET
|
||||||
|
if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {//支持ARP
|
||||||
|
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);//交给ARP处理
|
||||||
|
} else
|
||||||
|
#endif /* LWIP_ETHERNET */
|
||||||
|
{
|
||||||
|
ip_input(msg->msg.inp.p, msg->msg.inp.netif);//交给IP处理
|
||||||
|
}
|
||||||
|
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
||||||
|
break;
|
||||||
|
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||||
|
|
||||||
|
#if LWIP_NETIF_API
|
||||||
|
case TCPIP_MSG_NETIFAPI:
|
||||||
|
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
|
||||||
|
msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
|
||||||
|
break;
|
||||||
|
#endif /* LWIP_NETIF_API */
|
||||||
|
|
||||||
|
case TCPIP_MSG_CALLBACK://上层回调方式执行一个函数
|
||||||
|
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
|
||||||
|
msg->msg.cb.function(msg->msg.cb.ctx);
|
||||||
|
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if LWIP_TCPIP_TIMEOUT
|
||||||
|
case TCPIP_MSG_TIMEOUT://上层注册一个定时事件
|
||||||
|
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
|
||||||
|
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||||
|
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||||
|
break;
|
||||||
|
case TCPIP_MSG_UNTIMEOUT://上层删除一个定时事件
|
||||||
|
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
|
||||||
|
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||||
|
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||||
|
break;
|
||||||
|
#endif /* LWIP_TCPIP_TIMEOUT */
|
||||||
|
|
||||||
|
default:
|
||||||
|
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
|
||||||
|
LWIP_ASSERT("tcpip_thread: invalid message", 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass a received packet to tcpip_thread for input processing
|
||||||
|
*
|
||||||
|
* @param p the received packet, p->payload pointing to the Ethernet header or
|
||||||
|
* to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
|
||||||
|
* NETIF_FLAG_ETHERNET flags)
|
||||||
|
* @param inp the network interface on which the packet was received
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
tcpip_input(struct pbuf *p, struct netif *inp)
|
||||||
|
{
|
||||||
|
#if LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||||
|
err_t ret;
|
||||||
|
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp));
|
||||||
|
LOCK_TCPIP_CORE();
|
||||||
|
#if LWIP_ETHERNET
|
||||||
|
if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
|
||||||
|
ret = ethernet_input(p, inp);
|
||||||
|
} else
|
||||||
|
#endif /* LWIP_ETHERNET */
|
||||||
|
{
|
||||||
|
ret = ip_input(p, inp);
|
||||||
|
}
|
||||||
|
UNLOCK_TCPIP_CORE();
|
||||||
|
return ret;
|
||||||
|
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||||
|
struct tcpip_msg *msg;
|
||||||
|
|
||||||
|
if (sys_mbox_valid(&mbox)) {
|
||||||
|
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
|
||||||
|
if (msg == NULL) {
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->type = TCPIP_MSG_INPKT;
|
||||||
|
msg->msg.inp.p = p;
|
||||||
|
msg->msg.inp.netif = inp;
|
||||||
|
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
|
||||||
|
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
return ERR_VAL;
|
||||||
|
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call a specific function in the thread context of
|
||||||
|
* tcpip_thread for easy access synchronization.
|
||||||
|
* A function called in that way may access lwIP core code
|
||||||
|
* without fearing concurrent access.
|
||||||
|
*
|
||||||
|
* @param f the function to call
|
||||||
|
* @param ctx parameter passed to f
|
||||||
|
* @param block 1 to block until the request is posted, 0 to non-blocking mode
|
||||||
|
* @return ERR_OK if the function was called, another err_t if not
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
|
||||||
|
{
|
||||||
|
struct tcpip_msg *msg;
|
||||||
|
|
||||||
|
if (sys_mbox_valid(&mbox)) {
|
||||||
|
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||||
|
if (msg == NULL) {
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->type = TCPIP_MSG_CALLBACK;
|
||||||
|
msg->msg.cb.function = function;
|
||||||
|
msg->msg.cb.ctx = ctx;
|
||||||
|
if (block) {
|
||||||
|
sys_mbox_post(&mbox, msg);
|
||||||
|
} else {
|
||||||
|
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
|
||||||
|
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
return ERR_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_TCPIP_TIMEOUT
|
||||||
|
/**
|
||||||
|
* call sys_timeout in tcpip_thread
|
||||||
|
*
|
||||||
|
* @param msec time in milliseconds for timeout
|
||||||
|
* @param h function to be called on timeout
|
||||||
|
* @param arg argument to pass to timeout function h
|
||||||
|
* @return ERR_MEM on memory error, ERR_OK otherwise
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||||
|
{
|
||||||
|
struct tcpip_msg *msg;
|
||||||
|
|
||||||
|
if (sys_mbox_valid(&mbox)) {
|
||||||
|
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||||
|
if (msg == NULL) {
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->type = TCPIP_MSG_TIMEOUT;
|
||||||
|
msg->msg.tmo.msecs = msecs;
|
||||||
|
msg->msg.tmo.h = h;
|
||||||
|
msg->msg.tmo.arg = arg;
|
||||||
|
sys_mbox_post(&mbox, msg);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
return ERR_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* call sys_untimeout in tcpip_thread
|
||||||
|
*
|
||||||
|
* @param msec time in milliseconds for timeout
|
||||||
|
* @param h function to be called on timeout
|
||||||
|
* @param arg argument to pass to timeout function h
|
||||||
|
* @return ERR_MEM on memory error, ERR_OK otherwise
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
tcpip_untimeout(sys_timeout_handler h, void *arg)
|
||||||
|
{
|
||||||
|
struct tcpip_msg *msg;
|
||||||
|
|
||||||
|
if (sys_mbox_valid(&mbox)) {
|
||||||
|
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||||
|
if (msg == NULL) {
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->type = TCPIP_MSG_UNTIMEOUT;
|
||||||
|
msg->msg.tmo.h = h;
|
||||||
|
msg->msg.tmo.arg = arg;
|
||||||
|
sys_mbox_post(&mbox, msg);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
return ERR_VAL;
|
||||||
|
}
|
||||||
|
#endif /* LWIP_TCPIP_TIMEOUT */
|
||||||
|
|
||||||
|
#if LWIP_NETCONN
|
||||||
|
/**
|
||||||
|
* Call the lower part of a netconn_* function
|
||||||
|
* This function is then running in the thread context
|
||||||
|
* of tcpip_thread and has exclusive access to lwIP core code.
|
||||||
|
*
|
||||||
|
* @param apimsg a struct containing the function to call and its parameters
|
||||||
|
* @return ERR_OK if the function was called, another err_t if not
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
tcpip_apimsg(struct api_msg *apimsg)
|
||||||
|
{
|
||||||
|
struct tcpip_msg msg;
|
||||||
|
#ifdef LWIP_DEBUG
|
||||||
|
/* catch functions that don't set err */
|
||||||
|
apimsg->msg.err = ERR_VAL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sys_mbox_valid(&mbox)) {//内核邮箱有效
|
||||||
|
msg.type = TCPIP_MSG_API;
|
||||||
|
msg.msg.apimsg = apimsg;
|
||||||
|
sys_mbox_post(&mbox, &msg);//投递消息
|
||||||
|
sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);//等待消息处理完毕
|
||||||
|
return apimsg->msg.err;
|
||||||
|
}
|
||||||
|
return ERR_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_TCPIP_CORE_LOCKING
|
||||||
|
/**
|
||||||
|
* Call the lower part of a netconn_* function
|
||||||
|
* This function has exclusive access to lwIP core code by locking it
|
||||||
|
* before the function is called.
|
||||||
|
*
|
||||||
|
* @param apimsg a struct containing the function to call and its parameters
|
||||||
|
* @return ERR_OK (only for compatibility fo tcpip_apimsg())
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
tcpip_apimsg_lock(struct api_msg *apimsg)
|
||||||
|
{
|
||||||
|
#ifdef LWIP_DEBUG
|
||||||
|
/* catch functions that don't set err */
|
||||||
|
apimsg->msg.err = ERR_VAL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LOCK_TCPIP_CORE();
|
||||||
|
apimsg->function(&(apimsg->msg));
|
||||||
|
UNLOCK_TCPIP_CORE();
|
||||||
|
return apimsg->msg.err;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||||
|
#endif /* LWIP_NETCONN */
|
||||||
|
|
||||||
|
#if LWIP_NETIF_API
|
||||||
|
#if !LWIP_TCPIP_CORE_LOCKING
|
||||||
|
/**
|
||||||
|
* Much like tcpip_apimsg, but calls the lower part of a netifapi_*
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* @param netifapimsg a struct containing the function to call and its parameters
|
||||||
|
* @return error code given back by the function that was called
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
tcpip_netifapi(struct netifapi_msg* netifapimsg)
|
||||||
|
{
|
||||||
|
struct tcpip_msg msg;
|
||||||
|
|
||||||
|
if (sys_mbox_valid(&mbox)) {
|
||||||
|
err_t err = sys_sem_new(&netifapimsg->msg.sem, 0);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
netifapimsg->msg.err = err;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.type = TCPIP_MSG_NETIFAPI;
|
||||||
|
msg.msg.netifapimsg = netifapimsg;
|
||||||
|
sys_mbox_post(&mbox, &msg);
|
||||||
|
sys_sem_wait(&netifapimsg->msg.sem);
|
||||||
|
sys_sem_free(&netifapimsg->msg.sem);
|
||||||
|
return netifapimsg->msg.err;
|
||||||
|
}
|
||||||
|
return ERR_VAL;
|
||||||
|
}
|
||||||
|
#else /* !LWIP_TCPIP_CORE_LOCKING */
|
||||||
|
/**
|
||||||
|
* Call the lower part of a netifapi_* function
|
||||||
|
* This function has exclusive access to lwIP core code by locking it
|
||||||
|
* before the function is called.
|
||||||
|
*
|
||||||
|
* @param netifapimsg a struct containing the function to call and its parameters
|
||||||
|
* @return ERR_OK (only for compatibility fo tcpip_netifapi())
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
|
||||||
|
{
|
||||||
|
LOCK_TCPIP_CORE();
|
||||||
|
netifapimsg->function(&(netifapimsg->msg));
|
||||||
|
UNLOCK_TCPIP_CORE();
|
||||||
|
return netifapimsg->msg.err;
|
||||||
|
}
|
||||||
|
#endif /* !LWIP_TCPIP_CORE_LOCKING */
|
||||||
|
#endif /* LWIP_NETIF_API */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize this module:
|
||||||
|
* - initialize all sub modules
|
||||||
|
* - start the tcpip_thread
|
||||||
|
*
|
||||||
|
* @param initfunc a function to call when tcpip_thread is running and finished initializing
|
||||||
|
* @param arg argument to pass to initfunc
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
tcpip_init(tcpip_init_done_fn initfunc, void *arg)
|
||||||
|
{
|
||||||
|
lwip_init();//初始化内核
|
||||||
|
|
||||||
|
tcpip_init_done = initfunc;//注册用户自定义函数
|
||||||
|
tcpip_init_done_arg = arg;//函数参数
|
||||||
|
if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {//创建内核邮箱
|
||||||
|
LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
|
||||||
|
}
|
||||||
|
#if LWIP_TCPIP_CORE_LOCKING
|
||||||
|
if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
|
||||||
|
LWIP_ASSERT("failed to create lock_tcpip_core", 0);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||||
|
|
||||||
|
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);//创建内核进程
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple callback function used with tcpip_callback to free a pbuf
|
||||||
|
* (pbuf_free has a wrong signature for tcpip_callback)
|
||||||
|
*
|
||||||
|
* @param p The pbuf (chain) to be dereferenced.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pbuf_free_int(void *p)
|
||||||
|
{
|
||||||
|
struct pbuf *q = (struct pbuf *)p;
|
||||||
|
pbuf_free(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple wrapper function that allows you to free a pbuf from interrupt context.
|
||||||
|
*
|
||||||
|
* @param p The pbuf (chain) to be dereferenced.
|
||||||
|
* @return ERR_OK if callback could be enqueued, an err_t if not
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
pbuf_free_callback(struct pbuf *p)
|
||||||
|
{
|
||||||
|
return tcpip_callback_with_block(pbuf_free_int, p, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple wrapper function that allows you to free heap memory from
|
||||||
|
* interrupt context.
|
||||||
|
*
|
||||||
|
* @param m the heap memory to free
|
||||||
|
* @return ERR_OK if callback could be enqueued, an err_t if not
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
mem_free_callback(void *m)
|
||||||
|
{
|
||||||
|
return tcpip_callback_with_block(mem_free, m, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !NO_SYS */
|
1144
tools/sdk/lwip/src/app/dhcpserver.c
Normal file
1144
tools/sdk/lwip/src/app/dhcpserver.c
Normal file
File diff suppressed because it is too large
Load Diff
1303
tools/sdk/lwip/src/app/espconn.c
Normal file
1303
tools/sdk/lwip/src/app/espconn.c
Normal file
File diff suppressed because it is too large
Load Diff
134
tools/sdk/lwip/src/app/espconn_mdns.c
Normal file
134
tools/sdk/lwip/src/app/espconn_mdns.c
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Copyright 2013-2014 Espressif Systems (Wuxi)
|
||||||
|
*
|
||||||
|
* FileName: espconn_mdns.c
|
||||||
|
*
|
||||||
|
* Description: udp proto interface
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* 2014/3/31, v1.0 create this file.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include "ets_sys.h"
|
||||||
|
#include "os_type.h"
|
||||||
|
|
||||||
|
#include "lwip/mdns.h"
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_enable
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : host_ip -- the ip address of udp server
|
||||||
|
* multicast_ip -- multicast ip given by user
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
espconn_mdns_enable(void)
|
||||||
|
{
|
||||||
|
mdns_enable();
|
||||||
|
}
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_disable
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : host_ip -- the ip address of udp server
|
||||||
|
* multicast_ip -- multicast ip given by user
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
espconn_mdns_disable(void)
|
||||||
|
{
|
||||||
|
mdns_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_set_hostname
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : host_ip -- the ip address of udp server
|
||||||
|
* multicast_ip -- multicast ip given by user
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
espconn_mdns_set_hostname(char *name)
|
||||||
|
{
|
||||||
|
mdns_set_hostname(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_init
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : host_ip -- the ip address of udp server
|
||||||
|
* multicast_ip -- multicast ip given by user
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
char* ICACHE_FLASH_ATTR
|
||||||
|
espconn_mdns_get_hostname(void)
|
||||||
|
{
|
||||||
|
return (char *)mdns_get_hostname();
|
||||||
|
}
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_get_servername
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : info -- the info of mdns
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
espconn_mdns_set_servername(const char *name)
|
||||||
|
{
|
||||||
|
mdns_set_servername(name);
|
||||||
|
}
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_get_servername
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : info -- the info of mdns
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
char* ICACHE_FLASH_ATTR
|
||||||
|
espconn_mdns_get_servername(void)
|
||||||
|
{
|
||||||
|
return (char *)mdns_get_servername();
|
||||||
|
}
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : mdns_server_register
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : info -- the info of mdns
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
espconn_mdns_server_register(void)
|
||||||
|
{
|
||||||
|
mdns_server_register();
|
||||||
|
}
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : mdns_server_register
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : info -- the info of mdns
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
espconn_mdns_server_unregister(void)
|
||||||
|
{
|
||||||
|
mdns_server_unregister();
|
||||||
|
}
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_init
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : host_ip -- the ip address of udp server
|
||||||
|
* multicast_ip -- multicast ip given by user
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
espconn_mdns_close(void)
|
||||||
|
{
|
||||||
|
mdns_close();
|
||||||
|
}
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_mdns_init
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : host_ip -- the ip address of udp server
|
||||||
|
* multicast_ip -- multicast ip given by user
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
espconn_mdns_init(struct mdns_info *info)
|
||||||
|
{
|
||||||
|
mdns_init(info);
|
||||||
|
}
|
1390
tools/sdk/lwip/src/app/espconn_tcp.c
Normal file
1390
tools/sdk/lwip/src/app/espconn_tcp.c
Normal file
File diff suppressed because it is too large
Load Diff
423
tools/sdk/lwip/src/app/espconn_udp.c
Normal file
423
tools/sdk/lwip/src/app/espconn_udp.c
Normal file
@ -0,0 +1,423 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Copyright 2013-2014 Espressif Systems (Wuxi)
|
||||||
|
*
|
||||||
|
* FileName: espconn_udp.c
|
||||||
|
*
|
||||||
|
* Description: udp proto interface
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* 2014/3/31, v1.0 create this file.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include "ets_sys.h"
|
||||||
|
#include "os_type.h"
|
||||||
|
//#include "os.h"
|
||||||
|
|
||||||
|
#include "lwip/inet.h"
|
||||||
|
#include "lwip/err.h"
|
||||||
|
#include "lwip/pbuf.h"
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/tcp_impl.h"
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
|
||||||
|
#include "lwip/app/espconn_udp.h"
|
||||||
|
|
||||||
|
#ifdef MEMLEAK_DEBUG
|
||||||
|
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern espconn_msg *plink_active;
|
||||||
|
extern uint8 default_interface;
|
||||||
|
|
||||||
|
enum send_opt{
|
||||||
|
ESPCONN_SENDTO,
|
||||||
|
ESPCONN_SEND
|
||||||
|
};
|
||||||
|
static void ICACHE_FLASH_ATTR espconn_data_sentcb(struct espconn *pespconn)
|
||||||
|
{
|
||||||
|
if (pespconn == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pespconn->sent_callback != NULL) {
|
||||||
|
pespconn->sent_callback(pespconn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ICACHE_FLASH_ATTR espconn_data_sent(void *arg, enum send_opt opt)
|
||||||
|
{
|
||||||
|
espconn_msg *psent = arg;
|
||||||
|
|
||||||
|
if (psent == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (psent->pcommon.cntr == 0) {
|
||||||
|
psent->pespconn->state = ESPCONN_CONNECT;
|
||||||
|
if (psent->pcommon.err == 0)
|
||||||
|
espconn_data_sentcb(psent->pespconn);
|
||||||
|
} else {
|
||||||
|
if (opt == ESPCONN_SEND){
|
||||||
|
espconn_udp_sent(arg, psent->pcommon.ptrbuf, psent->pcommon.cntr);
|
||||||
|
} else {
|
||||||
|
espconn_udp_sendto(arg, psent->pcommon.ptrbuf, psent->pcommon.cntr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_udp_sent
|
||||||
|
* Description : sent data for client or server
|
||||||
|
* Parameters : void *arg -- client or server to send
|
||||||
|
* uint8* psent -- Data to send
|
||||||
|
* uint16 length -- Length of data to send
|
||||||
|
* Returns : return espconn error code.
|
||||||
|
* - ESPCONN_OK. Successful. No error occured.
|
||||||
|
* - ESPCONN_MEM. Out of memory.
|
||||||
|
* - ESPCONN_RTE. Could not find route to destination address.
|
||||||
|
* - More errors could be returned by lower protocol layers.
|
||||||
|
*******************************************************************************/
|
||||||
|
err_t ICACHE_FLASH_ATTR
|
||||||
|
espconn_udp_sent(void *arg, uint8 *psent, uint16 length)
|
||||||
|
{
|
||||||
|
espconn_msg *pudp_sent = arg;
|
||||||
|
struct udp_pcb *upcb = pudp_sent->pcommon.pcb;
|
||||||
|
struct pbuf *p, *q ,*p_temp;
|
||||||
|
u8_t *data = NULL;
|
||||||
|
u16_t cnt = 0;
|
||||||
|
u16_t datalen = 0;
|
||||||
|
u16_t i = 0;
|
||||||
|
err_t err;
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d %p\n", __LINE__, length, upcb));
|
||||||
|
|
||||||
|
if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) {
|
||||||
|
return ESPCONN_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1470 < length) {
|
||||||
|
datalen = 1470;
|
||||||
|
} else {
|
||||||
|
datalen = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p));
|
||||||
|
|
||||||
|
if (p != NULL) {
|
||||||
|
q = p;
|
||||||
|
|
||||||
|
while (q != NULL) {
|
||||||
|
data = (u8_t *)q->payload;
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, data));
|
||||||
|
|
||||||
|
for (i = 0; i < q->len; i++) {
|
||||||
|
data[i] = ((u8_t *) psent)[cnt++];
|
||||||
|
}
|
||||||
|
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ESPCONN_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
upcb->remote_port = pudp_sent->pespconn->proto.udp->remote_port;
|
||||||
|
IP4_ADDR(&upcb->remote_ip, pudp_sent->pespconn->proto.udp->remote_ip[0],
|
||||||
|
pudp_sent->pespconn->proto.udp->remote_ip[1],
|
||||||
|
pudp_sent->pespconn->proto.udp->remote_ip[2],
|
||||||
|
pudp_sent->pespconn->proto.udp->remote_ip[3]);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %x %d\n", __LINE__, upcb->remote_ip, upcb->remote_port));
|
||||||
|
|
||||||
|
struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00);
|
||||||
|
struct netif *ap_netif = (struct netif *)eagle_lwip_getif(0x01);
|
||||||
|
|
||||||
|
if(wifi_get_opmode() == ESPCONN_AP_STA && default_interface == ESPCONN_AP_STA && sta_netif != NULL && ap_netif != NULL)
|
||||||
|
{
|
||||||
|
if(netif_is_up(sta_netif) && netif_is_up(ap_netif) && \
|
||||||
|
ip_addr_isbroadcast(&upcb->remote_ip, sta_netif) && \
|
||||||
|
ip_addr_isbroadcast(&upcb->remote_ip, ap_netif)) {
|
||||||
|
|
||||||
|
p_temp = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);
|
||||||
|
if (pbuf_copy (p_temp,p) != ERR_OK) {
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent: copying to new pbuf failed\n"));
|
||||||
|
return ESPCONN_ARG;
|
||||||
|
}
|
||||||
|
netif_set_default(sta_netif);
|
||||||
|
err = udp_send(upcb, p_temp);
|
||||||
|
pbuf_free(p_temp);
|
||||||
|
netif_set_default(ap_netif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = udp_send(upcb, p);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d\n", __LINE__, err));
|
||||||
|
|
||||||
|
if (p->ref != 0) {
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p));
|
||||||
|
pbuf_free(p);
|
||||||
|
pudp_sent->pcommon.ptrbuf = psent + datalen;
|
||||||
|
pudp_sent->pcommon.cntr = length - datalen;
|
||||||
|
pudp_sent->pcommon.err = err;
|
||||||
|
espconn_data_sent(pudp_sent, ESPCONN_SEND);
|
||||||
|
if (err > 0)
|
||||||
|
return ESPCONN_IF;
|
||||||
|
return err;
|
||||||
|
} else {
|
||||||
|
pbuf_free(p);
|
||||||
|
return ESPCONN_RTE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_udp_sendto
|
||||||
|
* Description : sent data for UDP
|
||||||
|
* Parameters : void *arg -- UDP to send
|
||||||
|
* uint8* psent -- Data to send
|
||||||
|
* uint16 length -- Length of data to send
|
||||||
|
* Returns : return espconn error code.
|
||||||
|
* - ESPCONN_OK. Successful. No error occured.
|
||||||
|
* - ESPCONN_MEM. Out of memory.
|
||||||
|
* - ESPCONN_RTE. Could not find route to destination address.
|
||||||
|
* - More errors could be returned by lower protocol layers.
|
||||||
|
*******************************************************************************/
|
||||||
|
err_t ICACHE_FLASH_ATTR
|
||||||
|
espconn_udp_sendto(void *arg, uint8 *psent, uint16 length)
|
||||||
|
{
|
||||||
|
espconn_msg *pudp_sent = arg;
|
||||||
|
struct udp_pcb *upcb = pudp_sent->pcommon.pcb;
|
||||||
|
struct espconn *pespconn = pudp_sent->pespconn;
|
||||||
|
struct pbuf *p, *q ,*p_temp;
|
||||||
|
struct ip_addr dst_ip;
|
||||||
|
u16_t dst_port;
|
||||||
|
u8_t *data = NULL;
|
||||||
|
u16_t cnt = 0;
|
||||||
|
u16_t datalen = 0;
|
||||||
|
u16_t i = 0;
|
||||||
|
err_t err;
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d %p\n", __LINE__, length, upcb));
|
||||||
|
|
||||||
|
if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) {
|
||||||
|
return ESPCONN_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1470 < length) {
|
||||||
|
datalen = 1470;
|
||||||
|
} else {
|
||||||
|
datalen = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p));
|
||||||
|
|
||||||
|
if (p != NULL) {
|
||||||
|
q = p;
|
||||||
|
|
||||||
|
while (q != NULL) {
|
||||||
|
data = (u8_t *)q->payload;
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, data));
|
||||||
|
|
||||||
|
for (i = 0; i < q->len; i++) {
|
||||||
|
data[i] = ((u8_t *) psent)[cnt++];
|
||||||
|
}
|
||||||
|
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ESPCONN_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst_port = pespconn->proto.udp->remote_port;
|
||||||
|
IP4_ADDR(&dst_ip, pespconn->proto.udp->remote_ip[0],
|
||||||
|
pespconn->proto.udp->remote_ip[1], pespconn->proto.udp->remote_ip[2],
|
||||||
|
pespconn->proto.udp->remote_ip[3]);
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %x %d\n", __LINE__, upcb->remote_ip, upcb->remote_port));
|
||||||
|
|
||||||
|
struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00);
|
||||||
|
struct netif *ap_netif = (struct netif *)eagle_lwip_getif(0x01);
|
||||||
|
|
||||||
|
if(wifi_get_opmode() == ESPCONN_AP_STA && default_interface == ESPCONN_AP_STA && sta_netif != NULL && ap_netif != NULL)
|
||||||
|
{
|
||||||
|
if(netif_is_up(sta_netif) && netif_is_up(ap_netif) && \
|
||||||
|
ip_addr_isbroadcast(&upcb->remote_ip, sta_netif) && \
|
||||||
|
ip_addr_isbroadcast(&upcb->remote_ip, ap_netif)) {
|
||||||
|
|
||||||
|
p_temp = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);
|
||||||
|
if (pbuf_copy (p_temp,p) != ERR_OK) {
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sendto: copying to new pbuf failed\n"));
|
||||||
|
return ESPCONN_ARG;
|
||||||
|
}
|
||||||
|
netif_set_default(sta_netif);
|
||||||
|
err = udp_sendto(upcb, p_temp, &dst_ip, dst_port);
|
||||||
|
pbuf_free(p_temp);
|
||||||
|
netif_set_default(ap_netif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = udp_sendto(upcb, p, &dst_ip, dst_port);
|
||||||
|
|
||||||
|
if (p->ref != 0) {
|
||||||
|
pbuf_free(p);
|
||||||
|
pudp_sent->pcommon.ptrbuf = psent + datalen;
|
||||||
|
pudp_sent->pcommon.cntr = length - datalen;
|
||||||
|
pudp_sent->pcommon.err = err;
|
||||||
|
espconn_data_sent(pudp_sent, ESPCONN_SENDTO);
|
||||||
|
|
||||||
|
if (err > 0)
|
||||||
|
return ESPCONN_IF;
|
||||||
|
return err;
|
||||||
|
} else {
|
||||||
|
pbuf_free(p);
|
||||||
|
return ESPCONN_RTE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_udp_server_recv
|
||||||
|
* Description : This callback will be called when receiving a datagram.
|
||||||
|
* Parameters : arg -- user supplied argument
|
||||||
|
* upcb -- the udp_pcb which received data
|
||||||
|
* p -- the packet buffer that was received
|
||||||
|
* addr -- the remote IP address from which the packet was received
|
||||||
|
* port -- the remote port from which the packet was received
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
espconn_udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p,
|
||||||
|
struct ip_addr *addr, u16_t port)
|
||||||
|
{
|
||||||
|
espconn_msg *precv = arg;
|
||||||
|
u8_t *pdata = NULL;
|
||||||
|
u16_t length = 0;
|
||||||
|
struct ip_info ipconfig;
|
||||||
|
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_server_recv %d %p\n", __LINE__, upcb));
|
||||||
|
|
||||||
|
precv->pcommon.remote_ip[0] = ip4_addr1_16(addr);
|
||||||
|
precv->pcommon.remote_ip[1] = ip4_addr2_16(addr);
|
||||||
|
precv->pcommon.remote_ip[2] = ip4_addr3_16(addr);
|
||||||
|
precv->pcommon.remote_ip[3] = ip4_addr4_16(addr);
|
||||||
|
precv->pcommon.remote_port = port;
|
||||||
|
precv->pcommon.pcb = upcb;
|
||||||
|
|
||||||
|
if (wifi_get_opmode() != 1) {
|
||||||
|
wifi_get_ip_info(1, &ipconfig);
|
||||||
|
|
||||||
|
if (!ip_addr_netcmp(addr, &ipconfig.ip, &ipconfig.netmask)) {
|
||||||
|
wifi_get_ip_info(0, &ipconfig);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wifi_get_ip_info(0, &ipconfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
precv->pespconn->proto.udp->local_ip[0] = ip4_addr1_16(&ipconfig.ip);
|
||||||
|
precv->pespconn->proto.udp->local_ip[1] = ip4_addr2_16(&ipconfig.ip);
|
||||||
|
precv->pespconn->proto.udp->local_ip[2] = ip4_addr3_16(&ipconfig.ip);
|
||||||
|
precv->pespconn->proto.udp->local_ip[3] = ip4_addr4_16(&ipconfig.ip);
|
||||||
|
|
||||||
|
if (p != NULL) {
|
||||||
|
pdata = (u8_t *)os_zalloc(p ->tot_len + 1);
|
||||||
|
length = pbuf_copy_partial(p, pdata, p ->tot_len, 0);
|
||||||
|
precv->pcommon.pcb = upcb;
|
||||||
|
pbuf_free(p);
|
||||||
|
if (length != 0) {
|
||||||
|
if (precv->pespconn->recv_callback != NULL) {
|
||||||
|
precv->pespconn->recv_callback(precv->pespconn, (char *)pdata, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os_free(pdata);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_udp_disconnect
|
||||||
|
* Description : A new incoming connection has been disconnected.
|
||||||
|
* Parameters : espconn -- the espconn used to disconnect with host
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
void ICACHE_FLASH_ATTR espconn_udp_disconnect(espconn_msg *pdiscon)
|
||||||
|
{
|
||||||
|
if (pdiscon == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct udp_pcb *upcb = pdiscon->pcommon.pcb;
|
||||||
|
|
||||||
|
udp_disconnect(upcb);
|
||||||
|
|
||||||
|
udp_remove(upcb);
|
||||||
|
|
||||||
|
espconn_list_delete(&plink_active, pdiscon);
|
||||||
|
|
||||||
|
os_free(pdiscon);
|
||||||
|
pdiscon = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_udp_server
|
||||||
|
* Description : Initialize the server: set up a PCB and bind it to the port
|
||||||
|
* Parameters : pespconn -- the espconn used to build server
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
sint8 ICACHE_FLASH_ATTR
|
||||||
|
espconn_udp_server(struct espconn *pespconn)
|
||||||
|
{
|
||||||
|
struct udp_pcb *upcb = NULL;
|
||||||
|
espconn_msg *pserver = NULL;
|
||||||
|
upcb = udp_new();
|
||||||
|
|
||||||
|
if (upcb == NULL) {
|
||||||
|
return ESPCONN_MEM;
|
||||||
|
} else {
|
||||||
|
pserver = (espconn_msg *)os_zalloc(sizeof(espconn_msg));
|
||||||
|
|
||||||
|
if (pserver == NULL) {
|
||||||
|
udp_remove(upcb);
|
||||||
|
return ESPCONN_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
pserver->pcommon.pcb = upcb;
|
||||||
|
pserver->pespconn = pespconn;
|
||||||
|
espconn_list_creat(&plink_active, pserver);
|
||||||
|
udp_bind(upcb, IP_ADDR_ANY, pserver->pespconn->proto.udp->local_port);
|
||||||
|
udp_recv(upcb, espconn_udp_recv, (void *)pserver);
|
||||||
|
return ESPCONN_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_igmp_leave
|
||||||
|
* Description : leave a multicast group
|
||||||
|
* Parameters : host_ip -- the ip address of udp server
|
||||||
|
* multicast_ip -- multicast ip given by user
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
sint8 ICACHE_FLASH_ATTR
|
||||||
|
espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip)
|
||||||
|
{
|
||||||
|
if (igmp_leavegroup(host_ip, multicast_ip) != ERR_OK) {
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("udp_leave_multigrup failed!\n"));
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
return ESPCONN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* FunctionName : espconn_igmp_join
|
||||||
|
* Description : join a multicast group
|
||||||
|
* Parameters : host_ip -- the ip address of udp server
|
||||||
|
* multicast_ip -- multicast ip given by user
|
||||||
|
* Returns : none
|
||||||
|
*******************************************************************************/
|
||||||
|
sint8 ICACHE_FLASH_ATTR
|
||||||
|
espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip)
|
||||||
|
{
|
||||||
|
if (igmp_joingroup(host_ip, multicast_ip) != ERR_OK) {
|
||||||
|
LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("udp_join_multigrup failed!\n"));
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* join to any IP address at the port */
|
||||||
|
return ESPCONN_OK;
|
||||||
|
}
|
369
tools/sdk/lwip/src/app/netio.c
Normal file
369
tools/sdk/lwip/src/app/netio.c
Normal file
@ -0,0 +1,369 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* MetIO Server
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_TCP
|
||||||
|
#include "lwip/tcp.h"
|
||||||
|
|
||||||
|
#ifdef MEMLEAK_DEBUG
|
||||||
|
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This implements a netio server.
|
||||||
|
* The client sends a command word (4 bytes) then a data length word (4 bytes).
|
||||||
|
* If the command is "receive", the server is to consume "data length" bytes into
|
||||||
|
* a circular buffer until the first byte is non-zero, then it is to consume
|
||||||
|
* another command/data pair.
|
||||||
|
* If the command is "send", the server is to send "data length" bytes from a circular
|
||||||
|
* buffer with the first byte being zero, until "some time" (6 seconds in the
|
||||||
|
* current netio126.zip download) has passed and then send one final buffer with
|
||||||
|
* the first byte being non-zero. Then it is to consume another command/data pair.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */
|
||||||
|
|
||||||
|
/* implementation options */
|
||||||
|
#define NETIO_BUF_SIZE (4 * 1024)
|
||||||
|
#define NETIO_USE_STATIC_BUF 0
|
||||||
|
|
||||||
|
/* NetIO server state definition */
|
||||||
|
#define NETIO_STATE_WAIT_FOR_CMD 0
|
||||||
|
#define NETIO_STATE_RECV_DATA 1
|
||||||
|
#define NETIO_STATE_SEND_DATA 2
|
||||||
|
#define NETIO_STATE_SEND_DATA_LAST 3
|
||||||
|
#define NETIO_STATE_DONE 4
|
||||||
|
|
||||||
|
struct netio_state {
|
||||||
|
u32_t state;
|
||||||
|
u32_t cmd;
|
||||||
|
u32_t data_len;
|
||||||
|
u32_t cntr;
|
||||||
|
u8_t * buf_ptr;
|
||||||
|
u32_t buf_pos;
|
||||||
|
u32_t first_byte;
|
||||||
|
u32_t time_stamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* NetIO command protocol definition */
|
||||||
|
#define NETIO_CMD_QUIT 0
|
||||||
|
#define NETIO_CMD_C2S 1
|
||||||
|
#define NETIO_CMD_S2C 2
|
||||||
|
#define NETIO_CMD_RES 3
|
||||||
|
|
||||||
|
static err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
|
||||||
|
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
netio_close(void *arg, struct tcp_pcb *pcb)
|
||||||
|
{
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
struct netio_state *ns = arg;
|
||||||
|
ns->state = NETIO_STATE_DONE;
|
||||||
|
tcp_recv(pcb, NULL);
|
||||||
|
err = tcp_close(pcb);
|
||||||
|
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
/* closing failed, try again later */
|
||||||
|
tcp_recv(pcb, netio_recv);
|
||||||
|
} else {
|
||||||
|
/* closing succeeded */
|
||||||
|
#if NETIO_USE_STATIC_BUF != 1
|
||||||
|
if(ns->buf_ptr != NULL){
|
||||||
|
mem_free(ns->buf_ptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
tcp_arg(pcb, NULL);
|
||||||
|
tcp_poll(pcb, NULL, 0);
|
||||||
|
tcp_sent(pcb, NULL);
|
||||||
|
if (arg != NULL) {
|
||||||
|
mem_free(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t ICACHE_FLASH_ATTR
|
||||||
|
netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
|
||||||
|
{
|
||||||
|
struct netio_state *ns = arg;
|
||||||
|
u8_t * data_ptr;
|
||||||
|
u32_t data_cntr;
|
||||||
|
struct pbuf *q = p;
|
||||||
|
u16_t len;
|
||||||
|
|
||||||
|
if (p != NULL) {
|
||||||
|
tcp_recved(pcb, p->tot_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == ERR_OK && q != NULL) {
|
||||||
|
|
||||||
|
while (q != NULL) {
|
||||||
|
data_cntr = q->len;
|
||||||
|
data_ptr = q->payload;
|
||||||
|
while (data_cntr--) {
|
||||||
|
if (ns->state == NETIO_STATE_DONE){
|
||||||
|
netio_close(ns, pcb);
|
||||||
|
break;
|
||||||
|
} else if (ns->state == NETIO_STATE_WAIT_FOR_CMD) {
|
||||||
|
if (ns->cntr < 4) {
|
||||||
|
/* build up the CMD field */
|
||||||
|
ns->cmd <<= 8;
|
||||||
|
ns->cmd |= *data_ptr++;
|
||||||
|
ns->cntr++;
|
||||||
|
} else if (ns->cntr < 8) {
|
||||||
|
/* build up the DATA field */
|
||||||
|
ns->data_len <<= 8;
|
||||||
|
ns->data_len |= *data_ptr++;
|
||||||
|
ns->cntr++;
|
||||||
|
|
||||||
|
if (ns->cntr == 8) {
|
||||||
|
/* now we have full command and data words */
|
||||||
|
ns->cntr = 0;
|
||||||
|
ns->buf_pos = 0;
|
||||||
|
ns->buf_ptr[0] = 0;
|
||||||
|
if (ns->cmd == NETIO_CMD_C2S) {
|
||||||
|
ns->state = NETIO_STATE_RECV_DATA;
|
||||||
|
} else if (ns->cmd == NETIO_CMD_S2C) {
|
||||||
|
ns->state = NETIO_STATE_SEND_DATA;
|
||||||
|
/* start timer */
|
||||||
|
ns->time_stamp = sys_now();
|
||||||
|
/* send first round of data */
|
||||||
|
|
||||||
|
len = tcp_sndbuf(pcb);
|
||||||
|
len = LWIP_MIN(len, ns->data_len - ns->cntr);
|
||||||
|
len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
|
||||||
|
|
||||||
|
do {
|
||||||
|
err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
|
||||||
|
if (err == ERR_MEM) {
|
||||||
|
len /= 2;
|
||||||
|
}
|
||||||
|
} while ((err == ERR_MEM) && (len > 1));
|
||||||
|
|
||||||
|
ns->buf_pos += len;
|
||||||
|
ns->cntr += len;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* unrecognized command, punt */
|
||||||
|
ns->cntr = 0;
|
||||||
|
ns->buf_pos = 0;
|
||||||
|
ns->buf_ptr[0] = 0;
|
||||||
|
netio_close(ns, pcb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* in trouble... shouldn't be in this state! */
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (ns->state == NETIO_STATE_RECV_DATA) {
|
||||||
|
|
||||||
|
if(ns->cntr == 0){
|
||||||
|
/* save the first byte of this new round of data
|
||||||
|
* this will not match ns->buf_ptr[0] in the case that
|
||||||
|
* NETIO_BUF_SIZE is less than ns->data_len.
|
||||||
|
*/
|
||||||
|
ns->first_byte = *data_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ns->buf_ptr[ns->buf_pos++] = *data_ptr++;
|
||||||
|
ns->cntr++;
|
||||||
|
|
||||||
|
if (ns->buf_pos == NETIO_BUF_SIZE) {
|
||||||
|
/* circularize the buffer */
|
||||||
|
ns->buf_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ns->cntr == ns->data_len){
|
||||||
|
ns->cntr = 0;
|
||||||
|
if (ns->first_byte != 0) {
|
||||||
|
/* if this last round did not start with 0,
|
||||||
|
* go look for another command */
|
||||||
|
ns->state = NETIO_STATE_WAIT_FOR_CMD;
|
||||||
|
ns->data_len = 0;
|
||||||
|
ns->cmd = 0;
|
||||||
|
/* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
|
||||||
|
} else {
|
||||||
|
/* stay here and wait on more data */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (ns->state == NETIO_STATE_SEND_DATA
|
||||||
|
|| ns->state == NETIO_STATE_SEND_DATA_LAST) {
|
||||||
|
/* I don't think this should happen... */
|
||||||
|
} else {
|
||||||
|
/* done / quit */
|
||||||
|
netio_close(ns, pcb);
|
||||||
|
break;
|
||||||
|
} /* end of ns->state condition */
|
||||||
|
} /* end of while data still in this pbuf */
|
||||||
|
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf_free(p);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* error or closed by other side */
|
||||||
|
if (p != NULL) {
|
||||||
|
pbuf_free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* close the connection */
|
||||||
|
netio_close(ns, pcb);
|
||||||
|
|
||||||
|
}
|
||||||
|
return ERR_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t ICACHE_FLASH_ATTR
|
||||||
|
netio_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
|
||||||
|
{
|
||||||
|
struct netio_state *ns = arg;
|
||||||
|
err_t err = ERR_OK;
|
||||||
|
|
||||||
|
if (ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA) {
|
||||||
|
/* done with this round of sending */
|
||||||
|
ns->buf_pos = 0;
|
||||||
|
ns->cntr = 0;
|
||||||
|
|
||||||
|
/* check if timer expired */
|
||||||
|
if (sys_now() - ns->time_stamp > 600) {
|
||||||
|
ns->buf_ptr[0] = 1;
|
||||||
|
ns->state = NETIO_STATE_SEND_DATA_LAST;
|
||||||
|
} else {
|
||||||
|
ns->buf_ptr[0] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ns->state == NETIO_STATE_SEND_DATA_LAST || ns->state == NETIO_STATE_SEND_DATA){
|
||||||
|
len = tcp_sndbuf(pcb);
|
||||||
|
len = LWIP_MIN(len, ns->data_len - ns->cntr);
|
||||||
|
len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
|
||||||
|
|
||||||
|
if(ns->cntr < ns->data_len){
|
||||||
|
do {
|
||||||
|
err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
|
||||||
|
if (err == ERR_MEM) {
|
||||||
|
len /= 2;
|
||||||
|
}
|
||||||
|
} while ((err == ERR_MEM) && (len > 1));
|
||||||
|
|
||||||
|
ns->buf_pos += len;
|
||||||
|
if(ns->buf_pos >= NETIO_BUF_SIZE){
|
||||||
|
ns->buf_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ns->cntr += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA_LAST){
|
||||||
|
/* we have buffered up all our data to send this last round, go look for a command */
|
||||||
|
ns->state = NETIO_STATE_WAIT_FOR_CMD;
|
||||||
|
ns->cntr = 0;
|
||||||
|
/* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t ICACHE_FLASH_ATTR
|
||||||
|
netio_poll(void *arg, struct tcp_pcb *pcb)
|
||||||
|
{
|
||||||
|
struct netio_state * ns = arg;
|
||||||
|
if(ns->state == NETIO_STATE_SEND_DATA){
|
||||||
|
|
||||||
|
} else if(ns->state == NETIO_STATE_DONE){
|
||||||
|
netio_close(ns, pcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NETIO_USE_STATIC_BUF == 1
|
||||||
|
static u8_t netio_buf[NETIO_BUF_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static err_t ICACHE_FLASH_ATTR
|
||||||
|
netio_accept(void *arg, struct tcp_pcb *pcb, err_t err)
|
||||||
|
{
|
||||||
|
struct netio_state * ns;
|
||||||
|
|
||||||
|
LWIP_UNUSED_ARG(err);
|
||||||
|
|
||||||
|
ns = (struct netio_state *)mem_malloc(sizeof(struct netio_state));
|
||||||
|
|
||||||
|
if(ns == NULL){
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ns->state = NETIO_STATE_WAIT_FOR_CMD;
|
||||||
|
ns->data_len = 0;
|
||||||
|
ns->cmd = 0;
|
||||||
|
ns->cntr = 0;
|
||||||
|
ns->buf_pos = 0;
|
||||||
|
#if NETIO_USE_STATIC_BUF == 1
|
||||||
|
ns->buf_ptr = netio_buf;
|
||||||
|
#else
|
||||||
|
ns->buf_ptr = (u8_t *)mem_malloc(NETIO_BUF_SIZE);
|
||||||
|
|
||||||
|
if(ns->buf_ptr == NULL){
|
||||||
|
mem_free(ns);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ns->buf_ptr[0] = 0;
|
||||||
|
|
||||||
|
tcp_arg(pcb, ns);
|
||||||
|
tcp_sent(pcb, netio_sent);
|
||||||
|
tcp_recv(pcb, netio_recv);
|
||||||
|
tcp_poll(pcb, netio_poll, 4); /* every 2 seconds */
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICACHE_FLASH_ATTR netio_init(void)
|
||||||
|
{
|
||||||
|
struct tcp_pcb *pcb;
|
||||||
|
|
||||||
|
pcb = tcp_new();
|
||||||
|
tcp_bind(pcb, IP_ADDR_ANY, 18767);
|
||||||
|
pcb = tcp_listen(pcb);
|
||||||
|
tcp_accept(pcb, netio_accept);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_TCP */
|
329
tools/sdk/lwip/src/app/ping.c
Normal file
329
tools/sdk/lwip/src/app/ping.c
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Ping sender module
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an example of a "ping" sender (with raw API and socket API).
|
||||||
|
* It can be used as a start point to maintain opened a network connection, or
|
||||||
|
* like a network "watchdog" for your device.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* copyright (c) 2010 - 2011 Espressif System
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/raw.h"
|
||||||
|
#include "lwip/icmp.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
#include "lwip/timers.h"
|
||||||
|
#include "lwip/inet_chksum.h"
|
||||||
|
#include "os_type.h"
|
||||||
|
#include "osapi.h"
|
||||||
|
|
||||||
|
#include "lwip/app/ping.h"
|
||||||
|
|
||||||
|
#if PING_USE_SOCKETS
|
||||||
|
#include "lwip/sockets.h"
|
||||||
|
#include "lwip/inet.h"
|
||||||
|
#endif /* PING_USE_SOCKETS */
|
||||||
|
|
||||||
|
#ifdef MEMLEAK_DEBUG
|
||||||
|
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ping variables */
|
||||||
|
static u16_t ping_seq_num = 0;
|
||||||
|
static u32_t ping_time;
|
||||||
|
|
||||||
|
static void ICACHE_FLASH_ATTR ping_timeout(void* arg)
|
||||||
|
{
|
||||||
|
struct ping_msg *pingmsg = (struct ping_msg *)arg;
|
||||||
|
pingmsg->timeout_count ++;
|
||||||
|
if (pingmsg->ping_opt->recv_function == NULL){
|
||||||
|
os_printf("ping timeout\n");
|
||||||
|
} else {
|
||||||
|
struct ping_resp pingresp;
|
||||||
|
os_bzero(&pingresp, sizeof(struct ping_resp));
|
||||||
|
pingresp.ping_err = -1;
|
||||||
|
pingmsg->ping_opt->recv_function(pingmsg->ping_opt, (void*)&pingresp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Prepare a echo ICMP request */
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
size_t data_len = len - sizeof(struct icmp_echo_hdr);
|
||||||
|
|
||||||
|
ICMPH_TYPE_SET(iecho, ICMP_ECHO);
|
||||||
|
ICMPH_CODE_SET(iecho, 0);
|
||||||
|
iecho->chksum = 0;
|
||||||
|
iecho->id = PING_ID;
|
||||||
|
++ ping_seq_num;
|
||||||
|
if (ping_seq_num == 0x7fff)
|
||||||
|
ping_seq_num = 0;
|
||||||
|
|
||||||
|
iecho->seqno = htons(ping_seq_num);
|
||||||
|
|
||||||
|
/* fill the additional data buffer with some data */
|
||||||
|
for(i = 0; i < data_len; i++) {
|
||||||
|
((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
iecho->chksum = inet_chksum(iecho, len);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
ping_prepare_er(struct icmp_echo_hdr *iecho, u16_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
ICMPH_TYPE_SET(iecho, ICMP_ER);
|
||||||
|
ICMPH_CODE_SET(iecho, 0);
|
||||||
|
iecho->chksum = 0;
|
||||||
|
|
||||||
|
iecho->chksum = inet_chksum(iecho, len);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/* Ping using the raw ip */
|
||||||
|
static u8_t ICACHE_FLASH_ATTR
|
||||||
|
ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr)
|
||||||
|
{
|
||||||
|
struct icmp_echo_hdr *iecho = NULL;
|
||||||
|
static u16_t seqno = 0;
|
||||||
|
struct ping_msg *pingmsg = (struct ping_msg*)arg;
|
||||||
|
|
||||||
|
LWIP_UNUSED_ARG(arg);
|
||||||
|
LWIP_UNUSED_ARG(pcb);
|
||||||
|
LWIP_UNUSED_ARG(addr);
|
||||||
|
LWIP_ASSERT("p != NULL", p != NULL);
|
||||||
|
|
||||||
|
if (pbuf_header( p, -PBUF_IP_HLEN)==0) {
|
||||||
|
iecho = (struct icmp_echo_hdr *)p->payload;
|
||||||
|
|
||||||
|
if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)) && iecho->type == ICMP_ER) {
|
||||||
|
LWIP_DEBUGF( PING_DEBUG, ("ping: recv "));
|
||||||
|
ip_addr_debug_print(PING_DEBUG, addr);
|
||||||
|
LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now()-ping_time)));
|
||||||
|
if (iecho->seqno != seqno){
|
||||||
|
/* do some ping result processing */
|
||||||
|
{
|
||||||
|
struct ip_hdr *iphdr = NULL;
|
||||||
|
char ipaddrstr[16];
|
||||||
|
ip_addr_t source_ip;
|
||||||
|
sys_untimeout(ping_timeout, pingmsg);
|
||||||
|
os_bzero(&source_ip, sizeof(ip_addr_t));
|
||||||
|
os_bzero(ipaddrstr, sizeof(ipaddrstr));
|
||||||
|
uint32 delay = system_relative_time(pingmsg->ping_sent);
|
||||||
|
delay /= PING_COARSE;
|
||||||
|
iphdr = (struct ip_hdr*)((u8*)iecho - PBUF_IP_HLEN);
|
||||||
|
source_ip.addr = iphdr->src.addr;
|
||||||
|
ipaddr_ntoa_r(&source_ip,ipaddrstr, sizeof(ipaddrstr));
|
||||||
|
if (pingmsg->ping_opt->recv_function == NULL){
|
||||||
|
os_printf("recv %s: byte = %d, time = %d ms, seq = %d\n",ipaddrstr, PING_DATA_SIZE, delay, ntohs(iecho->seqno));
|
||||||
|
} else {
|
||||||
|
struct ping_resp pingresp;
|
||||||
|
os_bzero(&pingresp, sizeof(struct ping_resp));
|
||||||
|
pingresp.bytes = PING_DATA_SIZE;
|
||||||
|
pingresp.resp_time = delay;
|
||||||
|
pingresp.seqno = ntohs(iecho->seqno);
|
||||||
|
pingresp.ping_err = 0;
|
||||||
|
pingmsg->ping_opt->recv_function(pingmsg->ping_opt,(void*) &pingresp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seqno = iecho->seqno;
|
||||||
|
}
|
||||||
|
|
||||||
|
PING_RESULT(1);
|
||||||
|
pbuf_free(p);
|
||||||
|
return 1; /* eat the packet */
|
||||||
|
}
|
||||||
|
// } else if(iecho->type == ICMP_ECHO){
|
||||||
|
// struct pbuf *q = NULL;
|
||||||
|
// os_printf("receive ping request:seq=%d\n", ntohs(iecho->seqno));
|
||||||
|
// q = pbuf_alloc(PBUF_IP, (u16_t)p->tot_len, PBUF_RAM);
|
||||||
|
// if (q!=NULL) {
|
||||||
|
// pbuf_copy(q, p);
|
||||||
|
// iecho = (struct icmp_echo_hdr *)q->payload;
|
||||||
|
// ping_prepare_er(iecho, q->tot_len);
|
||||||
|
// raw_sendto(pcb, q, addr);
|
||||||
|
// pbuf_free(q);
|
||||||
|
// }
|
||||||
|
// pbuf_free(p);
|
||||||
|
// return 1;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* don't eat the packet */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
ping_send(struct raw_pcb *raw, ip_addr_t *addr)
|
||||||
|
{
|
||||||
|
struct pbuf *p = NULL;
|
||||||
|
struct icmp_echo_hdr *iecho = NULL;
|
||||||
|
size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
|
||||||
|
|
||||||
|
LWIP_DEBUGF( PING_DEBUG, ("ping: send "));
|
||||||
|
ip_addr_debug_print(PING_DEBUG, addr);
|
||||||
|
LWIP_DEBUGF( PING_DEBUG, ("\n"));
|
||||||
|
LWIP_ASSERT("ping_size <= 0xffff", ping_size <= 0xffff);
|
||||||
|
|
||||||
|
p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM);
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((p->len == p->tot_len) && (p->next == NULL)) {
|
||||||
|
iecho = (struct icmp_echo_hdr *)p->payload;
|
||||||
|
|
||||||
|
ping_prepare_echo(iecho, (u16_t)ping_size);
|
||||||
|
|
||||||
|
raw_sendto(raw, p, addr);
|
||||||
|
ping_time = sys_now();
|
||||||
|
}
|
||||||
|
pbuf_free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
ping_coarse_tmr(void *arg)
|
||||||
|
{
|
||||||
|
struct ping_msg *pingmsg = (struct ping_msg*)arg;
|
||||||
|
struct ping_option *ping_opt= NULL;
|
||||||
|
struct ping_resp pingresp;
|
||||||
|
ip_addr_t ping_target;
|
||||||
|
|
||||||
|
LWIP_ASSERT("ping_timeout: no pcb given!", pingmsg != NULL);
|
||||||
|
ping_target.addr = pingmsg->ping_opt->ip;
|
||||||
|
ping_opt = pingmsg->ping_opt;
|
||||||
|
if (--pingmsg->sent_count != 0){
|
||||||
|
pingmsg ->ping_sent = system_get_time();
|
||||||
|
ping_send(pingmsg->ping_pcb, &ping_target);
|
||||||
|
|
||||||
|
sys_timeout(PING_TIMEOUT_MS, ping_timeout, pingmsg);
|
||||||
|
sys_timeout(pingmsg->coarse_time, ping_coarse_tmr, pingmsg);
|
||||||
|
} else {
|
||||||
|
uint32 delay = system_relative_time(pingmsg->ping_start);
|
||||||
|
delay /= PING_COARSE;
|
||||||
|
// ping_seq_num = 0;
|
||||||
|
if (ping_opt->sent_function == NULL){
|
||||||
|
os_printf("ping %d, timeout %d, total payload %d bytes, %d ms\n",
|
||||||
|
pingmsg->max_count, pingmsg->timeout_count, PING_DATA_SIZE*(pingmsg->max_count - pingmsg->timeout_count),delay);
|
||||||
|
} else {
|
||||||
|
os_bzero(&pingresp, sizeof(struct ping_resp));
|
||||||
|
pingresp.total_count = pingmsg->max_count;
|
||||||
|
pingresp.timeout_count = pingmsg->timeout_count;
|
||||||
|
pingresp.total_bytes = PING_DATA_SIZE*(pingmsg->max_count - pingmsg->timeout_count);
|
||||||
|
pingresp.total_time = delay;
|
||||||
|
pingresp.ping_err = 0;
|
||||||
|
}
|
||||||
|
sys_untimeout(ping_coarse_tmr, pingmsg);
|
||||||
|
raw_remove(pingmsg->ping_pcb);
|
||||||
|
os_free(pingmsg);
|
||||||
|
if (ping_opt->sent_function != NULL)
|
||||||
|
ping_opt->sent_function(ping_opt,(uint8*)&pingresp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ICACHE_FLASH_ATTR
|
||||||
|
ping_raw_init(struct ping_msg *pingmsg)
|
||||||
|
{
|
||||||
|
if (pingmsg == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ip_addr_t ping_target;
|
||||||
|
pingmsg->ping_pcb = raw_new(IP_PROTO_ICMP);
|
||||||
|
LWIP_ASSERT("ping_pcb != NULL", pingmsg->ping_pcb != NULL);
|
||||||
|
|
||||||
|
raw_recv(pingmsg->ping_pcb, ping_recv, pingmsg);
|
||||||
|
raw_bind(pingmsg->ping_pcb, IP_ADDR_ANY);
|
||||||
|
|
||||||
|
ping_target.addr = pingmsg->ping_opt->ip;
|
||||||
|
pingmsg ->ping_sent = system_get_time();
|
||||||
|
ping_send(pingmsg->ping_pcb, &ping_target);
|
||||||
|
|
||||||
|
sys_timeout(PING_TIMEOUT_MS, ping_timeout, pingmsg);
|
||||||
|
sys_timeout(pingmsg->coarse_time, ping_coarse_tmr, pingmsg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICACHE_FLASH_ATTR
|
||||||
|
ping_start(struct ping_option *ping_opt)
|
||||||
|
{
|
||||||
|
struct ping_msg *pingmsg = NULL;
|
||||||
|
pingmsg = (struct ping_msg *)os_zalloc(sizeof(struct ping_msg));
|
||||||
|
if (pingmsg == NULL || ping_opt == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pingmsg->ping_opt = ping_opt;
|
||||||
|
if (ping_opt->count != 0)
|
||||||
|
pingmsg->max_count = ping_opt->count;
|
||||||
|
else
|
||||||
|
pingmsg->max_count = DEFAULT_PING_MAX_COUNT;
|
||||||
|
|
||||||
|
if (ping_opt->coarse_time != 0)
|
||||||
|
pingmsg->coarse_time = ping_opt->coarse_time * PING_COARSE;
|
||||||
|
else
|
||||||
|
pingmsg->coarse_time = PING_COARSE;
|
||||||
|
|
||||||
|
pingmsg->ping_start = system_get_time();
|
||||||
|
pingmsg->sent_count = pingmsg->max_count;
|
||||||
|
return ping_raw_init(pingmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICACHE_FLASH_ATTR
|
||||||
|
ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv)
|
||||||
|
{
|
||||||
|
if (ping_opt == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ping_opt ->recv_function = ping_recv;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICACHE_FLASH_ATTR
|
||||||
|
ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent)
|
||||||
|
{
|
||||||
|
if (ping_opt == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ping_opt ->sent_function = ping_sent;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_RAW */
|
108
tools/sdk/lwip/src/core/def.c
Normal file
108
tools/sdk/lwip/src/core/def.c
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Common functions used throughout the stack.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Simon Goldschmidt
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
#include "lwip/def.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These are reference implementations of the byte swapping functions.
|
||||||
|
* Again with the aim of being simple, correct and fully portable.
|
||||||
|
* Byte swapping is the second thing you would want to optimize. You will
|
||||||
|
* need to port it to your architecture and in your cc.h:
|
||||||
|
*
|
||||||
|
* #define LWIP_PLATFORM_BYTESWAP 1
|
||||||
|
* #define LWIP_PLATFORM_HTONS(x) <your_htons>
|
||||||
|
* #define LWIP_PLATFORM_HTONL(x) <your_htonl>
|
||||||
|
*
|
||||||
|
* Note ntohs() and ntohl() are merely references to the htonx counterparts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an u16_t from host- to network byte order.
|
||||||
|
*
|
||||||
|
* @param n u16_t in host byte order
|
||||||
|
* @return n in network byte order
|
||||||
|
*/
|
||||||
|
u16_t
|
||||||
|
lwip_htons(u16_t n)
|
||||||
|
{
|
||||||
|
return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an u16_t from network- to host byte order.
|
||||||
|
*
|
||||||
|
* @param n u16_t in network byte order
|
||||||
|
* @return n in host byte order
|
||||||
|
*/
|
||||||
|
u16_t
|
||||||
|
lwip_ntohs(u16_t n)
|
||||||
|
{
|
||||||
|
return lwip_htons(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an u32_t from host- to network byte order.
|
||||||
|
*
|
||||||
|
* @param n u32_t in host byte order
|
||||||
|
* @return n in network byte order
|
||||||
|
*/
|
||||||
|
u32_t
|
||||||
|
lwip_htonl(u32_t n)
|
||||||
|
{
|
||||||
|
return ((n & 0xff) << 24) |
|
||||||
|
((n & 0xff00) << 8) |
|
||||||
|
((n & 0xff0000UL) >> 8) |
|
||||||
|
((n & 0xff000000UL) >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an u32_t from network- to host byte order.
|
||||||
|
*
|
||||||
|
* @param n u32_t in network byte order
|
||||||
|
* @return n in host byte order
|
||||||
|
*/
|
||||||
|
u32_t
|
||||||
|
lwip_ntohl(u32_t n)
|
||||||
|
{
|
||||||
|
return lwip_htonl(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */
|
1815
tools/sdk/lwip/src/core/dhcp.c
Normal file
1815
tools/sdk/lwip/src/core/dhcp.c
Normal file
File diff suppressed because it is too large
Load Diff
980
tools/sdk/lwip/src/core/dns.c
Normal file
980
tools/sdk/lwip/src/core/dns.c
Normal file
@ -0,0 +1,980 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* DNS - host name to IP address resolver.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
* This file implements a DNS host name to IP address resolver.
|
||||||
|
|
||||||
|
* Port to lwIP from uIP
|
||||||
|
* by Jim Pettinato April 2007
|
||||||
|
|
||||||
|
* uIP version Copyright (c) 2002-2003, Adam Dunkels.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote
|
||||||
|
* products derived from this software without specific prior
|
||||||
|
* written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||||
|
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DNS.C
|
||||||
|
*
|
||||||
|
* The lwIP DNS resolver functions are used to lookup a host name and
|
||||||
|
* map it to a numerical IP address. It maintains a list of resolved
|
||||||
|
* hostnames that can be queried with the dns_lookup() function.
|
||||||
|
* New hostnames can be resolved using the dns_query() function.
|
||||||
|
*
|
||||||
|
* The lwIP version of the resolver also adds a non-blocking version of
|
||||||
|
* gethostbyname() that will work with a raw API application. This function
|
||||||
|
* checks for an IP address string first and converts it if it is valid.
|
||||||
|
* gethostbyname() then does a dns_lookup() to see if the name is
|
||||||
|
* already in the table. If so, the IP is returned. If not, a query is
|
||||||
|
* issued and the function returns with a ERR_INPROGRESS status. The app
|
||||||
|
* using the dns client must then go into a waiting state.
|
||||||
|
*
|
||||||
|
* Once a hostname has been resolved (or found to be non-existent),
|
||||||
|
* the resolver code calls a specified callback function (which
|
||||||
|
* must be implemented by the module that uses the resolver).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
* RFC 1035 - Domain names - implementation and specification
|
||||||
|
* RFC 2181 - Clarifications to the DNS Specification
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/** @todo: define good default values (rfc compliance) */
|
||||||
|
/** @todo: improve answer parsing, more checkings... */
|
||||||
|
/** @todo: check RFC1035 - 7.3. Processing responses */
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
* Includes
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/memp.h"
|
||||||
|
#include "lwip/dns.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef MEMLEAK_DEBUG
|
||||||
|
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** DNS server IP address */
|
||||||
|
#ifndef DNS_SERVER_ADDRESS
|
||||||
|
#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, 0xDEDE43D0)) /* resolver1.opendns.com(208.67.222.222) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** DNS server port address */
|
||||||
|
#ifndef DNS_SERVER_PORT
|
||||||
|
#define DNS_SERVER_PORT 53
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** DNS maximum number of retries when asking for a name, before "timeout". */
|
||||||
|
#ifndef DNS_MAX_RETRIES
|
||||||
|
#define DNS_MAX_RETRIES 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** DNS resource record max. TTL (one week as default) */
|
||||||
|
#ifndef DNS_MAX_TTL
|
||||||
|
#define DNS_MAX_TTL 604800
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* DNS protocol flags */
|
||||||
|
#define DNS_FLAG1_RESPONSE 0x80
|
||||||
|
#define DNS_FLAG1_OPCODE_STATUS 0x10
|
||||||
|
#define DNS_FLAG1_OPCODE_INVERSE 0x08
|
||||||
|
#define DNS_FLAG1_OPCODE_STANDARD 0x00
|
||||||
|
#define DNS_FLAG1_AUTHORATIVE 0x04
|
||||||
|
#define DNS_FLAG1_TRUNC 0x02
|
||||||
|
#define DNS_FLAG1_RD 0x01
|
||||||
|
#define DNS_FLAG2_RA 0x80
|
||||||
|
#define DNS_FLAG2_ERR_MASK 0x0f
|
||||||
|
#define DNS_FLAG2_ERR_NONE 0x00
|
||||||
|
#define DNS_FLAG2_ERR_NAME 0x03
|
||||||
|
|
||||||
|
/* DNS protocol states */
|
||||||
|
#define DNS_STATE_UNUSED 0
|
||||||
|
#define DNS_STATE_NEW 1
|
||||||
|
#define DNS_STATE_ASKING 2
|
||||||
|
#define DNS_STATE_DONE 3
|
||||||
|
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/bpstruct.h"
|
||||||
|
#endif
|
||||||
|
PACK_STRUCT_BEGIN
|
||||||
|
/** DNS message header */
|
||||||
|
struct dns_hdr {
|
||||||
|
PACK_STRUCT_FIELD(u16_t id);
|
||||||
|
PACK_STRUCT_FIELD(u8_t flags1);
|
||||||
|
PACK_STRUCT_FIELD(u8_t flags2);
|
||||||
|
PACK_STRUCT_FIELD(u16_t numquestions);
|
||||||
|
PACK_STRUCT_FIELD(u16_t numanswers);
|
||||||
|
PACK_STRUCT_FIELD(u16_t numauthrr);
|
||||||
|
PACK_STRUCT_FIELD(u16_t numextrarr);
|
||||||
|
} PACK_STRUCT_STRUCT;
|
||||||
|
PACK_STRUCT_END
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/epstruct.h"
|
||||||
|
#endif
|
||||||
|
#define SIZEOF_DNS_HDR 12
|
||||||
|
|
||||||
|
/** DNS query message structure.
|
||||||
|
No packing needed: only used locally on the stack. */
|
||||||
|
struct dns_query {
|
||||||
|
/* DNS query record starts with either a domain name or a pointer
|
||||||
|
to a name already present somewhere in the packet. */
|
||||||
|
u16_t type;
|
||||||
|
u16_t cls;
|
||||||
|
};
|
||||||
|
#define SIZEOF_DNS_QUERY 4
|
||||||
|
|
||||||
|
/** DNS answer message structure.
|
||||||
|
No packing needed: only used locally on the stack. */
|
||||||
|
struct dns_answer {
|
||||||
|
/* DNS answer record starts with either a domain name or a pointer
|
||||||
|
to a name already present somewhere in the packet. */
|
||||||
|
u16_t type;
|
||||||
|
u16_t cls;
|
||||||
|
u32_t ttl;
|
||||||
|
u16_t len;
|
||||||
|
};
|
||||||
|
#define SIZEOF_DNS_ANSWER 10
|
||||||
|
|
||||||
|
/** DNS table entry */
|
||||||
|
struct dns_table_entry {
|
||||||
|
u8_t state;
|
||||||
|
u8_t numdns;
|
||||||
|
u8_t tmr;
|
||||||
|
u8_t retries;
|
||||||
|
u8_t seqno;
|
||||||
|
u8_t err;
|
||||||
|
u32_t ttl;
|
||||||
|
char name[DNS_MAX_NAME_LENGTH];
|
||||||
|
ip_addr_t ipaddr;
|
||||||
|
/* pointer to callback on DNS query done */
|
||||||
|
dns_found_callback found;
|
||||||
|
void *arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if DNS_LOCAL_HOSTLIST
|
||||||
|
|
||||||
|
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||||
|
/** Local host-list. For hostnames in this list, no
|
||||||
|
* external name resolution is performed */
|
||||||
|
static struct local_hostlist_entry *local_hostlist_dynamic;
|
||||||
|
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||||
|
|
||||||
|
/** Defining this allows the local_hostlist_static to be placed in a different
|
||||||
|
* linker section (e.g. FLASH) */
|
||||||
|
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
|
||||||
|
#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
|
||||||
|
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
|
||||||
|
/** Defining this allows the local_hostlist_static to be placed in a different
|
||||||
|
* linker section (e.g. FLASH) */
|
||||||
|
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
|
||||||
|
#define DNS_LOCAL_HOSTLIST_STORAGE_POST
|
||||||
|
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
|
||||||
|
DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
|
||||||
|
DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
|
||||||
|
|
||||||
|
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||||
|
|
||||||
|
static void dns_init_local();
|
||||||
|
#endif /* DNS_LOCAL_HOSTLIST */
|
||||||
|
|
||||||
|
|
||||||
|
/* forward declarations */
|
||||||
|
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
|
||||||
|
static void dns_check_entries(void);
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
* Globales
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* DNS variables */
|
||||||
|
static struct udp_pcb *dns_pcb;
|
||||||
|
static u8_t dns_seqno;
|
||||||
|
static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
|
||||||
|
static ip_addr_t dns_servers[DNS_MAX_SERVERS];
|
||||||
|
/** Contiguous buffer for processing responses */
|
||||||
|
//static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
|
||||||
|
static u8_t* dns_payload;
|
||||||
|
static u8_t dns_random;
|
||||||
|
/**
|
||||||
|
* Initialize the resolver: set up the UDP pcb and configure the default server
|
||||||
|
* (DNS_SERVER_ADDRESS).
|
||||||
|
*/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
dns_init()
|
||||||
|
{
|
||||||
|
ip_addr_t dnsserver;
|
||||||
|
|
||||||
|
// dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
|
||||||
|
|
||||||
|
/* initialize default DNS server address */
|
||||||
|
DNS_SERVER_ADDRESS(&dnsserver);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
|
||||||
|
|
||||||
|
/* if dns client not yet initialized... */
|
||||||
|
if (dns_pcb == NULL) {
|
||||||
|
dns_pcb = udp_new();
|
||||||
|
|
||||||
|
if (dns_pcb != NULL) {
|
||||||
|
/* initialize DNS table not needed (initialized to zero since it is a
|
||||||
|
* global variable) */
|
||||||
|
LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
|
||||||
|
DNS_STATE_UNUSED == 0);
|
||||||
|
|
||||||
|
/* initialize DNS client */
|
||||||
|
udp_bind(dns_pcb, IP_ADDR_ANY, 0);
|
||||||
|
udp_recv(dns_pcb, dns_recv, NULL);
|
||||||
|
|
||||||
|
/* initialize default DNS primary server */
|
||||||
|
dns_setserver(0, &dnsserver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if DNS_LOCAL_HOSTLIST
|
||||||
|
dns_init_local();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize one of the DNS servers.
|
||||||
|
*
|
||||||
|
* @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
|
||||||
|
* @param dnsserver IP address of the DNS server to set
|
||||||
|
*/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
|
||||||
|
{
|
||||||
|
if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
|
||||||
|
(dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
|
||||||
|
dns_servers[numdns] = (*dnsserver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain one of the currently configured DNS server.
|
||||||
|
*
|
||||||
|
* @param numdns the index of the DNS server
|
||||||
|
* @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
|
||||||
|
* server has not been configured.
|
||||||
|
*/
|
||||||
|
ip_addr_t ICACHE_FLASH_ATTR
|
||||||
|
dns_getserver(u8_t numdns)
|
||||||
|
{
|
||||||
|
if (numdns < DNS_MAX_SERVERS) {
|
||||||
|
return dns_servers[numdns];
|
||||||
|
} else {
|
||||||
|
return *IP_ADDR_ANY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DNS resolver client timer - handle retries and timeouts and should
|
||||||
|
* be called every DNS_TMR_INTERVAL milliseconds (every second by default).
|
||||||
|
*/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
dns_tmr(void)
|
||||||
|
{
|
||||||
|
if (dns_pcb != NULL) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
|
||||||
|
dns_check_entries();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DNS_LOCAL_HOSTLIST
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
dns_init_local()
|
||||||
|
{
|
||||||
|
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
|
||||||
|
int i;
|
||||||
|
struct local_hostlist_entry *entry;
|
||||||
|
/* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
|
||||||
|
struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
|
||||||
|
size_t namelen;
|
||||||
|
for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
|
||||||
|
struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
|
||||||
|
LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
|
||||||
|
namelen = os_strlen(init_entry->name);
|
||||||
|
LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
|
||||||
|
entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
|
||||||
|
LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
|
||||||
|
if (entry != NULL) {
|
||||||
|
entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
|
||||||
|
MEMCPY((char*)entry->name, init_entry->name, namelen);
|
||||||
|
((char*)entry->name)[namelen] = 0;
|
||||||
|
entry->addr = init_entry->addr;
|
||||||
|
entry->next = local_hostlist_dynamic;
|
||||||
|
local_hostlist_dynamic = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans the local host-list for a hostname.
|
||||||
|
*
|
||||||
|
* @param hostname Hostname to look for in the local host-list
|
||||||
|
* @return The first IP address for the hostname in the local host-list or
|
||||||
|
* IPADDR_NONE if not found.
|
||||||
|
*/
|
||||||
|
static u32_t ICACHE_FLASH_ATTR
|
||||||
|
dns_lookup_local(const char *hostname)
|
||||||
|
{
|
||||||
|
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||||
|
struct local_hostlist_entry *entry = local_hostlist_dynamic;
|
||||||
|
while(entry != NULL) {
|
||||||
|
if(strcmp(entry->name, hostname) == 0) {
|
||||||
|
return ip4_addr_get_u32(&entry->addr);
|
||||||
|
}
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
|
||||||
|
if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
|
||||||
|
return ip4_addr_get_u32(&local_hostlist_static[i].addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||||
|
return IPADDR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||||
|
/** Remove all entries from the local host-list for a specific hostname
|
||||||
|
* and/or IP addess
|
||||||
|
*
|
||||||
|
* @param hostname hostname for which entries shall be removed from the local
|
||||||
|
* host-list
|
||||||
|
* @param addr address for which entries shall be removed from the local host-list
|
||||||
|
* @return the number of removed entries
|
||||||
|
*/
|
||||||
|
int ICACHE_FLASH_ATTR
|
||||||
|
dns_local_removehost(const char *hostname, const ip_addr_t *addr)
|
||||||
|
{
|
||||||
|
int removed = 0;
|
||||||
|
struct local_hostlist_entry *entry = local_hostlist_dynamic;
|
||||||
|
struct local_hostlist_entry *last_entry = NULL;
|
||||||
|
while (entry != NULL) {
|
||||||
|
if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
|
||||||
|
((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
|
||||||
|
struct local_hostlist_entry *free_entry;
|
||||||
|
if (last_entry != NULL) {
|
||||||
|
last_entry->next = entry->next;
|
||||||
|
} else {
|
||||||
|
local_hostlist_dynamic = entry->next;
|
||||||
|
}
|
||||||
|
free_entry = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
memp_free(MEMP_LOCALHOSTLIST, free_entry);
|
||||||
|
removed++;
|
||||||
|
} else {
|
||||||
|
last_entry = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a hostname/IP address pair to the local host-list.
|
||||||
|
* Duplicates are not checked.
|
||||||
|
*
|
||||||
|
* @param hostname hostname of the new entry
|
||||||
|
* @param addr IP address of the new entry
|
||||||
|
* @return ERR_OK if succeeded or ERR_MEM on memory error
|
||||||
|
*/
|
||||||
|
err_t ICACHE_FLASH_ATTR
|
||||||
|
dns_local_addhost(const char *hostname, const ip_addr_t *addr)
|
||||||
|
{
|
||||||
|
struct local_hostlist_entry *entry;
|
||||||
|
size_t namelen;
|
||||||
|
LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
|
||||||
|
namelen = os_strlen(hostname);
|
||||||
|
LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
|
||||||
|
entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
|
||||||
|
if (entry == NULL) {
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
|
||||||
|
MEMCPY((char*)entry->name, hostname, namelen);
|
||||||
|
((char*)entry->name)[namelen] = 0;
|
||||||
|
ip_addr_copy(entry->addr, *addr);
|
||||||
|
entry->next = local_hostlist_dynamic;
|
||||||
|
local_hostlist_dynamic = entry;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
|
||||||
|
#endif /* DNS_LOCAL_HOSTLIST */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up a hostname in the array of known hostnames.
|
||||||
|
*
|
||||||
|
* @note This function only looks in the internal array of known
|
||||||
|
* hostnames, it does not send out a query for the hostname if none
|
||||||
|
* was found. The function dns_enqueue() can be used to send a query
|
||||||
|
* for a hostname.
|
||||||
|
*
|
||||||
|
* @param name the hostname to look up
|
||||||
|
* @return the hostname's IP address, as u32_t (instead of ip_addr_t to
|
||||||
|
* better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname
|
||||||
|
* was not found in the cached dns_table.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
static u32_t ICACHE_FLASH_ATTR
|
||||||
|
dns_lookup(const char *name)
|
||||||
|
{
|
||||||
|
u8_t i;
|
||||||
|
#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
|
||||||
|
u32_t addr;
|
||||||
|
#endif
|
||||||
|
#if DNS_LOCAL_HOSTLIST
|
||||||
|
if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef DNS_LOOKUP_LOCAL_EXTERN
|
||||||
|
if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Walk through name list, return entry if found. If not, return NULL.
|
||||||
|
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
|
||||||
|
if ((dns_table[i].state == DNS_STATE_DONE) &&
|
||||||
|
(strcmp(name, dns_table[i].name) == 0)) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
|
||||||
|
ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
|
||||||
|
return ip4_addr_get_u32(&dns_table[i].ipaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return IPADDR_NONE;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#if DNS_DOES_NAME_CHECK
|
||||||
|
/**
|
||||||
|
* Compare the "dotted" name "query" with the encoded name "response"
|
||||||
|
* to make sure an answer from the DNS server matches the current dns_table
|
||||||
|
* entry (otherwise, answers might arrive late for hostname not on the list
|
||||||
|
* any more).
|
||||||
|
*
|
||||||
|
* @param query hostname (not encoded) from the dns_table
|
||||||
|
* @param response encoded hostname in the DNS response
|
||||||
|
* @return 0: names equal; 1: names differ
|
||||||
|
*/
|
||||||
|
static u8_t ICACHE_FLASH_ATTR
|
||||||
|
dns_compare_name(unsigned char *query, unsigned char *response)
|
||||||
|
{
|
||||||
|
unsigned char n;
|
||||||
|
|
||||||
|
do {
|
||||||
|
n = *response++;
|
||||||
|
/** @see RFC 1035 - 4.1.4. Message compression */
|
||||||
|
if ((n & 0xc0) == 0xc0) {
|
||||||
|
/* Compressed name */
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* Not compressed name */
|
||||||
|
while (n > 0) {
|
||||||
|
if ((*query) != (*response)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
++response;
|
||||||
|
++query;
|
||||||
|
--n;
|
||||||
|
};
|
||||||
|
++query;
|
||||||
|
}
|
||||||
|
} while (*response != 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* DNS_DOES_NAME_CHECK */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walk through a compact encoded DNS name and return the end of the name.
|
||||||
|
*
|
||||||
|
* @param query encoded DNS name in the DNS server response
|
||||||
|
* @return end of the name
|
||||||
|
*/
|
||||||
|
static unsigned char * ICACHE_FLASH_ATTR
|
||||||
|
dns_parse_name(unsigned char *query)
|
||||||
|
{
|
||||||
|
unsigned char n;
|
||||||
|
|
||||||
|
do {
|
||||||
|
n = *query++;
|
||||||
|
/** @see RFC 1035 - 4.1.4. Message compression */
|
||||||
|
if ((n & 0xc0) == 0xc0) {
|
||||||
|
/* Compressed name */
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* Not compressed name */
|
||||||
|
while (n > 0) {
|
||||||
|
++query;
|
||||||
|
--n;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} while (*query != 0);
|
||||||
|
|
||||||
|
return query + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a DNS query packet.
|
||||||
|
*
|
||||||
|
* @param numdns index of the DNS server in the dns_servers table
|
||||||
|
* @param name hostname to query
|
||||||
|
* @param id index of the hostname in dns_table, used as transaction ID in the
|
||||||
|
* DNS query packet
|
||||||
|
* @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
|
||||||
|
*/
|
||||||
|
static err_t ICACHE_FLASH_ATTR
|
||||||
|
dns_send(u8_t numdns, const char* name, u8_t id)
|
||||||
|
{
|
||||||
|
err_t err;
|
||||||
|
struct dns_hdr *hdr;
|
||||||
|
struct dns_query qry;
|
||||||
|
struct pbuf *p;
|
||||||
|
char *query, *nptr;
|
||||||
|
const char *pHostname;
|
||||||
|
u8_t n;
|
||||||
|
dns_random = os_random()%250;
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
|
||||||
|
(u16_t)(numdns), name));
|
||||||
|
LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
|
||||||
|
LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
|
||||||
|
|
||||||
|
/* if here, we have either a new query or a retry on a previous query to process */
|
||||||
|
p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
|
||||||
|
SIZEOF_DNS_QUERY, PBUF_RAM);
|
||||||
|
if (p != NULL) {
|
||||||
|
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
|
||||||
|
/* fill dns header */
|
||||||
|
hdr = (struct dns_hdr*)p->payload;
|
||||||
|
os_memset(hdr, 0, SIZEOF_DNS_HDR);
|
||||||
|
hdr->id = htons(id + dns_random);
|
||||||
|
hdr->flags1 = DNS_FLAG1_RD;
|
||||||
|
hdr->numquestions = PP_HTONS(1);
|
||||||
|
query = (char*)hdr + SIZEOF_DNS_HDR;
|
||||||
|
pHostname = name;
|
||||||
|
--pHostname;
|
||||||
|
|
||||||
|
/* convert hostname into suitable query format. */
|
||||||
|
do {
|
||||||
|
++pHostname;
|
||||||
|
nptr = query;
|
||||||
|
++query;
|
||||||
|
for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
|
||||||
|
*query = *pHostname;
|
||||||
|
++query;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
*nptr = n;
|
||||||
|
} while(*pHostname != 0);
|
||||||
|
*query++='\0';
|
||||||
|
|
||||||
|
/* fill dns query */
|
||||||
|
qry.type = PP_HTONS(DNS_RRTYPE_A);
|
||||||
|
qry.cls = PP_HTONS(DNS_RRCLASS_IN);
|
||||||
|
SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
|
||||||
|
|
||||||
|
/* resize pbuf to the exact dns query */
|
||||||
|
pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
|
||||||
|
|
||||||
|
/* connect to the server for faster receiving */
|
||||||
|
udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
|
||||||
|
/* send dns packet */
|
||||||
|
err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
|
||||||
|
|
||||||
|
/* free pbuf */
|
||||||
|
pbuf_free(p);
|
||||||
|
} else {
|
||||||
|
err = ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.
|
||||||
|
* Check an entry in the dns_table:
|
||||||
|
* - send out query for new entries
|
||||||
|
* - retry old pending entries on timeout (also with different servers)
|
||||||
|
* - remove completed entries from the table if their TTL has expired
|
||||||
|
*
|
||||||
|
* @param i index of the dns_table entry to check
|
||||||
|
*/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
dns_check_entry(u8_t i)
|
||||||
|
{
|
||||||
|
err_t err;
|
||||||
|
struct dns_table_entry *pEntry = &dns_table[i];
|
||||||
|
|
||||||
|
LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
|
||||||
|
|
||||||
|
switch(pEntry->state) {
|
||||||
|
|
||||||
|
case DNS_STATE_NEW: {
|
||||||
|
/* initialize new entry */
|
||||||
|
pEntry->state = DNS_STATE_ASKING;
|
||||||
|
pEntry->numdns = 0;
|
||||||
|
pEntry->tmr = 1;
|
||||||
|
pEntry->retries = 0;
|
||||||
|
|
||||||
|
/* send DNS packet for this entry */
|
||||||
|
err = dns_send(pEntry->numdns, pEntry->name, i);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
|
||||||
|
("dns_send returned error: %s\n", lwip_strerr(err)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DNS_STATE_ASKING: {
|
||||||
|
if (--pEntry->tmr == 0) {
|
||||||
|
if (++pEntry->retries == DNS_MAX_RETRIES) {
|
||||||
|
if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
|
||||||
|
/* change of server */
|
||||||
|
pEntry->numdns++;
|
||||||
|
pEntry->tmr = 1;
|
||||||
|
pEntry->retries = 0;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
|
||||||
|
/* call specified callback function if provided */
|
||||||
|
if (pEntry->found)
|
||||||
|
(*pEntry->found)(pEntry->name, NULL, pEntry->arg);
|
||||||
|
/* flush this entry */
|
||||||
|
pEntry->state = DNS_STATE_UNUSED;
|
||||||
|
pEntry->found = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait longer for the next retry */
|
||||||
|
pEntry->tmr = pEntry->retries;
|
||||||
|
|
||||||
|
/* send DNS packet for this entry */
|
||||||
|
err = dns_send(pEntry->numdns, pEntry->name, i);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
|
||||||
|
("dns_send returned error: %s\n", lwip_strerr(err)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DNS_STATE_DONE: {
|
||||||
|
/* if the time to live is nul */
|
||||||
|
if (--pEntry->ttl == 0) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
|
||||||
|
/* flush this entry */
|
||||||
|
pEntry->state = DNS_STATE_UNUSED;
|
||||||
|
pEntry->found = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DNS_STATE_UNUSED:
|
||||||
|
/* nothing to do */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LWIP_ASSERT("unknown dns_table entry state:", 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call dns_check_entry for each entry in dns_table - check all entries.
|
||||||
|
*/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
dns_check_entries(void)
|
||||||
|
{
|
||||||
|
u8_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
|
||||||
|
dns_check_entry(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive input function for DNS response packets arriving for the dns UDP pcb.
|
||||||
|
*
|
||||||
|
* @params see udp.h
|
||||||
|
*/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
|
||||||
|
{
|
||||||
|
u16_t i;
|
||||||
|
char *pHostname;
|
||||||
|
struct dns_hdr *hdr;
|
||||||
|
struct dns_answer ans;
|
||||||
|
struct dns_table_entry *pEntry;
|
||||||
|
u16_t nquestions, nanswers;
|
||||||
|
|
||||||
|
u8_t* dns_payload_buffer = (u8_t* )os_zalloc(LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE));
|
||||||
|
dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
|
||||||
|
|
||||||
|
LWIP_UNUSED_ARG(arg);
|
||||||
|
LWIP_UNUSED_ARG(pcb);
|
||||||
|
LWIP_UNUSED_ARG(addr);
|
||||||
|
LWIP_UNUSED_ARG(port);
|
||||||
|
|
||||||
|
/* is the dns message too big ? */
|
||||||
|
if (p->tot_len > DNS_MSG_SIZE) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
|
||||||
|
/* free pbuf and return */
|
||||||
|
goto memerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* is the dns message big enough ? */
|
||||||
|
if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
|
||||||
|
/* free pbuf and return */
|
||||||
|
goto memerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy dns payload inside static buffer for processing */
|
||||||
|
if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
|
||||||
|
/* The ID in the DNS header should be our entry into the name table. */
|
||||||
|
hdr = (struct dns_hdr*)dns_payload;
|
||||||
|
i = htons(hdr->id);
|
||||||
|
i = i - dns_random;
|
||||||
|
if (i < DNS_TABLE_SIZE) {
|
||||||
|
pEntry = &dns_table[i];
|
||||||
|
if(pEntry->state == DNS_STATE_ASKING) {
|
||||||
|
/* This entry is now completed. */
|
||||||
|
pEntry->state = DNS_STATE_DONE;
|
||||||
|
pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
|
||||||
|
|
||||||
|
/* We only care about the question(s) and the answers. The authrr
|
||||||
|
and the extrarr are simply discarded. */
|
||||||
|
nquestions = htons(hdr->numquestions);
|
||||||
|
nanswers = htons(hdr->numanswers);
|
||||||
|
|
||||||
|
/* Check for error. If so, call callback to inform. */
|
||||||
|
if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
|
||||||
|
/* call callback to indicate error, clean up memory and return */
|
||||||
|
goto responseerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DNS_DOES_NAME_CHECK
|
||||||
|
/* Check if the name in the "question" part match with the name in the entry. */
|
||||||
|
if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
|
||||||
|
/* call callback to indicate error, clean up memory and return */
|
||||||
|
goto responseerr;
|
||||||
|
}
|
||||||
|
#endif /* DNS_DOES_NAME_CHECK */
|
||||||
|
|
||||||
|
/* Skip the name in the "question" part */
|
||||||
|
pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
|
||||||
|
|
||||||
|
while (nanswers > 0) {
|
||||||
|
/* skip answer resource record's host name */
|
||||||
|
pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
|
||||||
|
|
||||||
|
/* Check for IP address type and Internet class. Others are discarded. */
|
||||||
|
SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
|
||||||
|
if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&
|
||||||
|
(ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {
|
||||||
|
/* read the answer resource record's TTL, and maximize it if needed */
|
||||||
|
pEntry->ttl = ntohl(ans.ttl);
|
||||||
|
if (pEntry->ttl > DNS_MAX_TTL) {
|
||||||
|
pEntry->ttl = DNS_MAX_TTL;
|
||||||
|
}
|
||||||
|
/* read the IP address after answer resource record's header */
|
||||||
|
SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
|
||||||
|
ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
|
||||||
|
/* call specified callback function if provided */
|
||||||
|
if (pEntry->found) {
|
||||||
|
(*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
|
||||||
|
}
|
||||||
|
/* deallocate memory and return */
|
||||||
|
goto memerr;
|
||||||
|
} else {
|
||||||
|
pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
|
||||||
|
}
|
||||||
|
--nanswers;
|
||||||
|
}
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
|
||||||
|
/* call callback to indicate error, clean up memory and return */
|
||||||
|
goto responseerr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* deallocate memory and return */
|
||||||
|
goto memerr;
|
||||||
|
|
||||||
|
responseerr:
|
||||||
|
/* ERROR: call specified callback function with NULL as name to indicate an error */
|
||||||
|
if (pEntry->found) {
|
||||||
|
(*pEntry->found)(pEntry->name, NULL, pEntry->arg);
|
||||||
|
}
|
||||||
|
/* flush this entry */
|
||||||
|
pEntry->state = DNS_STATE_UNUSED;
|
||||||
|
pEntry->found = NULL;
|
||||||
|
|
||||||
|
memerr:
|
||||||
|
/* free pbuf */
|
||||||
|
pbuf_free(p);
|
||||||
|
os_free(dns_payload_buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queues a new hostname to resolve and sends out a DNS query for that hostname
|
||||||
|
*
|
||||||
|
* @param name the hostname that is to be queried
|
||||||
|
* @param found a callback founction to be called on success, failure or timeout
|
||||||
|
* @param callback_arg argument to pass to the callback function
|
||||||
|
* @return @return a err_t return code.
|
||||||
|
*/
|
||||||
|
static err_t ICACHE_FLASH_ATTR
|
||||||
|
dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
|
||||||
|
{
|
||||||
|
u8_t i;
|
||||||
|
u8_t lseq, lseqi;
|
||||||
|
struct dns_table_entry *pEntry = NULL;
|
||||||
|
size_t namelen;
|
||||||
|
|
||||||
|
/* search an unused entry, or the oldest one */
|
||||||
|
lseq = lseqi = 0;
|
||||||
|
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
|
||||||
|
pEntry = &dns_table[i];
|
||||||
|
/* is it an unused entry ? */
|
||||||
|
if (pEntry->state == DNS_STATE_UNUSED)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* check if this is the oldest completed entry */
|
||||||
|
if (pEntry->state == DNS_STATE_DONE) {
|
||||||
|
if ((dns_seqno - pEntry->seqno) > lseq) {
|
||||||
|
lseq = dns_seqno - pEntry->seqno;
|
||||||
|
lseqi = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we don't have found an unused entry, use the oldest completed one */
|
||||||
|
if (i == DNS_TABLE_SIZE) {
|
||||||
|
if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
|
||||||
|
/* no entry can't be used now, table is full */
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
|
||||||
|
return ERR_MEM;
|
||||||
|
} else {
|
||||||
|
/* use the oldest completed one */
|
||||||
|
i = lseqi;
|
||||||
|
pEntry = &dns_table[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* use this entry */
|
||||||
|
LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
|
||||||
|
|
||||||
|
/* fill the entry */
|
||||||
|
pEntry->state = DNS_STATE_NEW;
|
||||||
|
pEntry->seqno = dns_seqno++;
|
||||||
|
pEntry->found = found;
|
||||||
|
pEntry->arg = callback_arg;
|
||||||
|
namelen = LWIP_MIN(os_strlen(name), DNS_MAX_NAME_LENGTH-1);
|
||||||
|
MEMCPY(pEntry->name, name, namelen);
|
||||||
|
pEntry->name[namelen] = 0;
|
||||||
|
|
||||||
|
/* force to send query without waiting timer */
|
||||||
|
dns_check_entry(i);
|
||||||
|
|
||||||
|
/* dns query is enqueued */
|
||||||
|
return ERR_INPROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a hostname (string) into an IP address.
|
||||||
|
* NON-BLOCKING callback version for use with raw API!!!
|
||||||
|
*
|
||||||
|
* Returns immediately with one of err_t return codes:
|
||||||
|
* - ERR_OK if hostname is a valid IP address string or the host
|
||||||
|
* name is already in the local names table.
|
||||||
|
* - ERR_INPROGRESS enqueue a request to be sent to the DNS server
|
||||||
|
* for resolution if no errors are present.
|
||||||
|
* - ERR_ARG: dns client not initialized or invalid hostname
|
||||||
|
*
|
||||||
|
* @param hostname the hostname that is to be queried
|
||||||
|
* @param addr pointer to a ip_addr_t where to store the address if it is already
|
||||||
|
* cached in the dns_table (only valid if ERR_OK is returned!)
|
||||||
|
* @param found a callback function to be called on success, failure or timeout (only if
|
||||||
|
* ERR_INPROGRESS is returned!)
|
||||||
|
* @param callback_arg argument to pass to the callback function
|
||||||
|
* @return a err_t return code.
|
||||||
|
*/
|
||||||
|
err_t ICACHE_FLASH_ATTR
|
||||||
|
dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
|
||||||
|
void *callback_arg)
|
||||||
|
{
|
||||||
|
u32_t ipaddr;
|
||||||
|
/* not initialized or no valid server yet, or invalid addr pointer
|
||||||
|
* or invalid hostname or invalid hostname length */
|
||||||
|
if ((dns_pcb == NULL) || (addr == NULL) ||
|
||||||
|
(!hostname) || (!hostname[0]) ||
|
||||||
|
(os_strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
|
||||||
|
return ERR_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_HAVE_LOOPIF
|
||||||
|
if (strcmp(hostname, "localhost")==0) {
|
||||||
|
ip_addr_set_loopback(addr);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
#endif /* LWIP_HAVE_LOOPIF */
|
||||||
|
|
||||||
|
/* host name already in octet notation? set ip addr and return ERR_OK */
|
||||||
|
ipaddr = ipaddr_addr(hostname);
|
||||||
|
if (ipaddr == IPADDR_NONE) {
|
||||||
|
/* already have this address cached? */
|
||||||
|
// ipaddr = dns_lookup(hostname);
|
||||||
|
}
|
||||||
|
if (ipaddr != IPADDR_NONE) {
|
||||||
|
ip4_addr_set_u32(addr, ipaddr);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* queue query with specified callback */
|
||||||
|
return dns_enqueue(hostname, found, callback_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_DNS */
|
325
tools/sdk/lwip/src/core/init.c
Normal file
325
tools/sdk/lwip/src/core/init.c
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Modules initialization
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#include "lwip/init.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/memp.h"
|
||||||
|
#include "lwip/pbuf.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
#include "lwip/sockets.h"
|
||||||
|
#include "lwip/ip.h"
|
||||||
|
#include "lwip/raw.h"
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "lwip/tcp_impl.h"
|
||||||
|
#include "lwip/snmp_msg.h"
|
||||||
|
#include "lwip/autoip.h"
|
||||||
|
#include "lwip/igmp.h"
|
||||||
|
#include "lwip/dns.h"
|
||||||
|
#include "lwip/timers.h"
|
||||||
|
#include "netif/etharp.h"
|
||||||
|
|
||||||
|
/* Compile-time sanity checks for configuration errors.
|
||||||
|
* These can be done independently of LWIP_DEBUG, without penalty.
|
||||||
|
*/
|
||||||
|
#ifndef BYTE_ORDER
|
||||||
|
#error "BYTE_ORDER is not defined, you have to define it in your cc.h"
|
||||||
|
#endif
|
||||||
|
#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV)
|
||||||
|
#error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (!LWIP_ARP && ARP_QUEUEING)
|
||||||
|
#error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (!LWIP_UDP && LWIP_UDPLITE)
|
||||||
|
#error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (!LWIP_UDP && LWIP_SNMP)
|
||||||
|
#error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (!LWIP_UDP && LWIP_DHCP)
|
||||||
|
#error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (!LWIP_UDP && LWIP_IGMP)
|
||||||
|
#error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (!LWIP_UDP && LWIP_SNMP)
|
||||||
|
#error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (!LWIP_UDP && LWIP_DNS)
|
||||||
|
#error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))
|
||||||
|
#error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0))
|
||||||
|
#error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0))
|
||||||
|
#error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
//#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))
|
||||||
|
// #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"
|
||||||
|
//#endif
|
||||||
|
//#if (LWIP_TCP && (TCP_WND > 0xffff))
|
||||||
|
// #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
|
||||||
|
//#endif
|
||||||
|
#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))
|
||||||
|
#error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2))
|
||||||
|
#error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work"
|
||||||
|
#endif
|
||||||
|
//#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))
|
||||||
|
// #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h"
|
||||||
|
//#endif
|
||||||
|
#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))
|
||||||
|
#error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t"
|
||||||
|
#endif
|
||||||
|
#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
|
||||||
|
#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (LWIP_NETIF_API && (NO_SYS==1))
|
||||||
|
#error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
|
||||||
|
#error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
|
||||||
|
#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (!LWIP_NETCONN && LWIP_SOCKET)
|
||||||
|
#error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP)
|
||||||
|
#error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK)
|
||||||
|
#error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (!LWIP_ARP && LWIP_AUTOIP)
|
||||||
|
#error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0))
|
||||||
|
#error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))
|
||||||
|
#error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))
|
||||||
|
#error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
|
||||||
|
#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
|
||||||
|
#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
|
||||||
|
#endif
|
||||||
|
#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
|
||||||
|
#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
|
||||||
|
#endif
|
||||||
|
#if (MEM_LIBC_MALLOC && MEM_USE_POOLS)
|
||||||
|
#error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)
|
||||||
|
#error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"
|
||||||
|
#endif
|
||||||
|
#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT)
|
||||||
|
#error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf"
|
||||||
|
#endif
|
||||||
|
#if (TCP_QUEUE_OOSEQ && !LWIP_TCP)
|
||||||
|
#error "TCP_QUEUE_OOSEQ requires LWIP_TCP"
|
||||||
|
#endif
|
||||||
|
#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))
|
||||||
|
#error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST"
|
||||||
|
#endif
|
||||||
|
#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT
|
||||||
|
#error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on"
|
||||||
|
#endif
|
||||||
|
#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT)
|
||||||
|
#error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT"
|
||||||
|
#endif
|
||||||
|
#if LWIP_IGMP && !defined(LWIP_RAND)
|
||||||
|
#error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
|
||||||
|
#endif
|
||||||
|
#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING
|
||||||
|
#error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too"
|
||||||
|
#endif
|
||||||
|
#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE
|
||||||
|
#error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets"
|
||||||
|
#endif
|
||||||
|
#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF
|
||||||
|
#error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Compile-time checks for deprecated options.
|
||||||
|
*/
|
||||||
|
#ifdef MEMP_NUM_TCPIP_MSG
|
||||||
|
#error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h."
|
||||||
|
#endif
|
||||||
|
#ifdef MEMP_NUM_API_MSG
|
||||||
|
#error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h."
|
||||||
|
#endif
|
||||||
|
#ifdef TCP_REXMIT_DEBUG
|
||||||
|
#error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h."
|
||||||
|
#endif
|
||||||
|
#ifdef RAW_STATS
|
||||||
|
#error "RAW_STATS option is deprecated. Remove it from your lwipopts.h."
|
||||||
|
#endif
|
||||||
|
#ifdef ETHARP_QUEUE_FIRST
|
||||||
|
#error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h."
|
||||||
|
#endif
|
||||||
|
#ifdef ETHARP_ALWAYS_INSERT
|
||||||
|
#error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LWIP_DEBUG
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
lwip_sanity_check(void)
|
||||||
|
{
|
||||||
|
/* Warnings */
|
||||||
|
#if LWIP_NETCONN
|
||||||
|
if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB))
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n"));
|
||||||
|
#endif /* LWIP_NETCONN */
|
||||||
|
#if LWIP_TCP
|
||||||
|
if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));
|
||||||
|
if (TCP_SND_BUF < 2 * TCP_MSS)
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n"));
|
||||||
|
if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n"));
|
||||||
|
if (TCP_SNDLOWAT >= TCP_SND_BUF)
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n"));
|
||||||
|
if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN)
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n"));
|
||||||
|
if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n"));
|
||||||
|
if (TCP_WND < TCP_MSS)
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
|
#if LWIP_SOCKET
|
||||||
|
/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
|
||||||
|
if (SO_ACCEPTCONN != SOF_ACCEPTCONN)
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n"));
|
||||||
|
if (SO_REUSEADDR != SOF_REUSEADDR)
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n"));
|
||||||
|
if (SO_KEEPALIVE != SOF_KEEPALIVE)
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n"));
|
||||||
|
if (SO_BROADCAST != SOF_BROADCAST)
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n"));
|
||||||
|
if (SO_LINGER != SOF_LINGER)
|
||||||
|
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n"));
|
||||||
|
#endif /* LWIP_SOCKET */
|
||||||
|
}
|
||||||
|
#else /* LWIP_DEBUG */
|
||||||
|
#define lwip_sanity_check()
|
||||||
|
#endif /* LWIP_DEBUG */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform Sanity check of user-configurable values, and initialize all modules.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lwip_init(void)
|
||||||
|
{
|
||||||
|
MEMP_NUM_TCP_PCB = 5;
|
||||||
|
TCP_WND = (4 * TCP_MSS);
|
||||||
|
TCP_MAXRTX = 12;
|
||||||
|
TCP_SYNMAXRTX = 6;
|
||||||
|
|
||||||
|
/* Sanity check user-configurable values */
|
||||||
|
lwip_sanity_check();
|
||||||
|
|
||||||
|
/* Modules initialization */
|
||||||
|
stats_init();
|
||||||
|
#if !NO_SYS
|
||||||
|
sys_init();
|
||||||
|
#endif /* !NO_SYS */
|
||||||
|
#if 0
|
||||||
|
mem_init(&_bss_end);
|
||||||
|
#endif
|
||||||
|
memp_init();
|
||||||
|
|
||||||
|
pbuf_init();
|
||||||
|
|
||||||
|
netif_init();
|
||||||
|
|
||||||
|
#if LWIP_SOCKET
|
||||||
|
lwip_socket_init();
|
||||||
|
#endif /* LWIP_SOCKET */
|
||||||
|
ip_init();
|
||||||
|
|
||||||
|
#if LWIP_ARP
|
||||||
|
etharp_init();
|
||||||
|
|
||||||
|
#endif /* LWIP_ARP */
|
||||||
|
#if LWIP_RAW
|
||||||
|
raw_init();
|
||||||
|
|
||||||
|
#endif /* LWIP_RAW */
|
||||||
|
#if LWIP_UDP
|
||||||
|
udp_init();
|
||||||
|
|
||||||
|
#endif /* LWIP_UDP */
|
||||||
|
#if LWIP_TCP
|
||||||
|
tcp_init();
|
||||||
|
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
|
#if LWIP_SNMP
|
||||||
|
snmp_init();
|
||||||
|
|
||||||
|
#endif /* LWIP_SNMP */
|
||||||
|
#if LWIP_AUTOIP
|
||||||
|
autoip_init();
|
||||||
|
|
||||||
|
#endif /* LWIP_AUTOIP */
|
||||||
|
#if LWIP_IGMP
|
||||||
|
igmp_init();
|
||||||
|
|
||||||
|
#endif /* LWIP_IGMP */
|
||||||
|
#if LWIP_DNS
|
||||||
|
dns_init();
|
||||||
|
|
||||||
|
#endif /* LWIP_DNS */
|
||||||
|
|
||||||
|
#if LWIP_TIMERS
|
||||||
|
sys_timeouts_init();
|
||||||
|
#endif /* LWIP_TIMERS */
|
||||||
|
}
|
536
tools/sdk/lwip/src/core/ipv4/autoip.c
Normal file
536
tools/sdk/lwip/src/core/ipv4/autoip.c
Normal file
@ -0,0 +1,536 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* AutoIP Automatic LinkLocal IP Configuration
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Author: Dominik Spies <kontakt@dspies.de>
|
||||||
|
*
|
||||||
|
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
|
||||||
|
* with RFC 3927.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Please coordinate changes and requests with Dominik Spies
|
||||||
|
* <kontakt@dspies.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* USAGE:
|
||||||
|
*
|
||||||
|
* define LWIP_AUTOIP 1 in your lwipopts.h
|
||||||
|
*
|
||||||
|
* If you don't use tcpip.c (so, don't call, you don't call tcpip_init):
|
||||||
|
* - First, call autoip_init().
|
||||||
|
* - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,
|
||||||
|
* that should be defined in autoip.h.
|
||||||
|
* I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
|
||||||
|
* Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
|
||||||
|
*
|
||||||
|
* Without DHCP:
|
||||||
|
* - Call autoip_start() after netif_add().
|
||||||
|
*
|
||||||
|
* With DHCP:
|
||||||
|
* - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
|
||||||
|
* - Configure your DHCP Client.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
#include "lwip/autoip.h"
|
||||||
|
#include "netif/etharp.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* 169.254.0.0 */
|
||||||
|
#define AUTOIP_NET 0xA9FE0000
|
||||||
|
/* 169.254.1.0 */
|
||||||
|
#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)
|
||||||
|
/* 169.254.254.255 */
|
||||||
|
#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF)
|
||||||
|
|
||||||
|
|
||||||
|
/** Pseudo random macro based on netif informations.
|
||||||
|
* You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
|
||||||
|
#ifndef LWIP_AUTOIP_RAND
|
||||||
|
#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
|
||||||
|
((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
|
||||||
|
((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
|
||||||
|
((u32_t)((netif->hwaddr[4]) & 0xff))) + \
|
||||||
|
(netif->autoip?netif->autoip->tried_llipaddr:0))
|
||||||
|
#endif /* LWIP_AUTOIP_RAND */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro that generates the initial IP address to be tried by AUTOIP.
|
||||||
|
* If you want to override this, define it to something else in lwipopts.h.
|
||||||
|
*/
|
||||||
|
#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
|
||||||
|
#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
|
||||||
|
htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
|
||||||
|
((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
|
||||||
|
#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
|
||||||
|
|
||||||
|
/* static functions */
|
||||||
|
static void autoip_handle_arp_conflict(struct netif *netif);
|
||||||
|
|
||||||
|
/* creates a pseudo random LL IP-Address for a network interface */
|
||||||
|
static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr);
|
||||||
|
|
||||||
|
/* sends an ARP probe */
|
||||||
|
static err_t autoip_arp_probe(struct netif *netif);
|
||||||
|
|
||||||
|
/* sends an ARP announce */
|
||||||
|
static err_t autoip_arp_announce(struct netif *netif);
|
||||||
|
|
||||||
|
/* configure interface for use with current LL IP-Address */
|
||||||
|
static err_t autoip_bind(struct netif *netif);
|
||||||
|
|
||||||
|
/* start sending probes for llipaddr */
|
||||||
|
static void autoip_start_probing(struct netif *netif);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize this module
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
autoip_init(void)
|
||||||
|
{
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set a statically allocated struct autoip to work with.
|
||||||
|
* Using this prevents autoip_start to allocate it using mem_malloc.
|
||||||
|
*
|
||||||
|
* @param netif the netif for which to set the struct autoip
|
||||||
|
* @param dhcp (uninitialised) dhcp struct allocated by the application
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
autoip_set_struct(struct netif *netif, struct autoip *autoip)
|
||||||
|
{
|
||||||
|
LWIP_ASSERT("netif != NULL", netif != NULL);
|
||||||
|
LWIP_ASSERT("autoip != NULL", autoip != NULL);
|
||||||
|
LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL);
|
||||||
|
|
||||||
|
/* clear data structure */
|
||||||
|
os_memset(autoip, 0, sizeof(struct autoip));
|
||||||
|
/* autoip->state = AUTOIP_STATE_OFF; */
|
||||||
|
netif->autoip = autoip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Restart AutoIP client and check the next address (conflict detected)
|
||||||
|
*
|
||||||
|
* @param netif The netif under AutoIP control
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
autoip_restart(struct netif *netif)
|
||||||
|
{
|
||||||
|
netif->autoip->tried_llipaddr++;
|
||||||
|
autoip_start(netif);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a IP address conflict after an ARP conflict detection
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
autoip_handle_arp_conflict(struct netif *netif)
|
||||||
|
{
|
||||||
|
/* Somehow detect if we are defending or retreating */
|
||||||
|
unsigned char defend = 1; /* tbd */
|
||||||
|
|
||||||
|
if(defend) {
|
||||||
|
if(netif->autoip->lastconflict > 0) {
|
||||||
|
/* retreat, there was a conflicting ARP in the last
|
||||||
|
* DEFEND_INTERVAL seconds
|
||||||
|
*/
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||||
|
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
|
||||||
|
|
||||||
|
/* TODO: close all TCP sessions */
|
||||||
|
autoip_restart(netif);
|
||||||
|
} else {
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||||
|
("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
|
||||||
|
autoip_arp_announce(netif);
|
||||||
|
netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||||
|
("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
|
||||||
|
/* TODO: close all TCP sessions */
|
||||||
|
autoip_restart(netif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
|
||||||
|
*
|
||||||
|
* @param netif network interface on which create the IP-Address
|
||||||
|
* @param ipaddr ip address to initialize
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
|
||||||
|
{
|
||||||
|
/* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
|
||||||
|
* compliant to RFC 3927 Section 2.1
|
||||||
|
* We have 254 * 256 possibilities */
|
||||||
|
|
||||||
|
u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
|
||||||
|
addr += netif->autoip->tried_llipaddr;
|
||||||
|
addr = AUTOIP_NET | (addr & 0xffff);
|
||||||
|
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
|
||||||
|
|
||||||
|
if (addr < AUTOIP_RANGE_START) {
|
||||||
|
addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
|
||||||
|
}
|
||||||
|
if (addr > AUTOIP_RANGE_END) {
|
||||||
|
addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
|
||||||
|
}
|
||||||
|
LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
|
||||||
|
(addr <= AUTOIP_RANGE_END));
|
||||||
|
ip4_addr_set_u32(ipaddr, htonl(addr));
|
||||||
|
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||||
|
("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
(u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
|
||||||
|
ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an ARP probe from a network interface
|
||||||
|
*
|
||||||
|
* @param netif network interface used to send the probe
|
||||||
|
*/
|
||||||
|
static err_t
|
||||||
|
autoip_arp_probe(struct netif *netif)
|
||||||
|
{
|
||||||
|
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast,
|
||||||
|
(struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, ðzero,
|
||||||
|
&netif->autoip->llipaddr, ARP_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an ARP announce from a network interface
|
||||||
|
*
|
||||||
|
* @param netif network interface used to send the announce
|
||||||
|
*/
|
||||||
|
static err_t
|
||||||
|
autoip_arp_announce(struct netif *netif)
|
||||||
|
{
|
||||||
|
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast,
|
||||||
|
(struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero,
|
||||||
|
&netif->autoip->llipaddr, ARP_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure interface for use with current LL IP-Address
|
||||||
|
*
|
||||||
|
* @param netif network interface to configure with current LL IP-Address
|
||||||
|
*/
|
||||||
|
static err_t
|
||||||
|
autoip_bind(struct netif *netif)
|
||||||
|
{
|
||||||
|
struct autoip *autoip = netif->autoip;
|
||||||
|
ip_addr_t sn_mask, gw_addr;
|
||||||
|
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||||
|
("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num,
|
||||||
|
ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
|
||||||
|
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
|
||||||
|
|
||||||
|
IP4_ADDR(&sn_mask, 255, 255, 0, 0);
|
||||||
|
IP4_ADDR(&gw_addr, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
netif_set_ipaddr(netif, &autoip->llipaddr);
|
||||||
|
netif_set_netmask(netif, &sn_mask);
|
||||||
|
netif_set_gw(netif, &gw_addr);
|
||||||
|
|
||||||
|
/* bring the interface up */
|
||||||
|
netif_set_up(netif);
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start AutoIP client
|
||||||
|
*
|
||||||
|
* @param netif network interface on which start the AutoIP client
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
autoip_start(struct netif *netif)
|
||||||
|
{
|
||||||
|
struct autoip *autoip = netif->autoip;
|
||||||
|
err_t result = ERR_OK;
|
||||||
|
|
||||||
|
if(netif_is_up(netif)) {
|
||||||
|
netif_set_down(netif);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set IP-Address, Netmask and Gateway to 0 to make sure that
|
||||||
|
* ARP Packets are formed correctly
|
||||||
|
*/
|
||||||
|
ip_addr_set_zero(&netif->ip_addr);
|
||||||
|
ip_addr_set_zero(&netif->netmask);
|
||||||
|
ip_addr_set_zero(&netif->gw);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||||
|
("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
|
||||||
|
netif->name[1], (u16_t)netif->num));
|
||||||
|
if(autoip == NULL) {
|
||||||
|
/* no AutoIP client attached yet? */
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||||
|
("autoip_start(): starting new AUTOIP client\n"));
|
||||||
|
autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
|
||||||
|
if(autoip == NULL) {
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||||
|
("autoip_start(): could not allocate autoip\n"));
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
os_memset(autoip, 0, sizeof(struct autoip));
|
||||||
|
/* store this AutoIP client in the netif */
|
||||||
|
netif->autoip = autoip;
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
|
||||||
|
} else {
|
||||||
|
autoip->state = AUTOIP_STATE_OFF;
|
||||||
|
autoip->ttw = 0;
|
||||||
|
autoip->sent_num = 0;
|
||||||
|
ip_addr_set_zero(&autoip->llipaddr);
|
||||||
|
autoip->lastconflict = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
autoip_create_addr(netif, &(autoip->llipaddr));
|
||||||
|
autoip_start_probing(netif);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
autoip_start_probing(struct netif *netif)
|
||||||
|
{
|
||||||
|
struct autoip *autoip = netif->autoip;
|
||||||
|
|
||||||
|
autoip->state = AUTOIP_STATE_PROBING;
|
||||||
|
autoip->sent_num = 0;
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||||
|
("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
|
||||||
|
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
|
||||||
|
|
||||||
|
/* time to wait to first probe, this is randomly
|
||||||
|
* choosen out of 0 to PROBE_WAIT seconds.
|
||||||
|
* compliant to RFC 3927 Section 2.2.1
|
||||||
|
*/
|
||||||
|
autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if we tried more then MAX_CONFLICTS we must limit our rate for
|
||||||
|
* accquiring and probing address
|
||||||
|
* compliant to RFC 3927 Section 2.2.1
|
||||||
|
*/
|
||||||
|
if(autoip->tried_llipaddr > MAX_CONFLICTS) {
|
||||||
|
autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a possible change in the network configuration.
|
||||||
|
*
|
||||||
|
* If there is an AutoIP address configured, take the interface down
|
||||||
|
* and begin probing with the same address.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
autoip_network_changed(struct netif *netif)
|
||||||
|
{
|
||||||
|
if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
|
||||||
|
netif_set_down(netif);
|
||||||
|
autoip_start_probing(netif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop AutoIP client
|
||||||
|
*
|
||||||
|
* @param netif network interface on which stop the AutoIP client
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
autoip_stop(struct netif *netif)
|
||||||
|
{
|
||||||
|
netif->autoip->state = AUTOIP_STATE_OFF;
|
||||||
|
netif_set_down(netif);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
autoip_tmr()
|
||||||
|
{
|
||||||
|
struct netif *netif = netif_list;
|
||||||
|
/* loop through netif's */
|
||||||
|
while (netif != NULL) {
|
||||||
|
/* only act on AutoIP configured interfaces */
|
||||||
|
if (netif->autoip != NULL) {
|
||||||
|
if(netif->autoip->lastconflict > 0) {
|
||||||
|
netif->autoip->lastconflict--;
|
||||||
|
}
|
||||||
|
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||||
|
("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
|
||||||
|
(u16_t)(netif->autoip->state), netif->autoip->ttw));
|
||||||
|
|
||||||
|
switch(netif->autoip->state) {
|
||||||
|
case AUTOIP_STATE_PROBING:
|
||||||
|
if(netif->autoip->ttw > 0) {
|
||||||
|
netif->autoip->ttw--;
|
||||||
|
} else {
|
||||||
|
if(netif->autoip->sent_num >= PROBE_NUM) {
|
||||||
|
netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
|
||||||
|
netif->autoip->sent_num = 0;
|
||||||
|
netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||||
|
("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
|
||||||
|
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
|
||||||
|
} else {
|
||||||
|
autoip_arp_probe(netif);
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||||
|
("autoip_tmr() PROBING Sent Probe\n"));
|
||||||
|
netif->autoip->sent_num++;
|
||||||
|
/* calculate time to wait to next probe */
|
||||||
|
netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
|
||||||
|
((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
|
||||||
|
PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUTOIP_STATE_ANNOUNCING:
|
||||||
|
if(netif->autoip->ttw > 0) {
|
||||||
|
netif->autoip->ttw--;
|
||||||
|
} else {
|
||||||
|
if(netif->autoip->sent_num == 0) {
|
||||||
|
/* We are here the first time, so we waited ANNOUNCE_WAIT seconds
|
||||||
|
* Now we can bind to an IP address and use it.
|
||||||
|
*
|
||||||
|
* autoip_bind calls netif_set_up. This triggers a gratuitous ARP
|
||||||
|
* which counts as an announcement.
|
||||||
|
*/
|
||||||
|
autoip_bind(netif);
|
||||||
|
} else {
|
||||||
|
autoip_arp_announce(netif);
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||||
|
("autoip_tmr() ANNOUNCING Sent Announce\n"));
|
||||||
|
}
|
||||||
|
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||||
|
netif->autoip->sent_num++;
|
||||||
|
|
||||||
|
if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
|
||||||
|
netif->autoip->state = AUTOIP_STATE_BOUND;
|
||||||
|
netif->autoip->sent_num = 0;
|
||||||
|
netif->autoip->ttw = 0;
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||||
|
("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
|
||||||
|
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* proceed to next network interface */
|
||||||
|
netif = netif->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles every incoming ARP Packet, called by etharp_arp_input.
|
||||||
|
*
|
||||||
|
* @param netif network interface to use for autoip processing
|
||||||
|
* @param hdr Incoming ARP packet
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
||||||
|
{
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
|
||||||
|
if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {
|
||||||
|
/* when ip.src == llipaddr && hw.src != netif->hwaddr
|
||||||
|
*
|
||||||
|
* when probing ip.dst == llipaddr && hw.src != netif->hwaddr
|
||||||
|
* we have a conflict and must solve it
|
||||||
|
*/
|
||||||
|
ip_addr_t sipaddr, dipaddr;
|
||||||
|
struct eth_addr netifaddr;
|
||||||
|
ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);
|
||||||
|
|
||||||
|
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
|
||||||
|
* structure packing (not using structure copy which breaks strict-aliasing rules).
|
||||||
|
*/
|
||||||
|
IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
|
||||||
|
IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
|
||||||
|
|
||||||
|
if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
|
||||||
|
((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
|
||||||
|
(netif->autoip->sent_num == 0))) {
|
||||||
|
/* RFC 3927 Section 2.2.1:
|
||||||
|
* from beginning to after ANNOUNCE_WAIT
|
||||||
|
* seconds we have a conflict if
|
||||||
|
* ip.src == llipaddr OR
|
||||||
|
* ip.dst == llipaddr && hw.src != own hwaddr
|
||||||
|
*/
|
||||||
|
if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
|
||||||
|
(ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
|
||||||
|
!eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
||||||
|
("autoip_arp_reply(): Probe Conflict detected\n"));
|
||||||
|
autoip_restart(netif);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* RFC 3927 Section 2.5:
|
||||||
|
* in any state we have a conflict if
|
||||||
|
* ip.src == llipaddr && hw.src != own hwaddr
|
||||||
|
*/
|
||||||
|
if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
|
||||||
|
!eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
|
||||||
|
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
||||||
|
("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
|
||||||
|
autoip_handle_arp_conflict(netif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_AUTOIP */
|
337
tools/sdk/lwip/src/core/ipv4/icmp.c
Normal file
337
tools/sdk/lwip/src/core/ipv4/icmp.c
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* ICMP - Internet Control Message Protocol
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Some ICMP messages should be passed to the transport protocols. This
|
||||||
|
is not implemented. */
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/icmp.h"
|
||||||
|
#include "lwip/inet_chksum.h"
|
||||||
|
#include "lwip/ip.h"
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
#include "lwip/snmp.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be
|
||||||
|
* used to modify and send a response packet (and to 1 if this is not the case,
|
||||||
|
* e.g. when link header is stripped of when receiving) */
|
||||||
|
#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||||
|
#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
|
||||||
|
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||||
|
|
||||||
|
/* The amount of data from the original packet to return in a dest-unreachable */
|
||||||
|
#define ICMP_DEST_UNREACH_DATASIZE 8
|
||||||
|
|
||||||
|
static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes ICMP input packets, called from ip_input().
|
||||||
|
*
|
||||||
|
* Currently only processes icmp echo requests and sends
|
||||||
|
* out the echo response.
|
||||||
|
*
|
||||||
|
* @param p the icmp echo request packet, p->payload pointing to the ip header
|
||||||
|
* @param inp the netif on which this packet was received
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
icmp_input(struct pbuf *p, struct netif *inp)
|
||||||
|
{
|
||||||
|
u8_t type;
|
||||||
|
#ifdef LWIP_DEBUG
|
||||||
|
u8_t code;
|
||||||
|
#endif /* LWIP_DEBUG */
|
||||||
|
struct icmp_echo_hdr *iecho;
|
||||||
|
struct ip_hdr *iphdr;
|
||||||
|
s16_t hlen;
|
||||||
|
|
||||||
|
ICMP_STATS_INC(icmp.recv);
|
||||||
|
snmp_inc_icmpinmsgs();
|
||||||
|
|
||||||
|
|
||||||
|
iphdr = (struct ip_hdr *)p->payload;
|
||||||
|
hlen = IPH_HL(iphdr) * 4;
|
||||||
|
if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
|
||||||
|
goto lenerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = *((u8_t *)p->payload);
|
||||||
|
#ifdef LWIP_DEBUG
|
||||||
|
code = *(((u8_t *)p->payload)+1);
|
||||||
|
#endif /* LWIP_DEBUG */
|
||||||
|
switch (type) {
|
||||||
|
case ICMP_ER:
|
||||||
|
/* This is OK, echo reply might have been parsed by a raw PCB
|
||||||
|
(as obviously, an echo request has been sent, too). */
|
||||||
|
break;
|
||||||
|
case ICMP_ECHO:
|
||||||
|
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
|
||||||
|
{
|
||||||
|
int accepted = 1;
|
||||||
|
#if !LWIP_MULTICAST_PING
|
||||||
|
/* multicast destination address? */
|
||||||
|
if (ip_addr_ismulticast(¤t_iphdr_dest)) {
|
||||||
|
accepted = 0;
|
||||||
|
}
|
||||||
|
#endif /* LWIP_MULTICAST_PING */
|
||||||
|
#if !LWIP_BROADCAST_PING
|
||||||
|
/* broadcast destination address? */
|
||||||
|
if (ip_addr_isbroadcast(¤t_iphdr_dest, inp)) {
|
||||||
|
accepted = 0;
|
||||||
|
}
|
||||||
|
#endif /* LWIP_BROADCAST_PING */
|
||||||
|
/* broadcast or multicast destination address not acceptd? */
|
||||||
|
if (!accepted) {
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
|
||||||
|
ICMP_STATS_INC(icmp.err);
|
||||||
|
pbuf_free(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
|
||||||
|
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
|
||||||
|
goto lenerr;
|
||||||
|
}
|
||||||
|
if (inet_chksum_pbuf(p) != 0) {
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
|
||||||
|
pbuf_free(p);
|
||||||
|
ICMP_STATS_INC(icmp.chkerr);
|
||||||
|
snmp_inc_icmpinerrors();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||||
|
if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
|
||||||
|
/* p is not big enough to contain link headers
|
||||||
|
* allocate a new one and copy p into it
|
||||||
|
*/
|
||||||
|
struct pbuf *r;
|
||||||
|
/* switch p->payload to ip header */
|
||||||
|
if (pbuf_header(p, hlen)) {
|
||||||
|
LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
|
||||||
|
goto memerr;
|
||||||
|
}
|
||||||
|
/* allocate new packet buffer with space for link headers */
|
||||||
|
r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
|
||||||
|
if (r == NULL) {
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
|
||||||
|
goto memerr;
|
||||||
|
}
|
||||||
|
LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
|
||||||
|
(r->len >= hlen + sizeof(struct icmp_echo_hdr)));
|
||||||
|
/* copy the whole packet including ip header */
|
||||||
|
if (pbuf_copy(r, p) != ERR_OK) {
|
||||||
|
LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
|
||||||
|
goto memerr;
|
||||||
|
}
|
||||||
|
iphdr = (struct ip_hdr *)r->payload;
|
||||||
|
/* switch r->payload back to icmp header */
|
||||||
|
if (pbuf_header(r, -hlen)) {
|
||||||
|
LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
|
||||||
|
goto memerr;
|
||||||
|
}
|
||||||
|
/* free the original p */
|
||||||
|
pbuf_free(p);
|
||||||
|
/* we now have an identical copy of p that has room for link headers */
|
||||||
|
p = r;
|
||||||
|
} else {
|
||||||
|
/* restore p->payload to point to icmp header */
|
||||||
|
if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
|
||||||
|
LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
|
||||||
|
goto memerr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||||
|
/* At this point, all checks are OK. */
|
||||||
|
/* We generate an answer by switching the dest and src ip addresses,
|
||||||
|
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
|
||||||
|
iecho = (struct icmp_echo_hdr *)p->payload;
|
||||||
|
ip_addr_copy(iphdr->src, *ip_current_dest_addr());
|
||||||
|
ip_addr_copy(iphdr->dest, *ip_current_src_addr());
|
||||||
|
ICMPH_TYPE_SET(iecho, ICMP_ER);
|
||||||
|
/* adjust the checksum */
|
||||||
|
if (iecho->chksum >= PP_HTONS(0xffff - (ICMP_ECHO << 8))) {
|
||||||
|
iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
|
||||||
|
} else {
|
||||||
|
iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the correct TTL and recalculate the header checksum. */
|
||||||
|
IPH_TTL_SET(iphdr, ICMP_TTL);
|
||||||
|
IPH_CHKSUM_SET(iphdr, 0);
|
||||||
|
#if CHECKSUM_GEN_IP
|
||||||
|
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||||
|
#endif /* CHECKSUM_GEN_IP */
|
||||||
|
|
||||||
|
ICMP_STATS_INC(icmp.xmit);
|
||||||
|
/* increase number of messages attempted to send */
|
||||||
|
snmp_inc_icmpoutmsgs();
|
||||||
|
/* increase number of echo replies attempted to send */
|
||||||
|
snmp_inc_icmpoutechoreps();
|
||||||
|
|
||||||
|
if(pbuf_header(p, hlen)) {
|
||||||
|
LWIP_ASSERT("Can't move over header in packet", 0);
|
||||||
|
} else {
|
||||||
|
err_t ret;
|
||||||
|
/* send an ICMP packet, src addr is the dest addr of the curren packet */
|
||||||
|
ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL,
|
||||||
|
ICMP_TTL, 0, IP_PROTO_ICMP, inp);
|
||||||
|
if (ret != ERR_OK) {
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
|
||||||
|
(s16_t)type, (s16_t)code));
|
||||||
|
ICMP_STATS_INC(icmp.proterr);
|
||||||
|
ICMP_STATS_INC(icmp.drop);
|
||||||
|
}
|
||||||
|
pbuf_free(p);
|
||||||
|
return;
|
||||||
|
lenerr:
|
||||||
|
pbuf_free(p);
|
||||||
|
ICMP_STATS_INC(icmp.lenerr);
|
||||||
|
snmp_inc_icmpinerrors();
|
||||||
|
return;
|
||||||
|
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||||
|
memerr:
|
||||||
|
pbuf_free(p);
|
||||||
|
ICMP_STATS_INC(icmp.err);
|
||||||
|
snmp_inc_icmpinerrors();
|
||||||
|
return;
|
||||||
|
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an icmp 'destination unreachable' packet, called from ip_input() if
|
||||||
|
* the transport layer protocol is unknown and from udp_input() if the local
|
||||||
|
* port is not bound.
|
||||||
|
*
|
||||||
|
* @param p the input packet for which the 'unreachable' should be sent,
|
||||||
|
* p->payload pointing to the IP header
|
||||||
|
* @param t type of the 'unreachable' packet
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||||
|
{
|
||||||
|
icmp_send_response(p, ICMP_DUR, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IP_FORWARD || IP_REASSEMBLY
|
||||||
|
/**
|
||||||
|
* Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.
|
||||||
|
*
|
||||||
|
* @param p the input packet for which the 'time exceeded' should be sent,
|
||||||
|
* p->payload pointing to the IP header
|
||||||
|
* @param t type of the 'time exceeded' packet
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
||||||
|
{
|
||||||
|
icmp_send_response(p, ICMP_TE, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* IP_FORWARD || IP_REASSEMBLY */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an icmp packet in response to an incoming packet.
|
||||||
|
*
|
||||||
|
* @param p the input packet for which the 'unreachable' should be sent,
|
||||||
|
* p->payload pointing to the IP header
|
||||||
|
* @param type Type of the ICMP header
|
||||||
|
* @param code Code of the ICMP header
|
||||||
|
*/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
|
||||||
|
{
|
||||||
|
struct pbuf *q;
|
||||||
|
struct ip_hdr *iphdr;
|
||||||
|
/* we can use the echo header here */
|
||||||
|
struct icmp_echo_hdr *icmphdr;
|
||||||
|
ip_addr_t iphdr_src;
|
||||||
|
|
||||||
|
/* ICMP header + IP header + 8 bytes of data */
|
||||||
|
//为差错报文申请pbuf空间,pbuf中预留IP首部和以太网首部空间,pbuf数据区
|
||||||
|
//长度=差错报文首部+差错报文数据长度(IP首部长度+8)
|
||||||
|
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
|
||||||
|
PBUF_RAM);
|
||||||
|
if (q == NULL) {//失败,返回
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
||||||
|
(q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
|
||||||
|
|
||||||
|
iphdr = (struct ip_hdr *)p->payload;//指向引起差错的IP数据包首部
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
|
||||||
|
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, (" to "));
|
||||||
|
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
|
||||||
|
LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
|
||||||
|
|
||||||
|
icmphdr = (struct icmp_echo_hdr *)q->payload;//指向差错报文首部
|
||||||
|
icmphdr->type = type;//填写类型字段
|
||||||
|
icmphdr->code = code;//填写代码字段
|
||||||
|
icmphdr->id = 0;//对于目的不可达和数据报超时
|
||||||
|
icmphdr->seqno = 0;//报文,首部剩余的4个字节都为0
|
||||||
|
|
||||||
|
/* copy fields from original packet 将引起差错的IP数据报的IP首部+8字节数据拷贝到差错报文数据区*/
|
||||||
|
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
|
||||||
|
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
|
||||||
|
|
||||||
|
/* calculate checksum */
|
||||||
|
icmphdr->chksum = 0;//报文校验和字段清0
|
||||||
|
icmphdr->chksum = inet_chksum(icmphdr, q->len);//计算填写校验和
|
||||||
|
ICMP_STATS_INC(icmp.xmit);
|
||||||
|
/* increase number of messages attempted to send */
|
||||||
|
snmp_inc_icmpoutmsgs();
|
||||||
|
/* increase number of destination unreachable messages attempted to send */
|
||||||
|
snmp_inc_icmpouttimeexcds();
|
||||||
|
ip_addr_copy(iphdr_src, iphdr->src);
|
||||||
|
ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);//调用IP层函数输出ICMP报文
|
||||||
|
pbuf_free(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_ICMP */
|
810
tools/sdk/lwip/src/core/ipv4/igmp.c
Normal file
810
tools/sdk/lwip/src/core/ipv4/igmp.c
Normal file
@ -0,0 +1,810 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* IGMP - Internet Group Management Protocol
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002 CITEL Technologies Ltd.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is a contribution to the lwIP TCP/IP stack.
|
||||||
|
* The Swedish Institute of Computer Science and Adam Dunkels
|
||||||
|
* are specifically granted permission to redistribute this
|
||||||
|
* source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------
|
||||||
|
Note 1)
|
||||||
|
Although the rfc requires V1 AND V2 capability
|
||||||
|
we will only support v2 since now V1 is very old (August 1989)
|
||||||
|
V1 can be added if required
|
||||||
|
|
||||||
|
a debug print and statistic have been implemented to
|
||||||
|
show this up.
|
||||||
|
-------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------
|
||||||
|
Note 2)
|
||||||
|
A query for a specific group address (as opposed to ALLHOSTS)
|
||||||
|
has now been implemented as I am unsure if it is required
|
||||||
|
|
||||||
|
a debug print and statistic have been implemented to
|
||||||
|
show this up.
|
||||||
|
-------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------
|
||||||
|
Note 3)
|
||||||
|
The router alert rfc 2113 is implemented in outgoing packets
|
||||||
|
but not checked rigorously incoming
|
||||||
|
-------------------------------------------------------------
|
||||||
|
Steve Reynolds
|
||||||
|
------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
* RFC 988 - Host extensions for IP multicasting - V0
|
||||||
|
* RFC 1054 - Host extensions for IP multicasting -
|
||||||
|
* RFC 1112 - Host extensions for IP multicasting - V1
|
||||||
|
* RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard)
|
||||||
|
* RFC 3376 - Internet Group Management Protocol, Version 3 - V3
|
||||||
|
* RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+
|
||||||
|
* RFC 2113 - IP Router Alert Option -
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
* Includes
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/igmp.h"
|
||||||
|
#include "lwip/debug.h"
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/ip.h"
|
||||||
|
#include "lwip/inet_chksum.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
#include "lwip/icmp.h"
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "lwip/tcp.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
#ifdef MEMLEAK_DEBUG
|
||||||
|
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IGMP constants
|
||||||
|
*/
|
||||||
|
#define IGMP_TTL 1
|
||||||
|
#define IGMP_MINLEN 8
|
||||||
|
#define ROUTER_ALERT 0x9404
|
||||||
|
#define ROUTER_ALERTLEN 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IGMP message types, including version number.
|
||||||
|
*/
|
||||||
|
#define IGMP_MEMB_QUERY 0x11 /* Membership query */
|
||||||
|
#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
|
||||||
|
#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
|
||||||
|
#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
|
||||||
|
|
||||||
|
/* Group membership states */
|
||||||
|
#define IGMP_GROUP_NON_MEMBER 0
|
||||||
|
#define IGMP_GROUP_DELAYING_MEMBER 1
|
||||||
|
#define IGMP_GROUP_IDLE_MEMBER 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IGMP packet format.
|
||||||
|
*/
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/bpstruct.h"
|
||||||
|
#endif
|
||||||
|
PACK_STRUCT_BEGIN
|
||||||
|
struct igmp_msg {
|
||||||
|
PACK_STRUCT_FIELD(u8_t igmp_msgtype);
|
||||||
|
PACK_STRUCT_FIELD(u8_t igmp_maxresp);
|
||||||
|
PACK_STRUCT_FIELD(u16_t igmp_checksum);
|
||||||
|
PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address);
|
||||||
|
} PACK_STRUCT_STRUCT;
|
||||||
|
PACK_STRUCT_END
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/epstruct.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)ICACHE_FLASH_ATTR;
|
||||||
|
static err_t igmp_remove_group(struct igmp_group *group)ICACHE_FLASH_ATTR;
|
||||||
|
static void igmp_timeout( struct igmp_group *group)ICACHE_FLASH_ATTR;
|
||||||
|
static void igmp_start_timer(struct igmp_group *group, u8_t max_time)ICACHE_FLASH_ATTR;
|
||||||
|
static void igmp_stop_timer(struct igmp_group *group)ICACHE_FLASH_ATTR;
|
||||||
|
static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp)ICACHE_FLASH_ATTR;
|
||||||
|
static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)ICACHE_FLASH_ATTR;
|
||||||
|
static void igmp_send(struct igmp_group *group, u8_t type)ICACHE_FLASH_ATTR;
|
||||||
|
|
||||||
|
|
||||||
|
static struct igmp_group* igmp_group_list;
|
||||||
|
static ip_addr_t allsystems;
|
||||||
|
static ip_addr_t allrouters;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the IGMP module
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
igmp_init(void)
|
||||||
|
{
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
|
||||||
|
|
||||||
|
IP4_ADDR(&allsystems, 224, 0, 0, 1);
|
||||||
|
IP4_ADDR(&allrouters, 224, 0, 0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LWIP_DEBUG
|
||||||
|
/**
|
||||||
|
* Dump global IGMP groups list
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
igmp_dump_group_list()
|
||||||
|
{
|
||||||
|
struct igmp_group *group = igmp_group_list;
|
||||||
|
|
||||||
|
while (group != NULL) {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
|
||||||
|
group = group->next;
|
||||||
|
}
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define igmp_dump_group_list()
|
||||||
|
#endif /* LWIP_DEBUG */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start IGMP processing on interface
|
||||||
|
*
|
||||||
|
* @param netif network interface on which start IGMP processing
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
igmp_start(struct netif *netif)
|
||||||
|
{
|
||||||
|
struct igmp_group* group;
|
||||||
|
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
|
||||||
|
|
||||||
|
group = igmp_lookup_group(netif, &allsystems);
|
||||||
|
|
||||||
|
if (group != NULL) {
|
||||||
|
group->group_state = IGMP_GROUP_IDLE_MEMBER;
|
||||||
|
group->use++;
|
||||||
|
|
||||||
|
/* Allow the igmp messages at the MAC level */
|
||||||
|
if (netif->igmp_mac_filter != NULL) {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, &allsystems);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||||
|
netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop IGMP processing on interface
|
||||||
|
*
|
||||||
|
* @param netif network interface on which stop IGMP processing
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
igmp_stop(struct netif *netif)
|
||||||
|
{
|
||||||
|
struct igmp_group *group = igmp_group_list;
|
||||||
|
struct igmp_group *prev = NULL;
|
||||||
|
struct igmp_group *next;
|
||||||
|
|
||||||
|
/* look for groups joined on this interface further down the list */
|
||||||
|
while (group != NULL) {
|
||||||
|
next = group->next;
|
||||||
|
/* is it a group joined on this interface? */
|
||||||
|
if (group->netif == netif) {
|
||||||
|
/* is it the first group of the list? */
|
||||||
|
if (group == igmp_group_list) {
|
||||||
|
igmp_group_list = next;
|
||||||
|
}
|
||||||
|
/* is there a "previous" group defined? */
|
||||||
|
if (prev != NULL) {
|
||||||
|
prev->next = next;
|
||||||
|
}
|
||||||
|
/* disable the group at the MAC level */
|
||||||
|
if (netif->igmp_mac_filter != NULL) {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||||
|
netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
|
||||||
|
}
|
||||||
|
/* free group */
|
||||||
|
memp_free(MEMP_IGMP_GROUP, group);
|
||||||
|
} else {
|
||||||
|
/* change the "previous" */
|
||||||
|
prev = group;
|
||||||
|
}
|
||||||
|
/* move to "next" */
|
||||||
|
group = next;
|
||||||
|
}
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report IGMP memberships for this interface
|
||||||
|
*
|
||||||
|
* @param netif network interface on which report IGMP memberships
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
igmp_report_groups(struct netif *netif)
|
||||||
|
{
|
||||||
|
struct igmp_group *group = igmp_group_list;
|
||||||
|
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
|
||||||
|
|
||||||
|
while (group != NULL) {
|
||||||
|
if (group->netif == netif) {
|
||||||
|
igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
|
||||||
|
}
|
||||||
|
group = group->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for a group in the global igmp_group_list
|
||||||
|
*
|
||||||
|
* @param ifp the network interface for which to look
|
||||||
|
* @param addr the group ip address to search for
|
||||||
|
* @return a struct igmp_group* if the group has been found,
|
||||||
|
* NULL if the group wasn't found.
|
||||||
|
*/
|
||||||
|
struct igmp_group *
|
||||||
|
igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)
|
||||||
|
{
|
||||||
|
struct igmp_group *group = igmp_group_list;
|
||||||
|
|
||||||
|
while (group != NULL) {
|
||||||
|
if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
group = group->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* to be clearer, we return NULL here instead of
|
||||||
|
* 'group' (which is also NULL at this point).
|
||||||
|
*/
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for a specific igmp group and create a new one if not found-
|
||||||
|
*
|
||||||
|
* @param ifp the network interface for which to look
|
||||||
|
* @param addr the group ip address to search
|
||||||
|
* @return a struct igmp_group*,
|
||||||
|
* NULL on memory error.
|
||||||
|
*/
|
||||||
|
struct igmp_group *
|
||||||
|
igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
|
||||||
|
{
|
||||||
|
struct igmp_group *group = igmp_group_list;
|
||||||
|
|
||||||
|
/* Search if the group already exists */
|
||||||
|
group = igmp_lookfor_group(ifp, addr);
|
||||||
|
if (group != NULL) {
|
||||||
|
/* Group already exists. */
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Group doesn't exist yet, create a new one */
|
||||||
|
group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
|
||||||
|
if (group != NULL) {
|
||||||
|
group->netif = ifp;
|
||||||
|
ip_addr_set(&(group->group_address), addr);
|
||||||
|
group->timer = 0; /* Not running */
|
||||||
|
group->group_state = IGMP_GROUP_NON_MEMBER;
|
||||||
|
group->last_reporter_flag = 0;
|
||||||
|
group->use = 0;
|
||||||
|
group->next = igmp_group_list;
|
||||||
|
|
||||||
|
igmp_group_list = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, addr);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a group in the global igmp_group_list
|
||||||
|
*
|
||||||
|
* @param group the group to remove from the global igmp_group_list
|
||||||
|
* @return ERR_OK if group was removed from the list, an err_t otherwise
|
||||||
|
*/
|
||||||
|
static err_t
|
||||||
|
igmp_remove_group(struct igmp_group *group)
|
||||||
|
{
|
||||||
|
err_t err = ERR_OK;
|
||||||
|
|
||||||
|
/* Is it the first group? */
|
||||||
|
if (igmp_group_list == group) {
|
||||||
|
igmp_group_list = group->next;
|
||||||
|
} else {
|
||||||
|
/* look for group further down the list */
|
||||||
|
struct igmp_group *tmpGroup;
|
||||||
|
for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
|
||||||
|
if (tmpGroup->next == group) {
|
||||||
|
tmpGroup->next = group->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Group not found in the global igmp_group_list */
|
||||||
|
if (tmpGroup == NULL)
|
||||||
|
err = ERR_ARG;
|
||||||
|
}
|
||||||
|
/* free group */
|
||||||
|
memp_free(MEMP_IGMP_GROUP, group);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from ip_input() if a new IGMP packet is received.
|
||||||
|
*
|
||||||
|
* @param p received igmp packet, p->payload pointing to the ip header
|
||||||
|
* @param inp network interface on which the packet was received
|
||||||
|
* @param dest destination ip address of the igmp packet
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
|
||||||
|
{
|
||||||
|
struct ip_hdr * iphdr;
|
||||||
|
struct igmp_msg* igmp;
|
||||||
|
struct igmp_group* group;
|
||||||
|
struct igmp_group* groupref;
|
||||||
|
|
||||||
|
IGMP_STATS_INC(igmp.recv);
|
||||||
|
|
||||||
|
/* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
|
||||||
|
iphdr = (struct ip_hdr *)p->payload;
|
||||||
|
if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
|
||||||
|
pbuf_free(p);
|
||||||
|
IGMP_STATS_INC(igmp.lenerr);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
|
||||||
|
|
||||||
|
/* Now calculate and check the checksum */
|
||||||
|
igmp = (struct igmp_msg *)p->payload;
|
||||||
|
if (inet_chksum(igmp, p->len)) {
|
||||||
|
pbuf_free(p);
|
||||||
|
IGMP_STATS_INC(igmp.chkerr);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Packet is ok so find an existing group */
|
||||||
|
group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
|
||||||
|
|
||||||
|
/* If group can be found or create... */
|
||||||
|
if (!group) {
|
||||||
|
pbuf_free(p);
|
||||||
|
IGMP_STATS_INC(igmp.drop);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOW ACT ON THE INCOMING MESSAGE TYPE... */
|
||||||
|
switch (igmp->igmp_msgtype) {
|
||||||
|
case IGMP_MEMB_QUERY: {
|
||||||
|
/* IGMP_MEMB_QUERY to the "all systems" address ? */
|
||||||
|
if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {
|
||||||
|
/* THIS IS THE GENERAL QUERY */
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
|
||||||
|
|
||||||
|
if (igmp->igmp_maxresp == 0) {
|
||||||
|
IGMP_STATS_INC(igmp.rx_v1);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
|
||||||
|
igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
|
||||||
|
} else {
|
||||||
|
IGMP_STATS_INC(igmp.rx_general);
|
||||||
|
}
|
||||||
|
|
||||||
|
groupref = igmp_group_list;
|
||||||
|
while (groupref) {
|
||||||
|
/* Do not send messages on the all systems group address! */
|
||||||
|
if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
|
||||||
|
igmp_delaying_member(groupref, igmp->igmp_maxresp);
|
||||||
|
}
|
||||||
|
groupref = groupref->next;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* IGMP_MEMB_QUERY to a specific group ? */
|
||||||
|
if (!ip_addr_isany(&igmp->igmp_group_address)) {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
|
||||||
|
if (ip_addr_cmp(dest, &allsystems)) {
|
||||||
|
ip_addr_t groupaddr;
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
|
||||||
|
/* we first need to re-look for the group since we used dest last time */
|
||||||
|
ip_addr_copy(groupaddr, igmp->igmp_group_address);
|
||||||
|
group = igmp_lookfor_group(inp, &groupaddr);
|
||||||
|
} else {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group != NULL) {
|
||||||
|
IGMP_STATS_INC(igmp.rx_group);
|
||||||
|
igmp_delaying_member(group, igmp->igmp_maxresp);
|
||||||
|
} else {
|
||||||
|
IGMP_STATS_INC(igmp.drop);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
IGMP_STATS_INC(igmp.proterr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IGMP_V2_MEMB_REPORT: {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
|
||||||
|
IGMP_STATS_INC(igmp.rx_report);
|
||||||
|
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
|
||||||
|
/* This is on a specific group we have already looked up */
|
||||||
|
group->timer = 0; /* stopped */
|
||||||
|
group->group_state = IGMP_GROUP_IDLE_MEMBER;
|
||||||
|
group->last_reporter_flag = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
|
||||||
|
igmp->igmp_msgtype, group->group_state, &group, group->netif));
|
||||||
|
IGMP_STATS_INC(igmp.proterr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf_free(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Join a group on one network interface.
|
||||||
|
*
|
||||||
|
* @param ifaddr ip address of the network interface which should join a new group
|
||||||
|
* @param groupaddr the ip address of the group which to join
|
||||||
|
* @return ERR_OK if group was joined on the netif(s), an err_t otherwise
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
|
||||||
|
{
|
||||||
|
err_t err = ERR_VAL; /* no matching interface */
|
||||||
|
struct igmp_group *group;
|
||||||
|
struct netif *netif;
|
||||||
|
|
||||||
|
/* make sure it is multicast address */
|
||||||
|
LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
|
||||||
|
LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
|
||||||
|
|
||||||
|
/* loop through netif's */
|
||||||
|
netif = netif_list;
|
||||||
|
while (netif != NULL) {
|
||||||
|
/* Should we join this interface ? */
|
||||||
|
if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
|
||||||
|
/* find group or create a new one if not found */
|
||||||
|
group = igmp_lookup_group(netif, groupaddr);
|
||||||
|
|
||||||
|
if (group != NULL) {
|
||||||
|
/* This should create a new group, check the state to make sure */
|
||||||
|
if (group->group_state != IGMP_GROUP_NON_MEMBER) {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
|
||||||
|
} else {
|
||||||
|
/* OK - it was new group */
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
||||||
|
|
||||||
|
/* If first use of the group, allow the group at the MAC level */
|
||||||
|
if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||||
|
netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
IGMP_STATS_INC(igmp.tx_join);
|
||||||
|
igmp_send(group, IGMP_V2_MEMB_REPORT);
|
||||||
|
|
||||||
|
igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
|
||||||
|
|
||||||
|
/* Need to work out where this timer comes from */
|
||||||
|
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
|
||||||
|
}
|
||||||
|
/* Increment group use */
|
||||||
|
group->use++;
|
||||||
|
/* Join on this interface */
|
||||||
|
err = ERR_OK;
|
||||||
|
} else {
|
||||||
|
/* Return an error even if some network interfaces are joined */
|
||||||
|
/** @todo undo any other netif already joined */
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* proceed to next network interface */
|
||||||
|
netif = netif->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Leave a group on one network interface.
|
||||||
|
*
|
||||||
|
* @param ifaddr ip address of the network interface which should leave a group
|
||||||
|
* @param groupaddr the ip address of the group which to leave
|
||||||
|
* @return ERR_OK if group was left on the netif(s), an err_t otherwise
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
|
||||||
|
{
|
||||||
|
err_t err = ERR_VAL; /* no matching interface */
|
||||||
|
struct igmp_group *group;
|
||||||
|
struct netif *netif;
|
||||||
|
|
||||||
|
/* make sure it is multicast address */
|
||||||
|
LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
|
||||||
|
LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
|
||||||
|
|
||||||
|
/* loop through netif's */
|
||||||
|
netif = netif_list;
|
||||||
|
while (netif != NULL) {
|
||||||
|
/* Should we leave this interface ? */
|
||||||
|
if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
|
||||||
|
/* find group */
|
||||||
|
group = igmp_lookfor_group(netif, groupaddr);
|
||||||
|
|
||||||
|
if (group != NULL) {
|
||||||
|
/* Only send a leave if the flag is set according to the state diagram */
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
||||||
|
|
||||||
|
/* If there is no other use of the group */
|
||||||
|
if (group->use <= 1) {
|
||||||
|
/* If we are the last reporter for this group */
|
||||||
|
if (group->last_reporter_flag) {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
|
||||||
|
IGMP_STATS_INC(igmp.tx_leave);
|
||||||
|
igmp_send(group, IGMP_LEAVE_GROUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable the group at the MAC level */
|
||||||
|
if (netif->igmp_mac_filter != NULL) {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||||
|
netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
||||||
|
|
||||||
|
/* Free the group */
|
||||||
|
igmp_remove_group(group);
|
||||||
|
} else {
|
||||||
|
/* Decrement group use */
|
||||||
|
group->use--;
|
||||||
|
}
|
||||||
|
/* Leave on this interface */
|
||||||
|
err = ERR_OK;
|
||||||
|
} else {
|
||||||
|
/* It's not a fatal error on "leavegroup" */
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* proceed to next network interface */
|
||||||
|
netif = netif->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The igmp timer function (both for NO_SYS=1 and =0)
|
||||||
|
* Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
igmp_tmr(void)
|
||||||
|
{
|
||||||
|
struct igmp_group *group = igmp_group_list;
|
||||||
|
|
||||||
|
while (group != NULL) {
|
||||||
|
if (group->timer > 0) {
|
||||||
|
group->timer--;
|
||||||
|
if (group->timer == 0) {
|
||||||
|
igmp_timeout(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
group = group->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called if a timeout for one group is reached.
|
||||||
|
* Sends a report for this group.
|
||||||
|
*
|
||||||
|
* @param group an igmp_group for which a timeout is reached
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
igmp_timeout(struct igmp_group *group)
|
||||||
|
{
|
||||||
|
/* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
|
||||||
|
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
|
||||||
|
ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
|
||||||
|
|
||||||
|
IGMP_STATS_INC(igmp.tx_report);
|
||||||
|
igmp_send(group, IGMP_V2_MEMB_REPORT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a timer for an igmp group
|
||||||
|
*
|
||||||
|
* @param group the igmp_group for which to start a timer
|
||||||
|
* @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
|
||||||
|
* every call to igmp_tmr())
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
igmp_start_timer(struct igmp_group *group, u8_t max_time)
|
||||||
|
{
|
||||||
|
/* ensure the input value is > 0 */
|
||||||
|
if (max_time == 0) {
|
||||||
|
max_time = 1;
|
||||||
|
}
|
||||||
|
/* ensure the random value is > 0 */
|
||||||
|
group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delaying membership report for a group if necessary
|
||||||
|
*
|
||||||
|
* @param group the igmp_group for which "delaying" membership report
|
||||||
|
* @param maxresp query delay
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
|
||||||
|
{
|
||||||
|
if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
|
||||||
|
((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
|
||||||
|
((group->timer == 0) || (maxresp < group->timer)))) {
|
||||||
|
igmp_start_timer(group, maxresp);
|
||||||
|
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an IP packet on a network interface. This function constructs the IP header
|
||||||
|
* and calculates the IP header checksum. If the source IP address is NULL,
|
||||||
|
* the IP address of the outgoing network interface is filled in as source address.
|
||||||
|
*
|
||||||
|
* @param p the packet to send (p->payload points to the data, e.g. next
|
||||||
|
protocol header; if dest == IP_HDRINCL, p already includes an IP
|
||||||
|
header and p->payload points to that IP header)
|
||||||
|
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
|
||||||
|
* IP address of the netif used to send is used as source address)
|
||||||
|
* @param dest the destination IP address to send the packet to
|
||||||
|
* @param ttl the TTL value to be set in the IP header
|
||||||
|
* @param proto the PROTOCOL to be set in the IP header
|
||||||
|
* @param netif the netif on which to send this packet
|
||||||
|
* @return ERR_OK if the packet was sent OK
|
||||||
|
* ERR_BUF if p doesn't have enough space for IP/LINK headers
|
||||||
|
* returns errors returned by netif->output
|
||||||
|
*/
|
||||||
|
static err_t
|
||||||
|
igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)
|
||||||
|
{
|
||||||
|
/* This is the "router alert" option */
|
||||||
|
u16_t ra[2];
|
||||||
|
ra[0] = PP_HTONS(ROUTER_ALERT);
|
||||||
|
ra[1] = 0x0000; /* Router shall examine packet */
|
||||||
|
IGMP_STATS_INC(igmp.xmit);
|
||||||
|
return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an igmp packet to a specific group.
|
||||||
|
*
|
||||||
|
* @param group the group to which to send the packet
|
||||||
|
* @param type the type of igmp packet to send
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
igmp_send(struct igmp_group *group, u8_t type)
|
||||||
|
{
|
||||||
|
struct pbuf* p = NULL;
|
||||||
|
struct igmp_msg* igmp = NULL;
|
||||||
|
ip_addr_t src = *IP_ADDR_ANY;
|
||||||
|
ip_addr_t* dest = NULL;
|
||||||
|
|
||||||
|
/* IP header + "router alert" option + IGMP header */
|
||||||
|
p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
igmp = (struct igmp_msg *)p->payload;
|
||||||
|
LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
|
||||||
|
(p->len >= sizeof(struct igmp_msg)));
|
||||||
|
ip_addr_copy(src, group->netif->ip_addr);
|
||||||
|
|
||||||
|
if (type == IGMP_V2_MEMB_REPORT) {
|
||||||
|
dest = &(group->group_address);
|
||||||
|
ip_addr_copy(igmp->igmp_group_address, group->group_address);
|
||||||
|
group->last_reporter_flag = 1; /* Remember we were the last to report */
|
||||||
|
} else {
|
||||||
|
if (type == IGMP_LEAVE_GROUP) {
|
||||||
|
dest = &allrouters;
|
||||||
|
ip_addr_copy(igmp->igmp_group_address, group->group_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
|
||||||
|
igmp->igmp_msgtype = type;
|
||||||
|
igmp->igmp_maxresp = 0;
|
||||||
|
igmp->igmp_checksum = 0;
|
||||||
|
igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
|
||||||
|
|
||||||
|
igmp_ip_output_if(p, &src, dest, group->netif);
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf_free(p);
|
||||||
|
} else {
|
||||||
|
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
|
||||||
|
IGMP_STATS_INC(igmp.memerr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_IGMP */
|
42
tools/sdk/lwip/src/core/ipv4/inet.c
Normal file
42
tools/sdk/lwip/src/core/ipv4/inet.c
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Functions common to all TCP/IPv4 modules, such as the byte order functions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#include "lwip/inet.h"
|
||||||
|
|
450
tools/sdk/lwip/src/core/ipv4/inet_chksum.c
Normal file
450
tools/sdk/lwip/src/core/ipv4/inet_chksum.c
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Incluse internet checksum functions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#include "lwip/inet_chksum.h"
|
||||||
|
#include "lwip/def.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* These are some reference implementations of the checksum algorithm, with the
|
||||||
|
* aim of being simple, correct and fully portable. Checksumming is the
|
||||||
|
* first thing you would want to optimize for your platform. If you create
|
||||||
|
* your own version, link it in and in your cc.h put:
|
||||||
|
*
|
||||||
|
* #define LWIP_CHKSUM <your_checksum_routine>
|
||||||
|
*
|
||||||
|
* Or you can select from the implementations below by defining
|
||||||
|
* LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LWIP_CHKSUM
|
||||||
|
# define LWIP_CHKSUM lwip_standard_chksum
|
||||||
|
# ifndef LWIP_CHKSUM_ALGORITHM
|
||||||
|
# define LWIP_CHKSUM_ALGORITHM 2
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
/* If none set: */
|
||||||
|
#ifndef LWIP_CHKSUM_ALGORITHM
|
||||||
|
# define LWIP_CHKSUM_ALGORITHM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
|
||||||
|
/**
|
||||||
|
* lwip checksum
|
||||||
|
*
|
||||||
|
* @param dataptr points to start of data to be summed at any boundary
|
||||||
|
* @param len length of data to be summed
|
||||||
|
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
||||||
|
*
|
||||||
|
* @note accumulator size limits summable length to 64k
|
||||||
|
* @note host endianess is irrelevant (p3 RFC1071)
|
||||||
|
*/
|
||||||
|
static u16_t ICACHE_FLASH_ATTR
|
||||||
|
lwip_standard_chksum(void *dataptr, u16_t len)
|
||||||
|
{
|
||||||
|
u32_t acc;
|
||||||
|
u16_t src;
|
||||||
|
u8_t *octetptr;
|
||||||
|
|
||||||
|
acc = 0;
|
||||||
|
/* dataptr may be at odd or even addresses */
|
||||||
|
octetptr = (u8_t*)dataptr;
|
||||||
|
while (len > 1) {
|
||||||
|
/* declare first octet as most significant
|
||||||
|
thus assume network order, ignoring host order */
|
||||||
|
src = (*octetptr) << 8;
|
||||||
|
octetptr++;
|
||||||
|
/* declare second octet as least significant */
|
||||||
|
src |= (*octetptr);
|
||||||
|
octetptr++;
|
||||||
|
acc += src;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
if (len > 0) {
|
||||||
|
/* accumulate remaining octet */
|
||||||
|
src = (*octetptr) << 8;
|
||||||
|
acc += src;
|
||||||
|
}
|
||||||
|
/* add deferred carry bits */
|
||||||
|
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
||||||
|
if ((acc & 0xffff0000UL) != 0) {
|
||||||
|
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
||||||
|
}
|
||||||
|
/* This maybe a little confusing: reorder sum using htons()
|
||||||
|
instead of ntohs() since it has a little less call overhead.
|
||||||
|
The caller must invert bits for Internet sum ! */
|
||||||
|
return htons((u16_t)acc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
|
||||||
|
/*
|
||||||
|
* Curt McDowell
|
||||||
|
* Broadcom Corp.
|
||||||
|
* csm@broadcom.com
|
||||||
|
*
|
||||||
|
* IP checksum two bytes at a time with support for
|
||||||
|
* unaligned buffer.
|
||||||
|
* Works for len up to and including 0x20000.
|
||||||
|
* by Curt McDowell, Broadcom Corp. 12/08/2005
|
||||||
|
*
|
||||||
|
* @param dataptr points to start of data to be summed at any boundary
|
||||||
|
* @param len length of data to be summed
|
||||||
|
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static u16_t ICACHE_FLASH_ATTR
|
||||||
|
lwip_standard_chksum(void *dataptr, int len)
|
||||||
|
{
|
||||||
|
u8_t *pb = (u8_t *)dataptr;
|
||||||
|
u16_t *ps, t = 0;
|
||||||
|
u32_t sum = 0;
|
||||||
|
int odd = ((mem_ptr_t)pb & 1);
|
||||||
|
|
||||||
|
/* Get aligned to u16_t */
|
||||||
|
if (odd && len > 0) {
|
||||||
|
((u8_t *)&t)[1] = *pb++;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the bulk of the data */
|
||||||
|
ps = (u16_t *)(void *)pb;
|
||||||
|
while (len > 1) {
|
||||||
|
sum += *ps++;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Consume left-over byte, if any */
|
||||||
|
if (len > 0) {
|
||||||
|
((u8_t *)&t)[0] = *(u8_t *)ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add end bytes */
|
||||||
|
sum += t;
|
||||||
|
|
||||||
|
/* Fold 32-bit sum to 16 bits
|
||||||
|
calling this twice is propably faster than if statements... */
|
||||||
|
sum = FOLD_U32T(sum);
|
||||||
|
sum = FOLD_U32T(sum);
|
||||||
|
|
||||||
|
/* Swap if alignment was odd */
|
||||||
|
if (odd) {
|
||||||
|
sum = SWAP_BYTES_IN_WORD(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (u16_t)sum;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
|
||||||
|
/**
|
||||||
|
* An optimized checksum routine. Basically, it uses loop-unrolling on
|
||||||
|
* the checksum loop, treating the head and tail bytes specially, whereas
|
||||||
|
* the inner loop acts on 8 bytes at a time.
|
||||||
|
*
|
||||||
|
* @arg start of buffer to be checksummed. May be an odd byte address.
|
||||||
|
* @len number of bytes in the buffer to be checksummed.
|
||||||
|
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
||||||
|
*
|
||||||
|
* by Curt McDowell, Broadcom Corp. December 8th, 2005
|
||||||
|
*/
|
||||||
|
|
||||||
|
static u16_t ICACHE_FLASH_ATTR
|
||||||
|
lwip_standard_chksum(void *dataptr, int len)
|
||||||
|
{
|
||||||
|
u8_t *pb = (u8_t *)dataptr;
|
||||||
|
u16_t *ps, t = 0;
|
||||||
|
u32_t *pl;
|
||||||
|
u32_t sum = 0, tmp;
|
||||||
|
/* starts at odd byte address? */
|
||||||
|
int odd = ((mem_ptr_t)pb & 1);
|
||||||
|
|
||||||
|
if (odd && len > 0) {
|
||||||
|
((u8_t *)&t)[1] = *pb++;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
ps = (u16_t *)pb;
|
||||||
|
|
||||||
|
if (((mem_ptr_t)ps & 3) && len > 1) {
|
||||||
|
sum += *ps++;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
pl = (u32_t *)ps;
|
||||||
|
|
||||||
|
while (len > 7) {
|
||||||
|
tmp = sum + *pl++; /* ping */
|
||||||
|
if (tmp < sum) {
|
||||||
|
tmp++; /* add back carry */
|
||||||
|
}
|
||||||
|
|
||||||
|
sum = tmp + *pl++; /* pong */
|
||||||
|
if (sum < tmp) {
|
||||||
|
sum++; /* add back carry */
|
||||||
|
}
|
||||||
|
|
||||||
|
len -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make room in upper bits */
|
||||||
|
sum = FOLD_U32T(sum);
|
||||||
|
|
||||||
|
ps = (u16_t *)pl;
|
||||||
|
|
||||||
|
/* 16-bit aligned word remaining? */
|
||||||
|
while (len > 1) {
|
||||||
|
sum += *ps++;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dangling tail byte remaining? */
|
||||||
|
if (len > 0) { /* include odd byte */
|
||||||
|
((u8_t *)&t)[0] = *(u8_t *)ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
sum += t; /* add end bytes */
|
||||||
|
|
||||||
|
/* Fold 32-bit sum to 16 bits
|
||||||
|
calling this twice is propably faster than if statements... */
|
||||||
|
sum = FOLD_U32T(sum);
|
||||||
|
sum = FOLD_U32T(sum);
|
||||||
|
|
||||||
|
if (odd) {
|
||||||
|
sum = SWAP_BYTES_IN_WORD(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (u16_t)sum;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* inet_chksum_pseudo:
|
||||||
|
*
|
||||||
|
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||||
|
* IP addresses are expected to be in network byte order.
|
||||||
|
*
|
||||||
|
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
||||||
|
* @param src source ip address (used for checksum of pseudo header)
|
||||||
|
* @param dst destination ip address (used for checksum of pseudo header)
|
||||||
|
* @param proto ip protocol (used for checksum of pseudo header)
|
||||||
|
* @param proto_len length of the ip data part (used for checksum of pseudo header)
|
||||||
|
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||||
|
*/
|
||||||
|
u16_t
|
||||||
|
inet_chksum_pseudo(struct pbuf *p,
|
||||||
|
ip_addr_t *src, ip_addr_t *dest,
|
||||||
|
u8_t proto, u16_t proto_len)
|
||||||
|
{
|
||||||
|
u32_t acc;
|
||||||
|
u32_t addr;
|
||||||
|
struct pbuf *q;
|
||||||
|
u8_t swapped;
|
||||||
|
|
||||||
|
acc = 0;
|
||||||
|
swapped = 0;
|
||||||
|
/* iterate through all pbuf in chain */
|
||||||
|
for(q = p; q != NULL; q = q->next) {
|
||||||
|
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
|
||||||
|
(void *)q, (void *)q->next));
|
||||||
|
acc += LWIP_CHKSUM(q->payload, q->len);
|
||||||
|
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||||
|
/* just executing this next line is probably faster that the if statement needed
|
||||||
|
to check whether we really need to execute it, and does no harm */
|
||||||
|
acc = FOLD_U32T(acc);
|
||||||
|
if (q->len % 2 != 0) {
|
||||||
|
swapped = 1 - swapped;
|
||||||
|
acc = SWAP_BYTES_IN_WORD(acc);
|
||||||
|
}
|
||||||
|
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swapped) {
|
||||||
|
acc = SWAP_BYTES_IN_WORD(acc);
|
||||||
|
}
|
||||||
|
addr = ip4_addr_get_u32(src);
|
||||||
|
acc += (addr & 0xffffUL);
|
||||||
|
acc += ((addr >> 16) & 0xffffUL);
|
||||||
|
addr = ip4_addr_get_u32(dest);
|
||||||
|
acc += (addr & 0xffffUL);
|
||||||
|
acc += ((addr >> 16) & 0xffffUL);
|
||||||
|
acc += (u32_t)htons((u16_t)proto);
|
||||||
|
acc += (u32_t)htons(proto_len);
|
||||||
|
|
||||||
|
/* Fold 32-bit sum to 16 bits
|
||||||
|
calling this twice is propably faster than if statements... */
|
||||||
|
acc = FOLD_U32T(acc);
|
||||||
|
acc = FOLD_U32T(acc);
|
||||||
|
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
|
||||||
|
return (u16_t)~(acc & 0xffffUL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inet_chksum_pseudo:
|
||||||
|
*
|
||||||
|
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||||
|
* IP addresses are expected to be in network byte order.
|
||||||
|
*
|
||||||
|
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
||||||
|
* @param src source ip address (used for checksum of pseudo header)
|
||||||
|
* @param dst destination ip address (used for checksum of pseudo header)
|
||||||
|
* @param proto ip protocol (used for checksum of pseudo header)
|
||||||
|
* @param proto_len length of the ip data part (used for checksum of pseudo header)
|
||||||
|
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||||
|
*/
|
||||||
|
u16_t
|
||||||
|
inet_chksum_pseudo_partial(struct pbuf *p,
|
||||||
|
ip_addr_t *src, ip_addr_t *dest,
|
||||||
|
u8_t proto, u16_t proto_len, u16_t chksum_len)
|
||||||
|
{
|
||||||
|
u32_t acc;
|
||||||
|
u32_t addr;
|
||||||
|
struct pbuf *q;
|
||||||
|
u8_t swapped;
|
||||||
|
u16_t chklen;
|
||||||
|
|
||||||
|
acc = 0;
|
||||||
|
swapped = 0;
|
||||||
|
/* iterate through all pbuf in chain */
|
||||||
|
for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
|
||||||
|
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
|
||||||
|
(void *)q, (void *)q->next));
|
||||||
|
chklen = q->len;
|
||||||
|
if (chklen > chksum_len) {
|
||||||
|
chklen = chksum_len;
|
||||||
|
}
|
||||||
|
acc += LWIP_CHKSUM(q->payload, chklen);
|
||||||
|
chksum_len -= chklen;
|
||||||
|
LWIP_ASSERT("delete me", chksum_len < 0x7fff);
|
||||||
|
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||||
|
/* fold the upper bit down */
|
||||||
|
acc = FOLD_U32T(acc);
|
||||||
|
if (q->len % 2 != 0) {
|
||||||
|
swapped = 1 - swapped;
|
||||||
|
acc = SWAP_BYTES_IN_WORD(acc);
|
||||||
|
}
|
||||||
|
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swapped) {
|
||||||
|
acc = SWAP_BYTES_IN_WORD(acc);
|
||||||
|
}
|
||||||
|
addr = ip4_addr_get_u32(src);
|
||||||
|
acc += (addr & 0xffffUL);
|
||||||
|
acc += ((addr >> 16) & 0xffffUL);
|
||||||
|
addr = ip4_addr_get_u32(dest);
|
||||||
|
acc += (addr & 0xffffUL);
|
||||||
|
acc += ((addr >> 16) & 0xffffUL);
|
||||||
|
acc += (u32_t)htons((u16_t)proto);
|
||||||
|
acc += (u32_t)htons(proto_len);
|
||||||
|
|
||||||
|
/* Fold 32-bit sum to 16 bits
|
||||||
|
calling this twice is propably faster than if statements... */
|
||||||
|
acc = FOLD_U32T(acc);
|
||||||
|
acc = FOLD_U32T(acc);
|
||||||
|
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
|
||||||
|
return (u16_t)~(acc & 0xffffUL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inet_chksum:
|
||||||
|
*
|
||||||
|
* Calculates the Internet checksum over a portion of memory. Used primarily for IP
|
||||||
|
* and ICMP.
|
||||||
|
*
|
||||||
|
* @param dataptr start of the buffer to calculate the checksum (no alignment needed)
|
||||||
|
* @param len length of the buffer to calculate the checksum
|
||||||
|
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||||
|
*/
|
||||||
|
|
||||||
|
u16_t
|
||||||
|
inet_chksum(void *dataptr, u16_t len)
|
||||||
|
{
|
||||||
|
return ~LWIP_CHKSUM(dataptr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate a checksum over a chain of pbufs (without pseudo-header, much like
|
||||||
|
* inet_chksum only pbufs are used).
|
||||||
|
*
|
||||||
|
* @param p pbuf chain over that the checksum should be calculated
|
||||||
|
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||||
|
*/
|
||||||
|
u16_t
|
||||||
|
inet_chksum_pbuf(struct pbuf *p)
|
||||||
|
{
|
||||||
|
u32_t acc;
|
||||||
|
struct pbuf *q;
|
||||||
|
u8_t swapped;
|
||||||
|
|
||||||
|
acc = 0;
|
||||||
|
swapped = 0;
|
||||||
|
for(q = p; q != NULL; q = q->next) {
|
||||||
|
acc += LWIP_CHKSUM(q->payload, q->len);
|
||||||
|
acc = FOLD_U32T(acc);
|
||||||
|
if (q->len % 2 != 0) {
|
||||||
|
swapped = 1 - swapped;
|
||||||
|
acc = SWAP_BYTES_IN_WORD(acc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swapped) {
|
||||||
|
acc = SWAP_BYTES_IN_WORD(acc);
|
||||||
|
}
|
||||||
|
return (u16_t)~(acc & 0xffffUL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* These are some implementations for LWIP_CHKSUM_COPY, which copies data
|
||||||
|
* like MEMCPY but generates a checksum at the same time. Since this is a
|
||||||
|
* performance-sensitive function, you might want to create your own version
|
||||||
|
* in assembly targeted at your hardware by defining it in lwipopts.h:
|
||||||
|
* #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */
|
||||||
|
/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM.
|
||||||
|
* For architectures with big caches, data might still be in cache when
|
||||||
|
* generating the checksum after copying.
|
||||||
|
*/
|
||||||
|
u16_t
|
||||||
|
lwip_chksum_copy(void *dst, const void *src, u16_t len)
|
||||||
|
{
|
||||||
|
MEMCPY(dst, src, len);
|
||||||
|
return LWIP_CHKSUM(dst, len);
|
||||||
|
}
|
||||||
|
#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */
|
910
tools/sdk/lwip/src/core/ipv4/ip.c
Normal file
910
tools/sdk/lwip/src/core/ipv4/ip.c
Normal file
@ -0,0 +1,910 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* This is the IPv4 layer implementation for incoming and outgoing IP traffic.
|
||||||
|
*
|
||||||
|
* @see ip_frag.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
#include "lwip/ip.h"
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/ip_frag.h"
|
||||||
|
#include "lwip/inet_chksum.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
#include "lwip/icmp.h"
|
||||||
|
#include "lwip/igmp.h"
|
||||||
|
#include "lwip/raw.h"
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "lwip/tcp_impl.h"
|
||||||
|
#include "lwip/snmp.h"
|
||||||
|
#include "lwip/dhcp.h"
|
||||||
|
#include "lwip/autoip.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
#include "arch/perf.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/** Set this to 0 in the rare case of wanting to call an extra function to
|
||||||
|
* generate the IP checksum (in contrast to calculating it on-the-fly). */
|
||||||
|
#ifndef LWIP_INLINE_IP_CHKSUM
|
||||||
|
#define LWIP_INLINE_IP_CHKSUM 1
|
||||||
|
#endif
|
||||||
|
#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP
|
||||||
|
#define CHECKSUM_GEN_IP_INLINE 1
|
||||||
|
#else
|
||||||
|
#define CHECKSUM_GEN_IP_INLINE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT)
|
||||||
|
#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1
|
||||||
|
|
||||||
|
/** Some defines for DHCP to let link-layer-addressed packets through while the
|
||||||
|
* netif is down.
|
||||||
|
* To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT
|
||||||
|
* to return 1 if the port is accepted and 0 if the port is not accepted.
|
||||||
|
*/
|
||||||
|
#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT)
|
||||||
|
/* accept DHCP client port and custom port */
|
||||||
|
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \
|
||||||
|
|| (LWIP_IP_ACCEPT_UDP_PORT(port)))
|
||||||
|
#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
|
||||||
|
/* accept custom port only */
|
||||||
|
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port))
|
||||||
|
#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
|
||||||
|
/* accept DHCP client port only */
|
||||||
|
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
|
||||||
|
#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
|
||||||
|
|
||||||
|
#else /* LWIP_DHCP */
|
||||||
|
#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0
|
||||||
|
#endif /* LWIP_DHCP */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface that provided the packet for the current callback
|
||||||
|
* invocation.
|
||||||
|
*/
|
||||||
|
struct netif *current_netif;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Header of the input packet currently being processed.
|
||||||
|
*/
|
||||||
|
const struct ip_hdr *current_header;
|
||||||
|
/** Source IP address of current_header */
|
||||||
|
ip_addr_t current_iphdr_src;
|
||||||
|
/** Destination IP address of current_header */
|
||||||
|
ip_addr_t current_iphdr_dest;
|
||||||
|
|
||||||
|
/** The IP header ID of the next outgoing IP packet */
|
||||||
|
static u16_t ip_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the appropriate network interface for a given IP address. It
|
||||||
|
* searches the list of network interfaces linearly. A match is found
|
||||||
|
* if the masked IP address of the network interface equals the masked
|
||||||
|
* IP address given to the function.
|
||||||
|
*
|
||||||
|
* @param dest the destination IP address for which to find the route
|
||||||
|
* @return the netif on which to send to reach dest
|
||||||
|
*/
|
||||||
|
struct netif *
|
||||||
|
ip_route(ip_addr_t *dest)
|
||||||
|
{
|
||||||
|
struct netif *netif;
|
||||||
|
|
||||||
|
/* iterate through netifs */
|
||||||
|
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||||
|
/* network mask matches? */
|
||||||
|
if (netif_is_up(netif)) {
|
||||||
|
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
|
||||||
|
/* return netif on which to forward IP packet */
|
||||||
|
return netif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* iterate through netifs */
|
||||||
|
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||||
|
/* network mask matches? */
|
||||||
|
if (netif_is_up(netif)) {
|
||||||
|
if (!ip_addr_isbroadcast(dest, netif) && netif == (struct netif *)eagle_lwip_getif(0)) {
|
||||||
|
return netif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
|
||||||
|
IP_STATS_INC(ip.rterr);
|
||||||
|
snmp_inc_ipoutnoroutes();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* no matching netif found, use default netif */
|
||||||
|
return netif_default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the appropriate network interface for a source IP address. It
|
||||||
|
* searches the list of network interfaces linearly. A match is found
|
||||||
|
* if the masked IP address of the network interface equals the masked
|
||||||
|
* IP address given to the function.
|
||||||
|
*
|
||||||
|
* @param source the sourcination IP address for which to find the route
|
||||||
|
* @return the netif on which to send to reach source
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct netif *ICACHE_FLASH_ATTR
|
||||||
|
ip_router(ip_addr_t *dest, ip_addr_t *source){
|
||||||
|
struct netif *netif;
|
||||||
|
/* iterate through netifs */
|
||||||
|
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||||
|
/* network mask matches? */
|
||||||
|
|
||||||
|
if (netif_is_up(netif)) {
|
||||||
|
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
|
||||||
|
/* return netif on which to forward IP packet */
|
||||||
|
return netif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (netif_is_up(netif)) {
|
||||||
|
if (ip_addr_netcmp(source, &(netif->ip_addr), &(netif->netmask))) {
|
||||||
|
/* return netif on which to forward IP packet */
|
||||||
|
return netif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
|
||||||
|
IP_STATS_INC(ip.rterr);
|
||||||
|
snmp_inc_ipoutnoroutes();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* no matching netif found, use default netif */
|
||||||
|
os_printf("ip_router %d %p\n", __LINE__, netif_default);
|
||||||
|
return netif_default;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IP_FORWARD
|
||||||
|
/**
|
||||||
|
* Forwards an IP packet. It finds an appropriate route for the
|
||||||
|
* packet, decrements the TTL value of the packet, adjusts the
|
||||||
|
* checksum and outputs the packet on the appropriate interface.
|
||||||
|
*
|
||||||
|
* @param p the packet to forward (p->payload points to IP header)
|
||||||
|
* @param iphdr the IP header of the input packet
|
||||||
|
* @param inp the netif on which this packet was received
|
||||||
|
*/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
|
||||||
|
{
|
||||||
|
struct netif *netif;
|
||||||
|
|
||||||
|
PERF_START;
|
||||||
|
|
||||||
|
/* RFC3927 2.7: do not forward link-local addresses */
|
||||||
|
if (ip_addr_islinklocal(¤t_iphdr_dest)) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest),
|
||||||
|
ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest)));
|
||||||
|
goto return_noroute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find network interface where to forward this IP packet to. */
|
||||||
|
netif = ip_route(¤t_iphdr_dest);
|
||||||
|
if (netif == NULL) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n",
|
||||||
|
ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest),
|
||||||
|
ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest)));
|
||||||
|
goto return_noroute;
|
||||||
|
}
|
||||||
|
/* Do not forward packets onto the same network interface on which
|
||||||
|
* they arrived. */
|
||||||
|
if (netif == inp) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
|
||||||
|
goto return_noroute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decrement TTL */
|
||||||
|
IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
|
||||||
|
/* send ICMP if TTL == 0 */
|
||||||
|
if (IPH_TTL(iphdr) == 0) {
|
||||||
|
snmp_inc_ipinhdrerrors();
|
||||||
|
#if LWIP_ICMP
|
||||||
|
/* Don't send ICMP messages in response to ICMP messages */
|
||||||
|
if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
|
||||||
|
icmp_time_exceeded(p, ICMP_TE_TTL);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_ICMP */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Incrementally update the IP checksum. */
|
||||||
|
if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffff - 0x100)) {
|
||||||
|
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
|
||||||
|
} else {
|
||||||
|
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
|
||||||
|
}
|
||||||
|
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest),
|
||||||
|
ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest)));
|
||||||
|
|
||||||
|
IP_STATS_INC(ip.fw);
|
||||||
|
IP_STATS_INC(ip.xmit);
|
||||||
|
snmp_inc_ipforwdatagrams();
|
||||||
|
|
||||||
|
PERF_STOP("ip_forward");
|
||||||
|
/* transmit pbuf on chosen interface */
|
||||||
|
netif->output(netif, p, ¤t_iphdr_dest);
|
||||||
|
return;
|
||||||
|
return_noroute:
|
||||||
|
snmp_inc_ipoutnoroutes();
|
||||||
|
}
|
||||||
|
#endif /* IP_FORWARD */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called by the network interface device driver when
|
||||||
|
* an IP packet is received. The function does the basic checks of the
|
||||||
|
* IP header such as packet size being at least larger than the header
|
||||||
|
* size etc. If the packet was not destined for us, the packet is
|
||||||
|
* forwarded (using ip_forward). The IP checksum is always checked.
|
||||||
|
*
|
||||||
|
* Finally, the packet is sent to the upper layer protocol input function.
|
||||||
|
*
|
||||||
|
* @param p the received IP packet (p->payload points to IP header)
|
||||||
|
* @param inp the netif on which this packet was received
|
||||||
|
* @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
|
||||||
|
* processed, but currently always returns ERR_OK)
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
ip_input(struct pbuf *p, struct netif *inp)
|
||||||
|
{
|
||||||
|
struct ip_hdr *iphdr;
|
||||||
|
struct netif *netif;
|
||||||
|
u16_t iphdr_hlen;
|
||||||
|
u16_t iphdr_len;
|
||||||
|
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
|
||||||
|
int check_ip_src=1;
|
||||||
|
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
|
||||||
|
|
||||||
|
IP_STATS_INC(ip.recv);
|
||||||
|
snmp_inc_ipinreceives();
|
||||||
|
|
||||||
|
/* identify the IP header */
|
||||||
|
iphdr = (struct ip_hdr *)p->payload;
|
||||||
|
if (IPH_V(iphdr) != 4) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
|
||||||
|
ip_debug_print(p);
|
||||||
|
pbuf_free(p);
|
||||||
|
IP_STATS_INC(ip.err);
|
||||||
|
IP_STATS_INC(ip.drop);
|
||||||
|
snmp_inc_ipinhdrerrors();
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* obtain IP header length in number of 32-bit words */
|
||||||
|
iphdr_hlen = IPH_HL(iphdr);
|
||||||
|
/* calculate IP header length in bytes */
|
||||||
|
iphdr_hlen *= 4;
|
||||||
|
/* obtain ip length in bytes */
|
||||||
|
iphdr_len = ntohs(IPH_LEN(iphdr));
|
||||||
|
|
||||||
|
/* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
|
||||||
|
if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
|
||||||
|
if (iphdr_hlen > p->len) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||||
|
("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
|
||||||
|
iphdr_hlen, p->len));
|
||||||
|
}
|
||||||
|
if (iphdr_len > p->tot_len) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||||
|
("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
|
||||||
|
iphdr_len, p->tot_len));
|
||||||
|
}
|
||||||
|
/* free (drop) packet pbufs */
|
||||||
|
pbuf_free(p);
|
||||||
|
IP_STATS_INC(ip.lenerr);
|
||||||
|
IP_STATS_INC(ip.drop);
|
||||||
|
snmp_inc_ipindiscards();
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify checksum */
|
||||||
|
#if CHECKSUM_CHECK_IP
|
||||||
|
if (inet_chksum(iphdr, iphdr_hlen) != 0) {
|
||||||
|
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||||
|
("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
|
||||||
|
ip_debug_print(p);
|
||||||
|
pbuf_free(p);
|
||||||
|
IP_STATS_INC(ip.chkerr);
|
||||||
|
IP_STATS_INC(ip.drop);
|
||||||
|
snmp_inc_ipinhdrerrors();
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Trim pbuf. This should have been done at the netif layer,
|
||||||
|
* but we'll do it anyway just to be sure that its done. */
|
||||||
|
pbuf_realloc(p, iphdr_len);
|
||||||
|
|
||||||
|
/* copy IP addresses to aligned ip_addr_t */
|
||||||
|
ip_addr_copy(current_iphdr_dest, iphdr->dest);
|
||||||
|
ip_addr_copy(current_iphdr_src, iphdr->src);
|
||||||
|
|
||||||
|
/* match packet against an interface, i.e. is this packet for us? */
|
||||||
|
#if LWIP_IGMP
|
||||||
|
if (ip_addr_ismulticast(¤t_iphdr_dest)) {
|
||||||
|
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ¤t_iphdr_dest))) {
|
||||||
|
netif = inp;
|
||||||
|
} else {
|
||||||
|
netif = NULL;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif /* LWIP_IGMP */
|
||||||
|
{
|
||||||
|
/* start trying with inp. if that's not acceptable, start walking the
|
||||||
|
list of configured netifs.
|
||||||
|
'first' is used as a boolean to mark whether we started walking the list */
|
||||||
|
int first = 1;
|
||||||
|
netif = inp;
|
||||||
|
do {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
|
||||||
|
ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr),
|
||||||
|
ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask),
|
||||||
|
ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask),
|
||||||
|
ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask)));
|
||||||
|
|
||||||
|
/* interface is up and configured? */
|
||||||
|
if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
|
||||||
|
/* unicast to this interface address? */
|
||||||
|
if (ip_addr_cmp(¤t_iphdr_dest, &(netif->ip_addr)) ||
|
||||||
|
/* or broadcast on this interface network address? */
|
||||||
|
ip_addr_isbroadcast(¤t_iphdr_dest, netif)) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
|
||||||
|
netif->name[0], netif->name[1]));
|
||||||
|
/* break out of for loop */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#if LWIP_AUTOIP
|
||||||
|
/* connections to link-local addresses must persist after changing
|
||||||
|
the netif's address (RFC3927 ch. 1.9) */
|
||||||
|
if ((netif->autoip != NULL) &&
|
||||||
|
ip_addr_cmp(¤t_iphdr_dest, &(netif->autoip->llipaddr))) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n",
|
||||||
|
netif->name[0], netif->name[1]));
|
||||||
|
/* break out of for loop */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* LWIP_AUTOIP */
|
||||||
|
}
|
||||||
|
if (first) {
|
||||||
|
first = 0;
|
||||||
|
netif = netif_list;
|
||||||
|
} else {
|
||||||
|
netif = netif->next;
|
||||||
|
}
|
||||||
|
if (netif == inp) {
|
||||||
|
netif = netif->next;
|
||||||
|
}
|
||||||
|
} while(netif != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
|
||||||
|
/* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
|
||||||
|
* using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
|
||||||
|
* According to RFC 1542 section 3.1.1, referred by RFC 2131).
|
||||||
|
*
|
||||||
|
* If you want to accept private broadcast communication while a netif is down,
|
||||||
|
* define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.:
|
||||||
|
*
|
||||||
|
* #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))
|
||||||
|
*/
|
||||||
|
if (netif == NULL) {
|
||||||
|
/* remote port is DHCP server? */
|
||||||
|
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
|
||||||
|
struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen);
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
|
||||||
|
ntohs(udphdr->dest)));
|
||||||
|
if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
|
||||||
|
netif = inp;
|
||||||
|
check_ip_src = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
|
||||||
|
|
||||||
|
/* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
|
||||||
|
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
|
||||||
|
/* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
|
||||||
|
if (check_ip_src && !ip_addr_isany(¤t_iphdr_src))
|
||||||
|
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
|
||||||
|
{ if ((ip_addr_isbroadcast(¤t_iphdr_src, inp)) ||
|
||||||
|
(ip_addr_ismulticast(¤t_iphdr_src))) {
|
||||||
|
/* packet source is not valid */
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
|
||||||
|
/* free (drop) packet pbufs */
|
||||||
|
pbuf_free(p);
|
||||||
|
IP_STATS_INC(ip.drop);
|
||||||
|
snmp_inc_ipinaddrerrors();
|
||||||
|
snmp_inc_ipindiscards();
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* packet not for us? */
|
||||||
|
if (netif == NULL) {
|
||||||
|
/* packet not for us, route or discard */
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
|
||||||
|
#if IP_FORWARD
|
||||||
|
/* non-broadcast packet? */
|
||||||
|
if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp)) {
|
||||||
|
/* try to forward IP packet on (other) interfaces */
|
||||||
|
ip_forward(p, iphdr, inp);
|
||||||
|
} else
|
||||||
|
#endif /* IP_FORWARD */
|
||||||
|
{
|
||||||
|
snmp_inc_ipinaddrerrors();
|
||||||
|
snmp_inc_ipindiscards();
|
||||||
|
}
|
||||||
|
pbuf_free(p);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
/* packet consists of multiple fragments? */
|
||||||
|
if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
|
||||||
|
#if IP_REASSEMBLY /* packet fragment reassembly code present? */
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
|
||||||
|
ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
|
||||||
|
/* reassemble the packet*/
|
||||||
|
p = ip_reass(p);
|
||||||
|
/* packet not fully reassembled yet? */
|
||||||
|
if (p == NULL) {
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
iphdr = (struct ip_hdr *)p->payload;
|
||||||
|
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
|
||||||
|
pbuf_free(p);
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
|
||||||
|
ntohs(IPH_OFFSET(iphdr))));
|
||||||
|
IP_STATS_INC(ip.opterr);
|
||||||
|
IP_STATS_INC(ip.drop);
|
||||||
|
/* unsupported protocol feature */
|
||||||
|
snmp_inc_ipinunknownprotos();
|
||||||
|
return ERR_OK;
|
||||||
|
#endif /* IP_REASSEMBLY */
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */
|
||||||
|
|
||||||
|
#if LWIP_IGMP
|
||||||
|
/* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
|
||||||
|
if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
|
||||||
|
#else
|
||||||
|
if (iphdr_hlen > IP_HLEN) {
|
||||||
|
#endif /* LWIP_IGMP */
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
|
||||||
|
pbuf_free(p);
|
||||||
|
IP_STATS_INC(ip.opterr);
|
||||||
|
IP_STATS_INC(ip.drop);
|
||||||
|
/* unsupported protocol feature */
|
||||||
|
snmp_inc_ipinunknownprotos();
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
#endif /* IP_OPTIONS_ALLOWED == 0 */
|
||||||
|
|
||||||
|
/* send to upper layers */
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
|
||||||
|
ip_debug_print(p);
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
|
||||||
|
|
||||||
|
current_netif = inp;
|
||||||
|
current_header = iphdr;
|
||||||
|
|
||||||
|
#if LWIP_RAW
|
||||||
|
/* raw input did not eat the packet? */
|
||||||
|
if (raw_input(p, inp) == 0)
|
||||||
|
#endif /* LWIP_RAW */
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (IPH_PROTO(iphdr)) {
|
||||||
|
#if LWIP_UDP
|
||||||
|
case IP_PROTO_UDP:
|
||||||
|
#if LWIP_UDPLITE
|
||||||
|
case IP_PROTO_UDPLITE:
|
||||||
|
#endif /* LWIP_UDPLITE */
|
||||||
|
snmp_inc_ipindelivers();
|
||||||
|
udp_input(p, inp);
|
||||||
|
break;
|
||||||
|
#endif /* LWIP_UDP */
|
||||||
|
#if LWIP_TCP
|
||||||
|
case IP_PROTO_TCP:
|
||||||
|
snmp_inc_ipindelivers();
|
||||||
|
tcp_input(p, inp);
|
||||||
|
break;
|
||||||
|
#endif /* LWIP_TCP */
|
||||||
|
#if LWIP_ICMP
|
||||||
|
case IP_PROTO_ICMP:
|
||||||
|
snmp_inc_ipindelivers();
|
||||||
|
icmp_input(p, inp);
|
||||||
|
break;
|
||||||
|
#endif /* LWIP_ICMP */
|
||||||
|
#if LWIP_IGMP
|
||||||
|
case IP_PROTO_IGMP:
|
||||||
|
igmp_input(p, inp, ¤t_iphdr_dest);
|
||||||
|
break;
|
||||||
|
#endif /* LWIP_IGMP */
|
||||||
|
default:
|
||||||
|
#if LWIP_ICMP
|
||||||
|
/* send ICMP destination protocol unreachable unless is was a broadcast */
|
||||||
|
if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp) &&
|
||||||
|
!ip_addr_ismulticast(¤t_iphdr_dest)) {
|
||||||
|
p->payload = iphdr;
|
||||||
|
icmp_dest_unreach(p, ICMP_DUR_PROTO);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_ICMP */
|
||||||
|
pbuf_free(p);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
|
||||||
|
|
||||||
|
IP_STATS_INC(ip.proterr);
|
||||||
|
IP_STATS_INC(ip.drop);
|
||||||
|
snmp_inc_ipinunknownprotos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current_netif = NULL;
|
||||||
|
current_header = NULL;
|
||||||
|
ip_addr_set_any(¤t_iphdr_src);
|
||||||
|
ip_addr_set_any(¤t_iphdr_dest);
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an IP packet on a network interface. This function constructs
|
||||||
|
* the IP header and calculates the IP header checksum. If the source
|
||||||
|
* IP address is NULL, the IP address of the outgoing network
|
||||||
|
* interface is filled in as source address.
|
||||||
|
* If the destination IP address is IP_HDRINCL, p is assumed to already
|
||||||
|
* include an IP header and p->payload points to it instead of the data.
|
||||||
|
*
|
||||||
|
* @param p the packet to send (p->payload points to the data, e.g. next
|
||||||
|
protocol header; if dest == IP_HDRINCL, p already includes an IP
|
||||||
|
header and p->payload points to that IP header)
|
||||||
|
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
|
||||||
|
* IP address of the netif used to send is used as source address)
|
||||||
|
* @param dest the destination IP address to send the packet to
|
||||||
|
* @param ttl the TTL value to be set in the IP header
|
||||||
|
* @param tos the TOS value to be set in the IP header
|
||||||
|
* @param proto the PROTOCOL to be set in the IP header
|
||||||
|
* @param netif the netif on which to send this packet
|
||||||
|
* @return ERR_OK if the packet was sent OK
|
||||||
|
* ERR_BUF if p doesn't have enough space for IP/LINK headers
|
||||||
|
* returns errors returned by netif->output
|
||||||
|
*
|
||||||
|
* @note ip_id: RFC791 "some host may be able to simply use
|
||||||
|
* unique identifiers independent of destination"
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||||
|
u8_t ttl, u8_t tos,
|
||||||
|
u8_t proto, struct netif *netif)
|
||||||
|
{
|
||||||
|
#if IP_OPTIONS_SEND
|
||||||
|
return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as ip_output_if() but with the possibility to include IP options:
|
||||||
|
*
|
||||||
|
* @ param ip_options pointer to the IP options, copied into the IP header
|
||||||
|
* @ param optlen length of ip_options
|
||||||
|
*/
|
||||||
|
err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||||
|
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
|
||||||
|
u16_t optlen)
|
||||||
|
{
|
||||||
|
#endif /* IP_OPTIONS_SEND */
|
||||||
|
struct ip_hdr *iphdr;
|
||||||
|
ip_addr_t dest_addr;
|
||||||
|
#if CHECKSUM_GEN_IP_INLINE
|
||||||
|
u32_t chk_sum = 0;
|
||||||
|
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||||
|
|
||||||
|
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
|
||||||
|
gets altered as the packet is passed down the stack */
|
||||||
|
LWIP_ASSERT("p->ref == 1", p->ref == 1);
|
||||||
|
|
||||||
|
snmp_inc_ipoutrequests();
|
||||||
|
|
||||||
|
/* Should the IP header be generated or is it already included in p? */
|
||||||
|
if (dest != IP_HDRINCL) {
|
||||||
|
u16_t ip_hlen = IP_HLEN;
|
||||||
|
#if IP_OPTIONS_SEND
|
||||||
|
u16_t optlen_aligned = 0;
|
||||||
|
if (optlen != 0) {
|
||||||
|
#if CHECKSUM_GEN_IP_INLINE
|
||||||
|
int i;
|
||||||
|
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||||
|
/* round up to a multiple of 4 */
|
||||||
|
optlen_aligned = ((optlen + 3) & ~3);
|
||||||
|
ip_hlen += optlen_aligned;
|
||||||
|
/* First write in the IP options */
|
||||||
|
if (pbuf_header(p, optlen_aligned)) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
|
||||||
|
IP_STATS_INC(ip.err);
|
||||||
|
snmp_inc_ipoutdiscards();
|
||||||
|
return ERR_BUF;
|
||||||
|
}
|
||||||
|
MEMCPY(p->payload, ip_options, optlen);
|
||||||
|
if (optlen < optlen_aligned) {
|
||||||
|
/* zero the remaining bytes */
|
||||||
|
os_memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
|
||||||
|
}
|
||||||
|
#if CHECKSUM_GEN_IP_INLINE
|
||||||
|
for (i = 0; i < optlen_aligned/2; i++) {
|
||||||
|
chk_sum += ((u16_t*)p->payload)[i];
|
||||||
|
}
|
||||||
|
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||||
|
}
|
||||||
|
#endif /* IP_OPTIONS_SEND */
|
||||||
|
/* generate IP header */
|
||||||
|
if (pbuf_header(p, IP_HLEN)) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
|
||||||
|
|
||||||
|
IP_STATS_INC(ip.err);
|
||||||
|
snmp_inc_ipoutdiscards();
|
||||||
|
return ERR_BUF;
|
||||||
|
}
|
||||||
|
|
||||||
|
iphdr = (struct ip_hdr *)p->payload;
|
||||||
|
LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
|
||||||
|
(p->len >= sizeof(struct ip_hdr)));
|
||||||
|
|
||||||
|
IPH_TTL_SET(iphdr, ttl);
|
||||||
|
IPH_PROTO_SET(iphdr, proto);
|
||||||
|
#if CHECKSUM_GEN_IP_INLINE
|
||||||
|
chk_sum += LWIP_MAKE_U16(proto, ttl);
|
||||||
|
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||||
|
|
||||||
|
/* dest cannot be NULL here */
|
||||||
|
ip_addr_copy(iphdr->dest, *dest);
|
||||||
|
#if CHECKSUM_GEN_IP_INLINE
|
||||||
|
chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF;
|
||||||
|
chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
|
||||||
|
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||||
|
|
||||||
|
IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
|
||||||
|
#if CHECKSUM_GEN_IP_INLINE
|
||||||
|
chk_sum += iphdr->_v_hl_tos;
|
||||||
|
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||||
|
IPH_LEN_SET(iphdr, htons(p->tot_len));
|
||||||
|
#if CHECKSUM_GEN_IP_INLINE
|
||||||
|
chk_sum += iphdr->_len;
|
||||||
|
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||||
|
IPH_OFFSET_SET(iphdr, 0);
|
||||||
|
IPH_ID_SET(iphdr, htons(ip_id));
|
||||||
|
#if CHECKSUM_GEN_IP_INLINE
|
||||||
|
chk_sum += iphdr->_id;
|
||||||
|
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||||
|
++ip_id;
|
||||||
|
|
||||||
|
if (ip_addr_isany(src)) {
|
||||||
|
ip_addr_copy(iphdr->src, netif->ip_addr);
|
||||||
|
} else {
|
||||||
|
/* src cannot be NULL here */
|
||||||
|
ip_addr_copy(iphdr->src, *src);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CHECKSUM_GEN_IP_INLINE
|
||||||
|
chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF;
|
||||||
|
chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16;
|
||||||
|
chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF);
|
||||||
|
chk_sum = (chk_sum >> 16) + chk_sum;
|
||||||
|
chk_sum = ~chk_sum;
|
||||||
|
iphdr->_chksum = chk_sum; /* network order */
|
||||||
|
#else /* CHECKSUM_GEN_IP_INLINE */
|
||||||
|
IPH_CHKSUM_SET(iphdr, 0);
|
||||||
|
#if CHECKSUM_GEN_IP
|
||||||
|
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
|
||||||
|
#endif
|
||||||
|
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||||
|
} else {
|
||||||
|
/* IP header already included in p */
|
||||||
|
iphdr = (struct ip_hdr *)p->payload;
|
||||||
|
ip_addr_copy(dest_addr, iphdr->dest);
|
||||||
|
dest = &dest_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
IP_STATS_INC(ip.xmit);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
|
||||||
|
ip_debug_print(p);
|
||||||
|
|
||||||
|
#if ENABLE_LOOPBACK
|
||||||
|
if (ip_addr_cmp(dest, &netif->ip_addr)) {
|
||||||
|
/* Packet to self, enqueue it for loopback */
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
|
||||||
|
return netif_loop_output(netif, p, dest);
|
||||||
|
}
|
||||||
|
#if LWIP_IGMP
|
||||||
|
if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {
|
||||||
|
netif_loop_output(netif, p, dest);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_IGMP */
|
||||||
|
#endif /* ENABLE_LOOPBACK */
|
||||||
|
#if IP_FRAG
|
||||||
|
/* don't fragment if interface has mtu set to 0 [loopif] */
|
||||||
|
if (netif->mtu && (p->tot_len > netif->mtu)) {
|
||||||
|
return ip_frag(p, netif, dest);
|
||||||
|
}
|
||||||
|
#endif /* IP_FRAG */
|
||||||
|
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("netif->output()\n"));
|
||||||
|
return netif->output(netif, p, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple interface to ip_output_if. It finds the outgoing network
|
||||||
|
* interface and calls upon ip_output_if to do the actual work.
|
||||||
|
*
|
||||||
|
* @param p the packet to send (p->payload points to the data, e.g. next
|
||||||
|
protocol header; if dest == IP_HDRINCL, p already includes an IP
|
||||||
|
header and p->payload points to that IP header)
|
||||||
|
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
|
||||||
|
* IP address of the netif used to send is used as source address)
|
||||||
|
* @param dest the destination IP address to send the packet to
|
||||||
|
* @param ttl the TTL value to be set in the IP header
|
||||||
|
* @param tos the TOS value to be set in the IP header
|
||||||
|
* @param proto the PROTOCOL to be set in the IP header
|
||||||
|
*
|
||||||
|
* @return ERR_RTE if no route is found
|
||||||
|
* see ip_output_if() for more return values
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||||
|
u8_t ttl, u8_t tos, u8_t proto)
|
||||||
|
{
|
||||||
|
struct netif *netif;
|
||||||
|
|
||||||
|
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
|
||||||
|
gets altered as the packet is passed down the stack */
|
||||||
|
LWIP_ASSERT("p->ref == 1", p->ref == 1);
|
||||||
|
|
||||||
|
if ((netif = ip_route(dest)) == NULL) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
|
||||||
|
IP_STATS_INC(ip.rterr);
|
||||||
|
return ERR_RTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
|
/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
|
||||||
|
* before calling ip_output_if.
|
||||||
|
*
|
||||||
|
* @param p the packet to send (p->payload points to the data, e.g. next
|
||||||
|
protocol header; if dest == IP_HDRINCL, p already includes an IP
|
||||||
|
header and p->payload points to that IP header)
|
||||||
|
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
|
||||||
|
* IP address of the netif used to send is used as source address)
|
||||||
|
* @param dest the destination IP address to send the packet to
|
||||||
|
* @param ttl the TTL value to be set in the IP header
|
||||||
|
* @param tos the TOS value to be set in the IP header
|
||||||
|
* @param proto the PROTOCOL to be set in the IP header
|
||||||
|
* @param addr_hint address hint pointer set to netif->addr_hint before
|
||||||
|
* calling ip_output_if()
|
||||||
|
*
|
||||||
|
* @return ERR_RTE if no route is found
|
||||||
|
* see ip_output_if() for more return values
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||||
|
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
|
||||||
|
{
|
||||||
|
struct netif *netif;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
|
||||||
|
gets altered as the packet is passed down the stack */
|
||||||
|
LWIP_ASSERT("p->ref == 1", p->ref == 1);
|
||||||
|
|
||||||
|
if ((netif = ip_route(dest)) == NULL) {
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
|
||||||
|
IP_STATS_INC(ip.rterr);
|
||||||
|
return ERR_RTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
netif->addr_hint = addr_hint;
|
||||||
|
err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
||||||
|
netif->addr_hint = NULL;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||||
|
|
||||||
|
#if IP_DEBUG
|
||||||
|
/* Print an IP header by using LWIP_DEBUGF
|
||||||
|
* @param p an IP packet, p->payload pointing to the IP header
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ip_debug_print(struct pbuf *p)
|
||||||
|
{
|
||||||
|
struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
|
||||||
|
u8_t *payload;
|
||||||
|
|
||||||
|
payload = (u8_t *)iphdr + IP_HLEN;
|
||||||
|
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n",
|
||||||
|
IPH_V(iphdr),
|
||||||
|
IPH_HL(iphdr),
|
||||||
|
IPH_TOS(iphdr),
|
||||||
|
ntohs(IPH_LEN(iphdr))));
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n",
|
||||||
|
ntohs(IPH_ID(iphdr)),
|
||||||
|
ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
|
||||||
|
ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
|
||||||
|
ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
|
||||||
|
ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n",
|
||||||
|
IPH_TTL(iphdr),
|
||||||
|
IPH_PROTO(iphdr),
|
||||||
|
ntohs(IPH_CHKSUM(iphdr))));
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n",
|
||||||
|
ip4_addr1_16(&iphdr->src),
|
||||||
|
ip4_addr2_16(&iphdr->src),
|
||||||
|
ip4_addr3_16(&iphdr->src),
|
||||||
|
ip4_addr4_16(&iphdr->src)));
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n",
|
||||||
|
ip4_addr1_16(&iphdr->dest),
|
||||||
|
ip4_addr2_16(&iphdr->dest),
|
||||||
|
ip4_addr3_16(&iphdr->dest),
|
||||||
|
ip4_addr4_16(&iphdr->dest)));
|
||||||
|
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||||
|
}
|
||||||
|
#endif /* IP_DEBUG */
|
329
tools/sdk/lwip/src/core/ipv4/ip_addr.c
Normal file
329
tools/sdk/lwip/src/core/ipv4/ip_addr.c
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* This is the IPv4 address tools implementation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
|
||||||
|
/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
|
||||||
|
const ip_addr_t ip_addr_any ICACHE_RODATA_ATTR = { IPADDR_ANY };
|
||||||
|
const ip_addr_t ip_addr_broadcast ICACHE_RODATA_ATTR = { IPADDR_BROADCAST };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if an address is a broadcast address on a network interface
|
||||||
|
*
|
||||||
|
* @param addr address to be checked
|
||||||
|
* @param netif the network interface against which the address is checked
|
||||||
|
* @return returns non-zero if the address is a broadcast address
|
||||||
|
*/
|
||||||
|
u8_t
|
||||||
|
ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
|
||||||
|
{
|
||||||
|
ip_addr_t ipaddr;
|
||||||
|
ip4_addr_set_u32(&ipaddr, addr);
|
||||||
|
|
||||||
|
/* all ones (broadcast) or all zeroes (old skool broadcast) */
|
||||||
|
if ((~addr == IPADDR_ANY) ||
|
||||||
|
(addr == IPADDR_ANY)) {
|
||||||
|
return 1;
|
||||||
|
/* no broadcast support on this network interface? */
|
||||||
|
} else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) {
|
||||||
|
/* the given address cannot be a broadcast address
|
||||||
|
* nor can we check against any broadcast addresses */
|
||||||
|
return 0;
|
||||||
|
/* address matches network interface address exactly? => no broadcast */
|
||||||
|
} else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {
|
||||||
|
return 0;
|
||||||
|
/* on the same (sub) network... */
|
||||||
|
} else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
|
||||||
|
/* ...and host identifier bits are all ones? =>... */
|
||||||
|
&& ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
|
||||||
|
(IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
|
||||||
|
/* => network broadcast address */
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks if a netmask is valid (starting with ones, then only zeros)
|
||||||
|
*
|
||||||
|
* @param netmask the IPv4 netmask to check (in network byte order!)
|
||||||
|
* @return 1 if the netmask is valid, 0 if it is not
|
||||||
|
*/
|
||||||
|
u8_t
|
||||||
|
ip4_addr_netmask_valid(u32_t netmask)
|
||||||
|
{
|
||||||
|
u32_t mask;
|
||||||
|
u32_t nm_hostorder = lwip_htonl(netmask);
|
||||||
|
|
||||||
|
/* first, check for the first zero */
|
||||||
|
for (mask = 1U << 31 ; mask != 0; mask >>= 1) {
|
||||||
|
if ((nm_hostorder & mask) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* then check that there is no one */
|
||||||
|
for (; mask != 0; mask >>= 1) {
|
||||||
|
if ((nm_hostorder & mask) != 0) {
|
||||||
|
/* there is a one after the first zero -> invalid */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* no one after the first zero -> valid */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Here for now until needed in other places in lwIP */
|
||||||
|
#ifndef isprint
|
||||||
|
#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
|
||||||
|
#define isprint(c) in_range(c, 0x20, 0x7f)
|
||||||
|
//#define isdigit(c) in_range(c, '0', '9')
|
||||||
|
//#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
|
||||||
|
#define islower(c) in_range(c, 'a', 'z')
|
||||||
|
#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ascii internet address interpretation routine.
|
||||||
|
* The value returned is in network order.
|
||||||
|
*
|
||||||
|
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
|
||||||
|
* @return ip address in network order
|
||||||
|
*/
|
||||||
|
u32_t
|
||||||
|
ipaddr_addr(const char *cp)
|
||||||
|
{
|
||||||
|
ip_addr_t val;
|
||||||
|
|
||||||
|
if (ipaddr_aton(cp, &val)) {
|
||||||
|
return ip4_addr_get_u32(&val);
|
||||||
|
}
|
||||||
|
return (IPADDR_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether "cp" is a valid ascii representation
|
||||||
|
* of an Internet address and convert to a binary address.
|
||||||
|
* Returns 1 if the address is valid, 0 if not.
|
||||||
|
* This replaces inet_addr, the return value from which
|
||||||
|
* cannot distinguish between failure and a local broadcast address.
|
||||||
|
*
|
||||||
|
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
|
||||||
|
* @param addr pointer to which to save the ip address in network order
|
||||||
|
* @return 1 if cp could be converted to addr, 0 on failure
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ipaddr_aton(const char *cp, ip_addr_t *addr)
|
||||||
|
{
|
||||||
|
u32_t val;
|
||||||
|
u8_t base;
|
||||||
|
char c;
|
||||||
|
char ch;
|
||||||
|
unsigned long cutoff;
|
||||||
|
int cutlim;
|
||||||
|
u32_t parts[4];
|
||||||
|
u32_t *pp = parts;
|
||||||
|
|
||||||
|
c = *cp;
|
||||||
|
for (;;) {
|
||||||
|
/*
|
||||||
|
* Collect number up to ``.''.
|
||||||
|
* Values are specified as for C:
|
||||||
|
* 0x=hex, 0=octal, 1-9=decimal.
|
||||||
|
*/
|
||||||
|
if (!isdigit(c))
|
||||||
|
return (0);
|
||||||
|
val = 0;
|
||||||
|
base = 10;
|
||||||
|
if (c == '0') {
|
||||||
|
c = *++cp;
|
||||||
|
if (c == 'x' || c == 'X') {
|
||||||
|
base = 16;
|
||||||
|
c = *++cp;
|
||||||
|
} else
|
||||||
|
base = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
cutoff =(unsigned long)0xffffffff / (unsigned long)base;
|
||||||
|
cutlim =(unsigned long)0xffffffff % (unsigned long)base;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (isdigit(c)) {
|
||||||
|
ch = (int)(c - '0');
|
||||||
|
|
||||||
|
if (val > cutoff || (val == cutoff && ch > cutlim))
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
val = (val * base) + (int)(c - '0');
|
||||||
|
c = *++cp;
|
||||||
|
} else if (base == 16 && isxdigit(c)) {
|
||||||
|
ch = (int)(c + 10 - (islower(c) ? 'a' : 'A'));
|
||||||
|
|
||||||
|
if (val > cutoff || (val == cutoff && ch > cutlim))
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
|
||||||
|
c = *++cp;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == '.') {
|
||||||
|
/*
|
||||||
|
* Internet format:
|
||||||
|
* a.b.c.d
|
||||||
|
* a.b.c (with c treated as 16 bits)
|
||||||
|
* a.b (with b treated as 24 bits)
|
||||||
|
*/
|
||||||
|
if (pp >= parts + 3) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
*pp++ = val;
|
||||||
|
c = *++cp;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check for trailing characters.
|
||||||
|
*/
|
||||||
|
if (c != '\0' && !isspace(c)) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Concoct the address according to
|
||||||
|
* the number of parts specified.
|
||||||
|
*/
|
||||||
|
switch (pp - parts + 1) {
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
return (0); /* initial nondigit */
|
||||||
|
|
||||||
|
case 1: /* a -- 32 bits */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: /* a.b -- 8.24 bits */
|
||||||
|
if ((val > 0xffffffUL) || (parts[0] > 0xff)) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
val |= parts[0] << 24;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: /* a.b.c -- 8.8.16 bits */
|
||||||
|
if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff)) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
val |= (parts[0] << 24) | (parts[1] << 16);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: /* a.b.c.d -- 8.8.8.8 bits */
|
||||||
|
if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LWIP_ASSERT("unhandled", 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (addr) {
|
||||||
|
ip4_addr_set_u32(addr, htonl(val));
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert numeric IP address into decimal dotted ASCII representation.
|
||||||
|
* returns ptr to static buffer; not reentrant!
|
||||||
|
*
|
||||||
|
* @param addr ip address in network order to convert
|
||||||
|
* @return pointer to a global static (!) buffer that holds the ASCII
|
||||||
|
* represenation of addr
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
ipaddr_ntoa(const ip_addr_t *addr)
|
||||||
|
{
|
||||||
|
static char str[16];
|
||||||
|
return ipaddr_ntoa_r(addr, str, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
|
||||||
|
*
|
||||||
|
* @param addr ip address in network order to convert
|
||||||
|
* @param buf target buffer where the string is stored
|
||||||
|
* @param buflen length of buf
|
||||||
|
* @return either pointer to buf which now holds the ASCII
|
||||||
|
* representation of addr or NULL if buf was too small
|
||||||
|
*/
|
||||||
|
char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
|
||||||
|
{
|
||||||
|
u32_t s_addr;
|
||||||
|
char inv[3];
|
||||||
|
char *rp;
|
||||||
|
u8_t *ap;
|
||||||
|
u8_t rem;
|
||||||
|
u8_t n;
|
||||||
|
u8_t i;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
s_addr = ip4_addr_get_u32(addr);
|
||||||
|
|
||||||
|
rp = buf;
|
||||||
|
ap = (u8_t *)&s_addr;
|
||||||
|
for(n = 0; n < 4; n++) {
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
rem = *ap % (u8_t)10;
|
||||||
|
*ap /= (u8_t)10;
|
||||||
|
inv[i++] = '0' + rem;
|
||||||
|
} while(*ap);
|
||||||
|
while(i--) {
|
||||||
|
if (len++ >= buflen) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*rp++ = inv[i];
|
||||||
|
}
|
||||||
|
if (len++ >= buflen) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*rp++ = '.';
|
||||||
|
ap++;
|
||||||
|
}
|
||||||
|
*--rp = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
863
tools/sdk/lwip/src/core/ipv4/ip_frag.c
Normal file
863
tools/sdk/lwip/src/core/ipv4/ip_frag.c
Normal file
@ -0,0 +1,863 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* This is the IPv4 packet segmentation and reassembly implementation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Jani Monoses <jani@iv.ro>
|
||||||
|
* Simon Goldschmidt
|
||||||
|
* original reassembly code by Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
#include "lwip/ip_frag.h"
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#include "lwip/inet_chksum.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
#include "lwip/snmp.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
#include "lwip/icmp.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if IP_REASSEMBLY
|
||||||
|
/**
|
||||||
|
* The IP reassembly code currently has the following limitations:
|
||||||
|
* - IP header options are not supported
|
||||||
|
* - fragments must not overlap (e.g. due to different routes),
|
||||||
|
* currently, overlapping or duplicate fragments are thrown away
|
||||||
|
* if IP_REASS_CHECK_OVERLAP=1 (the default)!
|
||||||
|
*
|
||||||
|
* @todo: work with IP header options
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Setting this to 0, you can turn off checking the fragments for overlapping
|
||||||
|
* regions. The code gets a little smaller. Only use this if you know that
|
||||||
|
* overlapping won't occur on your network! */
|
||||||
|
#ifndef IP_REASS_CHECK_OVERLAP
|
||||||
|
#define IP_REASS_CHECK_OVERLAP 1
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
|
|
||||||
|
/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
|
||||||
|
* full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
|
||||||
|
* Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
|
||||||
|
* is set to 1, so one datagram can be reassembled at a time, only. */
|
||||||
|
#ifndef IP_REASS_FREE_OLDEST
|
||||||
|
#define IP_REASS_FREE_OLDEST 1
|
||||||
|
#endif /* IP_REASS_FREE_OLDEST */
|
||||||
|
|
||||||
|
#define IP_REASS_FLAG_LASTFRAG 0x01
|
||||||
|
|
||||||
|
/** This is a helper struct which holds the starting
|
||||||
|
* offset and the ending offset of this fragment to
|
||||||
|
* easily chain the fragments.
|
||||||
|
* It has the same packing requirements as the IP header, since it replaces
|
||||||
|
* the IP header in memory in incoming fragments (after copying it) to keep
|
||||||
|
* track of the various fragments. (-> If the IP header doesn't need packing,
|
||||||
|
* this struct doesn't need packing, too.)
|
||||||
|
*/
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/bpstruct.h"
|
||||||
|
#endif
|
||||||
|
PACK_STRUCT_BEGIN
|
||||||
|
struct ip_reass_helper {
|
||||||
|
PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
|
||||||
|
PACK_STRUCT_FIELD(u16_t start);
|
||||||
|
PACK_STRUCT_FIELD(u16_t end);
|
||||||
|
} PACK_STRUCT_STRUCT;
|
||||||
|
PACK_STRUCT_END
|
||||||
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
# include "arch/epstruct.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
|
||||||
|
(ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
|
||||||
|
ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
|
||||||
|
IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
|
||||||
|
|
||||||
|
/* global variables */
|
||||||
|
static struct ip_reassdata *reassdatagrams;
|
||||||
|
static u16_t ip_reass_pbufcount;
|
||||||
|
|
||||||
|
/* function prototypes */
|
||||||
|
static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)ICACHE_FLASH_ATTR;
|
||||||
|
static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)ICACHE_FLASH_ATTR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reassembly timer base function
|
||||||
|
* for both NO_SYS == 0 and 1 (!).
|
||||||
|
*
|
||||||
|
* Should be called every 1000 msec (defined by IP_TMR_INTERVAL).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ip_reass_tmr(void)
|
||||||
|
{
|
||||||
|
struct ip_reassdata *r, *prev = NULL;
|
||||||
|
|
||||||
|
r = reassdatagrams;
|
||||||
|
while (r != NULL) {
|
||||||
|
/* Decrement the timer. Once it reaches 0,
|
||||||
|
* clean up the incomplete fragment assembly */
|
||||||
|
if (r->timer > 0) {
|
||||||
|
r->timer--;
|
||||||
|
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer));
|
||||||
|
prev = r;
|
||||||
|
r = r->next;
|
||||||
|
} else {
|
||||||
|
/* reassembly timed out */
|
||||||
|
struct ip_reassdata *tmp;
|
||||||
|
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n"));
|
||||||
|
tmp = r;
|
||||||
|
/* get the next pointer before freeing */
|
||||||
|
r = r->next;
|
||||||
|
/* free the helper struct and all enqueued pbufs */
|
||||||
|
ip_reass_free_complete_datagram(tmp, prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a datagram (struct ip_reassdata) and all its pbufs.
|
||||||
|
* Updates the total count of enqueued pbufs (ip_reass_pbufcount),
|
||||||
|
* SNMP counters and sends an ICMP time exceeded packet.
|
||||||
|
*
|
||||||
|
* @param ipr datagram to free
|
||||||
|
* @param prev the previous datagram in the linked list
|
||||||
|
* @return the number of pbufs freed
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
|
||||||
|
{
|
||||||
|
u16_t pbufs_freed = 0;
|
||||||
|
u8_t clen;
|
||||||
|
struct pbuf *p;
|
||||||
|
struct ip_reass_helper *iprh;
|
||||||
|
|
||||||
|
LWIP_ASSERT("prev != ipr", prev != ipr);
|
||||||
|
if (prev != NULL) {
|
||||||
|
LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
|
||||||
|
}
|
||||||
|
|
||||||
|
snmp_inc_ipreasmfails();
|
||||||
|
#if LWIP_ICMP
|
||||||
|
iprh = (struct ip_reass_helper *)ipr->p->payload;
|
||||||
|
if (iprh->start == 0) {
|
||||||
|
/* The first fragment was received, send ICMP time exceeded. */
|
||||||
|
/* First, de-queue the first pbuf from r->p. */
|
||||||
|
p = ipr->p;
|
||||||
|
ipr->p = iprh->next_pbuf;
|
||||||
|
/* Then, copy the original header into it. */
|
||||||
|
SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
|
||||||
|
icmp_time_exceeded(p, ICMP_TE_FRAG);
|
||||||
|
clen = pbuf_clen(p);
|
||||||
|
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
|
||||||
|
pbufs_freed += clen;
|
||||||
|
pbuf_free(p);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_ICMP */
|
||||||
|
|
||||||
|
/* First, free all received pbufs. The individual pbufs need to be released
|
||||||
|
separately as they have not yet been chained */
|
||||||
|
p = ipr->p;
|
||||||
|
while (p != NULL) {
|
||||||
|
struct pbuf *pcur;
|
||||||
|
iprh = (struct ip_reass_helper *)p->payload;
|
||||||
|
pcur = p;
|
||||||
|
/* get the next pointer before freeing */
|
||||||
|
p = iprh->next_pbuf;
|
||||||
|
clen = pbuf_clen(pcur);
|
||||||
|
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
|
||||||
|
pbufs_freed += clen;
|
||||||
|
pbuf_free(pcur);
|
||||||
|
}
|
||||||
|
/* Then, unchain the struct ip_reassdata from the list and free it. */
|
||||||
|
ip_reass_dequeue_datagram(ipr, prev);
|
||||||
|
LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);
|
||||||
|
ip_reass_pbufcount -= pbufs_freed;
|
||||||
|
|
||||||
|
return pbufs_freed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IP_REASS_FREE_OLDEST
|
||||||
|
/**
|
||||||
|
* Free the oldest datagram to make room for enqueueing new fragments.
|
||||||
|
* The datagram 'fraghdr' belongs to is not freed!
|
||||||
|
*
|
||||||
|
* @param fraghdr IP header of the current fragment
|
||||||
|
* @param pbufs_needed number of pbufs needed to enqueue
|
||||||
|
* (used for freeing other datagrams if not enough space)
|
||||||
|
* @return the number of pbufs freed
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
|
||||||
|
{
|
||||||
|
/* @todo Can't we simply remove the last datagram in the
|
||||||
|
* linked list behind reassdatagrams?
|
||||||
|
*/
|
||||||
|
struct ip_reassdata *r, *oldest, *prev;
|
||||||
|
int pbufs_freed = 0, pbufs_freed_current;
|
||||||
|
int other_datagrams;
|
||||||
|
|
||||||
|
/* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
|
||||||
|
* but don't free the datagram that 'fraghdr' belongs to! */
|
||||||
|
do {
|
||||||
|
oldest = NULL;
|
||||||
|
prev = NULL;
|
||||||
|
other_datagrams = 0;
|
||||||
|
r = reassdatagrams;
|
||||||
|
while (r != NULL) {
|
||||||
|
if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {
|
||||||
|
/* Not the same datagram as fraghdr */
|
||||||
|
other_datagrams++;
|
||||||
|
if (oldest == NULL) {
|
||||||
|
oldest = r;
|
||||||
|
} else if (r->timer <= oldest->timer) {
|
||||||
|
/* older than the previous oldest */
|
||||||
|
oldest = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r->next != NULL) {
|
||||||
|
prev = r;
|
||||||
|
}
|
||||||
|
r = r->next;
|
||||||
|
}
|
||||||
|
if (oldest != NULL) {
|
||||||
|
pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);
|
||||||
|
pbufs_freed += pbufs_freed_current;
|
||||||
|
}
|
||||||
|
} while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
|
||||||
|
return pbufs_freed;
|
||||||
|
}
|
||||||
|
#endif /* IP_REASS_FREE_OLDEST */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueues a new fragment into the fragment queue
|
||||||
|
* @param fraghdr points to the new fragments IP hdr
|
||||||
|
* @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space)
|
||||||
|
* @return A pointer to the queue location into which the fragment was enqueued
|
||||||
|
*/
|
||||||
|
static struct ip_reassdata* ICACHE_FLASH_ATTR
|
||||||
|
ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
|
||||||
|
{
|
||||||
|
struct ip_reassdata* ipr;
|
||||||
|
/* No matching previous fragment found, allocate a new reassdata struct */
|
||||||
|
ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
|
||||||
|
if (ipr == NULL) {
|
||||||
|
#if IP_REASS_FREE_OLDEST
|
||||||
|
if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
|
||||||
|
ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
|
||||||
|
}
|
||||||
|
if (ipr == NULL)
|
||||||
|
#endif /* IP_REASS_FREE_OLDEST */
|
||||||
|
{
|
||||||
|
IPFRAG_STATS_INC(ip_frag.memerr);
|
||||||
|
LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os_memset(ipr, 0, sizeof(struct ip_reassdata));
|
||||||
|
ipr->timer = IP_REASS_MAXAGE;
|
||||||
|
|
||||||
|
/* enqueue the new structure to the front of the list */
|
||||||
|
ipr->next = reassdatagrams;
|
||||||
|
reassdatagrams = ipr;
|
||||||
|
/* copy the ip header for later tests and input */
|
||||||
|
/* @todo: no ip options supported? */
|
||||||
|
SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);
|
||||||
|
return ipr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs.
|
||||||
|
* @param ipr points to the queue entry to dequeue
|
||||||
|
*/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* dequeue the reass struct */
|
||||||
|
if (reassdatagrams == ipr) {
|
||||||
|
/* it was the first in the list */
|
||||||
|
reassdatagrams = ipr->next;
|
||||||
|
} else {
|
||||||
|
/* it wasn't the first, so it must have a valid 'prev' */
|
||||||
|
LWIP_ASSERT("sanity check linked list", prev != NULL);
|
||||||
|
prev->next = ipr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now we can free the ip_reass struct */
|
||||||
|
memp_free(MEMP_REASSDATA, ipr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list
|
||||||
|
* will grow over time as new pbufs are rx.
|
||||||
|
* Also checks that the datagram passes basic continuity checks (if the last
|
||||||
|
* fragment was received at least once).
|
||||||
|
* @param root_p points to the 'root' pbuf for the current datagram being assembled.
|
||||||
|
* @param new_p points to the pbuf for the current fragment
|
||||||
|
* @return 0 if invalid, >0 otherwise
|
||||||
|
*/
|
||||||
|
static int ICACHE_FLASH_ATTR
|
||||||
|
ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)
|
||||||
|
{
|
||||||
|
struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
|
||||||
|
struct pbuf *q;
|
||||||
|
u16_t offset,len;
|
||||||
|
struct ip_hdr *fraghdr;
|
||||||
|
int valid = 1;
|
||||||
|
|
||||||
|
/* Extract length and fragment offset from current fragment */
|
||||||
|
fraghdr = (struct ip_hdr*)new_p->payload;
|
||||||
|
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
|
||||||
|
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
|
||||||
|
|
||||||
|
/* overwrite the fragment's ip header from the pbuf with our helper struct,
|
||||||
|
* and setup the embedded helper structure. */
|
||||||
|
/* make sure the struct ip_reass_helper fits into the IP header */
|
||||||
|
LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",
|
||||||
|
sizeof(struct ip_reass_helper) <= IP_HLEN);
|
||||||
|
iprh = (struct ip_reass_helper*)new_p->payload;
|
||||||
|
iprh->next_pbuf = NULL;
|
||||||
|
iprh->start = offset;
|
||||||
|
iprh->end = offset + len;
|
||||||
|
|
||||||
|
/* Iterate through until we either get to the end of the list (append),
|
||||||
|
* or we find on with a larger offset (insert). */
|
||||||
|
for (q = ipr->p; q != NULL;) {
|
||||||
|
iprh_tmp = (struct ip_reass_helper*)q->payload;
|
||||||
|
if (iprh->start < iprh_tmp->start) {
|
||||||
|
/* the new pbuf should be inserted before this */
|
||||||
|
iprh->next_pbuf = q;
|
||||||
|
if (iprh_prev != NULL) {
|
||||||
|
/* not the fragment with the lowest offset */
|
||||||
|
#if IP_REASS_CHECK_OVERLAP
|
||||||
|
if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
|
||||||
|
/* fragment overlaps with previous or following, throw away */
|
||||||
|
goto freepbuf;
|
||||||
|
}
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
|
iprh_prev->next_pbuf = new_p;
|
||||||
|
} else {
|
||||||
|
/* fragment with the lowest offset */
|
||||||
|
ipr->p = new_p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else if(iprh->start == iprh_tmp->start) {
|
||||||
|
/* received the same datagram twice: no need to keep the datagram */
|
||||||
|
goto freepbuf;
|
||||||
|
#if IP_REASS_CHECK_OVERLAP
|
||||||
|
} else if(iprh->start < iprh_tmp->end) {
|
||||||
|
/* overlap: no need to keep the new datagram */
|
||||||
|
goto freepbuf;
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
|
} else {
|
||||||
|
/* Check if the fragments received so far have no wholes. */
|
||||||
|
if (iprh_prev != NULL) {
|
||||||
|
if (iprh_prev->end != iprh_tmp->start) {
|
||||||
|
/* There is a fragment missing between the current
|
||||||
|
* and the previous fragment */
|
||||||
|
valid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
q = iprh_tmp->next_pbuf;
|
||||||
|
iprh_prev = iprh_tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If q is NULL, then we made it to the end of the list. Determine what to do now */
|
||||||
|
if (q == NULL) {
|
||||||
|
if (iprh_prev != NULL) {
|
||||||
|
/* this is (for now), the fragment with the highest offset:
|
||||||
|
* chain it to the last fragment */
|
||||||
|
#if IP_REASS_CHECK_OVERLAP
|
||||||
|
LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
|
iprh_prev->next_pbuf = new_p;
|
||||||
|
if (iprh_prev->end != iprh->start) {
|
||||||
|
valid = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#if IP_REASS_CHECK_OVERLAP
|
||||||
|
LWIP_ASSERT("no previous fragment, this must be the first fragment!",
|
||||||
|
ipr->p == NULL);
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
|
/* this is the first fragment we ever received for this ip datagram */
|
||||||
|
ipr->p = new_p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point, the validation part begins: */
|
||||||
|
/* If we already received the last fragment */
|
||||||
|
if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
|
||||||
|
/* and had no wholes so far */
|
||||||
|
if (valid) {
|
||||||
|
/* then check if the rest of the fragments is here */
|
||||||
|
/* Check if the queue starts with the first datagram */
|
||||||
|
if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {
|
||||||
|
valid = 0;
|
||||||
|
} else {
|
||||||
|
/* and check that there are no wholes after this datagram */
|
||||||
|
iprh_prev = iprh;
|
||||||
|
q = iprh->next_pbuf;
|
||||||
|
while (q != NULL) {
|
||||||
|
iprh = (struct ip_reass_helper*)q->payload;
|
||||||
|
if (iprh_prev->end != iprh->start) {
|
||||||
|
valid = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iprh_prev = iprh;
|
||||||
|
q = iprh->next_pbuf;
|
||||||
|
}
|
||||||
|
/* if still valid, all fragments are received
|
||||||
|
* (because to the MF==0 already arrived */
|
||||||
|
if (valid) {
|
||||||
|
LWIP_ASSERT("sanity check", ipr->p != NULL);
|
||||||
|
LWIP_ASSERT("sanity check",
|
||||||
|
((struct ip_reass_helper*)ipr->p->payload) != iprh);
|
||||||
|
LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",
|
||||||
|
iprh->next_pbuf == NULL);
|
||||||
|
LWIP_ASSERT("validate_datagram:datagram end!=datagram len",
|
||||||
|
iprh->end == ipr->datagram_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If valid is 0 here, there are some fragments missing in the middle
|
||||||
|
* (since MF == 0 has already arrived). Such datagrams simply time out if
|
||||||
|
* no more fragments are received... */
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
/* If we come here, not all fragments were received, yet! */
|
||||||
|
return 0; /* not yet valid! */
|
||||||
|
#if IP_REASS_CHECK_OVERLAP
|
||||||
|
freepbuf:
|
||||||
|
ip_reass_pbufcount -= pbuf_clen(new_p);
|
||||||
|
pbuf_free(new_p);
|
||||||
|
return 0;
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reassembles incoming IP fragments into an IP datagram.
|
||||||
|
*
|
||||||
|
* @param p points to a pbuf chain of the fragment
|
||||||
|
* @return NULL if reassembly is incomplete, ? otherwise
|
||||||
|
*/
|
||||||
|
struct pbuf *
|
||||||
|
ip_reass(struct pbuf *p)
|
||||||
|
{
|
||||||
|
struct pbuf *r;
|
||||||
|
struct ip_hdr *fraghdr;
|
||||||
|
struct ip_reassdata *ipr;
|
||||||
|
struct ip_reass_helper *iprh;
|
||||||
|
u16_t offset, len;
|
||||||
|
u8_t clen;
|
||||||
|
struct ip_reassdata *ipr_prev = NULL;
|
||||||
|
|
||||||
|
IPFRAG_STATS_INC(ip_frag.recv);
|
||||||
|
snmp_inc_ipreasmreqds();
|
||||||
|
|
||||||
|
fraghdr = (struct ip_hdr*)p->payload;
|
||||||
|
|
||||||
|
if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
|
||||||
|
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));
|
||||||
|
IPFRAG_STATS_INC(ip_frag.err);
|
||||||
|
goto nullreturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
|
||||||
|
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
|
||||||
|
|
||||||
|
/* Check if we are allowed to enqueue more datagrams. */
|
||||||
|
clen = pbuf_clen(p);
|
||||||
|
if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
|
||||||
|
#if IP_REASS_FREE_OLDEST
|
||||||
|
if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
|
||||||
|
((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
|
||||||
|
#endif /* IP_REASS_FREE_OLDEST */
|
||||||
|
{
|
||||||
|
/* No datagram could be freed and still too many pbufs enqueued */
|
||||||
|
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
|
||||||
|
ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
|
||||||
|
IPFRAG_STATS_INC(ip_frag.memerr);
|
||||||
|
/* @todo: send ICMP time exceeded here? */
|
||||||
|
/* drop this pbuf */
|
||||||
|
goto nullreturn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look for the datagram the fragment belongs to in the current datagram queue,
|
||||||
|
* remembering the previous in the queue for later dequeueing. */
|
||||||
|
for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
|
||||||
|
/* Check if the incoming fragment matches the one currently present
|
||||||
|
in the reassembly buffer. If so, we proceed with copying the
|
||||||
|
fragment into the buffer. */
|
||||||
|
if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
|
||||||
|
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
|
||||||
|
ntohs(IPH_ID(fraghdr))));
|
||||||
|
IPFRAG_STATS_INC(ip_frag.cachehit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ipr_prev = ipr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipr == NULL) {
|
||||||
|
/* Enqueue a new datagram into the datagram queue */
|
||||||
|
ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
|
||||||
|
/* Bail if unable to enqueue */
|
||||||
|
if(ipr == NULL) {
|
||||||
|
goto nullreturn;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
|
||||||
|
((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
|
||||||
|
/* ipr->iphdr is not the header from the first fragment, but fraghdr is
|
||||||
|
* -> copy fraghdr into ipr->iphdr since we want to have the header
|
||||||
|
* of the first fragment (for ICMP time exceeded and later, for copying
|
||||||
|
* all options, if supported)*/
|
||||||
|
SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Track the current number of pbufs current 'in-flight', in order to limit
|
||||||
|
the number of fragments that may be enqueued at any one time */
|
||||||
|
ip_reass_pbufcount += clen;
|
||||||
|
|
||||||
|
/* At this point, we have either created a new entry or pointing
|
||||||
|
* to an existing one */
|
||||||
|
|
||||||
|
/* check for 'no more fragments', and update queue entry*/
|
||||||
|
if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
|
||||||
|
ipr->flags |= IP_REASS_FLAG_LASTFRAG;
|
||||||
|
ipr->datagram_len = offset + len;
|
||||||
|
LWIP_DEBUGF(IP_REASS_DEBUG,
|
||||||
|
("ip_reass: last fragment seen, total len %"S16_F"\n",
|
||||||
|
ipr->datagram_len));
|
||||||
|
}
|
||||||
|
/* find the right place to insert this pbuf */
|
||||||
|
/* @todo: trim pbufs if fragments are overlapping */
|
||||||
|
if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
|
||||||
|
/* the totally last fragment (flag more fragments = 0) was received at least
|
||||||
|
* once AND all fragments are received */
|
||||||
|
ipr->datagram_len += IP_HLEN;
|
||||||
|
|
||||||
|
/* save the second pbuf before copying the header over the pointer */
|
||||||
|
r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
|
||||||
|
|
||||||
|
/* copy the original ip header back to the first pbuf */
|
||||||
|
fraghdr = (struct ip_hdr*)(ipr->p->payload);
|
||||||
|
SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
|
||||||
|
IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
|
||||||
|
IPH_OFFSET_SET(fraghdr, 0);
|
||||||
|
IPH_CHKSUM_SET(fraghdr, 0);
|
||||||
|
/* @todo: do we need to set calculate the correct checksum? */
|
||||||
|
IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
|
||||||
|
|
||||||
|
p = ipr->p;
|
||||||
|
|
||||||
|
/* chain together the pbufs contained within the reass_data list. */
|
||||||
|
while(r != NULL) {
|
||||||
|
iprh = (struct ip_reass_helper*)r->payload;
|
||||||
|
|
||||||
|
/* hide the ip header for every succeding fragment */
|
||||||
|
pbuf_header(r, -IP_HLEN);
|
||||||
|
pbuf_cat(p, r);
|
||||||
|
r = iprh->next_pbuf;
|
||||||
|
}
|
||||||
|
/* release the sources allocate for the fragment queue entry */
|
||||||
|
ip_reass_dequeue_datagram(ipr, ipr_prev);
|
||||||
|
|
||||||
|
/* and adjust the number of pbufs currently queued for reassembly. */
|
||||||
|
ip_reass_pbufcount -= pbuf_clen(p);
|
||||||
|
|
||||||
|
/* Return the pbuf chain */
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
/* the datagram is not (yet?) reassembled completely */
|
||||||
|
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
nullreturn:
|
||||||
|
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));
|
||||||
|
IPFRAG_STATS_INC(ip_frag.drop);
|
||||||
|
pbuf_free(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif /* IP_REASSEMBLY */
|
||||||
|
|
||||||
|
#if IP_FRAG
|
||||||
|
#if IP_FRAG_USES_STATIC_BUF
|
||||||
|
static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
|
||||||
|
#else /* IP_FRAG_USES_STATIC_BUF */
|
||||||
|
|
||||||
|
#if !LWIP_NETIF_TX_SINGLE_PBUF
|
||||||
|
/** Allocate a new struct pbuf_custom_ref */
|
||||||
|
static struct pbuf_custom_ref* ICACHE_FLASH_ATTR
|
||||||
|
ip_frag_alloc_pbuf_custom_ref(void)
|
||||||
|
{
|
||||||
|
return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Free a struct pbuf_custom_ref */
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
|
||||||
|
{
|
||||||
|
LWIP_ASSERT("p != NULL", p != NULL);
|
||||||
|
memp_free(MEMP_FRAG_PBUF, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Free-callback function to free a 'struct pbuf_custom_ref', called by
|
||||||
|
* pbuf_free. */
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
ipfrag_free_pbuf_custom(struct pbuf *p)
|
||||||
|
{
|
||||||
|
struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
|
||||||
|
LWIP_ASSERT("pcr != NULL", pcr != NULL);
|
||||||
|
LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
|
||||||
|
if (pcr->original != NULL) {
|
||||||
|
pbuf_free(pcr->original);
|
||||||
|
}
|
||||||
|
ip_frag_free_pbuf_custom_ref(pcr);
|
||||||
|
}
|
||||||
|
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
|
||||||
|
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fragment an IP datagram if too large for the netif.
|
||||||
|
*
|
||||||
|
* Chop the datagram in MTU sized chunks and send them in order
|
||||||
|
* by using a fixed size static memory buffer (PBUF_REF) or
|
||||||
|
* point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
|
||||||
|
*
|
||||||
|
* @param p ip packet to send
|
||||||
|
* @param netif the netif on which to send
|
||||||
|
* @param dest destination ip address to which to send
|
||||||
|
*
|
||||||
|
* @return ERR_OK if sent successfully, err_t otherwise
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
|
||||||
|
{
|
||||||
|
struct pbuf *rambuf;
|
||||||
|
#if IP_FRAG_USES_STATIC_BUF
|
||||||
|
struct pbuf *header;
|
||||||
|
#else
|
||||||
|
#if !LWIP_NETIF_TX_SINGLE_PBUF
|
||||||
|
struct pbuf *newpbuf;
|
||||||
|
#endif
|
||||||
|
struct ip_hdr *original_iphdr;
|
||||||
|
#endif
|
||||||
|
struct ip_hdr *iphdr;
|
||||||
|
u16_t nfb;
|
||||||
|
u16_t left, cop;
|
||||||
|
u16_t mtu = netif->mtu;
|
||||||
|
u16_t ofo, omf;
|
||||||
|
u16_t last;
|
||||||
|
u16_t poff = IP_HLEN;
|
||||||
|
u16_t tmp;
|
||||||
|
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
|
||||||
|
u16_t newpbuflen = 0;
|
||||||
|
u16_t left_to_copy;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Get a RAM based MTU sized pbuf */
|
||||||
|
#if IP_FRAG_USES_STATIC_BUF
|
||||||
|
/* When using a static buffer, we use a PBUF_REF, which we will
|
||||||
|
* use to reference the packet (without link header).
|
||||||
|
* Layer and length is irrelevant.
|
||||||
|
*/
|
||||||
|
rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
|
||||||
|
if (rambuf == NULL) {
|
||||||
|
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
rambuf->tot_len = rambuf->len = mtu;
|
||||||
|
rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
|
||||||
|
|
||||||
|
/* Copy the IP header in it */
|
||||||
|
iphdr = (struct ip_hdr *)rambuf->payload;
|
||||||
|
SMEMCPY(iphdr, p->payload, IP_HLEN);
|
||||||
|
#else /* IP_FRAG_USES_STATIC_BUF */
|
||||||
|
original_iphdr = (struct ip_hdr *)p->payload;
|
||||||
|
iphdr = original_iphdr;
|
||||||
|
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||||
|
|
||||||
|
/* Save original offset */
|
||||||
|
tmp = ntohs(IPH_OFFSET(iphdr));
|
||||||
|
ofo = tmp & IP_OFFMASK;
|
||||||
|
omf = tmp & IP_MF;
|
||||||
|
|
||||||
|
left = p->tot_len - IP_HLEN;
|
||||||
|
|
||||||
|
nfb = (mtu - IP_HLEN) / 8;
|
||||||
|
|
||||||
|
while (left) {
|
||||||
|
last = (left <= mtu - IP_HLEN);
|
||||||
|
|
||||||
|
/* Set new offset and MF flag */
|
||||||
|
tmp = omf | (IP_OFFMASK & (ofo));
|
||||||
|
if (!last) {
|
||||||
|
tmp = tmp | IP_MF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill this fragment */
|
||||||
|
cop = last ? left : nfb * 8;
|
||||||
|
|
||||||
|
#if IP_FRAG_USES_STATIC_BUF
|
||||||
|
poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
|
||||||
|
#else /* IP_FRAG_USES_STATIC_BUF */
|
||||||
|
#if LWIP_NETIF_TX_SINGLE_PBUF
|
||||||
|
rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
|
||||||
|
if (rambuf == NULL) {
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
LWIP_ASSERT("this needs a pbuf in one piece!",
|
||||||
|
(rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
|
||||||
|
poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
|
||||||
|
/* make room for the IP header */
|
||||||
|
if(pbuf_header(rambuf, IP_HLEN)) {
|
||||||
|
pbuf_free(rambuf);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
/* fill in the IP header */
|
||||||
|
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
|
||||||
|
iphdr = rambuf->payload;
|
||||||
|
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||||
|
/* When not using a static buffer, create a chain of pbufs.
|
||||||
|
* The first will be a PBUF_RAM holding the link and IP header.
|
||||||
|
* The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
|
||||||
|
* but limited to the size of an mtu.
|
||||||
|
*/
|
||||||
|
rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
|
||||||
|
if (rambuf == NULL) {
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
LWIP_ASSERT("this needs a pbuf in one piece!",
|
||||||
|
(p->len >= (IP_HLEN)));
|
||||||
|
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
|
||||||
|
iphdr = (struct ip_hdr *)rambuf->payload;
|
||||||
|
|
||||||
|
/* Can just adjust p directly for needed offset. */
|
||||||
|
p->payload = (u8_t *)p->payload + poff;
|
||||||
|
p->len -= poff;
|
||||||
|
|
||||||
|
left_to_copy = cop;
|
||||||
|
while (left_to_copy) {
|
||||||
|
struct pbuf_custom_ref *pcr;
|
||||||
|
newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
|
||||||
|
/* Is this pbuf already empty? */
|
||||||
|
if (!newpbuflen) {
|
||||||
|
p = p->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pcr = ip_frag_alloc_pbuf_custom_ref();
|
||||||
|
if (pcr == NULL) {
|
||||||
|
pbuf_free(rambuf);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
/* Mirror this pbuf, although we might not need all of it. */
|
||||||
|
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
|
||||||
|
if (newpbuf == NULL) {
|
||||||
|
ip_frag_free_pbuf_custom_ref(pcr);
|
||||||
|
pbuf_free(rambuf);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
pbuf_ref(p);
|
||||||
|
pcr->original = p;
|
||||||
|
pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
|
||||||
|
|
||||||
|
/* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
|
||||||
|
* so that it is removed when pbuf_dechain is later called on rambuf.
|
||||||
|
*/
|
||||||
|
pbuf_cat(rambuf, newpbuf);
|
||||||
|
left_to_copy -= newpbuflen;
|
||||||
|
if (left_to_copy) {
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poff = newpbuflen;
|
||||||
|
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||||
|
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||||
|
|
||||||
|
/* Correct header */
|
||||||
|
IPH_OFFSET_SET(iphdr, htons(tmp));
|
||||||
|
IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
|
||||||
|
IPH_CHKSUM_SET(iphdr, 0);
|
||||||
|
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||||
|
|
||||||
|
#if IP_FRAG_USES_STATIC_BUF
|
||||||
|
if (last) {
|
||||||
|
pbuf_realloc(rambuf, left + IP_HLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This part is ugly: we alloc a RAM based pbuf for
|
||||||
|
* the link level header for each chunk and then
|
||||||
|
* free it.A PBUF_ROM style pbuf for which pbuf_header
|
||||||
|
* worked would make things simpler.
|
||||||
|
*/
|
||||||
|
header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
|
||||||
|
if (header != NULL) {
|
||||||
|
pbuf_chain(header, rambuf);
|
||||||
|
netif->output(netif, header, dest);
|
||||||
|
IPFRAG_STATS_INC(ip_frag.xmit);
|
||||||
|
snmp_inc_ipfragcreates();
|
||||||
|
pbuf_free(header);
|
||||||
|
} else {
|
||||||
|
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
|
||||||
|
pbuf_free(rambuf);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
#else /* IP_FRAG_USES_STATIC_BUF */
|
||||||
|
/* No need for separate header pbuf - we allowed room for it in rambuf
|
||||||
|
* when allocated.
|
||||||
|
*/
|
||||||
|
netif->output(netif, rambuf, dest);
|
||||||
|
IPFRAG_STATS_INC(ip_frag.xmit);
|
||||||
|
|
||||||
|
/* Unfortunately we can't reuse rambuf - the hardware may still be
|
||||||
|
* using the buffer. Instead we free it (and the ensuing chain) and
|
||||||
|
* recreate it next time round the loop. If we're lucky the hardware
|
||||||
|
* will have already sent the packet, the free will really free, and
|
||||||
|
* there will be zero memory penalty.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pbuf_free(rambuf);
|
||||||
|
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||||
|
left -= cop;
|
||||||
|
ofo += nfb;
|
||||||
|
}
|
||||||
|
#if IP_FRAG_USES_STATIC_BUF
|
||||||
|
pbuf_free(rambuf);
|
||||||
|
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||||
|
snmp_inc_ipfragoks();
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
#endif /* IP_FRAG */
|
1106
tools/sdk/lwip/src/core/mdns.c
Normal file
1106
tools/sdk/lwip/src/core/mdns.c
Normal file
File diff suppressed because it is too large
Load Diff
644
tools/sdk/lwip/src/core/mem.c
Normal file
644
tools/sdk/lwip/src/core/mem.c
Normal file
@ -0,0 +1,644 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Dynamic memory manager
|
||||||
|
*
|
||||||
|
* This is a lightweight replacement for the standard C library malloc().
|
||||||
|
*
|
||||||
|
* If you want to use the standard C library malloc() instead, define
|
||||||
|
* MEM_LIBC_MALLOC to 1 in your lwipopts.h
|
||||||
|
*
|
||||||
|
* To let mem_malloc() use pools (prevents fragmentation and is much faster than
|
||||||
|
* a heap but might waste some memory), define MEM_USE_POOLS to 1, define
|
||||||
|
* MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
|
||||||
|
* of pools like this (more pools can be added between _START and _END):
|
||||||
|
*
|
||||||
|
* Define three pools with sizes 256, 512, and 1512 bytes
|
||||||
|
* LWIP_MALLOC_MEMPOOL_START
|
||||||
|
* LWIP_MALLOC_MEMPOOL(20, 256)
|
||||||
|
* LWIP_MALLOC_MEMPOOL(10, 512)
|
||||||
|
* LWIP_MALLOC_MEMPOOL(5, 1512)
|
||||||
|
* LWIP_MALLOC_MEMPOOL_END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
* Simon Goldschmidt
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
#include "lwip/err.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if MEM_USE_POOLS
|
||||||
|
/* lwIP head implemented with different sized pools */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate memory: determine the smallest pool that is big enough
|
||||||
|
* to contain an element of 'size' and get an element from that pool.
|
||||||
|
*
|
||||||
|
* @param size the size in bytes of the memory needed
|
||||||
|
* @return a pointer to the allocated memory or NULL if the pool is empty
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
mem_malloc(mem_size_t size)
|
||||||
|
{
|
||||||
|
struct memp_malloc_helper *element;
|
||||||
|
memp_t poolnr;
|
||||||
|
mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
|
||||||
|
|
||||||
|
for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {
|
||||||
|
#if MEM_USE_POOLS_TRY_BIGGER_POOL
|
||||||
|
again:
|
||||||
|
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
|
||||||
|
/* is this pool big enough to hold an element of the required size
|
||||||
|
plus a struct memp_malloc_helper that saves the pool this element came from? */
|
||||||
|
if (required_size <= memp_sizes[poolnr]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (poolnr > MEMP_POOL_LAST) {
|
||||||
|
LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
element = (struct memp_malloc_helper*)memp_malloc(poolnr);
|
||||||
|
if (element == NULL) {
|
||||||
|
/* No need to DEBUGF or ASSERT: This error is already
|
||||||
|
taken care of in memp.c */
|
||||||
|
#if MEM_USE_POOLS_TRY_BIGGER_POOL
|
||||||
|
/** Try a bigger pool if this one is empty! */
|
||||||
|
if (poolnr < MEMP_POOL_LAST) {
|
||||||
|
poolnr++;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save the pool number this element came from */
|
||||||
|
element->poolnr = poolnr;
|
||||||
|
/* and return a pointer to the memory directly after the struct memp_malloc_helper */
|
||||||
|
element++;
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free memory previously allocated by mem_malloc. Loads the pool number
|
||||||
|
* and calls memp_free with that pool number to put the element back into
|
||||||
|
* its pool
|
||||||
|
*
|
||||||
|
* @param rmem the memory element to free
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
mem_free(void *rmem)
|
||||||
|
{
|
||||||
|
struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;
|
||||||
|
|
||||||
|
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
|
||||||
|
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
|
||||||
|
|
||||||
|
/* get the original struct memp_malloc_helper */
|
||||||
|
hmem--;
|
||||||
|
|
||||||
|
LWIP_ASSERT("hmem != NULL", (hmem != NULL));
|
||||||
|
LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
|
||||||
|
LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));
|
||||||
|
|
||||||
|
/* and put it in the pool we saved earlier */
|
||||||
|
memp_free(hmem->poolnr, hmem);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* MEM_USE_POOLS */
|
||||||
|
/* lwIP replacement for your libc malloc() */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The heap is made up as a list of structs of this type.
|
||||||
|
* This does not have to be aligned since for getting its size,
|
||||||
|
* we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.
|
||||||
|
*/
|
||||||
|
struct mem {
|
||||||
|
/** index (-> ram[next]) of the next struct */
|
||||||
|
mem_size_t next;
|
||||||
|
/** index (-> ram[prev]) of the previous struct */
|
||||||
|
mem_size_t prev;
|
||||||
|
/** 1: this area is used; 0: this area is unused */
|
||||||
|
u8_t used;
|
||||||
|
u8_t pad[3]; /* XXX: pad here instead use global ALIGN */
|
||||||
|
} __ATTRIB_PACK;
|
||||||
|
|
||||||
|
/** All allocated blocks will be MIN_SIZE bytes big, at least!
|
||||||
|
* MIN_SIZE can be overridden to suit your needs. Smaller values save space,
|
||||||
|
* larger values could prevent too small blocks to fragment the RAM too much. */
|
||||||
|
#ifndef MIN_SIZE
|
||||||
|
#define MIN_SIZE 12
|
||||||
|
#endif /* MIN_SIZE */
|
||||||
|
/* some alignment macros: we define them here for better source code layout */
|
||||||
|
#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE)
|
||||||
|
#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
|
||||||
|
#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
|
||||||
|
|
||||||
|
/** If you want to relocate the heap to external memory, simply define
|
||||||
|
* LWIP_RAM_HEAP_POINTER as a void-pointer to that location.
|
||||||
|
* If so, make sure the memory at that location is big enough (see below on
|
||||||
|
* how that space is calculated). */
|
||||||
|
#ifndef LWIP_RAM_HEAP_POINTER
|
||||||
|
/** the heap. we need one struct mem at the end and some room for alignment */
|
||||||
|
/* enlarge heap as tx pbuf payload is allocate from heap as well */
|
||||||
|
u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT] SHMEM_ATTR;
|
||||||
|
#define LWIP_RAM_HEAP_POINTER ram_heap
|
||||||
|
#endif /* LWIP_RAM_HEAP_POINTER */
|
||||||
|
|
||||||
|
/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */
|
||||||
|
static u8_t *ram;
|
||||||
|
/** the last entry, always unused! */
|
||||||
|
static struct mem *ram_end;
|
||||||
|
/** pointer to the lowest free block, this is used for faster search */
|
||||||
|
static struct mem *lfree;
|
||||||
|
|
||||||
|
/** concurrent access protection */
|
||||||
|
//static sys_mutex_t mem_mutex;
|
||||||
|
|
||||||
|
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||||
|
|
||||||
|
static volatile u8_t mem_free_count;
|
||||||
|
|
||||||
|
/* Allow mem_free from other (e.g. interrupt) context */
|
||||||
|
#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free)
|
||||||
|
#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free)
|
||||||
|
#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free)
|
||||||
|
#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
|
||||||
|
#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc)
|
||||||
|
#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc)
|
||||||
|
|
||||||
|
#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||||
|
|
||||||
|
/* Protect the heap only by using a semaphore */
|
||||||
|
#define LWIP_MEM_FREE_DECL_PROTECT()
|
||||||
|
#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex)
|
||||||
|
#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex)
|
||||||
|
/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */
|
||||||
|
#define LWIP_MEM_ALLOC_DECL_PROTECT()
|
||||||
|
#define LWIP_MEM_ALLOC_PROTECT()
|
||||||
|
#define LWIP_MEM_ALLOC_UNPROTECT()
|
||||||
|
|
||||||
|
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Plug holes" by combining adjacent empty struct mems.
|
||||||
|
* After this function is through, there should not exist
|
||||||
|
* one empty struct mem pointing to another empty struct mem.
|
||||||
|
*
|
||||||
|
* @param mem this points to a struct mem which just has been freed
|
||||||
|
* @internal this function is only called by mem_free() and mem_trim()
|
||||||
|
*
|
||||||
|
* This assumes access to the heap is protected by the calling function
|
||||||
|
* already.
|
||||||
|
*/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
plug_holes(struct mem *mem)
|
||||||
|
{
|
||||||
|
struct mem *nmem;
|
||||||
|
struct mem *pmem;
|
||||||
|
|
||||||
|
LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
|
||||||
|
LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
|
||||||
|
LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
|
||||||
|
|
||||||
|
/* plug hole forward */
|
||||||
|
LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
|
||||||
|
|
||||||
|
nmem = (struct mem *)(void *)&ram[mem->next];
|
||||||
|
if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
|
||||||
|
/* if mem->next is unused and not end of ram, combine mem and mem->next */
|
||||||
|
if (lfree == nmem) {
|
||||||
|
lfree = mem;
|
||||||
|
}
|
||||||
|
mem->next = nmem->next;
|
||||||
|
((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* plug hole backward */
|
||||||
|
pmem = (struct mem *)(void *)&ram[mem->prev];
|
||||||
|
if (pmem != mem && pmem->used == 0) {
|
||||||
|
/* if mem->prev is unused, combine mem and mem->prev */
|
||||||
|
if (lfree == mem) {
|
||||||
|
lfree = pmem;
|
||||||
|
}
|
||||||
|
pmem->next = mem->next;
|
||||||
|
((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zero the heap and initialize start, end and lowest-free
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
mem_init(void)
|
||||||
|
{
|
||||||
|
struct mem *mem;
|
||||||
|
|
||||||
|
LWIP_ASSERT("Sanity check alignment",
|
||||||
|
(SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);
|
||||||
|
|
||||||
|
/* align the heap */
|
||||||
|
ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER);
|
||||||
|
/* initialize the start of the heap */
|
||||||
|
mem = (struct mem *)(void *)ram;
|
||||||
|
mem->next = MEM_SIZE_ALIGNED;
|
||||||
|
mem->prev = 0;
|
||||||
|
mem->used = 0;
|
||||||
|
/* initialize the end of the heap */
|
||||||
|
ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED];
|
||||||
|
ram_end->used = 1;
|
||||||
|
ram_end->next = MEM_SIZE_ALIGNED;
|
||||||
|
ram_end->prev = MEM_SIZE_ALIGNED;
|
||||||
|
|
||||||
|
/* initialize the lowest-free pointer to the start of the heap */
|
||||||
|
lfree = (struct mem *)(void *)ram;
|
||||||
|
|
||||||
|
MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
|
||||||
|
|
||||||
|
if(sys_mutex_new(&mem_mutex) != ERR_OK) {
|
||||||
|
LWIP_ASSERT("failed to create mem_mutex", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put a struct mem back on the heap
|
||||||
|
*
|
||||||
|
* @param rmem is the data portion of a struct mem as returned by a previous
|
||||||
|
* call to mem_malloc()
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
mem_free(void *rmem)
|
||||||
|
{
|
||||||
|
struct mem *mem;
|
||||||
|
LWIP_MEM_FREE_DECL_PROTECT();
|
||||||
|
|
||||||
|
if (rmem == NULL) {
|
||||||
|
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
|
||||||
|
|
||||||
|
LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
|
||||||
|
(u8_t *)rmem < (u8_t *)ram_end);
|
||||||
|
|
||||||
|
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
|
||||||
|
SYS_ARCH_DECL_PROTECT(lev);
|
||||||
|
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
|
||||||
|
/* protect mem stats from concurrent access */
|
||||||
|
SYS_ARCH_PROTECT(lev);
|
||||||
|
MEM_STATS_INC(illegal);
|
||||||
|
SYS_ARCH_UNPROTECT(lev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* protect the heap from concurrent access */
|
||||||
|
LWIP_MEM_FREE_PROTECT();
|
||||||
|
/* Get the corresponding struct mem ... */
|
||||||
|
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||||
|
/* ... which has to be in a used state ... */
|
||||||
|
LWIP_ASSERT("mem_free: mem->used", mem->used);
|
||||||
|
/* ... and is now unused. */
|
||||||
|
mem->used = 0;
|
||||||
|
|
||||||
|
if (mem < lfree) {
|
||||||
|
/* the newly freed struct is now the lowest */
|
||||||
|
lfree = mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram)));
|
||||||
|
|
||||||
|
/* finally, see if prev or next are free also */
|
||||||
|
plug_holes(mem);
|
||||||
|
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||||
|
mem_free_count = 1;
|
||||||
|
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||||
|
LWIP_MEM_FREE_UNPROTECT();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shrink memory returned by mem_malloc().
|
||||||
|
*
|
||||||
|
* @param rmem pointer to memory allocated by mem_malloc the is to be shrinked
|
||||||
|
* @param newsize required size after shrinking (needs to be smaller than or
|
||||||
|
* equal to the previous size)
|
||||||
|
* @return for compatibility reasons: is always == rmem, at the moment
|
||||||
|
* or NULL if newsize is > old size, in which case rmem is NOT touched
|
||||||
|
* or freed!
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
mem_trim(void *rmem, mem_size_t newsize)
|
||||||
|
{
|
||||||
|
mem_size_t size;
|
||||||
|
mem_size_t ptr, ptr2;
|
||||||
|
struct mem *mem, *mem2;
|
||||||
|
/* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
|
||||||
|
LWIP_MEM_FREE_DECL_PROTECT();
|
||||||
|
|
||||||
|
/* Expand the size of the allocated memory region so that we can
|
||||||
|
adjust for alignment. */
|
||||||
|
newsize = LWIP_MEM_ALIGN_SIZE(newsize);
|
||||||
|
|
||||||
|
if(newsize < MIN_SIZE_ALIGNED) {
|
||||||
|
/* every data block must be at least MIN_SIZE_ALIGNED long */
|
||||||
|
newsize = MIN_SIZE_ALIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newsize > MEM_SIZE_ALIGNED) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
|
||||||
|
(u8_t *)rmem < (u8_t *)ram_end);
|
||||||
|
|
||||||
|
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
|
||||||
|
SYS_ARCH_DECL_PROTECT(lev);
|
||||||
|
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n"));
|
||||||
|
/* protect mem stats from concurrent access */
|
||||||
|
SYS_ARCH_PROTECT(lev);
|
||||||
|
MEM_STATS_INC(illegal);
|
||||||
|
SYS_ARCH_UNPROTECT(lev);
|
||||||
|
return rmem;
|
||||||
|
}
|
||||||
|
/* Get the corresponding struct mem ... */
|
||||||
|
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||||
|
/* ... and its offset pointer */
|
||||||
|
ptr = (mem_size_t)((u8_t *)mem - ram);
|
||||||
|
|
||||||
|
size = mem->next - ptr - SIZEOF_STRUCT_MEM;
|
||||||
|
LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size);
|
||||||
|
if (newsize > size) {
|
||||||
|
/* not supported */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (newsize == size) {
|
||||||
|
/* No change in size, simply return */
|
||||||
|
return rmem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* protect the heap from concurrent access */
|
||||||
|
LWIP_MEM_FREE_PROTECT();
|
||||||
|
|
||||||
|
mem2 = (struct mem *)(void *)&ram[mem->next];
|
||||||
|
if(mem2->used == 0) {
|
||||||
|
/* The next struct is unused, we can simply move it at little */
|
||||||
|
mem_size_t next;
|
||||||
|
/* remember the old next pointer */
|
||||||
|
next = mem2->next;
|
||||||
|
/* create new struct mem which is moved directly after the shrinked mem */
|
||||||
|
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
|
||||||
|
if (lfree == mem2) {
|
||||||
|
lfree = (struct mem *)(void *)&ram[ptr2];
|
||||||
|
}
|
||||||
|
mem2 = (struct mem *)(void *)&ram[ptr2];
|
||||||
|
mem2->used = 0;
|
||||||
|
/* restore the next pointer */
|
||||||
|
mem2->next = next;
|
||||||
|
/* link it back to mem */
|
||||||
|
mem2->prev = ptr;
|
||||||
|
/* link mem to it */
|
||||||
|
mem->next = ptr2;
|
||||||
|
/* last thing to restore linked list: as we have moved mem2,
|
||||||
|
* let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not
|
||||||
|
* the end of the heap */
|
||||||
|
if (mem2->next != MEM_SIZE_ALIGNED) {
|
||||||
|
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
|
||||||
|
}
|
||||||
|
MEM_STATS_DEC_USED(used, (size - newsize));
|
||||||
|
/* no need to plug holes, we've already done that */
|
||||||
|
} else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {
|
||||||
|
/* Next struct is used but there's room for another struct mem with
|
||||||
|
* at least MIN_SIZE_ALIGNED of data.
|
||||||
|
* Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem
|
||||||
|
* ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED').
|
||||||
|
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
|
||||||
|
* region that couldn't hold data, but when mem->next gets freed,
|
||||||
|
* the 2 regions would be combined, resulting in more free memory */
|
||||||
|
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
|
||||||
|
mem2 = (struct mem *)(void *)&ram[ptr2];
|
||||||
|
if (mem2 < lfree) {
|
||||||
|
lfree = mem2;
|
||||||
|
}
|
||||||
|
mem2->used = 0;
|
||||||
|
mem2->next = mem->next;
|
||||||
|
mem2->prev = ptr;
|
||||||
|
mem->next = ptr2;
|
||||||
|
if (mem2->next != MEM_SIZE_ALIGNED) {
|
||||||
|
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
|
||||||
|
}
|
||||||
|
MEM_STATS_DEC_USED(used, (size - newsize));
|
||||||
|
/* the original mem->next is used, so no need to plug holes! */
|
||||||
|
}
|
||||||
|
/* else {
|
||||||
|
next struct mem is used but size between mem and mem2 is not big enough
|
||||||
|
to create another struct mem
|
||||||
|
-> don't do anyhting.
|
||||||
|
-> the remaining space stays unused since it is too small
|
||||||
|
} */
|
||||||
|
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||||
|
mem_free_count = 1;
|
||||||
|
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||||
|
LWIP_MEM_FREE_UNPROTECT();
|
||||||
|
return rmem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adam's mem_malloc() plus solution for bug #17922
|
||||||
|
* Allocate a block of memory with a minimum of 'size' bytes.
|
||||||
|
*
|
||||||
|
* @param size is the minimum size of the requested block in bytes.
|
||||||
|
* @return pointer to allocated memory or NULL if no free memory was found.
|
||||||
|
*
|
||||||
|
* Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
mem_malloc(mem_size_t size)
|
||||||
|
{
|
||||||
|
mem_size_t ptr, ptr2;
|
||||||
|
struct mem *mem, *mem2;
|
||||||
|
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||||
|
u8_t local_mem_free_count = 0;
|
||||||
|
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||||
|
LWIP_MEM_ALLOC_DECL_PROTECT();
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expand the size of the allocated memory region so that we can
|
||||||
|
adjust for alignment. */
|
||||||
|
size = LWIP_MEM_ALIGN_SIZE(size);
|
||||||
|
|
||||||
|
if(size < MIN_SIZE_ALIGNED) {
|
||||||
|
/* every data block must be at least MIN_SIZE_ALIGNED long */
|
||||||
|
size = MIN_SIZE_ALIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > MEM_SIZE_ALIGNED) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* protect the heap from concurrent access */
|
||||||
|
sys_mutex_lock(&mem_mutex);
|
||||||
|
LWIP_MEM_ALLOC_PROTECT();
|
||||||
|
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||||
|
/* run as long as a mem_free disturbed mem_malloc */
|
||||||
|
do {
|
||||||
|
local_mem_free_count = 0;
|
||||||
|
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||||
|
|
||||||
|
/* Scan through the heap searching for a free block that is big enough,
|
||||||
|
* beginning with the lowest free block.
|
||||||
|
*/
|
||||||
|
for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size;
|
||||||
|
ptr = ((struct mem *)(void *)&ram[ptr])->next) {
|
||||||
|
mem = (struct mem *)(void *)&ram[ptr];
|
||||||
|
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||||
|
mem_free_count = 0;
|
||||||
|
LWIP_MEM_ALLOC_UNPROTECT();
|
||||||
|
/* allow mem_free to run */
|
||||||
|
LWIP_MEM_ALLOC_PROTECT();
|
||||||
|
if (mem_free_count != 0) {
|
||||||
|
local_mem_free_count = mem_free_count;
|
||||||
|
}
|
||||||
|
mem_free_count = 0;
|
||||||
|
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||||
|
|
||||||
|
if ((!mem->used) &&
|
||||||
|
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
|
||||||
|
/* mem is not used and at least perfect fit is possible:
|
||||||
|
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
|
||||||
|
|
||||||
|
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
|
||||||
|
/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
|
||||||
|
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
|
||||||
|
* -> split large block, create empty remainder,
|
||||||
|
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
|
||||||
|
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
|
||||||
|
* struct mem would fit in but no data between mem2 and mem2->next
|
||||||
|
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
|
||||||
|
* region that couldn't hold data, but when mem->next gets freed,
|
||||||
|
* the 2 regions would be combined, resulting in more free memory
|
||||||
|
*/
|
||||||
|
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
|
||||||
|
/* create mem2 struct */
|
||||||
|
mem2 = (struct mem *)(void *)&ram[ptr2];
|
||||||
|
mem2->used = 0;
|
||||||
|
mem2->next = mem->next;
|
||||||
|
mem2->prev = ptr;
|
||||||
|
/* and insert it between mem and mem->next */
|
||||||
|
mem->next = ptr2;
|
||||||
|
mem->used = 1;
|
||||||
|
|
||||||
|
if (mem2->next != MEM_SIZE_ALIGNED) {
|
||||||
|
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
|
||||||
|
}
|
||||||
|
MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
|
||||||
|
} else {
|
||||||
|
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
|
||||||
|
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
|
||||||
|
* take care of this).
|
||||||
|
* -> near fit or excact fit: do not split, no mem2 creation
|
||||||
|
* also can't move mem->next directly behind mem, since mem->next
|
||||||
|
* will always be used at this point!
|
||||||
|
*/
|
||||||
|
mem->used = 1;
|
||||||
|
MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mem == lfree) {
|
||||||
|
/* Find next free block after mem and update lowest free pointer */
|
||||||
|
while (lfree->used && lfree != ram_end) {
|
||||||
|
LWIP_MEM_ALLOC_UNPROTECT();
|
||||||
|
/* prevent high interrupt latency... */
|
||||||
|
LWIP_MEM_ALLOC_PROTECT();
|
||||||
|
lfree = (struct mem *)(void *)&ram[lfree->next];
|
||||||
|
}
|
||||||
|
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
|
||||||
|
}
|
||||||
|
LWIP_MEM_ALLOC_UNPROTECT();
|
||||||
|
sys_mutex_unlock(&mem_mutex);
|
||||||
|
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
|
||||||
|
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
|
||||||
|
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
|
||||||
|
((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
|
||||||
|
LWIP_ASSERT("mem_malloc: sanity check alignment",
|
||||||
|
(((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
|
||||||
|
|
||||||
|
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||||
|
/* if we got interrupted by a mem_free, try again */
|
||||||
|
} while(local_mem_free_count != 0);
|
||||||
|
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||||
|
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
|
||||||
|
MEM_STATS_INC(err);
|
||||||
|
LWIP_MEM_ALLOC_UNPROTECT();
|
||||||
|
sys_mutex_unlock(&mem_mutex);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MEM_USE_POOLS */
|
||||||
|
/**
|
||||||
|
* Contiguously allocates enough space for count objects that are size bytes
|
||||||
|
* of memory each and returns a pointer to the allocated memory.
|
||||||
|
*
|
||||||
|
* The allocated memory is filled with bytes of value zero.
|
||||||
|
*
|
||||||
|
* @param count number of objects to allocate
|
||||||
|
* @param size size of the objects to allocate
|
||||||
|
* @return pointer to allocated memory / NULL pointer if there is an error
|
||||||
|
*/
|
||||||
|
void *mem_calloc(mem_size_t count, mem_size_t size)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
/* allocate 'count' objects of size 'size' */
|
||||||
|
p = mem_malloc(count * size);
|
||||||
|
if (p) {
|
||||||
|
/* zero the memory */
|
||||||
|
os_memset(p, 0, count * size);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !MEM_LIBC_MALLOC */
|
490
tools/sdk/lwip/src/core/memp.c
Normal file
490
tools/sdk/lwip/src/core/memp.c
Normal file
@ -0,0 +1,490 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Dynamic pool memory manager
|
||||||
|
*
|
||||||
|
* lwIP has dedicated pools for many structures (netconn, protocol control blocks,
|
||||||
|
* packet buffers, ...). All these pools are managed here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#include "lwip/memp.h"
|
||||||
|
#include "lwip/pbuf.h"
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "lwip/raw.h"
|
||||||
|
#include "lwip/tcp_impl.h"
|
||||||
|
#include "lwip/igmp.h"
|
||||||
|
#include "lwip/api.h"
|
||||||
|
#include "lwip/api_msg.h"
|
||||||
|
#include "lwip/tcpip.h"
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
#include "lwip/timers.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
#include "netif/etharp.h"
|
||||||
|
#include "lwip/ip_frag.h"
|
||||||
|
#include "lwip/snmp_structs.h"
|
||||||
|
#include "lwip/snmp_msg.h"
|
||||||
|
#include "lwip/dns.h"
|
||||||
|
#include "netif/ppp_oe.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
struct memp {
|
||||||
|
struct memp *next;
|
||||||
|
#if MEMP_OVERFLOW_CHECK
|
||||||
|
const char *file;
|
||||||
|
int line;
|
||||||
|
#endif /* MEMP_OVERFLOW_CHECK */
|
||||||
|
};
|
||||||
|
|
||||||
|
#if MEMP_OVERFLOW_CHECK
|
||||||
|
/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
|
||||||
|
* and at the end of each element, initialize them as 0xcd and check
|
||||||
|
* them later. */
|
||||||
|
/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
|
||||||
|
* every single element in each pool is checked!
|
||||||
|
* This is VERY SLOW but also very helpful. */
|
||||||
|
/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
|
||||||
|
* lwipopts.h to change the amount reserved for checking. */
|
||||||
|
#ifndef MEMP_SANITY_REGION_BEFORE
|
||||||
|
#define MEMP_SANITY_REGION_BEFORE 16
|
||||||
|
#endif /* MEMP_SANITY_REGION_BEFORE*/
|
||||||
|
#if MEMP_SANITY_REGION_BEFORE > 0
|
||||||
|
#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
|
||||||
|
#else
|
||||||
|
#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0
|
||||||
|
#endif /* MEMP_SANITY_REGION_BEFORE*/
|
||||||
|
#ifndef MEMP_SANITY_REGION_AFTER
|
||||||
|
#define MEMP_SANITY_REGION_AFTER 16
|
||||||
|
#endif /* MEMP_SANITY_REGION_AFTER*/
|
||||||
|
#if MEMP_SANITY_REGION_AFTER > 0
|
||||||
|
#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
|
||||||
|
#else
|
||||||
|
#define MEMP_SANITY_REGION_AFTER_ALIGNED 0
|
||||||
|
#endif /* MEMP_SANITY_REGION_AFTER*/
|
||||||
|
|
||||||
|
/* MEMP_SIZE: save space for struct memp and for sanity check */
|
||||||
|
#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
|
||||||
|
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
|
||||||
|
|
||||||
|
#else /* MEMP_OVERFLOW_CHECK */
|
||||||
|
|
||||||
|
/* No sanity checks
|
||||||
|
* We don't need to preserve the struct memp while not allocated, so we
|
||||||
|
* can save a little space and set MEMP_SIZE to 0.
|
||||||
|
*/
|
||||||
|
#define MEMP_SIZE 0
|
||||||
|
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
|
||||||
|
|
||||||
|
#endif /* MEMP_OVERFLOW_CHECK */
|
||||||
|
|
||||||
|
/** This array holds the first free element of each pool.
|
||||||
|
* Elements form a linked list. */
|
||||||
|
static struct memp *memp_tab[MEMP_MAX];
|
||||||
|
|
||||||
|
#else /* MEMP_MEM_MALLOC */
|
||||||
|
|
||||||
|
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
|
||||||
|
|
||||||
|
#endif /* MEMP_MEM_MALLOC */
|
||||||
|
|
||||||
|
/** This array holds the element sizes of each pool. */
|
||||||
|
#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
|
||||||
|
static
|
||||||
|
#endif
|
||||||
|
const u32_t memp_sizes[MEMP_MAX] ICACHE_RODATA_ATTR = { //LWIP_MEM_ALIGN_SIZE
|
||||||
|
#define LWIP_MEMPOOL(name,num,size,desc,attr) LWIP_MEM_ALIGN_SIZE(size),
|
||||||
|
#include "lwip/memp_std.h"
|
||||||
|
};
|
||||||
|
|
||||||
|
u16_t memp_sizes_test[1] = {PBUF_POOL_BUFSIZE,};
|
||||||
|
|
||||||
|
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
/** This array holds the number of elements in each pool. */
|
||||||
|
static const u16_t memp_num[MEMP_MAX] = {
|
||||||
|
#define LWIP_MEMPOOL(name,num,size,desc,attr) (num),
|
||||||
|
#include "lwip/memp_std.h"
|
||||||
|
};
|
||||||
|
|
||||||
|
/** This array holds a textual description of each pool. */
|
||||||
|
//#ifdef LWIP_DEBUG
|
||||||
|
//static const char *memp_desc[MEMP_MAX] = {
|
||||||
|
const char *memp_desc[MEMP_MAX] = {
|
||||||
|
#define LWIP_MEMPOOL(name,num,size,desc,attr) (desc),
|
||||||
|
#include "lwip/memp_std.h"
|
||||||
|
};
|
||||||
|
//#endif /* LWIP_DEBUG */
|
||||||
|
|
||||||
|
#if MEMP_SEPARATE_POOLS
|
||||||
|
|
||||||
|
/** This creates each memory pool. These are named memp_memory_XXX_base (where
|
||||||
|
* XXX is the name of the pool defined in memp_std.h).
|
||||||
|
* To relocate a pool, declare it as extern in cc.h. Example for GCC:
|
||||||
|
* extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[];
|
||||||
|
*/
|
||||||
|
#define LWIP_MEMPOOL(name,num,size,desc,attr) u8_t memp_memory_ ## name ## _base \
|
||||||
|
[((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))] attr;
|
||||||
|
#include "lwip/memp_std.h"
|
||||||
|
|
||||||
|
/** This array holds the base of each memory pool. */
|
||||||
|
static u8_t *const memp_bases[] = {
|
||||||
|
#define LWIP_MEMPOOL(name,num,size,desc,attr) memp_memory_ ## name ## _base,
|
||||||
|
#include "lwip/memp_std.h"
|
||||||
|
};
|
||||||
|
|
||||||
|
#else /* MEMP_SEPARATE_POOLS */
|
||||||
|
|
||||||
|
/** This is the actual memory used by the pools (all pools in one big block). */
|
||||||
|
static u8_t memp_memory[MEM_ALIGNMENT - 1
|
||||||
|
#define LWIP_MEMPOOL(name,num,size,desc, attr) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
|
||||||
|
#include "lwip/memp_std.h"
|
||||||
|
];
|
||||||
|
|
||||||
|
#endif /* MEMP_SEPARATE_POOLS */
|
||||||
|
|
||||||
|
#if MEMP_SANITY_CHECK
|
||||||
|
/**
|
||||||
|
* Check that memp-lists don't form a circle, modify by ives at 2014.4.23.
|
||||||
|
*/
|
||||||
|
static int ICACHE_FLASH_ATTR
|
||||||
|
memp_sanity(void)
|
||||||
|
{
|
||||||
|
s16_t i;
|
||||||
|
struct memp *t, *h;
|
||||||
|
|
||||||
|
for (i = 0; i < MEMP_MAX; i++) {
|
||||||
|
t = memp_tab[i];
|
||||||
|
if(t != NULL) {
|
||||||
|
for (h = t->next; (t != NULL) && (h != NULL); t = t->next,
|
||||||
|
h = (((h->next != NULL) && (h->next->next != NULL)) ? h->next->next : NULL)) {
|
||||||
|
if (t == h) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif /* MEMP_SANITY_CHECK*/
|
||||||
|
#if MEMP_OVERFLOW_CHECK
|
||||||
|
#if defined(LWIP_DEBUG) && MEMP_STATS
|
||||||
|
static const char * memp_overflow_names[] = {
|
||||||
|
#define LWIP_MEMPOOL(name,num,size,desc,attr) "/"desc,
|
||||||
|
#include "lwip/memp_std.h"
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a memp element was victim of an overflow
|
||||||
|
* (e.g. the restricted area after it has been altered)
|
||||||
|
*
|
||||||
|
* @param p the memp element to check
|
||||||
|
* @param memp_type the pool p comes from
|
||||||
|
*/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
|
||||||
|
{
|
||||||
|
u16_t k;
|
||||||
|
u8_t *m;
|
||||||
|
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
||||||
|
m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type];
|
||||||
|
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
|
||||||
|
if (m[k] != 0xcd) {
|
||||||
|
char errstr[128] = "detected memp overflow in pool ";
|
||||||
|
char digit[] = "0";
|
||||||
|
if(memp_type >= 10) {
|
||||||
|
digit[0] = '0' + (memp_type/10);
|
||||||
|
strcat(errstr, digit);
|
||||||
|
}
|
||||||
|
digit[0] = '0' + (memp_type%10);
|
||||||
|
strcat(errstr, digit);
|
||||||
|
#if defined(LWIP_DEBUG) && MEMP_STATS
|
||||||
|
strcat(errstr, memp_overflow_names[memp_type]);
|
||||||
|
#endif
|
||||||
|
LWIP_ASSERT(errstr, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a memp element was victim of an underflow
|
||||||
|
* (e.g. the restricted area before it has been altered)
|
||||||
|
*
|
||||||
|
* @param p the memp element to check
|
||||||
|
* @param memp_type the pool p comes from
|
||||||
|
*/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)
|
||||||
|
{
|
||||||
|
u16_t k;
|
||||||
|
u8_t *m;
|
||||||
|
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
|
||||||
|
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
|
||||||
|
for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
|
||||||
|
if (m[k] != 0xcd) {
|
||||||
|
char errstr[128] = "detected memp underflow in pool ";
|
||||||
|
char digit[] = "0";
|
||||||
|
if(memp_type >= 10) {
|
||||||
|
digit[0] = '0' + (memp_type/10);
|
||||||
|
strcat(errstr, digit);
|
||||||
|
}
|
||||||
|
digit[0] = '0' + (memp_type%10);
|
||||||
|
strcat(errstr, digit);
|
||||||
|
#if defined(LWIP_DEBUG) && MEMP_STATS
|
||||||
|
strcat(errstr, memp_overflow_names[memp_type]);
|
||||||
|
#endif
|
||||||
|
LWIP_ASSERT(errstr, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do an overflow check for all elements in every pool.
|
||||||
|
*
|
||||||
|
* @see memp_overflow_check_element for a description of the check
|
||||||
|
*/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
memp_overflow_check_all(void)
|
||||||
|
{
|
||||||
|
u16_t i, j;
|
||||||
|
struct memp *p;
|
||||||
|
|
||||||
|
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
|
||||||
|
for (i = 0; i < MEMP_MAX; ++i) {
|
||||||
|
p = p;
|
||||||
|
for (j = 0; j < memp_num[i]; ++j) {
|
||||||
|
memp_overflow_check_element_overflow(p, i);
|
||||||
|
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
|
||||||
|
for (i = 0; i < MEMP_MAX; ++i) {
|
||||||
|
p = p;
|
||||||
|
for (j = 0; j < memp_num[i]; ++j) {
|
||||||
|
memp_overflow_check_element_underflow(p, i);
|
||||||
|
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the restricted areas of all memp elements in every pool.
|
||||||
|
*/
|
||||||
|
static void ICACHE_FLASH_ATTR
|
||||||
|
memp_overflow_init(void)
|
||||||
|
{
|
||||||
|
u16_t i, j;
|
||||||
|
struct memp *p;
|
||||||
|
u8_t *m;
|
||||||
|
|
||||||
|
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
|
||||||
|
for (i = 0; i < MEMP_MAX; ++i) {
|
||||||
|
p = p;
|
||||||
|
for (j = 0; j < memp_num[i]; ++j) {
|
||||||
|
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
|
||||||
|
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
|
||||||
|
os_memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
|
||||||
|
#endif
|
||||||
|
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
||||||
|
m = (u8_t*)p + MEMP_SIZE + memp_sizes[i];
|
||||||
|
os_memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||||
|
#endif
|
||||||
|
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* MEMP_OVERFLOW_CHECK */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize this module.
|
||||||
|
*
|
||||||
|
* Carves out memp_memory into linked lists for each pool-type.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
memp_init(void)
|
||||||
|
{
|
||||||
|
struct memp *memp;
|
||||||
|
u16_t i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < MEMP_MAX; ++i) {
|
||||||
|
MEMP_STATS_AVAIL(used, i, 0);
|
||||||
|
MEMP_STATS_AVAIL(max, i, 0);
|
||||||
|
MEMP_STATS_AVAIL(err, i, 0);
|
||||||
|
MEMP_STATS_AVAIL(avail, i, memp_num[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !MEMP_SEPARATE_POOLS
|
||||||
|
memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
|
||||||
|
#endif /* !MEMP_SEPARATE_POOLS */
|
||||||
|
/* for every pool: */
|
||||||
|
for (i = 0; i < MEMP_MAX; ++i) {
|
||||||
|
memp_tab[i] = NULL;
|
||||||
|
#if MEMP_SEPARATE_POOLS
|
||||||
|
memp = (struct memp*)memp_bases[i];
|
||||||
|
#endif /* MEMP_SEPARATE_POOLS */
|
||||||
|
/* create a linked list of memp elements */
|
||||||
|
for (j = 0; j < memp_num[i]; ++j) {
|
||||||
|
memp->next = (struct memp *)memp_tab[i];
|
||||||
|
memp_tab[i] = memp;
|
||||||
|
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
|
||||||
|
#if MEMP_OVERFLOW_CHECK
|
||||||
|
+ MEMP_SANITY_REGION_AFTER_ALIGNED
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if MEMP_OVERFLOW_CHECK
|
||||||
|
memp_overflow_init();
|
||||||
|
/* check everything a first time to see if it worked */
|
||||||
|
memp_overflow_check_all();
|
||||||
|
#endif /* MEMP_OVERFLOW_CHECK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an element from a specific pool.
|
||||||
|
*
|
||||||
|
* @param type the pool to get an element from
|
||||||
|
*
|
||||||
|
* the debug version has two more parameters:
|
||||||
|
* @param file file name calling this function
|
||||||
|
* @param line number of line where this function is called
|
||||||
|
*
|
||||||
|
* @return a pointer to the allocated memory or a NULL pointer on error
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
#if !MEMP_OVERFLOW_CHECK
|
||||||
|
memp_malloc(memp_t type)
|
||||||
|
#else
|
||||||
|
memp_malloc_fn(memp_t type, const char* file, const int line)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct memp *memp;
|
||||||
|
SYS_ARCH_DECL_PROTECT(old_level);
|
||||||
|
|
||||||
|
LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
|
||||||
|
|
||||||
|
SYS_ARCH_PROTECT(old_level);
|
||||||
|
#if MEMP_OVERFLOW_CHECK >= 2
|
||||||
|
memp_overflow_check_all();
|
||||||
|
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
|
||||||
|
|
||||||
|
memp = memp_tab[type];
|
||||||
|
|
||||||
|
if (memp != NULL) {
|
||||||
|
memp_tab[type] = memp->next;
|
||||||
|
#if MEMP_OVERFLOW_CHECK
|
||||||
|
memp->next = NULL;
|
||||||
|
memp->file = file;
|
||||||
|
memp->line = line;
|
||||||
|
#endif /* MEMP_OVERFLOW_CHECK */
|
||||||
|
MEMP_STATS_INC_USED(used, type);
|
||||||
|
LWIP_ASSERT("memp_malloc: memp properly aligned",
|
||||||
|
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
|
||||||
|
memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
|
||||||
|
} else {
|
||||||
|
LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
|
||||||
|
MEMP_STATS_INC(err, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_ARCH_UNPROTECT(old_level);
|
||||||
|
|
||||||
|
return memp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put an element back into its pool.
|
||||||
|
*
|
||||||
|
* @param type the pool where to put mem
|
||||||
|
* @param mem the memp element to free
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
memp_free(memp_t type, void *mem)
|
||||||
|
{
|
||||||
|
struct memp *memp;
|
||||||
|
SYS_ARCH_DECL_PROTECT(old_level);
|
||||||
|
|
||||||
|
if (mem == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LWIP_ASSERT("memp_free: mem properly aligned",
|
||||||
|
((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
|
||||||
|
|
||||||
|
memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);
|
||||||
|
|
||||||
|
SYS_ARCH_PROTECT(old_level);
|
||||||
|
#if MEMP_OVERFLOW_CHECK
|
||||||
|
#if MEMP_OVERFLOW_CHECK >= 2
|
||||||
|
memp_overflow_check_all();
|
||||||
|
#else
|
||||||
|
memp_overflow_check_element_overflow(memp, type);
|
||||||
|
memp_overflow_check_element_underflow(memp, type);
|
||||||
|
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
|
||||||
|
#endif /* MEMP_OVERFLOW_CHECK */
|
||||||
|
|
||||||
|
MEMP_STATS_DEC(used, type);
|
||||||
|
|
||||||
|
memp->next = memp_tab[type];
|
||||||
|
memp_tab[type] = memp;
|
||||||
|
|
||||||
|
#if MEMP_SANITY_CHECK
|
||||||
|
LWIP_ASSERT("memp sanity", memp_sanity());
|
||||||
|
#endif /* MEMP_SANITY_CHECK */
|
||||||
|
|
||||||
|
SYS_ARCH_UNPROTECT(old_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MEMP_MEM_MALLOC */
|
||||||
|
#if 0
|
||||||
|
void memp_dump(void)
|
||||||
|
{
|
||||||
|
printf("sizeof raw_pcb %u, memp_s1 %u, %s\n", sizeof(struct raw_pcb), memp_sizes[0], memp_desc[0]);
|
||||||
|
printf("sizeof udp_pcb %u, memp_s2 %u, %s\n", sizeof(struct udp_pcb), memp_sizes[1], memp_desc[1]);
|
||||||
|
printf("sizeof tcp_pcb %u, memp_s3 %u, %s\n", sizeof(struct tcp_pcb), memp_sizes[2], memp_desc[2]);
|
||||||
|
printf("sizeof tcp_pcb_listen %u, memp_s4 %u, %s\n", sizeof(struct tcp_pcb_listen), memp_sizes[3], memp_desc[3]);
|
||||||
|
printf("sizeof tcp_seg %u, memp_s5 %u, %s\n", sizeof(struct tcp_seg), memp_sizes[4], memp_desc[4]);
|
||||||
|
printf("sizeof sys_timeo %u, memp_s6 %u, %s\n", sizeof(struct sys_timeo), memp_sizes[5], memp_desc[5]);
|
||||||
|
printf("sizeof pbuf %u, memp_s7 %u, %s\n", sizeof(struct pbuf), memp_sizes[6], memp_desc[6]);
|
||||||
|
printf("align pbuf size %u, memp_s8 %u, %s\n", (PBUF_POOL_BUFSIZE), memp_sizes[7], memp_desc[7]);
|
||||||
|
printf("TCP_MSS %d PBUF_LINK_HLEN %d ETH_PAD_SIZE %d\n", TCP_MSS, PBUF_LINK_HLEN, ETH_PAD_SIZE);
|
||||||
|
printf("TCP_MSS + PBUF_LINK_HLEN + ETH_PAD_SIZE %d \n", TCP_MSS+PBUF_LINK_HLEN+ETH_PAD_SIZE+40);
|
||||||
|
printf("test size %u\n",memp_sizes_test[0]);
|
||||||
|
printf("sizeof memp_memory_PBUF_pool %u \n", sizeof(memp_memory_PBUF_POOL_base));
|
||||||
|
}
|
||||||
|
#endif //0000
|
758
tools/sdk/lwip/src/core/netif.c
Normal file
758
tools/sdk/lwip/src/core/netif.c
Normal file
@ -0,0 +1,758 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* lwIP network interface abstraction
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
#include "lwip/tcp_impl.h"
|
||||||
|
#include "lwip/snmp.h"
|
||||||
|
#include "lwip/igmp.h"
|
||||||
|
#include "netif/etharp.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
#if ENABLE_LOOPBACK
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||||
|
#include "lwip/tcpip.h"
|
||||||
|
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||||
|
#endif /* ENABLE_LOOPBACK */
|
||||||
|
|
||||||
|
#if LWIP_AUTOIP
|
||||||
|
#include "lwip/autoip.h"
|
||||||
|
#endif /* LWIP_AUTOIP */
|
||||||
|
#if LWIP_DHCP
|
||||||
|
#include "lwip/dhcp.h"
|
||||||
|
#endif /* LWIP_DHCP */
|
||||||
|
|
||||||
|
#if LWIP_NETIF_STATUS_CALLBACK
|
||||||
|
#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
|
||||||
|
#else
|
||||||
|
#define NETIF_STATUS_CALLBACK(n)
|
||||||
|
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||||
|
|
||||||
|
#if LWIP_NETIF_LINK_CALLBACK
|
||||||
|
#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0)
|
||||||
|
#else
|
||||||
|
#define NETIF_LINK_CALLBACK(n)
|
||||||
|
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
||||||
|
|
||||||
|
struct netif *netif_list;
|
||||||
|
struct netif *netif_default;
|
||||||
|
|
||||||
|
#if LWIP_HAVE_LOOPIF
|
||||||
|
static struct netif loop_netif;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a lwip network interface structure for a loopback interface
|
||||||
|
*
|
||||||
|
* @param netif the lwip network interface structure for this loopif
|
||||||
|
* @return ERR_OK if the loopif is initialized
|
||||||
|
* ERR_MEM if private data couldn't be allocated
|
||||||
|
*/
|
||||||
|
static err_t ICACHE_FLASH_ATTR
|
||||||
|
netif_loopif_init(struct netif *netif)
|
||||||
|
{
|
||||||
|
/* initialize the snmp variables and counters inside the struct netif
|
||||||
|
* ifSpeed: no assumption can be made!
|
||||||
|
*/
|
||||||
|
NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0);
|
||||||
|
|
||||||
|
netif->name[0] = 'l';
|
||||||
|
netif->name[1] = 'o';
|
||||||
|
netif->output = netif_loop_output;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
#endif /* LWIP_HAVE_LOOPIF */
|
||||||
|
|
||||||
|
void
|
||||||
|
netif_init(void)
|
||||||
|
{
|
||||||
|
#if LWIP_HAVE_LOOPIF
|
||||||
|
ip_addr_t loop_ipaddr, loop_netmask, loop_gw;
|
||||||
|
IP4_ADDR(&loop_gw, 127,0,0,1);
|
||||||
|
IP4_ADDR(&loop_ipaddr, 127,0,0,1);
|
||||||
|
IP4_ADDR(&loop_netmask, 255,0,0,0);
|
||||||
|
|
||||||
|
#if NO_SYS
|
||||||
|
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input);
|
||||||
|
#else /* NO_SYS */
|
||||||
|
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input);
|
||||||
|
#endif /* NO_SYS */
|
||||||
|
netif_set_up(&loop_netif);
|
||||||
|
|
||||||
|
#endif /* LWIP_HAVE_LOOPIF */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a network interface to the list of lwIP netifs.
|
||||||
|
*
|
||||||
|
* @param netif a pre-allocated netif structure
|
||||||
|
* @param ipaddr IP address for the new netif
|
||||||
|
* @param netmask network mask for the new netif
|
||||||
|
* @param gw default gateway IP address for the new netif
|
||||||
|
* @param state opaque data passed to the new netif
|
||||||
|
* @param init callback function that initializes the interface
|
||||||
|
* @param input callback function that is called to pass
|
||||||
|
* ingress packets up in the protocol layer stack.
|
||||||
|
*
|
||||||
|
* @return netif, or NULL if failed.
|
||||||
|
*/
|
||||||
|
struct netif *
|
||||||
|
netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
|
||||||
|
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
|
||||||
|
{
|
||||||
|
static u8_t netifnum = 0;
|
||||||
|
|
||||||
|
LWIP_ASSERT("No init function given", init != NULL);
|
||||||
|
|
||||||
|
/* reset new interface configuration state */
|
||||||
|
ip_addr_set_zero(&netif->ip_addr);
|
||||||
|
ip_addr_set_zero(&netif->netmask);
|
||||||
|
ip_addr_set_zero(&netif->gw);
|
||||||
|
netif->flags = 0;
|
||||||
|
#if LWIP_DHCP
|
||||||
|
/* netif not under DHCP control by default */
|
||||||
|
netif->dhcp = NULL;
|
||||||
|
netif->dhcps_pcb = NULL;
|
||||||
|
#endif /* LWIP_DHCP */
|
||||||
|
#if LWIP_AUTOIP
|
||||||
|
/* netif not under AutoIP control by default */
|
||||||
|
netif->autoip = NULL;
|
||||||
|
#endif /* LWIP_AUTOIP */
|
||||||
|
#if LWIP_NETIF_STATUS_CALLBACK
|
||||||
|
netif->status_callback = NULL;
|
||||||
|
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||||
|
#if LWIP_NETIF_LINK_CALLBACK
|
||||||
|
netif->link_callback = NULL;
|
||||||
|
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
||||||
|
#if LWIP_IGMP
|
||||||
|
netif->igmp_mac_filter = NULL;
|
||||||
|
#endif /* LWIP_IGMP */
|
||||||
|
#if ENABLE_LOOPBACK
|
||||||
|
netif->loop_first = NULL;
|
||||||
|
netif->loop_last = NULL;
|
||||||
|
#endif /* ENABLE_LOOPBACK */
|
||||||
|
|
||||||
|
/* remember netif specific state information data */
|
||||||
|
netif->state = state;
|
||||||
|
netif->num = netifnum++;
|
||||||
|
netif->input = input;
|
||||||
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
|
netif->addr_hint = NULL;
|
||||||
|
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||||
|
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
|
||||||
|
netif->loop_cnt_current = 0;
|
||||||
|
#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
|
||||||
|
|
||||||
|
netif_set_addr(netif, ipaddr, netmask, gw);
|
||||||
|
|
||||||
|
/* call user specified initialization function for netif */
|
||||||
|
if (init(netif) != ERR_OK) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add this netif to the list */
|
||||||
|
netif->next = netif_list;
|
||||||
|
netif_list = netif;
|
||||||
|
snmp_inc_iflist();
|
||||||
|
|
||||||
|
#if LWIP_IGMP
|
||||||
|
/* start IGMP processing */
|
||||||
|
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||||
|
igmp_start(netif);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_IGMP */
|
||||||
|
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",
|
||||||
|
netif->name[0], netif->name[1]));
|
||||||
|
ip_addr_debug_print(NETIF_DEBUG, ipaddr);
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
|
||||||
|
ip_addr_debug_print(NETIF_DEBUG, netmask);
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
|
||||||
|
ip_addr_debug_print(NETIF_DEBUG, gw);
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
|
||||||
|
return netif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change IP address configuration for a network interface (including netmask
|
||||||
|
* and default gateway).
|
||||||
|
*
|
||||||
|
* @param netif the network interface to change
|
||||||
|
* @param ipaddr the new IP address
|
||||||
|
* @param netmask the new netmask
|
||||||
|
* @param gw the new default gateway
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
|
||||||
|
ip_addr_t *gw)
|
||||||
|
{
|
||||||
|
netif_set_ipaddr(netif, ipaddr);
|
||||||
|
netif_set_netmask(netif, netmask);
|
||||||
|
netif_set_gw(netif, gw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a network interface from the list of lwIP netifs.
|
||||||
|
*
|
||||||
|
* @param netif the network interface to remove
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netif_remove(struct netif *netif)
|
||||||
|
{
|
||||||
|
if (netif == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_IGMP
|
||||||
|
/* stop IGMP processing */
|
||||||
|
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||||
|
igmp_stop(netif);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_IGMP */
|
||||||
|
if (netif_is_up(netif)) {
|
||||||
|
/* set netif down before removing (call callback function) */
|
||||||
|
netif_set_down(netif);
|
||||||
|
}
|
||||||
|
|
||||||
|
snmp_delete_ipaddridx_tree(netif);
|
||||||
|
|
||||||
|
/* is it the first netif? */
|
||||||
|
if (netif_list == netif) {
|
||||||
|
netif_list = netif->next;
|
||||||
|
} else {
|
||||||
|
/* look for netif further down the list */
|
||||||
|
struct netif * tmpNetif;
|
||||||
|
for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {
|
||||||
|
if (tmpNetif->next == netif) {
|
||||||
|
tmpNetif->next = netif->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tmpNetif == NULL)
|
||||||
|
return; /* we didn't find any netif today */
|
||||||
|
}
|
||||||
|
snmp_dec_iflist();
|
||||||
|
/* this netif is default? */
|
||||||
|
if (netif_default == netif) {
|
||||||
|
/* reset default netif */
|
||||||
|
netif_set_default(NULL);
|
||||||
|
}
|
||||||
|
LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a network interface by searching for its name
|
||||||
|
*
|
||||||
|
* @param name the name of the netif (like netif->name) plus concatenated number
|
||||||
|
* in ascii representation (e.g. 'en0')
|
||||||
|
*/
|
||||||
|
struct netif *
|
||||||
|
netif_find(char *name)
|
||||||
|
{
|
||||||
|
struct netif *netif;
|
||||||
|
u8_t num;
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
num = name[2] - '0';
|
||||||
|
|
||||||
|
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||||
|
if (num == netif->num &&
|
||||||
|
name[0] == netif->name[0] &&
|
||||||
|
name[1] == netif->name[1]) {
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));
|
||||||
|
return netif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the IP address of a network interface
|
||||||
|
*
|
||||||
|
* @param netif the network interface to change
|
||||||
|
* @param ipaddr the new IP address
|
||||||
|
*
|
||||||
|
* @note call netif_set_addr() if you also want to change netmask and
|
||||||
|
* default gateway
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
|
||||||
|
{
|
||||||
|
/* TODO: Handling of obsolete pcbs */
|
||||||
|
/* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
|
||||||
|
#if LWIP_TCP
|
||||||
|
struct tcp_pcb *pcb;
|
||||||
|
struct tcp_pcb_listen *lpcb;
|
||||||
|
|
||||||
|
/* address is actually being changed? */
|
||||||
|
if (ipaddr && (ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
|
||||||
|
/* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
|
||||||
|
pcb = tcp_active_pcbs;
|
||||||
|
while (pcb != NULL) {
|
||||||
|
/* PCB bound to current local interface address? */
|
||||||
|
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))
|
||||||
|
#if LWIP_AUTOIP
|
||||||
|
/* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
|
||||||
|
&& !ip_addr_islinklocal(&(pcb->local_ip))
|
||||||
|
#endif /* LWIP_AUTOIP */
|
||||||
|
) {
|
||||||
|
/* this connection must be aborted */
|
||||||
|
struct tcp_pcb *next = pcb->next;
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
|
||||||
|
tcp_abort(pcb);
|
||||||
|
pcb = next;
|
||||||
|
} else {
|
||||||
|
pcb = pcb->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
||||||
|
/* PCB bound to current local interface address? */
|
||||||
|
if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
|
||||||
|
(ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
|
||||||
|
/* The PCB is listening to the old ipaddr and
|
||||||
|
* is set to listen to the new one instead */
|
||||||
|
ip_addr_set(&(lpcb->local_ip), ipaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
snmp_delete_ipaddridx_tree(netif);
|
||||||
|
snmp_delete_iprteidx_tree(0,netif);
|
||||||
|
/* set new IP address to netif */
|
||||||
|
ip_addr_set(&(netif->ip_addr), ipaddr);
|
||||||
|
snmp_insert_ipaddridx_tree(netif);
|
||||||
|
snmp_insert_iprteidx_tree(0,netif);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
netif->name[0], netif->name[1],
|
||||||
|
ip4_addr1_16(&netif->ip_addr),
|
||||||
|
ip4_addr2_16(&netif->ip_addr),
|
||||||
|
ip4_addr3_16(&netif->ip_addr),
|
||||||
|
ip4_addr4_16(&netif->ip_addr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the default gateway for a network interface
|
||||||
|
*
|
||||||
|
* @param netif the network interface to change
|
||||||
|
* @param gw the new default gateway
|
||||||
|
*
|
||||||
|
* @note call netif_set_addr() if you also want to change ip address and netmask
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netif_set_gw(struct netif *netif, ip_addr_t *gw)
|
||||||
|
{
|
||||||
|
ip_addr_set(&(netif->gw), gw);
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
netif->name[0], netif->name[1],
|
||||||
|
ip4_addr1_16(&netif->gw),
|
||||||
|
ip4_addr2_16(&netif->gw),
|
||||||
|
ip4_addr3_16(&netif->gw),
|
||||||
|
ip4_addr4_16(&netif->gw)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the netmask of a network interface
|
||||||
|
*
|
||||||
|
* @param netif the network interface to change
|
||||||
|
* @param netmask the new netmask
|
||||||
|
*
|
||||||
|
* @note call netif_set_addr() if you also want to change ip address and
|
||||||
|
* default gateway
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netif_set_netmask(struct netif *netif, ip_addr_t *netmask)
|
||||||
|
{
|
||||||
|
snmp_delete_iprteidx_tree(0, netif);
|
||||||
|
/* set new netmask to netif */
|
||||||
|
ip_addr_set(&(netif->netmask), netmask);
|
||||||
|
snmp_insert_iprteidx_tree(0, netif);
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
netif->name[0], netif->name[1],
|
||||||
|
ip4_addr1_16(&netif->netmask),
|
||||||
|
ip4_addr2_16(&netif->netmask),
|
||||||
|
ip4_addr3_16(&netif->netmask),
|
||||||
|
ip4_addr4_16(&netif->netmask)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a network interface as the default network interface
|
||||||
|
* (used to output all packets for which no specific route is found)
|
||||||
|
*
|
||||||
|
* @param netif the default network interface
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netif_set_default(struct netif *netif)
|
||||||
|
{
|
||||||
|
if (netif == NULL) {
|
||||||
|
/* remove default route */
|
||||||
|
snmp_delete_iprteidx_tree(1, netif);
|
||||||
|
} else {
|
||||||
|
/* install default route */
|
||||||
|
snmp_insert_iprteidx_tree(1, netif);
|
||||||
|
}
|
||||||
|
netif_default = netif;
|
||||||
|
LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",
|
||||||
|
netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bring an interface up, available for processing
|
||||||
|
* traffic.
|
||||||
|
*
|
||||||
|
* @note: Enabling DHCP on a down interface will make it come
|
||||||
|
* up once configured.
|
||||||
|
*
|
||||||
|
* @see dhcp_start()
|
||||||
|
*/
|
||||||
|
void netif_set_up(struct netif *netif)
|
||||||
|
{
|
||||||
|
if (!(netif->flags & NETIF_FLAG_UP)) {
|
||||||
|
netif->flags |= NETIF_FLAG_UP;
|
||||||
|
|
||||||
|
#if LWIP_SNMP
|
||||||
|
snmp_get_sysuptime(&netif->ts);
|
||||||
|
#endif /* LWIP_SNMP */
|
||||||
|
|
||||||
|
NETIF_STATUS_CALLBACK(netif);
|
||||||
|
|
||||||
|
if (netif->flags & NETIF_FLAG_LINK_UP) {
|
||||||
|
#if LWIP_ARP
|
||||||
|
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
|
||||||
|
if (netif->flags & (NETIF_FLAG_ETHARP)) {
|
||||||
|
etharp_gratuitous(netif);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_ARP */
|
||||||
|
|
||||||
|
#if LWIP_IGMP
|
||||||
|
/* resend IGMP memberships */
|
||||||
|
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||||
|
igmp_report_groups( netif);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_IGMP */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bring an interface down, disabling any traffic processing.
|
||||||
|
*
|
||||||
|
* @note: Enabling DHCP on a down interface will make it come
|
||||||
|
* up once configured.
|
||||||
|
*
|
||||||
|
* @see dhcp_start()
|
||||||
|
*/
|
||||||
|
void netif_set_down(struct netif *netif)
|
||||||
|
{
|
||||||
|
if (netif->flags & NETIF_FLAG_UP) {
|
||||||
|
netif->flags &= ~NETIF_FLAG_UP;
|
||||||
|
#if LWIP_SNMP
|
||||||
|
snmp_get_sysuptime(&netif->ts);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LWIP_ARP
|
||||||
|
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||||
|
etharp_cleanup_netif(netif);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_ARP */
|
||||||
|
NETIF_STATUS_CALLBACK(netif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_NETIF_STATUS_CALLBACK
|
||||||
|
/**
|
||||||
|
* Set callback to be called when interface is brought up/down
|
||||||
|
*/
|
||||||
|
void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)
|
||||||
|
{
|
||||||
|
if (netif) {
|
||||||
|
netif->status_callback = status_callback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by a driver when its link goes up
|
||||||
|
*/
|
||||||
|
void netif_set_link_up(struct netif *netif )
|
||||||
|
{
|
||||||
|
if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
|
||||||
|
netif->flags |= NETIF_FLAG_LINK_UP;
|
||||||
|
|
||||||
|
#if LWIP_DHCP
|
||||||
|
if (netif->dhcp) {
|
||||||
|
dhcp_network_changed(netif);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_DHCP */
|
||||||
|
|
||||||
|
#if LWIP_AUTOIP
|
||||||
|
if (netif->autoip) {
|
||||||
|
autoip_network_changed(netif);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_AUTOIP */
|
||||||
|
|
||||||
|
if (netif->flags & NETIF_FLAG_UP) {
|
||||||
|
#if LWIP_ARP
|
||||||
|
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
|
||||||
|
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||||
|
etharp_gratuitous(netif);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_ARP */
|
||||||
|
|
||||||
|
#if LWIP_IGMP
|
||||||
|
/* resend IGMP memberships */
|
||||||
|
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||||
|
igmp_report_groups( netif);
|
||||||
|
}
|
||||||
|
#endif /* LWIP_IGMP */
|
||||||
|
}
|
||||||
|
NETIF_LINK_CALLBACK(netif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by a driver when its link goes down
|
||||||
|
*/
|
||||||
|
void netif_set_link_down(struct netif *netif )
|
||||||
|
{
|
||||||
|
if (netif->flags & NETIF_FLAG_LINK_UP) {
|
||||||
|
netif->flags &= ~NETIF_FLAG_LINK_UP;
|
||||||
|
NETIF_LINK_CALLBACK(netif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_NETIF_LINK_CALLBACK
|
||||||
|
/**
|
||||||
|
* Set callback to be called when link is brought up/down
|
||||||
|
*/
|
||||||
|
void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)
|
||||||
|
{
|
||||||
|
if (netif) {
|
||||||
|
netif->link_callback = link_callback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
||||||
|
|
||||||
|
#if ENABLE_LOOPBACK
|
||||||
|
/**
|
||||||
|
* Send an IP packet to be received on the same netif (loopif-like).
|
||||||
|
* The pbuf is simply copied and handed back to netif->input.
|
||||||
|
* In multithreaded mode, this is done directly since netif->input must put
|
||||||
|
* the packet on a queue.
|
||||||
|
* In callback mode, the packet is put on an internal queue and is fed to
|
||||||
|
* netif->input by netif_poll().
|
||||||
|
*
|
||||||
|
* @param netif the lwip network interface structure
|
||||||
|
* @param p the (IP) packet to 'send'
|
||||||
|
* @param ipaddr the ip address to send the packet to (not used)
|
||||||
|
* @return ERR_OK if the packet has been sent
|
||||||
|
* ERR_MEM if the pbuf used to copy the packet couldn't be allocated
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
netif_loop_output(struct netif *netif, struct pbuf *p,
|
||||||
|
ip_addr_t *ipaddr)
|
||||||
|
{
|
||||||
|
struct pbuf *r;
|
||||||
|
err_t err;
|
||||||
|
struct pbuf *last;
|
||||||
|
#if LWIP_LOOPBACK_MAX_PBUFS
|
||||||
|
u8_t clen = 0;
|
||||||
|
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
||||||
|
/* If we have a loopif, SNMP counters are adjusted for it,
|
||||||
|
* if not they are adjusted for 'netif'. */
|
||||||
|
#if LWIP_SNMP
|
||||||
|
#if LWIP_HAVE_LOOPIF
|
||||||
|
struct netif *stats_if = &loop_netif;
|
||||||
|
#else /* LWIP_HAVE_LOOPIF */
|
||||||
|
struct netif *stats_if = netif;
|
||||||
|
#endif /* LWIP_HAVE_LOOPIF */
|
||||||
|
#endif /* LWIP_SNMP */
|
||||||
|
SYS_ARCH_DECL_PROTECT(lev);
|
||||||
|
LWIP_UNUSED_ARG(ipaddr);
|
||||||
|
|
||||||
|
/* Allocate a new pbuf */
|
||||||
|
r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
|
||||||
|
if (r == NULL) {
|
||||||
|
LINK_STATS_INC(link.memerr);
|
||||||
|
LINK_STATS_INC(link.drop);
|
||||||
|
snmp_inc_ifoutdiscards(stats_if);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
#if LWIP_LOOPBACK_MAX_PBUFS
|
||||||
|
clen = pbuf_clen(r);
|
||||||
|
/* check for overflow or too many pbuf on queue */
|
||||||
|
if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
|
||||||
|
((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
|
||||||
|
pbuf_free(r);
|
||||||
|
LINK_STATS_INC(link.memerr);
|
||||||
|
LINK_STATS_INC(link.drop);
|
||||||
|
snmp_inc_ifoutdiscards(stats_if);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
netif->loop_cnt_current += clen;
|
||||||
|
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
||||||
|
|
||||||
|
/* Copy the whole pbuf queue p into the single pbuf r */
|
||||||
|
if ((err = pbuf_copy(r, p)) != ERR_OK) {
|
||||||
|
pbuf_free(r);
|
||||||
|
LINK_STATS_INC(link.memerr);
|
||||||
|
LINK_STATS_INC(link.drop);
|
||||||
|
snmp_inc_ifoutdiscards(stats_if);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put the packet on a linked list which gets emptied through calling
|
||||||
|
netif_poll(). */
|
||||||
|
|
||||||
|
/* let last point to the last pbuf in chain r */
|
||||||
|
for (last = r; last->next != NULL; last = last->next);
|
||||||
|
|
||||||
|
SYS_ARCH_PROTECT(lev);
|
||||||
|
if(netif->loop_first != NULL) {
|
||||||
|
LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
|
||||||
|
netif->loop_last->next = r;
|
||||||
|
netif->loop_last = last;
|
||||||
|
} else {
|
||||||
|
netif->loop_first = r;
|
||||||
|
netif->loop_last = last;
|
||||||
|
}
|
||||||
|
SYS_ARCH_UNPROTECT(lev);
|
||||||
|
|
||||||
|
LINK_STATS_INC(link.xmit);
|
||||||
|
snmp_add_ifoutoctets(stats_if, p->tot_len);
|
||||||
|
snmp_inc_ifoutucastpkts(stats_if);
|
||||||
|
|
||||||
|
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||||
|
/* For multithreading environment, schedule a call to netif_poll */
|
||||||
|
tcpip_callback((tcpip_callback_fn)netif_poll, netif);
|
||||||
|
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call netif_poll() in the main loop of your application. This is to prevent
|
||||||
|
* reentering non-reentrant functions like tcp_input(). Packets passed to
|
||||||
|
* netif_loop_output() are put on a list that is passed to netif->input() by
|
||||||
|
* netif_poll().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netif_poll(struct netif *netif)
|
||||||
|
{
|
||||||
|
struct pbuf *in;
|
||||||
|
/* If we have a loopif, SNMP counters are adjusted for it,
|
||||||
|
* if not they are adjusted for 'netif'. */
|
||||||
|
#if LWIP_SNMP
|
||||||
|
#if LWIP_HAVE_LOOPIF
|
||||||
|
struct netif *stats_if = &loop_netif;
|
||||||
|
#else /* LWIP_HAVE_LOOPIF */
|
||||||
|
struct netif *stats_if = netif;
|
||||||
|
#endif /* LWIP_HAVE_LOOPIF */
|
||||||
|
#endif /* LWIP_SNMP */
|
||||||
|
SYS_ARCH_DECL_PROTECT(lev);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
|
||||||
|
SYS_ARCH_PROTECT(lev);
|
||||||
|
in = netif->loop_first;
|
||||||
|
if (in != NULL) {
|
||||||
|
struct pbuf *in_end = in;
|
||||||
|
#if LWIP_LOOPBACK_MAX_PBUFS
|
||||||
|
u8_t clen = pbuf_clen(in);
|
||||||
|
/* adjust the number of pbufs on queue */
|
||||||
|
LWIP_ASSERT("netif->loop_cnt_current underflow",
|
||||||
|
((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
|
||||||
|
netif->loop_cnt_current -= clen;
|
||||||
|
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
||||||
|
while (in_end->len != in_end->tot_len) {
|
||||||
|
LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
|
||||||
|
in_end = in_end->next;
|
||||||
|
}
|
||||||
|
/* 'in_end' now points to the last pbuf from 'in' */
|
||||||
|
if (in_end == netif->loop_last) {
|
||||||
|
/* this was the last pbuf in the list */
|
||||||
|
netif->loop_first = netif->loop_last = NULL;
|
||||||
|
} else {
|
||||||
|
/* pop the pbuf off the list */
|
||||||
|
netif->loop_first = in_end->next;
|
||||||
|
LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
|
||||||
|
}
|
||||||
|
/* De-queue the pbuf from its successors on the 'loop_' list. */
|
||||||
|
in_end->next = NULL;
|
||||||
|
}
|
||||||
|
SYS_ARCH_UNPROTECT(lev);
|
||||||
|
|
||||||
|
if (in != NULL) {
|
||||||
|
LINK_STATS_INC(link.recv);
|
||||||
|
snmp_add_ifinoctets(stats_if, in->tot_len);
|
||||||
|
snmp_inc_ifinucastpkts(stats_if);
|
||||||
|
/* loopback packets are always IP packets! */
|
||||||
|
if (ip_input(in, netif) != ERR_OK) {
|
||||||
|
pbuf_free(in);
|
||||||
|
}
|
||||||
|
/* Don't reference the packet any more! */
|
||||||
|
in = NULL;
|
||||||
|
}
|
||||||
|
/* go on while there is a packet on the list */
|
||||||
|
} while (netif->loop_first != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||||
|
/**
|
||||||
|
* Calls netif_poll() for every netif on the netif_list.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
netif_poll_all(void)
|
||||||
|
{
|
||||||
|
struct netif *netif = netif_list;
|
||||||
|
/* loop through netifs */
|
||||||
|
while (netif != NULL) {
|
||||||
|
netif_poll(netif);
|
||||||
|
/* proceed to next network interface */
|
||||||
|
netif = netif->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||||
|
#endif /* ENABLE_LOOPBACK */
|
1257
tools/sdk/lwip/src/core/pbuf.c
Normal file
1257
tools/sdk/lwip/src/core/pbuf.c
Normal file
File diff suppressed because it is too large
Load Diff
358
tools/sdk/lwip/src/core/raw.c
Normal file
358
tools/sdk/lwip/src/core/raw.c
Normal file
@ -0,0 +1,358 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Implementation of raw protocol PCBs for low-level handling of
|
||||||
|
* different types of protocols besides (or overriding) those
|
||||||
|
* already available in lwIP.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#include "lwip/memp.h"
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
#include "lwip/raw.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
#include "arch/perf.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef MEMLEAK_DEBUG
|
||||||
|
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** The list of RAW PCBs */
|
||||||
|
static struct raw_pcb *raw_pcbs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if in incoming IP packet is covered by a RAW PCB
|
||||||
|
* and if so, pass it to a user-provided receive callback function.
|
||||||
|
*
|
||||||
|
* Given an incoming IP datagram (as a chain of pbufs) this function
|
||||||
|
* finds a corresponding RAW PCB and calls the corresponding receive
|
||||||
|
* callback function.
|
||||||
|
*
|
||||||
|
* @param p pbuf to be demultiplexed to a RAW PCB.
|
||||||
|
* @param inp network interface on which the datagram was received.
|
||||||
|
* @return - 1 if the packet has been eaten by a RAW PCB receive
|
||||||
|
* callback function. The caller MAY NOT not reference the
|
||||||
|
* packet any longer, and MAY NOT call pbuf_free().
|
||||||
|
* @return - 0 if packet is not eaten (pbuf is still referenced by the
|
||||||
|
* caller).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
u8_t ICACHE_FLASH_ATTR
|
||||||
|
raw_input(struct pbuf *p, struct netif *inp)
|
||||||
|
{
|
||||||
|
struct raw_pcb *pcb, *prev;
|
||||||
|
struct ip_hdr *iphdr;
|
||||||
|
s16_t proto;
|
||||||
|
u8_t eaten = 0;
|
||||||
|
|
||||||
|
LWIP_UNUSED_ARG(inp);
|
||||||
|
|
||||||
|
iphdr = (struct ip_hdr *)p->payload;
|
||||||
|
proto = IPH_PROTO(iphdr);
|
||||||
|
|
||||||
|
prev = NULL;
|
||||||
|
pcb = raw_pcbs;
|
||||||
|
/* loop through all raw pcbs until the packet is eaten by one */
|
||||||
|
/* this allows multiple pcbs to match against the packet by design */
|
||||||
|
while ((eaten == 0) && (pcb != NULL)) {
|
||||||
|
if ((pcb->protocol == proto) &&
|
||||||
|
(ip_addr_isany(&pcb->local_ip) ||
|
||||||
|
ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest))) {
|
||||||
|
#if IP_SOF_BROADCAST_RECV
|
||||||
|
/* broadcast filter? */
|
||||||
|
if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(¤t_iphdr_dest, inp))
|
||||||
|
#endif /* IP_SOF_BROADCAST_RECV */
|
||||||
|
{
|
||||||
|
/* receive callback function available? */
|
||||||
|
if (pcb->recv != NULL) {
|
||||||
|
/* the receive callback function did not eat the packet? */
|
||||||
|
if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) {
|
||||||
|
/* receive function ate the packet */
|
||||||
|
p = NULL;
|
||||||
|
eaten = 1;
|
||||||
|
if (prev != NULL) {
|
||||||
|
/* move the pcb to the front of raw_pcbs so that is
|
||||||
|
found faster next time */
|
||||||
|
prev->next = pcb->next;
|
||||||
|
pcb->next = raw_pcbs;
|
||||||
|
raw_pcbs = pcb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* no receive callback function was set for this raw PCB */
|
||||||
|
}
|
||||||
|
/* drop the packet */
|
||||||
|
}
|
||||||
|
prev = pcb;
|
||||||
|
pcb = pcb->next;
|
||||||
|
}
|
||||||
|
return eaten;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a RAW PCB.
|
||||||
|
*
|
||||||
|
* @param pcb RAW PCB to be bound with a local address ipaddr.
|
||||||
|
* @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
|
||||||
|
* bind to all local interfaces.
|
||||||
|
*
|
||||||
|
* @return lwIP error code.
|
||||||
|
* - ERR_OK. Successful. No error occured.
|
||||||
|
* - ERR_USE. The specified IP address is already bound to by
|
||||||
|
* another RAW PCB.
|
||||||
|
*
|
||||||
|
* @see raw_disconnect()
|
||||||
|
*/
|
||||||
|
err_t ICACHE_FLASH_ATTR
|
||||||
|
raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
|
||||||
|
{
|
||||||
|
ip_addr_set(&pcb->local_ip, ipaddr);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect an RAW PCB. This function is required by upper layers
|
||||||
|
* of lwip. Using the raw api you could use raw_sendto() instead
|
||||||
|
*
|
||||||
|
* This will associate the RAW PCB with the remote address.
|
||||||
|
*
|
||||||
|
* @param pcb RAW PCB to be connected with remote address ipaddr and port.
|
||||||
|
* @param ipaddr remote IP address to connect with.
|
||||||
|
*
|
||||||
|
* @return lwIP error code
|
||||||
|
*
|
||||||
|
* @see raw_disconnect() and raw_sendto()
|
||||||
|
*/
|
||||||
|
err_t ICACHE_FLASH_ATTR
|
||||||
|
raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
|
||||||
|
{
|
||||||
|
ip_addr_set(&pcb->remote_ip, ipaddr);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the callback function for received packets that match the
|
||||||
|
* raw PCB's protocol and binding.
|
||||||
|
*
|
||||||
|
* The callback function MUST either
|
||||||
|
* - eat the packet by calling pbuf_free() and returning non-zero. The
|
||||||
|
* packet will not be passed to other raw PCBs or other protocol layers.
|
||||||
|
* - not free the packet, and return zero. The packet will be matched
|
||||||
|
* against further PCBs and/or forwarded to another protocol layers.
|
||||||
|
*
|
||||||
|
* @return non-zero if the packet was free()d, zero if the packet remains
|
||||||
|
* available for others.
|
||||||
|
*/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
|
||||||
|
{
|
||||||
|
/* remember recv() callback and user data */
|
||||||
|
pcb->recv = recv;
|
||||||
|
pcb->recv_arg = recv_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the raw IP packet to the given address. Note that actually you cannot
|
||||||
|
* modify the IP headers (this is inconsistent with the receive callback where
|
||||||
|
* you actually get the IP headers), you can only specify the IP payload here.
|
||||||
|
* It requires some more changes in lwIP. (there will be a raw_send() function
|
||||||
|
* then.)
|
||||||
|
*
|
||||||
|
* @param pcb the raw pcb which to send
|
||||||
|
* @param p the IP payload to send
|
||||||
|
* @param ipaddr the destination address of the IP packet
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
err_t ICACHE_FLASH_ATTR
|
||||||
|
raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
|
||||||
|
{
|
||||||
|
err_t err;
|
||||||
|
struct netif *netif;
|
||||||
|
ip_addr_t *src_ip;
|
||||||
|
struct pbuf *q; /* q will be sent down the stack */
|
||||||
|
|
||||||
|
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
|
||||||
|
|
||||||
|
/* not enough space to add an IP header to first pbuf in given p chain? */
|
||||||
|
if (pbuf_header(p, IP_HLEN)) {
|
||||||
|
/* allocate header in new pbuf */
|
||||||
|
q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
|
||||||
|
/* new header pbuf could not be allocated? */
|
||||||
|
if (q == NULL) {
|
||||||
|
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
if (p->tot_len != 0) {
|
||||||
|
/* chain header q in front of given pbuf p */
|
||||||
|
pbuf_chain(q, p);
|
||||||
|
}
|
||||||
|
/* { first pbuf q points to header pbuf } */
|
||||||
|
LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
|
||||||
|
} else {
|
||||||
|
/* first pbuf q equals given pbuf */
|
||||||
|
q = p;
|
||||||
|
if(pbuf_header(q, -IP_HLEN)) {
|
||||||
|
LWIP_ASSERT("Can't restore header we just removed!", 0);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((netif = ip_route(ipaddr)) == NULL) {
|
||||||
|
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
|
||||||
|
/* free any temporary header pbuf allocated by pbuf_header() */
|
||||||
|
if (q != p) {
|
||||||
|
pbuf_free(q);
|
||||||
|
}
|
||||||
|
return ERR_RTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IP_SOF_BROADCAST
|
||||||
|
/* broadcast filter? */
|
||||||
|
if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
|
||||||
|
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
|
||||||
|
/* free any temporary header pbuf allocated by pbuf_header() */
|
||||||
|
if (q != p) {
|
||||||
|
pbuf_free(q);
|
||||||
|
}
|
||||||
|
return ERR_VAL;
|
||||||
|
}
|
||||||
|
#endif /* IP_SOF_BROADCAST */
|
||||||
|
|
||||||
|
if (ip_addr_isany(&pcb->local_ip)) {
|
||||||
|
/* use outgoing network interface IP address as source address */
|
||||||
|
src_ip = &(netif->ip_addr);
|
||||||
|
} else {
|
||||||
|
/* use RAW PCB local IP address as source address */
|
||||||
|
src_ip = &(pcb->local_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
|
netif->addr_hint = &(pcb->addr_hint);
|
||||||
|
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||||
|
err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
|
||||||
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
|
netif->addr_hint = NULL;
|
||||||
|
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||||
|
|
||||||
|
/* did we chain a header earlier? */
|
||||||
|
if (q != p) {
|
||||||
|
/* free the header */
|
||||||
|
pbuf_free(q);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the raw IP packet to the address given by raw_connect()
|
||||||
|
*
|
||||||
|
* @param pcb the raw pcb which to send
|
||||||
|
* @param p the IP payload to send
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
err_t ICACHE_FLASH_ATTR
|
||||||
|
raw_send(struct raw_pcb *pcb, struct pbuf *p)
|
||||||
|
{
|
||||||
|
return raw_sendto(pcb, p, &pcb->remote_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an RAW PCB.
|
||||||
|
*
|
||||||
|
* @param pcb RAW PCB to be removed. The PCB is removed from the list of
|
||||||
|
* RAW PCB's and the data structure is freed from memory.
|
||||||
|
*
|
||||||
|
* @see raw_new()
|
||||||
|
*/
|
||||||
|
void ICACHE_FLASH_ATTR
|
||||||
|
raw_remove(struct raw_pcb *pcb)
|
||||||
|
{
|
||||||
|
struct raw_pcb *pcb2;
|
||||||
|
/* pcb to be removed is first in list? */
|
||||||
|
if (raw_pcbs == pcb) {
|
||||||
|
/* make list start at 2nd pcb */
|
||||||
|
raw_pcbs = raw_pcbs->next;
|
||||||
|
/* pcb not 1st in list */
|
||||||
|
} else {
|
||||||
|
for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
|
||||||
|
/* find pcb in raw_pcbs list */
|
||||||
|
if (pcb2->next != NULL && pcb2->next == pcb) {
|
||||||
|
/* remove pcb from list */
|
||||||
|
pcb2->next = pcb->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memp_free(MEMP_RAW_PCB, pcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a RAW PCB.
|
||||||
|
*
|
||||||
|
* @return The RAW PCB which was created. NULL if the PCB data structure
|
||||||
|
* could not be allocated.
|
||||||
|
*
|
||||||
|
* @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
|
||||||
|
*
|
||||||
|
* @see raw_remove()
|
||||||
|
*/
|
||||||
|
struct raw_pcb * ICACHE_FLASH_ATTR
|
||||||
|
raw_new(u8_t proto)
|
||||||
|
{
|
||||||
|
struct raw_pcb *pcb;
|
||||||
|
|
||||||
|
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
|
||||||
|
|
||||||
|
pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
|
||||||
|
/* could allocate RAW PCB? */
|
||||||
|
if (pcb != NULL) {
|
||||||
|
/* initialize PCB to all zeroes */
|
||||||
|
os_memset(pcb, 0, sizeof(struct raw_pcb));
|
||||||
|
pcb->protocol = proto;
|
||||||
|
pcb->ttl = RAW_TTL;
|
||||||
|
pcb->next = raw_pcbs;
|
||||||
|
raw_pcbs = pcb;
|
||||||
|
}
|
||||||
|
return pcb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_RAW */
|
1130
tools/sdk/lwip/src/core/sntp.c
Normal file
1130
tools/sdk/lwip/src/core/sntp.c
Normal file
File diff suppressed because it is too large
Load Diff
176
tools/sdk/lwip/src/core/stats.c
Normal file
176
tools/sdk/lwip/src/core/stats.c
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Statistics module
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
#include "lwip/mem.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct stats_ lwip_stats;
|
||||||
|
|
||||||
|
void stats_init(void)
|
||||||
|
{
|
||||||
|
#ifdef LWIP_DEBUG
|
||||||
|
#if MEMP_STATS
|
||||||
|
const char * memp_names[] = {
|
||||||
|
#define LWIP_MEMPOOL(name,num,size,desc) desc,
|
||||||
|
#include "lwip/memp_std.h"
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < MEMP_MAX; i++) {
|
||||||
|
lwip_stats.memp[i].name = memp_names[i];
|
||||||
|
}
|
||||||
|
#endif /* MEMP_STATS */
|
||||||
|
#if MEM_STATS
|
||||||
|
lwip_stats.mem.name = "MEM";
|
||||||
|
#endif /* MEM_STATS */
|
||||||
|
#endif /* LWIP_DEBUG */
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_STATS_DISPLAY
|
||||||
|
void
|
||||||
|
stats_display_proto(struct stats_proto *proto, char *name)
|
||||||
|
{
|
||||||
|
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
|
||||||
|
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));
|
||||||
|
LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv));
|
||||||
|
LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));
|
||||||
|
LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop));
|
||||||
|
LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr));
|
||||||
|
LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr));
|
||||||
|
LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr));
|
||||||
|
LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr));
|
||||||
|
LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr));
|
||||||
|
LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr));
|
||||||
|
LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err));
|
||||||
|
LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IGMP_STATS
|
||||||
|
void
|
||||||
|
stats_display_igmp(struct stats_igmp *igmp)
|
||||||
|
{
|
||||||
|
LWIP_PLATFORM_DIAG(("\nIGMP\n\t"));
|
||||||
|
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit));
|
||||||
|
LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv));
|
||||||
|
LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop));
|
||||||
|
LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr));
|
||||||
|
LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));
|
||||||
|
LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr));
|
||||||
|
LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr));
|
||||||
|
LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1));
|
||||||
|
LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n", igmp->rx_group));
|
||||||
|
LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n", igmp->rx_general));
|
||||||
|
LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report));
|
||||||
|
LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join));
|
||||||
|
LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave));
|
||||||
|
LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report));
|
||||||
|
}
|
||||||
|
#endif /* IGMP_STATS */
|
||||||
|
|
||||||
|
#if MEM_STATS || MEMP_STATS
|
||||||
|
void
|
||||||
|
stats_display_mem(struct stats_mem *mem, char *name)
|
||||||
|
{
|
||||||
|
LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name));
|
||||||
|
LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail));
|
||||||
|
LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used));
|
||||||
|
LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max));
|
||||||
|
LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MEMP_STATS
|
||||||
|
void
|
||||||
|
stats_display_memp(struct stats_mem *mem, int index)
|
||||||
|
{
|
||||||
|
char * memp_names[] = {
|
||||||
|
#define LWIP_MEMPOOL(name,num,size,desc) desc,
|
||||||
|
#include "lwip/memp_std.h"
|
||||||
|
};
|
||||||
|
if(index < MEMP_MAX) {
|
||||||
|
stats_display_mem(mem, memp_names[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* MEMP_STATS */
|
||||||
|
#endif /* MEM_STATS || MEMP_STATS */
|
||||||
|
|
||||||
|
#if SYS_STATS
|
||||||
|
void
|
||||||
|
stats_display_sys(struct stats_sys *sys)
|
||||||
|
{
|
||||||
|
LWIP_PLATFORM_DIAG(("\nSYS\n\t"));
|
||||||
|
LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used));
|
||||||
|
LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max));
|
||||||
|
LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err));
|
||||||
|
LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used));
|
||||||
|
LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max));
|
||||||
|
LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err));
|
||||||
|
LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used));
|
||||||
|
LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max));
|
||||||
|
LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err));
|
||||||
|
}
|
||||||
|
#endif /* SYS_STATS */
|
||||||
|
|
||||||
|
void
|
||||||
|
stats_display(void)
|
||||||
|
{
|
||||||
|
s16_t i;
|
||||||
|
|
||||||
|
LINK_STATS_DISPLAY();
|
||||||
|
ETHARP_STATS_DISPLAY();
|
||||||
|
IPFRAG_STATS_DISPLAY();
|
||||||
|
IP_STATS_DISPLAY();
|
||||||
|
IGMP_STATS_DISPLAY();
|
||||||
|
ICMP_STATS_DISPLAY();
|
||||||
|
UDP_STATS_DISPLAY();
|
||||||
|
TCP_STATS_DISPLAY();
|
||||||
|
MEM_STATS_DISPLAY();
|
||||||
|
for (i = 0; i < MEMP_MAX; i++) {
|
||||||
|
MEMP_STATS_DISPLAY(i);
|
||||||
|
}
|
||||||
|
SYS_STATS_DISPLAY();
|
||||||
|
}
|
||||||
|
#endif /* LWIP_STATS_DISPLAY */
|
||||||
|
|
||||||
|
#endif /* LWIP_STATS */
|
||||||
|
|
66
tools/sdk/lwip/src/core/sys.c
Normal file
66
tools/sdk/lwip/src/core/sys.c
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* lwIP Operating System abstraction
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||||
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the lwIP TCP/IP stack.
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
|
||||||
|
/* Most of the functions defined in sys.h must be implemented in the
|
||||||
|
* architecture-dependent file sys_arch.c */
|
||||||
|
|
||||||
|
#if !NO_SYS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sleep for some ms. Timeouts are NOT processed while sleeping.
|
||||||
|
*
|
||||||
|
* @param ms number of milliseconds to sleep
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
sys_msleep(u32_t ms)
|
||||||
|
{
|
||||||
|
if (ms > 0) {
|
||||||
|
sys_sem_t delaysem;
|
||||||
|
err_t err = sys_sem_new(&delaysem, 0);
|
||||||
|
if (err == ERR_OK) {
|
||||||
|
sys_arch_sem_wait(&delaysem, ms);
|
||||||
|
sys_sem_free(&delaysem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !NO_SYS */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user