4
0
mirror of https://github.com/RT-Thread/rt-thread.git synced 2025-01-30 03:30:26 +08:00

Merge branch 'master' of https://github.com/RT-Thread/rt-thread into fixed

This commit is contained in:
weety 2016-05-31 20:23:32 +08:00
commit 94e1935f1f
235 changed files with 1250 additions and 69021 deletions

63
bsp/stm32f10x/drivers/gpio.c Normal file → Executable file
View File

@ -8,8 +8,9 @@
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date Author Notes
* 2015-03-24 Bright the first version
* Date Author Notes
* 2015-03-24 Bright the first version
* 2016-05-23 Margguo@gmail.com Add 48 pins IC define
*/
#include <rthw.h>
@ -19,7 +20,7 @@
#ifdef RT_USING_PIN
#define STM32F10X_PIN_NUMBERS 100 //[ 64, 100, 144 ]
#define STM32F10X_PIN_NUMBERS 100 //[48, 64, 100, 144 ]
#define __STM32_PIN(index, rcc, gpio, gpio_index) { 0, RCC_##rcc##Periph_GPIO##gpio, GPIO##gpio, GPIO_Pin_##gpio_index}
#define __STM32_PIN_DEFAULT {-1, 0, 0, 0}
@ -35,6 +36,58 @@ struct pin_index
static const struct pin_index pins[] =
{
#if (STM32F10X_PIN_NUMBERS == 48)
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
__STM32_PIN(2, APB2, C, 13),
__STM32_PIN(3, APB2, C, 14),
__STM32_PIN(4, APB2, C, 15),
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
__STM32_PIN(10, APB2, A, 0),
__STM32_PIN(11, APB2, A, 1),
__STM32_PIN(12, APB2, A, 2),
__STM32_PIN(13, APB2, A, 3),
__STM32_PIN(14, APB2, A, 4),
__STM32_PIN(15, APB2, A, 5),
__STM32_PIN(16, APB2, A, 6),
__STM32_PIN(17, APB2, A, 7),
__STM32_PIN(18, APB2, B, 0),
__STM32_PIN(19, APB2, B, 1),
__STM32_PIN(20, APB2, B, 2),
__STM32_PIN(21, APB2, B, 10),
__STM32_PIN(22, APB2, B, 11),
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
__STM32_PIN(25, APB2, B, 12),
__STM32_PIN(26, APB2, B, 13),
__STM32_PIN(27, APB2, B, 14),
__STM32_PIN(28, APB2, B, 15),
__STM32_PIN(29, APB2, A, 8),
__STM32_PIN(30, APB2, A, 9),
__STM32_PIN(31, APB2, A, 10),
__STM32_PIN(32, APB2, A, 11),
__STM32_PIN(33, APB2, A, 12),
__STM32_PIN(34, APB2, A, 13),
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
__STM32_PIN(37, APB2, A, 14),
__STM32_PIN(38, APB2, A, 15),
__STM32_PIN(39, APB2, B, 3),
__STM32_PIN(40, APB2, B, 4),
__STM32_PIN(41, APB2, B, 5),
__STM32_PIN(42, APB2, B, 6),
__STM32_PIN(43, APB2, B, 7),
__STM32_PIN_DEFAULT,
__STM32_PIN(45, APB2, B, 8),
__STM32_PIN(46, APB2, B, 9),
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
#endif
#if (STM32F10X_PIN_NUMBERS == 64)
__STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT,
@ -216,7 +269,7 @@ static const struct pin_index pins[] =
__STM32_PIN(7, APB2, C, 13),
__STM32_PIN(8, APB2, C, 14),
__STM32_PIN(9, APB2, C, 15),
__STM32_PIN(10, APB2, F, 0),
__STM32_PIN(11, APB2, F, 1),
__STM32_PIN(12, APB2, F, 2),
@ -472,7 +525,7 @@ const static struct rt_pin_ops _stm32_pin_ops =
int stm32_hw_pin_init(void)
{
int result;
result = rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
return result;
}

View File

@ -13,6 +13,7 @@
* 2010-03-29 Bernard remove interrupt Tx and DMA Rx mode
* 2013-05-13 aozima update for kehong-lingtai.
* 2015-01-31 armink make sure the serial transmit complete in putc()
* 2016-05-13 armink add DMA Rx mode
*/
#include "stm32f10x.h"
@ -44,10 +45,22 @@
/* STM32 uart driver */
struct stm32_uart
{
USART_TypeDef* uart_device;
USART_TypeDef *uart_device;
IRQn_Type irq;
struct stm32_uart_dma {
/* dma channel */
DMA_Channel_TypeDef *rx_ch;
/* dma global flag */
uint32_t rx_gl_flag;
/* dma irq channel */
uint8_t rx_irq_ch;
/* last receive index */
rt_size_t last_recv_len;
} dma;
};
static void DMA_Configuration(struct rt_serial_device *serial);
static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
struct stm32_uart* uart;
@ -93,6 +106,7 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c
static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg)
{
struct stm32_uart* uart;
rt_uint32_t ctrl_arg = (rt_uint32_t)(arg);
RT_ASSERT(serial != RT_NULL);
uart = (struct stm32_uart *)serial->parent.user_data;
@ -113,8 +127,13 @@ static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *ar
/* enable interrupt */
USART_ITConfig(uart->uart_device, USART_IT_RXNE, ENABLE);
break;
/* USART config */
case RT_DEVICE_CTRL_CONFIG :
if (ctrl_arg == RT_DEVICE_FLAG_DMA_RX) {
DMA_Configuration(serial);
}
break;
}
return RT_EOK;
}
@ -148,6 +167,91 @@ static int stm32_getc(struct rt_serial_device *serial)
return ch;
}
/**
* Serial port receive idle process. This need add to uart idle ISR.
*
* @param serial serial device
*/
static void dma_uart_rx_idle_isr(struct rt_serial_device *serial) {
struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data;
rt_size_t recv_total_len, recv_len;
/* disable dma, stop receive data */
DMA_Cmd(uart->dma.rx_ch, DISABLE);
recv_total_len = serial->config.bufsz - DMA_GetCurrDataCounter(uart->dma.rx_ch);
if (recv_total_len > uart->dma.last_recv_len) {
recv_len = recv_total_len - uart->dma.last_recv_len;
} else {
recv_len = recv_total_len;
}
uart->dma.last_recv_len = recv_total_len;
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8));
/* read a data for clear receive idle interrupt flag */
USART_ReceiveData(uart->uart_device);
DMA_ClearFlag(uart->dma.rx_gl_flag);
DMA_Cmd(uart->dma.rx_ch, ENABLE);
}
/**
* DMA receive done process. This need add to DMA receive done ISR.
*
* @param serial serial device
*/
static void dma_rx_done_isr(struct rt_serial_device *serial) {
struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data;
rt_size_t recv_total_len, recv_len;
/* disable dma, stop receive data */
DMA_Cmd(uart->dma.rx_ch, DISABLE);
recv_total_len = serial->config.bufsz - DMA_GetCurrDataCounter(uart->dma.rx_ch);
if (recv_total_len > uart->dma.last_recv_len) {
recv_len = recv_total_len - uart->dma.last_recv_len;
} else {
recv_len = recv_total_len;
}
uart->dma.last_recv_len = recv_total_len;
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8));
DMA_ClearFlag(uart->dma.rx_gl_flag);
/* reload */
DMA_SetCurrDataCounter(uart->dma.rx_ch, serial->config.bufsz);
DMA_Cmd(uart->dma.rx_ch, ENABLE);
}
/**
* Uart common interrupt process. This need add to uart ISR.
*
* @param serial serial device
*/
static void uart_isr(struct rt_serial_device *serial) {
struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data;
RT_ASSERT(uart != RT_NULL);
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
{
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
/* clear interrupt */
USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE);
}
if(USART_GetITStatus(uart->uart_device, USART_IT_IDLE) != RESET)
{
dma_uart_rx_idle_isr(serial);
}
if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET)
{
/* clear interrupt */
USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
}
if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
{
stm32_getc(serial);
}
}
static const struct rt_uart_ops stm32_uart_ops =
{
stm32_configure,
@ -162,70 +266,68 @@ struct stm32_uart uart1 =
{
USART1,
USART1_IRQn,
{
DMA1_Channel5,
DMA1_FLAG_GL5,
DMA1_Channel5_IRQn,
0,
},
};
struct rt_serial_device serial1;
void USART1_IRQHandler(void)
{
struct stm32_uart* uart;
uart = &uart1;
/* enter interrupt */
rt_interrupt_enter();
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
{
rt_hw_serial_isr(&serial1, RT_SERIAL_EVENT_RX_IND);
/* clear interrupt */
USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE);
}
if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET)
{
/* clear interrupt */
USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
}
if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
{
stm32_getc(&serial1);
}
uart_isr(&serial1);
/* leave interrupt */
rt_interrupt_leave();
}
void DMA1_Channel5_IRQHandler(void) {
/* enter interrupt */
rt_interrupt_enter();
dma_rx_done_isr(&serial1);
/* leave interrupt */
rt_interrupt_leave();
}
#endif /* RT_USING_UART1 */
#if defined(RT_USING_UART2)
/* UART1 device driver structure */
/* UART2 device driver structure */
struct stm32_uart uart2 =
{
USART2,
USART2_IRQn,
{
DMA1_Channel6,
DMA1_FLAG_GL6,
DMA1_Channel6_IRQn,
0,
},
};
struct rt_serial_device serial2;
void USART2_IRQHandler(void)
{
struct stm32_uart* uart;
uart = &uart2;
/* enter interrupt */
rt_interrupt_enter();
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
{
rt_hw_serial_isr(&serial2, RT_SERIAL_EVENT_RX_IND);
/* clear interrupt */
USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE);
}
if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET)
{
/* clear interrupt */
USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
}
if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
{
stm32_getc(&serial2);
}
uart_isr(&serial2);
/* leave interrupt */
rt_interrupt_leave();
}
void DMA1_Channel6_IRQHandler(void) {
/* enter interrupt */
rt_interrupt_enter();
dma_rx_done_isr(&serial2);
/* leave interrupt */
rt_interrupt_leave();
@ -238,32 +340,31 @@ struct stm32_uart uart3 =
{
USART3,
USART3_IRQn,
{
DMA1_Channel3,
DMA1_FLAG_GL3,
DMA1_Channel3_IRQn,
0,
},
};
struct rt_serial_device serial3;
void USART3_IRQHandler(void)
{
struct stm32_uart* uart;
uart = &uart3;
/* enter interrupt */
rt_interrupt_enter();
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
{
rt_hw_serial_isr(&serial3, RT_SERIAL_EVENT_RX_IND);
/* clear interrupt */
USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE);
}
if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET)
{
/* clear interrupt */
USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
}
if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
{
stm32_getc(&serial3);
}
uart_isr(&serial3);
/* leave interrupt */
rt_interrupt_leave();
}
void DMA1_Channel3_IRQHandler(void) {
/* enter interrupt */
rt_interrupt_enter();
dma_rx_done_isr(&serial3);
/* leave interrupt */
rt_interrupt_leave();
@ -276,69 +377,66 @@ struct stm32_uart uart4 =
{
UART4,
UART4_IRQn,
{
DMA2_Channel3,
DMA2_FLAG_GL3,
DMA2_Channel3_IRQn,
0,
},
};
struct rt_serial_device serial4;
void UART4_IRQHandler(void)
{
struct stm32_uart* uart;
uart = &uart4;
/* enter interrupt */
rt_interrupt_enter();
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
{
rt_hw_serial_isr(&serial4, RT_SERIAL_EVENT_RX_IND);
/* clear interrupt */
USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE);
}
if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET)
{
/* clear interrupt */
USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
}
if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
{
stm32_getc(&serial4);
}
uart_isr(&serial4);
/* leave interrupt */
rt_interrupt_leave();
}
#endif /* RT_USING_UART3 */
void DMA2_Channel3_IRQHandler(void) {
/* enter interrupt */
rt_interrupt_enter();
dma_rx_done_isr(&serial4);
/* leave interrupt */
rt_interrupt_leave();
}
#endif /* RT_USING_UART4 */
static void RCC_Configuration(void)
{
#if defined(RT_USING_UART1)
/* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
/* Enable UART clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
#endif /* RT_USING_UART1 */
#if defined(RT_USING_UART2)
/* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
/* Enable UART clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
#endif /* RT_USING_UART2 */
#if defined(RT_USING_UART3)
/* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
/* Enable UART clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
#endif /* RT_USING_UART3 */
#if defined(RT_USING_UART4)
/* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
/* Enable UART clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
#endif /* RT_USING_UART4 */
}
static void GPIO_Configuration(void)
@ -390,7 +488,6 @@ static void GPIO_Configuration(void)
GPIO_InitStructure.GPIO_Pin = UART4_GPIO_TX;
GPIO_Init(UART4_GPIO, &GPIO_InitStructure);
#endif /* RT_USING_UART4 */
}
static void NVIC_Configuration(struct stm32_uart* uart)
@ -405,6 +502,46 @@ static void NVIC_Configuration(struct stm32_uart* uart)
NVIC_Init(&NVIC_InitStructure);
}
static void DMA_Configuration(struct rt_serial_device *serial) {
struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data;
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* enable transmit idle interrupt */
USART_ITConfig(uart->uart_device, USART_IT_IDLE , ENABLE);
/* DMA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
/* rx dma config */
DMA_DeInit(uart->dma.rx_ch);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(uart->uart_device->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) rx_fifo->buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = serial->config.bufsz;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(uart->dma.rx_ch, &DMA_InitStructure);
DMA_ClearFlag(uart->dma.rx_gl_flag);
DMA_ITConfig(uart->dma.rx_ch, DMA_IT_TC, ENABLE);
USART_DMACmd(uart->uart_device, USART_DMAReq_Rx, ENABLE);
DMA_Cmd(uart->dma.rx_ch, ENABLE);
/* rx dma interrupt config */
NVIC_InitStructure.NVIC_IRQChannel = uart->dma.rx_irq_ch;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void rt_hw_usart_init(void)
{
struct stm32_uart* uart;
@ -420,11 +557,11 @@ void rt_hw_usart_init(void)
serial1.ops = &stm32_uart_ops;
serial1.config = config;
NVIC_Configuration(&uart1);
NVIC_Configuration(uart);
/* register UART1 device */
rt_hw_serial_register(&serial1, "uart1",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX ,
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX,
uart);
#endif /* RT_USING_UART1 */
@ -435,11 +572,11 @@ void rt_hw_usart_init(void)
serial2.ops = &stm32_uart_ops;
serial2.config = config;
NVIC_Configuration(&uart2);
NVIC_Configuration(uart);
/* register UART1 device */
/* register UART2 device */
rt_hw_serial_register(&serial2, "uart2",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX,
uart);
#endif /* RT_USING_UART2 */
@ -451,11 +588,11 @@ void rt_hw_usart_init(void)
serial3.ops = &stm32_uart_ops;
serial3.config = config;
NVIC_Configuration(&uart3);
NVIC_Configuration(uart);
/* register UART1 device */
/* register UART3 device */
rt_hw_serial_register(&serial3, "uart3",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX,
uart);
#endif /* RT_USING_UART3 */
@ -467,12 +604,11 @@ void rt_hw_usart_init(void)
serial4.ops = &stm32_uart_ops;
serial4.config = config;
NVIC_Configuration(&uart4);
NVIC_Configuration(uart);
/* register UART4 device */
rt_hw_serial_register(&serial4, "uart4",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX,
uart);
#endif /* RT_USING_UART4 */
}

View File

@ -6,6 +6,6 @@ cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_LWIP'], CPPPATH = CPPPATH)
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_NET'], CPPPATH = CPPPATH)
Return('group')

View File

@ -1,7 +1,7 @@
/*
* File : dfs_lwip.c
* File : dfs_net.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2015, RT-Thread Development Team
* COPYRIGHT (C) 2015-2016, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -20,15 +20,16 @@
* Change Logs:
* Date Author Notes
* 2015-02-17 Bernard First version
* 2016-05-07 Bernard Rename dfs_lwip to dfs_net
*/
#include <rtthread.h>
#include <dfs.h>
#include <dfs_fs.h>
#include "dfs_lwip.h"
#include "dfs_net.h"
int dfs_lwip_getsocket(int fd)
int dfs_net_getsocket(int fd)
{
struct dfs_fd *_dfs_fd;
@ -40,12 +41,12 @@ int dfs_lwip_getsocket(int fd)
return (int)_dfs_fd->data;
}
int dfs_lwip_ioctl(struct dfs_fd* file, int cmd, void* args)
int dfs_net_ioctl(struct dfs_fd* file, int cmd, void* args)
{
return -DFS_STATUS_EIO;
}
int dfs_lwip_read(struct dfs_fd* file, void *buf, rt_size_t count)
int dfs_net_read(struct dfs_fd* file, void *buf, rt_size_t count)
{
int sock;
@ -55,7 +56,7 @@ int dfs_lwip_read(struct dfs_fd* file, void *buf, rt_size_t count)
return count;
}
int dfs_lwip_write(struct dfs_fd *file, const void *buf, rt_size_t count)
int dfs_net_write(struct dfs_fd *file, const void *buf, rt_size_t count)
{
int sock;
@ -65,7 +66,7 @@ int dfs_lwip_write(struct dfs_fd *file, const void *buf, rt_size_t count)
return count;
}
int dfs_lwip_close(struct dfs_fd* file)
int dfs_net_close(struct dfs_fd* file)
{
int sock;
int result;
@ -78,9 +79,9 @@ int dfs_lwip_close(struct dfs_fd* file)
return -result;
}
static const struct dfs_filesystem_operation _lwip_fs_ops =
static const struct dfs_filesystem_operation _net_fs_ops =
{
"lwip",
"net",
DFS_FS_FLAG_DEFAULT,
RT_NULL, /* mount */
RT_NULL, /* unmont */
@ -88,10 +89,10 @@ static const struct dfs_filesystem_operation _lwip_fs_ops =
RT_NULL, /* statfs */
RT_NULL, /* open */
dfs_lwip_close,
dfs_lwip_ioctl,
dfs_lwip_read,
dfs_lwip_write,
dfs_net_close,
dfs_net_ioctl,
dfs_net_read,
dfs_net_write,
RT_NULL,
RT_NULL, /* lseek */
RT_NULL, /* getdents */
@ -100,28 +101,28 @@ static const struct dfs_filesystem_operation _lwip_fs_ops =
RT_NULL, /* rename */
};
static struct dfs_filesystem _lwip_fs =
static struct dfs_filesystem _net_fs =
{
0, /* dev_id */
RT_NULL, /* path */
&_lwip_fs_ops,
&_net_fs_ops,
RT_NULL /* data */
};
struct dfs_filesystem* dfs_lwip_get_fs(void)
struct dfs_filesystem* dfs_net_get_fs(void)
{
return &_lwip_fs;
return &_net_fs;
}
/*
NOTE: Beause we don't need to mount lwIP file system, the filesystem_ops is not
registered to the system.
int dfs_lwip_system_init(void)
int dfs_net_system_init(void)
{
dfs_register(&_lwip_fs_ops);
dfs_register(&_net_fs_ops);
return 0;
}
INIT_FS_EXPORT(dfs_lwip_system_init);
INIT_FS_EXPORT(dfs_net_system_init);
*/

View File

@ -1,7 +1,7 @@
/*
* File : dfs_lwip.h
* File : dfs_net.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2015, RT-Thread Development Team
* COPYRIGHT (C) 2015-2016, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -20,10 +20,11 @@
* Change Logs:
* Date Author Notes
* 2015-02-17 Bernard First version
* 2016-05-05 Bernard rename dfs_lwip to dfs_net.
*/
#ifndef DFS_LWIP_H__
#define DFS_LWIP_H__
#ifndef DFS_NET_H__
#define DFS_NET_H__
#ifdef __cplusplus
extern "C" {
@ -31,10 +32,10 @@ extern "C" {
#include <lwip/sockets.h>
struct dfs_filesystem* dfs_lwip_get_fs(void);
int dfs_lwip_getsocket(int fd);
struct dfs_filesystem* dfs_net_get_fs(void);
int dfs_net_getsocket(int fd);
int dfs_lwip_system_init(void);
int dfs_net_system_init(void);
#ifdef __cplusplus
}

View File

@ -27,7 +27,7 @@
#ifdef RT_USING_LWIP
#include "dfs_lwip.h"
#include "dfs_net.h"
int
select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
@ -48,7 +48,7 @@ select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
for (index = 0; index < maxfdp1; index ++)
{
/* convert fd to sock */
sock = dfs_lwip_getsocket(index);
sock = dfs_net_getsocket(index);
if (sock == -1) continue;
if (sock > maxfd) maxfd = sock;

View File

@ -28,12 +28,12 @@
#include <sys/socket.h>
#include "dfs_lwip.h"
#include "dfs_net.h"
int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
int new_client = -1;
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
new_client = lwip_accept(sock, addr, addrlen);
if (new_client != -1)
@ -58,7 +58,7 @@ int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
d->type = FT_SOCKET;
d->path = RT_NULL;
d->fs = dfs_lwip_get_fs();
d->fs = dfs_net_get_fs();
d->flags = DFS_O_RDWR; /* set flags as read and write */
d->size = 0;
@ -79,7 +79,7 @@ RTM_EXPORT(accept);
int bind(int s, const struct sockaddr *name, socklen_t namelen)
{
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
return lwip_bind(sock, name, namelen);
}
@ -98,7 +98,7 @@ int shutdown(int s, int how)
return -1;
}
sock = dfs_lwip_getsocket(s);
sock = dfs_net_getsocket(s);
if (lwip_shutdown(sock, how) == 0)
{
/* socket has been closed, delete it from file system fd */
@ -114,7 +114,7 @@ RTM_EXPORT(shutdown);
int getpeername(int s, struct sockaddr *name, socklen_t *namelen)
{
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
return lwip_getpeername(sock, name, namelen);
}
@ -122,7 +122,7 @@ RTM_EXPORT(getpeername);
int getsockname(int s, struct sockaddr *name, socklen_t *namelen)
{
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
return lwip_getsockname(sock, name, namelen);
}
@ -130,7 +130,7 @@ RTM_EXPORT(getsockname);
int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
{
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
return lwip_getsockopt(sock, level, optname, optval, optlen);
}
@ -138,7 +138,7 @@ RTM_EXPORT(getsockopt);
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
{
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
return lwip_setsockopt(sock, level, optname, optval, optlen);
}
@ -146,7 +146,7 @@ RTM_EXPORT(setsockopt);
int connect(int s, const struct sockaddr *name, socklen_t namelen)
{
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
return lwip_connect(sock, name, namelen);
}
@ -154,7 +154,7 @@ RTM_EXPORT(connect);
int listen(int s, int backlog)
{
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
return lwip_listen(sock, backlog);
}
@ -162,7 +162,7 @@ RTM_EXPORT(listen);
int recv(int s, void *mem, size_t len, int flags)
{
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
return lwip_recv(sock, mem, len, flags);
}
@ -171,7 +171,7 @@ RTM_EXPORT(recv);
int recvfrom(int s, void *mem, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen)
{
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
return lwip_recvfrom(sock, mem, len, flags, from, fromlen);
}
@ -179,7 +179,7 @@ RTM_EXPORT(recvfrom);
int send(int s, const void *dataptr, size_t size, int flags)
{
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
return lwip_send(sock, dataptr, size, flags);
}
@ -188,7 +188,7 @@ RTM_EXPORT(send);
int sendto(int s, const void *dataptr, size_t size, int flags,
const struct sockaddr *to, socklen_t tolen)
{
int sock = dfs_lwip_getsocket(s);
int sock = dfs_net_getsocket(s);
return lwip_sendto(sock, dataptr, size, flags, to, tolen);
}
@ -219,7 +219,7 @@ int socket(int domain, int type, int protocol)
d->type = FT_SOCKET;
d->path = RT_NULL;
d->fs = dfs_lwip_get_fs();
d->fs = dfs_net_get_fs();
d->flags = DFS_O_RDWR; /* set flags as read and write */
d->size = 0;

View File

@ -220,6 +220,10 @@ rt_inline rt_uint32_t fls(rt_uint32_t val)
return bit;
}
#define MMCSD_HOST_PLUGED 0
#define MMCSD_HOST_UNPLUGED 1
int mmcsd_wait_cd_changed(rt_int32_t timeout);
void mmcsd_host_lock(struct rt_mmcsd_host *host);
void mmcsd_host_unlock(struct rt_mmcsd_host *host);
void mmcsd_req_complete(struct rt_mmcsd_host *host);

View File

@ -33,12 +33,15 @@
#define BAUD_RATE_2400 2400
#define BAUD_RATE_4800 4800
#define BAUD_RATE_9600 9600
#define BAUD_RATE_19200 19200
#define BAUD_RATE_38400 38400
#define BAUD_RATE_57600 57600
#define BAUD_RATE_115200 115200
#define BAUD_RATE_230400 230400
#define BAUD_RATE_460800 460800
#define BAUD_RATE_921600 921600
#define BAUD_RATE_2000000 2000000
#define BAUD_RATE_3000000 3000000
#define DATA_BITS_5 5
#define DATA_BITS_6 6
@ -106,7 +109,7 @@ struct serial_configure
rt_uint32_t parity :2;
rt_uint32_t bit_order :1;
rt_uint32_t invert :1;
rt_uint32_t bufsz :16;
rt_uint32_t bufsz :16;
rt_uint32_t reserved :4;
};
@ -115,15 +118,15 @@ struct serial_configure
*/
struct rt_serial_rx_fifo
{
/* software fifo */
rt_uint8_t *buffer;
/* software fifo */
rt_uint8_t *buffer;
rt_uint16_t put_index, get_index;
rt_uint16_t put_index, get_index;
};
struct rt_serial_tx_fifo
{
struct rt_completion completion;
struct rt_completion completion;
};
/*
@ -131,13 +134,13 @@ struct rt_serial_tx_fifo
*/
struct rt_serial_rx_dma
{
rt_bool_t activated;
rt_bool_t activated;
};
struct rt_serial_tx_dma
{
rt_bool_t activated;
struct rt_data_queue data_queue;
rt_bool_t activated;
struct rt_data_queue data_queue;
};
struct rt_serial_device
@ -147,8 +150,8 @@ struct rt_serial_device
const struct rt_uart_ops *ops;
struct serial_configure config;
void *serial_rx;
void *serial_tx;
void *serial_rx;
void *serial_tx;
};
typedef struct rt_serial_device rt_serial_t;
@ -163,7 +166,7 @@ struct rt_uart_ops
int (*putc)(struct rt_serial_device *serial, char c);
int (*getc)(struct rt_serial_device *serial);
rt_size_t (*dma_transmit)(struct rt_serial_device *serial, const rt_uint8_t *buf, rt_size_t size, int direction);
rt_size_t (*dma_transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
};
void rt_hw_serial_isr(struct rt_serial_device *serial, int event);
@ -174,4 +177,3 @@ rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
void *data);
#endif

