Merge pull request #33 from kendryte/develop

Release 0.7.0
master v0.7.0
sunnycase 2018-12-21 20:34:44 +08:00 committed by GitHub
commit bb468378b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
431 changed files with 157978 additions and 156 deletions

3
.gitignore vendored
View File

@ -12,4 +12,5 @@ CMakeSettings.json
.idea
*.tar
*.tar.*
cmake-build-*
cmake-build-*
/third_party/userland

View File

@ -22,5 +22,4 @@ add_subdirectory(third_party)
# compile project
add_source_files(src/${PROJ}/*.c src/${PROJ}/*.s src/${PROJ}/*.S src/${PROJ}/*.cpp)
include(./cmake/executable.cmake)
include(./cmake/executable.cmake)

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.0)
cmake_policy(VERSION 3.10)
cmake_policy(VERSION 3.0)
include(${CMAKE_CURRENT_LIST_DIR}/macros.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/macros.internal.cmake)
@ -37,7 +37,5 @@ include(${CMAKE_CURRENT_LIST_DIR}/compile-flags.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/fix-9985.cmake)
#add_source_files(${CMAKE_CURRENT_LIST_DIR}/../lib/bsp/crt.S)
removeDuplicateSubstring(${CMAKE_C_FLAGS} CMAKE_C_FLAGS)
removeDuplicateSubstring(${CMAKE_CXX_FLAGS} CMAKE_CXX_FLAGS)

View File

@ -20,7 +20,7 @@ add_compile_flags(BOTH
-fdata-sections
-fstrict-volatile-bitfields
-fno-zero-initialized-in-bss
-Os
-O2
-ggdb
)

View File

@ -23,10 +23,14 @@ set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C)
target_link_libraries(${PROJECT_NAME}
-Wl,--start-group
m freertos c bsp drivers
m freertos atomic bsp c stdc++ drivers posix
-Wl,--end-group
)
if (EXISTS ${SDK_ROOT}/src/${PROJ}/project.cmake)
include(${SDK_ROOT}/src/${PROJ}/project.cmake)
endif ()
IF(SUFFIX)
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SUFFIX ${SUFFIX})
ENDIF()

View File

@ -26,6 +26,9 @@ global_set(CMAKE_AR "${TOOLCHAIN}/riscv64-unknown-elf-ar${EXT}")
global_set(CMAKE_OBJCOPY "${TOOLCHAIN}/riscv64-unknown-elf-objcopy${EXT}")
global_set(CMAKE_SIZE "${TOOLCHAIN}/riscv64-unknown-elf-size${EXT}")
global_set(CMAKE_OBJDUMP "${TOOLCHAIN}/riscv64-unknown-elf-objdump${EXT}")
if (WIN32)
global_set(CMAKE_MAKE_PROGRAM "${TOOLCHAIN}/mingw32-make${EXT}")
endif ()
execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=crt0.o OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE CRT0_OBJ)
execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=crtbegin.o OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE CRTBEGIN_OBJ)

View File

@ -51,6 +51,7 @@ SECTIONS
.text.start :
{
KEEP( *(.text.start) )
KEEP( *(.text.systick) )
} > ram : DATA
.init :
@ -83,7 +84,6 @@ SECTIONS
{
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
} > ram : DATA
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } > ram : DYN_DATA
/* Exception handling */
.eh_frame :
{
@ -165,6 +165,7 @@ SECTIONS
. = .;
__bss_start = .;
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } > ram : DYN_DATA
.sbss :
{
*(.dynsbss)

View File

@ -5,4 +5,5 @@ INCLUDE_DIRECTORIES(${SDK_ROOT}/third_party)
ADD_SUBDIRECTORY(hal)
ADD_SUBDIRECTORY(freertos)
ADD_SUBDIRECTORY(bsp)
ADD_SUBDIRECTORY(drivers)
ADD_SUBDIRECTORY(drivers)
ADD_SUBDIRECTORY(posix)

View File

@ -16,8 +16,10 @@
#define _BSP_PLATFORM_H
#ifdef __INTELLISENSE__
#define __freertos__ 1
#define __attribute__(x)
#define _HAS_CXX17 1
#define noexcept
#endif
/* clang-format off */

View File

@ -468,16 +468,4 @@ _init:
_fini:
ret
.size _init, .-_init
.size _fini, .-_fini
.section ".tdata.begin"
.globl _tdata_begin
_tdata_begin:
.section ".tdata.end"
.globl _tdata_end
_tdata_end:
.section ".tbss.end"
.globl _tbss_end
_tbss_end:
.size _fini, .-_fini

View File

@ -586,6 +586,9 @@ private:
xSemaphoreGiveFromISR(driver.session_.completion_event, &xHigherPriorityTaskWoken);
}
if (xHigherPriorityTaskWoken)
portYIELD();
}
static int is_memory(uintptr_t address)

View File

@ -44,11 +44,10 @@ public:
{
sysctl_clock_enable(clock_);
rtc_timer_set_mode(RTC_TIMER_SETTING);
/* Unprotect RTC */
rtc_protect_set( 0);
rtc_protect_set(0);
/* Set RTC clock frequency */
rtc_timer_set_clock_frequency(sysctl_clock_get_freq(SYSCTL_CLOCK_PLL0));
rtc_timer_set_clock_frequency(sysctl_clock_get_freq(SYSCTL_CLOCK_IN0));
rtc_timer_set_clock_count_value(1);
/* Set RTC mode to timer running mode */
@ -62,6 +61,9 @@ public:
virtual void get_datetime(tm &datetime) override
{
if (rtc_timer_get_mode() != RTC_TIMER_RUNNING)
return;
rtc_date_t timer_date = read_pod(rtc_.date);
rtc_time_t timer_time = read_pod(rtc_.time);
rtc_extended_t timer_extended = read_pod(rtc_.extended);
@ -69,8 +71,8 @@ public:
datetime.tm_sec = timer_time.second % 60;
datetime.tm_min = timer_time.minute % 60;
datetime.tm_hour = timer_time.hour % 24;
datetime.tm_mday = timer_date.day % 31;
datetime.tm_mon = (timer_date.month % 12) - 1;
datetime.tm_mday = (timer_date.day - 1)% 31 + 1;
datetime.tm_mon = (timer_date.month - 1) % 12;
datetime.tm_year = (timer_date.year % 100) + (timer_extended.century * 100) - 1900;
datetime.tm_wday = timer_date.week;
datetime.tm_yday = rtc_get_yday(datetime.tm_year + 1900, datetime.tm_mon + 1, datetime.tm_mday);
@ -224,6 +226,35 @@ private:
return 0;
}
rtc_timer_mode_t rtc_timer_get_mode(void)
{
rtc_register_ctrl_t register_ctrl = read_pod(rtc_.register_ctrl);
rtc_timer_mode_t timer_mode = RTC_TIMER_PAUSE;
if ((!register_ctrl.read_enable) && (!register_ctrl.write_enable))
{
/* RTC_TIMER_PAUSE */
timer_mode = RTC_TIMER_PAUSE;
}
else if ((register_ctrl.read_enable) && (!register_ctrl.write_enable))
{
/* RTC_TIMER_RUNNING */
timer_mode = RTC_TIMER_RUNNING;
}
else if ((!register_ctrl.read_enable) && (register_ctrl.write_enable))
{
/* RTC_TIMER_SETTING */
timer_mode = RTC_TIMER_SETTING;
}
else
{
/* Something is error, reset timer mode */
rtc_timer_set_mode(timer_mode);
}
return timer_mode;
}
int rtc_protect_set(int enable)
{
rtc_register_ctrl_t register_ctrl = read_pod(rtc_.register_ctrl);
@ -286,9 +317,11 @@ private:
int rtc_timer_set_clock_frequency(unsigned int frequency)
{
rtc_initial_count_t initial_count;
initial_count.count = frequency;
rtc_timer_set_mode(RTC_TIMER_SETTING);
write_pod(rtc_.initial_count, initial_count);
rtc_timer_set_mode(RTC_TIMER_RUNNING);
return 0;
}
@ -297,7 +330,9 @@ private:
rtc_current_count_t current_count;
current_count.count = count;
rtc_timer_set_mode(RTC_TIMER_SETTING);
write_pod(rtc_.current_count, current_count);
rtc_timer_set_mode(RTC_TIMER_RUNNING);
return 0;
}

View File

@ -27,6 +27,7 @@
using namespace sys;
#define SPI_TRANSMISSION_THRESHOLD 0x800UL
/* SPI Controller */
#define TMOD_MASK (3 << tmod_off_)
@ -239,30 +240,63 @@ int k_spi_driver::read(k_spi_device_driver &device, gsl::span<uint8_t> buffer)
COMMON_ENTRY;
setup_device(device);
size_t frames = buffer.size() / device.buffer_width_;
uintptr_t dma_read = dma_open_free();
dma_set_request_source(dma_read, dma_req_);
uint8_t *ori_buffer = buffer.data();
uint32_t i = 0;
size_t rx_buffer_len = buffer.size();
size_t rx_frames = rx_buffer_len / device.buffer_width_;
auto buffer_read = buffer.data();
set_bit_mask(&spi_.ctrlr0, TMOD_MASK, TMOD_VALUE(2));
spi_.ctrlr1 = frames - 1;
spi_.dmacr = 0x1;
spi_.ctrlr1 = rx_frames - 1;
spi_.ssienr = 0x01;
if(device.frame_format_ == SPI_FF_STANDARD)
spi_.dr[0] = 0xFF;
SemaphoreHandle_t event_read = xSemaphoreCreateBinary();
if (device.frame_format_ == SPI_FF_STANDARD)
spi_.dr[0] = 0xFFFFFFFF;
dma_transmit_async(dma_read, &spi_.dr[0], ori_buffer, 0, 1, device.buffer_width_, frames, 1, event_read);
if (rx_frames < SPI_TRANSMISSION_THRESHOLD)
{
size_t index, fifo_len;
while (rx_buffer_len)
{
const uint8_t *buffer_it = buffer.data();
write_inst_addr(spi_.dr, &buffer_it, device.inst_width_);
write_inst_addr(spi_.dr, &buffer_it, device.addr_width_);
spi_.ser = device.chip_select_mask_;
const uint8_t *buffer_it = buffer.data();
write_inst_addr(spi_.dr, &buffer_it, device.inst_width_);
write_inst_addr(spi_.dr, &buffer_it, device.addr_width_);
spi_.ser = device.chip_select_mask_;
configASSERT(xSemaphoreTake(event_read, portMAX_DELAY) == pdTRUE);
dma_close(dma_read);
vSemaphoreDelete(event_read);
fifo_len = spi_.rxflr;
fifo_len = fifo_len < rx_buffer_len ? fifo_len : rx_buffer_len;
switch (device.buffer_width_)
{
case 4:
fifo_len = fifo_len / 4 * 4;
for (index = 0; index < fifo_len / 4; index++)
((uint32_t *)buffer_read)[i++] = spi_.dr[0];
break;
case 2:
fifo_len = fifo_len / 2 * 2;
for (index = 0; index < fifo_len / 2; index++)
((uint16_t *)buffer_read)[i++] = (uint16_t)spi_.dr[0];
break;
default:
for (index = 0; index < fifo_len; index++)
buffer_read[i++] = (uint8_t)spi_.dr[0];
break;
}
rx_buffer_len -= fifo_len;
}
}
else
{
uintptr_t dma_read = dma_open_free();
dma_set_request_source(dma_read, dma_req_);
spi_.dmacr = 0x1;
SemaphoreHandle_t event_read = xSemaphoreCreateBinary();
dma_transmit_async(dma_read, &spi_.dr[0], buffer_read, 0, 1, device.buffer_width_, rx_frames, 1, event_read);
const uint8_t *buffer_it = buffer.data();
write_inst_addr(spi_.dr, &buffer_it, device.inst_width_);
write_inst_addr(spi_.dr, &buffer_it, device.addr_width_);
spi_.ser = device.chip_select_mask_;
configASSERT(xSemaphoreTake(event_read, portMAX_DELAY) == pdTRUE);
dma_close(dma_read);
vSemaphoreDelete(event_read);
}
spi_.ser = 0x00;
spi_.ssienr = 0x00;
@ -275,26 +309,58 @@ int k_spi_driver::write(k_spi_device_driver &device, gsl::span<const uint8_t> bu
COMMON_ENTRY;
setup_device(device);
uintptr_t dma_write = dma_open_free();
dma_set_request_source(dma_write, dma_req_ + 1);
uint32_t i = 0;
size_t tx_buffer_len = buffer.size() - (device.inst_width_ + device.addr_width_);
size_t tx_frames = tx_buffer_len / device.buffer_width_;
auto buffer_write = buffer.data();
set_bit_mask(&spi_.ctrlr0, TMOD_MASK, TMOD_VALUE(1));
spi_.dmacr = 0x2;
spi_.ssienr = 0x01;
auto buffer_it = buffer.data();
write_inst_addr(spi_.dr, &buffer_it, device.inst_width_);
write_inst_addr(spi_.dr, &buffer_it, device.addr_width_);
size_t frames = (buffer.size() - (device.inst_width_ + device.addr_width_)) / device.buffer_width_;
SemaphoreHandle_t event_write = xSemaphoreCreateBinary();
dma_transmit_async(dma_write, buffer_it, &spi_.dr[0], 1, 0, device.buffer_width_, frames, 4, event_write);
spi_.ser = device.chip_select_mask_;
configASSERT(xSemaphoreTake(event_write, portMAX_DELAY) == pdTRUE);
dma_close(dma_write);
vSemaphoreDelete(event_write);
if (tx_frames < SPI_TRANSMISSION_THRESHOLD)
{
size_t index, fifo_len;
spi_.ssienr = 0x01;
write_inst_addr(spi_.dr, &buffer_write, device.inst_width_);
write_inst_addr(spi_.dr, &buffer_write, device.addr_width_);
spi_.ser = device.chip_select_mask_;
while (tx_buffer_len)
{
fifo_len = 32 - spi_.txflr;
fifo_len = fifo_len < tx_buffer_len ? fifo_len : tx_buffer_len;
switch (device.buffer_width_)
{
case 4:
fifo_len = fifo_len / 4 * 4;
for (index = 0; index < fifo_len / 4; index++)
spi_.dr[0] = ((uint32_t *)buffer_write)[i++];
break;
case 2:
fifo_len = fifo_len / 2 * 2;
for (index = 0; index < fifo_len / 2; index++)
spi_.dr[0] = ((uint16_t *)buffer_write)[i++];
break;
default:
for (index = 0; index < fifo_len; index++)
spi_.dr[0] = buffer_write[i++];
break;
}
tx_buffer_len -= fifo_len;
}
}
else
{
uintptr_t dma_write = dma_open_free();
dma_set_request_source(dma_write, dma_req_ + 1);
spi_.dmacr = 0x2;
spi_.ssienr = 0x01;
write_inst_addr(spi_.dr, &buffer_write, device.inst_width_);
write_inst_addr(spi_.dr, &buffer_write, device.addr_width_);
SemaphoreHandle_t event_write = xSemaphoreCreateBinary();
dma_transmit_async(dma_write, buffer_write, &spi_.dr[0], 1, 0, device.buffer_width_, tx_frames, 4, event_write);
spi_.ser = device.chip_select_mask_;
configASSERT(xSemaphoreTake(event_write, portMAX_DELAY) == pdTRUE);
dma_close(dma_write);
vSemaphoreDelete(event_write);
}
while ((spi_.sr & 0x05) != 0x04)
;
spi_.ser = 0x00;
@ -322,32 +388,91 @@ int k_spi_driver::transfer_sequential(k_spi_device_driver &device, gsl::span<con
int k_spi_driver::read_write(k_spi_device_driver &device, gsl::span<const uint8_t> write_buffer, gsl::span<uint8_t> read_buffer)
{
configASSERT(device.frame_format_ == SPI_FF_STANDARD);
size_t tx_buffer_len = write_buffer.size();
size_t rx_buffer_len = read_buffer.size();
size_t tx_frames = tx_buffer_len / device.buffer_width_;
size_t rx_frames = rx_buffer_len / device.buffer_width_;
auto buffer_read = read_buffer.data();
auto buffer_write = write_buffer.data();
uint32_t i = 0;
uintptr_t dma_write = dma_open_free();
uintptr_t dma_read = dma_open_free();
if (rx_frames < SPI_TRANSMISSION_THRESHOLD)
{
size_t index, fifo_len;
spi_.ctrlr1 = rx_frames - 1;
spi_.ssienr = 0x01;
while (tx_buffer_len)
{
fifo_len = 32 - spi_.txflr;
fifo_len = fifo_len < tx_buffer_len ? fifo_len : tx_buffer_len;
switch (device.buffer_width_)
{
case 4:
fifo_len = fifo_len / 4 * 4;
for (index = 0; index < fifo_len / 4; index++)
spi_.dr[0] = ((uint32_t *)buffer_write)[i++];
break;
case 2:
fifo_len = fifo_len / 2 * 2;
for (index = 0; index < fifo_len / 2; index++)
spi_.dr[0] = ((uint16_t *)buffer_write)[i++];
break;
default:
for (index = 0; index < fifo_len; index++)
spi_.dr[0] = buffer_write[i++];
break;
}
spi_.ser = device.chip_select_mask_;
tx_buffer_len -= fifo_len;
}
i = 0;
while (rx_buffer_len)
{
fifo_len = spi_.rxflr;
fifo_len = fifo_len < rx_buffer_len ? fifo_len : rx_buffer_len;
switch (device.buffer_width_)
{
case 4:
fifo_len = fifo_len / 4 * 4;
for (index = 0; index < fifo_len / 4; index++)
((uint32_t *)buffer_read)[i++] = spi_.dr[0];
break;
case 2:
fifo_len = fifo_len / 2 * 2;
for (index = 0; index < fifo_len / 2; index++)
((uint16_t *)buffer_read)[i++] = (uint16_t)spi_.dr[0];
break;
default:
for (index = 0; index < fifo_len; index++)
buffer_read[i++] = (uint8_t)spi_.dr[0];
break;
}
spi_.ser = device.chip_select_mask_;
rx_buffer_len -= fifo_len;
}
}
else
{
uintptr_t dma_write = dma_open_free();
uintptr_t dma_read = dma_open_free();
dma_set_request_source(dma_write, dma_req_ + 1);
dma_set_request_source(dma_read, dma_req_);
dma_set_request_source(dma_write, dma_req_ + 1);
dma_set_request_source(dma_read, dma_req_);
spi_.ctrlr1 = rx_frames - 1;
spi_.dmacr = 0x3;
spi_.ssienr = 0x01;
spi_.ser = device.chip_select_mask_;
SemaphoreHandle_t event_read = xSemaphoreCreateBinary(), event_write = xSemaphoreCreateBinary();
dma_transmit_async(dma_read, &spi_.dr[0], buffer_read, 0, 1, device.buffer_width_, rx_frames, 1, event_read);
dma_transmit_async(dma_write, buffer_write, &spi_.dr[0], 1, 0, device.buffer_width_, tx_frames, 4, event_write);
size_t tx_frames = write_buffer.size() / device.buffer_width_;
size_t rx_frames = read_buffer.size() / device.buffer_width_;
spi_.ctrlr1 = rx_frames - 1;
spi_.dmacr = 0x3;
spi_.ssienr = 0x01;
spi_.ser = device.chip_select_mask_;
SemaphoreHandle_t event_read = xSemaphoreCreateBinary(), event_write = xSemaphoreCreateBinary();
dma_transmit_async(dma_read, &spi_.dr[0], read_buffer.data(), 0, 1, device.buffer_width_, rx_frames, 1, event_read);
dma_transmit_async(dma_write, write_buffer.data(), &spi_.dr[0], 1, 0, device.buffer_width_, tx_frames, 4, event_write);
configASSERT(xSemaphoreTake(event_read, portMAX_DELAY) == pdTRUE && xSemaphoreTake(event_write, portMAX_DELAY) == pdTRUE);
dma_close(dma_write);
dma_close(dma_read);
vSemaphoreDelete(event_read);
vSemaphoreDelete(event_write);
configASSERT(xSemaphoreTake(event_read, portMAX_DELAY) == pdTRUE && xSemaphoreTake(event_write, portMAX_DELAY) == pdTRUE);
dma_close(dma_write);
dma_close(dma_read);
vSemaphoreDelete(event_read);
vSemaphoreDelete(event_write);
}
spi_.ser = 0x00;
spi_.ssienr = 0x00;
spi_.dmacr = 0x00;

View File

@ -26,16 +26,19 @@
using namespace sys;
static void *irq_context[3][4];
class k_timer_driver : public timer_driver, public static_object, public exclusive_object_access
{
public:
k_timer_driver(uintptr_t base_addr, sysctl_clock_t clock, plic_irq_t irq, uint32_t channel)
: timer_(*reinterpret_cast<volatile kendryte_timer_t *>(base_addr)), clock_(clock), irq_(irq), channel_(channel)
k_timer_driver(uintptr_t base_addr, sysctl_clock_t clock, plic_irq_t irq, uint32_t num, uint32_t channel)
: timer_(*reinterpret_cast<volatile kendryte_timer_t *>(base_addr)), clock_(clock), irq_(irq), num_(num), channel_(channel)
{
}
virtual void install() override
{
irq_context[num_][channel_] = this;
if (channel_ == 0)
{
sysctl_clock_enable(clock_);
@ -45,15 +48,26 @@ public:
for (i = 0; i < 4; i++)
timer_.channel[i].control = TIMER_CR_INTERRUPT_MASK;
pic_set_irq_handler(irq_, timer_isr, this);
pic_set_irq_handler(irq_ + 1, timer_isr, this);
pic_set_irq_handler(irq_, timer_isr, irq_context[num_]);
pic_set_irq_handler(irq_ + 1, timer_isr, irq_context[num_]);
pic_set_irq_priority(irq_, 1);
pic_set_irq_priority(irq_ + 1, 1);
pic_set_irq_enable(irq_, 1);
pic_set_irq_enable(irq_ + 1, 1);
sysctl_clock_disable(clock_);
}
}
virtual void on_first_open() override
{
sysctl_clock_enable(clock_);
}
virtual void on_last_close() override
{
sysctl_clock_disable(clock_);
}
virtual size_t set_interval(size_t nanoseconds) override
{
uint32_t clk_freq = sysctl_clock_get_freq(clock_);
@ -81,7 +95,8 @@ public:
private:
static void timer_isr(void *userdata)
{
auto &driver = *reinterpret_cast<k_timer_driver *>(userdata);
k_timer_driver **context = reinterpret_cast<k_timer_driver **>(userdata);
auto &driver = *context[0];
auto &timer = driver.timer_;
uint32_t channel = timer.intr_stat;
@ -90,8 +105,11 @@ private:
{
if (channel & 1)
{
if (driver.on_tick_)
driver.on_tick_(driver.ontick_data_);
auto &driver_ch = *context[i];
if (driver_ch.on_tick_)
{
driver_ch.on_tick_(driver_ch.ontick_data_);
}
}
channel >>= 1;
@ -104,6 +122,7 @@ private:
volatile kendryte_timer_t &timer_;
sysctl_clock_t clock_;
plic_irq_t irq_;
size_t num_;
size_t channel_;
timer_on_tick_t on_tick_;
@ -112,10 +131,10 @@ private:
/* clang-format off */
#define DEFINE_TIMER_DATA(i) \
{ TIMER##i##_BASE_ADDR, SYSCTL_CLOCK_TIMER##i, IRQN_TIMER##i##A_INTERRUPT, 0 }, \
{ TIMER##i##_BASE_ADDR, SYSCTL_CLOCK_TIMER##i, IRQN_TIMER##i##A_INTERRUPT, 1 }, \
{ TIMER##i##_BASE_ADDR, SYSCTL_CLOCK_TIMER##i, IRQN_TIMER##i##A_INTERRUPT, 2 }, \
{ TIMER##i##_BASE_ADDR, SYSCTL_CLOCK_TIMER##i, IRQN_TIMER##i##A_INTERRUPT, 3 }
{ TIMER##i##_BASE_ADDR, SYSCTL_CLOCK_TIMER##i, IRQN_TIMER##i##A_INTERRUPT, i, 0 }, \
{ TIMER##i##_BASE_ADDR, SYSCTL_CLOCK_TIMER##i, IRQN_TIMER##i##A_INTERRUPT, i, 1 }, \
{ TIMER##i##_BASE_ADDR, SYSCTL_CLOCK_TIMER##i, IRQN_TIMER##i##A_INTERRUPT, i, 2 }, \
{ TIMER##i##_BASE_ADDR, SYSCTL_CLOCK_TIMER##i, IRQN_TIMER##i##A_INTERRUPT, i, 3 }
/* clang format on */
#define INIT_TIMER_DRIVER(i) { { &dev_driver[i], timer_install, timer_open, timer_close }, timer_set_interval, timer_set_on_tick, timer_set_enable }

View File

@ -30,8 +30,6 @@ extern uint8_t __bss_start[];
extern uint8_t __bss_end[];
extern uint8_t _tls_data[];
extern __thread uint8_t _tdata_begin[], _tdata_end[], _tbss_end[];
extern int main(int argc, char* argv[]);
extern void __libc_init_array(void);
extern void __libc_fini_array(void);
@ -43,19 +41,6 @@ static void setup_clocks()
sysctl_pll_set_freq(SYSCTL_PLL2, PLL2_OUTPUT_FREQ);
}
static void init_tls(void)
{
register void* thread_pointer asm("tp");
size_t tdata_size = _tdata_end - _tdata_begin;
memcpy(thread_pointer, _tls_data, tdata_size);
size_t tbss_size = _tbss_end - _tdata_end;
memset(thread_pointer + tdata_size, 0, tbss_size);
}
static void init_bss(void)
{
memset(__bss_start, 0, __bss_end - __bss_start);
@ -63,9 +48,6 @@ static void init_bss(void)
void _init_bsp(int core_id, int number_of_cores)
{
/* Initialize thread local data */
init_tls();
if (core_id == 0)
{
/* Initialize bss data to 0 */

View File

@ -12,6 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "syscalls/syscalls.h"
#include <atomic.h>
#include <clint.h>
#include <devices.h>
@ -28,11 +29,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/unistd.h>
#include <sys/file.h>
#include "syscalls/syscalls.h"
#include <sysctl.h>
#include <syslog.h>
#include <uarths.h>
@ -248,7 +248,14 @@ static int sys_close(int file)
* Otherwise, -1 shall be returned and errno set to indicate
* the error.
*/
return io_close(file);
if (STDOUT_FILENO == file || STDERR_FILENO == file)
{
return 0;
}
else
{
return io_close(file);
}
}
static int sys_gettimeofday(struct timeval *tp, void *tzp)

View File

@ -52,11 +52,14 @@ int sys_open(const char *name, int flags, int mode)
return -1;
}
off_t sys_lseek(int fildes, off_t offset, int whence)
off_t sys_lseek(int fd, off_t offset, int whence)
{
if (STDOUT_FILENO == fd || STDERR_FILENO == fd)
return -1;
try
{
auto &obj = system_handle_to_object(fildes);
auto &obj = system_handle_to_object(fd);
if (auto f = obj.as<filesystem_file>())
{
if (whence == SEEK_SET)
@ -87,6 +90,9 @@ off_t sys_lseek(int fildes, off_t offset, int whence)
int sys_fstat(int fd, struct kernel_stat *buf)
{
if (STDOUT_FILENO == fd || STDERR_FILENO == fd)
return 0;
try
{
memset(buf, 0, sizeof(struct kernel_stat));

View File

@ -0,0 +1,45 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DRIVERS_DM9051_H
#define _DRIVERS_DM9051_H
#include <osdefs.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Install DM9051 driver
*
* @param[in] spi_handle The SPI controller handle
* @param[in] spi_cs_mask The SPI chip select
* @param[in] int_gpio_handle The GPIO controller handle for dm9051 interrupt
* @param[in] int_gpio_pin The GPIO pin for dm9051 interrupt
* @param[in] mac_address The MAC address for network
*
* @return result
* - 0 Fail
* - other The network adapter handle
*/
handle_t dm9051_driver_install(handle_t spi_handle, uint32_t spi_cs_mask, handle_t int_gpio_handle, uint32_t int_gpio_pin, const mac_address_t *mac_address);
#ifdef __cplusplus
}
#endif
#endif /* _DRIVERS_DM9051_H */

View File

@ -0,0 +1,610 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <FreeRTOS.h>
#include <atomic.h>
#include <semphr.h>
#include <hal.h>
#include <kernel/driver_impl.hpp>
#include <stdlib.h>
#include <string.h>
#include <printf.h>
#include <sys/unistd.h>
#include "network/dm9051.h"
#include "task.h"
using namespace sys;
/* Private typedef -----------------------------------------------------------------------------------------*/
enum DM9051_PHY_mode
{
DM9051_10MHD = 0,
DM9051_100MHD = 1,
DM9051_10MFD = 4,
DM9051_100MFD = 5,
DM9051_10M = 6,
DM9051_AUTO = 8,
DM9051_1M_HPNA = 0x10
};
enum DM9051_TYPE
{
TYPE_DM9051E,
TYPE_DM9051A,
TYPE_DM9051B,
TYPE_DM9051
};
/* Private constants ---------------------------------------------------------------------------------------*/
#define DM9051_PHY (0x40) /* PHY address 0x01 */
/* Exported typedef ----------------------------------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------------------------------------*/
#define DM9051_ID (0x90510A46) /* DM9051A ID */
#define DM9051_PKT_MAX (1536) /* Received packet max size */
#define DM9051_PKT_RDY (0x01) /* Packet ready to receive */
#define DM9051_NCR (0x00)
#define DM9051_NSR (0x01)
#define DM9051_TCR (0x02)
#define DM9051_TSR1 (0x03)
#define DM9051_TSR2 (0x04)
#define DM9051_RCR (0x05)
#define DM9051_RSR (0x06)
#define DM9051_ROCR (0x07)
#define DM9051_BPTR (0x08)
#define DM9051_FCTR (0x09)
#define DM9051_FCR (0x0A)
#define DM9051_EPCR (0x0B)
#define DM9051_EPAR (0x0C)
#define DM9051_EPDRL (0x0D)
#define DM9051_EPDRH (0x0E)
#define DM9051_WCR (0x0F)
#define DM9051_PAR (0x10)
#define DM9051_MAR (0x16)
#define DM9051_GPCR (0x1e)
#define DM9051_GPR (0x1f)
#define DM9051_TRPAL (0x22)
#define DM9051_TRPAH (0x23)
#define DM9051_RWPAL (0x24)
#define DM9051_RWPAH (0x25)
#define DM9051_VIDL (0x28)
#define DM9051_VIDH (0x29)
#define DM9051_PIDL (0x2A)
#define DM9051_PIDH (0x2B)
#define DM9051_CHIPR (0x2C)
#define DM9051_TCR2 (0x2D)
#define DM9051_OTCR (0x2E)
#define DM9051_SMCR (0x2F)
#define DM9051_ETCR (0x30) /* early transmit control/status register */
#define DM9051_CSCR (0x31) /* check sum control register */
#define DM9051_RCSSR (0x32) /* receive check sum status register */
#define DM9051_PBCR (0x38)
#define DM9051_INTR (0x39)
#define DM9051_MPCR (0x55)
#define DM9051_MRCMDX (0x70)
#define DM9051_MRCMDX1 (0x71)
#define DM9051_MRCMD (0x72)
#define DM9051_MRRL (0x74)
#define DM9051_MRRH (0x75)
#define DM9051_MWCMDX (0x76)
#define DM9051_MWCMD (0x78)
#define DM9051_MWRL (0x7A)
#define DM9051_MWRH (0x7B)
#define DM9051_TXPLL (0x7C)
#define DM9051_TXPLH (0x7D)
#define DM9051_ISR (0x7E)
#define DM9051_IMR (0x7F)
#define CHIPR_DM9051A (0x19)
#define CHIPR_DM9051B (0x1B)
#define DM9051_REG_RESET (0x01)
#define DM9051_IMR_OFF (0x80)
#define DM9051_TCR2_SET (0x90) /* set one packet */
#define DM9051_RCR_SET (0x31)
#define DM9051_BPTR_SET (0x37)
#define DM9051_FCTR_SET (0x38)
#define DM9051_FCR_SET (0x28)
#define DM9051_TCR_SET (0x01)
#define NCR_EXT_PHY (1 << 7)
#define NCR_WAKEEN (1 << 6)
#define NCR_FCOL (1 << 4)
#define NCR_FDX (1 << 3)
#define NCR_LBK (3 << 1)
#define NCR_RST (1 << 0)
#define NCR_DEFAULT (0x0) /* Disable Wakeup */
#define NSR_SPEED (1 << 7)
#define NSR_LINKST (1 << 6)
#define NSR_WAKEST (1 << 5)
#define NSR_TX2END (1 << 3)
#define NSR_TX1END (1 << 2)
#define NSR_RXOV (1 << 1)
#define NSR_CLR_STATUS (NSR_WAKEST | NSR_TX2END | NSR_TX1END)
#define TCR_TJDIS (1 << 6)
#define TCR_EXCECM (1 << 5)
#define TCR_PAD_DIS2 (1 << 4)
#define TCR_CRC_DIS2 (1 << 3)
#define TCR_PAD_DIS1 (1 << 2)
#define TCR_CRC_DIS1 (1 << 1)
#define TCR_TXREQ (1 << 0) /* Start TX */
#define TCR_DEFAULT (0x0)
#define TSR_TJTO (1 << 7)
#define TSR_LC (1 << 6)
#define TSR_NC (1 << 5)
#define TSR_LCOL (1 << 4)
#define TSR_COL (1 << 3)
#define TSR_EC (1 << 2)
#define RCR_WTDIS (1 << 6)
#define RCR_DIS_LONG (1 << 5)
#define RCR_DIS_CRC (1 << 4)
#define RCR_ALL (1 << 3)
#define RCR_RUNT (1 << 2)
#define RCR_PRMSC (1 << 1)
#define RCR_RXEN (1 << 0)
#define RCR_DEFAULT (RCR_DIS_LONG | RCR_DIS_CRC)
#define RSR_RF (1 << 7)
#define RSR_MF (1 << 6)
#define RSR_LCS (1 << 5)
#define RSR_RWTO (1 << 4)
#define RSR_PLE (1 << 3)
#define RSR_AE (1 << 2)
#define RSR_CE (1 << 1)
#define RSR_FOE (1 << 0)
#define BPTR_DEFAULT (0x3f)
#define FCTR_DEAFULT (0x38)
#define FCR_DEFAULT (0xFF)
#define SMCR_DEFAULT (0x0)
#define PBCR_MAXDRIVE (0x44)
//#define FCTR_HWOT(ot) ((ot & 0xF ) << 4 )
//#define FCTR_LWOT(ot) (ot & 0xF )
#define IMR_PAR (1 << 7)
#define IMR_LNKCHGI (1 << 5)
#define IMR_UDRUN (1 << 4)
#define IMR_ROOM (1 << 3)
#define IMR_ROM (1 << 2)
#define IMR_PTM (1 << 1)
#define IMR_PRM (1 << 0)
#define IMR_FULL (IMR_PAR | IMR_LNKCHGI | IMR_UDRUN | IMR_ROOM | IMR_ROM | IMR_PTM | IMR_PRM)
#define IMR_OFF (IMR_PAR)
#define IMR_DEFAULT (IMR_PAR | IMR_PRM | IMR_PTM)
#define ISR_ROOS (1 << 3)
#define ISR_ROS (1 << 2)
#define ISR_PTS (1 << 1)
#define ISR_PRS (1 << 0)
#define ISR_CLR_STATUS (0x80 | 0x3F)
#define EPCR_REEP (1 << 5)
#define EPCR_WEP (1 << 4)
#define EPCR_EPOS (1 << 3)
#define EPCR_ERPRR (1 << 2)
#define EPCR_ERPRW (1 << 1)
#define EPCR_ERRE (1 << 0)
#define GPCR_GEP_CNTL (1 << 0)
#define SPI_WR_BURST (0xF8)
#define SPI_RD_BURST (0x72)
#define SPI_READ (0x03)
#define SPI_WRITE (0x04)
#define SPI_WRITE_BUFFER (0x05) /* Send a series of bytes from the Master to the Slave */
#define SPI_READ_BUFFER (0x06) /* Send a series of bytes from the Slave to the Master */
class dm9051_driver : public network_adapter_driver, public heap_object, public exclusive_object_access
{
public:
dm9051_driver(handle_t spi_handle, uint32_t spi_cs_mask, handle_t int_gpio_handle, uint32_t int_gpio_pin, const mac_address_t &mac_address)
: spi_driver_(system_handle_to_object(spi_handle).get_object().as<spi_driver>())
, spi_cs_mask_(spi_cs_mask)
, mac_address_(mac_address)
, int_gpio_driver_(system_handle_to_object(int_gpio_handle).get_object().as<gpio_driver>())
, int_gpio_pin_(int_gpio_pin)
{
}
virtual void install() override
{
}
virtual void on_first_open() override
{
auto spi = make_accessor(spi_driver_);
spi_dev_ = make_accessor(spi->get_device(SPI_MODE_0, SPI_FF_STANDARD, spi_cs_mask_, 8));
spi_dev_->set_clock_rate(20000000);
int_gpio_ = make_accessor(int_gpio_driver_);
int_gpio_->set_drive_mode(int_gpio_pin_, GPIO_DM_INPUT);
int_gpio_->set_pin_edge(int_gpio_pin_, GPIO_PE_FALLING);
int_gpio_->set_on_changed(int_gpio_pin_, (gpio_on_changed_t)isr_handle, this);
uint32_t value = 0;
/* Read DM9051 PID / VID, Check MCU SPI Setting correct */
value |= (uint32_t)read(DM9051_VIDL);
value |= (uint32_t)read(DM9051_VIDH) << 8;
value |= (uint32_t)read(DM9051_PIDL) << 16;
value |= (uint32_t)read(DM9051_PIDH) << 24;
configASSERT(value == 0x90510a46);
}
virtual void on_last_close() override
{
spi_dev_.reset();
}
virtual void set_handler(network_adapter_handler *handler) override
{
handler_ = handler;
}
virtual mac_address_t get_mac_address() override
{
return mac_address_;
}
virtual bool is_packet_available() override
{
uint8_t rxbyte;
/* Check packet ready or not */
rxbyte = read(DM9051_MRCMDX);
rxbyte = read(DM9051_MRCMDX);
if ((rxbyte != 1) && (rxbyte != 0))
{
/* Reset RX FIFO pointer */
write(DM9051_RCR, RCR_DEFAULT); //RX disable
write(DM9051_MPCR, 0x01); //Reset RX FIFO pointer
usleep(2e3);
write(DM9051_RCR, (RCR_DEFAULT | RCR_RXEN)); //RX Enable
return false;
}
return (rxbyte & 0b1) == 0b1;
}
virtual void reset(SemaphoreHandle_t interrupt_event) override
{
interrupt_event_ = interrupt_event;
write(DM9051_NCR, DM9051_REG_RESET);
while (read(DM9051_NCR) & DM9051_REG_RESET)
;
write(DM9051_GPCR, GPCR_GEP_CNTL);
write(DM9051_GPR, 0x00); //Power on PHY
usleep(1e5);
set_phy_mode(DM9051_AUTO);
set_mac_address(mac_address_);
/* set multicast address */
for (size_t i = 0; i < 8; i++)
{ /* Clear Multicast set */
/* Set Broadcast */
write(DM9051_MAR + i, (7 == i) ? 0x80 : 0x00);
}
/************************************************
*** Activate DM9051 and Setup DM9051 Registers **
*************************************************/
/* Clear DM9051 Set and Disable Wakeup function */
write(DM9051_NCR, NCR_DEFAULT);
/* Clear TCR Register set */
write(DM9051_TCR, TCR_DEFAULT);
/* Discard long Packet and CRC error Packet */
write(DM9051_RCR, RCR_DEFAULT);
/* Set 1.15 ms Jam Pattern Timer */
write(DM9051_BPTR, BPTR_DEFAULT);
/* Open / Close Flow Control */
//DM9051_Write_Reg(DM9051_FCTR, FCTR_DEAFULT);
write(DM9051_FCTR, 0x3A);
write(DM9051_FCR, FCR_DEFAULT);
/* Set Memory Conttrol Register£¬TX = 3K£¬RX = 13K */
write(DM9051_SMCR, SMCR_DEFAULT);
/* Set Send one or two command Packet*/
write(DM9051_TCR2, DM9051_TCR2_SET);
//DM9051_Write_Reg(DM9051_TCR2, 0x80);
write(DM9051_INTR, 0x1);
/* Clear status */
write(DM9051_NSR, NSR_CLR_STATUS);
write(DM9051_ISR, ISR_CLR_STATUS);
write(DM9051_IMR, IMR_PAR | IMR_PRM);
write(DM9051_RCR, (RCR_DEFAULT | RCR_RXEN)); /* Enable RX */
}
virtual void begin_send(size_t length) override
{
configASSERT(length <= std::numeric_limits<uint16_t>::max());
while (read(DM9051_TCR) & DM9051_TCR_SET)
;
write(DM9051_TXPLL, length & 0xff);
write(DM9051_TXPLH, (length >> 8) & 0xff);
}
virtual void send(gsl::span<const uint8_t> buffer) override
{
write_memory(buffer);
}
virtual void end_send() override
{
/* Issue TX polling command */
write(DM9051_TCR, TCR_TXREQ);
}
virtual size_t begin_receive() override
{
uint16_t len = 0;
uint16_t status;
read(DM9051_MRCMDX); // dummy read
uint8_t header[4];
read_memory({ header });
status = header[0] | (header[1] << 8);
len = header[2] | (header[3] << 8);
if (len > DM9051_PKT_MAX)
{ // read-error
len = 0; // read-error (keep no change to rx fifo)
}
if ((status & 0xbf00) || (len < 0x40) || (len > DM9051_PKT_MAX))
{
if (status & 0x8000)
{
printf("rx length error \r\n");
}
if (len > DM9051_PKT_MAX)
{
printf("rx length too big \r\n");
}
}
return len;
}
virtual void receive(gsl::span<uint8_t> buffer) override
{
read_memory(buffer);
}
virtual void end_receive() override
{
}
virtual void disable_rx() override
{
uint8_t rxchk;
/* Disable DM9051a interrupt */
write(DM9051_IMR, IMR_PAR);
/* Must rx packet available */
rxchk = read(DM9051_ISR);
if (!(rxchk & ISR_PRS))
{
/* restore receive interrupt */
//.DM9051_device.imr_all |= IMR_PRM;
//.DM9051_Write_Reg(DM9051_IMR, DM9051_device.imr_all);
//.return false;
}
/* clear the rx interrupt-event */
write(DM9051_ISR, rxchk);
}
virtual void enable_rx() override
{
/* restore receive interrupt */
write(DM9051_IMR, IMR_PAR | IMR_PRM);
}
virtual bool interface_check() override
{
uint8_t link_status = 0;
link_status = read(DM9051_NSR);
link_status = read(DM9051_NSR);
if ((link_status)&0x40)
{
return true;
}
else
{
return false;
}
}
private:
static void isr_handle(uint32_t pin, void *userdata)
{
auto &driver = *reinterpret_cast<dm9051_driver *>(userdata);
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(driver.interrupt_event_, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken)
{
portYIELD();
}
}
uint8_t read(uint8_t addr)
{
const uint8_t to_write[1] = { addr };
uint8_t to_read[1];
spi_dev_->transfer_sequential({ to_write }, { to_read });
return to_read[0];
}
void write(uint8_t addr, uint8_t data)
{
const uint8_t to_write[] = { static_cast<uint8_t>(addr | 0x80), data };
spi_dev_->write({ to_write });
}
void write_phy(uint8_t addr, uint16_t data)
{
/* Fill the phyxcer register into REG_0C */
write(DM9051_EPAR, DM9051_PHY | addr);
/* Fill the written data into REG_0D & REG_0E */
write(DM9051_EPDRL, (data & 0xff));
write(DM9051_EPDRH, ((data >> 8) & 0xff));
/* Issue phyxcer write command */
write(DM9051_EPCR, 0xa);
/* Wait write complete */
//_DM9051_Delay_ms(500);
while (read(DM9051_EPCR) & 0x1)
{
usleep(1000);
}; //Wait complete
/* Clear phyxcer write command */
write(DM9051_EPCR, 0x0);
}
uint16_t read_phy(uint8_t addr)
{
/* Fill the phyxcer register into REG_0C */
write(DM9051_EPAR, DM9051_PHY | addr);
/* Issue phyxcer read command */
write(DM9051_EPCR, 0xc);
/* Wait read complete */
//_DM9051_Delay_ms(100);
while (read(DM9051_EPCR) & 0x1)
{
usleep(1000);
}; //Wait complete
/* Clear phyxcer read command */
write(DM9051_EPCR, 0x0);
return (read(DM9051_EPDRH) << 8) | read(DM9051_EPDRL);
}
void read_memory(gsl::span<uint8_t> buffer)
{
const uint8_t to_write[1] = { SPI_RD_BURST };
spi_dev_->transfer_sequential({ to_write }, buffer);
}
void write_memory(gsl::span<const uint8_t> buffer)
{
auto new_buffer = std::make_unique<uint8_t[]>(buffer.size_bytes() + 1);
std::copy(buffer.begin(), buffer.end(), new_buffer.get() + 1);
new_buffer[0] = SPI_WR_BURST;
spi_dev_->write({ new_buffer.get(), buffer.size_bytes() + 1 });
}
void set_mac_address(const mac_address_t &mac_addr)
{
write(DM9051_PAR + 0, mac_addr.data[0]);
write(DM9051_PAR + 1, mac_addr.data[1]);
write(DM9051_PAR + 2, mac_addr.data[2]);
write(DM9051_PAR + 3, mac_addr.data[3]);
write(DM9051_PAR + 4, mac_addr.data[4]);
write(DM9051_PAR + 5, mac_addr.data[5]);
configASSERT(read(DM9051_PAR) == mac_addr.data[0]);
}
void set_phy_mode(uint32_t media_mode)
{
uint16_t phy_reg4 = 0x01e1, phy_reg0 = 0x1000;
if (!(media_mode & DM9051_AUTO))
{
switch (media_mode)
{
case DM9051_10MHD:
phy_reg4 = 0x21;
phy_reg0 = 0x0000;
break;
case DM9051_10MFD:
phy_reg4 = 0x41;
phy_reg0 = 0x1100;
break;
case DM9051_100MHD:
phy_reg4 = 0x81;
phy_reg0 = 0x2000;
break;
case DM9051_100MFD:
phy_reg4 = 0x101;
phy_reg0 = 0x3100;
break;
case DM9051_10M:
phy_reg4 = 0x61;
phy_reg0 = 0x1200;
break;
}
/* Set PHY media mode */
write_phy(4, phy_reg4);
/* Write rphy_reg0 to Tmp */
write_phy(0, phy_reg0);
usleep(10000);
}
}
private:
object_ptr<spi_driver> spi_driver_;
uint32_t spi_cs_mask_;
mac_address_t mac_address_;
network_adapter_handler *handler_;
object_ptr<gpio_driver> int_gpio_driver_;
uint32_t int_gpio_pin_;
object_accessor<gpio_driver> int_gpio_;
object_accessor<spi_device_driver> spi_dev_;
SemaphoreHandle_t interrupt_event_;
};
handle_t dm9051_driver_install(handle_t spi_handle, uint32_t spi_cs_mask, handle_t int_gpio_handle, uint32_t int_gpio_pin, const mac_address_t *mac_address)
{
try
{
configASSERT(mac_address);
auto driver = make_object<dm9051_driver>(spi_handle, spi_cs_mask, int_gpio_handle, int_gpio_pin, * mac_address);
driver->install();
return system_alloc_handle(make_accessor(driver));
}
catch (...)
{
return NULL_HANDLE;
}
}

View File

@ -19,6 +19,6 @@ SET_SOURCE_FILES_PROPERTIES(${ASSEMBLY_FILES} PROPERTIES COMPILE_FLAGS "-x assem
ADD_LIBRARY(freertos STATIC ${LIB_SRC})
SET_TARGET_PROPERTIES(freertos PROPERTIES LINKER_LANGUAGE C)
TARGET_LINK_LIBRARIES(freertos PRIVATE hal PRIVATE fatfs)
TARGET_LINK_LIBRARIES(freertos PRIVATE hal PRIVATE fatfs PRIVATE lwipcore)
TARGET_INCLUDE_DIRECTORIES(freertos PUBLIC ${LIB_INC})

View File

@ -72,7 +72,14 @@
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 0
#define configQUEUE_REGISTRY_SIZE 8
#define configCHECK_FOR_STACK_OVERFLOW 0
/* TLS */
enum
{
PTHREAD_TLS_INDEX = 0
};
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1
/* mutex */
#define configUSE_MUTEXES 1
@ -87,13 +94,12 @@
/* memory */
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 1024 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 1024 * 1024 ) )
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_APPLICATION_TASK_TAG 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_TICKLESS_IDLE 1
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
@ -109,7 +115,7 @@
/* Main task */
#define configMAIN_TASK_PRIORITY 1
#define configMAIN_TASK_STACK_SIZE 4096
#define configMAIN_TASK_STACK_SIZE (4096 * 2)
/* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
@ -122,6 +128,11 @@
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
/* Diagnostics */
#define configCHECK_FOR_STACK_OVERFLOW 1
/* configASSERT behaviour */
extern void vPortFatal(const char* file, int line, const char* message);
/* Normal assert() semantics without relying on the provision of an assert.h header file. */

View File

@ -25,6 +25,7 @@ static volatile UBaseType_t s_core_sync_events[portNUM_PROCESSORS] = { 0 };
static volatile TaskHandle_t s_pending_to_add_tasks[portNUM_PROCESSORS] = { 0 };
static volatile UBaseType_t s_core_awake[portNUM_PROCESSORS] = { 1, 0 };
static volatile UBaseType_t s_core_sync_in_progress[portNUM_PROCESSORS] = { 0 };
extern UBaseType_t *volatile pxCurrentTCB[portNUM_PROCESSORS];
void handle_irq_m_soft(uintptr_t cause, uintptr_t epc)
{
@ -54,12 +55,18 @@ void handle_irq_m_soft(uintptr_t cause, uintptr_t epc)
void handle_irq_m_timer(uintptr_t cause, uintptr_t epc)
{
prvSetNextTimerInterrupt();
/* Increment the RTOS tick. */
if (xTaskIncrementTick() != pdFALSE)
if (pxCurrentTCB[uxPortGetProcessorId()])
{
core_sync_request_context_switch(uxPortGetProcessorId());
prvSetNextTimerInterrupt();
/* Increment the RTOS tick. */
if (xTaskIncrementTick() != pdFALSE)
{
core_sync_request_context_switch(uxPortGetProcessorId());
}
}
else
{
clear_csr(mie, MIP_MTIP);
}
}

View File

@ -15,8 +15,6 @@
#ifndef _FREERTOS_FILESYSTEM_H
#define _FREERTOS_FILESYSTEM_H
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "osdefs.h"

View File

@ -58,6 +58,7 @@ namespace sys
{
MAKE_ENUM_CLASS_BITMASK_TYPE(file_access_t);
MAKE_ENUM_CLASS_BITMASK_TYPE(file_mode_t);
MAKE_ENUM_CLASS_BITMASK_TYPE(socket_message_flag_t);
class object_access : public virtual object
{
@ -384,6 +385,46 @@ public:
virtual void flush() = 0;
};
class network_adapter_handler
{
public:
virtual void notify_input() = 0;
};
class network_adapter_driver : public driver
{
public:
virtual void set_handler(network_adapter_handler *handler) = 0;
virtual mac_address_t get_mac_address() = 0;
virtual void disable_rx(void) = 0;
virtual void enable_rx(void) = 0;
virtual bool interface_check() = 0;
virtual bool is_packet_available() = 0;
virtual void reset(SemaphoreHandle_t interrupt_event) = 0;
virtual void begin_send(size_t length) = 0;
virtual void send(gsl::span<const uint8_t> buffer) = 0;
virtual void end_send() = 0;
virtual size_t begin_receive() = 0;
virtual void receive(gsl::span<uint8_t> buffer) = 0;
virtual void end_receive() = 0;
};
class network_socket : public virtual object_access
{
public:
virtual object_accessor<network_socket> accept(socket_address_t *remote_address) = 0;
virtual void bind(const socket_address_t &address) = 0;
virtual void connect(const socket_address_t &address) = 0;
virtual void listen(uint32_t backlog) = 0;
virtual void shutdown(socket_shutdown_t how) = 0;
virtual size_t send(gsl::span<const uint8_t> buffer, socket_message_flag_t flags) = 0;
virtual size_t receive(gsl::span<uint8_t> buffer, socket_message_flag_t flags) = 0;
virtual size_t send_to(gsl::span<const uint8_t> buffer, socket_message_flag_t flags, const socket_address_t &to) = 0;
virtual size_t receive_from(gsl::span<uint8_t> buffer, socket_message_flag_t flags, socket_address_t *from) = 0;
virtual size_t read(gsl::span<uint8_t> buffer) = 0;
virtual size_t write(gsl::span<const uint8_t> buffer) = 0;
};
extern driver_registry_t g_hal_drivers[];
extern driver_registry_t g_dma_drivers[];
extern driver_registry_t g_system_drivers[];

View File

@ -76,6 +76,8 @@ class semaphore_lock
{
public:
semaphore_lock(SemaphoreHandle_t semaphore) noexcept;
semaphore_lock(semaphore_lock &) = delete;
semaphore_lock &operator=(semaphore_lock &) = delete;
~semaphore_lock();
private:

View File

@ -0,0 +1,303 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _FREERTOS_NETWORK_H
#define _FREERTOS_NETWORK_H
#include "osdefs.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Initialize network
*
* @return result
* - 0 Success
* - other Fail
*/
int network_init();
/**
* @brief Add network interface
*
* @param[in] adapter_handle The network adapter handle
* @param[in] ip_address The network ip addr
* @param[in] net_mask The network mask
* @param[in] gateway The network gateway
*
* @return result
* - 0 Fail
* - other The network driver handle
*/
handle_t network_interface_add(handle_t adapter_handle, const ip_address_t *ip_address, const ip_address_t *net_mask, const ip_address_t *gateway);
/**
* @brief Enable network interface
*
* @param[in] netif_handle The network driver handle
* @param[in] enable interface up or down
*
* @return result
* - 0 Success
* - other Fail
*/
int network_interface_set_enable(handle_t netif_handle, bool enable);
/**
* @brief Set a network interface as the default network interface
*
* @param[in] netif_handle The network driver handle
*
* @return result
* - 0 Success
* - other Fail
*/
int network_interface_set_as_default(handle_t netif_handle);
/**
* @brief Change the IP address of a network interface
*
* @param[in] netif_handle The network driver handle
* @param[in] ip_address The network ip addr
* @param[in] net_mask The network mask
* @param[in] gateway The network gateway
*
* @return result
* - 0 Success
* - other Fail
*/
int network_set_addr(handle_t netif_handle, const ip_address_t *ip_address, const ip_address_t *net_mask, const ip_address_t *gateway);
/**
* @brief Get the IP address of a network interface
*
* @param[in] netif_handle The network driver handle
* @param[out] ip_address The network ip addr
* @param[out] net_mask The network mask
* @param[out] gateway The network gateway
*
* @return result
* - 0 Success
* - other Fail
*/
int network_get_addr(handle_t netif_handle, ip_address_t *ip_address, ip_address_t *net_mask, ip_address_t *gateway);
/**
* @brief Get IP address through DHCP
*
* @param[in] netif_handle The network driver handle
*
* @return result
* - DHCP_ADDRESS_ASSIGNED Success
* - other Fail
*/
dhcp_state_t network_interface_dhcp_pooling(handle_t netif_handle);
/**
* @brief Open network socket and returns a socket handle
*
* @param[in] address_family The protocol family which will be used for communication
* Currently defined family are:
* AF_INTERNETWORK IPv4 Internet protocols
* @param[in] type The socket has the indicated type, which specifies the communication semantics.
* Currently defined type are:
* SOCKET_STREAM Connect based byte streams
* SOCKET_DATAGRAM Supports datagrams
* @param[in] protocol The protocol specifies a particular protocol to be used with the socket
* Currently defined protocol are:
* PROTCL_IP For IP
*
* @return result
* - 0 Success
* - other Fail
*/
handle_t network_socket_open(address_family_t address_family, socket_type_t type, protocol_type_t protocol);
/**
* @brief Close a socket handle
*
* @param[in] socket_handle The network driver handle
*
* @return result
* - 0 Success
* - other Fail
*/
handle_t network_socket_close(handle_t socket_handle);
/**
* @brief Bind a address to a socket
*
* @param[in] socket_handle The network driver handle
* @param[in] local_address Bind a local address
*
* @return result
* - 0 Success
* - other Fail
*/
int network_socket_bind(handle_t socket_handle, const socket_address_t *local_address);
/**
* @brief Initiate a connection on a socket
*
* @param[in] socket_handle The network driver handle
* @param[in] remote_address Send to remote address
*
* @return result
* - 0 Success
* - other Fail
*/
int network_socket_connect(handle_t socket_handle, const socket_address_t *remote_address);
/**
* @brief Listen for connections on a socket
*
* @param[in] socket_handle The network driver handle
* @param[in] backlog The backlog argument defines the maximum length to which
* the queue of pending connections for sockfd may grow.
*
* @return result
* - 0 Success
* - other Fail
*/
int network_socket_listen(handle_t socket_handle, uint32_t backlog);
/**
* @brief Accept a connection on a socket
*
* @param[in] socket_handle The network driver handle
* @param[out] remote_address It is filled in with the address of the peer socket
*
* @return result
* - 0 Success
* - other Fail
*/
handle_t network_socket_accept(handle_t socket_handle, socket_address_t *remote_address);
/**
* @brief Shut down part of a full-duplex connection
*
* @param[in] socket_handle The network driver handle
* @param[in] how SOCKSHTDN_SEND :further transmissions will be disallowed.
* SOCKSHTDN_RECEIVE :further receptions will be disallowed.
* SOCKSHTDN_BOTH :further transmissions and receptions will be disallowed.
*
* @return result
* - 0 Success
* - other Fail
*/
int network_socket_shutdown(handle_t socket_handle, socket_shutdown_t how);
/**
* @brief Send a message on a socket
*
* @param[in] socket_handle The network driver handle
* @param[in] data The address of message data
* @param[in] len The message data length
* @param[in] flags The flags argument is the bitwise OR of zero or more of the following flags
*
* @return result
* - 0 Success
* - other Fail
*/
int network_socket_send(handle_t socket_handle, const uint8_t *data, size_t len, socket_message_flag_t flags);
/**
* @brief Receive a message from a socket
*
* @param[in] socket_handle The network driver handle
* @param[out] data The address of message data
* @param[in] len The message data length
* @param[in] flags The flags argument is the bitwise OR of zero or more of the following flags
*
* @return result
* - 0 Success
* - other Fail
*/
int network_socket_receive(handle_t socket_handle, uint8_t *data, size_t len, socket_message_flag_t flags);
/**
* @brief Send a message on a socket
*
* @param[in] socket_handle The network driver handle
* @param[in] data The address of message data
* @param[in] len The message data length
* @param[in] flags The flags argument is the bitwise OR of zero or more of the following flags
* @param[in] to The address of remote socket
*
* @return result
* - 0 Success
* - other Fail
*/
int network_socket_send_to(handle_t socket_handle, const uint8_t *data, size_t len, socket_message_flag_t flags, const socket_address_t *to);
/**
* @brief Receive a message from a socket
*
* @param[in] socket_handle The network driver handle
* @param[out] data The address of message data
* @param[in] len The message data length
* @param[in] flags The flags argument is the bitwise OR of zero or more of the following flags
*
* @return result
* - 0 Success
* - other Fail
*/
int network_socket_receive_from(handle_t socket_handle, uint8_t *data, size_t len, socket_message_flag_t flags, socket_address_t *from);
/**
* @brief Get host address information by name
*
* @param[in] name host name
* @param[out] hostent host entry
*
* @return result
* - 0 Success
* - other Fail
*/
int network_socket_gethostbyname(const char *name, hostent_t *hostent);
/**
* @brief Socket addr parse
*
* @param[in] ip_addr ip address
* @param[in] port port number
* @param[out] socket_addr socket address
*
* @return result
* - 0 Success
* - other Fail
*/
int network_socket_addr_parse(const char *ip_addr, int port, uint8_t *socket_addr);
/**
* @brief Socket addr to string
*
* @param[in] socket_addr socket address
* @param[out] ip_addr ip address
* @param[out] port port number
*
* @return result
* - 0 Success
* - other Fail
*/
int network_socket_addr_to_string(uint8_t *socket_addr, char *ip_addr, int *port);
#ifdef __cplusplus
}
#endif
#endif /* _FREERTOS_NETWORK_H */

View File

@ -246,6 +246,82 @@ typedef struct _find_file_data
char filename[MAX_PATH];
} find_find_data_t;
typedef enum _address_family
{
AF_UNSPECIFIED,
AF_INTERNETWORK
} address_family_t;
typedef enum _socket_type
{
SOCKET_STREAM,
SOCKET_DATAGRAM
} socket_type_t;
typedef enum _socket_message_flag
{
MESSAGE_NORMAL = 0x00,
MESSAGE_PEEK = 0x01,
MESSAGE_WAITALL = 0x02,
MESSAGE_OOB = 0x04,
MESSAGE_DONTWAIT = 0x08,
MESSAGE_MORE = 0x10
} socket_message_flag_t;
typedef enum _protocol_type
{
PROTCL_IP
} protocol_type_t;
typedef struct _socket_address
{
uint8_t size;
address_family_t family;
uint8_t data[14];
} socket_address_t;
typedef enum _socket_shutdown
{
SOCKSHTDN_RECEIVE,
SOCKSHTDN_SEND,
SOCKSHTDN_BOTH
} socket_shutdown_t;
typedef struct _ip_address
{
address_family_t family;
uint8_t data[16];
} ip_address_t;
typedef struct _mac_address
{
uint8_t data[6];
} mac_address_t;
typedef struct _hostent
{
/* Official name of the host. */
char *h_name;
/* A pointer to an array of pointers to alternative host names, terminated by a null pointer. */
char **h_aliases;
/* Address type. */
uint32_t h_addrtype;
/* The length, in bytes, of the address. */
uint32_t h_length;
/* A pointer to an array of pointers to network addresses (in
network byte order) for the host, terminated by a null pointer. */
uint8_t **h_addr_list;
} hostent_t;
typedef enum _dhcp_state
{
DHCP_START = 0,
DHCP_WAIT_ADDRESS,
DHCP_ADDRESS_ASSIGNED,
DHCP_TIMEOUT,
DHCP_FAIL
} dhcp_state_t;
#ifdef __cplusplus
}
#endif

View File

@ -61,13 +61,13 @@
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) )
/* Only the current stack state is to be checked. */
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
/* Is the currently saved stack pointer within the stack limit? */ \
if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \
{ \
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
} \
#define taskCHECK_FOR_STACK_OVERFLOW() \
{ \
/* Is the currently saved stack pointer within the stack limit? */ \
if( pxCurrentTCB[uxPsrId]->pxTopOfStack <= pxCurrentTCB[uxPsrId]->pxStack ) \
{ \
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB[uxPsrId], pxCurrentTCB[uxPsrId]->pcTaskName ); \
} \
}
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */

View File

@ -192,12 +192,14 @@ static void dma_add_free();
int io_read(handle_t file, uint8_t *buffer, size_t len)
{
configASSERT(file >= HANDLE_OFFSET);
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET];
/* clang-format off */
DEFINE_READ_PROXY(uart_driver)
else DEFINE_READ_PROXY(i2c_device_driver)
else DEFINE_READ_PROXY(spi_device_driver)
else DEFINE_READ_PROXY(filesystem_file)
else DEFINE_READ_PROXY(network_socket)
else
{
return -1;
@ -260,6 +262,7 @@ int io_close(handle_t file)
{
if (file)
{
configASSERT(file >= HANDLE_OFFSET);
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET];
io_free(rfile);
atomic_set(handles_ + file - HANDLE_OFFSET, 0);
@ -270,12 +273,14 @@ int io_close(handle_t file)
int io_write(handle_t file, const uint8_t *buffer, size_t len)
{
configASSERT(file >= HANDLE_OFFSET);
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET];
/* clang-format off */
DEFINE_WRITE_PROXY(uart_driver)
else DEFINE_WRITE_PROXY(i2c_device_driver)
else DEFINE_WRITE_PROXY(spi_device_driver)
else DEFINE_WRITE_PROXY(filesystem_file)
else DEFINE_WRITE_PROXY(network_socket)
else
{
return -1;
@ -294,13 +299,13 @@ int io_control(handle_t file, uint32_t control_code, const uint8_t *write_buffer
/* Device IO Implementation Helper Macros */
#define COMMON_ENTRY(t) \
configASSERT(file); \
configASSERT(file >= HANDLE_OFFSET); \
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET]; \
configASSERT(rfile && rfile->object.is<t##_driver>()); \
auto t = rfile->object.as<t##_driver>();
#define COMMON_ENTRY_FILE(file, t) \
configASSERT(file); \
configASSERT(file >= HANDLE_OFFSET); \
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET]; \
configASSERT(rfile && rfile->object.is<t##_driver>()); \
auto t = rfile->object.as<t##_driver>();

View File

@ -0,0 +1,495 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "network.h"
#include "FreeRTOS.h"
#include "devices.h"
#include "kernel/driver_impl.hpp"
#include "task.h"
#include <lwip/etharp.h>
#include <lwip/init.h>
#include <lwip/snmp.h>
#include <lwip/tcpip.h>
#include <lwip/dhcp.h>
#include <lwip/netif.h>
#include <lwip/netdb.h>
#include <netif/ethernet.h>
#include <string.h>
using namespace sys;
#define MAX_DHCP_TRIES 5
int network_init()
{
tcpip_init(NULL, NULL);
return 0;
}
class k_ethernet_interface : public virtual object_access, public heap_object, public exclusive_object_access, private network_adapter_handler
{
public:
k_ethernet_interface(object_accessor<network_adapter_driver> adapter, const ip_address_t &ip_address, const ip_address_t &net_mask, const ip_address_t &gateway)
: adapter_(std::move(adapter))
{
ip4_addr_t ipaddr, netmask, gw;
completion_event_ = xSemaphoreCreateCounting(20, 0);
IP4_ADDR(&ipaddr, ip_address.data[0], ip_address.data[1], ip_address.data[2], ip_address.data[3]);
IP4_ADDR(&netmask, net_mask.data[0], net_mask.data[1], net_mask.data[2], net_mask.data[3]);
IP4_ADDR(&gw, gateway.data[0], gateway.data[1], gateway.data[2], gateway.data[3]);
if (!netif_add(&netif_, &ipaddr, &netmask, &gw, this, ethernetif_init, ethernet_input))
throw std::runtime_error("Unable to init netif.");
}
void set_enable(bool enable)
{
if (enable)
{
netif_set_up(&netif_);
TaskHandle_t h;
auto ret = xTaskCreate(poll_thread, "poll", 10240, this, 3, &h);
configASSERT(ret == pdTRUE);
}
else
{
netif_set_down(&netif_);
}
}
void set_as_default()
{
netif_set_default(&netif_);
}
dhcp_state_t dhcp_pooling()
{
auto &netif = netif_;
uint32_t ip_address;
dhcp_state_t dhcp_state;
dhcp_state = DHCP_START;
for (;;)
{
switch (dhcp_state)
{
case DHCP_START:
{
dhcp_start(&netif);
ip_address = 0;
dhcp_state = DHCP_WAIT_ADDRESS;
}
break;
case DHCP_WAIT_ADDRESS:
{
ip_address = netif.ip_addr.addr;
if (ip_address != 0)
{
dhcp_state = DHCP_ADDRESS_ASSIGNED;
dhcp_stop(&netif);
dhcp_cleanup(&netif);
return dhcp_state;
}
else
{
struct dhcp *dhcp = netif_dhcp_data(&netif);
if (dhcp->tries > MAX_DHCP_TRIES)
{
dhcp_state = DHCP_TIMEOUT;
dhcp_stop(&netif);
dhcp_cleanup(&netif);
return dhcp_state;
}
}
}
break;
default:
return dhcp_state;
}
vTaskDelay(250);
}
return DHCP_FAIL;
}
void set_addr(const ip_address_t &ip_address, const ip_address_t &net_mask, const ip_address_t &gate_way)
{
ip4_addr_t ipaddr, netmask, gw;
IP4_ADDR(&ipaddr, ip_address.data[0], ip_address.data[1], ip_address.data[2], ip_address.data[3]);
IP4_ADDR(&netmask, net_mask.data[0], net_mask.data[1], net_mask.data[2], net_mask.data[3]);
IP4_ADDR(&gw, gate_way.data[0], gate_way.data[1], gate_way.data[2], gate_way.data[3]);
netif_set_addr(&netif_, &ipaddr, &netmask, &gw);
}
void get_addr(ip_address_t &ip_address, ip_address_t &net_mask, ip_address_t &gate_way)
{
ip_address.data[0] = ip4_addr1(&netif_.ip_addr);
ip_address.data[1] = ip4_addr2(&netif_.ip_addr);
ip_address.data[2] = ip4_addr3(&netif_.ip_addr);
ip_address.data[3] = ip4_addr4(&netif_.ip_addr);
net_mask.data[0] = ip4_addr1(&netif_.gw);
net_mask.data[1] = ip4_addr2(&netif_.gw);
net_mask.data[2] = ip4_addr3(&netif_.gw);
net_mask.data[3] = ip4_addr4(&netif_.gw);
gate_way.data[0] = ip4_addr1(&netif_.netmask);
gate_way.data[1] = ip4_addr2(&netif_.netmask);
gate_way.data[2] = ip4_addr3(&netif_.netmask);
gate_way.data[3] = ip4_addr4(&netif_.netmask);
}
private:
virtual void notify_input() override
{
while (adapter_->is_packet_available())
{
ethernetif_input(&netif_);
}
}
static void poll_thread(void *args)
{
auto &ethnetif = *reinterpret_cast<k_ethernet_interface *>(args);
auto &adapter = ethnetif.adapter_;
while (1)
{
if (xSemaphoreTake(ethnetif.completion_event_, portMAX_DELAY) == pdTRUE)
{
if (adapter->interface_check())
{
adapter->disable_rx();
ethnetif.notify_input();
adapter->enable_rx();
}
}
}
}
static err_t ethernetif_init(struct netif *netif)
{
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */
#if LWIP_IPV4
netif->output = etharp_output;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
netif->linkoutput = low_level_output;
/* initialize the hardware */
low_level_init(netif);
return ERR_OK;
}
static void ethernetif_input(struct netif *netif)
{
struct pbuf *p;
/* move received packet into a new pbuf */
p = low_level_input(netif);
/* if no packet could be read, silently ignore this */
if (p != NULL)
{
/* pass all packets to ethernet_input, which decides what packets it supports */
if (netif->input(p, netif) != ERR_OK)
{
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
p = NULL;
}
}
}
static void low_level_init(struct netif *netif)
{
auto &ethnetif = *reinterpret_cast<k_ethernet_interface *>(netif->state);
auto &adapter = ethnetif.adapter_;
auto mac_address = adapter->get_mac_address();
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* set MAC hardware address */
netif->hwaddr[0] = mac_address.data[0];
netif->hwaddr[1] = mac_address.data[1];
netif->hwaddr[2] = mac_address.data[2];
netif->hwaddr[3] = mac_address.data[3];
netif->hwaddr[4] = mac_address.data[4];
netif->hwaddr[5] = mac_address.data[5];
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
#if LWIP_IPV6 && LWIP_IPV6_MLD
/*
* For hardware/netifs that implement MAC filtering.
* All-nodes link-local is handled by default, so we must let the hardware know
* to allow multicast packets in.
* Should set mld_mac_filter previously. */
if (netif->mld_mac_filter != NULL)
{
ip6_addr_t ip6_allnodes_ll;
ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);
}
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
/* Do whatever else is needed to initialize interface. */
adapter->reset(ethnetif.completion_event_);
}
static struct pbuf *low_level_input(struct netif *netif)
{
auto &ethnetif = *reinterpret_cast<k_ethernet_interface *>(netif->state);
auto &adapter = ethnetif.adapter_;
struct pbuf *p, *q;
u16_t len;
/* Obtain the size of the packet and put it into the "len" variable. */
len = adapter->begin_receive();
#if ETH_PAD_SIZE
len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif
/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL)
{
#if ETH_PAD_SIZE
pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */
#endif
/* We iterate over the pbuf chain until we have read the entire
* packet into the pbuf. */
for (q = p; q != NULL; q = q->next)
{
/* Read enough bytes to fill this pbuf in the chain. The
* available data in the pbuf is given by the q->len
* variable.
* This does not necessarily have to be a memcpy, you can also preallocate
* pbufs for a DMA-enabled MAC and after receiving truncate it to the
* actually received size. In this case, ensure the tot_len member of the
* pbuf is the sum of the chained pbuf len members.
*/
adapter->receive({ (uint8_t *)q->payload, q->len });
}
adapter->end_receive();
MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
if (((u8_t *)p->payload)[0] & 1)
{
/* broadcast or multicast packet*/
MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
}
else
{
/* unicast packet*/
MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
}
#if ETH_PAD_SIZE
pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
LINK_STATS_INC(link.recv);
}
else
{
adapter->end_receive();
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
MIB2_STATS_NETIF_INC(netif, ifindiscards);
}
return p;
}
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
auto &ethnetif = *reinterpret_cast<k_ethernet_interface *>(netif->state);
auto &adapter = ethnetif.adapter_;
struct pbuf *q;
adapter->begin_send(p->tot_len);
#if ETH_PAD_SIZE
pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */
#endif
for (q = p; q != NULL; q = q->next)
{
/* Send the data from the pbuf to the interface, one pbuf at a
time. The size of the data in each pbuf is kept in the ->len
variable. */
adapter->send({ (uint8_t *)q->payload, q->len });
}
adapter->end_send();
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
if (((u8_t *)p->payload)[0] & 1)
{
/* broadcast or multicast packet*/
MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
}
else
{
/* unicast packet */
MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
}
/* increase ifoutdiscards or ifouterrors on error */
#if ETH_PAD_SIZE
pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
LINK_STATS_INC(link.xmit);
return ERR_OK;
}
private:
object_accessor<network_adapter_driver> adapter_;
netif netif_;
SemaphoreHandle_t completion_event_;
};
#define NETIF_ENTRY \
auto &obj = system_handle_to_object(netif_handle); \
configASSERT(obj.is<k_ethernet_interface>()); \
auto f = obj.as<k_ethernet_interface>();
#define CATCH_ALL \
catch (...) { return -1; }
handle_t network_interface_add(handle_t adapter_handle, const ip_address_t *ip_address, const ip_address_t *net_mask, const ip_address_t *gateway)
{
try
{
if (!ip_address || !net_mask || !gateway)
return -1;
auto netif = make_object<k_ethernet_interface>(system_handle_to_object(adapter_handle).move_as<network_adapter_driver>(), *ip_address, *net_mask, *gateway);
netif->add_ref(); // Pin the object
return system_alloc_handle(make_accessor<object_access>(netif));
}
catch (...)
{
return NULL_HANDLE;
}
}
int network_interface_set_enable(handle_t netif_handle, bool enable)
{
try
{
NETIF_ENTRY;
f->set_enable(enable);
return 0;
}
CATCH_ALL;
}
int network_interface_set_as_default(handle_t netif_handle)
{
try
{
NETIF_ENTRY;
f->set_as_default();
return 0;
}
CATCH_ALL;
}
int network_set_addr(handle_t netif_handle, const ip_address_t *ip_address, const ip_address_t *net_mask, const ip_address_t *gateway)
{
try
{
NETIF_ENTRY;
f->set_addr(*ip_address, *net_mask, *gateway);
return 0;
}
CATCH_ALL;
}
int network_get_addr(handle_t netif_handle, ip_address_t *ip_address, ip_address_t *net_mask, ip_address_t *gateway)
{
try
{
NETIF_ENTRY;
f->get_addr(*ip_address, *net_mask, *gateway);
return 0;
}
CATCH_ALL;
}
dhcp_state_t network_interface_dhcp_pooling(handle_t netif_handle)
{
try
{
NETIF_ENTRY;
return f->dhcp_pooling();
}
catch (...)
{
return DHCP_FAIL;
}
}
int network_socket_gethostbyname(const char *name, hostent_t *hostent)
{
try
{
struct hostent *lwip_hostent = lwip_gethostbyname(name);
hostent->h_name = lwip_hostent->h_name;
hostent->h_aliases = lwip_hostent->h_aliases;
hostent->h_length = lwip_hostent->h_length;
hostent->h_addr_list = reinterpret_cast<uint8_t **>(lwip_hostent->h_addr_list);
switch (lwip_hostent->h_addrtype)
{
case AF_INET:
hostent->h_addrtype = AF_INTERNETWORK;
break;
default:
throw std::invalid_argument("Invalid address type.");
}
return 0;
}
CATCH_ALL;
}

View File

@ -0,0 +1,461 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "FreeRTOS.h"
#include "devices.h"
#include "kernel/driver_impl.hpp"
#include "network.h"
#include <lwip/sockets.h>
#include <string.h>
using namespace sys;
static void check_lwip_error(int result)
{
if (result < 0)
throw std::runtime_error(strerror(errno));
}
static void to_lwip_sockaddr(sockaddr_in &addr, const socket_address_t &socket_addr)
{
if (socket_addr.family != AF_INTERNETWORK)
throw std::runtime_error("Invalid socket address.");
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(*reinterpret_cast<const uint16_t *>(socket_addr.data + 4));
addr.sin_addr.s_addr = LWIP_MAKEU32(socket_addr.data[3], socket_addr.data[2], socket_addr.data[1], socket_addr.data[0]);
}
static void to_sys_sockaddr(socket_address_t &addr, const sockaddr_in &socket_addr)
{
if (socket_addr.sin_family != AF_INET)
throw std::runtime_error("Invalid socket address.");
addr.family = AF_INTERNETWORK;
addr.data[3] = (socket_addr.sin_addr.s_addr >> 24) & 0xFF;
addr.data[2] = (socket_addr.sin_addr.s_addr >> 16) & 0xFF;
addr.data[1] = (socket_addr.sin_addr.s_addr >> 8) & 0xFF;
addr.data[0] = socket_addr.sin_addr.s_addr & 0xFF;
*reinterpret_cast<uint16_t *>(addr.data + 4) = ntohs(socket_addr.sin_port);
}
class k_network_socket : public network_socket, public heap_object, public exclusive_object_access
{
public:
k_network_socket(address_family_t address_family, socket_type_t type, protocol_type_t protocol)
{
int domain;
switch (address_family)
{
case AF_UNSPECIFIED:
case AF_INTERNETWORK:
domain = AF_INET;
break;
default:
throw std::invalid_argument("Invalid address family.");
}
int s_type;
switch (type)
{
case SOCKET_STREAM:
s_type = SOCK_STREAM;
break;
case SOCKET_DATAGRAM:
s_type = SOCK_DGRAM;
break;
default:
throw std::invalid_argument("Invalid socket type.");
}
int s_protocol;
switch (protocol)
{
case PROTCL_IP:
s_protocol = IPPROTO_IP;
break;
default:
throw std::invalid_argument("Invalid protocol type.");
}
auto sock = lwip_socket(domain, s_type, s_protocol);
check_lwip_error(sock);
sock_ = sock;
}
explicit k_network_socket(int sock)
: sock_(sock)
{
}
~k_network_socket()
{
lwip_close(sock_);
}
virtual object_accessor<network_socket> accept(socket_address_t *remote_address) override
{
object_ptr<k_network_socket> socket(std::in_place, new k_network_socket());
sockaddr_in remote;
socklen_t remote_len = sizeof(remote);
auto sock = lwip_accept(sock_, reinterpret_cast<sockaddr *>(&remote), &remote_len);
check_lwip_error(sock);
socket->sock_ = sock;
if (remote_address)
to_sys_sockaddr(*remote_address, remote);
return make_accessor(socket);
}
virtual void bind(const socket_address_t &address) override
{
sockaddr_in addr;
to_lwip_sockaddr(addr, address);
check_lwip_error(lwip_bind(sock_, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)));
}
virtual void connect(const socket_address_t &address) override
{
sockaddr_in addr;
to_lwip_sockaddr(addr, address);
check_lwip_error(lwip_connect(sock_, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)));
}
virtual void listen(uint32_t backlog) override
{
check_lwip_error(lwip_listen(sock_, backlog));
}
virtual void shutdown(socket_shutdown_t how) override
{
int s_how;
switch (how)
{
case SOCKSHTDN_SEND:
s_how = SHUT_WR;
break;
case SOCKSHTDN_RECEIVE:
s_how = SHUT_RD;
break;
case SOCKSHTDN_BOTH:
s_how = SHUT_RDWR;
break;
default:
throw std::invalid_argument("Invalid how.");
}
check_lwip_error(lwip_shutdown(sock_, s_how));
}
virtual size_t send(gsl::span<const uint8_t> buffer, socket_message_flag_t flags) override
{
uint8_t send_flags = 0;
if (flags & MESSAGE_PEEK)
send_flags |= MSG_PEEK;
if (flags & MESSAGE_WAITALL)
send_flags |= MSG_WAITALL;
if (flags & MESSAGE_OOB)
send_flags |= MSG_OOB;
if (flags & MESSAGE_DONTWAIT)
send_flags |= MSG_DONTWAIT;
if (flags & MESSAGE_MORE)
send_flags |= MSG_MORE;
auto ret = lwip_send(sock_, buffer.data(), buffer.size_bytes(), send_flags);
check_lwip_error(ret);
configASSERT(ret == buffer.size_bytes());
return ret;
}
virtual size_t receive(gsl::span<uint8_t> buffer, socket_message_flag_t flags) override
{
uint8_t recv_flags = 0;
if (flags & MESSAGE_PEEK)
recv_flags |= MSG_PEEK;
if (flags & MESSAGE_WAITALL)
recv_flags |= MSG_WAITALL;
if (flags & MESSAGE_OOB)
recv_flags |= MSG_OOB;
if (flags & MESSAGE_DONTWAIT)
recv_flags |= MSG_DONTWAIT;
if (flags & MESSAGE_MORE)
recv_flags |= MSG_MORE;
auto ret = lwip_recv(sock_, buffer.data(), buffer.size_bytes(), recv_flags);
check_lwip_error(ret);
return ret;
}
virtual size_t send_to(gsl::span<const uint8_t> buffer, socket_message_flag_t flags, const socket_address_t &to) override
{
uint8_t send_flags = 0;
if (flags & MESSAGE_PEEK)
send_flags |= MSG_PEEK;
if (flags & MESSAGE_WAITALL)
send_flags |= MSG_WAITALL;
if (flags & MESSAGE_OOB)
send_flags |= MSG_OOB;
if (flags & MESSAGE_DONTWAIT)
send_flags |= MSG_DONTWAIT;
if (flags & MESSAGE_MORE)
send_flags |= MSG_MORE;
sockaddr_in remote;
socklen_t remote_len = sizeof(remote);
to_lwip_sockaddr(remote, to);
auto ret = lwip_sendto(sock_, buffer.data(), buffer.size_bytes(), send_flags, reinterpret_cast<const sockaddr *>(&remote), remote_len);
check_lwip_error(ret);
configASSERT(ret == buffer.size_bytes());
return ret;
}
virtual size_t receive_from(gsl::span<uint8_t> buffer, socket_message_flag_t flags, socket_address_t *from) override
{
uint8_t recv_flags = 0;
if (flags & MESSAGE_PEEK)
recv_flags |= MSG_PEEK;
if (flags & MESSAGE_WAITALL)
recv_flags |= MSG_WAITALL;
if (flags & MESSAGE_OOB)
recv_flags |= MSG_OOB;
if (flags & MESSAGE_DONTWAIT)
recv_flags |= MSG_DONTWAIT;
if (flags & MESSAGE_MORE)
recv_flags |= MSG_MORE;
sockaddr_in remote;
socklen_t remote_len = sizeof(remote);
auto ret = lwip_recvfrom(sock_, buffer.data(), buffer.size_bytes(), recv_flags, reinterpret_cast<sockaddr *>(&remote), &remote_len);
check_lwip_error(ret);
if (from)
to_sys_sockaddr(*from, remote);
return ret;
}
virtual size_t read(gsl::span<uint8_t> buffer) override
{
auto ret = lwip_read(sock_, buffer.data(), buffer.size_bytes());
check_lwip_error(ret);
return ret;
}
virtual size_t write(gsl::span<const uint8_t> buffer) override
{
auto ret = lwip_write(sock_, buffer.data(), buffer.size_bytes());
check_lwip_error(ret);
configASSERT(ret == buffer.size_bytes());
return ret;
}
private:
k_network_socket()
: sock_(0)
{
}
private:
int sock_;
};
#define SOCKET_ENTRY \
auto &obj = system_handle_to_object(socket_handle); \
configASSERT(obj.is<k_network_socket>()); \
auto f = obj.as<k_network_socket>();
#define CATCH_ALL \
catch (...) { return -1; }
#define CHECK_ARG(x) \
if (!x) \
throw std::invalid_argument(#x " is invalid.");
handle_t network_socket_open(address_family_t address_family, socket_type_t type, protocol_type_t protocol)
{
try
{
auto socket = make_object<k_network_socket>(address_family, type, protocol);
return system_alloc_handle(make_accessor<object_access>(socket));
}
catch (...)
{
return NULL_HANDLE;
}
}
handle_t network_socket_close(handle_t socket_handle)
{
return io_close(socket_handle);
}
int network_socket_connect(handle_t socket_handle, const socket_address_t *remote_address)
{
try
{
SOCKET_ENTRY;
CHECK_ARG(remote_address);
f->connect(*remote_address);
return 0;
}
CATCH_ALL;
}
int network_socket_listen(handle_t socket_handle, uint32_t backlog)
{
try
{
SOCKET_ENTRY;
f->listen(backlog);
return 0;
}
CATCH_ALL;
}
handle_t network_socket_accept(handle_t socket_handle, socket_address_t *remote_address)
{
try
{
SOCKET_ENTRY;
CHECK_ARG(remote_address);
return system_alloc_handle(f->accept(remote_address));
}
catch (...)
{
return NULL_HANDLE;
}
}
int network_socket_shutdown(handle_t socket_handle, socket_shutdown_t how)
{
try
{
SOCKET_ENTRY;
f->shutdown(how);
return 0;
}
CATCH_ALL;
}
int network_socket_bind(handle_t socket_handle, const socket_address_t *local_address)
{
try
{
SOCKET_ENTRY;
CHECK_ARG(local_address);
f->bind(*local_address);
return 0;
}
CATCH_ALL;
}
int network_socket_send(handle_t socket_handle, const uint8_t *data, size_t len, socket_message_flag_t flags)
{
try
{
SOCKET_ENTRY;
f->send({ data, std::ptrdiff_t(len) }, flags);
return 0;
}
CATCH_ALL;
}
int network_socket_receive(handle_t socket_handle, uint8_t *data, size_t len, socket_message_flag_t flags)
{
try
{
SOCKET_ENTRY;
return f->receive({ data, std::ptrdiff_t(len) }, flags);
}
CATCH_ALL;
}
int network_socket_send_to(handle_t socket_handle, const uint8_t *data, size_t len, socket_message_flag_t flags, const socket_address_t *to)
{
try
{
SOCKET_ENTRY;
f->send_to({ data, std::ptrdiff_t(len) }, flags, *to);
return 0;
}
CATCH_ALL;
}
int network_socket_receive_from(handle_t socket_handle, uint8_t *data, size_t len, socket_message_flag_t flags, socket_address_t *from)
{
try
{
SOCKET_ENTRY;
return f->receive_from({ data, std::ptrdiff_t(len) }, flags, from);
}
CATCH_ALL;
}
int network_socket_addr_parse(const char *ip_addr, int port, uint8_t *socket_addr)
{
try
{
const char *sep = ".";
char *p;
int data;
char ip_addr_p[16];
strcpy(ip_addr_p, ip_addr);
uint8_t *socket_addr_p = socket_addr;
p = strtok(ip_addr_p, sep);
while (p)
{
data = atoi(p);
if (data > 255)
throw std::invalid_argument(" ipaddr is invalid.");
*socket_addr_p++ = (uint8_t)data;
p = strtok(NULL, sep);
}
if (socket_addr_p - socket_addr != 4)
throw std::invalid_argument(" ipaddr size is invalid.");
*socket_addr_p++ = port & 0xff;
*socket_addr_p = (port >> 8) & 0xff;
return 0;
}
CATCH_ALL;
}
int network_socket_addr_to_string(uint8_t *socket_addr, char *ip_addr, int *port)
{
try
{
char *p = ip_addr;
int i = 0;
do
{
char tmp[8] = { 0 };
itoa(socket_addr[i++], tmp, 10);
strcpy(p, tmp);
p += strlen(tmp);
} while ((i < 4) && (*p++ = '.'));
*port = (int)(socket_addr[4] | (socket_addr[5] << 8));
return 0;
}
CATCH_ALL;
}

View File

@ -28,6 +28,9 @@ typedef struct
int ret;
} main_thunk_param_t;
static StaticTask_t s_idle_task;
static StackType_t s_idle_task_stack[configMINIMAL_STACK_SIZE];
void start_scheduler(int core_id);
static void main_thunk(void *p)
@ -91,3 +94,23 @@ void start_scheduler(int core_id)
void vApplicationIdleHook(void)
{
}
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize)
{
/* Pass out a pointer to the StaticTask_t structure in which the Idle task's
state will be stored. */
*ppxIdleTaskTCBBuffer = &s_idle_task;
/* Pass out the array that will be used as the Idle task's stack. */
*ppxIdleTaskStackBuffer = s_idle_task_stack;
/* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
Note that, as the array is necessarily of type StackType_t,
configMINIMAL_STACK_SIZE is specified in words, not bytes. */
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{
configASSERT(!"Stackoverflow !");
}

View File

@ -199,6 +199,8 @@ void vPortFatal(const char* file, int line, const char* message)
portDISABLE_INTERRUPTS();
corelock_lock(&xCoreLock);
LOGE("FreeRTOS", "(%s:%d) %s", file, line, message);
while (1)
;
exit(-1);
while (1)
;

View File

@ -273,14 +273,15 @@
mret
.endm
xPortSysTickInt:
portSAVE_CONTEXT
jal vPortSysTickHandler
portRESTORE_CONTEXT
xPortStartScheduler:
jal vPortSetupTimer
portRESTORE_CONTEXT
vPortEndScheduler:
ret
.section .text.systick, "ax", @progbits
xPortSysTickInt:
portSAVE_CONTEXT
call vPortSysTickHandler
portRESTORE_CONTEXT

View File

@ -638,7 +638,7 @@ static void prvAddNewTaskToReadyList( UBaseType_t xProcessorId, TCB_t *pxNewTCB
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL );
prvAddNewTaskToReadyList( pxNewTCB );
prvAddNewTaskToReadyList( uxPortGetProcessorId(), pxNewTCB );
}
else
{
@ -1962,7 +1962,7 @@ BaseType_t xReturn;
UBaseType_t uxPsrId = uxPortGetProcessorId();
/* Add the idle task at the lowest priority. */
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
#if( configSUPPORT_STATIC_ALLOCATION == 1 && 0)
{
StaticTask_t *pxIdleTaskTCBBuffer = NULL;
StackType_t *pxIdleTaskStackBuffer = NULL;
@ -2833,12 +2833,13 @@ UBaseType_t uxPsrId = uxPortGetProcessorId();
void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction )
{
TCB_t *xTCB;
UBaseType_t uxPsrId = uxPortGetProcessorId();
/* If xTask is NULL then it is the task hook of the calling task that is
getting set. */
if( xTask == NULL )
{
xTCB = ( TCB_t * ) pxCurrentTCB;
xTCB = ( TCB_t * ) pxCurrentTCB[uxPsrId];
}
else
{
@ -2860,12 +2861,13 @@ UBaseType_t uxPsrId = uxPortGetProcessorId();
TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask )
{
TCB_t *xTCB;
UBaseType_t uxPsrId = uxPortGetProcessorId();
TaskHookFunction_t xReturn;
/* If xTask is NULL then we are setting our own task hook. */
if( xTask == NULL )
{
xTCB = ( TCB_t * ) pxCurrentTCB;
xTCB = ( TCB_t * ) pxCurrentTCB[uxPsrId];
}
else
{
@ -2891,12 +2893,13 @@ UBaseType_t uxPsrId = uxPortGetProcessorId();
BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter )
{
TCB_t *xTCB;
UBaseType_t uxPsrId = uxPortGetProcessorId();
BaseType_t xReturn;
/* If xTask is NULL then we are calling our own task hook. */
if( xTask == NULL )
{
xTCB = ( TCB_t * ) pxCurrentTCB;
xTCB = ( TCB_t * ) pxCurrentTCB[uxPsrId];
}
else
{
@ -3464,6 +3467,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue )
{
TCB_t *pxTCB;
UBaseType_t uxPsrId = uxPortGetProcessorId();
if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
{
@ -3481,6 +3485,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
{
void *pvReturn = NULL;
TCB_t *pxTCB;
UBaseType_t uxPsrId = uxPortGetProcessorId();
if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
{

View File

@ -1269,6 +1269,7 @@ uint32_t sysctl_clock_get_freq(sysctl_clock_t clock)
*/
case SYSCTL_CLOCK_IN0:
source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0);
result = source;
break;
/*

23
lib/posix/CMakeLists.txt Normal file
View File

@ -0,0 +1,23 @@
#project(bsp)
# create bsp library
FILE(GLOB_RECURSE LIB_SRC_NOASM
"${CMAKE_CURRENT_LIST_DIR}/*.cpp"
"${CMAKE_CURRENT_LIST_DIR}/*.c"
)
FILE(GLOB_RECURSE ASSEMBLY_FILES
"${CMAKE_CURRENT_LIST_DIR}/*.s"
"${CMAKE_CURRENT_LIST_DIR}/*.S"
)
SET(LIB_SRC ${LIB_SRC_NOASM} ${ASSEMBLY_FILES})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}/include)
SET_PROPERTY(SOURCE ${ASSEMBLY_FILES} PROPERTY LANGUAGE C)
SET_SOURCE_FILES_PROPERTIES(${ASSEMBLY_FILES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -D __riscv64")
ADD_LIBRARY(posix STATIC ${LIB_SRC})
SET_TARGET_PROPERTIES(posix PROPERTIES LINKER_LANGUAGE C)
TARGET_LINK_LIBRARIES(posix PRIVATE freertos)
TARGET_INCLUDE_DIRECTORIES(posix PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)

View File

@ -0,0 +1,158 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* IPv4 address API
*/
/*
* 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>
*
*/
#ifndef LWIP_HDR_IP4_ADDR_H
#define LWIP_HDR_IP4_ADDR_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** This is the aligned version of ip4_addr_t,
used as local variable, on the stack, etc. */
struct ip4_addr {
uint32_t addr;
};
/** ip4_addr_t uses a struct for convenience only, so that the same defines can
* operate both on ip4_addr_t as well as on ip4_addr_p_t. */
typedef struct ip4_addr ip4_addr_t;
/* Forward declaration to not include netif.h */
struct netif;
/** 255.255.255.255 */
#define IPADDR_NONE ((uint32_t)0xffffffffUL)
/** 127.0.0.1 */
#define IPADDR_LOOPBACK ((uint32_t)0x7f000001UL)
/** 0.0.0.0 */
#define IPADDR_ANY ((uint32_t)0x00000000UL)
/** 255.255.255.255 */
#define IPADDR_BROADCAST ((uint32_t)0xffffffffUL)
/* Definitions of the bits in an Internet address integer.
On subnets, host and network parts are found according to
the subnet mask, not these masks. */
#define IP_CLASSA(a) ((((uint32_t)(a)) & 0x80000000UL) == 0)
#define IP_CLASSA_NET 0xff000000
#define IP_CLASSA_NSHIFT 24
#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET)
#define IP_CLASSA_MAX 128
#define IP_CLASSB(a) ((((uint32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
#define IP_CLASSB_NET 0xffff0000
#define IP_CLASSB_NSHIFT 16
#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET)
#define IP_CLASSB_MAX 65536
#define IP_CLASSC(a) ((((uint32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
#define IP_CLASSC_NET 0xffffff00
#define IP_CLASSC_NSHIFT 8
#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET)
#define IP_CLASSD(a) (((uint32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */
#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */
#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */
#define IP_MULTICAST(a) IP_CLASSD(a)
#define IP_EXPERIMENTAL(a) (((uint32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IP_BADCLASS(a) (((uint32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IP_LOOPBACKNET 127 /* official! */
/** Set an IP address given by the four byte-parts */
#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = PP_HTONL(LWIP_MAKEU32(a,b,c,d))
/** Copy IP address - faster than ip4_addr_set: no NULL check */
#define ip4_addr_copy(dest, src) ((dest).addr = (src).addr)
/** Safely copy one IP address to another (src may be NULL) */
#define ip4_addr_set(dest, src) ((dest)->addr = \
((src) == NULL ? 0 : \
(src)->addr))
/** Set complete address to zero */
#define ip4_addr_set_zero(ipaddr) ((ipaddr)->addr = 0)
/** Set address to IPADDR_ANY (no need for lwip_htonl()) */
#define ip4_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY)
/** Set address to loopback address */
#define ip4_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK))
/** Check if an address is in the loopback region */
#define ip4_addr_isloopback(ipaddr) (((ipaddr)->addr & PP_HTONL(IP_CLASSA_NET)) == PP_HTONL(((uint32_t)IP_LOOPBACKNET) << 24))
/** Safely copy one IP address to another and change byte order
* from host- to network-order. */
#define ip4_addr_set_hton(dest, src) ((dest)->addr = \
((src) == NULL ? 0:\
lwip_htonl((src)->addr)))
/** IPv4 only: set the IP address given as an uint32_t */
#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32))
/** IPv4 only: get the IP address as an uint32_t */
#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)
/** Get the network address by combining host address with netmask */
#define ip4_addr_get_network(target, host, netmask) do { ((target)->addr = ((host)->addr) & ((netmask)->addr)); } while(0)
#define IP4ADDR_STRLEN_MAX 16
/** For backwards compatibility */
#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr)
int sys_ip4addr_aton(const char *cp, ip4_addr_t *addr);
char *sys_ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen);
char *sys_ip4addr_ntoa(const ip4_addr_t *addr);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_IP_ADDR_H */

View File

@ -0,0 +1,29 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _POSIX_SYS_IP_ADDR_H
#define _POSIX_SYS_IP_ADDR_H
#include <stddef.h>
#include <stdint.h>
#include "sys/ip4_addr.h"
typedef ip4_addr_t ip_addr_t;
#define IPADDR4_INIT(u32val) \
{ \
u32val \
}
#endif

View File

@ -0,0 +1,43 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _POSIX_SYS_NETDB_H
#define _POSIX_SYS_NETDB_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
struct hostent {
char *h_name; /* Official name of the host. */
char **h_aliases; /* A pointer to an array of pointers to alternative host names,
terminated by a null pointer. */
int h_addrtype; /* Address type. */
int h_length; /* The length, in bytes, of the address. */
char **h_addr_list; /* A pointer to an array of pointers to network addresses (in
network byte order) for the host, terminated by a null pointer. */
#define h_addr h_addr_list[0] /* for backward compatibility */
};
struct hostent *gethostbyname(const char *name);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,304 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _POSIX_SYS_SOCKET_H
#define _POSIX_SYS_SOCKET_H
#include <stddef.h>
#include <stdint.h>
#include "sys/ip_addr.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** Create u32_t value from bytes */
#define LWIP_MAKEU32(a, b, c, d) (((uint32_t)((a)&0xff) << 24) | \
((uint32_t)((b)&0xff) << 16) | \
((uint32_t)((c)&0xff) << 8) | \
(uint32_t)((d)&0xff))
/* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED
to prevent this code from redefining it. */
#if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED)
typedef uint8_t sa_family_t;
#endif
/* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED
to prevent this code from redefining it. */
#if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED)
typedef uint32_t in_addr_t;
#endif
struct in_addr
{
in_addr_t s_addr;
};
/* If your port already typedef's in_port_t, define IN_PORT_T_DEFINED
to prevent this code from redefining it. */
#if !defined(in_port_t) && !defined(IN_PORT_T_DEFINED)
typedef uint16_t in_port_t;
#endif
/* members are in network byte order */
struct sockaddr_in
{
uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
#define SIN_ZERO_LEN 8
char sin_zero[SIN_ZERO_LEN];
};
struct sockaddr
{
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[14];
};
/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED
to prevent this code from redefining it. */
#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED)
typedef uint32_t socklen_t;
#endif
struct msghdr
{
void *msg_name;
socklen_t msg_namelen;
struct iovec *msg_iov;
int msg_iovlen;
void *msg_control;
socklen_t msg_controllen;
int msg_flags;
};
/* struct msghdr->msg_flags bit field values */
#define MSG_TRUNC 0x04
#define MSG_CTRUNC 0x08
/* RFC 3542, Section 20: Ancillary Data */
struct cmsghdr
{
socklen_t cmsg_len; /* number of bytes, including header */
int cmsg_level; /* originating protocol */
int cmsg_type; /* protocol-specific type */
};
/* Data section follows header and possible padding, typically referred to as
unsigned char cmsg_data[]; */
/* cmsg header/data alignment. NOTE: we align to native word size (double word
size on 16-bit arch) so structures are not placed at an unaligned address.
16-bit arch needs double word to ensure 32-bit alignment because socklen_t
could be 32 bits. If we ever have cmsg data with a 64-bit variable, alignment
will need to increase long long */
#define ALIGN_H(size) (((size) + sizeof(long) - 1U) & ~(sizeof(long)-1U))
#define ALIGN_D(size) ALIGN_H(size)
#define CMSG_FIRSTHDR(mhdr) \
((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
(struct cmsghdr *)(mhdr)->msg_control : \
(struct cmsghdr *)NULL)
#define CMSG_NXTHDR(mhdr, cmsg) \
(((cmsg) == NULL) ? CMSG_FIRSTHDR(mhdr) : \
(((u8_t *)(cmsg) + ALIGN_H((cmsg)->cmsg_len) \
+ ALIGN_D(sizeof(struct cmsghdr)) > \
(u8_t *)((mhdr)->msg_control) + (mhdr)->msg_controllen) ? \
(struct cmsghdr *)NULL : \
(struct cmsghdr *)((void*)((u8_t *)(cmsg) + \
ALIGN_H((cmsg)->cmsg_len)))))
#define CMSG_DATA(cmsg) ((void *)((u8_t *)(cmsg) + ALIGN_D(sizeof(struct cmsghdr))))
#define CMSG_SPACE(length) (ALIGN_D(sizeof(struct cmsghdr)) + ALIGN_H(length))
#define CMSG_LEN(length) (ALIGN_D(sizeof(struct cmsghdr)) + length)
/* Socket protocol types (TCP/UDP/RAW) */
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3
/*
* Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c)
*/
#define SO_REUSEADDR 0x0004 /* Allow local address reuse */
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
/*
* Additional options, not kept in so_options.
*/
#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */
#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */
#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */
#define SO_LINGER 0x0080 /* linger on close if data present */
#define SO_DONTLINGER ((int)(~SO_LINGER))
#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */
#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */
#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */
#define SO_RCVBUF 0x1002 /* receive buffer size */
#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */
#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */
#define SO_SNDTIMEO 0x1005 /* send timeout */
#define SO_RCVTIMEO 0x1006 /* receive timeout */
#define SO_ERROR 0x1007 /* get error status and clear */
#define SO_TYPE 0x1008 /* get socket type */
#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */
#define SO_NO_CHECK 0x100a /* don't create UDP checksum */
#define SO_BINDTODEVICE 0x100b /* bind to device */
/*
* Structure used for manipulating linger option.
*/
struct linger
{
int l_onoff; /* option on/off */
int l_linger; /* linger time in seconds */
};
/*
* Level number for (get/set)sockopt() to apply to socket itself.
*/
#define SOL_SOCKET 0xfff /* options for socket level */
#define AF_UNSPEC 0
#define AF_INET 2
#define AF_INET6 AF_UNSPEC
#define PF_INET AF_INET
#define PF_INET6 AF_INET6
#define PF_UNSPEC AF_UNSPEC
#define IPPROTO_IP 0
#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
#define IPPROTO_UDPLITE 136
#define IPPROTO_RAW 255
/* Flags we can use with send and recv. */
#define MSG_PEEK 0x01 /* Peeks at an incoming message */
#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */
#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */
#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */
#define MSG_MORE 0x10 /* Sender will send more */
#define MSG_NOSIGNAL 0x20 /* Uninmplemented: Requests not to send the SIGPIPE signal if an attempt to send is made on a stream-oriented socket that is no longer connected. */
/*
* Options for level IPPROTO_IP
*/
#define IP_TOS 1
#define IP_TTL 2
#define IP_PKTINFO 8
/*
* Options for level IPPROTO_TCP
*/
#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */
#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */
#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */
#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */
/*
* The Type of Service provides an indication of the abstract
* parameters of the quality of service desired. These parameters are
* to be used to guide the selection of the actual service parameters
* when transmitting a datagram through a particular network. Several
* networks offer service precedence, which somehow treats high
* precedence traffic as more important than other traffic (generally
* by accepting only traffic above a certain precedence at time of high
* load). The major choice is a three way tradeoff between low-delay,
* high-reliability, and high-throughput.
* The use of the Delay, Throughput, and Reliability indications may
* increase the cost (in some sense) of the service. In many networks
* better performance for one of these parameters is coupled with worse
* performance on another. Except for very unusual cases at most two
* of these three indications should be set.
*/
#define IPTOS_TOS_MASK 0x1E
#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK)
#define IPTOS_LOWDELAY 0x10
#define IPTOS_THROUGHPUT 0x08
#define IPTOS_RELIABILITY 0x04
#define IPTOS_LOWCOST 0x02
#define IPTOS_MINCOST IPTOS_LOWCOST
/*
* The Network Control precedence designation is intended to be used
* within a network only. The actual use and control of that
* designation is up to each network. The Internetwork Control
* designation is intended for use by gateway control originators only.
* If the actual use of these precedence designations is of concern to
* a particular network, it is the responsibility of that network to
* control the access to, and use of, those precedence designations.
*/
#define IPTOS_PREC_MASK 0xe0
#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK)
#define IPTOS_PREC_NETCONTROL 0xe0
#define IPTOS_PREC_INTERNETCONTROL 0xc0
#define IPTOS_PREC_CRITIC_ECP 0xa0
#define IPTOS_PREC_FLASHOVERRIDE 0x80
#define IPTOS_PREC_FLASH 0x60
#define IPTOS_PREC_IMMEDIATE 0x40
#define IPTOS_PREC_PRIORITY 0x20
#define IPTOS_PREC_ROUTINE 0x00
#ifndef SHUT_RD
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2
#endif
#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)
#define htons(x) ((uint16_t)((((x) & (uint16_t)0x00ffU) << 8) | (((x) & (uint16_t)0xff00U) >> 8)))
#define ntohs(x) htons(x)
int socket(int domain, int type, int protocol);
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
int accept(int socket, struct sockaddr *address, socklen_t *address_len);
int shutdown(int s, int how);
int connect(int socket, const struct sockaddr *address, socklen_t address_len);
int listen(int socket, int backlog);
int recv(int socket, void *mem, size_t len, int flags);
int send(int socket, const void *data, size_t size, int flags);
int recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
int sendto(int socket, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen);
#define inet_addr(cp) sys_ipaddr_addr(cp)
#define inet_aton(cp, addr) sys_ip4addr_aton(cp, (ip4_addr_t *)addr)
#define inet_ntoa(addr) sys_ip4addr_ntoa((const ip4_addr_t *)&(addr))
#define inet_ntop(af, src, dst, size) \
(((af) == AF_INET) ? sys_ip4addr_ntoa_r((const ip4_addr_t *)(src), (dst), (size)) : NULL)
#define inet_pton(af, src, dst) \
(((af) == AF_INET) ? sys_ip4addr_aton((src), (ip4_addr_t *)(dst)) : 0)
#define htonl(x) ((((x)&0x000000ffUL) << 24) | \
(((x)&0x0000ff00UL) << 8) | \
(((x)&0x00ff0000UL) >> 8) | \
(((x)&0xff000000UL) >> 24))
#ifdef __cplusplus
}
#endif
#endif

272
lib/posix/ip4_addr.cpp Normal file
View File

@ -0,0 +1,272 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @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 <cstdio>
#include "sys/ip_addr.h"
#include <ctype.h>
#define lwip_isdigit(c) isdigit((unsigned char)(c))
#define lwip_isxdigit(c) isxdigit((unsigned char)(c))
#define lwip_islower(c) islower((unsigned char)(c))
#define lwip_isspace(c) isspace((unsigned char)(c))
#define lwip_isupper(c) isupper((unsigned char)(c))
#define lwip_tolower(c) tolower((unsigned char)(c))
#define lwip_toupper(c) toupper((unsigned char)(c))
#define lwip_htonl(x) ((((x)&0x000000ffUL) << 24) | (((x)&0x0000ff00UL) << 8) | (((x)&0x00ff0000UL) >> 8) | (((x)&0xff000000UL) >> 24))
/* used by IP4_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
const ip_addr_t ip_addr_any = IPADDR4_INIT(IPADDR_ANY);
const ip_addr_t ip_addr_broadcast = IPADDR4_INIT(IPADDR_BROADCAST);
/**
* Ascii internet address interpretation routine.
* The value returned is in network order.
*
* @param cp IP address in ascii representation (e.g. "127.0.0.1")
* @return ip address in network order
*/
uint32_t
sys_ipaddr_addr(const char *cp)
{
ip4_addr_t val;
if (sys_ip4addr_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 representation (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 sys_ip4addr_aton(const char *cp, ip4_addr_t *addr)
{
uint32_t val;
uint8_t base;
char c;
uint32_t parts[4];
uint32_t *pp = parts;
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, 1-9=decimal.
*/
if (!lwip_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;
}
}
for (;;) {
if (lwip_isdigit(c)) {
val = (val * base) + (uint32_t)(c - '0');
c = *++cp;
} else if (base == 16 && lwip_isxdigit(c)) {
val = (val << 4) | (uint32_t)(c + 10 - (lwip_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' && !lwip_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) {
return 0;
}
if (parts[0] > 0xff) {
return 0;
}
val |= parts[0] << 24;
break;
case 3: /* a.b.c -- 8.8.16 bits */
if (val > 0xffff) {
return 0;
}
if ((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) {
return 0;
}
if ((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) {
return 0;
}
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
break;
default:
printf("unhandled");
break;
}
if (addr) {
ip4_addr_set_u32(addr, lwip_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
* representation of addr
*/
char *
sys_ip4addr_ntoa(const ip4_addr_t *addr)
{
static char str[IP4ADDR_STRLEN_MAX];
return sys_ip4addr_ntoa_r(addr, str, IP4ADDR_STRLEN_MAX);
}
/**
* Same as ip4addr_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 *
sys_ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen)
{
uint32_t s_addr;
char inv[3];
char *rp;
uint8_t *ap;
uint8_t rem;
uint8_t n;
uint8_t i;
int len = 0;
s_addr = ip4_addr_get_u32(addr);
rp = buf;
ap = (uint8_t *)&s_addr;
for (n = 0; n < 4; n++) {
i = 0;
do {
rem = *ap % (uint8_t)10;
*ap /= (uint8_t)10;
inv[i++] = (char)('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;
}

47
lib/posix/memory.cpp Normal file
View File

@ -0,0 +1,47 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <FreeRTOS.h>
#include <stdlib.h>
extern "C"
{
void *_aligned_malloc(size_t size, size_t alignment);
void _aligned_free(void *ptr);
}
void *_aligned_malloc(size_t size, size_t alignment)
{
auto offset = alignment - 1 + sizeof(void *);
auto p_head = malloc(size + offset);
if (p_head)
{
auto p_ret = (uintptr_t(p_head) + offset) & ~(alignment - 1);
auto p_link = reinterpret_cast<void **>(p_ret - sizeof(void *));
*p_link = p_head;
return reinterpret_cast<void *>(p_ret);
}
return nullptr;
}
void _aligned_free(void *ptr)
{
if (ptr)
{
auto puc = uintptr_t(ptr);
auto p_link = reinterpret_cast<void **>(puc - sizeof(void *));
free(*p_link);
}
}

50
lib/posix/netdb.cpp Normal file
View File

@ -0,0 +1,50 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sys/netdb.h"
#include "utils.h"
#include <kernel/driver_impl.hpp>
#include <network.h>
#include <string.h>
#include <sys/socket.h>
using namespace sys;
static struct hostent posix_hostent;
struct hostent *gethostbyname(const char *name)
{
try
{
hostent_t sys_hostent;
network_socket_gethostbyname(name, &sys_hostent);
posix_hostent.h_name = sys_hostent.h_name;
posix_hostent.h_aliases = sys_hostent.h_aliases;
posix_hostent.h_length = sys_hostent.h_length;
posix_hostent.h_addr_list = reinterpret_cast<char **>(sys_hostent.h_addr_list);
switch (sys_hostent.h_addrtype)
{
case AF_INTERNETWORK:
posix_hostent.h_addrtype = AF_INET;
break;
default:
throw std::invalid_argument("Invalid address type.");
}
return &posix_hostent;
}
catch (...)
{
return NULL;
}
}

28
lib/posix/posix_conf.cpp Normal file
View File

@ -0,0 +1,28 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/unistd.h>
long sysconf(int __name)
{
switch (__name)
{
case _SC_NPROCESSORS_CONF:
return 1;
default:
break;
}
return -1;
}

328
lib/posix/pthread.cpp Normal file
View File

@ -0,0 +1,328 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <FreeRTOS.h>
#include <atomic.h>
#include <atomic>
#include <climits>
#include <cstring>
#include <errno.h>
#include <kernel/driver_impl.hpp>
#include <platform.h>
#include <pthread.h>
#include <semphr.h>
#include <task.h>
#include <unordered_map>
// Workaround for keeping pthread functions
void *g_pthread_keep[] = {
(void *)pthread_cond_init,
(void *)pthread_mutex_init,
(void *)pthread_self
};
static const pthread_attr_t s_default_thread_attributes = {
.stacksize = 4096,
.schedparam = { .sched_priority = tskIDLE_PRIORITY },
.detachstate = PTHREAD_CREATE_JOINABLE
};
struct k_pthread_key
{
void (*destructor)(void *);
};
struct k_pthread_tls
{
std::unordered_map<pthread_key_t, uintptr_t> storage;
};
struct k_pthread
{
pthread_attr_t attr;
StaticSemaphore_t join_mutex;
StaticSemaphore_t join_barrier;
void *(*startroutine)(void *);
void *arg;
TaskHandle_t handle;
void *ret;
k_pthread(pthread_attr_t attr, void *(*startroutine)(void *), void *arg) noexcept
: attr(attr), startroutine(startroutine), arg(arg)
{
if (attr.detachstate == PTHREAD_CREATE_JOINABLE)
{
xSemaphoreCreateMutexStatic(&join_mutex);
xSemaphoreCreateBinaryStatic(&join_barrier);
}
}
BaseType_t create() noexcept
{
auto ret = xTaskCreate(thread_thunk, "posix", (uint16_t)(attr.stacksize / sizeof(StackType_t)), this, attr.schedparam.sched_priority, &handle);
if (ret == pdPASS)
{
/* Store the pointer to the thread object in the task tag. */
vTaskSetApplicationTaskTag(handle, (TaskHookFunction_t)this);
}
return ret;
}
void cancel() noexcept
{
vTaskSuspendAll();
on_exit();
xTaskResumeAll();
}
private:
static void thread_thunk(void *arg)
{
k_pthread *k_thread = reinterpret_cast<k_pthread *>(arg);
k_thread->ret = k_thread->startroutine(k_thread->arg);
k_thread->on_exit();
}
void on_exit()
{
/* If this thread is joinable, wait for a call to pthread_join. */
if (attr.detachstate == PTHREAD_CREATE_JOINABLE)
{
xSemaphoreGive(&join_barrier);
/* Suspend until the call to pthread_join. The caller of pthread_join
* will perform cleanup. */
vTaskSuspend(NULL);
}
else
{
/* For a detached thread, perform cleanup of thread object. */
delete this;
delete reinterpret_cast<k_pthread_tls *>(pvTaskGetThreadLocalStoragePointer(NULL, PTHREAD_TLS_INDEX));
vTaskDelete(NULL);
}
}
};
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*startroutine)(void *), void *arg)
{
int iStatus = 0;
k_pthread *k_thrd = NULL;
/* Allocate memory for new thread object. */
k_thrd = new (std::nothrow) k_pthread(attr ? *attr : s_default_thread_attributes, startroutine, arg);
if (!k_thrd)
{
/* No memory. */
iStatus = EAGAIN;
}
if (iStatus == 0)
{
/* Suspend all tasks to create a critical section. This ensures that
* the new thread doesn't exit before a tag is assigned. */
vTaskSuspendAll();
/* Create the FreeRTOS task that will run the pthread. */
if (k_thrd->create() != pdPASS)
{
/* Task creation failed, no memory. */
delete k_thrd;
iStatus = EAGAIN;
}
else
{
/* Set the thread object for the user. */
*thread = reinterpret_cast<uintptr_t>(k_thrd);
}
/* End the critical section. */
xTaskResumeAll();
}
return iStatus;
}
int pthread_join(pthread_t pthread, void **retval)
{
int iStatus = 0;
k_pthread *k_thrd = reinterpret_cast<k_pthread *>(pthread);
/* Make sure pthread is joinable. Otherwise, this function would block
* forever waiting for an unjoinable thread. */
if (k_thrd->attr.detachstate != PTHREAD_CREATE_JOINABLE)
{
iStatus = EDEADLK;
}
/* Only one thread may attempt to join another. Lock the join mutex
* to prevent other threads from calling pthread_join on the same thread. */
if (iStatus == 0)
{
if (xSemaphoreTake(&k_thrd->join_mutex, 0) != pdPASS)
{
/* Another thread has already joined the requested thread, which would
* cause this thread to wait forever. */
iStatus = EDEADLK;
}
}
/* Attempting to join the calling thread would cause a deadlock. */
if (iStatus == 0)
{
if (pthread_equal(pthread_self(), pthread) != 0)
{
iStatus = EDEADLK;
}
}
if (iStatus == 0)
{
/* Wait for the joining thread to finish. Because this call waits forever,
* it should never fail. */
(void)xSemaphoreTake(&k_thrd->join_barrier, portMAX_DELAY);
/* Create a critical section to clean up the joined thread. */
vTaskSuspendAll();
/* Release xJoinBarrier and delete it. */
(void)xSemaphoreGive(&k_thrd->join_barrier);
vSemaphoreDelete(&k_thrd->join_barrier);
/* Release xJoinMutex and delete it. */
(void)xSemaphoreGive(&k_thrd->join_mutex);
vSemaphoreDelete(&k_thrd->join_mutex);
/* Set the return value. */
if (retval != NULL)
{
*retval = k_thrd->ret;
}
/* Free the thread object. */
delete reinterpret_cast<k_pthread_tls *>(pvTaskGetThreadLocalStoragePointer(k_thrd->handle, PTHREAD_TLS_INDEX));
/* Delete the FreeRTOS task that ran the thread. */
vTaskDelete(k_thrd->handle);
delete k_thrd;
/* End the critical section. */
xTaskResumeAll();
}
return iStatus;
}
pthread_t pthread_self(void)
{
/* Return a reference to this pthread object, which is stored in the
* FreeRTOS task tag. */
return (uintptr_t)xTaskGetApplicationTaskTag(NULL);
}
int pthread_cancel(pthread_t pthread)
{
k_pthread *k_thrd = reinterpret_cast<k_pthread *>(pthread);
k_thrd->cancel();
return 0;
}
int pthread_key_create(pthread_key_t *__key, void (*__destructor)(void *))
{
auto k_key = new (std::nothrow) k_pthread_key;
if (k_key)
{
k_key->destructor = __destructor;
*__key = reinterpret_cast<uintptr_t>(k_key);
return 0;
}
return ENOMEM;
}
int pthread_key_delete(pthread_key_t key)
{
auto k_key = reinterpret_cast<k_pthread_key *>(key);
delete k_key;
return 0;
}
void *pthread_getspecific(pthread_key_t key)
{
auto tls = reinterpret_cast<k_pthread_tls *>(pvTaskGetThreadLocalStoragePointer(NULL, PTHREAD_TLS_INDEX));
if (tls)
{
auto it = tls->storage.find(key);
if (it != tls->storage.end())
return reinterpret_cast<void *>(it->second);
}
return nullptr;
}
int pthread_setspecific(pthread_key_t key, const void *value)
{
auto tls = reinterpret_cast<k_pthread_tls *>(pvTaskGetThreadLocalStoragePointer(NULL, PTHREAD_TLS_INDEX));
if (!tls)
{
tls = new (std::nothrow) k_pthread_tls;
if (!tls)
return ENOMEM;
vTaskSetThreadLocalStoragePointer(NULL, PTHREAD_TLS_INDEX, tls);
}
try
{
tls->storage[key] = uintptr_t(value);
return 0;
}
catch (...)
{
return ENOMEM;
}
}
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
{
while (true)
{
if (atomic_read(&once_control->init_executed) == 1)
return 0;
if (atomic_cas(&once_control->init_executed, 0, 2) == 0)
break;
}
init_routine();
atomic_set(&once_control->init_executed, 1);
return 0;
}
int pthread_equal(pthread_t t1, pthread_t t2)
{
int iStatus = 0;
/* Compare the thread IDs. */
if (t1 && t2)
{
iStatus = (t1 == t2);
}
return iStatus;
}

236
lib/posix/pthread_cond.cpp Normal file
View File

@ -0,0 +1,236 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "utils.h"
#include <FreeRTOS.h>
#include <atomic>
#include <climits>
#include <cstring>
#include <errno.h>
#include <kernel/driver_impl.hpp>
#include <platform.h>
#include <pthread.h>
#include <semphr.h>
#include <task.h>
using namespace sys;
static const pthread_condattr_t s_default_cond_attributes = {
.is_initialized = true,
.clock = portMAX_DELAY
};
struct k_pthread_cond
{
StaticSemaphore_t mutex;
StaticSemaphore_t wait_semphr;
uint32_t waiting_threads;
k_pthread_cond() noexcept
: waiting_threads(0)
{
xSemaphoreCreateMutexStatic(&mutex);
xSemaphoreCreateCountingStatic(UINT_MAX, 0U, &wait_semphr);
}
~k_pthread_cond()
{
vSemaphoreDelete(&mutex);
vSemaphoreDelete(&wait_semphr);
}
semaphore_lock lock() noexcept
{
return { &mutex };
}
void give() noexcept
{
xSemaphoreGive(&wait_semphr);
waiting_threads--;
}
};
static void pthread_cond_init_if_static(pthread_cond_t *cond)
{
if (*cond == PTHREAD_COND_INITIALIZER)
{
configASSERT(pthread_cond_init(cond, nullptr) == 0);
}
}
int pthread_condattr_init(pthread_condattr_t *__attr)
{
*__attr = s_default_cond_attributes;
return 0;
}
int pthread_condattr_destroy(pthread_condattr_t *__attr)
{
__attr->is_initialized = false;
return 0;
}
int pthread_condattr_getclock(const pthread_condattr_t *__attr, clockid_t *__clock_id)
{
*__clock_id = __attr->clock;
return 0;
}
int pthread_condattr_setclock(pthread_condattr_t *__attr, clockid_t __clock_id)
{
__attr->clock = __clock_id;
return 0;
}
int pthread_condattr_getpshared(const pthread_condattr_t *__attr, int *__pshared)
{
*__pshared = 1;
return 0;
}
int pthread_condattr_setpshared(pthread_condattr_t *__attr, int __pshared)
{
return 0;
}
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
{
int iStatus = 0;
k_pthread_cond *k_cond = nullptr;
/* Silence warnings about unused parameters. */
(void)attr;
k_cond = new (std::nothrow) k_pthread_cond();
if (!k_cond)
{
iStatus = ENOMEM;
}
if (iStatus == 0)
{
/* Set the output. */
*cond = reinterpret_cast<uintptr_t>(k_cond);
}
return iStatus;
}
int pthread_cond_destroy(pthread_cond_t *cond)
{
k_pthread_cond *k_cond = reinterpret_cast<k_pthread_cond *>(*cond);
delete k_cond;
return 0;
}
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
return pthread_cond_timedwait(cond, mutex, NULL);
}
int pthread_cond_signal(pthread_cond_t *cond)
{
pthread_cond_init_if_static(cond);
k_pthread_cond *k_cond = reinterpret_cast<k_pthread_cond *>(*cond);
/* Check that at least one thread is waiting for a signal. */
if (k_cond->waiting_threads)
{
/* Lock xCondMutex to protect access to iWaitingThreads.
* This call will never fail because it blocks forever. */
auto lock = k_cond->lock();
xSemaphoreTake(&k_cond->mutex, portMAX_DELAY);
/* Check again that at least one thread is waiting for a signal after
* taking xCondMutex. If so, unblock it. */
if (k_cond->waiting_threads)
k_cond->give();
}
return 0;
}
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
{
int iStatus = 0;
pthread_cond_init_if_static(cond);
k_pthread_cond *k_cond = reinterpret_cast<k_pthread_cond *>(*cond);
TickType_t xDelay = portMAX_DELAY;
/* Convert abstime to a delay in TickType_t if provided. */
if (abstime != NULL)
{
xDelay = timespec_to_ticks(*abstime);
}
/* Increase the counter of threads blocking on condition variable, then
* unlock mutex. */
if (iStatus == 0)
{
{
auto lock = k_cond->lock();
k_cond->waiting_threads++;
}
iStatus = pthread_mutex_unlock(mutex);
}
/* Wait on the condition variable. */
if (iStatus == 0)
{
if (xSemaphoreTake(&k_cond->wait_semphr, xDelay) == pdPASS)
{
/* When successful, relock mutex. */
iStatus = pthread_mutex_lock(mutex);
}
else
{
/* Timeout. Relock mutex and decrement number of waiting threads. */
iStatus = ETIMEDOUT;
(void)pthread_mutex_lock(mutex);
{
auto lock = k_cond->lock();
k_cond->waiting_threads--;
}
}
}
return iStatus;
}
int pthread_cond_broadcast(pthread_cond_t *cond)
{
int i = 0;
pthread_cond_init_if_static(cond);
k_pthread_cond *k_cond = reinterpret_cast<k_pthread_cond *>(*cond);
/* Lock xCondMutex to protect access to iWaitingThreads.
* This call will never fail because it blocks forever. */
auto locker = k_cond->lock();
/* Unblock all threads waiting on this condition variable. */
for (i = 0; i < k_cond->waiting_threads; i++)
{
xSemaphoreGive(&k_cond->wait_semphr);
}
/* All threads were unblocked, set waiting threads to 0. */
k_cond->waiting_threads = 0;
return 0;
}

235
lib/posix/pthread_mutex.cpp Normal file
View File

@ -0,0 +1,235 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "utils.h"
#include <FreeRTOS.h>
#include <atomic>
#include <cstring>
#include <errno.h>
#include <memory>
#include <platform.h>
#include <pthread.h>
#include <semphr.h>
#include <task.h>
static const pthread_mutexattr_t s_default_mutex_attributes = {
.is_initialized = true,
.type = PTHREAD_MUTEX_DEFAULT,
.recursive = 0
};
struct k_pthread_mutex
{
pthread_mutexattr_t attr;
StaticSemaphore_t semphr;
TaskHandle_t owner;
k_pthread_mutex(pthread_mutexattr_t attr) noexcept
: attr(attr)
{
if (attr.type == PTHREAD_MUTEX_RECURSIVE)
xSemaphoreCreateRecursiveMutexStatic(&semphr);
else
xSemaphoreCreateMutexStatic(&semphr);
}
void give() noexcept
{
if (attr.type == PTHREAD_MUTEX_RECURSIVE)
xSemaphoreGiveRecursive(&semphr);
else
xSemaphoreGive(&semphr);
}
void update_owner() noexcept
{
owner = xSemaphoreGetMutexHolder(&semphr);
}
};
static void pthread_mutex_init_if_static(pthread_mutex_t *mutex)
{
if (*mutex == PTHREAD_MUTEX_INITIALIZER)
{
configASSERT(pthread_mutex_init(mutex, nullptr) == 0);
}
}
int pthread_mutexattr_init(pthread_mutexattr_t *__attr)
{
*__attr = s_default_mutex_attributes;
return 0;
}
int pthread_mutexattr_destroy(pthread_mutexattr_t *__attr)
{
__attr->is_initialized = false;
return 0;
}
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *__attr, int *__pshared)
{
*__pshared = 1;
return 0;
}
int pthread_mutexattr_setpshared(pthread_mutexattr_t *__attr, int __pshared)
{
return 0;
}
int pthread_mutexattr_gettype(const pthread_mutexattr_t * __attr, int *__kind)
{
*__kind = __attr->type;
return 0;
}
int pthread_mutexattr_settype(pthread_mutexattr_t * __attr, int __kind)
{
__attr->type = __kind;
return 0;
}
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
{
int iStatus = 0;
k_pthread_mutex *k_mutex = nullptr;
k_mutex = new (std::nothrow) k_pthread_mutex(attr ? *attr : s_default_mutex_attributes);
if (!k_mutex)
{
iStatus = ENOMEM;
}
if (iStatus == 0)
{
/* Set the output. */
*mutex = reinterpret_cast<uintptr_t>(k_mutex);
}
return iStatus;
}
int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
k_pthread_mutex *k_mutex = reinterpret_cast<k_pthread_mutex *>(*mutex);
/* Free resources in use by the mutex. */
if (k_mutex->owner == NULL)
{
delete k_mutex;
}
return 0;
}
int pthread_mutex_lock(pthread_mutex_t *mutex)
{
return pthread_mutex_timedlock(mutex, NULL);
}
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime)
{
pthread_mutex_init_if_static(mutex);
int iStatus = 0;
k_pthread_mutex *k_mutex = reinterpret_cast<k_pthread_mutex *>(*mutex);
TickType_t xDelay = portMAX_DELAY;
BaseType_t xFreeRTOSMutexTakeStatus = pdFALSE;
/* Convert abstime to a delay in TickType_t if provided. */
if (abstime != NULL)
xDelay = timespec_to_ticks(*abstime);
/* Check if trying to lock a currently owned mutex. */
if ((iStatus == 0) && (k_mutex->attr.type == PTHREAD_MUTEX_ERRORCHECK) && /* Only PTHREAD_MUTEX_ERRORCHECK type detects deadlock. */
(k_mutex->owner == xTaskGetCurrentTaskHandle())) /* Check if locking a currently owned mutex. */
{
iStatus = EDEADLK;
}
if (iStatus == 0)
{
/* Call the correct FreeRTOS mutex take function based on mutex type. */
if (k_mutex->attr.type == PTHREAD_MUTEX_RECURSIVE)
{
xFreeRTOSMutexTakeStatus = xSemaphoreTakeRecursive(&k_mutex->semphr, xDelay);
}
else
{
xFreeRTOSMutexTakeStatus = xSemaphoreTake(&k_mutex->semphr, xDelay);
}
/* If the mutex was successfully taken, set its owner. */
if (xFreeRTOSMutexTakeStatus == pdPASS)
{
k_mutex->owner = xTaskGetCurrentTaskHandle();
}
/* Otherwise, the mutex take timed out. */
else
{
iStatus = ETIMEDOUT;
}
}
return iStatus;
}
int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
int iStatus = 0;
struct timespec xTimeout = {
.tv_sec = 0,
.tv_nsec = 0
};
/* Attempt to lock with no timeout. */
iStatus = pthread_mutex_timedlock(mutex, &xTimeout);
/* POSIX specifies that this function should return EBUSY instead of
* ETIMEDOUT for attempting to lock a locked mutex. */
if (iStatus == ETIMEDOUT)
{
iStatus = EBUSY;
}
return iStatus;
}
int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
pthread_mutex_init_if_static(mutex);
int iStatus = 0;
k_pthread_mutex *k_mutex = reinterpret_cast<k_pthread_mutex *>(*mutex);
/* Check if trying to unlock an unowned mutex. */
if (((k_mutex->attr.type == PTHREAD_MUTEX_ERRORCHECK) || (k_mutex->attr.type == PTHREAD_MUTEX_RECURSIVE)) && (k_mutex->owner != xTaskGetCurrentTaskHandle()))
{
iStatus = EPERM;
}
if (iStatus == 0)
{
/* Call the correct FreeRTOS mutex unlock function based on mutex type. */
k_mutex->give();
/* Update the owner of the mutex. A recursive mutex may still have an
* owner, so it should be updated with xSemaphoreGetMutexHolder. */
k_mutex->update_owner();
}
return iStatus;
}

281
lib/posix/socket.cpp Normal file
View File

@ -0,0 +1,281 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sys/socket.h"
#include "utils.h"
#include <kernel/driver_impl.hpp>
#include <network.h>
#include <string.h>
using namespace sys;
#define SOCKET_ENTRY \
auto &obj = system_handle_to_object(socket); \
configASSERT(obj.is<network_socket>()); \
auto f = obj.as<network_socket>();
#define CATCH_ALL \
catch (...) { return -1; }
#define CHECK_ARG(x) \
if (!x) \
throw std::invalid_argument(#x " is invalid.");
static void to_posix_sockaddr(sockaddr_in &addr, const socket_address_t &socket_addr)
{
if (socket_addr.family != AF_INTERNETWORK)
throw std::runtime_error("Invalid socket address.");
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(*reinterpret_cast<const uint16_t *>(socket_addr.data + 4));
addr.sin_addr.s_addr = LWIP_MAKEU32(socket_addr.data[3], socket_addr.data[2], socket_addr.data[1], socket_addr.data[0]);
}
static void to_sys_sockaddr(socket_address_t &addr, const sockaddr_in &socket_addr)
{
if (socket_addr.sin_family != AF_INET)
throw std::runtime_error("Invalid socket address.");
addr.family = AF_INTERNETWORK;
addr.data[3] = (socket_addr.sin_addr.s_addr >> 24) & 0xFF;
addr.data[2] = (socket_addr.sin_addr.s_addr >> 16) & 0xFF;
addr.data[1] = (socket_addr.sin_addr.s_addr >> 8) & 0xFF;
addr.data[0] = socket_addr.sin_addr.s_addr & 0xFF;
*reinterpret_cast<uint16_t *>(addr.data + 4) = ntohs(socket_addr.sin_port);
}
int socket(int domain, int type, int protocol)
{
try
{
address_family_t address_family;
switch (domain)
{
case AF_INET:
address_family = AF_INTERNETWORK;
break;
default:
throw std::invalid_argument("Invalid domain.");
}
socket_type_t s_type;
switch (type)
{
case SOCK_STREAM:
s_type = SOCKET_STREAM;
break;
case SOCK_DGRAM:
s_type = SOCKET_DATAGRAM;
break;
default:
throw std::invalid_argument("Invalid type.");
}
protocol_type_t s_protocol;
switch (protocol)
{
case IPPROTO_IP:
s_protocol = PROTCL_IP;
break;
case IPPROTO_TCP:
s_protocol = PROTCL_IP;
break;
case IPPROTO_UDP:
s_protocol = PROTCL_IP;
break;
default:
throw std::invalid_argument("Invalid protocol.");
}
return network_socket_open(address_family, s_type, s_protocol);
}
catch (...)
{
return NULL_HANDLE;
}
}
int bind(int socket, const struct sockaddr *address, socklen_t address_len)
{
try
{
SOCKET_ENTRY;
CHECK_ARG(address);
socket_address_t local_addr;
to_sys_sockaddr(local_addr, *(reinterpret_cast<const sockaddr_in *>(address)));
f->bind(local_addr);
return 0;
}
CATCH_ALL;
}
int accept(int socket, struct sockaddr *address, socklen_t *address_len)
{
try
{
SOCKET_ENTRY;
CHECK_ARG(address);
socket_address_t remote_addr;
auto ret = f->accept(&remote_addr);
sockaddr_in *addr = reinterpret_cast<sockaddr_in *>(address);
to_posix_sockaddr(*addr, remote_addr);
return system_alloc_handle(std::move(ret));
}
CATCH_ALL;
}
int shutdown(int socket, int how)
{
try
{
SOCKET_ENTRY;
f->shutdown((socket_shutdown_t)how);
return 0;
}
CATCH_ALL;
}
int connect(int socket, const struct sockaddr *address, socklen_t address_len)
{
try
{
SOCKET_ENTRY;
CHECK_ARG(address);
socket_address_t remote_addr;
to_sys_sockaddr(remote_addr, *reinterpret_cast<const sockaddr_in *>(address));
f->connect(remote_addr);
return 0;
}
CATCH_ALL;
}
int listen(int socket, int backlog)
{
try
{
SOCKET_ENTRY;
f->listen(backlog);
return 0;
}
CATCH_ALL;
}
int recv(int socket, void *mem, size_t len, int flags)
{
try
{
socket_message_flag_t recv_flags = MESSAGE_NORMAL;
if (flags & MSG_PEEK)
recv_flags |= MESSAGE_PEEK;
if (flags & MSG_WAITALL)
recv_flags |= MESSAGE_WAITALL;
if (flags & MSG_OOB)
recv_flags |= MESSAGE_OOB;
if (flags & MSG_DONTWAIT)
recv_flags |= MESSAGE_DONTWAIT;
if (flags & MSG_MORE)
recv_flags |= MESSAGE_MORE;
SOCKET_ENTRY;
return f->receive({ (uint8_t *)mem, std::ptrdiff_t(len) }, recv_flags);
}
CATCH_ALL;
}
int send(int socket, const void *data, size_t size, int flags)
{
try
{
socket_message_flag_t send_flags = MESSAGE_NORMAL;
if (flags & MSG_PEEK)
send_flags |= MESSAGE_PEEK;
if (flags & MSG_WAITALL)
send_flags |= MESSAGE_WAITALL;
if (flags & MSG_OOB)
send_flags |= MESSAGE_OOB;
if (flags & MSG_DONTWAIT)
send_flags |= MESSAGE_DONTWAIT;
if (flags & MSG_MORE)
send_flags |= MESSAGE_MORE;
SOCKET_ENTRY;
f->send({ (const uint8_t *)data, std::ptrdiff_t(size) }, send_flags);
return 0;
}
CATCH_ALL;
}
int recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
{
try
{
socket_message_flag_t recv_flags = MESSAGE_NORMAL;
if (flags & MSG_PEEK)
recv_flags |= MESSAGE_PEEK;
if (flags & MSG_WAITALL)
recv_flags |= MESSAGE_WAITALL;
if (flags & MSG_OOB)
recv_flags |= MESSAGE_OOB;
if (flags & MSG_DONTWAIT)
recv_flags |= MESSAGE_DONTWAIT;
if (flags & MSG_MORE)
recv_flags |= MESSAGE_MORE;
SOCKET_ENTRY;
socket_address_t remote_addr;
auto ret = f->receive_from({ (uint8_t *)mem, std::ptrdiff_t(len) }, recv_flags, &remote_addr);
sockaddr_in *addr = reinterpret_cast<sockaddr_in *>(from);
to_posix_sockaddr(*addr, remote_addr);
return ret;
}
CATCH_ALL;
}
int sendto(int socket, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)
{
try
{
socket_message_flag_t send_flags = MESSAGE_NORMAL;
if (flags & MSG_PEEK)
send_flags |= MESSAGE_PEEK;
if (flags & MSG_WAITALL)
send_flags |= MESSAGE_WAITALL;
if (flags & MSG_OOB)
send_flags |= MESSAGE_OOB;
if (flags & MSG_DONTWAIT)
send_flags |= MESSAGE_DONTWAIT;
if (flags & MSG_MORE)
send_flags |= MESSAGE_MORE;
SOCKET_ENTRY;
socket_address_t remote_addr;
to_sys_sockaddr(remote_addr, *reinterpret_cast<const sockaddr_in *>(to));
f->send_to({ (const uint8_t *)data, std::ptrdiff_t(size) }, send_flags, remote_addr);
return 0;
}
CATCH_ALL;
}

23
lib/posix/utils.cpp Normal file
View File

@ -0,0 +1,23 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "utils.h"
#include <FreeRTOS.h>
uint32_t timespec_to_ticks(const struct timespec &ts)
{
uint64_t nsec_ms = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
return pdMS_TO_TICKS(nsec_ms);
}

30
lib/posix/utils.h Normal file
View File

@ -0,0 +1,30 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _POSIX_UTILS_H
#define _POSIX_UTILS_H
#include <cstdint>
#include <sys/time.h>
#ifdef __cplusplus
extern "C" {
#endif
uint32_t timespec_to_ticks(const struct timespec &ts);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1 +1,2 @@
add_subdirectory(fatfs)
add_subdirectory(fatfs)
add_subdirectory(lwip)

4
third_party/lwip/.gitattributes vendored Normal file
View File

@ -0,0 +1,4 @@
# These files are text and should be normalized
*.txt text
*.c text
*.h text

19
third_party/lwip/.gitignore vendored Normal file
View File

@ -0,0 +1,19 @@
*.o
*.a
/doc/doxygen/output/html
/src/apps/snmp/LwipMibCompiler/CCodeGeneration/bin/
/src/apps/snmp/LwipMibCompiler/CCodeGeneration/obj/
/src/apps/snmp/LwipMibCompiler/LwipMibCompiler/bin/
/src/apps/snmp/LwipMibCompiler/LwipMibCompiler/obj/
/src/apps/snmp/LwipMibCompiler/MibViewer/bin/
/src/apps/snmp/LwipMibCompiler/MibViewer/obj/
/src/apps/snmp/LwipMibCompiler/LwipSnmpCodeGeneration/bin/
/src/apps/snmp/LwipMibCompiler/LwipSnmpCodeGeneration/obj/
/src/apps/snmp/LwipMibCompiler/SharpSnmpLib/bin/
/src/apps/snmp/LwipMibCompiler/SharpSnmpLib/obj/
/src/apps/snmp/LwipMibCompiler/LwipMibCompiler.userprefs
/src/apps/snmp/LwipMibCompiler/*.suo
/test/fuzz/output
/test/fuzz/lwip_fuzz
/test/fuzz/.depend
/build

4493
third_party/lwip/CHANGELOG vendored Normal file

File diff suppressed because it is too large Load Diff

7
third_party/lwip/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.7)
project(lwIP)
set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${LWIP_DIR}/src/include ${SDK_ROOT}/lib/freertos/include ${SDK_ROOT}/lib/freertos/conf ${SDK_ROOT}/lib/freertos/portable)
include(src/Filelists.cmake)

33
third_party/lwip/COPYING vendored Normal file
View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2001, 2002 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>
*
*/

11
third_party/lwip/FEATURES vendored Normal file
View File

@ -0,0 +1,11 @@
lwIP is a small independent implementation of the TCP/IP protocol suite targeted at embedded systems.
The focus of the lwIP TCP/IP implementation is to reduce resource usage while still having a full scale TCP. This makes lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM.
Main features include:
- Protocols: IP, IPv6, ICMP, ND, MLD, UDP, TCP, IGMP, ARP, PPPoS, PPPoE, 6LowPAN (via IEEE 802.15.4, BLE or ZEP; since v2.1.0)
- DHCP client, stateless DHCPv6 (since v2.1.0), DNS client (incl. mDNS hostname resolver), AutoIP/APIPA (Zeroconf), SNMP agent (v1, v2c, v3 (since v2.1.0), private MIB support & MIB compiler)
- APIs: specialized APIs for enhanced performance & zero copy, optional Berkeley-alike socket API
- Extended features: IP forwarding over multiple network interfaces
- Extended TCP features: congestion control, RTT estimation and fast recovery/fast retransmit, sending SACKs (since v2.1.0), "altcp": nearly transparent TLS for any tcp pcb (since v2.1.0)
- Addon applications: HTTP server (HTTPS via altcp), HTTP(S) client (since v2.1.0), SNTP client, SMTP client (SMTPS via altcp), ping, NetBIOS nameserver, mDNS responder, MQTT client (TLS support since v2.1.0), TFTP server, iPerf2 counterpart

5
third_party/lwip/FILES vendored Normal file
View File

@ -0,0 +1,5 @@
src/ - The source code for the lwIP TCP/IP stack.
doc/ - The documentation for lwIP.
test/ - Some code to test whether the sources do what they should.
See also the FILES file in each subdirectory.

106
third_party/lwip/README vendored Normal file
View File

@ -0,0 +1,106 @@
INTRODUCTION
lwIP is a small independent implementation of the TCP/IP protocol suite.
The focus of the lwIP TCP/IP implementation is to reduce the RAM usage
while still having a full scale TCP. This making lwIP suitable for use
in embedded systems with tens of kilobytes of free RAM and room for
around 40 kilobytes of code ROM.
lwIP was originally developed by Adam Dunkels at the Computer and Networks
Architectures (CNA) lab at the Swedish Institute of Computer Science (SICS)
and is now developed and maintained by a worldwide network of developers.
FEATURES
* IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over
multiple network interfaces
* ICMP (Internet Control Message Protocol) for network maintenance and debugging
* IGMP (Internet Group Management Protocol) for multicast traffic management
* MLD (Multicast listener discovery for IPv6). Aims to be compliant with
RFC 2710. No support for MLDv2
* ND (Neighbor discovery and stateless address autoconfiguration for IPv6).
Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
(Address autoconfiguration)
* DHCP, AutoIP/APIPA (Zeroconf) and (stateless) DHCPv6
* UDP (User Datagram Protocol) including experimental UDP-lite extensions
* TCP (Transmission Control Protocol) with congestion control, RTT estimation
fast recovery/fast retransmit and sending SACKs
* raw/native API for enhanced performance
* Optional Berkeley-like socket API
* TLS: optional layered TCP ("altcp") for nearly transparent TLS for any
TCP-based protocol (ported to mbedTLS) (see changelog for more info)
* PPPoS and PPPoE (Point-to-point protocol over Serial/Ethernet)
* DNS (Domain name resolver incl. mDNS)
* 6LoWPAN (via IEEE 802.15.4, BLE or ZEP)
APPLICATIONS
* HTTP server with SSI and CGI (HTTPS via altcp)
* SNMPv2c agent with MIB compiler (Simple Network Management Protocol), v3 via altcp
* SNTP (Simple network time protocol)
* NetBIOS name service responder
* MDNS (Multicast DNS) responder
* iPerf server implementation
* MQTT client (TLS support via altcp)
LICENSE
lwIP is freely available under a BSD license.
DEVELOPMENT
lwIP has grown into an excellent TCP/IP stack for embedded devices,
and developers using the stack often submit bug fixes, improvements,
and additions to the stack to further increase its usefulness.
Development of lwIP is hosted on Savannah, a central point for
software development, maintenance and distribution. Everyone can
help improve lwIP by use of Savannah's interface, Git and the
mailing list. A core team of developers will commit changes to the
Git source tree.
The lwIP TCP/IP stack is maintained in the 'lwip' Git module and
contributions (such as platform ports) are in the 'contrib' Git module.
See doc/savannah.txt for details on Git server access for users and
developers.
The current Git trees are web-browsable:
http://git.savannah.gnu.org/cgit/lwip.git
http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git
Submit patches and bugs via the lwIP project page:
http://savannah.nongnu.org/projects/lwip/
Continuous integration builds (GCC, clang):
https://travis-ci.org/yarrick/lwip-merged
DOCUMENTATION
Self documentation of the source code is regularly extracted from the current
Git sources and is available from this web page:
http://www.nongnu.org/lwip/
There is now a constantly growing wiki about lwIP at
http://lwip.wikia.com/wiki/LwIP_Wiki
Also, there are mailing lists you can subscribe at
http://savannah.nongnu.org/mail/?group=lwip
plus searchable archives:
http://lists.nongnu.org/archive/html/lwip-users/
http://lists.nongnu.org/archive/html/lwip-devel/
lwIP was originally written by Adam Dunkels:
http://dunkels.com/adam/
Reading Adam's papers, the files in docs/, browsing the source code
documentation and browsing the mailing list archives is a good way to
become familiar with the design of lwIP.
Adam Dunkels <adam@sics.se>
Leon Woestenberg <leon.woestenberg@gmx.net>

278
third_party/lwip/UPGRADING vendored Normal file
View File

@ -0,0 +1,278 @@
This file lists major changes between release versions that require
ports or applications to be changed. Use it to update a port or an
application written for an older version of lwIP to correctly work
with newer versions.
(git master)
* [Enter new changes just after this line - do not remove this line]
(2.1.0)
++ Application changes:
* Use the new altcp API for seamless TLS integration into existing TCP applications (see changelog)
* TCP only kills existing connections with a LOWER priority than the one currently being opened.
Previous implementations also kill existing connections of the SAME priority.
* ip4_route_src: parameter order is reversed: ip4_route_src(dest, src) -> ip4_route_src(src, dest)
to make parameter order consistent with other ip*_route*() functions.
Same also applies to LWIP_HOOK_IP4_ROUTE_SRC() parameter order.
* pbuf API: pbuf->type (an u8_t holding the enum 'pbuf_type') has changed to only hold a
description of the pbuf (e.g. data following pbuf struct, data volatile, allocation
source heap/pool/etc.). As a consequence, applications can't test pbuf->type any more.
Use pbuf_match_type(pbuf, type) instead.
* socket API: according to the standard, SO_ERROR now only returns asynchronous errors.
All other/normal/synchronous errors are (and always were) available via 'errno'.
LWIP_SOCKET_SET_ERRNO has been removed - 'errno' is always set - and required!
* httpd LWIP_HTTPD_CGI_SSI: httpd_cgi_handler() has an additional parameter "struct fs_file *"
++ Port changes:
* tcpip_trycallback() was renamed to tcpip_callbackmsg_trycallback() to avoid confusion
with tcpip_try_callback()
* compatibility headers: moved from 'src/include/posix' to 'src/include/compat/posix',
'src/include/compat/stdc' etc.
* The IPv6 implementation now supports address scopes. (See LWIP_IPV6_SCOPES documentation
and ip6_zone.h for more documentation)
* LWIP_HOOK_DHCP_APPEND_OPTIONS() has changed, see description in opt.h (options_out_len is not
available in struct dhcp any more)
* Added debug helper asserts to ensure threading/locking requirements are met (define
LWIP_MARK_TCPIP_THREAD() and LWIP_ASSERT_CORE_LOCKED()).
* Added sys_mbox_trypost_fromisr() and tcpip_callbackmsg_trycallback_fromisr()
These can be used to post preallocated messages from an ISR to the tcpip thread
(e.g. when using FreeRTOS)
(2.0.2)
++ Application changes:
* slipif: The way to pass serial port number has changed. netif->num is not
supported any more, netif->state is interpreted as an u8_t port number now
(it's not a POINTER to an u8_t any more!)
(2.0.1)
++ Application changes:
* UDP does NOT receive multicast traffic from ALL netifs on an UDP PCB bound to a specific
netif any more. Users need to bind to IP_ADDR_ANY to receive multicast traffic and compare
ip_current_netif() to the desired netif for every packet.
See bug #49662 for an explanation.
(2.0.0)
++ Application changes:
* Changed netif "up" flag handling to be an administrative flag (as opposed to the previous meaning of
"ip4-address-valid", a netif will now not be used for transmission if not up) -> even a DHCP netif
has to be set "up" before starting the DHCP client
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
* Changed ip_addr_t to be a union in dual-stack mode (use ip4_addr_t where referring to IPv4 only).
* Major rewrite of SNMP (added MIB parser that creates code stubs for custom MIBs);
supports SNMPv2c (experimental v3 support)
* Moved some core applications from contrib repository to src/apps (and include/lwip/apps)
+++ Raw API:
* Changed TCP listen backlog: removed tcp_accepted(), added the function pair tcp_backlog_delayed()/
tcp_backlog_accepted() to explicitly delay backlog handling on a connection pcb
+++ Socket API:
* Added an implementation for posix sendmsg()
* Added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram
++ Port changes
+++ new files:
* MANY new and moved files!
* Added src/Filelists.mk for use in Makefile projects
* Continued moving stack-internal parts from abc.h to abc_priv.h in sub-folder "priv"
to let abc.h only contain the actual application programmer's API
+++ sys layer:
* Made LWIP_TCPIP_CORE_LOCKING==1 the default as it usually performs better than
the traditional message passing (although with LWIP_COMPAT_MUTEX you are still
open to priority inversion, so this is not recommended any more)
* Added LWIP_NETCONN_SEM_PER_THREAD to use one "op_completed" semaphore per thread
instead of using one per netconn (these semaphores are used even with core locking
enabled as some longer lasting functions like big writes still need to delay)
* Added generalized abstraction for itoa(), strnicmp(), stricmp() and strnstr()
in def.h (to be overridden in cc.h) instead of config
options for netbiosns, httpd, dns, etc. ...
* New abstraction for hton* and ntoh* functions in def.h.
To override them, use the following in cc.h:
#define lwip_htons(x) <your_htons>
#define lwip_htonl(x) <your_htonl>
+++ new options:
* TODO
+++ new pools:
* Added LWIP_MEMPOOL_* (declare/init/alloc/free) to declare private memp pools
that share memp.c code but do not have to be made global via lwippools.h
* Added pools for IPv6, MPU_COMPATIBLE, dns-api, netif-api, etc.
* added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when a memp pool was empty and an item
is now available
* Signature of LWIP_HOOK_VLAN_SET macro was changed
* LWIP_DECLARE_MEMORY_ALIGNED() may be used to declare aligned memory buffers (mem/memp)
or to move buffers to dedicated memory using compiler attributes
* Standard C headers are used to define sized types and printf formatters
(disable by setting LWIP_NO_STDINT_H=1 or LWIP_NO_INTTYPES_H=1 if your compiler
does not support these)
++ Major bugfixes/improvements
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
* Major rewrite of PPP (incl. keep-up with apache pppd)
see doc/ppp.txt for an upgrading how-to
* Major rewrite of SNMP (incl. MIB parser)
* Fixed timing issues that might have lead to losing a DHCP lease
* Made rx processing path more robust against crafted errors
* TCP window scaling support
* modification of api modules to support FreeRTOS-MPU (don't pass stack-pointers to other threads)
* made DNS client more robust
* support PBUF_REF for RX packets
* LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate
threads each (needs LWIP_NETCONN_SEM_PER_THREAD)
* Moved and reordered stats (mainly memp/mib2)
(1.4.0)
++ Application changes:
* Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for
compatibility to old applications, but will be removed in the future).
* Renamed mem_realloc() to mem_trim() to prevent confusion with realloc()
+++ Raw API:
* Changed the semantics of tcp_close() (since it was rather a
shutdown before): Now the application does *NOT* get any calls to the recv
callback (aside from NULL/closed) after calling tcp_close()
* When calling tcp_abort() from a raw API TCP callback function,
make sure you return ERR_ABRT to prevent accessing unallocated memory.
(ERR_ABRT now means the applicaiton has called tcp_abort!)
+++ Netconn API:
* Changed netconn_receive() and netconn_accept() to return
err_t, not a pointer to new data/netconn.
+++ Socket API:
* LWIP_SO_RCVTIMEO: when accept() or recv() time out, they
now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT.
* Added a minimal version of posix fctl() to have a
standardised way to set O_NONBLOCK for nonblocking sockets.
+++ all APIs:
* correctly implemented SO(F)_REUSEADDR
++ Port changes
+++ new files:
* Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h:
* Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains
the actual application programmer's API
* Separated timer implementation from sys.h/.c, moved to timers.h/.c;
Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you
still want to use your own timer implementation for NO_SYS==0 (as before).
+++ sys layer:
* Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/
sys_sem_t;
* Converted sys_mbox_new/sys_sem_new to take pointers and return err_t;
* Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use
binary semaphores instead of mutexes - as before)
+++ new options:
* Don't waste memory when chaining segments, added option TCP_OVERSIZE to
prevent creating many small pbufs when calling tcp_write with many small
blocks of data. Instead, pbufs are allocated larger than needed and the
space is used for later calls to tcp_write.
* Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs
in tcp_write/udp_send.
* Added an additional option LWIP_ETHERNET to support ethernet without ARP
(necessary for pure PPPoE)
* Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may
be used to place these pools into user-defined memory by using external
declaration.
* Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT
+++ new pools:
* Netdb uses a memp pool for allocating memory when getaddrinfo() is called,
so MEMP_NUM_NETDB has to be set accordingly.
* DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so
MEMP_NUM_LOCALHOSTLIST has to be set accordingly.
* Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have
to be set accordingly.
* PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES
has to be set accordingly
* Integrated loopif into netif.c - loopif does not have to be created by the
port any more, just define LWIP_HAVE_LOOPIF to 1.
* Added define LWIP_RAND() for lwip-wide randomization (needs to be defined
in cc.h, e.g. used by igmp)
* Added printf-formatter X8_F to printf u8_t as hex
* The heap now may be moved to user-defined memory by defining
LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address
* added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work
with user-allocated structs instead of calling mem_malloc
* Added const char* name to mem- and memp-stats for easier debugging.
* Calculate the TCP/UDP checksum while copying to only fetch data once:
Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum
* Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to
more than one pcb.
* Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned
off any more, if this is set to 0, only one packet (the most recent one) is
queued (like demanded by RFC 1122).
++ Major bugfixes/improvements
* Implemented tcp_shutdown() to only shut down one end of a connection
* Implemented shutdown() at socket- and netconn-level
* Added errorset support to select() + improved select speed overhead
* Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x)
* Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1
* Use macros defined in ip_addr.h to work with IP addresses
* Implemented many nonblocking socket/netconn functions
* Fixed ARP input processing: only add a new entry if a request was directed as us
* mem_realloc() to mem_trim() to prevent confusion with realloc()
* Some improvements for AutoIP (don't route/forward link-local addresses, don't break
existing connections when assigning a routable address)
* Correctly handle remote side overrunning our rcv_wnd in ooseq case
* Removed packing from ip_addr_t, the packed version is now only used in protocol headers
* Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0
* Added support for static ARP table entries
(STABLE-1.3.2)
* initial version of this file

9
third_party/lwip/doc/FILES vendored Normal file
View File

@ -0,0 +1,9 @@
doxygen/ - Configuration files and scripts to create the lwIP doxygen source
documentation (found at http://www.nongnu.org/lwip/)
savannah.txt - How to obtain the current development source code.
contrib.txt - How to contribute to lwIP as a developer.
rawapi.txt - The documentation for the core API of lwIP.
Also provides an overview about the other APIs and multithreading.
sys_arch.txt - The documentation for a system abstraction layer of lwIP.
ppp.txt - Documentation of the PPP interface for lwIP.

122
third_party/lwip/doc/NO_SYS_SampleCode.c vendored Normal file
View File

@ -0,0 +1,122 @@
void
eth_mac_irq()
{
/* Service MAC IRQ here */
/* Allocate pbuf from pool (avoid using heap in interrupts) */
struct pbuf* p = pbuf_alloc(PBUF_RAW, eth_data_count, PBUF_POOL);
if(p != NULL) {
/* Copy ethernet frame into pbuf */
pbuf_take(p, eth_data, eth_data_count);
/* Put in a queue which is processed in main loop */
if(!queue_try_put(&queue, p)) {
/* queue is full -> packet loss */
pbuf_free(p);
}
}
}
static err_t
netif_output(struct netif *netif, struct pbuf *p)
{
LINK_STATS_INC(link.xmit);
/* Update SNMP stats (only if you use SNMP) */
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
int unicast = ((p->payload[0] & 0x01) == 0);
if (unicast) {
MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
} else {
MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
}
lock_interrupts();
pbuf_copy_partial(p, mac_send_buffer, p->tot_len, 0);
/* Start MAC transmit here */
unlock_interrupts();
return ERR_OK;
}
static void
netif_status_callback(struct netif *netif)
{
printf("netif status changed %s\n", ip4addr_ntoa(netif_ip4_addr(netif)));
}
static err_t
netif_init(struct netif *netif)
{
netif->linkoutput = netif_output;
netif->output = etharp_output;
netif->output_ip6 = ethip6_output;
netif->mtu = ETHERNET_MTU;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6;
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 100000000);
SMEMCPY(netif->hwaddr, your_mac_address_goes_here, ETH_HWADDR_LEN);
netif->hwaddr_len = ETH_HWADDR_LEN;
return ERR_OK;
}
void
main(void)
{
struct netif netif;
lwip_init();
netif_add(&netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY, NULL, netif_init, netif_input);
netif.name[0] = 'e';
netif.name[1] = '0';
netif_create_ip6_linklocal_address(&netif, 1);
netif.ip6_autoconfig_enabled = 1;
netif_set_status_callback(&netif, netif_status_callback);
netif_set_default(&netif);
netif_set_up(&netif);
/* Start DHCP and HTTPD */
dhcp_start(&netif );
httpd_init();
while(1) {
/* Check link state, e.g. via MDIO communication with PHY */
if(link_state_changed()) {
if(link_is_up()) {
netif_set_link_up(&netif);
} else {
netif_set_link_down(&netif);
}
}
/* Check for received frames, feed them to lwIP */
lock_interrupts();
struct pbuf* p = queue_try_get(&queue);
unlock_interrupts();
if(p != NULL) {
LINK_STATS_INC(link.recv);
/* Update SNMP stats (only if you use SNMP) */
MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
int unicast = ((p->payload[0] & 0x01) == 0);
if (unicast) {
MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
} else {
MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
}
if(netif.input(p, &netif) != ERR_OK) {
pbuf_free(p);
}
}
/* Cyclic lwIP timers check */
sys_check_timeouts();
/* your application goes here */
}
}

45
third_party/lwip/doc/ZeroCopyRx.c vendored Normal file
View File

@ -0,0 +1,45 @@
typedef struct my_custom_pbuf
{
struct pbuf_custom p;
void* dma_descriptor;
} my_custom_pbuf_t;
LWIP_MEMPOOL_DECLARE(RX_POOL, 10, sizeof(my_custom_pbuf_t), "Zero-copy RX PBUF pool");
void my_pbuf_free_custom(void* p)
{
SYS_ARCH_DECL_PROTECT(old_level);
my_custom_pbuf_t* my_puf = (my_custom_pbuf_t*)p;
// invalidate data cache here - lwIP and/or application may have written into buffer!
// (invalidate is faster than flushing, and noone needs the correct data in the buffer)
invalidate_cpu_cache(p->payload, p->tot_len);
SYS_ARCH_PROTECT(old_level);
free_rx_dma_descriptor(my_pbuf->dma_descriptor);
LWIP_MEMPOOL_FREE(RX_POOL, my_pbuf);
SYS_ARCH_UNPROTECT(old_level);
}
void eth_rx_irq()
{
dma_descriptor* dma_desc = get_RX_DMA_descriptor_from_ethernet();
my_custom_pbuf_t* my_pbuf = (my_custom_pbuf_t*)LWIP_MEMPOOL_ALLOC(RX_POOL);
my_pbuf->p.custom_free_function = my_pbuf_free_custom;
my_pbuf->dma_descriptor = dma_desc;
invalidate_cpu_cache(dma_desc->rx_data, dma_desc->rx_length);
struct pbuf* p = pbuf_alloced_custom(PBUF_RAW,
dma_desc->rx_length,
PBUF_REF,
&my_pbuf->p,
dma_desc->rx_data,
dma_desc->max_buffer_size);
if(netif->input(p, netif) != ERR_OK) {
pbuf_free(p);
}
}

58
third_party/lwip/doc/contrib.txt vendored Normal file
View File

@ -0,0 +1,58 @@
1 Introduction
This document describes some guidelines for people participating
in lwIP development.
2 How to contribute to lwIP
Here is a short list of suggestions to anybody working with lwIP and
trying to contribute bug reports, fixes, enhancements, platform ports etc.
First of all as you may already know lwIP is a volunteer project so feedback
to fixes or questions might often come late. Hopefully the bug and patch tracking
features of Savannah help us not lose users' input.
2.1 Source code style:
1. do not use tabs.
2. indentation is two spaces per level (i.e. per tab).
3. end debug messages with a trailing newline (\n).
4. one space between keyword and opening bracket.
5. no space between function and opening bracket.
6. one space and no newline before opening curly braces of a block.
7. closing curly brace on a single line.
8. spaces surrounding assignment and comparisons.
9. don't initialize static and/or global variables to zero, the compiler takes care of that.
10. use current source code style as further reference.
2.2 Source code documentation style:
1. JavaDoc compliant and Doxygen compatible.
2. Function documentation above functions in .c files, not .h files.
(This forces you to synchronize documentation and implementation.)
3. Use current documentation style as further reference.
2.3 Bug reports and patches:
1. Make sure you are reporting bugs or send patches against the latest
sources. (From the latest release and/or the current Git sources.)
2. If you think you found a bug make sure it's not already filed in the
bugtracker at Savannah.
3. If you have a fix put the patch on Savannah. If it is a patch that affects
both core and arch specific stuff please separate them so that the core can
be applied separately while leaving the other patch 'open'. The preferred way
is to NOT touch archs you can't test and let maintainers take care of them.
This is a good way to see if they are used at all - the same goes for unix
netifs except tapif.
4. Do not file a bug and post a fix to it to the patch area. Either a bug report
or a patch will be enough.
If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area.
5. Patches should be specific to a single change or to related changes. Do not mix bugfixes with spelling and other
trivial fixes unless the bugfix is trivial too. Do not reorganize code and rename identifiers in the same patch you
change behaviour if not necessary. A patch is easier to read and understand if it's to the point and short than
if it's not to the point and long :) so the chances for it to be applied are greater.
2.4 Platform porters:
1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and
you think it could benefit others[1] you might want discuss this on the mailing list. You
can also ask for Git access to submit and maintain your port in the contrib Git module.

View File

@ -0,0 +1 @@
doxygen lwip.Doxyfile

View File

@ -0,0 +1,3 @@
#!/bin/sh
doxygen lwip.Doxyfile

2531
third_party/lwip/doc/doxygen/lwip.Doxyfile vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

403
third_party/lwip/doc/doxygen/main_page.h vendored Normal file
View File

@ -0,0 +1,403 @@
/**
* @defgroup lwip lwIP
*
* @defgroup infrastructure Infrastructure
*
* @defgroup api APIs
* lwIP provides three Application Program's Interfaces (APIs) for programs
* to use for communication with the TCP/IP code:
* - low-level "core" / "callback" or @ref callbackstyle_api.
* - higher-level @ref sequential_api.
* - BSD-style @ref socket.
*
* The raw TCP/IP interface allows the application program to integrate
* better with the TCP/IP code. Program execution is event based by
* having callback functions being called from within the TCP/IP
* code. The TCP/IP code and the application program both run in the same
* thread. The sequential API has a much higher overhead and is not very
* well suited for small systems since it forces a multithreaded paradigm
* on the application.
*
* The raw TCP/IP interface is not only faster in terms of code execution
* time but is also less memory intensive. The drawback is that program
* development is somewhat harder and application programs written for
* the raw TCP/IP interface are more difficult to understand. Still, this
* is the preferred way of writing applications that should be small in
* code size and memory usage.
*
* All APIs can be used simultaneously by different application
* programs. In fact, the sequential API is implemented as an application
* program using the raw TCP/IP interface.
*
* Do not confuse the lwIP raw API with raw Ethernet or IP sockets.
* The former is a way of interfacing the lwIP network stack (including
* TCP and UDP), the latter refers to processing raw Ethernet or IP data
* instead of TCP connections or UDP packets.
*
* Raw API applications may never block since all packet processing
* (input and output) as well as timer processing (TCP mainly) is done
* in a single execution context.
*
* @defgroup callbackstyle_api "raw" APIs
* @ingroup api
* Non thread-safe APIs, callback style for maximum performance and minimum
* memory footprint.
* Program execution is driven by callbacks functions, which are then
* invoked by the lwIP core when activity related to that application
* occurs. A particular application may register to be notified via a
* callback function for events such as incoming data available, outgoing
* data sent, error notifications, poll timer expiration, connection
* closed, etc. An application can provide a callback function to perform
* processing for any or all of these events. Each callback is an ordinary
* C function that is called from within the TCP/IP code. Every callback
* function is passed the current TCP or UDP connection state as an
* argument. Also, in order to be able to keep program specific state,
* the callback functions are called with a program specified argument
* that is independent of the TCP/IP state.
* The raw API (sometimes called native API) is an event-driven API designed
* to be used without an operating system that implements zero-copy send and
* receive. This API is also used by the core stack for interaction between
* the various protocols. It is the only API available when running lwIP
* without an operating system.
*
* @defgroup sequential_api Sequential-style APIs
* @ingroup api
* Sequential-style APIs, blocking functions. More overhead, but can be called
* from any thread except TCPIP thread.
* The sequential API provides a way for ordinary, sequential, programs
* to use the lwIP stack. It is quite similar to the BSD socket API. The
* model of execution is based on the blocking open-read-write-close
* paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
* code and the application program must reside in different execution
* contexts (threads).
*
* @defgroup socket Socket API
* @ingroup api
* BSD-style socket API.\n
* Thread-safe, to be called from non-TCPIP threads only.\n
* Can be activated by defining @ref LWIP_SOCKET to 1.\n
* Header is in posix/sys/socket.h\n
* The socket API is a compatibility API for existing applications,
* currently it is built on top of the sequential API. It is meant to
* provide all functions needed to run socket API applications running
* on other platforms (e.g. unix / windows etc.). However, due to limitations
* in the specification of this API, there might be incompatibilities
* that require small modifications of existing programs.
*
* @defgroup netifs NETIFs
*
* @defgroup apps Applications
*/
/**
* @mainpage Overview
* @verbinclude "README"
*/
/**
* @page upgrading Upgrading
* @verbinclude "UPGRADING"
*/
/**
* @page changelog Changelog
*
* 2.1.0
* -----
* * Support TLS via new @ref altcp_api connection API (https, smtps, mqtt over TLS)
* * Switch to cmake as the main build system (Makefile file lists are still
* maintained for now)
* * Improve IPv6 support: support address scopes, support stateless DHCPv6, bugfixes
* * Add debug helper asserts to ensure threading/locking requirements are met
* * Add sys_mbox_trypost_fromisr() and tcpip_callbackmsg_trycallback_fromisr()
* (for FreeRTOS, mainly)
* * socket API: support poll(), sendmsg() and recvmsg(); fix problems on close
*
* Detailed Changelog
* ------------------
* @verbinclude "CHANGELOG"
*/
/**
* @page contrib How to contribute to lwIP
* @verbinclude "contrib.txt"
*/
/**
* @page pitfalls Common pitfalls
*
* Multiple Execution Contexts in lwIP code
* ========================================
*
* The most common source of lwIP problems is to have multiple execution contexts
* inside the lwIP code.
*
* lwIP can be used in two basic modes: @ref lwip_nosys (no OS/RTOS
* running on target system) or @ref lwip_os (there is an OS running
* on the target system).
*
* See also: @ref multithreading (especially the part about @ref LWIP_ASSERT_CORE_LOCKED()!)
*
* Mainloop Mode
* -------------
* In mainloop mode, only @ref callbackstyle_api can be used.
* The user has two possibilities to ensure there is only one
* exection context at a time in lwIP:
*
* 1) Deliver RX ethernet packets directly in interrupt context to lwIP
* by calling netif->input directly in interrupt. This implies all lwIP
* callback functions are called in IRQ context, which may cause further
* problems in application code: IRQ is blocked for a long time, multiple
* execution contexts in application code etc. When the application wants
* to call lwIP, it only needs to disable interrupts during the call.
* If timers are involved, even more locking code is needed to lock out
* timer IRQ and ethernet IRQ from each other, assuming these may be nested.
*
* 2) Run lwIP in a mainloop. There is example code here: @ref lwip_nosys.
* lwIP is _ONLY_ called from mainloop callstacks here. The ethernet IRQ
* has to put received telegrams into a queue which is polled in the
* mainloop. Ensure lwIP is _NEVER_ called from an interrupt, e.g.
* some SPI IRQ wants to forward data to udp_send() or tcp_write()!
*
* OS Mode
* -------
* In OS mode, @ref callbackstyle_api AND @ref sequential_api can be used.
* @ref sequential_api are designed to be called from threads other than
* the TCPIP thread, so there is nothing to consider here.
* But @ref callbackstyle_api functions must _ONLY_ be called from
* TCPIP thread. It is a common error to call these from other threads
* or from IRQ contexts. Ethernet RX needs to deliver incoming packets
* in the correct way by sending a message to TCPIP thread, this is
* implemented in tcpip_input().
* Again, ensure lwIP is _NEVER_ called from an interrupt, e.g.
* some SPI IRQ wants to forward data to udp_send() or tcp_write()!
*
* 1) tcpip_callback() can be used get called back from TCPIP thread,
* it is safe to call any @ref callbackstyle_api from there.
*
* 2) Use @ref LWIP_TCPIP_CORE_LOCKING. All @ref callbackstyle_api
* functions can be called when lwIP core lock is aquired, see
* @ref LOCK_TCPIP_CORE() and @ref UNLOCK_TCPIP_CORE().
* These macros cannot be used in an interrupt context!
* Note the OS must correctly handle priority inversion for this.
*
* Cache / DMA issues
* ==================
*
* DMA-capable ethernet hardware and zero-copy RX
* ----------------------------------------------
*
* lwIP changes the content of RECEIVED pbufs in the TCP code path.
* This implies one or more cacheline(s) of the RX pbuf become dirty
* and need to be flushed before the memory is handed over to the
* DMA ethernet hardware for the next telegram to be received.
* See http://lists.nongnu.org/archive/html/lwip-devel/2017-12/msg00070.html
* for a more detailed explanation.
* Also keep in mind the user application may also write into pbufs,
* so it is generally a bug not to flush the data cache before handing
* a buffer to DMA hardware.
*
* DMA-capable ethernet hardware and cacheline alignment
* -----------------------------------------------------
* Nice description about DMA capable hardware and buffer handling:
* http://www.pebblebay.com/a-guide-to-using-direct-memory-access-in-embedded-systems-part-two/
* Read especially sections "Cache coherency" and "Buffer alignment".
*/
/**
* @page bugs Reporting bugs
* Please report bugs in the lwIP bug tracker at savannah.\n
* BEFORE submitting, please check if the bug has already been reported!\n
* https://savannah.nongnu.org/bugs/?group=lwip
*/
/**
* @page zerocopyrx Zero-copy RX
* The following code is an example for zero-copy RX ethernet driver:
* @include ZeroCopyRx.c
*/
/**
* @defgroup lwip_nosys Mainloop mode ("NO_SYS")
* @ingroup lwip
* Use this mode if you do not run an OS on your system. \#define NO_SYS to 1.
* Feed incoming packets to netif->input(pbuf, netif) function from mainloop,
* *not* *from* *interrupt* *context*. You can allocate a @ref pbuf in interrupt
* context and put them into a queue which is processed from mainloop.\n
* Call sys_check_timeouts() periodically in the mainloop.\n
* Porting: implement all functions in @ref sys_time, @ref sys_prot and
* @ref compiler_abstraction.\n
* You can only use @ref callbackstyle_api in this mode.\n
* Sample code:\n
* @include NO_SYS_SampleCode.c
*/
/**
* @defgroup lwip_os OS mode (TCPIP thread)
* @ingroup lwip
* Use this mode if you run an OS on your system. It is recommended to
* use an RTOS that correctly handles priority inversion and
* to use @ref LWIP_TCPIP_CORE_LOCKING.\n
* Porting: implement all functions in @ref sys_layer.\n
* You can use @ref callbackstyle_api together with @ref tcpip_callback,
* and all @ref sequential_api.
*/
/**
* @page sys_init System initalization
A truly complete and generic sequence for initializing the lwIP stack
cannot be given because it depends on additional initializations for
your runtime environment (e.g. timers).
We can give you some idea on how to proceed when using the raw API.
We assume a configuration using a single Ethernet netif and the
UDP and TCP transport layers, IPv4 and the DHCP client.
Call these functions in the order of appearance:
- lwip_init(): Initialize the lwIP stack and all of its subsystems.
- netif_add(struct netif *netif, ...):
Adds your network interface to the netif_list. Allocate a struct
netif and pass a pointer to this structure as the first argument.
Give pointers to cleared ip_addr structures when using DHCP,
or fill them with sane numbers otherwise. The state pointer may be NULL.
The init function pointer must point to a initialization function for
your Ethernet netif interface. The following code illustrates its use.
@code{.c}
err_t netif_if_init(struct netif *netif)
{
u8_t i;
for (i = 0; i < ETHARP_HWADDR_LEN; i++) {
netif->hwaddr[i] = some_eth_addr[i];
}
init_my_eth_device();
return ERR_OK;
}
@endcode
For Ethernet drivers, the input function pointer must point to the lwIP
function ethernet_input() declared in "netif/etharp.h". Other drivers
must use ip_input() declared in "lwip/ip.h".
- netif_set_default(struct netif *netif)
Registers the default network interface.
- netif_set_link_up(struct netif *netif)
This is the hardware link state; e.g. whether cable is plugged for wired
Ethernet interface. This function must be called even if you don't know
the current state. Having link up and link down events is optional but
DHCP and IPv6 discover benefit well from those events.
- netif_set_up(struct netif *netif)
This is the administrative (= software) state of the netif, when the
netif is fully configured this function must be called.
- dhcp_start(struct netif *netif)
Creates a new DHCP client for this interface on the first call.
You can peek in the netif->dhcp struct for the actual DHCP status.
- sys_check_timeouts()
When the system is running, you have to periodically call
sys_check_timeouts() which will handle all timers for all protocols in
the stack; add this to your main loop or equivalent.
*/
/**
* @page multithreading Multithreading
* lwIP started targeting single-threaded environments. When adding multi-
* threading support, instead of making the core thread-safe, another
* approach was chosen: there is one main thread running the lwIP core
* (also known as the "tcpip_thread"). When running in a multithreaded
* environment, raw API functions MUST only be called from the core thread
* since raw API functions are not protected from concurrent access (aside
* from pbuf- and memory management functions). Application threads using
* the sequential- or socket API communicate with this main thread through
* message passing.
*
* As such, the list of functions that may be called from
* other threads or an ISR is very limited! Only functions
* from these API header files are thread-safe:
* - api.h
* - netbuf.h
* - netdb.h
* - netifapi.h
* - pppapi.h
* - sockets.h
* - sys.h
*
* Additionaly, memory (de-)allocation functions may be
* called from multiple threads (not ISR!) with NO_SYS=0
* since they are protected by @ref SYS_LIGHTWEIGHT_PROT and/or
* semaphores.
*
* Netconn or Socket API functions are thread safe against the
* core thread but they are not reentrant at the control block
* granularity level. That is, a UDP or TCP control block must
* not be shared among multiple threads without proper locking.
*
* If @ref SYS_LIGHTWEIGHT_PROT is set to 1 and
* @ref LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
* pbuf_free() may also be called from another thread or
* an ISR (since only then, mem_free - for PBUF_RAM - may
* be called from an ISR: otherwise, the HEAP is only
* protected by semaphores).
*
* How to get threading done right
* -------------------------------
*
* It is strongly recommended to implement the LWIP_ASSERT_CORE_LOCKED()
* macro in an application that uses multithreading. lwIP code has
* several places where a check for a correct thread context is
* implemented which greatly helps the user to get threading done right.
* See the example sys_arch.c files in unix and Win32 port
* in the contrib repository.
*
* In short: Copy the functions sys_mark_tcpip_thread() and
* sys_check_core_locking() to your port and modify them to work with your OS.
* Then let @ref LWIP_ASSERT_CORE_LOCKED() and @ref LWIP_MARK_TCPIP_THREAD()
* point to these functions.
*
* If you use @ref LWIP_TCPIP_CORE_LOCKING, you also need to copy and adapt
* the functions sys_lock_tcpip_core() and sys_unlock_tcpip_core().
* Let @ref LOCK_TCPIP_CORE() and @ref UNLOCK_TCPIP_CORE() point
* to these functions.
*/
/**
* @page optimization Optimization hints
The first thing you want to optimize is the lwip_standard_checksum()
routine from src/core/inet.c. You can override this standard
function with the \#define LWIP_CHKSUM your_checksum_routine().
There are C examples given in inet.c or you might want to
craft an assembly function for this. RFC1071 is a good
introduction to this subject.
Other significant improvements can be made by supplying
assembly or inline replacements for htons() and htonl()
if you're using a little-endian architecture.
\#define lwip_htons(x) your_htons()
\#define lwip_htonl(x) your_htonl()
If you \#define them to htons() and htonl(), you should
\#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from
defining htonx / ntohx compatibility macros.
Check your network interface driver if it reads at
a higher speed than the maximum wire-speed. If the
hardware isn't serviced frequently and fast enough
buffer overflows are likely to occur.
E.g. when using the cs8900 driver, call cs8900if_service(ethif)
as frequently as possible. When using an RTOS let the cs8900 interrupt
wake a high priority task that services your driver using a binary
semaphore or event flag. Some drivers might allow additional tuning
to match your application and network.
For a production release it is recommended to set LWIP_STATS to 0.
Note that speed performance isn't influenced much by simply setting
high values to the memory options.
*/

View File

@ -0,0 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Redirection</title>
<meta http-equiv="refresh" content="0; url=html/index.html" />
</head>
<body>
<a href="html/index.html">index.html</a>
</body>
</html>

112
third_party/lwip/doc/mdns.txt vendored Normal file
View File

@ -0,0 +1,112 @@
Multicast DNS for lwIP
Author: Erik Ekman
Note! The MDNS responder does not have all features required by the standards.
See notes in src/apps/mdns/mdns.c for what is left. It is however usable in normal
cases - but watch out if many devices on the same network try to use the same
host/service instance names.
How to enable:
==============
MDNS support does not depend on DNS.
MDNS supports using IPv4 only, v6 only, or v4+v6.
To enable MDNS responder, set
LWIP_MDNS_RESPONDER = 1
in lwipopts.h and add src/apps/mdns/mdns.c to your list of files to build.
The max number of services supported per netif is defined by MDNS_MAX_SERVICES,
default is 1.
Increase MEMP_NUM_UDP_PCB by 1. MDNS needs one PCB.
Increase LWIP_NUM_NETIF_CLIENT_DATA by 1 (MDNS needs one entry on netif).
MDNS with IPv4 requires LWIP_IGMP = 1, and preferably LWIP_AUTOIP = 1.
MDNS with IPv6 requires LWIP_IPV6_MLD = 1, and that a link-local address is
generated.
The MDNS code puts its structs on the stack where suitable to reduce dynamic
memory allocation. It may use up to 1kB of stack.
MDNS (like other apps) needs a strncasecmp() implementation. If you have one, define
'lwip_strnicmp' to it. Otherwise the code will provide an implementation
for you.
How to use:
===========
Call mdns_resp_init() during system initialization.
This opens UDP sockets on port 5353 for IPv4 and IPv6.
To start responding on a netif, run
mdns_resp_add_netif(struct netif *netif, char *hostname, u32_t dns_ttl)
The hostname will be copied. If this returns successfully, the netif will join
the multicast groups and any MDNS/legacy DNS requests sent unicast or multicast
to port 5353 will be handled:
- <hostname>.local type A, AAAA or ANY returns relevant IP addresses
- Reverse lookups (PTR in-addr.arpa, ip6.arpa) of netif addresses
returns <hostname>.local
Answers will use the supplied TTL (in seconds)
MDNS allows UTF-8 names, but it is recommended to stay within ASCII,
since the default case-insensitive comparison assumes this.
Call mdns_resp_announce() every time the IP address on the netif has changed.
Call mdns_resp_restart() every time the network interface comes up after being
down, for example cable connected after being disconnected, administrative
interface comes up after being down, or the device wakes up from sleep.
To stop responding on a netif, run
mdns_resp_remove_netif(struct netif *netif)
Adding services:
================
The netif first needs to be registered. Then run
mdns_resp_add_service(struct netif *netif, char *name, char *service,
u16_t proto, u16_t port, u32_t dns_ttl,
service_get_txt_fn_t txt_fn, void *txt_userdata);
The name and service pointers will be copied. Name refers to the name of the
service instance, and service is the type of service, like _http
proto can be DNSSD_PROTO_UDP or DNSSD_PROTO_TCP which represent _udp and _tcp.
If this call returns successfully, the following queries will be answered:
- _services._dns-sd._udp.local type PTR returns <service>.<proto>.local
- <service>.<proto>.local type PTR returns <name>.<service>.<proto>.local
- <name>.<service>.<proto>.local type SRV returns hostname and port of service
- <name>.<service>.<proto>.local type TXT builds text strings by calling txt_fn
with the supplied userdata. The callback adds strings to the reply by calling
mdns_resp_add_service_txtitem(struct mdns_service *service, char *txt,
int txt_len). Example callback method:
static void srv_txt(struct mdns_service *service, void *txt_userdata)
{
res = mdns_resp_add_service_txtitem(service, "path=/", 6);
LWIP_ERROR("mdns add service txt failed\n", (res == ERR_OK), return);
}
Since a hostname struct is used for TXT storage each single item can be max
63 bytes long, and the total max length (including length bytes for each
item) is 255 bytes.
If your device runs a webserver on port 80, an example call might be:
mdns_resp_add_service(netif, "myweb", "_http"
DNSSD_PROTO_TCP, 80, 3600, srv_txt, NULL);
which will publish myweb._http._tcp.local for any hosts looking for web servers,
and point them to <hostname>.local:80
Relevant information will be sent as additional records to reduce number of
requests required from a client.
To remove a service from a netif, run
mdns_resp_del_service(struct netif *netif, s8_t slot)

162
third_party/lwip/doc/mqtt_client.txt vendored Normal file
View File

@ -0,0 +1,162 @@
MQTT client for lwIP
Author: Erik Andersson
Details of the MQTT protocol can be found at:
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
-----------------------------------------------------------------
1. Initial steps, reserve memory and make connection to server:
1.1: Provide storage
Static allocation:
mqtt_client_t static_client;
example_do_connect(&static_client);
Dynamic allocation:
mqtt_client_t *client = mqtt_client_new();
if(client != NULL) {
example_do_connect(&client);
}
1.2: Establish Connection with server
void example_do_connect(mqtt_client_t *client)
{
struct mqtt_connect_client_info_t ci;
err_t err;
/* Setup an empty client info structure */
memset(&ci, 0, sizeof(ci));
/* Minimal amount of information required is client identifier, so set it here */
ci.client_id = "lwip_test";
/* Initiate client and connect to server, if this fails immediately an error code is returned
otherwise mqtt_connection_cb will be called with connection result after attempting
to establish a connection with the server.
For now MQTT version 3.1.1 is always used */
err = mqtt_client_connect(client, ip_addr, MQTT_PORT, mqtt_connection_cb, 0, &ci);
/* For now just print the result code if something goes wrong */
if(err != ERR_OK) {
printf("mqtt_connect return %d\n", err);
}
}
Connection to server can also be probed by calling mqtt_client_is_connected(client)
-----------------------------------------------------------------
2. Implementing the connection status callback
static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
{
err_t err;
if(status == MQTT_CONNECT_ACCEPTED) {
printf("mqtt_connection_cb: Successfully connected\n");
/* Setup callback for incoming publish requests */
mqtt_set_inpub_callback(client, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, arg);
/* Subscribe to a topic named "subtopic" with QoS level 1, call mqtt_sub_request_cb with result */
err = mqtt_subscribe(client, "subtopic", 1, mqtt_sub_request_cb, arg);
if(err != ERR_OK) {
printf("mqtt_subscribe return: %d\n", err);
}
} else {
printf("mqtt_connection_cb: Disconnected, reason: %d\n", status);
/* Its more nice to be connected, so try to reconnect */
example_do_connect(client);
}
}
static void mqtt_sub_request_cb(void *arg, err_t result)
{
/* Just print the result code here for simplicity,
normal behaviour would be to take some action if subscribe fails like
notifying user, retry subscribe or disconnect from server */
printf("Subscribe result: %d\n", result);
}
-----------------------------------------------------------------
3. Implementing callbacks for incoming publish and data
/* The idea is to demultiplex topic and create some reference to be used in data callbacks
Example here uses a global variable, better would be to use a member in arg
If RAM and CPU budget allows it, the easiest implementation might be to just take a copy of
the topic string and use it in mqtt_incoming_data_cb
*/
static int inpub_id;
static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len)
{
printf("Incoming publish at topic %s with total length %u\n", topic, (unsigned int)tot_len);
/* Decode topic string into a user defined reference */
if(strcmp(topic, "print_payload") == 0) {
inpub_id = 0;
} else if(topic[0] == 'A') {
/* All topics starting with 'A' might be handled at the same way */
inpub_id = 1;
} else {
/* For all other topics */
inpub_id = 2;
}
}
static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
{
printf("Incoming publish payload with length %d, flags %u\n", len, (unsigned int)flags);
if(flags & MQTT_DATA_FLAG_LAST) {
/* Last fragment of payload received (or whole part if payload fits receive buffer
See MQTT_VAR_HEADER_BUFFER_LEN) */
/* Call function or do action depending on reference, in this case inpub_id */
if(inpub_id == 0) {
/* Don't trust the publisher, check zero termination */
if(data[len-1] == 0) {
printf("mqtt_incoming_data_cb: %s\n", (const char *)data);
}
} else if(inpub_id == 1) {
/* Call an 'A' function... */
} else {
printf("mqtt_incoming_data_cb: Ignoring payload...\n");
}
} else {
/* Handle fragmented payload, store in buffer, write to file or whatever */
}
}
-----------------------------------------------------------------
4. Using outgoing publish
void example_publish(mqtt_client_t *client, void *arg)
{
const char *pub_payload= "PubSubHubLubJub";
err_t err;
u8_t qos = 2; /* 0 1 or 2, see MQTT specification */
u8_t retain = 0; /* No don't retain such crappy payload... */
err = mqtt_publish(client, "pub_topic", pub_payload, strlen(pub_payload), qos, retain, mqtt_pub_request_cb, arg);
if(err != ERR_OK) {
printf("Publish err: %d\n", err);
}
}
/* Called when publish is complete either with sucess or failure */
static void mqtt_pub_request_cb(void *arg, err_t result)
{
if(result != ERR_OK) {
printf("Publish result: %d\n", result);
}
}
-----------------------------------------------------------------
5. Disconnecting
Simply call mqtt_disconnect(client)

529
third_party/lwip/doc/ppp.txt vendored Normal file
View File

@ -0,0 +1,529 @@
PPP interface for lwIP
Author: Sylvain Rochet
Table of Contents:
1 - Supported PPP protocols and features
2 - Raw API PPP example for all protocols
3 - PPPoS input path (raw API, IRQ safe API, TCPIP API)
4 - Thread safe PPP API (PPPAPI)
5 - Notify phase callback (PPP_NOTIFY_PHASE)
6 - Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x
1 Supported PPP protocols and features
======================================
Supported Low level protocols:
* PPP over serial using HDLC-like framing, such as wired dialup modems
or mobile telecommunications GPRS/EDGE/UMTS/HSPA+/LTE modems
* PPP over Ethernet, such as xDSL modems
* PPP over L2TP (Layer 2 Tunneling Protocol) LAC (L2TP Access Concentrator),
IP tunnel over UDP, such as VPN access
Supported auth protocols:
* PAP, Password Authentication Protocol
* CHAP, Challenge-Handshake Authentication Protocol, also known as CHAP-MD5
* MSCHAPv1, Microsoft version of CHAP, version 1
* MSCHAPv2, Microsoft version of CHAP, version 2
* EAP, Extensible Authentication Protocol
Supported address protocols:
* IPCP, IP Control Protocol, IPv4 addresses negotiation
* IP6CP, IPv6 Control Protocol, IPv6 link-local addresses negotiation
Supported encryption protocols:
* MPPE, Microsoft Point-to-Point Encryption
Supported compression or miscellaneous protocols, for serial links only:
* PFC, Protocol Field Compression
* ACFC, Address-and-Control-Field-Compression
* ACCM, Asynchronous-Control-Character-Map
* VJ, Van Jacobson TCP/IP Header Compression
2 Raw API PPP example for all protocols
=======================================
As usual, raw API for lwIP means the lightweight API which *MUST* only be used
for NO_SYS=1 systems or called inside lwIP core thread for NO_SYS=0 systems.
/*
* Globals
* =======
*/
/* The PPP control block */
ppp_pcb *ppp;
/* The PPP IP interface */
struct netif ppp_netif;
/*
* PPP status callback
* ===================
*
* PPP status callback is called on PPP status change (up, down, …) from lwIP
* core thread
*/
/* PPP status callback example */
static void status_cb(ppp_pcb *pcb, int err_code, void *ctx) {
struct netif *pppif = ppp_netif(pcb);
LWIP_UNUSED_ARG(ctx);
switch(err_code) {
case PPPERR_NONE: {
#if LWIP_DNS
const ip_addr_t *ns;
#endif /* LWIP_DNS */
printf("status_cb: Connected\n");
#if PPP_IPV4_SUPPORT
printf(" our_ipaddr = %s\n", ipaddr_ntoa(&pppif->ip_addr));
printf(" his_ipaddr = %s\n", ipaddr_ntoa(&pppif->gw));
printf(" netmask = %s\n", ipaddr_ntoa(&pppif->netmask));
#if LWIP_DNS
ns = dns_getserver(0);
printf(" dns1 = %s\n", ipaddr_ntoa(ns));
ns = dns_getserver(1);
printf(" dns2 = %s\n", ipaddr_ntoa(ns));
#endif /* LWIP_DNS */
#endif /* PPP_IPV4_SUPPORT */
#if PPP_IPV6_SUPPORT
printf(" our6_ipaddr = %s\n", ip6addr_ntoa(netif_ip6_addr(pppif, 0)));
#endif /* PPP_IPV6_SUPPORT */
break;
}
case PPPERR_PARAM: {
printf("status_cb: Invalid parameter\n");
break;
}
case PPPERR_OPEN: {
printf("status_cb: Unable to open PPP session\n");
break;
}
case PPPERR_DEVICE: {
printf("status_cb: Invalid I/O device for PPP\n");
break;
}
case PPPERR_ALLOC: {
printf("status_cb: Unable to allocate resources\n");
break;
}
case PPPERR_USER: {
printf("status_cb: User interrupt\n");
break;
}
case PPPERR_CONNECT: {
printf("status_cb: Connection lost\n");
break;
}
case PPPERR_AUTHFAIL: {
printf("status_cb: Failed authentication challenge\n");
break;
}
case PPPERR_PROTOCOL: {
printf("status_cb: Failed to meet protocol\n");
break;
}
case PPPERR_PEERDEAD: {
printf("status_cb: Connection timeout\n");
break;
}
case PPPERR_IDLETIMEOUT: {
printf("status_cb: Idle Timeout\n");
break;
}
case PPPERR_CONNECTTIME: {
printf("status_cb: Max connect time reached\n");
break;
}
case PPPERR_LOOPBACK: {
printf("status_cb: Loopback detected\n");
break;
}
default: {
printf("status_cb: Unknown error code %d\n", err_code);
break;
}
}
/*
* This should be in the switch case, this is put outside of the switch
* case for example readability.
*/
if (err_code == PPPERR_NONE) {
return;
}
/* ppp_close() was previously called, don't reconnect */
if (err_code == PPPERR_USER) {
/* ppp_free(); -- can be called here */
return;
}
/*
* Try to reconnect in 30 seconds, if you need a modem chatscript you have
* to do a much better signaling here ;-)
*/
ppp_connect(pcb, 30);
/* OR ppp_listen(pcb); */
}
/*
* Creating a new PPPoS session
* ============================
*
* In lwIP, PPPoS is not PPPoSONET, in lwIP PPPoS is PPPoSerial.
*/
#include "netif/ppp/pppos.h"
/*
* PPPoS serial output callback
*
* ppp_pcb, PPP control block
* data, buffer to write to serial port
* len, length of the data buffer
* ctx, optional user-provided callback context pointer
*
* Return value: len if write succeed
*/
static u32_t output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) {
return uart_write(UART, data, len);
}
/*
* Create a new PPPoS interface
*
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
* output_cb, PPPoS serial output callback
* status_cb, PPP status callback, called on PPP status change (up, down, …)
* ctx_cb, optional user-provided callback context pointer
*/
ppp = pppos_create(&ppp_netif,
output_cb, status_cb, ctx_cb);
/*
* Creating a new PPPoE session
* ============================
*/
#include "netif/ppp/pppoe.h"
/*
* Create a new PPPoE interface
*
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
* ethif, already existing and setup Ethernet interface to use
* service_name, PPPoE service name discriminator (not supported yet)
* concentrator_name, PPPoE concentrator name discriminator (not supported yet)
* status_cb, PPP status callback, called on PPP status change (up, down, …)
* ctx_cb, optional user-provided callback context pointer
*/
ppp = pppoe_create(&ppp_netif,
&ethif,
service_name, concentrator_name,
status_cb, ctx_cb);
/*
* Creating a new PPPoL2TP session
* ===============================
*/
#include "netif/ppp/pppol2tp.h"
/*
* Create a new PPPoL2TP interface
*
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
* netif, optional already existing and setup output netif, necessary if you
* want to set this interface as default route to settle the chicken
* and egg problem with VPN links
* ipaddr, IP to connect to
* port, UDP port to connect to (usually 1701)
* secret, L2TP secret to use
* secret_len, size in bytes of the L2TP secret
* status_cb, PPP status callback, called on PPP status change (up, down, …)
* ctx_cb, optional user-provided callback context pointer
*/
ppp = pppol2tp_create(&ppp_netif,
struct netif *netif, ip_addr_t *ipaddr, u16_t port,
u8_t *secret, u8_t secret_len,
ppp_link_status_cb_fn link_status_cb, void *ctx_cb);
/*
* Initiate PPP client connection
* ==============================
*/
/* Set this interface as default route */
ppp_set_default(ppp);
/*
* Basic PPP client configuration. Can only be set if PPP session is in the
* dead state (i.e. disconnected). We don't need to provide thread-safe
* equivalents through PPPAPI because those helpers are only changing
* structure members while session is inactive for lwIP core. Configuration
* only need to be done once.
*/
/* Ask the peer for up to 2 DNS server addresses. */
ppp_set_usepeerdns(ppp, 1);
/* Auth configuration, this is pretty self-explanatory */
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password");
/*
* Initiate PPP negotiation, without waiting (holdoff=0), can only be called
* if PPP session is in the dead state (i.e. disconnected).
*/
u16_t holdoff = 0;
ppp_connect(ppp, holdoff);
/*
* Initiate PPP server listener
* ============================
*/
/*
* Basic PPP server configuration. Can only be set if PPP session is in the
* dead state (i.e. disconnected). We don't need to provide thread-safe
* equivalents through PPPAPI because those helpers are only changing
* structure members while session is inactive for lwIP core. Configuration
* only need to be done once.
*/
ip4_addr_t addr;
/* Set our address */
IP4_ADDR(&addr, 192,168,0,1);
ppp_set_ipcp_ouraddr(ppp, &addr);
/* Set peer(his) address */
IP4_ADDR(&addr, 192,168,0,2);
ppp_set_ipcp_hisaddr(ppp, &addr);
/* Set primary DNS server */
IP4_ADDR(&addr, 192,168,10,20);
ppp_set_ipcp_dnsaddr(ppp, 0, &addr);
/* Set secondary DNS server */
IP4_ADDR(&addr, 192,168,10,21);
ppp_set_ipcp_dnsaddr(ppp, 1, &addr);
/* Auth configuration, this is pretty self-explanatory */
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password");
/* Require peer to authenticate */
ppp_set_auth_required(ppp, 1);
/*
* Only for PPPoS, the PPP session should be up and waiting for input.
*
* Note: for PPPoS, ppp_connect() and ppp_listen() are actually the same thing.
* The listen call is meant for future support of PPPoE and PPPoL2TP server
* mode, where we will need to negotiate the incoming PPPoE session or L2TP
* session before initiating PPP itself. We need this call because there is
* two passive modes for PPPoS, ppp_set_passive and ppp_set_silent.
*/
ppp_set_silent(pppos, 1);
/*
* Initiate PPP listener (i.e. wait for an incoming connection), can only
* be called if PPP session is in the dead state (i.e. disconnected).
*/
ppp_listen(ppp);
/*
* Closing PPP connection
* ======================
*/
/*
* Initiate the end of the PPP session, without carrier lost signal
* (nocarrier=0), meaning a clean shutdown of PPP protocols.
* You can call this function at anytime.
*/
u8_t nocarrier = 0;
ppp_close(ppp, nocarrier);
/*
* Then you must wait your status_cb() to be called, it may takes from a few
* seconds to several tens of seconds depending on the current PPP state.
*/
/*
* Freeing a PPP connection
* ========================
*/
/*
* Free the PPP control block, can only be called if PPP session is in the
* dead state (i.e. disconnected). You need to call ppp_close() before.
*/
ppp_free(ppp);
3 PPPoS input path (raw API, IRQ safe API, TCPIP API)
=====================================================
Received data on serial port should be sent to lwIP using the pppos_input()
function or the pppos_input_tcpip() function.
If NO_SYS is 1 and if PPP_INPROC_IRQ_SAFE is 0 (the default), pppos_input()
is not IRQ safe and then *MUST* only be called inside your main loop.
Whatever the NO_SYS value, if PPP_INPROC_IRQ_SAFE is 1, pppos_input() is IRQ
safe and can be safely called from an interrupt context, using that is going
to reduce your need of buffer if pppos_input() is called byte after byte in
your rx serial interrupt.
if NO_SYS is 0, the thread safe way outside an interrupt context is to use
the pppos_input_tcpip() function to pass input data to the lwIP core thread
using the TCPIP API. This is thread safe in all cases but you should avoid
passing data byte after byte because it uses heavy locking (mailbox) and it
allocates pbuf, better fill them !
if NO_SYS is 0 and if PPP_INPROC_IRQ_SAFE is 1, you may also use pppos_input()
from an RX thread, however pppos_input() is not thread safe by itself. You can
do that *BUT* you should NEVER call pppos_connect(), pppos_listen() and
ppp_free() if pppos_input() can still be running, doing this is NOT thread safe
at all. Using PPP_INPROC_IRQ_SAFE from an RX thread is discouraged unless you
really know what you are doing, your move ;-)
/*
* Fonction to call for received data
*
* ppp, PPP control block
* buffer, input buffer
* buffer_len, buffer length in bytes
*/
void pppos_input(ppp, buffer, buffer_len);
or
void pppos_input_tcpip(ppp, buffer, buffer_len);
4 Thread safe PPP API (PPPAPI)
==============================
There is a thread safe API for all corresponding ppp_* functions, you have to
enable LWIP_PPP_API in your lwipopts.h file, then see
include/netif/ppp/pppapi.h, this is actually pretty obvious.
5 Notify phase callback (PPP_NOTIFY_PHASE)
==========================================
Notify phase callback, enabled using the PPP_NOTIFY_PHASE config option, let
you configure a callback that is called on each PPP internal state change.
This is different from the status callback which only warns you about
up(running) and down(dead) events.
Notify phase callback can be used, for example, to set a LED pattern depending
on the current phase of the PPP session. Here is a callback example which
tries to mimic what we usually see on xDSL modems while they are negotiating
the link, which should be self-explanatory:
static void ppp_notify_phase_cb(ppp_pcb *pcb, u8_t phase, void *ctx) {
switch (phase) {
/* Session is down (either permanently or briefly) */
case PPP_PHASE_DEAD:
led_set(PPP_LED, LED_OFF);
break;
/* We are between two sessions */
case PPP_PHASE_HOLDOFF:
led_set(PPP_LED, LED_SLOW_BLINK);
break;
/* Session just started */
case PPP_PHASE_INITIALIZE:
led_set(PPP_LED, LED_FAST_BLINK);
break;
/* Session is running */
case PPP_PHASE_RUNNING:
led_set(PPP_LED, LED_ON);
break;
default:
break;
}
}
6 Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x
===============================================
PPP API was fully reworked between 1.4.x and 2.0.x releases. However porting
from previous lwIP version is pretty easy:
* Previous PPP API used an integer to identify PPP sessions, we are now
using ppp_pcb* control block, therefore all functions changed from "int ppp"
to "ppp_pcb *ppp"
* struct netif was moved outside the PPP structure, you have to provide a netif
for PPP interface in pppoX_create() functions
* PPP session are not started automatically after you created them anymore,
you have to call ppp_connect(), this way you can configure the session before
starting it.
* Previous PPP API used CamelCase, we are now using snake_case.
* Previous PPP API mixed PPPoS and PPPoE calls, this isn't the case anymore,
PPPoS functions are now prefixed pppos_ and PPPoE functions are now prefixed
pppoe_, common functions are now prefixed ppp_.
* New PPPERR_ error codes added, check you have all of them in your status
callback function
* Only the following include files should now be used in user application:
#include "netif/ppp/pppapi.h"
#include "netif/ppp/pppos.h"
#include "netif/ppp/pppoe.h"
#include "netif/ppp/pppol2tp.h"
Functions from ppp.h can be used, but you don't need to include this header
file as it is already included by above header files.
* PPP_INPROC_OWNTHREAD was broken by design and was removed, you have to create
your own serial rx thread
* PPP_INPROC_MULTITHREADED option was misnamed and confusing and was renamed
PPP_INPROC_IRQ_SAFE, please read the "PPPoS input path" documentation above
because you might have been fooled by that
* If you used tcpip_callback_with_block() on ppp_ functions you may wish to use
the PPPAPI API instead.
* ppp_sighup and ppp_close functions were merged using an optional argument
"nocarrier" on ppp_close.
* DNS servers are now only remotely asked if LWIP_DNS is set and if
ppp_set_usepeerdns() is set to true, they are now automatically registered
using the dns_setserver() function so you don't need to do that in the PPP
callback anymore.
* PPPoS does not use the SIO API anymore, as such it now requires a serial
output callback in place of sio_write
* PPP_MAXIDLEFLAG is now in ms instead of jiffies

120
third_party/lwip/doc/savannah.txt vendored Normal file
View File

@ -0,0 +1,120 @@
Daily Use Guide for using Savannah for lwIP
Table of Contents:
1 - Obtaining lwIP from the Git repository
2 - Committers/developers Git access using SSH
3 - Merging a development branch to master branch
4 - How to release lwIP
1 Obtaining lwIP from the Git repository
----------------------------------------
To perform an anonymous Git clone of the master branch (this is where
bug fixes and incremental enhancements occur), do this:
git clone git://git.savannah.nongnu.org/lwip.git
Or, obtain a stable branch (updated with bug fixes only) as follows:
git clone --branch DEVEL-1_4_1 git://git.savannah.nongnu.org/lwip.git
Or, obtain a specific (fixed) release as follows:
git clone --branch STABLE-1_4_1 git://git.savannah.nongnu.org/lwip.git
2 Committers/developers Git access using SSH
--------------------------------------------
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
As such, Git commits to the server occur through a SSH tunnel for project members.
To create a SSH2 key pair in UNIX-like environments, do this:
ssh-keygen
Under Windows, a recommended SSH client is "PuTTY", freely available with good
documentation and a graphic user interface. Use its key generator.
Now paste the id_rsa.pub contents into your Savannah account public key list. Wait
a while so that Savannah can update its configuration (This can take minutes).
Try to login using SSH:
ssh -v your_login@git.sv.gnu.org
If it tells you:
Linux vcs.savannah.gnu.org 2.6.32-5-xen-686 #1 SMP Wed Jun 17 17:10:03 UTC 2015 i686
Interactive shell login is not possible for security reasons.
VCS commands are allowed.
Last login: Tue May 15 23:10:12 2012 from 82.245.102.129
You tried to execute:
Sorry, you are not allowed to execute that command.
Shared connection to git.sv.gnu.org closed.
then you could login; Savannah refuses to give you a shell - which is OK, as we
are allowed to use SSH for Git only. Now, you should be able to do this:
git clone your_login@git.sv.gnu.org:/srv/git/lwip.git
After which you can edit your local files with bug fixes or new features and
commit them. Make sure you know what you are doing when using Git to make
changes on the repository. If in doubt, ask on the lwip-members mailing list.
(If SSH asks about authenticity of the host, you can check the key
fingerprint against https://savannah.nongnu.org/git/?group=lwip
3 - Merging a development branch to master branch
-------------------------------------------------
Merging is a straightforward process in Git. How to merge all changes in a
development branch since our last merge from main:
Checkout the master branch:
git checkout master
Merge the development branch to master:
git merge your-development-branch
Resolve any conflict.
Commit the merge result.
git commit -a
Push your commits:
git push
4 How to release lwIP
---------------------
First, tag the release using Git: (I use release number 1.4.1 throughout
this example).
git tag -a STABLE-1_4_1
Share the tag reference by pushing it to remote:
git push origin STABLE-1_4_1
Prepare the release:
cp -r lwip lwip-1.4.1
rm -rf lwip-1.4.1/.git lwip-1.4.1/.gitattributes
Archive the current directory using tar, gzip'd, bzip2'd and zip'd.
tar czvf lwip-1.4.1.tar.gz lwip-1.4.1
tar cjvf lwip-1.4.1.tar.bz2 lwip-1.4.1
zip -r lwip-1.4.1.zip lwip-1.4.1
Now, sign the archives with a detached GPG binary signature as follows:
gpg -b lwip-1.4.1.tar.gz
gpg -b lwip-1.4.1.tar.bz2
gpg -b lwip-1.4.1.zip
Upload these files using anonymous FTP:
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
ncftp> mput *1.4.1.*
Additionally, you may post a news item on Savannah, like this:
A new 1.4.1 release is now available here:
http://savannah.nongnu.org/files/?group=lwip&highlight=1.4.1
You will have to submit this via the user News interface, then approve
this via the Administrator News interface.

15
third_party/lwip/src/FILES vendored Normal file
View File

@ -0,0 +1,15 @@
api/ - The code for the high-level wrapper API. Not needed if
you use the lowel-level call-back/raw API.
apps/ - Higher layer applications that are specifically programmed
with the lwIP low-level raw API.
core/ - The core of the TPC/IP stack; protocol implementations,
memory and buffer management, and the low-level raw API.
include/ - lwIP include files.
netif/ - Generic network interface device drivers are kept here.
For more information on the various subdirectories, check the FILES
file in each directory.

256
third_party/lwip/src/Filelists.cmake vendored Normal file
View File

@ -0,0 +1,256 @@
# This file is indended to be included in end-user CMakeLists.txt
# include(/path/to/Filelists.cmake)
# It assumes the variable LWIP_DIR is defined pointing to the
# root path of lwIP sources.
#
# This file is NOT designed (on purpose) to be used as cmake
# subdir via add_subdirectory()
# The intention is to provide greater flexibility to users to
# create their own targets using the *_SRCS variables.
set(LWIP_VERSION_MAJOR "2")
set(LWIP_VERSION_MINOR "1")
set(LWIP_VERSION_REVISION "0")
# LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases
# LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for Git versions
# Numbers 1..31 are reserved for release candidates
set(LWIP_VERSION_RC "LWIP_RC_RELEASE")
if ("${LWIP_VERSION_RC}" STREQUAL "LWIP_RC_RELEASE")
set(LWIP_VERSION_STRING
"${LWIP_VERSION_MAJOR}.${LWIP_VERSION_MINOR}.${LWIP_VERSION_REVISION}"
)
elseif ("${LWIP_VERSION_RC}" STREQUAL "LWIP_RC_DEVELOPMENT")
set(LWIP_VERSION_STRING
"${LWIP_VERSION_MAJOR}.${LWIP_VERSION_MINOR}.${LWIP_VERSION_REVISION}.dev"
)
else ("${LWIP_VERSION_RC}" STREQUAL "LWIP_RC_RELEASE")
set(LWIP_VERSION_STRING
"${LWIP_VERSION_MAJOR}.${LWIP_VERSION_MINOR}.${LWIP_VERSION_REVISION}.rc${LWIP_VERSION_RC}"
)
endif ("${LWIP_VERSION_RC}" STREQUAL "LWIP_RC_RELEASE")
# The minimum set of files needed for lwIP.
set(lwipcore_SRCS
${LWIP_DIR}/src/core/init.c
${LWIP_DIR}/src/core/def.c
${LWIP_DIR}/src/core/dns.c
${LWIP_DIR}/src/core/inet_chksum.c
${LWIP_DIR}/src/core/ip.c
${LWIP_DIR}/src/core/mem.c
${LWIP_DIR}/src/core/memp.c
${LWIP_DIR}/src/core/netif.c
${LWIP_DIR}/src/core/pbuf.c
${LWIP_DIR}/src/core/raw.c
${LWIP_DIR}/src/core/stats.c
${LWIP_DIR}/src/core/sys.c
${LWIP_DIR}/src/core/altcp.c
${LWIP_DIR}/src/core/altcp_alloc.c
${LWIP_DIR}/src/core/altcp_tcp.c
${LWIP_DIR}/src/core/tcp.c
${LWIP_DIR}/src/core/tcp_in.c
${LWIP_DIR}/src/core/tcp_out.c
${LWIP_DIR}/src/core/timeouts.c
${LWIP_DIR}/src/core/udp.c
${LWIP_DIR}/src/arch/sys_arch.c
)
set(lwipcore4_SRCS
${LWIP_DIR}/src/core/ipv4/autoip.c
${LWIP_DIR}/src/core/ipv4/dhcp.c
${LWIP_DIR}/src/core/ipv4/etharp.c
${LWIP_DIR}/src/core/ipv4/icmp.c
${LWIP_DIR}/src/core/ipv4/igmp.c
${LWIP_DIR}/src/core/ipv4/ip4_frag.c
${LWIP_DIR}/src/core/ipv4/ip4.c
${LWIP_DIR}/src/core/ipv4/ip4_addr.c
)
set(lwipcore6_SRCS
${LWIP_DIR}/src/core/ipv6/dhcp6.c
${LWIP_DIR}/src/core/ipv6/ethip6.c
${LWIP_DIR}/src/core/ipv6/icmp6.c
${LWIP_DIR}/src/core/ipv6/inet6.c
${LWIP_DIR}/src/core/ipv6/ip6.c
${LWIP_DIR}/src/core/ipv6/ip6_addr.c
${LWIP_DIR}/src/core/ipv6/ip6_frag.c
${LWIP_DIR}/src/core/ipv6/mld6.c
${LWIP_DIR}/src/core/ipv6/nd6.c
)
# APIFILES: The files which implement the sequential and socket APIs.
set(lwipapi_SRCS
${LWIP_DIR}/src/api/api_lib.c
${LWIP_DIR}/src/api/api_msg.c
${LWIP_DIR}/src/api/err.c
${LWIP_DIR}/src/api/if_api.c
${LWIP_DIR}/src/api/netbuf.c
${LWIP_DIR}/src/api/netdb.c
${LWIP_DIR}/src/api/netifapi.c
${LWIP_DIR}/src/api/sockets.c
${LWIP_DIR}/src/api/tcpip.c
)
# Files implementing various generic network interface functions
set(lwipnetif_SRCS
${LWIP_DIR}/src/netif/ethernet.c
${LWIP_DIR}/src/netif/bridgeif.c
${LWIP_DIR}/src/netif/bridgeif_fdb.c
${LWIP_DIR}/src/netif/slipif.c
)
# 6LoWPAN
set(lwipsixlowpan_SRCS
${LWIP_DIR}/src/netif/lowpan6_common.c
${LWIP_DIR}/src/netif/lowpan6.c
${LWIP_DIR}/src/netif/lowpan6_ble.c
${LWIP_DIR}/src/netif/zepif.c
)
# PPP
set(lwipppp_SRCS
${LWIP_DIR}/src/netif/ppp/auth.c
${LWIP_DIR}/src/netif/ppp/ccp.c
${LWIP_DIR}/src/netif/ppp/chap-md5.c
${LWIP_DIR}/src/netif/ppp/chap_ms.c
${LWIP_DIR}/src/netif/ppp/chap-new.c
${LWIP_DIR}/src/netif/ppp/demand.c
${LWIP_DIR}/src/netif/ppp/eap.c
${LWIP_DIR}/src/netif/ppp/ecp.c
${LWIP_DIR}/src/netif/ppp/eui64.c
${LWIP_DIR}/src/netif/ppp/fsm.c
${LWIP_DIR}/src/netif/ppp/ipcp.c
${LWIP_DIR}/src/netif/ppp/ipv6cp.c
${LWIP_DIR}/src/netif/ppp/lcp.c
${LWIP_DIR}/src/netif/ppp/magic.c
${LWIP_DIR}/src/netif/ppp/mppe.c
${LWIP_DIR}/src/netif/ppp/multilink.c
${LWIP_DIR}/src/netif/ppp/ppp.c
${LWIP_DIR}/src/netif/ppp/pppapi.c
${LWIP_DIR}/src/netif/ppp/pppcrypt.c
${LWIP_DIR}/src/netif/ppp/pppoe.c
${LWIP_DIR}/src/netif/ppp/pppol2tp.c
${LWIP_DIR}/src/netif/ppp/pppos.c
${LWIP_DIR}/src/netif/ppp/upap.c
${LWIP_DIR}/src/netif/ppp/utils.c
${LWIP_DIR}/src/netif/ppp/vj.c
${LWIP_DIR}/src/netif/ppp/polarssl/arc4.c
${LWIP_DIR}/src/netif/ppp/polarssl/des.c
${LWIP_DIR}/src/netif/ppp/polarssl/md4.c
${LWIP_DIR}/src/netif/ppp/polarssl/md5.c
${LWIP_DIR}/src/netif/ppp/polarssl/sha1.c
)
# SNMPv3 agent
set(lwipsnmp_SRCS
${LWIP_DIR}/src/apps/snmp/snmp_asn1.c
${LWIP_DIR}/src/apps/snmp/snmp_core.c
${LWIP_DIR}/src/apps/snmp/snmp_mib2.c
${LWIP_DIR}/src/apps/snmp/snmp_mib2_icmp.c
${LWIP_DIR}/src/apps/snmp/snmp_mib2_interfaces.c
${LWIP_DIR}/src/apps/snmp/snmp_mib2_ip.c
${LWIP_DIR}/src/apps/snmp/snmp_mib2_snmp.c
${LWIP_DIR}/src/apps/snmp/snmp_mib2_system.c
${LWIP_DIR}/src/apps/snmp/snmp_mib2_tcp.c
${LWIP_DIR}/src/apps/snmp/snmp_mib2_udp.c
${LWIP_DIR}/src/apps/snmp/snmp_snmpv2_framework.c
${LWIP_DIR}/src/apps/snmp/snmp_snmpv2_usm.c
${LWIP_DIR}/src/apps/snmp/snmp_msg.c
${LWIP_DIR}/src/apps/snmp/snmpv3.c
${LWIP_DIR}/src/apps/snmp/snmp_netconn.c
${LWIP_DIR}/src/apps/snmp/snmp_pbuf_stream.c
${LWIP_DIR}/src/apps/snmp/snmp_raw.c
${LWIP_DIR}/src/apps/snmp/snmp_scalar.c
${LWIP_DIR}/src/apps/snmp/snmp_table.c
${LWIP_DIR}/src/apps/snmp/snmp_threadsync.c
${LWIP_DIR}/src/apps/snmp/snmp_traps.c
)
# HTTP server + client
set(lwiphttp_SRCS
${LWIP_DIR}/src/apps/http/altcp_proxyconnect.c
${LWIP_DIR}/src/apps/http/fs.c
${LWIP_DIR}/src/apps/http/http_client.c
${LWIP_DIR}/src/apps/http/httpd.c
)
# MAKEFSDATA HTTP server host utility
set(lwipmakefsdata_SRCS
${LWIP_DIR}/src/apps/http/makefsdata/makefsdata.c
)
# IPERF server
set(lwipiperf_SRCS
${LWIP_DIR}/src/apps/lwiperf/lwiperf.c
)
# SMTP client
set(lwipsmtp_SRCS
${LWIP_DIR}/src/apps/smtp/smtp.c
)
# SNTP client
set(lwipsntp_SRCS
${LWIP_DIR}/src/apps/sntp/sntp.c
)
# MDNS responder
set(lwipmdns_SRCS
${LWIP_DIR}/src/apps/mdns/mdns.c
)
# NetBIOS name server
set(lwipnetbios_SRCS
${LWIP_DIR}/src/apps/netbiosns/netbiosns.c
)
# TFTP server files
set(lwiptftp_SRCS
${LWIP_DIR}/src/apps/tftp/tftp_server.c
)
# MQTT client files
set(lwipmqtt_SRCS
${LWIP_DIR}/src/apps/mqtt/mqtt.c
)
# ARM MBEDTLS related files of lwIP rep
set(lwipmbedtls_SRCS
${LWIP_DIR}/src/apps/altcp_tls/altcp_tls_mbedtls.c
${LWIP_DIR}/src/apps/altcp_tls/altcp_tls_mbedtls_mem.c
${LWIP_DIR}/src/apps/snmp/snmpv3_mbedtls.c
)
# All LWIP files without apps
set(lwipnoapps_SRCS
${lwipcore_SRCS}
${lwipcore4_SRCS}
${lwipcore6_SRCS}
${lwipapi_SRCS}
${lwipnetif_SRCS}
${lwipsixlowpan_SRCS}
${lwipppp_SRCS}
)
# LWIPAPPFILES: All LWIP APPs
set(lwipallapps_SRCS
${lwipsnmp_SRCS}
${lwiphttp_SRCS}
${lwipiperf_SRCS}
${lwipsmtp_SRCS}
${lwipsntp_SRCS}
${lwipmdns_SRCS}
${lwipnetbios_SRCS}
${lwiptftp_SRCS}
${lwipmqtt_SRCS}
${lwipmbedtls_SRCS}
)
# Generate lwip/init.h (version info)
#configure_file(${LWIP_DIR}/src/include/lwip/init.h.cmake.in ${LWIP_DIR}/src/include/lwip/init.h)
set(LWIP_INCLUDE_DIRS ${LWIP_DIR}/src/include)
# lwIP libraries
add_library(lwipcore EXCLUDE_FROM_ALL ${lwipnoapps_SRCS})
target_compile_options(lwipcore PRIVATE ${LWIP_COMPILER_FLAGS})
target_compile_definitions(lwipcore PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS})
target_include_directories(lwipcore PUBLIC ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS})

205
third_party/lwip/src/Filelists.mk vendored Normal file
View File

@ -0,0 +1,205 @@
#
# Copyright (c) 2001, 2002 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>
#
# COREFILES, CORE4FILES: The minimum set of files needed for lwIP.
COREFILES=$(LWIPDIR)/core/init.c \
$(LWIPDIR)/core/def.c \
$(LWIPDIR)/core/dns.c \
$(LWIPDIR)/core/inet_chksum.c \
$(LWIPDIR)/core/ip.c \
$(LWIPDIR)/core/mem.c \
$(LWIPDIR)/core/memp.c \
$(LWIPDIR)/core/netif.c \
$(LWIPDIR)/core/pbuf.c \
$(LWIPDIR)/core/raw.c \
$(LWIPDIR)/core/stats.c \
$(LWIPDIR)/core/sys.c \
$(LWIPDIR)/core/altcp.c \
$(LWIPDIR)/core/altcp_alloc.c \
$(LWIPDIR)/core/altcp_tcp.c \
$(LWIPDIR)/core/tcp.c \
$(LWIPDIR)/core/tcp_in.c \
$(LWIPDIR)/core/tcp_out.c \
$(LWIPDIR)/core/timeouts.c \
$(LWIPDIR)/core/udp.c
CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c \
$(LWIPDIR)/core/ipv4/dhcp.c \
$(LWIPDIR)/core/ipv4/etharp.c \
$(LWIPDIR)/core/ipv4/icmp.c \
$(LWIPDIR)/core/ipv4/igmp.c \
$(LWIPDIR)/core/ipv4/ip4_frag.c \
$(LWIPDIR)/core/ipv4/ip4.c \
$(LWIPDIR)/core/ipv4/ip4_addr.c
CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c \
$(LWIPDIR)/core/ipv6/ethip6.c \
$(LWIPDIR)/core/ipv6/icmp6.c \
$(LWIPDIR)/core/ipv6/inet6.c \
$(LWIPDIR)/core/ipv6/ip6.c \
$(LWIPDIR)/core/ipv6/ip6_addr.c \
$(LWIPDIR)/core/ipv6/ip6_frag.c \
$(LWIPDIR)/core/ipv6/mld6.c \
$(LWIPDIR)/core/ipv6/nd6.c
# APIFILES: The files which implement the sequential and socket APIs.
APIFILES=$(LWIPDIR)/api/api_lib.c \
$(LWIPDIR)/api/api_msg.c \
$(LWIPDIR)/api/err.c \
$(LWIPDIR)/api/if_api.c \
$(LWIPDIR)/api/netbuf.c \
$(LWIPDIR)/api/netdb.c \
$(LWIPDIR)/api/netifapi.c \
$(LWIPDIR)/api/sockets.c \
$(LWIPDIR)/api/tcpip.c
# NETIFFILES: Files implementing various generic network interface functions
NETIFFILES=$(LWIPDIR)/netif/ethernet.c \
$(LWIPDIR)/netif/bridgeif.c \
$(LWIPDIR)/netif/bridgeif_fdb.c \
$(LWIPDIR)/netif/slipif.c
# SIXLOWPAN: 6LoWPAN
SIXLOWPAN=$(LWIPDIR)/netif/lowpan6_common.c \
$(LWIPDIR)/netif/lowpan6.c \
$(LWIPDIR)/netif/lowpan6_ble.c \
$(LWIPDIR)/netif/zepif.c
# PPPFILES: PPP
PPPFILES=$(LWIPDIR)/netif/ppp/auth.c \
$(LWIPDIR)/netif/ppp/ccp.c \
$(LWIPDIR)/netif/ppp/chap-md5.c \
$(LWIPDIR)/netif/ppp/chap_ms.c \
$(LWIPDIR)/netif/ppp/chap-new.c \
$(LWIPDIR)/netif/ppp/demand.c \
$(LWIPDIR)/netif/ppp/eap.c \
$(LWIPDIR)/netif/ppp/ecp.c \
$(LWIPDIR)/netif/ppp/eui64.c \
$(LWIPDIR)/netif/ppp/fsm.c \
$(LWIPDIR)/netif/ppp/ipcp.c \
$(LWIPDIR)/netif/ppp/ipv6cp.c \
$(LWIPDIR)/netif/ppp/lcp.c \
$(LWIPDIR)/netif/ppp/magic.c \
$(LWIPDIR)/netif/ppp/mppe.c \
$(LWIPDIR)/netif/ppp/multilink.c \
$(LWIPDIR)/netif/ppp/ppp.c \
$(LWIPDIR)/netif/ppp/pppapi.c \
$(LWIPDIR)/netif/ppp/pppcrypt.c \
$(LWIPDIR)/netif/ppp/pppoe.c \
$(LWIPDIR)/netif/ppp/pppol2tp.c \
$(LWIPDIR)/netif/ppp/pppos.c \
$(LWIPDIR)/netif/ppp/upap.c \
$(LWIPDIR)/netif/ppp/utils.c \
$(LWIPDIR)/netif/ppp/vj.c \
$(LWIPDIR)/netif/ppp/polarssl/arc4.c \
$(LWIPDIR)/netif/ppp/polarssl/des.c \
$(LWIPDIR)/netif/ppp/polarssl/md4.c \
$(LWIPDIR)/netif/ppp/polarssl/md5.c \
$(LWIPDIR)/netif/ppp/polarssl/sha1.c
# LWIPNOAPPSFILES: All LWIP files without apps
LWIPNOAPPSFILES=$(COREFILES) \
$(CORE4FILES) \
$(CORE6FILES) \
$(APIFILES) \
$(NETIFFILES) \
$(PPPFILES) \
$(SIXLOWPAN)
# SNMPFILES: SNMPv2c agent
SNMPFILES=$(LWIPDIR)/apps/snmp/snmp_asn1.c \
$(LWIPDIR)/apps/snmp/snmp_core.c \
$(LWIPDIR)/apps/snmp/snmp_mib2.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_icmp.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_interfaces.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_ip.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_snmp.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_system.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_tcp.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_udp.c \
$(LWIPDIR)/apps/snmp/snmp_snmpv2_framework.c \
$(LWIPDIR)/apps/snmp/snmp_snmpv2_usm.c \
$(LWIPDIR)/apps/snmp/snmp_msg.c \
$(LWIPDIR)/apps/snmp/snmpv3.c \
$(LWIPDIR)/apps/snmp/snmp_netconn.c \
$(LWIPDIR)/apps/snmp/snmp_pbuf_stream.c \
$(LWIPDIR)/apps/snmp/snmp_raw.c \
$(LWIPDIR)/apps/snmp/snmp_scalar.c \
$(LWIPDIR)/apps/snmp/snmp_table.c \
$(LWIPDIR)/apps/snmp/snmp_threadsync.c \
$(LWIPDIR)/apps/snmp/snmp_traps.c
# HTTPFILES: HTTP server + client
HTTPFILES=$(LWIPDIR)/apps/http/altcp_proxyconnect.c \
$(LWIPDIR)/apps/http/fs.c \
$(LWIPDIR)/apps/http/http_client.c \
$(LWIPDIR)/apps/http/httpd.c
# MAKEFSDATA: MAKEFSDATA HTTP server host utility
MAKEFSDATAFILES=$(LWIPDIR)/apps/http/makefsdata/makefsdata.c
# LWIPERFFILES: IPERF server
LWIPERFFILES=$(LWIPDIR)/apps/lwiperf/lwiperf.c
# SMTPFILES: SMTP client
SMTPFILES=$(LWIPDIR)/apps/smtp/smtp.c
# SNTPFILES: SNTP client
SNTPFILES=$(LWIPDIR)/apps/sntp/sntp.c
# MDNSFILES: MDNS responder
MDNSFILES=$(LWIPDIR)/apps/mdns/mdns.c
# NETBIOSNSFILES: NetBIOS name server
NETBIOSNSFILES=$(LWIPDIR)/apps/netbiosns/netbiosns.c
# TFTPFILES: TFTP server files
TFTPFILES=$(LWIPDIR)/apps/tftp/tftp_server.c
# MQTTFILES: MQTT client files
MQTTFILES=$(LWIPDIR)/apps/mqtt/mqtt.c
# MBEDTLS_FILES: MBEDTLS related files of lwIP rep
MBEDTLS_FILES=$(LWIPDIR)/apps/altcp_tls/altcp_tls_mbedtls.c \
$(LWIPDIR)/apps/altcp_tls/altcp_tls_mbedtls_mem.c \
$(LWIPDIR)/apps/snmp/snmpv3_mbedtls.c
# LWIPAPPFILES: All LWIP APPs
LWIPAPPFILES=$(SNMPFILES) \
$(HTTPFILES) \
$(LWIPERFFILES) \
$(SMTPFILES) \
$(SNTPFILES) \
$(MDNSFILES) \
$(NETBIOSNSFILES) \
$(TFTPFILES) \
$(MQTTFILES) \
$(MBEDTLS_FILES)

1367
third_party/lwip/src/api/api_lib.c vendored Normal file

File diff suppressed because it is too large Load Diff

2173
third_party/lwip/src/api/api_msg.c vendored Normal file

File diff suppressed because it is too large Load Diff

115
third_party/lwip/src/api/err.c vendored Normal file
View File

@ -0,0 +1,115 @@
/**
* @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"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/errno.h"
#if !NO_SYS
/** Table to quickly map an lwIP error (err_t) to a socket error
* by using -err as an index */
static const int err_to_errno_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
ENOMEM, /* ERR_MEM -1 Out of memory error. */
ENOBUFS, /* ERR_BUF -2 Buffer error. */
EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
EINVAL, /* ERR_VAL -6 Illegal value. */
EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
EADDRINUSE, /* ERR_USE -8 Address in use. */
EALREADY, /* ERR_ALREADY -9 Already connecting. */
EISCONN, /* ERR_ISCONN -10 Conn already established.*/
ENOTCONN, /* ERR_CONN -11 Not connected. */
-1, /* ERR_IF -12 Low-level netif error */
ECONNABORTED, /* ERR_ABRT -13 Connection aborted. */
ECONNRESET, /* ERR_RST -14 Connection reset. */
ENOTCONN, /* ERR_CLSD -15 Connection closed. */
EIO /* ERR_ARG -16 Illegal argument. */
};
int
err_to_errno(err_t err)
{
if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_to_errno_table))) {
return EIO;
}
return err_to_errno_table[-err];
}
#endif /* !NO_SYS */
#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 */
"Address in use.", /* ERR_USE -8 */
"Already connecting.", /* ERR_ALREADY -9 */
"Already connected.", /* ERR_ISCONN -10 */
"Not connected.", /* ERR_CONN -11 */
"Low-level netif error.", /* ERR_IF -12 */
"Connection aborted.", /* ERR_ABRT -13 */
"Connection reset.", /* ERR_RST -14 */
"Connection closed.", /* ERR_CLSD -15 */
"Illegal argument." /* ERR_ARG -16 */
};
/**
* 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)
{
if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_strerr))) {
return "Unknown error.";
}
return err_strerr[-err];
}
#endif /* LWIP_DEBUG */

102
third_party/lwip/src/api/if_api.c vendored Normal file
View File

@ -0,0 +1,102 @@
/**
* @file
* Interface Identification APIs from:
* RFC 3493: Basic Socket Interface Extensions for IPv6
* Section 4: Interface Identification
*
* @defgroup if_api Interface Identification API
* @ingroup socket
*/
/*
* Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. <joel.cunningham@garmin.com>
* 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: Joel Cunningham <joel.cunningham@me.com>
*
*/
#include "lwip/opt.h"
#if LWIP_SOCKET
#include "lwip/errno.h"
#include "lwip/if_api.h"
#include "lwip/netifapi.h"
#include "lwip/priv/sockets_priv.h"
/**
* @ingroup if_api
* Maps an interface index to its corresponding name.
* @param ifindex interface index
* @param ifname shall point to a buffer of at least {IF_NAMESIZE} bytes
* @return If ifindex is an interface index, then the function shall return the
* value supplied in ifname, which points to a buffer now containing the interface name.
* Otherwise, the function shall return a NULL pointer.
*/
char *
lwip_if_indextoname(unsigned int ifindex, char *ifname)
{
#if LWIP_NETIF_API
if (ifindex <= 0xff) {
err_t err = netifapi_netif_index_to_name((u8_t)ifindex, ifname);
if (!err && ifname[0] != '\0') {
return ifname;
}
}
#else /* LWIP_NETIF_API */
LWIP_UNUSED_ARG(ifindex);
LWIP_UNUSED_ARG(ifname);
#endif /* LWIP_NETIF_API */
set_errno(ENXIO);
return NULL;
}
/**
* @ingroup if_api
* Returs the interface index corresponding to name ifname.
* @param ifname Interface name
* @return The corresponding index if ifname is the name of an interface;
* otherwise, zero.
*/
unsigned int
lwip_if_nametoindex(const char *ifname)
{
#if LWIP_NETIF_API
err_t err;
u8_t idx;
err = netifapi_netif_name_to_index(ifname, &idx);
if (!err) {
return idx;
}
#else /* LWIP_NETIF_API */
LWIP_UNUSED_ARG(ifname);
#endif /* LWIP_NETIF_API */
return 0; /* invalid index */
}
#endif /* LWIP_SOCKET */

250
third_party/lwip/src/api/netbuf.c vendored Normal file
View File

@ -0,0 +1,250 @@
/**
* @file
* Network buffer management
*
* @defgroup netbuf Network buffers
* @ingroup netconn
* Network buffer descriptor for @ref netconn. Based on @ref pbuf internally
* to avoid copying data around.\n
* Buffers must not be shared accross multiple threads, all functions except
* netbuf_new() and netbuf_delete() are not thread-safe.
*/
/*
* 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>
/**
* @ingroup netbuf
* Create (allocate) and initialize a new netbuf.
* The netbuf doesn't yet contain a packet buffer!
*
* @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) {
memset(buf, 0, sizeof(struct netbuf));
}
return buf;
}
/**
* @ingroup netbuf
* Deallocate a netbuf allocated by netbuf_new().
*
* @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);
}
}
/**
* @ingroup netbuf
* Allocate memory for a packet buffer for a given netbuf.
*
* @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;
}
/**
* @ingroup netbuf
* Free the packet buffer included in a netbuf
*
* @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;
#if LWIP_CHECKSUM_ON_COPY
buf->flags = 0;
buf->toport_chksum = 0;
#endif /* LWIP_CHECKSUM_ON_COPY */
}
/**
* @ingroup netbuf
* 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;
}
((struct pbuf_rom *)buf->p)->payload = dataptr;
buf->p->len = buf->p->tot_len = size;
buf->ptr = buf->p;
return ERR_OK;
}
/**
* @ingroup netbuf
* 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_chain: 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);
}
/**
* @ingroup netbuf
* 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 retrieved,
* 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;
}
/**
* @ingroup netbuf
* 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_next: 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;
}
/**
* @ingroup netbuf
* 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_first: invalid buf", (buf != NULL), return;);
buf->ptr = buf->p;
}
#endif /* LWIP_NETCONN */

414
third_party/lwip/src/api/netdb.c vendored Normal file
View File

@ -0,0 +1,414 @@
/**
* @file
* API functions for name resolving
*
* @defgroup netdbapi NETDB API
* @ingroup socket
*/
/*
* 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> /* memset */
#include <stdlib.h> /* atoi */
/** helper struct for gethostbyname_r to access the char* buffer */
struct gethostbyname_r_helper {
ip_addr_t *addr_list[2];
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];
HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1];
/* 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;
strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH);
s_hostname[DNS_MAX_NAME_LENGTH] = 0;
s_hostent.h_name = s_hostname;
s_aliases = NULL;
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", (void *)s_hostent.h_aliases));
/* h_aliases are always empty */
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", (void *)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, ipaddr_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 == NULL)) {
/* not all arguments given */
*h_errnop = EINVAL;
return -1;
}
namelen = strlen(name);
if (buflen < (sizeof(struct gethostbyname_r_helper) + LWIP_MEM_ALIGN_BUFFER(namelen + 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 = HOST_NOT_FOUND;
return -1;
}
/* copy the hostname into buf */
MEMCPY(hostname, name, namelen);
hostname[namelen] = 0;
/* fill hostent */
h->addr_list[0] = &h->addr;
h->addr_list[1] = NULL;
h->aliases = NULL;
ret->h_name = hostname;
ret->h_aliases = &h->aliases;
ret->h_addrtype = AF_INET;
ret->h_length = sizeof(ip_addr_t);
ret->h_addr_list = (char **)&h->addr_list;
/* 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
*
* @todo: implement AI_V4MAPPED, AI_ADDRCONFIG
*/
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_storage *sa = NULL;
int port_nr = 0;
size_t total_size;
size_t namelen = 0;
int ai_family;
if (res == NULL) {
return EAI_FAIL;
}
*res = NULL;
if ((nodename == NULL) && (servname == NULL)) {
return EAI_NONAME;
}
if (hints != NULL) {
ai_family = hints->ai_family;
if ((ai_family != AF_UNSPEC)
#if LWIP_IPV4
&& (ai_family != AF_INET)
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
&& (ai_family != AF_INET6)
#endif /* LWIP_IPV6 */
) {
return EAI_FAMILY;
}
} else {
ai_family = AF_UNSPEC;
}
if (servname != NULL) {
/* service name specified: convert to port number
* @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */
port_nr = atoi(servname);
if ((port_nr <= 0) || (port_nr > 0xffff)) {
return EAI_SERVICE;
}
}
if (nodename != NULL) {
/* service location specified, try to resolve */
if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) {
/* no DNS lookup, just parse for an address string */
if (!ipaddr_aton(nodename, &addr)) {
return EAI_NONAME;
}
#if LWIP_IPV4 && LWIP_IPV6
if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) ||
(IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) {
return EAI_NONAME;
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
} else {
#if LWIP_IPV4 && LWIP_IPV6
/* AF_UNSPEC: prefer IPv4 */
u8_t type = NETCONN_DNS_IPV4_IPV6;
if (ai_family == AF_INET) {
type = NETCONN_DNS_IPV4;
} else if (ai_family == AF_INET6) {
type = NETCONN_DNS_IPV6;
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
err = netconn_gethostbyname_addrtype(nodename, &addr, type);
if (err != ERR_OK) {
return EAI_FAIL;
}
}
} else {
/* service location specified, use loopback address */
if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) {
ip_addr_set_any_val(ai_family == AF_INET6, addr);
} else {
ip_addr_set_loopback_val(ai_family == AF_INET6, addr);
}
}
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
if (nodename != NULL) {
namelen = strlen(nodename);
if (namelen > DNS_MAX_NAME_LENGTH) {
/* invalid name length */
return EAI_FAIL;
}
LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size);
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) {
return EAI_MEMORY;
}
memset(ai, 0, total_size);
/* cast through void* to get rid of alignment warnings */
sa = (struct sockaddr_storage *)(void *)((u8_t *)ai + sizeof(struct addrinfo));
if (IP_IS_V6_VAL(addr)) {
#if LWIP_IPV6
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
/* set up sockaddr */
inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr));
sa6->sin6_family = AF_INET6;
sa6->sin6_len = sizeof(struct sockaddr_in6);
sa6->sin6_port = lwip_htons((u16_t)port_nr);
sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr));
ai->ai_family = AF_INET6;
#endif /* LWIP_IPV6 */
} else {
#if LWIP_IPV4
struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
/* set up sockaddr */
inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
sa4->sin_family = AF_INET;
sa4->sin_len = sizeof(struct sockaddr_in);
sa4->sin_port = lwip_htons((u16_t)port_nr);
ai->ai_family = AF_INET;
#endif /* LWIP_IPV4 */
}
/* set up addrinfo */
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_storage));
MEMCPY(ai->ai_canonname, nodename, namelen);
ai->ai_canonname[namelen] = 0;
}
ai->ai_addrlen = sizeof(struct sockaddr_storage);
ai->ai_addr = (struct sockaddr *)sa;
*res = ai;
return 0;
}
#endif /* LWIP_DNS && LWIP_SOCKET */

380
third_party/lwip/src/api/netifapi.c vendored Normal file
View File

@ -0,0 +1,380 @@
/**
* @file
* Network Interface Sequential API module
*
* @defgroup netifapi NETIF API
* @ingroup sequential_api
* Thread-safe functions to be called from non-TCPIP threads
*
* @defgroup netifapi_netif NETIF related
* @ingroup netifapi
* To be called from non-TCPIP threads
*/
/*
* 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/etharp.h"
#include "lwip/netifapi.h"
#include "lwip/memp.h"
#include "lwip/priv/tcpip_priv.h"
#include <string.h> /* strncpy */
#define NETIFAPI_VAR_REF(name) API_VAR_REF(name)
#define NETIFAPI_VAR_DECLARE(name) API_VAR_DECLARE(struct netifapi_msg, name)
#define NETIFAPI_VAR_ALLOC(name) API_VAR_ALLOC(struct netifapi_msg, MEMP_NETIFAPI_MSG, name, ERR_MEM)
#define NETIFAPI_VAR_FREE(name) API_VAR_FREE(MEMP_NETIFAPI_MSG, name)
/**
* Call netif_add() inside the tcpip_thread context.
*/
static err_t
netifapi_do_netif_add(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct netifapi_msg */
struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
if (!netif_add( msg->netif,
#if LWIP_IPV4
API_EXPR_REF(msg->msg.add.ipaddr),
API_EXPR_REF(msg->msg.add.netmask),
API_EXPR_REF(msg->msg.add.gw),
#endif /* LWIP_IPV4 */
msg->msg.add.state,
msg->msg.add.init,
msg->msg.add.input)) {
return ERR_IF;
} else {
return ERR_OK;
}
}
#if LWIP_IPV4
/**
* Call netif_set_addr() inside the tcpip_thread context.
*/
static err_t
netifapi_do_netif_set_addr(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct netifapi_msg */
struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
netif_set_addr( msg->netif,
API_EXPR_REF(msg->msg.add.ipaddr),
API_EXPR_REF(msg->msg.add.netmask),
API_EXPR_REF(msg->msg.add.gw));
return ERR_OK;
}
#endif /* LWIP_IPV4 */
/**
* Call netif_name_to_index() inside the tcpip_thread context.
*/
static err_t
netifapi_do_name_to_index(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct netifapi_msg */
struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
msg->msg.ifs.index = netif_name_to_index(msg->msg.ifs.name);
return ERR_OK;
}
/**
* Call netif_index_to_name() inside the tcpip_thread context.
*/
static err_t
netifapi_do_index_to_name(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct netifapi_msg */
struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
if (!netif_index_to_name(msg->msg.ifs.index, msg->msg.ifs.name)) {
/* return failure via empty name */
msg->msg.ifs.name[0] = '\0';
}
return ERR_OK;
}
/**
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
* tcpip_thread context.
*/
static err_t
netifapi_do_netif_common(struct tcpip_api_call_data *m)
{
/* cast through void* to silence alignment warnings.
* We know it works because the structs have been instantiated as struct netifapi_msg */
struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
if (msg->msg.common.errtfunc != NULL) {
return msg->msg.common.errtfunc(msg->netif);
} else {
msg->msg.common.voidfunc(msg->netif);
return ERR_OK;
}
}
#if LWIP_ARP && LWIP_IPV4
/**
* @ingroup netifapi_arp
* Add or update an entry in the ARP cache.
* For an update, ipaddr is used to find the cache entry.
*
* @param ipaddr IPv4 address of cache entry
* @param ethaddr hardware address mapped to ipaddr
* @param type type of ARP cache entry
* @return ERR_OK: entry added/updated, else error from err_t
*/
err_t
netifapi_arp_add(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, enum netifapi_arp_entry type)
{
err_t err;
/* We only support permanent entries currently */
LWIP_UNUSED_ARG(type);
#if ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING
LOCK_TCPIP_CORE();
err = etharp_add_static_entry(ipaddr, ethaddr);
UNLOCK_TCPIP_CORE();
#else
/* @todo add new vars to struct netifapi_msg and create a 'do' func */
LWIP_UNUSED_ARG(ipaddr);
LWIP_UNUSED_ARG(ethaddr);
err = ERR_VAL;
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING */
return err;
}
/**
* @ingroup netifapi_arp
* Remove an entry in the ARP cache identified by ipaddr
*
* @param ipaddr IPv4 address of cache entry
* @param type type of ARP cache entry
* @return ERR_OK: entry removed, else error from err_t
*/
err_t
netifapi_arp_remove(const ip4_addr_t *ipaddr, enum netifapi_arp_entry type)
{
err_t err;
/* We only support permanent entries currently */
LWIP_UNUSED_ARG(type);
#if ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING
LOCK_TCPIP_CORE();
err = etharp_remove_static_entry(ipaddr);
UNLOCK_TCPIP_CORE();
#else
/* @todo add new vars to struct netifapi_msg and create a 'do' func */
LWIP_UNUSED_ARG(ipaddr);
err = ERR_VAL;
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES && LWIP_TCPIP_CORE_LOCKING */
return err;
}
#endif /* LWIP_ARP && LWIP_IPV4 */
/**
* @ingroup netifapi_netif
* 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,
#if LWIP_IPV4
const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw,
#endif /* LWIP_IPV4 */
void *state, netif_init_fn init, netif_input_fn input)
{
err_t err;
NETIFAPI_VAR_DECLARE(msg);
NETIFAPI_VAR_ALLOC(msg);
#if LWIP_IPV4
if (ipaddr == NULL) {
ipaddr = IP4_ADDR_ANY4;
}
if (netmask == NULL) {
netmask = IP4_ADDR_ANY4;
}
if (gw == NULL) {
gw = IP4_ADDR_ANY4;
}
#endif /* LWIP_IPV4 */
NETIFAPI_VAR_REF(msg).netif = netif;
#if LWIP_IPV4
NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr);
NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask);
NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw);
#endif /* LWIP_IPV4 */
NETIFAPI_VAR_REF(msg).msg.add.state = state;
NETIFAPI_VAR_REF(msg).msg.add.init = init;
NETIFAPI_VAR_REF(msg).msg.add.input = input;
err = tcpip_api_call(netifapi_do_netif_add, &API_VAR_REF(msg).call);
NETIFAPI_VAR_FREE(msg);
return err;
}
#if LWIP_IPV4
/**
* @ingroup netifapi_netif
* 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,
const ip4_addr_t *ipaddr,
const ip4_addr_t *netmask,
const ip4_addr_t *gw)
{
err_t err;
NETIFAPI_VAR_DECLARE(msg);
NETIFAPI_VAR_ALLOC(msg);
if (ipaddr == NULL) {
ipaddr = IP4_ADDR_ANY4;
}
if (netmask == NULL) {
netmask = IP4_ADDR_ANY4;
}
if (gw == NULL) {
gw = IP4_ADDR_ANY4;
}
NETIFAPI_VAR_REF(msg).netif = netif;
NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr);
NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask);
NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw);
err = tcpip_api_call(netifapi_do_netif_set_addr, &API_VAR_REF(msg).call);
NETIFAPI_VAR_FREE(msg);
return err;
}
#endif /* LWIP_IPV4 */
/**
* 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)
{
err_t err;
NETIFAPI_VAR_DECLARE(msg);
NETIFAPI_VAR_ALLOC(msg);
NETIFAPI_VAR_REF(msg).netif = netif;
NETIFAPI_VAR_REF(msg).msg.common.voidfunc = voidfunc;
NETIFAPI_VAR_REF(msg).msg.common.errtfunc = errtfunc;
err = tcpip_api_call(netifapi_do_netif_common, &API_VAR_REF(msg).call);
NETIFAPI_VAR_FREE(msg);
return err;
}
/**
* @ingroup netifapi_netif
* Call netif_name_to_index() in a thread-safe way by running that function inside the
* tcpip_thread context.
*
* @param name the interface name of the netif
* @param idx output index of the found netif
*/
err_t
netifapi_netif_name_to_index(const char *name, u8_t *idx)
{
err_t err;
NETIFAPI_VAR_DECLARE(msg);
NETIFAPI_VAR_ALLOC(msg);
*idx = 0;
#if LWIP_MPU_COMPATIBLE
strncpy(NETIFAPI_VAR_REF(msg).msg.ifs.name, name, NETIF_NAMESIZE - 1);
NETIFAPI_VAR_REF(msg).msg.ifs.name[NETIF_NAMESIZE - 1] = '\0';
#else
NETIFAPI_VAR_REF(msg).msg.ifs.name = LWIP_CONST_CAST(char *, name);
#endif /* LWIP_MPU_COMPATIBLE */
err = tcpip_api_call(netifapi_do_name_to_index, &API_VAR_REF(msg).call);
if (!err) {
*idx = NETIFAPI_VAR_REF(msg).msg.ifs.index;
}
NETIFAPI_VAR_FREE(msg);
return err;
}
/**
* @ingroup netifapi_netif
* Call netif_index_to_name() in a thread-safe way by running that function inside the
* tcpip_thread context.
*
* @param idx the interface index of the netif
* @param name output name of the found netif, empty '\0' string if netif not found.
* name should be of at least NETIF_NAMESIZE bytes
*/
err_t
netifapi_netif_index_to_name(u8_t idx, char *name)
{
err_t err;
NETIFAPI_VAR_DECLARE(msg);
NETIFAPI_VAR_ALLOC(msg);
NETIFAPI_VAR_REF(msg).msg.ifs.index = idx;
#if !LWIP_MPU_COMPATIBLE
NETIFAPI_VAR_REF(msg).msg.ifs.name = name;
#endif /* LWIP_MPU_COMPATIBLE */
err = tcpip_api_call(netifapi_do_index_to_name, &API_VAR_REF(msg).call);
#if LWIP_MPU_COMPATIBLE
if (!err) {
strncpy(name, NETIFAPI_VAR_REF(msg).msg.ifs.name, NETIF_NAMESIZE - 1);
name[NETIF_NAMESIZE - 1] = '\0';
}
#endif /* LWIP_MPU_COMPATIBLE */
NETIFAPI_VAR_FREE(msg);
return err;
}
#endif /* LWIP_NETIF_API */

4161
third_party/lwip/src/api/sockets.c vendored Normal file

File diff suppressed because it is too large Load Diff

658
third_party/lwip/src/api/tcpip.c vendored Normal file
View File

@ -0,0 +1,658 @@
/**
* @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/priv/tcpip_priv.h"
#include "lwip/sys.h"
#include "lwip/memp.h"
#include "lwip/mem.h"
#include "lwip/init.h"
#include "lwip/ip.h"
#include "lwip/pbuf.h"
#include "lwip/etharp.h"
#include "netif/ethernet.h"
#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name)
#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name)
#define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM)
#define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name)
/* global variables */
static tcpip_init_done_fn tcpip_init_done;
static void *tcpip_init_done_arg;
static sys_mbox_t tcpip_mbox;
#if LWIP_TCPIP_CORE_LOCKING
/** The global semaphore to lock the stack. */
sys_mutex_t lock_tcpip_core;
#endif /* LWIP_TCPIP_CORE_LOCKING */
static void tcpip_thread_handle_msg(struct tcpip_msg *msg);
#if !LWIP_TIMERS
/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */
#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg)
#else /* !LWIP_TIMERS */
/* wait for a message, timeouts are processed while waiting */
#define TCPIP_MBOX_FETCH(mbox, msg) tcpip_timeouts_mbox_fetch(mbox, msg)
/**
* Wait (forever) for a message to arrive in an mbox.
* While waiting, timeouts are processed.
*
* @param mbox the mbox to fetch the message from
* @param msg the place to store the message
*/
static void
tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
{
u32_t sleeptime, res;
again:
LWIP_ASSERT_CORE_LOCKED();
sleeptime = sys_timeouts_sleeptime();
if (sleeptime == SYS_TIMEOUTS_SLEEPTIME_INFINITE) {
UNLOCK_TCPIP_CORE();
sys_arch_mbox_fetch(mbox, msg, 0);
LOCK_TCPIP_CORE();
return;
} else if (sleeptime == 0) {
sys_check_timeouts();
/* We try again to fetch a message from the mbox. */
goto again;
}
UNLOCK_TCPIP_CORE();
res = sys_arch_mbox_fetch(mbox, msg, sleeptime);
LOCK_TCPIP_CORE();
if (res == SYS_ARCH_TIMEOUT) {
/* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred
before a message could be fetched. */
sys_check_timeouts();
/* We try again to fetch a message from the mbox. */
goto again;
}
}
#endif /* !LWIP_TIMERS */
/**
* 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);
LWIP_MARK_TCPIP_THREAD();
LOCK_TCPIP_CORE();
if (tcpip_init_done != NULL) {
tcpip_init_done(tcpip_init_done_arg);
}
while (1) { /* MAIN Loop */
LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */
TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg);
if (msg == NULL) {
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
continue;
}
tcpip_thread_handle_msg(msg);
}
}
/* Handle a single tcpip_msg
* This is in its own function for access by tests only.
*/
static void
tcpip_thread_handle_msg(struct tcpip_msg *msg)
{
switch (msg->type) {
#if !LWIP_TCPIP_CORE_LOCKING
case TCPIP_MSG_API:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
msg->msg.api_msg.function(msg->msg.api_msg.msg);
break;
case TCPIP_MSG_API_CALL:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg));
msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg);
sys_sem_signal(msg->msg.api_call.sem);
break;
#endif /* !LWIP_TCPIP_CORE_LOCKING */
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
case TCPIP_MSG_INPKT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
if (msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif) != ERR_OK) {
pbuf_free(msg->msg.inp.p);
}
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
break;
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
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 && LWIP_TIMERS */
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;
case TCPIP_MSG_CALLBACK_STATIC:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
break;
default:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
break;
}
}
#ifdef TCPIP_THREAD_TEST
/** Work on queued items in single-threaded test mode */
int
tcpip_thread_poll_one(void)
{
int ret = 0;
struct tcpip_msg *msg;
if (sys_arch_mbox_tryfetch(&tcpip_mbox, (void **)&msg) != SYS_ARCH_TIMEOUT) {
LOCK_TCPIP_CORE();
if (msg != NULL) {
tcpip_thread_handle_msg(msg);
ret = 1;
}
UNLOCK_TCPIP_CORE();
}
return ret;
}
#endif
/**
* Pass a received packet to tcpip_thread for input processing
*
* @param p the received packet
* @param inp the network interface on which the packet was received
* @param input_fn input function to call
*/
err_t
tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
{
#if LWIP_TCPIP_CORE_LOCKING_INPUT
err_t ret;
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp));
LOCK_TCPIP_CORE();
ret = input_fn(p, inp);
UNLOCK_TCPIP_CORE();
return ret;
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
struct tcpip_msg *msg;
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_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;
msg->msg.inp.input_fn = input_fn;
if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
return ERR_MEM;
}
return ERR_OK;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
}
/**
* @ingroup lwip_os
* Pass a received packet to tcpip_thread for input processing with
* ethernet_input or ip_input. Don't call directly, pass to netif_add()
* and call netif->input().
*
* @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_ETHERNET
if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
return tcpip_inpkt(p, inp, ethernet_input);
} else
#endif /* LWIP_ETHERNET */
return tcpip_inpkt(p, inp, ip_input);
}
/**
* @ingroup lwip_os
* 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.
* Blocks until the request is posted.
* Must not be called from interrupt context!
*
* @param function the function to call
* @param ctx parameter passed to f
* @return ERR_OK if the function was called, another err_t if not
*
* @see tcpip_try_callback
*/
err_t
tcpip_callback(tcpip_callback_fn function, void *ctx)
{
struct tcpip_msg *msg;
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_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;
sys_mbox_post(&tcpip_mbox, msg);
return ERR_OK;
}
/**
* @ingroup lwip_os
* 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.
* Does NOT block when the request cannot be posted because the
* tcpip_mbox is full, but returns ERR_MEM instead.
* Can be called from interrupt context.
*
* @param function the function to call
* @param ctx parameter passed to f
* @return ERR_OK if the function was called, another err_t if not
*
* @see tcpip_callback
*/
err_t
tcpip_try_callback(tcpip_callback_fn function, void *ctx)
{
struct tcpip_msg *msg;
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_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 (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_API, msg);
return ERR_MEM;
}
return ERR_OK;
}
#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
/**
* call sys_timeout in tcpip_thread
*
* @param msecs 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;
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_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(&tcpip_mbox, msg);
return ERR_OK;
}
/**
* call sys_untimeout in tcpip_thread
*
* @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;
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_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(&tcpip_mbox, msg);
return ERR_OK;
}
#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
/**
* Sends a message to TCPIP thread to call a function. Caller thread blocks on
* on a provided semaphore, which ist NOT automatically signalled by TCPIP thread,
* this has to be done by the user.
* It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way
* with least runtime overhead.
*
* @param fn function to be called from TCPIP thread
* @param apimsg argument to API function
* @param sem semaphore to wait on
* @return ERR_OK if the function was called, another err_t if not
*/
err_t
tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem)
{
#if LWIP_TCPIP_CORE_LOCKING
LWIP_UNUSED_ARG(sem);
LOCK_TCPIP_CORE();
fn(apimsg);
UNLOCK_TCPIP_CORE();
return ERR_OK;
#else /* LWIP_TCPIP_CORE_LOCKING */
TCPIP_MSG_VAR_DECLARE(msg);
LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem));
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
TCPIP_MSG_VAR_ALLOC(msg);
TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API;
TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn;
TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg;
sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg));
sys_arch_sem_wait(sem, 0);
TCPIP_MSG_VAR_FREE(msg);
return ERR_OK;
#endif /* LWIP_TCPIP_CORE_LOCKING */
}
/**
* Synchronously calls function in TCPIP thread and waits for its completion.
* It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or
* LWIP_NETCONN_SEM_PER_THREAD.
* If not, a semaphore is created and destroyed on every call which is usually
* an expensive/slow operation.
* @param fn Function to call
* @param call Call parameters
* @return Return value from tcpip_api_call_fn
*/
err_t
tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
{
#if LWIP_TCPIP_CORE_LOCKING
err_t err;
LOCK_TCPIP_CORE();
err = fn(call);
UNLOCK_TCPIP_CORE();
return err;
#else /* LWIP_TCPIP_CORE_LOCKING */
TCPIP_MSG_VAR_DECLARE(msg);
#if !LWIP_NETCONN_SEM_PER_THREAD
err_t err = sys_sem_new(&call->sem, 0);
if (err != ERR_OK) {
return err;
}
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
TCPIP_MSG_VAR_ALLOC(msg);
TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL;
TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call;
TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn;
#if LWIP_NETCONN_SEM_PER_THREAD
TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET();
#else /* LWIP_NETCONN_SEM_PER_THREAD */
TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem;
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg));
sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0);
TCPIP_MSG_VAR_FREE(msg);
#if !LWIP_NETCONN_SEM_PER_THREAD
sys_sem_free(&call->sem);
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
return call->err;
#endif /* LWIP_TCPIP_CORE_LOCKING */
}
/**
* @ingroup lwip_os
* Allocate a structure for a static callback message and initialize it.
* The message has a special type such that lwIP never frees it.
* This is intended to be used to send "static" messages from interrupt context,
* e.g. the message is allocated once and posted several times from an IRQ
* using tcpip_callbackmsg_trycallback().
* Example usage: Trigger execution of an ethernet IRQ DPC routine in lwIP thread context.
*
* @param function the function to call
* @param ctx parameter passed to function
* @return a struct pointer to pass to tcpip_callbackmsg_trycallback().
*
* @see tcpip_callbackmsg_trycallback()
* @see tcpip_callbackmsg_delete()
*/
struct tcpip_callback_msg *
tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
{
struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return NULL;
}
msg->type = TCPIP_MSG_CALLBACK_STATIC;
msg->msg.cb.function = function;
msg->msg.cb.ctx = ctx;
return (struct tcpip_callback_msg *)msg;
}
/**
* @ingroup lwip_os
* Free a callback message allocated by tcpip_callbackmsg_new().
*
* @param msg the message to free
*
* @see tcpip_callbackmsg_new()
*/
void
tcpip_callbackmsg_delete(struct tcpip_callback_msg *msg)
{
memp_free(MEMP_TCPIP_MSG_API, msg);
}
/**
* @ingroup lwip_os
* Try to post a callback-message to the tcpip_thread tcpip_mbox.
*
* @param msg pointer to the message to post
* @return sys_mbox_trypost() return code
*
* @see tcpip_callbackmsg_new()
*/
err_t
tcpip_callbackmsg_trycallback(struct tcpip_callback_msg *msg)
{
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
return sys_mbox_trypost(&tcpip_mbox, msg);
}
/**
* @ingroup lwip_os
* Try to post a callback-message to the tcpip_thread mbox.
* Same as @ref tcpip_callbackmsg_trycallback but calls sys_mbox_trypost_fromisr(),
* mainly to help FreeRTOS, where calls differ between task level and ISR level.
*
* @param msg pointer to the message to post
* @return sys_mbox_trypost_fromisr() return code (without change, so this
* knowledge can be used to e.g. propagate "bool needs_scheduling")
*
* @see tcpip_callbackmsg_new()
*/
err_t
tcpip_callbackmsg_trycallback_fromisr(struct tcpip_callback_msg *msg)
{
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
return sys_mbox_trypost_fromisr(&tcpip_mbox, msg);
}
/**
* @ingroup lwip_os
* 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(&tcpip_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_try_callback(pbuf_free_int, p);
}
/**
* 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_try_callback(mem_free, m);
}
#endif /* !NO_SYS */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,210 @@
/**
* @file
* Application layered TCP connection API (to be used from TCPIP thread)
*
* This file contains memory management functions for a TLS layer using mbedTLS.
*
* ATTENTION: For production usage, you might want to override this file with
* your own implementation since this implementation simply uses the
* lwIP heap without caring for fragmentation or leaving heap for
* other parts of lwIP!
*/
/*
* Copyright (c) 2017 Simon Goldschmidt
* 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 <goldsimon@gmx.de>
*
* Missing things / @todo:
* - RX data is acknowledged after receiving (tcp_recved is called when enqueueing
* the pbuf for mbedTLS receive, not when processed by mbedTLS or the inner
* connection; altcp_recved() from inner connection does nothing)
* - TX data is marked as 'sent' (i.e. acknowledged; sent callback is called) right
* after enqueueing for transmission, not when actually ACKed be the remote host.
*/
#include "lwip/opt.h"
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/altcp_tls_mbedtls_opts.h"
#if LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS
#include "altcp_tls_mbedtls_mem.h"
#include "altcp_tls_mbedtls_structs.h"
#include "lwip/mem.h"
#include "mbedtls/platform.h"
#include <string.h>
#ifndef ALTCP_MBEDTLS_MEM_DEBUG
#define ALTCP_MBEDTLS_MEM_DEBUG LWIP_DBG_OFF
#endif
#if defined(MBEDTLS_PLATFORM_MEMORY) && \
(!defined(MBEDTLS_PLATFORM_FREE_MACRO) || \
defined(MBEDTLS_PLATFORM_CALLOC_MACRO))
#define ALTCP_MBEDTLS_PLATFORM_ALLOC 1
#else
#define ALTCP_MBEDTLS_PLATFORM_ALLOC 0
#endif
#if ALTCP_MBEDTLS_PLATFORM_ALLOC
#ifndef ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS
#define ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS 0
#endif
/* This is an example/debug implementation of alloc/free functions only */
typedef struct altcp_mbedtls_malloc_helper_s {
size_t c;
size_t len;
} altcp_mbedtls_malloc_helper_t;
#if ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS
typedef struct altcp_mbedtls_malloc_stats_s {
size_t allocedBytes;
size_t allocCnt;
size_t maxBytes;
size_t totalBytes;
} altcp_mbedtls_malloc_stats_t;
altcp_mbedtls_malloc_stats_t altcp_mbedtls_malloc_stats;
volatile int altcp_mbedtls_malloc_clear_stats;
#endif
static void *
tls_malloc(size_t c, size_t len)
{
altcp_mbedtls_malloc_helper_t *hlpr;
void *ret;
size_t alloc_size;
#if ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS
if (altcp_mbedtls_malloc_clear_stats) {
altcp_mbedtls_malloc_clear_stats = 0;
memset(&altcp_mbedtls_malloc_stats, 0, sizeof(altcp_mbedtls_malloc_stats));
}
#endif
alloc_size = sizeof(altcp_mbedtls_malloc_helper_t) + (c * len);
/* check for maximum allocation size, mainly to prevent mem_size_t overflow */
if (alloc_size > MEM_SIZE) {
LWIP_DEBUGF(ALTCP_MBEDTLS_MEM_DEBUG, ("mbedtls allocation too big: %c * %d bytes vs MEM_SIZE=%d",
(int)c, (int)len, (int)MEM_SIZE));
return NULL;
}
hlpr = (altcp_mbedtls_malloc_helper_t *)mem_malloc((mem_size_t)alloc_size);
if (hlpr == NULL) {
LWIP_DEBUGF(ALTCP_MBEDTLS_MEM_DEBUG, ("mbedtls alloc callback failed for %c * %d bytes", (int)c, (int)len));
return NULL;
}
#if ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS
altcp_mbedtls_malloc_stats.allocCnt++;
altcp_mbedtls_malloc_stats.allocedBytes += c * len;
if (altcp_mbedtls_malloc_stats.allocedBytes > altcp_mbedtls_malloc_stats.maxBytes) {
altcp_mbedtls_malloc_stats.maxBytes = altcp_mbedtls_malloc_stats.allocedBytes;
}
altcp_mbedtls_malloc_stats.totalBytes += c * len;
#endif
hlpr->c = c;
hlpr->len = len;
ret = hlpr + 1;
/* zeroing the allocated chunk is required by mbedTLS! */
memset(ret, 0, c * len);
return ret;
}
static void
tls_free(void *ptr)
{
altcp_mbedtls_malloc_helper_t *hlpr;
if (ptr == NULL) {
/* this obviously happened in mbedtls... */
return;
}
hlpr = ((altcp_mbedtls_malloc_helper_t *)ptr) - 1;
#if ALTCP_MBEDTLS_PLATFORM_ALLOC_STATS
if (!altcp_mbedtls_malloc_clear_stats) {
altcp_mbedtls_malloc_stats.allocedBytes -= hlpr->c * hlpr->len;
}
#endif
mem_free(hlpr);
}
#endif /* ALTCP_MBEDTLS_PLATFORM_ALLOC*/
void
altcp_mbedtls_mem_init(void)
{
/* not much to do here when using the heap */
#if ALTCP_MBEDTLS_PLATFORM_ALLOC
/* set mbedtls allocation methods */
mbedtls_platform_set_calloc_free(&tls_malloc, &tls_free);
#endif
}
altcp_mbedtls_state_t *
altcp_mbedtls_alloc(void *conf)
{
altcp_mbedtls_state_t *ret = (altcp_mbedtls_state_t *)mem_calloc(1, sizeof(altcp_mbedtls_state_t));
if (ret != NULL) {
ret->conf = conf;
}
return ret;
}
void
altcp_mbedtls_free(void *conf, altcp_mbedtls_state_t *state)
{
LWIP_UNUSED_ARG(conf);
LWIP_ASSERT("state != NULL", state != NULL);
mem_free(state);
}
void *
altcp_mbedtls_alloc_config(size_t size)
{
void *ret;
size_t checked_size = (mem_size_t)size;
if (size != checked_size) {
/* allocation too big (mem_size_t overflow) */
return NULL;
}
ret = (altcp_mbedtls_state_t *)mem_calloc(1, (mem_size_t)size);
return ret;
}
void
altcp_mbedtls_free_config(void *item)
{
LWIP_ASSERT("item != NULL", item != NULL);
mem_free(item);
}
#endif /* LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS */
#endif /* LWIP_ALTCP */

View File

@ -0,0 +1,72 @@
/**
* @file
* Application layered TCP/TLS connection API (to be used from TCPIP thread)
*
* This file contains memory management function prototypes for a TLS layer using mbedTLS.
*
* Memory management contains:
* - allocating/freeing altcp_mbedtls_state_t
* - allocating/freeing memory used in the mbedTLS library
*/
/*
* Copyright (c) 2017 Simon Goldschmidt
* 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 <goldsimon@gmx.de>
*
*/
#ifndef LWIP_HDR_ALTCP_MBEDTLS_MEM_H
#define LWIP_HDR_ALTCP_MBEDTLS_MEM_H
#include "lwip/opt.h"
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/altcp_tls_mbedtls_opts.h"
#if LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS
#include "altcp_tls_mbedtls_structs.h"
#ifdef __cplusplus
extern "C" {
#endif
void altcp_mbedtls_mem_init(void);
altcp_mbedtls_state_t *altcp_mbedtls_alloc(void *conf);
void altcp_mbedtls_free(void *conf, altcp_mbedtls_state_t *state);
void *altcp_mbedtls_alloc_config(size_t size);
void altcp_mbedtls_free_config(void *item);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS */
#endif /* LWIP_ALTCP */
#endif /* LWIP_HDR_ALTCP_MBEDTLS_MEM_H */

View File

@ -0,0 +1,83 @@
/**
* @file
* Application layered TCP/TLS connection API (to be used from TCPIP thread)
*
* This file contains structure definitions for a TLS layer using mbedTLS.
*/
/*
* Copyright (c) 2017 Simon Goldschmidt
* 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 <goldsimon@gmx.de>
*
*/
#ifndef LWIP_HDR_ALTCP_MBEDTLS_STRUCTS_H
#define LWIP_HDR_ALTCP_MBEDTLS_STRUCTS_H
#include "lwip/opt.h"
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/altcp_tls_mbedtls_opts.h"
#if LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS
#include "lwip/altcp.h"
#include "lwip/pbuf.h"
#include "mbedtls/ssl.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE 0x01
#define ALTCP_MBEDTLS_FLAGS_UPPER_CALLED 0x02
#define ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED 0x04
#define ALTCP_MBEDTLS_FLAGS_RX_CLOSED 0x08
#define ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT 0x10
typedef struct altcp_mbedtls_state_s {
void *conf;
mbedtls_ssl_context ssl_context;
/* chain of rx pbufs (before decryption) */
struct pbuf *rx;
struct pbuf *rx_app;
u8_t flags;
int rx_passed_unrecved;
int bio_bytes_read;
int bio_bytes_appl;
} altcp_mbedtls_state_t;
#ifdef __cplusplus
}
#endif
#endif /* LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS */
#endif /* LWIP_ALTCP */
#endif /* LWIP_HDR_ALTCP_MBEDTLS_STRUCTS_H */

View File

@ -0,0 +1,582 @@
/**
* @file
* Application layered TCP connection API that executes a proxy-connect.
*
* This file provides a starting layer that executes a proxy-connect e.g. to
* set up TLS connections through a http proxy.
*/
/*
* Copyright (c) 2018 Simon Goldschmidt
* 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 <goldsimon@gmx.de>
*
*/
#include "lwip/apps/altcp_proxyconnect.h"
#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
#include "lwip/altcp.h"
#include "lwip/priv/altcp_priv.h"
#include "lwip/altcp_tcp.h"
#include "lwip/altcp_tls.h"
#include "lwip/mem.h"
#include "lwip/init.h"
/** This string is passed in the HTTP header as "User-Agent: " */
#ifndef ALTCP_PROXYCONNECT_CLIENT_AGENT
#define ALTCP_PROXYCONNECT_CLIENT_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)"
#endif
#define ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED 0x01
#define ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE 0x02
typedef struct altcp_proxyconnect_state_s
{
ip_addr_t outer_addr;
u16_t outer_port;
struct altcp_proxyconnect_config *conf;
u8_t flags;
} altcp_proxyconnect_state_t;
/* Variable prototype, the actual declaration is at the end of this file
since it contains pointers to static functions declared here */
extern const struct altcp_functions altcp_proxyconnect_functions;
/* memory management functions: */
static altcp_proxyconnect_state_t *
altcp_proxyconnect_state_alloc(void)
{
altcp_proxyconnect_state_t *ret = (altcp_proxyconnect_state_t *)mem_calloc(1, sizeof(altcp_proxyconnect_state_t));
return ret;
}
static void
altcp_proxyconnect_state_free(altcp_proxyconnect_state_t *state)
{
LWIP_ASSERT("state != NULL", state != NULL);
mem_free(state);
}
/* helper functions */
#define PROXY_CONNECT "CONNECT %s:%d HTTP/1.1\r\n" /* HOST, PORT */ \
"User-Agent: %s\r\n" /* User-Agent */\
"Proxy-Connection: keep-alive\r\n" \
"Connection: keep-alive\r\n" \
"\r\n"
#define PROXY_CONNECT_FORMAT(host, port) PROXY_CONNECT, host, port, ALTCP_PROXYCONNECT_CLIENT_AGENT
/* Format the http proxy connect request via snprintf */
static int
altcp_proxyconnect_format_request(char *buffer, size_t bufsize, const char *host, int port)
{
return snprintf(buffer, bufsize, PROXY_CONNECT_FORMAT(host, port));
}
/* Create and send the http proxy connect request */
static err_t
altcp_proxyconnect_send_request(struct altcp_pcb *conn)
{
int len, len2;
mem_size_t alloc_len;
char *buffer, *host;
altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
if (!state) {
return ERR_VAL;
}
/* Use printf with zero length to get the required allocation size */
len = altcp_proxyconnect_format_request(NULL, 0, "", state->outer_port);
if (len < 0) {
return ERR_VAL;
}
/* add allocation size for IP address strings */
#if LWIP_IPV6
len += 40; /* worst-case IPv6 address length */
#else
len += 16; /* worst-case IPv4 address length */
#endif
alloc_len = (mem_size_t)len;
if ((len < 0) || (int)alloc_len != len) {
/* overflow */
return ERR_MEM;
}
/* Allocate a bufer for the request string */
buffer = (char *)mem_malloc(alloc_len);
if (buffer == NULL) {
return ERR_MEM;
}
host = ipaddr_ntoa(&state->outer_addr);
len2 = altcp_proxyconnect_format_request(buffer, alloc_len, host, state->outer_port);
if ((len2 > 0) && (len2 <= len) && (len2 <= 0xFFFF)) {
err_t err = altcp_write(conn->inner_conn, buffer, (u16_t)len2, TCP_WRITE_FLAG_COPY);
if (err != ERR_OK) {
/* @todo: abort? */
mem_free(buffer);
return err;
}
}
mem_free(buffer);
return ERR_OK;
}
/* callback functions from inner/lower connection: */
/** Connected callback from lower connection (i.e. TCP).
* Not really implemented/tested yet...
*/
static err_t
altcp_proxyconnect_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err)
{
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
if (conn && conn->state) {
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
/* upper connected is called when handshake is done */
if (err != ERR_OK) {
if (conn->connected) {
if (conn->connected(conn->arg, conn, err) == ERR_ABRT) {
return ERR_ABRT;
}
return ERR_OK;
}
}
/* send proxy connect request here */
return altcp_proxyconnect_send_request(conn);
}
return ERR_VAL;
}
/** Recv callback from lower connection (i.e. TCP)
* This one mainly differs between connection setup (wait for proxy OK string)
* and application phase (data is passed on to the application).
*/
static err_t
altcp_proxyconnect_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err)
{
altcp_proxyconnect_state_t *state;
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
LWIP_ASSERT("no err expected", err == ERR_OK);
LWIP_UNUSED_ARG(err);
if (!conn) {
/* no connection given as arg? should not happen, but prevent pbuf/conn leaks */
if (p != NULL) {
pbuf_free(p);
}
altcp_close(inner_conn);
return ERR_CLSD;
}
state = (altcp_proxyconnect_state_t *)conn->state;
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
if (!state) {
/* already closed */
if (p != NULL) {
pbuf_free(p);
}
altcp_close(inner_conn);
return ERR_CLSD;
}
if (state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE) {
/* application phase, just pass this through */
if (conn->recv) {
return conn->recv(conn->arg, conn, p, err);
}
pbuf_free(p);
return ERR_OK;
} else {
/* setup phase */
/* handle NULL pbuf (inner connection closed) */
if (p == NULL) {
if (altcp_close(conn) != ERR_OK) {
altcp_abort(conn);
return ERR_ABRT;
}
return ERR_OK;
} else {
/* @todo: parse setup phase rx data
for now, we just wait for the end of the header... */
u16_t idx = pbuf_memfind(p, "\r\n\r\n", 4, 0);
altcp_recved(inner_conn, p->tot_len);
pbuf_free(p);
if (idx != 0xFFFF) {
state->flags |= ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE;
if (conn->connected) {
return conn->connected(conn->arg, conn, ERR_OK);
}
}
return ERR_OK;
}
}
}
/** Sent callback from lower connection (i.e. TCP)
* This only informs the upper layer to try to send more, not about
* the number of ACKed bytes.
*/
static err_t
altcp_proxyconnect_lower_sent(void *arg, struct altcp_pcb *inner_conn, u16_t len)
{
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
LWIP_UNUSED_ARG(len);
if (conn) {
altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
if (!state || !(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
/* @todo: do something here? */
return ERR_OK;
}
/* pass this on to upper sent */
if (conn->sent) {
return conn->sent(conn->arg, conn, len);
}
}
return ERR_OK;
}
/** Poll callback from lower connection (i.e. TCP)
* Just pass this on to the application.
* @todo: retry sending?
*/
static err_t
altcp_proxyconnect_lower_poll(void *arg, struct altcp_pcb *inner_conn)
{
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
if (conn) {
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
if (conn->poll) {
return conn->poll(conn->arg, conn);
}
}
return ERR_OK;
}
static void
altcp_proxyconnect_lower_err(void *arg, err_t err)
{
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
if (conn) {
conn->inner_conn = NULL; /* already freed */
if (conn->err) {
conn->err(conn->arg, err);
}
altcp_free(conn);
}
}
/* setup functions */
static void
altcp_proxyconnect_setup_callbacks(struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
{
altcp_arg(inner_conn, conn);
altcp_recv(inner_conn, altcp_proxyconnect_lower_recv);
altcp_sent(inner_conn, altcp_proxyconnect_lower_sent);
altcp_err(inner_conn, altcp_proxyconnect_lower_err);
/* tcp_poll is set when interval is set by application */
/* listen is set totally different :-) */
}
static err_t
altcp_proxyconnect_setup(struct altcp_proxyconnect_config *config, struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
{
altcp_proxyconnect_state_t *state;
if (!config) {
return ERR_ARG;
}
LWIP_ASSERT("invalid inner_conn", conn != inner_conn);
/* allocate proxyconnect context */
state = altcp_proxyconnect_state_alloc();
if (state == NULL) {
return ERR_MEM;
}
state->flags = 0;
state->conf = config;
altcp_proxyconnect_setup_callbacks(conn, inner_conn);
conn->inner_conn = inner_conn;
conn->fns = &altcp_proxyconnect_functions;
conn->state = state;
return ERR_OK;
}
/** Allocate a new altcp layer connecting through a proxy.
* This function gets the inner pcb passed.
*
* @param config struct altcp_proxyconnect_config that contains the proxy settings
* @param inner_pcb pcb that makes the connection to the proxy (i.e. tcp pcb)
*/
struct altcp_pcb *
altcp_proxyconnect_new(struct altcp_proxyconnect_config *config, struct altcp_pcb *inner_pcb)
{
struct altcp_pcb *ret;
if (inner_pcb == NULL) {
return NULL;
}
ret = altcp_alloc();
if (ret != NULL) {
if (altcp_proxyconnect_setup(config, ret, inner_pcb) != ERR_OK) {
altcp_free(ret);
return NULL;
}
}
return ret;
}
/** Allocate a new altcp layer connecting through a proxy.
* This function allocates the inner pcb as tcp pcb, resulting in a direct tcp
* connection to the proxy.
*
* @param config struct altcp_proxyconnect_config that contains the proxy settings
* @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
*/
struct altcp_pcb *
altcp_proxyconnect_new_tcp(struct altcp_proxyconnect_config *config, u8_t ip_type)
{
struct altcp_pcb *inner_pcb, *ret;
/* inner pcb is tcp */
inner_pcb = altcp_tcp_new_ip_type(ip_type);
if (inner_pcb == NULL) {
return NULL;
}
ret = altcp_proxyconnect_new(config, inner_pcb);
if (ret == NULL) {
altcp_close(inner_pcb);
}
return ret;
}
/** Allocator function to allocate a proxy connect altcp pcb connecting directly
* via tcp to the proxy.
*
* The returned pcb is a chain: altcp_proxyconnect - altcp_tcp - tcp pcb
*
* This function is meant for use with @ref altcp_new.
*
* @param arg struct altcp_proxyconnect_config that contains the proxy settings
* @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
*/
struct altcp_pcb *
altcp_proxyconnect_alloc(void *arg, u8_t ip_type)
{
return altcp_proxyconnect_new_tcp((struct altcp_proxyconnect_config *)arg, ip_type);
}
#if LWIP_ALTCP_TLS
/** Allocator function to allocate a TLS connection through a proxy.
*
* The returned pcb is a chain: altcp_tls - altcp_proxyconnect - altcp_tcp - tcp pcb
*
* This function is meant for use with @ref altcp_new.
*
* @param arg struct altcp_proxyconnect_tls_config that contains the proxy settings
* and tls settings
* @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
*/
struct altcp_pcb *
altcp_proxyconnect_tls_alloc(void *arg, u8_t ip_type)
{
struct altcp_proxyconnect_tls_config *cfg = (struct altcp_proxyconnect_tls_config *)arg;
struct altcp_pcb *proxy_pcb;
struct altcp_pcb *tls_pcb;
proxy_pcb = altcp_proxyconnect_new_tcp(&cfg->proxy, ip_type);
tls_pcb = altcp_tls_wrap(cfg->tls_config, proxy_pcb);
if (tls_pcb == NULL) {
altcp_close(proxy_pcb);
}
return tls_pcb;
}
#endif /* LWIP_ALTCP_TLS */
/* "virtual" functions */
static void
altcp_proxyconnect_set_poll(struct altcp_pcb *conn, u8_t interval)
{
if (conn != NULL) {
altcp_poll(conn->inner_conn, altcp_proxyconnect_lower_poll, interval);
}
}
static void
altcp_proxyconnect_recved(struct altcp_pcb *conn, u16_t len)
{
altcp_proxyconnect_state_t *state;
if (conn == NULL) {
return;
}
state = (altcp_proxyconnect_state_t *)conn->state;
if (state == NULL) {
return;
}
if (!(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
return;
}
altcp_recved(conn->inner_conn, len);
}
static err_t
altcp_proxyconnect_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
{
altcp_proxyconnect_state_t *state;
if ((conn == NULL) || (ipaddr == NULL)) {
return ERR_VAL;
}
state = (altcp_proxyconnect_state_t *)conn->state;
if (state == NULL) {
return ERR_VAL;
}
if (state->flags & ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED) {
return ERR_VAL;
}
state->flags |= ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED;
conn->connected = connected;
/* connect to our proxy instead, but store the requested address and port */
ip_addr_copy(state->outer_addr, *ipaddr);
state->outer_port = port;
return altcp_connect(conn->inner_conn, &state->conf->proxy_addr, state->conf->proxy_port, altcp_proxyconnect_lower_connected);
}
static struct altcp_pcb *
altcp_proxyconnect_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err)
{
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(backlog);
LWIP_UNUSED_ARG(err);
/* listen not supported! */
return NULL;
}
static void
altcp_proxyconnect_abort(struct altcp_pcb *conn)
{
if (conn != NULL) {
if (conn->inner_conn != NULL) {
altcp_abort(conn->inner_conn);
}
altcp_free(conn);
}
}
static err_t
altcp_proxyconnect_close(struct altcp_pcb *conn)
{
if (conn == NULL) {
return ERR_VAL;
}
if (conn->inner_conn != NULL) {
err_t err = altcp_close(conn->inner_conn);
if (err != ERR_OK) {
/* closing inner conn failed, return the error */
return err;
}
}
/* no inner conn or closing it succeeded, deallocate myself */
altcp_free(conn);
return ERR_OK;
}
static err_t
altcp_proxyconnect_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
{
altcp_proxyconnect_state_t *state;
LWIP_UNUSED_ARG(apiflags);
if (conn == NULL) {
return ERR_VAL;
}
state = (altcp_proxyconnect_state_t *)conn->state;
if (state == NULL) {
/* @todo: which error? */
return ERR_CLSD;
}
if (!(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
/* @todo: which error? */
return ERR_VAL;
}
return altcp_write(conn->inner_conn, dataptr, len, apiflags);
}
static void
altcp_proxyconnect_dealloc(struct altcp_pcb *conn)
{
/* clean up and free tls state */
if (conn) {
altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
if (state) {
altcp_proxyconnect_state_free(state);
conn->state = NULL;
}
}
}
const struct altcp_functions altcp_proxyconnect_functions = {
altcp_proxyconnect_set_poll,
altcp_proxyconnect_recved,
altcp_default_bind,
altcp_proxyconnect_connect,
altcp_proxyconnect_listen,
altcp_proxyconnect_abort,
altcp_proxyconnect_close,
altcp_default_shutdown,
altcp_proxyconnect_write,
altcp_default_output,
altcp_default_mss,
altcp_default_sndbuf,
altcp_default_sndqueuelen,
altcp_default_nagle_disable,
altcp_default_nagle_enable,
altcp_default_nagle_disabled,
altcp_default_setprio,
altcp_proxyconnect_dealloc,
altcp_default_get_tcp_addrinfo,
altcp_default_get_ip,
altcp_default_get_port
#ifdef LWIP_DEBUG
, altcp_default_dbg_get_tcp_state
#endif
};
#endif /* LWIP_ALTCP */

174
third_party/lwip/src/apps/http/fs.c vendored Normal file
View File

@ -0,0 +1,174 @@
/*
* Copyright (c) 2001-2003 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/apps/httpd_opts.h"
#include "lwip/def.h"
#include "lwip/apps/fs.h"
#include <string.h>
#include HTTPD_FSDATA_FILE
/*-----------------------------------------------------------------------------------*/
#if LWIP_HTTPD_CUSTOM_FILES
int fs_open_custom(struct fs_file *file, const char *name);
void fs_close_custom(struct fs_file *file);
#if LWIP_HTTPD_FS_ASYNC_READ
u8_t fs_canread_custom(struct fs_file *file);
u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg);
int fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg);
#else /* LWIP_HTTPD_FS_ASYNC_READ */
int fs_read_custom(struct fs_file *file, char *buffer, int count);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
#endif /* LWIP_HTTPD_CUSTOM_FILES */
/*-----------------------------------------------------------------------------------*/
err_t
fs_open(struct fs_file *file, const char *name)
{
const struct fsdata_file *f;
if ((file == NULL) || (name == NULL)) {
return ERR_ARG;
}
#if LWIP_HTTPD_CUSTOM_FILES
if (fs_open_custom(file, name)) {
file->is_custom_file = 1;
return ERR_OK;
}
file->is_custom_file = 0;
#endif /* LWIP_HTTPD_CUSTOM_FILES */
for (f = FS_ROOT; f != NULL; f = f->next) {
if (!strcmp(name, (const char *)f->name)) {
file->data = (const char *)f->data;
file->len = f->len;
file->index = f->len;
file->pextension = NULL;
file->flags = f->flags;
#if HTTPD_PRECALCULATED_CHECKSUM
file->chksum_count = f->chksum_count;
file->chksum = f->chksum;
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
#if LWIP_HTTPD_FILE_STATE
file->state = fs_state_init(file, name);
#endif /* #if LWIP_HTTPD_FILE_STATE */
return ERR_OK;
}
}
/* file not found */
return ERR_VAL;
}
/*-----------------------------------------------------------------------------------*/
void
fs_close(struct fs_file *file)
{
#if LWIP_HTTPD_CUSTOM_FILES
if (file->is_custom_file) {
fs_close_custom(file);
}
#endif /* LWIP_HTTPD_CUSTOM_FILES */
#if LWIP_HTTPD_FILE_STATE
fs_state_free(file, file->state);
#endif /* #if LWIP_HTTPD_FILE_STATE */
LWIP_UNUSED_ARG(file);
}
/*-----------------------------------------------------------------------------------*/
#if LWIP_HTTPD_DYNAMIC_FILE_READ
#if LWIP_HTTPD_FS_ASYNC_READ
int
fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg)
#else /* LWIP_HTTPD_FS_ASYNC_READ */
int
fs_read(struct fs_file *file, char *buffer, int count)
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
{
int read;
if (file->index == file->len) {
return FS_READ_EOF;
}
#if LWIP_HTTPD_FS_ASYNC_READ
LWIP_UNUSED_ARG(callback_fn);
LWIP_UNUSED_ARG(callback_arg);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
#if LWIP_HTTPD_CUSTOM_FILES
if (file->is_custom_file) {
#if LWIP_HTTPD_FS_ASYNC_READ
return fs_read_async_custom(file, buffer, count, callback_fn, callback_arg);
#else /* LWIP_HTTPD_FS_ASYNC_READ */
return fs_read_custom(file, buffer, count);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
}
#endif /* LWIP_HTTPD_CUSTOM_FILES */
read = file->len - file->index;
if (read > count) {
read = count;
}
MEMCPY(buffer, (file->data + file->index), read);
file->index += read;
return (read);
}
#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
/*-----------------------------------------------------------------------------------*/
#if LWIP_HTTPD_FS_ASYNC_READ
int
fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg)
{
if (file != NULL) {
#if LWIP_HTTPD_FS_ASYNC_READ
#if LWIP_HTTPD_CUSTOM_FILES
if (!fs_canread_custom(file)) {
if (fs_wait_read_custom(file, callback_fn, callback_arg)) {
return 0;
}
}
#else /* LWIP_HTTPD_CUSTOM_FILES */
LWIP_UNUSED_ARG(callback_fn);
LWIP_UNUSED_ARG(callback_arg);
#endif /* LWIP_HTTPD_CUSTOM_FILES */
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
}
return 1;
}
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
/*-----------------------------------------------------------------------------------*/
int
fs_bytes_left(struct fs_file *file)
{
return file->len - file->index;
}

View File

@ -0,0 +1,21 @@
<html>
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
<body bgcolor="white" text="black">
<table width="100%">
<tr valign="top"><td width="80">
<a href="http://www.sics.se/"><img src="/img/sics.gif"
border="0" alt="SICS logo" title="SICS logo"></a>
</td><td width="500">
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
<h2>404 - Page not found</h2>
<p>
Sorry, the page you are requesting was not found on this
server.
</p>
</td><td>
&nbsp;
</td></tr>
</table>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

View File

@ -0,0 +1,47 @@
<html>
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
<body bgcolor="white" text="black">
<table width="100%">
<tr valign="top"><td width="80">
<a href="http://www.sics.se/"><img src="/img/sics.gif"
border="0" alt="SICS logo" title="SICS logo"></a>
</td><td width="500">
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
<p>
The web page you are watching was served by a simple web
server running on top of the lightweight TCP/IP stack <a
href="http://www.sics.se/~adam/lwip/">lwIP</a>.
</p>
<p>
lwIP is an open source implementation of the TCP/IP
protocol suite that was originally written by <a
href="http://www.sics.se/~adam/lwip/">Adam Dunkels
of the Swedish Institute of Computer Science</a> but now is
being actively developed by a team of developers
distributed world-wide. Since it's release, lwIP has
spurred a lot of interest and has been ported to several
platforms and operating systems. lwIP can be used either
with or without an underlying OS.
</p>
<p>
The focus of the lwIP TCP/IP implementation is to reduce
the RAM usage while still having a full scale TCP. This
makes lwIP suitable for use in embedded systems with tens
of kilobytes of free RAM and room for around 40 kilobytes
of code ROM.
</p>
<p>
More information about lwIP can be found at the lwIP
homepage at <a
href="http://savannah.nongnu.org/projects/lwip/">http://savannah.nongnu.org/projects/lwip/</a>
or at the lwIP wiki at <a
href="http://lwip.wikia.com/">http://lwip.wikia.com/</a>.
</p>
</td><td>
&nbsp;
</td></tr>
</table>
</body>
</html>

337
third_party/lwip/src/apps/http/fsdata.c vendored Normal file
View File

@ -0,0 +1,337 @@
#include "lwip/apps/fs.h"
#include "lwip/def.h"
#define file_NULL (struct fsdata_file *) NULL
#ifndef FS_FILE_FLAGS_HEADER_INCLUDED
#define FS_FILE_FLAGS_HEADER_INCLUDED 1
#endif
#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT
#define FS_FILE_FLAGS_HEADER_PERSISTENT 0
#endif
/* FSDATA_FILE_ALIGNMENT: 0=off, 1=by variable, 2=by include */
#ifndef FSDATA_FILE_ALIGNMENT
#define FSDATA_FILE_ALIGNMENT 0
#endif
#ifndef FSDATA_ALIGN_PRE
#define FSDATA_ALIGN_PRE
#endif
#ifndef FSDATA_ALIGN_POST
#define FSDATA_ALIGN_POST
#endif
#if FSDATA_FILE_ALIGNMENT==2
#include "fsdata_alignment.h"
#endif
#if FSDATA_FILE_ALIGNMENT==1
static const unsigned int dummy_align__img_sics_gif = 0;
#endif
static const unsigned char FSDATA_ALIGN_PRE data__img_sics_gif[] FSDATA_ALIGN_POST = {
/* /img/sics.gif (14 chars) */
0x2f,0x69,0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x00,0x00,0x00,
/* HTTP header */
/* "HTTP/1.0 200 OK
" (17 bytes) */
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
0x0a,
/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip)
" (64 bytes) */
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30,
0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,
0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,
0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
/* "Content-Length: 724
" (18+ bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,
0x37,0x32,0x34,0x0d,0x0a,
/* "Content-Type: image/gif
" (27 bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x69,0x6d,
0x61,0x67,0x65,0x2f,0x67,0x69,0x66,0x0d,0x0a,0x0d,0x0a,
/* raw file data (724 bytes) */
0x47,0x49,0x46,0x38,0x39,0x61,0x46,0x00,0x22,0x00,0xa5,0x00,0x00,0xd9,0x2b,0x39,
0x6a,0x6a,0x6a,0xbf,0xbf,0xbf,0x93,0x93,0x93,0x0f,0x0f,0x0f,0xb0,0xb0,0xb0,0xa6,
0xa6,0xa6,0x80,0x80,0x80,0x76,0x76,0x76,0x1e,0x1e,0x1e,0x9d,0x9d,0x9d,0x2e,0x2e,
0x2e,0x49,0x49,0x49,0x54,0x54,0x54,0x8a,0x8a,0x8a,0x60,0x60,0x60,0xc6,0xa6,0x99,
0xbd,0xb5,0xb2,0xc2,0xab,0xa1,0xd9,0x41,0x40,0xd5,0x67,0x55,0xc0,0xb0,0xaa,0xd5,
0x5e,0x4e,0xd6,0x50,0x45,0xcc,0x93,0x7d,0xc8,0xa1,0x90,0xce,0x8b,0x76,0xd2,0x7b,
0x65,0xd1,0x84,0x6d,0xc9,0x99,0x86,0x3a,0x3a,0x3a,0x00,0x00,0x00,0xb8,0xb8,0xb8,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2c,0x00,0x00,
0x00,0x00,0x46,0x00,0x22,0x00,0x00,0x06,0xfe,0x40,0x90,0x70,0x48,0x2c,0x1a,0x8f,
0xc8,0xa4,0x72,0xc9,0x6c,0x3a,0x9f,0xd0,0xa8,0x74,0x4a,0xad,0x5a,0xaf,0xd8,0xac,
0x76,0xa9,0x40,0x04,0xbe,0x83,0xe2,0x60,0x3c,0x50,0x20,0x0d,0x8e,0x6f,0x00,0x31,
0x28,0x1c,0x0d,0x07,0xb5,0xc3,0x60,0x75,0x24,0x3e,0xf8,0xfc,0x87,0x11,0x06,0xe9,
0x3d,0x46,0x07,0x0b,0x7a,0x7a,0x7c,0x43,0x06,0x1e,0x84,0x78,0x0b,0x07,0x6e,0x51,
0x01,0x8a,0x84,0x08,0x7e,0x79,0x80,0x87,0x89,0x91,0x7a,0x93,0x0a,0x04,0x99,0x78,
0x96,0x4f,0x03,0x9e,0x79,0x01,0x94,0x9f,0x43,0x9c,0xa3,0xa4,0x05,0x77,0xa3,0xa0,
0x4e,0x98,0x79,0x0b,0x1e,0x83,0xa4,0xa6,0x1f,0x96,0x05,0x9d,0xaa,0x78,0x01,0x07,
0x84,0x04,0x1e,0x1e,0xbb,0xb8,0x51,0x84,0x0e,0x43,0x05,0x07,0x77,0xa5,0x7f,0x42,
0xb1,0xb2,0x01,0x63,0x08,0x0d,0xbb,0x01,0x0c,0x7a,0x0d,0x44,0x0e,0xd8,0xaf,0x4c,
0x05,0x7a,0x04,0x47,0x07,0x07,0xb7,0x80,0xa2,0xe1,0x7d,0x44,0x05,0x01,0x04,0x01,
0xd0,0xea,0x87,0x93,0x4f,0xe0,0x9a,0x49,0xce,0xd8,0x79,0x04,0x66,0x20,0x15,0x10,
0x10,0x11,0x92,0x29,0x80,0xb6,0xc0,0x91,0x15,0x45,0x1e,0x90,0x19,0x71,0x46,0xa8,
0x5c,0x04,0x0e,0x00,0x22,0x4e,0xe8,0x40,0x24,0x9f,0x3e,0x04,0x06,0xa7,0x58,0xd4,
0x93,0xa0,0x1c,0x91,0x3f,0xe8,0xf0,0x88,0x03,0xb1,0x21,0xa2,0x49,0x00,0x19,0x86,
0xfc,0x52,0x44,0xe0,0x01,0x9d,0x29,0x21,0x15,0x25,0x50,0xf7,0x67,0x25,0x1e,0x06,
0xfd,0x4e,0x9a,0xb4,0x90,0xac,0x15,0xfa,0xcb,0x52,0x53,0x1e,0x8c,0xf2,0xf8,0x07,
0x92,0x2d,0x08,0x3a,0x4d,0x12,0x49,0x95,0x49,0xdb,0x14,0x04,0xc4,0x14,0x85,0x29,
0xaa,0xe7,0x01,0x08,0xa4,0x49,0x01,0x14,0x51,0xe0,0x53,0x91,0xd5,0x29,0x06,0x1a,
0x64,0x02,0xf4,0xc7,0x81,0x9e,0x05,0x20,0x22,0x64,0xa5,0x30,0xae,0xab,0x9e,0x97,
0x53,0xd8,0xb9,0xfd,0x50,0xef,0x93,0x02,0x42,0x74,0x34,0xe8,0x9c,0x20,0x21,0xc9,
0x01,0x68,0x78,0xe6,0x55,0x29,0x20,0x56,0x4f,0x4c,0x40,0x51,0x71,0x82,0xc0,0x70,
0x21,0x22,0x85,0xbe,0x4b,0x1c,0x44,0x05,0xea,0xa4,0x01,0xbf,0x22,0xb5,0xf0,0x1c,
0x06,0x51,0x38,0x8f,0xe0,0x22,0xec,0x18,0xac,0x39,0x22,0xd4,0xd6,0x93,0x44,0x01,
0x32,0x82,0xc8,0xfc,0x61,0xb3,0x01,0x45,0x0c,0x2e,0x83,0x30,0xd0,0x0e,0x17,0x24,
0x0f,0x70,0x85,0x94,0xee,0x05,0x05,0x53,0x4b,0x32,0x1b,0x3f,0x98,0xd3,0x1d,0x29,
0x81,0xb0,0xae,0x1e,0x8c,0x7e,0x68,0xe0,0x60,0x5a,0x54,0x8f,0xb0,0x78,0x69,0x73,
0x06,0xa2,0x00,0x6b,0x57,0xca,0x3d,0x11,0x50,0xbd,0x04,0x30,0x4b,0x3a,0xd4,0xab,
0x5f,0x1f,0x9b,0x3d,0x13,0x74,0x27,0x88,0x3c,0x25,0xe0,0x17,0xbe,0x7a,0x79,0x45,
0x0d,0x0c,0xb0,0x8b,0xda,0x90,0xca,0x80,0x06,0x5d,0x17,0x60,0x1c,0x22,0x4c,0xd8,
0x57,0x22,0x06,0x20,0x00,0x98,0x07,0x08,0xe4,0x56,0x80,0x80,0x1c,0xc5,0xb7,0xc5,
0x82,0x0c,0x36,0xe8,0xe0,0x83,0x10,0x46,0x28,0xe1,0x84,0x14,0x56,0x68,0xa1,0x10,
0x41,0x00,0x00,0x3b,};
#if FSDATA_FILE_ALIGNMENT==1
static const unsigned int dummy_align__404_html = 1;
#endif
static const unsigned char FSDATA_ALIGN_PRE data__404_html[] FSDATA_ALIGN_POST = {
/* /404.html (10 chars) */
0x2f,0x34,0x30,0x34,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x00,
/* HTTP header */
/* "HTTP/1.0 404 File not found
" (29 bytes) */
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x34,0x30,0x34,0x20,0x46,0x69,0x6c,
0x65,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x0d,0x0a,
/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip)
" (64 bytes) */
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30,
0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,
0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,
0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
/* "Content-Length: 565
" (18+ bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,
0x35,0x36,0x35,0x0d,0x0a,
/* "Content-Type: text/html
" (27 bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a,
/* raw file data (565 bytes) */
0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74,
0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,
0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,
0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f,
0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63,
0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78,
0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20,
0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,
0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74,
0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c,
0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20,
0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,
0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20,
0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,
0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,
0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f,
0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69,
0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09,
0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,
0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,
0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20,
0x20,0x3c,0x68,0x32,0x3e,0x34,0x30,0x34,0x20,0x2d,0x20,0x50,0x61,0x67,0x65,0x20,
0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3c,0x2f,0x68,0x32,0x3e,0x0d,0x0a,
0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x53,0x6f,0x72,
0x72,0x79,0x2c,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,
0x20,0x61,0x72,0x65,0x20,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x69,0x6e,0x67,0x20,
0x77,0x61,0x73,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x6f,0x6e,
0x20,0x74,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,
0x65,0x72,0x2e,0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,
0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e,
0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72,
0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,
0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,
0x6d,0x6c,0x3e,0x0d,0x0a,};
#if FSDATA_FILE_ALIGNMENT==1
static const unsigned int dummy_align__index_html = 2;
#endif
static const unsigned char FSDATA_ALIGN_PRE data__index_html[] FSDATA_ALIGN_POST = {
/* /index.html (12 chars) */
0x2f,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x00,
/* HTTP header */
/* "HTTP/1.0 200 OK
" (17 bytes) */
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
0x0a,
/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip)
" (64 bytes) */
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30,
0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,
0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,
0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
/* "Content-Length: 1751
" (18+ bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,
0x31,0x37,0x35,0x31,0x0d,0x0a,
/* "Content-Type: text/html
" (27 bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a,
/* raw file data (1751 bytes) */
0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74,
0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,
0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,
0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f,
0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63,
0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78,
0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20,
0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,
0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74,
0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c,
0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20,
0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,
0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20,
0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,
0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,
0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f,
0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69,
0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09,
0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,
0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,
0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20,
0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x77,
0x65,0x62,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,0x20,0x61,0x72,0x65,0x20,
0x77,0x61,0x74,0x63,0x68,0x69,0x6e,0x67,0x20,0x77,0x61,0x73,0x20,0x73,0x65,0x72,
0x76,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x73,0x69,0x6d,0x70,0x6c,0x65,0x20,
0x77,0x65,0x62,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,0x65,0x72,
0x20,0x72,0x75,0x6e,0x6e,0x69,0x6e,0x67,0x20,0x6f,0x6e,0x20,0x74,0x6f,0x70,0x20,
0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,
0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20,0x73,0x74,0x61,0x63,0x6b,0x20,
0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x6c,
0x77,0x49,0x50,0x3c,0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,
0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,
0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,
0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,
0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,
0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,
0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,
0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,
0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,
0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,
0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,
0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,
0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,
0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,
0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,
0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,
0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,
0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,
0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,
0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,
0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,
0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,
0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,
0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,
0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,
0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,
0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,
0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,
0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,
0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,
0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,
0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,
0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,
0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,
0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,
0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x66,0x6f,0x63,0x75,0x73,0x20,0x6f,
0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x54,0x43,0x50,0x2f,0x49,
0x50,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,
0x20,0x69,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x0d,0x0a,0x09,
0x20,0x20,0x20,0x20,0x74,0x68,0x65,0x20,0x52,0x41,0x4d,0x20,0x75,0x73,0x61,0x67,
0x65,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x73,0x74,0x69,0x6c,0x6c,0x20,0x68,0x61,
0x76,0x69,0x6e,0x67,0x20,0x61,0x20,0x66,0x75,0x6c,0x6c,0x20,0x73,0x63,0x61,0x6c,
0x65,0x20,0x54,0x43,0x50,0x2e,0x20,0x54,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,
0x20,0x20,0x6d,0x61,0x6b,0x65,0x73,0x20,0x6c,0x77,0x49,0x50,0x20,0x73,0x75,0x69,
0x74,0x61,0x62,0x6c,0x65,0x20,0x66,0x6f,0x72,0x20,0x75,0x73,0x65,0x20,0x69,0x6e,
0x20,0x65,0x6d,0x62,0x65,0x64,0x64,0x65,0x64,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,
0x73,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x65,0x6e,0x73,0x0d,0x0a,0x09,0x20,0x20,
0x20,0x20,0x6f,0x66,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x20,0x6f,
0x66,0x20,0x66,0x72,0x65,0x65,0x20,0x52,0x41,0x4d,0x20,0x61,0x6e,0x64,0x20,0x72,
0x6f,0x6f,0x6d,0x20,0x66,0x6f,0x72,0x20,0x61,0x72,0x6f,0x75,0x6e,0x64,0x20,0x34,
0x30,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x0d,0x0a,0x09,0x20,0x20,
0x20,0x20,0x6f,0x66,0x20,0x63,0x6f,0x64,0x65,0x20,0x52,0x4f,0x4d,0x2e,0x0d,0x0a,
0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,
0x0a,0x09,0x20,0x20,0x20,0x20,0x4d,0x6f,0x72,0x65,0x20,0x69,0x6e,0x66,0x6f,0x72,
0x6d,0x61,0x74,0x69,0x6f,0x6e,0x20,0x61,0x62,0x6f,0x75,0x74,0x20,0x6c,0x77,0x49,
0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x61,
0x74,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,
0x20,0x68,0x6f,0x6d,0x65,0x70,0x61,0x67,0x65,0x20,0x61,0x74,0x20,0x3c,0x61,0x0d,
0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,
0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,
0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,
0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,
0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,
0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x2f,
0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x72,0x20,0x61,0x74,
0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x77,0x69,0x6b,0x69,0x20,0x61,
0x74,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,
0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,
0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x3c,
0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,
0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e,
0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72,
0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,
0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,
0x6d,0x6c,0x3e,0x0d,0x0a,0x0d,0x0a,};
const struct fsdata_file file__img_sics_gif[] = { {
file_NULL,
data__img_sics_gif,
data__img_sics_gif + 16,
sizeof(data__img_sics_gif) - 16,
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
}};
const struct fsdata_file file__404_html[] = { {
file__img_sics_gif,
data__404_html,
data__404_html + 12,
sizeof(data__404_html) - 12,
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
}};
const struct fsdata_file file__index_html[] = { {
file__404_html,
data__index_html,
data__index_html + 12,
sizeof(data__index_html) - 12,
FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT,
}};
#define FS_ROOT file__index_html
#define FS_NUMFILES 3

41
third_party/lwip/src/apps/http/fsdata.h vendored Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2001-2003 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>
*
*/
#ifndef LWIP_FSDATA_H
#define LWIP_FSDATA_H
#include "lwip/apps/httpd_opts.h"
#include "lwip/apps/fs.h"
/* THIS FILE IS DEPRECATED AND WILL BE REMOVED IN THE FUTURE */
/* content was moved to fs.h to simplify #include structure */
#endif /* LWIP_FSDATA_H */

View File

@ -0,0 +1,908 @@
/**
* @file
* HTTP client
*/
/*
* Copyright (c) 2018 Simon Goldschmidt <goldsimon@gmx.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.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt <goldsimon@gmx.de>
*/
/**
* @defgroup httpc HTTP client
* @ingroup apps
* @todo:
* - persistent connections
* - select outgoing http version
* - optionally follow redirect
* - check request uri for invalid characters? (e.g. encode spaces)
* - IPv6 support
*/
#include "lwip/apps/http_client.h"
#include "lwip/altcp_tcp.h"
#include "lwip/dns.h"
#include "lwip/debug.h"
#include "lwip/mem.h"
#include "lwip/altcp_tls.h"
#include "lwip/init.h"
#include <stdio.h>
#include <string.h>
#if LWIP_TCP && LWIP_CALLBACK_API
/**
* HTTPC_DEBUG: Enable debugging for HTTP client.
*/
#ifndef HTTPC_DEBUG
#define HTTPC_DEBUG LWIP_DBG_OFF
#endif
/** Set this to 1 to keep server name and uri in request state */
#ifndef HTTPC_DEBUG_REQUEST
#define HTTPC_DEBUG_REQUEST 0
#endif
/** This string is passed in the HTTP header as "User-Agent: " */
#ifndef HTTPC_CLIENT_AGENT
#define HTTPC_CLIENT_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)"
#endif
/* the various debug levels for this file */
#define HTTPC_DEBUG_TRACE (HTTPC_DEBUG | LWIP_DBG_TRACE)
#define HTTPC_DEBUG_STATE (HTTPC_DEBUG | LWIP_DBG_STATE)
#define HTTPC_DEBUG_WARN (HTTPC_DEBUG | LWIP_DBG_LEVEL_WARNING)
#define HTTPC_DEBUG_WARN_STATE (HTTPC_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
#define HTTPC_DEBUG_SERIOUS (HTTPC_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
#define HTTPC_POLL_INTERVAL 1
#define HTTPC_POLL_TIMEOUT 30 /* 15 seconds */
#define HTTPC_CONTENT_LEN_INVALID 0xFFFFFFFF
/* GET request basic */
#define HTTPC_REQ_11 "GET %s HTTP/1.1\r\n" /* URI */\
"User-Agent: %s\r\n" /* User-Agent */ \
"Accept: */*\r\n" \
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
"\r\n"
#define HTTPC_REQ_11_FORMAT(uri) HTTPC_REQ_11, uri, HTTPC_CLIENT_AGENT
/* GET request with host */
#define HTTPC_REQ_11_HOST "GET %s HTTP/1.1\r\n" /* URI */\
"User-Agent: %s\r\n" /* User-Agent */ \
"Accept: */*\r\n" \
"Host: %s\r\n" /* server name */ \
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
"\r\n"
#define HTTPC_REQ_11_HOST_FORMAT(uri, srv_name) HTTPC_REQ_11_HOST, uri, HTTPC_CLIENT_AGENT, srv_name
/* GET request with proxy */
#define HTTPC_REQ_11_PROXY "GET http://%s%s HTTP/1.1\r\n" /* HOST, URI */\
"User-Agent: %s\r\n" /* User-Agent */ \
"Accept: */*\r\n" \
"Host: %s\r\n" /* server name */ \
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
"\r\n"
#define HTTPC_REQ_11_PROXY_FORMAT(host, uri, srv_name) HTTPC_REQ_11_PROXY, host, uri, HTTPC_CLIENT_AGENT, srv_name
/* GET request with proxy (non-default server port) */
#define HTTPC_REQ_11_PROXY_PORT "GET http://%s:%d%s HTTP/1.1\r\n" /* HOST, host-port, URI */\
"User-Agent: %s\r\n" /* User-Agent */ \
"Accept: */*\r\n" \
"Host: %s\r\n" /* server name */ \
"Connection: Close\r\n" /* we don't support persistent connections, yet */ \
"\r\n"
#define HTTPC_REQ_11_PROXY_PORT_FORMAT(host, host_port, uri, srv_name) HTTPC_REQ_11_PROXY_PORT, host, host_port, uri, HTTPC_CLIENT_AGENT, srv_name
typedef enum ehttpc_parse_state {
HTTPC_PARSE_WAIT_FIRST_LINE = 0,
HTTPC_PARSE_WAIT_HEADERS,
HTTPC_PARSE_RX_DATA
} httpc_parse_state_t;
typedef struct _httpc_state
{
struct altcp_pcb* pcb;
ip_addr_t remote_addr;
u16_t remote_port;
int timeout_ticks;
struct pbuf *request;
struct pbuf *rx_hdrs;
u16_t rx_http_version;
u16_t rx_status;
altcp_recv_fn recv_fn;
const httpc_connection_t *conn_settings;
void* callback_arg;
u32_t rx_content_len;
u32_t hdr_content_len;
httpc_parse_state_t parse_state;
#if HTTPC_DEBUG_REQUEST
char* server_name;
char* uri;
#endif
} httpc_state_t;
/** Free http client state and deallocate all resources within */
static err_t
httpc_free_state(httpc_state_t* req)
{
struct altcp_pcb* tpcb;
if (req->request != NULL) {
pbuf_free(req->request);
req->request = NULL;
}
if (req->rx_hdrs != NULL) {
pbuf_free(req->rx_hdrs);
req->rx_hdrs = NULL;
}
tpcb = req->pcb;
mem_free(req);
req = NULL;
if (tpcb != NULL) {
err_t r;
altcp_arg(tpcb, NULL);
altcp_recv(tpcb, NULL);
altcp_err(tpcb, NULL);
altcp_poll(tpcb, NULL, 0);
altcp_sent(tpcb, NULL);
r = altcp_close(tpcb);
if (r != ERR_OK) {
altcp_abort(tpcb);
return ERR_ABRT;
}
}
return ERR_OK;
}
/** Close the connection: call finished callback and free the state */
static err_t
httpc_close(httpc_state_t* req, httpc_result_t result, u32_t server_response, err_t err)
{
if (req != NULL) {
if (req->conn_settings != NULL) {
if (req->conn_settings->result_fn != NULL) {
req->conn_settings->result_fn(req->callback_arg, result, req->rx_content_len, server_response, err);
}
}
return httpc_free_state(req);
}
return ERR_OK;
}
/** Parse http header response line 1 */
static err_t
http_parse_response_status(struct pbuf *p, u16_t *http_version, u16_t *http_status, u16_t *http_status_str_offset)
{
u16_t end1 = pbuf_memfind(p, "\r\n", 2, 0);
if (end1 != 0xFFFF) {
/* get parts of first line */
u16_t space1, space2;
space1 = pbuf_memfind(p, " ", 1, 0);
if (space1 != 0xFFFF) {
if ((pbuf_memcmp(p, 0, "HTTP/", 5) == 0) && (pbuf_get_at(p, 6) == '.')) {
char status_num[10];
size_t status_num_len;
/* parse http version */
u16_t version = pbuf_get_at(p, 5) - '0';
version <<= 8;
version |= pbuf_get_at(p, 7) - '0';
*http_version = version;
/* parse http status number */
space2 = pbuf_memfind(p, " ", 1, space1 + 1);
if (space2 != 0xFFFF) {
*http_status_str_offset = space2 + 1;
status_num_len = space2 - space1 - 1;
} else {
status_num_len = end1 - space1 - 1;
}
memset(status_num, 0, sizeof(status_num));
if (pbuf_copy_partial(p, status_num, (u16_t)status_num_len, space1 + 1) == status_num_len) {
int status = atoi(status_num);
if ((status > 0) && (status <= 0xFFFF)) {
*http_status = (u16_t)status;
return ERR_OK;
}
}
}
}
}
return ERR_VAL;
}
/** Wait for all headers to be received, return its length and content-length (if available) */
static err_t
http_wait_headers(struct pbuf *p, u32_t *content_length, u16_t *total_header_len)
{
u16_t end1 = pbuf_memfind(p, "\r\n\r\n", 4, 0);
if (end1 < (0xFFFF - 2)) {
/* all headers received */
/* check if we have a content length (@todo: case insensitive?) */
u16_t content_len_hdr;
*content_length = HTTPC_CONTENT_LEN_INVALID;
*total_header_len = end1 + 4;
content_len_hdr = pbuf_memfind(p, "Content-Length: ", 16, 0);
if (content_len_hdr != 0xFFFF) {
u16_t content_len_line_end = pbuf_memfind(p, "\r\n", 2, content_len_hdr);
if (content_len_line_end != 0xFFFF) {
char content_len_num[16];
u16_t content_len_num_len = (u16_t)(content_len_line_end - content_len_hdr - 16);
memset(content_len_num, 0, sizeof(content_len_num));
if (pbuf_copy_partial(p, content_len_num, content_len_num_len, content_len_hdr + 16) == content_len_num_len) {
int len = atoi(content_len_num);
if ((len >= 0) && ((u32_t)len < HTTPC_CONTENT_LEN_INVALID)) {
*content_length = (u32_t)len;
}
}
}
}
return ERR_OK;
}
return ERR_VAL;
}
/** http client tcp recv callback */
static err_t
httpc_tcp_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t r)
{
httpc_state_t* req = (httpc_state_t*)arg;
LWIP_UNUSED_ARG(r);
if (p == NULL) {
httpc_result_t result;
if (req->parse_state != HTTPC_PARSE_RX_DATA) {
/* did not get RX data yet */
result = HTTPC_RESULT_ERR_CLOSED;
} else if ((req->hdr_content_len != HTTPC_CONTENT_LEN_INVALID) &&
(req->hdr_content_len != req->rx_content_len)) {
/* header has been received with content length but not all data received */
result = HTTPC_RESULT_ERR_CONTENT_LEN;
} else {
/* receiving data and either all data received or no content length header */
result = HTTPC_RESULT_OK;
}
return httpc_close(req, result, req->rx_status, ERR_OK);
}
if (req->parse_state != HTTPC_PARSE_RX_DATA) {
if (req->rx_hdrs == NULL) {
req->rx_hdrs = p;
} else {
pbuf_cat(req->rx_hdrs, p);
}
if (req->parse_state == HTTPC_PARSE_WAIT_FIRST_LINE) {
u16_t status_str_off;
err_t err = http_parse_response_status(req->rx_hdrs, &req->rx_http_version, &req->rx_status, &status_str_off);
if (err == ERR_OK) {
/* don't care status string */
req->parse_state = HTTPC_PARSE_WAIT_HEADERS;
}
}
if (req->parse_state == HTTPC_PARSE_WAIT_HEADERS) {
u16_t total_header_len;
err_t err = http_wait_headers(req->rx_hdrs, &req->hdr_content_len, &total_header_len);
if (err == ERR_OK) {
struct pbuf *q;
/* full header received, send window update for header bytes and call into client callback */
altcp_recved(pcb, total_header_len);
if (req->conn_settings) {
if (req->conn_settings->headers_done_fn) {
err = req->conn_settings->headers_done_fn(req, req->callback_arg, req->rx_hdrs, total_header_len, req->hdr_content_len);
if (err != ERR_OK) {
return httpc_close(req, HTTPC_RESULT_LOCAL_ABORT, req->rx_status, err);
}
}
}
/* hide header bytes in pbuf */
q = pbuf_free_header(req->rx_hdrs, total_header_len);
p = q;
req->rx_hdrs = NULL;
/* go on with data */
req->parse_state = HTTPC_PARSE_RX_DATA;
}
}
}
if ((p != NULL) && (req->parse_state == HTTPC_PARSE_RX_DATA)) {
req->rx_content_len += p->tot_len;
if (req->recv_fn != NULL) {
/* directly return here: the connection migth already be aborted from the callback! */
return req->recv_fn(req->callback_arg, pcb, p, r);
} else {
altcp_recved(pcb, p->tot_len);
pbuf_free(p);
}
}
return ERR_OK;
}
/** http client tcp err callback */
static void
httpc_tcp_err(void *arg, err_t err)
{
httpc_state_t* req = (httpc_state_t*)arg;
if (req != NULL) {
/* pcb has already been deallocated */
req->pcb = NULL;
httpc_close(req, HTTPC_RESULT_ERR_CLOSED, 0, err);
}
}
/** http client tcp poll callback */
static err_t
httpc_tcp_poll(void *arg, struct altcp_pcb *pcb)
{
/* implement timeout */
httpc_state_t* req = (httpc_state_t*)arg;
LWIP_UNUSED_ARG(pcb);
if (req != NULL) {
if (req->timeout_ticks) {
req->timeout_ticks--;
}
if (!req->timeout_ticks) {
return httpc_close(req, HTTPC_RESULT_ERR_TIMEOUT, 0, ERR_OK);
}
}
return ERR_OK;
}
/** http client tcp sent callback */
static err_t
httpc_tcp_sent(void *arg, struct altcp_pcb *pcb, u16_t len)
{
/* nothing to do here for now */
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(pcb);
LWIP_UNUSED_ARG(len);
return ERR_OK;
}
/** http client tcp connected callback */
static err_t
httpc_tcp_connected(void *arg, struct altcp_pcb *pcb, err_t err)
{
err_t r;
httpc_state_t* req = (httpc_state_t*)arg;
LWIP_UNUSED_ARG(pcb);
LWIP_UNUSED_ARG(err);
/* send request; last char is zero termination */
r = altcp_write(req->pcb, req->request->payload, req->request->len - 1, TCP_WRITE_FLAG_COPY);
if (r != ERR_OK) {
/* could not write the single small request -> fail, don't retry */
return httpc_close(req, HTTPC_RESULT_ERR_MEM, 0, r);
}
/* everything written, we can free the request */
pbuf_free(req->request);
req->request = NULL;
altcp_output(req->pcb);
return ERR_OK;
}
/** Start the http request when the server IP addr is known */
static err_t
httpc_get_internal_addr(httpc_state_t* req, const ip_addr_t *ipaddr)
{
err_t err;
LWIP_ASSERT("req != NULL", req != NULL);
if (&req->remote_addr != ipaddr) {
/* fill in remote addr if called externally */
req->remote_addr = *ipaddr;
}
err = altcp_connect(req->pcb, &req->remote_addr, req->remote_port, httpc_tcp_connected);
if (err == ERR_OK) {
return ERR_OK;
}
LWIP_DEBUGF(HTTPC_DEBUG_WARN_STATE, ("tcp_connect failed: %d\n", (int)err));
return err;
}
#if LWIP_DNS
/** DNS callback
* If ipaddr is non-NULL, resolving succeeded and the request can be sent, otherwise it failed.
*/
static void
httpc_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
{
httpc_state_t* req = (httpc_state_t*)arg;
err_t err;
httpc_result_t result;
LWIP_UNUSED_ARG(hostname);
if (ipaddr != NULL) {
err = httpc_get_internal_addr(req, ipaddr);
if (err == ERR_OK) {
return;
}
result = HTTPC_RESULT_ERR_CONNECT;
} else {
LWIP_DEBUGF(HTTPC_DEBUG_WARN_STATE, ("httpc_dns_found: failed to resolve hostname: %s\n",
hostname));
result = HTTPC_RESULT_ERR_HOSTNAME;
err = ERR_ARG;
}
httpc_close(req, result, 0, err);
}
#endif /* LWIP_DNS */
/** Start the http request after converting 'server_name' to ip address (DNS or address string) */
static err_t
httpc_get_internal_dns(httpc_state_t* req, const char* server_name)
{
err_t err;
LWIP_ASSERT("req != NULL", req != NULL);
#if LWIP_DNS
err = dns_gethostbyname(server_name, &req->remote_addr, httpc_dns_found, req);
#else
err = ipaddr_aton(server_name, &req->remote_addr) ? ERR_OK : ERR_ARG;
#endif
if (err == ERR_OK) {
/* cached or IP-string */
err = httpc_get_internal_addr(req, &req->remote_addr);
} else if (err == ERR_INPROGRESS) {
return ERR_OK;
}
return err;
}
static int
httpc_create_request_string(const httpc_connection_t *settings, const char* server_name, int server_port, const char* uri,
int use_host, char *buffer, size_t buffer_size)
{
if (settings->use_proxy) {
LWIP_ASSERT("server_name != NULL", server_name != NULL);
if (server_port != HTTP_DEFAULT_PORT) {
return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_PORT_FORMAT(server_name, server_port, uri, server_name));
} else {
return snprintf(buffer, buffer_size, HTTPC_REQ_11_PROXY_FORMAT(server_name, uri, server_name));
}
} else if (use_host) {
LWIP_ASSERT("server_name != NULL", server_name != NULL);
return snprintf(buffer, buffer_size, HTTPC_REQ_11_HOST_FORMAT(uri, server_name));
} else {
return snprintf(buffer, buffer_size, HTTPC_REQ_11_FORMAT(uri));
}
}
/** Initialize the connection struct */
static err_t
httpc_init_connection_common(httpc_state_t **connection, const httpc_connection_t *settings, const char* server_name,
u16_t server_port, const char* uri, altcp_recv_fn recv_fn, void* callback_arg, int use_host)
{
size_t alloc_len;
mem_size_t mem_alloc_len;
int req_len, req_len2;
httpc_state_t *req;
#if HTTPC_DEBUG_REQUEST
size_t server_name_len, uri_len;
#endif
LWIP_ASSERT("uri != NULL", uri != NULL);
/* get request len */
req_len = httpc_create_request_string(settings, server_name, server_port, uri, use_host, NULL, 0);
if ((req_len < 0) || (req_len > 0xFFFF)) {
return ERR_VAL;
}
/* alloc state and request in one block */
alloc_len = sizeof(httpc_state_t);
#if HTTPC_DEBUG_REQUEST
server_name_len = server_name ? strlen(server_name) : 0;
uri_len = strlen(uri);
alloc_len += server_name_len + 1 + uri_len + 1;
#endif
mem_alloc_len = (mem_size_t)alloc_len;
if ((mem_alloc_len < alloc_len) || (req_len + 1 > 0xFFFF)) {
return ERR_VAL;
}
req = (httpc_state_t*)mem_malloc((mem_size_t)alloc_len);
if(req == NULL) {
return ERR_MEM;
}
memset(req, 0, sizeof(httpc_state_t));
req->timeout_ticks = HTTPC_POLL_TIMEOUT;
req->request = pbuf_alloc(PBUF_RAW, (u16_t)(req_len + 1), PBUF_RAM);
if (req->request == NULL) {
httpc_free_state(req);
return ERR_MEM;
}
if (req->request->next != NULL) {
/* need a pbuf in one piece */
httpc_free_state(req);
return ERR_MEM;
}
req->hdr_content_len = HTTPC_CONTENT_LEN_INVALID;
#if HTTPC_DEBUG_REQUEST
req->server_name = (char*)(req + 1);
if (server_name) {
memcpy(req->server_name, server_name, server_name_len + 1);
}
req->uri = req->server_name + server_name_len + 1;
memcpy(req->uri, uri, uri_len + 1);
#endif
req->pcb = altcp_new(settings->altcp_allocator);
if(req->pcb == NULL) {
httpc_free_state(req);
return ERR_MEM;
}
req->remote_port = settings->use_proxy ? settings->proxy_port : server_port;
altcp_arg(req->pcb, req);
altcp_recv(req->pcb, httpc_tcp_recv);
altcp_err(req->pcb, httpc_tcp_err);
altcp_poll(req->pcb, httpc_tcp_poll, HTTPC_POLL_INTERVAL);
altcp_sent(req->pcb, httpc_tcp_sent);
/* set up request buffer */
req_len2 = httpc_create_request_string(settings, server_name, server_port, uri, use_host,
(char *)req->request->payload, req_len + 1);
if (req_len2 != req_len) {
httpc_free_state(req);
return ERR_VAL;
}
req->recv_fn = recv_fn;
req->conn_settings = settings;
req->callback_arg = callback_arg;
*connection = req;
return ERR_OK;
}
/**
* Initialize the connection struct
*/
static err_t
httpc_init_connection(httpc_state_t **connection, const httpc_connection_t *settings, const char* server_name,
u16_t server_port, const char* uri, altcp_recv_fn recv_fn, void* callback_arg)
{
return httpc_init_connection_common(connection, settings, server_name, server_port, uri, recv_fn, callback_arg, 1);
}
/**
* Initialize the connection struct (from IP address)
*/
static err_t
httpc_init_connection_addr(httpc_state_t **connection, const httpc_connection_t *settings,
const ip_addr_t* server_addr, u16_t server_port, const char* uri,
altcp_recv_fn recv_fn, void* callback_arg)
{
char *server_addr_str = ipaddr_ntoa(server_addr);
if (server_addr_str == NULL) {
return ERR_VAL;
}
return httpc_init_connection_common(connection, settings, server_addr_str, server_port, uri,
recv_fn, callback_arg, 1);
}
/**
* @ingroup httpc
* HTTP client API: get a file by passing server IP address
*
* @param server_addr IP address of the server to connect
* @param port tcp port of the server
* @param uri uri to get from the server, remember leading "/"!
* @param settings connection settings (callbacks, proxy, etc.)
* @param recv_fn the http body (not the headers) are passed to this callback
* @param callback_arg argument passed to all the callbacks
* @param connection retreives the connection handle (to match in callbacks)
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
* or an error code
*/
err_t
httpc_get_file(const ip_addr_t* server_addr, u16_t port, const char* uri, const httpc_connection_t *settings,
altcp_recv_fn recv_fn, void* callback_arg, httpc_state_t **connection)
{
err_t err;
httpc_state_t* req;
LWIP_ERROR("invalid parameters", (server_addr != NULL) && (uri != NULL) && (recv_fn != NULL), return ERR_ARG;);
err = httpc_init_connection_addr(&req, settings, server_addr, port,
uri, recv_fn, callback_arg);
if (err != ERR_OK) {
return err;
}
if (settings->use_proxy) {
err = httpc_get_internal_addr(req, &settings->proxy_addr);
} else {
err = httpc_get_internal_addr(req, server_addr);
}
if(err != ERR_OK) {
httpc_free_state(req);
return err;
}
if (connection != NULL) {
*connection = req;
}
return ERR_OK;
}
/**
* @ingroup httpc
* HTTP client API: get a file by passing server name as string (DNS name or IP address string)
*
* @param server_name server name as string (DNS name or IP address string)
* @param port tcp port of the server
* @param uri uri to get from the server, remember leading "/"!
* @param settings connection settings (callbacks, proxy, etc.)
* @param recv_fn the http body (not the headers) are passed to this callback
* @param callback_arg argument passed to all the callbacks
* @param connection retreives the connection handle (to match in callbacks)
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
* or an error code
*/
err_t
httpc_get_file_dns(const char* server_name, u16_t port, const char* uri, const httpc_connection_t *settings,
altcp_recv_fn recv_fn, void* callback_arg, httpc_state_t **connection)
{
err_t err;
httpc_state_t* req;
LWIP_ERROR("invalid parameters", (server_name != NULL) && (uri != NULL) && (recv_fn != NULL), return ERR_ARG;);
err = httpc_init_connection(&req, settings, server_name, port, uri, recv_fn, callback_arg);
if (err != ERR_OK) {
return err;
}
if (settings->use_proxy) {
err = httpc_get_internal_addr(req, &settings->proxy_addr);
} else {
err = httpc_get_internal_dns(req, server_name);
}
if(err != ERR_OK) {
httpc_free_state(req);
return err;
}
if (connection != NULL) {
*connection = req;
}
return ERR_OK;
}
#if LWIP_HTTPC_HAVE_FILE_IO
/* Implementation to disk via fopen/fwrite/fclose follows */
typedef struct _httpc_filestate
{
const char* local_file_name;
FILE *file;
httpc_connection_t settings;
const httpc_connection_t *client_settings;
void *callback_arg;
} httpc_filestate_t;
static void httpc_fs_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len,
u32_t srv_res, err_t err);
/** Initalize http client state for download to file system */
static err_t
httpc_fs_init(httpc_filestate_t **filestate_out, const char* local_file_name,
const httpc_connection_t *settings, void* callback_arg)
{
httpc_filestate_t *filestate;
size_t file_len, alloc_len;
FILE *f;
file_len = strlen(local_file_name);
alloc_len = sizeof(httpc_filestate_t) + file_len + 1;
filestate = (httpc_filestate_t *)mem_malloc((mem_size_t)alloc_len);
if (filestate == NULL) {
return ERR_MEM;
}
memset(filestate, 0, sizeof(httpc_filestate_t));
filestate->local_file_name = (const char *)(filestate + 1);
memcpy((char *)(filestate + 1), local_file_name, file_len + 1);
filestate->file = NULL;
filestate->client_settings = settings;
filestate->callback_arg = callback_arg;
/* copy client settings but override result callback */
memcpy(&filestate->settings, settings, sizeof(httpc_connection_t));
filestate->settings.result_fn = httpc_fs_result;
f = fopen(local_file_name, "wb");
if(f == NULL) {
/* could not open file */
mem_free(filestate);
return ERR_VAL;
}
filestate->file = f;
*filestate_out = filestate;
return ERR_OK;
}
/** Free http client state for download to file system */
static void
httpc_fs_free(httpc_filestate_t *filestate)
{
if (filestate != NULL) {
if (filestate->file != NULL) {
fclose(filestate->file);
filestate->file = NULL;
}
mem_free(filestate);
}
}
/** Connection closed (success or error) */
static void
httpc_fs_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len,
u32_t srv_res, err_t err)
{
httpc_filestate_t *filestate = (httpc_filestate_t *)arg;
if (filestate != NULL) {
if (filestate->client_settings->result_fn != NULL) {
filestate->client_settings->result_fn(filestate->callback_arg, httpc_result, rx_content_len,
srv_res, err);
}
httpc_fs_free(filestate);
}
}
/** tcp recv callback */
static err_t
httpc_fs_tcp_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err)
{
httpc_filestate_t *filestate = (httpc_filestate_t*)arg;
struct pbuf* q;
LWIP_UNUSED_ARG(err);
LWIP_ASSERT("p != NULL", p != NULL);
for (q = p; q != NULL; q = q->next) {
fwrite(q->payload, 1, q->len, filestate->file);
}
altcp_recved(pcb, p->tot_len);
pbuf_free(p);
return ERR_OK;
}
/**
* @ingroup httpc
* HTTP client API: get a file to disk by passing server IP address
*
* @param server_addr IP address of the server to connect
* @param port tcp port of the server
* @param uri uri to get from the server, remember leading "/"!
* @param settings connection settings (callbacks, proxy, etc.)
* @param callback_arg argument passed to all the callbacks
* @param connection retreives the connection handle (to match in callbacks)
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
* or an error code
*/
err_t
httpc_get_file_to_disk(const ip_addr_t* server_addr, u16_t port, const char* uri, const httpc_connection_t *settings,
void* callback_arg, const char* local_file_name, httpc_state_t **connection)
{
err_t err;
httpc_state_t* req;
httpc_filestate_t *filestate;
LWIP_ERROR("invalid parameters", (server_addr != NULL) && (uri != NULL) && (local_file_name != NULL), return ERR_ARG;);
err = httpc_fs_init(&filestate, local_file_name, settings, callback_arg);
if (err != ERR_OK) {
return err;
}
err = httpc_init_connection_addr(&req, &filestate->settings, server_addr, port,
uri, httpc_fs_tcp_recv, filestate);
if (err != ERR_OK) {
httpc_fs_free(filestate);
return err;
}
if (settings->use_proxy) {
err = httpc_get_internal_addr(req, &settings->proxy_addr);
} else {
err = httpc_get_internal_addr(req, server_addr);
}
if(err != ERR_OK) {
httpc_fs_free(filestate);
httpc_free_state(req);
return err;
}
if (connection != NULL) {
*connection = req;
}
return ERR_OK;
}
/**
* @ingroup httpc
* HTTP client API: get a file to disk by passing server name as string (DNS name or IP address string)
*
* @param server_name server name as string (DNS name or IP address string)
* @param port tcp port of the server
* @param uri uri to get from the server, remember leading "/"!
* @param settings connection settings (callbacks, proxy, etc.)
* @param callback_arg argument passed to all the callbacks
* @param connection retreives the connection handle (to match in callbacks)
* @return ERR_OK if starting the request succeeds (callback_fn will be called later)
* or an error code
*/
err_t
httpc_get_file_dns_to_disk(const char* server_name, u16_t port, const char* uri, const httpc_connection_t *settings,
void* callback_arg, const char* local_file_name, httpc_state_t **connection)
{
err_t err;
httpc_state_t* req;
httpc_filestate_t *filestate;
LWIP_ERROR("invalid parameters", (server_name != NULL) && (uri != NULL) && (local_file_name != NULL), return ERR_ARG;);
err = httpc_fs_init(&filestate, local_file_name, settings, callback_arg);
if (err != ERR_OK) {
return err;
}
err = httpc_init_connection(&req, &filestate->settings, server_name, port,
uri, httpc_fs_tcp_recv, filestate);
if (err != ERR_OK) {
httpc_fs_free(filestate);
return err;
}
if (settings->use_proxy) {
err = httpc_get_internal_addr(req, &settings->proxy_addr);
} else {
err = httpc_get_internal_dns(req, server_name);
}
if(err != ERR_OK) {
httpc_fs_free(filestate);
httpc_free_state(req);
return err;
}
if (connection != NULL) {
*connection = req;
}
return ERR_OK;
}
#endif /* LWIP_HTTPC_HAVE_FILE_IO */
#endif /* LWIP_TCP && LWIP_CALLBACK_API */

2746
third_party/lwip/src/apps/http/httpd.c vendored Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More