View File

@ -44,6 +44,8 @@ static struct rt_thread mmcsd_detect_thread;
static rt_uint8_t mmcsd_stack[RT_MMCSD_STACK_SIZE];
static struct rt_mailbox mmcsd_detect_mb;
static rt_uint32_t mmcsd_detect_mb_pool[4];
static struct rt_mailbox mmcsd_hotpluge_mb;
static rt_uint32_t mmcsd_hotpluge_mb_pool[4];
void mmcsd_host_lock(struct rt_mmcsd_host *host)
{
@ -594,6 +596,24 @@ static void mmcsd_power_off(struct rt_mmcsd_host *host)
mmcsd_set_iocfg(host);
}
int mmcsd_wait_cd_changed(rt_int32_t timeout)
{
struct rt_mmcsd_host *host;
if (rt_mb_recv(&mmcsd_hotpluge_mb, (rt_uint32_t*)&host, timeout) == RT_EOK)
{
if(host->card == RT_NULL)
{
return MMCSD_HOST_UNPLUGED;
}
else
{
return MMCSD_HOST_PLUGED;
}
}
return -RT_ETIMEOUT;
}
RTM_EXPORT(mmcsd_wait_cd_changed);
void mmcsd_change(struct rt_mmcsd_host *host)
{
rt_mb_send(&mmcsd_detect_mb, (rt_uint32_t)host);
@ -647,6 +667,7 @@ void mmcsd_detect(void *param)
if (init_mmc(host, ocr))
mmcsd_power_off(host);
mmcsd_host_unlock(host);
rt_mb_send(&mmcsd_hotpluge_mb, (rt_uint32_t)host);
continue;
}
mmcsd_host_unlock(host);
@ -667,6 +688,7 @@ void mmcsd_detect(void *param)
host->card = RT_NULL;
}
mmcsd_host_unlock(host);
rt_mb_send(&mmcsd_hotpluge_mb, (rt_uint32_t)host);
}
}
}
@ -711,11 +733,15 @@ void rt_mmcsd_core_init(void)
/* initialize detect SD cart thread */
/* initialize mailbox and create detect SD card thread */
ret = rt_mb_init(&mmcsd_detect_mb, "mmcsdmb",
&mmcsd_detect_mb_pool[0], sizeof(mmcsd_detect_mb_pool),
&mmcsd_detect_mb_pool[0], sizeof(mmcsd_detect_mb_pool) / sizeof(mmcsd_detect_mb_pool[0]),
RT_IPC_FLAG_FIFO);
RT_ASSERT(ret == RT_EOK);
ret = rt_thread_init(&mmcsd_detect_thread, "mmcsd_detect", mmcsd_detect, RT_NULL,
ret = rt_mb_init(&mmcsd_hotpluge_mb, "mmcsdhotplugmb",
&mmcsd_hotpluge_mb_pool[0], sizeof(mmcsd_hotpluge_mb_pool) / sizeof(mmcsd_hotpluge_mb_pool[0]),
RT_IPC_FLAG_FIFO);
RT_ASSERT(ret == RT_EOK);
ret = rt_thread_init(&mmcsd_detect_thread, "mmcsd_detect", mmcsd_detect, RT_NULL,
&mmcsd_stack[0], RT_MMCSD_STACK_SIZE, RT_MMCSD_THREAD_PREORITY, 20);
if (ret == RT_EOK)
{

View File

@ -27,9 +27,10 @@
* the size of ring buffer.
* 2014-07-10 bernard rewrite serial framework
* 2014-12-31 bernard use open_flag for poll_tx stream mode.
* 2015-05-19 Quintin fix DMA tx mod tx_dma->activated flag !=RT_FALSE BUG
* 2015-05-19 Quintin fix DMA tx mod tx_dma->activated flag !=RT_FALSE BUG
* in open function.
* 2015-11-10 bernard fix the poll rx issue when there is no data.
* 2016-05-10 armink add fifo mode to DMA rx when serial->config.bufsz != 0.
*/
#include <rthw.h>
@ -37,13 +38,13 @@
#include <rtdevice.h>
/*
* Serial poll routines
* Serial poll routines
*/
rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
{
int ch;
int size;
RT_ASSERT(serial != RT_NULL);
size = length;
@ -52,7 +53,7 @@ rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data,
ch = serial->ops->getc(serial);
if (ch == -1) break;
*data = ch;
*data = ch;
data ++; length --;
if (ch == '\n') break;
@ -77,9 +78,9 @@ rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t
{
serial->ops->putc(serial, '\r');
}
serial->ops->putc(serial, *data);
++ data;
-- length;
}
@ -96,8 +97,8 @@ rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data,
struct rt_serial_rx_fifo* rx_fifo;
RT_ASSERT(serial != RT_NULL);
size = length;
size = length;
rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx;
RT_ASSERT(rx_fifo != RT_NULL);
@ -136,7 +137,7 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
{
int size;
struct rt_serial_tx_fifo *tx;
RT_ASSERT(serial != RT_NULL);
size = length;
@ -157,32 +158,136 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
return size - length;
}
/**
* Calculate DMA received data length.
*
* @param serial serial device
*
* @return length
*/
static rt_size_t rt_dma_calc_recved_len(struct rt_serial_device *serial) {
static rt_size_t rx_length;
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
RT_ASSERT(rx_fifo != RT_NULL);
rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):
(serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index));
return rx_length;
}
/**
* Read data finish by DMA mode then update the gut index for receive fifo.
*
* @param serial serial device
* @param len get data length for this operate
*/
static void rt_dma_recv_update_get_index(struct rt_serial_device *serial, rt_size_t len) {
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
RT_ASSERT(rx_fifo != RT_NULL);
RT_ASSERT(len <= rt_dma_calc_recved_len(serial));
rx_fifo->get_index += len;
if (rx_fifo->get_index > serial->config.bufsz ) {
rx_fifo->get_index -= serial->config.bufsz;
}
}
/**
* DMA received finish then update put index for receive fifo.
*
* @param serial serial device
* @param len received length for this transmit
*/
static void rt_dma_recv_update_put_index(struct rt_serial_device *serial, rt_size_t len) {
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
rt_size_t i;
RT_ASSERT(rx_fifo != RT_NULL);
if (rx_fifo->get_index <= rx_fifo->put_index) {
rx_fifo->put_index += len;
/* beyond the fifo end */
if (rx_fifo->put_index >= serial->config.bufsz) {
for (i = 0; i <= len / serial->config.bufsz; i++) {
rx_fifo->put_index -= serial->config.bufsz;
}
/* force overwrite get index */
if (rx_fifo->put_index >= rx_fifo->get_index) {
rx_fifo->get_index = rx_fifo->put_index + 1;
}
}
} else {
rx_fifo->put_index += len;
if(rx_fifo->put_index >= rx_fifo->get_index) {
/* beyond the fifo end */
if(rx_fifo->put_index >= serial->config.bufsz) {
for (i = 0; i <= len / serial->config.bufsz; i++) {
rx_fifo->put_index -= serial->config.bufsz;
}
}
/* force overwrite get index */
rx_fifo->get_index = rx_fifo->put_index + 1;
}
}
}
/*
* Serial DMA routines
*/
rt_inline int _serial_dma_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
{
rt_base_t level;
int result = RT_EOK;
struct rt_serial_rx_dma *rx_dma;
RT_ASSERT((serial != RT_NULL) && (data != RT_NULL));
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
RT_ASSERT(rx_dma != RT_NULL);
level = rt_hw_interrupt_disable();
if (rx_dma->activated != RT_TRUE)
{
rx_dma->activated = RT_TRUE;
serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_RX);
if (serial->config.bufsz == 0) {
int result = RT_EOK;
struct rt_serial_rx_dma *rx_dma;
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
RT_ASSERT(rx_dma != RT_NULL);
if (rx_dma->activated != RT_TRUE)
{
rx_dma->activated = RT_TRUE;
RT_ASSERT(serial->ops->dma_transmit != RT_NULL);
serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_RX);
}
else result = -RT_EBUSY;
rt_hw_interrupt_enable(level);
if (result == RT_EOK) return length;
rt_set_errno(result);
return 0;
} else {
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
rt_size_t recv_len = 0, fifo_recved_len = rt_dma_calc_recved_len(serial);
RT_ASSERT(rx_fifo != RT_NULL);
if (length < fifo_recved_len) {
recv_len = length;
} else {
recv_len = fifo_recved_len;
}
if (rx_fifo->get_index + recv_len < serial->config.bufsz) {
rt_memcpy(data, rx_fifo->buffer + rx_fifo->get_index, recv_len);
} else {
rt_memcpy(data, rx_fifo->buffer + rx_fifo->get_index,
serial->config.bufsz - rx_fifo->get_index);
rt_memcpy(data + serial->config.bufsz - rx_fifo->get_index, rx_fifo->buffer,
recv_len + rx_fifo->get_index - serial->config.bufsz);
}
rt_dma_recv_update_get_index(serial, recv_len);
rt_hw_interrupt_enable(level);
return recv_len;
}
else result = -RT_EBUSY;
rt_hw_interrupt_enable(level);
if (result == RT_EOK) return length;
rt_set_errno(result);
return 0;
}
rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
@ -192,8 +297,8 @@ rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *
struct rt_serial_tx_dma *tx_dma;
tx_dma = (struct rt_serial_tx_dma*)(serial->serial_tx);
result = rt_data_queue_push(&(tx_dma->data_queue), data, length, RT_WAITING_FOREVER);
result = rt_data_queue_push(&(tx_dma->data_queue), data, length, RT_WAITING_FOREVER);
if (result == RT_EOK)
{
level = rt_hw_interrupt_disable();
@ -203,7 +308,7 @@ rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *
rt_hw_interrupt_enable(level);
/* make a DMA transfer */
serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_TX);
serial->ops->dma_transmit(serial, (rt_uint8_t *)data, length, RT_SERIAL_DMA_TX);
}
else
{
@ -250,7 +355,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
serial = (struct rt_serial_device *)dev;
/* check device flag with the open flag */
if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
return -RT_EIO;
if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
return -RT_EIO;
@ -261,26 +366,41 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
/* get open flags */
dev->open_flag = oflag & 0xff;
/* initialize the Rx/Tx structure according to open flag */
if (serial->serial_rx == RT_NULL)
{
if (oflag & RT_DEVICE_FLAG_DMA_RX)
{
struct rt_serial_rx_dma* rx_dma;
if (serial->config.bufsz == 0) {
struct rt_serial_rx_dma* rx_dma;
rx_dma = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma));
RT_ASSERT(rx_dma != RT_NULL);
rx_dma->activated = RT_FALSE;
rx_dma = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma));
RT_ASSERT(rx_dma != RT_NULL);
rx_dma->activated = RT_FALSE;
serial->serial_rx = rx_dma;
serial->serial_rx = rx_dma;
} else {
struct rt_serial_rx_fifo* rx_fifo;
rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
serial->config.bufsz);
RT_ASSERT(rx_fifo != RT_NULL);
rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
rt_memset(rx_fifo->buffer, 0, serial->config.bufsz);
rx_fifo->put_index = 0;
rx_fifo->get_index = 0;
serial->serial_rx = rx_fifo;
/* configure fifo address and length to low level device */
serial->ops->control(serial, RT_DEVICE_CTRL_CONFIG, (void *) RT_DEVICE_FLAG_DMA_RX);
}
dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
}
else if (oflag & RT_DEVICE_FLAG_INT_RX)
{
struct rt_serial_rx_fifo* rx_fifo;
rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
serial->config.bufsz);
RT_ASSERT(rx_fifo != RT_NULL);
rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
@ -308,7 +428,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma));
RT_ASSERT(tx_dma != RT_NULL);
tx_dma->activated = RT_FALSE;
rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL);
serial->serial_tx = tx_dma;
@ -346,7 +466,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
/* this device has more reference count */
if (dev->ref_count > 1) return RT_EOK;
if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
{
struct rt_serial_rx_fifo* rx_fifo;
@ -362,12 +482,23 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
}
else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
{
struct rt_serial_rx_dma* rx_dma;
if (serial->config.bufsz == 0) {
struct rt_serial_rx_dma* rx_dma;
rx_dma = (struct rt_serial_rx_dma*)serial->serial_tx;
RT_ASSERT(rx_dma != RT_NULL);
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
RT_ASSERT(rx_dma != RT_NULL);
rt_free(rx_dma);
rt_free(rx_dma);
} else {
struct rt_serial_rx_fifo* rx_fifo;
rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
RT_ASSERT(rx_fifo != RT_NULL);
rt_free(rx_fifo);
}
/* configure low level device */
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *) RT_DEVICE_FLAG_DMA_RX);
serial->serial_rx = RT_NULL;
dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX;
}
@ -376,7 +507,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
{
struct rt_serial_tx_fifo* tx_fifo;
tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_rx;
tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_tx;
RT_ASSERT(tx_fifo != RT_NULL);
rt_free(tx_fifo);
@ -534,30 +665,30 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
ch = serial->ops->getc(serial);
if (ch == -1) break;
/* disable interrupt */
level = rt_hw_interrupt_disable();
rx_fifo->buffer[rx_fifo->put_index] = ch;
rx_fifo->put_index += 1;
if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0;
/* if the next position is read index, discard this 'read char' */
if (rx_fifo->put_index == rx_fifo->get_index)
{
rx_fifo->get_index += 1;
if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
}
/* invoke callback */
if (serial->parent.rx_indicate != RT_NULL)
{
rt_size_t rx_length;
/* get rx length */
level = rt_hw_interrupt_disable();
rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):
@ -584,19 +715,19 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
struct rt_serial_tx_dma* tx_dma;
tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx;
rt_data_queue_pop(&(tx_dma->data_queue), &last_data_ptr, &data_size, 0);
if (rt_data_queue_peak(&(tx_dma->data_queue), &data_ptr, &data_size) == RT_EOK)
{
/* transmit next data node */
tx_dma->activated = RT_TRUE;
serial->ops->dma_transmit(serial, data_ptr, data_size, RT_SERIAL_DMA_TX);
serial->ops->dma_transmit(serial, (rt_uint8_t *)data_ptr, data_size, RT_SERIAL_DMA_TX);
}
else
{
tx_dma->activated = RT_FALSE;
}
/* invoke callback */
if (serial->parent.tx_complete != RT_NULL)
{
@ -607,13 +738,27 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
case RT_SERIAL_EVENT_RX_DMADONE:
{
int length;
struct rt_serial_rx_dma* rx_dma;
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
/* get DMA rx length */
length = (event & (~0xff)) >> 8;
serial->parent.rx_indicate(&(serial->parent), length);
rx_dma->activated = RT_FALSE;
if (serial->config.bufsz == 0) {
struct rt_serial_rx_dma* rx_dma;
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
RT_ASSERT(rx_dma != RT_NULL);
RT_ASSERT(serial->parent.rx_indicate != RT_NULL);
serial->parent.rx_indicate(&(serial->parent), length);
rx_dma->activated = RT_FALSE;
} else {
/* update fifo put index */
rt_dma_recv_update_put_index(serial, length);
/* invoke callback */
if (serial->parent.rx_indicate != RT_NULL) {
serial->parent.rx_indicate(&(serial->parent), rt_dma_calc_recved_len(serial));
}
}
break;
}
}

View File

@ -21,6 +21,9 @@ if GetDepend('RT_USING_AT45DBXX'):
if GetDepend('RT_USING_SST25VFXX'):
src_device += ['spi_flash_sst25vfxx.c']
if GetDepend('RT_USING_GD'):
src_device += ['spi_flash_gd.c']
src += src_device
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH)

View File

@ -675,7 +675,7 @@ static struct pbuf *enc28j60_rx(rt_device_t dev)
else
{
/* allocation pbuf */
p = pbuf_alloc(PBUF_LINK, len, PBUF_RAM);
p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL);
if (p != RT_NULL)
{
struct pbuf* q;

View File

@ -0,0 +1,36 @@
/*
* File : spi_flash.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2016, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2016/5/20 bernard the first version
*/
#ifndef SPI_FLASH_H__
#define SPI_FLASH_H__
struct spi_flash_device
{
struct rt_device flash_device;
struct rt_device_blk_geometry geometry;
struct rt_spi_device * rt_spi_device;
struct rt_mutex lock;
};
#endif

View File

@ -1,11 +1,21 @@
/*
* File : rtdef.h
* File : spi_flash_at45dbxx.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes

View File

@ -1,3 +1,27 @@
/*
* File : spi_flash_at45dbxx.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2011-12-16 aozima the first version
*/
#ifndef SPI_FLASH_AT45DBXX_H_INCLUDED
#define SPI_FLASH_AT45DBXX_H_INCLUDED

View File

@ -0,0 +1,346 @@
/*
* File : spi_flash_gd.c
* This file is part of RT-Thread RTOS
* Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd.
* All rights reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2015-10-11 fullhan copy from winbond flash
*/
#include <stdint.h>
#include <rtthread.h>
#include <rtdevice.h>
#include "spi_flash.h"
#include "spi_flash_gd.h"
#define FLASH_DEBUG
#ifdef FLASH_DEBUG
#define FLASH_TRACE rt_kprintf
#else
#define FLASH_TRACE(...)
#endif /* #ifdef FLASH_DEBUG */
#define PAGE_SIZE 4096
/* JEDEC Manufacturer's ID */
#define MF_ID (0xC8)
/* JEDEC Device ID: Memory type and Capacity */
#define MTC_GD25Q128 (0x4018)
/* command list */
#define CMD_WRSR (0x01) /* Write Status Register */
#define CMD_PP (0x02) /* Page Program */
#define CMD_READ (0x03) /* Read Data */
#define CMD_WRDI (0x04) /* Write Disable */
#define CMD_RDSR1 (0x05) /* Read Status Register-1 */
#define CMD_WREN (0x06) /* Write Enable */
#define CMD_FAST_READ (0x0B) /* Fast Read */
#define CMD_ERASE_4K (0x20) /* Sector Erase:4K */
#define CMD_RDSR2 (0x35) /* Read Status Register-2 */
#define CMD_ERASE_32K (0x52) /* 32KB Block Erase */
#define CMD_JEDEC_ID (0x9F) /* Read JEDEC ID */
#define CMD_ERASE_full (0xC7) /* Chip Erase */
#define CMD_ERASE_64K (0xD8) /* 64KB Block Erase */
#define DUMMY (0xFF)
static struct spi_flash_device spi_flash_device;
static void flash_lock(struct spi_flash_device * flash_device)
{
rt_mutex_take(&flash_device->lock, RT_WAITING_FOREVER);
}
static void flash_unlock(struct spi_flash_device * flash_device)
{
rt_mutex_release(&flash_device->lock);
}
static uint8_t w25qxx_read_status(void)
{
return rt_spi_sendrecv8(spi_flash_device.rt_spi_device, CMD_RDSR1);
}
static void w25qxx_wait_busy(void)
{
while( w25qxx_read_status() & (0x01));
}
/** \brief read [size] byte from [offset] to [buffer]
*
* \param offset uint32_t unit : byte
* \param buffer uint8_t*
* \param size uint32_t unit : byte
* \return uint32_t byte for read
*
*/
static uint32_t w25qxx_read(uint32_t offset, uint8_t * buffer, uint32_t size)
{
uint8_t send_buffer[4];
send_buffer[0] = CMD_WRDI;
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
send_buffer[0] = CMD_READ;
send_buffer[1] = (uint8_t)(offset>>16);
send_buffer[2] = (uint8_t)(offset>>8);
send_buffer[3] = (uint8_t)(offset);
rt_spi_send_then_recv(spi_flash_device.rt_spi_device,
send_buffer, 4,
buffer, size);
return size;
}
/** \brief write N page on [page]
*
* \param page_addr uint32_t unit : byte (4096 * N,1 page = 4096byte)
* \param buffer const uint8_t*
* \return uint32_t
*
*/
static uint32_t w25qxx_page_write(uint32_t page_addr, const uint8_t* buffer)
{
uint32_t index;
uint8_t send_buffer[4];
RT_ASSERT((page_addr&0xFF) == 0); /* page addr must align to 256byte. */
send_buffer[0] = CMD_WREN;
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
send_buffer[0] = CMD_ERASE_4K;
send_buffer[1] = (page_addr >> 16);
send_buffer[2] = (page_addr >> 8);
send_buffer[3] = (page_addr);
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 4);
w25qxx_wait_busy(); // wait erase done.
for(index=0; index < (PAGE_SIZE / 256); index++)
{
send_buffer[0] = CMD_WREN;
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
send_buffer[0] = CMD_PP;
send_buffer[1] = (uint8_t)(page_addr >> 16);
send_buffer[2] = (uint8_t)(page_addr >> 8);
send_buffer[3] = (uint8_t)(page_addr);
rt_spi_send_then_send(spi_flash_device.rt_spi_device,
send_buffer,
4,
buffer,
256);
buffer += 256;
page_addr += 256;
w25qxx_wait_busy();
}
send_buffer[0] = CMD_WRDI;
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
return PAGE_SIZE;
}
/* RT-Thread device interface */
static rt_err_t w25qxx_flash_init(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t w25qxx_flash_open(rt_device_t dev, rt_uint16_t oflag)
{
uint8_t send_buffer[3];
flash_lock((struct spi_flash_device *)dev);
send_buffer[0] = CMD_WREN;
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
send_buffer[0] = CMD_WRSR;
send_buffer[1] = 0;
send_buffer[2] = 0;
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 3);
w25qxx_wait_busy();
flash_unlock((struct spi_flash_device *)dev);
return RT_EOK;
}
static rt_err_t w25qxx_flash_close(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t w25qxx_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
{
RT_ASSERT(dev != RT_NULL);
if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
{
struct rt_device_blk_geometry *geometry;
geometry = (struct rt_device_blk_geometry *)args;
if (geometry == RT_NULL) return -RT_ERROR;
geometry->bytes_per_sector = spi_flash_device.geometry.bytes_per_sector;
geometry->sector_count = spi_flash_device.geometry.sector_count;
geometry->block_size = spi_flash_device.geometry.block_size;
}
return RT_EOK;
}
static rt_size_t w25qxx_flash_read(rt_device_t dev,
rt_off_t pos,
void* buffer,
rt_size_t size)
{
flash_lock((struct spi_flash_device *)dev);
w25qxx_read(pos*spi_flash_device.geometry.bytes_per_sector,
buffer,
size*spi_flash_device.geometry.bytes_per_sector);
flash_unlock((struct spi_flash_device *)dev);
return size;
}
static rt_size_t w25qxx_flash_write(rt_device_t dev,
rt_off_t pos,
const void* buffer,
rt_size_t size)
{
rt_size_t i = 0;
rt_size_t block = size;
const uint8_t * ptr = buffer;
flash_lock((struct spi_flash_device *)dev);
while(block--)
{
w25qxx_page_write((pos + i)*spi_flash_device.geometry.bytes_per_sector,
ptr);
ptr += PAGE_SIZE;
i++;
}
flash_unlock((struct spi_flash_device *)dev);
return size;
}
rt_err_t gd_init(const char * flash_device_name, const char * spi_device_name)
{
struct rt_spi_device * rt_spi_device;
/* initialize mutex */
if (rt_mutex_init(&spi_flash_device.lock, spi_device_name, RT_IPC_FLAG_FIFO) != RT_EOK)
{
rt_kprintf("init sd lock mutex failed\n");
return -RT_ENOSYS;
}
rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
if(rt_spi_device == RT_NULL)
{
FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
return -RT_ENOSYS;
}
spi_flash_device.rt_spi_device = rt_spi_device;
/* config spi */
{
struct rt_spi_configuration cfg;
cfg.data_width = 8;
cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
cfg.max_hz = 50 * 1000 * 1000; /* 50M */
rt_spi_configure(spi_flash_device.rt_spi_device, &cfg);
}
/* init flash */
{
rt_uint8_t cmd;
rt_uint8_t id_recv[3];
uint16_t memory_type_capacity;
flash_lock(&spi_flash_device);
cmd = 0xFF; /* reset SPI FLASH, cancel all cmd in processing. */
rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1);
cmd = CMD_WRDI;
rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1);
/* read flash id */
cmd = CMD_JEDEC_ID;
rt_spi_send_then_recv(spi_flash_device.rt_spi_device, &cmd, 1, id_recv, 3);
flash_unlock(&spi_flash_device);
if(id_recv[0] != MF_ID)
{
FLASH_TRACE("Manufacturers ID error!\r\n");
FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
return -RT_ENOSYS;
}
spi_flash_device.geometry.bytes_per_sector = 4096;
spi_flash_device.geometry.block_size = 4096; /* block erase: 4k */
/* get memory type and capacity */
memory_type_capacity = id_recv[1];
memory_type_capacity = (memory_type_capacity << 8) | id_recv[2];
if(memory_type_capacity == MTC_GD25Q128)
{
FLASH_TRACE("GD128 detection\r\n");
spi_flash_device.geometry.sector_count = 4096;
}
else
{
FLASH_TRACE("Memory Capacity error!\r\n");
return -RT_ENOSYS;
}
}
/* register device */
spi_flash_device.flash_device.type = RT_Device_Class_Block;
spi_flash_device.flash_device.init = w25qxx_flash_init;
spi_flash_device.flash_device.open = w25qxx_flash_open;
spi_flash_device.flash_device.close = w25qxx_flash_close;
spi_flash_device.flash_device.read = w25qxx_flash_read;
spi_flash_device.flash_device.write = w25qxx_flash_write;
spi_flash_device.flash_device.control = w25qxx_flash_control;
/* no private */
spi_flash_device.flash_device.user_data = RT_NULL;
rt_device_register(&spi_flash_device.flash_device, flash_device_name,
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
return RT_EOK;
}

View File

@ -0,0 +1,32 @@
/*
* File : spi_flash_gd.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2016, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2015-10-11 fullhan copy from winbond flash
*/
#ifndef SPI_FLASH_GD_H_
#define SPI_FLASH_GD_H_
#include <rtthread.h>
extern rt_err_t gd_init(const char * flash_device_name, const char * spi_device_name);
#endif /* SPI_FLASH_GD_H_ */

View File

@ -1,11 +1,21 @@
/*
* File : rtdef.h
* File : spi_flash_sst25vfxx.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes

View File

@ -1,11 +1,21 @@
/*
* File : rtdef.h
* File : spi_flash_sst25vxx.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes

View File

@ -3,9 +3,19 @@
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
@ -13,10 +23,12 @@
* 2012-05-06 aozima can page write.
* 2012-08-23 aozima add flash lock.
* 2012-08-24 aozima fixed write status register BUG.
* 2015-05-13 bernard add GD25Q flash ID.
*/
#include <stdint.h>
#include <rtdevice.h>
#include "spi_flash.h"
#include "spi_flash_w25qxx.h"
#define FLASH_DEBUG
@ -31,7 +43,6 @@
/* JEDEC Manufacturer<65><72>s ID */
#define MF_ID (0xEF)
#define GD_ID (0xC8)
/* JEDEC Device ID: Memory type and Capacity */
#define MTC_W25Q80_BV (0x4014) /* W25Q80BV */
@ -301,7 +312,7 @@ rt_err_t w25qxx_init(const char * flash_device_name, const char * spi_device_nam
flash_unlock(&spi_flash_device);
if(id_recv[0] != MF_ID && id_recv[0] != GD_ID)
if(id_recv[0] != MF_ID)
{
FLASH_TRACE("Manufacturers ID error!\r\n");
FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);

View File

@ -3,9 +3,19 @@
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
@ -17,18 +27,8 @@
#define SPI_FLASH_W25QXX_H_INCLUDED
#include <rtthread.h>
#include <drivers/spi.h>
struct spi_flash_device
{
struct rt_device flash_device;
struct rt_device_blk_geometry geometry;
struct rt_spi_device * rt_spi_device;
struct rt_mutex lock;
};
extern rt_err_t w25qxx_init(const char * flash_device_name,
const char * spi_device_name);
#endif // SPI_FLASH_W25QXX_H_INCLUDED

View File

@ -1,11 +1,9 @@
Import('RTT_ROOT')
Import('rtconfig')
from building import *
import os
CAIRO_VERSION = '1.10.2'
CAIRO_PATH = 'cairo-' + CAIRO_VERSION
cwd = GetCurrentDir()
if GetDepend('RT_USING_CAIRO') and not os.path.exists(CAIRO_PATH):
print '================ERROR============================'
@ -99,7 +97,7 @@ cairo.c
for item in range(len(src)):
src[item] = CAIRO_PATH + '/src/' + src[item]
CPPPATH = [RTT_ROOT + '/components/external/cairo/' + CAIRO_PATH + '/src', RTT_ROOT + '/components/external/cairo/']
CPPPATH = [cwd + '/' + CAIRO_PATH + '/src', cwd]
group = DefineGroup('cairo', src, depend = ['RT_USING_CAIRO', 'RT_USING_NEWLIB', 'RTGUI_IMAGE_PNG', 'RT_USING_PTHREADS'], CPPPATH = CPPPATH)
Return('group')

View File

@ -1,12 +1,11 @@
Import('RTT_ROOT')
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = Split('''
minilzo.c
lzo.c
''')
CPPPATH = [RTT_ROOT + '/components/external/lzo']
CPPPATH = [cwd]
group = DefineGroup('lzo', src, depend = ['RT_USING_LZO'], CPPPATH = CPPPATH)

View File

@ -1,13 +1,12 @@
Import('RTT_ROOT')
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = Split('''
pb_common.c
pb_decode.c
pb_encode.c
''')
CPPPATH = [RTT_ROOT + '/components/external/nanopb']
CPPPATH = [cwd]
group = DefineGroup('Nanopb', src, depend = ['RT_USING_NANOPB'], CPPPATH = CPPPATH)

View File

@ -17,4 +17,7 @@ else:
if rtconfig.PLATFORM == 'gcc' and rtconfig.ARCH != 'sim':
objs = objs + SConscript('minilibc/SConscript')
objs = objs + SConscript('pthreads/SConscript')
objs = objs + SConscript('libdl/SConscript')
Return('objs')

View File

@ -1,9 +1,9 @@
Import('RTT_ROOT')
Import('rtconfig')
from building import *
src = Glob('*.c')
CPPPATH = [RTT_ROOT + '/components/libdl']
cwd = GetCurrentDir()
CPPPATH = [cwd]
group = DefineGroup('libdl', src, depend = ['RT_USING_MODULE', 'RT_USING_LIBDL'], CPPPATH = CPPPATH)
Return('group')

View File

@ -447,3 +447,18 @@ void __libc_init_array(void)
{
/* we not use __libc init_aray to initialize C++ objects */
}
void abort(void)
{
if (rt_thread_self())
{
rt_thread_t self = rt_thread_self();
rt_kprintf("thread:%-8.*s abort!\n", RT_NAME_MAX, self->name);
rt_thread_suspend(self);
rt_schedule();
}
while (1);
}

View File

@ -1,8 +1,9 @@
Import('RTT_ROOT')
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [RTT_ROOT + '/components/pthreads']
CPPPATH = [cwd]
group = DefineGroup('pthreads', src, depend = ['RT_USING_PTHREADS', 'RT_USING_LIBC'], CPPPATH = CPPPATH)
Return('group')

View File

@ -142,6 +142,20 @@ typedef struct pthread_barrier pthread_barrier_t;
/* pthread thread interface */
int pthread_attr_destroy(pthread_attr_t *attr);
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int state);
int pthread_attr_getdetachstate(pthread_attr_t const *attr, int *state);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(pthread_attr_t const *attr, int *policy);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stack_size);
int pthread_attr_getstacksize(pthread_attr_t const *attr, size_t *stack_size);
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack_addr);
int pthread_attr_getstackaddr(pthread_attr_t const *attr, void **stack_addr);
int pthread_attr_setstack(pthread_attr_t *attr,
void *stack_base,
size_t stack_size);
int pthread_attr_getstack(pthread_attr_t const *attr,
void **stack_base,
size_t *stack_size);
int pthread_system_init(void);
int pthread_create (pthread_t *tid, const pthread_attr_t *attr,

View File

@ -4,14 +4,15 @@ Import('RTT_ROOT')
from building import *
objs = []
list = os.listdir(os.path.join(RTT_ROOT, 'components', 'net'))
cwd = GetCurrentDir()
list = os.listdir(cwd)
# the default version of LWIP is 1.4.1
if not GetDepend('RT_USING_LWIP132') and not GetDepend('RT_USING_LWIP140') and not GetDepend('RT_USING_LWIP_HEAD'):
AddDepend('RT_USING_LWIP141')
for d in list:
path = os.path.join(RTT_ROOT, 'components', 'net', d)
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))

View File

@ -76,7 +76,7 @@ typedef rt_uint32_t mem_ptr_t;
#define LWIP_TIMEVAL_PRIVATE 1
#endif
#if defined(RT_USING_DFS_LWIP)
#if defined(RT_USING_DFS_NET)
#define LWIP_COMPAT_SOCKETS 0
#endif

View File

@ -1248,6 +1248,12 @@ tcp_rexmit_rto(struct tcp_pcb *pcb)
for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
/* concatenate unsent queue after unacked queue */
seg->next = pcb->unsent;
#if TCP_OVERSIZE && TCP_OVERSIZE_DBGCHECK
/* if last unsent changed, we need to update unsent_oversize */
if (pcb->unsent == NULL) {
pcb->unsent_oversize = seg->oversize_left;
}
#endif /* TCP_OVERSIZE && TCP_OVERSIZE_DBGCHECK*/
/* unsent queue is the concatenated queue (of unacked, unsent) */
pcb->unsent = pcb->unacked;
/* unacked queue is now empty */

View File

@ -139,6 +139,7 @@ PACK_STRUCT_END
#define ETHTYPE_VLAN 0x8100U
#define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */
#define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session Stage */
#define ETHTYPE_EAPOL 0x888eU /* EAPOL */
/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables
* or known to be 32-bit aligned within the protocol header. */

View File

@ -38,10 +38,6 @@
#define LWIP_PLATFORM_BYTESWAP 0
#define BYTE_ORDER LITTLE_ENDIAN
/* Enable SO_RCVTIMEO/LWIP_SO_SNDTIMEO processing. */
#define LWIP_SO_RCVTIMEO 1
#define LWIP_SO_SNDTIMEO 1
/* #define RT_LWIP_DEBUG */
#ifdef RT_LWIP_DEBUG
@ -355,5 +351,62 @@
#include <stdlib.h>
#define LWIP_RAND rand
#endif
/*
------------------------------------
---------- Socket options ----------
------------------------------------
*/
/*
* LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
*/
#ifndef LWIP_SOCKET
#define LWIP_SOCKET 1
#endif
/*
* LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names.
* (only used if you use sockets.c)
*/
#ifndef LWIP_COMPAT_SOCKETS
#define LWIP_COMPAT_SOCKETS 1
#endif
/**
* LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and
* SO_SNDTIMEO processing.
*/
#ifndef LWIP_SO_SNDTIMEO
#define LWIP_SO_SNDTIMEO 1
#endif
/**
* LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and
* SO_RCVTIMEO processing.
*/
#ifndef LWIP_SO_RCVTIMEO
#define LWIP_SO_RCVTIMEO 1
#endif
/**
* LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing.
*/
#ifndef LWIP_SO_RCVBUF
#define LWIP_SO_RCVBUF 1
#endif
/**
* If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize.
*/
#ifndef RECV_BUFSIZE_DEFAULT
#define RECV_BUFSIZE_DEFAULT 8192
#endif
/**
* SO_REUSE==1: Enable SO_REUSEADDR option.
*/
#ifndef SO_REUSE
#define SO_REUSE 0
#endif
#endif /* __LWIPOPTS_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +0,0 @@
/*
* 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>
*
*/

View File

@ -1,4 +0,0 @@
src/ - The source code for the lwIP TCP/IP stack.
doc/ - The documentation for lwIP.
See also the FILES file in each subdirectory.

View File

@ -1,89 +0,0 @@
INTRODUCTION
lwIP is a small independent implementation of the TCP/IP protocol
suite that has been developed by Adam Dunkels at the Computer and
Networks Architectures (CNA) lab at the Swedish Institute of Computer
Science (SICS).
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.
FEATURES
* IP (Internet Protocol) 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
* UDP (User Datagram Protocol) including experimental UDP-lite extensions
* TCP (Transmission Control Protocol) with congestion control, RTT estimation
and fast recovery/fast retransmit
* Specialized raw/native API for enhanced performance
* Optional Berkeley-like socket API
* DNS (Domain names resolver)
* SNMP (Simple Network Management Protocol)
* DHCP (Dynamic Host Configuration Protocol)
* AUTOIP (for IPv4, conform with RFC 3927)
* PPP (Point-to-Point Protocol)
* ARP (Address Resolution Protocol) for Ethernet
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, CVS and the
mailing list. A core team of developers will commit changes to the
CVS source tree.
The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and
contributions (such as platform ports) are in the 'contrib' module.
See doc/savannah.txt for details on CVS server access for users and
developers.
Last night's CVS tar ball can be downloaded from:
http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING]
The current CVS trees are web-browsable:
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/
Submit patches and bugs via the lwIP project page:
http://savannah.nongnu.org/projects/lwip/
DOCUMENTATION
The original out-dated homepage of lwIP and Adam Dunkels' papers on
lwIP are at the official lwIP home page:
http://www.sics.se/~adam/lwip/
Self documentation of the source code is regularly extracted from the
current CVS sources and is available from this web page:
http://www.nongnu.org/lwip/
There is now a constantly growin 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/
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>

View File

@ -1,87 +0,0 @@
Import('RTT_ROOT')
from building import *
src = Split("""
src/api/api_lib.c
src/api/api_msg.c
src/api/err.c
src/api/netbuf.c
src/api/netdb.c
src/api/netifapi.c
src/api/sockets.c
src/api/tcpip.c
src/arch/sys_arch.c
src/core/def.c
src/core/dhcp.c
src/core/dns.c
src/core/init.c
src/core/memp.c
src/core/netif.c
src/core/pbuf.c
src/core/raw.c
src/core/stats.c
src/core/sys.c
src/core/tcp.c
src/core/tcp_in.c
src/core/tcp_out.c
src/core/timers.c
src/core/udp.c
src/core/ipv4/autoip.c
src/core/ipv4/icmp.c
src/core/ipv4/igmp.c
src/core/ipv4/inet.c
src/core/ipv4/inet_chksum.c
src/core/ipv4/ip.c
src/core/ipv4/ip_addr.c
src/core/ipv4/ip_frag.c
src/netif/etharp.c
src/netif/ethernetif.c
src/netif/slipif.c
""")
snmp_src = Split("""
src/core/snmp/asn1_dec.c
src/core/snmp/asn1_enc.c
src/core/snmp/mib2.c
src/core/snmp/mib_structs.c
src/core/snmp/msg_in.c
src/core/snmp/msg_out.c
""")
ppp_src = Split("""
src/netif/ppp/auth.c
src/netif/ppp/chap.c
src/netif/ppp/chpms.c
src/netif/ppp/fsm.c
src/netif/ppp/ipcp.c
src/netif/ppp/lcp.c
src/netif/ppp/magic.c
src/netif/ppp/md5.c
src/netif/ppp/pap.c
src/netif/ppp/ppp.c
src/netif/ppp/ppp_oe.c
src/netif/ppp/randm.c
src/netif/ppp/vj.c
""")
# The set of source files associated with this SConscript file.
path = [GetCurrentDir() + '/src',
GetCurrentDir() + '/src/include',
GetCurrentDir() + '/src/include/ipv4',
GetCurrentDir() + '/src/arch/include',
GetCurrentDir() + '/src/include/netif']
if GetDepend(['RT_LWIP_SNMP']):
src += snmp_src
if GetDepend(['RT_LWIP_PPP']):
src += ppp_src
path += [GetCurrentDir() + '/src/netif/ppp']
# For testing apps
if GetDepend(['RT_USING_NETUTILS']):
src += Glob('./apps/*.c')
group = DefineGroup('LwIP', src, depend = ['RT_USING_LWIP', 'RT_USING_LWIP140'], CPPPATH = path)
Return('group')

View File

@ -1,144 +0,0 @@
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.
(CVS HEAD)
* [Enter new changes just after this line - do not remove this line]
++ 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

View File

@ -1,7 +0,0 @@
Import('RTT_ROOT')
from building import *
src = Glob('*.c')
group = DefineGroup('netutils', src, depend = ['RT_USING_NETUTILS'])
Return('group')

View File

@ -1,216 +0,0 @@
#include <rtthread.h>
#include "lwip/sockets.h"
#define MAX_SERV 32 /* Maximum number of chargen services. Don't need too many */
#define CHARGEN_THREAD_NAME "chargen"
#if RT_THREAD_PRIORITY_MAX == 32
#define CHARGEN_PRIORITY 20 /* Really low priority */
#else
#define CHARGEN_PRIORITY 200 /* Really low priority */
#endif
#define CHARGEN_THREAD_STACKSIZE 1024
struct charcb
{
struct charcb *next;
int socket;
struct sockaddr_in cliaddr;
socklen_t clilen;
char nextchar;
};
static struct charcb *charcb_list = 0;
static int do_read(struct charcb *p_charcb);
static void close_chargen(struct charcb *p_charcb);
/**************************************************************
* void chargen_thread(void *arg)
*
* chargen task. This server will wait for connections on well
* known TCP port number: 19. For every connection, the server will
* write as much data as possible to the tcp port.
**************************************************************/
static void chargen_thread(void *arg)
{
int listenfd;
struct sockaddr_in chargen_saddr;
fd_set readset;
fd_set writeset;
int i, maxfdp1;
struct charcb *p_charcb;
/* First acquire our socket for listening for connections */
listenfd = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
LWIP_ASSERT("chargen_thread(): Socket create failed.", listenfd >= 0);
memset(&chargen_saddr, 0, sizeof(chargen_saddr));
chargen_saddr.sin_family = AF_INET;
chargen_saddr.sin_addr.s_addr = htonl(INADDR_ANY);
chargen_saddr.sin_port = htons(19); // Chargen server port
if (lwip_bind(listenfd, (struct sockaddr *) &chargen_saddr, sizeof(chargen_saddr)) == -1)
LWIP_ASSERT("chargen_thread(): Socket bind failed.", 0);
/* Put socket into listening mode */
if (lwip_listen(listenfd, MAX_SERV) == -1)
LWIP_ASSERT("chargen_thread(): Listen failed.", 0);
/* Wait forever for network input: This could be connections or data */
for (;;)
{
maxfdp1 = listenfd+1;
/* Determine what sockets need to be in readset */
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_SET(listenfd, &readset);
for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
{
if (maxfdp1 < p_charcb->socket + 1)
maxfdp1 = p_charcb->socket + 1;
FD_SET(p_charcb->socket, &readset);
FD_SET(p_charcb->socket, &writeset);
}
/* Wait for data or a new connection */
i = lwip_select(maxfdp1, &readset, &writeset, 0, 0);
if (i == 0) continue;
/* At least one descriptor is ready */
if (FD_ISSET(listenfd, &readset))
{
/* We have a new connection request!!! */
/* Lets create a new control block */
p_charcb = (struct charcb *)rt_calloc(1, sizeof(struct charcb));
if (p_charcb)
{
p_charcb->socket = lwip_accept(listenfd,
(struct sockaddr *) &p_charcb->cliaddr,
&p_charcb->clilen);
if (p_charcb->socket < 0)
rt_free(p_charcb);
else
{
/* Keep this tecb in our list */
p_charcb->next = charcb_list;
charcb_list = p_charcb;
p_charcb->nextchar = 0x21;
}
}
else
{
/* No memory to accept connection. Just accept and then close */
int sock;
struct sockaddr cliaddr;
socklen_t clilen;
sock = lwip_accept(listenfd, &cliaddr, &clilen);
if (sock >= 0)
lwip_close(sock);
}
}
/* Go through list of connected clients and process data */
for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
{
if (FD_ISSET(p_charcb->socket, &readset))
{
/* This socket is ready for reading. This could be because someone typed
* some characters or it could be because the socket is now closed. Try reading
* some data to see. */
if (do_read(p_charcb) < 0)
break;
}
if (FD_ISSET(p_charcb->socket, &writeset))
{
char line[80];
char setchar = p_charcb->nextchar;
for( i = 0; i < 59; i++)
{
line[i] = setchar;
if (++setchar == 0x7f)
setchar = 0x21;
}
line[i] = 0;
strcat(line, "\n\r");
if (lwip_write(p_charcb->socket, line, strlen(line)) < 0)
{
close_chargen(p_charcb);
break;
}
if (++p_charcb->nextchar == 0x7f)
p_charcb->nextchar = 0x21;
}
}
}
}
/**************************************************************
* void close_chargen(struct charcb *p_charcb)
*
* Close the socket and remove this charcb from the list.
**************************************************************/
static void close_chargen(struct charcb *p_charcb)
{
struct charcb *p_search_charcb;
/* Either an error or tcp connection closed on other
* end. Close here */
lwip_close(p_charcb->socket);
/* Free charcb */
if (charcb_list == p_charcb)
charcb_list = p_charcb->next;
else
for (p_search_charcb = charcb_list; p_search_charcb; p_search_charcb = p_search_charcb->next)
{
if (p_search_charcb->next == p_charcb)
{
p_search_charcb->next = p_charcb->next;
break;
}
}
rt_free(p_charcb);
}
/**************************************************************
* void do_read(struct charcb *p_charcb)
*
* Socket definitely is ready for reading. Read a buffer from the socket and
* discard the data. If no data is read, then the socket is closed and the
* charcb is removed from the list and freed.
**************************************************************/
static int do_read(struct charcb *p_charcb)
{
char buffer[80];
int readcount;
/* Read some data */
readcount = lwip_read(p_charcb->socket, &buffer, 80);
if (readcount <= 0)
{
close_chargen(p_charcb);
return -1;
}
return 0;
}
void chargen_init(void)
{
rt_thread_t chargen;
chargen = rt_thread_create(CHARGEN_THREAD_NAME,
chargen_thread, RT_NULL,
CHARGEN_THREAD_STACKSIZE,
CHARGEN_PRIORITY, 5);
if (chargen != RT_NULL) rt_thread_startup(chargen);
}
#ifdef RT_USING_FINSH
#include <finsh.h>
void chargen()
{
chargen_init();
}
FINSH_FUNCTION_EXPORT(chargen, start chargen server);
#endif

View File

@ -1,985 +0,0 @@
#include <string.h>
#include <stdlib.h>
#include <rtthread.h>
#include <dfs_posix.h>
#include <lwip/sockets.h>
#include <time.h>
#define FTP_PORT 21
#define FTP_SRV_ROOT "/"
#define FTP_MAX_CONNECTION 2
#define FTP_USER "rtt"
#define FTP_PASSWORD "demo"
#define FTP_WELCOME_MSG "220 welcome on RT-Thread FTP server.\r\n"
#define FTP_BUFFER_SIZE 1024
#define INET_ADDRSTRLEN 16
struct ftp_session
{
rt_bool_t is_anonymous;
int sockfd;
struct sockaddr_in remote;
struct sockaddr_in server;
char serveraddr[INET_ADDRSTRLEN];
/* pasv data */
int pasv_listen_sockfd;
char pasv_active;
int pasv_sockfd;
unsigned short pasv_port;
size_t offset;
/* current directory */
char currentdir[256];
struct ftp_session* next;
};
static struct ftp_session* session_list = NULL;
int ftp_process_request(struct ftp_session* session, char * buf);
int ftp_get_filesize(char *filename);
struct ftp_session* ftp_new_session()
{
struct ftp_session* session;
session = (struct ftp_session*)rt_malloc(sizeof(struct ftp_session));
rt_memset((void *)session, 0, sizeof(struct ftp_session));
session->next = session_list;
session_list = session;
return session;
}
void ftp_close_session(struct ftp_session* session)
{
struct ftp_session* list;
if (session_list == session)
{
session_list = session_list->next;
session->next = NULL;
}
else
{
list = session_list;
while (list->next != session) list = list->next;
list->next = session->next;
session->next = NULL;
}
rt_free(session);
}
static int open_data_connection(struct ftp_session* session)
{
socklen_t len = sizeof(struct sockaddr);
struct sockaddr_in sin;
#if 0
/* Previous PORT command from client */
if (ctrl->data_address[0]) {
ctrl->data_sd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == ctrl->data_sd) {
printf("Failed creating data socket");
return -1;
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(ctrl->data_port);
inet_aton(ctrl->data_address, &(sin.sin_addr));
if (connect(ctrl->data_sd, (struct sockaddr *)&sin, len) == -1) {
printf("Failed connecting data socket to client");
close(ctrl->data_sd);
ctrl->data_sd = -1;
return -1;
}
DBG("Connected successfully to client's previously requested address:PORT %s:%d", ctrl->data_address, ctrl->data_port);
return 0;
}
#endif
/* Previous PASV command, accept connect from client */
if (session->pasv_listen_sockfd > 0) {
char client_ip[100];
session->pasv_sockfd = accept(session->pasv_listen_sockfd, (struct sockaddr *)&sin, &len);
if (-1 == session->pasv_sockfd) {
printf("Failed accepting connection from client");
return -1;
}
len = sizeof(struct sockaddr);
if (-1 == getpeername(session->pasv_sockfd, (struct sockaddr *)&sin, &len)) {
printf("Cannot determine client address");
closesocket(session->pasv_sockfd);
session->pasv_sockfd = -1;
return -1;
}
printf("Client PASV data connection from %s\n", inet_ntoa(sin.sin_addr));
}
return 0;
}
static void close_data_connection(struct ftp_session* session)
{
/* PASV server listening socket */
if (session->pasv_listen_sockfd > 0) {
closesocket(session->pasv_listen_sockfd);
session->pasv_listen_sockfd = -1;
}
/* PASV client socket */
if (session->pasv_sockfd > 0) {
closesocket(session->pasv_sockfd);
session->pasv_sockfd = -1;
}
#if 0
/* PORT */
if (ctrl->data_address[0]) {
ctrl->data_address[0] = 0;
ctrl->data_port = 0;
}
#endif
}
int ftp_get_filesize(char * filename)
{
int pos;
int end;
int fd;
fd = open(filename, O_RDONLY, 0);
if (fd < 0) return -1;
pos = lseek(fd, 0, SEEK_CUR);
end = lseek(fd, 0, SEEK_END);
lseek (fd, pos, SEEK_SET);
close(fd);
return end;
}
rt_bool_t is_absolute_path(char* path)
{
#ifdef _WIN32
if (path[0] == '\\' ||
(path[1] == ':' && path[2] == '\\'))
return RT_TRUE;
#else
if (path[0] == '/') return RT_TRUE;
#endif
return RT_FALSE;
}
int build_full_path(struct ftp_session* session, char* path, char* new_path, size_t size)
{
if (is_absolute_path(path) == RT_TRUE)
strcpy(new_path, path);
else
{
rt_sprintf(new_path, "%s/%s", session->currentdir, path);
}
return 0;
}
void ftpd_thread_entry(void* parameter)
{
int numbytes;
int sockfd, maxfdp1;
struct sockaddr_in local;
fd_set readfds, tmpfds;
struct ftp_session* session;
rt_uint32_t addr_len = sizeof(struct sockaddr);
char * buffer = (char *) rt_malloc(FTP_BUFFER_SIZE);
local.sin_port=htons(FTP_PORT);
local.sin_family=PF_INET;
local.sin_addr.s_addr=INADDR_ANY;
FD_ZERO(&readfds);
FD_ZERO(&tmpfds);
sockfd=socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
rt_kprintf("create socket failed\n");
return ;
}
bind(sockfd, (struct sockaddr *)&local, addr_len);
listen(sockfd, FTP_MAX_CONNECTION);
FD_SET(sockfd, &readfds);
for(;;)
{
/* get maximum fd */
maxfdp1 = sockfd + 1;
session = session_list;
while (session != RT_NULL)
{
if (maxfdp1 < session->sockfd + 1)
maxfdp1 = session->sockfd + 1;
FD_SET(session->sockfd, &readfds);
session = session->next;
}
tmpfds=readfds;
if (select(maxfdp1, &tmpfds, 0, 0, 0) == 0) continue;
if(FD_ISSET(sockfd, &tmpfds))
{
int com_socket;
struct sockaddr_in remote;
com_socket = accept(sockfd, (struct sockaddr*)&remote, &addr_len);
if(com_socket == -1)
{
rt_kprintf("Error on accept()\nContinuing...\n");
continue;
}
else
{
rt_kprintf("Got connection from %s\n", inet_ntoa(remote.sin_addr));
send(com_socket, FTP_WELCOME_MSG, strlen(FTP_WELCOME_MSG), 0);
FD_SET(com_socket, &readfds);
/* new session */
session = ftp_new_session();
if (session != NULL)
{
if (-1 == getsockname(com_socket, (struct sockaddr *)&session->server, &addr_len)) {
printf("Cannot determine our address, need it if client should connect to us\n");
}
ipaddr_ntoa_r(&(session->server.sin_addr), session->serveraddr, sizeof(session->serveraddr));
strcpy(session->currentdir, FTP_SRV_ROOT);
session->sockfd = com_socket;
session->remote = remote;
}
}
}
{
struct ftp_session* next;
session = session_list;
while (session != NULL)
{
next = session->next;
if (FD_ISSET(session->sockfd, &tmpfds))
{
numbytes=recv(session->sockfd, buffer, FTP_BUFFER_SIZE, 0);
if(numbytes==0 || numbytes==-1)
{
rt_kprintf("Client %s disconnected\n", inet_ntoa(session->remote.sin_addr));
FD_CLR(session->sockfd, &readfds);
closesocket(session->sockfd);
session->sockfd = -1;
ftp_close_session(session);
}
else
{
buffer[numbytes]=0;
if(ftp_process_request(session, buffer)==-1)
{
rt_kprintf("Client %s disconnected\r\n", inet_ntoa(session->remote.sin_addr));
closesocket(session->sockfd);
session->sockfd = -1;
ftp_close_session(session);
}
}
}
session = next;
}
}
}
// rt_free(buffer);
}
int do_list(char* directory, int sockfd)
{
DIR* dirp;
struct dirent* entry;
char line_buffer[256], line_length;
#ifdef _WIN32
struct _stat s;
#else
struct stat s;
#endif
dirp = opendir(directory);
if (dirp == NULL)
{
line_length = rt_sprintf(line_buffer, "500 Internal Error\r\n");
send(sockfd, line_buffer, line_length, 0);
return -1;
}
while (1)
{
entry = readdir(dirp);
if (entry == NULL) break;
rt_sprintf(line_buffer, "%s/%s", directory, entry->d_name);
#ifdef _WIN32
if (_stat(line_buffer, &s) ==0)
#else
if (stat(line_buffer, &s) == 0)
#endif
{
if (s.st_mode & S_IFDIR)
line_length = rt_sprintf(line_buffer, "drw-r--r-- 1 admin admin %d Jan 1 2000 %s\r\n", 0, entry->d_name);
else
line_length = rt_sprintf(line_buffer, "-rw-r--r-- 1 admin admin %d Jan 1 2000 %s\r\n", s.st_size, entry->d_name);
send(sockfd, line_buffer, line_length, 0);
}
else
{
rt_kprintf("Get directory entry error\n");
break;
}
}
closedir(dirp);
return 0;
}
int do_simple_list(char* directory, int sockfd)
{
DIR* dirp;
struct dirent* entry;
char line_buffer[256], line_length;
dirp = opendir(directory);
if (dirp == NULL)
{
line_length = rt_sprintf(line_buffer, "500 Internal Error\r\n");
send(sockfd, line_buffer, line_length, 0);
return -1;
}
while (1)
{
entry = readdir(dirp);
if (entry == NULL) break;
line_length = rt_sprintf(line_buffer, "%s\r\n", entry->d_name);
send(sockfd, line_buffer, line_length, 0);
}
closedir(dirp);
return 0;
}
int str_begin_with(char* src, char* match)
{
while (*match)
{
/* check source */
if (*src == 0) return -1;
if (*match != *src) return -1;
match ++; src ++;
}
return 0;
}
int ftp_process_request(struct ftp_session* session, char *buf)
{
int fd;
struct timeval tv;
fd_set readfds;
char filename[256];
int numbytes;
char *sbuf;
char *parameter_ptr, *ptr;
rt_uint32_t addr_len = sizeof(struct sockaddr_in);
struct sockaddr_in local, pasvremote;
sbuf =(char *)rt_malloc(FTP_BUFFER_SIZE);
tv.tv_sec=3, tv.tv_usec=0;
local.sin_family=PF_INET;
local.sin_addr.s_addr=INADDR_ANY;
/* remove \r\n */
ptr = buf;
while (*ptr)
{
if (*ptr == '\r' || *ptr == '\n') *ptr = 0;
ptr ++;
}
/* get request parameter */
parameter_ptr = strchr(buf, ' '); if (parameter_ptr != NULL) parameter_ptr ++;
// debug:
rt_kprintf("%s requested: \"%s\"\n", inet_ntoa(session->remote.sin_addr), buf);
//
//-----------------------
if(str_begin_with(buf, "USER")==0)
{
rt_kprintf("%s sent login \"%s\"\n", inet_ntoa(session->remote.sin_addr), parameter_ptr);
// login correct
if(strcmp(parameter_ptr, "anonymous") == 0)
{
session->is_anonymous = RT_TRUE;
rt_sprintf(sbuf, "331 Anonymous login OK send e-mail address for password.\r\n", parameter_ptr);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else if (strcmp(parameter_ptr, FTP_USER) == 0)
{
session->is_anonymous = RT_FALSE;
rt_sprintf(sbuf, "331 Password required for %s\r\n", parameter_ptr);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else
{
// incorrect login
rt_sprintf(sbuf, "530 Login incorrect. Bye.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
rt_free(sbuf);
return -1;
}
return 0;
}
else if(str_begin_with(buf, "PASS")==0)
{
rt_kprintf("%s sent password \"%s\"\n", inet_ntoa(session->remote.sin_addr), parameter_ptr);
if (strcmp(parameter_ptr, FTP_PASSWORD)==0 ||
session->is_anonymous == RT_TRUE)
{
// password correct
rt_sprintf(sbuf, "230 User logged in.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
rt_free(sbuf);
return 0;
}
// incorrect password
rt_sprintf(sbuf, "530 Login or Password incorrect. Bye!\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
rt_free(sbuf);
return -1;
}
else if(str_begin_with(buf, "LIST")==0 )
{
memset(sbuf,0,FTP_BUFFER_SIZE);
open_data_connection(session);
rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
do_list(session->currentdir, session->pasv_sockfd);
close_data_connection(session);
session->pasv_active = 0;
rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else if(str_begin_with(buf, "NLST")==0 )
{
memset(sbuf, 0, FTP_BUFFER_SIZE);
rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
open_data_connection(session);
do_simple_list(session->currentdir, session->pasv_sockfd);
close_data_connection(session);
session->pasv_active = 0;
rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else if(str_begin_with(buf, "PWD")==0 || str_begin_with(buf, "XPWD")==0)
{
rt_sprintf(sbuf, "257 \"%s\" is current directory.\r\n", session->currentdir);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else if(str_begin_with(buf, "TYPE")==0)
{
// Ignore it
if(strcmp(parameter_ptr, "I")==0)
{
rt_sprintf(sbuf, "200 Type set to binary.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else
{
rt_sprintf(sbuf, "200 Type set to ascii.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
}
else if(str_begin_with(buf, "PASV")==0)
{
int dig1, dig2;
//int sockfd;
int optval=1;
int port;
struct sockaddr_in data;
socklen_t len = sizeof(struct sockaddr);
char *msg, *p;
if (session->pasv_sockfd > 0) {
closesocket(session->pasv_sockfd);
session->pasv_sockfd = -1;
}
if (session->pasv_listen_sockfd > 0)
closesocket(session->pasv_listen_sockfd);
session->pasv_port = 10000;
session->pasv_active = 1;
local.sin_port=htons(session->pasv_port);
local.sin_addr.s_addr=INADDR_ANY;
dig1 = (int)(session->pasv_port/256);
dig2 = session->pasv_port % 256;
FD_ZERO(&readfds);
if((session->pasv_listen_sockfd=socket(PF_INET, SOCK_STREAM, 0))==-1)
{
rt_sprintf(sbuf, "425 Can't open data connection0.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
goto err1;
}
if(setsockopt(session->pasv_listen_sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1)
{
rt_sprintf(sbuf, "425 Can't open data connection1.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
goto err1;
}
if(bind(session->pasv_listen_sockfd, (struct sockaddr *)&local, addr_len)==-1)
{
rt_sprintf(sbuf, "425 Can't open data connection2.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
goto err1;
}
if(listen(session->pasv_listen_sockfd, 1)==-1)
{
rt_sprintf(sbuf, "425 Can't open data connection3.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
goto err1;
}
if (-1 == getsockname(session->pasv_listen_sockfd, (struct sockaddr *)&data, &len)) {
rt_kprintf("Cannot determine our address, need it if client should connect to us\n");
goto err1;
}
port = ntohs(data.sin_port);
rt_kprintf("Port %d\n", port);
/* Convert server IP address and port to comma separated list */
msg = strdup(session->serveraddr);
if (!msg) {
rt_sprintf(sbuf, "426 Internal server error.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
goto err1;
}
p = msg;
while ((p = strchr(p, '.')))
*p++ = ',';
rt_kprintf("Listening %d seconds @ port %d\n", tv.tv_sec, session->pasv_port);
rt_sprintf(sbuf, "227 Entering passive mode (%s,%d,%d)\r\n", msg, port / 256, port % 256);
send(session->sockfd, sbuf, strlen(sbuf), 0);
rt_free(sbuf);
rt_free(msg);
return 0;
#if 0
FD_SET(sockfd, &readfds);
select(0, &readfds, 0, 0, &tv);
if(FD_ISSET(sockfd, &readfds))
{
if((session->pasv_sockfd = accept(sockfd, (struct sockaddr*)&pasvremote, &addr_len))==-1)
{
rt_sprintf(sbuf, "425 Can't open data connection4.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
goto err1;
}
else
{
rt_kprintf("Got Data(PASV) connection from %s\n", inet_ntoa(pasvremote.sin_addr));
session->pasv_active = 1;
closesocket(sockfd);
}
}
else
{
err1:
closesocket(session->pasv_sockfd);
session->pasv_active = 0;
rt_free(sbuf);
return 0;
}
#endif
err1:
close_data_connection(session);
session->pasv_active = 0;
rt_free(sbuf);
rt_free(msg);
return 0;
}
else if (str_begin_with(buf, "RETR")==0)
{
int file_size;
open_data_connection(session);
strcpy(filename, buf + 5);
build_full_path(session, parameter_ptr, filename, 256);
file_size = ftp_get_filesize(filename);
if (file_size == -1)
{
rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
session->offset=0;
close_data_connection(session);
rt_free(sbuf);
return 0;
}
fd = open(filename, O_RDONLY, 0);
if (fd < 0)
{
close_data_connection(session);
rt_free(sbuf);
return 0;
}
if(session->offset>0 && session->offset < file_size)
{
lseek(fd, session->offset, SEEK_SET);
rt_sprintf(sbuf, "150 Opening binary mode data connection for partial \"%s\" (%d/%d bytes).\r\n",
filename, file_size - session->offset, file_size);
}
else
{
rt_sprintf(sbuf, "150 Opening binary mode data connection for \"%s\" (%d bytes).\r\n", filename, file_size);
}
send(session->sockfd, sbuf, strlen(sbuf), 0);
while((numbytes = read(fd, sbuf, FTP_BUFFER_SIZE))>0)
{
send(session->pasv_sockfd, sbuf, numbytes, 0);
}
rt_sprintf(sbuf, "226 Finished.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
close(fd);
close_data_connection(session);
}
else if (str_begin_with(buf, "STOR")==0)
{
open_data_connection(session);
if(session->is_anonymous == RT_TRUE)
{
rt_sprintf(sbuf, "550 Permission denied.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
close_data_connection(session);
rt_free(sbuf);
return 0;
}
build_full_path(session, parameter_ptr, filename, 256);
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0);
if(fd < 0)
{
rt_sprintf(sbuf, "550 Cannot open \"%s\" for writing.\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
close_data_connection(session);
rt_free(sbuf);
return 0;
}
rt_sprintf(sbuf, "150 Opening binary mode data connection for \"%s\".\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
FD_ZERO(&readfds);
FD_SET(session->pasv_sockfd, &readfds);
rt_kprintf("Waiting %d seconds for data...\n", tv.tv_sec);
while(select(session->pasv_sockfd+1, &readfds, 0, 0, &tv)>0 )
{
if((numbytes=recv(session->pasv_sockfd, sbuf, FTP_BUFFER_SIZE, 0))>0)
{
write(fd, sbuf, numbytes);
}
else if(numbytes==0)
{
close(fd);
close_data_connection(session);
rt_sprintf(sbuf, "226 Finished.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
break;
}
else if(numbytes==-1)
{
close(fd);
close_data_connection(session);
rt_free(sbuf);
return -1;
}
}
close_data_connection(session);
}
else if(str_begin_with(buf, "SIZE")==0)
{
int file_size;
build_full_path(session, parameter_ptr, filename, 256);
file_size = ftp_get_filesize(filename);
if( file_size == -1)
{
rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else
{
rt_sprintf(sbuf, "213 %d\r\n", file_size);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
}
else if(str_begin_with(buf, "MDTM")==0)
{
rt_sprintf(sbuf, "550 \"/\" : not a regular file\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else if(str_begin_with(buf, "SYST")==0)
{
rt_sprintf(sbuf, "215 %s\r\n", "RT-Thread RTOS");
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else if(str_begin_with(buf, "CWD")==0)
{
build_full_path(session, parameter_ptr, filename, 256);
rt_sprintf(sbuf, "250 Changed to directory \"%s\"\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
strcpy(session->currentdir, filename);
rt_kprintf("Changed to directory %s", filename);
}
else if(str_begin_with(buf, "CDUP")==0)
{
rt_sprintf(filename, "%s/%s", session->currentdir, "..");
rt_sprintf(sbuf, "250 Changed to directory \"%s\"\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
strcpy(session->currentdir, filename);
rt_kprintf("Changed to directory %s", filename);
}
else if(str_begin_with(buf, "PORT")==0)
{
int i;
int portcom[6];
char tmpip[100];
i=0;
portcom[i++]=atoi(strtok(parameter_ptr, ".,;()"));
for(;i<6;i++)
portcom[i]=atoi(strtok(0, ".,;()"));
rt_sprintf(tmpip, "%d.%d.%d.%d", portcom[0], portcom[1], portcom[2], portcom[3]);
FD_ZERO(&readfds);
if((session->pasv_sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1)
{
rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
closesocket(session->pasv_sockfd);
session->pasv_active = 0;
rt_free(sbuf);
return 0;
}
pasvremote.sin_addr.s_addr=inet_addr(tmpip);
pasvremote.sin_port=htons(portcom[4] * 256 + portcom[5]);
pasvremote.sin_family=PF_INET;
if(connect(session->pasv_sockfd, (struct sockaddr *)&pasvremote, addr_len)==-1)
{
// is it only local address?try using gloal ip addr
pasvremote.sin_addr=session->remote.sin_addr;
if(connect(session->pasv_sockfd, (struct sockaddr *)&pasvremote, addr_len)==-1)
{
rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
closesocket(session->pasv_sockfd);
rt_free(sbuf);
return 0;
}
}
session->pasv_active=1;
session->pasv_port = portcom[4] * 256 + portcom[5];
rt_kprintf("Connected to Data(PORT) %s @ %d\n", tmpip, portcom[4] * 256 + portcom[5]);
rt_sprintf(sbuf, "200 Port Command Successful.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else if(str_begin_with(buf, "REST")==0)
{
if(atoi(parameter_ptr)>=0)
{
session->offset=atoi(parameter_ptr);
rt_sprintf(sbuf, "350 Send RETR or STOR to start transfert.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
}
else if(str_begin_with(buf, "MKD")==0)
{
if (session->is_anonymous == RT_TRUE)
{
rt_sprintf(sbuf, "530 Permission denied.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
rt_free(sbuf);
return 0;
}
build_full_path(session, parameter_ptr, filename, 256);
if(mkdir(filename, 0) == -1)
{
rt_sprintf(sbuf, "550 File \"%s\" exists.\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else
{
rt_sprintf(sbuf, "257 directory \"%s\" successfully created.\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
}
else if(str_begin_with(buf, "DELE")==0)
{
if (session->is_anonymous == RT_TRUE)
{
rt_sprintf(sbuf, "530 Permission denied.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
rt_free(sbuf);
return 0;
}
build_full_path(session, parameter_ptr, filename, 256);
if(unlink(filename)==0)
rt_sprintf(sbuf, "250 Successfully deleted file \"%s\".\r\n", filename);
else
{
rt_sprintf(sbuf, "550 Not such file or directory: %s.\r\n", filename);
}
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else if(str_begin_with(buf, "RMD")==0)
{
if (session->is_anonymous == RT_TRUE)
{
rt_sprintf(sbuf, "530 Permission denied.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
rt_free(sbuf);
return 0;
}
build_full_path(session, parameter_ptr, filename, 256);
if(unlink(filename) == -1)
{
rt_sprintf(sbuf, "550 Directory \"%s\" doesn't exist.\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else
{
rt_sprintf(sbuf, "257 directory \"%s\" successfully deleted.\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
}
else if(str_begin_with(buf, "RNFR")==0)
{
if (session->is_anonymous == RT_TRUE)
{
rt_sprintf(sbuf, "530 Permission denied.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
rt_free(sbuf);
return 0;
}
build_full_path(session, parameter_ptr, filename, 256);
rt_sprintf(sbuf, "350 Successfully rececive old file \"%s\".\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else if(str_begin_with(buf, "RNTO")==0)
{
char new_filename[256];
if (session->is_anonymous == RT_TRUE)
{
rt_sprintf(sbuf, "530 Permission denied.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
rt_free(sbuf);
return 0;
}
build_full_path(session, parameter_ptr, new_filename, 256);
if(rename(filename, new_filename) == -1)
{
rt_sprintf(sbuf, "553 rename file \"%s\" error.\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else
{
rt_sprintf(sbuf, "250 Successfully rename to new file \"%s\".\r\n", filename);
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
}
else if((str_begin_with(buf, "NOOP")==0) || str_begin_with(buf, "noop")==0)
{
rt_sprintf(sbuf, "200 noop!\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
else if(str_begin_with(buf, "QUIT")==0)
{
rt_sprintf(sbuf, "221 Bye!\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
rt_free(sbuf);
return -1;
}
else
{
rt_sprintf(sbuf, "502 Not Implemented.\r\n");
send(session->sockfd, sbuf, strlen(sbuf), 0);
}
rt_free(sbuf);
return 0;
}
void ftpd_start()
{
rt_thread_t tid;
tid = rt_thread_create("ftpd",
ftpd_thread_entry, RT_NULL,
4096, 30, 5);
if (tid != RT_NULL) rt_thread_startup(tid);
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(ftpd_start, start ftp server);
#ifdef FINSH_USING_MSH
int cmd_ftpd_start(int argc, char** argv)
{
ftpd_start();
return 0;
}
FINSH_FUNCTION_EXPORT_ALIAS(cmd_ftpd_start, __cmd_ftpd_start, start ftp server.);
#endif
#endif

View File

@ -1,370 +0,0 @@
/**
* @file
* MetIO Server
*
*/
/*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwip/opt.h"
#if LWIP_TCP
#include "lwip/tcp.h"
/*
* This implements a netio server.
* The client sends a command word (4 bytes) then a data length word (4 bytes).
* If the command is "receive", the server is to consume "data length" bytes into
* a circular buffer until the first byte is non-zero, then it is to consume
* another command/data pair.
* If the command is "send", the server is to send "data length" bytes from a circular
* buffer with the first byte being zero, until "some time" (6 seconds in the
* current netio126.zip download) has passed and then send one final buffer with
* the first byte being non-zero. Then it is to consume another command/data pair.
*/
/* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */
/* implementation options */
#define NETIO_BUF_SIZE (4 * 1024)
#define NETIO_USE_STATIC_BUF 0
/* NetIO server state definition */
#define NETIO_STATE_WAIT_FOR_CMD 0
#define NETIO_STATE_RECV_DATA 1
#define NETIO_STATE_SEND_DATA 2
#define NETIO_STATE_SEND_DATA_LAST 3
#define NETIO_STATE_DONE 4
struct netio_state {
u32_t state;
u32_t cmd;
u32_t data_len;
u32_t cntr;
u8_t * buf_ptr;
u32_t buf_pos;
u32_t first_byte;
u32_t time_stamp;
};
/* NetIO command protocol definition */
#define NETIO_CMD_QUIT 0
#define NETIO_CMD_C2S 1
#define NETIO_CMD_S2C 2
#define NETIO_CMD_RES 3
static err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
static void
netio_close(void *arg, struct tcp_pcb *pcb)
{
err_t err;
struct netio_state *ns = arg;
ns->state = NETIO_STATE_DONE;
tcp_recv(pcb, NULL);
err = tcp_close(pcb);
if (err != ERR_OK) {
/* closing failed, try again later */
tcp_recv(pcb, netio_recv);
} else {
/* closing succeeded */
#if NETIO_USE_STATIC_BUF != 1
if(ns->buf_ptr != NULL){
mem_free(ns->buf_ptr);
}
#endif
tcp_arg(pcb, NULL);
tcp_poll(pcb, NULL, 0);
tcp_sent(pcb, NULL);
if (arg != NULL) {
mem_free(arg);
}
}
}
static err_t
netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
struct netio_state *ns = arg;
u8_t * data_ptr;
u32_t data_cntr;
struct pbuf *q = p;
u16_t len;
if (p != NULL) {
tcp_recved(pcb, p->tot_len);
}
if (err == ERR_OK && q != NULL) {
while (q != NULL) {
data_cntr = q->len;
data_ptr = q->payload;
while (data_cntr--) {
if (ns->state == NETIO_STATE_DONE){
netio_close(ns, pcb);
break;
} else if (ns->state == NETIO_STATE_WAIT_FOR_CMD) {
if (ns->cntr < 4) {
/* build up the CMD field */
ns->cmd <<= 8;
ns->cmd |= *data_ptr++;
ns->cntr++;
} else if (ns->cntr < 8) {
/* build up the DATA field */
ns->data_len <<= 8;
ns->data_len |= *data_ptr++;
ns->cntr++;
if (ns->cntr == 8) {
/* now we have full command and data words */
ns->cntr = 0;
ns->buf_pos = 0;
ns->buf_ptr[0] = 0;
if (ns->cmd == NETIO_CMD_C2S) {
ns->state = NETIO_STATE_RECV_DATA;
} else if (ns->cmd == NETIO_CMD_S2C) {
ns->state = NETIO_STATE_SEND_DATA;
/* start timer */
ns->time_stamp = rt_tick_get();
/* send first round of data */
len = tcp_sndbuf(pcb);
len = LWIP_MIN(len, ns->data_len - ns->cntr);
len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
do {
err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
if (err == ERR_MEM) {
len /= 2;
}
} while ((err == ERR_MEM) && (len > 1));
ns->buf_pos += len;
ns->cntr += len;
} else {
/* unrecognized command, punt */
ns->cntr = 0;
ns->buf_pos = 0;
ns->buf_ptr[0] = 0;
netio_close(ns, pcb);
break;
}
}
} else {
/* in trouble... shouldn't be in this state! */
}
} else if (ns->state == NETIO_STATE_RECV_DATA) {
if(ns->cntr == 0){
/* save the first byte of this new round of data
* this will not match ns->buf_ptr[0] in the case that
* NETIO_BUF_SIZE is less than ns->data_len.
*/
ns->first_byte = *data_ptr;
}
ns->buf_ptr[ns->buf_pos++] = *data_ptr++;
ns->cntr++;
if (ns->buf_pos == NETIO_BUF_SIZE) {
/* circularize the buffer */
ns->buf_pos = 0;
}
if(ns->cntr == ns->data_len){
ns->cntr = 0;
if (ns->first_byte != 0) {
/* if this last round did not start with 0,
* go look for another command */
ns->state = NETIO_STATE_WAIT_FOR_CMD;
ns->data_len = 0;
ns->cmd = 0;
/* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
} else {
/* stay here and wait on more data */
}
}
} else if (ns->state == NETIO_STATE_SEND_DATA
|| ns->state == NETIO_STATE_SEND_DATA_LAST) {
/* I don't think this should happen... */
} else {
/* done / quit */
netio_close(ns, pcb);
break;
} /* end of ns->state condition */
} /* end of while data still in this pbuf */
q = q->next;
}
pbuf_free(p);
} else {
/* error or closed by other side */
if (p != NULL) {
pbuf_free(p);
}
/* close the connection */
netio_close(ns, pcb);
}
return ERR_OK;
}
static err_t
netio_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
struct netio_state *ns = arg;
err_t err = ERR_OK;
if (ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA) {
/* done with this round of sending */
ns->buf_pos = 0;
ns->cntr = 0;
/* check if timer expired */
if (rt_tick_get() - ns->time_stamp > 600) {
ns->buf_ptr[0] = 1;
ns->state = NETIO_STATE_SEND_DATA_LAST;
} else {
ns->buf_ptr[0] = 0;
}
}
if(ns->state == NETIO_STATE_SEND_DATA_LAST || ns->state == NETIO_STATE_SEND_DATA){
len = tcp_sndbuf(pcb);
len = LWIP_MIN(len, ns->data_len - ns->cntr);
len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
if(ns->cntr < ns->data_len){
do {
err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
if (err == ERR_MEM) {
len /= 2;
}
} while ((err == ERR_MEM) && (len > 1));
ns->buf_pos += len;
if(ns->buf_pos >= NETIO_BUF_SIZE){
ns->buf_pos = 0;
}
ns->cntr += len;
}
}
if(ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA_LAST){
/* we have buffered up all our data to send this last round, go look for a command */
ns->state = NETIO_STATE_WAIT_FOR_CMD;
ns->cntr = 0;
/* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
}
return ERR_OK;
}
static err_t
netio_poll(void *arg, struct tcp_pcb *pcb)
{
struct netio_state * ns = arg;
if(ns->state == NETIO_STATE_SEND_DATA){
} else if(ns->state == NETIO_STATE_DONE){
netio_close(ns, pcb);
}
return ERR_OK;
}
#if NETIO_USE_STATIC_BUF == 1
static u8_t netio_buf[NETIO_BUF_SIZE];
#endif
static err_t
netio_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct netio_state * ns;
LWIP_UNUSED_ARG(err);
ns = mem_malloc(sizeof(struct netio_state));
if(ns == NULL){
return ERR_MEM;
}
ns->state = NETIO_STATE_WAIT_FOR_CMD;
ns->data_len = 0;
ns->cmd = 0;
ns->cntr = 0;
ns->buf_pos = 0;
#if NETIO_USE_STATIC_BUF == 1
ns->buf_ptr = netio_buf;
#else
ns->buf_ptr = mem_malloc(NETIO_BUF_SIZE);
if(ns->buf_ptr == NULL){
mem_free(ns);
return ERR_MEM;
}
#endif
ns->buf_ptr[0] = 0;
tcp_arg(pcb, ns);
tcp_sent(pcb, netio_sent);
tcp_recv(pcb, netio_recv);
tcp_poll(pcb, netio_poll, 4); /* every 2 seconds */
return ERR_OK;
}
void netio_init(void)
{
struct tcp_pcb *pcb;
pcb = tcp_new();
tcp_bind(pcb, IP_ADDR_ANY, 18767);
pcb = tcp_listen(pcb);
tcp_accept(pcb, netio_accept);
}
#endif /* LWIP_TCP */
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(netio_init, netio server);
#endif

View File

@ -1,180 +0,0 @@
/*
* netutils: ping implementation
*/
#include "lwip/opt.h"
#include "lwip/mem.h"
#include "lwip/icmp.h"
#include "lwip/netif.h"
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include "lwip/inet.h"
#include "lwip/inet_chksum.h"
#include "lwip/ip.h"
/**
* PING_DEBUG: Enable debugging for PING.
*/
#ifndef PING_DEBUG
#define PING_DEBUG LWIP_DBG_ON
#endif
/** ping receive timeout - in milliseconds */
#define PING_RCV_TIMEO 1000
/** ping delay - in milliseconds */
#define PING_DELAY 100
/** ping identifier - must fit on a u16_t */
#ifndef PING_ID
#define PING_ID 0xAFAF
#endif
/** ping additional data size to include in the packet */
#ifndef PING_DATA_SIZE
#define PING_DATA_SIZE 32
#endif
/* ping variables */
static u16_t ping_seq_num;
struct _ip_addr
{
rt_uint8_t addr0, addr1, addr2, addr3;
};
/** Prepare a echo ICMP request */
static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
{
size_t i;
size_t data_len = len - sizeof(struct icmp_echo_hdr);
ICMPH_TYPE_SET(iecho, ICMP_ECHO);
ICMPH_CODE_SET(iecho, 0);
iecho->chksum = 0;
iecho->id = PING_ID;
iecho->seqno = htons(++ping_seq_num);
/* fill the additional data buffer with some data */
for(i = 0; i < data_len; i++)
{
((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
}
iecho->chksum = inet_chksum(iecho, len);
}
/* Ping using the socket ip */
static err_t ping_send(int s, struct ip_addr *addr, int size)
{
int err;
struct icmp_echo_hdr *iecho;
struct sockaddr_in to;
size_t ping_size = sizeof(struct icmp_echo_hdr) + size;
LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
iecho = rt_malloc(ping_size);
if (iecho == RT_NULL)
{
return ERR_MEM;
}
ping_prepare_echo(iecho, (u16_t)ping_size);
to.sin_len = sizeof(to);
to.sin_family = AF_INET;
to.sin_addr.s_addr = addr->addr;
err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to));
rt_free(iecho);
return (err ? ERR_OK : ERR_VAL);
}
static void ping_recv(int s)
{
char buf[64];
int fromlen, len;
struct sockaddr_in from;
struct ip_hdr *iphdr;
struct icmp_echo_hdr *iecho;
struct _ip_addr *addr;
while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0)
{
if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr)))
{
addr = (struct _ip_addr *)&(from.sin_addr);
rt_kprintf("ping: recv %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
iphdr = (struct ip_hdr *)buf;
iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4));
if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)))
{
return;
}
else
{
rt_kprintf("ping: drop\n");
}
}
}
if (len <= 0)
{
rt_kprintf("ping: timeout\n");
}
}
rt_err_t ping(char* target, rt_uint32_t time, rt_size_t size)
{
int s;
int timeout = PING_RCV_TIMEO;
struct ip_addr ping_target;
rt_uint32_t send_time;
struct _ip_addr
{
rt_uint8_t addr0, addr1, addr2, addr3;
} *addr;
send_time = 0;
if(size == 0)
size = PING_DATA_SIZE;
if (inet_aton(target, (struct in_addr*)&ping_target) == 0) return -RT_ERROR;
addr = (struct _ip_addr*)&ping_target;
if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0)
{
rt_kprintf("create socket failled\n");
return -RT_ERROR;
}
lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
while (1)
{
if (ping_send(s, &ping_target, size) == ERR_OK)
{
rt_kprintf("ping: send %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
ping_recv(s);
}
else
{
rt_kprintf("ping: send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
}
send_time ++;
if (send_time >= time) break; /* send ping times reached, stop */
rt_thread_delay(PING_DELAY); /* take a delay */
}
lwip_close(s);
return RT_EOK;
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(ping, ping network host);
#endif

View File

@ -1,213 +0,0 @@
/**
* @file
* SNTP client module
*
*/
/*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include <string.h>
#include <time.h>
/** This is an example of a "SNTP" client (with socket API).
*
* For a list of some public NTP servers, see this link :
* http://support.ntp.org/bin/view/Servers/NTPPoolServers
*
*/
/**
* SNTP_DEBUG: Enable debugging for SNTP.
*/
#ifndef SNTP_DEBUG
#define SNTP_DEBUG LWIP_DBG_ON
#endif
/** SNTP server port */
#ifndef SNTP_PORT
#define SNTP_PORT 123
#endif
/** SNTP server address as IPv4 address in "u32_t" format */
#ifndef SNTP_SERVER_ADDRESS
#define SNTP_SERVER_ADDRESS inet_addr("213.161.194.93") /* pool.ntp.org */
#endif
/** SNTP receive timeout - in milliseconds */
#ifndef SNTP_RECV_TIMEOUT
#define SNTP_RECV_TIMEOUT 3000
#endif
/** SNTP update delay - in milliseconds */
#ifndef SNTP_UPDATE_DELAY
#define SNTP_UPDATE_DELAY 60000
#endif
/** SNTP macro to change system time and/or the update the RTC clock */
#ifndef SNTP_SYSTEM_TIME
#define SNTP_SYSTEM_TIME(t)
#endif
/* SNTP protocol defines */
#define SNTP_MAX_DATA_LEN 48
#define SNTP_RCV_TIME_OFS 32
#define SNTP_LI_NO_WARNING 0x00
#define SNTP_VERSION (4/* NTP Version 4*/<<3)
#define SNTP_MODE_CLIENT 0x03
#define SNTP_MODE_SERVER 0x04
#define SNTP_MODE_BROADCAST 0x05
#define SNTP_MODE_MASK 0x07
/* number of seconds between 1900 and 1970 */
#define DIFF_SEC_1900_1970 (2208988800)
/**
* SNTP processing
*/
static void sntp_process( time_t t)
{
/* change system time and/or the update the RTC clock */
SNTP_SYSTEM_TIME(t);
/* display local time from GMT time */
LWIP_DEBUGF( SNTP_DEBUG, ("sntp_process: %s", ctime(&t)));
}
/**
* SNTP request
*/
static void sntp_request()
{
int sock;
struct sockaddr_in local;
struct sockaddr_in to;
int tolen;
int size;
int timeout;
u8_t sntp_request [SNTP_MAX_DATA_LEN];
u8_t sntp_response[SNTP_MAX_DATA_LEN];
u32_t sntp_server_address;
u32_t timestamp;
time_t t;
/* initialize SNTP server address */
sntp_server_address = SNTP_SERVER_ADDRESS;
/* if we got a valid SNTP server address... */
if (sntp_server_address!=0)
{
/* create new socket */
sock = socket( AF_INET, SOCK_DGRAM, 0);
if (sock>=0)
{
/* prepare local address */
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(INADDR_ANY);
local.sin_addr.s_addr = htonl(INADDR_ANY);
/* bind to local address */
if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0)
{
/* set recv timeout */
timeout = SNTP_RECV_TIMEOUT;
setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
/* prepare SNTP request */
memset( sntp_request, 0, sizeof(sntp_request));
sntp_request[0] = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
/* prepare SNTP server address */
memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_port = htons(SNTP_PORT);
to.sin_addr.s_addr = sntp_server_address;
/* send SNTP request to server */
if (sendto( sock, sntp_request, sizeof(sntp_request), 0, (struct sockaddr *)&to, sizeof(to))>=0)
{
/* receive SNTP server response */
tolen = sizeof(to);
size = recvfrom( sock, sntp_response, sizeof(sntp_response), 0, (struct sockaddr *)&to, (socklen_t *)&tolen);
/* if the response size is good */
if (size == SNTP_MAX_DATA_LEN)
{
/* if this is a SNTP response... */
if (((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_SERVER) || ((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_BROADCAST))
{
/* extract GMT time from response */
SMEMCPY( &timestamp, (sntp_response+SNTP_RCV_TIME_OFS), sizeof(timestamp));
t = (ntohl(timestamp) - DIFF_SEC_1900_1970);
/* do time processing */
sntp_process(t);
}
else
{
LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not response frame code\n"));
}
}
else
{
LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not recvfrom==%i\n", errno));
}
}
else
{
LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not sendto==%i\n", errno));
}
}
/* close the socket */
closesocket(sock);
}
}
}
/**
* SNTP thread
*/
static void
sntp_thread(void *arg)
{
LWIP_UNUSED_ARG(arg);
while(1)
{
sntp_request();
sys_msleep(SNTP_UPDATE_DELAY);
}
}
void sntp_init(void)
{
sys_thread_new("sntp_thread", sntp_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
}

View File

@ -1,68 +0,0 @@
#include <lwip/api.h>
#define TCP_ECHO_PORT 7
void tcpecho_entry(void *parameter)
{
struct netconn *conn, *newconn;
err_t err;
/* Create a new connection identifier. */
conn = netconn_new(NETCONN_TCP);
/* Bind connection to well known port number 7. */
netconn_bind(conn, NULL, TCP_ECHO_PORT);
/* Tell connection to go into listening mode. */
netconn_listen(conn);
while(1)
{
/* Grab new connection. */
err = netconn_accept(conn, &newconn);
/* Process the new connection. */
if(err == ERR_OK)
{
struct netbuf *buf;
void *data;
u16_t len;
while(netconn_recv(newconn, &buf) == ERR_OK)
{
do
{
netbuf_data(buf, &data, &len);
err = netconn_write(newconn, data, len, NETCONN_COPY);
if(err != ERR_OK){}
}
while(netbuf_next(buf) >= 0);
netbuf_delete(buf);
}
/* Close connection and discard connection identifier. */
netconn_delete(newconn);
}
}
}
#ifdef RT_USING_FINSH
#include <finsh.h>
static rt_thread_t echo_tid = RT_NULL;
void tcpecho(rt_uint32_t startup)
{
if (startup && echo_tid == RT_NULL)
{
echo_tid = rt_thread_create("echo",
tcpecho_entry, RT_NULL,
512, 30, 5);
if (echo_tid != RT_NULL)
rt_thread_startup(echo_tid);
}
else
{
if (echo_tid != RT_NULL)
rt_thread_delete(echo_tid); /* delete thread */
echo_tid = RT_NULL;
}
}
FINSH_FUNCTION_EXPORT(tcpecho, startup or stop TCP echo server);
#endif

View File

@ -1,206 +0,0 @@
#include <rtthread.h>
#include <dfs_posix.h>
#include <lwip/sockets.h>
#include <finsh.h>
#define TFTP_PORT 69
/* opcode */
#define TFTP_RRQ 1 /* read request */
#define TFTP_WRQ 2 /* write request */
#define TFTP_DATA 3 /* data */
#define TFTP_ACK 4 /* ACK */
#define TFTP_ERROR 5 /* error */
rt_uint8_t tftp_buffer[512 + 4];
/* tftp client */
void tftp_get(const char* host, const char* dir, const char* filename)
{
int fd, sock_fd, sock_opt;
struct sockaddr_in tftp_addr, from_addr;
rt_uint32_t length;
socklen_t fromlen;
/* make local file name */
rt_snprintf((char*)tftp_buffer, sizeof(tftp_buffer),
"%s/%s", dir, filename);
/* open local file for write */
fd = open((char*)tftp_buffer, O_RDWR | O_CREAT, 0);
if (fd < 0)
{
rt_kprintf("can't open local filename\n");
return;
}
/* connect to tftp server */
inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr));
tftp_addr.sin_family = AF_INET;
tftp_addr.sin_port = htons(TFTP_PORT);
sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if (sock_fd < 0)
{
close(fd);
rt_kprintf("can't create a socket\n");
return ;
}
/* set socket option */
sock_opt = 5000; /* 5 seconds */
lwip_setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt));
/* make tftp request */
tftp_buffer[0] = 0; /* opcode */
tftp_buffer[1] = TFTP_RRQ; /* RRQ */
length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2;
tftp_buffer[length] = 0; length ++;
length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet");
tftp_buffer[length] = 0; length ++;
fromlen = sizeof(struct sockaddr_in);
/* send request */
lwip_sendto(sock_fd, tftp_buffer, length, 0,
(struct sockaddr *)&tftp_addr, fromlen);
do
{
length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0,
(struct sockaddr *)&from_addr, &fromlen);
if (length > 0)
{
write(fd, (char*)&tftp_buffer[4], length - 4);
rt_kprintf("#");
/* make ACK */
tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_ACK; /* opcode */
/* send ACK */
lwip_sendto(sock_fd, tftp_buffer, 4, 0,
(struct sockaddr *)&from_addr, fromlen);
}
} while (length == 516);
if (length == 0) rt_kprintf("timeout\n");
else rt_kprintf("done\n");
close(fd);
lwip_close(sock_fd);
}
FINSH_FUNCTION_EXPORT(tftp_get, get file from tftp server);
void tftp_put(const char* host, const char* dir, const char* filename)
{
int fd, sock_fd, sock_opt;
struct sockaddr_in tftp_addr, from_addr;
rt_uint32_t length, block_number = 0;
socklen_t fromlen;
/* make local file name */
rt_snprintf((char*)tftp_buffer, sizeof(tftp_buffer),
"%s/%s", dir, filename);
/* open local file for write */
fd = open((char*)tftp_buffer, O_RDONLY, 0);
if (fd < 0)
{
rt_kprintf("can't open local filename\n");
return;
}
/* connect to tftp server */
inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr));
tftp_addr.sin_family = AF_INET;
tftp_addr.sin_port = htons(TFTP_PORT);
sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if (sock_fd < 0)
{
close(fd);
rt_kprintf("can't create a socket\n");
return ;
}
/* set socket option */
sock_opt = 5000; /* 5 seconds */
lwip_setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt));
/* make tftp request */
tftp_buffer[0] = 0; /* opcode */
tftp_buffer[1] = TFTP_WRQ; /* WRQ */
length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2;
tftp_buffer[length] = 0; length ++;
length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet");
tftp_buffer[length] = 0; length ++;
fromlen = sizeof(struct sockaddr_in);
/* send request */
lwip_sendto(sock_fd, tftp_buffer, length, 0,
(struct sockaddr *)&tftp_addr, fromlen);
/* wait ACK 0 */
length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0,
(struct sockaddr *)&from_addr, &fromlen);
if (!(tftp_buffer[0] == 0 &&
tftp_buffer[1] == TFTP_ACK &&
tftp_buffer[2] == 0 &&
tftp_buffer[3] == 0))
{
rt_kprintf("tftp server error\n");
close(fd);
return;
}
block_number = 1;
while (1)
{
length = read(fd, (char*)&tftp_buffer[4], 512);
if (length > 0)
{
/* make opcode and block number */
tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_DATA;
tftp_buffer[2] = (block_number >> 8) & 0xff;
tftp_buffer[3] = block_number & 0xff;
lwip_sendto(sock_fd, tftp_buffer, length + 4, 0,
(struct sockaddr *)&from_addr, fromlen);
}
else
{
rt_kprintf("done\n");
break; /* no data yet */
}
/* receive ack */
length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0,
(struct sockaddr *)&from_addr, &fromlen);
if (length > 0)
{
if ((tftp_buffer[0] == 0 &&
tftp_buffer[1] == TFTP_ACK &&
tftp_buffer[2] == (block_number >> 8) & 0xff) &&
tftp_buffer[3] == (block_number & 0xff))
{
block_number ++;
rt_kprintf("#");
}
else
{
rt_kprintf("server respondes with an error\n");
break;
}
}
else if (length == 0)
{
rt_kprintf("server timeout\n");
break;
}
}
close(fd);
lwip_close(sock_fd);
}
FINSH_FUNCTION_EXPORT(tftp_put, put file to tftp server);

View File

@ -1,56 +0,0 @@
#include <lwip/api.h>
#define UDP_ECHO_PORT 7
void udpecho_entry(void *parameter)
{
struct netconn *conn;
struct netbuf *buf;
struct ip_addr *addr;
unsigned short port;
conn = netconn_new(NETCONN_UDP);
netconn_bind(conn, IP_ADDR_ANY, 7);
while(1)
{
/* received data to buffer */
netconn_recv(conn, &buf);
addr = netbuf_fromaddr(buf);
port = netbuf_fromport(buf);
/* send the data to buffer */
netconn_connect(conn, addr, port);
/* reset address, and send to client */
buf->addr = *IP_ADDR_ANY;
netconn_send(conn, buf);
/* release buffer */
netbuf_delete(buf);
}
}
#ifdef RT_USING_FINSH
#include <finsh.h>
static rt_thread_t echo_tid = RT_NULL;
void udpecho(rt_uint32_t startup)
{
if (startup && echo_tid == RT_NULL)
{
echo_tid = rt_thread_create("uecho",
udpecho_entry, RT_NULL,
512, 30, 5);
if (echo_tid != RT_NULL)
rt_thread_startup(echo_tid);
}
else
{
if (echo_tid != RT_NULL)
rt_thread_delete(echo_tid); /* delete thread */
echo_tid = RT_NULL;
}
}
FINSH_FUNCTION_EXPORT(udpecho, startup or stop UDP echo server);
#endif

View File

@ -1,6 +0,0 @@
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.
snmp_agent.txt - The documentation for the lwIP SNMP agent.
sys_arch.txt - The documentation for a system abstraction layer of lwIP.

View File

@ -1,63 +0,0 @@
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 CVS 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 prefered 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. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two)
can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded
as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead
for reporting a compiler warning fix.
6. 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 CVS access to submit and maintain your port in the contrib CVS module.

View File

@ -1,505 +0,0 @@
Raw TCP/IP interface for lwIP
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
lwIP provides three Application Program's Interfaces (APIs) for programs
to use for communication with the TCP/IP code:
* low-level "core" / "callback" or "raw" API.
* higher-level "sequential" API.
* BSD-style socket API.
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).
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.
** Threading
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"). The raw API may only be used from
this thread! 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
- 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 SYS_LIGHTWEIGHT_PROT and/or
semaphores.
Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1
and 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).
** The remainder of this document discusses the "raw" API. **
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.
Both 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.
--- Callbacks
Program execution is driven by callbacks. 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 function for setting the application connection state is:
- void tcp_arg(struct tcp_pcb *pcb, void *arg)
Specifies the program specific state that should be passed to all
other callback functions. The "pcb" argument is the current TCP
connection control block, and the "arg" argument is the argument
that will be passed to the callbacks.
--- TCP connection setup
The functions used for setting up connections is similar to that of
the sequential API and of the BSD socket API. A new TCP connection
identifier (i.e., a protocol control block - PCB) is created with the
tcp_new() function. This PCB can then be either set to listen for new
incoming connections or be explicitly connected to another host.
- struct tcp_pcb *tcp_new(void)
Creates a new connection identifier (PCB). If memory is not
available for creating the new pcb, NULL is returned.
- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port)
Binds the pcb to a local IP address and port number. The IP address
can be specified as IP_ADDR_ANY in order to bind the connection to
all local IP addresses.
If another connection is bound to the same port, the function will
return ERR_USE, otherwise ERR_OK is returned.
- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)
Commands a pcb to start listening for incoming connections. When an
incoming connection is accepted, the function specified with the
tcp_accept() function will be called. The pcb will have to be bound
to a local port with the tcp_bind() function.
The tcp_listen() function returns a new connection identifier, and
the one passed as an argument to the function will be
deallocated. The reason for this behavior is that less memory is
needed for a connection that is listening, so tcp_listen() will
reclaim the memory needed for the original connection and allocate a
new smaller memory block for the listening connection.
tcp_listen() may return NULL if no memory was available for the
listening connection. If so, the memory associated with the pcb
passed as an argument to tcp_listen() will not be deallocated.
- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
Same as tcp_listen, but limits the number of outstanding connections
in the listen queue to the value specified by the backlog argument.
To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.
- void tcp_accepted(struct tcp_pcb *pcb)
Inform lwIP that an incoming connection has been accepted. This would
usually be called from the accept callback. This allows lwIP to perform
housekeeping tasks, such as allowing further incoming connections to be
queued in the listen backlog.
- void tcp_accept(struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
err_t err))
Specified the callback function that should be called when a new
connection arrives on a listening connection.
- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port, err_t (* connected)(void *arg,
struct tcp_pcb *tpcb,
err_t err));
Sets up the pcb to connect to the remote host and sends the
initial SYN segment which opens the connection.
The tcp_connect() function returns immediately; it does not wait for
the connection to be properly setup. Instead, it will call the
function specified as the fourth argument (the "connected" argument)
when the connection is established. If the connection could not be
properly established, either because the other host refused the
connection or because the other host didn't answer, the "err"
callback function of this pcb (registered with tcp_err, see below)
will be called.
The tcp_connect() function can return ERR_MEM if no memory is
available for enqueueing the SYN segment. If the SYN indeed was
enqueued successfully, the tcp_connect() function returns ERR_OK.
--- Sending TCP data
TCP data is sent by enqueueing the data with a call to
tcp_write(). When the data is successfully transmitted to the remote
host, the application will be notified with a call to a specified
callback function.
- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len,
u8_t copy)
Enqueues the data pointed to by the argument dataptr. The length of
the data is passed as the len parameter. The copy argument is either
0 or 1 and indicates whether the new memory should be allocated for
the data to be copied into. If the argument is 0, no new memory
should be allocated and the data should only be referenced by
pointer.
The tcp_write() function will fail and return ERR_MEM if the length
of the data exceeds the current send buffer size or if the length of
the queue of outgoing segment is larger than the upper limit defined
in lwipopts.h. The number of bytes available in the output queue can
be retrieved with the tcp_sndbuf() function.
The proper way to use this function is to call the function with at
most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,
the application should wait until some of the currently enqueued
data has been successfully received by the other host and try again.
- void tcp_sent(struct tcp_pcb *pcb,
err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
u16_t len))
Specifies the callback function that should be called when data has
successfully been received (i.e., acknowledged) by the remote
host. The len argument passed to the callback function gives the
amount bytes that was acknowledged by the last acknowledgment.
--- Receiving TCP data
TCP data reception is callback based - an application specified
callback function is called when new data arrives. When the
application has taken the data, it has to call the tcp_recved()
function to indicate that TCP can advertise increase the receive
window.
- void tcp_recv(struct tcp_pcb *pcb,
err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err))
Sets the callback function that will be called when new data
arrives. The callback function will be passed a NULL pbuf to
indicate that the remote host has closed the connection. If
there are no errors and the callback function is to return
ERR_OK, then it must free the pbuf. Otherwise, it must not
free the pbuf so that lwIP core code can store it.
- void tcp_recved(struct tcp_pcb *pcb, u16_t len)
Must be called when the application has received the data. The len
argument indicates the length of the received data.
--- Application polling
When a connection is idle (i.e., no data is either transmitted or
received), lwIP will repeatedly poll the application by calling a
specified callback function. This can be used either as a watchdog
timer for killing connections that have stayed idle for too long, or
as a method of waiting for memory to become available. For instance,
if a call to tcp_write() has failed because memory wasn't available,
the application may use the polling functionality to call tcp_write()
again when the connection has been idle for a while.
- void tcp_poll(struct tcp_pcb *pcb,
err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
u8_t interval)
Specifies the polling interval and the callback function that should
be called to poll the application. The interval is specified in
number of TCP coarse grained timer shots, which typically occurs
twice a second. An interval of 10 means that the application would
be polled every 5 seconds.
--- Closing and aborting connections
- err_t tcp_close(struct tcp_pcb *pcb)
Closes the connection. The function may return ERR_MEM if no memory
was available for closing the connection. If so, the application
should wait and try again either by using the acknowledgment
callback or the polling functionality. If the close succeeds, the
function returns ERR_OK.
The pcb is deallocated by the TCP code after a call to tcp_close().
- void tcp_abort(struct tcp_pcb *pcb)
Aborts the connection by sending a RST (reset) segment to the remote
host. The pcb is deallocated. This function never fails.
ATTENTION: When calling this from one of the TCP callbacks, make
sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
or you will risk accessing deallocated memory or memory leaks!
If a connection is aborted because of an error, the application is
alerted of this event by the err callback. Errors that might abort a
connection are when there is a shortage of memory. The callback
function to be called is set using the tcp_err() function.
- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,
err_t err))
The error callback function does not get the pcb passed to it as a
parameter since the pcb may already have been deallocated.
--- Lower layer TCP interface
TCP provides a simple interface to the lower layers of the
system. During system initialization, the function tcp_init() has
to be called before any other TCP function is called. When the system
is running, the two timer functions tcp_fasttmr() and tcp_slowtmr()
must be called with regular intervals. The tcp_fasttmr() should be
called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and
tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds.
--- UDP interface
The UDP interface is similar to that of TCP, but due to the lower
level of complexity of UDP, the interface is significantly simpler.
- struct udp_pcb *udp_new(void)
Creates a new UDP pcb which can be used for UDP communication. The
pcb is not active until it has either been bound to a local address
or connected to a remote address.
- void udp_remove(struct udp_pcb *pcb)
Removes and deallocates the pcb.
- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port)
Binds the pcb to a local address. The IP-address argument "ipaddr"
can be IP_ADDR_ANY to indicate that it should listen to any local IP
address. The function currently always return ERR_OK.
- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port)
Sets the remote end of the pcb. This function does not generate any
network traffic, but only set the remote address of the pcb.
- err_t udp_disconnect(struct udp_pcb *pcb)
Remove the remote end of the pcb. This function does not generate
any network traffic, but only removes the remote address of the pcb.
- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
Sends the pbuf p. The pbuf is not deallocated.
- void udp_recv(struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb,
struct pbuf *p,
struct ip_addr *addr,
u16_t port),
void *recv_arg)
Specifies a callback function that should be called when a UDP
datagram is received.
--- System initalization
A truly complete and generic sequence for initializing the lwip stack
cannot be given because it depends on the build configuration (lwipopts.h)
and 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:
- stats_init()
Clears the structure where runtime statistics are gathered.
- sys_init()
Not of much use since we set the NO_SYS 1 option in lwipopts.h,
to be called for easy configuration changes.
- mem_init()
Initializes the dynamic memory heap defined by MEM_SIZE.
- memp_init()
Initializes the memory pools defined by MEMP_NUM_x.
- pbuf_init()
Initializes the pbuf memory pool defined by PBUF_POOL_SIZE.
- etharp_init()
Initializes the ARP table and queue.
Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval
after this initialization.
- ip_init()
Doesn't do much, it should be called to handle future changes.
- udp_init()
Clears the UDP PCB list.
- tcp_init()
Clears the TCP PCB list and clears some internal TCP timers.
Note: you must call tcp_fasttmr() and tcp_slowtmr() at the
predefined regular intervals after this initialization.
- netif_add(struct netif *netif, struct ip_addr *ipaddr,
struct ip_addr *netmask, struct ip_addr *gw,
void *state, err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, 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 it's use.
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;
}
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_up(struct netif *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.
Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
the predefined regular intervals after starting the client.
You can peek in the netif->dhcp struct for the actual DHCP status.
--- Optimalization 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_PLATFORM_BYTESWAP 1
#define LWIP_PLATFORM_HTONS(x) <your_htons>
#define LWIP_PLATFORM_HTONL(x) <your_htonl>
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.
For more optimization hints take a look at the lwIP wiki.
--- Zero-copy MACs
To achieve zero-copy on transmit, the data passed to the raw API must
remain unchanged until sent. Because the send- (or write-)functions return
when the packets have been enqueued for sending, data must be kept stable
after that, too.
This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions
must *not* be reused by the application unless their ref-count is 1.
For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too,
but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while
PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change).
Also, data passed to tcp_write without the copy-flag must not be changed!
Therefore, be careful which type of PBUF you use and if you copy TCP data
or not!

View File

@ -1,135 +0,0 @@
Daily Use Guide for using Savannah for lwIP
Table of Contents:
1 - Obtaining lwIP from the CVS repository
2 - Committers/developers CVS access using SSH (to be written)
3 - Merging from DEVEL branch to main trunk (stable branch)
4 - How to release lwIP
1 Obtaining lwIP from the CVS repository
----------------------------------------
To perform an anonymous CVS checkout of the main trunk (this is where
bug fixes and incremental enhancements occur), do this:
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip
Or, obtain a stable branch (updated with bug fixes only) as follows:
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_7 -d lwip-0.7 lwip
Or, obtain a specific (fixed) release as follows:
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_7_0 -d lwip-0.7.0 lwip
3 Committers/developers CVS access using SSH
--------------------------------------------
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
As such, CVS 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 -t dsa
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_dsa.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@cvs.sv.gnu.org
If it tells you:
Authenticating with public key "your_key_name"...
Server refused to allocate pty
then you could login; Savannah refuses to give you a shell - which is OK, as we
are allowed to use SSH for CVS only. Now, you should be able to do this:
export CVS_RSH=ssh
cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip
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 CVS 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 http://savannah.nongnu.org/cvs/?group=lwip)
3 Merging from DEVEL branch to main trunk (stable)
--------------------------------------------------
Merging is a delicate process in CVS and requires the
following disciplined steps in order to prevent conflicts
in the future. Conflicts can be hard to solve!
Merging from branch A to branch B requires that the A branch
has a tag indicating the previous merger. This tag is called
'merged_from_A_to_B'. After merging, the tag is moved in the
A branch to remember this merger for future merge actions.
IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE
REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE
MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME).
Merge all changes in DEVEL since our last merge to main:
In the working copy of the main trunk:
cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL
(This will apply the changes between 'merged_from_DEVEL_to_main'
and 'DEVEL' to your work set of files)
We can now commit the merge result.
cvs commit -R -m "Merged from DEVEL to main."
If this worked out OK, we now move the tag in the DEVEL branch
to this merge point, so we can use this point for future merges:
cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip
4 How to release lwIP
---------------------
First, checkout a clean copy of the branch to be released. Tag this set with
tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example).
Login CVS using pserver authentication, then export a clean copy of the
tagged tree. Export is similar to a checkout, except that the CVS metadata
is not created locally.
export CVS_RSH=ssh
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_6_3 -d lwip-0.6.3 lwip
Archive this directory using tar, gzip'd, bzip2'd and zip'd.
tar czvf lwip-0.6.3.tar.gz lwip-0.6.3
tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3
zip -r lwip-0.6.3.zip lwip-0.6.3
Now, sign the archives with a detached GPG binary signature as follows:
gpg -b lwip-0.6.3.tar.gz
gpg -b lwip-0.6.3.tar.bz2
gpg -b lwip-0.6.3.zip
Upload these files using anonymous FTP:
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
ncftp>mput *0.6.3.*
Additionally, you may post a news item on Savannah, like this:
A new 0.6.3 release is now available here:
http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3
You will have to submit this via the user News interface, then approve
this via the Administrator News interface.

View File

@ -1,181 +0,0 @@
SNMPv1 agent for lwIP
Author: Christiaan Simons
This is a brief introduction how to use and configure the SNMP agent.
Note the agent uses the raw-API UDP interface so you may also want to
read rawapi.txt to gain a better understanding of the SNMP message handling.
0 Agent Capabilities
====================
SNMPv1 per RFC1157
This is an old(er) standard but is still widely supported.
For SNMPv2c and v3 have a greater complexity and need many
more lines of code. IMHO this breaks the idea of "lightweight IP".
Note the S in SNMP stands for "Simple". Note that "Simple" is
relative. SNMP is simple compared to the complex ISO network
management protocols CMIP (Common Management Information Protocol)
and CMOT (CMip Over Tcp).
MIB II per RFC1213
The standard lwIP stack management information base.
This is a required MIB, so this is always enabled.
When builing lwIP without TCP, the mib-2.tcp group is omitted.
The groups EGP, CMOT and transmission are disabled by default.
Most mib-2 objects are not writable except:
sysName, sysLocation, sysContact, snmpEnableAuthenTraps.
Writing to or changing the ARP and IP address and route
tables is not possible.
Note lwIP has a very limited notion of IP routing. It currently
doen't have a route table and doesn't have a notion of the U,G,H flags.
Instead lwIP uses the interface list with only one default interface
acting as a single gateway interface (G) for the default route.
The agent returns a "virtual table" with the default route 0.0.0.0
for the default interface and network routes (no H) for each
network interface in the netif_list.
All routes are considered to be up (U).
Loading additional MIBs
MIBs can only be added in compile-time, not in run-time.
There is no MIB compiler thus additional MIBs must be hand coded.
Large SNMP message support
The packet decoding and encoding routines are designed
to use pbuf-chains. Larger payloads than the minimum
SNMP requirement of 484 octets are supported if the
PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your
local requirement.
1 Building the Agent
====================
First of all you'll need to add the following define
to your local lwipopts.h:
#define LWIP_SNMP 1
and add the source files in lwip/src/core/snmp
and some snmp headers in lwip/src/include/lwip to your makefile.
Note you'll might need to adapt you network driver to update
the mib2 variables for your interface.
2 Running the Agent
===================
The following function calls must be made in your program to
actually get the SNMP agent running.
Before starting the agent you should supply pointers
to non-volatile memory for sysContact, sysLocation,
and snmpEnableAuthenTraps. You can do this by calling
snmp_set_syscontact()
snmp_set_syslocation()
snmp_set_snmpenableauthentraps()
Additionally you may want to set
snmp_set_sysdescr()
snmp_set_sysobjid() (if you have a private MIB)
snmp_set_sysname()
Also before starting the agent you need to setup
one or more trap destinations using these calls:
snmp_trap_dst_enable();
snmp_trap_dst_ip_set();
In the lwIP initialisation sequence call snmp_init() just after
the call to udp_init().
Exactly every 10 msec the SNMP uptime timestamp must be updated with
snmp_inc_sysuptime(). You should call this from a timer interrupt
or a timer signal handler depending on your runtime environment.
An alternative way to update the SNMP uptime timestamp is to do a call like
snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to
a lower frequency). Another one is to not call snmp_inc_sysuptime() or
snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro.
This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside
snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only
when it's queried (any function which need "sysuptime" have to call
snmp_get_sysuptime).
3 Private MIBs
==============
If want to extend the agent with your own private MIB you'll need to
add the following define to your local lwipopts.h:
#define SNMP_PRIVATE_MIB 1
You must provide the private_mib.h and associated files yourself.
Note we don't have a "MIB compiler" that generates C source from a MIB,
so you're required to do some serious coding if you enable this!
Note the lwIP enterprise ID (26381) is assigned to the lwIP project,
ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP
MAINTAINERS!
If you need to create your own private MIB you'll need
to apply for your own enterprise ID with IANA: http://www.iana.org/numbers.html
You can set it by passing a struct snmp_obj_id to the agent
using snmp_set_sysobjid(&my_object_id), just before snmp_init().
Note the object identifiers for thes MIB-2 and your private MIB
tree must be kept in sorted ascending (lexicographical) order.
This to ensure correct getnext operation.
An example for a private MIB is part of the "minimal Unix" project:
contrib/ports/unix/proj/minimal/lwip_prvmib.c
The next chapter gives a more detailed description of the
MIB-2 tree and the optional private MIB.
4 The Gory Details
==================
4.0 Object identifiers and the MIB tree.
We have three distinct parts for all object identifiers:
The prefix
.iso.org.dod.internet
the middle part
.mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress
and the index part
.1.192.168.0.1
Objects located above the .internet hierarchy aren't supported.
Currently only the .mgmt sub-tree is available and
when the SNMP_PRIVATE_MIB is enabled the .private tree
becomes available too.
Object identifiers from incoming requests are checked
for a matching prefix, middle part and index part
or are expanded(*) for GetNext requests with short
or inexisting names in the request.
(* we call this "expansion" but this also
resembles the "auto-completion" operation)
The middle part is usually located in ROM (const)
to preserve precious RAM on small microcontrollers.
However RAM location is possible for a dynamically
changing private tree.
The index part is handled by functions which in
turn use dynamically allocated index trees from RAM.
These trees are updated by e.g. the etharp code
when new entries are made or removed form the ARP cache.
/** @todo more gory details */

View File

@ -1,216 +0,0 @@
sys_arch interface for lwIP 0.6++
Author: Adam Dunkels
The operating system emulation layer provides a common interface
between the lwIP code and the underlying operating system kernel. The
general idea is that porting lwIP to new architectures requires only
small changes to a few header files and a new sys_arch
implementation. It is also possible to do a sys_arch implementation
that does not rely on any underlying operating system.
The sys_arch provides semaphores and mailboxes to lwIP. For the full
lwIP functionality, multiple threads support can be implemented in the
sys_arch, but this is not required for the basic lwIP
functionality. Previous versions of lwIP required the sys_arch to
implement timer scheduling as well but as of lwIP 0.5 this is
implemented in a higher layer.
In addition to the source file providing the functionality of sys_arch,
the OS emulation layer must provide several header files defining
macros used throughout lwip. The files required and the macros they
must define are listed below the sys_arch description.
Semaphores can be either counting or binary - lwIP works with both
kinds. Mailboxes are used for message passing and can be implemented
either as a queue which allows multiple messages to be posted to a
mailbox, or as a rendez-vous point where only one message can be
posted at a time. lwIP works with both kinds, but the former type will
be more efficient. A message in a mailbox is just a pointer, nothing
more.
Semaphores are represented by the type "sys_sem_t" which is typedef'd
in the sys_arch.h file. Mailboxes are equivalently represented by the
type "sys_mbox_t". lwIP does not place any restrictions on how
sys_sem_t or sys_mbox_t are represented internally.
The following functions must be implemented by the sys_arch:
- void sys_init(void)
Is called to initialize the sys_arch layer.
- sys_sem_t sys_sem_new(u8_t count)
Creates and returns a new semaphore. The "count" argument specifies
the initial state of the semaphore.
- void sys_sem_free(sys_sem_t sem)
Deallocates a semaphore.
- void sys_sem_signal(sys_sem_t sem)
Signals a semaphore.
- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
Blocks the thread while waiting for the semaphore to be
signaled. If the "timeout" argument is non-zero, the thread should
only be blocked for the specified time (measured in
milliseconds). If the "timeout" argument is zero, the thread should be
blocked until the semaphore is signalled.
If the timeout argument is non-zero, the return value is the number of
milliseconds spent waiting for the semaphore to be signaled. If the
semaphore wasn't signaled within the specified time, the return value is
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
(i.e., it was already signaled), the function may return zero.
Notice that lwIP implements a function with a similar name,
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
- sys_mbox_t sys_mbox_new(int size)
Creates an empty mailbox for maximum "size" elements. Elements stored
in mailboxes are pointers. You have to define macros "_MBOX_SIZE"
in your lwipopts.h, or ignore this parameter in your implementation
and use a default size.
- void sys_mbox_free(sys_mbox_t mbox)
Deallocates a mailbox. If there are messages still present in the
mailbox when the mailbox is deallocated, it is an indication of a
programming error in lwIP and the developer should be notified.
- void sys_mbox_post(sys_mbox_t mbox, void *msg)
Posts the "msg" to the mailbox. This function have to block until
the "msg" is really posted.
- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
Try to post the "msg" to the mailbox. Returns ERR_MEM if this one
is full, else, ERR_OK if the "msg" is posted.
- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
Blocks the thread until a message arrives in the mailbox, but does
not block the thread longer than "timeout" milliseconds (similar to
the sys_arch_sem_wait() function). If "timeout" is 0, the thread should
be blocked until a message arrives. The "msg" argument is a result
parameter that is set by the function (i.e., by doing "*msg =
ptr"). The "msg" parameter maybe NULL to indicate that the message
should be dropped.
The return values are the same as for the sys_arch_sem_wait() function:
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
timeout.
Note that a function with a similar name, sys_mbox_fetch(), is
implemented by lwIP.
- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
This is similar to sys_arch_mbox_fetch, however if a message is not
present in the mailbox, it immediately returns with the code
SYS_MBOX_EMPTY. On success 0 is returned.
To allow for efficient implementations, this can be defined as a
function-like macro in sys_arch.h instead of a normal function. For
example, a naive implementation could be:
#define sys_arch_mbox_tryfetch(mbox,msg) \
sys_arch_mbox_fetch(mbox,msg,1)
although this would introduce unnecessary delays.
If threads are supported by the underlying operating system and if
such functionality is needed in lwIP, the following function will have
to be implemented as well:
- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
Starts a new thread named "name" with priority "prio" that will begin its
execution in the function "thread()". The "arg" argument will be passed as an
argument to the thread() function. The stack size to used for this thread is
the "stacksize" parameter. The id of the new thread is returned. Both the id
and the priority are system dependent.
- sys_prot_t sys_arch_protect(void)
This optional function does a "fast" critical region protection and returns
the previous protection level. This function is only called during very short
critical regions. An embedded system which supports ISR-based drivers might
want to implement this function by disabling interrupts. Task-based systems
might want to implement this by using a mutex or disabling tasking. This
function should support recursive calls from the same task or interrupt. In
other words, sys_arch_protect() could be called while already protected. In
that case the return value indicates that it is already protected.
sys_arch_protect() is only required if your port is supporting an operating
system.
- void sys_arch_unprotect(sys_prot_t pval)
This optional function does a "fast" set of critical region protection to the
value specified by pval. See the documentation for sys_arch_protect() for
more information. This function is only required if your port is supporting
an operating system.
Note:
Be carefull with using mem_malloc() in sys_arch. When malloc() refers to
mem_malloc() you can run into a circular function call problem. In mem.c
mem_init() tries to allcate a semaphore using mem_malloc, which of course
can't be performed when sys_arch uses mem_malloc.
-------------------------------------------------------------------------------
Additional files required for the "OS support" emulation layer:
-------------------------------------------------------------------------------
cc.h - Architecture environment, some compiler specific, some
environment specific (probably should move env stuff
to sys_arch.h.)
Typedefs for the types used by lwip -
u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t
Compiler hints for packing lwip's structures -
PACK_STRUCT_FIELD(x)
PACK_STRUCT_STRUCT
PACK_STRUCT_BEGIN
PACK_STRUCT_END
Platform specific diagnostic output -
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
Portability defines for printf formatters:
U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
"lightweight" synchronization mechanisms -
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
SYS_ARCH_PROTECT(x) - enter protection mode.
SYS_ARCH_UNPROTECT(x) - leave protection mode.
If the compiler does not provide memset() this file must include a
definition of it, or include a file which defines it.
This file must either include a system-local <errno.h> which defines
the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO
to make lwip/arch.h define the codes which are used throughout.
perf.h - Architecture specific performance measurement.
Measurement calls made throughout lwip, these can be defined to nothing.
PERF_START - start measuring something.
PERF_STOP(x) - stop measuring something, and record the result.
sys_arch.h - Tied to sys_arch.c
Arch dependent types for the following objects:
sys_sem_t, sys_mbox_t, sys_thread_t,
And, optionally:
sys_prot_t
Defines to set vars of sys_mbox_t and sys_sem_t to NULL.
SYS_MBOX_NULL NULL
SYS_SEM_NULL NULL

View File

@ -1,26 +0,0 @@
syntax: glob
*.pyc
*.orig
*.rej
*~
TAGS
Module.symvers
*.ncb
*.suo
*.bak
*.orig
*.rej
syntax: regexp
\.\#.+
[\\/]CVS$
^CVS$
^build$
^install$
^logs.build_tree$
[\\/]bin$
^bin$
[\\/]obj$
^obj$
\.cvsignore

View File

@ -1,13 +0,0 @@
api/ - The code for the high-level wrapper API. Not needed if
you use the lowel-level call-back/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,
as well as the ARP module.
For more information on the various subdirectories, check the FILES
file in each directory.

View File

@ -1,740 +0,0 @@
/**
* @file
* Sequential API External module
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/* This is the part of the API that is linked with
the application */
#include "lwip/opt.h"
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
#include "lwip/api.h"
#include "lwip/tcpip.h"
#include "lwip/memp.h"
#include "lwip/ip.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include <string.h>
/**
* Create a new netconn (of a specific type) that has a callback function.
* The corresponding pcb is also created.
*
* @param t the type of 'connection' to create (@see enum netconn_type)
* @param proto the IP protocol for RAW IP pcbs
* @param callback a function to call on status changes (RX available, TX'ed)
* @return a newly allocated struct netconn or
* NULL on memory error
*/
struct netconn*
netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
{
struct netconn *conn;
struct api_msg msg;
conn = netconn_alloc(t, callback);
if (conn != NULL) {
msg.function = do_newconn;
msg.msg.msg.n.proto = proto;
msg.msg.conn = conn;
if (TCPIP_APIMSG(&msg) != ERR_OK) {
LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
#if LWIP_TCP
LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
#endif /* LWIP_TCP */
sys_sem_free(&conn->op_completed);
sys_mbox_free(&conn->recvmbox);
memp_free(MEMP_NETCONN, conn);
return NULL;
}
}
return conn;
}
/**
* Close a netconn 'connection' and free its resources.
* UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
* after this returns.
*
* @param conn the netconn to delete
* @return ERR_OK if the connection was deleted
*/
err_t
netconn_delete(struct netconn *conn)
{
struct api_msg msg;
/* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
if (conn == NULL) {
return ERR_OK;
}
msg.function = do_delconn;
msg.msg.conn = conn;
tcpip_apimsg(&msg);
netconn_free(conn);
/* don't care for return value of do_delconn since it only calls void functions */
return ERR_OK;
}
/**
* Get the local or remote IP address and port of a netconn.
* For RAW netconns, this returns the protocol instead of a port!
*
* @param conn the netconn to query
* @param addr a pointer to which to save the IP address
* @param port a pointer to which to save the port (or protocol for RAW)
* @param local 1 to get the local IP address, 0 to get the remote one
* @return ERR_CONN for invalid connections
* ERR_OK if the information was retrieved
*/
err_t
netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
msg.function = do_getaddr;
msg.msg.conn = conn;
msg.msg.msg.ad.ipaddr = addr;
msg.msg.msg.ad.port = port;
msg.msg.msg.ad.local = local;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Bind a netconn to a specific local IP address and port.
* Binding one netconn twice might not always be checked correctly!
*
* @param conn the netconn to bind
* @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY
* to bind to all addresses)
* @param port the local port to bind the netconn to (not used for RAW)
* @return ERR_OK if bound, any other err_t on failure
*/
err_t
netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_bind;
msg.msg.conn = conn;
msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Connect a netconn to a specific remote IP address and port.
*
* @param conn the netconn to connect
* @param addr the remote IP address to connect to
* @param port the remote port to connect to (no used for RAW)
* @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
*/
err_t
netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_connect;
msg.msg.conn = conn;
msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port;
/* This is the only function which need to not block tcpip_thread */
err = tcpip_apimsg(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Disconnect a netconn from its current peer (only valid for UDP netconns).
*
* @param conn the netconn to disconnect
* @return TODO: return value is not set here...
*/
err_t
netconn_disconnect(struct netconn *conn)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_disconnect;
msg.msg.conn = conn;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Set a TCP netconn into listen mode
*
* @param conn the tcp netconn to set to listen mode
* @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
* @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
* don't return any error (yet?))
*/
err_t
netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
{
#if LWIP_TCP
struct api_msg msg;
err_t err;
/* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
LWIP_UNUSED_ARG(backlog);
LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_listen;
msg.msg.conn = conn;
#if TCP_LISTEN_BACKLOG
msg.msg.msg.lb.backlog = backlog;
#endif /* TCP_LISTEN_BACKLOG */
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(backlog);
return ERR_ARG;
#endif /* LWIP_TCP */
}
/**
* Accept a new connection on a TCP listening netconn.
*
* @param conn the TCP listen netconn
* @param new_conn pointer where the new connection is stored
* @return ERR_OK if a new connection has been received or an error
* code otherwise
*/
err_t
netconn_accept(struct netconn *conn, struct netconn **new_conn)
{
#if LWIP_TCP
struct netconn *newconn;
err_t err;
#if TCP_LISTEN_BACKLOG
struct api_msg msg;
#endif /* TCP_LISTEN_BACKLOG */
LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
*new_conn = NULL;
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;);
err = conn->last_err;
if (ERR_IS_FATAL(err)) {
/* don't recv on fatal errors: this might block the application task
waiting on acceptmbox forever! */
return err;
}
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
return ERR_TIMEOUT;
}
#else
sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);
#endif /* LWIP_SO_RCVTIMEO*/
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
if (newconn == NULL) {
/* connection has been aborted */
NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
return ERR_ABRT;
}
#if TCP_LISTEN_BACKLOG
/* Let the stack know that we have accepted the connection. */
msg.function = do_recv;
msg.msg.conn = conn;
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
#endif /* TCP_LISTEN_BACKLOG */
*new_conn = newconn;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(new_conn);
return ERR_ARG;
#endif /* LWIP_TCP */
}
/**
* Receive data: actual implementation that doesn't care whether pbuf or netbuf
* is received
*
* @param conn the netconn from which to receive data
* @param new_buf pointer where a new pbuf/netbuf is stored when received data
* @return ERR_OK if data has been received, an error code otherwise (timeout,
* memory error or another error)
*/
static err_t
netconn_recv_data(struct netconn *conn, void **new_buf)
{
void *buf = NULL;
u16_t len;
err_t err;
#if LWIP_TCP
struct api_msg msg;
#endif /* LWIP_TCP */
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
*new_buf = NULL;
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
err = conn->last_err;
if (ERR_IS_FATAL(err)) {
/* don't recv on fatal errors: this might block the application task
waiting on recvmbox forever! */
/* @todo: this does not allow us to fetch data that has been put into recvmbox
before the fatal error occurred - is that a problem? */
return err;
}
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
return ERR_TIMEOUT;
}
#else
sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
#endif /* LWIP_SO_RCVTIMEO*/
#if LWIP_TCP
if (conn->type == NETCONN_TCP) {
if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
/* Let the stack know that we have taken the data. */
/* TODO: Speedup: Don't block and wait for the answer here
(to prevent multiple thread-switches). */
msg.function = do_recv;
msg.msg.conn = conn;
if (buf != NULL) {
msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;
} else {
msg.msg.msg.r.len = 1;
}
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
}
/* If we are closed, we indicate that we no longer wish to use the socket */
if (buf == NULL) {
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
/* Avoid to lose any previous error code */
NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
return ERR_CLSD;
}
len = ((struct pbuf *)buf)->tot_len;
}
#endif /* LWIP_TCP */
#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
else
#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
#if (LWIP_UDP || LWIP_RAW)
{
LWIP_ASSERT("buf != NULL", buf != NULL);
len = netbuf_len((struct netbuf *)buf);
}
#endif /* (LWIP_UDP || LWIP_RAW) */
#if LWIP_SO_RCVBUF
SYS_ARCH_DEC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
*new_buf = buf;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
}
/**
* Receive data (in form of a pbuf) from a TCP netconn
*
* @param conn the netconn from which to receive data
* @param new_buf pointer where a new pbuf is stored when received data
* @return ERR_OK if data has been received, an error code otherwise (timeout,
* memory error or another error)
* ERR_ARG if conn is not a TCP netconn
*/
err_t
netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
{
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
netconn_type(conn) == NETCONN_TCP, return ERR_ARG;);
return netconn_recv_data(conn, (void **)new_buf);
}
/**
* Receive data (in form of a netbuf containing a packet buffer) from a netconn
*
* @param conn the netconn from which to receive data
* @param new_buf pointer where a new netbuf is stored when received data
* @return ERR_OK if data has been received, an error code otherwise (timeout,
* memory error or another error)
*/
err_t
netconn_recv(struct netconn *conn, struct netbuf **new_buf)
{
#if LWIP_TCP
struct netbuf *buf = NULL;
err_t err;
#endif /* LWIP_TCP */
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
*new_buf = NULL;
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
#if LWIP_TCP
if (conn->type == NETCONN_TCP) {
struct pbuf *p = NULL;
/* This is not a listening netconn, since recvmbox is set */
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
if (buf == NULL) {
NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
return ERR_MEM;
}
err = netconn_recv_data(conn, (void **)&p);
if (err != ERR_OK) {
memp_free(MEMP_NETBUF, buf);
return err;
}
LWIP_ASSERT("p != NULL", p != NULL);
buf->p = p;
buf->ptr = p;
buf->port = 0;
ip_addr_set_any(&buf->addr);
*new_buf = buf;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
} else
#endif /* LWIP_TCP */
{
#if (LWIP_UDP || LWIP_RAW)
return netconn_recv_data(conn, (void **)new_buf);
#endif /* (LWIP_UDP || LWIP_RAW) */
}
}
/**
* TCP: update the receive window: by calling this, the application
* tells the stack that it has processed data and is able to accept
* new data.
* ATTENTION: use with care, this is mainly used for sockets!
* Can only be used when calling netconn_set_noautorecved(conn, 1) before.
*
* @param conn the netconn for which to update the receive window
* @param length amount of data processed (ATTENTION: this must be accurate!)
*/
void
netconn_recved(struct netconn *conn, u32_t length)
{
#if LWIP_TCP
if ((conn != NULL) && (conn->type == NETCONN_TCP) &&
(netconn_get_noautorecved(conn))) {
struct api_msg msg;
/* Let the stack know that we have taken the data. */
/* TODO: Speedup: Don't block and wait for the answer here
(to prevent multiple thread-switches). */
msg.function = do_recv;
msg.msg.conn = conn;
msg.msg.msg.r.len = length;
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
}
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(length);
#endif /* LWIP_TCP */
}
/**
* Send data (in form of a netbuf) to a specific remote IP address and port.
* Only to be used for UDP and RAW netconns (not TCP).
*
* @param conn the netconn over which to send data
* @param buf a netbuf containing the data to send
* @param addr the remote IP address to which to send the data
* @param port the remote port to which to send the data
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)
{
if (buf != NULL) {
ip_addr_set(&buf->addr, addr);
buf->port = port;
return netconn_send(conn, buf);
}
return ERR_VAL;
}
/**
* Send data over a UDP or RAW netconn (that is already connected).
*
* @param conn the UDP or RAW netconn over which to send data
* @param buf a netbuf containing the data to send
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_send(struct netconn *conn, struct netbuf *buf)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
msg.function = do_send;
msg.msg.conn = conn;
msg.msg.msg.b = buf;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Send data over a TCP netconn.
*
* @param conn the TCP netconn over which to send data
* @param dataptr pointer to the application buffer that contains the data to send
* @param size size of the application data to send
* @param apiflags combination of following flags :
* - NETCONN_COPY: data will be copied into memory belonging to the stack
* - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
* - NETCONN_DONTBLOCK: only write the data if all dat can be written at once
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
if (size == 0) {
return ERR_OK;
}
/* @todo: for non-blocking write, check if 'size' would ever fit into
snd_queue or snd_buf */
msg.function = do_write;
msg.msg.conn = conn;
msg.msg.msg.w.dataptr = dataptr;
msg.msg.msg.w.apiflags = apiflags;
msg.msg.msg.w.len = size;
/* For locking the core: this _can_ be delayed on low memory/low send buffer,
but if it is, this is done inside api_msg.c:do_write(), so we can use the
non-blocking version here. */
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Close ot shutdown a TCP netconn (doesn't delete it).
*
* @param conn the TCP netconn to close or shutdown
* @param how fully close or only shutdown one side?
* @return ERR_OK if the netconn was closed, any other err_t on error
*/
static err_t
netconn_close_shutdown(struct netconn *conn, u8_t how)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_close;
msg.msg.conn = conn;
/* shutting down both ends is the same as closing */
msg.msg.msg.sd.shut = how;
/* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,
don't use TCPIP_APIMSG here */
err = tcpip_apimsg(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Close a TCP netconn (doesn't delete it).
*
* @param conn the TCP netconn to close
* @return ERR_OK if the netconn was closed, any other err_t on error
*/
err_t
netconn_close(struct netconn *conn)
{
/* shutting down both ends is the same as closing */
return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
}
/**
* Shut down one or both sides of a TCP netconn (doesn't delete it).
*
* @param conn the TCP netconn to shut down
* @return ERR_OK if the netconn was closed, any other err_t on error
*/
err_t
netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
{
return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
}
#if LWIP_IGMP
/**
* Join multicast groups for UDP netconns.
*
* @param conn the UDP netconn for which to change multicast addresses
* @param multiaddr IP address of the multicast group to join or leave
* @param netif_addr the IP address of the network interface on which to send
* the igmp message
* @param join_or_leave flag whether to send a join- or leave-message
* @return ERR_OK if the action was taken, any err_t on error
*/
err_t
netconn_join_leave_group(struct netconn *conn,
ip_addr_t *multiaddr,
ip_addr_t *netif_addr,
enum netconn_igmp join_or_leave)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_join_leave_group;
msg.msg.conn = conn;
msg.msg.msg.jl.multiaddr = multiaddr;
msg.msg.msg.jl.netif_addr = netif_addr;
msg.msg.msg.jl.join_or_leave = join_or_leave;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
#endif /* LWIP_IGMP */
#if LWIP_DNS
/**
* Execute a DNS query, only one IP address is returned
*
* @param name a string representation of the DNS host name to query
* @param addr a preallocated ip_addr_t where to store the resolved IP address
* @return ERR_OK: resolving succeeded
* ERR_MEM: memory error, try again later
* ERR_ARG: dns client not initialized or invalid hostname
* ERR_VAL: dns server response was invalid
*/
err_t
netconn_gethostbyname(const char *name, ip_addr_t *addr)
{
struct dns_api_msg msg;
err_t err;
sys_sem_t sem;
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
err = sys_sem_new(&sem, 0);
if (err != ERR_OK) {
return err;
}
msg.name = name;
msg.addr = addr;
msg.err = &err;
msg.sem = &sem;
tcpip_callback(do_gethostbyname, &msg);
sys_sem_wait(&sem);
sys_sem_free(&sem);
return err;
}
#endif /* LWIP_DNS*/
#endif /* LWIP_NETCONN */

File diff suppressed because it is too large Load Diff

View File

@ -1,75 +0,0 @@
/**
* @file
* Error Management module
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/err.h"
#ifdef LWIP_DEBUG
static const char *err_strerr[] = {
"Ok.", /* ERR_OK 0 */
"Out of memory error.", /* ERR_MEM -1 */
"Buffer error.", /* ERR_BUF -2 */
"Timeout.", /* ERR_TIMEOUT -3 */
"Routing problem.", /* ERR_RTE -4 */
"Operation in progress.", /* ERR_INPROGRESS -5 */
"Illegal value.", /* ERR_VAL -6 */
"Operation would block.", /* ERR_WOULDBLOCK -7 */
"Address in use.", /* ERR_USE -8 */
"Already connected.", /* ERR_ISCONN -9 */
"Connection aborted.", /* ERR_ABRT -10 */
"Connection reset.", /* ERR_RST -11 */
"Connection closed.", /* ERR_CLSD -12 */
"Not connected.", /* ERR_CONN -13 */
"Illegal argument.", /* ERR_ARG -14 */
"Low-level netif error.", /* ERR_IF -15 */
};
/**
* Convert an lwip internal error to a string representation.
*
* @param err an lwip internal err_t
* @return a string representation for err
*/
const char *
lwip_strerr(err_t err)
{
return err_strerr[-err];
}
#endif /* LWIP_DEBUG */

View File

@ -1,245 +0,0 @@
/**
* @file
* Network buffer management
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
#include "lwip/netbuf.h"
#include "lwip/memp.h"
#include <string.h>
/**
* Create (allocate) and initialize a new netbuf.
* The netbuf doesn't yet contain a packet buffer!
*
* @return a pointer to a new netbuf
* NULL on lack of memory
*/
struct
netbuf *netbuf_new(void)
{
struct netbuf *buf;
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
if (buf != NULL) {
buf->p = NULL;
buf->ptr = NULL;
ip_addr_set_any(&buf->addr);
buf->port = 0;
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
#if LWIP_CHECKSUM_ON_COPY
buf->flags = 0;
#endif /* LWIP_CHECKSUM_ON_COPY */
buf->toport_chksum = 0;
#if LWIP_NETBUF_RECVINFO
ip_addr_set_any(&buf->toaddr);
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
return buf;
} else {
return NULL;
}
}
/**
* Deallocate a netbuf allocated by netbuf_new().
*
* @param buf pointer to a netbuf allocated by netbuf_new()
*/
void
netbuf_delete(struct netbuf *buf)
{
if (buf != NULL) {
if (buf->p != NULL) {
pbuf_free(buf->p);
buf->p = buf->ptr = NULL;
}
memp_free(MEMP_NETBUF, buf);
}
}
/**
* Allocate memory for a packet buffer for a given netbuf.
*
* @param buf the netbuf for which to allocate a packet buffer
* @param size the size of the packet buffer to allocate
* @return pointer to the allocated memory
* NULL if no memory could be allocated
*/
void *
netbuf_alloc(struct netbuf *buf, u16_t size)
{
LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;);
/* Deallocate any previously allocated memory. */
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
if (buf->p == NULL) {
return NULL;
}
LWIP_ASSERT("check that first pbuf can hold size",
(buf->p->len >= size));
buf->ptr = buf->p;
return buf->p->payload;
}
/**
* Free the packet buffer included in a netbuf
*
* @param buf pointer to the netbuf which contains the packet buffer to free
*/
void
netbuf_free(struct netbuf *buf)
{
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = buf->ptr = NULL;
}
/**
* Let a netbuf reference existing (non-volatile) data.
*
* @param buf netbuf which should reference the data
* @param dataptr pointer to the data to reference
* @param size size of the data
* @return ERR_OK if data is referenced
* ERR_MEM if data couldn't be referenced due to lack of memory
*/
err_t
netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
{
LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;);
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
if (buf->p == NULL) {
buf->ptr = NULL;
return ERR_MEM;
}
buf->p->payload = (void*)dataptr;
buf->p->len = buf->p->tot_len = size;
buf->ptr = buf->p;
return ERR_OK;
}
/**
* Chain one netbuf to another (@see pbuf_chain)
*
* @param head the first netbuf
* @param tail netbuf to chain after head, freed by this function, may not be reference after returning
*/
void
netbuf_chain(struct netbuf *head, struct netbuf *tail)
{
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
pbuf_cat(head->p, tail->p);
head->ptr = head->p;
memp_free(MEMP_NETBUF, tail);
}
/**
* Get the data pointer and length of the data inside a netbuf.
*
* @param buf netbuf to get the data from
* @param dataptr pointer to a void pointer where to store the data pointer
* @param len pointer to an u16_t where the length of the data is stored
* @return ERR_OK if the information was retreived,
* ERR_BUF on error.
*/
err_t
netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
{
LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;);
LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;);
LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;);
if (buf->ptr == NULL) {
return ERR_BUF;
}
*dataptr = buf->ptr->payload;
*len = buf->ptr->len;
return ERR_OK;
}
/**
* Move the current data pointer of a packet buffer contained in a netbuf
* to the next part.
* The packet buffer itself is not modified.
*
* @param buf the netbuf to modify
* @return -1 if there is no next part
* 1 if moved to the next part but now there is no next part
* 0 if moved to the next part and there are still more parts
*/
s8_t
netbuf_next(struct netbuf *buf)
{
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);
if (buf->ptr->next == NULL) {
return -1;
}
buf->ptr = buf->ptr->next;
if (buf->ptr->next == NULL) {
return 1;
}
return 0;
}
/**
* Move the current data pointer of a packet buffer contained in a netbuf
* to the beginning of the packet.
* The packet buffer itself is not modified.
*
* @param buf the netbuf to modify
*/
void
netbuf_first(struct netbuf *buf)
{
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
buf->ptr = buf->p;
}
#endif /* LWIP_NETCONN */

View File

@ -1,352 +0,0 @@
/**
* @file
* API functions for name resolving
*
*/
/*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt
*
*/
#include "lwip/netdb.h"
#if LWIP_DNS && LWIP_SOCKET
#include "lwip/err.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/ip_addr.h"
#include "lwip/api.h"
#include "lwip/dns.h"
#include <string.h>
#include <stdlib.h>
/** helper struct for gethostbyname_r to access the char* buffer */
struct gethostbyname_r_helper {
ip_addr_t *addrs;
ip_addr_t addr;
char *aliases;
};
/** h_errno is exported in netdb.h for access by applications. */
#if LWIP_DNS_API_DECLARE_H_ERRNO
int h_errno;
#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */
/** define "hostent" variables storage: 0 if we use a static (but unprotected)
* set of variables for lwip_gethostbyname, 1 if we use a local storage */
#ifndef LWIP_DNS_API_HOSTENT_STORAGE
#define LWIP_DNS_API_HOSTENT_STORAGE 0
#endif
/** define "hostent" variables storage */
#if LWIP_DNS_API_HOSTENT_STORAGE
#define HOSTENT_STORAGE
#else
#define HOSTENT_STORAGE static
#endif /* LWIP_DNS_API_STATIC_HOSTENT */
/**
* Returns an entry containing addresses of address family AF_INET
* for the host with name name.
* Due to dns_gethostbyname limitations, only one address is returned.
*
* @param name the hostname to resolve
* @return an entry containing addresses of address family AF_INET
* for the host with name name
*/
struct hostent*
lwip_gethostbyname(const char *name)
{
err_t err;
ip_addr_t addr;
/* buffer variables for lwip_gethostbyname() */
HOSTENT_STORAGE struct hostent s_hostent;
HOSTENT_STORAGE char *s_aliases;
HOSTENT_STORAGE ip_addr_t s_hostent_addr;
HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
/* query host IP address */
err = netconn_gethostbyname(name, &addr);
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
h_errno = HOST_NOT_FOUND;
return NULL;
}
/* fill hostent */
s_hostent_addr = addr;
s_phostent_addr[0] = &s_hostent_addr;
s_phostent_addr[1] = NULL;
s_hostent.h_name = (char*)name;
s_hostent.h_aliases = &s_aliases;
s_hostent.h_addrtype = AF_INET;
s_hostent.h_length = sizeof(ip_addr_t);
s_hostent.h_addr_list = (char**)&s_phostent_addr;
#if DNS_DEBUG
/* dump hostent */
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases));
if (s_hostent.h_aliases != NULL) {
u8_t idx;
for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
}
}
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list));
if (s_hostent.h_addr_list != NULL) {
u8_t idx;
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx])));
}
}
#endif /* DNS_DEBUG */
#if LWIP_DNS_API_HOSTENT_STORAGE
/* this function should return the "per-thread" hostent after copy from s_hostent */
return sys_thread_hostent(&s_hostent);
#else
return &s_hostent;
#endif /* LWIP_DNS_API_HOSTENT_STORAGE */
}
/**
* Thread-safe variant of lwip_gethostbyname: instead of using a static
* buffer, this function takes buffer and errno pointers as arguments
* and uses these for the result.
*
* @param name the hostname to resolve
* @param ret pre-allocated struct where to store the result
* @param buf pre-allocated buffer where to store additional data
* @param buflen the size of buf
* @param result pointer to a hostent pointer that is set to ret on success
* and set to zero on error
* @param h_errnop pointer to an int where to store errors (instead of modifying
* the global h_errno)
* @return 0 on success, non-zero on error, additional error information
* is stored in *h_errnop instead of h_errno to be thread-safe
*/
int
lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
size_t buflen, struct hostent **result, int *h_errnop)
{
err_t err;
struct gethostbyname_r_helper *h;
char *hostname;
size_t namelen;
int lh_errno;
if (h_errnop == NULL) {
/* ensure h_errnop is never NULL */
h_errnop = &lh_errno;
}
if (result == NULL) {
/* not all arguments given */
*h_errnop = EINVAL;
return -1;
}
/* first thing to do: set *result to nothing */
*result = NULL;
if ((name == NULL) || (ret == NULL) || (buf == 0)) {
/* not all arguments given */
*h_errnop = EINVAL;
return -1;
}
namelen = strlen(name);
if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {
/* buf can't hold the data needed + a copy of name */
*h_errnop = ERANGE;
return -1;
}
h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);
hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
/* query host IP address */
err = netconn_gethostbyname(name, &(h->addr));
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
*h_errnop = ENSRNOTFOUND;
return -1;
}
/* copy the hostname into buf */
MEMCPY(hostname, name, namelen);
hostname[namelen] = 0;
/* fill hostent */
h->addrs = &(h->addr);
h->aliases = NULL;
ret->h_name = (char*)hostname;
ret->h_aliases = &(h->aliases);
ret->h_addrtype = AF_INET;
ret->h_length = sizeof(ip_addr_t);
ret->h_addr_list = (char**)&(h->addrs);
/* set result != NULL */
*result = ret;
/* return success */
return 0;
}
/**
* Frees one or more addrinfo structures returned by getaddrinfo(), along with
* any additional storage associated with those structures. If the ai_next field
* of the structure is not null, the entire list of structures is freed.
*
* @param ai struct addrinfo to free
*/
void
lwip_freeaddrinfo(struct addrinfo *ai)
{
struct addrinfo *next;
while (ai != NULL) {
next = ai->ai_next;
memp_free(MEMP_NETDB, ai);
ai = next;
}
}
/**
* Translates the name of a service location (for example, a host name) and/or
* a service name and returns a set of socket addresses and associated
* information to be used in creating a socket with which to address the
* specified service.
* Memory for the result is allocated internally and must be freed by calling
* lwip_freeaddrinfo()!
*
* Due to a limitation in dns_gethostbyname, only the first address of a
* host is returned.
* Also, service names are not supported (only port numbers)!
*
* @param nodename descriptive name or address string of the host
* (may be NULL -> local address)
* @param servname port number as string of NULL
* @param hints structure containing input values that set socktype and protocol
* @param res pointer to a pointer where to store the result (set to NULL on failure)
* @return 0 on success, non-zero on failure
*/
int
lwip_getaddrinfo(const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
err_t err;
ip_addr_t addr;
struct addrinfo *ai;
struct sockaddr_in *sa = NULL;
int port_nr = 0;
size_t total_size;
size_t namelen = 0;
if (res == NULL) {
return EAI_FAIL;
}
*res = NULL;
if ((nodename == NULL) && (servname == NULL)) {
return EAI_NONAME;
}
if (servname != NULL) {
/* service name specified: convert to port number
* @todo?: currently, only ASCII integers (port numbers) are supported! */
port_nr = atoi(servname);
if ((port_nr <= 0) || (port_nr > 0xffff)) {
return EAI_SERVICE;
}
}
if (nodename != NULL) {
/* service location specified, try to resolve */
err = netconn_gethostbyname(nodename, &addr);
if (err != ERR_OK) {
return EAI_FAIL;
}
} else {
/* service location specified, use loopback address */
ip_addr_set_loopback(&addr);
}
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
if (nodename != NULL) {
namelen = strlen(nodename);
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
total_size += namelen + 1;
}
/* If this fails, please report to lwip-devel! :-) */
LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
total_size <= NETDB_ELEM_SIZE);
ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
if (ai == NULL) {
goto memerr;
}
memset(ai, 0, total_size);
sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
/* set up sockaddr */
inet_addr_from_ipaddr(&sa->sin_addr, &addr);
sa->sin_family = AF_INET;
sa->sin_len = sizeof(struct sockaddr_in);
sa->sin_port = htons((u16_t)port_nr);
/* set up addrinfo */
ai->ai_family = AF_INET;
if (hints != NULL) {
/* copy socktype & protocol from hints if specified */
ai->ai_socktype = hints->ai_socktype;
ai->ai_protocol = hints->ai_protocol;
}
if (nodename != NULL) {
/* copy nodename to canonname if specified */
ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
MEMCPY(ai->ai_canonname, nodename, namelen);
ai->ai_canonname[namelen] = 0;
}
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr = (struct sockaddr*)sa;
*res = ai;
return 0;
memerr:
if (ai != NULL) {
memp_free(MEMP_NETDB, ai);
}
return EAI_MEMORY;
}
#endif /* LWIP_DNS && LWIP_SOCKET */

View File

@ -1,160 +0,0 @@
/**
* @file
* Network Interface Sequential API module
*
*/
/*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwip/opt.h"
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
#include "lwip/netifapi.h"
#include "lwip/tcpip.h"
/**
* Call netif_add() inside the tcpip_thread context.
*/
void
do_netifapi_netif_add(struct netifapi_msg_msg *msg)
{
if (!netif_add( msg->netif,
msg->msg.add.ipaddr,
msg->msg.add.netmask,
msg->msg.add.gw,
msg->msg.add.state,
msg->msg.add.init,
msg->msg.add.input)) {
msg->err = ERR_IF;
} else {
msg->err = ERR_OK;
}
TCPIP_NETIFAPI_ACK(msg);
}
/**
* Call netif_set_addr() inside the tcpip_thread context.
*/
void
do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
{
netif_set_addr( msg->netif,
msg->msg.add.ipaddr,
msg->msg.add.netmask,
msg->msg.add.gw);
msg->err = ERR_OK;
TCPIP_NETIFAPI_ACK(msg);
}
/**
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
* tcpip_thread context.
*/
void
do_netifapi_netif_common(struct netifapi_msg_msg *msg)
{
if (msg->msg.common.errtfunc != NULL) {
msg->err = msg->msg.common.errtfunc(msg->netif);
} else {
msg->err = ERR_OK;
msg->msg.common.voidfunc(msg->netif);
}
TCPIP_NETIFAPI_ACK(msg);
}
/**
* Call netif_add() in a thread-safe way by running that function inside the
* tcpip_thread context.
*
* @note for params @see netif_add()
*/
err_t
netifapi_netif_add(struct netif *netif,
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw,
void *state,
netif_init_fn init,
netif_input_fn input)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_add;
msg.msg.netif = netif;
msg.msg.msg.add.ipaddr = ipaddr;
msg.msg.msg.add.netmask = netmask;
msg.msg.msg.add.gw = gw;
msg.msg.msg.add.state = state;
msg.msg.msg.add.init = init;
msg.msg.msg.add.input = input;
TCPIP_NETIFAPI(&msg);
return msg.msg.err;
}
/**
* Call netif_set_addr() in a thread-safe way by running that function inside the
* tcpip_thread context.
*
* @note for params @see netif_set_addr()
*/
err_t
netifapi_netif_set_addr(struct netif *netif,
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_set_addr;
msg.msg.netif = netif;
msg.msg.msg.add.ipaddr = ipaddr;
msg.msg.msg.add.netmask = netmask;
msg.msg.msg.add.gw = gw;
TCPIP_NETIFAPI(&msg);
return msg.msg.err;
}
/**
* call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
* way by running that function inside the tcpip_thread context.
*
* @note use only for functions where there is only "netif" parameter.
*/
err_t
netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
netifapi_errt_fn errtfunc)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_common;
msg.msg.netif = netif;
msg.msg.msg.common.voidfunc = voidfunc;
msg.msg.msg.common.errtfunc = errtfunc;
TCPIP_NETIFAPI(&msg);
return msg.msg.err;
}
#endif /* LWIP_NETIF_API */

File diff suppressed because it is too large Load Diff

View File

@ -1,460 +0,0 @@
/**
* @file
* Sequential API Main thread module
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
#include "lwip/sys.h"
#include "lwip/memp.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/tcpip.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "netif/ppp_oe.h"
/* global variables */
static tcpip_init_done_fn tcpip_init_done;
static void *tcpip_init_done_arg;
static sys_mbox_t mbox;
#if LWIP_TCPIP_CORE_LOCKING
/** The global semaphore to lock the stack. */
sys_mutex_t lock_tcpip_core;
#endif /* LWIP_TCPIP_CORE_LOCKING */
/**
* The main lwIP thread. This thread has exclusive access to lwIP core functions
* (unless access to them is not locked). Other threads communicate with this
* thread using message boxes.
*
* It also starts all the timers to make sure they are running in the right
* thread context.
*
* @param arg unused argument
*/
static void
tcpip_thread(void *arg)
{
struct tcpip_msg *msg;
LWIP_UNUSED_ARG(arg);
if (tcpip_init_done != NULL) {
tcpip_init_done(tcpip_init_done_arg);
}
LOCK_TCPIP_CORE();
while (1) { /* MAIN Loop */
UNLOCK_TCPIP_CORE();
LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
LOCK_TCPIP_CORE();
switch (msg->type) {
#if LWIP_NETCONN
case TCPIP_MSG_API:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
break;
#endif /* LWIP_NETCONN */
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
case TCPIP_MSG_INPKT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
#if LWIP_ETHERNET
if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
} else
#endif /* LWIP_ETHERNET */
{
ip_input(msg->msg.inp.p, msg->msg.inp.netif);
}
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
break;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
#if LWIP_NETIF_API
case TCPIP_MSG_NETIFAPI:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
break;
#endif /* LWIP_NETIF_API */
case TCPIP_MSG_CALLBACK:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
#if LWIP_TCPIP_TIMEOUT
case TCPIP_MSG_TIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
case TCPIP_MSG_UNTIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
#endif /* LWIP_TCPIP_TIMEOUT */
default:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
break;
}
}
}
/**
* Pass a received packet to tcpip_thread for input processing
*
* @param p the received packet, p->payload pointing to the Ethernet header or
* to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
* NETIF_FLAG_ETHERNET flags)
* @param inp the network interface on which the packet was received
*/
err_t
tcpip_input(struct pbuf *p, struct netif *inp)
{
#if LWIP_TCPIP_CORE_LOCKING_INPUT
err_t ret;
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp));
LOCK_TCPIP_CORE();
#if LWIP_ETHERNET
if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
ret = ethernet_input(p, inp);
} else
#endif /* LWIP_ETHERNET */
{
ret = ip_input(p, inp);
}
UNLOCK_TCPIP_CORE();
return ret;
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
struct tcpip_msg *msg;
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_INPKT;
msg->msg.inp.p = p;
msg->msg.inp.netif = inp;
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
return ERR_MEM;
}
return ERR_OK;
}
return ERR_VAL;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
}
/**
* Call a specific function in the thread context of
* tcpip_thread for easy access synchronization.
* A function called in that way may access lwIP core code
* without fearing concurrent access.
*
* @param f the function to call
* @param ctx parameter passed to f
* @param block 1 to block until the request is posted, 0 to non-blocking mode
* @return ERR_OK if the function was called, another err_t if not
*/
err_t
tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
{
struct tcpip_msg *msg;
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_CALLBACK;
msg->msg.cb.function = function;
msg->msg.cb.ctx = ctx;
if (block) {
sys_mbox_post(&mbox, msg);
} else {
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_API, msg);
return ERR_MEM;
}
}
return ERR_OK;
}
return ERR_VAL;
}
#if LWIP_TCPIP_TIMEOUT
/**
* call sys_timeout in tcpip_thread
*
* @param msec time in milliseconds for timeout
* @param h function to be called on timeout
* @param arg argument to pass to timeout function h
* @return ERR_MEM on memory error, ERR_OK otherwise
*/
err_t
tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_TIMEOUT;
msg->msg.tmo.msecs = msecs;
msg->msg.tmo.h = h;
msg->msg.tmo.arg = arg;
sys_mbox_post(&mbox, msg);
return ERR_OK;
}
return ERR_VAL;
}
/**
* call sys_untimeout in tcpip_thread
*
* @param msec time in milliseconds for timeout
* @param h function to be called on timeout
* @param arg argument to pass to timeout function h
* @return ERR_MEM on memory error, ERR_OK otherwise
*/
err_t
tcpip_untimeout(sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_UNTIMEOUT;
msg->msg.tmo.h = h;
msg->msg.tmo.arg = arg;
sys_mbox_post(&mbox, msg);
return ERR_OK;
}
return ERR_VAL;
}
#endif /* LWIP_TCPIP_TIMEOUT */
#if LWIP_NETCONN
/**
* Call the lower part of a netconn_* function
* This function is then running in the thread context
* of tcpip_thread and has exclusive access to lwIP core code.
*
* @param apimsg a struct containing the function to call and its parameters
* @return ERR_OK if the function was called, another err_t if not
*/
err_t
tcpip_apimsg(struct api_msg *apimsg)
{
struct tcpip_msg msg;
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
if (sys_mbox_valid(&mbox)) {
msg.type = TCPIP_MSG_API;
msg.msg.apimsg = apimsg;
sys_mbox_post(&mbox, &msg);
sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);
return apimsg->msg.err;
}
return ERR_VAL;
}
#if LWIP_TCPIP_CORE_LOCKING
/**
* Call the lower part of a netconn_* function
* This function has exclusive access to lwIP core code by locking it
* before the function is called.
*
* @param apimsg a struct containing the function to call and its parameters
* @return ERR_OK (only for compatibility fo tcpip_apimsg())
*/
err_t
tcpip_apimsg_lock(struct api_msg *apimsg)
{
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
LOCK_TCPIP_CORE();
apimsg->function(&(apimsg->msg));
UNLOCK_TCPIP_CORE();
return apimsg->msg.err;
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETCONN */
#if LWIP_NETIF_API
#if !LWIP_TCPIP_CORE_LOCKING
/**
* Much like tcpip_apimsg, but calls the lower part of a netifapi_*
* function.
*
* @param netifapimsg a struct containing the function to call and its parameters
* @return error code given back by the function that was called
*/
err_t
tcpip_netifapi(struct netifapi_msg* netifapimsg)
{
struct tcpip_msg msg;
if (sys_mbox_valid(&mbox)) {
err_t err = sys_sem_new(&netifapimsg->msg.sem, 0);
if (err != ERR_OK) {
netifapimsg->msg.err = err;
return err;
}
msg.type = TCPIP_MSG_NETIFAPI;
msg.msg.netifapimsg = netifapimsg;
sys_mbox_post(&mbox, &msg);
sys_sem_wait(&netifapimsg->msg.sem);
sys_sem_free(&netifapimsg->msg.sem);
return netifapimsg->msg.err;
}
return ERR_VAL;
}
#else /* !LWIP_TCPIP_CORE_LOCKING */
/**
* Call the lower part of a netifapi_* function
* This function has exclusive access to lwIP core code by locking it
* before the function is called.
*
* @param netifapimsg a struct containing the function to call and its parameters
* @return ERR_OK (only for compatibility fo tcpip_netifapi())
*/
err_t
tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
{
LOCK_TCPIP_CORE();
netifapimsg->function(&(netifapimsg->msg));
UNLOCK_TCPIP_CORE();
return netifapimsg->msg.err;
}
#endif /* !LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETIF_API */
/**
* Initialize this module:
* - initialize all sub modules
* - start the tcpip_thread
*
* @param initfunc a function to call when tcpip_thread is running and finished initializing
* @param arg argument to pass to initfunc
*/
void
tcpip_init(tcpip_init_done_fn initfunc, void *arg)
{
lwip_init();
tcpip_init_done = initfunc;
tcpip_init_done_arg = arg;
if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
}
#if LWIP_TCPIP_CORE_LOCKING
if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
LWIP_ASSERT("failed to create lock_tcpip_core", 0);
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
}
/**
* Simple callback function used with tcpip_callback to free a pbuf
* (pbuf_free has a wrong signature for tcpip_callback)
*
* @param p The pbuf (chain) to be dereferenced.
*/
static void
pbuf_free_int(void *p)
{
struct pbuf *q = (struct pbuf *)p;
pbuf_free(q);
}
/**
* A simple wrapper function that allows you to free a pbuf from interrupt context.
*
* @param p The pbuf (chain) to be dereferenced.
* @return ERR_OK if callback could be enqueued, an err_t if not
*/
err_t
pbuf_free_callback(struct pbuf *p)
{
return tcpip_callback_with_block(pbuf_free_int, p, 0);
}
/**
* A simple wrapper function that allows you to free heap memory from
* interrupt context.
*
* @param m the heap memory to free
* @return ERR_OK if callback could be enqueued, an err_t if not
*/
err_t
mem_free_callback(void *m)
{
return tcpip_callback_with_block(mem_free, m, 0);
}
#endif /* !NO_SYS */

View File

@ -1,35 +0,0 @@
/*
* 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>
*
*/
#if defined(__ICCARM__)
#pragma pack(1)
#endif

View File

@ -1,107 +0,0 @@
/*
* Copyright (c) 2001, 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. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
* $Id: cc.h,v 1.1.1.1 2004/12/16 14:17:13 bear Exp $
*/
#ifndef __ARCH_CC_H__
#define __ARCH_CC_H__
#include <rthw.h>
#include <rtthread.h>
typedef rt_uint8_t u8_t;
typedef rt_int8_t s8_t;
typedef rt_uint16_t u16_t;
typedef rt_int16_t s16_t;
typedef rt_uint32_t u32_t;
typedef rt_int32_t s32_t;
typedef rt_uint32_t mem_ptr_t;
#define U16_F "hu"
#define S16_F "hd"
#define X16_F "hx"
#define U32_F "lu"
#define S32_F "ld"
#define X32_F "lx"
#ifdef RT_USING_NEWLIB
#include <errno.h>
/* some errno not defined in newlib */
#define ENSRNOTFOUND 163 /* Domain name not found */
/* WARNING: ESHUTDOWN also not defined in newlib. We chose
180 here because the number "108" which is used
in arch.h has been assigned to another error code. */
#define ESHUTDOWN 180
#elif RT_USING_MINILIBC
#include <errno.h>
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#else
#define LWIP_PROVIDE_ERRNO
#endif
#ifdef RT_USING_MINILIBC
#include <time.h>
#define LWIP_TIMEVAL_PRIVATE 0
#endif
#if defined(__CC_ARM) /* ARMCC compiler */
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_END
#elif defined(__IAR_SYSTEMS_ICC__) /* IAR Compiler */
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES
#elif defined(__GNUC__) /* GNU GCC Compiler */
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_STRUCT __attribute__((packed))
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_END
#elif defined(_MSC_VER)
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_END
#endif
void sys_arch_assert(const char* file, int line);
#define LWIP_PLATFORM_DIAG(x) do {rt_kprintf x;} while(0)
#define LWIP_PLATFORM_ASSERT(x) do {rt_kprintf(x); sys_arch_assert(__FILE__, __LINE__);}while(0)
#include "string.h"
#endif /* __ARCH_CC_H__ */

View File

@ -1,35 +0,0 @@
/*
* 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>
*
*/
#if defined(__ICCARM__)
#pragma pack()
#endif

View File

@ -1,52 +0,0 @@
/*
* Copyright (c) 2001, 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. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
* $Id: perf.h,v 1.1.1.1 2004/12/16 14:17:13 bear Exp $
*/
#ifndef __ARCH_PERF_H__
#define __ARCH_PERF_H__
//#include <sys/times.h>
#define PERF_START /* null definition */
#define PERF_STOP(x) /* null definition */
/*
void perf_print(unsigned long c1l, unsigned long c1h,
unsigned long c2l, unsigned long c2h,
char *key);
void perf_print_times(struct tms *start, struct tms *end, char *key);
void perf_init(char *fname);
*/
#endif /* __ARCH_PERF_H__ */

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