+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/*\r
- * Creates six tasks that operate on three queues as follows:\r
- *\r
- * The first two tasks send and receive an incrementing number to/from a queue.\r
- * One task acts as a producer and the other as the consumer. The consumer is a\r
- * higher priority than the producer and is set to block on queue reads. The queue\r
- * only has space for one item - as soon as the producer posts a message on the\r
- * queue the consumer will unblock, pre-empt the producer, and remove the item.\r
- *\r
- * The second two tasks work the other way around. Again the queue used only has\r
- * enough space for one item. This time the consumer has a lower priority than the\r
- * producer. The producer will try to post on the queue blocking when the queue is\r
- * full. When the consumer wakes it will remove the item from the queue, causing\r
- * the producer to unblock, pre-empt the consumer, and immediately re-fill the\r
- * queue.\r
- *\r
- * The last two tasks use the same queue producer and consumer functions. This time the queue has\r
- * enough space for lots of items and the tasks operate at the same priority. The\r
- * producer will execute, placing items into the queue. The consumer will start\r
- * executing when either the queue becomes full (causing the producer to block) or\r
- * a context switch occurs (tasks of the same priority will time slice).\r
- *\r
- */\r
-\r
-/*\r
-\r
-Changes from V4.1.1\r
-\r
- + The second set of tasks were created the wrong way around. This has been\r
- corrected.\r
-*/\r
-\r
-\r
-#include <stdlib.h>\r
-\r
-/* Scheduler include files. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-\r
-/* Demo program include files. */\r
-#include "BlockQ.h"\r
-\r
-#define blckqSTACK_SIZE configMINIMAL_STACK_SIZE\r
-#define blckqNUM_TASK_SETS ( 3 )\r
-\r
-/* Structure used to pass parameters to the blocking queue tasks. */\r
-typedef struct BLOCKING_QUEUE_PARAMETERS\r
-{\r
- xQueueHandle xQueue; /*< The queue to be used by the task. */\r
- portTickType xBlockTime; /*< The block time to use on queue reads/writes. */\r
- volatile short *psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */\r
-} xBlockingQueueParameters;\r
-\r
-/* Task function that creates an incrementing number and posts it on a queue. */\r
-static portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters );\r
-\r
-/* Task function that removes the incrementing number from a queue and checks that\r
-it is the expected number. */\r
-static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, pvParameters );\r
-\r
-/* Variables which are incremented each time an item is removed from a queue, and\r
-found to be the expected value.\r
-These are used to check that the tasks are still running. */\r
-static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned short ) 0 };\r
-\r
-/* Variable which are incremented each time an item is posted on a queue. These\r
-are used to check that the tasks are still running. */\r
-static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned short ) 0 };\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority )\r
-{\r
-xBlockingQueueParameters *pxQueueParameters1, *pxQueueParameters2;\r
-xBlockingQueueParameters *pxQueueParameters3, *pxQueueParameters4;\r
-xBlockingQueueParameters *pxQueueParameters5, *pxQueueParameters6;\r
-const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5;\r
-const portTickType xBlockTime = ( portTickType ) 1000 / portTICK_RATE_MS;\r
-const portTickType xDontBlock = ( portTickType ) 0;\r
-\r
- /* Create the first two tasks as described at the top of the file. */\r
- \r
- /* First create the structure used to pass parameters to the consumer tasks. */\r
- pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );\r
-\r
- /* Create the queue used by the first two tasks to pass the incrementing number.\r
- Pass a pointer to the queue in the parameter structure. */\r
- pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );\r
-\r
- /* The consumer is created first so gets a block time as described above. */\r
- pxQueueParameters1->xBlockTime = xBlockTime;\r
-\r
- /* Pass in the variable that this task is going to increment so we can check it\r
- is still running. */\r
- pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );\r
- \r
- /* Create the structure used to pass parameters to the producer task. */\r
- pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );\r
-\r
- /* Pass the queue to this task also, using the parameter structure. */\r
- pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;\r
-\r
- /* The producer is not going to block - as soon as it posts the consumer will\r
- wake and remove the item so the producer should always have room to post. */\r
- pxQueueParameters2->xBlockTime = xDontBlock;\r
-\r
- /* Pass in the variable that this task is going to increment so we can check\r
- it is still running. */\r
- pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );\r
-\r
-\r
- /* Note the producer has a lower priority than the consumer when the tasks are\r
- spawned. */\r
- xTaskCreate( vBlockingQueueConsumer, ( signed char * ) "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );\r
- xTaskCreate( vBlockingQueueProducer, ( signed char * ) "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );\r
-\r
- \r
-\r
- /* Create the second two tasks as described at the top of the file. This uses\r
- the same mechanism but reverses the task priorities. */\r
-\r
- pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );\r
- pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );\r
- pxQueueParameters3->xBlockTime = xDontBlock;\r
- pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );\r
-\r
- pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );\r
- pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;\r
- pxQueueParameters4->xBlockTime = xBlockTime;\r
- pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );\r
-\r
- xTaskCreate( vBlockingQueueConsumer, ( signed char * ) "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );\r
- xTaskCreate( vBlockingQueueProducer, ( signed char * ) "QConsB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );\r
-\r
-\r
-\r
- /* Create the last two tasks as described above. The mechanism is again just\r
- the same. This time both parameter structures are given a block time. */\r
- pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );\r
- pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );\r
- pxQueueParameters5->xBlockTime = xBlockTime;\r
- pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );\r
-\r
- pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );\r
- pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;\r
- pxQueueParameters6->xBlockTime = xBlockTime;\r
- pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] ); \r
-\r
- xTaskCreate( vBlockingQueueProducer, ( signed char * ) "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );\r
- xTaskCreate( vBlockingQueueConsumer, ( signed char * ) "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portTASK_FUNCTION( vBlockingQueueProducer, pvParameters )\r
-{\r
-unsigned short usValue = 0;\r
-xBlockingQueueParameters *pxQueueParameters;\r
-short sErrorEverOccurred = pdFALSE;\r
-\r
- pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;\r
-\r
- for( ;; )\r
- { \r
- if( xQueueSend( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )\r
- {\r
- sErrorEverOccurred = pdTRUE;\r
- }\r
- else\r
- {\r
- /* We have successfully posted a message, so increment the variable\r
- used to check we are still running. */\r
- if( sErrorEverOccurred == pdFALSE )\r
- {\r
- ( *pxQueueParameters->psCheckVariable )++;\r
- }\r
-\r
- /* Increment the variable we are going to post next time round. The\r
- consumer will expect the numbers to follow in numerical order. */\r
- ++usValue;\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portTASK_FUNCTION( vBlockingQueueConsumer, pvParameters )\r
-{\r
-unsigned short usData, usExpectedValue = 0;\r
-xBlockingQueueParameters *pxQueueParameters;\r
-short sErrorEverOccurred = pdFALSE;\r
-\r
- pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;\r
-\r
- for( ;; )\r
- { \r
- if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )\r
- {\r
- if( usData != usExpectedValue )\r
- {\r
- /* Catch-up. */\r
- usExpectedValue = usData;\r
-\r
- sErrorEverOccurred = pdTRUE;\r
- }\r
- else\r
- {\r
- /* We have successfully received a message, so increment the\r
- variable used to check we are still running. */ \r
- if( sErrorEverOccurred == pdFALSE )\r
- {\r
- ( *pxQueueParameters->psCheckVariable )++;\r
- }\r
- \r
- /* Increment the value we expect to remove from the queue next time\r
- round. */\r
- ++usExpectedValue;\r
- } \r
- } \r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* This is called to check that all the created tasks are still running. */\r
-portBASE_TYPE xAreBlockingQueuesStillRunning( void )\r
-{\r
-static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned short ) 0 };\r
-static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned short ) 0 };\r
-portBASE_TYPE xReturn = pdPASS, xTasks;\r
-\r
- /* Not too worried about mutual exclusion on these variables as they are 16\r
- bits and we are only reading them. We also only care to see if they have\r
- changed or not.\r
- \r
- Loop through each check variable to and return pdFALSE if any are found not\r
- to have changed since the last call. */\r
-\r
- for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )\r
- {\r
- if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )\r
- {\r
- xReturn = pdFALSE;\r
- }\r
- sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];\r
-\r
-\r
- if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )\r
- {\r
- xReturn = pdFALSE;\r
- }\r
- sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];\r
- }\r
-\r
- return xReturn;\r
-}\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-\r
-/* \r
- * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 - \r
- * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and \r
- * mutex behaviour. \r
- *\r
- * See the comments above the prvSendFrontAndBackTest() and \r
- * prvLowPriorityMutexTask() prototypes below for more information.\r
- */\r
-\r
-\r
-#include <stdlib.h>\r
-\r
-/* Scheduler include files. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-#include "semphr.h"\r
-\r
-/* Demo program include files. */\r
-#include "GenQTest.h"\r
-\r
-#define genqQUEUE_LENGTH ( 5 )\r
-#define genqNO_BLOCK ( 0 )\r
-\r
-#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )\r
-#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
-#define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
-#define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 )\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()\r
- * macros by using both to fill a queue, then reading from the queue to\r
- * check the resultant queue order is as expected. Queue data is also\r
- * peeked.\r
- */\r
-static void prvSendFrontAndBackTest( void *pvParameters );\r
-\r
-/*\r
- * The following three tasks are used to demonstrate the mutex behaviour.\r
- * Each task is given a different priority to demonstrate the priority\r
- * inheritance mechanism.\r
- *\r
- * The low priority task obtains a mutex. After this a high priority task\r
- * attempts to obtain the same mutex, causing its priority to be inherited\r
- * by the low priority task. The task with the inherited high priority then\r
- * resumes a medium priority task to ensure it is not blocked by the medium\r
- * priority task while it holds the inherited high priority. Once the mutex\r
- * is returned the task with the inherited priority returns to its original\r
- * low priority, and is therefore immediately preempted by first the high\r
- * priority task and then the medium prioroity task before it can continue.\r
- */\r
-static void prvLowPriorityMutexTask( void *pvParameters );\r
-static void prvMediumPriorityMutexTask( void *pvParameters );\r
-static void prvHighPriorityMutexTask( void *pvParameters );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Flag that will be latched to pdTRUE should any unexpected behaviour be\r
-detected in any of the tasks. */\r
-static portBASE_TYPE xErrorDetected = pdFALSE;\r
-\r
-/* Counters that are incremented on each cycle of a test. This is used to\r
-detect a stalled task - a test that is no longer running. */\r
-static volatile unsigned portLONG ulLoopCounter = 0;\r
-static volatile unsigned portLONG ulLoopCounter2 = 0;\r
-\r
-/* The variable that is guarded by the mutex in the mutex demo tasks. */\r
-static volatile unsigned portLONG ulGuardedVariable = 0;\r
-\r
-/* Handles used in the mutext test to suspend and resume the high and medium\r
-priority mutex test tasks. */\r
-static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority )\r
-{\r
-xQueueHandle xQueue;\r
-xSemaphoreHandle xMutex;\r
-\r
- /* Create the queue that we are going to use for the\r
- prvSendFrontAndBackTest demo. */\r
- xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );\r
-\r
- /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
- in use. The queue registry is provided as a means for kernel aware \r
- debuggers to locate queues and has no purpose if a kernel aware debugger\r
- is not being used. The call to vQueueAddToRegistry() will be removed\r
- by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is \r
- defined to be less than 1. */\r
- vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Gen_Queue_Test" );\r
-\r
- /* Create the demo task and pass it the queue just created. We are\r
- passing the queue handle by value so it does not matter that it is\r
- declared on the stack here. */\r
- xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * )"GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );\r
-\r
- /* Create the mutex used by the prvMutexTest task. */\r
- xMutex = xSemaphoreCreateMutex();\r
-\r
- /* vQueueAddToRegistry() adds the mutex to the registry, if one is\r
- in use. The registry is provided as a means for kernel aware \r
- debuggers to locate mutexes and has no purpose if a kernel aware debugger\r
- is not being used. The call to vQueueAddToRegistry() will be removed\r
- by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is \r
- defined to be less than 1. */\r
- vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Gen_Queue_Mutex" );\r
-\r
- /* Create the mutex demo tasks and pass it the mutex just created. We are\r
- passing the mutex handle by value so it does not matter that it is declared\r
- on the stack here. */\r
- xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * )"MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );\r
- xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * )"MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );\r
- xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * )"MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvSendFrontAndBackTest( void *pvParameters )\r
-{\r
-unsigned portLONG ulData, ulData2;\r
-xQueueHandle xQueue;\r
-\r
- #ifdef USE_STDIO\r
- void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );\r
- \r
- const portCHAR * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";\r
-\r
- /* Queue a message for printing to say the task has started. */\r
- vPrintDisplayMessage( &pcTaskStartMsg );\r
- #endif\r
-\r
- xQueue = ( xQueueHandle ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* The queue is empty, so sending an item to the back of the queue\r
- should have the same efect as sending it to the front of the queue.\r
-\r
- First send to the front and check everything is as expected. */\r
- xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );\r
-\r
- if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* The data we sent to the queue should equal the data we just received\r
- from the queue. */\r
- if( ulLoopCounter != ulData )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Then do the same, sending the data to the back, checking everything\r
- is as expected. */\r
- if( uxQueueMessagesWaiting( xQueue ) != 0 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );\r
-\r
- if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( uxQueueMessagesWaiting( xQueue ) != 0 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* The data we sent to the queue should equal the data we just received\r
- from the queue. */\r
- if( ulLoopCounter != ulData )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
-\r
-\r
-\r
- /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */\r
- for( ulData = 2; ulData < 5; ulData++ )\r
- {\r
- xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );\r
- }\r
-\r
- /* Now the order in the queue should be 2, 3, 4, with 2 being the first\r
- thing to be read out. Now add 1 then 0 to the front of the queue. */\r
- if( uxQueueMessagesWaiting( xQueue ) != 3 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
- ulData = 1;\r
- xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );\r
- ulData = 0;\r
- xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );\r
-\r
- /* Now the queue should be full, and when we read the data out we\r
- should receive 0, 1, 2, 3, 4. */\r
- if( uxQueueMessagesWaiting( xQueue ) != 5 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
-\r
- /* Check the data we read out is in the expected order. */\r
- for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )\r
- {\r
- /* Try peeking the data first. */\r
- if( xQueuePeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( ulData != ulData2 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
- \r
-\r
- /* Now try receiving the data for real. The value should be the\r
- same. Clobber the value first so we know we really received it. */\r
- ulData2 = ~ulData2;\r
- if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( ulData != ulData2 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
- }\r
-\r
- /* The queue should now be empty again. */\r
- if( uxQueueMessagesWaiting( xQueue ) != 0 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
-\r
-\r
- /* Our queue is empty once more, add 10, 11 to the back. */\r
- ulData = 10;\r
- if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
- ulData = 11;\r
- if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( uxQueueMessagesWaiting( xQueue ) != 2 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the\r
- front. */\r
- for( ulData = 9; ulData >= 7; ulData-- )\r
- {\r
- if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
- }\r
-\r
- /* Now check that the queue is full, and that receiving data provides\r
- the expected sequence of 7, 8, 9, 10, 11. */\r
- if( uxQueueMessagesWaiting( xQueue ) != 5 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
-\r
- /* Check the data we read out is in the expected order. */\r
- for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )\r
- {\r
- if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( ulData != ulData2 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
- }\r
-\r
- if( uxQueueMessagesWaiting( xQueue ) != 0 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- ulLoopCounter++;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvLowPriorityMutexTask( void *pvParameters )\r
-{\r
-xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;\r
-\r
- #ifdef USE_STDIO\r
- void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );\r
- \r
- const portCHAR * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";\r
-\r
- /* Queue a message for printing to say the task has started. */\r
- vPrintDisplayMessage( &pcTaskStartMsg );\r
- #endif\r
-\r
- for( ;; )\r
- {\r
- /* Take the mutex. It should be available now. */\r
- if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Set our guarded variable to a known start value. */\r
- ulGuardedVariable = 0;\r
-\r
- /* Our priority should be as per that assigned when the task was\r
- created. */\r
- if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Now unsuspend the high priority task. This will attempt to take the\r
- mutex, and block when it finds it cannot obtain it. */\r
- vTaskResume( xHighPriorityMutexTask );\r
-\r
- /* We should now have inherited the prioritoy of the high priority task,\r
- as by now it will have attempted to get the mutex. */\r
- if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* We can attempt to set our priority to the test priority - between the\r
- idle priority and the medium/high test priorities, but our actual\r
- prioroity should remain at the high priority. */\r
- vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );\r
- if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Now unsuspend the medium priority task. This should not run as our\r
- inherited priority is above that of the medium priority task. */\r
- vTaskResume( xMediumPriorityMutexTask );\r
-\r
- /* If the did run then it will have incremented our guarded variable. */\r
- if( ulGuardedVariable != 0 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* When we give back the semaphore our priority should be disinherited\r
- back to the priority to which we attempted to set ourselves. This means\r
- that when the high priority task next blocks, the medium priority task\r
- should execute and increment the guarded variable. When we next run\r
- both the high and medium priority tasks will have been suspended again. */\r
- if( xSemaphoreGive( xMutex ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Check that the guarded variable did indeed increment... */\r
- if( ulGuardedVariable != 1 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* ... and that our priority has been disinherited to\r
- genqMUTEX_TEST_PRIORITY. */\r
- if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Set our priority back to our original priority ready for the next\r
- loop around this test. */\r
- vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );\r
-\r
- /* Just to show we are still running. */\r
- ulLoopCounter2++;\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif \r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvMediumPriorityMutexTask( void *pvParameters )\r
-{\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* The medium priority task starts by suspending itself. The low\r
- priority task will unsuspend this task when required. */\r
- vTaskSuspend( NULL );\r
-\r
- /* When this task unsuspends all it does is increment the guarded\r
- variable, this is so the low priority task knows that it has\r
- executed. */\r
- ulGuardedVariable++;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvHighPriorityMutexTask( void *pvParameters )\r
-{\r
-xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* The high priority task starts by suspending itself. The low\r
- priority task will unsuspend this task when required. */\r
- vTaskSuspend( NULL );\r
-\r
- /* When this task unsuspends all it does is attempt to obtain\r
- the mutex. It should find the mutex is not available so a\r
- block time is specified. */\r
- if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* When we eventually obtain the mutex we just give it back then\r
- return to suspend ready for the next test. */\r
- if( xSemaphoreGive( xMutex ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- } \r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* This is called to check that all the created tasks are still running. */\r
-portBASE_TYPE xAreGenericQueueTasksStillRunning( void )\r
-{\r
-static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;\r
-\r
- /* If the demo task is still running then we expect the loopcounters to\r
- have incremented since this function was last called. */\r
- if( ulLastLoopCounter == ulLoopCounter )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( ulLastLoopCounter2 == ulLoopCounter2 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- ulLastLoopCounter = ulLoopCounter;\r
- ulLastLoopCounter2 = ulLoopCounter2; \r
-\r
- /* Errors detected in the task itself will have latched xErrorDetected\r
- to true. */\r
-\r
- return !xErrorDetected;\r
-}\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/*\r
- * This version of PollQ. c is for use on systems that have limited stack\r
- * space and no display facilities. The complete version can be found in\r
- * the Demo/Common/Full directory.\r
- *\r
- * Creates two tasks that communicate over a single queue. One task acts as a\r
- * producer, the other a consumer.\r
- *\r
- * The producer loops for three iteration, posting an incrementing number onto the\r
- * queue each cycle. It then delays for a fixed period before doing exactly the\r
- * same again.\r
- *\r
- * The consumer loops emptying the queue. Each item removed from the queue is\r
- * checked to ensure it contains the expected value. When the queue is empty it\r
- * blocks for a fixed period, then does the same again.\r
- *\r
- * All queue access is performed without blocking. The consumer completely empties\r
- * the queue each time it runs so the producer should never find the queue full.\r
- *\r
- * An error is flagged if the consumer obtains an unexpected value or the producer\r
- * find the queue is full.\r
- */\r
-\r
-/*\r
-Changes from V2.0.0\r
-\r
- + Delay periods are now specified using variables and constants of\r
- portTickType rather than unsigned long.\r
-*/\r
-\r
-#include <stdlib.h>\r
-\r
-/* Scheduler include files. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-\r
-/* Demo program include files. */\r
-#include "PollQ.h"\r
-\r
-#define pollqSTACK_SIZE configMINIMAL_STACK_SIZE\r
-#define pollqQUEUE_SIZE ( 10 )\r
-#define pollqPRODUCER_DELAY ( ( portTickType ) 200 / portTICK_RATE_MS )\r
-#define pollqCONSUMER_DELAY ( pollqPRODUCER_DELAY - ( portTickType ) ( 20 / portTICK_RATE_MS ) )\r
-#define pollqNO_DELAY ( ( portTickType ) 0 )\r
-#define pollqVALUES_TO_PRODUCE ( ( signed portBASE_TYPE ) 3 )\r
-#define pollqINITIAL_VALUE ( ( signed portBASE_TYPE ) 0 )\r
-\r
-/* The task that posts the incrementing number onto the queue. */\r
-static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters );\r
-\r
-/* The task that empties the queue. */\r
-static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters );\r
-\r
-/* Variables that are used to check that the tasks are still running with no\r
-errors. */\r
-static volatile signed portBASE_TYPE xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority )\r
-{\r
-static xQueueHandle xPolledQueue;\r
-\r
- /* Create the queue used by the producer and consumer. */\r
- xPolledQueue = xQueueCreate( pollqQUEUE_SIZE, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );\r
-\r
- /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
- in use. The queue registry is provided as a means for kernel aware \r
- debuggers to locate queues and has no purpose if a kernel aware debugger\r
- is not being used. The call to vQueueAddToRegistry() will be removed\r
- by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is \r
- defined to be less than 1. */\r
- vQueueAddToRegistry( xPolledQueue, ( signed char * ) "Poll_Test_Queue" );\r
-\r
- /* Spawn the producer and consumer. */\r
- xTaskCreate( vPolledQueueConsumer, ( signed char * ) "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL );\r
- xTaskCreate( vPolledQueueProducer, ( signed char * ) "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portTASK_FUNCTION( vPolledQueueProducer, pvParameters )\r
-{\r
-unsigned short usValue = ( unsigned short ) 0;\r
-signed portBASE_TYPE xError = pdFALSE, xLoop;\r
-\r
- for( ;; )\r
- { \r
- for( xLoop = 0; xLoop < pollqVALUES_TO_PRODUCE; xLoop++ )\r
- {\r
- /* Send an incrementing number on the queue without blocking. */\r
- if( xQueueSend( *( ( xQueueHandle * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS )\r
- {\r
- /* We should never find the queue full so if we get here there\r
- has been an error. */\r
- xError = pdTRUE;\r
- }\r
- else\r
- {\r
- if( xError == pdFALSE )\r
- {\r
- /* If an error has ever been recorded we stop incrementing the\r
- check variable. */\r
- portENTER_CRITICAL();\r
- xPollingProducerCount++;\r
- portEXIT_CRITICAL();\r
- }\r
-\r
- /* Update the value we are going to post next time around. */\r
- usValue++;\r
- }\r
- }\r
-\r
- /* Wait before we start posting again to ensure the consumer runs and\r
- empties the queue. */\r
- vTaskDelay( pollqPRODUCER_DELAY );\r
- }\r
-} /*lint !e818 Function prototype must conform to API. */\r
-/*-----------------------------------------------------------*/\r
-\r
-static portTASK_FUNCTION( vPolledQueueConsumer, pvParameters )\r
-{\r
-unsigned short usData, usExpectedValue = ( unsigned short ) 0;\r
-signed portBASE_TYPE xError = pdFALSE;\r
-\r
- for( ;; )\r
- { \r
- /* Loop until the queue is empty. */\r
- while( uxQueueMessagesWaiting( *( ( xQueueHandle * ) pvParameters ) ) )\r
- {\r
- if( xQueueReceive( *( ( xQueueHandle * ) pvParameters ), &usData, pollqNO_DELAY ) == pdPASS )\r
- {\r
- if( usData != usExpectedValue )\r
- {\r
- /* This is not what we expected to receive so an error has\r
- occurred. */\r
- xError = pdTRUE;\r
-\r
- /* Catch-up to the value we received so our next expected\r
- value should again be correct. */\r
- usExpectedValue = usData;\r
- }\r
- else\r
- {\r
- if( xError == pdFALSE )\r
- {\r
- /* Only increment the check variable if no errors have\r
- occurred. */\r
- portENTER_CRITICAL();\r
- xPollingConsumerCount++;\r
- portEXIT_CRITICAL();\r
- }\r
- }\r
-\r
- /* Next time round we would expect the number to be one higher. */\r
- usExpectedValue++;\r
- }\r
- }\r
-\r
- /* Now the queue is empty we block, allowing the producer to place more\r
- items in the queue. */\r
- vTaskDelay( pollqCONSUMER_DELAY );\r
- }\r
-} /*lint !e818 Function prototype must conform to API. */\r
-/*-----------------------------------------------------------*/\r
-\r
-/* This is called to check that all the created tasks are still running with no errors. */\r
-portBASE_TYPE xArePollingQueuesStillRunning( void )\r
-{\r
-portBASE_TYPE xReturn;\r
-\r
- /* Check both the consumer and producer poll count to check they have both\r
- been changed since out last trip round. We do not need a critical section\r
- around the check variables as this is called from a higher priority than\r
- the other tasks that access the same variables. */\r
- if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) ||\r
- ( xPollingProducerCount == pollqINITIAL_VALUE )\r
- )\r
- {\r
- xReturn = pdFALSE;\r
- }\r
- else\r
- {\r
- xReturn = pdTRUE;\r
- }\r
-\r
- /* Set the check variables back down so we know if they have been\r
- incremented the next time around. */\r
- xPollingConsumerCount = pollqINITIAL_VALUE;\r
- xPollingProducerCount = pollqINITIAL_VALUE;\r
-\r
- return xReturn;\r
-}\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-\r
-/* \r
- * Tests the behaviour when data is peeked from a queue when there are\r
- * multiple tasks blocked on the queue.\r
- */\r
-\r
-\r
-#include <stdlib.h>\r
-\r
-/* Scheduler include files. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-#include "semphr.h"\r
-\r
-/* Demo program include files. */\r
-#include "QPeek.h"\r
-\r
-#define qpeekQUEUE_LENGTH ( 5 )\r
-#define qpeekNO_BLOCK ( 0 )\r
-#define qpeekSHORT_DELAY ( 10 )\r
-\r
-#define qpeekLOW_PRIORITY ( tskIDLE_PRIORITY + 0 )\r
-#define qpeekMEDIUM_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
-#define qpeekHIGH_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
-#define qpeekHIGHEST_PRIORITY ( tskIDLE_PRIORITY + 3 )\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * The following three tasks are used to demonstrate the peeking behaviour.\r
- * Each task is given a different priority to demonstrate the order in which\r
- * tasks are woken as data is peeked from a queue.\r
- */\r
-static void prvLowPriorityPeekTask( void *pvParameters );\r
-static void prvMediumPriorityPeekTask( void *pvParameters );\r
-static void prvHighPriorityPeekTask( void *pvParameters );\r
-static void prvHighestPriorityPeekTask( void *pvParameters );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Flag that will be latched to pdTRUE should any unexpected behaviour be\r
-detected in any of the tasks. */\r
-static volatile portBASE_TYPE xErrorDetected = pdFALSE;\r
-\r
-/* Counter that is incremented on each cycle of a test. This is used to\r
-detect a stalled task - a test that is no longer running. */\r
-static volatile unsigned portLONG ulLoopCounter = 0;\r
-\r
-/* Handles to the test tasks. */\r
-xTaskHandle xMediumPriorityTask, xHighPriorityTask, xHighestPriorityTask;\r
-/*-----------------------------------------------------------*/\r
-\r
-void vStartQueuePeekTasks( void )\r
-{\r
-xQueueHandle xQueue;\r
-\r
- /* Create the queue that we are going to use for the test/demo. */\r
- xQueue = xQueueCreate( qpeekQUEUE_LENGTH, sizeof( unsigned portLONG ) );\r
-\r
- /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
- in use. The queue registry is provided as a means for kernel aware \r
- debuggers to locate queues and has no purpose if a kernel aware debugger\r
- is not being used. The call to vQueueAddToRegistry() will be removed\r
- by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is \r
- defined to be less than 1. */\r
- vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "QPeek_Test_Queue" );\r
-\r
- /* Create the demo tasks and pass it the queue just created. We are\r
- passing the queue handle by value so it does not matter that it is declared\r
- on the stack here. */\r
- xTaskCreate( prvLowPriorityPeekTask, ( signed portCHAR * )"PeekL", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL );\r
- xTaskCreate( prvMediumPriorityPeekTask, ( signed portCHAR * )"PeekM", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask );\r
- xTaskCreate( prvHighPriorityPeekTask, ( signed portCHAR * )"PeekH1", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask );\r
- xTaskCreate( prvHighestPriorityPeekTask, ( signed portCHAR * )"PeekH2", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGHEST_PRIORITY, &xHighestPriorityTask );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvHighestPriorityPeekTask( void *pvParameters )\r
-{\r
-xQueueHandle xQueue = ( xQueueHandle ) pvParameters;\r
-unsigned portLONG ulValue;\r
-\r
- #ifdef USE_STDIO\r
- {\r
- void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );\r
- \r
- const portCHAR * const pcTaskStartMsg = "Queue peek test started.\r\n";\r
-\r
- /* Queue a message for printing to say the task has started. */\r
- vPrintDisplayMessage( &pcTaskStartMsg );\r
- }\r
- #endif\r
-\r
- for( ;; )\r
- {\r
- /* Try peeking from the queue. The queue should be empty so we will\r
- block, allowing the high priority task to execute. */\r
- if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
- {\r
- /* We expected to have received something by the time we unblock. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* When we reach here the high and medium priority tasks should still\r
- be blocked on the queue. We unblocked because the low priority task\r
- wrote a value to the queue, which we should have peeked. Peeking the\r
- data (rather than receiving it) will leave the data on the queue, so\r
- the high priority task should then have also been unblocked, but not\r
- yet executed. */\r
- if( ulValue != 0x11223344 )\r
- {\r
- /* We did not receive the expected value. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
- {\r
- /* The message should have been left on the queue. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Now we are going to actually receive the data, so when the high\r
- priority task runs it will find the queue empty and return to the\r
- blocked state. */\r
- ulValue = 0;\r
- if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )\r
- {\r
- /* We expected to receive the value. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( ulValue != 0x11223344 )\r
- {\r
- /* We did not receive the expected value - which should have been\r
- the same value as was peeked. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Now we will block again as the queue is once more empty. The low \r
- priority task can then execute again. */\r
- if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
- {\r
- /* We expected to have received something by the time we unblock. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* When we get here the low priority task should have again written to the\r
- queue. */\r
- if( ulValue != 0x01234567 )\r
- {\r
- /* We did not receive the expected value. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
- {\r
- /* The message should have been left on the queue. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* We only peeked the data, so suspending ourselves now should enable\r
- the high priority task to also peek the data. The high priority task\r
- will have been unblocked when we peeked the data as we left the data\r
- in the queue. */\r
- vTaskSuspend( NULL );\r
-\r
-\r
-\r
- /* This time we are going to do the same as the above test, but the\r
- high priority task is going to receive the data, rather than peek it.\r
- This means that the medium priority task should never peek the value. */\r
- if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( ulValue != 0xaabbaabb )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- vTaskSuspend( NULL ); \r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvHighPriorityPeekTask( void *pvParameters )\r
-{\r
-xQueueHandle xQueue = ( xQueueHandle ) pvParameters;\r
-unsigned portLONG ulValue;\r
-\r
- for( ;; )\r
- {\r
- /* Try peeking from the queue. The queue should be empty so we will\r
- block, allowing the medium priority task to execute. Both the high\r
- and highest priority tasks will then be blocked on the queue. */\r
- if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
- {\r
- /* We expected to have received something by the time we unblock. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* When we get here the highest priority task should have peeked the data\r
- (unblocking this task) then suspended (allowing this task to also peek\r
- the data). */\r
- if( ulValue != 0x01234567 )\r
- {\r
- /* We did not receive the expected value. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
- {\r
- /* The message should have been left on the queue. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* We only peeked the data, so suspending ourselves now should enable\r
- the medium priority task to also peek the data. The medium priority task\r
- will have been unblocked when we peeked the data as we left the data\r
- in the queue. */\r
- vTaskSuspend( NULL );\r
-\r
-\r
- /* This time we are going actually receive the value, so the medium\r
- priority task will never peek the data - we removed it from the queue. */\r
- if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( ulValue != 0xaabbaabb )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- vTaskSuspend( NULL ); \r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvMediumPriorityPeekTask( void *pvParameters )\r
-{\r
-xQueueHandle xQueue = ( xQueueHandle ) pvParameters;\r
-unsigned portLONG ulValue;\r
-\r
- for( ;; )\r
- {\r
- /* Try peeking from the queue. The queue should be empty so we will\r
- block, allowing the low priority task to execute. The highest, high\r
- and medium priority tasks will then all be blocked on the queue. */\r
- if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
- {\r
- /* We expected to have received something by the time we unblock. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* When we get here the high priority task should have peeked the data\r
- (unblocking this task) then suspended (allowing this task to also peek\r
- the data). */\r
- if( ulValue != 0x01234567 )\r
- {\r
- /* We did not receive the expected value. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
- {\r
- /* The message should have been left on the queue. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Just so we know the test is still running. */\r
- ulLoopCounter++;\r
-\r
- /* Now we can suspend ourselves so the low priority task can execute\r
- again. */\r
- vTaskSuspend( NULL );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvLowPriorityPeekTask( void *pvParameters )\r
-{\r
-xQueueHandle xQueue = ( xQueueHandle ) pvParameters;\r
-unsigned portLONG ulValue;\r
-\r
- for( ;; )\r
- {\r
- /* Write some data to the queue. This should unblock the highest \r
- priority task that is waiting to peek data from the queue. */\r
- ulValue = 0x11223344;\r
- if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )\r
- {\r
- /* We were expecting the queue to be empty so we should not of\r
- had a problem writing to the queue. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* By the time we get here the data should have been removed from\r
- the queue. */\r
- if( uxQueueMessagesWaiting( xQueue ) != 0 )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Write another value to the queue, again waking the highest priority\r
- task that is blocked on the queue. */\r
- ulValue = 0x01234567;\r
- if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )\r
- {\r
- /* We were expecting the queue to be empty so we should not of\r
- had a problem writing to the queue. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* All the other tasks should now have successfully peeked the data.\r
- The data is still in the queue so we should be able to receive it. */\r
- ulValue = 0;\r
- if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )\r
- {\r
- /* We expected to receive the data. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- if( ulValue != 0x01234567 )\r
- {\r
- /* We did not receive the expected value. */\r
- }\r
- \r
- /* Lets just delay a while as this is an intensive test as we don't\r
- want to starve other tests of processing time. */\r
- vTaskDelay( qpeekSHORT_DELAY );\r
-\r
- /* Unsuspend the other tasks so we can repeat the test - this time\r
- however not all the other tasks will peek the data as the high\r
- priority task is actually going to remove it from the queue. Send\r
- to front is used just to be different. As the queue is empty it\r
- makes no difference to the result. */\r
- vTaskResume( xMediumPriorityTask );\r
- vTaskResume( xHighPriorityTask );\r
- vTaskResume( xHighestPriorityTask );\r
-\r
- ulValue = 0xaabbaabb;\r
- if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )\r
- {\r
- /* We were expecting the queue to be empty so we should not of\r
- had a problem writing to the queue. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* This time we should find that the queue is empty. The high priority\r
- task actually removed the data rather than just peeking it. */\r
- if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY )\r
- {\r
- /* We expected to receive the data. */\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- /* Unsuspend the highest and high priority tasks so we can go back\r
- and repeat the whole thing. The medium priority task should not be\r
- suspended as it was not able to peek the data in this last case. */\r
- vTaskResume( xHighPriorityTask );\r
- vTaskResume( xHighestPriorityTask ); \r
-\r
- /* Lets just delay a while as this is an intensive test as we don't\r
- want to starve other tests of processing time. */\r
- vTaskDelay( qpeekSHORT_DELAY );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* This is called to check that all the created tasks are still running. */\r
-portBASE_TYPE xAreQueuePeekTasksStillRunning( void )\r
-{\r
-static unsigned portLONG ulLastLoopCounter = 0;\r
-\r
- /* If the demo task is still running then we expect the loopcounter to\r
- have incremented since this function was last called. */\r
- if( ulLastLoopCounter == ulLoopCounter )\r
- {\r
- xErrorDetected = pdTRUE;\r
- }\r
-\r
- ulLastLoopCounter = ulLoopCounter;\r
-\r
- /* Errors detected in the task itself will have latched xErrorDetected\r
- to true. */\r
-\r
- return !xErrorDetected;\r
-}\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-\r
-/*\r
- * Tests the behaviour of timers. Some timers are created before the scheduler\r
- * is started, and some after.\r
- */\r
-\r
-/* Standard includes. */\r
-#include <string.h>\r
-\r
-/* Scheduler include files. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "timers.h"\r
-\r
-/* Demo program include files. */\r
-#include "TimerDemo.h"\r
-\r
-#if ( configTIMER_TASK_PRIORITY < 1 )\r
- #error configTIMER_TASK_PRIORITY must be set to at least 1 for this test/demo to function correctly.\r
-#endif\r
-\r
-#define tmrdemoDONT_BLOCK ( ( portTickType ) 0 )\r
-#define tmrdemoONE_SHOT_TIMER_PERIOD ( xBasePeriod * ( portTickType ) 3 )\r
-#define trmdemoNUM_TIMER_RESETS ( ( unsigned char ) 10 )\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* The callback functions used by the timers. These each increment a counter\r
-to indicate which timer has expired. The auto-reload timers that are used by\r
-the test task (as opposed to being used from an ISR) all share the same\r
-prvAutoReloadTimerCallback() callback function, and use the ID of the\r
-pxExpiredTimer parameter passed into that function to know which counter to\r
-increment. The other timers all have their own unique callback function and\r
-simply increment their counters without using the callback function parameter. */\r
-static void prvAutoReloadTimerCallback( xTimerHandle pxExpiredTimer );\r
-static void prvOneShotTimerCallback( xTimerHandle pxExpiredTimer );\r
-static void prvTimerTestTask( void *pvParameters );\r
-static void prvISRAutoReloadTimerCallback( xTimerHandle pxExpiredTimer );\r
-static void prvISROneShotTimerCallback( xTimerHandle pxExpiredTimer );\r
-\r
-/* The test functions used by the timer test task. These manipulate the auto\r
-reload and one shot timers in various ways, then delay, then inspect the timers\r
-to ensure they have behaved as expected. */\r
-static void prvTest1_CreateTimersWithoutSchedulerRunning( void );\r
-static void prvTest2_CheckTaskAndTimersInitialState( void );\r
-static void prvTest3_CheckAutoReloadExpireRates( void );\r
-static void prvTest4_CheckAutoReloadTimersCanBeStopped( void );\r
-static void prvTest5_CheckBasicOneShotTimerBehaviour( void );\r
-static void prvTest6_CheckAutoReloadResetBehaviour( void );\r
-static void prvResetStartConditionsForNextIteration( void );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Flag that will be latched to pdFAIL should any unexpected behaviour be\r
-detected in any of the demo tests. */\r
-static volatile portBASE_TYPE xTestStatus = pdPASS;\r
-\r
-/* Counter that is incremented on each cycle of a test. This is used to\r
-detect a stalled task - a test that is no longer running. */\r
-static volatile unsigned long ulLoopCounter = 0;\r
-\r
-/* A set of auto reload timers - each of which use the same callback function.\r
-The callback function uses the timer ID to index into, and then increment, a\r
-counter in the ucAutoReloadTimerCounters[] array. The auto reload timers\r
-referenced from xAutoReloadTimers[] are used by the prvTimerTestTask task. */\r
-static xTimerHandle xAutoReloadTimers[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };\r
-static unsigned char ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };\r
-\r
-/* The one shot timer is configured to use a callback function that increments\r
-ucOneShotTimerCounter each time it gets called. */\r
-static xTimerHandle xOneShotTimer = NULL;\r
-static unsigned char ucOneShotTimerCounter = ( unsigned char ) 0;\r
-\r
-/* The ISR reload timer is controlled from the tick hook to exercise the timer\r
-API functions that can be used from an ISR. It is configured to increment\r
-ucISRReloadTimerCounter each time its callback function is executed. */\r
-static xTimerHandle xISRAutoReloadTimer = NULL;\r
-static unsigned char ucISRAutoReloadTimerCounter = ( unsigned char ) 0;\r
-\r
-/* The ISR one shot timer is controlled from the tick hook to exercise the timer\r
-API functions that can be used from an ISR. It is configured to increment\r
-ucISRReloadTimerCounter each time its callback function is executed. */\r
-static xTimerHandle xISROneShotTimer = NULL;\r
-static unsigned char ucISROneShotTimerCounter = ( unsigned char ) 0;\r
-\r
-/* The period of all the timers are a multiple of the base period. The base\r
-period is configured by the parameter to vStartTimerDemoTask(). */\r
-static portTickType xBasePeriod = 0;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vStartTimerDemoTask( portTickType xBasePeriodIn )\r
-{\r
- /* Start with the timer and counter arrays clear - this is only necessary\r
- where the compiler does not clear them automatically on start up. */\r
- memset( ucAutoReloadTimerCounters, 0x00, sizeof( ucAutoReloadTimerCounters ) );\r
- memset( xAutoReloadTimers, 0x00, sizeof( xAutoReloadTimers ) );\r
-\r
- /* Store the period from which all the timer periods will be generated from\r
- (multiples of). */\r
- xBasePeriod = xBasePeriodIn;\r
-\r
- /* Create a set of timers for use by this demo/test. */\r
- prvTest1_CreateTimersWithoutSchedulerRunning();\r
-\r
- /* Create the task that will control and monitor the timers. This is\r
- created at a lower priority than the timer service task to ensure, as\r
- far as it is concerned, commands on timers are actioned immediately\r
- (sending a command to the timer service task will unblock the timer service\r
- task, which will then preempt this task). */\r
- if( xTestStatus != pdFAIL )\r
- {\r
- xTaskCreate( prvTimerTestTask, ( signed portCHAR * ) "Tmr Tst", configMINIMAL_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY - 1, NULL );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvTimerTestTask( void *pvParameters )\r
-{\r
- ( void ) pvParameters;\r
-\r
- /* Create a one-shot timer for use later on in this test. */\r
- xOneShotTimer = xTimerCreate( ( const signed char * ) "Oneshot Timer",/* Text name to facilitate debugging. The kernel does not use this itself. */\r
- tmrdemoONE_SHOT_TIMER_PERIOD, /* The period for the timer. */\r
- pdFALSE, /* Don't auto-reload - hence a one shot timer. */\r
- ( void * ) 0, /* The timer identifier. In this case this is not used as the timer has its own callback. */\r
- prvOneShotTimerCallback ); /* The callback to be called when the timer expires. */\r
-\r
- if( xOneShotTimer == NULL )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
-\r
- /* Ensure all the timers are in their expected initial state. This\r
- depends on the timer service task having a higher priority than this task. */\r
- prvTest2_CheckTaskAndTimersInitialState();\r
-\r
- for( ;; )\r
- {\r
- /* Check the auto reload timers expire at the expected/correct rates. */\r
- prvTest3_CheckAutoReloadExpireRates();\r
-\r
- /* Check the auto reload timers can be stopped correctly, and correctly\r
- report their state. */\r
- prvTest4_CheckAutoReloadTimersCanBeStopped();\r
- \r
- /* Check the one shot timer only calls its callback once after it has been\r
- started, and that it reports its state correctly. */\r
- prvTest5_CheckBasicOneShotTimerBehaviour();\r
-\r
- /* Check timer reset behaviour. */\r
- prvTest6_CheckAutoReloadResetBehaviour();\r
-\r
- /* Start the timers again to restart all the tests over again. */\r
- prvResetStartConditionsForNextIteration();\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* This is called to check that the created task is still running and has not\r
-detected any errors. */\r
-portBASE_TYPE xAreTimerDemoTasksStillRunning( portTickType xCycleFrequency )\r
-{\r
-static unsigned long ulLastLoopCounter = 0UL;\r
-portTickType xMaxBlockTimeUsedByTheseTests, xLoopCounterIncrementTimeMax;\r
-static portTickType xIterationsWithoutCounterIncrement = ( portTickType ) 0, xLastCycleFrequency;\r
-\r
- if( xLastCycleFrequency != xCycleFrequency )\r
- {\r
- /* The cycle frequency has probably become much faster due to an error\r
- elsewhere. Start counting Iterations again. */\r
- xIterationsWithoutCounterIncrement = ( portTickType ) 0;\r
- xLastCycleFrequency = xCycleFrequency;\r
- } \r
-\r
- /* Calculate the maximum number of times that it is permissible for this\r
- function to be called without ulLoopCounter being incremented. This is\r
- necessary because the tests in this file block for extended periods, and the\r
- block period might be longer than the time between calls to this function. */\r
- xMaxBlockTimeUsedByTheseTests = ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;\r
- xLoopCounterIncrementTimeMax = xMaxBlockTimeUsedByTheseTests / xCycleFrequency;\r
-\r
- /* If the demo task is still running then we expect the loopcounter to\r
- have incremented every xLoopCounterIncrementTimeMax calls. */\r
- if( ulLastLoopCounter == ulLoopCounter )\r
- {\r
- xIterationsWithoutCounterIncrement++;\r
- if( xIterationsWithoutCounterIncrement > xLoopCounterIncrementTimeMax )\r
- {\r
- /* The tests appear to be no longer running (stalled). */\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
- else\r
- {\r
- /* ulLoopCounter changed, so the count of times this function was called\r
- without a change can be reset to zero. */\r
- xIterationsWithoutCounterIncrement = ( portTickType ) 0;\r
- }\r
-\r
- ulLastLoopCounter = ulLoopCounter;\r
-\r
- /* Errors detected in the task itself will have latched xTestStatus\r
- to pdFAIL. */\r
-\r
- return xTestStatus;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvTest1_CreateTimersWithoutSchedulerRunning( void )\r
-{\r
-unsigned portBASE_TYPE xTimer;\r
-\r
- for( xTimer = 0; xTimer < configTIMER_QUEUE_LENGTH; xTimer++ )\r
- {\r
- /* As the timer queue is not yet full, it should be possible to both create\r
- and start a timer. These timers are being started before the scheduler has\r
- been started, so their block times should get set to zero within the timer\r
- API itself. */\r
- xAutoReloadTimers[ xTimer ] = xTimerCreate( ( const signed char * )"FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */\r
- ( ( xTimer + ( portTickType ) 1 ) * xBasePeriod ),/* The period for the timer. The plus 1 ensures a period of zero is not specified. */\r
- pdTRUE, /* Auto-reload is set to true. */\r
- ( void * ) xTimer, /* An identifier for the timer as all the auto reload timers use the same callback. */\r
- prvAutoReloadTimerCallback ); /* The callback to be called when the timer expires. */\r
-\r
- if( xAutoReloadTimers[ xTimer ] == NULL )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- else\r
- {\r
- /* The scheduler has not yet started, so the block period of\r
- portMAX_DELAY should just get set to zero in xTimerStart(). Also,\r
- the timer queue is not yet full so xTimerStart() should return\r
- pdPASS. */\r
- if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) != pdPASS )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
- }\r
-\r
- /* The timers queue should now be full, so it should be possible to create\r
- another timer, but not possible to start it (the timer queue will not get\r
- drained until the scheduler has been started. */\r
- xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] = xTimerCreate( ( const signed char * ) "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */\r
- ( configTIMER_QUEUE_LENGTH * xBasePeriod ), /* The period for the timer. */\r
- pdTRUE, /* Auto-reload is set to true. */\r
- ( void * ) xTimer, /* An identifier for the timer as all the auto reload timers use the same callback. */\r
- prvAutoReloadTimerCallback ); /* The callback executed when the timer expires. */\r
-\r
- if( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] == NULL )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- else\r
- {\r
- if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) == pdPASS )\r
- {\r
- /* This time it would not be expected that the timer could be\r
- started at this point. */\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
- \r
- /* Create the timers that are used from the tick interrupt to test the timer\r
- API functions that can be called from an ISR. */\r
- xISRAutoReloadTimer = xTimerCreate( ( const signed char * ) "ISR AR", /* The text name given to the timer. */\r
- 0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */\r
- pdTRUE, /* This is an auto reload timer. */\r
- ( void * ) NULL, /* The identifier is not required. */\r
- prvISRAutoReloadTimerCallback ); /* The callback that is executed when the timer expires. */\r
-\r
- xISROneShotTimer = xTimerCreate( ( const signed char * ) "ISR OS", /* The text name given to the timer. */\r
- 0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */\r
- pdFALSE, /* This is a one shot timer. */\r
- ( void * ) NULL, /* The identifier is not required. */\r
- prvISROneShotTimerCallback ); /* The callback that is executed when the timer expires. */\r
- \r
- if( ( xISRAutoReloadTimer == NULL ) || ( xISROneShotTimer == NULL ) )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-volatile int icalls = 0;\r
-static void prvTest2_CheckTaskAndTimersInitialState( void )\r
-{\r
-unsigned char ucTimer;\r
-icalls++;\r
- /* Ensure all the timers are in their expected initial state. This depends\r
- on the timer service task having a higher priority than this task.\r
-\r
- auto reload timers 0 to ( configTIMER_QUEUE_LENGTH - 1 ) should now be active,\r
- and auto reload timer configTIMER_QUEUE_LENGTH should not yet be active (it\r
- could not be started prior to the scheduler being started when it was\r
- created). */\r
- for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )\r
- {\r
- if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
-\r
- if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] ) != pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvTest3_CheckAutoReloadExpireRates( void )\r
-{\r
-unsigned char ucMaxAllowableValue, ucMinAllowableValue, ucTimer;\r
-portTickType xBlockPeriod, xTimerPeriod, xExpectedNumber;\r
-\r
- /* Check the auto reload timers expire at the expected rates. */\r
-\r
- \r
- /* Delaying for configTIMER_QUEUE_LENGTH * xBasePeriod ticks should allow\r
- all the auto reload timers to expire at least once. */\r
- xBlockPeriod = ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;\r
- vTaskDelay( xBlockPeriod );\r
-\r
- /* Check that all the auto reload timers have called their callback \r
- function the expected number of times. */\r
- for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )\r
- {\r
- /* The expected number of expiries is equal to the block period divided\r
- by the timer period. */\r
- xTimerPeriod = ( ( ( portTickType ) ucTimer + ( portTickType ) 1 ) * xBasePeriod );\r
- xExpectedNumber = xBlockPeriod / xTimerPeriod;\r
- \r
- ucMaxAllowableValue = ( ( unsigned char ) xExpectedNumber ) ;\r
- ucMinAllowableValue = ( ( unsigned char ) xExpectedNumber - ( unsigned char ) 1 );\r
-\r
- if( ( ucAutoReloadTimerCounters[ ucTimer ] < ucMinAllowableValue ) ||\r
- ( ucAutoReloadTimerCounters[ ucTimer ] > ucMaxAllowableValue )\r
- )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
-\r
- if( xTestStatus == pdPASS )\r
- {\r
- /* No errors have been reported so increment the loop counter so the\r
- check task knows this task is still running. */\r
- ulLoopCounter++;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvTest4_CheckAutoReloadTimersCanBeStopped( void )\r
-{ \r
-unsigned char ucTimer;\r
-\r
- /* Check the auto reload timers can be stopped correctly, and correctly\r
- report their state. */\r
-\r
- /* Stop all the active timers. */\r
- for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )\r
- {\r
- /* The timer has not been stopped yet! */\r
- if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- /* Now stop the timer. This will appear to happen immediately to\r
- this task because this task is running at a priority below the\r
- timer service task. */\r
- xTimerStop( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );\r
-\r
- /* The timer should now be inactive. */\r
- if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
-\r
- taskENTER_CRITICAL();\r
- {\r
- /* The timer in array position configTIMER_QUEUE_LENGTH should not\r
- be active. The critical section is used to ensure the timer does\r
- not call its callback between the next line running and the array\r
- being cleared back to zero, as that would mask an error condition. */\r
- if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH ] != ( unsigned char ) 0 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- /* Clear the timer callback count. */\r
- memset( ( void * ) ucAutoReloadTimerCounters, 0, sizeof( ucAutoReloadTimerCounters ) );\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- /* The timers are now all inactive, so this time, after delaying, none\r
- of the callback counters should have incremented. */\r
- vTaskDelay( ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );\r
- for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )\r
- {\r
- if( ucAutoReloadTimerCounters[ ucTimer ] != ( unsigned char ) 0 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
-\r
- if( xTestStatus == pdPASS )\r
- {\r
- /* No errors have been reported so increment the loop counter so\r
- the check task knows this task is still running. */\r
- ulLoopCounter++;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvTest5_CheckBasicOneShotTimerBehaviour( void )\r
-{\r
- /* Check the one shot timer only calls its callback once after it has been\r
- started, and that it reports its state correctly. */\r
-\r
- /* The one shot timer should not be active yet. */\r
- if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- if( ucOneShotTimerCounter != ( unsigned char ) 0 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- /* Start the one shot timer and check that it reports its state correctly. */\r
- xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );\r
- if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- /* Delay for three times as long as the one shot timer period, then check\r
- to ensure it has only called its callback once, and is now not in the\r
- active state. */\r
- vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD * ( portTickType ) 3 );\r
-\r
- if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- if( ucOneShotTimerCounter != ( unsigned char ) 1 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- else\r
- {\r
- /* Reset the one shot timer callback count. */\r
- ucOneShotTimerCounter = ( unsigned char ) 0;\r
- }\r
-\r
- if( xTestStatus == pdPASS )\r
- {\r
- /* No errors have been reported so increment the loop counter so the\r
- check task knows this task is still running. */\r
- ulLoopCounter++;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvTest6_CheckAutoReloadResetBehaviour( void )\r
-{\r
-unsigned char ucTimer;\r
-\r
- /* Check timer reset behaviour. */\r
-\r
- /* Restart the one shot timer and check it reports its status correctly. */\r
- xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );\r
- if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- /* Restart one of the auto reload timers and check that it reports its\r
- status correctly. */\r
- xTimerStart( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );\r
- if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- for( ucTimer = 0; ucTimer < trmdemoNUM_TIMER_RESETS; ucTimer++ )\r
- {\r
- /* Delay for half as long as the one shot timer period, then reset it.\r
- It should never expire while this is done, so its callback count should\r
- never increment. */\r
- vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD / 2 );\r
-\r
- /* Check both running timers are still active, but have not called their\r
- callback functions. */\r
- if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- if( ucOneShotTimerCounter != ( unsigned char ) 0 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] != ( unsigned char ) 0 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- /* Reset both running timers. */\r
- xTimerReset( xOneShotTimer, tmrdemoDONT_BLOCK );\r
- xTimerReset( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );\r
-\r
- if( xTestStatus == pdPASS )\r
- {\r
- /* No errors have been reported so increment the loop counter so\r
- the check task knows this task is still running. */\r
- ulLoopCounter++;\r
- }\r
- }\r
-\r
- /* Finally delay long enough for both running timers to expire. */\r
- vTaskDelay( ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );\r
-\r
- /* The timers were not reset during the above delay period so should now\r
- both have called their callback functions. */\r
- if( ucOneShotTimerCounter != ( unsigned char ) 1 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] == 0 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- /* The one shot timer should no longer be active, while the auto reload\r
- timer should still be active. */\r
- if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- if( xTimerIsTimerActive( xOneShotTimer ) == pdTRUE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- /* Stop the auto reload timer again. */\r
- xTimerStop( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );\r
-\r
- if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) != pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- /* Clear the timer callback counts, ready for another iteration of these\r
- tests. */\r
- ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] = ( unsigned char ) 0;\r
- ucOneShotTimerCounter = ( unsigned char ) 0;\r
-\r
- if( xTestStatus == pdPASS )\r
- {\r
- /* No errors have been reported so increment the loop counter so the check\r
- task knows this task is still running. */\r
- ulLoopCounter++;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvResetStartConditionsForNextIteration( void )\r
-{\r
-unsigned char ucTimer;\r
-\r
- /* Start the timers again to start all the tests over again. */\r
-\r
- /* Start the timers again. */\r
- for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )\r
- {\r
- /* The timer has not been started yet! */\r
- if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-\r
- /* Now start the timer. This will appear to happen immediately to\r
- this task because this task is running at a priority below the timer\r
- service task. */\r
- xTimerStart( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );\r
-\r
- /* The timer should now be active. */\r
- if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
-\r
- if( xTestStatus == pdPASS )\r
- {\r
- /* No errors have been reported so increment the loop counter so the\r
- check task knows this task is still running. */\r
- ulLoopCounter++;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vTimerPeriodicISRTests( void )\r
-{\r
-static portTickType uxTick = ( portTickType ) -1;\r
-\r
-/* The xHigherPriorityTaskWoken parameter is not used in this case as this\r
-function is called from the tick hook anyway. However the API required it\r
-to be present. */\r
-portBASE_TYPE xHigherPriorityTaskWoken = pdTRUE;\r
-portTickType xMargin;\r
-\r
- if( configTIMER_TASK_PRIORITY != ( configMAX_PRIORITIES - 1 ) )\r
- {\r
- /* The timer service task is not the highest priority task, so it cannot\r
- be assumed that timings will be exact. Timers should never call their\r
- callback before their expiry time, but a margin is permissible for calling\r
- their callback after their expiry time. If exact timing is required then\r
- configTIMER_TASK_PRIORITY must be set to ensure the timer service task\r
- is the highest priority task in the system. */\r
- xMargin = 5;\r
- }\r
- else\r
- {\r
- xMargin = 1;\r
- }\r
-\r
- /* This test is called from the tick ISR even when the scheduler is suspended.\r
- Therefore, it is possible for the xTickCount to be temporarily less than the\r
- uxTicks count maintained in this function. That can result in calculated\r
- unblock times being too short, as this function is not called as missed ticks\r
- (ticks that occur while the scheduler is suspended) are unwound to re-instate\r
- the real tick value. Therefore, if this happens, just abandon the test\r
- and start again. */\r
- if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
- {\r
- uxTick = ( portTickType ) -1;\r
- }\r
- else\r
- {\r
- uxTick++;\r
- }\r
-\r
- if( uxTick == 0 )\r
- {\r
- /* The timers will have been created, but not started. Start them\r
- now by setting their period. */\r
- ucISRAutoReloadTimerCounter = 0;\r
- ucISROneShotTimerCounter = 0;\r
- xTimerChangePeriodFromISR( xISRAutoReloadTimer, xBasePeriod, &xHigherPriorityTaskWoken );\r
- xTimerChangePeriodFromISR( xISROneShotTimer, xBasePeriod, &xHigherPriorityTaskWoken );\r
- }\r
- else if( uxTick == xBasePeriod )\r
- {\r
- /* Neither timer should have expired yet. */\r
- if( ( ucISRAutoReloadTimerCounter != 0 ) || ( ucISROneShotTimerCounter != 0 ) )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
- else if( uxTick == ( xBasePeriod + xMargin ) )\r
- {\r
- /* Both timers should now have expired once. The auto reload timer will\r
- still be active, but the one shot timer should now have stopped. */\r
- if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
- else if( uxTick == ( 2 * xBasePeriod ) )\r
- {\r
- /* The auto reload timer will still be active, but the one shot timer\r
- should now have stopped - however, at this time neither of the timers\r
- should have expired again since the last test. */\r
- if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- } \r
- }\r
- else if( uxTick == ( ( 2 * xBasePeriod ) + xMargin ) )\r
- {\r
- /* The auto reload timer will still be active, but the one shot timer\r
- should now have stopped. At this time the auto reload timer should have\r
- expired again, but the one shot timer count should not have changed. */\r
- if( ucISRAutoReloadTimerCounter != 2 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- if( ucISROneShotTimerCounter != 1 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
- else if( uxTick == ( ( 2 * xBasePeriod ) + ( xBasePeriod >> ( portTickType ) 2U ) ) )\r
- {\r
- /* The auto reload timer will still be active, but the one shot timer\r
- should now have stopped. Again though, at this time, neither timer call\r
- back should have been called since the last test. */\r
- if( ucISRAutoReloadTimerCounter != 2 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- if( ucISROneShotTimerCounter != 1 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- } \r
- else if( uxTick == ( 3 * xBasePeriod ) )\r
- {\r
- /* Start the one shot timer again. */\r
- xTimerStartFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );\r
- }\r
- else if( uxTick == ( ( 3 * xBasePeriod ) + xMargin ) )\r
- {\r
- /* The auto reload timer and one shot timer will be active. At\r
- this time the auto reload timer should have expired again, but the one\r
- shot timer count should not have changed yet. */\r
- if( ucISRAutoReloadTimerCounter != 3 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- if( ucISROneShotTimerCounter != 1 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- /* Now stop the auto reload timer. The one shot timer was started\r
- a few ticks ago. */\r
- xTimerStopFromISR( xISRAutoReloadTimer, &xHigherPriorityTaskWoken );\r
- } \r
- else if( uxTick == ( 4 * xBasePeriod ) )\r
- {\r
- /* The auto reload timer is now stopped, and the one shot timer is\r
- active, but at this time neither timer should have expired since the\r
- last test. */\r
- if( ucISRAutoReloadTimerCounter != 3 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- if( ucISROneShotTimerCounter != 1 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- } \r
- else if( uxTick == ( ( 4 * xBasePeriod ) + xMargin ) )\r
- {\r
- /* The auto reload timer is now stopped, and the one shot timer is\r
- active. The one shot timer should have expired again, but the auto\r
- reload timer should not have executed its callback. */\r
- if( ucISRAutoReloadTimerCounter != 3 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- if( ucISROneShotTimerCounter != 2 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- } \r
- else if( uxTick == ( ( 8 * xBasePeriod ) + xMargin ) )\r
- {\r
- /* The auto reload timer is now stopped, and the one shot timer has\r
- already expired and then stopped itself. Both callback counters should\r
- not have incremented since the last test. */\r
- if( ucISRAutoReloadTimerCounter != 3 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- if( ucISROneShotTimerCounter != 2 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- /* Now reset the one shot timer. */\r
- xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );\r
- } \r
- else if( uxTick == ( 9 * xBasePeriod ) )\r
- {\r
- /* Only the one shot timer should be running, but it should not have\r
- expired since the last test. Check the callback counters have not\r
- incremented, then reset the one shot timer again. */\r
- if( ucISRAutoReloadTimerCounter != 3 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- if( ucISROneShotTimerCounter != 2 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );\r
- } \r
- else if( uxTick == ( 10 * xBasePeriod ) )\r
- {\r
- /* Only the one shot timer should be running, but it should not have\r
- expired since the last test. Check the callback counters have not\r
- incremented, then reset the one shot timer again. */\r
- if( ucISRAutoReloadTimerCounter != 3 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- if( ucISROneShotTimerCounter != 2 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );\r
- }\r
- else if( uxTick == ( 11 * xBasePeriod ) )\r
- {\r
- /* Only the one shot timer should be running, but it should not have\r
- expired since the last test. Check the callback counters have not\r
- incremented, then reset the one shot timer once again. */\r
- if( ucISRAutoReloadTimerCounter != 3 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- if( ucISROneShotTimerCounter != 2 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );\r
- } \r
- else if( uxTick == ( ( 12 * xBasePeriod ) + xMargin ) )\r
- {\r
- /* Only the one shot timer should have been running and this time it\r
- should have expired. Check its callback count has been incremented.\r
- The auto reload timer is still not running so should still have the same\r
- count value. This time the one shot timer is not reset so should not\r
- restart from its expiry period again. */\r
- if( ucISRAutoReloadTimerCounter != 3 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- if( ucISROneShotTimerCounter != 3 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- }\r
- else if( uxTick == ( 15 * xBasePeriod ) )\r
- {\r
- /* Neither timer should be running now. Check neither callback count\r
- has incremented, then go back to the start to run these tests all\r
- over again. */\r
- if( ucISRAutoReloadTimerCounter != 3 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- if( ucISROneShotTimerCounter != 3 )\r
- {\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
- \r
- uxTick = ( portTickType ) -1;\r
- } \r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*** Timer callback functions are defined below here. ***/\r
-\r
-static void prvAutoReloadTimerCallback( xTimerHandle pxExpiredTimer )\r
-{\r
-portBASE_TYPE xTimerID;\r
-\r
- xTimerID = ( portBASE_TYPE ) pvTimerGetTimerID( pxExpiredTimer );\r
- if( xTimerID <= ( configTIMER_QUEUE_LENGTH + 1 ) )\r
- {\r
- ( ucAutoReloadTimerCounters[ xTimerID ] )++;\r
- }\r
- else\r
- {\r
- /* The timer ID appears to be unexpected (invalid). */\r
- xTestStatus = pdFAIL;\r
- configASSERT( xTestStatus );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvOneShotTimerCallback( xTimerHandle pxExpiredTimer )\r
-{\r
- /* The parameter is not used in this case as only one timer uses this\r
- callback function. */\r
- ( void ) pxExpiredTimer;\r
-\r
- ucOneShotTimerCounter++;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvISRAutoReloadTimerCallback( xTimerHandle pxExpiredTimer )\r
-{\r
- /* The parameter is not used in this case as only one timer uses this\r
- callback function. */\r
- ( void ) pxExpiredTimer;\r
-\r
- ucISRAutoReloadTimerCounter++;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvISROneShotTimerCallback( xTimerHandle pxExpiredTimer )\r
-{\r
- /* The parameter is not used in this case as only one timer uses this\r
- callback function. */\r
- ( void ) pxExpiredTimer;\r
-\r
- ucISROneShotTimerCounter++;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/*\r
- * This file contains some test scenarios that ensure tasks do not exit queue\r
- * send or receive functions prematurely. A description of the tests is\r
- * included within the code.\r
- */\r
-\r
-/* Kernel includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-\r
-/* Demo includes. */\r
-#include "blocktim.h"\r
-\r
-/* Task priorities. Allow these to be overridden. */\r
-#ifndef bktPRIMARY_PRIORITY\r
- #define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )\r
-#endif\r
-\r
-#ifndef bktSECONDARY_PRIORITY\r
- #define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )\r
-#endif\r
-\r
-/* Task behaviour. */\r
-#define bktQUEUE_LENGTH ( 5 )\r
-#define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )\r
-#define bktPRIMARY_BLOCK_TIME ( 10 )\r
-#define bktALLOWABLE_MARGIN ( 15 )\r
-#define bktTIME_TO_BLOCK ( 175 )\r
-#define bktDONT_BLOCK ( ( portTickType ) 0 )\r
-#define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )\r
-\r
-/* The queue on which the tasks block. */\r
-static xQueueHandle xTestQueue;\r
-\r
-/* Handle to the secondary task is required by the primary task for calls\r
-to vTaskSuspend/Resume(). */\r
-static xTaskHandle xSecondary;\r
-\r
-/* Used to ensure that tasks are still executing without error. */\r
-static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;\r
-static volatile portBASE_TYPE xErrorOccurred = pdFALSE;\r
-\r
-/* Provides a simple mechanism for the primary task to know when the\r
-secondary task has executed. */\r
-static volatile unsigned portBASE_TYPE xRunIndicator;\r
-\r
-/* The two test tasks. Their behaviour is commented within the files. */\r
-static void vPrimaryBlockTimeTestTask( void *pvParameters );\r
-static void vSecondaryBlockTimeTestTask( void *pvParameters );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vCreateBlockTimeTasks( void )\r
-{\r
- /* Create the queue on which the two tasks block. */\r
- xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );\r
-\r
- /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
- in use. The queue registry is provided as a means for kernel aware\r
- debuggers to locate queues and has no purpose if a kernel aware debugger\r
- is not being used. The call to vQueueAddToRegistry() will be removed\r
- by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
- defined to be less than 1. */\r
- vQueueAddToRegistry( xTestQueue, ( signed char * ) "Block_Time_Queue" );\r
-\r
- /* Create the two test tasks. */\r
- xTaskCreate( vPrimaryBlockTimeTestTask, ( signed char * )"BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );\r
- xTaskCreate( vSecondaryBlockTimeTestTask, ( signed char * )"BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void vPrimaryBlockTimeTestTask( void *pvParameters )\r
-{\r
-portBASE_TYPE xItem, xData;\r
-portTickType xTimeWhenBlocking;\r
-portTickType xTimeToBlock, xBlockedTime;\r
-\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /*********************************************************************\r
- Test 1\r
-\r
- Simple block time wakeup test on queue receives. */\r
- for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
- {\r
- /* The queue is empty. Attempt to read from the queue using a block\r
- time. When we wake, ensure the delta in time is as expected. */\r
- xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;\r
-\r
- xTimeWhenBlocking = xTaskGetTickCount();\r
-\r
- /* We should unblock after xTimeToBlock having not received\r
- anything on the queue. */\r
- if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* How long were we blocked for? */\r
- xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
-\r
- if( xBlockedTime < xTimeToBlock )\r
- {\r
- /* Should not have blocked for less than we requested. */\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )\r
- {\r
- /* Should not have blocked for longer than we requested,\r
- although we would not necessarily run as soon as we were\r
- unblocked so a margin is allowed. */\r
- xErrorOccurred = pdTRUE;\r
- }\r
- }\r
-\r
- /*********************************************************************\r
- Test 2\r
-\r
- Simple block time wakeup test on queue sends.\r
-\r
- First fill the queue. It should be empty so all sends should pass. */\r
- for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
- {\r
- if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
- }\r
-\r
- for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
- {\r
- /* The queue is full. Attempt to write to the queue using a block\r
- time. When we wake, ensure the delta in time is as expected. */\r
- xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;\r
-\r
- xTimeWhenBlocking = xTaskGetTickCount();\r
-\r
- /* We should unblock after xTimeToBlock having not received\r
- anything on the queue. */\r
- if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* How long were we blocked for? */\r
- xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
-\r
- if( xBlockedTime < xTimeToBlock )\r
- {\r
- /* Should not have blocked for less than we requested. */\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )\r
- {\r
- /* Should not have blocked for longer than we requested,\r
- although we would not necessarily run as soon as we were\r
- unblocked so a margin is allowed. */\r
- xErrorOccurred = pdTRUE;\r
- }\r
- }\r
-\r
- /*********************************************************************\r
- Test 3\r
-\r
- Wake the other task, it will block attempting to post to the queue.\r
- When we read from the queue the other task will wake, but before it\r
- can run we will post to the queue again. When the other task runs it\r
- will find the queue still full, even though it was woken. It should\r
- recognise that its block time has not expired and return to block for\r
- the remains of its block time.\r
-\r
- Wake the other task so it blocks attempting to post to the already\r
- full queue. */\r
- xRunIndicator = 0;\r
- vTaskResume( xSecondary );\r
-\r
- /* We need to wait a little to ensure the other task executes. */\r
- while( xRunIndicator != bktRUN_INDICATOR )\r
- {\r
- /* The other task has not yet executed. */\r
- vTaskDelay( bktSHORT_WAIT );\r
- }\r
- /* Make sure the other task is blocked on the queue. */\r
- vTaskDelay( bktSHORT_WAIT );\r
- xRunIndicator = 0;\r
-\r
- for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
- {\r
- /* Now when we make space on the queue the other task should wake\r
- but not execute as this task has higher priority. */\r
- if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* Now fill the queue again before the other task gets a chance to\r
- execute. If the other task had executed we would find the queue\r
- full ourselves, and the other task have set xRunIndicator. */\r
- if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- if( xRunIndicator == bktRUN_INDICATOR )\r
- {\r
- /* The other task should not have executed. */\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* Raise the priority of the other task so it executes and blocks\r
- on the queue again. */\r
- vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );\r
-\r
- /* The other task should now have re-blocked without exiting the\r
- queue function. */\r
- if( xRunIndicator == bktRUN_INDICATOR )\r
- {\r
- /* The other task should not have executed outside of the\r
- queue function. */\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* Set the priority back down. */\r
- vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );\r
- }\r
-\r
- /* Let the other task timeout. When it unblockes it will check that it\r
- unblocked at the correct time, then suspend itself. */\r
- while( xRunIndicator != bktRUN_INDICATOR )\r
- {\r
- vTaskDelay( bktSHORT_WAIT );\r
- }\r
- vTaskDelay( bktSHORT_WAIT );\r
- xRunIndicator = 0;\r
-\r
-\r
- /*********************************************************************\r
- Test 4\r
-\r
- As per test 3 - but with the send and receive the other way around.\r
- The other task blocks attempting to read from the queue.\r
-\r
- Empty the queue. We should find that it is full. */\r
- for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
- {\r
- if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
- }\r
-\r
- /* Wake the other task so it blocks attempting to read from the\r
- already empty queue. */\r
- vTaskResume( xSecondary );\r
-\r
- /* We need to wait a little to ensure the other task executes. */\r
- while( xRunIndicator != bktRUN_INDICATOR )\r
- {\r
- vTaskDelay( bktSHORT_WAIT );\r
- }\r
- vTaskDelay( bktSHORT_WAIT );\r
- xRunIndicator = 0;\r
-\r
- for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
- {\r
- /* Now when we place an item on the queue the other task should\r
- wake but not execute as this task has higher priority. */\r
- if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* Now empty the queue again before the other task gets a chance to\r
- execute. If the other task had executed we would find the queue\r
- empty ourselves, and the other task would be suspended. */\r
- if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- if( xRunIndicator == bktRUN_INDICATOR )\r
- {\r
- /* The other task should not have executed. */\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* Raise the priority of the other task so it executes and blocks\r
- on the queue again. */\r
- vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );\r
-\r
- /* The other task should now have re-blocked without exiting the\r
- queue function. */\r
- if( xRunIndicator == bktRUN_INDICATOR )\r
- {\r
- /* The other task should not have executed outside of the\r
- queue function. */\r
- xErrorOccurred = pdTRUE;\r
- }\r
- vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );\r
- }\r
-\r
- /* Let the other task timeout. When it unblockes it will check that it\r
- unblocked at the correct time, then suspend itself. */\r
- while( xRunIndicator != bktRUN_INDICATOR )\r
- {\r
- vTaskDelay( bktSHORT_WAIT );\r
- }\r
- vTaskDelay( bktSHORT_WAIT );\r
-\r
- xPrimaryCycles++;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void vSecondaryBlockTimeTestTask( void *pvParameters )\r
-{\r
-portTickType xTimeWhenBlocking, xBlockedTime;\r
-portBASE_TYPE xData;\r
-\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /*********************************************************************\r
- Test 1 and 2\r
-\r
- This task does does not participate in these tests. */\r
- vTaskSuspend( NULL );\r
-\r
- /*********************************************************************\r
- Test 3\r
-\r
- The first thing we do is attempt to read from the queue. It should be\r
- full so we block. Note the time before we block so we can check the\r
- wake time is as per that expected. */\r
- xTimeWhenBlocking = xTaskGetTickCount();\r
-\r
- /* We should unblock after bktTIME_TO_BLOCK having not sent\r
- anything to the queue. */\r
- xData = 0;\r
- xRunIndicator = bktRUN_INDICATOR;\r
- if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* How long were we inside the send function? */\r
- xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
-\r
- /* We should not have blocked for less time than bktTIME_TO_BLOCK. */\r
- if( xBlockedTime < bktTIME_TO_BLOCK )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* We should of not blocked for much longer than bktALLOWABLE_MARGIN\r
- either. A margin is permitted as we would not necessarily run as\r
- soon as we unblocked. */\r
- if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* Suspend ready for test 3. */\r
- xRunIndicator = bktRUN_INDICATOR;\r
- vTaskSuspend( NULL );\r
-\r
- /*********************************************************************\r
- Test 4\r
-\r
- As per test three, but with the send and receive reversed. */\r
- xTimeWhenBlocking = xTaskGetTickCount();\r
-\r
- /* We should unblock after bktTIME_TO_BLOCK having not received\r
- anything on the queue. */\r
- xRunIndicator = bktRUN_INDICATOR;\r
- if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
-\r
- /* We should not have blocked for less time than bktTIME_TO_BLOCK. */\r
- if( xBlockedTime < bktTIME_TO_BLOCK )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* We should of not blocked for much longer than bktALLOWABLE_MARGIN\r
- either. A margin is permitted as we would not necessarily run as soon\r
- as we unblocked. */\r
- if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- xRunIndicator = bktRUN_INDICATOR;\r
-\r
- xSecondaryCycles++;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )\r
-{\r
-static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;\r
-portBASE_TYPE xReturn = pdPASS;\r
-\r
- /* Have both tasks performed at least one cycle since this function was\r
- last called? */\r
- if( xPrimaryCycles == xLastPrimaryCycleCount )\r
- {\r
- xReturn = pdFAIL;\r
- }\r
-\r
- if( xSecondaryCycles == xLastSecondaryCycleCount )\r
- {\r
- xReturn = pdFAIL;\r
- }\r
-\r
- if( xErrorOccurred == pdTRUE )\r
- {\r
- xReturn = pdFAIL;\r
- }\r
-\r
- xLastSecondaryCycleCount = xSecondaryCycles;\r
- xLastPrimaryCycleCount = xPrimaryCycles;\r
-\r
- return xReturn;\r
-}\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-\r
-/*\r
- * Creates a task and a timer that operate on an interrupt driven serial port.\r
- * This demo assumes that the characters transmitted on a port will also be\r
- * received on the same port. Therefore, the UART must either be connected to\r
- * an echo server, or the uart connector must have a loopback connector fitted.\r
- * See http://www.serialporttool.com/CommEcho.htm for a suitable echo server\r
- * for Windows hosts.\r
- *\r
- * The timer sends a string to the UART, toggles an LED, then resets itself by \r
- * changing its own period. The period is calculated as a pseudo random number \r
- * between comTX_MAX_BLOCK_TIME and comTX_MIN_BLOCK_TIME.\r
- *\r
- * The task blocks on an Rx queue waiting for a character to become available. \r
- * Received characters are checked to ensure they match those transmitted by the \r
- * Tx timer. An error is latched if characters are missing, incorrect, or \r
- * arrive too slowly.\r
- *\r
- * How characters are actually transmitted and received is port specific. Demos\r
- * that include this test/demo file will provide example drivers. The Tx timer\r
- * executes in the context of the timer service (daemon) task, and must \r
- * therefore never attempt to block.\r
- *\r
- */\r
-\r
-/* Scheduler include files. */\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "timers.h"\r
-\r
-#ifndef configUSE_TIMERS\r
- #error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.\r
-#endif\r
-\r
-#if configUSE_TIMERS != 1\r
- #error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.\r
-#endif\r
-\r
-\r
-/* Demo program include files. */\r
-#include "serial.h"\r
-#include "comtest_strings.h"\r
-#include "partest.h"\r
-\r
-/* The size of the stack given to the Rx task. */\r
-#define comSTACK_SIZE configMINIMAL_STACK_SIZE\r
-\r
-/* See the comment above the declaraction of the uxBaseLED variable. */\r
-#define comTX_LED_OFFSET ( 0 )\r
-#define comRX_LED_OFFSET ( 1 )\r
-\r
-/* The Tx timer transmits the sequence of characters at a pseudo random\r
-interval that is capped between comTX_MAX_BLOCK_TIME and\r
-comTX_MIN_BLOCK_TIME. */\r
-#define comTX_MAX_BLOCK_TIME ( ( portTickType ) 0x96 )\r
-#define comTX_MIN_BLOCK_TIME ( ( portTickType ) 0x32 )\r
-#define comOFFSET_TIME ( ( portTickType ) 3 )\r
-\r
-/* States for the simple state machine implemented in the Rx task. */\r
-#define comtstWAITING_START_OF_STRING 0\r
-#define comtstWAITING_END_OF_STRING 1\r
-\r
-/* A short delay in ticks - this delay is used to allow the Rx queue to fill up\r
-a bit so more than one character can be processed at a time. This is relative\r
-to comTX_MIN_BLOCK_TIME to ensure it is never longer than the shortest gap\r
-between transmissions. It could be worked out more scientifically from the\r
-baud rate being used. */\r
-#define comSHORT_DELAY ( comTX_MIN_BLOCK_TIME >> ( portTickType ) 2 )\r
-\r
-/* The string that is transmitted and received. */\r
-#define comTRANSACTED_STRING "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"\r
-\r
-/* A block time of 0 simply means "don't block". */\r
-#define comtstDONT_BLOCK ( portTickType ) 0\r
-\r
-/* Handle to the com port used by both tasks. */\r
-static xComPortHandle xPort = NULL;\r
-\r
-/* The callback function allocated to the transmit timer, as described in the\r
-comments at the top of this file. */\r
-static void prvComTxTimerCallback( xTimerHandle xTimer );\r
-\r
-/* The receive task as described in the comments at the top of this file. */\r
-static void vComRxTask( void *pvParameters );\r
-\r
-/* The Rx task will toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task\r
-will toggle LED ( uxBaseLED + comTX_LED_OFFSET ). */\r
-static unsigned portBASE_TYPE uxBaseLED = 0;\r
-\r
-/* The Rx task toggles uxRxLoops on each successful iteration of its defined\r
-function - provided no errors have ever been latched. If this variable stops\r
-incrementing, then an error has occurred. */\r
-static volatile unsigned portBASE_TYPE uxRxLoops = 0UL;\r
-\r
-/* The timer used to periodically transmit the string. This is the timer that\r
-has prvComTxTimerCallback allocated to it as its callback function. */\r
-static xTimerHandle xTxTimer = NULL;\r
-\r
-/* The string length is held at file scope so the Tx timer does not need to\r
-calculate it each time it executes. */
-static size_t xStringLength = 0U;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vStartComTestStringsTasks( unsigned portBASE_TYPE uxPriority, unsigned long ulBaudRate, unsigned portBASE_TYPE uxLED )\r
-{\r
- /* Store values that are used at run time. */\r
- uxBaseLED = uxLED;\r
-\r
- /* Calculate the string length here, rather than each time the Tx timer\r
- executes. */\r
- xStringLength = strlen( comTRANSACTED_STRING );\r
-\r
- /* Include the null terminator in the string length as this is used to\r
- detect the end of the string in the Rx task. */\r
- xStringLength++;\r
-\r
- /* Initialise the com port, then spawn the Rx task and create the Tx\r
- timer. */\r
- xSerialPortInitMinimal( ulBaudRate, ( xStringLength * 2U ) );\r
-\r
- /* Create the Rx task and the Tx timer. The timer is started from the\r
- Rx task. */
- xTaskCreate( vComRxTask, ( signed char * ) "COMRx", comSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );\r
- xTxTimer = xTimerCreate( ( const signed char * ) "TxTimer", comTX_MIN_BLOCK_TIME, pdFALSE, NULL, prvComTxTimerCallback );\r
- configASSERT( xTxTimer );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvComTxTimerCallback( xTimerHandle xTimer )\r
-{\r
-portTickType xTimeToWait;\r
-\r
- /* The parameter is not used in this case. */\r
- ( void ) xTimer;\r
-\r
- /* Send the string. How this is actually performed depends on the\r
- sample driver provided with this demo. However - as this is a timer,\r
- it executes in the context of the timer task and therefore must not\r
- block. */\r
- vSerialPutString( xPort, ( const signed char * const ) comTRANSACTED_STRING, xStringLength );\r
-\r
- /* Toggle an LED to give a visible indication that another transmission\r
- has been performed. */
- vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );\r
-\r
- /* Wait a pseudo random time before sending the string again. */\r
- xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;\r
-\r
- /* Ensure the time to wait is not greater than comTX_MAX_BLOCK_TIME. */\r
- xTimeToWait %= comTX_MAX_BLOCK_TIME;\r
-\r
- /* Ensure the time to wait is not less than comTX_MIN_BLOCK_TIME. */\r
- if( xTimeToWait < comTX_MIN_BLOCK_TIME )\r
- {\r
- xTimeToWait = comTX_MIN_BLOCK_TIME;\r
- }\r
-\r
- /* Reset the timer to run again xTimeToWait ticks from now. This function\r
- is called from the context of the timer task, so the block time must not\r
- be anything other than zero. */\r
- xTimerChangePeriod( xTxTimer, xTimeToWait, comtstDONT_BLOCK );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void vComRxTask( void *pvParameters )\r
-{\r
-portBASE_TYPE xState = comtstWAITING_START_OF_STRING, xErrorOccurred = pdFALSE;\r
-signed char *pcExpectedByte, cRxedChar;\r
-const xComPortHandle xPort = NULL;\r
-\r
- /* The parameter is not used in this example. */\r
- ( void ) pvParameters;\r
-\r
- /* Start the Tx timer. This only needs to be started once, as it will\r
- reset itself thereafter. */\r
- xTimerStart( xTxTimer, portMAX_DELAY );\r
-\r
- /* The first expected Rx character is the first in the string that is\r
- transmitted. */
- pcExpectedByte = ( signed char * ) comTRANSACTED_STRING;\r
-\r
- for( ;; )\r
- {\r
- /* Wait for the next character. */\r
- if( xSerialGetChar( xPort, &cRxedChar, ( comTX_MAX_BLOCK_TIME * 2 ) ) == pdFALSE )\r
- {\r
- /* A character definitely should have been received by now. As a\r
- character was not received an error must have occurred (which might\r
- just be that the loopback connector is not fitted). */\r
- xErrorOccurred = pdTRUE;
- }\r
-\r
- switch( xState )\r
- {\r
- case comtstWAITING_START_OF_STRING:\r
- if( cRxedChar == *pcExpectedByte )\r
- {\r
- /* The received character was the first character of the\r
- string. Move to the next state to check each character\r
- as it comes in until the entire string has been received. */\r
- xState = comtstWAITING_END_OF_STRING;\r
- pcExpectedByte++;\r
-\r
- /* Block for a short period. This just allows the Rx queue \r
- to contain more than one character, and therefore prevent\r
- thrashing reads to the queue, and repetitive context \r
- switches as each character is received. */\r
- vTaskDelay( comSHORT_DELAY );\r
- }\r
- break;\r
-\r
- case comtstWAITING_END_OF_STRING:\r
- if( cRxedChar == *pcExpectedByte )\r
- {\r
- /* The received character was the expected character. Was\r
- it the last character in the string - i.e. the null\r
- terminator? */\r
- if( cRxedChar == 0x00 )\r
- {\r
- /* The entire string has been received. If no errors\r
- have been latched, then increment the loop counter to\r
- show this task is still healthy. */
- if( xErrorOccurred == pdFALSE )\r
- {\r
- uxRxLoops++;\r
-\r
- /* Toggle an LED to give a visible sign that a\r
- complete string has been received. */
- vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );\r
- }\r
-\r
- /* Go back to wait for the start of the next string. */\r
- pcExpectedByte = ( signed char * ) comTRANSACTED_STRING;\r
- xState = comtstWAITING_START_OF_STRING;\r
- }\r
- else\r
- {\r
- /* Wait for the next character in the string. */\r
- pcExpectedByte++;\r
- }\r
- }\r
- else\r
- {\r
- /* The character received was not that expected. */\r
- xErrorOccurred = pdTRUE;\r
- }\r
- break;\r
-\r
- default:\r
- /* Should not get here. Stop the Rx loop counter from\r
- incrementing to latch the error. */\r
- xErrorOccurred = pdTRUE;\r
- break;\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-portBASE_TYPE xAreComTestTasksStillRunning( void )\r
-{\r
-portBASE_TYPE xReturn;\r
-\r
- /* If the count of successful reception loops has not changed than at\r
- some time an error occurred (i.e. a character was received out of sequence)\r
- and false is returned. */\r
- if( uxRxLoops == 0UL )\r
- {\r
- xReturn = pdFALSE;\r
- }\r
- else\r
- {\r
- xReturn = pdTRUE;\r
- }\r
-\r
- /* Reset the count of successful Rx loops. When this function is called\r
- again it should have been incremented again. */\r
- uxRxLoops = 0UL;\r
-\r
- return xReturn;\r
-}\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/**\r
- * Create a single persistent task which periodically dynamically creates another\r
- * two tasks. The original task is called the creator task, the two tasks it\r
- * creates are called suicidal tasks.\r
- *\r
- * One of the created suicidal tasks kill one other suicidal task before killing\r
- * itself - leaving just the original task remaining.\r
- *\r
- * The creator task must be spawned after all of the other demo application tasks\r
- * as it keeps a check on the number of tasks under the scheduler control. The\r
- * number of tasks it expects to see running should never be greater than the\r
- * number of tasks that were in existence when the creator task was spawned, plus\r
- * one set of four suicidal tasks. If this number is exceeded an error is flagged.\r
- *\r
- * \page DeathC death.c\r
- * \ingroup DemoFiles\r
- * <HR>\r
- */\r
-\r
-/*\r
-Changes from V3.0.0\r
- + CreationCount sizes changed from unsigned portBASE_TYPE to\r
- unsigned short to minimize the risk of overflowing.\r
- \r
- + Reset of usLastCreationCount added\r
- \r
-Changes from V3.1.0\r
- + Changed the dummy calculation to use variables of type long, rather than\r
- float. This allows the file to be used with ports that do not support\r
- floating point.\r
-\r
-*/\r
-\r
-#include <stdlib.h>\r
-\r
-/* Scheduler include files. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-\r
-/* Demo program include files. */\r
-#include "death.h"\r
-\r
-#define deathSTACK_SIZE ( configMINIMAL_STACK_SIZE + 60 )\r
-\r
-/* The task originally created which is responsible for periodically dynamically\r
-creating another four tasks. */\r
-static portTASK_FUNCTION_PROTO( vCreateTasks, pvParameters );\r
-\r
-/* The task function of the dynamically created tasks. */\r
-static portTASK_FUNCTION_PROTO( vSuicidalTask, pvParameters );\r
-\r
-/* A variable which is incremented every time the dynamic tasks are created. This\r
-is used to check that the task is still running. */\r
-static volatile unsigned short usCreationCount = 0;\r
-\r
-/* Used to store the number of tasks that were originally running so the creator\r
-task can tell if any of the suicidal tasks have failed to die.\r
-*/\r
-static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0;\r
-\r
-/* Tasks are deleted by the idle task. Under heavy load the idle task might\r
-not get much processing time, so it would be legitimate for several tasks to\r
-remain undeleted for a short period. */\r
-static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 2;\r
-\r
-/* Used to store a handle to the task that should be killed by a suicidal task,\r
-before it kills itself. */\r
-xTaskHandle xCreatedTask;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority )\r
-{\r
-unsigned portBASE_TYPE *puxPriority;\r
-\r
- /* Create the Creator tasks - passing in as a parameter the priority at which\r
- the suicidal tasks should be created. */\r
- puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) );\r
- *puxPriority = uxPriority;\r
-\r
- xTaskCreate( vCreateTasks, ( signed char * ) "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL );\r
-\r
- /* Record the number of tasks that are running now so we know if any of the\r
- suicidal tasks have failed to be killed. */\r
- uxTasksRunningAtStart = ( unsigned portBASE_TYPE ) uxTaskGetNumberOfTasks();\r
- \r
- /* FreeRTOS.org versions before V3.0 started the idle-task as the very\r
- first task. The idle task was then already included in uxTasksRunningAtStart.\r
- From FreeRTOS V3.0 on, the idle task is started when the scheduler is\r
- started. Therefore the idle task is not yet accounted for. We correct\r
- this by increasing uxTasksRunningAtStart by 1. */\r
- uxTasksRunningAtStart++;\r
- \r
- /* From FreeRTOS version 7.0.0 can optionally create a timer service task. \r
- If this is done, then uxTasksRunningAtStart needs incrementing again as that\r
- too is created when the scheduler is started. */\r
- #if configUSE_TIMERS == 1\r
- uxTasksRunningAtStart++;\r
- #endif\r
-}\r
-/*-----------------------------------------------------------*/\r
- \r
-static portTASK_FUNCTION( vSuicidalTask, pvParameters )\r
-{\r
-volatile long l1, l2;\r
-xTaskHandle xTaskToKill;\r
-const portTickType xDelay = ( portTickType ) 200 / portTICK_RATE_MS;\r
-\r
- if( pvParameters != NULL )\r
- {\r
- /* This task is periodically created four times. Two created tasks are\r
- passed a handle to the other task so it can kill it before killing itself.\r
- The other task is passed in null. */\r
- xTaskToKill = *( xTaskHandle* )pvParameters;\r
- }\r
- else\r
- {\r
- xTaskToKill = NULL;\r
- }\r
-\r
- for( ;; )\r
- {\r
- /* Do something random just to use some stack and registers. */\r
- l1 = 2;\r
- l2 = 89;\r
- l2 *= l1;\r
- vTaskDelay( xDelay );\r
-\r
- if( xTaskToKill != NULL )\r
- {\r
- /* Make sure the other task has a go before we delete it. */\r
- vTaskDelay( ( portTickType ) 0 );\r
-\r
- /* Kill the other task that was created by vCreateTasks(). */\r
- vTaskDelete( xTaskToKill );\r
-\r
- /* Kill ourselves. */\r
- vTaskDelete( NULL );\r
- }\r
- }\r
-}/*lint !e818 !e550 Function prototype must be as per standard for task functions. */\r
-/*-----------------------------------------------------------*/\r
-\r
-static portTASK_FUNCTION( vCreateTasks, pvParameters )\r
-{\r
-const portTickType xDelay = ( portTickType ) 1000 / portTICK_RATE_MS;\r
-unsigned portBASE_TYPE uxPriority;\r
-\r
- uxPriority = *( unsigned portBASE_TYPE * ) pvParameters;\r
- vPortFree( pvParameters );\r
-\r
- for( ;; )\r
- {\r
- /* Just loop round, delaying then creating the four suicidal tasks. */\r
- vTaskDelay( xDelay );\r
-\r
- xCreatedTask = NULL;\r
-\r
- xTaskCreate( vSuicidalTask, ( signed char * ) "SUICID1", configMINIMAL_STACK_SIZE, NULL, uxPriority, &xCreatedTask );\r
- xTaskCreate( vSuicidalTask, ( signed char * ) "SUICID2", configMINIMAL_STACK_SIZE, &xCreatedTask, uxPriority, NULL );\r
-\r
- ++usCreationCount;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* This is called to check that the creator task is still running and that there\r
-are not any more than four extra tasks. */\r
-portBASE_TYPE xIsCreateTaskStillRunning( void )\r
-{\r
-static unsigned short usLastCreationCount = 0xfff;\r
-portBASE_TYPE xReturn = pdTRUE;\r
-static unsigned portBASE_TYPE uxTasksRunningNow;\r
-\r
- if( usLastCreationCount == usCreationCount )\r
- {\r
- xReturn = pdFALSE;\r
- }\r
- else\r
- {\r
- usLastCreationCount = usCreationCount;\r
- }\r
- \r
- uxTasksRunningNow = ( unsigned portBASE_TYPE ) uxTaskGetNumberOfTasks();\r
-\r
- if( uxTasksRunningNow < uxTasksRunningAtStart )\r
- {\r
- xReturn = pdFALSE;\r
- }\r
- else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning )\r
- {\r
- xReturn = pdFALSE;\r
- }\r
- else\r
- {\r
- /* Everything is okay. */\r
- }\r
-\r
- return xReturn;\r
-}\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/*\r
- * The first test creates three tasks - two counter tasks (one continuous count \r
- * and one limited count) and one controller. A "count" variable is shared \r
- * between all three tasks. The two counter tasks should never be in a "ready" \r
- * state at the same time. The controller task runs at the same priority as \r
- * the continuous count task, and at a lower priority than the limited count \r
- * task.\r
- *\r
- * One counter task loops indefinitely, incrementing the shared count variable\r
- * on each iteration. To ensure it has exclusive access to the variable it\r
- * raises it's priority above that of the controller task before each \r
- * increment, lowering it again to it's original priority before starting the\r
- * next iteration.\r
- *\r
- * The other counter task increments the shared count variable on each\r
- * iteration of it's loop until the count has reached a limit of 0xff - at\r
- * which point it suspends itself. It will not start a new loop until the \r
- * controller task has made it "ready" again by calling vTaskResume (). \r
- * This second counter task operates at a higher priority than controller \r
- * task so does not need to worry about mutual exclusion of the counter \r
- * variable.\r
- *\r
- * The controller task is in two sections. The first section controls and\r
- * monitors the continuous count task. When this section is operational the \r
- * limited count task is suspended. Likewise, the second section controls \r
- * and monitors the limited count task. When this section is operational the \r
- * continuous count task is suspended.\r
- *\r
- * In the first section the controller task first takes a copy of the shared\r
- * count variable. To ensure mutual exclusion on the count variable it\r
- * suspends the continuous count task, resuming it again when the copy has been\r
- * taken. The controller task then sleeps for a fixed period - during which\r
- * the continuous count task will execute and increment the shared variable.\r
- * When the controller task wakes it checks that the continuous count task\r
- * has executed by comparing the copy of the shared variable with its current\r
- * value. This time, to ensure mutual exclusion, the scheduler itself is \r
- * suspended with a call to vTaskSuspendAll (). This is for demonstration \r
- * purposes only and is not a recommended technique due to its inefficiency.\r
- *\r
- * After a fixed number of iterations the controller task suspends the \r
- * continuous count task, and moves on to its second section.\r
- *\r
- * At the start of the second section the shared variable is cleared to zero.\r
- * The limited count task is then woken from it's suspension by a call to\r
- * vTaskResume (). As this counter task operates at a higher priority than\r
- * the controller task the controller task should not run again until the\r
- * shared variable has been counted up to the limited value causing the counter\r
- * task to suspend itself. The next line after vTaskResume () is therefore\r
- * a check on the shared variable to ensure everything is as expected.\r
- *\r
- *\r
- * The second test consists of a couple of very simple tasks that post onto a \r
- * queue while the scheduler is suspended. This test was added to test parts\r
- * of the scheduler not exercised by the first test.\r
- *\r
- */\r
-\r
-#include <stdlib.h>\r
-\r
-/* Scheduler include files. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "semphr.h"\r
-\r
-/* Demo app include files. */\r
-#include "dynamic.h"\r
-\r
-/* Function that implements the "limited count" task as described above. */\r
-static portTASK_FUNCTION_PROTO( vLimitedIncrementTask, pvParameters );\r
-\r
-/* Function that implements the "continuous count" task as described above. */\r
-static portTASK_FUNCTION_PROTO( vContinuousIncrementTask, pvParameters );\r
-\r
-/* Function that implements the controller task as described above. */\r
-static portTASK_FUNCTION_PROTO( vCounterControlTask, pvParameters );\r
-\r
-static portTASK_FUNCTION_PROTO( vQueueReceiveWhenSuspendedTask, pvParameters );\r
-static portTASK_FUNCTION_PROTO( vQueueSendWhenSuspendedTask, pvParameters );\r
-\r
-/* Demo task specific constants. */\r
-#define priSTACK_SIZE ( configMINIMAL_STACK_SIZE )\r
-#define priSLEEP_TIME ( ( portTickType ) 128 / portTICK_RATE_MS )\r
-#define priLOOPS ( 5 )\r
-#define priMAX_COUNT ( ( unsigned long ) 0xff )\r
-#define priNO_BLOCK ( ( portTickType ) 0 )\r
-#define priSUSPENDED_QUEUE_LENGTH ( 1 )\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Handles to the two counter tasks. These could be passed in as parameters\r
-to the controller task to prevent them having to be file scope. */\r
-static xTaskHandle xContinousIncrementHandle, xLimitedIncrementHandle;\r
-\r
-/* The shared counter variable. This is passed in as a parameter to the two \r
-counter variables for demonstration purposes. */\r
-static unsigned long ulCounter;\r
-\r
-/* Variables used to check that the tasks are still operating without error.\r
-Each complete iteration of the controller task increments this variable\r
-provided no errors have been found. The variable maintaining the same value\r
-is therefore indication of an error. */\r
-static volatile unsigned short usCheckVariable = ( unsigned short ) 0;\r
-static volatile portBASE_TYPE xSuspendedQueueSendError = pdFALSE;\r
-static volatile portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE;\r
-\r
-/* Queue used by the second test. */\r
-xQueueHandle xSuspendedTestQueue;\r
-\r
-/*-----------------------------------------------------------*/\r
-/*\r
- * Start the three tasks as described at the top of the file.\r
- * Note that the limited count task is given a higher priority.\r
- */\r
-void vStartDynamicPriorityTasks( void )\r
-{\r
- xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned long ) );\r
-\r
- /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
- in use. The queue registry is provided as a means for kernel aware \r
- debuggers to locate queues and has no purpose if a kernel aware debugger\r
- is not being used. The call to vQueueAddToRegistry() will be removed\r
- by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is \r
- defined to be less than 1. */\r
- vQueueAddToRegistry( xSuspendedTestQueue, ( signed char * ) "Suspended_Test_Queue" );\r
-\r
- xTaskCreate( vContinuousIncrementTask, ( signed char * ) "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinousIncrementHandle );\r
- xTaskCreate( vLimitedIncrementTask, ( signed char * ) "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );\r
- xTaskCreate( vCounterControlTask, ( signed char * ) "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
- xTaskCreate( vQueueSendWhenSuspendedTask, ( signed char * ) "SUSP_TX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
- xTaskCreate( vQueueReceiveWhenSuspendedTask, ( signed char * ) "SUSP_RX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Just loops around incrementing the shared variable until the limit has been\r
- * reached. Once the limit has been reached it suspends itself. \r
- */\r
-static portTASK_FUNCTION( vLimitedIncrementTask, pvParameters )\r
-{\r
-unsigned long *pulCounter;\r
-\r
- /* Take a pointer to the shared variable from the parameters passed into\r
- the task. */\r
- pulCounter = ( unsigned long * ) pvParameters;\r
-\r
- /* This will run before the control task, so the first thing it does is\r
- suspend - the control task will resume it when ready. */\r
- vTaskSuspend( NULL );\r
-\r
- for( ;; )\r
- {\r
- /* Just count up to a value then suspend. */\r
- ( *pulCounter )++; \r
- \r
- if( *pulCounter >= priMAX_COUNT )\r
- {\r
- vTaskSuspend( NULL );\r
- } \r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Just keep counting the shared variable up. The control task will suspend\r
- * this task when it wants.\r
- */\r
-static portTASK_FUNCTION( vContinuousIncrementTask, pvParameters )\r
-{\r
-unsigned long *pulCounter;\r
-unsigned portBASE_TYPE uxOurPriority;\r
-\r
- /* Take a pointer to the shared variable from the parameters passed into\r
- the task. */\r
- pulCounter = ( unsigned long * ) pvParameters;\r
-\r
- /* Query our priority so we can raise it when exclusive access to the \r
- shared variable is required. */\r
- uxOurPriority = uxTaskPriorityGet( NULL );\r
-\r
- for( ;; )\r
- {\r
- /* Raise our priority above the controller task to ensure a context\r
- switch does not occur while we are accessing this variable. */\r
- vTaskPrioritySet( NULL, uxOurPriority + 1 );\r
- ( *pulCounter )++; \r
- vTaskPrioritySet( NULL, uxOurPriority );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Controller task as described above.\r
- */\r
-static portTASK_FUNCTION( vCounterControlTask, pvParameters )\r
-{\r
-unsigned long ulLastCounter;\r
-short sLoops;\r
-short sError = pdFALSE;\r
-\r
- /* Just to stop warning messages. */\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* Start with the counter at zero. */\r
- ulCounter = ( unsigned long ) 0;\r
-\r
- /* First section : */\r
-\r
- /* Check the continuous count task is running. */\r
- for( sLoops = 0; sLoops < priLOOPS; sLoops++ )\r
- {\r
- /* Suspend the continuous count task so we can take a mirror of the\r
- shared variable without risk of corruption. */\r
- vTaskSuspend( xContinousIncrementHandle );\r
- ulLastCounter = ulCounter;\r
- vTaskResume( xContinousIncrementHandle );\r
- \r
- /* Now delay to ensure the other task has processor time. */\r
- vTaskDelay( priSLEEP_TIME );\r
-\r
- /* Check the shared variable again. This time to ensure mutual \r
- exclusion the whole scheduler will be locked. This is just for\r
- demo purposes! */\r
- vTaskSuspendAll();\r
- {\r
- if( ulLastCounter == ulCounter )\r
- {\r
- /* The shared variable has not changed. There is a problem\r
- with the continuous count task so flag an error. */\r
- sError = pdTRUE;\r
- }\r
- }\r
- xTaskResumeAll();\r
- }\r
-\r
-\r
- /* Second section: */\r
-\r
- /* Suspend the continuous counter task so it stops accessing the shared variable. */\r
- vTaskSuspend( xContinousIncrementHandle );\r
-\r
- /* Reset the variable. */\r
- ulCounter = ( unsigned long ) 0;\r
-\r
- /* Resume the limited count task which has a higher priority than us.\r
- We should therefore not return from this call until the limited count\r
- task has suspended itself with a known value in the counter variable. */\r
- vTaskResume( xLimitedIncrementHandle );\r
-\r
- /* Does the counter variable have the expected value? */\r
- if( ulCounter != priMAX_COUNT )\r
- {\r
- sError = pdTRUE;\r
- }\r
-\r
- if( sError == pdFALSE )\r
- {\r
- /* If no errors have occurred then increment the check variable. */\r
- portENTER_CRITICAL();\r
- usCheckVariable++;\r
- portEXIT_CRITICAL();\r
- }\r
-\r
- /* Resume the continuous count task and do it all again. */\r
- vTaskResume( xContinousIncrementHandle );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portTASK_FUNCTION( vQueueSendWhenSuspendedTask, pvParameters )\r
-{\r
-static unsigned long ulValueToSend = ( unsigned long ) 0;\r
-\r
- /* Just to stop warning messages. */\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- vTaskSuspendAll();\r
- {\r
- /* We must not block while the scheduler is suspended! */\r
- if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )\r
- {\r
- xSuspendedQueueSendError = pdTRUE;\r
- }\r
- }\r
- xTaskResumeAll();\r
-\r
- vTaskDelay( priSLEEP_TIME );\r
-\r
- ++ulValueToSend;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portTASK_FUNCTION( vQueueReceiveWhenSuspendedTask, pvParameters )\r
-{\r
-static unsigned long ulExpectedValue = ( unsigned long ) 0, ulReceivedValue;\r
-portBASE_TYPE xGotValue;\r
-\r
- /* Just to stop warning messages. */\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- do\r
- {\r
- /* Suspending the scheduler here is fairly pointless and \r
- undesirable for a normal application. It is done here purely\r
- to test the scheduler. The inner xTaskResumeAll() should\r
- never return pdTRUE as the scheduler is still locked by the\r
- outer call. */\r
- vTaskSuspendAll();\r
- {\r
- vTaskSuspendAll();\r
- {\r
- xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );\r
- }\r
- if( xTaskResumeAll() )\r
- {\r
- xSuspendedQueueReceiveError = pdTRUE;\r
- }\r
- }\r
- xTaskResumeAll();\r
-\r
- #if configUSE_PREEMPTION == 0\r
- {\r
- taskYIELD();\r
- }\r
- #endif\r
-\r
- } while( xGotValue == pdFALSE );\r
-\r
- if( ulReceivedValue != ulExpectedValue )\r
- {\r
- xSuspendedQueueReceiveError = pdTRUE;\r
- }\r
-\r
- ++ulExpectedValue;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Called to check that all the created tasks are still running without error. */\r
-portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void )\r
-{\r
-/* Keep a history of the check variables so we know if it has been incremented \r
-since the last call. */\r
-static unsigned short usLastTaskCheck = ( unsigned short ) 0;\r
-portBASE_TYPE xReturn = pdTRUE;\r
-\r
- /* Check the tasks are still running by ensuring the check variable\r
- is still incrementing. */\r
-\r
- if( usCheckVariable == usLastTaskCheck )\r
- {\r
- /* The check has not incremented so an error exists. */\r
- xReturn = pdFALSE;\r
- }\r
-\r
- if( xSuspendedQueueSendError == pdTRUE )\r
- {\r
- xReturn = pdFALSE;\r
- }\r
-\r
- if( xSuspendedQueueReceiveError == pdTRUE )\r
- {\r
- xReturn = pdFALSE;\r
- }\r
-\r
- usLastTaskCheck = usCheckVariable;\r
- return xReturn;\r
-}\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/**\r
- * This version of flash .c is for use on systems that have limited stack space\r
- * and no display facilities. The complete version can be found in the \r
- * Demo/Common/Full directory.\r
- * \r
- * Three tasks are created, each of which flash an LED at a different rate. The first \r
- * LED flashes every 200ms, the second every 400ms, the third every 600ms.\r
- *\r
- * The LED flash tasks provide instant visual feedback. They show that the scheduler \r
- * is still operational.\r
- *\r
- */\r
-\r
-\r
-#include <stdlib.h>\r
-\r
-/* Scheduler include files. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-\r
-/* Demo program include files. */\r
-#include "partest.h"\r
-#include "flash.h"\r
-\r
-#define ledSTACK_SIZE configMINIMAL_STACK_SIZE\r
-#define ledNUMBER_OF_LEDS ( 3 )\r
-#define ledFLASH_RATE_BASE ( ( portTickType ) 333 )\r
-\r
-/* Variable used by the created tasks to calculate the LED number to use, and\r
-the rate at which they should flash the LED. */\r
-static volatile unsigned portBASE_TYPE uxFlashTaskNumber = 0;\r
-\r
-/* The task that is created three times. */\r
-static portTASK_FUNCTION_PROTO( vLEDFlashTask, pvParameters );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority )\r
-{\r
-signed portBASE_TYPE xLEDTask;\r
-\r
- /* Create the three tasks. */\r
- for( xLEDTask = 0; xLEDTask < ledNUMBER_OF_LEDS; ++xLEDTask )\r
- {\r
- /* Spawn the task. */\r
- xTaskCreate( vLEDFlashTask, ( signed char * ) "LEDx", ledSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portTASK_FUNCTION( vLEDFlashTask, pvParameters )\r
-{\r
-portTickType xFlashRate, xLastFlashTime;\r
-unsigned portBASE_TYPE uxLED;\r
-\r
- /* The parameters are not used. */\r
- ( void ) pvParameters;\r
-\r
- /* Calculate the LED and flash rate. */\r
- portENTER_CRITICAL();\r
- {\r
- /* See which of the eight LED's we should use. */\r
- uxLED = uxFlashTaskNumber;\r
-\r
- /* Update so the next task uses the next LED. */\r
- uxFlashTaskNumber++;\r
- }\r
- portEXIT_CRITICAL();\r
-\r
- xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE * ( portTickType ) uxLED );\r
- xFlashRate /= portTICK_RATE_MS;\r
-\r
- /* We will turn the LED on and off again in the delay period, so each\r
- delay is only half the total period. */\r
- xFlashRate /= ( portTickType ) 2;\r
-\r
- /* We need to initialise xLastFlashTime prior to the first call to \r
- vTaskDelayUntil(). */\r
- xLastFlashTime = xTaskGetTickCount();\r
-\r
- for(;;)\r
- {\r
- /* Delay for half the flash period then turn the LED on. */\r
- vTaskDelayUntil( &xLastFlashTime, xFlashRate );\r
- vParTestToggleLED( uxLED );\r
-\r
- /* Delay for half the flash period then turn the LED off. */\r
- vTaskDelayUntil( &xLastFlashTime, xFlashRate );\r
- vParTestToggleLED( uxLED );\r
- }\r
-} /*lint !e715 !e818 !e830 Function definition must be standard for task creation. */\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef BLOCK_Q_H\r
-#define BLOCK_Q_H\r
-\r
-void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority );\r
-portBASE_TYPE xAreBlockingQueuesStillRunning( void );\r
-\r
-#endif\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef GEN_Q_TEST_H\r
-#define GEN_Q_TEST_H\r
-\r
-void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority );\r
-portBASE_TYPE xAreGenericQueueTasksStillRunning( void );\r
-\r
-#endif /* GEN_Q_TEST_H */\r
-\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef POLLED_Q_H\r
-#define POLLED_Q_H\r
-\r
-void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority );\r
-portBASE_TYPE xArePollingQueuesStillRunning( void );\r
-\r
-#endif\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef Q_PEEK_TEST_H\r
-#define Q_PEEK_TEST_H\r
-\r
-void vStartQueuePeekTasks( void );\r
-portBASE_TYPE xAreQueuePeekTasksStillRunning( void );\r
-\r
-#endif /* Q_PEEK_TEST_H */\r
-\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef TIMER_DEMO_H\r
-#define TIMER_DEMO_H\r
-\r
-void vStartTimerDemoTask( portTickType xBaseFrequencyIn );\r
-portBASE_TYPE xAreTimerDemoTasksStillRunning( portTickType xCycleFrequency );\r
-void vTimerPeriodicISRTests( void );\r
-\r
-#endif /* TIMER_DEMO_H */\r
-\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef BLOCK_TIME_TEST_H\r
-#define BLOCK_TIME_TEST_H\r
-\r
-void vCreateBlockTimeTasks( void );\r
-portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void );\r
-\r
-#endif\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef COMTEST_H\r
-#define COMTEST_H\r
-\r
-void vAltStartComTestTasks( unsigned portBASE_TYPE uxPriority, unsigned long ulBaudRate, unsigned portBASE_TYPE uxLED );\r
-void vStartComTestTasks( unsigned portBASE_TYPE uxPriority, eCOMPort ePort, eBaud eBaudRate );\r
-portBASE_TYPE xAreComTestTasksStillRunning( void );\r
-void vComTestUnsuspendTask( void );\r
-\r
-#endif\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef COMTEST_STRINGS_H\r
-#define COMTEST_STRINGS_H\r
-\r
-void vStartComTestStringsTasks( unsigned portBASE_TYPE uxPriority, unsigned long ulBaudRate, unsigned portBASE_TYPE uxLED );\r
-portBASE_TYPE xAreComTestTasksStillRunning( void );\r
-\r
-#endif\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef SUICIDE_TASK_H\r
-#define SUICIDE_TASK_H\r
-\r
-void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority );\r
-portBASE_TYPE xIsCreateTaskStillRunning( void );\r
-\r
-#endif\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef DYNAMIC_MANIPULATION_H\r
-#define DYNAMIC_MANIPULATION_H\r
-\r
-void vStartDynamicPriorityTasks( void );\r
-portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void );\r
-\r
-#endif\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef FLASH_LED_H\r
-#define FLASH_LED_H\r
-\r
-void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority );\r
-\r
-#endif\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef FLOP_TASKS_H\r
-#define FLOP_TASKS_H\r
-\r
-void vStartMathTasks( unsigned portBASE_TYPE uxPriority );\r
-portBASE_TYPE xAreMathsTaskStillRunning( void );\r
-\r
-#endif\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef PARTEST_H\r
-#define PARTEST_H\r
-\r
-#define partstDEFAULT_PORT_ADDRESS ( ( unsigned short ) 0x378 )\r
-\r
-void vParTestInitialise( void );\r
-void vParTestSetLED( unsigned portBASE_TYPE uxLED, signed portBASE_TYPE xValue );\r
-void vParTestToggleLED( unsigned portBASE_TYPE uxLED );\r
-\r
-#endif\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef RECURSIVE_MUTEX_TEST_H\r
-#define RECURSIVE_MUTEX_TEST_H\r
-\r
-void vStartRecursiveMutexTasks( void );\r
-portBASE_TYPE xAreRecursiveMutexTasksStillRunning( void );\r
-\r
-#endif\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef SEMAPHORE_TEST_H\r
-#define SEMAPHORE_TEST_H\r
-\r
-void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority );\r
-portBASE_TYPE xAreSemaphoreTasksStillRunning( void );\r
-\r
-#endif\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef SERIAL_COMMS_H\r
-#define SERIAL_COMMS_H\r
-\r
-typedef void * xComPortHandle;\r
-\r
-typedef enum\r
-{ \r
- serCOM1, \r
- serCOM2, \r
- serCOM3, \r
- serCOM4, \r
- serCOM5, \r
- serCOM6, \r
- serCOM7, \r
- serCOM8 \r
-} eCOMPort;\r
-\r
-typedef enum \r
-{ \r
- serNO_PARITY, \r
- serODD_PARITY, \r
- serEVEN_PARITY, \r
- serMARK_PARITY, \r
- serSPACE_PARITY \r
-} eParity;\r
-\r
-typedef enum \r
-{ \r
- serSTOP_1, \r
- serSTOP_2 \r
-} eStopBits;\r
-\r
-typedef enum \r
-{ \r
- serBITS_5, \r
- serBITS_6, \r
- serBITS_7, \r
- serBITS_8 \r
-} eDataBits;\r
-\r
-typedef enum \r
-{ \r
- ser50, \r
- ser75, \r
- ser110, \r
- ser134, \r
- ser150, \r
- ser200,\r
- ser300, \r
- ser600, \r
- ser1200, \r
- ser1800, \r
- ser2400, \r
- ser4800,\r
- ser9600, \r
- ser19200, \r
- ser38400, \r
- ser57600, \r
- ser115200\r
-} eBaud;\r
-\r
-xComPortHandle xSerialPortInitMinimal( unsigned long ulWantedBaud, unsigned portBASE_TYPE uxQueueLength );\r
-xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );\r
-void vSerialPutString( xComPortHandle pxPort, const signed char * const pcString, unsigned portBASE_TYPE uxStringLength );\r
-signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed char *pcRxedChar, portTickType xBlockTime );\r
-signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed char cOutChar, portTickType xBlockTime );\r
-portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort );\r
-void vSerialClose( xComPortHandle xPort );\r
-\r
-#endif\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/*\r
- The tasks defined on this page demonstrate the use of recursive mutexes.\r
-\r
- For recursive mutex functionality the created mutex should be created using\r
- xSemaphoreCreateRecursiveMutex(), then be manipulated\r
- using the xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() API\r
- functions.\r
-\r
- This demo creates three tasks all of which access the same recursive mutex:\r
-\r
- prvRecursiveMutexControllingTask() has the highest priority so executes \r
- first and grabs the mutex. It then performs some recursive accesses - \r
- between each of which it sleeps for a short period to let the lower \r
- priority tasks execute. When it has completed its demo functionality\r
- it gives the mutex back before suspending itself.\r
-\r
- prvRecursiveMutexBlockingTask() attempts to access the mutex by performing\r
- a blocking 'take'. The blocking task has a lower priority than the \r
- controlling task so by the time it executes the mutex has already been\r
- taken by the controlling task, causing the blocking task to block. It \r
- does not unblock until the controlling task has given the mutex back, \r
- and it does not actually run until the controlling task has suspended \r
- itself (due to the relative priorities). When it eventually does obtain\r
- the mutex all it does is give the mutex back prior to also suspending \r
- itself. At this point both the controlling task and the blocking task are \r
- suspended.\r
-\r
- prvRecursiveMutexPollingTask() runs at the idle priority. It spins round\r
- a tight loop attempting to obtain the mutex with a non-blocking call. As\r
- the lowest priority task it will not successfully obtain the mutex until\r
- both the controlling and blocking tasks are suspended. Once it eventually \r
- does obtain the mutex it first unsuspends both the controlling task and\r
- blocking task prior to giving the mutex back - resulting in the polling\r
- task temporarily inheriting the controlling tasks priority.\r
-*/\r
-\r
-/* Scheduler include files. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "semphr.h"\r
-\r
-/* Demo app include files. */\r
-#include "recmutex.h"\r
-\r
-/* Priorities assigned to the three tasks. */\r
-#define recmuCONTROLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
-#define recmuBLOCKING_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
-#define recmuPOLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 0 )\r
-\r
-/* The recursive call depth. */\r
-#define recmuMAX_COUNT ( 10 )\r
-\r
-/* Misc. */\r
-#define recmuSHORT_DELAY ( 20 / portTICK_RATE_MS )\r
-#define recmuNO_DELAY ( ( portTickType ) 0 )\r
-#define recmuTWO_TICK_DELAY ( ( portTickType ) 2 )\r
-\r
-/* The three tasks as described at the top of this file. */\r
-static void prvRecursiveMutexControllingTask( void *pvParameters );\r
-static void prvRecursiveMutexBlockingTask( void *pvParameters );\r
-static void prvRecursiveMutexPollingTask( void *pvParameters );\r
-\r
-/* The mutex used by the demo. */\r
-static xSemaphoreHandle xMutex;\r
-\r
-/* Variables used to detect and latch errors. */\r
-static volatile portBASE_TYPE xErrorOccurred = pdFALSE, xControllingIsSuspended = pdFALSE, xBlockingIsSuspended = pdFALSE;\r
-static volatile unsigned portBASE_TYPE uxControllingCycles = 0, uxBlockingCycles = 0, uxPollingCycles = 0;\r
-\r
-/* Handles of the two higher priority tasks, required so they can be resumed \r
-(unsuspended). */\r
-static xTaskHandle xControllingTaskHandle, xBlockingTaskHandle;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vStartRecursiveMutexTasks( void )\r
-{\r
- /* Just creates the mutex and the three tasks. */\r
-\r
- xMutex = xSemaphoreCreateRecursiveMutex();\r
-\r
- /* vQueueAddToRegistry() adds the mutex to the registry, if one is\r
- in use. The registry is provided as a means for kernel aware \r
- debuggers to locate mutex and has no purpose if a kernel aware debugger\r
- is not being used. The call to vQueueAddToRegistry() will be removed\r
- by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is \r
- defined to be less than 1. */\r
- vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Recursive_Mutex" );\r
-\r
-\r
- if( xMutex != NULL )\r
- {\r
- xTaskCreate( prvRecursiveMutexControllingTask, ( signed portCHAR * ) "Rec1", configMINIMAL_STACK_SIZE, NULL, recmuCONTROLLING_TASK_PRIORITY, &xControllingTaskHandle );\r
- xTaskCreate( prvRecursiveMutexBlockingTask, ( signed portCHAR * ) "Rec2", configMINIMAL_STACK_SIZE, NULL, recmuBLOCKING_TASK_PRIORITY, &xBlockingTaskHandle );\r
- xTaskCreate( prvRecursiveMutexPollingTask, ( signed portCHAR * ) "Rec3", configMINIMAL_STACK_SIZE, NULL, recmuPOLLING_TASK_PRIORITY, NULL );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvRecursiveMutexControllingTask( void *pvParameters )\r
-{\r
-unsigned portBASE_TYPE ux;\r
-\r
- /* Just to remove compiler warning. */\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* Should not be able to 'give' the mutex, as we have not yet 'taken'\r
- it. The first time through, the mutex will not have been used yet,\r
- subsequent times through, at this point the mutex will be held by the\r
- polling task. */\r
- if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- for( ux = 0; ux < recmuMAX_COUNT; ux++ )\r
- {\r
- /* We should now be able to take the mutex as many times as\r
- we like.\r
- \r
- The first time through the mutex will be immediately available, on\r
- subsequent times through the mutex will be held by the polling task\r
- at this point and this Take will cause the polling task to inherit\r
- the priority of this task. In this case the block time must be\r
- long enough to ensure the polling task will execute again before the\r
- block time expires. If the block time does expire then the error\r
- flag will be set here. */\r
- if( xSemaphoreTakeRecursive( xMutex, recmuTWO_TICK_DELAY ) != pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* Ensure the other task attempting to access the mutex (and the\r
- other demo tasks) are able to execute to ensure they either block\r
- (where a block time is specified) or return an error (where no \r
- block time is specified) as the mutex is held by this task. */\r
- vTaskDelay( recmuSHORT_DELAY );\r
- }\r
-\r
- /* For each time we took the mutex, give it back. */\r
- for( ux = 0; ux < recmuMAX_COUNT; ux++ )\r
- {\r
- /* Ensure the other task attempting to access the mutex (and the\r
- other demo tasks) are able to execute. */\r
- vTaskDelay( recmuSHORT_DELAY );\r
-\r
- /* We should now be able to give the mutex as many times as we\r
- took it. When the mutex is available again the Blocking task\r
- should be unblocked but not run because it has a lower priority\r
- than this task. The polling task should also not run at this point\r
- as it too has a lower priority than this task. */\r
- if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
- }\r
-\r
- /* Having given it back the same number of times as it was taken, we\r
- should no longer be the mutex owner, so the next give sh ould fail. */\r
- if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* Keep count of the number of cycles this task has performed so a \r
- stall can be detected. */\r
- uxControllingCycles++;\r
-\r
- /* Suspend ourselves to the blocking task can execute. */\r
- xControllingIsSuspended = pdTRUE;\r
- vTaskSuspend( NULL );\r
- xControllingIsSuspended = pdFALSE;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvRecursiveMutexBlockingTask( void *pvParameters )\r
-{\r
- /* Just to remove compiler warning. */\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* This task will run while the controlling task is blocked, and the\r
- controlling task will block only once it has the mutex - therefore\r
- this call should block until the controlling task has given up the \r
- mutex, and not actually execute past this call until the controlling \r
- task is suspended. */\r
- if( xSemaphoreTakeRecursive( xMutex, portMAX_DELAY ) == pdPASS )\r
- {\r
- if( xControllingIsSuspended != pdTRUE )\r
- {\r
- /* Did not expect to execute until the controlling task was\r
- suspended. */\r
- xErrorOccurred = pdTRUE;\r
- }\r
- else\r
- {\r
- /* Give the mutex back before suspending ourselves to allow\r
- the polling task to obtain the mutex. */\r
- if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- xBlockingIsSuspended = pdTRUE;\r
- vTaskSuspend( NULL );\r
- xBlockingIsSuspended = pdFALSE;\r
- }\r
- }\r
- else\r
- {\r
- /* We should not leave the xSemaphoreTakeRecursive() function\r
- until the mutex was obtained. */\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* The controlling and blocking tasks should be in lock step. */\r
- if( uxControllingCycles != ( uxBlockingCycles + 1 ) )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
-\r
- /* Keep count of the number of cycles this task has performed so a \r
- stall can be detected. */\r
- uxBlockingCycles++;\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvRecursiveMutexPollingTask( void *pvParameters )\r
-{\r
- /* Just to remove compiler warning. */\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* Keep attempting to obtain the mutex. We should only obtain it when\r
- the blocking task has suspended itself, which in turn should only\r
- happen when the controlling task is also suspended. */\r
- if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS )\r
- {\r
- /* Is the blocking task suspended? */\r
- if( ( xBlockingIsSuspended != pdTRUE ) || ( xControllingIsSuspended != pdTRUE ) )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
- else\r
- {\r
- /* Keep count of the number of cycles this task has performed \r
- so a stall can be detected. */\r
- uxPollingCycles++;\r
-\r
- /* We can resume the other tasks here even though they have a\r
- higher priority than the polling task. When they execute they\r
- will attempt to obtain the mutex but fail because the polling\r
- task is still the mutex holder. The polling task (this task)\r
- will then inherit the higher priority. The Blocking task will\r
- block indefinitely when it attempts to obtain the mutex, the\r
- Controlling task will only block for a fixed period and an\r
- error will be latched if the polling task has not returned the\r
- mutex by the time this fixed period has expired. */\r
- vTaskResume( xBlockingTaskHandle );\r
- vTaskResume( xControllingTaskHandle );\r
- \r
- /* The other two tasks should now have executed and no longer\r
- be suspended. */\r
- if( ( xBlockingIsSuspended == pdTRUE ) || ( xControllingIsSuspended == pdTRUE ) )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- } \r
- \r
- /* Release the mutex, disinheriting the higher priority again. */\r
- if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
- }\r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- {\r
- taskYIELD();\r
- }\r
- #endif\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* This is called to check that all the created tasks are still running. */\r
-portBASE_TYPE xAreRecursiveMutexTasksStillRunning( void )\r
-{\r
-portBASE_TYPE xReturn;\r
-static unsigned portBASE_TYPE uxLastControllingCycles = 0, uxLastBlockingCycles = 0, uxLastPollingCycles = 0;\r
-\r
- /* Is the controlling task still cycling? */\r
- if( uxLastControllingCycles == uxControllingCycles )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
- else\r
- {\r
- uxLastControllingCycles = uxControllingCycles;\r
- }\r
-\r
- /* Is the blocking task still cycling? */\r
- if( uxLastBlockingCycles == uxBlockingCycles )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
- else\r
- {\r
- uxLastBlockingCycles = uxBlockingCycles;\r
- }\r
-\r
- /* Is the polling task still cycling? */\r
- if( uxLastPollingCycles == uxPollingCycles )\r
- {\r
- xErrorOccurred = pdTRUE;\r
- }\r
- else\r
- {\r
- uxLastPollingCycles = uxPollingCycles;\r
- }\r
-\r
- if( xErrorOccurred == pdTRUE )\r
- {\r
- xReturn = pdFAIL;\r
- }\r
- else\r
- {\r
- xReturn = pdTRUE;\r
- }\r
-\r
- return xReturn;\r
-}\r
-\r
-\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/*\r
- * Creates two sets of two tasks. The tasks within a set share a variable, access \r
- * to which is guarded by a semaphore.\r
- * \r
- * Each task starts by attempting to obtain the semaphore. On obtaining a \r
- * semaphore a task checks to ensure that the guarded variable has an expected \r
- * value. It then clears the variable to zero before counting it back up to the \r
- * expected value in increments of 1. After each increment the variable is checked \r
- * to ensure it contains the value to which it was just set. When the starting \r
- * value is again reached the task releases the semaphore giving the other task in \r
- * the set a chance to do exactly the same thing. The starting value is high \r
- * enough to ensure that a tick is likely to occur during the incrementing loop.\r
- *\r
- * An error is flagged if at any time during the process a shared variable is \r
- * found to have a value other than that expected. Such an occurrence would \r
- * suggest an error in the mutual exclusion mechanism by which access to the \r
- * variable is restricted.\r
- *\r
- * The first set of two tasks poll their semaphore. The second set use blocking \r
- * calls.\r
- *\r
- */\r
-\r
-\r
-#include <stdlib.h>\r
-\r
-/* Scheduler include files. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "semphr.h"\r
-\r
-/* Demo app include files. */\r
-#include "semtest.h"\r
-\r
-/* The value to which the shared variables are counted. */\r
-#define semtstBLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xfff )\r
-#define semtstNON_BLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xff )\r
-\r
-#define semtstSTACK_SIZE configMINIMAL_STACK_SIZE\r
-\r
-#define semtstNUM_TASKS ( 4 )\r
-\r
-#define semtstDELAY_FACTOR ( ( portTickType ) 10 )\r
-\r
-/* The task function as described at the top of the file. */\r
-static portTASK_FUNCTION_PROTO( prvSemaphoreTest, pvParameters );\r
-\r
-/* Structure used to pass parameters to each task. */\r
-typedef struct SEMAPHORE_PARAMETERS\r
-{\r
- xSemaphoreHandle xSemaphore;\r
- volatile unsigned long *pulSharedVariable;\r
- portTickType xBlockTime;\r
-} xSemaphoreParameters;\r
-\r
-/* Variables used to check that all the tasks are still running without errors. */\r
-static volatile short sCheckVariables[ semtstNUM_TASKS ] = { 0 };\r
-static volatile short sNextCheckVariable = 0;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )\r
-{\r
-xSemaphoreParameters *pxFirstSemaphoreParameters, *pxSecondSemaphoreParameters;\r
-const portTickType xBlockTime = ( portTickType ) 100;\r
-\r
- /* Create the structure used to pass parameters to the first two tasks. */\r
- pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );\r
-\r
- if( pxFirstSemaphoreParameters != NULL )\r
- {\r
- /* Create the semaphore used by the first two tasks. */\r
- vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore );\r
-\r
- if( pxFirstSemaphoreParameters->xSemaphore != NULL )\r
- {\r
- /* Create the variable which is to be shared by the first two tasks. */\r
- pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );\r
-\r
- /* Initialise the share variable to the value the tasks expect. */\r
- *( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;\r
-\r
- /* The first two tasks do not block on semaphore calls. */\r
- pxFirstSemaphoreParameters->xBlockTime = ( portTickType ) 0;\r
-\r
- /* Spawn the first two tasks. As they poll they operate at the idle priority. */\r
- xTaskCreate( prvSemaphoreTest, ( signed char * ) "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
- xTaskCreate( prvSemaphoreTest, ( signed char * ) "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
- }\r
- }\r
-\r
- /* Do exactly the same to create the second set of tasks, only this time \r
- provide a block time for the semaphore calls. */\r
- pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );\r
- if( pxSecondSemaphoreParameters != NULL )\r
- {\r
- vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );\r
-\r
- if( pxSecondSemaphoreParameters->xSemaphore != NULL )\r
- {\r
- pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );\r
- *( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;\r
- pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_RATE_MS;\r
-\r
- xTaskCreate( prvSemaphoreTest, ( signed char * ) "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );\r
- xTaskCreate( prvSemaphoreTest, ( signed char * ) "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );\r
- }\r
- }\r
-\r
- /* vQueueAddToRegistry() adds the semaphore to the registry, if one is\r
- in use. The registry is provided as a means for kernel aware \r
- debuggers to locate semaphores and has no purpose if a kernel aware debugger\r
- is not being used. The call to vQueueAddToRegistry() will be removed\r
- by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is \r
- defined to be less than 1. */\r
- vQueueAddToRegistry( ( xQueueHandle ) pxFirstSemaphoreParameters->xSemaphore, ( signed char * ) "Counting_Sem_1" );\r
- vQueueAddToRegistry( ( xQueueHandle ) pxSecondSemaphoreParameters->xSemaphore, ( signed char * ) "Counting_Sem_2" );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portTASK_FUNCTION( prvSemaphoreTest, pvParameters )\r
-{\r
-xSemaphoreParameters *pxParameters;\r
-volatile unsigned long *pulSharedVariable, ulExpectedValue;\r
-unsigned long ulCounter;\r
-short sError = pdFALSE, sCheckVariableToUse;\r
-\r
- /* See which check variable to use. sNextCheckVariable is not semaphore \r
- protected! */\r
- portENTER_CRITICAL();\r
- sCheckVariableToUse = sNextCheckVariable;\r
- sNextCheckVariable++;\r
- portEXIT_CRITICAL();\r
-\r
- /* A structure is passed in as the parameter. This contains the shared \r
- variable being guarded. */\r
- pxParameters = ( xSemaphoreParameters * ) pvParameters;\r
- pulSharedVariable = pxParameters->pulSharedVariable;\r
-\r
- /* If we are blocking we use a much higher count to ensure loads of context\r
- switches occur during the count. */\r
- if( pxParameters->xBlockTime > ( portTickType ) 0 )\r
- {\r
- ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;\r
- }\r
- else\r
- {\r
- ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;\r
- }\r
-\r
- for( ;; )\r
- {\r
- /* Try to obtain the semaphore. */\r
- if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )\r
- {\r
- /* We have the semaphore and so expect any other tasks using the\r
- shared variable to have left it in the state we expect to find\r
- it. */\r
- if( *pulSharedVariable != ulExpectedValue )\r
- {\r
- sError = pdTRUE;\r
- }\r
- \r
- /* Clear the variable, then count it back up to the expected value\r
- before releasing the semaphore. Would expect a context switch or\r
- two during this time. */\r
- for( ulCounter = ( unsigned long ) 0; ulCounter <= ulExpectedValue; ulCounter++ )\r
- {\r
- *pulSharedVariable = ulCounter;\r
- if( *pulSharedVariable != ulCounter )\r
- {\r
- sError = pdTRUE;\r
- }\r
- }\r
-\r
- /* Release the semaphore, and if no errors have occurred increment the check\r
- variable. */\r
- if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )\r
- {\r
- sError = pdTRUE;\r
- }\r
-\r
- if( sError == pdFALSE )\r
- {\r
- if( sCheckVariableToUse < semtstNUM_TASKS )\r
- {\r
- ( sCheckVariables[ sCheckVariableToUse ] )++;\r
- }\r
- }\r
-\r
- /* If we have a block time then we are running at a priority higher\r
- than the idle priority. This task takes a long time to complete\r
- a cycle (deliberately so to test the guarding) so will be starving\r
- out lower priority tasks. Block for some time to allow give lower\r
- priority tasks some processor time. */\r
- vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );\r
- }\r
- else\r
- {\r
- if( pxParameters->xBlockTime == ( portTickType ) 0 )\r
- {\r
- /* We have not got the semaphore yet, so no point using the\r
- processor. We are not blocking when attempting to obtain the\r
- semaphore. */\r
- taskYIELD();\r
- }\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* This is called to check that all the created tasks are still running. */\r
-portBASE_TYPE xAreSemaphoreTasksStillRunning( void )\r
-{\r
-static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };\r
-portBASE_TYPE xTask, xReturn = pdTRUE;\r
-\r
- for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )\r
- {\r
- if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )\r
- {\r
- xReturn = pdFALSE;\r
- }\r
-\r
- sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];\r
- }\r
-\r
- return xReturn;\r
-}\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/*\r
- * Creates eight tasks, each of which loops continuously performing a floating \r
- * point calculation - using single precision variables.\r
- *\r
- * All the tasks run at the idle priority and never block or yield. This causes \r
- * all eight tasks to time slice with the idle task, and other idle priority\r
- * tasks. Running at the idle priority means that these tasks will get \r
- * pre-empted any time another task is ready to run or a time slice occurs. \r
- * More often than not the pre-emption will occur mid calculation, creating a \r
- * good test of the schedulers context switch mechanism - a calculation \r
- * producing an unexpected result could be a symptom of a corruption in the \r
- * context of a task.\r
- */\r
-\r
-/* Standard includes. */\r
-#include <stdlib.h>\r
-#include <math.h>\r
-\r
-/* Scheduler include files. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-\r
-/* Demo program include files. */\r
-#include "flop.h"\r
-\r
-/* The size of the stack allocated to each floating point test task. */\r
-#define mathSTACK_SIZE configMINIMAL_STACK_SIZE\r
-\r
-/* The number of tasks that are created. */\r
-#define mathNUMBER_OF_TASKS ( 8 )\r
-\r
-/* Four tasks, each of which performs a different floating point calculation. \r
-Each of the four is created twice. */\r
-static void prvCompetingMathTask1( void *pvParameters );\r
-static void prvCompetingMathTask2( void *pvParameters );\r
-static void prvCompetingMathTask3( void *pvParameters );\r
-static void prvCompetingMathTask4( void *pvParameters );\r
-\r
-/* These variables are used to check that all the tasks are still running. If a \r
-task gets a calculation wrong it will stop incrementing its check variable. */\r
-static volatile unsigned short usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vStartMathTasks( unsigned portBASE_TYPE uxPriority )\r
-{\r
- xTaskCreate( prvCompetingMathTask1, ( signed char * ) "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );\r
- xTaskCreate( prvCompetingMathTask2, ( signed char * ) "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );\r
- xTaskCreate( prvCompetingMathTask3, ( signed char * ) "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );\r
- xTaskCreate( prvCompetingMathTask4, ( signed char * ) "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );\r
- xTaskCreate( prvCompetingMathTask1, ( signed char * ) "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );\r
- xTaskCreate( prvCompetingMathTask2, ( signed char * ) "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );\r
- xTaskCreate( prvCompetingMathTask3, ( signed char * ) "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );\r
- xTaskCreate( prvCompetingMathTask4, ( signed char * ) "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCompetingMathTask1( void *pvParameters )\r
-{\r
-volatile float f1, f2, f3, f4;\r
-volatile unsigned short *pusTaskCheckVariable;\r
-volatile float fAnswer;\r
-short sError = pdFALSE;\r
-\r
- f1 = 123.4567F;\r
- f2 = 2345.6789F;\r
- f3 = -918.222F;\r
-\r
- fAnswer = ( f1 + f2 ) * f3;\r
-\r
- /* The variable this task increments to show it is still running is passed in \r
- as the parameter. */\r
- pusTaskCheckVariable = ( unsigned short * ) pvParameters;\r
-\r
- /* Keep performing a calculation and checking the result against a constant. */\r
- for(;;)\r
- {\r
- f1 = 123.4567F;\r
- f2 = 2345.6789F;\r
- f3 = -918.222F;\r
-\r
- f4 = ( f1 + f2 ) * f3;\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
-\r
- /* If the calculation does not match the expected constant, stop the \r
- increment of the check variable. */\r
- if( fabs( f4 - fAnswer ) > 0.001F )\r
- {\r
- sError = pdTRUE;\r
- }\r
-\r
- if( sError == pdFALSE )\r
- {\r
- /* If the calculation has always been correct, increment the check \r
- variable so we know this task is still running okay. */\r
- ( *pusTaskCheckVariable )++;\r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
-\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCompetingMathTask2( void *pvParameters )\r
-{\r
-volatile float f1, f2, f3, f4;\r
-volatile unsigned short *pusTaskCheckVariable;\r
-volatile float fAnswer;\r
-short sError = pdFALSE;\r
-\r
- f1 = -389.38F;\r
- f2 = 32498.2F;\r
- f3 = -2.0001F;\r
-\r
- fAnswer = ( f1 / f2 ) * f3;\r
-\r
-\r
- /* The variable this task increments to show it is still running is passed in \r
- as the parameter. */\r
- pusTaskCheckVariable = ( unsigned short * ) pvParameters;\r
-\r
- /* Keep performing a calculation and checking the result against a constant. */\r
- for( ;; )\r
- {\r
- f1 = -389.38F;\r
- f2 = 32498.2F;\r
- f3 = -2.0001F;\r
-\r
- f4 = ( f1 / f2 ) * f3;\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
- \r
- /* If the calculation does not match the expected constant, stop the \r
- increment of the check variable. */\r
- if( fabs( f4 - fAnswer ) > 0.001F )\r
- {\r
- sError = pdTRUE;\r
- }\r
-\r
- if( sError == pdFALSE )\r
- {\r
- /* If the calculation has always been correct, increment the check \r
- variable so we know\r
- this task is still running okay. */\r
- ( *pusTaskCheckVariable )++;\r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCompetingMathTask3( void *pvParameters )\r
-{\r
-volatile float *pfArray, fTotal1, fTotal2, fDifference, fPosition;\r
-volatile unsigned short *pusTaskCheckVariable;\r
-const size_t xArraySize = 10;\r
-size_t xPosition;\r
-short sError = pdFALSE;\r
-\r
- /* The variable this task increments to show it is still running is passed in \r
- as the parameter. */\r
- pusTaskCheckVariable = ( unsigned short * ) pvParameters;\r
-\r
- pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) );\r
-\r
- /* Keep filling an array, keeping a running total of the values placed in the \r
- array. Then run through the array adding up all the values. If the two totals \r
- do not match, stop the check variable from incrementing. */\r
- for( ;; )\r
- {\r
- fTotal1 = 0.0F;\r
- fTotal2 = 0.0F;\r
- fPosition = 0.0F;\r
- \r
- for( xPosition = 0; xPosition < xArraySize; xPosition++ )\r
- {\r
- pfArray[ xPosition ] = fPosition + 5.5F;\r
- fTotal1 += fPosition + 5.5F; \r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
-\r
- for( xPosition = 0; xPosition < xArraySize; xPosition++ )\r
- {\r
- fTotal2 += pfArray[ xPosition ];\r
- }\r
-\r
- fDifference = fTotal1 - fTotal2;\r
- if( fabs( fDifference ) > 0.001F )\r
- {\r
- sError = pdTRUE;\r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
-\r
- if( sError == pdFALSE )\r
- {\r
- /* If the calculation has always been correct, increment the check \r
- variable so we know this task is still running okay. */\r
- ( *pusTaskCheckVariable )++;\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCompetingMathTask4( void *pvParameters )\r
-{\r
-volatile float *pfArray, fTotal1, fTotal2, fDifference, fPosition;\r
-volatile unsigned short *pusTaskCheckVariable;\r
-const size_t xArraySize = 10;\r
-size_t xPosition;\r
-short sError = pdFALSE;\r
-\r
- /* The variable this task increments to show it is still running is passed in \r
- as the parameter. */\r
- pusTaskCheckVariable = ( unsigned short * ) pvParameters;\r
-\r
- pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) );\r
-\r
- /* Keep filling an array, keeping a running total of the values placed in the \r
- array. Then run through the array adding up all the values. If the two totals \r
- do not match, stop the check variable from incrementing. */\r
- for( ;; )\r
- {\r
- fTotal1 = 0.0F;\r
- fTotal2 = 0.0F;\r
- fPosition = 0.0F;\r
-\r
- for( xPosition = 0; xPosition < xArraySize; xPosition++ )\r
- {\r
- pfArray[ xPosition ] = fPosition * 12.123F;\r
- fTotal1 += fPosition * 12.123F; \r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
-\r
- for( xPosition = 0; xPosition < xArraySize; xPosition++ )\r
- {\r
- fTotal2 += pfArray[ xPosition ];\r
- }\r
-\r
- fDifference = fTotal1 - fTotal2;\r
- if( fabs( fDifference ) > 0.001F )\r
- {\r
- sError = pdTRUE;\r
- }\r
-\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
-\r
- if( sError == pdFALSE )\r
- {\r
- /* If the calculation has always been correct, increment the check \r
- variable so we know this task is still running okay. */\r
- ( *pusTaskCheckVariable )++;\r
- }\r
- }\r
-} \r
-/*-----------------------------------------------------------*/\r
-\r
-/* This is called to check that all the created tasks are still running. */\r
-portBASE_TYPE xAreMathsTaskStillRunning( void )\r
-{\r
-/* Keep a history of the check variables so it can be determined if they have \r
-been incremented since the last call of this function. */\r
-static unsigned short usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };\r
-portBASE_TYPE xReturn = pdTRUE, xTask;\r
-\r
- /* Check the maths tasks are still running by ensuring their check variables \r
- are still incrementing. */\r
- for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )\r
- {\r
- if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )\r
- {\r
- /* The check has not incremented so an error exists. */\r
- xReturn = pdFALSE;\r
- }\r
-\r
- usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];\r
- }\r
-\r
- return xReturn;\r
-}\r
-\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef INC_FREERTOS_H\r
-#define INC_FREERTOS_H\r
-\r
-\r
-/*\r
- * Include the generic headers required for the FreeRTOS port being used.\r
- */\r
-#include <stddef.h>\r
-\r
-/* Basic FreeRTOS definitions. */\r
-#include "projdefs.h"\r
-\r
-/* Application specific configuration options. */\r
-#include "FreeRTOSConfig.h"\r
-\r
-/* Definitions specific to the port being used. */\r
-#include "portable.h"\r
-\r
-\r
-/* Defines the prototype to which the application task hook function must\r
-conform. */\r
-typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * );\r
-\r
-\r
-\r
-\r
-\r
-/*\r
- * Check all the required application specific macros have been defined.\r
- * These macros are application specific and (as downloaded) are defined\r
- * within FreeRTOSConfig.h.\r
- */\r
-\r
-#ifndef configUSE_PREEMPTION\r
- #error Missing definition: configUSE_PREEMPTION should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef configUSE_IDLE_HOOK\r
- #error Missing definition: configUSE_IDLE_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef configUSE_TICK_HOOK\r
- #error Missing definition: configUSE_TICK_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef configUSE_CO_ROUTINES\r
- #error Missing definition: configUSE_CO_ROUTINES should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef INCLUDE_vTaskPrioritySet\r
- #error Missing definition: INCLUDE_vTaskPrioritySet should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef INCLUDE_uxTaskPriorityGet\r
- #error Missing definition: INCLUDE_uxTaskPriorityGet should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef INCLUDE_vTaskDelete \r
- #error Missing definition: INCLUDE_vTaskDelete should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef INCLUDE_vTaskCleanUpResources\r
- #error Missing definition: INCLUDE_vTaskCleanUpResources should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef INCLUDE_vTaskSuspend \r
- #error Missing definition: INCLUDE_vTaskSuspend should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef INCLUDE_vTaskDelayUntil\r
- #error Missing definition: INCLUDE_vTaskDelayUntil should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef INCLUDE_vTaskDelay\r
- #error Missing definition: INCLUDE_vTaskDelay should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef configUSE_16_BIT_TICKS\r
- #error Missing definition: configUSE_16_BIT_TICKS should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.\r
-#endif\r
-\r
-#ifndef configUSE_APPLICATION_TASK_TAG\r
- #define configUSE_APPLICATION_TASK_TAG 0\r
-#endif\r
-\r
-#ifndef INCLUDE_uxTaskGetStackHighWaterMark\r
- #define INCLUDE_uxTaskGetStackHighWaterMark 0\r
-#endif\r
-\r
-#ifndef configUSE_RECURSIVE_MUTEXES\r
- #define configUSE_RECURSIVE_MUTEXES 0\r
-#endif\r
-\r
-#ifndef configUSE_MUTEXES\r
- #define configUSE_MUTEXES 0\r
-#endif\r
-\r
-#ifndef configUSE_TIMERS\r
- #define configUSE_TIMERS 0\r
-#endif\r
-\r
-#ifndef configUSE_COUNTING_SEMAPHORES\r
- #define configUSE_COUNTING_SEMAPHORES 0\r
-#endif\r
-\r
-#ifndef configUSE_ALTERNATIVE_API\r
- #define configUSE_ALTERNATIVE_API 0\r
-#endif\r
-\r
-#ifndef portCRITICAL_NESTING_IN_TCB\r
- #define portCRITICAL_NESTING_IN_TCB 0\r
-#endif\r
-\r
-#ifndef configMAX_TASK_NAME_LEN\r
- #define configMAX_TASK_NAME_LEN 16\r
-#endif\r
-\r
-#ifndef configIDLE_SHOULD_YIELD\r
- #define configIDLE_SHOULD_YIELD 1\r
-#endif\r
-\r
-#if configMAX_TASK_NAME_LEN < 1\r
- #error configMAX_TASK_NAME_LEN must be set to a minimum of 1 in FreeRTOSConfig.h\r
-#endif\r
-\r
-#ifndef INCLUDE_xTaskResumeFromISR\r
- #define INCLUDE_xTaskResumeFromISR 1\r
-#endif\r
-\r
-#ifndef configASSERT\r
- #define configASSERT( x )\r
-#endif\r
-\r
-/* The timers module relies on xTaskGetSchedulerState(). */\r
-#if configUSE_TIMERS == 1\r
-\r
- #ifndef configTIMER_TASK_PRIORITY\r
- #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_PRIORITY must also be defined.\r
- #endif /* configTIMER_TASK_PRIORITY */\r
-\r
- #ifndef configTIMER_QUEUE_LENGTH\r
- #error If configUSE_TIMERS is set to 1 then configTIMER_QUEUE_LENGTH must also be defined.\r
- #endif /* configTIMER_QUEUE_LENGTH */\r
-\r
- #ifndef configTIMER_TASK_STACK_DEPTH\r
- #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_STACK_DEPTH must also be defined.\r
- #endif /* configTIMER_TASK_STACK_DEPTH */\r
-\r
-#endif /* configUSE_TIMERS */\r
-\r
-#ifndef INCLUDE_xTaskGetSchedulerState\r
- #define INCLUDE_xTaskGetSchedulerState 0\r
-#endif\r
-\r
-#ifndef INCLUDE_xTaskGetCurrentTaskHandle\r
- #define INCLUDE_xTaskGetCurrentTaskHandle 0\r
-#endif\r
-\r
-\r
-#ifndef portSET_INTERRUPT_MASK_FROM_ISR\r
- #define portSET_INTERRUPT_MASK_FROM_ISR() 0\r
-#endif\r
-\r
-#ifndef portCLEAR_INTERRUPT_MASK_FROM_ISR\r
- #define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) uxSavedStatusValue\r
-#endif\r
-\r
-\r
-#ifndef configQUEUE_REGISTRY_SIZE\r
- #define configQUEUE_REGISTRY_SIZE 0U\r
-#endif\r
-\r
-#if ( configQUEUE_REGISTRY_SIZE < 1U )\r
- #define vQueueAddToRegistry( xQueue, pcName )\r
- #define vQueueUnregisterQueue( xQueue )\r
-#endif\r
-\r
-\r
-/* Remove any unused trace macros. */\r
-#ifndef traceSTART\r
- /* Used to perform any necessary initialisation - for example, open a file\r
- into which trace is to be written. */\r
- #define traceSTART()\r
-#endif\r
-\r
-#ifndef traceEND\r
- /* Use to close a trace, for example close a file into which trace has been\r
- written. */\r
- #define traceEND()\r
-#endif\r
-\r
-#ifndef traceTASK_SWITCHED_IN\r
- /* Called after a task has been selected to run. pxCurrentTCB holds a pointer\r
- to the task control block of the selected task. */\r
- #define traceTASK_SWITCHED_IN()\r
-#endif\r
-\r
-#ifndef traceTASK_SWITCHED_OUT\r
- /* Called before a task has been selected to run. pxCurrentTCB holds a pointer\r
- to the task control block of the task being switched out. */\r
- #define traceTASK_SWITCHED_OUT()\r
-#endif\r
-\r
-#ifndef traceBLOCKING_ON_QUEUE_RECEIVE\r
- /* Task is about to block because it cannot read from a\r
- queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore\r
- upon which the read was attempted. pxCurrentTCB points to the TCB of the\r
- task that attempted the read. */\r
- #define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue )\r
-#endif\r
-\r
-#ifndef traceBLOCKING_ON_QUEUE_SEND\r
- /* Task is about to block because it cannot write to a\r
- queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore\r
- upon which the write was attempted. pxCurrentTCB points to the TCB of the\r
- task that attempted the write. */\r
- #define traceBLOCKING_ON_QUEUE_SEND( pxQueue )\r
-#endif\r
-\r
-#ifndef configCHECK_FOR_STACK_OVERFLOW\r
- #define configCHECK_FOR_STACK_OVERFLOW 0\r
-#endif\r
-\r
-/* The following event macros are embedded in the kernel API calls. */\r
-\r
-#ifndef traceQUEUE_CREATE \r
- #define traceQUEUE_CREATE( pxNewQueue )\r
-#endif\r
-\r
-#ifndef traceQUEUE_CREATE_FAILED\r
- #define traceQUEUE_CREATE_FAILED()\r
-#endif\r
-\r
-#ifndef traceCREATE_MUTEX\r
- #define traceCREATE_MUTEX( pxNewQueue )\r
-#endif\r
-\r
-#ifndef traceCREATE_MUTEX_FAILED\r
- #define traceCREATE_MUTEX_FAILED()\r
-#endif\r
-\r
-#ifndef traceGIVE_MUTEX_RECURSIVE\r
- #define traceGIVE_MUTEX_RECURSIVE( pxMutex )\r
-#endif\r
-\r
-#ifndef traceGIVE_MUTEX_RECURSIVE_FAILED\r
- #define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex )\r
-#endif\r
-\r
-#ifndef traceTAKE_MUTEX_RECURSIVE\r
- #define traceTAKE_MUTEX_RECURSIVE( pxMutex )\r
-#endif\r
-\r
-#ifndef traceTAKE_MUTEX_RECURSIVE_FAILED\r
- #define traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex )\r
-#endif\r
-\r
-#ifndef traceCREATE_COUNTING_SEMAPHORE\r
- #define traceCREATE_COUNTING_SEMAPHORE()\r
-#endif\r
-\r
-#ifndef traceCREATE_COUNTING_SEMAPHORE_FAILED\r
- #define traceCREATE_COUNTING_SEMAPHORE_FAILED()\r
-#endif\r
-\r
-#ifndef traceQUEUE_SEND\r
- #define traceQUEUE_SEND( pxQueue )\r
-#endif\r
-\r
-#ifndef traceQUEUE_SEND_FAILED\r
- #define traceQUEUE_SEND_FAILED( pxQueue )\r
-#endif\r
-\r
-#ifndef traceQUEUE_RECEIVE\r
- #define traceQUEUE_RECEIVE( pxQueue )\r
-#endif\r
-\r
-#ifndef traceQUEUE_PEEK\r
- #define traceQUEUE_PEEK( pxQueue )\r
-#endif\r
-\r
-#ifndef traceQUEUE_RECEIVE_FAILED\r
- #define traceQUEUE_RECEIVE_FAILED( pxQueue )\r
-#endif\r
-\r
-#ifndef traceQUEUE_SEND_FROM_ISR\r
- #define traceQUEUE_SEND_FROM_ISR( pxQueue )\r
-#endif\r
-\r
-#ifndef traceQUEUE_SEND_FROM_ISR_FAILED\r
- #define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue )\r
-#endif\r
-\r
-#ifndef traceQUEUE_RECEIVE_FROM_ISR\r
- #define traceQUEUE_RECEIVE_FROM_ISR( pxQueue )\r
-#endif\r
-\r
-#ifndef traceQUEUE_RECEIVE_FROM_ISR_FAILED\r
- #define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue )\r
-#endif\r
-\r
-#ifndef traceQUEUE_DELETE\r
- #define traceQUEUE_DELETE( pxQueue )\r
-#endif\r
-\r
-#ifndef traceTASK_CREATE\r
- #define traceTASK_CREATE( pxNewTCB )\r
-#endif\r
-\r
-#ifndef traceTASK_CREATE_FAILED\r
- #define traceTASK_CREATE_FAILED()\r
-#endif\r
-\r
-#ifndef traceTASK_DELETE\r
- #define traceTASK_DELETE( pxTaskToDelete )\r
-#endif\r
-\r
-#ifndef traceTASK_DELAY_UNTIL\r
- #define traceTASK_DELAY_UNTIL()\r
-#endif\r
-\r
-#ifndef traceTASK_DELAY\r
- #define traceTASK_DELAY()\r
-#endif\r
-\r
-#ifndef traceTASK_PRIORITY_SET\r
- #define traceTASK_PRIORITY_SET( pxTask, uxNewPriority )\r
-#endif\r
-\r
-#ifndef traceTASK_SUSPEND\r
- #define traceTASK_SUSPEND( pxTaskToSuspend )\r
-#endif\r
-\r
-#ifndef traceTASK_RESUME\r
- #define traceTASK_RESUME( pxTaskToResume )\r
-#endif\r
-\r
-#ifndef traceTASK_RESUME_FROM_ISR\r
- #define traceTASK_RESUME_FROM_ISR( pxTaskToResume )\r
-#endif\r
-\r
-#ifndef traceTASK_INCREMENT_TICK\r
- #define traceTASK_INCREMENT_TICK( xTickCount )\r
-#endif\r
-\r
-#ifndef traceTIMER_CREATE\r
- #define traceTIMER_CREATE( pxNewTimer )\r
-#endif\r
-\r
-#ifndef traceTIMER_CREATE_FAILED\r
- #define traceTIMER_CREATE_FAILED()\r
-#endif\r
-\r
-#ifndef traceTIMER_COMMAND_SEND\r
- #define traceTIMER_COMMAND_SEND( xTimer, xMessageID, xMessageValueValue, xReturn )\r
-#endif\r
-\r
-#ifndef traceTIMER_EXPIRED\r
- #define traceTIMER_EXPIRED( pxTimer )\r
-#endif\r
-\r
-#ifndef traceTIMER_COMMAND_RECEIVED\r
- #define traceTIMER_COMMAND_RECEIVED( pxTimer, xMessageID, xMessageValue )\r
-#endif\r
-\r
-#ifndef configGENERATE_RUN_TIME_STATS\r
- #define configGENERATE_RUN_TIME_STATS 0\r
-#endif\r
-\r
-#if ( configGENERATE_RUN_TIME_STATS == 1 )\r
-\r
- #ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS\r
- #error If configGENERATE_RUN_TIME_STATS is defined then portCONFIGURE_TIMER_FOR_RUN_TIME_STATS must also be defined. portCONFIGURE_TIMER_FOR_RUN_TIME_STATS should call a port layer function to setup a peripheral timer/counter that can then be used as the run time counter time base.\r
- #endif /* portCONFIGURE_TIMER_FOR_RUN_TIME_STATS */\r
-\r
- #ifndef portGET_RUN_TIME_COUNTER_VALUE\r
- #ifndef portALT_GET_RUN_TIME_COUNTER_VALUE\r
- #error If configGENERATE_RUN_TIME_STATS is defined then either portGET_RUN_TIME_COUNTER_VALUE or portALT_GET_RUN_TIME_COUNTER_VALUE must also be defined. See the examples provided and the FreeRTOS web site for more information.\r
- #endif /* portALT_GET_RUN_TIME_COUNTER_VALUE */\r
- #endif /* portGET_RUN_TIME_COUNTER_VALUE */\r
-\r
-#endif /* configGENERATE_RUN_TIME_STATS */\r
-\r
-#ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS\r
- #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()\r
-#endif\r
-\r
-#ifndef configUSE_MALLOC_FAILED_HOOK\r
- #define configUSE_MALLOC_FAILED_HOOK 0\r
-#endif\r
-\r
-#ifndef portPRIVILEGE_BIT\r
- #define portPRIVILEGE_BIT ( ( unsigned portBASE_TYPE ) 0x00 )\r
-#endif\r
-\r
-#ifndef portYIELD_WITHIN_API\r
- #define portYIELD_WITHIN_API portYIELD\r
-#endif\r
-\r
-#ifndef pvPortMallocAligned\r
- #define pvPortMallocAligned( x, puxStackBuffer ) ( ( ( puxStackBuffer ) == NULL ) ? ( pvPortMalloc( ( x ) ) ) : ( puxStackBuffer ) )\r
-#endif\r
-\r
-#ifndef vPortFreeAligned\r
- #define vPortFreeAligned( pvBlockToFree ) vPortFree( pvBlockToFree )\r
-#endif\r
-\r
-#endif /* INC_FREERTOS_H */\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef STACK_MACROS_H\r
-#define STACK_MACROS_H\r
-\r
-/*\r
- * Call the stack overflow hook function if the stack of the task being swapped\r
- * out is currently overflowed, or looks like it might have overflowed in the\r
- * past.\r
- *\r
- * Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check\r
- * the current stack state only - comparing the current top of stack value to\r
- * the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1\r
- * will also cause the last few stack bytes to be checked to ensure the value\r
- * to which the bytes were set when the task was created have not been\r
- * overwritten. Note this second test does not guarantee that an overflowed\r
- * stack will always be recognised.\r
- */\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( configCHECK_FOR_STACK_OVERFLOW == 0 )\r
-\r
- /* FreeRTOSConfig.h is not set to check for stack overflows. */\r
- #define taskFIRST_CHECK_FOR_STACK_OVERFLOW()\r
- #define taskSECOND_CHECK_FOR_STACK_OVERFLOW()\r
-\r
-#endif /* configCHECK_FOR_STACK_OVERFLOW == 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( configCHECK_FOR_STACK_OVERFLOW == 1 )\r
-\r
- /* FreeRTOSConfig.h is only set to use the first method of\r
- overflow checking. */\r
- #define taskSECOND_CHECK_FOR_STACK_OVERFLOW()\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH < 0 ) )\r
-\r
- /* Only the current stack state is to be checked. */\r
- #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() \\r
- { \\r
- /* Is the currently saved stack pointer within the stack limit? */ \\r
- if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \\r
- { \\r
- vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \\r
- } \\r
- }\r
-\r
-#endif /* configCHECK_FOR_STACK_OVERFLOW > 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH > 0 ) )\r
-\r
- /* Only the current stack state is to be checked. */\r
- #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() \\r
- { \\r
- \\r
- /* Is the currently saved stack pointer within the stack limit? */ \\r
- if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \\r
- { \\r
- vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \\r
- } \\r
- }\r
-\r
-#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) )\r
-\r
- #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \\r
- { \\r
- static const unsigned char ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \\r
- tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \\r
- tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \\r
- tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \\r
- tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \\r
- \\r
- \\r
- /* Has the extremity of the task stack ever been written over? */ \\r
- if( memcmp( ( void * ) pxCurrentTCB->pxStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \\r
- { \\r
- vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \\r
- } \\r
- }\r
-\r
-#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) )\r
-\r
- #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \\r
- { \\r
- char *pcEndOfStack = ( char * ) pxCurrentTCB->pxEndOfStack; \\r
- static const unsigned char ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \\r
- tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \\r
- tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \\r
- tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \\r
- tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \\r
- \\r
- \\r
- pcEndOfStack -= sizeof( ucExpectedStackBytes ); \\r
- \\r
- /* Has the extremity of the task stack ever been written over? */ \\r
- if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \\r
- { \\r
- vApplicationStackOverflowHook( ( xTaskHandle ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \\r
- } \\r
- }\r
-\r
-#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */\r
-/*-----------------------------------------------------------*/\r
-\r
-#endif /* STACK_MACROS_H */\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef CO_ROUTINE_H\r
-#define CO_ROUTINE_H\r
-\r
-#ifndef INC_FREERTOS_H\r
- #error "include FreeRTOS.h must appear in source files before include croutine.h"\r
-#endif\r
-\r
-#include "list.h"\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-/* Used to hide the implementation of the co-routine control block. The\r
-control block structure however has to be included in the header due to\r
-the macro implementation of the co-routine functionality. */\r
-typedef void * xCoRoutineHandle;\r
-\r
-/* Defines the prototype to which co-routine functions must conform. */\r
-typedef void (*crCOROUTINE_CODE)( xCoRoutineHandle, unsigned portBASE_TYPE );\r
-\r
-typedef struct corCoRoutineControlBlock\r
-{\r
- crCOROUTINE_CODE pxCoRoutineFunction;\r
- xListItem xGenericListItem; /*< List item used to place the CRCB in ready and blocked queues. */\r
- xListItem xEventListItem; /*< List item used to place the CRCB in event lists. */\r
- unsigned portBASE_TYPE uxPriority; /*< The priority of the co-routine in relation to other co-routines. */\r
- unsigned portBASE_TYPE uxIndex; /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */\r
- unsigned short uxState; /*< Used internally by the co-routine implementation. */\r
-} corCRCB; /* Co-routine control block. Note must be identical in size down to uxPriority with tskTCB. */\r
-\r
-/**\r
- * croutine. h\r
- *<pre>\r
- portBASE_TYPE xCoRoutineCreate(\r
- crCOROUTINE_CODE pxCoRoutineCode,\r
- unsigned portBASE_TYPE uxPriority,\r
- unsigned portBASE_TYPE uxIndex\r
- );</pre>\r
- *\r
- * Create a new co-routine and add it to the list of co-routines that are\r
- * ready to run.\r
- *\r
- * @param pxCoRoutineCode Pointer to the co-routine function. Co-routine\r
- * functions require special syntax - see the co-routine section of the WEB\r
- * documentation for more information.\r
- *\r
- * @param uxPriority The priority with respect to other co-routines at which\r
- * the co-routine will run.\r
- *\r
- * @param uxIndex Used to distinguish between different co-routines that\r
- * execute the same function. See the example below and the co-routine section\r
- * of the WEB documentation for further information.\r
- *\r
- * @return pdPASS if the co-routine was successfully created and added to a ready\r
- * list, otherwise an error code defined with ProjDefs.h.\r
- *\r
- * Example usage:\r
- <pre>\r
- // Co-routine to be created.\r
- void vFlashCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )\r
- {\r
- // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
- // This may not be necessary for const variables.\r
- static const char cLedToFlash[ 2 ] = { 5, 6 };\r
- static const portTickType uxFlashRates[ 2 ] = { 200, 400 };\r
-\r
- // Must start every co-routine with a call to crSTART();\r
- crSTART( xHandle );\r
-\r
- for( ;; )\r
- {\r
- // This co-routine just delays for a fixed period, then toggles\r
- // an LED. Two co-routines are created using this function, so\r
- // the uxIndex parameter is used to tell the co-routine which\r
- // LED to flash and how long to delay. This assumes xQueue has\r
- // already been created.\r
- vParTestToggleLED( cLedToFlash[ uxIndex ] );\r
- crDELAY( xHandle, uxFlashRates[ uxIndex ] );\r
- }\r
-\r
- // Must end every co-routine with a call to crEND();\r
- crEND();\r
- }\r
-\r
- // Function that creates two co-routines.\r
- void vOtherFunction( void )\r
- {\r
- unsigned char ucParameterToPass;\r
- xTaskHandle xHandle;\r
- \r
- // Create two co-routines at priority 0. The first is given index 0\r
- // so (from the code above) toggles LED 5 every 200 ticks. The second\r
- // is given index 1 so toggles LED 6 every 400 ticks.\r
- for( uxIndex = 0; uxIndex < 2; uxIndex++ )\r
- {\r
- xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );\r
- }\r
- }\r
- </pre>\r
- * \defgroup xCoRoutineCreate xCoRoutineCreate\r
- * \ingroup Tasks\r
- */\r
-signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex );\r
-\r
-\r
-/**\r
- * croutine. h\r
- *<pre>\r
- void vCoRoutineSchedule( void );</pre>\r
- *\r
- * Run a co-routine.\r
- *\r
- * vCoRoutineSchedule() executes the highest priority co-routine that is able\r
- * to run. The co-routine will execute until it either blocks, yields or is\r
- * preempted by a task. Co-routines execute cooperatively so one\r
- * co-routine cannot be preempted by another, but can be preempted by a task.\r
- *\r
- * If an application comprises of both tasks and co-routines then\r
- * vCoRoutineSchedule should be called from the idle task (in an idle task\r
- * hook).\r
- *\r
- * Example usage:\r
- <pre>\r
- // This idle task hook will schedule a co-routine each time it is called.\r
- // The rest of the idle task will execute between co-routine calls.\r
- void vApplicationIdleHook( void )\r
- {\r
- vCoRoutineSchedule();\r
- }\r
-\r
- // Alternatively, if you do not require any other part of the idle task to\r
- // execute, the idle task hook can call vCoRoutineScheduler() within an\r
- // infinite loop.\r
- void vApplicationIdleHook( void )\r
- {\r
- for( ;; )\r
- {\r
- vCoRoutineSchedule();\r
- }\r
- }\r
- </pre>\r
- * \defgroup vCoRoutineSchedule vCoRoutineSchedule\r
- * \ingroup Tasks\r
- */\r
-void vCoRoutineSchedule( void );\r
-\r
-/**\r
- * croutine. h\r
- * <pre>\r
- crSTART( xCoRoutineHandle xHandle );</pre>\r
- *\r
- * This macro MUST always be called at the start of a co-routine function.\r
- *\r
- * Example usage:\r
- <pre>\r
- // Co-routine to be created.\r
- void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )\r
- {\r
- // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
- static long ulAVariable;\r
-\r
- // Must start every co-routine with a call to crSTART();\r
- crSTART( xHandle );\r
-\r
- for( ;; )\r
- {\r
- // Co-routine functionality goes here.\r
- }\r
-\r
- // Must end every co-routine with a call to crEND();\r
- crEND();\r
- }</pre>\r
- * \defgroup crSTART crSTART\r
- * \ingroup Tasks\r
- */\r
-#define crSTART( pxCRCB ) switch( ( ( corCRCB * )( pxCRCB ) )->uxState ) { case 0:\r
-\r
-/**\r
- * croutine. h\r
- * <pre>\r
- crEND();</pre>\r
- *\r
- * This macro MUST always be called at the end of a co-routine function.\r
- *\r
- * Example usage:\r
- <pre>\r
- // Co-routine to be created.\r
- void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )\r
- {\r
- // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
- static long ulAVariable;\r
-\r
- // Must start every co-routine with a call to crSTART();\r
- crSTART( xHandle );\r
-\r
- for( ;; )\r
- {\r
- // Co-routine functionality goes here.\r
- }\r
-\r
- // Must end every co-routine with a call to crEND();\r
- crEND();\r
- }</pre>\r
- * \defgroup crSTART crSTART\r
- * \ingroup Tasks\r
- */\r
-#define crEND() }\r
-\r
-/*\r
- * These macros are intended for internal use by the co-routine implementation\r
- * only. The macros should not be used directly by application writers.\r
- */\r
-#define crSET_STATE0( xHandle ) ( ( corCRCB * )( xHandle ) )->uxState = (__LINE__ * 2); return; case (__LINE__ * 2):\r
-#define crSET_STATE1( xHandle ) ( ( corCRCB * )( xHandle ) )->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1):\r
-\r
-/**\r
- * croutine. h\r
- *<pre>\r
- crDELAY( xCoRoutineHandle xHandle, portTickType xTicksToDelay );</pre>\r
- *\r
- * Delay a co-routine for a fixed period of time.\r
- *\r
- * crDELAY can only be called from the co-routine function itself - not\r
- * from within a function called by the co-routine function. This is because\r
- * co-routines do not maintain their own stack.\r
- *\r
- * @param xHandle The handle of the co-routine to delay. This is the xHandle\r
- * parameter of the co-routine function.\r
- *\r
- * @param xTickToDelay The number of ticks that the co-routine should delay\r
- * for. The actual amount of time this equates to is defined by\r
- * configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant portTICK_RATE_MS\r
- * can be used to convert ticks to milliseconds.\r
- *\r
- * Example usage:\r
- <pre>\r
- // Co-routine to be created.\r
- void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )\r
- {\r
- // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
- // This may not be necessary for const variables.\r
- // We are to delay for 200ms.\r
- static const xTickType xDelayTime = 200 / portTICK_RATE_MS;\r
-\r
- // Must start every co-routine with a call to crSTART();\r
- crSTART( xHandle );\r
-\r
- for( ;; )\r
- {\r
- // Delay for 200ms.\r
- crDELAY( xHandle, xDelayTime );\r
-\r
- // Do something here.\r
- }\r
-\r
- // Must end every co-routine with a call to crEND();\r
- crEND();\r
- }</pre>\r
- * \defgroup crDELAY crDELAY\r
- * \ingroup Tasks\r
- */\r
-#define crDELAY( xHandle, xTicksToDelay ) \\r
- if( ( xTicksToDelay ) > 0 ) \\r
- { \\r
- vCoRoutineAddToDelayedList( ( xTicksToDelay ), NULL ); \\r
- } \\r
- crSET_STATE0( ( xHandle ) );\r
-\r
-/**\r
- * <pre>\r
- crQUEUE_SEND(\r
- xCoRoutineHandle xHandle,\r
- xQueueHandle pxQueue,\r
- void *pvItemToQueue,\r
- portTickType xTicksToWait,\r
- portBASE_TYPE *pxResult\r
- )</pre>\r
- *\r
- * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine\r
- * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.\r
- *\r
- * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas\r
- * xQueueSend() and xQueueReceive() can only be used from tasks.\r
- *\r
- * crQUEUE_SEND can only be called from the co-routine function itself - not\r
- * from within a function called by the co-routine function. This is because\r
- * co-routines do not maintain their own stack.\r
- *\r
- * See the co-routine section of the WEB documentation for information on\r
- * passing data between tasks and co-routines and between ISR's and\r
- * co-routines.\r
- *\r
- * @param xHandle The handle of the calling co-routine. This is the xHandle\r
- * parameter of the co-routine function.\r
- *\r
- * @param pxQueue The handle of the queue on which the data will be posted.\r
- * The handle is obtained as the return value when the queue is created using\r
- * the xQueueCreate() API function.\r
- *\r
- * @param pvItemToQueue A pointer to the data being posted onto the queue.\r
- * The number of bytes of each queued item is specified when the queue is\r
- * created. This number of bytes is copied from pvItemToQueue into the queue\r
- * itself.\r
- *\r
- * @param xTickToDelay The number of ticks that the co-routine should block\r
- * to wait for space to become available on the queue, should space not be\r
- * available immediately. The actual amount of time this equates to is defined\r
- * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant\r
- * portTICK_RATE_MS can be used to convert ticks to milliseconds (see example\r
- * below).\r
- *\r
- * @param pxResult The variable pointed to by pxResult will be set to pdPASS if\r
- * data was successfully posted onto the queue, otherwise it will be set to an\r
- * error defined within ProjDefs.h.\r
- *\r
- * Example usage:\r
- <pre>\r
- // Co-routine function that blocks for a fixed period then posts a number onto\r
- // a queue.\r
- static void prvCoRoutineFlashTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )\r
- {\r
- // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
- static portBASE_TYPE xNumberToPost = 0;\r
- static portBASE_TYPE xResult;\r
-\r
- // Co-routines must begin with a call to crSTART().\r
- crSTART( xHandle );\r
-\r
- for( ;; )\r
- {\r
- // This assumes the queue has already been created.\r
- crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );\r
-\r
- if( xResult != pdPASS )\r
- {\r
- // The message was not posted!\r
- }\r
-\r
- // Increment the number to be posted onto the queue.\r
- xNumberToPost++;\r
-\r
- // Delay for 100 ticks.\r
- crDELAY( xHandle, 100 );\r
- }\r
-\r
- // Co-routines must end with a call to crEND().\r
- crEND();\r
- }</pre>\r
- * \defgroup crQUEUE_SEND crQUEUE_SEND\r
- * \ingroup Tasks\r
- */\r
-#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult ) \\r
-{ \\r
- *( pxResult ) = xQueueCRSend( ( pxQueue) , ( pvItemToQueue) , ( xTicksToWait ) ); \\r
- if( *( pxResult ) == errQUEUE_BLOCKED ) \\r
- { \\r
- crSET_STATE0( ( xHandle ) ); \\r
- *pxResult = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), 0 ); \\r
- } \\r
- if( *pxResult == errQUEUE_YIELD ) \\r
- { \\r
- crSET_STATE1( ( xHandle ) ); \\r
- *pxResult = pdPASS; \\r
- } \\r
-}\r
-\r
-/**\r
- * croutine. h\r
- * <pre>\r
- crQUEUE_RECEIVE(\r
- xCoRoutineHandle xHandle,\r
- xQueueHandle pxQueue,\r
- void *pvBuffer,\r
- portTickType xTicksToWait,\r
- portBASE_TYPE *pxResult\r
- )</pre>\r
- *\r
- * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine\r
- * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.\r
- *\r
- * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas\r
- * xQueueSend() and xQueueReceive() can only be used from tasks.\r
- *\r
- * crQUEUE_RECEIVE can only be called from the co-routine function itself - not\r
- * from within a function called by the co-routine function. This is because\r
- * co-routines do not maintain their own stack.\r
- *\r
- * See the co-routine section of the WEB documentation for information on\r
- * passing data between tasks and co-routines and between ISR's and\r
- * co-routines.\r
- *\r
- * @param xHandle The handle of the calling co-routine. This is the xHandle\r
- * parameter of the co-routine function.\r
- *\r
- * @param pxQueue The handle of the queue from which the data will be received.\r
- * The handle is obtained as the return value when the queue is created using\r
- * the xQueueCreate() API function.\r
- *\r
- * @param pvBuffer The buffer into which the received item is to be copied.\r
- * The number of bytes of each queued item is specified when the queue is\r
- * created. This number of bytes is copied into pvBuffer.\r
- *\r
- * @param xTickToDelay The number of ticks that the co-routine should block\r
- * to wait for data to become available from the queue, should data not be\r
- * available immediately. The actual amount of time this equates to is defined\r
- * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant\r
- * portTICK_RATE_MS can be used to convert ticks to milliseconds (see the\r
- * crQUEUE_SEND example).\r
- *\r
- * @param pxResult The variable pointed to by pxResult will be set to pdPASS if\r
- * data was successfully retrieved from the queue, otherwise it will be set to\r
- * an error code as defined within ProjDefs.h.\r
- *\r
- * Example usage:\r
- <pre>\r
- // A co-routine receives the number of an LED to flash from a queue. It\r
- // blocks on the queue until the number is received.\r
- static void prvCoRoutineFlashWorkTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )\r
- {\r
- // Variables in co-routines must be declared static if they must maintain value across a blocking call.\r
- static portBASE_TYPE xResult;\r
- static unsigned portBASE_TYPE uxLEDToFlash;\r
-\r
- // All co-routines must start with a call to crSTART().\r
- crSTART( xHandle );\r
-\r
- for( ;; )\r
- {\r
- // Wait for data to become available on the queue.\r
- crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );\r
-\r
- if( xResult == pdPASS )\r
- {\r
- // We received the LED to flash - flash it!\r
- vParTestToggleLED( uxLEDToFlash );\r
- }\r
- }\r
-\r
- crEND();\r
- }</pre>\r
- * \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE\r
- * \ingroup Tasks\r
- */\r
-#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult ) \\r
-{ \\r
- *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), ( xTicksToWait ) ); \\r
- if( *( pxResult ) == errQUEUE_BLOCKED ) \\r
- { \\r
- crSET_STATE0( ( xHandle ) ); \\r
- *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), 0 ); \\r
- } \\r
- if( *( pxResult ) == errQUEUE_YIELD ) \\r
- { \\r
- crSET_STATE1( ( xHandle ) ); \\r
- *( pxResult ) = pdPASS; \\r
- } \\r
-}\r
-\r
-/**\r
- * croutine. h\r
- * <pre>\r
- crQUEUE_SEND_FROM_ISR(\r
- xQueueHandle pxQueue,\r
- void *pvItemToQueue,\r
- portBASE_TYPE xCoRoutinePreviouslyWoken\r
- )</pre>\r
- *\r
- * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the\r
- * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()\r
- * functions used by tasks.\r
- *\r
- * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to\r
- * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and\r
- * xQueueReceiveFromISR() can only be used to pass data between a task and and\r
- * ISR.\r
- *\r
- * crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue\r
- * that is being used from within a co-routine.\r
- *\r
- * See the co-routine section of the WEB documentation for information on\r
- * passing data between tasks and co-routines and between ISR's and\r
- * co-routines.\r
- *\r
- * @param xQueue The handle to the queue on which the item is to be posted.\r
- *\r
- * @param pvItemToQueue A pointer to the item that is to be placed on the\r
- * queue. The size of the items the queue will hold was defined when the\r
- * queue was created, so this many bytes will be copied from pvItemToQueue\r
- * into the queue storage area.\r
- *\r
- * @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto\r
- * the same queue multiple times from a single interrupt. The first call\r
- * should always pass in pdFALSE. Subsequent calls should pass in\r
- * the value returned from the previous call.\r
- *\r
- * @return pdTRUE if a co-routine was woken by posting onto the queue. This is\r
- * used by the ISR to determine if a context switch may be required following\r
- * the ISR.\r
- *\r
- * Example usage:\r
- <pre>\r
- // A co-routine that blocks on a queue waiting for characters to be received.\r
- static void vReceivingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )\r
- {\r
- char cRxedChar;\r
- portBASE_TYPE xResult;\r
-\r
- // All co-routines must start with a call to crSTART().\r
- crSTART( xHandle );\r
-\r
- for( ;; )\r
- {\r
- // Wait for data to become available on the queue. This assumes the\r
- // queue xCommsRxQueue has already been created!\r
- crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );\r
-\r
- // Was a character received?\r
- if( xResult == pdPASS )\r
- {\r
- // Process the character here.\r
- }\r
- }\r
-\r
- // All co-routines must end with a call to crEND().\r
- crEND();\r
- }\r
-\r
- // An ISR that uses a queue to send characters received on a serial port to\r
- // a co-routine.\r
- void vUART_ISR( void )\r
- {\r
- char cRxedChar;\r
- portBASE_TYPE xCRWokenByPost = pdFALSE;\r
-\r
- // We loop around reading characters until there are none left in the UART.\r
- while( UART_RX_REG_NOT_EMPTY() )\r
- {\r
- // Obtain the character from the UART.\r
- cRxedChar = UART_RX_REG;\r
-\r
- // Post the character onto a queue. xCRWokenByPost will be pdFALSE\r
- // the first time around the loop. If the post causes a co-routine\r
- // to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.\r
- // In this manner we can ensure that if more than one co-routine is\r
- // blocked on the queue only one is woken by this ISR no matter how\r
- // many characters are posted to the queue.\r
- xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );\r
- }\r
- }</pre>\r
- * \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR\r
- * \ingroup Tasks\r
- */\r
-#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( xCoRoutinePreviouslyWoken ) )\r
-\r
-\r
-/**\r
- * croutine. h\r
- * <pre>\r
- crQUEUE_SEND_FROM_ISR(\r
- xQueueHandle pxQueue,\r
- void *pvBuffer,\r
- portBASE_TYPE * pxCoRoutineWoken\r
- )</pre>\r
- *\r
- * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the\r
- * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()\r
- * functions used by tasks.\r
- *\r
- * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to\r
- * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and\r
- * xQueueReceiveFromISR() can only be used to pass data between a task and and\r
- * ISR.\r
- *\r
- * crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data\r
- * from a queue that is being used from within a co-routine (a co-routine\r
- * posted to the queue).\r
- *\r
- * See the co-routine section of the WEB documentation for information on\r
- * passing data between tasks and co-routines and between ISR's and\r
- * co-routines.\r
- *\r
- * @param xQueue The handle to the queue on which the item is to be posted.\r
- *\r
- * @param pvBuffer A pointer to a buffer into which the received item will be\r
- * placed. The size of the items the queue will hold was defined when the\r
- * queue was created, so this many bytes will be copied from the queue into\r
- * pvBuffer.\r
- *\r
- * @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become\r
- * available on the queue. If crQUEUE_RECEIVE_FROM_ISR causes such a\r
- * co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise\r
- * *pxCoRoutineWoken will remain unchanged.\r
- *\r
- * @return pdTRUE an item was successfully received from the queue, otherwise\r
- * pdFALSE.\r
- *\r
- * Example usage:\r
- <pre>\r
- // A co-routine that posts a character to a queue then blocks for a fixed\r
- // period. The character is incremented each time.\r
- static void vSendingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )\r
- {\r
- // cChar holds its value while this co-routine is blocked and must therefore\r
- // be declared static.\r
- static char cCharToTx = 'a';\r
- portBASE_TYPE xResult;\r
-\r
- // All co-routines must start with a call to crSTART().\r
- crSTART( xHandle );\r
-\r
- for( ;; )\r
- {\r
- // Send the next character to the queue.\r
- crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );\r
-\r
- if( xResult == pdPASS )\r
- {\r
- // The character was successfully posted to the queue.\r
- }\r
- else\r
- {\r
- // Could not post the character to the queue.\r
- }\r
-\r
- // Enable the UART Tx interrupt to cause an interrupt in this\r
- // hypothetical UART. The interrupt will obtain the character\r
- // from the queue and send it.\r
- ENABLE_RX_INTERRUPT();\r
-\r
- // Increment to the next character then block for a fixed period.\r
- // cCharToTx will maintain its value across the delay as it is\r
- // declared static.\r
- cCharToTx++;\r
- if( cCharToTx > 'x' )\r
- {\r
- cCharToTx = 'a';\r
- }\r
- crDELAY( 100 );\r
- }\r
-\r
- // All co-routines must end with a call to crEND().\r
- crEND();\r
- }\r
-\r
- // An ISR that uses a queue to receive characters to send on a UART.\r
- void vUART_ISR( void )\r
- {\r
- char cCharToTx;\r
- portBASE_TYPE xCRWokenByPost = pdFALSE;\r
-\r
- while( UART_TX_REG_EMPTY() )\r
- {\r
- // Are there any characters in the queue waiting to be sent?\r
- // xCRWokenByPost will automatically be set to pdTRUE if a co-routine\r
- // is woken by the post - ensuring that only a single co-routine is\r
- // woken no matter how many times we go around this loop.\r
- if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )\r
- {\r
- SEND_CHARACTER( cCharToTx );\r
- }\r
- }\r
- }</pre>\r
- * \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR\r
- * \ingroup Tasks\r
- */\r
-#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( ( pxQueue ), ( pvBuffer ), ( pxCoRoutineWoken ) )\r
-\r
-/*\r
- * This function is intended for internal use by the co-routine macros only.\r
- * The macro nature of the co-routine implementation requires that the\r
- * prototype appears here. The function should not be used by application\r
- * writers.\r
- *\r
- * Removes the current co-routine from its ready list and places it in the\r
- * appropriate delayed list.\r
- */\r
-void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList );\r
-\r
-/*\r
- * This function is intended for internal use by the queue implementation only.\r
- * The function should not be used by application writers.\r
- *\r
- * Removes the highest priority co-routine from the event list and places it in\r
- * the pending ready list.\r
- */\r
-signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList );\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-\r
-#endif /* CO_ROUTINE_H */\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/*\r
- * This is the list implementation used by the scheduler. While it is tailored\r
- * heavily for the schedulers needs, it is also available for use by\r
- * application code.\r
- *\r
- * xLists can only store pointers to xListItems. Each xListItem contains a\r
- * numeric value (xItemValue). Most of the time the lists are sorted in\r
- * descending item value order.\r
- *\r
- * Lists are created already containing one list item. The value of this\r
- * item is the maximum possible that can be stored, it is therefore always at\r
- * the end of the list and acts as a marker. The list member pxHead always\r
- * points to this marker - even though it is at the tail of the list. This\r
- * is because the tail contains a wrap back pointer to the true head of\r
- * the list.\r
- *\r
- * In addition to it's value, each list item contains a pointer to the next\r
- * item in the list (pxNext), a pointer to the list it is in (pxContainer)\r
- * and a pointer to back to the object that contains it. These later two\r
- * pointers are included for efficiency of list manipulation. There is\r
- * effectively a two way link between the object containing the list item and\r
- * the list item itself.\r
- *\r
- *\r
- * \page ListIntroduction List Implementation\r
- * \ingroup FreeRTOSIntro\r
- */\r
-\r
-\r
-#ifndef LIST_H\r
-#define LIST_H\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-/*\r
- * Definition of the only type of object that a list can contain.\r
- */\r
-struct xLIST_ITEM\r
-{\r
- portTickType xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */\r
- volatile struct xLIST_ITEM * pxNext; /*< Pointer to the next xListItem in the list. */\r
- volatile struct xLIST_ITEM * pxPrevious;/*< Pointer to the previous xListItem in the list. */\r
- void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */\r
- void * pvContainer; /*< Pointer to the list in which this list item is placed (if any). */\r
-};\r
-typedef struct xLIST_ITEM xListItem; /* For some reason lint wants this as two separate definitions. */\r
-\r
-struct xMINI_LIST_ITEM\r
-{\r
- portTickType xItemValue;\r
- volatile struct xLIST_ITEM *pxNext;\r
- volatile struct xLIST_ITEM *pxPrevious;\r
-};\r
-typedef struct xMINI_LIST_ITEM xMiniListItem;\r
-\r
-/*\r
- * Definition of the type of queue used by the scheduler.\r
- */\r
-typedef struct xLIST\r
-{\r
- volatile unsigned portBASE_TYPE uxNumberOfItems;\r
- volatile xListItem * pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to pvListGetOwnerOfNextEntry (). */\r
- volatile xMiniListItem xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */\r
-} xList;\r
-\r
-/*\r
- * Access macro to set the owner of a list item. The owner of a list item\r
- * is the object (usually a TCB) that contains the list item.\r
- *\r
- * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER\r
- * \ingroup LinkedList\r
- */\r
-#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( pxListItem )->pvOwner = ( void * ) ( pxOwner )\r
-\r
-/*\r
- * Access macro to set the value of the list item. In most cases the value is\r
- * used to sort the list in descending order.\r
- *\r
- * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE\r
- * \ingroup LinkedList\r
- */\r
-#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( pxListItem )->xItemValue = ( xValue )\r
-\r
-/*\r
- * Access macro the retrieve the value of the list item. The value can\r
- * represent anything - for example a the priority of a task, or the time at\r
- * which a task should be unblocked.\r
- *\r
- * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE\r
- * \ingroup LinkedList\r
- */\r
-#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )\r
-\r
-/*\r
- * Access macro the retrieve the value of the list item at the head of a given\r
- * list.\r
- *\r
- * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE\r
- * \ingroup LinkedList\r
- */\r
-#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->xItemValue )\r
-\r
-/*\r
- * Access macro to determine if a list contains any items. The macro will\r
- * only have the value true if the list is empty.\r
- *\r
- * \page listLIST_IS_EMPTY listLIST_IS_EMPTY\r
- * \ingroup LinkedList\r
- */\r
-#define listLIST_IS_EMPTY( pxList ) ( ( pxList )->uxNumberOfItems == ( unsigned portBASE_TYPE ) 0 )\r
-\r
-/*\r
- * Access macro to return the number of items in the list.\r
- */\r
-#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )\r
-\r
-/*\r
- * Access function to obtain the owner of the next entry in a list.\r
- *\r
- * The list member pxIndex is used to walk through a list. Calling\r
- * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list\r
- * and returns that entries pxOwner parameter. Using multiple calls to this\r
- * function it is therefore possible to move through every item contained in\r
- * a list.\r
- *\r
- * The pxOwner parameter of a list item is a pointer to the object that owns\r
- * the list item. In the scheduler this is normally a task control block.\r
- * The pxOwner parameter effectively creates a two way link between the list\r
- * item and its owner.\r
- *\r
- * @param pxList The list from which the next item owner is to be returned.\r
- *\r
- * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY\r
- * \ingroup LinkedList\r
- */\r
-#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \\r
-{ \\r
-xList * const pxConstList = ( pxList ); \\r
- /* Increment the index to the next item and return the item, ensuring */ \\r
- /* we don't return the marker used at the end of the list. */ \\r
- ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \\r
- if( ( pxConstList )->pxIndex == ( xListItem * ) &( ( pxConstList )->xListEnd ) ) \\r
- { \\r
- ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \\r
- } \\r
- ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \\r
-}\r
-\r
-\r
-/*\r
- * Access function to obtain the owner of the first entry in a list. Lists\r
- * are normally sorted in ascending item value order.\r
- *\r
- * This function returns the pxOwner member of the first item in the list.\r
- * The pxOwner parameter of a list item is a pointer to the object that owns\r
- * the list item. In the scheduler this is normally a task control block.\r
- * The pxOwner parameter effectively creates a two way link between the list\r
- * item and its owner.\r
- *\r
- * @param pxList The list from which the owner of the head item is to be\r
- * returned.\r
- *\r
- * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY\r
- * \ingroup LinkedList\r
- */\r
-#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )\r
-\r
-/*\r
- * Check to see if a list item is within a list. The list item maintains a\r
- * "container" pointer that points to the list it is in. All this macro does\r
- * is check to see if the container and the list match.\r
- *\r
- * @param pxList The list we want to know if the list item is within.\r
- * @param pxListItem The list item we want to know if is in the list.\r
- * @return pdTRUE is the list item is in the list, otherwise pdFALSE.\r
- * pointer against\r
- */\r
-#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) )\r
-\r
-/*\r
- * Must be called before a list is used! This initialises all the members\r
- * of the list structure and inserts the xListEnd item into the list as a\r
- * marker to the back of the list.\r
- *\r
- * @param pxList Pointer to the list being initialised.\r
- *\r
- * \page vListInitialise vListInitialise\r
- * \ingroup LinkedList\r
- */\r
-void vListInitialise( xList *pxList );\r
-\r
-/*\r
- * Must be called before a list item is used. This sets the list container to\r
- * null so the item does not think that it is already contained in a list.\r
- *\r
- * @param pxItem Pointer to the list item being initialised.\r
- *\r
- * \page vListInitialiseItem vListInitialiseItem\r
- * \ingroup LinkedList\r
- */\r
-void vListInitialiseItem( xListItem *pxItem );\r
-\r
-/*\r
- * Insert a list item into a list. The item will be inserted into the list in\r
- * a position determined by its item value (descending item value order).\r
- *\r
- * @param pxList The list into which the item is to be inserted.\r
- *\r
- * @param pxNewListItem The item to that is to be placed in the list.\r
- *\r
- * \page vListInsert vListInsert\r
- * \ingroup LinkedList\r
- */\r
-void vListInsert( xList *pxList, xListItem *pxNewListItem );\r
-\r
-/*\r
- * Insert a list item into a list. The item will be inserted in a position\r
- * such that it will be the last item within the list returned by multiple\r
- * calls to listGET_OWNER_OF_NEXT_ENTRY.\r
- *\r
- * The list member pvIndex is used to walk through a list. Calling\r
- * listGET_OWNER_OF_NEXT_ENTRY increments pvIndex to the next item in the list.\r
- * Placing an item in a list using vListInsertEnd effectively places the item\r
- * in the list position pointed to by pvIndex. This means that every other\r
- * item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before\r
- * the pvIndex parameter again points to the item being inserted.\r
- *\r
- * @param pxList The list into which the item is to be inserted.\r
- *\r
- * @param pxNewListItem The list item to be inserted into the list.\r
- *\r
- * \page vListInsertEnd vListInsertEnd\r
- * \ingroup LinkedList\r
- */\r
-void vListInsertEnd( xList *pxList, xListItem *pxNewListItem );\r
-\r
-/*\r
- * Remove an item from a list. The list item has a pointer to the list that\r
- * it is in, so only the list item need be passed into the function.\r
- *\r
- * @param vListRemove The item to be removed. The item will remove itself from\r
- * the list pointed to by it's pxContainer parameter.\r
- *\r
- * \page vListRemove vListRemove\r
- * \ingroup LinkedList\r
- */\r
-void vListRemove( xListItem *pxItemToRemove );\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-\r
-#endif\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef MPU_WRAPPERS_H\r
-#define MPU_WRAPPERS_H\r
-\r
-/* This file redefines API functions to be called through a wrapper macro, but\r
-only for ports that are using the MPU. */\r
-#ifdef portUSING_MPU_WRAPPERS\r
-\r
- /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE will be defined when this file is\r
- included from queue.c or task.c to prevent it from having an effect within\r
- those files. */\r
- #ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
-\r
- #define xTaskGenericCreate MPU_xTaskGenericCreate\r
- #define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions\r
- #define vTaskDelete MPU_vTaskDelete\r
- #define vTaskDelayUntil MPU_vTaskDelayUntil\r
- #define vTaskDelay MPU_vTaskDelay\r
- #define uxTaskPriorityGet MPU_uxTaskPriorityGet\r
- #define vTaskPrioritySet MPU_vTaskPrioritySet\r
- #define vTaskSuspend MPU_vTaskSuspend\r
- #define xTaskIsTaskSuspended MPU_xTaskIsTaskSuspended\r
- #define vTaskResume MPU_vTaskResume\r
- #define vTaskSuspendAll MPU_vTaskSuspendAll\r
- #define xTaskResumeAll MPU_xTaskResumeAll\r
- #define xTaskGetTickCount MPU_xTaskGetTickCount\r
- #define uxTaskGetNumberOfTasks MPU_uxTaskGetNumberOfTasks\r
- #define vTaskList MPU_vTaskList\r
- #define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats\r
- #define vTaskStartTrace MPU_vTaskStartTrace\r
- #define ulTaskEndTrace MPU_ulTaskEndTrace\r
- #define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag\r
- #define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag\r
- #define xTaskCallApplicationTaskHook MPU_xTaskCallApplicationTaskHook\r
- #define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark\r
- #define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle\r
- #define xTaskGetSchedulerState MPU_xTaskGetSchedulerState\r
-\r
- #define xQueueCreate MPU_xQueueCreate\r
- #define xQueueCreateMutex MPU_xQueueCreateMutex\r
- #define xQueueGiveMutexRecursive MPU_xQueueGiveMutexRecursive\r
- #define xQueueTakeMutexRecursive MPU_xQueueTakeMutexRecursive\r
- #define xQueueCreateCountingSemaphore MPU_xQueueCreateCountingSemaphore\r
- #define xQueueGenericSend MPU_xQueueGenericSend\r
- #define xQueueAltGenericSend MPU_xQueueAltGenericSend\r
- #define xQueueAltGenericReceive MPU_xQueueAltGenericReceive\r
- #define xQueueGenericReceive MPU_xQueueGenericReceive\r
- #define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting\r
- #define vQueueDelete MPU_vQueueDelete\r
-\r
- #define pvPortMalloc MPU_pvPortMalloc\r
- #define vPortFree MPU_vPortFree\r
- #define xPortGetFreeHeapSize MPU_xPortGetFreeHeapSize\r
- #define vPortInitialiseBlocks MPU_vPortInitialiseBlocks\r
-\r
- #if configQUEUE_REGISTRY_SIZE > 0\r
- #define vQueueAddToRegistry MPU_vQueueAddToRegistry\r
- #define vQueueUnregisterQueue MPU_vQueueUnregisterQueue\r
- #endif\r
-\r
- /* Remove the privileged function macro. */\r
- #define PRIVILEGED_FUNCTION\r
-\r
- #else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */\r
-\r
- /* Ensure API functions go in the privileged execution section. */\r
- #define PRIVILEGED_FUNCTION __attribute__((section("privileged_functions")))\r
- #define PRIVILEGED_DATA __attribute__((section("privileged_data")))\r
- //#define PRIVILEGED_DATA\r
-\r
- #endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */\r
-\r
-#else /* portUSING_MPU_WRAPPERS */\r
-\r
- #define PRIVILEGED_FUNCTION\r
- #define PRIVILEGED_DATA\r
- #define portUSING_MPU_WRAPPERS 0\r
-\r
-#endif /* portUSING_MPU_WRAPPERS */\r
-\r
-\r
-#endif /* MPU_WRAPPERS_H */\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/*-----------------------------------------------------------\r
- * Portable layer API. Each function must be defined for each port.\r
- *----------------------------------------------------------*/\r
-\r
-#ifndef PORTABLE_H\r
-#define PORTABLE_H\r
-\r
-/* Include the macro file relevant to the port being used. */\r
-\r
-#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT\r
- #include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h"\r
- typedef void ( __interrupt __far *pxISR )();\r
-#endif\r
-\r
-#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT\r
- #include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h"\r
- typedef void ( __interrupt __far *pxISR )();\r
-#endif\r
-\r
-#ifdef GCC_MEGA_AVR\r
- #include "../portable/GCC/ATMega323/portmacro.h"\r
-#endif\r
-\r
-#ifdef IAR_MEGA_AVR\r
- #include "../portable/IAR/ATMega323/portmacro.h"\r
-#endif\r
-\r
-#ifdef MPLAB_PIC24_PORT\r
- #include "..\..\Source\portable\MPLAB\PIC24_dsPIC\portmacro.h"\r
-#endif\r
-\r
-#ifdef MPLAB_DSPIC_PORT\r
- #include "..\..\Source\portable\MPLAB\PIC24_dsPIC\portmacro.h"\r
-#endif\r
-\r
-#ifdef MPLAB_PIC18F_PORT\r
- #include "..\..\Source\portable\MPLAB\PIC18F\portmacro.h"\r
-#endif\r
-\r
-#ifdef MPLAB_PIC32MX_PORT\r
- #include "..\..\Source\portable\MPLAB\PIC32MX\portmacro.h"\r
-#endif\r
-\r
-#ifdef _FEDPICC\r
- #include "libFreeRTOS/Include/portmacro.h"\r
-#endif\r
-\r
-#ifdef SDCC_CYGNAL\r
- #include "../../Source/portable/SDCC/Cygnal/portmacro.h"\r
-#endif\r
-\r
-#ifdef GCC_ARM7\r
- #include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h"\r
-#endif\r
-\r
-#ifdef GCC_ARM7_ECLIPSE\r
- #include "portmacro.h"\r
-#endif\r
-\r
-#ifdef ROWLEY_LPC23xx\r
- #include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h"\r
-#endif\r
-\r
-#ifdef IAR_MSP430\r
- #include "..\..\Source\portable\IAR\MSP430\portmacro.h" \r
-#endif\r
- \r
-#ifdef GCC_MSP430\r
- #include "../../Source/portable/GCC/MSP430F449/portmacro.h"\r
-#endif\r
-\r
-#ifdef ROWLEY_MSP430\r
- #include "../../Source/portable/Rowley/MSP430F449/portmacro.h"\r
-#endif\r
-\r
-#ifdef ARM7_LPC21xx_KEIL_RVDS\r
- #include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h"\r
-#endif\r
-\r
-#ifdef SAM7_GCC\r
- #include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h"\r
-#endif\r
-\r
-#ifdef SAM7_IAR\r
- #include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h"\r
-#endif\r
-\r
-#ifdef SAM9XE_IAR\r
- #include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h"\r
-#endif\r
-\r
-#ifdef LPC2000_IAR\r
- #include "..\..\Source\portable\IAR\LPC2000\portmacro.h"\r
-#endif\r
-\r
-#ifdef STR71X_IAR\r
- #include "..\..\Source\portable\IAR\STR71x\portmacro.h"\r
-#endif\r
-\r
-#ifdef STR75X_IAR\r
- #include "..\..\Source\portable\IAR\STR75x\portmacro.h"\r
-#endif\r
- \r
-#ifdef STR75X_GCC\r
- #include "..\..\Source\portable\GCC\STR75x\portmacro.h"\r
-#endif\r
-\r
-#ifdef STR91X_IAR\r
- #include "..\..\Source\portable\IAR\STR91x\portmacro.h"\r
-#endif\r
- \r
-#ifdef GCC_H8S\r
- #include "../../Source/portable/GCC/H8S2329/portmacro.h"\r
-#endif\r
-\r
-#ifdef GCC_AT91FR40008\r
- #include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h"\r
-#endif\r
-\r
-#ifdef RVDS_ARMCM3_LM3S102\r
- #include "../../Source/portable/RVDS/ARM_CM3/portmacro.h"\r
-#endif\r
-\r
-#ifdef GCC_ARMCM3_LM3S102\r
- #include "../../Source/portable/GCC/ARM_CM3/portmacro.h"\r
-#endif\r
-\r
-#ifdef GCC_ARMCM3\r
- #include "../../Source/portable/GCC/ARM_CM3/portmacro.h"\r
-#endif\r
-\r
-#ifdef IAR_ARM_CM3\r
- #include "../../Source/portable/IAR/ARM_CM3/portmacro.h"\r
-#endif\r
-\r
-#ifdef IAR_ARMCM3_LM\r
- #include "../../Source/portable/IAR/ARM_CM3/portmacro.h"\r
-#endif\r
- \r
-#ifdef HCS12_CODE_WARRIOR\r
- #include "../../Source/portable/CodeWarrior/HCS12/portmacro.h"\r
-#endif \r
-\r
-#ifdef MICROBLAZE_GCC\r
- #include "../../Source/portable/GCC/MicroBlaze/portmacro.h"\r
-#endif\r
-\r
-#ifdef TERN_EE\r
- #include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h"\r
-#endif\r
-\r
-#ifdef GCC_HCS12\r
- #include "../../Source/portable/GCC/HCS12/portmacro.h"\r
-#endif\r
-\r
-#ifdef GCC_MCF5235\r
- #include "../../Source/portable/GCC/MCF5235/portmacro.h"\r
-#endif\r
-\r
-#ifdef COLDFIRE_V2_GCC\r
- #include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h"\r
-#endif\r
-\r
-#ifdef COLDFIRE_V2_CODEWARRIOR\r
- #include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h"\r
-#endif\r
-\r
-#ifdef GCC_PPC405\r
- #include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h"\r
-#endif\r
-\r
-#ifdef GCC_PPC440\r
- #include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h"\r
-#endif\r
-\r
-#ifdef _16FX_SOFTUNE\r
- #include "..\..\Source\portable\Softune\MB96340\portmacro.h"\r
-#endif\r
-\r
-#ifdef BCC_INDUSTRIAL_PC_PORT\r
- /* A short file name has to be used in place of the normal\r
- FreeRTOSConfig.h when using the Borland compiler. */\r
- #include "frconfig.h"\r
- #include "..\portable\BCC\16BitDOS\PC\prtmacro.h"\r
- typedef void ( __interrupt __far *pxISR )();\r
-#endif\r
-\r
-#ifdef BCC_FLASH_LITE_186_PORT\r
- /* A short file name has to be used in place of the normal\r
- FreeRTOSConfig.h when using the Borland compiler. */\r
- #include "frconfig.h"\r
- #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h"\r
- typedef void ( __interrupt __far *pxISR )();\r
-#endif\r
-\r
-#ifdef __GNUC__\r
- #ifdef __AVR32_AVR32A__\r
- #include "portmacro.h"\r
- #endif\r
-#endif\r
-\r
-#ifdef __ICCAVR32__\r
- #ifdef __CORE__\r
- #if __CORE__ == __AVR32A__\r
- #include "portmacro.h"\r
- #endif\r
- #endif\r
-#endif\r
-\r
-#ifdef __91467D\r
- #include "portmacro.h"\r
-#endif\r
-\r
-#ifdef __96340\r
- #include "portmacro.h"\r
-#endif\r
-\r
-\r
-#ifdef __IAR_V850ES_Fx3__\r
- #include "../../Source/portable/IAR/V850ES/portmacro.h"\r
-#endif\r
-\r
-#ifdef __IAR_V850ES_Jx3__\r
- #include "../../Source/portable/IAR/V850ES/portmacro.h"\r
-#endif\r
-\r
-#ifdef __IAR_V850ES_Jx3_L__\r
- #include "../../Source/portable/IAR/V850ES/portmacro.h"\r
-#endif\r
-\r
-#ifdef __IAR_V850ES_Jx2__\r
- #include "../../Source/portable/IAR/V850ES/portmacro.h"\r
-#endif\r
-\r
-#ifdef __IAR_V850ES_Hx2__\r
- #include "../../Source/portable/IAR/V850ES/portmacro.h"\r
-#endif\r
-\r
-#ifdef __IAR_78K0R_Kx3__\r
- #include "../../Source/portable/IAR/78K0R/portmacro.h"\r
-#endif\r
- \r
-#ifdef __IAR_78K0R_Kx3L__\r
- #include "../../Source/portable/IAR/78K0R/portmacro.h"\r
-#endif\r
- \r
-/* Catch all to ensure portmacro.h is included in the build. Newer demos\r
-have the path as part of the project options, rather than as relative from\r
-the project location. If portENTER_CRITICAL() has not been defined then\r
-portmacro.h has not yet been included - as every portmacro.h provides a\r
-portENTER_CRITICAL() definition. Check the demo application for your demo\r
-to find the path to the correct portmacro.h file. */\r
-#ifndef portENTER_CRITICAL\r
- #include "portmacro.h" \r
-#endif\r
- \r
-#if portBYTE_ALIGNMENT == 8\r
- #define portBYTE_ALIGNMENT_MASK ( 0x0007 )\r
-#endif\r
-\r
-#if portBYTE_ALIGNMENT == 4\r
- #define portBYTE_ALIGNMENT_MASK ( 0x0003 )\r
-#endif\r
-\r
-#if portBYTE_ALIGNMENT == 2\r
- #define portBYTE_ALIGNMENT_MASK ( 0x0001 )\r
-#endif\r
-\r
-#if portBYTE_ALIGNMENT == 1\r
- #define portBYTE_ALIGNMENT_MASK ( 0x0000 )\r
-#endif\r
-\r
-#ifndef portBYTE_ALIGNMENT_MASK\r
- #error "Invalid portBYTE_ALIGNMENT definition"\r
-#endif\r
-\r
-#ifndef portNUM_CONFIGURABLE_REGIONS\r
- #define portNUM_CONFIGURABLE_REGIONS 1\r
-#endif\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-#include "mpu_wrappers.h"\r
-\r
-/*\r
- * Setup the stack of a new task so it is ready to be placed under the\r
- * scheduler control. The registers have to be placed on the stack in\r
- * the order that the port expects to find them.\r
- *\r
- */\r
-#if( portUSING_MPU_WRAPPERS == 1 )\r
- portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters, portBASE_TYPE xRunPrivileged ) PRIVILEGED_FUNCTION;\r
-#else\r
- portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters );\r
-#endif\r
-\r
-/*\r
- * Map to the memory management routines required for the port.\r
- */\r
-void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION;\r
-void vPortFree( void *pv ) PRIVILEGED_FUNCTION;\r
-void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;\r
-size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Setup the hardware ready for the scheduler to take control. This generally\r
- * sets up a tick interrupt and sets timers for the correct tick frequency.\r
- */\r
-portBASE_TYPE xPortStartScheduler( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Undo any hardware/ISR setup that was performed by xPortStartScheduler() so\r
- * the hardware is left in its original condition after the scheduler stops\r
- * executing.\r
- */\r
-void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * The structures and methods of manipulating the MPU are contained within the\r
- * port layer.\r
- *\r
- * Fills the xMPUSettings structure with the memory region information\r
- * contained in xRegions.\r
- */\r
-#if( portUSING_MPU_WRAPPERS == 1 ) \r
- struct xMEMORY_REGION;\r
- void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, portSTACK_TYPE *pxBottomOfStack, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;\r
-#endif\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-\r
-#endif /* PORTABLE_H */\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef PROJDEFS_H\r
-#define PROJDEFS_H\r
-\r
-/* Defines the prototype to which task functions must conform. */\r
-typedef void (*pdTASK_CODE)( void * );\r
-\r
-#define pdTRUE ( 1 )\r
-#define pdFALSE ( 0 )\r
-\r
-#define pdPASS ( 1 )\r
-#define pdFAIL ( 0 )\r
-#define errQUEUE_EMPTY ( 0 )\r
-#define errQUEUE_FULL ( 0 )\r
-\r
-/* Error definitions. */\r
-#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 )\r
-#define errNO_TASK_TO_RUN ( -2 )\r
-#define errQUEUE_BLOCKED ( -4 )\r
-#define errQUEUE_YIELD ( -5 )\r
-\r
-#endif /* PROJDEFS_H */\r
-\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-\r
-#ifndef QUEUE_H\r
-#define QUEUE_H\r
-\r
-#ifndef INC_FREERTOS_H\r
- #error "#include FreeRTOS.h" must appear in source files before "#include queue.h"\r
-#endif\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-\r
-#include "mpu_wrappers.h"\r
-\r
-/**\r
- * Type by which queues are referenced. For example, a call to xQueueCreate\r
- * returns (via a pointer parameter) an xQueueHandle variable that can then\r
- * be used as a parameter to xQueueSend(), xQueueReceive(), etc.\r
- */\r
-typedef void * xQueueHandle;\r
-\r
-\r
-/* For internal use only. */\r
-#define queueSEND_TO_BACK ( 0 )\r
-#define queueSEND_TO_FRONT ( 1 )\r
-\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- xQueueHandle xQueueCreate(\r
- unsigned portBASE_TYPE uxQueueLength,\r
- unsigned portBASE_TYPE uxItemSize\r
- );\r
- * </pre>\r
- *\r
- * Creates a new queue instance. This allocates the storage required by the\r
- * new queue and returns a handle for the queue.\r
- *\r
- * @param uxQueueLength The maximum number of items that the queue can contain.\r
- *\r
- * @param uxItemSize The number of bytes each item in the queue will require.\r
- * Items are queued by copy, not by reference, so this is the number of bytes\r
- * that will be copied for each posted item. Each item on the queue must be\r
- * the same size.\r
- *\r
- * @return If the queue is successfully create then a handle to the newly\r
- * created queue is returned. If the queue cannot be created then 0 is\r
- * returned.\r
- *\r
- * Example usage:\r
- <pre>\r
- struct AMessage\r
- {\r
- char ucMessageID;\r
- char ucData[ 20 ];\r
- };\r
-\r
- void vATask( void *pvParameters )\r
- {\r
- xQueueHandle xQueue1, xQueue2;\r
-\r
- // Create a queue capable of containing 10 unsigned long values.\r
- xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );\r
- if( xQueue1 == 0 )\r
- {\r
- // Queue was not created and must not be used.\r
- }\r
-\r
- // Create a queue capable of containing 10 pointers to AMessage structures.\r
- // These should be passed by pointer as they contain a lot of data.\r
- xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );\r
- if( xQueue2 == 0 )\r
- {\r
- // Queue was not created and must not be used.\r
- }\r
-\r
- // ... Rest of task code.\r
- }\r
- </pre>\r
- * \defgroup xQueueCreate xQueueCreate\r
- * \ingroup QueueManagement\r
- */\r
-xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueueSendToToFront(\r
- xQueueHandle xQueue,\r
- const void * pvItemToQueue,\r
- portTickType xTicksToWait\r
- );\r
- * </pre>\r
- *\r
- * This is a macro that calls xQueueGenericSend().\r
- *\r
- * Post an item to the front of a queue. The item is queued by copy, not by\r
- * reference. This function must not be called from an interrupt service\r
- * routine. See xQueueSendFromISR () for an alternative which may be used\r
- * in an ISR.\r
- *\r
- * @param xQueue The handle to the queue on which the item is to be posted.\r
- *\r
- * @param pvItemToQueue A pointer to the item that is to be placed on the\r
- * queue. The size of the items the queue will hold was defined when the\r
- * queue was created, so this many bytes will be copied from pvItemToQueue\r
- * into the queue storage area.\r
- *\r
- * @param xTicksToWait The maximum amount of time the task should block\r
- * waiting for space to become available on the queue, should it already\r
- * be full. The call will return immediately if this is set to 0 and the\r
- * queue is full. The time is defined in tick periods so the constant\r
- * portTICK_RATE_MS should be used to convert to real time if this is required.\r
- *\r
- * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.\r
- *\r
- * Example usage:\r
- <pre>\r
- struct AMessage\r
- {\r
- char ucMessageID;\r
- char ucData[ 20 ];\r
- } xMessage;\r
-\r
- unsigned long ulVar = 10UL;\r
-\r
- void vATask( void *pvParameters )\r
- {\r
- xQueueHandle xQueue1, xQueue2;\r
- struct AMessage *pxMessage;\r
-\r
- // Create a queue capable of containing 10 unsigned long values.\r
- xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );\r
-\r
- // Create a queue capable of containing 10 pointers to AMessage structures.\r
- // These should be passed by pointer as they contain a lot of data.\r
- xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );\r
-\r
- // ...\r
-\r
- if( xQueue1 != 0 )\r
- {\r
- // Send an unsigned long. Wait for 10 ticks for space to become\r
- // available if necessary.\r
- if( xQueueSendToFront( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )\r
- {\r
- // Failed to post the message, even after 10 ticks.\r
- }\r
- }\r
-\r
- if( xQueue2 != 0 )\r
- {\r
- // Send a pointer to a struct AMessage object. Don't block if the\r
- // queue is already full.\r
- pxMessage = & xMessage;\r
- xQueueSendToFront( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );\r
- }\r
-\r
- // ... Rest of task code.\r
- }\r
- </pre>\r
- * \defgroup xQueueSend xQueueSend\r
- * \ingroup QueueManagement\r
- */\r
-#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueueSendToBack(\r
- xQueueHandle xQueue,\r
- const void * pvItemToQueue,\r
- portTickType xTicksToWait\r
- );\r
- * </pre>\r
- *\r
- * This is a macro that calls xQueueGenericSend().\r
- *\r
- * Post an item to the back of a queue. The item is queued by copy, not by\r
- * reference. This function must not be called from an interrupt service\r
- * routine. See xQueueSendFromISR () for an alternative which may be used\r
- * in an ISR.\r
- *\r
- * @param xQueue The handle to the queue on which the item is to be posted.\r
- *\r
- * @param pvItemToQueue A pointer to the item that is to be placed on the\r
- * queue. The size of the items the queue will hold was defined when the\r
- * queue was created, so this many bytes will be copied from pvItemToQueue\r
- * into the queue storage area.\r
- *\r
- * @param xTicksToWait The maximum amount of time the task should block\r
- * waiting for space to become available on the queue, should it already\r
- * be full. The call will return immediately if this is set to 0 and the queue\r
- * is full. The time is defined in tick periods so the constant\r
- * portTICK_RATE_MS should be used to convert to real time if this is required.\r
- *\r
- * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.\r
- *\r
- * Example usage:\r
- <pre>\r
- struct AMessage\r
- {\r
- char ucMessageID;\r
- char ucData[ 20 ];\r
- } xMessage;\r
-\r
- unsigned long ulVar = 10UL;\r
-\r
- void vATask( void *pvParameters )\r
- {\r
- xQueueHandle xQueue1, xQueue2;\r
- struct AMessage *pxMessage;\r
-\r
- // Create a queue capable of containing 10 unsigned long values.\r
- xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );\r
-\r
- // Create a queue capable of containing 10 pointers to AMessage structures.\r
- // These should be passed by pointer as they contain a lot of data.\r
- xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );\r
-\r
- // ...\r
-\r
- if( xQueue1 != 0 )\r
- {\r
- // Send an unsigned long. Wait for 10 ticks for space to become\r
- // available if necessary.\r
- if( xQueueSendToBack( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )\r
- {\r
- // Failed to post the message, even after 10 ticks.\r
- }\r
- }\r
-\r
- if( xQueue2 != 0 )\r
- {\r
- // Send a pointer to a struct AMessage object. Don't block if the\r
- // queue is already full.\r
- pxMessage = & xMessage;\r
- xQueueSendToBack( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );\r
- }\r
-\r
- // ... Rest of task code.\r
- }\r
- </pre>\r
- * \defgroup xQueueSend xQueueSend\r
- * \ingroup QueueManagement\r
- */\r
-#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueueSend(\r
- xQueueHandle xQueue,\r
- const void * pvItemToQueue,\r
- portTickType xTicksToWait\r
- );\r
- * </pre>\r
- *\r
- * This is a macro that calls xQueueGenericSend(). It is included for\r
- * backward compatibility with versions of FreeRTOS.org that did not\r
- * include the xQueueSendToFront() and xQueueSendToBack() macros. It is\r
- * equivalent to xQueueSendToBack().\r
- *\r
- * Post an item on a queue. The item is queued by copy, not by reference.\r
- * This function must not be called from an interrupt service routine.\r
- * See xQueueSendFromISR () for an alternative which may be used in an ISR.\r
- *\r
- * @param xQueue The handle to the queue on which the item is to be posted.\r
- *\r
- * @param pvItemToQueue A pointer to the item that is to be placed on the\r
- * queue. The size of the items the queue will hold was defined when the\r
- * queue was created, so this many bytes will be copied from pvItemToQueue\r
- * into the queue storage area.\r
- *\r
- * @param xTicksToWait The maximum amount of time the task should block\r
- * waiting for space to become available on the queue, should it already\r
- * be full. The call will return immediately if this is set to 0 and the\r
- * queue is full. The time is defined in tick periods so the constant\r
- * portTICK_RATE_MS should be used to convert to real time if this is required.\r
- *\r
- * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.\r
- *\r
- * Example usage:\r
- <pre>\r
- struct AMessage\r
- {\r
- char ucMessageID;\r
- char ucData[ 20 ];\r
- } xMessage;\r
-\r
- unsigned long ulVar = 10UL;\r
-\r
- void vATask( void *pvParameters )\r
- {\r
- xQueueHandle xQueue1, xQueue2;\r
- struct AMessage *pxMessage;\r
-\r
- // Create a queue capable of containing 10 unsigned long values.\r
- xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );\r
-\r
- // Create a queue capable of containing 10 pointers to AMessage structures.\r
- // These should be passed by pointer as they contain a lot of data.\r
- xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );\r
-\r
- // ...\r
-\r
- if( xQueue1 != 0 )\r
- {\r
- // Send an unsigned long. Wait for 10 ticks for space to become\r
- // available if necessary.\r
- if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )\r
- {\r
- // Failed to post the message, even after 10 ticks.\r
- }\r
- }\r
-\r
- if( xQueue2 != 0 )\r
- {\r
- // Send a pointer to a struct AMessage object. Don't block if the\r
- // queue is already full.\r
- pxMessage = & xMessage;\r
- xQueueSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );\r
- }\r
-\r
- // ... Rest of task code.\r
- }\r
- </pre>\r
- * \defgroup xQueueSend xQueueSend\r
- * \ingroup QueueManagement\r
- */\r
-#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )\r
-\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueueGenericSend(\r
- xQueueHandle xQueue,\r
- const void * pvItemToQueue,\r
- portTickType xTicksToWait\r
- portBASE_TYPE xCopyPosition\r
- );\r
- * </pre>\r
- *\r
- * It is preferred that the macros xQueueSend(), xQueueSendToFront() and\r
- * xQueueSendToBack() are used in place of calling this function directly.\r
- *\r
- * Post an item on a queue. The item is queued by copy, not by reference.\r
- * This function must not be called from an interrupt service routine.\r
- * See xQueueSendFromISR () for an alternative which may be used in an ISR.\r
- *\r
- * @param xQueue The handle to the queue on which the item is to be posted.\r
- *\r
- * @param pvItemToQueue A pointer to the item that is to be placed on the\r
- * queue. The size of the items the queue will hold was defined when the\r
- * queue was created, so this many bytes will be copied from pvItemToQueue\r
- * into the queue storage area.\r
- *\r
- * @param xTicksToWait The maximum amount of time the task should block\r
- * waiting for space to become available on the queue, should it already\r
- * be full. The call will return immediately if this is set to 0 and the\r
- * queue is full. The time is defined in tick periods so the constant\r
- * portTICK_RATE_MS should be used to convert to real time if this is required.\r
- *\r
- * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the\r
- * item at the back of the queue, or queueSEND_TO_FRONT to place the item\r
- * at the front of the queue (for high priority messages).\r
- *\r
- * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.\r
- *\r
- * Example usage:\r
- <pre>\r
- struct AMessage\r
- {\r
- char ucMessageID;\r
- char ucData[ 20 ];\r
- } xMessage;\r
-\r
- unsigned long ulVar = 10UL;\r
-\r
- void vATask( void *pvParameters )\r
- {\r
- xQueueHandle xQueue1, xQueue2;\r
- struct AMessage *pxMessage;\r
-\r
- // Create a queue capable of containing 10 unsigned long values.\r
- xQueue1 = xQueueCreate( 10, sizeof( unsigned long ) );\r
-\r
- // Create a queue capable of containing 10 pointers to AMessage structures.\r
- // These should be passed by pointer as they contain a lot of data.\r
- xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );\r
-\r
- // ...\r
-\r
- if( xQueue1 != 0 )\r
- {\r
- // Send an unsigned long. Wait for 10 ticks for space to become\r
- // available if necessary.\r
- if( xQueueGenericSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10, queueSEND_TO_BACK ) != pdPASS )\r
- {\r
- // Failed to post the message, even after 10 ticks.\r
- }\r
- }\r
-\r
- if( xQueue2 != 0 )\r
- {\r
- // Send a pointer to a struct AMessage object. Don't block if the\r
- // queue is already full.\r
- pxMessage = & xMessage;\r
- xQueueGenericSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0, queueSEND_TO_BACK );\r
- }\r
-\r
- // ... Rest of task code.\r
- }\r
- </pre>\r
- * \defgroup xQueueSend xQueueSend\r
- * \ingroup QueueManagement\r
- */\r
-signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueuePeek(\r
- xQueueHandle xQueue,\r
- void *pvBuffer,\r
- portTickType xTicksToWait\r
- );</pre>\r
- *\r
- * This is a macro that calls the xQueueGenericReceive() function.\r
- *\r
- * Receive an item from a queue without removing the item from the queue.\r
- * The item is received by copy so a buffer of adequate size must be\r
- * provided. The number of bytes copied into the buffer was defined when\r
- * the queue was created.\r
- *\r
- * Successfully received items remain on the queue so will be returned again\r
- * by the next call, or a call to xQueueReceive().\r
- *\r
- * This macro must not be used in an interrupt service routine.\r
- *\r
- * @param pxQueue The handle to the queue from which the item is to be\r
- * received.\r
- *\r
- * @param pvBuffer Pointer to the buffer into which the received item will\r
- * be copied.\r
- *\r
- * @param xTicksToWait The maximum amount of time the task should block\r
- * waiting for an item to receive should the queue be empty at the time\r
- * of the call. The time is defined in tick periods so the constant\r
- * portTICK_RATE_MS should be used to convert to real time if this is required.\r
- * xQueuePeek() will return immediately if xTicksToWait is 0 and the queue\r
- * is empty.\r
- *\r
- * @return pdTRUE if an item was successfully received from the queue,\r
- * otherwise pdFALSE.\r
- *\r
- * Example usage:\r
- <pre>\r
- struct AMessage\r
- {\r
- char ucMessageID;\r
- char ucData[ 20 ];\r
- } xMessage;\r
-\r
- xQueueHandle xQueue;\r
-\r
- // Task to create a queue and post a value.\r
- void vATask( void *pvParameters )\r
- {\r
- struct AMessage *pxMessage;\r
-\r
- // Create a queue capable of containing 10 pointers to AMessage structures.\r
- // These should be passed by pointer as they contain a lot of data.\r
- xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );\r
- if( xQueue == 0 )\r
- {\r
- // Failed to create the queue.\r
- }\r
-\r
- // ...\r
-\r
- // Send a pointer to a struct AMessage object. Don't block if the\r
- // queue is already full.\r
- pxMessage = & xMessage;\r
- xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );\r
-\r
- // ... Rest of task code.\r
- }\r
-\r
- // Task to peek the data from the queue.\r
- void vADifferentTask( void *pvParameters )\r
- {\r
- struct AMessage *pxRxedMessage;\r
-\r
- if( xQueue != 0 )\r
- {\r
- // Peek a message on the created queue. Block for 10 ticks if a\r
- // message is not immediately available.\r
- if( xQueuePeek( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )\r
- {\r
- // pcRxedMessage now points to the struct AMessage variable posted\r
- // by vATask, but the item still remains on the queue.\r
- }\r
- }\r
-\r
- // ... Rest of task code.\r
- }\r
- </pre>\r
- * \defgroup xQueueReceive xQueueReceive\r
- * \ingroup QueueManagement\r
- */\r
-#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE )\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueueReceive(\r
- xQueueHandle xQueue,\r
- void *pvBuffer,\r
- portTickType xTicksToWait\r
- );</pre>\r
- *\r
- * This is a macro that calls the xQueueGenericReceive() function.\r
- *\r
- * Receive an item from a queue. The item is received by copy so a buffer of\r
- * adequate size must be provided. The number of bytes copied into the buffer\r
- * was defined when the queue was created.\r
- *\r
- * Successfully received items are removed from the queue.\r
- *\r
- * This function must not be used in an interrupt service routine. See\r
- * xQueueReceiveFromISR for an alternative that can.\r
- *\r
- * @param pxQueue The handle to the queue from which the item is to be\r
- * received.\r
- *\r
- * @param pvBuffer Pointer to the buffer into which the received item will\r
- * be copied.\r
- *\r
- * @param xTicksToWait The maximum amount of time the task should block\r
- * waiting for an item to receive should the queue be empty at the time\r
- * of the call. xQueueReceive() will return immediately if xTicksToWait\r
- * is zero and the queue is empty. The time is defined in tick periods so the\r
- * constant portTICK_RATE_MS should be used to convert to real time if this is\r
- * required.\r
- *\r
- * @return pdTRUE if an item was successfully received from the queue,\r
- * otherwise pdFALSE.\r
- *\r
- * Example usage:\r
- <pre>\r
- struct AMessage\r
- {\r
- char ucMessageID;\r
- char ucData[ 20 ];\r
- } xMessage;\r
-\r
- xQueueHandle xQueue;\r
-\r
- // Task to create a queue and post a value.\r
- void vATask( void *pvParameters )\r
- {\r
- struct AMessage *pxMessage;\r
-\r
- // Create a queue capable of containing 10 pointers to AMessage structures.\r
- // These should be passed by pointer as they contain a lot of data.\r
- xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );\r
- if( xQueue == 0 )\r
- {\r
- // Failed to create the queue.\r
- }\r
-\r
- // ...\r
-\r
- // Send a pointer to a struct AMessage object. Don't block if the\r
- // queue is already full.\r
- pxMessage = & xMessage;\r
- xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );\r
-\r
- // ... Rest of task code.\r
- }\r
-\r
- // Task to receive from the queue.\r
- void vADifferentTask( void *pvParameters )\r
- {\r
- struct AMessage *pxRxedMessage;\r
-\r
- if( xQueue != 0 )\r
- {\r
- // Receive a message on the created queue. Block for 10 ticks if a\r
- // message is not immediately available.\r
- if( xQueueReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )\r
- {\r
- // pcRxedMessage now points to the struct AMessage variable posted\r
- // by vATask.\r
- }\r
- }\r
-\r
- // ... Rest of task code.\r
- }\r
- </pre>\r
- * \defgroup xQueueReceive xQueueReceive\r
- * \ingroup QueueManagement\r
- */\r
-#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )\r
-\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueueGenericReceive(\r
- xQueueHandle xQueue,\r
- void *pvBuffer,\r
- portTickType xTicksToWait\r
- portBASE_TYPE xJustPeek\r
- );</pre>\r
- *\r
- * It is preferred that the macro xQueueReceive() be used rather than calling\r
- * this function directly.\r
- *\r
- * Receive an item from a queue. The item is received by copy so a buffer of\r
- * adequate size must be provided. The number of bytes copied into the buffer\r
- * was defined when the queue was created.\r
- *\r
- * This function must not be used in an interrupt service routine. See\r
- * xQueueReceiveFromISR for an alternative that can.\r
- *\r
- * @param pxQueue The handle to the queue from which the item is to be\r
- * received.\r
- *\r
- * @param pvBuffer Pointer to the buffer into which the received item will\r
- * be copied.\r
- *\r
- * @param xTicksToWait The maximum amount of time the task should block\r
- * waiting for an item to receive should the queue be empty at the time\r
- * of the call. The time is defined in tick periods so the constant\r
- * portTICK_RATE_MS should be used to convert to real time if this is required.\r
- * xQueueGenericReceive() will return immediately if the queue is empty and\r
- * xTicksToWait is 0.\r
- *\r
- * @param xJustPeek When set to true, the item received from the queue is not\r
- * actually removed from the queue - meaning a subsequent call to\r
- * xQueueReceive() will return the same item. When set to false, the item\r
- * being received from the queue is also removed from the queue.\r
- *\r
- * @return pdTRUE if an item was successfully received from the queue,\r
- * otherwise pdFALSE.\r
- *\r
- * Example usage:\r
- <pre>\r
- struct AMessage\r
- {\r
- char ucMessageID;\r
- char ucData[ 20 ];\r
- } xMessage;\r
-\r
- xQueueHandle xQueue;\r
-\r
- // Task to create a queue and post a value.\r
- void vATask( void *pvParameters )\r
- {\r
- struct AMessage *pxMessage;\r
-\r
- // Create a queue capable of containing 10 pointers to AMessage structures.\r
- // These should be passed by pointer as they contain a lot of data.\r
- xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );\r
- if( xQueue == 0 )\r
- {\r
- // Failed to create the queue.\r
- }\r
-\r
- // ...\r
-\r
- // Send a pointer to a struct AMessage object. Don't block if the\r
- // queue is already full.\r
- pxMessage = & xMessage;\r
- xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );\r
-\r
- // ... Rest of task code.\r
- }\r
-\r
- // Task to receive from the queue.\r
- void vADifferentTask( void *pvParameters )\r
- {\r
- struct AMessage *pxRxedMessage;\r
-\r
- if( xQueue != 0 )\r
- {\r
- // Receive a message on the created queue. Block for 10 ticks if a\r
- // message is not immediately available.\r
- if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )\r
- {\r
- // pcRxedMessage now points to the struct AMessage variable posted\r
- // by vATask.\r
- }\r
- }\r
-\r
- // ... Rest of task code.\r
- }\r
- </pre>\r
- * \defgroup xQueueReceive xQueueReceive\r
- * \ingroup QueueManagement\r
- */\r
-signed portBASE_TYPE xQueueGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeek );\r
-\r
-/**\r
- * queue. h\r
- * <pre>unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue );</pre>\r
- *\r
- * Return the number of messages stored in a queue.\r
- *\r
- * @param xQueue A handle to the queue being queried.\r
- *\r
- * @return The number of messages available in the queue.\r
- *\r
- * \page uxQueueMessagesWaiting uxQueueMessagesWaiting\r
- * \ingroup QueueManagement\r
- */\r
-unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle xQueue );\r
-\r
-/**\r
- * queue. h\r
- * <pre>void vQueueDelete( xQueueHandle xQueue );</pre>\r
- *\r
- * Delete a queue - freeing all the memory allocated for storing of items\r
- * placed on the queue.\r
- *\r
- * @param xQueue A handle to the queue to be deleted.\r
- *\r
- * \page vQueueDelete vQueueDelete\r
- * \ingroup QueueManagement\r
- */\r
-void vQueueDelete( xQueueHandle pxQueue );\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueueSendToFrontFromISR(\r
- xQueueHandle pxQueue,\r
- const void *pvItemToQueue,\r
- portBASE_TYPE *pxHigherPriorityTaskWoken\r
- );\r
- </pre>\r
- *\r
- * This is a macro that calls xQueueGenericSendFromISR().\r
- *\r
- * Post an item to the front of a queue. It is safe to use this macro from\r
- * within an interrupt service routine.\r
- *\r
- * Items are queued by copy not reference so it is preferable to only\r
- * queue small items, especially when called from an ISR. In most cases\r
- * it would be preferable to store a pointer to the item being queued.\r
- *\r
- * @param xQueue The handle to the queue on which the item is to be posted.\r
- *\r
- * @param pvItemToQueue A pointer to the item that is to be placed on the\r
- * queue. The size of the items the queue will hold was defined when the\r
- * queue was created, so this many bytes will be copied from pvItemToQueue\r
- * into the queue storage area.\r
- *\r
- * @param pxHigherPriorityTaskWoken xQueueSendToFrontFromISR() will set\r
- * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task\r
- * to unblock, and the unblocked task has a priority higher than the currently\r
- * running task. If xQueueSendToFromFromISR() sets this value to pdTRUE then\r
- * a context switch should be requested before the interrupt is exited.\r
- *\r
- * @return pdTRUE if the data was successfully sent to the queue, otherwise\r
- * errQUEUE_FULL.\r
- *\r
- * Example usage for buffered IO (where the ISR can obtain more than one value\r
- * per call):\r
- <pre>\r
- void vBufferISR( void )\r
- {\r
- char cIn;\r
- portBASE_TYPE xHigherPrioritTaskWoken;\r
-\r
- // We have not woken a task at the start of the ISR.\r
- xHigherPriorityTaskWoken = pdFALSE;\r
-\r
- // Loop until the buffer is empty.\r
- do\r
- {\r
- // Obtain a byte from the buffer.\r
- cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );\r
-\r
- // Post the byte.\r
- xQueueSendToFrontFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );\r
-\r
- } while( portINPUT_BYTE( BUFFER_COUNT ) );\r
-\r
- // Now the buffer is empty we can switch context if necessary.\r
- if( xHigherPriorityTaskWoken )\r
- {\r
- taskYIELD ();\r
- }\r
- }\r
- </pre>\r
- *\r
- * \defgroup xQueueSendFromISR xQueueSendFromISR\r
- * \ingroup QueueManagement\r
- */\r
-#define xQueueSendToFrontFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT )\r
-\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueueSendToBackFromISR(\r
- xQueueHandle pxQueue,\r
- const void *pvItemToQueue,\r
- portBASE_TYPE *pxHigherPriorityTaskWoken\r
- );\r
- </pre>\r
- *\r
- * This is a macro that calls xQueueGenericSendFromISR().\r
- *\r
- * Post an item to the back of a queue. It is safe to use this macro from\r
- * within an interrupt service routine.\r
- *\r
- * Items are queued by copy not reference so it is preferable to only\r
- * queue small items, especially when called from an ISR. In most cases\r
- * it would be preferable to store a pointer to the item being queued.\r
- *\r
- * @param xQueue The handle to the queue on which the item is to be posted.\r
- *\r
- * @param pvItemToQueue A pointer to the item that is to be placed on the\r
- * queue. The size of the items the queue will hold was defined when the\r
- * queue was created, so this many bytes will be copied from pvItemToQueue\r
- * into the queue storage area.\r
- *\r
- * @param pxHigherPriorityTaskWoken xQueueSendToBackFromISR() will set\r
- * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task\r
- * to unblock, and the unblocked task has a priority higher than the currently\r
- * running task. If xQueueSendToBackFromISR() sets this value to pdTRUE then\r
- * a context switch should be requested before the interrupt is exited.\r
- *\r
- * @return pdTRUE if the data was successfully sent to the queue, otherwise\r
- * errQUEUE_FULL.\r
- *\r
- * Example usage for buffered IO (where the ISR can obtain more than one value\r
- * per call):\r
- <pre>\r
- void vBufferISR( void )\r
- {\r
- char cIn;\r
- portBASE_TYPE xHigherPriorityTaskWoken;\r
-\r
- // We have not woken a task at the start of the ISR.\r
- xHigherPriorityTaskWoken = pdFALSE;\r
-\r
- // Loop until the buffer is empty.\r
- do\r
- {\r
- // Obtain a byte from the buffer.\r
- cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );\r
-\r
- // Post the byte.\r
- xQueueSendToBackFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );\r
-\r
- } while( portINPUT_BYTE( BUFFER_COUNT ) );\r
-\r
- // Now the buffer is empty we can switch context if necessary.\r
- if( xHigherPriorityTaskWoken )\r
- {\r
- taskYIELD ();\r
- }\r
- }\r
- </pre>\r
- *\r
- * \defgroup xQueueSendFromISR xQueueSendFromISR\r
- * \ingroup QueueManagement\r
- */\r
-#define xQueueSendToBackFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueueSendFromISR(\r
- xQueueHandle pxQueue,\r
- const void *pvItemToQueue,\r
- portBASE_TYPE *pxHigherPriorityTaskWoken\r
- );\r
- </pre>\r
- *\r
- * This is a macro that calls xQueueGenericSendFromISR(). It is included\r
- * for backward compatibility with versions of FreeRTOS.org that did not\r
- * include the xQueueSendToBackFromISR() and xQueueSendToFrontFromISR()\r
- * macros.\r
- *\r
- * Post an item to the back of a queue. It is safe to use this function from\r
- * within an interrupt service routine.\r
- *\r
- * Items are queued by copy not reference so it is preferable to only\r
- * queue small items, especially when called from an ISR. In most cases\r
- * it would be preferable to store a pointer to the item being queued.\r
- *\r
- * @param xQueue The handle to the queue on which the item is to be posted.\r
- *\r
- * @param pvItemToQueue A pointer to the item that is to be placed on the\r
- * queue. The size of the items the queue will hold was defined when the\r
- * queue was created, so this many bytes will be copied from pvItemToQueue\r
- * into the queue storage area.\r
- *\r
- * @param pxHigherPriorityTaskWoken xQueueSendFromISR() will set\r
- * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task\r
- * to unblock, and the unblocked task has a priority higher than the currently\r
- * running task. If xQueueSendFromISR() sets this value to pdTRUE then\r
- * a context switch should be requested before the interrupt is exited.\r
- *\r
- * @return pdTRUE if the data was successfully sent to the queue, otherwise\r
- * errQUEUE_FULL.\r
- *\r
- * Example usage for buffered IO (where the ISR can obtain more than one value\r
- * per call):\r
- <pre>\r
- void vBufferISR( void )\r
- {\r
- char cIn;\r
- portBASE_TYPE xHigherPriorityTaskWoken;\r
-\r
- // We have not woken a task at the start of the ISR.\r
- xHigherPriorityTaskWoken = pdFALSE;\r
-\r
- // Loop until the buffer is empty.\r
- do\r
- {\r
- // Obtain a byte from the buffer.\r
- cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );\r
-\r
- // Post the byte.\r
- xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );\r
-\r
- } while( portINPUT_BYTE( BUFFER_COUNT ) );\r
-\r
- // Now the buffer is empty we can switch context if necessary.\r
- if( xHigherPriorityTaskWoken )\r
- {\r
- // Actual macro used here is port specific.\r
- taskYIELD_FROM_ISR ();\r
- }\r
- }\r
- </pre>\r
- *\r
- * \defgroup xQueueSendFromISR xQueueSendFromISR\r
- * \ingroup QueueManagement\r
- */\r
-#define xQueueSendFromISR( pxQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueueGenericSendFromISR(\r
- xQueueHandle pxQueue,\r
- const void *pvItemToQueue,\r
- portBASE_TYPE *pxHigherPriorityTaskWoken,\r
- portBASE_TYPE xCopyPosition\r
- );\r
- </pre>\r
- *\r
- * It is preferred that the macros xQueueSendFromISR(),\r
- * xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place\r
- * of calling this function directly.\r
- *\r
- * Post an item on a queue. It is safe to use this function from within an\r
- * interrupt service routine.\r
- *\r
- * Items are queued by copy not reference so it is preferable to only\r
- * queue small items, especially when called from an ISR. In most cases\r
- * it would be preferable to store a pointer to the item being queued.\r
- *\r
- * @param xQueue The handle to the queue on which the item is to be posted.\r
- *\r
- * @param pvItemToQueue A pointer to the item that is to be placed on the\r
- * queue. The size of the items the queue will hold was defined when the\r
- * queue was created, so this many bytes will be copied from pvItemToQueue\r
- * into the queue storage area.\r
- *\r
- * @param pxHigherPriorityTaskWoken xQueueGenericSendFromISR() will set\r
- * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task\r
- * to unblock, and the unblocked task has a priority higher than the currently\r
- * running task. If xQueueGenericSendFromISR() sets this value to pdTRUE then\r
- * a context switch should be requested before the interrupt is exited.\r
- *\r
- * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the\r
- * item at the back of the queue, or queueSEND_TO_FRONT to place the item\r
- * at the front of the queue (for high priority messages).\r
- *\r
- * @return pdTRUE if the data was successfully sent to the queue, otherwise\r
- * errQUEUE_FULL.\r
- *\r
- * Example usage for buffered IO (where the ISR can obtain more than one value\r
- * per call):\r
- <pre>\r
- void vBufferISR( void )\r
- {\r
- char cIn;\r
- portBASE_TYPE xHigherPriorityTaskWokenByPost;\r
-\r
- // We have not woken a task at the start of the ISR.\r
- xHigherPriorityTaskWokenByPost = pdFALSE;\r
-\r
- // Loop until the buffer is empty.\r
- do\r
- {\r
- // Obtain a byte from the buffer.\r
- cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );\r
-\r
- // Post each byte.\r
- xQueueGenericSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWokenByPost, queueSEND_TO_BACK );\r
-\r
- } while( portINPUT_BYTE( BUFFER_COUNT ) );\r
-\r
- // Now the buffer is empty we can switch context if necessary. Note that the\r
- // name of the yield function required is port specific.\r
- if( xHigherPriorityTaskWokenByPost )\r
- {\r
- taskYIELD_YIELD_FROM_ISR();\r
- }\r
- }\r
- </pre>\r
- *\r
- * \defgroup xQueueSendFromISR xQueueSendFromISR\r
- * \ingroup QueueManagement\r
- */\r
-signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition );\r
-\r
-/**\r
- * queue. h\r
- * <pre>\r
- portBASE_TYPE xQueueReceiveFromISR(\r
- xQueueHandle pxQueue,\r
- void *pvBuffer,\r
- portBASE_TYPE *pxTaskWoken\r
- );\r
- * </pre>\r
- *\r
- * Receive an item from a queue. It is safe to use this function from within an\r
- * interrupt service routine.\r
- *\r
- * @param pxQueue The handle to the queue from which the item is to be\r
- * received.\r
- *\r
- * @param pvBuffer Pointer to the buffer into which the received item will\r
- * be copied.\r
- *\r
- * @param pxTaskWoken A task may be blocked waiting for space to become\r
- * available on the queue. If xQueueReceiveFromISR causes such a task to\r
- * unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will\r
- * remain unchanged.\r
- *\r
- * @return pdTRUE if an item was successfully received from the queue,\r
- * otherwise pdFALSE.\r
- *\r
- * Example usage:\r
- <pre>\r
-\r
- xQueueHandle xQueue;\r
-\r
- // Function to create a queue and post some values.\r
- void vAFunction( void *pvParameters )\r
- {\r
- char cValueToPost;\r
- const portTickType xBlockTime = ( portTickType )0xff;\r
-\r
- // Create a queue capable of containing 10 characters.\r
- xQueue = xQueueCreate( 10, sizeof( char ) );\r
- if( xQueue == 0 )\r
- {\r
- // Failed to create the queue.\r
- }\r
-\r
- // ...\r
-\r
- // Post some characters that will be used within an ISR. If the queue\r
- // is full then this task will block for xBlockTime ticks.\r
- cValueToPost = 'a';\r
- xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );\r
- cValueToPost = 'b';\r
- xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );\r
-\r
- // ... keep posting characters ... this task may block when the queue\r
- // becomes full.\r
-\r
- cValueToPost = 'c';\r
- xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );\r
- }\r
-\r
- // ISR that outputs all the characters received on the queue.\r
- void vISR_Routine( void )\r
- {\r
- portBASE_TYPE xTaskWokenByReceive = pdFALSE;\r
- char cRxedChar;\r
-\r
- while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) )\r
- {\r
- // A character was received. Output the character now.\r
- vOutputCharacter( cRxedChar );\r
-\r
- // If removing the character from the queue woke the task that was\r
- // posting onto the queue cTaskWokenByReceive will have been set to\r
- // pdTRUE. No matter how many times this loop iterates only one\r
- // task will be woken.\r
- }\r
-\r
- if( cTaskWokenByPost != ( char ) pdFALSE;\r
- {\r
- taskYIELD ();\r
- }\r
- }\r
- </pre>\r
- * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR\r
- * \ingroup QueueManagement\r
- */\r
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );\r
-\r
-/*\r
- * Utilities to query queue that are safe to use from an ISR. These utilities\r
- * should be used only from witin an ISR, or within a critical section.\r
- */\r
-signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue );\r
-signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue );\r
-unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue );\r
-\r
-\r
-/*\r
- * xQueueAltGenericSend() is an alternative version of xQueueGenericSend().\r
- * Likewise xQueueAltGenericReceive() is an alternative version of\r
- * xQueueGenericReceive().\r
- *\r
- * The source code that implements the alternative (Alt) API is much\r
- * simpler because it executes everything from within a critical section.\r
- * This is the approach taken by many other RTOSes, but FreeRTOS.org has the\r
- * preferred fully featured API too. The fully featured API has more\r
- * complex code that takes longer to execute, but makes much less use of\r
- * critical sections. Therefore the alternative API sacrifices interrupt\r
- * responsiveness to gain execution speed, whereas the fully featured API\r
- * sacrifices execution speed to ensure better interrupt responsiveness.\r
- */\r
-signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );\r
-signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );\r
-#define xQueueAltSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )\r
-#define xQueueAltSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )\r
-#define xQueueAltReceive( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )\r
-#define xQueueAltPeek( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE )\r
-\r
-/*\r
- * The functions defined above are for passing data to and from tasks. The\r
- * functions below are the equivalents for passing data to and from\r
- * co-routines.\r
- *\r
- * These functions are called from the co-routine macro implementation and\r
- * should not be called directly from application code. Instead use the macro\r
- * wrappers defined within croutine.h.\r
- */\r
-signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );\r
-signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );\r
-signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );\r
-signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );\r
-\r
-/*\r
- * For internal use only. Use xSemaphoreCreateMutex() or\r
- * xSemaphoreCreateCounting() instead of calling these functions directly.\r
- */\r
-xQueueHandle xQueueCreateMutex( void );\r
-xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount );\r
-\r
-/*\r
- * For internal use only. Use xSemaphoreTakeMutexRecursive() or\r
- * xSemaphoreGiveMutexRecursive() instead of calling these functions directly.\r
- */\r
-portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime );\r
-portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex );\r
-\r
-/*\r
- * The registry is provided as a means for kernel aware debuggers to\r
- * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add\r
- * a queue, semaphore or mutex handle to the registry if you want the handle\r
- * to be available to a kernel aware debugger. If you are not using a kernel\r
- * aware debugger then this function can be ignored.\r
- *\r
- * configQUEUE_REGISTRY_SIZE defines the maximum number of handles the\r
- * registry can hold. configQUEUE_REGISTRY_SIZE must be greater than 0\r
- * within FreeRTOSConfig.h for the registry to be available. Its value\r
- * does not effect the number of queues, semaphores and mutexes that can be\r
- * created - just the number that the registry can hold.\r
- *\r
- * @param xQueue The handle of the queue being added to the registry. This\r
- * is the handle returned by a call to xQueueCreate(). Semaphore and mutex\r
- * handles can also be passed in here.\r
- *\r
- * @param pcName The name to be associated with the handle. This is the\r
- * name that the kernel aware debugger will display.\r
- */\r
-#if configQUEUE_REGISTRY_SIZE > 0U\r
- void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcName );\r
-#endif\r
-\r
-/* Not a public API function, hence the 'Restricted' in the name. */\r
-void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait );\r
-\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-\r
-#endif /* QUEUE_H */\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef SEMAPHORE_H\r
-#define SEMAPHORE_H\r
-\r
-#ifndef INC_FREERTOS_H\r
- #error "#include FreeRTOS.h" must appear in source files before "#include semphr.h"\r
-#endif\r
-\r
-#include "queue.h"\r
-\r
-typedef xQueueHandle xSemaphoreHandle;\r
-\r
-#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( unsigned char ) 1U )\r
-#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned char ) 0U )\r
-#define semGIVE_BLOCK_TIME ( ( portTickType ) 0U )\r
-\r
-\r
-/**\r
- * semphr. h\r
- * <pre>vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore )</pre>\r
- *\r
- * <i>Macro</i> that implements a semaphore by using the existing queue mechanism.\r
- * The queue length is 1 as this is a binary semaphore. The data size is 0\r
- * as we don't want to actually store any data - we just want to know if the\r
- * queue is empty or full.\r
- *\r
- * This type of semaphore can be used for pure synchronisation between tasks or\r
- * between an interrupt and a task. The semaphore need not be given back once\r
- * obtained, so one task/interrupt can continuously 'give' the semaphore while\r
- * another continuously 'takes' the semaphore. For this reason this type of\r
- * semaphore does not use a priority inheritance mechanism. For an alternative\r
- * that does use priority inheritance see xSemaphoreCreateMutex().\r
- *\r
- * @param xSemaphore Handle to the created semaphore. Should be of type xSemaphoreHandle.\r
- *\r
- * Example usage:\r
- <pre>\r
- xSemaphoreHandle xSemaphore;\r
-\r
- void vATask( void * pvParameters )\r
- {\r
- // Semaphore cannot be used before a call to vSemaphoreCreateBinary ().\r
- // This is a macro so pass the variable in directly.\r
- vSemaphoreCreateBinary( xSemaphore );\r
-\r
- if( xSemaphore != NULL )\r
- {\r
- // The semaphore was created successfully.\r
- // The semaphore can now be used. \r
- }\r
- }\r
- </pre>\r
- * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary\r
- * \ingroup Semaphores\r
- */\r
-#define vSemaphoreCreateBinary( xSemaphore ) { \\r
- ( xSemaphore ) = xQueueCreate( ( unsigned portBASE_TYPE ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH ); \\r
- if( ( xSemaphore ) != NULL ) \\r
- { \\r
- xSemaphoreGive( ( xSemaphore ) ); \\r
- } \\r
- }\r
-\r
-/**\r
- * semphr. h\r
- * <pre>xSemaphoreTake( \r
- * xSemaphoreHandle xSemaphore, \r
- * portTickType xBlockTime \r
- * )</pre>\r
- *\r
- * <i>Macro</i> to obtain a semaphore. The semaphore must have previously been\r
- * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or\r
- * xSemaphoreCreateCounting().\r
- *\r
- * @param xSemaphore A handle to the semaphore being taken - obtained when\r
- * the semaphore was created.\r
- *\r
- * @param xBlockTime The time in ticks to wait for the semaphore to become\r
- * available. The macro portTICK_RATE_MS can be used to convert this to a\r
- * real time. A block time of zero can be used to poll the semaphore. A block\r
- * time of portMAX_DELAY can be used to block indefinitely (provided\r
- * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h).\r
- *\r
- * @return pdTRUE if the semaphore was obtained. pdFALSE\r
- * if xBlockTime expired without the semaphore becoming available.\r
- *\r
- * Example usage:\r
- <pre>\r
- xSemaphoreHandle xSemaphore = NULL;\r
-\r
- // A task that creates a semaphore.\r
- void vATask( void * pvParameters )\r
- {\r
- // Create the semaphore to guard a shared resource.\r
- vSemaphoreCreateBinary( xSemaphore );\r
- }\r
-\r
- // A task that uses the semaphore.\r
- void vAnotherTask( void * pvParameters )\r
- {\r
- // ... Do other things.\r
-\r
- if( xSemaphore != NULL )\r
- {\r
- // See if we can obtain the semaphore. If the semaphore is not available\r
- // wait 10 ticks to see if it becomes free. \r
- if( xSemaphoreTake( xSemaphore, ( portTickType ) 10 ) == pdTRUE )\r
- {\r
- // We were able to obtain the semaphore and can now access the\r
- // shared resource.\r
-\r
- // ...\r
-\r
- // We have finished accessing the shared resource. Release the \r
- // semaphore.\r
- xSemaphoreGive( xSemaphore );\r
- }\r
- else\r
- {\r
- // We could not obtain the semaphore and can therefore not access\r
- // the shared resource safely.\r
- }\r
- }\r
- }\r
- </pre>\r
- * \defgroup xSemaphoreTake xSemaphoreTake\r
- * \ingroup Semaphores\r
- */\r
-#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )\r
-\r
-/**\r
- * semphr. h\r
- * xSemaphoreTakeRecursive( \r
- * xSemaphoreHandle xMutex, \r
- * portTickType xBlockTime \r
- * )\r
- *\r
- * <i>Macro</i> to recursively obtain, or 'take', a mutex type semaphore. \r
- * The mutex must have previously been created using a call to \r
- * xSemaphoreCreateRecursiveMutex();\r
- * \r
- * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this\r
- * macro to be available.\r
- * \r
- * This macro must not be used on mutexes created using xSemaphoreCreateMutex().\r
- *\r
- * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex \r
- * doesn't become available again until the owner has called \r
- * xSemaphoreGiveRecursive() for each successful 'take' request. For example, \r
- * if a task successfully 'takes' the same mutex 5 times then the mutex will \r
- * not be available to any other task until it has also 'given' the mutex back\r
- * exactly five times.\r
- *\r
- * @param xMutex A handle to the mutex being obtained. This is the\r
- * handle returned by xSemaphoreCreateRecursiveMutex();\r
- *\r
- * @param xBlockTime The time in ticks to wait for the semaphore to become\r
- * available. The macro portTICK_RATE_MS can be used to convert this to a\r
- * real time. A block time of zero can be used to poll the semaphore. If\r
- * the task already owns the semaphore then xSemaphoreTakeRecursive() will\r
- * return immediately no matter what the value of xBlockTime. \r
- *\r
- * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime\r
- * expired without the semaphore becoming available.\r
- *\r
- * Example usage:\r
- <pre>\r
- xSemaphoreHandle xMutex = NULL;\r
-\r
- // A task that creates a mutex.\r
- void vATask( void * pvParameters )\r
- {\r
- // Create the mutex to guard a shared resource.\r
- xMutex = xSemaphoreCreateRecursiveMutex();\r
- }\r
-\r
- // A task that uses the mutex.\r
- void vAnotherTask( void * pvParameters )\r
- {\r
- // ... Do other things.\r
-\r
- if( xMutex != NULL )\r
- {\r
- // See if we can obtain the mutex. If the mutex is not available\r
- // wait 10 ticks to see if it becomes free. \r
- if( xSemaphoreTakeRecursive( xSemaphore, ( portTickType ) 10 ) == pdTRUE )\r
- {\r
- // We were able to obtain the mutex and can now access the\r
- // shared resource.\r
-\r
- // ...\r
- // For some reason due to the nature of the code further calls to \r
- // xSemaphoreTakeRecursive() are made on the same mutex. In real\r
- // code these would not be just sequential calls as this would make\r
- // no sense. Instead the calls are likely to be buried inside\r
- // a more complex call structure.\r
- xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );\r
- xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );\r
-\r
- // The mutex has now been 'taken' three times, so will not be \r
- // available to another task until it has also been given back\r
- // three times. Again it is unlikely that real code would have\r
- // these calls sequentially, but instead buried in a more complex\r
- // call structure. This is just for illustrative purposes.\r
- xSemaphoreGiveRecursive( xMutex );\r
- xSemaphoreGiveRecursive( xMutex );\r
- xSemaphoreGiveRecursive( xMutex );\r
-\r
- // Now the mutex can be taken by other tasks.\r
- }\r
- else\r
- {\r
- // We could not obtain the mutex and can therefore not access\r
- // the shared resource safely.\r
- }\r
- }\r
- }\r
- </pre>\r
- * \defgroup xSemaphoreTakeRecursive xSemaphoreTakeRecursive\r
- * \ingroup Semaphores\r
- */\r
-#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )\r
-\r
-\r
-/* \r
- * xSemaphoreAltTake() is an alternative version of xSemaphoreTake().\r
- *\r
- * The source code that implements the alternative (Alt) API is much \r
- * simpler because it executes everything from within a critical section. \r
- * This is the approach taken by many other RTOSes, but FreeRTOS.org has the \r
- * preferred fully featured API too. The fully featured API has more \r
- * complex code that takes longer to execute, but makes much less use of \r
- * critical sections. Therefore the alternative API sacrifices interrupt \r
- * responsiveness to gain execution speed, whereas the fully featured API\r
- * sacrifices execution speed to ensure better interrupt responsiveness.\r
- */\r
-#define xSemaphoreAltTake( xSemaphore, xBlockTime ) xQueueAltGenericReceive( ( xQueueHandle ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )\r
-\r
-/**\r
- * semphr. h\r
- * <pre>xSemaphoreGive( xSemaphoreHandle xSemaphore )</pre>\r
- *\r
- * <i>Macro</i> to release a semaphore. The semaphore must have previously been\r
- * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or\r
- * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake().\r
- *\r
- * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for\r
- * an alternative which can be used from an ISR.\r
- *\r
- * This macro must also not be used on semaphores created using \r
- * xSemaphoreCreateRecursiveMutex().\r
- *\r
- * @param xSemaphore A handle to the semaphore being released. This is the\r
- * handle returned when the semaphore was created.\r
- *\r
- * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred.\r
- * Semaphores are implemented using queues. An error can occur if there is\r
- * no space on the queue to post a message - indicating that the \r
- * semaphore was not first obtained correctly.\r
- *\r
- * Example usage:\r
- <pre>\r
- xSemaphoreHandle xSemaphore = NULL;\r
-\r
- void vATask( void * pvParameters )\r
- {\r
- // Create the semaphore to guard a shared resource.\r
- vSemaphoreCreateBinary( xSemaphore );\r
-\r
- if( xSemaphore != NULL )\r
- {\r
- if( xSemaphoreGive( xSemaphore ) != pdTRUE )\r
- {\r
- // We would expect this call to fail because we cannot give\r
- // a semaphore without first "taking" it!\r
- }\r
-\r
- // Obtain the semaphore - don't block if the semaphore is not\r
- // immediately available.\r
- if( xSemaphoreTake( xSemaphore, ( portTickType ) 0 ) )\r
- {\r
- // We now have the semaphore and can access the shared resource.\r
-\r
- // ...\r
-\r
- // We have finished accessing the shared resource so can free the\r
- // semaphore.\r
- if( xSemaphoreGive( xSemaphore ) != pdTRUE )\r
- {\r
- // We would not expect this call to fail because we must have\r
- // obtained the semaphore to get here.\r
- }\r
- }\r
- }\r
- }\r
- </pre>\r
- * \defgroup xSemaphoreGive xSemaphoreGive\r
- * \ingroup Semaphores\r
- */\r
-#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )\r
-\r
-/**\r
- * semphr. h\r
- * <pre>xSemaphoreGiveRecursive( xSemaphoreHandle xMutex )</pre>\r
- *\r
- * <i>Macro</i> to recursively release, or 'give', a mutex type semaphore.\r
- * The mutex must have previously been created using a call to \r
- * xSemaphoreCreateRecursiveMutex();\r
- * \r
- * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this\r
- * macro to be available.\r
- *\r
- * This macro must not be used on mutexes created using xSemaphoreCreateMutex().\r
- * \r
- * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex \r
- * doesn't become available again until the owner has called \r
- * xSemaphoreGiveRecursive() for each successful 'take' request. For example, \r
- * if a task successfully 'takes' the same mutex 5 times then the mutex will \r
- * not be available to any other task until it has also 'given' the mutex back\r
- * exactly five times.\r
- *\r
- * @param xMutex A handle to the mutex being released, or 'given'. This is the\r
- * handle returned by xSemaphoreCreateMutex();\r
- *\r
- * @return pdTRUE if the semaphore was given.\r
- *\r
- * Example usage:\r
- <pre>\r
- xSemaphoreHandle xMutex = NULL;\r
-\r
- // A task that creates a mutex.\r
- void vATask( void * pvParameters )\r
- {\r
- // Create the mutex to guard a shared resource.\r
- xMutex = xSemaphoreCreateRecursiveMutex();\r
- }\r
-\r
- // A task that uses the mutex.\r
- void vAnotherTask( void * pvParameters )\r
- {\r
- // ... Do other things.\r
-\r
- if( xMutex != NULL )\r
- {\r
- // See if we can obtain the mutex. If the mutex is not available\r
- // wait 10 ticks to see if it becomes free. \r
- if( xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 ) == pdTRUE )\r
- {\r
- // We were able to obtain the mutex and can now access the\r
- // shared resource.\r
-\r
- // ...\r
- // For some reason due to the nature of the code further calls to \r
- // xSemaphoreTakeRecursive() are made on the same mutex. In real\r
- // code these would not be just sequential calls as this would make\r
- // no sense. Instead the calls are likely to be buried inside\r
- // a more complex call structure.\r
- xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );\r
- xSemaphoreTakeRecursive( xMutex, ( portTickType ) 10 );\r
-\r
- // The mutex has now been 'taken' three times, so will not be \r
- // available to another task until it has also been given back\r
- // three times. Again it is unlikely that real code would have\r
- // these calls sequentially, it would be more likely that the calls\r
- // to xSemaphoreGiveRecursive() would be called as a call stack\r
- // unwound. This is just for demonstrative purposes.\r
- xSemaphoreGiveRecursive( xMutex );\r
- xSemaphoreGiveRecursive( xMutex );\r
- xSemaphoreGiveRecursive( xMutex );\r
-\r
- // Now the mutex can be taken by other tasks.\r
- }\r
- else\r
- {\r
- // We could not obtain the mutex and can therefore not access\r
- // the shared resource safely.\r
- }\r
- }\r
- }\r
- </pre>\r
- * \defgroup xSemaphoreGiveRecursive xSemaphoreGiveRecursive\r
- * \ingroup Semaphores\r
- */\r
-#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) )\r
-\r
-/* \r
- * xSemaphoreAltGive() is an alternative version of xSemaphoreGive().\r
- *\r
- * The source code that implements the alternative (Alt) API is much \r
- * simpler because it executes everything from within a critical section. \r
- * This is the approach taken by many other RTOSes, but FreeRTOS.org has the \r
- * preferred fully featured API too. The fully featured API has more \r
- * complex code that takes longer to execute, but makes much less use of \r
- * critical sections. Therefore the alternative API sacrifices interrupt \r
- * responsiveness to gain execution speed, whereas the fully featured API\r
- * sacrifices execution speed to ensure better interrupt responsiveness.\r
- */\r
-#define xSemaphoreAltGive( xSemaphore ) xQueueAltGenericSend( ( xQueueHandle ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )\r
-\r
-/**\r
- * semphr. h\r
- * <pre>\r
- xSemaphoreGiveFromISR( \r
- xSemaphoreHandle xSemaphore, \r
- signed portBASE_TYPE *pxHigherPriorityTaskWoken\r
- )</pre>\r
- *\r
- * <i>Macro</i> to release a semaphore. The semaphore must have previously been\r
- * created with a call to vSemaphoreCreateBinary() or xSemaphoreCreateCounting().\r
- *\r
- * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex())\r
- * must not be used with this macro.\r
- *\r
- * This macro can be used from an ISR.\r
- *\r
- * @param xSemaphore A handle to the semaphore being released. This is the\r
- * handle returned when the semaphore was created.\r
- *\r
- * @param pxHigherPriorityTaskWoken xSemaphoreGiveFromISR() will set\r
- * *pxHigherPriorityTaskWoken to pdTRUE if giving the semaphore caused a task\r
- * to unblock, and the unblocked task has a priority higher than the currently\r
- * running task. If xSemaphoreGiveFromISR() sets this value to pdTRUE then\r
- * a context switch should be requested before the interrupt is exited.\r
- *\r
- * @return pdTRUE if the semaphore was successfully given, otherwise errQUEUE_FULL.\r
- *\r
- * Example usage:\r
- <pre>\r
- \#define LONG_TIME 0xffff\r
- \#define TICKS_TO_WAIT 10\r
- xSemaphoreHandle xSemaphore = NULL;\r
-\r
- // Repetitive task.\r
- void vATask( void * pvParameters )\r
- {\r
- for( ;; )\r
- {\r
- // We want this task to run every 10 ticks of a timer. The semaphore \r
- // was created before this task was started.\r
-\r
- // Block waiting for the semaphore to become available.\r
- if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )\r
- {\r
- // It is time to execute.\r
-\r
- // ...\r
-\r
- // We have finished our task. Return to the top of the loop where\r
- // we will block on the semaphore until it is time to execute \r
- // again. Note when using the semaphore for synchronisation with an\r
- // ISR in this manner there is no need to 'give' the semaphore back.\r
- }\r
- }\r
- }\r
-\r
- // Timer ISR\r
- void vTimerISR( void * pvParameters )\r
- {\r
- static unsigned char ucLocalTickCount = 0;\r
- static signed portBASE_TYPE xHigherPriorityTaskWoken;\r
-\r
- // A timer tick has occurred.\r
-\r
- // ... Do other time functions.\r
-\r
- // Is it time for vATask () to run?\r
- xHigherPriorityTaskWoken = pdFALSE;\r
- ucLocalTickCount++;\r
- if( ucLocalTickCount >= TICKS_TO_WAIT )\r
- {\r
- // Unblock the task by releasing the semaphore.\r
- xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );\r
-\r
- // Reset the count so we release the semaphore again in 10 ticks time.\r
- ucLocalTickCount = 0;\r
- }\r
-\r
- if( xHigherPriorityTaskWoken != pdFALSE )\r
- {\r
- // We can force a context switch here. Context switching from an\r
- // ISR uses port specific syntax. Check the demo task for your port\r
- // to find the syntax required.\r
- }\r
- }\r
- </pre>\r
- * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR\r
- * \ingroup Semaphores\r
- */\r
-#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueueHandle ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )\r
-\r
-/**\r
- * semphr. h\r
- * <pre>xSemaphoreHandle xSemaphoreCreateMutex( void )</pre>\r
- *\r
- * <i>Macro</i> that implements a mutex semaphore by using the existing queue \r
- * mechanism.\r
- *\r
- * Mutexes created using this macro can be accessed using the xSemaphoreTake()\r
- * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and \r
- * xSemaphoreGiveRecursive() macros should not be used.\r
- * \r
- * This type of semaphore uses a priority inheritance mechanism so a task \r
- * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the \r
- * semaphore it is no longer required. \r
- *\r
- * Mutex type semaphores cannot be used from within interrupt service routines. \r
- *\r
- * See vSemaphoreCreateBinary() for an alternative implementation that can be \r
- * used for pure synchronisation (where one task or interrupt always 'gives' the \r
- * semaphore and another always 'takes' the semaphore) and from within interrupt \r
- * service routines.\r
- *\r
- * @return xSemaphore Handle to the created mutex semaphore. Should be of type \r
- * xSemaphoreHandle.\r
- *\r
- * Example usage:\r
- <pre>\r
- xSemaphoreHandle xSemaphore;\r
-\r
- void vATask( void * pvParameters )\r
- {\r
- // Semaphore cannot be used before a call to xSemaphoreCreateMutex().\r
- // This is a macro so pass the variable in directly.\r
- xSemaphore = xSemaphoreCreateMutex();\r
-\r
- if( xSemaphore != NULL )\r
- {\r
- // The semaphore was created successfully.\r
- // The semaphore can now be used. \r
- }\r
- }\r
- </pre>\r
- * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex\r
- * \ingroup Semaphores\r
- */\r
-#define xSemaphoreCreateMutex() xQueueCreateMutex()\r
-\r
-\r
-/**\r
- * semphr. h\r
- * <pre>xSemaphoreHandle xSemaphoreCreateRecursiveMutex( void )</pre>\r
- *\r
- * <i>Macro</i> that implements a recursive mutex by using the existing queue \r
- * mechanism.\r
- *\r
- * Mutexes created using this macro can be accessed using the \r
- * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The \r
- * xSemaphoreTake() and xSemaphoreGive() macros should not be used.\r
- *\r
- * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex \r
- * doesn't become available again until the owner has called \r
- * xSemaphoreGiveRecursive() for each successful 'take' request. For example, \r
- * if a task successfully 'takes' the same mutex 5 times then the mutex will \r
- * not be available to any other task until it has also 'given' the mutex back\r
- * exactly five times.\r
- * \r
- * This type of semaphore uses a priority inheritance mechanism so a task \r
- * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the \r
- * semaphore it is no longer required. \r
- *\r
- * Mutex type semaphores cannot be used from within interrupt service routines. \r
- *\r
- * See vSemaphoreCreateBinary() for an alternative implementation that can be \r
- * used for pure synchronisation (where one task or interrupt always 'gives' the \r
- * semaphore and another always 'takes' the semaphore) and from within interrupt \r
- * service routines.\r
- *\r
- * @return xSemaphore Handle to the created mutex semaphore. Should be of type \r
- * xSemaphoreHandle.\r
- *\r
- * Example usage:\r
- <pre>\r
- xSemaphoreHandle xSemaphore;\r
-\r
- void vATask( void * pvParameters )\r
- {\r
- // Semaphore cannot be used before a call to xSemaphoreCreateMutex().\r
- // This is a macro so pass the variable in directly.\r
- xSemaphore = xSemaphoreCreateRecursiveMutex();\r
-\r
- if( xSemaphore != NULL )\r
- {\r
- // The semaphore was created successfully.\r
- // The semaphore can now be used. \r
- }\r
- }\r
- </pre>\r
- * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex\r
- * \ingroup Semaphores\r
- */\r
-#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex()\r
-\r
-/**\r
- * semphr. h\r
- * <pre>xSemaphoreHandle xSemaphoreCreateCounting( unsigned portBASE_TYPE uxMaxCount, unsigned portBASE_TYPE uxInitialCount )</pre>\r
- *\r
- * <i>Macro</i> that creates a counting semaphore by using the existing \r
- * queue mechanism. \r
- *\r
- * Counting semaphores are typically used for two things:\r
- *\r
- * 1) Counting events. \r
- *\r
- * In this usage scenario an event handler will 'give' a semaphore each time\r
- * an event occurs (incrementing the semaphore count value), and a handler \r
- * task will 'take' a semaphore each time it processes an event \r
- * (decrementing the semaphore count value). The count value is therefore \r
- * the difference between the number of events that have occurred and the \r
- * number that have been processed. In this case it is desirable for the \r
- * initial count value to be zero.\r
- *\r
- * 2) Resource management.\r
- *\r
- * In this usage scenario the count value indicates the number of resources\r
- * available. To obtain control of a resource a task must first obtain a \r
- * semaphore - decrementing the semaphore count value. When the count value\r
- * reaches zero there are no free resources. When a task finishes with the\r
- * resource it 'gives' the semaphore back - incrementing the semaphore count\r
- * value. In this case it is desirable for the initial count value to be\r
- * equal to the maximum count value, indicating that all resources are free.\r
- *\r
- * @param uxMaxCount The maximum count value that can be reached. When the \r
- * semaphore reaches this value it can no longer be 'given'.\r
- *\r
- * @param uxInitialCount The count value assigned to the semaphore when it is\r
- * created.\r
- *\r
- * @return Handle to the created semaphore. Null if the semaphore could not be\r
- * created.\r
- * \r
- * Example usage:\r
- <pre>\r
- xSemaphoreHandle xSemaphore;\r
-\r
- void vATask( void * pvParameters )\r
- {\r
- xSemaphoreHandle xSemaphore = NULL;\r
-\r
- // Semaphore cannot be used before a call to xSemaphoreCreateCounting().\r
- // The max value to which the semaphore can count should be 10, and the\r
- // initial value assigned to the count should be 0.\r
- xSemaphore = xSemaphoreCreateCounting( 10, 0 );\r
-\r
- if( xSemaphore != NULL )\r
- {\r
- // The semaphore was created successfully.\r
- // The semaphore can now be used. \r
- }\r
- }\r
- </pre>\r
- * \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting\r
- * \ingroup Semaphores\r
- */\r
-#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )\r
-\r
-/**\r
- * semphr. h\r
- * <pre>void vSemaphoreDelete( xSemaphoreHandle xSemaphore );</pre>\r
- *\r
- * Delete a semaphore. This function must be used with care. For example,\r
- * do not delete a mutex type semaphore if the mutex is held by a task.\r
- *\r
- * @param xSemaphore A handle to the semaphore to be deleted.\r
- *\r
- * \page vSemaphoreDelete vSemaphoreDelete\r
- * \ingroup Semaphores\r
- */\r
-#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( xQueueHandle ) xSemaphore )\r
-\r
-#endif /* SEMAPHORE_H */\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-\r
-#ifndef TASK_H\r
-#define TASK_H\r
-\r
-#ifndef INC_FREERTOS_H\r
- #error "include FreeRTOS.h must appear in source files before include task.h"\r
-#endif\r
-\r
-#include "portable.h"\r
-#include "list.h"\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-/*-----------------------------------------------------------\r
- * MACROS AND DEFINITIONS\r
- *----------------------------------------------------------*/\r
-\r
-#define tskKERNEL_VERSION_NUMBER "V7.0.1"\r
-\r
-/**\r
- * task. h\r
- *\r
- * Type by which tasks are referenced. For example, a call to xTaskCreate\r
- * returns (via a pointer parameter) an xTaskHandle variable that can then\r
- * be used as a parameter to vTaskDelete to delete the task.\r
- *\r
- * \page xTaskHandle xTaskHandle\r
- * \ingroup Tasks\r
- */\r
-typedef void * xTaskHandle;\r
-\r
-/*\r
- * Used internally only.\r
- */\r
-typedef struct xTIME_OUT\r
-{\r
- portBASE_TYPE xOverflowCount;\r
- portTickType xTimeOnEntering;\r
-} xTimeOutType;\r
-\r
-/*\r
- * Defines the memory ranges allocated to the task when an MPU is used.\r
- */\r
-typedef struct xMEMORY_REGION\r
-{\r
- void *pvBaseAddress;\r
- unsigned long ulLengthInBytes;\r
- unsigned long ulParameters;\r
-} xMemoryRegion;\r
-\r
-/*\r
- * Parameters required to create an MPU protected task.\r
- */\r
-typedef struct xTASK_PARAMTERS\r
-{\r
- pdTASK_CODE pvTaskCode;\r
- const signed char * const pcName;\r
- unsigned short usStackDepth;\r
- void *pvParameters;\r
- unsigned portBASE_TYPE uxPriority;\r
- portSTACK_TYPE *puxStackBuffer;\r
- xMemoryRegion xRegions[ portNUM_CONFIGURABLE_REGIONS ];\r
-} xTaskParameters;\r
-\r
-/*\r
- * Defines the priority used by the idle task. This must not be modified.\r
- *\r
- * \ingroup TaskUtils\r
- */\r
-#define tskIDLE_PRIORITY ( ( unsigned portBASE_TYPE ) 0U )\r
-\r
-/**\r
- * task. h\r
- *\r
- * Macro for forcing a context switch.\r
- *\r
- * \page taskYIELD taskYIELD\r
- * \ingroup SchedulerControl\r
- */\r
-#define taskYIELD() portYIELD()\r
-\r
-/**\r
- * task. h\r
- *\r
- * Macro to mark the start of a critical code region. Preemptive context\r
- * switches cannot occur when in a critical region.\r
- *\r
- * NOTE: This may alter the stack (depending on the portable implementation)\r
- * so must be used with care!\r
- *\r
- * \page taskENTER_CRITICAL taskENTER_CRITICAL\r
- * \ingroup SchedulerControl\r
- */\r
-#define taskENTER_CRITICAL() portENTER_CRITICAL()\r
-\r
-/**\r
- * task. h\r
- *\r
- * Macro to mark the end of a critical code region. Preemptive context\r
- * switches cannot occur when in a critical region.\r
- *\r
- * NOTE: This may alter the stack (depending on the portable implementation)\r
- * so must be used with care!\r
- *\r
- * \page taskEXIT_CRITICAL taskEXIT_CRITICAL\r
- * \ingroup SchedulerControl\r
- */\r
-#define taskEXIT_CRITICAL() portEXIT_CRITICAL()\r
-\r
-/**\r
- * task. h\r
- *\r
- * Macro to disable all maskable interrupts.\r
- *\r
- * \page taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS\r
- * \ingroup SchedulerControl\r
- */\r
-#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS()\r
-\r
-/**\r
- * task. h\r
- *\r
- * Macro to enable microcontroller interrupts.\r
- *\r
- * \page taskENABLE_INTERRUPTS taskENABLE_INTERRUPTS\r
- * \ingroup SchedulerControl\r
- */\r
-#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS()\r
-\r
-/* Definitions returned by xTaskGetSchedulerState(). */\r
-#define taskSCHEDULER_NOT_STARTED 0\r
-#define taskSCHEDULER_RUNNING 1\r
-#define taskSCHEDULER_SUSPENDED 2\r
-\r
-/*-----------------------------------------------------------\r
- * TASK CREATION API\r
- *----------------------------------------------------------*/\r
-\r
-/**\r
- * task. h\r
- *<pre>\r
- portBASE_TYPE xTaskCreate(\r
- pdTASK_CODE pvTaskCode,\r
- const signed char * const pcName,\r
- unsigned short usStackDepth,\r
- void *pvParameters,\r
- unsigned portBASE_TYPE uxPriority,\r
- xTaskHandle *pvCreatedTask\r
- );</pre>\r
- *\r
- * Create a new task and add it to the list of tasks that are ready to run.\r
- *\r
- * xTaskCreate() can only be used to create a task that has unrestricted\r
- * access to the entire microcontroller memory map. Systems that include MPU\r
- * support can alternatively create an MPU constrained task using\r
- * xTaskCreateRestricted().\r
- *\r
- * @param pvTaskCode Pointer to the task entry function. Tasks\r
- * must be implemented to never return (i.e. continuous loop).\r
- *\r
- * @param pcName A descriptive name for the task. This is mainly used to\r
- * facilitate debugging. Max length defined by tskMAX_TASK_NAME_LEN - default\r
- * is 16.\r
- *\r
- * @param usStackDepth The size of the task stack specified as the number of\r
- * variables the stack can hold - not the number of bytes. For example, if\r
- * the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes\r
- * will be allocated for stack storage.\r
- *\r
- * @param pvParameters Pointer that will be used as the parameter for the task\r
- * being created.\r
- *\r
- * @param uxPriority The priority at which the task should run. Systems that\r
- * include MPU support can optionally create tasks in a privileged (system)\r
- * mode by setting bit portPRIVILEGE_BIT of the priority parameter. For\r
- * example, to create a privileged task at priority 2 the uxPriority parameter\r
- * should be set to ( 2 | portPRIVILEGE_BIT ).\r
- *\r
- * @param pvCreatedTask Used to pass back a handle by which the created task\r
- * can be referenced.\r
- *\r
- * @return pdPASS if the task was successfully created and added to a ready\r
- * list, otherwise an error code defined in the file errors. h\r
- *\r
- * Example usage:\r
- <pre>\r
- // Task to be created.\r
- void vTaskCode( void * pvParameters )\r
- {\r
- for( ;; )\r
- {\r
- // Task code goes here.\r
- }\r
- }\r
-\r
- // Function that creates a task.\r
- void vOtherFunction( void )\r
- {\r
- static unsigned char ucParameterToPass;\r
- xTaskHandle xHandle;\r
-\r
- // Create the task, storing the handle. Note that the passed parameter ucParameterToPass\r
- // must exist for the lifetime of the task, so in this case is declared static. If it was just an\r
- // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time\r
- // the new task attempts to access it.\r
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );\r
-\r
- // Use the handle to delete the task.\r
- vTaskDelete( xHandle );\r
- }\r
- </pre>\r
- * \defgroup xTaskCreate xTaskCreate\r
- * \ingroup Tasks\r
- */\r
-#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )\r
-\r
-/**\r
- * task. h\r
- *<pre>\r
- portBASE_TYPE xTaskCreateRestricted( xTaskParameters *pxTaskDefinition, xTaskHandle *pxCreatedTask );</pre>\r
- *\r
- * xTaskCreateRestricted() should only be used in systems that include an MPU\r
- * implementation.\r
- *\r
- * Create a new task and add it to the list of tasks that are ready to run.\r
- * The function parameters define the memory regions and associated access\r
- * permissions allocated to the task.\r
- *\r
- * @param pxTaskDefinition Pointer to a structure that contains a member\r
- * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API\r
- * documentation) plus an optional stack buffer and the memory region\r
- * definitions.\r
- *\r
- * @param pxCreatedTask Used to pass back a handle by which the created task\r
- * can be referenced.\r
- *\r
- * @return pdPASS if the task was successfully created and added to a ready\r
- * list, otherwise an error code defined in the file errors. h\r
- *\r
- * Example usage:\r
- <pre>\r
-// Create an xTaskParameters structure that defines the task to be created.\r
-static const xTaskParameters xCheckTaskParameters =\r
-{\r
- vATask, // pvTaskCode - the function that implements the task.\r
- "ATask", // pcName - just a text name for the task to assist debugging.\r
- 100, // usStackDepth - the stack size DEFINED IN WORDS.\r
- NULL, // pvParameters - passed into the task function as the function parameters.\r
- ( 1UL | portPRIVILEGE_BIT ),// uxPriority - task priority, set the portPRIVILEGE_BIT if the task should run in a privileged state.\r
- cStackBuffer,// puxStackBuffer - the buffer to be used as the task stack.\r
-\r
- // xRegions - Allocate up to three separate memory regions for access by\r
- // the task, with appropriate access permissions. Different processors have\r
- // different memory alignment requirements - refer to the FreeRTOS documentation\r
- // for full information.\r
- { \r
- // Base address Length Parameters\r
- { cReadWriteArray, 32, portMPU_REGION_READ_WRITE },\r
- { cReadOnlyArray, 32, portMPU_REGION_READ_ONLY },\r
- { cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE }\r
- }\r
-};\r
-\r
-int main( void )\r
-{\r
-xTaskHandle xHandle;\r
-\r
- // Create a task from the const structure defined above. The task handle\r
- // is requested (the second parameter is not NULL) but in this case just for\r
- // demonstration purposes as its not actually used.\r
- xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );\r
-\r
- // Start the scheduler.\r
- vTaskStartScheduler();\r
-\r
- // Will only get here if there was insufficient memory to create the idle\r
- // task.\r
- for( ;; );\r
-}\r
- </pre>\r
- * \defgroup xTaskCreateRestricted xTaskCreateRestricted\r
- * \ingroup Tasks\r
- */\r
-#define xTaskCreateRestricted( x, pxCreatedTask ) xTaskGenericCreate( ((x)->pvTaskCode), ((x)->pcName), ((x)->usStackDepth), ((x)->pvParameters), ((x)->uxPriority), (pxCreatedTask), ((x)->puxStackBuffer), ((x)->xRegions) )\r
-\r
-/**\r
- * task. h\r
- *<pre>\r
- void vTaskAllocateMPURegions( xTaskHandle xTask, const xMemoryRegion * const pxRegions );</pre>\r
- *\r
- * Memory regions are assigned to a restricted task when the task is created by\r
- * a call to xTaskCreateRestricted(). These regions can be redefined using\r
- * vTaskAllocateMPURegions().\r
- *\r
- * @param xTask The handle of the task being updated.\r
- *\r
- * @param xRegions A pointer to an xMemoryRegion structure that contains the\r
- * new memory region definitions.\r
- *\r
- * Example usage:\r
- <pre>\r
-// Define an array of xMemoryRegion structures that configures an MPU region\r
-// allowing read/write access for 1024 bytes starting at the beginning of the\r
-// ucOneKByte array. The other two of the maximum 3 definable regions are\r
-// unused so set to zero.\r
-static const xMemoryRegion xAltRegions[ portNUM_CONFIGURABLE_REGIONS ] =\r
-{ \r
- // Base address Length Parameters\r
- { ucOneKByte, 1024, portMPU_REGION_READ_WRITE },\r
- { 0, 0, 0 },\r
- { 0, 0, 0 }\r
-};\r
-\r
-void vATask( void *pvParameters )\r
-{\r
- // This task was created such that it has access to certain regions of\r
- // memory as defined by the MPU configuration. At some point it is\r
- // desired that these MPU regions are replaced with that defined in the\r
- // xAltRegions const struct above. Use a call to vTaskAllocateMPURegions()\r
- // for this purpose. NULL is used as the task handle to indicate that this\r
- // function should modify the MPU regions of the calling task.\r
- vTaskAllocateMPURegions( NULL, xAltRegions );\r
- \r
- // Now the task can continue its function, but from this point on can only\r
- // access its stack and the ucOneKByte array (unless any other statically\r
- // defined or shared regions have been declared elsewhere).\r
-}\r
- </pre>\r
- * \defgroup xTaskCreateRestricted xTaskCreateRestricted\r
- * \ingroup Tasks\r
- */\r
-void vTaskAllocateMPURegions( xTaskHandle xTask, const xMemoryRegion * const pxRegions ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <pre>void vTaskDelete( xTaskHandle pxTask );</pre>\r
- *\r
- * INCLUDE_vTaskDelete must be defined as 1 for this function to be available.\r
- * See the configuration section for more information.\r
- *\r
- * Remove a task from the RTOS real time kernels management. The task being\r
- * deleted will be removed from all ready, blocked, suspended and event lists.\r
- *\r
- * NOTE: The idle task is responsible for freeing the kernel allocated\r
- * memory from tasks that have been deleted. It is therefore important that\r
- * the idle task is not starved of microcontroller processing time if your\r
- * application makes any calls to vTaskDelete (). Memory allocated by the\r
- * task code is not automatically freed, and should be freed before the task\r
- * is deleted.\r
- *\r
- * See the demo application file death.c for sample code that utilises\r
- * vTaskDelete ().\r
- *\r
- * @param pxTask The handle of the task to be deleted. Passing NULL will\r
- * cause the calling task to be deleted.\r
- *\r
- * Example usage:\r
- <pre>\r
- void vOtherFunction( void )\r
- {\r
- xTaskHandle xHandle;\r
-\r
- // Create the task, storing the handle.\r
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );\r
-\r
- // Use the handle to delete the task.\r
- vTaskDelete( xHandle );\r
- }\r
- </pre>\r
- * \defgroup vTaskDelete vTaskDelete\r
- * \ingroup Tasks\r
- */\r
-void vTaskDelete( xTaskHandle pxTaskToDelete ) PRIVILEGED_FUNCTION;\r
-\r
-/*-----------------------------------------------------------\r
- * TASK CONTROL API\r
- *----------------------------------------------------------*/\r
-\r
-/**\r
- * task. h\r
- * <pre>void vTaskDelay( portTickType xTicksToDelay );</pre>\r
- *\r
- * Delay a task for a given number of ticks. The actual time that the\r
- * task remains blocked depends on the tick rate. The constant\r
- * portTICK_RATE_MS can be used to calculate real time from the tick\r
- * rate - with the resolution of one tick period.\r
- *\r
- * INCLUDE_vTaskDelay must be defined as 1 for this function to be available.\r
- * See the configuration section for more information.\r
- *\r
- *\r
- * vTaskDelay() specifies a time at which the task wishes to unblock relative to\r
- * the time at which vTaskDelay() is called. For example, specifying a block\r
- * period of 100 ticks will cause the task to unblock 100 ticks after\r
- * vTaskDelay() is called. vTaskDelay() does not therefore provide a good method\r
- * of controlling the frequency of a cyclical task as the path taken through the\r
- * code, as well as other task and interrupt activity, will effect the frequency\r
- * at which vTaskDelay() gets called and therefore the time at which the task\r
- * next executes. See vTaskDelayUntil() for an alternative API function designed\r
- * to facilitate fixed frequency execution. It does this by specifying an\r
- * absolute time (rather than a relative time) at which the calling task should\r
- * unblock.\r
- *\r
- * @param xTicksToDelay The amount of time, in tick periods, that\r
- * the calling task should block.\r
- *\r
- * Example usage:\r
-\r
- void vTaskFunction( void * pvParameters )\r
- {\r
- void vTaskFunction( void * pvParameters )\r
- {\r
- // Block for 500ms.\r
- const portTickType xDelay = 500 / portTICK_RATE_MS;\r
-\r
- for( ;; )\r
- {\r
- // Simply toggle the LED every 500ms, blocking between each toggle.\r
- vToggleLED();\r
- vTaskDelay( xDelay );\r
- }\r
- }\r
-\r
- * \defgroup vTaskDelay vTaskDelay\r
- * \ingroup TaskCtrl\r
- */\r
-void vTaskDelay( portTickType xTicksToDelay ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <pre>void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );</pre>\r
- *\r
- * INCLUDE_vTaskDelayUntil must be defined as 1 for this function to be available.\r
- * See the configuration section for more information.\r
- *\r
- * Delay a task until a specified time. This function can be used by cyclical\r
- * tasks to ensure a constant execution frequency.\r
- *\r
- * This function differs from vTaskDelay () in one important aspect: vTaskDelay () will\r
- * cause a task to block for the specified number of ticks from the time vTaskDelay () is\r
- * called. It is therefore difficult to use vTaskDelay () by itself to generate a fixed\r
- * execution frequency as the time between a task starting to execute and that task\r
- * calling vTaskDelay () may not be fixed [the task may take a different path though the\r
- * code between calls, or may get interrupted or preempted a different number of times\r
- * each time it executes].\r
- *\r
- * Whereas vTaskDelay () specifies a wake time relative to the time at which the function\r
- * is called, vTaskDelayUntil () specifies the absolute (exact) time at which it wishes to\r
- * unblock.\r
- *\r
- * The constant portTICK_RATE_MS can be used to calculate real time from the tick\r
- * rate - with the resolution of one tick period.\r
- *\r
- * @param pxPreviousWakeTime Pointer to a variable that holds the time at which the\r
- * task was last unblocked. The variable must be initialised with the current time\r
- * prior to its first use (see the example below). Following this the variable is\r
- * automatically updated within vTaskDelayUntil ().\r
- *\r
- * @param xTimeIncrement The cycle time period. The task will be unblocked at\r
- * time *pxPreviousWakeTime + xTimeIncrement. Calling vTaskDelayUntil with the\r
- * same xTimeIncrement parameter value will cause the task to execute with\r
- * a fixed interface period.\r
- *\r
- * Example usage:\r
- <pre>\r
- // Perform an action every 10 ticks.\r
- void vTaskFunction( void * pvParameters )\r
- {\r
- portTickType xLastWakeTime;\r
- const portTickType xFrequency = 10;\r
-\r
- // Initialise the xLastWakeTime variable with the current time.\r
- xLastWakeTime = xTaskGetTickCount ();\r
- for( ;; )\r
- {\r
- // Wait for the next cycle.\r
- vTaskDelayUntil( &xLastWakeTime, xFrequency );\r
-\r
- // Perform action here.\r
- }\r
- }\r
- </pre>\r
- * \defgroup vTaskDelayUntil vTaskDelayUntil\r
- * \ingroup TaskCtrl\r
- */\r
-void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <pre>unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );</pre>\r
- *\r
- * INCLUDE_xTaskPriorityGet must be defined as 1 for this function to be available.\r
- * See the configuration section for more information.\r
- *\r
- * Obtain the priority of any task.\r
- *\r
- * @param pxTask Handle of the task to be queried. Passing a NULL\r
- * handle results in the priority of the calling task being returned.\r
- *\r
- * @return The priority of pxTask.\r
- *\r
- * Example usage:\r
- <pre>\r
- void vAFunction( void )\r
- {\r
- xTaskHandle xHandle;\r
-\r
- // Create a task, storing the handle.\r
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );\r
-\r
- // ...\r
-\r
- // Use the handle to obtain the priority of the created task.\r
- // It was created with tskIDLE_PRIORITY, but may have changed\r
- // it itself.\r
- if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )\r
- {\r
- // The task has changed it's priority.\r
- }\r
-\r
- // ...\r
-\r
- // Is our priority higher than the created task?\r
- if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )\r
- {\r
- // Our priority (obtained using NULL handle) is higher.\r
- }\r
- }\r
- </pre>\r
- * \defgroup uxTaskPriorityGet uxTaskPriorityGet\r
- * \ingroup TaskCtrl\r
- */\r
-unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <pre>void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );</pre>\r
- *\r
- * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available.\r
- * See the configuration section for more information.\r
- *\r
- * Set the priority of any task.\r
- *\r
- * A context switch will occur before the function returns if the priority\r
- * being set is higher than the currently executing task.\r
- *\r
- * @param pxTask Handle to the task for which the priority is being set.\r
- * Passing a NULL handle results in the priority of the calling task being set.\r
- *\r
- * @param uxNewPriority The priority to which the task will be set.\r
- *\r
- * Example usage:\r
- <pre>\r
- void vAFunction( void )\r
- {\r
- xTaskHandle xHandle;\r
-\r
- // Create a task, storing the handle.\r
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );\r
-\r
- // ...\r
-\r
- // Use the handle to raise the priority of the created task.\r
- vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 );\r
-\r
- // ...\r
-\r
- // Use a NULL handle to raise our priority to the same value.\r
- vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );\r
- }\r
- </pre>\r
- * \defgroup vTaskPrioritySet vTaskPrioritySet\r
- * \ingroup TaskCtrl\r
- */\r
-void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <pre>void vTaskSuspend( xTaskHandle pxTaskToSuspend );</pre>\r
- *\r
- * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.\r
- * See the configuration section for more information.\r
- *\r
- * Suspend any task. When suspended a task will never get any microcontroller\r
- * processing time, no matter what its priority.\r
- *\r
- * Calls to vTaskSuspend are not accumulative -\r
- * i.e. calling vTaskSuspend () twice on the same task still only requires one\r
- * call to vTaskResume () to ready the suspended task.\r
- *\r
- * @param pxTaskToSuspend Handle to the task being suspended. Passing a NULL\r
- * handle will cause the calling task to be suspended.\r
- *\r
- * Example usage:\r
- <pre>\r
- void vAFunction( void )\r
- {\r
- xTaskHandle xHandle;\r
-\r
- // Create a task, storing the handle.\r
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );\r
-\r
- // ...\r
-\r
- // Use the handle to suspend the created task.\r
- vTaskSuspend( xHandle );\r
-\r
- // ...\r
-\r
- // The created task will not run during this period, unless\r
- // another task calls vTaskResume( xHandle ).\r
-\r
- //...\r
-\r
-\r
- // Suspend ourselves.\r
- vTaskSuspend( NULL );\r
-\r
- // We cannot get here unless another task calls vTaskResume\r
- // with our handle as the parameter.\r
- }\r
- </pre>\r
- * \defgroup vTaskSuspend vTaskSuspend\r
- * \ingroup TaskCtrl\r
- */\r
-void vTaskSuspend( xTaskHandle pxTaskToSuspend ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <pre>void vTaskResume( xTaskHandle pxTaskToResume );</pre>\r
- *\r
- * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.\r
- * See the configuration section for more information.\r
- *\r
- * Resumes a suspended task.\r
- *\r
- * A task that has been suspended by one of more calls to vTaskSuspend ()\r
- * will be made available for running again by a single call to\r
- * vTaskResume ().\r
- *\r
- * @param pxTaskToResume Handle to the task being readied.\r
- *\r
- * Example usage:\r
- <pre>\r
- void vAFunction( void )\r
- {\r
- xTaskHandle xHandle;\r
-\r
- // Create a task, storing the handle.\r
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );\r
-\r
- // ...\r
-\r
- // Use the handle to suspend the created task.\r
- vTaskSuspend( xHandle );\r
-\r
- // ...\r
-\r
- // The created task will not run during this period, unless\r
- // another task calls vTaskResume( xHandle ).\r
-\r
- //...\r
-\r
-\r
- // Resume the suspended task ourselves.\r
- vTaskResume( xHandle );\r
-\r
- // The created task will once again get microcontroller processing\r
- // time in accordance with it priority within the system.\r
- }\r
- </pre>\r
- * \defgroup vTaskResume vTaskResume\r
- * \ingroup TaskCtrl\r
- */\r
-void vTaskResume( xTaskHandle pxTaskToResume ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <pre>void xTaskResumeFromISR( xTaskHandle pxTaskToResume );</pre>\r
- *\r
- * INCLUDE_xTaskResumeFromISR must be defined as 1 for this function to be\r
- * available. See the configuration section for more information.\r
- *\r
- * An implementation of vTaskResume() that can be called from within an ISR.\r
- *\r
- * A task that has been suspended by one of more calls to vTaskSuspend ()\r
- * will be made available for running again by a single call to\r
- * xTaskResumeFromISR ().\r
- *\r
- * @param pxTaskToResume Handle to the task being readied.\r
- *\r
- * \defgroup vTaskResumeFromISR vTaskResumeFromISR\r
- * \ingroup TaskCtrl\r
- */\r
-portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume ) PRIVILEGED_FUNCTION;\r
-\r
-/*-----------------------------------------------------------\r
- * SCHEDULER CONTROL\r
- *----------------------------------------------------------*/\r
-\r
-/**\r
- * task. h\r
- * <pre>void vTaskStartScheduler( void );</pre>\r
- *\r
- * Starts the real time kernel tick processing. After calling the kernel\r
- * has control over which tasks are executed and when. This function\r
- * does not return until an executing task calls vTaskEndScheduler ().\r
- *\r
- * At least one task should be created via a call to xTaskCreate ()\r
- * before calling vTaskStartScheduler (). The idle task is created\r
- * automatically when the first application task is created.\r
- *\r
- * See the demo application file main.c for an example of creating\r
- * tasks and starting the kernel.\r
- *\r
- * Example usage:\r
- <pre>\r
- void vAFunction( void )\r
- {\r
- // Create at least one task before starting the kernel.\r
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
-\r
- // Start the real time kernel with preemption.\r
- vTaskStartScheduler ();\r
-\r
- // Will not get here unless a task calls vTaskEndScheduler ()\r
- }\r
- </pre>\r
- *\r
- * \defgroup vTaskStartScheduler vTaskStartScheduler\r
- * \ingroup SchedulerControl\r
- */\r
-void vTaskStartScheduler( void ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <pre>void vTaskEndScheduler( void );</pre>\r
- *\r
- * Stops the real time kernel tick. All created tasks will be automatically\r
- * deleted and multitasking (either preemptive or cooperative) will\r
- * stop. Execution then resumes from the point where vTaskStartScheduler ()\r
- * was called, as if vTaskStartScheduler () had just returned.\r
- *\r
- * See the demo application file main. c in the demo/PC directory for an\r
- * example that uses vTaskEndScheduler ().\r
- *\r
- * vTaskEndScheduler () requires an exit function to be defined within the\r
- * portable layer (see vPortEndScheduler () in port. c for the PC port). This\r
- * performs hardware specific operations such as stopping the kernel tick.\r
- *\r
- * vTaskEndScheduler () will cause all of the resources allocated by the\r
- * kernel to be freed - but will not free resources allocated by application\r
- * tasks.\r
- *\r
- * Example usage:\r
- <pre>\r
- void vTaskCode( void * pvParameters )\r
- {\r
- for( ;; )\r
- {\r
- // Task code goes here.\r
-\r
- // At some point we want to end the real time kernel processing\r
- // so call ...\r
- vTaskEndScheduler ();\r
- }\r
- }\r
-\r
- void vAFunction( void )\r
- {\r
- // Create at least one task before starting the kernel.\r
- xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
-\r
- // Start the real time kernel with preemption.\r
- vTaskStartScheduler ();\r
-\r
- // Will only get here when the vTaskCode () task has called\r
- // vTaskEndScheduler (). When we get here we are back to single task\r
- // execution.\r
- }\r
- </pre>\r
- *\r
- * \defgroup vTaskEndScheduler vTaskEndScheduler\r
- * \ingroup SchedulerControl\r
- */\r
-void vTaskEndScheduler( void ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <pre>void vTaskSuspendAll( void );</pre>\r
- *\r
- * Suspends all real time kernel activity while keeping interrupts (including the\r
- * kernel tick) enabled.\r
- *\r
- * After calling vTaskSuspendAll () the calling task will continue to execute\r
- * without risk of being swapped out until a call to xTaskResumeAll () has been\r
- * made.\r
- *\r
- * API functions that have the potential to cause a context switch (for example,\r
- * vTaskDelayUntil(), xQueueSend(), etc.) must not be called while the scheduler\r
- * is suspended.\r
- *\r
- * Example usage:\r
- <pre>\r
- void vTask1( void * pvParameters )\r
- {\r
- for( ;; )\r
- {\r
- // Task code goes here.\r
-\r
- // ...\r
-\r
- // At some point the task wants to perform a long operation during\r
- // which it does not want to get swapped out. It cannot use\r
- // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the\r
- // operation may cause interrupts to be missed - including the\r
- // ticks.\r
-\r
- // Prevent the real time kernel swapping out the task.\r
- vTaskSuspendAll ();\r
-\r
- // Perform the operation here. There is no need to use critical\r
- // sections as we have all the microcontroller processing time.\r
- // During this time interrupts will still operate and the kernel\r
- // tick count will be maintained.\r
-\r
- // ...\r
-\r
- // The operation is complete. Restart the kernel.\r
- xTaskResumeAll ();\r
- }\r
- }\r
- </pre>\r
- * \defgroup vTaskSuspendAll vTaskSuspendAll\r
- * \ingroup SchedulerControl\r
- */\r
-void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <pre>char xTaskResumeAll( void );</pre>\r
- *\r
- * Resumes real time kernel activity following a call to vTaskSuspendAll ().\r
- * After a call to vTaskSuspendAll () the kernel will take control of which\r
- * task is executing at any time.\r
- *\r
- * @return If resuming the scheduler caused a context switch then pdTRUE is\r
- * returned, otherwise pdFALSE is returned.\r
- *\r
- * Example usage:\r
- <pre>\r
- void vTask1( void * pvParameters )\r
- {\r
- for( ;; )\r
- {\r
- // Task code goes here.\r
-\r
- // ...\r
-\r
- // At some point the task wants to perform a long operation during\r
- // which it does not want to get swapped out. It cannot use\r
- // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the\r
- // operation may cause interrupts to be missed - including the\r
- // ticks.\r
-\r
- // Prevent the real time kernel swapping out the task.\r
- vTaskSuspendAll ();\r
-\r
- // Perform the operation here. There is no need to use critical\r
- // sections as we have all the microcontroller processing time.\r
- // During this time interrupts will still operate and the real\r
- // time kernel tick count will be maintained.\r
-\r
- // ...\r
-\r
- // The operation is complete. Restart the kernel. We want to force\r
- // a context switch - but there is no point if resuming the scheduler\r
- // caused a context switch already.\r
- if( !xTaskResumeAll () )\r
- {\r
- taskYIELD ();\r
- }\r
- }\r
- }\r
- </pre>\r
- * \defgroup xTaskResumeAll xTaskResumeAll\r
- * \ingroup SchedulerControl\r
- */\r
-signed portBASE_TYPE xTaskResumeAll( void ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <pre>signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask );</pre>\r
- *\r
- * Utility task that simply returns pdTRUE if the task referenced by xTask is\r
- * currently in the Suspended state, or pdFALSE if the task referenced by xTask\r
- * is in any other state.\r
- *\r
- */\r
-signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask ) PRIVILEGED_FUNCTION;\r
-\r
-/*-----------------------------------------------------------\r
- * TASK UTILITIES\r
- *----------------------------------------------------------*/\r
-\r
-/**\r
- * task. h\r
- * <PRE>portTickType xTaskGetTickCount( void );</PRE>\r
- *\r
- * @return The count of ticks since vTaskStartScheduler was called.\r
- *\r
- * \page xTaskGetTickCount xTaskGetTickCount\r
- * \ingroup TaskUtils\r
- */\r
-portTickType xTaskGetTickCount( void ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <PRE>portTickType xTaskGetTickCountFromISR( void );</PRE>\r
- *\r
- * @return The count of ticks since vTaskStartScheduler was called.\r
- *\r
- * This is a version of xTaskGetTickCount() that is safe to be called from an\r
- * ISR - provided that portTickType is the natural word size of the\r
- * microcontroller being used or interrupt nesting is either not supported or\r
- * not being used.\r
- *\r
- * \page xTaskGetTickCount xTaskGetTickCount\r
- * \ingroup TaskUtils\r
- */\r
-portTickType xTaskGetTickCountFromISR( void ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <PRE>unsigned short uxTaskGetNumberOfTasks( void );</PRE>\r
- *\r
- * @return The number of tasks that the real time kernel is currently managing.\r
- * This includes all ready, blocked and suspended tasks. A task that\r
- * has been deleted but not yet freed by the idle task will also be\r
- * included in the count.\r
- *\r
- * \page uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks\r
- * \ingroup TaskUtils\r
- */\r
-unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <PRE>signed char *pcTaskGetTaskName( xTaskHandle xTaskToQuery );</PRE>\r
- *\r
- * @return The text (human readable) name of the task referenced by the handle\r
- * xTaskToQueury. A task can query its own name by either passing in its own\r
- * handle, or by setting xTaskToQuery to NULL.\r
- *\r
- * \page uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks\r
- * \ingroup TaskUtils\r
- */\r
-signed char *pcTaskGetTaskName( xTaskHandle xTaskToQuery );\r
-\r
-/**\r
- * task. h\r
- * <PRE>void vTaskList( char *pcWriteBuffer );</PRE>\r
- *\r
- * configUSE_TRACE_FACILITY must be defined as 1 for this function to be\r
- * available. See the configuration section for more information.\r
- *\r
- * NOTE: This function will disable interrupts for its duration. It is\r
- * not intended for normal application runtime use but as a debug aid.\r
- *\r
- * Lists all the current tasks, along with their current state and stack\r
- * usage high water mark.\r
- *\r
- * Tasks are reported as blocked ('B'), ready ('R'), deleted ('D') or\r
- * suspended ('S').\r
- *\r
- * @param pcWriteBuffer A buffer into which the above mentioned details\r
- * will be written, in ascii form. This buffer is assumed to be large\r
- * enough to contain the generated report. Approximately 40 bytes per\r
- * task should be sufficient.\r
- *\r
- * \page vTaskList vTaskList\r
- * \ingroup TaskUtils\r
- */\r
-void vTaskList( signed char *pcWriteBuffer ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <PRE>void vTaskGetRunTimeStats( char *pcWriteBuffer );</PRE>\r
- *\r
- * configGENERATE_RUN_TIME_STATS must be defined as 1 for this function\r
- * to be available. The application must also then provide definitions\r
- * for portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and\r
- * portGET_RUN_TIME_COUNTER_VALUE to configure a peripheral timer/counter\r
- * and return the timers current count value respectively. The counter\r
- * should be at least 10 times the frequency of the tick count.\r
- *\r
- * NOTE: This function will disable interrupts for its duration. It is\r
- * not intended for normal application runtime use but as a debug aid.\r
- *\r
- * Setting configGENERATE_RUN_TIME_STATS to 1 will result in a total\r
- * accumulated execution time being stored for each task. The resolution\r
- * of the accumulated time value depends on the frequency of the timer\r
- * configured by the portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() macro.\r
- * Calling vTaskGetRunTimeStats() writes the total execution time of each\r
- * task into a buffer, both as an absolute count value and as a percentage\r
- * of the total system execution time.\r
- *\r
- * @param pcWriteBuffer A buffer into which the execution times will be\r
- * written, in ascii form. This buffer is assumed to be large enough to\r
- * contain the generated report. Approximately 40 bytes per task should\r
- * be sufficient.\r
- *\r
- * \page vTaskGetRunTimeStats vTaskGetRunTimeStats\r
- * \ingroup TaskUtils\r
- */\r
-void vTaskGetRunTimeStats( signed char *pcWriteBuffer ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <PRE>void vTaskStartTrace( char * pcBuffer, unsigned portBASE_TYPE uxBufferSize );</PRE>\r
- *\r
- * Starts a real time kernel activity trace. The trace logs the identity of\r
- * which task is running when.\r
- *\r
- * The trace file is stored in binary format. A separate DOS utility called\r
- * convtrce.exe is used to convert this into a tab delimited text file which\r
- * can be viewed and plotted in a spread sheet.\r
- *\r
- * @param pcBuffer The buffer into which the trace will be written.\r
- *\r
- * @param ulBufferSize The size of pcBuffer in bytes. The trace will continue\r
- * until either the buffer in full, or ulTaskEndTrace () is called.\r
- *\r
- * \page vTaskStartTrace vTaskStartTrace\r
- * \ingroup TaskUtils\r
- */\r
-void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task. h\r
- * <PRE>unsigned long ulTaskEndTrace( void );</PRE>\r
- *\r
- * Stops a kernel activity trace. See vTaskStartTrace ().\r
- *\r
- * @return The number of bytes that have been written into the trace buffer.\r
- *\r
- * \page usTaskEndTrace usTaskEndTrace\r
- * \ingroup TaskUtils\r
- */\r
-unsigned long ulTaskEndTrace( void ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * task.h\r
- * <PRE>unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask );</PRE>\r
- *\r
- * INCLUDE_uxTaskGetStackHighWaterMark must be set to 1 in FreeRTOSConfig.h for\r
- * this function to be available.\r
- *\r
- * Returns the high water mark of the stack associated with xTask. That is,\r
- * the minimum free stack space there has been (in words, so on a 32 bit machine\r
- * a value of 1 means 4 bytes) since the task started. The smaller the returned\r
- * number the closer the task has come to overflowing its stack.\r
- *\r
- * @param xTask Handle of the task associated with the stack to be checked.\r
- * Set xTask to NULL to check the stack of the calling task.\r
- *\r
- * @return The smallest amount of free stack space there has been (in bytes)\r
- * since the task referenced by xTask was created.\r
- */\r
-unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask ) PRIVILEGED_FUNCTION;\r
-\r
-/* When using trace macros it is sometimes necessary to include tasks.h before\r
-FreeRTOS.h. When this is done pdTASK_HOOK_CODE will not yet have been defined,\r
-so the following two prototypes will cause a compilation error. This can be\r
-fixed by simply guarding against the inclusion of these two prototypes unless\r
-they are explicitly required by the configUSE_APPLICATION_TASK_TAG configuration\r
-constant. */\r
-#ifdef configUSE_APPLICATION_TASK_TAG\r
- #if configUSE_APPLICATION_TASK_TAG == 1\r
- /**\r
- * task.h\r
- * <pre>void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction );</pre>\r
- *\r
- * Sets pxHookFunction to be the task hook function used by the task xTask.\r
- * Passing xTask as NULL has the effect of setting the calling tasks hook\r
- * function.\r
- */\r
- void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction ) PRIVILEGED_FUNCTION;\r
-\r
- /**\r
- * task.h\r
- * <pre>void xTaskGetApplicationTaskTag( xTaskHandle xTask );</pre>\r
- *\r
- * Returns the pxHookFunction value assigned to the task xTask.\r
- */\r
- pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask ) PRIVILEGED_FUNCTION;\r
- #endif /* configUSE_APPLICATION_TASK_TAG ==1 */\r
-#endif /* ifdef configUSE_APPLICATION_TASK_TAG */\r
-\r
-/**\r
- * task.h\r
- * <pre>portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction );</pre>\r
- *\r
- * Calls the hook function associated with xTask. Passing xTask as NULL has\r
- * the effect of calling the Running tasks (the calling task) hook function.\r
- *\r
- * pvParameter is passed to the hook function for the task to interpret as it\r
- * wants.\r
- */\r
-portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * xTaskGetIdleTaskHandle() is only available if \r
- * INCLUDE_xTaskGetIdleTaskHandle is set to 1 in FreeRTOSConfig.h.\r
- *\r
- * Simply returns the handle of the idle task. It is not valid to call\r
- * xTaskGetIdleTaskHandle() before the scheduler has been started.\r
- */\r
-xTaskHandle xTaskGetIdleTaskHandle( void );\r
-\r
-/*-----------------------------------------------------------\r
- * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES\r
- *----------------------------------------------------------*/\r
-\r
-/*\r
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY\r
- * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS\r
- * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.\r
- *\r
- * Called from the real time kernel tick (either preemptive or cooperative),\r
- * this increments the tick count and checks if any tasks that are blocked\r
- * for a finite period required removing from a blocked list and placing on\r
- * a ready list.\r
- */\r
-void vTaskIncrementTick( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN\r
- * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.\r
- *\r
- * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.\r
- *\r
- * Removes the calling task from the ready list and places it both\r
- * on the list of tasks waiting for a particular event, and the\r
- * list of delayed tasks. The task will be removed from both lists\r
- * and replaced on the ready list should either the event occur (and\r
- * there be no higher priority tasks waiting on the same event) or\r
- * the delay period expires.\r
- *\r
- * @param pxEventList The list containing tasks that are blocked waiting\r
- * for the event to occur.\r
- *\r
- * @param xTicksToWait The maximum amount of time that the task should wait\r
- * for the event to occur. This is specified in kernel ticks,the constant\r
- * portTICK_RATE_MS can be used to convert kernel ticks into a real time\r
- * period.\r
- */\r
-void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN\r
- * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.\r
- *\r
- * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.\r
- *\r
- * This function performs nearly the same function as vTaskPlaceOnEventList().\r
- * The difference being that this function does not permit tasks to block\r
- * indefinitely, whereas vTaskPlaceOnEventList() does.\r
- *\r
- * @return pdTRUE if the task being removed has a higher priority than the task\r
- * making the call, otherwise pdFALSE.\r
- */\r
-void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN\r
- * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.\r
- *\r
- * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.\r
- *\r
- * Removes a task from both the specified event list and the list of blocked\r
- * tasks, and places it on a ready queue.\r
- *\r
- * xTaskRemoveFromEventList () will be called if either an event occurs to\r
- * unblock a task, or the block timeout period expires.\r
- *\r
- * @return pdTRUE if the task being removed has a higher priority than the task\r
- * making the call, otherwise pdFALSE.\r
- */\r
-signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN\r
- * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.\r
- *\r
- * INCLUDE_vTaskCleanUpResources and INCLUDE_vTaskSuspend must be defined as 1\r
- * for this function to be available.\r
- * See the configuration section for more information.\r
- *\r
- * Empties the ready and delayed queues of task control blocks, freeing the\r
- * memory allocated for the task control block and task stacks as it goes.\r
- */\r
-void vTaskCleanUpResources( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY\r
- * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS\r
- * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.\r
- *\r
- * Sets the pointer to the current TCB to the TCB of the highest priority task\r
- * that is ready to run.\r
- */\r
-void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Return the handle of the calling task.\r
- */\r
-xTaskHandle xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Capture the current time status for future reference.\r
- */\r
-void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Compare the time status now with that previously captured to see if the\r
- * timeout has expired.\r
- */\r
-portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Shortcut used by the queue implementation to prevent unnecessary call to\r
- * taskYIELD();\r
- */\r
-void vTaskMissedYield( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Returns the scheduler state as taskSCHEDULER_RUNNING,\r
- * taskSCHEDULER_NOT_STARTED or taskSCHEDULER_SUSPENDED.\r
- */\r
-portBASE_TYPE xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Raises the priority of the mutex holder to that of the calling task should\r
- * the mutex holder have a priority less than the calling task.\r
- */\r
-void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Set the priority of a task back to its proper priority in the case that it\r
- * inherited a higher priority while it was holding a semaphore.\r
- */\r
-void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Generic version of the task creation function which is in turn called by the\r
- * xTaskCreate() and xTaskCreateRestricted() macros.\r
- */\r
-signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions ) PRIVILEGED_FUNCTION;\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-#endif /* TASK_H */\r
-\r
-\r
-\r
+++ /dev/null
-#ifndef TIMER_TEST_H\r
-#define TIMER_TEST_H\r
-\r
-#define tmrtestNUM_TIMERS 15\r
-\r
-\r
-extern portTickType xTickCount;\r
-extern xTaskHandle pxCurrentTCB;\r
-extern portTickType xNumOfOverflows;\r
-\r
-static void vTimerTest_Initialise( void );\r
-static portBASE_TYPE xTimerTest1_xTimeStartAndResetWakeTimeCalculation( void );\r
-portBASE_TYPE xTimerTest2_xTestFreeRunningBehaviour( unsigned portBASE_TYPE uxPeriodMultiplier );\r
-\r
-static void prvCheckServiceTaskBehaviour( portBASE_TYPE x, portBASE_TYPE xExpireTimeHasOverflowed, portBASE_TYPE xTickCountOverflowed );\r
-\r
-static void prvTestFailed( void );\r
-\r
-xTIMER *xAutoReloadTimers[ tmrtestNUM_TIMERS ];\r
-unsigned portBASE_TYPE uxAutoReloadTimerCounters[ tmrtestNUM_TIMERS ];\r
-portBASE_TYPE xTestStatus = pdPASS;\r
-xTaskHandle xTestTask1 = NULL, xTestTask2 = NULL;\r
-\r
-struct xTestData\r
-{\r
- portTickType xStartTickCount;\r
- portTickType xTimerPeriod;\r
- portTickType xTickIncrementBetweenCommandAndProcessing;\r
- portTickType xExpectedCalculatedExpiryTime;\r
- xList * pxExpectedList;\r
- unsigned portBASE_TYPE uxExpectedCallbackCount;\r
-};\r
-\r
-const struct xTestData xTestCase[] =\r
-{\r
- /* xStartTickCount, xTimerPeriod, Tck Inc, Expected Expire Time, Expected list, Expected callback count, Second tick inc */\r
-\r
- /* Test cases when the command to start a timer and the processing of the\r
- start command execute without the tick count incrementing in between. */\r
- { portMAX_DELAY - 8, 2, 0, ( portMAX_DELAY - 8 ) + 2, &xActiveTimerList1, 0 }, /* Expire before an overflow. */\r
- { portMAX_DELAY - 8, 8, 0, ( portMAX_DELAY - 8 ) + 8, &xActiveTimerList1, 0 }, /* Expire immediately before and overflow. */\r
- { portMAX_DELAY - 8, 9, 0, 0, &xActiveTimerList2, 0 }, /* Expire on an overflow. */\r
- { portMAX_DELAY - 8, portMAX_DELAY, 0, ( ( portMAX_DELAY - 8 ) - 1 ), &xActiveTimerList2, 0 }, /* Delay for the longest possible time. */\r
- { portMAX_DELAY, portMAX_DELAY, 0, ( portMAX_DELAY - 1 ), &xActiveTimerList2, 0 }, /* Delay for the longest possible time starting from the maximum tick count. */\r
- { 0, portMAX_DELAY, 0, ( portMAX_DELAY ), &xActiveTimerList1, 0 }, /* Delay for the maximum ticks, starting with from the minimum tick count. */\r
-\r
- /* Test cases when the command to start a timer and the processing of the\r
- start command execute at different tick count values. */\r
- { portMAX_DELAY - 8, 2, 1, ( portMAX_DELAY - 8 ) + 2, &xActiveTimerList1, 0 }, /* The expire time does not overflow, and the tick count does not overflow between the command and processing the command. */\r
- { portMAX_DELAY - 8, 8, 2, ( portMAX_DELAY - 8 ) + 8, &xActiveTimerList1, 0 }, /* The expire time does not overflow but is on the portMAX_DELAY limit, and the tick count does not overflow between the command and processing the command. */\r
- { portMAX_DELAY - 8, 9, 3, 0, &xActiveTimerList2, 0 }, /* The expire time overflows to 0, and the tick count does not overflow between the command and processing the command. */\r
- { portMAX_DELAY - 2, 9, 1, ( portMAX_DELAY - 2 ) + 9, &xActiveTimerList2, 0 }, /* The expire time overflows, but the tick count does not overflow between the command and processing the command. */\r
- { portMAX_DELAY - 2, 9, 3, ( portMAX_DELAY - 2 ) + 9, &xActiveTimerList2, 0 }, /* The timer overflows between the command and processing the command. The expire time also overflows. */\r
-\r
- /* Add tests where the timer should have expired by the time the command is processed. */\r
- { 10, 9, 10, ( 10 + ( 2 * 9 ) ), &xActiveTimerList1, 1 }, /* Nothing overflows, but the time between the timer being set and the command being processed is greater than the timers expiry time. The timer should get processed immediately, so the expected expire time is twice the period as the timer will get auto-reloaded. */\r
- { portMAX_DELAY - 2, 9, 10, ( portMAX_DELAY - 2 ) + ( 2 * 9 ), &xActiveTimerList2, 1 }, /* The timer overflows between the command and processing the command. The expire time also overflows and the number of ticks that occur between the command and the processing exceeds the timer expiry period. The timer should get processed immediately, so the expected expire time is twice the period as the timer will get auto-reloaded.*/\r
- { portMAX_DELAY - 2, 9, 9, ( portMAX_DELAY - 2 ) + ( 2 * 9 ), &xActiveTimerList2, 1 }, /* The timer overflows between the command and processing the command. The expire time also overflows and the number of ticks between command and processing equals the timer expiry period. The timer should get processed immediately, so the expected expire time is twice the period as the timer will get auto-reloaded.*/\r
-\r
- { portMAX_DELAY - 20, 9, 21, ( portMAX_DELAY - 20 ) + ( 3 * 9 ), &xActiveTimerList2, 2 }, /* The tick count has overflowed but the timer expire time has not overflowed. The tick count overflows to 0. The timer should get processed immediately, so the expected expire time is twice the period as the timer will get auto-reloaded.*/\r
- { portMAX_DELAY - 20, 9, 22, ( portMAX_DELAY - 20 ) + ( 3 * 9 ), &xActiveTimerList2, 2 }, /* The tick count has overflowed but the timer expire time has not overflowed. The tick count overflows to greater than 0. The timer should get processed immediately, so the expected expire time is twice the period as the timer will get auto-reloaded.*/\r
- { portMAX_DELAY - 5, 2, 20, ( portMAX_DELAY - 5 ) + ( 11 * 2 ), &xActiveTimerList2, 10 }, /* The tick and expire time overflow, but the first expire time overflow results in a time that is less than the tick count. */\r
-};\r
-\r
-typedef struct tskTaskControlBlockx\r
-{\r
- volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */\r
-\r
- #if ( portUSING_MPU_WRAPPERS == 1 )\r
- xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */\r
- #endif \r
- \r
- xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */\r
- xListItem xEventListItem; /*< List item used to place the TCB in event lists. */\r
- unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */\r
- portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */\r
- signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */\r
-\r
- #if ( portSTACK_GROWTH > 0 )\r
- portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */\r
- #endif\r
-\r
- #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
- unsigned portBASE_TYPE uxCriticalNesting;\r
- #endif\r
-\r
- #if ( configUSE_TRACE_FACILITY == 1 )\r
- unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */\r
- #endif\r
-\r
- #if ( configUSE_MUTEXES == 1 )\r
- unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */\r
- #endif\r
-\r
- #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
- pdTASK_HOOK_CODE pxTaskTag;\r
- #endif\r
-\r
- #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
- unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */\r
- #endif\r
-\r
-} tskTCBx;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static void vAutoReloadTimerCallback( xTIMER *pxTimer )\r
-{\r
-portBASE_TYPE xTimerID = ( portBASE_TYPE ) pxTimer->pvTimerID;\r
-\r
- if( xTimerID < tmrtestNUM_TIMERS )\r
- {\r
- ( uxAutoReloadTimerCounters[ xTimerID ] )++;\r
- }\r
- else\r
- {\r
- prvTestFailed();\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void vTimerTest_Initialise( void )\r
-{\r
-portBASE_TYPE xTimerNumber;\r
-extern void prvInitialiseTaskLists( void );\r
-extern portBASE_TYPE xSchedulerRunning;\r
-\r
- prvInitialiseTaskLists();\r
- xTimerQueue = NULL;\r
- xSchedulerRunning = pdTRUE;\r
-\r
- for( xTimerNumber = 0; xTimerNumber < tmrtestNUM_TIMERS; xTimerNumber++ )\r
- {\r
- /* Delete any existing timers. */\r
- if( xAutoReloadTimers[ xTimerNumber ] != NULL )\r
- {\r
- vPortFree( xAutoReloadTimers[ xTimerNumber ] );\r
- }\r
-\r
- /* Create new autoreload timers. */\r
- xAutoReloadTimers[ xTimerNumber ] = xTimerCreate( "Timer", 0xffff, pdTRUE, ( void * ) xTimerNumber, vAutoReloadTimerCallback );\r
- uxAutoReloadTimerCounters[ xTimerNumber ] = 0;\r
- if( xAutoReloadTimers == NULL )\r
- {\r
- prvTestFailed();\r
- }\r
- }\r
-\r
- /* Initialise lists so they are empty. */\r
- vListInitialise( &xActiveTimerList1 );\r
- vListInitialise( &xActiveTimerList2 );\r
-\r
- /* Call prvSampleTimeNow with a tick count of zero so it sets its \r
- internal static "last time" variable to zero. */\r
- xTickCount = 0;\r
- xNumOfOverflows = 0;\r
- prvSampleTimeNow( &xTimerNumber );\r
-\r
- /* Initialise the list pointers in case prvSampleTimeNow() changed them. */\r
- pxCurrentTimerList = &xActiveTimerList1;\r
- pxOverflowTimerList = &xActiveTimerList2;\r
-\r
-// if( xTestTask1 == NULL )\r
- {\r
- xTaskCreate( (pdTASK_CODE)prvTestFailed, "Task1", configMINIMAL_STACK_SIZE, NULL, 0, &xTestTask1 );\r
- }\r
-\r
-// if( xTestTask2 == NULL )\r
- {\r
- xTaskCreate( (pdTASK_CODE)prvTestFailed, "Task1", configMINIMAL_STACK_SIZE, NULL, 0, &xTestTask2 );\r
- }\r
-\r
- pxCurrentTCB = xTestTask1;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvTestFailed( void )\r
-{\r
-static unsigned long ulFailures = 0;\r
-\r
- ulFailures++;\r
- xTestStatus = pdFAIL;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCheckServiceTaskBehaviour( portBASE_TYPE x, portBASE_TYPE xExpireTimeHasOverflowed, portBASE_TYPE xTickCountOverflowed )\r
-{\r
-portBASE_TYPE xListWasEmpty;\r
-portTickType xNextExpireTime;\r
-extern xList * volatile pxOverflowDelayedTaskList, *pxDelayedTaskList;\r
-extern xList pxReadyTasksLists[];\r
-\r
- xListWasEmpty = portMAX_DELAY;\r
- xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );\r
-\r
- /* If the timer expire time has overflowed it should be present in the overflow \r
- list of active timers, unless the tick count has also overflowed and the expire\r
- time has not passed. If the expire time has not overflowed it should be \r
- present in the current list of active timers. Either way, its expire time should \r
- equal the expected expire time. */\r
- if( ( xExpireTimeHasOverflowed == pdTRUE ) && ( xTickCountOverflowed == pdFALSE ) )\r
- { \r
- /* The timer will be in the overflow list, so prvGetNextExpireTime()\r
- should not have found it, but instead returned an expire time that\r
- will ensure the timer service task will unblock when the lists need\r
- switching. */\r
- if( ( xNextExpireTime != 0 ) || ( xListWasEmpty == pdFALSE ) )\r
- {\r
- prvTestFailed();\r
- }\r
- }\r
- else\r
- {\r
- if( ( xNextExpireTime != xTestCase[ x ].xExpectedCalculatedExpiryTime ) || ( xListWasEmpty != pdFALSE ) )\r
- {\r
- prvTestFailed();\r
- }\r
- }\r
-\r
- prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );\r
-\r
- /* Has the timer expired the expected number of times? */\r
- if( uxAutoReloadTimerCounters[ 0 ] != xTestCase[ x ].uxExpectedCallbackCount )\r
- {\r
- prvTestFailed();\r
- }\r
-\r
- /* The task should now be blocked. It should only appear in the overflow\r
- delayed task list if xNextExpireTime is equal to 0. */\r
- if( xNextExpireTime == 0 )\r
- {\r
- if( listIS_CONTAINED_WITHIN( pxOverflowDelayedTaskList, &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) == pdFALSE )\r
- {\r
- prvTestFailed();\r
- }\r
-\r
- if( listGET_LIST_ITEM_VALUE( &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) != 0 )\r
- {\r
- prvTestFailed();\r
- }\r
- }\r
- else\r
- {\r
- if( listIS_CONTAINED_WITHIN( pxDelayedTaskList, &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) == pdFALSE )\r
- {\r
- prvTestFailed();\r
- }\r
-\r
- if( listGET_LIST_ITEM_VALUE( &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) != xTestCase[ x ].xExpectedCalculatedExpiryTime )\r
- {\r
- prvTestFailed();\r
- }\r
- }\r
-\r
- /* The timer should have be re-loaded, and still be referenced from one\r
- or other of the active lists. */\r
- if( listGET_LIST_ITEM_VALUE( &( xAutoReloadTimers[ 0 ]->xTimerListItem ) ) != xTestCase[ x ].xExpectedCalculatedExpiryTime )\r
- {\r
- prvTestFailed();\r
- }\r
- if( listIS_CONTAINED_WITHIN( NULL, &( xAutoReloadTimers[ 0 ]->xTimerListItem ) ) == pdTRUE )\r
- {\r
- prvTestFailed();\r
- }\r
-\r
- /* Move the task back to the ready list from the delayed list. */\r
- vListRemove( &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) );\r
- vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ 0 ] ), &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portBASE_TYPE xTimerTest1_xTimeStartAndResetWakeTimeCalculation( void )\r
-{\r
-portBASE_TYPE x, xListWasEmpty;\r
-portTickType xNextExpireTime;\r
-\r
- if( sizeof( portTickType ) != 2 )\r
- {\r
- /* This test should be performed using 16bit ticks. */\r
- prvTestFailed();\r
- }\r
-\r
- for( x = 0; x < ( sizeof( xTestCase ) / sizeof( struct xTestData ) ); x++ )\r
- {\r
- /* Set everything back to its start condition. */\r
- vTimerTest_Initialise();\r
-\r
- /* Load the tick count with the test case data. */\r
- xTickCount = xTestCase[ x ].xStartTickCount;\r
-\r
- /* Query the timers list to see if it contains any timers, and if so,\r
- obtain the time at which the next timer will expire. The list should be\r
- empty, so 0 should be returned (to cause the task to unblock when a\r
- tick overflow occurs. Likewise xListWasEmpty should be set to pdTRUE. */\r
- xListWasEmpty = portMAX_DELAY;\r
- xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );\r
-\r
- if( ( xListWasEmpty != pdTRUE ) || ( xNextExpireTime != ( portTickType ) 0 ) )\r
- {\r
- prvTestFailed();\r
- }\r
-\r
-\r
-\r
- /* Call prvProcessReceivedCommands() just so the code under test knows\r
- what the tick count is in the pre-condition state. */\r
- prvProcessReceivedCommands();\r
-\r
- xAutoReloadTimers[ 0 ]->xTimerPeriodInTicks = xTestCase[ x ].xTimerPeriod;\r
- xTimerStart( xAutoReloadTimers[ 0 ], 0 );\r
-\r
- /* Move the tick count on to the time at which the command should be \r
- processed. */\r
- xTickCount += xTestCase[ x ].xTickIncrementBetweenCommandAndProcessing;\r
-\r
- /* Process the sent command with the updated tick count. */\r
- prvProcessReceivedCommands();\r
-\r
- if( listGET_LIST_ITEM_VALUE( &( xAutoReloadTimers[ 0 ]->xTimerListItem ) ) != xTestCase[ x ].xExpectedCalculatedExpiryTime )\r
- {\r
- prvTestFailed();\r
- }\r
- if( listIS_CONTAINED_WITHIN( xTestCase[ x ].pxExpectedList, &( xAutoReloadTimers[ 0 ]->xTimerListItem ) ) == pdFALSE )\r
- {\r
- prvTestFailed();\r
- }\r
- if( uxAutoReloadTimerCounters[ 0 ] != xTestCase[ x ].uxExpectedCallbackCount )\r
- {\r
- prvTestFailed();\r
- }\r
-\r
- if( xTickCount < xTestCase[ x ].xStartTickCount ) /* The tick count has overflowed */\r
- {\r
- if( xTestCase[ x ].pxExpectedList == &xActiveTimerList2 ) /* The timer expire time has overflowed. */\r
- {\r
- if( xTestCase[ x ].xExpectedCalculatedExpiryTime <= xTickCount ) /* The timer expire time has passed */\r
- {\r
- /* The expire time should never have passed when here is\r
- reached because the timer whould have been processed enough\r
- times to make the expire time catch up. */\r
- prvTestFailed();\r
- }\r
- else /* The timer expire time has not passed. */\r
- {\r
- prvCheckServiceTaskBehaviour( x, pdTRUE, pdTRUE );\r
- }\r
- }\r
- else /* The timer expire time has not overflowed. */\r
- {\r
- /* If the timer expire time has not overflowed but the tick count has \r
- overflowed, then the timer expire time must have been passed. The \r
- expire time should never have passed when here is reached because \r
- the timer whould have been processed enough times to make the expire \r
- time catch up. */\r
- prvTestFailed();\r
- }\r
- }\r
- else /* The tick count has not overflowed. */\r
- {\r
- if( xTestCase[ x ].pxExpectedList == &xActiveTimerList2 ) /* The timer expire time has overflowed */\r
- {\r
- /* If the expire time has overflowed, but the tick count has not\r
- overflowed, then the timer expire time cannot have been passed. */\r
- prvCheckServiceTaskBehaviour( x, pdTRUE, pdFALSE );\r
- }\r
- else /* The timer expire time has not overflowed. */\r
- {\r
- if( xTickCount >= xTestCase[ x ].xExpectedCalculatedExpiryTime ) /* The timer expire time has passed */\r
- {\r
- /* The expire time should never have passed when here is\r
- reached because the timer whould have been processed enough\r
- times to make the expire time catch up. */\r
- prvTestFailed();\r
- }\r
- else /* The timer expire time has not passed. */\r
- {\r
- prvCheckServiceTaskBehaviour( x, pdFALSE, pdFALSE );\r
- }\r
- }\r
- }\r
- }\r
-\r
- return xTestStatus;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-portBASE_TYPE xTimerTest2_xTestFreeRunningBehaviour( unsigned portBASE_TYPE uxPeriodMultiplier )\r
-{\r
-unsigned portBASE_TYPE uxExpectedIncrements, x, uxMix = 0, uxPeriod;\r
-const unsigned portBASE_TYPE uxMaxIterations = 0x1fffff;\r
-extern xList pxReadyTasksLists[];\r
-portTickType xNextExpireTime;\r
-portBASE_TYPE xListWasEmpty;\r
-extern xTaskHandle pxCurrentTCB;\r
-\r
- if( sizeof( portTickType ) != 2 )\r
- {\r
- /* This test should be performed using 16bit ticks. */\r
- prvTestFailed();\r
- }\r
-\r
- /* Initialise the test. This will create tmrtestNUM_TIMERS timers. */\r
- vTimerTest_Initialise();\r
-\r
- /* Give each timer a period, then start it running. */\r
- for( x = 0; x < tmrtestNUM_TIMERS; x++ )\r
- {\r
- uxPeriod = ( x + ( unsigned portBASE_TYPE ) 1 ) * uxPeriodMultiplier;\r
- xTimerChangePeriod( xAutoReloadTimers[ x ], ( portTickType ) uxPeriod, 0 );\r
- xTimerStart( xAutoReloadTimers[ x ], 0 );\r
- prvProcessReceivedCommands();\r
- }\r
-\r
- xTickCount = 1;\r
- x = 1;\r
-\r
- /* Simulate the task running. */\r
- while( x <= uxMaxIterations )\r
- {\r
- /* Query the timers list to see if it contains any timers, and if so,\r
- obtain the time at which the next timer will expire. */\r
- xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );\r
-\r
- /* It is legitimate for tick increments to occur here. */\r
- if( ( uxMix < 2 ) && ( x < uxMaxIterations - 5 ) )\r
- {\r
- vTaskIncrementTick();\r
- x++;\r
- vTaskIncrementTick();\r
- x++;\r
- vTaskIncrementTick();\r
- x++;\r
- }\r
-\r
- /* If a timer has expired, process it. Otherwise, block this task\r
- until either a timer does expire, or a command is received. */\r
- prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );\r
- \r
- /* If the task blocked, increment the tick until it unblocks. */\r
- while( listIS_CONTAINED_WITHIN( ( xList * ) &( pxReadyTasksLists[ 0 ] ), &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) == pdFALSE )\r
- {\r
- if( ( uxMix == 1 ) && ( x < ( uxMaxIterations + 3 ) ) )\r
- {\r
- vTaskIncrementTick();\r
- x++;\r
- vTaskIncrementTick();\r
- x++;\r
- vTaskIncrementTick();\r
- x++;\r
- }\r
- if( ( uxMix == 2 ) && ( x < ( uxMaxIterations + 2 ) ) )\r
- {\r
- vTaskIncrementTick();\r
- x++;\r
- vTaskIncrementTick();\r
- x++;\r
- }\r
- else\r
- {\r
- vTaskIncrementTick();\r
- x++;\r
- }\r
- }\r
-\r
- uxMix++;\r
- if( uxMix > 8 )\r
- {\r
- uxMix = 0;\r
- }\r
-\r
- /* Make sure time does not go past that expected. */\r
- if( x > uxMaxIterations )\r
- {\r
- xTickCount -= ( portTickType ) ( x - uxMaxIterations );\r
- }\r
-\r
- /* Empty the command queue. */\r
- prvProcessReceivedCommands(); \r
- }\r
-\r
- /* Catch up with the tick count, if it was incremented more than once in one\r
- go. */\r
- xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );\r
- prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );\r
- \r
- /* This time, if the task blocked, there is nothing left to do. If it didn't\r
- block then empty the command queue for good measure. */\r
- if( listIS_CONTAINED_WITHIN( ( xList * ) &( pxReadyTasksLists[ 0 ] ), &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) != pdFALSE )\r
- {\r
- /* Empty the command queue. */\r
- prvProcessReceivedCommands(); \r
- }\r
-\r
- /* Check each timer has incremented the expected number of times. */\r
- for( x = 0; x < tmrtestNUM_TIMERS; x++ )\r
- {\r
- uxPeriod = ( x + ( unsigned portBASE_TYPE ) 1 ) * uxPeriodMultiplier;\r
- uxExpectedIncrements = ( uxMaxIterations / ( unsigned portBASE_TYPE ) uxPeriod );\r
- \r
- if( ( uxExpectedIncrements - uxAutoReloadTimerCounters[ x ] ) > 1 )\r
- {\r
- prvTestFailed();\r
- }\r
- }\r
-\r
- return xTestStatus;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void vRunTimerModuleTests( void )\r
-{\r
-unsigned long x;\r
-\r
- xTimerTest1_xTimeStartAndResetWakeTimeCalculation();\r
-\r
- for( x = 1; x < 1000; x++ )\r
- {\r
- xTimerTest2_xTestFreeRunningBehaviour( x );\r
- }\r
-\r
- for( ;; );\r
-}\r
-\r
-#endif TIMER_TEST_H\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-\r
-#ifndef TIMERS_H\r
-#define TIMERS_H\r
-\r
-#ifndef INC_FREERTOS_H\r
- #error "include FreeRTOS.h must appear in source files before include timers.h"\r
-#endif\r
-\r
-#include "portable.h"\r
-#include "list.h"\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-/* IDs for commands that can be sent/received on the timer queue. These are to\r
-be used solely through the macros that make up the public software timer API,\r
-as defined below. */\r
-#define tmrCOMMAND_START 0\r
-#define tmrCOMMAND_STOP 1\r
-#define tmrCOMMAND_CHANGE_PERIOD 2\r
-#define tmrCOMMAND_DELETE 3\r
-\r
-/*-----------------------------------------------------------\r
- * MACROS AND DEFINITIONS\r
- *----------------------------------------------------------*/\r
-\r
- /**\r
- * Type by which software timers are referenced. For example, a call to\r
- * xTimerCreate() returns an xTimerHandle variable that can then be used to\r
- * reference the subject timer in calls to other software timer API functions\r
- * (for example, xTimerStart(), xTimerReset(), etc.).\r
- */\r
-typedef void * xTimerHandle;\r
-\r
-/* Define the prototype to which timer callback functions must conform. */\r
-typedef void (*tmrTIMER_CALLBACK)( xTimerHandle xTimer );\r
-\r
-/**\r
- * xTimerHandle xTimerCreate( const signed char *pcTimerName,\r
- * portTickType xTimerPeriod,\r
- * unsigned portBASE_TYPE uxAutoReload,\r
- * void * pvTimerID,\r
- * tmrTIMER_CALLBACK pxCallbackFunction );\r
- *\r
- * Creates a new software timer instance. This allocates the storage required\r
- * by the new timer, initialises the new timers internal state, and returns a\r
- * handle by which the new timer can be referenced.\r
- *\r
- * Timers are created in the dormant state. The xTimerStart(), xTimerReset(),\r
- * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and\r
- * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the\r
- * active state.\r
- *\r
- * @param pcTimerName A text name that is assigned to the timer. This is done\r
- * purely to assist debugging. The kernel itself only ever references a timer by\r
- * its handle, and never by its name.\r
- *\r
- * @param xTimerPeriod The timer period. The time is defined in tick periods so\r
- * the constant portTICK_RATE_MS can be used to convert a time that has been\r
- * specified in milliseconds. For example, if the timer must expire after 100\r
- * ticks, then xTimerPeriod should be set to 100. Alternatively, if the timer\r
- * must expire after 500ms, then xPeriod can be set to ( 500 / portTICK_RATE_MS )\r
- * provided configTICK_RATE_HZ is less than or equal to 1000.\r
- *\r
- * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will\r
- * expire repeatedly with a frequency set by the xTimerPeriod parameter. If\r
- * uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and\r
- * enter the dormant state after it expires.\r
- *\r
- * @param pvTimerID An identifier that is assigned to the timer being created.\r
- * Typically this would be used in the timer callback function to identify which\r
- * timer expired when the same callback function is assigned to more than one\r
- * timer.\r
- *\r
- * @param pxCallbackFunction The function to call when the timer expires.\r
- * Callback functions must have the prototype defined by tmrTIMER_CALLBACK,\r
- * which is "void vCallbackFunction( xTimerHandle xTimer );".\r
- *\r
- * @return If the timer is successfully create then a handle to the newly\r
- * created timer is returned. If the timer cannot be created (because either\r
- * there is insufficient FreeRTOS heap remaining to allocate the timer\r
- * structures, or the timer period was set to 0) then 0 is returned.\r
- *\r
- * Example usage:\r
- *\r
- *\r
- * #define NUM_TIMERS 5\r
- *\r
- * // An array to hold handles to the created timers.\r
- * xTimerHandle xTimers[ NUM_TIMERS ];\r
- *\r
- * // An array to hold a count of the number of times each timer expires.\r
- * long lExpireCounters[ NUM_TIMERS ] = { 0 };\r
- *\r
- * // Define a callback function that will be used by multiple timer instances.\r
- * // The callback function does nothing but count the number of times the\r
- * // associated timer expires, and stop the timer once the timer has expired\r
- * // 10 times.\r
- * void vTimerCallback( xTimerHandle pxTimer )\r
- * {\r
- * long lArrayIndex;\r
- * const long xMaxExpiryCountBeforeStopping = 10;\r
- *\r
- * // Optionally do something if the pxTimer parameter is NULL.\r
- * configASSERT( pxTimer );\r
- * \r
- * // Which timer expired?\r
- * lArrayIndex = ( long ) pvTimerGetTimerID( pxTimer );\r
- *\r
- * // Increment the number of times that pxTimer has expired.\r
- * lExpireCounters[ lArrayIndex ] += 1;\r
- *\r
- * // If the timer has expired 10 times then stop it from running.\r
- * if( lExpireCounters[ lArrayIndex ] == xMaxExpiryCountBeforeStopping )\r
- * {\r
- * // Do not use a block time if calling a timer API function from a\r
- * // timer callback function, as doing so could cause a deadlock!\r
- * xTimerStop( pxTimer, 0 );\r
- * }\r
- * }\r
- *\r
- * void main( void )\r
- * {\r
- * long x;\r
- *\r
- * // Create then start some timers. Starting the timers before the scheduler\r
- * // has been started means the timers will start running immediately that\r
- * // the scheduler starts.\r
- * for( x = 0; x < NUM_TIMERS; x++ )\r
- * {\r
- * xTimers[ x ] = xTimerCreate( "Timer", // Just a text name, not used by the kernel.\r
- * ( 100 * x ), // The timer period in ticks.\r
- * pdTRUE, // The timers will auto-reload themselves when they expire.\r
- * ( void * ) x, // Assign each timer a unique id equal to its array index.\r
- * vTimerCallback // Each timer calls the same callback when it expires.\r
- * );\r
- *\r
- * if( xTimers[ x ] == NULL )\r
- * {\r
- * // The timer was not created.\r
- * }\r
- * else\r
- * {\r
- * // Start the timer. No block time is specified, and even if one was\r
- * // it would be ignored because the scheduler has not yet been\r
- * // started.\r
- * if( xTimerStart( xTimers[ x ], 0 ) != pdPASS )\r
- * {\r
- * // The timer could not be set into the Active state.\r
- * }\r
- * }\r
- * }\r
- *\r
- * // ...\r
- * // Create tasks here.\r
- * // ...\r
- *\r
- * // Starting the scheduler will start the timers running as they have already\r
- * // been set into the active state.\r
- * xTaskStartScheduler();\r
- *\r
- * // Should not reach here.\r
- * for( ;; );\r
- * }\r
- */\r
-xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void * pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * void *pvTimerGetTimerID( xTimerHandle xTimer );\r
- *\r
- * Returns the ID assigned to the timer.\r
- *\r
- * IDs are assigned to timers using the pvTimerID parameter of the call to\r
- * xTimerCreated() that was used to create the timer.\r
- *\r
- * If the same callback function is assigned to multiple timers then the timer\r
- * ID can be used within the callback function to identify which timer actually\r
- * expired.\r
- *\r
- * @param xTimer The timer being queried.\r
- *\r
- * @return The ID assigned to the timer being queried.\r
- *\r
- * Example usage:\r
- *\r
- * See the xTimerCreate() API function example usage scenario.\r
- */\r
-void *pvTimerGetTimerID( xTimerHandle xTimer ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer );\r
- *\r
- * Queries a timer to see if it is active or dormant.\r
- *\r
- * A timer will be dormant if:\r
- * 1) It has been created but not started, or\r
- * 2) It is an expired on-shot timer that has not been restarted.\r
- *\r
- * Timers are created in the dormant state. The xTimerStart(), xTimerReset(),\r
- * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and\r
- * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the\r
- * active state.\r
- *\r
- * @param xTimer The timer being queried.\r
- *\r
- * @return pdFALSE will be returned if the timer is dormant. A value other than\r
- * pdFALSE will be returned if the timer is active.\r
- *\r
- * Example usage:\r
- *\r
- * // This function assumes xTimer has already been created.\r
- * void vAFunction( xTimerHandle xTimer )\r
- * {\r
- * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )"\r
- * {\r
- * // xTimer is active, do something.\r
- * }\r
- * else\r
- * {\r
- * // xTimer is not active, do something else.\r
- * }\r
- * }\r
- */\r
-portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ) PRIVILEGED_FUNCTION;\r
-\r
-/**\r
- * xTimerGetTimerTaskHandle() is only available if \r
- * INCLUDE_xTimerGetTimerTaskHandle is set to 1 in FreeRTOSConfig.h.\r
- *\r
- * Simply returns the handle of the timer service/daemon task. It it not valid\r
- * to call xTimerGetTimerTaskHandle() before the scheduler has been started.\r
- */\r
-xTaskHandle xTimerGetTimerTaskHandle( void );\r
-\r
-/**\r
- * portBASE_TYPE xTimerStart( xTimerHandle xTimer, portTickType xBlockTime );\r
- *\r
- * Timer functionality is provided by a timer service/daemon task. Many of the\r
- * public FreeRTOS timer API functions send commands to the timer service task\r
- * though a queue called the timer command queue. The timer command queue is\r
- * private to the kernel itself and is not directly accessible to application\r
- * code. The length of the timer command queue is set by the\r
- * configTIMER_QUEUE_LENGTH configuration constant.\r
- *\r
- * xTimerStart() starts a timer that was previously created using the\r
- * xTimerCreate() API function. If the timer had already been started and was\r
- * already in the active state, then xTimerStart() has equivalent functionality\r
- * to the xTimerReset() API function.\r
- *\r
- * Starting a timer ensures the timer is in the active state. If the timer\r
- * is not stopped, deleted, or reset in the mean time, the callback function\r
- * associated with the timer will get called 'n' ticks after xTimerStart() was\r
- * called, where 'n' is the timers defined period.\r
- *\r
- * It is valid to call xTimerStart() before the scheduler has been started, but\r
- * when this is done the timer will not actually start until the scheduler is\r
- * started, and the timers expiry time will be relative to when the scheduler is\r
- * started, not relative to when xTimerStart() was called.\r
- *\r
- * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStart()\r
- * to be available.\r
- *\r
- * @param xTimer The handle of the timer being started/restarted.\r
- *\r
- * @param xBlockTime Specifies the time, in ticks, that the calling task should\r
- * be held in the Blocked state to wait for the start command to be successfully\r
- * sent to the timer command queue, should the queue already be full when\r
- * xTimerStart() was called. xBlockTime is ignored if xTimerStart() is called\r
- * before the scheduler is started.\r
- *\r
- * @return pdFAIL will be returned if the start command could not be sent to\r
- * the timer command queue even after xBlockTime ticks had passed. pdPASS will\r
- * be returned if the command was successfully sent to the timer command queue.\r
- * When the command is actually processed will depend on the priority of the\r
- * timer service/daemon task relative to other tasks in the system, although the\r
- * timers expiry time is relative to when xTimerStart() is actually called. The\r
- * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY\r
- * configuration constant.\r
- *\r
- * Example usage:\r
- *\r
- * See the xTimerCreate() API function example usage scenario.\r
- *\r
- */\r
-#define xTimerStart( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) )\r
-\r
-/**\r
- * portBASE_TYPE xTimerStop( xTimerHandle xTimer, portTickType xBlockTime );\r
- *\r
- * Timer functionality is provided by a timer service/daemon task. Many of the\r
- * public FreeRTOS timer API functions send commands to the timer service task\r
- * though a queue called the timer command queue. The timer command queue is\r
- * private to the kernel itself and is not directly accessible to application\r
- * code. The length of the timer command queue is set by the\r
- * configTIMER_QUEUE_LENGTH configuration constant.\r
- *\r
- * xTimerStop() stops a timer that was previously started using either of the\r
- * The xTimerStart(), xTimerReset(), xTimerStartFromISR(), xTimerResetFromISR(),\r
- * xTimerChangePeriod() or xTimerChangePeriodFromISR() API functions.\r
- *\r
- * Stopping a timer ensures the timer is not in the active state.\r
- *\r
- * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStop()\r
- * to be available.\r
- *\r
- * @param xTimer The handle of the timer being stopped.\r
- *\r
- * @param xBlockTime Specifies the time, in ticks, that the calling task should\r
- * be held in the Blocked state to wait for the stop command to be successfully\r
- * sent to the timer command queue, should the queue already be full when\r
- * xTimerStop() was called. xBlockTime is ignored if xTimerStop() is called\r
- * before the scheduler is started.\r
- *\r
- * @return pdFAIL will be returned if the stop command could not be sent to\r
- * the timer command queue even after xBlockTime ticks had passed. pdPASS will\r
- * be returned if the command was successfully sent to the timer command queue.\r
- * When the command is actually processed will depend on the priority of the\r
- * timer service/daemon task relative to other tasks in the system. The timer\r
- * service/daemon task priority is set by the configTIMER_TASK_PRIORITY\r
- * configuration constant.\r
- *\r
- * Example usage:\r
- *\r
- * See the xTimerCreate() API function example usage scenario.\r
- *\r
- */\r
-#define xTimerStop( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xBlockTime ) )\r
-\r
-/**\r
- * portBASE_TYPE xTimerChangePeriod( xTimerHandle xTimer,\r
- * portTickType xNewPeriod,\r
- * portTickType xBlockTime );\r
- *\r
- * Timer functionality is provided by a timer service/daemon task. Many of the\r
- * public FreeRTOS timer API functions send commands to the timer service task\r
- * though a queue called the timer command queue. The timer command queue is\r
- * private to the kernel itself and is not directly accessible to application\r
- * code. The length of the timer command queue is set by the\r
- * configTIMER_QUEUE_LENGTH configuration constant.\r
- *\r
- * xTimerChangePeriod() changes the period of a timer that was previously\r
- * created using the xTimerCreate() API function.\r
- *\r
- * xTimerChangePeriod() can be called to change the period of an active or\r
- * dormant state timer.\r
- *\r
- * The configUSE_TIMERS configuration constant must be set to 1 for\r
- * xTimerChangePeriod() to be available.\r
- *\r
- * @param xTimer The handle of the timer that is having its period changed.\r
- *\r
- * @param xNewPeriod The new period for xTimer. Timer periods are specified in\r
- * tick periods, so the constant portTICK_RATE_MS can be used to convert a time\r
- * that has been specified in milliseconds. For example, if the timer must\r
- * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively,\r
- * if the timer must expire after 500ms, then xNewPeriod can be set to\r
- * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than\r
- * or equal to 1000.\r
- *\r
- * @param xBlockTime Specifies the time, in ticks, that the calling task should\r
- * be held in the Blocked state to wait for the change period command to be\r
- * successfully sent to the timer command queue, should the queue already be\r
- * full when xTimerChangePeriod() was called. xBlockTime is ignored if\r
- * xTimerChangePeriod() is called before the scheduler is started.\r
- *\r
- * @return pdFAIL will be returned if the change period command could not be\r
- * sent to the timer command queue even after xBlockTime ticks had passed.\r
- * pdPASS will be returned if the command was successfully sent to the timer\r
- * command queue. When the command is actually processed will depend on the\r
- * priority of the timer service/daemon task relative to other tasks in the\r
- * system. The timer service/daemon task priority is set by the\r
- * configTIMER_TASK_PRIORITY configuration constant.\r
- *\r
- * Example usage:\r
- *\r
- * // This function assumes xTimer has already been created. If the timer\r
- * // referenced by xTimer is already active when it is called, then the timer\r
- * // is deleted. If the timer referenced by xTimer is not active when it is\r
- * // called, then the period of the timer is set to 500ms and the timer is\r
- * // started.\r
- * void vAFunction( xTimerHandle xTimer )\r
- * {\r
- * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )"\r
- * {\r
- * // xTimer is already active - delete it.\r
- * xTimerDelete( xTimer );\r
- * }\r
- * else\r
- * {\r
- * // xTimer is not active, change its period to 500ms. This will also\r
- * // cause the timer to start. Block for a maximum of 100 ticks if the\r
- * // change period command cannot immediately be sent to the timer\r
- * // command queue.\r
- * if( xTimerChangePeriod( xTimer, 500 / portTICK_RATE_MS, 100 ) == pdPASS )\r
- * {\r
- * // The command was successfully sent.\r
- * }\r
- * else\r
- * {\r
- * // The command could not be sent, even after waiting for 100 ticks\r
- * // to pass. Take appropriate action here.\r
- * }\r
- * }\r
- * }\r
- */\r
- #define xTimerChangePeriod( xTimer, xNewPeriod, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), NULL, ( xBlockTime ) )\r
-\r
-/**\r
- * portBASE_TYPE xTimerDelete( xTimerHandle xTimer, portTickType xBlockTime );\r
- *\r
- * Timer functionality is provided by a timer service/daemon task. Many of the\r
- * public FreeRTOS timer API functions send commands to the timer service task\r
- * though a queue called the timer command queue. The timer command queue is\r
- * private to the kernel itself and is not directly accessible to application\r
- * code. The length of the timer command queue is set by the\r
- * configTIMER_QUEUE_LENGTH configuration constant.\r
- *\r
- * xTimerDelete() deletes a timer that was previously created using the\r
- * xTimerCreate() API function.\r
- *\r
- * The configUSE_TIMERS configuration constant must be set to 1 for\r
- * xTimerDelete() to be available.\r
- *\r
- * @param xTimer The handle of the timer being deleted.\r
- *\r
- * @param xBlockTime Specifies the time, in ticks, that the calling task should\r
- * be held in the Blocked state to wait for the delete command to be\r
- * successfully sent to the timer command queue, should the queue already be\r
- * full when xTimerDelete() was called. xBlockTime is ignored if xTimerDelete()\r
- * is called before the scheduler is started.\r
- *\r
- * @return pdFAIL will be returned if the delete command could not be sent to\r
- * the timer command queue even after xBlockTime ticks had passed. pdPASS will\r
- * be returned if the command was successfully sent to the timer command queue.\r
- * When the command is actually processed will depend on the priority of the\r
- * timer service/daemon task relative to other tasks in the system. The timer\r
- * service/daemon task priority is set by the configTIMER_TASK_PRIORITY\r
- * configuration constant.\r
- *\r
- * Example usage:\r
- *\r
- * See the xTimerChangePeriod() API function example usage scenario.\r
- */\r
-#define xTimerDelete( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_DELETE, 0U, NULL, ( xBlockTime ) )\r
-\r
-/**\r
- * portBASE_TYPE xTimerReset( xTimerHandle xTimer, portTickType xBlockTime );\r
- *\r
- * Timer functionality is provided by a timer service/daemon task. Many of the\r
- * public FreeRTOS timer API functions send commands to the timer service task\r
- * though a queue called the timer command queue. The timer command queue is\r
- * private to the kernel itself and is not directly accessible to application\r
- * code. The length of the timer command queue is set by the\r
- * configTIMER_QUEUE_LENGTH configuration constant.\r
- *\r
- * xTimerReset() re-starts a timer that was previously created using the\r
- * xTimerCreate() API function. If the timer had already been started and was\r
- * already in the active state, then xTimerReset() will cause the timer to\r
- * re-evaluate its expiry time so that it is relative to when xTimerReset() was\r
- * called. If the timer was in the dormant state then xTimerReset() has\r
- * equivalent functionality to the xTimerStart() API function.\r
- *\r
- * Resetting a timer ensures the timer is in the active state. If the timer\r
- * is not stopped, deleted, or reset in the mean time, the callback function\r
- * associated with the timer will get called 'n' ticks after xTimerReset() was\r
- * called, where 'n' is the timers defined period.\r
- *\r
- * It is valid to call xTimerReset() before the scheduler has been started, but\r
- * when this is done the timer will not actually start until the scheduler is\r
- * started, and the timers expiry time will be relative to when the scheduler is\r
- * started, not relative to when xTimerReset() was called.\r
- *\r
- * The configUSE_TIMERS configuration constant must be set to 1 for xTimerReset()\r
- * to be available.\r
- *\r
- * @param xTimer The handle of the timer being reset/started/restarted.\r
- *\r
- * @param xBlockTime Specifies the time, in ticks, that the calling task should\r
- * be held in the Blocked state to wait for the reset command to be successfully\r
- * sent to the timer command queue, should the queue already be full when\r
- * xTimerReset() was called. xBlockTime is ignored if xTimerReset() is called\r
- * before the scheduler is started.\r
- *\r
- * @return pdFAIL will be returned if the reset command could not be sent to\r
- * the timer command queue even after xBlockTime ticks had passed. pdPASS will\r
- * be returned if the command was successfully sent to the timer command queue.\r
- * When the command is actually processed will depend on the priority of the\r
- * timer service/daemon task relative to other tasks in the system, although the\r
- * timers expiry time is relative to when xTimerStart() is actually called. The\r
- * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY\r
- * configuration constant.\r
- *\r
- * Example usage:\r
- *\r
- * // When a key is pressed, an LCD back-light is switched on. If 5 seconds pass\r
- * // without a key being pressed, then the LCD back-light is switched off. In\r
- * // this case, the timer is a one-shot timer.\r
- *\r
- * xTimerHandle xBacklightTimer = NULL;\r
- *\r
- * // The callback function assigned to the one-shot timer. In this case the\r
- * // parameter is not used.\r
- * void vBacklightTimerCallback( xTimerHandle pxTimer )\r
- * {\r
- * // The timer expired, therefore 5 seconds must have passed since a key\r
- * // was pressed. Switch off the LCD back-light.\r
- * vSetBacklightState( BACKLIGHT_OFF );\r
- * }\r
- *\r
- * // The key press event handler.\r
- * void vKeyPressEventHandler( char cKey )\r
- * {\r
- * // Ensure the LCD back-light is on, then reset the timer that is\r
- * // responsible for turning the back-light off after 5 seconds of\r
- * // key inactivity. Wait 10 ticks for the command to be successfully sent\r
- * // if it cannot be sent immediately.\r
- * vSetBacklightState( BACKLIGHT_ON );\r
- * if( xTimerReset( xBacklightTimer, 100 ) != pdPASS )\r
- * {\r
- * // The reset command was not executed successfully. Take appropriate\r
- * // action here.\r
- * }\r
- *\r
- * // Perform the rest of the key processing here.\r
- * }\r
- *\r
- * void main( void )\r
- * {\r
- * long x;\r
- *\r
- * // Create then start the one-shot timer that is responsible for turning\r
- * // the back-light off if no keys are pressed within a 5 second period.\r
- * xBacklightTimer = xTimerCreate( "BacklightTimer", // Just a text name, not used by the kernel.\r
- * ( 5000 / portTICK_RATE_MS), // The timer period in ticks.\r
- * pdFALSE, // The timer is a one-shot timer.\r
- * 0, // The id is not used by the callback so can take any value.\r
- * vBacklightTimerCallback // The callback function that switches the LCD back-light off.\r
- * );\r
- *\r
- * if( xBacklightTimer == NULL )\r
- * {\r
- * // The timer was not created.\r
- * }\r
- * else\r
- * {\r
- * // Start the timer. No block time is specified, and even if one was\r
- * // it would be ignored because the scheduler has not yet been\r
- * // started.\r
- * if( xTimerStart( xBacklightTimer, 0 ) != pdPASS )\r
- * {\r
- * // The timer could not be set into the Active state.\r
- * }\r
- * }\r
- *\r
- * // ...\r
- * // Create tasks here.\r
- * // ...\r
- *\r
- * // Starting the scheduler will start the timer running as it has already\r
- * // been set into the active state.\r
- * xTaskStartScheduler();\r
- *\r
- * // Should not reach here.\r
- * for( ;; );\r
- * }\r
- */\r
-#define xTimerReset( xTimer, xBlockTime ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xBlockTime ) )\r
-\r
-/**\r
- * portBASE_TYPE xTimerStartFromISR( xTimerHandle xTimer,\r
- * portBASE_TYPE *pxHigherPriorityTaskWoken );\r
- *\r
- * A version of xTimerStart() that can be called from an interrupt service\r
- * routine.\r
- *\r
- * @param xTimer The handle of the timer being started/restarted.\r
- *\r
- * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most\r
- * of its time in the Blocked state, waiting for messages to arrive on the timer\r
- * command queue. Calling xTimerStartFromISR() writes a message to the timer\r
- * command queue, so has the potential to transition the timer service/daemon\r
- * task out of the Blocked state. If calling xTimerStartFromISR() causes the\r
- * timer service/daemon task to leave the Blocked state, and the timer service/\r
- * daemon task has a priority equal to or greater than the currently executing\r
- * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will\r
- * get set to pdTRUE internally within the xTimerStartFromISR() function. If\r
- * xTimerStartFromISR() sets this value to pdTRUE then a context switch should\r
- * be performed before the interrupt exits.\r
- *\r
- * @return pdFAIL will be returned if the start command could not be sent to\r
- * the timer command queue. pdPASS will be returned if the command was\r
- * successfully sent to the timer command queue. When the command is actually\r
- * processed will depend on the priority of the timer service/daemon task\r
- * relative to other tasks in the system, although the timers expiry time is\r
- * relative to when xTimerStartFromISR() is actually called. The timer service/daemon\r
- * task priority is set by the configTIMER_TASK_PRIORITY configuration constant.\r
- *\r
- * Example usage:\r
- *\r
- * // This scenario assumes xBacklightTimer has already been created. When a\r
- * // key is pressed, an LCD back-light is switched on. If 5 seconds pass\r
- * // without a key being pressed, then the LCD back-light is switched off. In\r
- * // this case, the timer is a one-shot timer, and unlike the example given for\r
- * // the xTimerReset() function, the key press event handler is an interrupt\r
- * // service routine.\r
- *\r
- * // The callback function assigned to the one-shot timer. In this case the\r
- * // parameter is not used.\r
- * void vBacklightTimerCallback( xTimerHandle pxTimer )\r
- * {\r
- * // The timer expired, therefore 5 seconds must have passed since a key\r
- * // was pressed. Switch off the LCD back-light.\r
- * vSetBacklightState( BACKLIGHT_OFF );\r
- * }\r
- *\r
- * // The key press interrupt service routine.\r
- * void vKeyPressEventInterruptHandler( void )\r
- * {\r
- * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
- *\r
- * // Ensure the LCD back-light is on, then restart the timer that is\r
- * // responsible for turning the back-light off after 5 seconds of\r
- * // key inactivity. This is an interrupt service routine so can only\r
- * // call FreeRTOS API functions that end in "FromISR".\r
- * vSetBacklightState( BACKLIGHT_ON );\r
- *\r
- * // xTimerStartFromISR() or xTimerResetFromISR() could be called here\r
- * // as both cause the timer to re-calculate its expiry time.\r
- * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was\r
- * // declared (in this function).\r
- * if( xTimerStartFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS )\r
- * {\r
- * // The start command was not executed successfully. Take appropriate\r
- * // action here.\r
- * }\r
- *\r
- * // Perform the rest of the key processing here.\r
- *\r
- * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch\r
- * // should be performed. The syntax required to perform a context switch\r
- * // from inside an ISR varies from port to port, and from compiler to\r
- * // compiler. Inspect the demos for the port you are using to find the\r
- * // actual syntax required.\r
- * if( xHigherPriorityTaskWoken != pdFALSE )\r
- * {\r
- * // Call the interrupt safe yield function here (actual function\r
- * // depends on the FreeRTOS port being used.\r
- * }\r
- * }\r
- */\r
-#define xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )\r
-\r
-/**\r
- * portBASE_TYPE xTimerStopFromISR( xTimerHandle xTimer,\r
- * portBASE_TYPE *pxHigherPriorityTaskWoken );\r
- *\r
- * A version of xTimerStop() that can be called from an interrupt service\r
- * routine.\r
- *\r
- * @param xTimer The handle of the timer being stopped.\r
- *\r
- * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most\r
- * of its time in the Blocked state, waiting for messages to arrive on the timer\r
- * command queue. Calling xTimerStopFromISR() writes a message to the timer\r
- * command queue, so has the potential to transition the timer service/daemon\r
- * task out of the Blocked state. If calling xTimerStopFromISR() causes the\r
- * timer service/daemon task to leave the Blocked state, and the timer service/\r
- * daemon task has a priority equal to or greater than the currently executing\r
- * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will\r
- * get set to pdTRUE internally within the xTimerStopFromISR() function. If\r
- * xTimerStopFromISR() sets this value to pdTRUE then a context switch should\r
- * be performed before the interrupt exits.\r
- *\r
- * @return pdFAIL will be returned if the stop command could not be sent to\r
- * the timer command queue. pdPASS will be returned if the command was\r
- * successfully sent to the timer command queue. When the command is actually\r
- * processed will depend on the priority of the timer service/daemon task\r
- * relative to other tasks in the system. The timer service/daemon task\r
- * priority is set by the configTIMER_TASK_PRIORITY configuration constant.\r
- *\r
- * Example usage:\r
- *\r
- * // This scenario assumes xTimer has already been created and started. When\r
- * // an interrupt occurs, the timer should be simply stopped.\r
- *\r
- * // The interrupt service routine that stops the timer.\r
- * void vAnExampleInterruptServiceRoutine( void )\r
- * {\r
- * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
- *\r
- * // The interrupt has occurred - simply stop the timer.\r
- * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined\r
- * // (within this function). As this is an interrupt service routine, only\r
- * // FreeRTOS API functions that end in "FromISR" can be used.\r
- * if( xTimerStopFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS )\r
- * {\r
- * // The stop command was not executed successfully. Take appropriate\r
- * // action here.\r
- * }\r
- *\r
- * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch\r
- * // should be performed. The syntax required to perform a context switch\r
- * // from inside an ISR varies from port to port, and from compiler to\r
- * // compiler. Inspect the demos for the port you are using to find the\r
- * // actual syntax required.\r
- * if( xHigherPriorityTaskWoken != pdFALSE )\r
- * {\r
- * // Call the interrupt safe yield function here (actual function\r
- * // depends on the FreeRTOS port being used.\r
- * }\r
- * }\r
- */\r
-#define xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0, ( pxHigherPriorityTaskWoken ), 0U )\r
-\r
-/**\r
- * portBASE_TYPE xTimerChangePeriodFromISR( xTimerHandle xTimer,\r
- * portTickType xNewPeriod,\r
- * portBASE_TYPE *pxHigherPriorityTaskWoken );\r
- *\r
- * A version of xTimerChangePeriod() that can be called from an interrupt\r
- * service routine.\r
- *\r
- * @param xTimer The handle of the timer that is having its period changed.\r
- *\r
- * @param xNewPeriod The new period for xTimer. Timer periods are specified in\r
- * tick periods, so the constant portTICK_RATE_MS can be used to convert a time\r
- * that has been specified in milliseconds. For example, if the timer must\r
- * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively,\r
- * if the timer must expire after 500ms, then xNewPeriod can be set to\r
- * ( 500 / portTICK_RATE_MS ) provided configTICK_RATE_HZ is less than\r
- * or equal to 1000.\r
- *\r
- * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most\r
- * of its time in the Blocked state, waiting for messages to arrive on the timer\r
- * command queue. Calling xTimerChangePeriodFromISR() writes a message to the\r
- * timer command queue, so has the potential to transition the timer service/\r
- * daemon task out of the Blocked state. If calling xTimerChangePeriodFromISR()\r
- * causes the timer service/daemon task to leave the Blocked state, and the\r
- * timer service/daemon task has a priority equal to or greater than the\r
- * currently executing task (the task that was interrupted), then\r
- * *pxHigherPriorityTaskWoken will get set to pdTRUE internally within the\r
- * xTimerChangePeriodFromISR() function. If xTimerChangePeriodFromISR() sets\r
- * this value to pdTRUE then a context switch should be performed before the\r
- * interrupt exits.\r
- *\r
- * @return pdFAIL will be returned if the command to change the timers period\r
- * could not be sent to the timer command queue. pdPASS will be returned if the\r
- * command was successfully sent to the timer command queue. When the command\r
- * is actually processed will depend on the priority of the timer service/daemon\r
- * task relative to other tasks in the system. The timer service/daemon task\r
- * priority is set by the configTIMER_TASK_PRIORITY configuration constant.\r
- *\r
- * Example usage:\r
- *\r
- * // This scenario assumes xTimer has already been created and started. When\r
- * // an interrupt occurs, the period of xTimer should be changed to 500ms.\r
- *\r
- * // The interrupt service routine that changes the period of xTimer.\r
- * void vAnExampleInterruptServiceRoutine( void )\r
- * {\r
- * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
- *\r
- * // The interrupt has occurred - change the period of xTimer to 500ms.\r
- * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined\r
- * // (within this function). As this is an interrupt service routine, only\r
- * // FreeRTOS API functions that end in "FromISR" can be used.\r
- * if( xTimerChangePeriodFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS )\r
- * {\r
- * // The command to change the timers period was not executed\r
- * // successfully. Take appropriate action here.\r
- * }\r
- *\r
- * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch\r
- * // should be performed. The syntax required to perform a context switch\r
- * // from inside an ISR varies from port to port, and from compiler to\r
- * // compiler. Inspect the demos for the port you are using to find the\r
- * // actual syntax required.\r
- * if( xHigherPriorityTaskWoken != pdFALSE )\r
- * {\r
- * // Call the interrupt safe yield function here (actual function\r
- * // depends on the FreeRTOS port being used.\r
- * }\r
- * }\r
- */\r
-#define xTimerChangePeriodFromISR( xTimer, xNewPeriod, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), ( pxHigherPriorityTaskWoken ), 0U )\r
-\r
-/**\r
- * portBASE_TYPE xTimerResetFromISR( xTimerHandle xTimer,\r
- * portBASE_TYPE *pxHigherPriorityTaskWoken );\r
- *\r
- * A version of xTimerReset() that can be called from an interrupt service\r
- * routine.\r
- *\r
- * @param xTimer The handle of the timer that is to be started, reset, or\r
- * restarted.\r
- *\r
- * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most\r
- * of its time in the Blocked state, waiting for messages to arrive on the timer\r
- * command queue. Calling xTimerResetFromISR() writes a message to the timer\r
- * command queue, so has the potential to transition the timer service/daemon\r
- * task out of the Blocked state. If calling xTimerResetFromISR() causes the\r
- * timer service/daemon task to leave the Blocked state, and the timer service/\r
- * daemon task has a priority equal to or greater than the currently executing\r
- * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will\r
- * get set to pdTRUE internally within the xTimerResetFromISR() function. If\r
- * xTimerResetFromISR() sets this value to pdTRUE then a context switch should\r
- * be performed before the interrupt exits.\r
- *\r
- * @return pdFAIL will be returned if the reset command could not be sent to\r
- * the timer command queue. pdPASS will be returned if the command was\r
- * successfully sent to the timer command queue. When the command is actually\r
- * processed will depend on the priority of the timer service/daemon task\r
- * relative to other tasks in the system, although the timers expiry time is\r
- * relative to when xTimerResetFromISR() is actually called. The timer service/daemon\r
- * task priority is set by the configTIMER_TASK_PRIORITY configuration constant.\r
- *\r
- * Example usage:\r
- *\r
- * // This scenario assumes xBacklightTimer has already been created. When a\r
- * // key is pressed, an LCD back-light is switched on. If 5 seconds pass\r
- * // without a key being pressed, then the LCD back-light is switched off. In\r
- * // this case, the timer is a one-shot timer, and unlike the example given for\r
- * // the xTimerReset() function, the key press event handler is an interrupt\r
- * // service routine.\r
- *\r
- * // The callback function assigned to the one-shot timer. In this case the\r
- * // parameter is not used.\r
- * void vBacklightTimerCallback( xTimerHandle pxTimer )\r
- * {\r
- * // The timer expired, therefore 5 seconds must have passed since a key\r
- * // was pressed. Switch off the LCD back-light.\r
- * vSetBacklightState( BACKLIGHT_OFF );\r
- * }\r
- *\r
- * // The key press interrupt service routine.\r
- * void vKeyPressEventInterruptHandler( void )\r
- * {\r
- * portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
- *\r
- * // Ensure the LCD back-light is on, then reset the timer that is\r
- * // responsible for turning the back-light off after 5 seconds of\r
- * // key inactivity. This is an interrupt service routine so can only\r
- * // call FreeRTOS API functions that end in "FromISR".\r
- * vSetBacklightState( BACKLIGHT_ON );\r
- *\r
- * // xTimerStartFromISR() or xTimerResetFromISR() could be called here\r
- * // as both cause the timer to re-calculate its expiry time.\r
- * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was\r
- * // declared (in this function).\r
- * if( xTimerResetFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS )\r
- * {\r
- * // The reset command was not executed successfully. Take appropriate\r
- * // action here.\r
- * }\r
- *\r
- * // Perform the rest of the key processing here.\r
- *\r
- * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch\r
- * // should be performed. The syntax required to perform a context switch\r
- * // from inside an ISR varies from port to port, and from compiler to\r
- * // compiler. Inspect the demos for the port you are using to find the\r
- * // actual syntax required.\r
- * if( xHigherPriorityTaskWoken != pdFALSE )\r
- * {\r
- * // Call the interrupt safe yield function here (actual function\r
- * // depends on the FreeRTOS port being used.\r
- * }\r
- * }\r
- */\r
-#define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )\r
-\r
-/*\r
- * Functions beyond this part are not part of the public API and are intended\r
- * for use by the kernel only.\r
- */\r
-portBASE_TYPE xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION;\r
-portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime ) PRIVILEGED_FUNCTION;\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-#endif /* TIMERS_H */\r
-\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-\r
-#include <stdlib.h>\r
-#include "FreeRTOS.h"\r
-#include "list.h"\r
-\r
-/*-----------------------------------------------------------\r
- * PUBLIC LIST API documented in list.h\r
- *----------------------------------------------------------*/\r
-\r
-void vListInitialise( xList *pxList )\r
-{\r
- /* The list structure contains a list item which is used to mark the\r
- end of the list. To initialise the list the list end is inserted\r
- as the only list entry. */\r
- pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );\r
-\r
- /* The list end value is the highest possible value in the list to\r
- ensure it remains at the end of the list. */\r
- pxList->xListEnd.xItemValue = portMAX_DELAY;\r
-\r
- /* The list end next and previous pointers point to itself so we know\r
- when the list is empty. */\r
- pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd );\r
- pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );\r
-\r
- pxList->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0U;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vListInitialiseItem( xListItem *pxItem )\r
-{\r
- /* Make sure the list item is not recorded as being on a list. */\r
- pxItem->pvContainer = NULL;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vListInsertEnd( xList *pxList, xListItem *pxNewListItem )\r
-{\r
-volatile xListItem * pxIndex;\r
-\r
- /* Insert a new list item into pxList, but rather than sort the list,\r
- makes the new list item the last item to be removed by a call to\r
- pvListGetOwnerOfNextEntry. This means it has to be the item pointed to by\r
- the pxIndex member. */\r
- pxIndex = pxList->pxIndex;\r
-\r
- pxNewListItem->pxNext = pxIndex->pxNext;\r
- pxNewListItem->pxPrevious = pxList->pxIndex;\r
- pxIndex->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;\r
- pxIndex->pxNext = ( volatile xListItem * ) pxNewListItem;\r
- pxList->pxIndex = ( volatile xListItem * ) pxNewListItem;\r
-\r
- /* Remember which list the item is in. */\r
- pxNewListItem->pvContainer = ( void * ) pxList;\r
-\r
- ( pxList->uxNumberOfItems )++;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vListInsert( xList *pxList, xListItem *pxNewListItem )\r
-{\r
-volatile xListItem *pxIterator;\r
-portTickType xValueOfInsertion;\r
-\r
- /* Insert the new list item into the list, sorted in ulListItem order. */\r
- xValueOfInsertion = pxNewListItem->xItemValue;\r
-\r
- /* If the list already contains a list item with the same item value then\r
- the new list item should be placed after it. This ensures that TCB's which\r
- are stored in ready lists (all of which have the same ulListItem value)\r
- get an equal share of the CPU. However, if the xItemValue is the same as\r
- the back marker the iteration loop below will not end. This means we need\r
- to guard against this by checking the value first and modifying the\r
- algorithm slightly if necessary. */\r
- if( xValueOfInsertion == portMAX_DELAY )\r
- {\r
- pxIterator = pxList->xListEnd.pxPrevious;\r
- }\r
- else\r
- {\r
- /* *** NOTE ***********************************************************\r
- If you find your application is crashing here then likely causes are:\r
- 1) Stack overflow -\r
- see http://www.freertos.org/Stacks-and-stack-overflow-checking.html\r
- 2) Incorrect interrupt priority assignment, especially on Cortex-M3\r
- parts where numerically high priority values denote low actual\r
- interrupt priories, which can seem counter intuitive. See\r
- configMAX_SYSCALL_INTERRUPT_PRIORITY on http://www.freertos.org/a00110.html\r
- 3) Calling an API function from within a critical section or when\r
- the scheduler is suspended.\r
- 4) Using a queue or semaphore before it has been initialised or\r
- before the scheduler has been started (are interrupts firing\r
- before vTaskStartScheduler() has been called?).\r
- See http://www.freertos.org/FAQHelp.html for more tips.\r
- **********************************************************************/\r
- \r
- for( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext )\r
- {\r
- /* There is nothing to do here, we are just iterating to the\r
- wanted insertion position. */\r
- }\r
- }\r
-\r
- pxNewListItem->pxNext = pxIterator->pxNext;\r
- pxNewListItem->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;\r
- pxNewListItem->pxPrevious = pxIterator;\r
- pxIterator->pxNext = ( volatile xListItem * ) pxNewListItem;\r
-\r
- /* Remember which list the item is in. This allows fast removal of the\r
- item later. */\r
- pxNewListItem->pvContainer = ( void * ) pxList;\r
-\r
- ( pxList->uxNumberOfItems )++;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vListRemove( xListItem *pxItemToRemove )\r
-{\r
-xList * pxList;\r
-\r
- pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;\r
- pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;\r
- \r
- /* The list item knows which list it is in. Obtain the list from the list\r
- item. */\r
- pxList = ( xList * ) pxItemToRemove->pvContainer;\r
-\r
- /* Make sure the index is left pointing to a valid item. */\r
- if( pxList->pxIndex == pxItemToRemove )\r
- {\r
- pxList->pxIndex = pxItemToRemove->pxPrevious;\r
- }\r
-\r
- pxItemToRemove->pvContainer = NULL;\r
- ( pxList->uxNumberOfItems )--;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/*-----------------------------------------------------------\r
- * Implementation of functions defined in portable.h for the MicroBlaze port.\r
- *----------------------------------------------------------*/\r
-\r
-\r
-/* Scheduler includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-\r
-/* Standard includes. */\r
-#include <string.h>\r
-\r
-/* Hardware includes. */\r
-#include <xintc_i.h>\r
-#include <xil_exception.h>\r
-#include <microblaze_exceptions_g.h>\r
-\r
-/* Tasks are started with a critical section nesting of 0 - however, prior to \r
-the scheduler being commenced interrupts should not be enabled, so the critical \r
-nesting variable is initialised to a non-zero value. */\r
-#define portINITIAL_NESTING_VALUE ( 0xff )\r
-\r
-/* The bit within the MSR register that enabled/disables interrupts. */\r
-#define portMSR_IE ( 0x02U )\r
-\r
-/* If the floating point unit is included in the MicroBlaze build, then the\r
-FSR register is saved as part of the task context. portINITIAL_FSR is the value\r
-given to the FSR register when the initial context is set up for a task being\r
-created. */\r
-#define portINITIAL_FSR ( 0U )\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Initialise the interrupt controller instance.\r
- */\r
-static long prvInitialiseInterruptController( void );\r
-\r
-/* Ensure the interrupt controller instance variable is initialised before it is \r
- * used, and that the initialisation only happens once. \r
- */\r
-static long prvEnsureInterruptControllerIsInitialised( void );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Counts the nesting depth of calls to portENTER_CRITICAL(). Each task \r
-maintains its own count, so this variable is saved as part of the task\r
-context. */\r
-volatile unsigned portBASE_TYPE uxCriticalNesting = portINITIAL_NESTING_VALUE;\r
-\r
-/* This port uses a separate stack for interrupts. This prevents the stack of\r
-every task needing to be large enough to hold an entire interrupt stack on top\r
-of the task stack. */\r
-unsigned long *pulISRStack;\r
-\r
-/* If an interrupt requests a context switch, then ulTaskSwitchRequested will\r
-get set to 1. ulTaskSwitchRequested is inspected just before the main interrupt\r
-handler exits. If, at that time, ulTaskSwitchRequested is set to 1, the kernel\r
-will call vTaskSwitchContext() to ensure the task that runs immediately after\r
-the interrupt exists is the highest priority task that is able to run. This is \r
-an unusual mechanism, but is used for this port because a single interrupt can \r
-cause the servicing of multiple peripherals - and it is inefficient to call\r
-vTaskSwitchContext() multiple times as each peripheral is serviced. */\r
-volatile unsigned long ulTaskSwitchRequested = 0UL;\r
-\r
-/* The instance of the interrupt controller used by this port. This is required\r
-by the Xilinx library API functions. */\r
-static XIntc xInterruptControllerInstance;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* \r
- * Initialise the stack of a task to look exactly as if a call to \r
- * portSAVE_CONTEXT had been made.\r
- * \r
- * See the portable.h header file.\r
- */\r
-portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )\r
-{\r
-extern void *_SDA2_BASE_, *_SDA_BASE_;\r
-const unsigned long ulR2 = ( unsigned long ) &_SDA2_BASE_;\r
-const unsigned long ulR13 = ( unsigned long ) &_SDA_BASE_;\r
-\r
- /* Place a few bytes of known values on the bottom of the stack. \r
- This is essential for the Microblaze port and these lines must\r
- not be omitted. */\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x00000000;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x00000000;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x00000000;\r
- pxTopOfStack--;\r
-\r
- #if XPAR_MICROBLAZE_0_USE_FPU == 1\r
- /* The FSR value placed in the initial task context is just 0. */\r
- *pxTopOfStack = portINITIAL_FSR;\r
- pxTopOfStack--;\r
- #endif\r
-\r
- /* The MSR value placed in the initial task context should have interrupts\r
- disabled. Each task will enable interrupts automatically when it enters\r
- the running state for the first time. */\r
- *pxTopOfStack = mfmsr() & ~portMSR_IE;\r
- pxTopOfStack--;\r
-\r
- /* First stack an initial value for the critical section nesting. This\r
- is initialised to zero. */\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x00;\r
- \r
- /* R0 is always zero. */\r
- /* R1 is the SP. */\r
-\r
- /* Place an initial value for all the general purpose registers. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) ulR2; /* R2 - read only small data area. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x03; /* R3 - return values and temporaries. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x04; /* R4 - return values and temporaries. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) pvParameters;/* R5 contains the function call parameters. */\r
-\r
- #ifdef portPRE_LOAD_STACK_FOR_DEBUGGING\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x06; /* R6 - other parameters and temporaries. Used as the return address from vPortTaskEntryPoint. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x07; /* R7 - other parameters and temporaries. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x08; /* R8 - other parameters and temporaries. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x09; /* R9 - other parameters and temporaries. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x0a; /* R10 - other parameters and temporaries. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x0b; /* R11 - temporaries. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x0c; /* R12 - temporaries. */\r
- pxTopOfStack--;\r
- #else\r
- pxTopOfStack-= 8;\r
- #endif\r
- \r
- *pxTopOfStack = ( portSTACK_TYPE ) ulR13; /* R13 - read/write small data area. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* R14 - return address for interrupt. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) NULL; /* R15 - return address for subroutine. */\r
- \r
- #ifdef portPRE_LOAD_STACK_FOR_DEBUGGING\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x10; /* R16 - return address for trap (debugger). */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x11; /* R17 - return address for exceptions, if configured. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x12; /* R18 - reserved for assembler and compiler temporaries. */\r
- pxTopOfStack--;\r
- #else\r
- pxTopOfStack -= 4;\r
- #endif\r
- \r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x00; /* R19 - must be saved across function calls. Callee-save. Seems to be interpreted as the frame pointer. */\r
- \r
- #ifdef portPRE_LOAD_STACK_FOR_DEBUGGING \r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x14; /* R20 - reserved for storing a pointer to the Global Offset Table (GOT) in Position Independent Code (PIC). Non-volatile in non-PIC code. Must be saved across function calls. Callee-save. Not used by FreeRTOS. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x15; /* R21 - must be saved across function calls. Callee-save. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x16; /* R22 - must be saved across function calls. Callee-save. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x17; /* R23 - must be saved across function calls. Callee-save. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x18; /* R24 - must be saved across function calls. Callee-save. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x19; /* R25 - must be saved across function calls. Callee-save. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x1a; /* R26 - must be saved across function calls. Callee-save. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x1b; /* R27 - must be saved across function calls. Callee-save. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x1c; /* R28 - must be saved across function calls. Callee-save. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x1d; /* R29 - must be saved across function calls. Callee-save. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x1e; /* R30 - must be saved across function calls. Callee-save. */\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( portSTACK_TYPE ) 0x1f; /* R31 - must be saved across function calls. Callee-save. */\r
- pxTopOfStack--;\r
- #else\r
- pxTopOfStack -= 13;\r
- #endif\r
-\r
- /* Return a pointer to the top of the stack that has been generated so this \r
- can be stored in the task control block for the task. */\r
- return pxTopOfStack;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-portBASE_TYPE xPortStartScheduler( void )\r
-{\r
-extern void ( vPortStartFirstTask )( void );\r
-extern unsigned long _stack[];\r
-\r
- /* Setup the hardware to generate the tick. Interrupts are disabled when\r
- this function is called. \r
- \r
- This port uses an application defined callback function to install the tick\r
- interrupt handler because the kernel will run on lots of different \r
- MicroBlaze and FPGA configurations - not all of which will have the same \r
- timer peripherals defined or available. An example definition of\r
- vApplicationSetupTimerInterrupt() is provided in the official demo\r
- application that accompanies this port. */\r
- vApplicationSetupTimerInterrupt();\r
-\r
- /* Reuse the stack from main() as the stack for the interrupts/exceptions. */\r
- pulISRStack = ( unsigned long * ) _stack;\r
-\r
- /* Ensure there is enough space for the functions called from the interrupt\r
- service routines to write back into the stack frame of the caller. */
- pulISRStack -= 2;\r
-\r
- /* Restore the context of the first task that is going to run. From here\r
- on, the created tasks will be executing. */\r
- vPortStartFirstTask();\r
-\r
- /* Should not get here as the tasks are now running! */\r
- return pdFALSE;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vPortEndScheduler( void )\r
-{\r
- /* Not implemented. */\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Manual context switch called by portYIELD or taskYIELD. \r
- */\r
-void vPortYield( void )\r
-{\r
-extern void VPortYieldASM( void );\r
-\r
- /* Perform the context switch in a critical section to assure it is\r
- not interrupted by the tick ISR. It is not a problem to do this as\r
- each task maintains its own interrupt status. */\r
- portENTER_CRITICAL();\r
- {\r
- /* Jump directly to the yield function to ensure there is no\r
- compiler generated prologue code. */\r
- asm volatile ( "bralid r14, VPortYieldASM \n\t" \\r
- "or r0, r0, r0 \n\t" );\r
- }\r
- portEXIT_CRITICAL();\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vPortEnableInterrupt( unsigned char ucInterruptID )\r
-{\r
-long lReturn;\r
-\r
- /* An API function is provided to enable an interrupt in the interrupt\r
- controller because the interrupt controller instance variable is private\r
- to this file. */\r
- lReturn = prvEnsureInterruptControllerIsInitialised();\r
- if( lReturn == pdPASS )\r
- {\r
- XIntc_Enable( &xInterruptControllerInstance, ucInterruptID );\r
- }\r
- \r
- configASSERT( lReturn );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vPortDisableInterrupt( unsigned char ucInterruptID )\r
-{\r
-long lReturn;\r
-\r
- /* An API function is provided to disable an interrupt in the interrupt\r
- controller because the interrupt controller instance variable is private\r
- to this file. */\r
- lReturn = prvEnsureInterruptControllerIsInitialised();\r
- \r
- if( lReturn == pdPASS )\r
- {\r
- XIntc_Disable( &xInterruptControllerInstance, ucInterruptID );\r
- }\r
- \r
- configASSERT( lReturn );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-portBASE_TYPE xPortInstallInterruptHandler( unsigned char ucInterruptID, XInterruptHandler pxHandler, void *pvCallBackRef )\r
-{\r
-long lReturn;\r
-\r
- /* An API function is provided to install an interrupt handler because the \r
- interrupt controller instance variable is private to this file. */\r
-\r
- lReturn = prvEnsureInterruptControllerIsInitialised();\r
- \r
- if( lReturn == pdPASS )\r
- {\r
- lReturn = XIntc_Connect( &xInterruptControllerInstance, ucInterruptID, pxHandler, pvCallBackRef );\r
- }\r
-\r
- if( lReturn == XST_SUCCESS )\r
- {\r
- lReturn = pdPASS;\r
- }\r
- \r
- configASSERT( lReturn == pdPASS );\r
-\r
- return lReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static long prvEnsureInterruptControllerIsInitialised( void )\r
-{\r
-static long lInterruptControllerInitialised = pdFALSE;\r
-long lReturn;\r
-\r
- /* Ensure the interrupt controller instance variable is initialised before\r
- it is used, and that the initialisation only happens once. */\r
- if( lInterruptControllerInitialised != pdTRUE )\r
- {\r
- lReturn = prvInitialiseInterruptController();\r
- \r
- if( lReturn == pdPASS )\r
- {\r
- lInterruptControllerInitialised = pdTRUE;\r
- }\r
- }\r
- else\r
- {\r
- lReturn = pdPASS;\r
- }\r
-\r
- return lReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* \r
- * Handler for the timer interrupt. This is the handler that the application\r
- * defined callback function vApplicationSetupTimerInterrupt() should install.\r
- */\r
-void vPortTickISR( void *pvUnused )\r
-{\r
-extern void vApplicationClearTimerInterrupt( void );\r
-\r
- /* Ensure the unused parameter does not generate a compiler warning. */\r
- ( void ) pvUnused;\r
-\r
- /* This port uses an application defined callback function to clear the tick\r
- interrupt because the kernel will run on lots of different MicroBlaze and \r
- FPGA configurations - not all of which will have the same timer peripherals \r
- defined or available. An example definition of\r
- vApplicationClearTimerInterrupt() is provided in the official demo\r
- application that accompanies this port. */ \r
- vApplicationClearTimerInterrupt();\r
-\r
- /* Increment the RTOS tick - this might cause a task to unblock. */\r
- vTaskIncrementTick();\r
-\r
- /* If the preemptive scheduler is being used then a context switch should be\r
- requested in case incrementing the tick unblocked a task, or a time slice\r
- should cause another task to enter the Running state. */\r
- #if configUSE_PREEMPTION == 1\r
- /* Force vTaskSwitchContext() to be called as the interrupt exits. */\r
- ulTaskSwitchRequested = 1;\r
- #endif\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static long prvInitialiseInterruptController( void )\r
-{\r
-long lStatus;\r
-\r
- lStatus = XIntc_Initialize( &xInterruptControllerInstance, configINTERRUPT_CONTROLLER_TO_USE );\r
-\r
- if( lStatus == XST_SUCCESS )\r
- {\r
- /* Initialise the exception table. */\r
- Xil_ExceptionInit();\r
-\r
- /* Service all pending interrupts each time the handler is entered. */\r
- XIntc_SetIntrSvcOption( xInterruptControllerInstance.BaseAddress, XIN_SVC_ALL_ISRS_OPTION );\r
-\r
- /* Install exception handlers if the MicroBlaze is configured to handle\r
- exceptions, and the application defined constant\r
- configINSTALL_EXCEPTION_HANDLERS is set to 1. */\r
- #if ( MICROBLAZE_EXCEPTIONS_ENABLED == 1 ) && ( configINSTALL_EXCEPTION_HANDLERS == 1 )\r
- {\r
- vPortExceptionsInstallHandlers();\r
- }\r
- #endif /* MICROBLAZE_EXCEPTIONS_ENABLED */\r
-\r
- /* Start the interrupt controller. Interrupts are enabled when the\r
- scheduler starts. */\r
- lStatus = XIntc_Start( &xInterruptControllerInstance, XIN_REAL_MODE );\r
-\r
- if( lStatus == XST_SUCCESS )\r
- {\r
- lStatus = pdPASS;\r
- }\r
- else\r
- {\r
- lStatus = pdFAIL;\r
- }\r
- }\r
-\r
- configASSERT( lStatus == pdPASS );\r
-\r
- return lStatus;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/* Scheduler includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-\r
-/* Hardware includes. */\r
-#include <microblaze_exceptions_i.h>\r
-#include <microblaze_exceptions_g.h>\r
-\r
-/* The Xilinx library defined exception entry point stacks a number of\r
-registers. These definitions are offsets from the stack pointer to the various\r
-stacked register values. */\r
-#define portexR3_STACK_OFFSET 4\r
-#define portexR4_STACK_OFFSET 5\r
-#define portexR5_STACK_OFFSET 6\r
-#define portexR6_STACK_OFFSET 7\r
-#define portexR7_STACK_OFFSET 8\r
-#define portexR8_STACK_OFFSET 9\r
-#define portexR9_STACK_OFFSET 10\r
-#define portexR10_STACK_OFFSET 11\r
-#define portexR11_STACK_OFFSET 12\r
-#define portexR12_STACK_OFFSET 13\r
-#define portexR15_STACK_OFFSET 16\r
-#define portexR18_STACK_OFFSET 19\r
-#define portexMSR_STACK_OFFSET 20\r
-#define portexR19_STACK_OFFSET -1\r
-\r
-/* This is defined to equal the size, in bytes, of the stack frame generated by\r
-the Xilinx standard library exception entry point. It is required to determine\r
-the stack pointer value prior to the exception being entered. */\r
-#define portexASM_HANDLER_STACK_FRAME_SIZE 84UL\r
-\r
-/* The number of bytes a MicroBlaze instruction consumes. */\r
-#define portexINSTRUCTION_SIZE 4\r
-\r
-/* Exclude this entire file if the MicroBlaze is not configured to handle\r
-exceptions, or the application defined configuration constant\r
-configINSTALL_EXCEPTION_HANDLERS is not set to 1. */\r
-#if ( MICROBLAZE_EXCEPTIONS_ENABLED == 1 ) && ( configINSTALL_EXCEPTION_HANDLERS == 1 )\r
-\r
-/* This variable is set in the exception entry code, before\r
-vPortExceptionHandler is called. */\r
-unsigned long *pulStackPointerOnFunctionEntry = NULL;\r
-\r
-/* This is the structure that is filled with the MicroBlaze context as it\r
-existed immediately prior to the exception occurrence. A pointer to this\r
-structure is passed into the vApplicationExceptionRegisterDump() callback\r
-function, if one is defined. */\r
-static xPortRegisterDump xRegisterDump;\r
-\r
-/* This is the FreeRTOS exception handler that is installed for all exception\r
-types. It is called from vPortExceptionHanlderEntry() - which is itself defined\r
-in portasm.S. */\r
-void vPortExceptionHandler( void *pvExceptionID );\r
-extern void vPortExceptionHandlerEntry( void *pvExceptionID );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* vApplicationExceptionRegisterDump() is a callback function that the \r
-application can optionally define to receive a populated xPortRegisterDump\r
-structure. If the application chooses not to define a version of \r
-vApplicationExceptionRegisterDump() then this weekly defined default \r
-implementation will be called instead. */\r
-extern void vApplicationExceptionRegisterDump( xPortRegisterDump *xRegisterDump ) __attribute__((weak));\r
-void vApplicationExceptionRegisterDump( xPortRegisterDump *xRegisterDump )\r
-{\r
- ( void ) xRegisterDump;\r
-\r
- for( ;; )\r
- {\r
- portNOP();\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vPortExceptionHandler( void *pvExceptionID )\r
-{\r
-extern void *pxCurrentTCB;\r
-\r
- /* Fill an xPortRegisterDump structure with the MicroBlaze context as it\r
- was immediately before the exception occurrence. */\r
- \r
- /* First fill in the name and handle of the task that was in the Running \r
- state when the exception occurred. */\r
- xRegisterDump.xCurrentTaskHandle = pxCurrentTCB;\r
- xRegisterDump.pcCurrentTaskName = pcTaskGetTaskName( NULL );\r
-\r
- configASSERT( pulStackPointerOnFunctionEntry );\r
-\r
- /* Obtain the values of registers that were stacked prior to this function\r
- being called, and may have changed since they were stacked. */
- xRegisterDump.ulR3 = pulStackPointerOnFunctionEntry[ portexR3_STACK_OFFSET ];\r
- xRegisterDump.ulR4 = pulStackPointerOnFunctionEntry[ portexR4_STACK_OFFSET ];\r
- xRegisterDump.ulR5 = pulStackPointerOnFunctionEntry[ portexR5_STACK_OFFSET ];\r
- xRegisterDump.ulR6 = pulStackPointerOnFunctionEntry[ portexR6_STACK_OFFSET ];\r
- xRegisterDump.ulR7 = pulStackPointerOnFunctionEntry[ portexR7_STACK_OFFSET ];\r
- xRegisterDump.ulR8 = pulStackPointerOnFunctionEntry[ portexR8_STACK_OFFSET ];\r
- xRegisterDump.ulR9 = pulStackPointerOnFunctionEntry[ portexR9_STACK_OFFSET ];\r
- xRegisterDump.ulR10 = pulStackPointerOnFunctionEntry[ portexR10_STACK_OFFSET ];\r
- xRegisterDump.ulR11 = pulStackPointerOnFunctionEntry[ portexR11_STACK_OFFSET ];\r
- xRegisterDump.ulR12 = pulStackPointerOnFunctionEntry[ portexR12_STACK_OFFSET ];\r
- xRegisterDump.ulR15_return_address_from_subroutine = pulStackPointerOnFunctionEntry[ portexR15_STACK_OFFSET ];\r
- xRegisterDump.ulR18 = pulStackPointerOnFunctionEntry[ portexR18_STACK_OFFSET ];\r
- xRegisterDump.ulR19 = pulStackPointerOnFunctionEntry[ portexR19_STACK_OFFSET ];\r
- xRegisterDump.ulMSR = pulStackPointerOnFunctionEntry[ portexMSR_STACK_OFFSET ];\r
- \r
- /* Obtain the value of all other registers. */\r
- xRegisterDump.ulR2_small_data_area = mfgpr( R2 );\r
- xRegisterDump.ulR13_read_write_small_data_area = mfgpr( R13 );\r
- xRegisterDump.ulR14_return_address_from_interrupt = mfgpr( R14 );\r
- xRegisterDump.ulR16_return_address_from_trap = mfgpr( R16 );\r
- xRegisterDump.ulR17_return_address_from_exceptions = mfgpr( R17 );\r
- xRegisterDump.ulR20 = mfgpr( R20 );\r
- xRegisterDump.ulR21 = mfgpr( R21 );\r
- xRegisterDump.ulR22 = mfgpr( R22 );\r
- xRegisterDump.ulR23 = mfgpr( R23 );\r
- xRegisterDump.ulR24 = mfgpr( R24 );\r
- xRegisterDump.ulR25 = mfgpr( R25 );\r
- xRegisterDump.ulR26 = mfgpr( R26 );\r
- xRegisterDump.ulR27 = mfgpr( R27 );\r
- xRegisterDump.ulR28 = mfgpr( R28 );\r
- xRegisterDump.ulR29 = mfgpr( R29 );\r
- xRegisterDump.ulR30 = mfgpr( R30 );\r
- xRegisterDump.ulR31 = mfgpr( R31 );\r
- xRegisterDump.ulR1_SP = ( ( unsigned long ) pulStackPointerOnFunctionEntry ) + portexASM_HANDLER_STACK_FRAME_SIZE;\r
- xRegisterDump.ulEAR = mfear();\r
- xRegisterDump.ulESR = mfesr();\r
- xRegisterDump.ulEDR = mfedr();\r
- \r
- /* Move the saved program counter back to the instruction that was executed\r
- when the exception occurred. This is only valid for certain types of\r
- exception. */\r
- xRegisterDump.ulPC = xRegisterDump.ulR17_return_address_from_exceptions - portexINSTRUCTION_SIZE;\r
-\r
- #if XPAR_MICROBLAZE_0_USE_FPU == 1\r
- {\r
- xRegisterDump.ulFSR = mffsr();\r
- }\r
- #else\r
- {\r
- xRegisterDump.ulFSR = 0UL;\r
- }\r
- #endif\r
-\r
- /* Also fill in a string that describes what type of exception this is.\r
- The string uses the same ID names as defined in the MicroBlaze standard\r
- library exception header files. */\r
- switch( ( unsigned long ) pvExceptionID )\r
- {\r
- case XEXC_ID_FSL :\r
- xRegisterDump.pcExceptionCause = ( signed char * const ) "XEXC_ID_FSL";\r
- break;\r
-\r
- case XEXC_ID_UNALIGNED_ACCESS :\r
- xRegisterDump.pcExceptionCause = ( signed char * const ) "XEXC_ID_UNALIGNED_ACCESS";\r
- break;\r
-\r
- case XEXC_ID_ILLEGAL_OPCODE :\r
- xRegisterDump.pcExceptionCause = ( signed char * const ) "XEXC_ID_ILLEGAL_OPCODE";\r
- break;\r
-\r
- case XEXC_ID_M_AXI_I_EXCEPTION :\r
- xRegisterDump.pcExceptionCause = ( signed char * const ) "XEXC_ID_M_AXI_I_EXCEPTION or XEXC_ID_IPLB_EXCEPTION";\r
- break;\r
-\r
- case XEXC_ID_M_AXI_D_EXCEPTION :\r
- xRegisterDump.pcExceptionCause = ( signed char * const ) "XEXC_ID_M_AXI_D_EXCEPTION or XEXC_ID_DPLB_EXCEPTION";\r
- break;\r
-\r
- case XEXC_ID_DIV_BY_ZERO :\r
- xRegisterDump.pcExceptionCause = ( signed char * const ) "XEXC_ID_DIV_BY_ZERO";\r
- break;\r
-\r
- case XEXC_ID_STACK_VIOLATION :\r
- xRegisterDump.pcExceptionCause = ( signed char * const ) "XEXC_ID_STACK_VIOLATION or XEXC_ID_MMU";\r
- break;\r
-\r
- #if XPAR_MICROBLAZE_0_USE_FPU == 1\r
-\r
- case XEXC_ID_FPU :\r
- /*_RB_ More decoding required here and in other exceptions. */\r
- xRegisterDump.pcExceptionCause = ( signed char * const ) "XEXC_ID_FPU see ulFSR value";\r
- break;\r
-\r
- #endif /* XPAR_MICROBLAZE_0_USE_FPU */\r
- }\r
-\r
- /* vApplicationExceptionRegisterDump() is a callback function that the \r
- application can optionally define to receive the populated xPortRegisterDump\r
- structure. If the application chooses not to define a version of \r
- vApplicationExceptionRegisterDump() then the weekly defined default \r
- implementation within this file will be called instead. */\r
- vApplicationExceptionRegisterDump( &xRegisterDump );\r
-\r
- /* Must not attempt to leave this function! */\r
- for( ;; )\r
- {\r
- portNOP();\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vPortExceptionsInstallHandlers( void )\r
-{\r
-static unsigned long ulHandlersAlreadyInstalled = pdFALSE;\r
-\r
- if( ulHandlersAlreadyInstalled == pdFALSE )\r
- {\r
- ulHandlersAlreadyInstalled = pdTRUE;\r
-\r
- #if XPAR_MICROBLAZE_0_UNALIGNED_EXCEPTIONS == 1\r
- microblaze_register_exception_handler( XEXC_ID_UNALIGNED_ACCESS, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_UNALIGNED_ACCESS );\r
- #endif /* XPAR_MICROBLAZE_0_UNALIGNED_EXCEPTIONS*/\r
-\r
- #if XPAR_MICROBLAZE_0_ILL_OPCODE_EXCEPTION == 1\r
- microblaze_register_exception_handler( XEXC_ID_ILLEGAL_OPCODE, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_ILLEGAL_OPCODE );\r
- #endif /* XPAR_MICROBLAZE_0_ILL_OPCODE_EXCEPTION*/\r
-\r
- #if XPAR_MICROBLAZE_0_M_AXI_I_BUS_EXCEPTION == 1\r
- microblaze_register_exception_handler( XEXC_ID_M_AXI_I_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_M_AXI_I_EXCEPTION );\r
- #endif /* XPAR_MICROBLAZE_0_M_AXI_I_BUS_EXCEPTION*/\r
-\r
- #if XPAR_MICROBLAZE_0_M_AXI_D_BUS_EXCEPTION == 1\r
- microblaze_register_exception_handler( XEXC_ID_M_AXI_D_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_M_AXI_D_EXCEPTION );\r
- #endif /* XPAR_MICROBLAZE_0_M_AXI_D_BUS_EXCEPTION*/\r
-\r
- #if XPAR_MICROBLAZE_0_IPLB_BUS_EXCEPTION == 1\r
- microblaze_register_exception_handler( XEXC_ID_IPLB_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_IPLB_EXCEPTION );\r
- #endif /* XPAR_MICROBLAZE_0_IPLB_BUS_EXCEPTION*/\r
-\r
- #if XPAR_MICROBLAZE_0_DPLB_BUS_EXCEPTION == 1\r
- microblaze_register_exception_handler( XEXC_ID_DPLB_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_DPLB_EXCEPTION );\r
- #endif /* XPAR_MICROBLAZE_0_DPLB_BUS_EXCEPTION*/\r
-\r
- #if XPAR_MICROBLAZE_0_DIV_ZERO_EXCEPTION == 1\r
- microblaze_register_exception_handler( XEXC_ID_DIV_BY_ZERO, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_DIV_BY_ZERO );\r
- #endif /* XPAR_MICROBLAZE_0_DIV_ZERO_EXCEPTION*/\r
-\r
- #if XPAR_MICROBLAZE_0_FPU_EXCEPTION == 1\r
- microblaze_register_exception_handler( XEXC_ID_FPU, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_FPU );\r
- #endif /* XPAR_MICROBLAZE_0_FPU_EXCEPTION*/\r
-\r
- #if XPAR_MICROBLAZE_0_FSL_EXCEPTION == 1\r
- microblaze_register_exception_handler( XEXC_ID_FSL, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_FSL );\r
- #endif /* XPAR_MICROBLAZE_0_FSL_EXCEPTION*/\r
- }\r
-}\r
-\r
-/* Exclude the entire file if the MicroBlaze is not configured to handle\r
-exceptions, or the application defined configuration item \r
-configINSTALL_EXCEPTION_HANDLERS is not set to 1. */\r
-#endif /* ( MICROBLAZE_EXCEPTIONS_ENABLED == 1 ) && ( configINSTALL_EXCEPTION_HANDLERS == 1 ) */\r
-\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
-\r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development\r
- tools for C/C++ development, code analysis and test automation.\r
- See http://www.atollic.com\r
-\r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/* FreeRTOS includes. */\r
-#include "FreeRTOSConfig.h"\r
-\r
-/* Xilinx library includes. */\r
-#include "microblaze_exceptions_g.h"\r
-#include "xparameters.h"\r
-\r
-/* The context is oversized to allow functions called from the ISR to write\r
-back into the caller stack. */\r
-#if XPAR_MICROBLAZE_0_USE_FPU == 1\r
- #define portCONTEXT_SIZE 136\r
- #define portMINUS_CONTEXT_SIZE -136\r
-#else\r
- #define portCONTEXT_SIZE 132\r
- #define portMINUS_CONTEXT_SIZE -132\r
-#endif\r
-\r
-/* Offsets from the stack pointer at which saved registers are placed. */\r
-#define portR31_OFFSET 4\r
-#define portR30_OFFSET 8\r
-#define portR29_OFFSET 12\r
-#define portR28_OFFSET 16\r
-#define portR27_OFFSET 20\r
-#define portR26_OFFSET 24\r
-#define portR25_OFFSET 28\r
-#define portR24_OFFSET 32\r
-#define portR23_OFFSET 36\r
-#define portR22_OFFSET 40\r
-#define portR21_OFFSET 44\r
-#define portR20_OFFSET 48\r
-#define portR19_OFFSET 52\r
-#define portR18_OFFSET 56\r
-#define portR17_OFFSET 60\r
-#define portR16_OFFSET 64\r
-#define portR15_OFFSET 68\r
-#define portR14_OFFSET 72\r
-#define portR13_OFFSET 76\r
-#define portR12_OFFSET 80\r
-#define portR11_OFFSET 84\r
-#define portR10_OFFSET 88\r
-#define portR9_OFFSET 92\r
-#define portR8_OFFSET 96\r
-#define portR7_OFFSET 100\r
-#define portR6_OFFSET 104\r
-#define portR5_OFFSET 108\r
-#define portR4_OFFSET 112\r
-#define portR3_OFFSET 116\r
-#define portR2_OFFSET 120\r
-#define portCRITICAL_NESTING_OFFSET 124\r
-#define portMSR_OFFSET 128\r
-#define portFSR_OFFSET 132\r
-\r
- .extern pxCurrentTCB\r
- .extern XIntc_DeviceInterruptHandler\r
- .extern vTaskSwitchContext\r
- .extern uxCriticalNesting\r
- .extern pulISRStack\r
- .extern ulTaskSwitchRequested\r
- .extern vPortExceptionHandler\r
- .extern pulStackPointerOnFunctionEntry\r
-\r
- .global _interrupt_handler\r
- .global VPortYieldASM\r
- .global vPortStartFirstTask\r
- .global vPortExceptionHandlerEntry\r
-\r
-\r
-.macro portSAVE_CONTEXT\r
-\r
- /* Make room for the context on the stack. */\r
- addik r1, r1, portMINUS_CONTEXT_SIZE\r
-\r
- /* Stack general registers. */\r
- swi r31, r1, portR31_OFFSET\r
- swi r30, r1, portR30_OFFSET\r
- swi r29, r1, portR29_OFFSET\r
- swi r28, r1, portR28_OFFSET\r
- swi r27, r1, portR27_OFFSET\r
- swi r26, r1, portR26_OFFSET\r
- swi r25, r1, portR25_OFFSET\r
- swi r24, r1, portR24_OFFSET\r
- swi r23, r1, portR23_OFFSET\r
- swi r22, r1, portR22_OFFSET\r
- swi r21, r1, portR21_OFFSET\r
- swi r20, r1, portR20_OFFSET\r
- swi r19, r1, portR19_OFFSET\r
- swi r18, r1, portR18_OFFSET\r
- swi r17, r1, portR17_OFFSET\r
- swi r16, r1, portR16_OFFSET\r
- swi r15, r1, portR15_OFFSET\r
- /* R14 is saved later as it needs adjustment if a yield is performed. */\r
- swi r13, r1, portR13_OFFSET\r
- swi r12, r1, portR12_OFFSET\r
- swi r11, r1, portR11_OFFSET\r
- swi r10, r1, portR10_OFFSET\r
- swi r9, r1, portR9_OFFSET\r
- swi r8, r1, portR8_OFFSET\r
- swi r7, r1, portR7_OFFSET\r
- swi r6, r1, portR6_OFFSET\r
- swi r5, r1, portR5_OFFSET\r
- swi r4, r1, portR4_OFFSET\r
- swi r3, r1, portR3_OFFSET\r
- swi r2, r1, portR2_OFFSET\r
-\r
- /* Stack the critical section nesting value. */\r
- lwi r18, r0, uxCriticalNesting\r
- swi r18, r1, portCRITICAL_NESTING_OFFSET\r
-\r
- /* Stack MSR. */\r
- mfs r18, rmsr\r
- swi r18, r1, portMSR_OFFSET\r
-\r
- #if XPAR_MICROBLAZE_0_USE_FPU == 1\r
- /* Stack FSR. */\r
- mfs r18, rfsr\r
- swi r18, r1, portFSR_OFFSET\r
- #endif\r
-\r
- /* Save the top of stack value to the TCB. */\r
- lwi r3, r0, pxCurrentTCB\r
- sw r1, r0, r3\r
- \r
- .endm\r
-\r
-.macro portRESTORE_CONTEXT\r
-\r
- /* Load the top of stack value from the TCB. */\r
- lwi r18, r0, pxCurrentTCB\r
- lw r1, r0, r18\r
-\r
- /* Restore the general registers. */\r
- lwi r31, r1, portR31_OFFSET\r
- lwi r30, r1, portR30_OFFSET\r
- lwi r29, r1, portR29_OFFSET\r
- lwi r28, r1, portR28_OFFSET\r
- lwi r27, r1, portR27_OFFSET\r
- lwi r26, r1, portR26_OFFSET\r
- lwi r25, r1, portR25_OFFSET\r
- lwi r24, r1, portR24_OFFSET\r
- lwi r23, r1, portR23_OFFSET\r
- lwi r22, r1, portR22_OFFSET\r
- lwi r21, r1, portR21_OFFSET\r
- lwi r20, r1, portR20_OFFSET\r
- lwi r19, r1, portR19_OFFSET\r
- lwi r17, r1, portR17_OFFSET\r
- lwi r16, r1, portR16_OFFSET\r
- lwi r15, r1, portR15_OFFSET\r
- lwi r14, r1, portR14_OFFSET\r
- lwi r13, r1, portR13_OFFSET\r
- lwi r12, r1, portR12_OFFSET\r
- lwi r11, r1, portR11_OFFSET\r
- lwi r10, r1, portR10_OFFSET\r
- lwi r9, r1, portR9_OFFSET\r
- lwi r8, r1, portR8_OFFSET\r
- lwi r7, r1, portR7_OFFSET\r
- lwi r6, r1, portR6_OFFSET\r
- lwi r5, r1, portR5_OFFSET\r
- lwi r4, r1, portR4_OFFSET\r
- lwi r3, r1, portR3_OFFSET\r
- lwi r2, r1, portR2_OFFSET\r
-\r
- /* Reload the rmsr from the stack. */\r
- lwi r18, r1, portMSR_OFFSET\r
- mts rmsr, r18\r
-\r
- #if XPAR_MICROBLAZE_0_USE_FPU == 1\r
- /* Reload the FSR from the stack. */\r
- lwi r18, r1, portFSR_OFFSET\r
- mts rfsr, r18\r
- #endif\r
-\r
- /* Load the critical nesting value. */\r
- lwi r18, r1, portCRITICAL_NESTING_OFFSET\r
- swi r18, r0, uxCriticalNesting\r
-\r
- /* Test the critical nesting value. If it is non zero then the task last\r
- exited the running state using a yield. If it is zero, then the task\r
- last exited the running state through an interrupt. */\r
- xori r18, r18, 0\r
- bnei r18, exit_from_yield\r
-\r
- /* r18 was being used as a temporary. Now restore its true value from the\r
- stack. */\r
- lwi r18, r1, portR18_OFFSET\r
-\r
- /* Remove the stack frame. */\r
- addik r1, r1, portCONTEXT_SIZE\r
-\r
- /* Return using rtid so interrupts are re-enabled as this function is\r
- exited. */\r
- rtid r14, 0\r
- or r0, r0, r0\r
-\r
- .endm\r
-\r
-/* This function is used to exit portRESTORE_CONTEXT() if the task being\r
-returned to last left the Running state by calling taskYIELD() (rather than\r
-being preempted by an interrupt). */\r
- .text\r
- .align 2\r
-exit_from_yield:\r
-\r
- /* r18 was being used as a temporary. Now restore its true value from the\r
- stack. */\r
- lwi r18, r1, portR18_OFFSET\r
-\r
- /* Remove the stack frame. */\r
- addik r1, r1, portCONTEXT_SIZE\r
-\r
- /* Return to the task. */\r
- rtsd r14, 0\r
- or r0, r0, r0\r
-\r
-\r
- .text\r
- .align 2\r
-_interrupt_handler:\r
-\r
- portSAVE_CONTEXT\r
-\r
- /* Stack the return address. */\r
- swi r14, r1, portR14_OFFSET\r
-\r
- /* Switch to the ISR stack. */\r
- lwi r1, r0, pulISRStack\r
-\r
- /* The parameter to the interrupt handler. */\r
- ori r5, r0, configINTERRUPT_CONTROLLER_TO_USE\r
-\r
- /* Execute any pending interrupts. */\r
- bralid r15, XIntc_DeviceInterruptHandler\r
- or r0, r0, r0\r
-\r
- /* See if a new task should be selected to execute. */\r
- lwi r18, r0, ulTaskSwitchRequested\r
- or r18, r18, r0\r
-\r
- /* If ulTaskSwitchRequested is already zero, then jump straight to\r
- restoring the task that is already in the Running state. */\r
- beqi r18, task_switch_not_requested\r
-\r
- /* Set ulTaskSwitchRequested back to zero as a task switch is about to be\r
- performed. */\r
- swi r0, r0, ulTaskSwitchRequested\r
-\r
- /* ulTaskSwitchRequested was not 0 when tested. Select the next task to\r
- execute. */\r
- bralid r15, vTaskSwitchContext\r
- or r0, r0, r0\r
-\r
-task_switch_not_requested:\r
-\r
- /* Restore the context of the next task scheduled to execute. */\r
- portRESTORE_CONTEXT\r
-\r
-\r
- .text\r
- .align 2\r
-VPortYieldASM:\r
-\r
- portSAVE_CONTEXT\r
-\r
- /* Modify the return address so a return is done to the instruction after\r
- the call to VPortYieldASM. */\r
- addi r14, r14, 8\r
- swi r14, r1, portR14_OFFSET\r
-\r
- /* Switch to use the ISR stack. */\r
- lwi r1, r0, pulISRStack\r
-\r
- /* Select the next task to execute. */\r
- bralid r15, vTaskSwitchContext\r
- or r0, r0, r0\r
-\r
- /* Restore the context of the next task scheduled to execute. */\r
- portRESTORE_CONTEXT\r
-\r
- .text\r
- .align 2\r
-vPortStartFirstTask:\r
-\r
- portRESTORE_CONTEXT\r
- \r
-\r
-\r
-#if MICROBLAZE_EXCEPTIONS_ENABLED == 1\r
- \r
- .text\r
- .align 2\r
-vPortExceptionHandlerEntry:\r
-\r
- /* Take a copy of the stack pointer before vPortExecptionHandler is called,\r
- storing its value prior to the function stack frame being created. */\r
- swi r1, r0, pulStackPointerOnFunctionEntry\r
- bralid r15, vPortExceptionHandler\r
- or r0, r0, r0\r
-\r
-#endif /* MICROBLAZE_EXCEPTIONS_ENABLED */\r
-\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#ifndef PORTMACRO_H\r
-#define PORTMACRO_H\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-/* BSP includes. */\r
-#include <mb_interface.h>\r
-#include <xparameters.h>\r
-\r
-/*-----------------------------------------------------------\r
- * Port specific definitions. \r
- *\r
- * The settings in this file configure FreeRTOS correctly for the\r
- * given hardware and compiler.\r
- *\r
- * These settings should not be altered.\r
- *-----------------------------------------------------------\r
- */\r
-\r
-/* Type definitions. */\r
-#define portCHAR char\r
-#define portFLOAT float\r
-#define portDOUBLE double\r
-#define portLONG long\r
-#define portSHORT short\r
-#define portSTACK_TYPE unsigned long\r
-#define portBASE_TYPE long\r
-\r
-#if( configUSE_16_BIT_TICKS == 1 )\r
- typedef unsigned portSHORT portTickType;\r
- #define portMAX_DELAY ( portTickType ) 0xffff\r
-#else\r
- typedef unsigned portLONG portTickType;\r
- #define portMAX_DELAY ( portTickType ) 0xffffffff\r
-#endif\r
-/*-----------------------------------------------------------*/ \r
-\r
-/* Interrupt control macros and functions. */\r
-void microblaze_disable_interrupts( void );\r
-void microblaze_enable_interrupts( void );\r
-#define portDISABLE_INTERRUPTS() microblaze_disable_interrupts()\r
-#define portENABLE_INTERRUPTS() microblaze_enable_interrupts()\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Critical section macros. */\r
-void vPortEnterCritical( void );\r
-void vPortExitCritical( void );\r
-#define portENTER_CRITICAL() { \\r
- extern volatile unsigned portBASE_TYPE uxCriticalNesting; \\r
- microblaze_disable_interrupts(); \\r
- uxCriticalNesting++; \\r
- }\r
-\r
-#define portEXIT_CRITICAL() { \\r
- extern volatile unsigned portBASE_TYPE uxCriticalNesting; \\r
- /* Interrupts are disabled, so we can */ \\r
- /* access the variable directly. */ \\r
- uxCriticalNesting--; \\r
- if( uxCriticalNesting == 0 ) \\r
- { \\r
- /* The nesting has unwound and we \\r
- can enable interrupts again. */ \\r
- portENABLE_INTERRUPTS(); \\r
- } \\r
- }\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* The yield macro maps directly to the vPortYield() function. */\r
-void vPortYield( void );\r
-#define portYIELD() vPortYield()\r
-\r
-/* portYIELD_FROM_ISR() does not directly call vTaskSwitchContext(), but instead\r
-sets a flag to say that a yield has been requested. The interrupt exit code\r
-then checks this flag, and calls vTaskSwitchContext() before restoring a task\r
-context, if the flag is not false. This is done to prevent multiple calls to\r
-vTaskSwitchContext() being made from a single interrupt, as a single interrupt\r
-can result in multiple peripherals being serviced. */\r
-extern volatile unsigned long ulTaskSwitchRequested;\r
-#define portYIELD_FROM_ISR( x ) if( x != pdFALSE ) ulTaskSwitchRequested = 1\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Hardware specifics. */\r
-#define portBYTE_ALIGNMENT 4\r
-#define portSTACK_GROWTH ( -1 )\r
-#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )\r
-#define portNOP() asm volatile ( "NOP" )\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Task function macros as described on the FreeRTOS.org WEB site. */\r
-#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )\r
-#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )\r
-/*-----------------------------------------------------------*/\r
-\r
-/* The following structure is used by the FreeRTOS exception handler. It is\r
-filled with the MicroBlaze context as it was at the time the exception occurred.\r
-This is done as an aid to debugging exception occurrences. */\r
-typedef struct PORT_REGISTER_DUMP\r
-{\r
- /* The following structure members hold the values of the MicroBlaze\r
- registers at the time the exception was raised. */\r
- unsigned long ulR1_SP;\r
- unsigned long ulR2_small_data_area;\r
- unsigned long ulR3;\r
- unsigned long ulR4;\r
- unsigned long ulR5;\r
- unsigned long ulR6;\r
- unsigned long ulR7;\r
- unsigned long ulR8;\r
- unsigned long ulR9;\r
- unsigned long ulR10;\r
- unsigned long ulR11;\r
- unsigned long ulR12;\r
- unsigned long ulR13_read_write_small_data_area;\r
- unsigned long ulR14_return_address_from_interrupt;\r
- unsigned long ulR15_return_address_from_subroutine;\r
- unsigned long ulR16_return_address_from_trap;\r
- unsigned long ulR17_return_address_from_exceptions; /* The exception entry code will copy the BTR into R17 if the exception occurred in the delay slot of a branch instruction. */\r
- unsigned long ulR18;\r
- unsigned long ulR19;\r
- unsigned long ulR20;\r
- unsigned long ulR21;\r
- unsigned long ulR22;\r
- unsigned long ulR23;\r
- unsigned long ulR24;\r
- unsigned long ulR25;\r
- unsigned long ulR26;\r
- unsigned long ulR27;\r
- unsigned long ulR28;\r
- unsigned long ulR29;\r
- unsigned long ulR30;\r
- unsigned long ulR31;\r
- unsigned long ulPC;\r
- unsigned long ulESR;\r
- unsigned long ulMSR;\r
- unsigned long ulEAR;\r
- unsigned long ulFSR;\r
- unsigned long ulEDR;\r
-\r
- /* A human readable description of the exception cause. The strings used\r
- are the same as the #define constant names found in the\r
- microblaze_exceptions_i.h header file */\r
- signed char *pcExceptionCause;\r
-\r
- /* The human readable name of the task that was running at the time the\r
- exception occurred. This is the name that was given to the task when the\r
- task was created using the FreeRTOS xTaskCreate() API function. */\r
- signed char *pcCurrentTaskName;\r
-\r
- /* The handle of the task that was running a the time the exception\r
- occurred. */\r
- void * xCurrentTaskHandle;\r
-\r
-} xPortRegisterDump;\r
-\r
-\r
-/*\r
- * Installs pxHandler as the interrupt handler for the peripheral specified by \r
- * the ucInterruptID parameter.\r
- *\r
- * ucInterruptID:\r
- * \r
- * The ID of the peripheral that will have pxHandler assigned as its interrupt\r
- * handler. Peripheral IDs are defined in the xparameters.h header file, which \r
- * is itself part of the BSP project. For example, in the official demo \r
- * application for this port, xparameters.h defines the following IDs for the \r
- * four possible interrupt sources:\r
- *\r
- * XPAR_INTC_0_UARTLITE_1_VEC_ID - for the UARTlite peripheral.\r
- * XPAR_INTC_0_TMRCTR_0_VEC_ID - for the AXI Timer 0 peripheral.\r
- * XPAR_INTC_0_EMACLITE_0_VEC_ID - for the Ethernet lite peripheral.\r
- * XPAR_INTC_0_GPIO_1_VEC_ID - for the button inputs.\r
- *\r
- *\r
- * pxHandler:\r
- * \r
- * A pointer to the interrupt handler function itself. This must be a void\r
- * function that takes a (void *) parameter.\r
- *\r
- *\r
- * pvCallBackRef:\r
- *\r
- * The parameter passed into the handler function. In many cases this will not\r
- * be used and can be NULL. Some times it is used to pass in a reference to\r
- * the peripheral instance variable, so it can be accessed from inside the\r
- * handler function.\r
- *\r
- * \r
- * pdPASS is returned if the function executes successfully. Any other value\r
- * being returned indicates that the function did not execute correctly.\r
- */\r
-portBASE_TYPE xPortInstallInterruptHandler( unsigned char ucInterruptID, XInterruptHandler pxHandler, void *pvCallBackRef );\r
-\r
-\r
-/*\r
- * Enables the interrupt, within the interrupt controller, for the peripheral \r
- * specified by the ucInterruptID parameter.\r
- *\r
- * ucInterruptID:\r
- * \r
- * The ID of the peripheral that will have its interrupt enabled in the\r
- * interrupt controller. Peripheral IDs are defined in the xparameters.h header \r
- * file, which is itself part of the BSP project. For example, in the official \r
- * demo application for this port, xparameters.h defines the following IDs for \r
- * the four possible interrupt sources:\r
- *\r
- * XPAR_INTC_0_UARTLITE_1_VEC_ID - for the UARTlite peripheral.\r
- * XPAR_INTC_0_TMRCTR_0_VEC_ID - for the AXI Timer 0 peripheral.\r
- * XPAR_INTC_0_EMACLITE_0_VEC_ID - for the Ethernet lite peripheral.\r
- * XPAR_INTC_0_GPIO_1_VEC_ID - for the button inputs.\r
- *\r
- */\r
-void vPortEnableInterrupt( unsigned char ucInterruptID );\r
-\r
-/*\r
- * Disables the interrupt, within the interrupt controller, for the peripheral \r
- * specified by the ucInterruptID parameter.\r
- *\r
- * ucInterruptID:\r
- * \r
- * The ID of the peripheral that will have its interrupt disabled in the\r
- * interrupt controller. Peripheral IDs are defined in the xparameters.h header \r
- * file, which is itself part of the BSP project. For example, in the official \r
- * demo application for this port, xparameters.h defines the following IDs for \r
- * the four possible interrupt sources:\r
- *\r
- * XPAR_INTC_0_UARTLITE_1_VEC_ID - for the UARTlite peripheral.\r
- * XPAR_INTC_0_TMRCTR_0_VEC_ID - for the AXI Timer 0 peripheral.\r
- * XPAR_INTC_0_EMACLITE_0_VEC_ID - for the Ethernet lite peripheral.\r
- * XPAR_INTC_0_GPIO_1_VEC_ID - for the button inputs.\r
- *\r
- */\r
-void vPortDisableInterrupt( unsigned char ucInterruptID );\r
-\r
-/*\r
- * This is an application defined callback function used to install the tick\r
- * interrupt handler. It is provided as an application callback because the \r
- * kernel will run on lots of different MicroBlaze and FPGA configurations - not \r
- * all of which will have the same timer peripherals defined or available. This \r
- * example uses the AXI Timer 0. If that is available on your hardware platform \r
- * then this example callback implementation should not require modification. \r
- * The name of the interrupt handler that should be installed is vPortTickISR(), \r
- * which the function below declares as an extern.\r
- */ \r
-void vApplicationSetupTimerInterrupt( void );\r
-\r
-/* \r
- * This is an application defined callback function used to clear whichever\r
- * interrupt was installed by the the vApplicationSetupTimerInterrupt() callback\r
- * function - in this case the interrupt generated by the AXI timer. It is \r
- * provided as an application callback because the kernel will run on lots of \r
- * different MicroBlaze and FPGA configurations - not all of which will have the \r
- * same timer peripherals defined or available. This example uses the AXI Timer 0. \r
- * If that is available on your hardware platform then this example callback \r
- * implementation should not require modification provided the example definition\r
- * of vApplicationSetupTimerInterrupt() is also not modified. \r
- */\r
-void vApplicationClearTimerInterrupt( void );\r
-\r
-/*\r
- * vPortExceptionsInstallHandlers() is only available when the MicroBlaze\r
- * is configured to include exception functionality, and \r
- * configINSTALL_EXCEPTION_HANDLERS is set to 1 in FreeRTOSConfig.h.\r
- *\r
- * vPortExceptionsInstallHandlers() installs the FreeRTOS exception handler\r
- * for every possible exception cause. \r
- *\r
- * vPortExceptionsInstallHandlers() can be called explicitly from application\r
- * code. After that is done, the default FreeRTOS exception handler that will\r
- * have been installed can be replaced for any specific exception cause by using \r
- * the standard Xilinx library function microblaze_register_exception_handler().\r
- *\r
- * If vPortExceptionsInstallHandlers() is not called explicitly by the \r
- * application, it will be called automatically by the kernel the first time\r
- * xPortInstallInterruptHandler() is called. At that time, any exception \r
- * handlers that may have already been installed will be replaced.\r
- *\r
- * See the description of vApplicationExceptionRegisterDump() for information\r
- * on the processing performed by the FreeRTOS exception handler.\r
- */\r
-void vPortExceptionsInstallHandlers( void );\r
-\r
-/*\r
- * The FreeRTOS exception handler fills an xPortRegisterDump structure (defined \r
- * in portmacro.h) with the MicroBlaze context, as it was at the time the \r
- * exception occurred. The exception handler then calls\r
- * vApplicationExceptionRegisterDump(), passing in the completed\r
- * xPortRegisterDump structure as its parameter.\r
- *\r
- * The FreeRTOS kernel provides its own implementation of\r
- * vApplicationExceptionRegisterDump(), but the kernel provided implementation \r
- * is declared as being 'weak'. The weak definition allows the application \r
- * writer to provide their own implementation, should they wish to use the \r
- * register dump information. For example, an implementation could be provided\r
- * that wrote the register dump data to a display, or a UART port.\r
- */\r
-void vApplicationExceptionRegisterDump( xPortRegisterDump *xRegisterDump );\r
-\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-\r
-#endif /* PORTMACRO_H */\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/*\r
- * A sample implementation of pvPortMalloc() and vPortFree() that permits\r
- * allocated blocks to be freed, but does not combine adjacent free blocks\r
- * into a single larger block.\r
- *\r
- * See heap_1.c and heap_3.c for alternative implementations, and the memory\r
- * management pages of http://www.FreeRTOS.org for more information.\r
- */\r
-#include <stdlib.h>\r
-\r
-/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
-all the API functions to use the MPU wrappers. That should only be done when\r
-task.h is included from an application file. */\r
-#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
-\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-\r
-#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
-\r
-/* Allocate the memory for the heap. The struct is used to force byte\r
-alignment without using any non-portable code. */\r
-static union xRTOS_HEAP\r
-{\r
- #if portBYTE_ALIGNMENT == 8\r
- volatile portDOUBLE dDummy;\r
- #else\r
- volatile unsigned long ulDummy;\r
- #endif\r
- unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];\r
-} xHeap;\r
-\r
-/* Define the linked list structure. This is used to link free blocks in order\r
-of their size. */\r
-typedef struct A_BLOCK_LINK\r
-{\r
- struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */\r
- size_t xBlockSize; /*<< The size of the free block. */\r
-} xBlockLink;\r
-\r
-\r
-static const unsigned short heapSTRUCT_SIZE = ( sizeof( xBlockLink ) + portBYTE_ALIGNMENT - ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) );\r
-#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )\r
-\r
-/* Create a couple of list links to mark the start and end of the list. */\r
-static xBlockLink xStart, xEnd;\r
-\r
-/* Keeps track of the number of free bytes remaining, but says nothing about\r
-fragmentation. */\r
-static size_t xFreeBytesRemaining = configTOTAL_HEAP_SIZE;\r
-\r
-/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */\r
-\r
-/*\r
- * Insert a block into the list of free blocks - which is ordered by size of\r
- * the block. Small blocks at the start of the list and large blocks at the end\r
- * of the list.\r
- */\r
-#define prvInsertBlockIntoFreeList( pxBlockToInsert ) \\r
-{ \\r
-xBlockLink *pxIterator; \\r
-size_t xBlockSize; \\r
- \\r
- xBlockSize = pxBlockToInsert->xBlockSize; \\r
- \\r
- /* Iterate through the list until a block is found that has a larger size */ \\r
- /* than the block we are inserting. */ \\r
- for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \\r
- { \\r
- /* There is nothing to do here - just iterate to the correct position. */ \\r
- } \\r
- \\r
- /* Update the list to include the block being inserted in the correct */ \\r
- /* position. */ \\r
- pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \\r
- pxIterator->pxNextFreeBlock = pxBlockToInsert; \\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#define prvHeapInit() \\r
-{ \\r
-xBlockLink *pxFirstFreeBlock; \\r
- \\r
- /* xStart is used to hold a pointer to the first item in the list of free */ \\r
- /* blocks. The void cast is used to prevent compiler warnings. */ \\r
- xStart.pxNextFreeBlock = ( void * ) xHeap.ucHeap; \\r
- xStart.xBlockSize = ( size_t ) 0; \\r
- \\r
- /* xEnd is used to mark the end of the list of free blocks. */ \\r
- xEnd.xBlockSize = configTOTAL_HEAP_SIZE; \\r
- xEnd.pxNextFreeBlock = NULL; \\r
- \\r
- /* To start with there is a single free block that is sized to take up the \\r
- entire heap space. */ \\r
- pxFirstFreeBlock = ( void * ) xHeap.ucHeap; \\r
- pxFirstFreeBlock->xBlockSize = configTOTAL_HEAP_SIZE; \\r
- pxFirstFreeBlock->pxNextFreeBlock = &xEnd; \\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void *pvPortMalloc( size_t xWantedSize )\r
-{\r
-xBlockLink *pxBlock, *pxPreviousBlock, *pxNewBlockLink;\r
-static portBASE_TYPE xHeapHasBeenInitialised = pdFALSE;\r
-void *pvReturn = NULL;\r
-\r
- vTaskSuspendAll();\r
- {\r
- /* If this is the first call to malloc then the heap will require\r
- initialisation to setup the list of free blocks. */\r
- if( xHeapHasBeenInitialised == pdFALSE )\r
- {\r
- prvHeapInit();\r
- xHeapHasBeenInitialised = pdTRUE;\r
- }\r
-\r
- /* The wanted size is increased so it can contain a xBlockLink\r
- structure in addition to the requested amount of bytes. */\r
- if( xWantedSize > 0 )\r
- {\r
- xWantedSize += heapSTRUCT_SIZE;\r
-\r
- /* Ensure that blocks are always aligned to the required number of bytes. */\r
- if( xWantedSize & portBYTE_ALIGNMENT_MASK )\r
- {\r
- /* Byte alignment required. */\r
- xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );\r
- }\r
- }\r
-\r
- if( ( xWantedSize > 0 ) && ( xWantedSize < configTOTAL_HEAP_SIZE ) )\r
- {\r
- /* Blocks are stored in byte order - traverse the list from the start\r
- (smallest) block until one of adequate size is found. */\r
- pxPreviousBlock = &xStart;\r
- pxBlock = xStart.pxNextFreeBlock;\r
- while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock ) )\r
- {\r
- pxPreviousBlock = pxBlock;\r
- pxBlock = pxBlock->pxNextFreeBlock;\r
- }\r
-\r
- /* If we found the end marker then a block of adequate size was not found. */\r
- if( pxBlock != &xEnd )\r
- {\r
- /* Return the memory space - jumping over the xBlockLink structure\r
- at its start. */\r
- pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );\r
-\r
- /* This block is being returned for use so must be taken our of the\r
- list of free blocks. */\r
- pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;\r
-\r
- /* If the block is larger than required it can be split into two. */\r
- if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )\r
- {\r
- /* This block is to be split into two. Create a new block\r
- following the number of bytes requested. The void cast is\r
- used to prevent byte alignment warnings from the compiler. */\r
- pxNewBlockLink = ( void * ) ( ( ( unsigned char * ) pxBlock ) + xWantedSize );\r
-\r
- /* Calculate the sizes of two blocks split from the single\r
- block. */\r
- pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;\r
- pxBlock->xBlockSize = xWantedSize;\r
-\r
- /* Insert the new block into the list of free blocks. */\r
- prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );\r
- }\r
- \r
- xFreeBytesRemaining -= pxBlock->xBlockSize;\r
- }\r
- }\r
- }\r
- xTaskResumeAll();\r
-\r
- #if( configUSE_MALLOC_FAILED_HOOK == 1 )\r
- {\r
- if( pvReturn == NULL )\r
- {\r
- extern void vApplicationMallocFailedHook( void );\r
- vApplicationMallocFailedHook();\r
- }\r
- }\r
- #endif\r
-\r
- return pvReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vPortFree( void *pv )\r
-{\r
-unsigned char *puc = ( unsigned char * ) pv;\r
-xBlockLink *pxLink;\r
-\r
- if( pv )\r
- {\r
- /* The memory being freed will have an xBlockLink structure immediately\r
- before it. */\r
- puc -= heapSTRUCT_SIZE;\r
-\r
- /* This casting is to keep the compiler from issuing warnings. */\r
- pxLink = ( void * ) puc;\r
-\r
- vTaskSuspendAll();\r
- {\r
- /* Add this block to the list of free blocks. */\r
- prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) );\r
- xFreeBytesRemaining += pxLink->xBlockSize;\r
- }\r
- xTaskResumeAll();\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-size_t xPortGetFreeHeapSize( void )\r
-{\r
- return xFreeBytesRemaining;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vPortInitialiseBlocks( void )\r
-{\r
- /* This just exists to keep the linker quiet. */\r
-}\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-#include <stdlib.h>\r
-#include <string.h>\r
-\r
-/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
-all the API functions to use the MPU wrappers. That should only be done when\r
-task.h is included from an application file. */\r
-#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
-\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "croutine.h"\r
-\r
-#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
-\r
-/*-----------------------------------------------------------\r
- * PUBLIC LIST API documented in list.h\r
- *----------------------------------------------------------*/\r
-\r
-/* Constants used with the cRxLock and cTxLock structure members. */\r
-#define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )\r
-#define queueLOCKED_UNMODIFIED ( ( signed portBASE_TYPE ) 0 )\r
-\r
-#define queueERRONEOUS_UNBLOCK ( -1 )\r
-\r
-/* For internal use only. */\r
-#define queueSEND_TO_BACK ( 0 )\r
-#define queueSEND_TO_FRONT ( 1 )\r
-\r
-/* Effectively make a union out of the xQUEUE structure. */\r
-#define pxMutexHolder pcTail\r
-#define uxQueueType pcHead\r
-#define uxRecursiveCallCount pcReadFrom\r
-#define queueQUEUE_IS_MUTEX NULL\r
-\r
-/* Semaphores do not actually store or copy data, so have an items size of\r
-zero. */\r
-#define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( 0 )\r
-#define queueDONT_BLOCK ( ( portTickType ) 0 )\r
-#define queueMUTEX_GIVE_BLOCK_TIME ( ( portTickType ) 0 )\r
-\r
-/*\r
- * Definition of the queue used by the scheduler.\r
- * Items are queued by copy, not reference.\r
- */\r
-typedef struct QueueDefinition\r
-{\r
- signed char *pcHead; /*< Points to the beginning of the queue storage area. */\r
- signed char *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */\r
-\r
- signed char *pcWriteTo; /*< Points to the free next place in the storage area. */\r
- signed char *pcReadFrom; /*< Points to the last place that a queued item was read from. */\r
-\r
- xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */\r
- xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */\r
-\r
- volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */\r
- unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */\r
- unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */\r
-\r
- signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */\r
- signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */\r
-\r
-} xQUEUE;\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Inside this file xQueueHandle is a pointer to a xQUEUE structure.\r
- * To keep the definition private the API header file defines it as a\r
- * pointer to void.\r
- */\r
-typedef xQUEUE * xQueueHandle;\r
-\r
-/*\r
- * Prototypes for public functions are included here so we don't have to\r
- * include the API header file (as it defines xQueueHandle differently). These\r
- * functions are documented in the API header file.\r
- */\r
-xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize ) PRIVILEGED_FUNCTION;\r
-signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;\r
-unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
-void vQueueDelete( xQueueHandle xQueue ) PRIVILEGED_FUNCTION;\r
-signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;\r
-signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) PRIVILEGED_FUNCTION;\r
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken ) PRIVILEGED_FUNCTION;\r
-xQueueHandle xQueueCreateMutex( void ) PRIVILEGED_FUNCTION;\r
-xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount ) PRIVILEGED_FUNCTION;\r
-portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime ) PRIVILEGED_FUNCTION;\r
-portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex ) PRIVILEGED_FUNCTION;\r
-signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION;\r
-signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) PRIVILEGED_FUNCTION;\r
-signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
-signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
-unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
-void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Co-routine queue functions differ from task queue functions. Co-routines are\r
- * an optional component.\r
- */\r
-#if configUSE_CO_ROUTINES == 1\r
- signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ) PRIVILEGED_FUNCTION;\r
- signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken ) PRIVILEGED_FUNCTION;\r
- signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;\r
- signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;\r
-#endif\r
-\r
-/*\r
- * The queue registry is just a means for kernel aware debuggers to locate\r
- * queue structures. It has no other purpose so is an optional component.\r
- */\r
-#if configQUEUE_REGISTRY_SIZE > 0\r
-\r
- /* The type stored within the queue registry array. This allows a name\r
- to be assigned to each queue making kernel aware debugging a little\r
- more user friendly. */\r
- typedef struct QUEUE_REGISTRY_ITEM\r
- {\r
- signed char *pcQueueName;\r
- xQueueHandle xHandle;\r
- } xQueueRegistryItem;\r
-\r
- /* The queue registry is simply an array of xQueueRegistryItem structures.\r
- The pcQueueName member of a structure being NULL is indicative of the\r
- array position being vacant. */\r
- xQueueRegistryItem xQueueRegistry[ configQUEUE_REGISTRY_SIZE ];\r
-\r
- /* Removes a queue from the registry by simply setting the pcQueueName\r
- member to NULL. */\r
- static void vQueueUnregisterQueue( xQueueHandle xQueue ) PRIVILEGED_FUNCTION;\r
- void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName ) PRIVILEGED_FUNCTION;\r
-#endif\r
-\r
-/*\r
- * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not\r
- * prevent an ISR from adding or removing items to the queue, but does prevent\r
- * an ISR from removing tasks from the queue event lists. If an ISR finds a\r
- * queue is locked it will instead increment the appropriate queue lock count\r
- * to indicate that a task may require unblocking. When the queue in unlocked\r
- * these lock counts are inspected, and the appropriate action taken.\r
- */\r
-static void prvUnlockQueue( xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Uses a critical section to determine if there is any data in a queue.\r
- *\r
- * @return pdTRUE if the queue contains no items, otherwise pdFALSE.\r
- */\r
-static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Uses a critical section to determine if there is any space in a queue.\r
- *\r
- * @return pdTRUE if there is no space, otherwise pdFALSE;\r
- */\r
-static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Copies an item into the queue, either at the front of the queue or the\r
- * back of the queue.\r
- */\r
-static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Copies an item out of a queue.\r
- */\r
-static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) PRIVILEGED_FUNCTION;\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Macro to mark a queue as locked. Locking a queue prevents an ISR from\r
- * accessing the queue event lists.\r
- */\r
-#define prvLockQueue( pxQueue ) \\r
- taskENTER_CRITICAL(); \\r
- { \\r
- if( ( pxQueue )->xRxLock == queueUNLOCKED ) \\r
- { \\r
- ( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED; \\r
- } \\r
- if( ( pxQueue )->xTxLock == queueUNLOCKED ) \\r
- { \\r
- ( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED; \\r
- } \\r
- } \\r
- taskEXIT_CRITICAL()\r
-/*-----------------------------------------------------------*/\r
-\r
-\r
-/*-----------------------------------------------------------\r
- * PUBLIC QUEUE MANAGEMENT API documented in queue.h\r
- *----------------------------------------------------------*/\r
-\r
-xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )\r
-{\r
-xQUEUE *pxNewQueue;\r
-size_t xQueueSizeInBytes;\r
-xQueueHandle xReturn = NULL;\r
-\r
- /* Allocate the new queue structure. */\r
- if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
- if( pxNewQueue != NULL )\r
- {\r
- /* Create the list of pointers to queue items. The queue is one byte\r
- longer than asked for to make wrap checking easier/faster. */\r
- xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;\r
-\r
- pxNewQueue->pcHead = ( signed char * ) pvPortMalloc( xQueueSizeInBytes );\r
- if( pxNewQueue->pcHead != NULL )\r
- {\r
- /* Initialise the queue members as described above where the\r
- queue type is defined. */\r
- pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );\r
- pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U;\r
- pxNewQueue->pcWriteTo = pxNewQueue->pcHead;\r
- pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - ( unsigned portBASE_TYPE ) 1U ) * uxItemSize );\r
- pxNewQueue->uxLength = uxQueueLength;\r
- pxNewQueue->uxItemSize = uxItemSize;\r
- pxNewQueue->xRxLock = queueUNLOCKED;\r
- pxNewQueue->xTxLock = queueUNLOCKED;\r
-\r
- /* Likewise ensure the event queues start with the correct state. */\r
- vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
- vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
-\r
- traceQUEUE_CREATE( pxNewQueue );\r
- xReturn = pxNewQueue;\r
- }\r
- else\r
- {\r
- traceQUEUE_CREATE_FAILED();\r
- vPortFree( pxNewQueue );\r
- }\r
- }\r
- }\r
-\r
- configASSERT( xReturn );\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( configUSE_MUTEXES == 1 )\r
-\r
- xQueueHandle xQueueCreateMutex( void )\r
- {\r
- xQUEUE *pxNewQueue;\r
-\r
- /* Allocate the new queue structure. */\r
- pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
- if( pxNewQueue != NULL )\r
- {\r
- /* Information required for priority inheritance. */\r
- pxNewQueue->pxMutexHolder = NULL;\r
- pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;\r
-\r
- /* Queues used as a mutex no data is actually copied into or out\r
- of the queue. */\r
- pxNewQueue->pcWriteTo = NULL;\r
- pxNewQueue->pcReadFrom = NULL;\r
-\r
- /* Each mutex has a length of 1 (like a binary semaphore) and\r
- an item size of 0 as nothing is actually copied into or out\r
- of the mutex. */\r
- pxNewQueue->uxMessagesWaiting = ( unsigned portBASE_TYPE ) 0U;\r
- pxNewQueue->uxLength = ( unsigned portBASE_TYPE ) 1U;\r
- pxNewQueue->uxItemSize = ( unsigned portBASE_TYPE ) 0U;\r
- pxNewQueue->xRxLock = queueUNLOCKED;\r
- pxNewQueue->xTxLock = queueUNLOCKED;\r
-\r
- /* Ensure the event queues start with the correct state. */\r
- vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
- vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
-\r
- /* Start with the semaphore in the expected state. */\r
- xQueueGenericSend( pxNewQueue, NULL, ( portTickType ) 0U, queueSEND_TO_BACK );\r
-\r
- traceCREATE_MUTEX( pxNewQueue );\r
- }\r
- else\r
- {\r
- traceCREATE_MUTEX_FAILED();\r
- }\r
-\r
- configASSERT( pxNewQueue );\r
- return pxNewQueue;\r
- }\r
-\r
-#endif /* configUSE_MUTEXES */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configUSE_RECURSIVE_MUTEXES == 1\r
-\r
- portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex )\r
- {\r
- portBASE_TYPE xReturn;\r
-\r
- configASSERT( pxMutex );\r
-\r
- /* If this is the task that holds the mutex then pxMutexHolder will not\r
- change outside of this task. If this task does not hold the mutex then\r
- pxMutexHolder can never coincidentally equal the tasks handle, and as\r
- this is the only condition we are interested in it does not matter if\r
- pxMutexHolder is accessed simultaneously by another task. Therefore no\r
- mutual exclusion is required to test the pxMutexHolder variable. */\r
- if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )\r
- {\r
- traceGIVE_MUTEX_RECURSIVE( pxMutex );\r
-\r
- /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to\r
- the task handle, therefore no underflow check is required. Also,\r
- uxRecursiveCallCount is only modified by the mutex holder, and as\r
- there can only be one, no mutual exclusion is required to modify the\r
- uxRecursiveCallCount member. */\r
- ( pxMutex->uxRecursiveCallCount )--;\r
-\r
- /* Have we unwound the call count? */\r
- if( pxMutex->uxRecursiveCallCount == 0 )\r
- {\r
- /* Return the mutex. This will automatically unblock any other\r
- task that might be waiting to access the mutex. */\r
- xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );\r
- }\r
-\r
- xReturn = pdPASS;\r
- }\r
- else\r
- {\r
- /* We cannot give the mutex because we are not the holder. */\r
- xReturn = pdFAIL;\r
-\r
- traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );\r
- }\r
-\r
- return xReturn;\r
- }\r
-\r
-#endif /* configUSE_RECURSIVE_MUTEXES */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configUSE_RECURSIVE_MUTEXES == 1\r
-\r
- portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime )\r
- {\r
- portBASE_TYPE xReturn;\r
-\r
- configASSERT( pxMutex );\r
-\r
- /* Comments regarding mutual exclusion as per those within\r
- xQueueGiveMutexRecursive(). */\r
-\r
- traceTAKE_MUTEX_RECURSIVE( pxMutex );\r
-\r
- if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )\r
- {\r
- ( pxMutex->uxRecursiveCallCount )++;\r
- xReturn = pdPASS;\r
- }\r
- else\r
- {\r
- xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE );\r
-\r
- /* pdPASS will only be returned if we successfully obtained the mutex,\r
- we may have blocked to reach here. */\r
- if( xReturn == pdPASS )\r
- {\r
- ( pxMutex->uxRecursiveCallCount )++;\r
- }\r
- else\r
- {\r
- traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex );\r
- }\r
- }\r
-\r
- return xReturn;\r
- }\r
-\r
-#endif /* configUSE_RECURSIVE_MUTEXES */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configUSE_COUNTING_SEMAPHORES == 1\r
-\r
- xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount )\r
- {\r
- xQueueHandle pxHandle;\r
-\r
- pxHandle = xQueueCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH );\r
-\r
- if( pxHandle != NULL )\r
- {\r
- pxHandle->uxMessagesWaiting = uxInitialCount;\r
-\r
- traceCREATE_COUNTING_SEMAPHORE();\r
- }\r
- else\r
- {\r
- traceCREATE_COUNTING_SEMAPHORE_FAILED();\r
- }\r
-\r
- configASSERT( pxHandle );\r
- return pxHandle;\r
- }\r
-\r
-#endif /* configUSE_COUNTING_SEMAPHORES */\r
-/*-----------------------------------------------------------*/\r
-\r
-signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\r
-{\r
-signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
-xTimeOutType xTimeOut;\r
-\r
- configASSERT( pxQueue );\r
- configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
-\r
- /* This function relaxes the coding standard somewhat to allow return\r
- statements within the function itself. This is done in the interest\r
- of execution time efficiency. */\r
- for( ;; )\r
- {\r
- taskENTER_CRITICAL();\r
- {\r
- /* Is there room on the queue now? To be running we must be\r
- the highest priority task wanting to access the queue. */\r
- if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
- {\r
- traceQUEUE_SEND( pxQueue );\r
- prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
-\r
- /* If there was a task waiting for data to arrive on the\r
- queue then unblock it now. */\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
- {\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
- {\r
- /* The unblocked task has a priority higher than\r
- our own so yield immediately. Yes it is ok to do\r
- this from within the critical section - the kernel\r
- takes care of that. */\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
-\r
- taskEXIT_CRITICAL();\r
-\r
- /* Return to the original privilege level before exiting the\r
- function. */\r
- return pdPASS;\r
- }\r
- else\r
- {\r
- if( xTicksToWait == ( portTickType ) 0 )\r
- {\r
- /* The queue was full and no block time is specified (or\r
- the block time has expired) so leave now. */\r
- taskEXIT_CRITICAL();\r
-\r
- /* Return to the original privilege level before exiting\r
- the function. */\r
- traceQUEUE_SEND_FAILED( pxQueue );\r
- return errQUEUE_FULL;\r
- }\r
- else if( xEntryTimeSet == pdFALSE )\r
- {\r
- /* The queue was full and a block time was specified so\r
- configure the timeout structure. */\r
- vTaskSetTimeOutState( &xTimeOut );\r
- xEntryTimeSet = pdTRUE;\r
- }\r
- }\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- /* Interrupts and other tasks can send to and receive from the queue\r
- now the critical section has been exited. */\r
-\r
- vTaskSuspendAll();\r
- prvLockQueue( pxQueue );\r
-\r
- /* Update the timeout state to see if it has expired yet. */\r
- if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
- {\r
- if( prvIsQueueFull( pxQueue ) )\r
- {\r
- traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
- vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
-\r
- /* Unlocking the queue means queue events can effect the\r
- event list. It is possible that interrupts occurring now\r
- remove this task from the event list again - but as the\r
- scheduler is suspended the task will go onto the pending\r
- ready last instead of the actual ready list. */\r
- prvUnlockQueue( pxQueue );\r
-\r
- /* Resuming the scheduler will move tasks from the pending\r
- ready list into the ready list - so it is feasible that this\r
- task is already in a ready list before it yields - in which\r
- case the yield will not cause a context switch unless there\r
- is also a higher priority task in the pending ready list. */\r
- if( !xTaskResumeAll() )\r
- {\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- else\r
- {\r
- /* Try again. */\r
- prvUnlockQueue( pxQueue );\r
- ( void ) xTaskResumeAll();\r
- }\r
- }\r
- else\r
- {\r
- /* The timeout has expired. */\r
- prvUnlockQueue( pxQueue );\r
- ( void ) xTaskResumeAll();\r
-\r
- /* Return to the original privilege level before exiting the\r
- function. */\r
- traceQUEUE_SEND_FAILED( pxQueue );\r
- return errQUEUE_FULL;\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configUSE_ALTERNATIVE_API == 1\r
-\r
- signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\r
- {\r
- signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
- xTimeOutType xTimeOut;\r
-\r
- configASSERT( pxQueue );\r
- configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
-\r
- for( ;; )\r
- {\r
- taskENTER_CRITICAL();\r
- {\r
- /* Is there room on the queue now? To be running we must be\r
- the highest priority task wanting to access the queue. */\r
- if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
- {\r
- traceQUEUE_SEND( pxQueue );\r
- prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
-\r
- /* If there was a task waiting for data to arrive on the\r
- queue then unblock it now. */\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
- {\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
- {\r
- /* The unblocked task has a priority higher than\r
- our own so yield immediately. */\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
-\r
- taskEXIT_CRITICAL();\r
- return pdPASS;\r
- }\r
- else\r
- {\r
- if( xTicksToWait == ( portTickType ) 0 )\r
- {\r
- taskEXIT_CRITICAL();\r
- return errQUEUE_FULL;\r
- }\r
- else if( xEntryTimeSet == pdFALSE )\r
- {\r
- vTaskSetTimeOutState( &xTimeOut );\r
- xEntryTimeSet = pdTRUE;\r
- }\r
- }\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- taskENTER_CRITICAL();\r
- {\r
- if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
- {\r
- if( prvIsQueueFull( pxQueue ) )\r
- {\r
- traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
- vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- else\r
- {\r
- taskEXIT_CRITICAL();\r
- traceQUEUE_SEND_FAILED( pxQueue );\r
- return errQUEUE_FULL;\r
- }\r
- }\r
- taskEXIT_CRITICAL();\r
- }\r
- }\r
-\r
-#endif /* configUSE_ALTERNATIVE_API */\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configUSE_ALTERNATIVE_API == 1\r
-\r
- signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
- {\r
- signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
- xTimeOutType xTimeOut;\r
- signed char *pcOriginalReadPosition;\r
-\r
- configASSERT( pxQueue );\r
- configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
-\r
- for( ;; )\r
- {\r
- taskENTER_CRITICAL();\r
- {\r
- if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- /* Remember our read position in case we are just peeking. */\r
- pcOriginalReadPosition = pxQueue->pcReadFrom;\r
-\r
- prvCopyDataFromQueue( pxQueue, pvBuffer );\r
-\r
- if( xJustPeeking == pdFALSE )\r
- {\r
- traceQUEUE_RECEIVE( pxQueue );\r
-\r
- /* We are actually removing data. */\r
- --( pxQueue->uxMessagesWaiting );\r
-\r
- #if ( configUSE_MUTEXES == 1 )\r
- {\r
- if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
- {\r
- /* Record the information required to implement\r
- priority inheritance should it become necessary. */\r
- pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
- }\r
- }\r
- #endif\r
-\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
- {\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
- {\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- }\r
- else\r
- {\r
- traceQUEUE_PEEK( pxQueue );\r
-\r
- /* We are not removing the data, so reset our read\r
- pointer. */\r
- pxQueue->pcReadFrom = pcOriginalReadPosition;\r
-\r
- /* The data is being left in the queue, so see if there are\r
- any other tasks waiting for the data. */\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
- {\r
- /* Tasks that are removed from the event list will get added to\r
- the pending ready list as the scheduler is still suspended. */\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
- {\r
- /* The task waiting has a higher priority than this task. */\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
-\r
- }\r
-\r
- taskEXIT_CRITICAL();\r
- return pdPASS;\r
- }\r
- else\r
- {\r
- if( xTicksToWait == ( portTickType ) 0 )\r
- {\r
- taskEXIT_CRITICAL();\r
- traceQUEUE_RECEIVE_FAILED( pxQueue );\r
- return errQUEUE_EMPTY;\r
- }\r
- else if( xEntryTimeSet == pdFALSE )\r
- {\r
- vTaskSetTimeOutState( &xTimeOut );\r
- xEntryTimeSet = pdTRUE;\r
- }\r
- }\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- taskENTER_CRITICAL();\r
- {\r
- if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
- {\r
- if( prvIsQueueEmpty( pxQueue ) )\r
- {\r
- traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
-\r
- #if ( configUSE_MUTEXES == 1 )\r
- {\r
- if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
- {\r
- portENTER_CRITICAL();\r
- vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
- portEXIT_CRITICAL();\r
- }\r
- }\r
- #endif\r
-\r
- vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- else\r
- {\r
- taskEXIT_CRITICAL();\r
- traceQUEUE_RECEIVE_FAILED( pxQueue );\r
- return errQUEUE_EMPTY;\r
- }\r
- }\r
- taskEXIT_CRITICAL();\r
- }\r
- }\r
-\r
-\r
-#endif /* configUSE_ALTERNATIVE_API */\r
-/*-----------------------------------------------------------*/\r
-\r
-signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition )\r
-{\r
-signed portBASE_TYPE xReturn;\r
-unsigned portBASE_TYPE uxSavedInterruptStatus;\r
-\r
- configASSERT( pxQueue );\r
- configASSERT( pxHigherPriorityTaskWoken );\r
- configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
-\r
- /* Similar to xQueueGenericSend, except we don't block if there is no room\r
- in the queue. Also we don't directly wake a task that was blocked on a\r
- queue read, instead we return a flag to say whether a context switch is\r
- required or not (i.e. has a task with a higher priority than us been woken\r
- by this post). */\r
- uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
- {\r
- if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
- {\r
- traceQUEUE_SEND_FROM_ISR( pxQueue );\r
-\r
- prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
-\r
- /* If the queue is locked we do not alter the event list. This will\r
- be done when the queue is unlocked later. */\r
- if( pxQueue->xTxLock == queueUNLOCKED )\r
- {\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
- {\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
- {\r
- /* The task waiting has a higher priority so record that a\r
- context switch is required. */\r
- *pxHigherPriorityTaskWoken = pdTRUE;\r
- }\r
- }\r
- }\r
- else\r
- {\r
- /* Increment the lock count so the task that unlocks the queue\r
- knows that data was posted while it was locked. */\r
- ++( pxQueue->xTxLock );\r
- }\r
-\r
- xReturn = pdPASS;\r
- }\r
- else\r
- {\r
- traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );\r
- xReturn = errQUEUE_FULL;\r
- }\r
- }\r
- portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
-{\r
-signed portBASE_TYPE xEntryTimeSet = pdFALSE;\r
-xTimeOutType xTimeOut;\r
-signed char *pcOriginalReadPosition;\r
-\r
- configASSERT( pxQueue );\r
- configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
-\r
- /* This function relaxes the coding standard somewhat to allow return\r
- statements within the function itself. This is done in the interest\r
- of execution time efficiency. */\r
-\r
- for( ;; )\r
- {\r
- taskENTER_CRITICAL();\r
- {\r
- /* Is there data in the queue now? To be running we must be\r
- the highest priority task wanting to access the queue. */\r
- if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- /* Remember our read position in case we are just peeking. */\r
- pcOriginalReadPosition = pxQueue->pcReadFrom;\r
-\r
- prvCopyDataFromQueue( pxQueue, pvBuffer );\r
-\r
- if( xJustPeeking == pdFALSE )\r
- {\r
- traceQUEUE_RECEIVE( pxQueue );\r
-\r
- /* We are actually removing data. */\r
- --( pxQueue->uxMessagesWaiting );\r
-\r
- #if ( configUSE_MUTEXES == 1 )\r
- {\r
- if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
- {\r
- /* Record the information required to implement\r
- priority inheritance should it become necessary. */\r
- pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
- }\r
- }\r
- #endif\r
-\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
- {\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
- {\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- }\r
- else\r
- {\r
- traceQUEUE_PEEK( pxQueue );\r
-\r
- /* We are not removing the data, so reset our read\r
- pointer. */\r
- pxQueue->pcReadFrom = pcOriginalReadPosition;\r
-\r
- /* The data is being left in the queue, so see if there are\r
- any other tasks waiting for the data. */\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
- {\r
- /* Tasks that are removed from the event list will get added to\r
- the pending ready list as the scheduler is still suspended. */\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
- {\r
- /* The task waiting has a higher priority than this task. */\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
-\r
- }\r
-\r
- taskEXIT_CRITICAL();\r
- return pdPASS;\r
- }\r
- else\r
- {\r
- if( xTicksToWait == ( portTickType ) 0 )\r
- {\r
- /* The queue was empty and no block time is specified (or\r
- the block time has expired) so leave now. */\r
- taskEXIT_CRITICAL();\r
- traceQUEUE_RECEIVE_FAILED( pxQueue );\r
- return errQUEUE_EMPTY;\r
- }\r
- else if( xEntryTimeSet == pdFALSE )\r
- {\r
- /* The queue was empty and a block time was specified so\r
- configure the timeout structure. */\r
- vTaskSetTimeOutState( &xTimeOut );\r
- xEntryTimeSet = pdTRUE;\r
- }\r
- }\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- /* Interrupts and other tasks can send to and receive from the queue\r
- now the critical section has been exited. */\r
-\r
- vTaskSuspendAll();\r
- prvLockQueue( pxQueue );\r
-\r
- /* Update the timeout state to see if it has expired yet. */\r
- if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
- {\r
- if( prvIsQueueEmpty( pxQueue ) )\r
- {\r
- traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
-\r
- #if ( configUSE_MUTEXES == 1 )\r
- {\r
- if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
- {\r
- portENTER_CRITICAL();\r
- {\r
- vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
- }\r
- portEXIT_CRITICAL();\r
- }\r
- }\r
- #endif\r
-\r
- vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
- prvUnlockQueue( pxQueue );\r
- if( !xTaskResumeAll() )\r
- {\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- else\r
- {\r
- /* Try again. */\r
- prvUnlockQueue( pxQueue );\r
- ( void ) xTaskResumeAll();\r
- }\r
- }\r
- else\r
- {\r
- prvUnlockQueue( pxQueue );\r
- ( void ) xTaskResumeAll();\r
- traceQUEUE_RECEIVE_FAILED( pxQueue );\r
- return errQUEUE_EMPTY;\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )\r
-{\r
-signed portBASE_TYPE xReturn;\r
-unsigned portBASE_TYPE uxSavedInterruptStatus;\r
-\r
- configASSERT( pxQueue );\r
- configASSERT( pxTaskWoken );\r
- configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );\r
-\r
- uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
- {\r
- /* We cannot block from an ISR, so check there is data available. */\r
- if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- traceQUEUE_RECEIVE_FROM_ISR( pxQueue );\r
-\r
- prvCopyDataFromQueue( pxQueue, pvBuffer );\r
- --( pxQueue->uxMessagesWaiting );\r
-\r
- /* If the queue is locked we will not modify the event list. Instead\r
- we update the lock count so the task that unlocks the queue will know\r
- that an ISR has removed data while the queue was locked. */\r
- if( pxQueue->xRxLock == queueUNLOCKED )\r
- {\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
- {\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
- {\r
- /* The task waiting has a higher priority than us so\r
- force a context switch. */\r
- *pxTaskWoken = pdTRUE;\r
- }\r
- }\r
- }\r
- else\r
- {\r
- /* Increment the lock count so the task that unlocks the queue\r
- knows that data was removed while it was locked. */\r
- ++( pxQueue->xRxLock );\r
- }\r
-\r
- xReturn = pdPASS;\r
- }\r
- else\r
- {\r
- xReturn = pdFAIL;\r
- traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );\r
- }\r
- }\r
- portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )\r
-{\r
-unsigned portBASE_TYPE uxReturn;\r
-\r
- configASSERT( pxQueue );\r
-\r
- taskENTER_CRITICAL();\r
- uxReturn = pxQueue->uxMessagesWaiting;\r
- taskEXIT_CRITICAL();\r
-\r
- return uxReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue )\r
-{\r
-unsigned portBASE_TYPE uxReturn;\r
-\r
- configASSERT( pxQueue );\r
-\r
- uxReturn = pxQueue->uxMessagesWaiting;\r
-\r
- return uxReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vQueueDelete( xQueueHandle pxQueue )\r
-{\r
- configASSERT( pxQueue );\r
-\r
- traceQUEUE_DELETE( pxQueue );\r
- vQueueUnregisterQueue( pxQueue );\r
- vPortFree( pxQueue->pcHead );\r
- vPortFree( pxQueue );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )\r
-{\r
- if( pxQueue->uxItemSize == ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- #if ( configUSE_MUTEXES == 1 )\r
- {\r
- if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
- {\r
- /* The mutex is no longer being held. */\r
- vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );\r
- pxQueue->pxMutexHolder = NULL;\r
- }\r
- }\r
- #endif\r
- }\r
- else if( xPosition == queueSEND_TO_BACK )\r
- {\r
- memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
- pxQueue->pcWriteTo += pxQueue->uxItemSize;\r
- if( pxQueue->pcWriteTo >= pxQueue->pcTail )\r
- {\r
- pxQueue->pcWriteTo = pxQueue->pcHead;\r
- }\r
- }\r
- else\r
- {\r
- memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
- pxQueue->pcReadFrom -= pxQueue->uxItemSize;\r
- if( pxQueue->pcReadFrom < pxQueue->pcHead )\r
- {\r
- pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );\r
- }\r
- }\r
-\r
- ++( pxQueue->uxMessagesWaiting );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )\r
-{\r
- if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )\r
- {\r
- pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
- if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
- {\r
- pxQueue->pcReadFrom = pxQueue->pcHead;\r
- }\r
- memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvUnlockQueue( xQueueHandle pxQueue )\r
-{\r
- /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */\r
-\r
- /* The lock counts contains the number of extra data items placed or\r
- removed from the queue while the queue was locked. When a queue is\r
- locked items can be added or removed, but the event lists cannot be\r
- updated. */\r
- taskENTER_CRITICAL();\r
- {\r
- /* See if data was added to the queue while it was locked. */\r
- while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED )\r
- {\r
- /* Data was posted while the queue was locked. Are any tasks\r
- blocked waiting for data to become available? */\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
- {\r
- /* Tasks that are removed from the event list will get added to\r
- the pending ready list as the scheduler is still suspended. */\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
- {\r
- /* The task waiting has a higher priority so record that a\r
- context switch is required. */\r
- vTaskMissedYield();\r
- }\r
-\r
- --( pxQueue->xTxLock );\r
- }\r
- else\r
- {\r
- break;\r
- }\r
- }\r
-\r
- pxQueue->xTxLock = queueUNLOCKED;\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- /* Do the same for the Rx lock. */\r
- taskENTER_CRITICAL();\r
- {\r
- while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED )\r
- {\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
- {\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
- {\r
- vTaskMissedYield();\r
- }\r
-\r
- --( pxQueue->xRxLock );\r
- }\r
- else\r
- {\r
- break;\r
- }\r
- }\r
-\r
- pxQueue->xRxLock = queueUNLOCKED;\r
- }\r
- taskEXIT_CRITICAL();\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )\r
-{\r
-signed portBASE_TYPE xReturn;\r
-\r
- taskENTER_CRITICAL();\r
- xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
- taskEXIT_CRITICAL();\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue )\r
-{\r
-signed portBASE_TYPE xReturn;\r
-\r
- configASSERT( pxQueue );\r
- xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )\r
-{\r
-signed portBASE_TYPE xReturn;\r
-\r
- taskENTER_CRITICAL();\r
- xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
- taskEXIT_CRITICAL();\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue )\r
-{\r
-signed portBASE_TYPE xReturn;\r
-\r
- configASSERT( pxQueue );\r
- xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configUSE_CO_ROUTINES == 1\r
-signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
-{\r
-signed portBASE_TYPE xReturn;\r
-\r
- /* If the queue is already full we may have to block. A critical section\r
- is required to prevent an interrupt removing something from the queue\r
- between the check to see if the queue is full and blocking on the queue. */\r
- portDISABLE_INTERRUPTS();\r
- {\r
- if( prvIsQueueFull( pxQueue ) )\r
- {\r
- /* The queue is full - do we want to block or just leave without\r
- posting? */\r
- if( xTicksToWait > ( portTickType ) 0 )\r
- {\r
- /* As this is called from a coroutine we cannot block directly, but\r
- return indicating that we need to block. */\r
- vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );\r
- portENABLE_INTERRUPTS();\r
- return errQUEUE_BLOCKED;\r
- }\r
- else\r
- {\r
- portENABLE_INTERRUPTS();\r
- return errQUEUE_FULL;\r
- }\r
- }\r
- }\r
- portENABLE_INTERRUPTS();\r
-\r
- portNOP();\r
-\r
- portDISABLE_INTERRUPTS();\r
- {\r
- if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
- {\r
- /* There is room in the queue, copy the data into the queue. */\r
- prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
- xReturn = pdPASS;\r
-\r
- /* Were any co-routines waiting for data to become available? */\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
- {\r
- /* In this instance the co-routine could be placed directly\r
- into the ready list as we are within a critical section.\r
- Instead the same pending ready list mechanism is used as if\r
- the event were caused from within an interrupt. */\r
- if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
- {\r
- /* The co-routine waiting has a higher priority so record\r
- that a yield might be appropriate. */\r
- xReturn = errQUEUE_YIELD;\r
- }\r
- }\r
- }\r
- else\r
- {\r
- xReturn = errQUEUE_FULL;\r
- }\r
- }\r
- portENABLE_INTERRUPTS();\r
-\r
- return xReturn;\r
-}\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configUSE_CO_ROUTINES == 1\r
-signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )\r
-{\r
-signed portBASE_TYPE xReturn;\r
-\r
- /* If the queue is already empty we may have to block. A critical section\r
- is required to prevent an interrupt adding something to the queue\r
- between the check to see if the queue is empty and blocking on the queue. */\r
- portDISABLE_INTERRUPTS();\r
- {\r
- if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- /* There are no messages in the queue, do we want to block or just\r
- leave with nothing? */\r
- if( xTicksToWait > ( portTickType ) 0 )\r
- {\r
- /* As this is a co-routine we cannot block directly, but return\r
- indicating that we need to block. */\r
- vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );\r
- portENABLE_INTERRUPTS();\r
- return errQUEUE_BLOCKED;\r
- }\r
- else\r
- {\r
- portENABLE_INTERRUPTS();\r
- return errQUEUE_FULL;\r
- }\r
- }\r
- }\r
- portENABLE_INTERRUPTS();\r
-\r
- portNOP();\r
-\r
- portDISABLE_INTERRUPTS();\r
- {\r
- if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- /* Data is available from the queue. */\r
- pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
- if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
- {\r
- pxQueue->pcReadFrom = pxQueue->pcHead;\r
- }\r
- --( pxQueue->uxMessagesWaiting );\r
- memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
-\r
- xReturn = pdPASS;\r
-\r
- /* Were any co-routines waiting for space to become available? */\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
- {\r
- /* In this instance the co-routine could be placed directly\r
- into the ready list as we are within a critical section.\r
- Instead the same pending ready list mechanism is used as if\r
- the event were caused from within an interrupt. */\r
- if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
- {\r
- xReturn = errQUEUE_YIELD;\r
- }\r
- }\r
- }\r
- else\r
- {\r
- xReturn = pdFAIL;\r
- }\r
- }\r
- portENABLE_INTERRUPTS();\r
-\r
- return xReturn;\r
-}\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-\r
-\r
-#if configUSE_CO_ROUTINES == 1\r
-signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )\r
-{\r
- /* Cannot block within an ISR so if there is no space on the queue then\r
- exit without doing anything. */\r
- if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
- {\r
- prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
-\r
- /* We only want to wake one co-routine per ISR, so check that a\r
- co-routine has not already been woken. */\r
- if( !xCoRoutinePreviouslyWoken )\r
- {\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
- {\r
- if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
- {\r
- return pdTRUE;\r
- }\r
- }\r
- }\r
- }\r
-\r
- return xCoRoutinePreviouslyWoken;\r
-}\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configUSE_CO_ROUTINES == 1\r
-signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )\r
-{\r
-signed portBASE_TYPE xReturn;\r
-\r
- /* We cannot block from an ISR, so check there is data available. If\r
- not then just leave without doing anything. */\r
- if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- /* Copy the data from the queue. */\r
- pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
- if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
- {\r
- pxQueue->pcReadFrom = pxQueue->pcHead;\r
- }\r
- --( pxQueue->uxMessagesWaiting );\r
- memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
-\r
- if( !( *pxCoRoutineWoken ) )\r
- {\r
- if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
- {\r
- if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
- {\r
- *pxCoRoutineWoken = pdTRUE;\r
- }\r
- }\r
- }\r
-\r
- xReturn = pdPASS;\r
- }\r
- else\r
- {\r
- xReturn = pdFAIL;\r
- }\r
-\r
- return xReturn;\r
-}\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configQUEUE_REGISTRY_SIZE > 0\r
-\r
- void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName )\r
- {\r
- unsigned portBASE_TYPE ux;\r
-\r
- /* See if there is an empty space in the registry. A NULL name denotes\r
- a free slot. */\r
- for( ux = ( unsigned portBASE_TYPE ) 0U; ux < configQUEUE_REGISTRY_SIZE; ux++ )\r
- {\r
- if( xQueueRegistry[ ux ].pcQueueName == NULL )\r
- {\r
- /* Store the information on this queue. */\r
- xQueueRegistry[ ux ].pcQueueName = pcQueueName;\r
- xQueueRegistry[ ux ].xHandle = xQueue;\r
- break;\r
- }\r
- }\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configQUEUE_REGISTRY_SIZE > 0\r
-\r
- static void vQueueUnregisterQueue( xQueueHandle xQueue )\r
- {\r
- unsigned portBASE_TYPE ux;\r
-\r
- /* See if the handle of the queue being unregistered in actually in the\r
- registry. */\r
- for( ux = ( unsigned portBASE_TYPE ) 0U; ux < configQUEUE_REGISTRY_SIZE; ux++ )\r
- {\r
- if( xQueueRegistry[ ux ].xHandle == xQueue )\r
- {\r
- /* Set the name to NULL to show that this slot if free again. */\r
- xQueueRegistry[ ux ].pcQueueName = NULL;\r
- break;\r
- }\r
- }\r
-\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configUSE_TIMERS == 1\r
-\r
- void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait )\r
- {\r
- /* This function should not be called by application code hence the\r
- 'Restricted' in its name. It is not part of the public API. It is\r
- designed for use by kernel code, and has special calling requirements.\r
- It can result in vListInsert() being called on a list that can only\r
- possibly ever have one item in it, so the list will be fast, but even\r
- so it should be called with the scheduler locked and not from a critical\r
- section. */\r
-\r
- /* Only do anything if there are no messages in the queue. This function\r
- will not actually cause the task to block, just place it on a blocked\r
- list. It will not block until the scheduler is unlocked - at which\r
- time a yield will be performed. If an item is added to the queue while\r
- the queue is locked, and the calling task blocks on the queue, then the\r
- calling task will be immediately unblocked when the queue is unlocked. */\r
- prvLockQueue( pxQueue );\r
- if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U )\r
- {\r
- /* There is nothing in the queue, block for the specified period. */\r
- vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
- }\r
- prvUnlockQueue( pxQueue );\r
- }\r
-\r
-#endif\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-\r
-/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
-all the API functions to use the MPU wrappers. That should only be done when\r
-task.h is included from an application file. */\r
-#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
-\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "timers.h"\r
-#include "StackMacros.h"\r
-\r
-#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
-\r
-/*\r
- * Macro to define the amount of stack available to the idle task.\r
- */\r
-#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE\r
-\r
-/*\r
- * Task control block. A task control block (TCB) is allocated to each task,\r
- * and stores the context of the task.\r
- */\r
-typedef struct tskTaskControlBlock\r
-{\r
- volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */\r
-\r
- #if ( portUSING_MPU_WRAPPERS == 1 )\r
- xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */\r
- #endif \r
- \r
- xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */\r
- xListItem xEventListItem; /*< List item used to place the TCB in event lists. */\r
- unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */\r
- portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */\r
- signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */\r
-\r
- #if ( portSTACK_GROWTH > 0 )\r
- portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */\r
- #endif\r
-\r
- #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
- unsigned portBASE_TYPE uxCriticalNesting;\r
- #endif\r
-\r
- #if ( configUSE_TRACE_FACILITY == 1 )\r
- unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */\r
- #endif\r
-\r
- #if ( configUSE_MUTEXES == 1 )\r
- unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */\r
- #endif\r
-\r
- #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
- pdTASK_HOOK_CODE pxTaskTag;\r
- #endif\r
-\r
- #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
- unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */\r
- #endif\r
-\r
-} tskTCB;\r
-\r
-\r
-/*\r
- * Some kernel aware debuggers require data to be viewed to be global, rather\r
- * than file scope.\r
- */\r
-#ifdef portREMOVE_STATIC_QUALIFIER\r
- #define static\r
-#endif\r
-\r
-/*lint -e956 */\r
-PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;\r
-\r
-/* Lists for ready and blocked tasks. --------------------*/\r
-\r
-PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */\r
-PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */\r
-PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */\r
-PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ; /*< Points to the delayed task list currently being used. */\r
-PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */\r
-PRIVILEGED_DATA static xList xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready queue when the scheduler is resumed. */\r
-\r
-#if ( INCLUDE_vTaskDelete == 1 )\r
-\r
- PRIVILEGED_DATA static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */\r
- PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;\r
-\r
-#endif\r
-\r
-#if ( INCLUDE_vTaskSuspend == 1 )\r
-\r
- PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */\r
-\r
-#endif\r
-\r
-#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )\r
- \r
- PRIVILEGED_DATA static xTaskHandle xIdleTaskHandle = NULL;\r
- \r
-#endif\r
-\r
-/* File private variables. --------------------------------*/\r
-PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0;\r
-PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0;\r
-PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;\r
-PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;\r
-PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;\r
-PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;\r
-PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsigned portBASE_TYPE ) 0;\r
-PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;\r
-PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;\r
-PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0;\r
-PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) portMAX_DELAY;\r
-\r
-#if ( configGENERATE_RUN_TIME_STATS == 1 )\r
-\r
- PRIVILEGED_DATA static char pcStatsString[ 50 ] ;\r
- PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */\r
- static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime ) PRIVILEGED_FUNCTION;\r
-\r
-#endif\r
-\r
-/* Debugging and trace facilities private variables and macros. ------------*/\r
-\r
-/*\r
- * The value used to fill the stack of a task when the task is created. This\r
- * is used purely for checking the high water mark for tasks.\r
- */\r
-#define tskSTACK_FILL_BYTE ( 0xa5U )\r
-\r
-/*\r
- * Macros used by vListTask to indicate which state a task is in.\r
- */\r
-#define tskBLOCKED_CHAR ( ( signed char ) 'B' )\r
-#define tskREADY_CHAR ( ( signed char ) 'R' )\r
-#define tskDELETED_CHAR ( ( signed char ) 'D' )\r
-#define tskSUSPENDED_CHAR ( ( signed char ) 'S' )\r
-\r
-/*\r
- * Macros and private variables used by the trace facility.\r
- */\r
-#if ( configUSE_TRACE_FACILITY == 1 )\r
-\r
- #define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned long ) ( sizeof( unsigned long ) + sizeof( unsigned long ) ) )\r
- PRIVILEGED_DATA static volatile signed char * volatile pcTraceBuffer;\r
- PRIVILEGED_DATA static signed char *pcTraceBufferStart;\r
- PRIVILEGED_DATA static signed char *pcTraceBufferEnd;\r
- PRIVILEGED_DATA static signed portBASE_TYPE xTracing = pdFALSE;\r
- static unsigned portBASE_TYPE uxPreviousTask = 255U;\r
- PRIVILEGED_DATA static char pcStatusString[ 50 ];\r
-\r
-#endif\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Macro that writes a trace of scheduler activity to a buffer. This trace\r
- * shows which task is running when and is very useful as a debugging tool.\r
- * As this macro is called each context switch it is a good idea to undefine\r
- * it if not using the facility.\r
- */\r
-#if ( configUSE_TRACE_FACILITY == 1 )\r
-\r
- #define vWriteTraceToBuffer() \\r
- { \\r
- if( xTracing ) \\r
- { \\r
- if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \\r
- { \\r
- if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \\r
- { \\r
- uxPreviousTask = pxCurrentTCB->uxTCBNumber; \\r
- *( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount; \\r
- pcTraceBuffer += sizeof( unsigned long ); \\r
- *( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask; \\r
- pcTraceBuffer += sizeof( unsigned long ); \\r
- } \\r
- else \\r
- { \\r
- xTracing = pdFALSE; \\r
- } \\r
- } \\r
- } \\r
- }\r
-\r
-#else\r
-\r
- #define vWriteTraceToBuffer()\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Place the task represented by pxTCB into the appropriate ready queue for\r
- * the task. It is inserted at the end of the list. One quirk of this is\r
- * that if the task being inserted is at the same priority as the currently\r
- * executing task, then it will only be rescheduled after the currently\r
- * executing task has been rescheduled.\r
- */\r
-#define prvAddTaskToReadyQueue( pxTCB ) \\r
- if( ( pxTCB )->uxPriority > uxTopReadyPriority ) \\r
- { \\r
- uxTopReadyPriority = ( pxTCB )->uxPriority; \\r
- } \\r
- vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Macro that looks at the list of tasks that are currently delayed to see if\r
- * any require waking.\r
- *\r
- * Tasks are stored in the queue in the order of their wake time - meaning\r
- * once one tasks has been found whose timer has not expired we need not look\r
- * any further down the list.\r
- */\r
-#define prvCheckDelayedTasks() \\r
-{ \\r
-portTickType xItemValue; \\r
- \\r
- /* Is the tick count greater than or equal to the wake time of the first \\r
- task referenced from the delayed tasks list? */ \\r
- if( xTickCount >= xNextTaskUnblockTime ) \\r
- { \\r
- for( ;; ) \\r
- { \\r
- if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) \\r
- { \\r
- /* The delayed list is empty. Set xNextTaskUnblockTime to the \\r
- maximum possible value so it is extremely unlikely that the \\r
- if( xTickCount >= xNextTaskUnblockTime ) test will pass next \\r
- time through. */ \\r
- xNextTaskUnblockTime = portMAX_DELAY; \\r
- break; \\r
- } \\r
- else \\r
- { \\r
- /* The delayed list is not empty, get the value of the item at \\r
- the head of the delayed list. This is the time at which the \\r
- task at the head of the delayed list should be removed from \\r
- the Blocked state. */ \\r
- pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); \\r
- xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); \\r
- \\r
- if( xTickCount < xItemValue ) \\r
- { \\r
- /* It is not time to unblock this item yet, but the item \\r
- value is the time at which the task at the head of the \\r
- blocked list should be removed from the Blocked state - \\r
- so record the item value in xNextTaskUnblockTime. */ \\r
- xNextTaskUnblockTime = xItemValue; \\r
- break; \\r
- } \\r
- \\r
- /* It is time to remove the item from the Blocked state. */ \\r
- vListRemove( &( pxTCB->xGenericListItem ) ); \\r
- \\r
- /* Is the task waiting on an event also? */ \\r
- if( pxTCB->xEventListItem.pvContainer ) \\r
- { \\r
- vListRemove( &( pxTCB->xEventListItem ) ); \\r
- } \\r
- prvAddTaskToReadyQueue( pxTCB ); \\r
- } \\r
- } \\r
- } \\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Several functions take an xTaskHandle parameter that can optionally be NULL,\r
- * where NULL is used to indicate that the handle of the currently executing\r
- * task should be used in place of the parameter. This macro simply checks to\r
- * see if the parameter is NULL and returns a pointer to the appropriate TCB.\r
- */\r
-#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) ( pxHandle ) )\r
-\r
-/* Callback function prototypes. --------------------------*/\r
-extern void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName );\r
-extern void vApplicationTickHook( void );\r
- \r
-/* File private functions. --------------------------------*/\r
-\r
-/*\r
- * Utility to ready a TCB for a given task. Mainly just copies the parameters\r
- * into the TCB structure.\r
- */\r
-static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Utility to ready all the lists used by the scheduler. This is called\r
- * automatically upon the creation of the first task.\r
- */\r
-static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * The idle task, which as all tasks is implemented as a never ending loop.\r
- * The idle task is automatically created and added to the ready lists upon\r
- * creation of the first user task.\r
- *\r
- * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific\r
- * language extensions. The equivalent prototype for this function is:\r
- *\r
- * void prvIdleTask( void *pvParameters );\r
- *\r
- */\r
-static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );\r
-\r
-/*\r
- * Utility to free all memory allocated by the scheduler to hold a TCB,\r
- * including the stack pointed to by the TCB.\r
- *\r
- * This does not free memory allocated by the task itself (i.e. memory\r
- * allocated by calls to pvPortMalloc from within the tasks application code).\r
- */\r
-#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )\r
-\r
- static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;\r
-\r
-#endif\r
-\r
-/*\r
- * Used only by the idle task. This checks to see if anything has been placed\r
- * in the list of tasks waiting to be deleted. If so the task is cleaned up\r
- * and its TCB deleted.\r
- */\r
-static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * The currently executing task is entering the Blocked state. Add the task to\r
- * either the current or the overflow delayed task list.\r
- */\r
-static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Allocates memory from the heap for a TCB and associated stack. Checks the\r
- * allocation was successful.\r
- */\r
-static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Called from vTaskList. vListTasks details all the tasks currently under\r
- * control of the scheduler. The tasks may be in one of a number of lists.\r
- * prvListTaskWithinSingleList accepts a list and details the tasks from\r
- * within just that list.\r
- *\r
- * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM\r
- * NORMAL APPLICATION CODE.\r
- */\r
-#if ( configUSE_TRACE_FACILITY == 1 )\r
-\r
- static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus ) PRIVILEGED_FUNCTION;\r
-\r
-#endif\r
-\r
-/*\r
- * When a task is created, the stack of the task is filled with a known value.\r
- * This function determines the 'high water mark' of the task stack by\r
- * determining how much of the stack remains at the original preset value.\r
- */\r
-#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )\r
-\r
- static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;\r
-\r
-#endif\r
-\r
-\r
-/*lint +e956 */\r
-\r
-\r
-\r
-/*-----------------------------------------------------------\r
- * TASK CREATION API documented in task.h\r
- *----------------------------------------------------------*/\r
-\r
-signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )\r
-{\r
-signed portBASE_TYPE xReturn;\r
-tskTCB * pxNewTCB;\r
-\r
- configASSERT( pxTaskCode );\r
- configASSERT( ( uxPriority < configMAX_PRIORITIES ) );\r
-\r
- /* Allocate the memory required by the TCB and stack for the new task,\r
- checking that the allocation was successful. */\r
- pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );\r
-\r
- if( pxNewTCB != NULL )\r
- {\r
- portSTACK_TYPE *pxTopOfStack;\r
-\r
- #if( portUSING_MPU_WRAPPERS == 1 )\r
- /* Should the task be created in privileged mode? */\r
- portBASE_TYPE xRunPrivileged;\r
- if( ( uxPriority & portPRIVILEGE_BIT ) != 0x00 )\r
- {\r
- xRunPrivileged = pdTRUE;\r
- }\r
- else\r
- {\r
- xRunPrivileged = pdFALSE;\r
- }\r
- uxPriority &= ~portPRIVILEGE_BIT;\r
- #endif /* portUSING_MPU_WRAPPERS == 1 */\r
-\r
- /* Calculate the top of stack address. This depends on whether the\r
- stack grows from high memory to low (as per the 80x86) or visa versa.\r
- portSTACK_GROWTH is used to make the result positive or negative as\r
- required by the port. */\r
- #if( portSTACK_GROWTH < 0 )\r
- {\r
- pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );\r
- pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( unsigned long ) pxTopOfStack ) & ( ( unsigned long ) ~portBYTE_ALIGNMENT_MASK ) );\r
-\r
- /* Check the alignment of the calculated top of stack is correct. */\r
- configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );\r
- }\r
- #else\r
- {\r
- pxTopOfStack = pxNewTCB->pxStack;\r
- \r
- /* Check the alignment of the stack buffer is correct. */\r
- configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );\r
-\r
- /* If we want to use stack checking on architectures that use\r
- a positive stack growth direction then we also need to store the\r
- other extreme of the stack space. */\r
- pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );\r
- }\r
- #endif\r
-\r
- /* Setup the newly allocated TCB with the initial state of the task. */\r
- prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );\r
-\r
- /* Initialize the TCB stack to look as if the task was already running,\r
- but had been interrupted by the scheduler. The return address is set\r
- to the start of the task function. Once the stack has been initialised\r
- the top of stack variable is updated. */\r
- #if( portUSING_MPU_WRAPPERS == 1 )\r
- {\r
- pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );\r
- }\r
- #else\r
- {\r
- pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );\r
- }\r
- #endif\r
-\r
- /* Check the alignment of the initialised stack. */\r
- configASSERT( ( ( ( unsigned long ) pxNewTCB->pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );\r
-\r
- if( ( void * ) pxCreatedTask != NULL )\r
- {\r
- /* Pass the TCB out - in an anonymous way. The calling function/\r
- task can use this as a handle to delete the task later if\r
- required.*/\r
- *pxCreatedTask = ( xTaskHandle ) pxNewTCB;\r
- }\r
- \r
- /* We are going to manipulate the task queues to add this task to a\r
- ready list, so must make sure no interrupts occur. */\r
- taskENTER_CRITICAL();\r
- {\r
- uxCurrentNumberOfTasks++;\r
- if( pxCurrentTCB == NULL )\r
- {\r
- /* There are no other tasks, or all the other tasks are in\r
- the suspended state - make this the current task. */\r
- pxCurrentTCB = pxNewTCB;\r
-\r
- if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )\r
- {\r
- /* This is the first task to be created so do the preliminary\r
- initialisation required. We will not recover if this call\r
- fails, but we will report the failure. */\r
- prvInitialiseTaskLists();\r
- }\r
- }\r
- else\r
- {\r
- /* If the scheduler is not already running, make this task the\r
- current task if it is the highest priority task to be created\r
- so far. */\r
- if( xSchedulerRunning == pdFALSE )\r
- {\r
- if( pxCurrentTCB->uxPriority <= uxPriority )\r
- {\r
- pxCurrentTCB = pxNewTCB;\r
- }\r
- }\r
- }\r
-\r
- /* Remember the top priority to make context switching faster. Use\r
- the priority in pxNewTCB as this has been capped to a valid value. */\r
- if( pxNewTCB->uxPriority > uxTopUsedPriority )\r
- {\r
- uxTopUsedPriority = pxNewTCB->uxPriority;\r
- }\r
-\r
- #if ( configUSE_TRACE_FACILITY == 1 )\r
- {\r
- /* Add a counter into the TCB for tracing only. */\r
- pxNewTCB->uxTCBNumber = uxTaskNumber;\r
- }\r
- #endif\r
- uxTaskNumber++;\r
-\r
- prvAddTaskToReadyQueue( pxNewTCB );\r
-\r
- xReturn = pdPASS;\r
- traceTASK_CREATE( pxNewTCB );\r
- }\r
- taskEXIT_CRITICAL();\r
- }\r
- else\r
- {\r
- xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;\r
- traceTASK_CREATE_FAILED();\r
- }\r
-\r
- if( xReturn == pdPASS )\r
- {\r
- if( xSchedulerRunning != pdFALSE )\r
- {\r
- /* If the created task is of a higher priority than the current task\r
- then it should run now. */\r
- if( pxCurrentTCB->uxPriority < uxPriority )\r
- {\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- }\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( INCLUDE_vTaskDelete == 1 )\r
-\r
- void vTaskDelete( xTaskHandle pxTaskToDelete )\r
- {\r
- tskTCB *pxTCB;\r
-\r
- taskENTER_CRITICAL();\r
- {\r
- /* Ensure a yield is performed if the current task is being\r
- deleted. */\r
- if( pxTaskToDelete == pxCurrentTCB )\r
- {\r
- pxTaskToDelete = NULL;\r
- }\r
-\r
- /* If null is passed in here then we are deleting ourselves. */\r
- pxTCB = prvGetTCBFromHandle( pxTaskToDelete );\r
-\r
- /* Remove task from the ready list and place in the termination list.\r
- This will stop the task from be scheduled. The idle task will check\r
- the termination list and free up any memory allocated by the\r
- scheduler for the TCB and stack. */\r
- vListRemove( &( pxTCB->xGenericListItem ) );\r
-\r
- /* Is the task waiting on an event also? */\r
- if( pxTCB->xEventListItem.pvContainer )\r
- {\r
- vListRemove( &( pxTCB->xEventListItem ) );\r
- }\r
-\r
- vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );\r
-\r
- /* Increment the ucTasksDeleted variable so the idle task knows\r
- there is a task that has been deleted and that it should therefore\r
- check the xTasksWaitingTermination list. */\r
- ++uxTasksDeleted;\r
-\r
- /* Increment the uxTaskNumberVariable also so kernel aware debuggers\r
- can detect that the task lists need re-generating. */\r
- uxTaskNumber++;\r
-\r
- traceTASK_DELETE( pxTCB );\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- /* Force a reschedule if we have just deleted the current task. */\r
- if( xSchedulerRunning != pdFALSE )\r
- {\r
- if( ( void * ) pxTaskToDelete == NULL )\r
- {\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- }\r
-\r
-#endif\r
-\r
-\r
-\r
-\r
-\r
-\r
-/*-----------------------------------------------------------\r
- * TASK CONTROL API documented in task.h\r
- *----------------------------------------------------------*/\r
-\r
-#if ( INCLUDE_vTaskDelayUntil == 1 )\r
-\r
- void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )\r
- {\r
- portTickType xTimeToWake;\r
- portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;\r
-\r
- configASSERT( pxPreviousWakeTime );\r
- configASSERT( ( xTimeIncrement > 0 ) );\r
-\r
- vTaskSuspendAll();\r
- {\r
- /* Generate the tick time at which the task wants to wake. */\r
- xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;\r
-\r
- if( xTickCount < *pxPreviousWakeTime )\r
- {\r
- /* The tick count has overflowed since this function was\r
- lasted called. In this case the only time we should ever\r
- actually delay is if the wake time has also overflowed,\r
- and the wake time is greater than the tick time. When this\r
- is the case it is as if neither time had overflowed. */\r
- if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )\r
- {\r
- xShouldDelay = pdTRUE;\r
- }\r
- }\r
- else\r
- {\r
- /* The tick time has not overflowed. In this case we will\r
- delay if either the wake time has overflowed, and/or the\r
- tick time is less than the wake time. */\r
- if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )\r
- {\r
- xShouldDelay = pdTRUE;\r
- }\r
- }\r
-\r
- /* Update the wake time ready for the next call. */\r
- *pxPreviousWakeTime = xTimeToWake;\r
-\r
- if( xShouldDelay != pdFALSE )\r
- {\r
- traceTASK_DELAY_UNTIL();\r
-\r
- /* We must remove ourselves from the ready list before adding\r
- ourselves to the blocked list as the same list item is used for\r
- both lists. */\r
- vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
- prvAddCurrentTaskToDelayedList( xTimeToWake );\r
- }\r
- }\r
- xAlreadyYielded = xTaskResumeAll();\r
-\r
- /* Force a reschedule if xTaskResumeAll has not already done so, we may\r
- have put ourselves to sleep. */\r
- if( !xAlreadyYielded )\r
- {\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( INCLUDE_vTaskDelay == 1 )\r
-\r
- void vTaskDelay( portTickType xTicksToDelay )\r
- {\r
- portTickType xTimeToWake;\r
- signed portBASE_TYPE xAlreadyYielded = pdFALSE;\r
-\r
- /* A delay time of zero just forces a reschedule. */\r
- if( xTicksToDelay > ( portTickType ) 0 )\r
- {\r
- vTaskSuspendAll();\r
- {\r
- traceTASK_DELAY();\r
-\r
- /* A task that is removed from the event list while the\r
- scheduler is suspended will not get placed in the ready\r
- list or removed from the blocked list until the scheduler\r
- is resumed.\r
-\r
- This task cannot be in an event list as it is the currently\r
- executing task. */\r
-\r
- /* Calculate the time to wake - this may overflow but this is\r
- not a problem. */\r
- xTimeToWake = xTickCount + xTicksToDelay;\r
-\r
- /* We must remove ourselves from the ready list before adding\r
- ourselves to the blocked list as the same list item is used for\r
- both lists. */\r
- vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
- prvAddCurrentTaskToDelayedList( xTimeToWake );\r
- }\r
- xAlreadyYielded = xTaskResumeAll();\r
- }\r
-\r
- /* Force a reschedule if xTaskResumeAll has not already done so, we may\r
- have put ourselves to sleep. */\r
- if( !xAlreadyYielded )\r
- {\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( INCLUDE_uxTaskPriorityGet == 1 )\r
-\r
- unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )\r
- {\r
- tskTCB *pxTCB;\r
- unsigned portBASE_TYPE uxReturn;\r
-\r
- taskENTER_CRITICAL();\r
- {\r
- /* If null is passed in here then we are changing the\r
- priority of the calling function. */\r
- pxTCB = prvGetTCBFromHandle( pxTask );\r
- uxReturn = pxTCB->uxPriority;\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- return uxReturn;\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( INCLUDE_vTaskPrioritySet == 1 )\r
-\r
- void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )\r
- {\r
- tskTCB *pxTCB;\r
- unsigned portBASE_TYPE uxCurrentPriority;\r
- portBASE_TYPE xYieldRequired = pdFALSE;\r
-\r
- configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );\r
-\r
- /* Ensure the new priority is valid. */\r
- if( uxNewPriority >= configMAX_PRIORITIES )\r
- {\r
- uxNewPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;\r
- }\r
-\r
- taskENTER_CRITICAL();\r
- {\r
- if( pxTask == pxCurrentTCB )\r
- {\r
- pxTask = NULL;\r
- }\r
-\r
- /* If null is passed in here then we are changing the\r
- priority of the calling function. */\r
- pxTCB = prvGetTCBFromHandle( pxTask );\r
-\r
- traceTASK_PRIORITY_SET( pxTask, uxNewPriority );\r
-\r
- #if ( configUSE_MUTEXES == 1 )\r
- {\r
- uxCurrentPriority = pxTCB->uxBasePriority;\r
- }\r
- #else\r
- {\r
- uxCurrentPriority = pxTCB->uxPriority;\r
- }\r
- #endif\r
-\r
- if( uxCurrentPriority != uxNewPriority )\r
- {\r
- /* The priority change may have readied a task of higher\r
- priority than the calling task. */\r
- if( uxNewPriority > uxCurrentPriority )\r
- {\r
- if( pxTask != NULL )\r
- {\r
- /* The priority of another task is being raised. If we\r
- were raising the priority of the currently running task\r
- there would be no need to switch as it must have already\r
- been the highest priority task. */\r
- xYieldRequired = pdTRUE;\r
- }\r
- }\r
- else if( pxTask == NULL )\r
- {\r
- /* Setting our own priority down means there may now be another\r
- task of higher priority that is ready to execute. */\r
- xYieldRequired = pdTRUE;\r
- }\r
-\r
-\r
-\r
- #if ( configUSE_MUTEXES == 1 )\r
- {\r
- /* Only change the priority being used if the task is not\r
- currently using an inherited priority. */\r
- if( pxTCB->uxBasePriority == pxTCB->uxPriority )\r
- {\r
- pxTCB->uxPriority = uxNewPriority;\r
- }\r
-\r
- /* The base priority gets set whatever. */\r
- pxTCB->uxBasePriority = uxNewPriority;\r
- }\r
- #else\r
- {\r
- pxTCB->uxPriority = uxNewPriority;\r
- }\r
- #endif\r
-\r
- listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );\r
-\r
- /* If the task is in the blocked or suspended list we need do\r
- nothing more than change it's priority variable. However, if\r
- the task is in a ready list it needs to be removed and placed\r
- in the queue appropriate to its new priority. */\r
- if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )\r
- {\r
- /* The task is currently in its ready list - remove before adding\r
- it to it's new ready list. As we are in a critical section we\r
- can do this even if the scheduler is suspended. */\r
- vListRemove( &( pxTCB->xGenericListItem ) );\r
- prvAddTaskToReadyQueue( pxTCB );\r
- }\r
-\r
- if( xYieldRequired == pdTRUE )\r
- {\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- }\r
- taskEXIT_CRITICAL();\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( INCLUDE_vTaskSuspend == 1 )\r
-\r
- void vTaskSuspend( xTaskHandle pxTaskToSuspend )\r
- {\r
- tskTCB *pxTCB;\r
-\r
- taskENTER_CRITICAL();\r
- {\r
- /* Ensure a yield is performed if the current task is being\r
- suspended. */\r
- if( pxTaskToSuspend == pxCurrentTCB )\r
- {\r
- pxTaskToSuspend = NULL;\r
- }\r
-\r
- /* If null is passed in here then we are suspending ourselves. */\r
- pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );\r
-\r
- traceTASK_SUSPEND( pxTCB );\r
-\r
- /* Remove task from the ready/delayed list and place in the suspended list. */\r
- vListRemove( &( pxTCB->xGenericListItem ) );\r
-\r
- /* Is the task waiting on an event also? */\r
- if( pxTCB->xEventListItem.pvContainer )\r
- {\r
- vListRemove( &( pxTCB->xEventListItem ) );\r
- }\r
-\r
- vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- if( ( void * ) pxTaskToSuspend == NULL )\r
- {\r
- if( xSchedulerRunning != pdFALSE )\r
- {\r
- /* We have just suspended the current task. */\r
- portYIELD_WITHIN_API();\r
- }\r
- else\r
- {\r
- /* The scheduler is not running, but the task that was pointed\r
- to by pxCurrentTCB has just been suspended and pxCurrentTCB\r
- must be adjusted to point to a different task. */\r
- if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) \r
- {\r
- /* No other tasks are ready, so set pxCurrentTCB back to\r
- NULL so when the next task is created pxCurrentTCB will\r
- be set to point to it no matter what its relative priority\r
- is. */\r
- pxCurrentTCB = NULL;\r
- }\r
- else\r
- {\r
- vTaskSwitchContext();\r
- }\r
- }\r
- }\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( INCLUDE_vTaskSuspend == 1 )\r
-\r
- signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )\r
- {\r
- portBASE_TYPE xReturn = pdFALSE;\r
- const tskTCB * const pxTCB = ( tskTCB * ) xTask;\r
-\r
- /* It does not make sense to check if the calling task is suspended. */\r
- configASSERT( xTask );\r
-\r
- /* Is the task we are attempting to resume actually in the\r
- suspended list? */\r
- if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )\r
- {\r
- /* Has the task already been resumed from within an ISR? */\r
- if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )\r
- {\r
- /* Is it in the suspended list because it is in the\r
- Suspended state? It is possible to be in the suspended\r
- list because it is blocked on a task with no timeout\r
- specified. */\r
- if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )\r
- {\r
- xReturn = pdTRUE;\r
- }\r
- }\r
- }\r
-\r
- return xReturn;\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( INCLUDE_vTaskSuspend == 1 )\r
-\r
- void vTaskResume( xTaskHandle pxTaskToResume )\r
- {\r
- tskTCB *pxTCB;\r
-\r
- /* It does not make sense to resume the calling task. */\r
- configASSERT( pxTaskToResume );\r
-\r
- /* Remove the task from whichever list it is currently in, and place\r
- it in the ready list. */\r
- pxTCB = ( tskTCB * ) pxTaskToResume;\r
-\r
- /* The parameter cannot be NULL as it is impossible to resume the\r
- currently executing task. */\r
- if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )\r
- {\r
- taskENTER_CRITICAL();\r
- {\r
- if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )\r
- {\r
- traceTASK_RESUME( pxTCB );\r
-\r
- /* As we are in a critical section we can access the ready\r
- lists even if the scheduler is suspended. */\r
- vListRemove( &( pxTCB->xGenericListItem ) );\r
- prvAddTaskToReadyQueue( pxTCB );\r
-\r
- /* We may have just resumed a higher priority task. */\r
- if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
- {\r
- /* This yield may not cause the task just resumed to run, but\r
- will leave the lists in the correct state for the next yield. */\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- }\r
- taskEXIT_CRITICAL();\r
- }\r
- }\r
-\r
-#endif\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )\r
-\r
- portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )\r
- {\r
- portBASE_TYPE xYieldRequired = pdFALSE;\r
- tskTCB *pxTCB;\r
-\r
- configASSERT( pxTaskToResume );\r
-\r
- pxTCB = ( tskTCB * ) pxTaskToResume;\r
-\r
- if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )\r
- {\r
- traceTASK_RESUME_FROM_ISR( pxTCB );\r
-\r
- if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
- {\r
- xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );\r
- vListRemove( &( pxTCB->xGenericListItem ) );\r
- prvAddTaskToReadyQueue( pxTCB );\r
- }\r
- else\r
- {\r
- /* We cannot access the delayed or ready lists, so will hold this\r
- task pending until the scheduler is resumed, at which point a\r
- yield will be performed if necessary. */\r
- vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );\r
- }\r
- }\r
-\r
- return xYieldRequired;\r
- }\r
-\r
-#endif\r
-\r
-\r
-\r
-\r
-/*-----------------------------------------------------------\r
- * PUBLIC SCHEDULER CONTROL documented in task.h\r
- *----------------------------------------------------------*/\r
-\r
-\r
-void vTaskStartScheduler( void )\r
-{\r
-portBASE_TYPE xReturn;\r
-\r
- /* Add the idle task at the lowest priority. */\r
- #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )\r
- {\r
- /* Create the idle task, storing its handle in xIdleTaskHandle so it can\r
- be returned by the xTaskGetIdleTaskhandle() function. */\r
- xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle );\r
- }\r
- #else\r
- {\r
- /* Create the idle task without storing its handle. */\r
- xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL );\r
- }\r
- #endif\r
-\r
- #if ( configUSE_TIMERS == 1 )\r
- {\r
- if( xReturn == pdPASS )\r
- {\r
- xReturn = xTimerCreateTimerTask();\r
- }\r
- }\r
- #endif\r
-\r
- if( xReturn == pdPASS )\r
- {\r
- /* Interrupts are turned off here, to ensure a tick does not occur\r
- before or during the call to xPortStartScheduler(). The stacks of\r
- the created tasks contain a status word with interrupts switched on\r
- so interrupts will automatically get re-enabled when the first task\r
- starts to run.\r
-\r
- STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE\r
- DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */\r
- portDISABLE_INTERRUPTS();\r
-\r
- xSchedulerRunning = pdTRUE;\r
- xTickCount = ( portTickType ) 0;\r
-\r
- /* If configGENERATE_RUN_TIME_STATS is defined then the following\r
- macro must be defined to configure the timer/counter used to generate\r
- the run time counter time base. */\r
- portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();\r
- \r
- /* Setting up the timer tick is hardware specific and thus in the\r
- portable interface. */\r
- if( xPortStartScheduler() )\r
- {\r
- /* Should not reach here as if the scheduler is running the\r
- function will not return. */\r
- }\r
- else\r
- {\r
- /* Should only reach here if a task calls xTaskEndScheduler(). */\r
- }\r
- }\r
-\r
- /* This line will only be reached if the kernel could not be started. */\r
- configASSERT( xReturn );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vTaskEndScheduler( void )\r
-{\r
- /* Stop the scheduler interrupts and call the portable scheduler end\r
- routine so the original ISRs can be restored if necessary. The port\r
- layer must ensure interrupts enable bit is left in the correct state. */\r
- portDISABLE_INTERRUPTS();\r
- xSchedulerRunning = pdFALSE;\r
- vPortEndScheduler();\r
-}\r
-/*----------------------------------------------------------*/\r
-\r
-void vTaskSuspendAll( void )\r
-{\r
- /* A critical section is not required as the variable is of type\r
- portBASE_TYPE. */\r
- ++uxSchedulerSuspended;\r
-}\r
-/*----------------------------------------------------------*/\r
-\r
-signed portBASE_TYPE xTaskResumeAll( void )\r
-{\r
-register tskTCB *pxTCB;\r
-signed portBASE_TYPE xAlreadyYielded = pdFALSE;\r
-\r
- /* If uxSchedulerSuspended is zero then this function does not match a\r
- previous call to vTaskSuspendAll(). */\r
- configASSERT( uxSchedulerSuspended );\r
-\r
- /* It is possible that an ISR caused a task to be removed from an event\r
- list while the scheduler was suspended. If this was the case then the\r
- removed task will have been added to the xPendingReadyList. Once the\r
- scheduler has been resumed it is safe to move all the pending ready\r
- tasks from this list into their appropriate ready list. */\r
- taskENTER_CRITICAL();\r
- {\r
- --uxSchedulerSuspended;\r
-\r
- if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
- {\r
- if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- portBASE_TYPE xYieldRequired = pdFALSE;\r
-\r
- /* Move any readied tasks from the pending list into the\r
- appropriate ready list. */\r
- while( listLIST_IS_EMPTY( ( xList * ) &xPendingReadyList ) == pdFALSE )\r
- {\r
- pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) );\r
- vListRemove( &( pxTCB->xEventListItem ) );\r
- vListRemove( &( pxTCB->xGenericListItem ) );\r
- prvAddTaskToReadyQueue( pxTCB );\r
-\r
- /* If we have moved a task that has a priority higher than\r
- the current task then we should yield. */\r
- if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
- {\r
- xYieldRequired = pdTRUE;\r
- }\r
- }\r
-\r
- /* If any ticks occurred while the scheduler was suspended then\r
- they should be processed now. This ensures the tick count does not\r
- slip, and that any delayed tasks are resumed at the correct time. */\r
- if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- vTaskIncrementTick();\r
- --uxMissedTicks;\r
- }\r
-\r
- /* As we have processed some ticks it is appropriate to yield\r
- to ensure the highest priority task that is ready to run is\r
- the task actually running. */\r
- #if configUSE_PREEMPTION == 1\r
- {\r
- xYieldRequired = pdTRUE;\r
- }\r
- #endif\r
- }\r
-\r
- if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )\r
- {\r
- xAlreadyYielded = pdTRUE;\r
- xMissedYield = pdFALSE;\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- }\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- return xAlreadyYielded;\r
-}\r
-\r
-\r
-\r
-\r
-\r
-\r
-/*-----------------------------------------------------------\r
- * PUBLIC TASK UTILITIES documented in task.h\r
- *----------------------------------------------------------*/\r
-\r
-\r
-\r
-portTickType xTaskGetTickCount( void )\r
-{\r
-portTickType xTicks;\r
-\r
- /* Critical section required if running on a 16 bit processor. */\r
- taskENTER_CRITICAL();\r
- {\r
- xTicks = xTickCount;\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- return xTicks;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-portTickType xTaskGetTickCountFromISR( void )\r
-{\r
-portTickType xReturn;\r
-unsigned portBASE_TYPE uxSavedInterruptStatus;\r
-\r
- uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
- xReturn = xTickCount;\r
- portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )\r
-{\r
- /* A critical section is not required because the variables are of type\r
- portBASE_TYPE. */\r
- return uxCurrentNumberOfTasks;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-signed char *pcTaskGetTaskName( xTaskHandle xTaskToQuery )\r
-{\r
-tskTCB *pxTCB;\r
-\r
- /* If null is passed in here then we are suspending ourselves. */\r
- pxTCB = prvGetTCBFromHandle( xTaskToQuery );\r
- configASSERT( pxTCB );\r
- return &( pxTCB->pcTaskName[ 0 ] );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( configUSE_TRACE_FACILITY == 1 )\r
-\r
- void vTaskList( signed char *pcWriteBuffer )\r
- {\r
- unsigned portBASE_TYPE uxQueue;\r
-\r
- /* This is a VERY costly function that should be used for debug only.\r
- It leaves interrupts disabled for a LONG time. */\r
-\r
- vTaskSuspendAll();\r
- {\r
- /* Run through all the lists that could potentially contain a TCB and\r
- report the task name, state and stack high water mark. */\r
-\r
- *pcWriteBuffer = ( signed char ) 0x00;\r
- strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );\r
-\r
- uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;\r
-\r
- do\r
- {\r
- uxQueue--;\r
-\r
- if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )\r
- {\r
- prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );\r
- }\r
- }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );\r
-\r
- if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )\r
- {\r
- prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );\r
- }\r
-\r
- if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )\r
- {\r
- prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );\r
- }\r
-\r
- #if( INCLUDE_vTaskDelete == 1 )\r
- {\r
- if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )\r
- {\r
- prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );\r
- }\r
- }\r
- #endif\r
-\r
- #if ( INCLUDE_vTaskSuspend == 1 )\r
- {\r
- if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )\r
- {\r
- prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );\r
- }\r
- }\r
- #endif\r
- }\r
- xTaskResumeAll();\r
- }\r
-\r
-#endif\r
-/*----------------------------------------------------------*/\r
-\r
-#if ( configGENERATE_RUN_TIME_STATS == 1 )\r
-\r
- void vTaskGetRunTimeStats( signed char *pcWriteBuffer )\r
- {\r
- unsigned portBASE_TYPE uxQueue;\r
- unsigned long ulTotalRunTime;\r
-\r
- /* This is a VERY costly function that should be used for debug only.\r
- It leaves interrupts disabled for a LONG time. */\r
-\r
- vTaskSuspendAll();\r
- {\r
- #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE\r
- portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );\r
- #else\r
- ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();\r
- #endif\r
-\r
- /* Divide ulTotalRunTime by 100 to make the percentage caluclations\r
- simpler in the prvGenerateRunTimeStatsForTasksInList() function. */\r
- ulTotalRunTime /= 100UL;\r
- \r
- /* Run through all the lists that could potentially contain a TCB,\r
- generating a table of run timer percentages in the provided\r
- buffer. */\r
-\r
- *pcWriteBuffer = ( signed char ) 0x00;\r
- strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );\r
-\r
- uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;\r
-\r
- do\r
- {\r
- uxQueue--;\r
-\r
- if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )\r
- {\r
- prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime );\r
- }\r
- }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );\r
-\r
- if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )\r
- {\r
- prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime );\r
- }\r
-\r
- if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )\r
- {\r
- prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime );\r
- }\r
-\r
- #if ( INCLUDE_vTaskDelete == 1 )\r
- {\r
- if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )\r
- {\r
- prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime );\r
- }\r
- }\r
- #endif\r
-\r
- #if ( INCLUDE_vTaskSuspend == 1 )\r
- {\r
- if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )\r
- {\r
- prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime );\r
- }\r
- }\r
- #endif\r
- }\r
- xTaskResumeAll();\r
- }\r
-\r
-#endif\r
-/*----------------------------------------------------------*/\r
-\r
-#if ( configUSE_TRACE_FACILITY == 1 )\r
-\r
- void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize )\r
- {\r
- configASSERT( pcBuffer );\r
- configASSERT( ulBufferSize );\r
-\r
- taskENTER_CRITICAL();\r
- {\r
- pcTraceBuffer = ( signed char * )pcBuffer;\r
- pcTraceBufferStart = pcBuffer;\r
- pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );\r
- xTracing = pdTRUE;\r
- }\r
- taskEXIT_CRITICAL();\r
- }\r
-\r
-#endif\r
-/*----------------------------------------------------------*/\r
-\r
-#if ( configUSE_TRACE_FACILITY == 1 )\r
-\r
- unsigned long ulTaskEndTrace( void )\r
- {\r
- unsigned long ulBufferLength;\r
-\r
- taskENTER_CRITICAL();\r
- xTracing = pdFALSE;\r
- taskEXIT_CRITICAL();\r
-\r
- ulBufferLength = ( unsigned long ) ( pcTraceBuffer - pcTraceBufferStart );\r
-\r
- return ulBufferLength;\r
- }\r
-\r
-#endif\r
-/*----------------------------------------------------------*/\r
-\r
-#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )\r
-\r
- xTaskHandle xTaskGetIdleTaskHandle( void )\r
- {\r
- /* If xTaskGetIdleTaskHandle() is called before the scheduler has been\r
- started, then xIdleTaskHandle will be NULL. */\r
- configASSERT( ( xIdleTaskHandle != NULL ) );\r
- return xIdleTaskHandle;\r
- }\r
- \r
-#endif\r
-\r
-/*-----------------------------------------------------------\r
- * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES\r
- * documented in task.h\r
- *----------------------------------------------------------*/\r
-\r
-\r
-void vTaskIncrementTick( void )\r
-{\r
-tskTCB * pxTCB;\r
-\r
- /* Called by the portable layer each time a tick interrupt occurs.\r
- Increments the tick then checks to see if the new tick value will cause any\r
- tasks to be unblocked. */\r
- if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
- {\r
- ++xTickCount;\r
- if( xTickCount == ( portTickType ) 0 )\r
- {\r
- xList *pxTemp;\r
-\r
- /* Tick count has overflowed so we need to swap the delay lists.\r
- If there are any items in pxDelayedTaskList here then there is\r
- an error! */\r
- configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );\r
- \r
- pxTemp = pxDelayedTaskList;\r
- pxDelayedTaskList = pxOverflowDelayedTaskList;\r
- pxOverflowDelayedTaskList = pxTemp;\r
- xNumOfOverflows++;\r
- \r
- if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )\r
- {\r
- /* The new current delayed list is empty. Set \r
- xNextTaskUnblockTime to the maximum possible value so it is \r
- extremely unlikely that the \r
- if( xTickCount >= xNextTaskUnblockTime ) test will pass until \r
- there is an item in the delayed list. */\r
- xNextTaskUnblockTime = portMAX_DELAY;\r
- }\r
- else\r
- {\r
- /* The new current delayed list is not empty, get the value of \r
- the item at the head of the delayed list. This is the time at \r
- which the task at the head of the delayed list should be removed \r
- from the Blocked state. */\r
- pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );\r
- xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );\r
- }\r
- }\r
-\r
- /* See if this tick has made a timeout expire. */\r
- prvCheckDelayedTasks();\r
- }\r
- else\r
- {\r
- ++uxMissedTicks;\r
-\r
- /* The tick hook gets called at regular intervals, even if the\r
- scheduler is locked. */\r
- #if ( configUSE_TICK_HOOK == 1 )\r
- {\r
- vApplicationTickHook();\r
- }\r
- #endif\r
- }\r
-\r
- #if ( configUSE_TICK_HOOK == 1 )\r
- {\r
- /* Guard against the tick hook being called when the missed tick\r
- count is being unwound (when the scheduler is being unlocked. */\r
- if( uxMissedTicks == ( unsigned portBASE_TYPE ) 0U )\r
- {\r
- vApplicationTickHook();\r
- }\r
- }\r
- #endif\r
-\r
- traceTASK_INCREMENT_TICK( xTickCount );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )\r
-\r
- void vTaskCleanUpResources( void )\r
- {\r
- unsigned short usQueue;\r
- volatile tskTCB *pxTCB;\r
-\r
- usQueue = ( unsigned short ) uxTopUsedPriority + ( unsigned short ) 1;\r
-\r
- /* Remove any TCB's from the ready queues. */\r
- do\r
- {\r
- usQueue--;\r
-\r
- while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) == pdFALSE )\r
- {\r
- listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );\r
- vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );\r
-\r
- prvDeleteTCB( ( tskTCB * ) pxTCB );\r
- }\r
- }while( usQueue > ( unsigned short ) tskIDLE_PRIORITY );\r
-\r
- /* Remove any TCB's from the delayed queue. */\r
- while( listLIST_IS_EMPTY( &xDelayedTaskList1 ) == pdFALSE )\r
- {\r
- listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );\r
- vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );\r
-\r
- prvDeleteTCB( ( tskTCB * ) pxTCB );\r
- }\r
-\r
- /* Remove any TCB's from the overflow delayed queue. */\r
- while( listLIST_IS_EMPTY( &xDelayedTaskList2 ) == pdFALSE )\r
- {\r
- listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );\r
- vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );\r
-\r
- prvDeleteTCB( ( tskTCB * ) pxTCB );\r
- }\r
-\r
- while( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )\r
- {\r
- listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );\r
- vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );\r
-\r
- prvDeleteTCB( ( tskTCB * ) pxTCB );\r
- }\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
-\r
- void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction )\r
- {\r
- tskTCB *xTCB;\r
-\r
- /* If xTask is NULL then we are setting our own task hook. */\r
- if( xTask == NULL )\r
- {\r
- xTCB = ( tskTCB * ) pxCurrentTCB;\r
- }\r
- else\r
- {\r
- xTCB = ( tskTCB * ) xTask;\r
- }\r
-\r
- /* Save the hook function in the TCB. A critical section is required as\r
- the value can be accessed from an interrupt. */\r
- taskENTER_CRITICAL();\r
- xTCB->pxTaskTag = pxHookFunction;\r
- taskEXIT_CRITICAL();\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
-\r
- pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )\r
- {\r
- tskTCB *xTCB;\r
- pdTASK_HOOK_CODE xReturn;\r
-\r
- /* If xTask is NULL then we are setting our own task hook. */\r
- if( xTask == NULL )\r
- {\r
- xTCB = ( tskTCB * ) pxCurrentTCB;\r
- }\r
- else\r
- {\r
- xTCB = ( tskTCB * ) xTask;\r
- }\r
-\r
- /* Save the hook function in the TCB. A critical section is required as\r
- the value can be accessed from an interrupt. */\r
- taskENTER_CRITICAL();\r
- xReturn = xTCB->pxTaskTag;\r
- taskEXIT_CRITICAL();\r
-\r
- return xReturn;\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
-\r
- portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )\r
- {\r
- tskTCB *xTCB;\r
- portBASE_TYPE xReturn;\r
-\r
- /* If xTask is NULL then we are calling our own task hook. */\r
- if( xTask == NULL )\r
- {\r
- xTCB = ( tskTCB * ) pxCurrentTCB;\r
- }\r
- else\r
- {\r
- xTCB = ( tskTCB * ) xTask;\r
- }\r
-\r
- if( xTCB->pxTaskTag != NULL )\r
- {\r
- xReturn = xTCB->pxTaskTag( pvParameter );\r
- }\r
- else\r
- {\r
- xReturn = pdFAIL;\r
- }\r
-\r
- return xReturn;\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-void vTaskSwitchContext( void )\r
-{\r
- if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )\r
- {\r
- /* The scheduler is currently suspended - do not allow a context\r
- switch. */\r
- xMissedYield = pdTRUE;\r
- }\r
- else\r
- {\r
- traceTASK_SWITCHED_OUT();\r
- \r
- #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
- {\r
- unsigned long ulTempCounter;\r
- \r
- #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE\r
- portALT_GET_RUN_TIME_COUNTER_VALUE( ulTempCounter );\r
- #else\r
- ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();\r
- #endif\r
- \r
- /* Add the amount of time the task has been running to the accumulated\r
- time so far. The time the task started running was stored in\r
- ulTaskSwitchedInTime. Note that there is no overflow protection here\r
- so count values are only valid until the timer overflows. Generally\r
- this will be about 1 hour assuming a 1uS timer increment. */\r
- pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );\r
- ulTaskSwitchedInTime = ulTempCounter;\r
- }\r
- #endif\r
- \r
- taskFIRST_CHECK_FOR_STACK_OVERFLOW();\r
- taskSECOND_CHECK_FOR_STACK_OVERFLOW();\r
- \r
- /* Find the highest priority queue that contains ready tasks. */\r
- while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )\r
- {\r
- configASSERT( uxTopReadyPriority );\r
- --uxTopReadyPriority;\r
- }\r
- \r
- /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the\r
- same priority get an equal share of the processor time. */\r
- listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );\r
- \r
- traceTASK_SWITCHED_IN();\r
- vWriteTraceToBuffer();\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )\r
-{\r
-portTickType xTimeToWake;\r
-\r
- configASSERT( pxEventList );\r
-\r
- /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE\r
- SCHEDULER SUSPENDED. */\r
-\r
- /* Place the event list item of the TCB in the appropriate event list.\r
- This is placed in the list in priority order so the highest priority task\r
- is the first to be woken by the event. */\r
- vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );\r
-\r
- /* We must remove ourselves from the ready list before adding ourselves\r
- to the blocked list as the same list item is used for both lists. We have\r
- exclusive access to the ready lists as the scheduler is locked. */\r
- vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
-\r
-\r
- #if ( INCLUDE_vTaskSuspend == 1 )\r
- {\r
- if( xTicksToWait == portMAX_DELAY )\r
- {\r
- /* Add ourselves to the suspended task list instead of a delayed task\r
- list to ensure we are not woken by a timing event. We will block\r
- indefinitely. */\r
- vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
- }\r
- else\r
- {\r
- /* Calculate the time at which the task should be woken if the event does\r
- not occur. This may overflow but this doesn't matter. */\r
- xTimeToWake = xTickCount + xTicksToWait;\r
- prvAddCurrentTaskToDelayedList( xTimeToWake );\r
- }\r
- }\r
- #else\r
- {\r
- /* Calculate the time at which the task should be woken if the event does\r
- not occur. This may overflow but this doesn't matter. */\r
- xTimeToWake = xTickCount + xTicksToWait;\r
- prvAddCurrentTaskToDelayedList( xTimeToWake );\r
- }\r
- #endif\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if configUSE_TIMERS == 1\r
-\r
- void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait )\r
- {\r
- portTickType xTimeToWake;\r
-\r
- configASSERT( pxEventList );\r
-\r
- /* This function should not be called by application code hence the\r
- 'Restricted' in its name. It is not part of the public API. It is\r
- designed for use by kernel code, and has special calling requirements -\r
- it should be called from a critical section. */\r
-\r
-\r
- /* Place the event list item of the TCB in the appropriate event list.\r
- In this case it is assume that this is the only task that is going to\r
- be waiting on this event list, so the faster vListInsertEnd() function\r
- can be used in place of vListInsert. */\r
- vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );\r
-\r
- /* We must remove this task from the ready list before adding it to the\r
- blocked list as the same list item is used for both lists. This\r
- function is called form a critical section. */\r
- vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
-\r
- /* Calculate the time at which the task should be woken if the event does\r
- not occur. This may overflow but this doesn't matter. */\r
- xTimeToWake = xTickCount + xTicksToWait;\r
- prvAddCurrentTaskToDelayedList( xTimeToWake );\r
- }\r
- \r
-#endif /* configUSE_TIMERS */\r
-/*-----------------------------------------------------------*/\r
-\r
-signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )\r
-{\r
-tskTCB *pxUnblockedTCB;\r
-portBASE_TYPE xReturn;\r
-\r
- /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE\r
- SCHEDULER SUSPENDED. It can also be called from within an ISR. */\r
-\r
- /* The event list is sorted in priority order, so we can remove the\r
- first in the list, remove the TCB from the delayed list, and add\r
- it to the ready list.\r
-\r
- If an event is for a queue that is locked then this function will never\r
- get called - the lock count on the queue will get modified instead. This\r
- means we can always expect exclusive access to the event list here.\r
- \r
- This function assumes that a check has already been made to ensure that\r
- pxEventList is not empty. */\r
- pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );\r
- configASSERT( pxUnblockedTCB );\r
- vListRemove( &( pxUnblockedTCB->xEventListItem ) );\r
-\r
- if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
- {\r
- vListRemove( &( pxUnblockedTCB->xGenericListItem ) );\r
- prvAddTaskToReadyQueue( pxUnblockedTCB );\r
- }\r
- else\r
- {\r
- /* We cannot access the delayed or ready lists, so will hold this\r
- task pending until the scheduler is resumed. */\r
- vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );\r
- }\r
-\r
- if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
- {\r
- /* Return true if the task removed from the event list has\r
- a higher priority than the calling task. This allows\r
- the calling task to know if it should force a context\r
- switch now. */\r
- xReturn = pdTRUE;\r
- }\r
- else\r
- {\r
- xReturn = pdFALSE;\r
- }\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )\r
-{\r
- configASSERT( pxTimeOut );\r
- pxTimeOut->xOverflowCount = xNumOfOverflows;\r
- pxTimeOut->xTimeOnEntering = xTickCount;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )\r
-{\r
-portBASE_TYPE xReturn;\r
-\r
- configASSERT( pxTimeOut );\r
- configASSERT( pxTicksToWait );\r
-\r
- taskENTER_CRITICAL();\r
- {\r
- #if ( INCLUDE_vTaskSuspend == 1 )\r
- /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is\r
- the maximum block time then the task should block indefinitely, and\r
- therefore never time out. */\r
- if( *pxTicksToWait == portMAX_DELAY )\r
- {\r
- xReturn = pdFALSE;\r
- }\r
- else /* We are not blocking indefinitely, perform the checks below. */\r
- #endif\r
-\r
- if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )\r
- {\r
- /* The tick count is greater than the time at which vTaskSetTimeout()\r
- was called, but has also overflowed since vTaskSetTimeOut() was called.\r
- It must have wrapped all the way around and gone past us again. This\r
- passed since vTaskSetTimeout() was called. */\r
- xReturn = pdTRUE;\r
- }\r
- else if( ( ( portTickType ) ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) ) < ( portTickType ) *pxTicksToWait )\r
- {\r
- /* Not a genuine timeout. Adjust parameters for time remaining. */\r
- *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );\r
- vTaskSetTimeOutState( pxTimeOut );\r
- xReturn = pdFALSE;\r
- }\r
- else\r
- {\r
- xReturn = pdTRUE;\r
- }\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vTaskMissedYield( void )\r
-{\r
- xMissedYield = pdTRUE;\r
-}\r
-\r
-/*\r
- * -----------------------------------------------------------\r
- * The Idle task.\r
- * ----------------------------------------------------------\r
- *\r
- * The portTASK_FUNCTION() macro is used to allow port/compiler specific\r
- * language extensions. The equivalent prototype for this function is:\r
- *\r
- * void prvIdleTask( void *pvParameters );\r
- *\r
- */\r
-static portTASK_FUNCTION( prvIdleTask, pvParameters )\r
-{\r
- /* Stop warnings. */\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* See if any tasks have been deleted. */\r
- prvCheckTasksWaitingTermination();\r
-\r
- #if ( configUSE_PREEMPTION == 0 )\r
- {\r
- /* If we are not using preemption we keep forcing a task switch to\r
- see if any other task has become available. If we are using\r
- preemption we don't need to do this as any task becoming available\r
- will automatically get the processor anyway. */\r
- taskYIELD();\r
- }\r
- #endif\r
-\r
- #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )\r
- {\r
- /* When using preemption tasks of equal priority will be\r
- timesliced. If a task that is sharing the idle priority is ready\r
- to run then the idle task should yield before the end of the\r
- timeslice.\r
-\r
- A critical region is not required here as we are just reading from\r
- the list, and an occasional incorrect value will not matter. If\r
- the ready list at the idle priority contains more than one task\r
- then a task other than the idle task is ready to execute. */\r
- if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )\r
- {\r
- taskYIELD();\r
- }\r
- }\r
- #endif\r
-\r
- #if ( configUSE_IDLE_HOOK == 1 )\r
- {\r
- extern void vApplicationIdleHook( void );\r
-\r
- /* Call the user defined function from within the idle task. This\r
- allows the application designer to add background functionality\r
- without the overhead of a separate task.\r
- NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,\r
- CALL A FUNCTION THAT MIGHT BLOCK. */\r
- vApplicationIdleHook();\r
- }\r
- #endif\r
- }\r
-} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-/*-----------------------------------------------------------\r
- * File private functions documented at the top of the file.\r
- *----------------------------------------------------------*/\r
-\r
-\r
-\r
-static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )\r
-{\r
- /* Store the function name in the TCB. */\r
- #if configMAX_TASK_NAME_LEN > 1\r
- {\r
- /* Don't bring strncpy into the build unnecessarily. */\r
- strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN );\r
- }\r
- #endif\r
- pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = ( signed char ) '\0';\r
-\r
- /* This is used as an array index so must ensure it's not too large. First\r
- remove the privilege bit if one is present. */\r
- if( uxPriority >= configMAX_PRIORITIES )\r
- {\r
- uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;\r
- }\r
-\r
- pxTCB->uxPriority = uxPriority;\r
- #if ( configUSE_MUTEXES == 1 )\r
- {\r
- pxTCB->uxBasePriority = uxPriority;\r
- }\r
- #endif\r
-\r
- vListInitialiseItem( &( pxTCB->xGenericListItem ) );\r
- vListInitialiseItem( &( pxTCB->xEventListItem ) );\r
-\r
- /* Set the pxTCB as a link back from the xListItem. This is so we can get\r
- back to the containing TCB from a generic item in a list. */\r
- listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );\r
-\r
- /* Event lists are always in priority order. */\r
- listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );\r
- listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );\r
-\r
- #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
- {\r
- pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;\r
- }\r
- #endif\r
-\r
- #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
- {\r
- pxTCB->pxTaskTag = NULL;\r
- }\r
- #endif\r
-\r
- #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
- {\r
- pxTCB->ulRunTimeCounter = 0UL;\r
- }\r
- #endif\r
-\r
- #if ( portUSING_MPU_WRAPPERS == 1 )\r
- {\r
- vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );\r
- }\r
- #else\r
- {\r
- ( void ) xRegions;\r
- ( void ) usStackDepth;\r
- }\r
- #endif\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( portUSING_MPU_WRAPPERS == 1 )\r
-\r
- void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )\r
- {\r
- tskTCB *pxTCB;\r
- \r
- if( xTaskToModify == pxCurrentTCB )\r
- {\r
- xTaskToModify = NULL;\r
- }\r
-\r
- /* If null is passed in here then we are deleting ourselves. */\r
- pxTCB = prvGetTCBFromHandle( xTaskToModify );\r
-\r
- vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );\r
- }\r
- /*-----------------------------------------------------------*/\r
-#endif\r
-\r
-static void prvInitialiseTaskLists( void )\r
-{\r
-unsigned portBASE_TYPE uxPriority;\r
-\r
- for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < configMAX_PRIORITIES; uxPriority++ )\r
- {\r
- vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );\r
- }\r
-\r
- vListInitialise( ( xList * ) &xDelayedTaskList1 );\r
- vListInitialise( ( xList * ) &xDelayedTaskList2 );\r
- vListInitialise( ( xList * ) &xPendingReadyList );\r
-\r
- #if ( INCLUDE_vTaskDelete == 1 )\r
- {\r
- vListInitialise( ( xList * ) &xTasksWaitingTermination );\r
- }\r
- #endif\r
-\r
- #if ( INCLUDE_vTaskSuspend == 1 )\r
- {\r
- vListInitialise( ( xList * ) &xSuspendedTaskList );\r
- }\r
- #endif\r
-\r
- /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList\r
- using list2. */\r
- pxDelayedTaskList = &xDelayedTaskList1;\r
- pxOverflowDelayedTaskList = &xDelayedTaskList2;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCheckTasksWaitingTermination( void )\r
-{\r
- #if ( INCLUDE_vTaskDelete == 1 )\r
- {\r
- portBASE_TYPE xListIsEmpty;\r
-\r
- /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called\r
- too often in the idle task. */\r
- if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )\r
- {\r
- vTaskSuspendAll();\r
- xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );\r
- xTaskResumeAll();\r
-\r
- if( xListIsEmpty == pdFALSE )\r
- {\r
- tskTCB *pxTCB;\r
-\r
- taskENTER_CRITICAL();\r
- {\r
- pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );\r
- vListRemove( &( pxTCB->xGenericListItem ) );\r
- --uxCurrentNumberOfTasks;\r
- --uxTasksDeleted;\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- prvDeleteTCB( pxTCB );\r
- }\r
- }\r
- }\r
- #endif\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake )\r
-{\r
- /* The list item will be inserted in wake time order. */\r
- listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );\r
-\r
- if( xTimeToWake < xTickCount )\r
- {\r
- /* Wake time has overflowed. Place this item in the overflow list. */\r
- vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
- }\r
- else\r
- {\r
- /* The wake time has not overflowed, so we can use the current block list. */\r
- vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
-\r
- /* If the task entering the blocked state was placed at the head of the\r
- list of blocked tasks then xNextTaskUnblockTime needs to be updated\r
- too. */\r
- if( xTimeToWake < xNextTaskUnblockTime )\r
- {\r
- xNextTaskUnblockTime = xTimeToWake;\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )\r
-{\r
-tskTCB *pxNewTCB;\r
-\r
- /* Allocate space for the TCB. Where the memory comes from depends on\r
- the implementation of the port malloc function. */\r
- pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );\r
-\r
- if( pxNewTCB != NULL )\r
- {\r
- /* Allocate space for the stack used by the task being created.\r
- The base of the stack memory stored in the TCB so the task can\r
- be deleted later if required. */\r
- pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );\r
-\r
- if( pxNewTCB->pxStack == NULL )\r
- {\r
- /* Could not allocate the stack. Delete the allocated TCB. */\r
- vPortFree( pxNewTCB );\r
- pxNewTCB = NULL;\r
- }\r
- else\r
- {\r
- /* Just to help debugging. */\r
- memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );\r
- }\r
- }\r
-\r
- return pxNewTCB;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( configUSE_TRACE_FACILITY == 1 )\r
-\r
- static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus )\r
- {\r
- volatile tskTCB *pxNextTCB, *pxFirstTCB;\r
- unsigned short usStackRemaining;\r
-\r
- /* Write the details of all the TCB's in pxList into the buffer. */\r
- listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );\r
- do\r
- {\r
- listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );\r
- #if ( portSTACK_GROWTH > 0 )\r
- {\r
- usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );\r
- }\r
- #else\r
- {\r
- usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );\r
- }\r
- #endif \r
- \r
- sprintf( pcStatusString, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );\r
- strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatusString );\r
-\r
- } while( pxNextTCB != pxFirstTCB );\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( configGENERATE_RUN_TIME_STATS == 1 )\r
-\r
- static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime )\r
- {\r
- volatile tskTCB *pxNextTCB, *pxFirstTCB;\r
- unsigned long ulStatsAsPercentage;\r
-\r
- /* Write the run time stats of all the TCB's in pxList into the buffer. */\r
- listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );\r
- do\r
- {\r
- /* Get next TCB in from the list. */\r
- listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );\r
-\r
- /* Divide by zero check. */\r
- if( ulTotalRunTime > 0UL )\r
- {\r
- /* Has the task run at all? */\r
- if( pxNextTCB->ulRunTimeCounter == 0 )\r
- {\r
- /* The task has used no CPU time at all. */\r
- sprintf( pcStatsString, ( char * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );\r
- }\r
- else\r
- {\r
- /* What percentage of the total run time has the task used?\r
- This will always be rounded down to the nearest integer.\r
- ulTotalRunTime has already been divided by 100. */\r
- ulStatsAsPercentage = pxNextTCB->ulRunTimeCounter / ulTotalRunTime;\r
-\r
- if( ulStatsAsPercentage > 0UL )\r
- {\r
- #ifdef portLU_PRINTF_SPECIFIER_REQUIRED\r
- {\r
- sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter, ulStatsAsPercentage ); \r
- }\r
- #else\r
- {\r
- /* sizeof( int ) == sizeof( long ) so a smaller\r
- printf() library can be used. */\r
- sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );\r
- }\r
- #endif\r
- }\r
- else\r
- {\r
- /* If the percentage is zero here then the task has\r
- consumed less than 1% of the total run time. */\r
- #ifdef portLU_PRINTF_SPECIFIER_REQUIRED\r
- {\r
- sprintf( pcStatsString, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter ); \r
- }\r
- #else\r
- {\r
- /* sizeof( int ) == sizeof( long ) so a smaller\r
- printf() library can be used. */\r
- sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );\r
- }\r
- #endif\r
- }\r
- }\r
-\r
- strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatsString );\r
- }\r
-\r
- } while( pxNextTCB != pxFirstTCB );\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )\r
-\r
- static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte )\r
- {\r
- register unsigned short usCount = 0;\r
-\r
- while( *pucStackByte == tskSTACK_FILL_BYTE )\r
- {\r
- pucStackByte -= portSTACK_GROWTH;\r
- usCount++;\r
- }\r
-\r
- usCount /= sizeof( portSTACK_TYPE );\r
-\r
- return usCount;\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )\r
-\r
- unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )\r
- {\r
- tskTCB *pxTCB;\r
- unsigned char *pcEndOfStack;\r
- unsigned portBASE_TYPE uxReturn;\r
-\r
- pxTCB = prvGetTCBFromHandle( xTask );\r
-\r
- #if portSTACK_GROWTH < 0\r
- {\r
- pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;\r
- }\r
- #else\r
- {\r
- pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;\r
- }\r
- #endif\r
-\r
- uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );\r
-\r
- return uxReturn;\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )\r
-\r
- static void prvDeleteTCB( tskTCB *pxTCB )\r
- {\r
- /* Free up the memory allocated by the scheduler for the task. It is up to\r
- the task to free any memory allocated at the application level. */\r
- vPortFreeAligned( pxTCB->pxStack );\r
- vPortFree( pxTCB );\r
- }\r
-\r
-#endif\r
-\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )\r
-\r
- xTaskHandle xTaskGetCurrentTaskHandle( void )\r
- {\r
- xTaskHandle xReturn;\r
-\r
- /* A critical section is not required as this is not called from\r
- an interrupt and the current TCB will always be the same for any\r
- individual execution thread. */\r
- xReturn = pxCurrentTCB;\r
-\r
- return xReturn;\r
- }\r
-\r
-#endif\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )\r
-\r
- portBASE_TYPE xTaskGetSchedulerState( void )\r
- {\r
- portBASE_TYPE xReturn;\r
-\r
- if( xSchedulerRunning == pdFALSE )\r
- {\r
- xReturn = taskSCHEDULER_NOT_STARTED;\r
- }\r
- else\r
- {\r
- if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
- {\r
- xReturn = taskSCHEDULER_RUNNING;\r
- }\r
- else\r
- {\r
- xReturn = taskSCHEDULER_SUSPENDED;\r
- }\r
- }\r
-\r
- return xReturn;\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( configUSE_MUTEXES == 1 )\r
-\r
- void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )\r
- {\r
- tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;\r
-\r
- configASSERT( pxMutexHolder );\r
-\r
- if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )\r
- {\r
- /* Adjust the mutex holder state to account for its new priority. */\r
- listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );\r
-\r
- /* If the task being modified is in the ready state it will need to\r
- be moved in to a new list. */\r
- if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )\r
- {\r
- vListRemove( &( pxTCB->xGenericListItem ) );\r
-\r
- /* Inherit the priority before being moved into the new list. */\r
- pxTCB->uxPriority = pxCurrentTCB->uxPriority;\r
- prvAddTaskToReadyQueue( pxTCB );\r
- }\r
- else\r
- {\r
- /* Just inherit the priority. */\r
- pxTCB->uxPriority = pxCurrentTCB->uxPriority;\r
- }\r
- }\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( configUSE_MUTEXES == 1 )\r
-\r
- void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )\r
- {\r
- tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;\r
-\r
- if( pxMutexHolder != NULL )\r
- {\r
- if( pxTCB->uxPriority != pxTCB->uxBasePriority )\r
- {\r
- /* We must be the running task to be able to give the mutex back.\r
- Remove ourselves from the ready list we currently appear in. */\r
- vListRemove( &( pxTCB->xGenericListItem ) );\r
-\r
- /* Disinherit the priority before adding ourselves into the new\r
- ready list. */\r
- pxTCB->uxPriority = pxTCB->uxBasePriority;\r
- listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );\r
- prvAddTaskToReadyQueue( pxTCB );\r
- }\r
- }\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
-\r
- void vTaskEnterCritical( void )\r
- {\r
- portDISABLE_INTERRUPTS();\r
-\r
- if( xSchedulerRunning != pdFALSE )\r
- {\r
- ( pxCurrentTCB->uxCriticalNesting )++;\r
- }\r
- }\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
-\r
-void vTaskExitCritical( void )\r
-{\r
- if( xSchedulerRunning != pdFALSE )\r
- {\r
- if( pxCurrentTCB->uxCriticalNesting > 0 )\r
- {\r
- ( pxCurrentTCB->uxCriticalNesting )--;\r
-\r
- if( pxCurrentTCB->uxCriticalNesting == 0 )\r
- {\r
- portENABLE_INTERRUPTS();\r
- }\r
- }\r
- }\r
-}\r
-\r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-\r
-\r
-\r
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- FreeRTOS supports many tools and architectures. V7.0.0 is sponsored by:\r
- Atollic AB - Atollic provides professional embedded systems development \r
- tools for C/C++ development, code analysis and test automation. \r
- See http://www.atollic.com\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
-all the API functions to use the MPU wrappers. That should only be done when\r
-task.h is included from an application file. */\r
-#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
-\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-#include "timers.h"\r
-\r
-#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
-\r
-/* This entire source file will be skipped if the application is not configured\r
-to include software timer functionality. This #if is closed at the very bottom\r
-of this file. If you want to include software timer functionality then ensure\r
-configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */\r
-#if ( configUSE_TIMERS == 1 )\r
-\r
-/* Misc definitions. */\r
-#define tmrNO_DELAY ( portTickType ) 0U\r
-\r
-/* The definition of the timers themselves. */\r
-typedef struct tmrTimerControl\r
-{\r
- const signed char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */\r
- xListItem xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */\r
- portTickType xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */\r
- unsigned portBASE_TYPE uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one shot timer. */\r
- void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */\r
- tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */\r
-} xTIMER;\r
-\r
-/* The definition of messages that can be sent and received on the timer\r
-queue. */\r
-typedef struct tmrTimerQueueMessage\r
-{\r
- portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */\r
- portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */\r
- xTIMER * pxTimer; /*<< The timer to which the command will be applied. */\r
-} xTIMER_MESSAGE;\r
-\r
-\r
-/* The list in which active timers are stored. Timers are referenced in expire\r
-time order, with the nearest expiry time at the front of the list. Only the\r
-timer service task is allowed to access xActiveTimerList. */\r
-PRIVILEGED_DATA static xList xActiveTimerList1;\r
-PRIVILEGED_DATA static xList xActiveTimerList2;\r
-PRIVILEGED_DATA static xList *pxCurrentTimerList;\r
-PRIVILEGED_DATA static xList *pxOverflowTimerList;\r
-\r
-/* A queue that is used to send commands to the timer service task. */\r
-PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;\r
-\r
-#if ( INCLUDE_xTimerGetTimerTaskHandle == 1 )\r
- \r
- PRIVILEGED_DATA static xTaskHandle xTimerTaskHandle = NULL;\r
- \r
-#endif\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Initialise the infrastructure used by the timer service task if it has not\r
- * been initialised already.\r
- */\r
-static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * The timer service task (daemon). Timer functionality is controlled by this\r
- * task. Other tasks communicate with the timer service task using the\r
- * xTimerQueue queue.\r
- */\r
-static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Called by the timer service task to interpret and process a command it\r
- * received on the timer queue.\r
- */\r
-static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,\r
- * depending on if the expire time causes a timer counter overflow.\r
- */\r
-static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * An active timer has reached its expire time. Reload the timer if it is an\r
- * auto reload timer, then call its callback.\r
- */\r
-static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * The tick count has overflowed. Switch the timer lists after ensuring the\r
- * current timer list does not still reference some timers.\r
- */\r
-static void prvSwitchTimerLists( portTickType xLastTime ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE\r
- * if a tick count overflow occurred since prvSampleTimeNow() was last called.\r
- */\r
-static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * If the timer list contains any active timers then return the expire time of\r
- * the timer that will expire first and set *pxListWasEmpty to false. If the\r
- * timer list does not contain any timers then return 0 and set *pxListWasEmpty\r
- * to pdTRUE.\r
- */\r
-static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION;\r
-\r
-/*\r
- * If a timer has expired, process it. Otherwise, block the timer service task\r
- * until either a timer does expire or a command is received.\r
- */\r
-static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-portBASE_TYPE xTimerCreateTimerTask( void )\r
-{\r
-portBASE_TYPE xReturn = pdFAIL;\r
-\r
- /* This function is called when the scheduler is started if\r
- configUSE_TIMERS is set to 1. Check that the infrastructure used by the\r
- timer service task has been created/initialised. If timers have already\r
- been created then the initialisation will already have been performed. */\r
- prvCheckForValidListAndQueue();\r
-\r
- if( xTimerQueue != NULL )\r
- {\r
- #if ( INCLUDE_xTimerGetTimerTaskHandle == 1 )\r
- {\r
- /* Create the timer task, storing its handle in xTimerTaskHandle so\r
- it can be returned by the xTimerGetTimerTaskHandle() function. */\r
- xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY, &xTimerTaskHandle ); \r
- }\r
- #else\r
- {\r
- /* Create the timer task without storing its handle. */\r
- xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY, NULL);\r
- }\r
- #endif\r
- }\r
-\r
- configASSERT( xReturn );\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction )\r
-{\r
-xTIMER *pxNewTimer;\r
-\r
- /* Allocate the timer structure. */\r
- if( xTimerPeriodInTicks == ( portTickType ) 0U )\r
- {\r
- pxNewTimer = NULL;\r
- configASSERT( ( xTimerPeriodInTicks > 0 ) );\r
- }\r
- else\r
- {\r
- pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );\r
- if( pxNewTimer != NULL )\r
- {\r
- /* Ensure the infrastructure used by the timer service task has been\r
- created/initialised. */\r
- prvCheckForValidListAndQueue();\r
- \r
- /* Initialise the timer structure members using the function parameters. */\r
- pxNewTimer->pcTimerName = pcTimerName;\r
- pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;\r
- pxNewTimer->uxAutoReload = uxAutoReload;\r
- pxNewTimer->pvTimerID = pvTimerID;\r
- pxNewTimer->pxCallbackFunction = pxCallbackFunction;\r
- vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );\r
- \r
- traceTIMER_CREATE( pxNewTimer );\r
- }\r
- else\r
- {\r
- traceTIMER_CREATE_FAILED();\r
- }\r
- }\r
- \r
- return ( xTimerHandle ) pxNewTimer;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime )\r
-{\r
-portBASE_TYPE xReturn = pdFAIL;\r
-xTIMER_MESSAGE xMessage;\r
-\r
- /* Send a message to the timer service task to perform a particular action\r
- on a particular timer definition. */\r
- if( xTimerQueue != NULL )\r
- {\r
- /* Send a command to the timer service task to start the xTimer timer. */\r
- xMessage.xMessageID = xCommandID;\r
- xMessage.xMessageValue = xOptionalValue;\r
- xMessage.pxTimer = ( xTIMER * ) xTimer;\r
-\r
- if( pxHigherPriorityTaskWoken == NULL )\r
- {\r
- if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )\r
- {\r
- xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );\r
- }\r
- else\r
- {\r
- xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );\r
- }\r
- }\r
- else\r
- {\r
- xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );\r
- }\r
- \r
- traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );\r
- }\r
- \r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if ( INCLUDE_xTimerGetTimerTaskHandle == 1 )\r
-\r
- xTaskHandle xTimerGetTimerTaskHandle( void )\r
- {\r
- /* If xTimerGetTimerTaskHandle() is called before the scheduler has been\r
- started, then xTimerTaskHandle will be NULL. */\r
- configASSERT( ( xTimerTaskHandle != NULL ) );\r
- return xTimerTaskHandle;\r
- }\r
- \r
-#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow )\r
-{\r
-xTIMER *pxTimer;\r
-portBASE_TYPE xResult;\r
-\r
- /* Remove the timer from the list of active timers. A check has already\r
- been performed to ensure the list is not empty. */\r
- pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );\r
- vListRemove( &( pxTimer->xTimerListItem ) );\r
- traceTIMER_EXPIRED( pxTimer );\r
-\r
- /* If the timer is an auto reload timer then calculate the next\r
- expiry time and re-insert the timer in the list of active timers. */\r
- if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )\r
- {\r
- /* This is the only time a timer is inserted into a list using\r
- a time relative to anything other than the current time. It\r
- will therefore be inserted into the correct list relative to\r
- the time this task thinks it is now, even if a command to\r
- switch lists due to a tick count overflow is already waiting in\r
- the timer queue. */\r
- if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE )\r
- {\r
- /* The timer expired before it was added to the active timer\r
- list. Reload it now. */\r
- xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );\r
- configASSERT( xResult );\r
- ( void ) xResult;\r
- }\r
- }\r
-\r
- /* Call the timer callback. */\r
- pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvTimerTask( void *pvParameters )\r
-{\r
-portTickType xNextExpireTime;\r
-portBASE_TYPE xListWasEmpty;\r
-\r
- /* Just to avoid compiler warnings. */\r
- ( void ) pvParameters;\r
-\r
- for( ;; )\r
- {\r
- /* Query the timers list to see if it contains any timers, and if so,\r
- obtain the time at which the next timer will expire. */\r
- xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );\r
-\r
- /* If a timer has expired, process it. Otherwise, block this task\r
- until either a timer does expire, or a command is received. */\r
- prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );\r
- \r
- /* Empty the command queue. */\r
- prvProcessReceivedCommands(); \r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty )\r
-{\r
-portTickType xTimeNow;\r
-portBASE_TYPE xTimerListsWereSwitched;\r
-\r
- vTaskSuspendAll();\r
- {\r
- /* Obtain the time now to make an assessment as to whether the timer\r
- has expired or not. If obtaining the time causes the lists to switch\r
- then don't process this timer as any timers that remained in the list\r
- when the lists were switched will have been processed within the\r
- prvSampelTimeNow() function. */\r
- xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );\r
- if( xTimerListsWereSwitched == pdFALSE )\r
- {\r
- /* The tick count has not overflowed, has the timer expired? */\r
- if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )\r
- {\r
- xTaskResumeAll();\r
- prvProcessExpiredTimer( xNextExpireTime, xTimeNow );\r
- }\r
- else\r
- {\r
- /* The tick count has not overflowed, and the next expire\r
- time has not been reached yet. This task should therefore\r
- block to wait for the next expire time or a command to be\r
- received - whichever comes first. The following line cannot\r
- be reached unless xNextExpireTime > xTimeNow, except in the\r
- case when the current timer list is empty. */\r
- vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );\r
-\r
- if( xTaskResumeAll() == pdFALSE )\r
- {\r
- /* Yield to wait for either a command to arrive, or the block time\r
- to expire. If a command arrived between the critical section being\r
- exited and this yield then the yield will not cause the task\r
- to block. */\r
- portYIELD_WITHIN_API();\r
- }\r
- }\r
- }\r
- else\r
- {\r
- xTaskResumeAll();\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty )\r
-{\r
-portTickType xNextExpireTime;\r
-\r
- /* Timers are listed in expiry time order, with the head of the list\r
- referencing the task that will expire first. Obtain the time at which\r
- the timer with the nearest expiry time will expire. If there are no\r
- active timers then just set the next expire time to 0. That will cause\r
- this task to unblock when the tick count overflows, at which point the\r
- timer lists will be switched and the next expiry time can be\r
- re-assessed. */\r
- *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );\r
- if( *pxListWasEmpty == pdFALSE )\r
- {\r
- xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );\r
- }\r
- else\r
- {\r
- /* Ensure the task unblocks when the tick count rolls over. */\r
- xNextExpireTime = ( portTickType ) 0U;\r
- }\r
-\r
- return xNextExpireTime;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched )\r
-{\r
-portTickType xTimeNow;\r
-static portTickType xLastTime = ( portTickType ) 0U;\r
-\r
- xTimeNow = xTaskGetTickCount();\r
- \r
- if( xTimeNow < xLastTime )\r
- {\r
- prvSwitchTimerLists( xLastTime );\r
- *pxTimerListsWereSwitched = pdTRUE;\r
- }\r
- else\r
- {\r
- *pxTimerListsWereSwitched = pdFALSE;\r
- }\r
- \r
- xLastTime = xTimeNow;\r
- \r
- return xTimeNow;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime )\r
-{\r
-portBASE_TYPE xProcessTimerNow = pdFALSE;\r
-\r
- listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );\r
- listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );\r
- \r
- if( xNextExpiryTime <= xTimeNow )\r
- {\r
- /* Has the expiry time elapsed between the command to start/reset a\r
- timer was issued, and the time the command was processed? */\r
- if( ( ( portTickType ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks )\r
- {\r
- /* The time between a command being issued and the command being\r
- processed actually exceeds the timers period. */\r
- xProcessTimerNow = pdTRUE;\r
- }\r
- else\r
- {\r
- vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );\r
- }\r
- }\r
- else\r
- {\r
- if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )\r
- {\r
- /* If, since the command was issued, the tick count has overflowed\r
- but the expiry time has not, then the timer must have already passed\r
- its expiry time and should be processed immediately. */\r
- xProcessTimerNow = pdTRUE;\r
- }\r
- else\r
- {\r
- vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );\r
- }\r
- }\r
-\r
- return xProcessTimerNow;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvProcessReceivedCommands( void )\r
-{\r
-xTIMER_MESSAGE xMessage;\r
-xTIMER *pxTimer;\r
-portBASE_TYPE xTimerListsWereSwitched, xResult;\r
-portTickType xTimeNow;\r
-\r
- /* In this case the xTimerListsWereSwitched parameter is not used, but it\r
- must be present in the function call. */\r
- xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );\r
-\r
- while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )\r
- {\r
- pxTimer = xMessage.pxTimer;\r
-\r
- /* Is the timer already in a list of active timers? When the command\r
- is trmCOMMAND_PROCESS_TIMER_OVERFLOW, the timer will be NULL as the\r
- command is to the task rather than to an individual timer. */\r
- if( pxTimer != NULL )\r
- {\r
- if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )\r
- {\r
- /* The timer is in a list, remove it. */\r
- vListRemove( &( pxTimer->xTimerListItem ) );\r
- }\r
- }\r
-\r
- traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue );\r
- \r
- switch( xMessage.xMessageID )\r
- {\r
- case tmrCOMMAND_START : \r
- /* Start or restart a timer. */\r
- if( prvInsertTimerInActiveList( pxTimer, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE )\r
- {\r
- /* The timer expired before it was added to the active timer\r
- list. Process it now. */\r
- pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );\r
-\r
- if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )\r
- {\r
- xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );\r
- configASSERT( xResult );\r
- ( void ) xResult;\r
- }\r
- }\r
- break;\r
-\r
- case tmrCOMMAND_STOP : \r
- /* The timer has already been removed from the active list.\r
- There is nothing to do here. */\r
- break;\r
-\r
- case tmrCOMMAND_CHANGE_PERIOD :\r
- pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;\r
- configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );\r
- prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );\r
- break;\r
-\r
- case tmrCOMMAND_DELETE :\r
- /* The timer has already been removed from the active list,\r
- just free up the memory. */\r
- vPortFree( pxTimer );\r
- break;\r
-\r
- default : \r
- /* Don't expect to get here. */\r
- break;\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvSwitchTimerLists( portTickType xLastTime )\r
-{\r
-portTickType xNextExpireTime, xReloadTime;\r
-xList *pxTemp;\r
-xTIMER *pxTimer;\r
-portBASE_TYPE xResult;\r
-\r
- /* Remove compiler warnings if configASSERT() is not defined. */\r
- ( void ) xLastTime;\r
- \r
- /* The tick count has overflowed. The timer lists must be switched.\r
- If there are any timers still referenced from the current timer list\r
- then they must have expired and should be processed before the lists\r
- are switched. */\r
- while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )\r
- {\r
- xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );\r
-\r
- /* Remove the timer from the list. */\r
- pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );\r
- vListRemove( &( pxTimer->xTimerListItem ) );\r
-\r
- /* Execute its callback, then send a command to restart the timer if\r
- it is an auto-reload timer. It cannot be restarted here as the lists\r
- have not yet been switched. */\r
- pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );\r
-\r
- if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )\r
- {\r
- /* Calculate the reload value, and if the reload value results in\r
- the timer going into the same timer list then it has already expired\r
- and the timer should be re-inserted into the current list so it is\r
- processed again within this loop. Otherwise a command should be sent\r
- to restart the timer to ensure it is only inserted into a list after\r
- the lists have been swapped. */\r
- xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );\r
- if( xReloadTime > xNextExpireTime )\r
- {\r
- listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );\r
- listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );\r
- vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );\r
- }\r
- else\r
- {\r
- xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );\r
- configASSERT( xResult );\r
- ( void ) xResult;\r
- }\r
- }\r
- }\r
-\r
- pxTemp = pxCurrentTimerList;\r
- pxCurrentTimerList = pxOverflowTimerList;\r
- pxOverflowTimerList = pxTemp;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCheckForValidListAndQueue( void )\r
-{\r
- /* Check that the list from which active timers are referenced, and the\r
- queue used to communicate with the timer service, have been\r
- initialised. */\r
- taskENTER_CRITICAL();\r
- {\r
- if( xTimerQueue == NULL )\r
- {\r
- vListInitialise( &xActiveTimerList1 );\r
- vListInitialise( &xActiveTimerList2 );\r
- pxCurrentTimerList = &xActiveTimerList1;\r
- pxOverflowTimerList = &xActiveTimerList2;\r
- xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );\r
- }\r
- }\r
- taskEXIT_CRITICAL();\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer )\r
-{\r
-portBASE_TYPE xTimerIsInActiveList;\r
-xTIMER *pxTimer = ( xTIMER * ) xTimer;\r
-\r
- /* Is the timer in the list of active timers? */\r
- taskENTER_CRITICAL();\r
- {\r
- /* Checking to see if it is in the NULL list in effect checks to see if\r
- it is referenced from either the current or the overflow timer lists in\r
- one go, but the logic has to be reversed, hence the '!'. */\r
- xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );\r
- }\r
- taskEXIT_CRITICAL();\r
-\r
- return xTimerIsInActiveList;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void *pvTimerGetTimerID( xTimerHandle xTimer )\r
-{\r
-xTIMER *pxTimer = ( xTIMER * ) xTimer;\r
-\r
- return pxTimer->pvTimerID;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-/* This entire source file will be skipped if the application is not configured\r
-to include software timer functionality. If you want to include software timer\r
-functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */\r
-#endif /* configUSE_TIMERS == 1 */\r
+++ /dev/null
-/**
- * @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 */
+++ /dev/null
-/**
- * @file
- * Sequential API Internal module
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/api_msg.h"
-
-#include "lwip/ip.h"
-#include "lwip/udp.h"
-#include "lwip/tcp.h"
-#include "lwip/raw.h"
-
-#include "lwip/memp.h"
-#include "lwip/tcpip.h"
-#include "lwip/igmp.h"
-#include "lwip/dns.h"
-
-#include <string.h>
-
-#define SET_NONBLOCKING_CONNECT(conn, val) do { if(val) { \
- (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
-} else { \
- (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)
-#define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)
-
-/* forward declarations */
-#if LWIP_TCP
-static err_t do_writemore(struct netconn *conn);
-static void do_close_internal(struct netconn *conn);
-#endif
-
-#if LWIP_RAW
-/**
- * Receive callback function for RAW netconns.
- * Doesn't 'eat' the packet, only references it and sends it to
- * conn->recvmbox
- *
- * @see raw.h (struct raw_pcb.recv) for parameters and return value
- */
-static u8_t
-recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
- ip_addr_t *addr)
-{
- struct pbuf *q;
- struct netbuf *buf;
- struct netconn *conn;
-
- LWIP_UNUSED_ARG(addr);
- conn = (struct netconn *)arg;
-
- if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {
-#if LWIP_SO_RCVBUF
- int recv_avail;
- SYS_ARCH_GET(conn->recv_avail, recv_avail);
- if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
- return 0;
- }
-#endif /* LWIP_SO_RCVBUF */
- /* copy the whole packet into new pbufs */
- q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
- if(q != NULL) {
- if (pbuf_copy(q, p) != ERR_OK) {
- pbuf_free(q);
- q = NULL;
- }
- }
-
- if (q != NULL) {
- u16_t len;
- buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
- if (buf == NULL) {
- pbuf_free(q);
- return 0;
- }
-
- buf->p = q;
- buf->ptr = q;
- ip_addr_copy(buf->addr, *ip_current_src_addr());
- buf->port = pcb->protocol;
-
- len = q->tot_len;
- if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
- netbuf_delete(buf);
- return 0;
- } else {
-#if LWIP_SO_RCVBUF
- SYS_ARCH_INC(conn->recv_avail, len);
-#endif /* LWIP_SO_RCVBUF */
- /* Register event with callback */
- API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
- }
- }
- }
-
- return 0; /* do not eat the packet */
-}
-#endif /* LWIP_RAW*/
-
-#if LWIP_UDP
-/**
- * Receive callback function for UDP netconns.
- * Posts the packet to conn->recvmbox or deletes it on memory error.
- *
- * @see udp.h (struct udp_pcb.recv) for parameters
- */
-static void
-recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
- ip_addr_t *addr, u16_t port)
-{
- struct netbuf *buf;
- struct netconn *conn;
- u16_t len;
-#if LWIP_SO_RCVBUF
- int recv_avail;
-#endif /* LWIP_SO_RCVBUF */
-
- LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
- LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
- LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
- conn = (struct netconn *)arg;
- LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
-
-#if LWIP_SO_RCVBUF
- SYS_ARCH_GET(conn->recv_avail, recv_avail);
- if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||
- ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
-#else /* LWIP_SO_RCVBUF */
- if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {
-#endif /* LWIP_SO_RCVBUF */
- pbuf_free(p);
- return;
- }
-
- buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
- if (buf == NULL) {
- pbuf_free(p);
- return;
- } else {
- buf->p = p;
- buf->ptr = p;
- ip_addr_set(&buf->addr, addr);
- buf->port = port;
-#if LWIP_NETBUF_RECVINFO
- {
- const struct ip_hdr* iphdr = ip_current_header();
- /* get the UDP header - always in the first pbuf, ensured by udp_input */
- const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
-#if LWIP_CHECKSUM_ON_COPY
- buf->flags = NETBUF_FLAG_DESTADDR;
-#endif /* LWIP_CHECKSUM_ON_COPY */
- ip_addr_set(&buf->toaddr, ip_current_dest_addr());
- buf->toport_chksum = udphdr->dest;
- }
-#endif /* LWIP_NETBUF_RECVINFO */
- }
-
- len = p->tot_len;
- if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
- netbuf_delete(buf);
- return;
- } else {
-#if LWIP_SO_RCVBUF
- SYS_ARCH_INC(conn->recv_avail, len);
-#endif /* LWIP_SO_RCVBUF */
- /* Register event with callback */
- API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
- }
-}
-#endif /* LWIP_UDP */
-
-#if LWIP_TCP
-/**
- * Receive callback function for TCP netconns.
- * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
- *
- * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
- */
-static err_t
-recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
-{
- struct netconn *conn;
- u16_t len;
-
- LWIP_UNUSED_ARG(pcb);
- LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
- LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
- conn = (struct netconn *)arg;
- LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
-
- if (conn == NULL) {
- return ERR_VAL;
- }
- if (!sys_mbox_valid(&conn->recvmbox)) {
- /* recvmbox already deleted */
- if (p != NULL) {
- tcp_recved(pcb, p->tot_len);
- pbuf_free(p);
- }
- return ERR_OK;
- }
- /* Unlike for UDP or RAW pcbs, don't check for available space
- using recv_avail since that could break the connection
- (data is already ACKed) */
-
- /* don't overwrite fatal errors! */
- NETCONN_SET_SAFE_ERR(conn, err);
-
- if (p != NULL) {
- len = p->tot_len;
- } else {
- len = 0;
- }
-
- if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
- /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
- return ERR_MEM;
- } else {
-#if LWIP_SO_RCVBUF
- SYS_ARCH_INC(conn->recv_avail, len);
-#endif /* LWIP_SO_RCVBUF */
- /* Register event with callback */
- API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
- }
-
- return ERR_OK;
-}
-
-/**
- * Poll callback function for TCP netconns.
- * Wakes up an application thread that waits for a connection to close
- * or data to be sent. The application thread then takes the
- * appropriate action to go on.
- *
- * Signals the conn->sem.
- * netconn_close waits for conn->sem if closing failed.
- *
- * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
- */
-static err_t
-poll_tcp(void *arg, struct tcp_pcb *pcb)
-{
- struct netconn *conn = (struct netconn *)arg;
-
- LWIP_UNUSED_ARG(pcb);
- LWIP_ASSERT("conn != NULL", (conn != NULL));
-
- if (conn->state == NETCONN_WRITE) {
- do_writemore(conn);
- } else if (conn->state == NETCONN_CLOSE) {
- do_close_internal(conn);
- }
- /* @todo: implement connect timeout here? */
-
- /* Did a nonblocking write fail before? Then check available write-space. */
- if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
- /* If the queued byte- or pbuf-count drops below the configured low-water limit,
- let select mark this pcb as writable again. */
- if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
- (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
- conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
- API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
- }
- }
-
- return ERR_OK;
-}
-
-/**
- * Sent callback function for TCP netconns.
- * Signals the conn->sem and calls API_EVENT.
- * netconn_write waits for conn->sem if send buffer is low.
- *
- * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
- */
-static err_t
-sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
-{
- struct netconn *conn = (struct netconn *)arg;
-
- LWIP_UNUSED_ARG(pcb);
- LWIP_ASSERT("conn != NULL", (conn != NULL));
-
- if (conn->state == NETCONN_WRITE) {
- do_writemore(conn);
- } else if (conn->state == NETCONN_CLOSE) {
- do_close_internal(conn);
- }
-
- if (conn) {
- /* If the queued byte- or pbuf-count drops below the configured low-water limit,
- let select mark this pcb as writable again. */
- if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
- (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
- conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
- API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
- }
- }
-
- return ERR_OK;
-}
-
-/**
- * Error callback function for TCP netconns.
- * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
- * The application thread has then to decide what to do.
- *
- * @see tcp.h (struct tcp_pcb.err) for parameters
- */
-static void
-err_tcp(void *arg, err_t err)
-{
- struct netconn *conn;
- enum netconn_state old_state;
- SYS_ARCH_DECL_PROTECT(lev);
-
- conn = (struct netconn *)arg;
- LWIP_ASSERT("conn != NULL", (conn != NULL));
-
- conn->pcb.tcp = NULL;
-
- /* no check since this is always fatal! */
- SYS_ARCH_PROTECT(lev);
- conn->last_err = err;
- SYS_ARCH_UNPROTECT(lev);
-
- /* reset conn->state now before waking up other threads */
- old_state = conn->state;
- conn->state = NETCONN_NONE;
-
- /* Notify the user layer about a connection error. Used to signal
- select. */
- API_EVENT(conn, NETCONN_EVT_ERROR, 0);
- /* Try to release selects pending on 'read' or 'write', too.
- They will get an error if they actually try to read or write. */
- API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
- API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
-
- /* pass NULL-message to recvmbox to wake up pending recv */
- if (sys_mbox_valid(&conn->recvmbox)) {
- /* use trypost to prevent deadlock */
- sys_mbox_trypost(&conn->recvmbox, NULL);
- }
- /* pass NULL-message to acceptmbox to wake up pending accept */
- if (sys_mbox_valid(&conn->acceptmbox)) {
- /* use trypost to preven deadlock */
- sys_mbox_trypost(&conn->acceptmbox, NULL);
- }
-
- if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
- (old_state == NETCONN_CONNECT)) {
- /* calling do_writemore/do_close_internal is not necessary
- since the pcb has already been deleted! */
- int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
- SET_NONBLOCKING_CONNECT(conn, 0);
-
- if (!was_nonblocking_connect) {
- /* set error return code */
- LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
- conn->current_msg->err = err;
- conn->current_msg = NULL;
- /* wake up the waiting task */
- sys_sem_signal(&conn->op_completed);
- }
- } else {
- LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
- }
-}
-
-/**
- * Setup a tcp_pcb with the correct callback function pointers
- * and their arguments.
- *
- * @param conn the TCP netconn to setup
- */
-static void
-setup_tcp(struct netconn *conn)
-{
- struct tcp_pcb *pcb;
-
- pcb = conn->pcb.tcp;
- tcp_arg(pcb, conn);
- tcp_recv(pcb, recv_tcp);
- tcp_sent(pcb, sent_tcp);
- tcp_poll(pcb, poll_tcp, 4);
- tcp_err(pcb, err_tcp);
-}
-
-/**
- * Accept callback function for TCP netconns.
- * Allocates a new netconn and posts that to conn->acceptmbox.
- *
- * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
- */
-static err_t
-accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
-{
- struct netconn *newconn;
- struct netconn *conn = (struct netconn *)arg;
-
- LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));
-
- if (!sys_mbox_valid(&conn->acceptmbox)) {
- LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
- return ERR_VAL;
- }
-
- /* We have to set the callback here even though
- * the new socket is unknown. conn->socket is marked as -1. */
- newconn = netconn_alloc(conn->type, conn->callback);
- if (newconn == NULL) {
- return ERR_MEM;
- }
- newconn->pcb.tcp = newpcb;
- setup_tcp(newconn);
- /* no protection: when creating the pcb, the netconn is not yet known
- to the application thread */
- newconn->last_err = err;
-
- if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
- /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
- so do nothing here! */
- newconn->pcb.tcp = NULL;
- /* no need to drain since we know the recvmbox is empty. */
- sys_mbox_free(&newconn->recvmbox);
- sys_mbox_set_invalid(&newconn->recvmbox);
- netconn_free(newconn);
- return ERR_MEM;
- } else {
- /* Register event with callback */
- API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
- }
-
- return ERR_OK;
-}
-#endif /* LWIP_TCP */
-
-/**
- * Create a new pcb of a specific type.
- * Called from do_newconn().
- *
- * @param msg the api_msg_msg describing the connection type
- * @return msg->conn->err, but the return value is currently ignored
- */
-static void
-pcb_new(struct api_msg_msg *msg)
-{
- LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
-
- /* Allocate a PCB for this connection */
- switch(NETCONNTYPE_GROUP(msg->conn->type)) {
-#if LWIP_RAW
- case NETCONN_RAW:
- msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
- if(msg->conn->pcb.raw == NULL) {
- msg->err = ERR_MEM;
- break;
- }
- raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
- break;
-#endif /* LWIP_RAW */
-#if LWIP_UDP
- case NETCONN_UDP:
- msg->conn->pcb.udp = udp_new();
- if(msg->conn->pcb.udp == NULL) {
- msg->err = ERR_MEM;
- break;
- }
-#if LWIP_UDPLITE
- if (msg->conn->type==NETCONN_UDPLITE) {
- udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
- }
-#endif /* LWIP_UDPLITE */
- if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
- udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
- }
- udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
- break;
-#endif /* LWIP_UDP */
-#if LWIP_TCP
- case NETCONN_TCP:
- msg->conn->pcb.tcp = tcp_new();
- if(msg->conn->pcb.tcp == NULL) {
- msg->err = ERR_MEM;
- break;
- }
- setup_tcp(msg->conn);
- break;
-#endif /* LWIP_TCP */
- default:
- /* Unsupported netconn type, e.g. protocol disabled */
- msg->err = ERR_VAL;
- break;
- }
-}
-
-/**
- * Create a new pcb of a specific type inside a netconn.
- * Called from netconn_new_with_proto_and_callback.
- *
- * @param msg the api_msg_msg describing the connection type
- */
-void
-do_newconn(struct api_msg_msg *msg)
-{
- msg->err = ERR_OK;
- if(msg->conn->pcb.tcp == NULL) {
- pcb_new(msg);
- }
- /* Else? This "new" connection already has a PCB allocated. */
- /* Is this an error condition? Should it be deleted? */
- /* We currently just are happy and return. */
-
- TCPIP_APIMSG_ACK(msg);
-}
-
-/**
- * Create a new netconn (of a specific type) that has a callback function.
- * The corresponding pcb is NOT 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_alloc(enum netconn_type t, netconn_callback callback)
-{
- struct netconn *conn;
- int size;
-
- conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
- if (conn == NULL) {
- return NULL;
- }
-
- conn->last_err = ERR_OK;
- conn->type = t;
- conn->pcb.tcp = NULL;
-
-#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \
- (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)
- size = DEFAULT_RAW_RECVMBOX_SIZE;
-#else
- switch(NETCONNTYPE_GROUP(t)) {
-#if LWIP_RAW
- case NETCONN_RAW:
- size = DEFAULT_RAW_RECVMBOX_SIZE;
- break;
-#endif /* LWIP_RAW */
-#if LWIP_UDP
- case NETCONN_UDP:
- size = DEFAULT_UDP_RECVMBOX_SIZE;
- break;
-#endif /* LWIP_UDP */
-#if LWIP_TCP
- case NETCONN_TCP:
- size = DEFAULT_TCP_RECVMBOX_SIZE;
- break;
-#endif /* LWIP_TCP */
- default:
- LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
- break;
- }
-#endif
-
- if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
- memp_free(MEMP_NETCONN, conn);
- return NULL;
- }
- if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
- sys_sem_free(&conn->op_completed);
- memp_free(MEMP_NETCONN, conn);
- return NULL;
- }
-
-#if LWIP_TCP
- sys_mbox_set_invalid(&conn->acceptmbox);
-#endif
- conn->state = NETCONN_NONE;
-#if LWIP_SOCKET
- /* initialize socket to -1 since 0 is a valid socket */
- conn->socket = -1;
-#endif /* LWIP_SOCKET */
- conn->callback = callback;
-#if LWIP_TCP
- conn->current_msg = NULL;
- conn->write_offset = 0;
-#endif /* LWIP_TCP */
-#if LWIP_SO_RCVTIMEO
- conn->recv_timeout = 0;
-#endif /* LWIP_SO_RCVTIMEO */
-#if LWIP_SO_RCVBUF
- conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
- conn->recv_avail = 0;
-#endif /* LWIP_SO_RCVBUF */
- conn->flags = 0;
- return conn;
-}
-
-/**
- * Delete a netconn and all its resources.
- * The pcb is NOT freed (since we might not be in the right thread context do this).
- *
- * @param conn the netconn to free
- */
-void
-netconn_free(struct netconn *conn)
-{
- LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
- LWIP_ASSERT("recvmbox must be deallocated before calling this function",
- !sys_mbox_valid(&conn->recvmbox));
-#if LWIP_TCP
- LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
- !sys_mbox_valid(&conn->acceptmbox));
-#endif /* LWIP_TCP */
-
- sys_sem_free(&conn->op_completed);
- sys_sem_set_invalid(&conn->op_completed);
-
- memp_free(MEMP_NETCONN, conn);
-}
-
-/**
- * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
- * these mboxes
- *
- * @param conn the netconn to free
- * @bytes_drained bytes drained from recvmbox
- * @accepts_drained pending connections drained from acceptmbox
- */
-static void
-netconn_drain(struct netconn *conn)
-{
- void *mem;
-#if LWIP_TCP
- struct pbuf *p;
-#endif /* LWIP_TCP */
-
- /* This runs in tcpip_thread, so we don't need to lock against rx packets */
-
- /* Delete and drain the recvmbox. */
- if (sys_mbox_valid(&conn->recvmbox)) {
- while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
-#if LWIP_TCP
- if (conn->type == NETCONN_TCP) {
- if(mem != NULL) {
- p = (struct pbuf*)mem;
- /* pcb might be set to NULL already by err_tcp() */
- if (conn->pcb.tcp != NULL) {
- tcp_recved(conn->pcb.tcp, p->tot_len);
- }
- pbuf_free(p);
- }
- } else
-#endif /* LWIP_TCP */
- {
- netbuf_delete((struct netbuf *)mem);
- }
- }
- sys_mbox_free(&conn->recvmbox);
- sys_mbox_set_invalid(&conn->recvmbox);
- }
-
- /* Delete and drain the acceptmbox. */
-#if LWIP_TCP
- if (sys_mbox_valid(&conn->acceptmbox)) {
- while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
- struct netconn *newconn = (struct netconn *)mem;
- /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
- /* pcb might be set to NULL already by err_tcp() */
- if (conn->pcb.tcp != NULL) {
- tcp_accepted(conn->pcb.tcp);
- }
- /* drain recvmbox */
- netconn_drain(newconn);
- if (newconn->pcb.tcp != NULL) {
- tcp_abort(newconn->pcb.tcp);
- newconn->pcb.tcp = NULL;
- }
- netconn_free(newconn);
- }
- sys_mbox_free(&conn->acceptmbox);
- sys_mbox_set_invalid(&conn->acceptmbox);
- }
-#endif /* LWIP_TCP */
-}
-
-#if LWIP_TCP
-/**
- * Internal helper function to close a TCP netconn: since this sometimes
- * doesn't work at the first attempt, this function is called from multiple
- * places.
- *
- * @param conn the TCP netconn to close
- */
-static void
-do_close_internal(struct netconn *conn)
-{
- err_t err;
- u8_t shut, shut_rx, shut_tx, close;
-
- LWIP_ASSERT("invalid conn", (conn != NULL));
- LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
- LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
- LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
- LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
-
- shut = conn->current_msg->msg.sd.shut;
- shut_rx = shut & NETCONN_SHUT_RD;
- shut_tx = shut & NETCONN_SHUT_WR;
- /* shutting down both ends is the same as closing */
- close = shut == NETCONN_SHUT_RDWR;
-
- /* Set back some callback pointers */
- if (close) {
- tcp_arg(conn->pcb.tcp, NULL);
- }
- if (conn->pcb.tcp->state == LISTEN) {
- tcp_accept(conn->pcb.tcp, NULL);
- } else {
- /* some callbacks have to be reset if tcp_close is not successful */
- if (shut_rx) {
- tcp_recv(conn->pcb.tcp, NULL);
- tcp_accept(conn->pcb.tcp, NULL);
- }
- if (shut_tx) {
- tcp_sent(conn->pcb.tcp, NULL);
- }
- if (close) {
- tcp_poll(conn->pcb.tcp, NULL, 4);
- tcp_err(conn->pcb.tcp, NULL);
- }
- }
- /* Try to close the connection */
- if (shut == NETCONN_SHUT_RDWR) {
- err = tcp_close(conn->pcb.tcp);
- } else {
- err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR);
- }
- if (err == ERR_OK) {
- /* Closing succeeded */
- conn->current_msg->err = ERR_OK;
- conn->current_msg = NULL;
- conn->state = NETCONN_NONE;
- /* Set back some callback pointers as conn is going away */
- conn->pcb.tcp = NULL;
- /* Trigger select() in socket layer. Make sure everybody notices activity
- on the connection, error first! */
- if (close) {
- API_EVENT(conn, NETCONN_EVT_ERROR, 0);
- }
- if (shut_rx) {
- API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
- }
- if (shut_tx) {
- API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
- }
- /* wake up the application task */
- sys_sem_signal(&conn->op_completed);
- } else {
- /* Closing failed, restore some of the callbacks */
- /* Closing of listen pcb will never fail! */
- LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
- tcp_sent(conn->pcb.tcp, sent_tcp);
- tcp_poll(conn->pcb.tcp, poll_tcp, 4);
- tcp_err(conn->pcb.tcp, err_tcp);
- tcp_arg(conn->pcb.tcp, conn);
- /* don't restore recv callback: we don't want to receive any more data */
- }
- /* If closing didn't succeed, we get called again either
- from poll_tcp or from sent_tcp */
-}
-#endif /* LWIP_TCP */
-
-/**
- * Delete the pcb inside a netconn.
- * Called from netconn_delete.
- *
- * @param msg the api_msg_msg pointing to the connection
- */
-void
-do_delconn(struct api_msg_msg *msg)
-{
- /* @todo TCP: abort running write/connect? */
- if ((msg->conn->state != NETCONN_NONE) &&
- (msg->conn->state != NETCONN_LISTEN) &&
- (msg->conn->state != NETCONN_CONNECT)) {
- /* this only happens for TCP netconns */
- LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
- msg->err = ERR_INPROGRESS;
- } else {
- LWIP_ASSERT("blocking connect in progress",
- (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
- /* Drain and delete mboxes */
- netconn_drain(msg->conn);
-
- if (msg->conn->pcb.tcp != NULL) {
-
- switch (NETCONNTYPE_GROUP(msg->conn->type)) {
-#if LWIP_RAW
- case NETCONN_RAW:
- raw_remove(msg->conn->pcb.raw);
- break;
-#endif /* LWIP_RAW */
-#if LWIP_UDP
- case NETCONN_UDP:
- msg->conn->pcb.udp->recv_arg = NULL;
- udp_remove(msg->conn->pcb.udp);
- break;
-#endif /* LWIP_UDP */
-#if LWIP_TCP
- case NETCONN_TCP:
- LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
- msg->conn->write_offset == 0);
- msg->conn->state = NETCONN_CLOSE;
- msg->msg.sd.shut = NETCONN_SHUT_RDWR;
- msg->conn->current_msg = msg;
- do_close_internal(msg->conn);
- /* API_EVENT is called inside do_close_internal, before releasing
- the application thread, so we can return at this point! */
- return;
-#endif /* LWIP_TCP */
- default:
- break;
- }
- msg->conn->pcb.tcp = NULL;
- }
- /* tcp netconns don't come here! */
-
- /* @todo: this lets select make the socket readable and writable,
- which is wrong! errfd instead? */
- API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
- API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
- }
- if (sys_sem_valid(&msg->conn->op_completed)) {
- sys_sem_signal(&msg->conn->op_completed);
- }
-}
-
-/**
- * Bind a pcb contained in a netconn
- * Called from netconn_bind.
- *
- * @param msg the api_msg_msg pointing to the connection and containing
- * the IP address and port to bind to
- */
-void
-do_bind(struct api_msg_msg *msg)
-{
- if (ERR_IS_FATAL(msg->conn->last_err)) {
- msg->err = msg->conn->last_err;
- } else {
- msg->err = ERR_VAL;
- if (msg->conn->pcb.tcp != NULL) {
- switch (NETCONNTYPE_GROUP(msg->conn->type)) {
-#if LWIP_RAW
- case NETCONN_RAW:
- msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
- break;
-#endif /* LWIP_RAW */
-#if LWIP_UDP
- case NETCONN_UDP:
- msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
- break;
-#endif /* LWIP_UDP */
-#if LWIP_TCP
- case NETCONN_TCP:
- msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
- break;
-#endif /* LWIP_TCP */
- default:
- break;
- }
- }
- }
- TCPIP_APIMSG_ACK(msg);
-}
-
-#if LWIP_TCP
-/**
- * TCP callback function if a connection (opened by tcp_connect/do_connect) has
- * been established (or reset by the remote host).
- *
- * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
- */
-static err_t
-do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
-{
- struct netconn *conn;
- int was_blocking;
-
- LWIP_UNUSED_ARG(pcb);
-
- conn = (struct netconn *)arg;
-
- if (conn == NULL) {
- return ERR_VAL;
- }
-
- LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
- LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
- (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
-
- if (conn->current_msg != NULL) {
- conn->current_msg->err = err;
- }
- if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
- setup_tcp(conn);
- }
- was_blocking = !IN_NONBLOCKING_CONNECT(conn);
- SET_NONBLOCKING_CONNECT(conn, 0);
- conn->current_msg = NULL;
- conn->state = NETCONN_NONE;
- if (!was_blocking) {
- NETCONN_SET_SAFE_ERR(conn, ERR_OK);
- }
- API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
-
- if (was_blocking) {
- sys_sem_signal(&conn->op_completed);
- }
- return ERR_OK;
-}
-#endif /* LWIP_TCP */
-
-/**
- * Connect a pcb contained inside a netconn
- * Called from netconn_connect.
- *
- * @param msg the api_msg_msg pointing to the connection and containing
- * the IP address and port to connect to
- */
-void
-do_connect(struct api_msg_msg *msg)
-{
- if (msg->conn->pcb.tcp == NULL) {
- /* This may happen when calling netconn_connect() a second time */
- msg->err = ERR_CLSD;
- } else {
- switch (NETCONNTYPE_GROUP(msg->conn->type)) {
-#if LWIP_RAW
- case NETCONN_RAW:
- msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
- break;
-#endif /* LWIP_RAW */
-#if LWIP_UDP
- case NETCONN_UDP:
- msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
- break;
-#endif /* LWIP_UDP */
-#if LWIP_TCP
- case NETCONN_TCP:
- /* Prevent connect while doing any other action. */
- if (msg->conn->state != NETCONN_NONE) {
- msg->err = ERR_ISCONN;
- } else {
- setup_tcp(msg->conn);
- msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr,
- msg->msg.bc.port, do_connected);
- if (msg->err == ERR_OK) {
- u8_t non_blocking = netconn_is_nonblocking(msg->conn);
- msg->conn->state = NETCONN_CONNECT;
- SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
- if (non_blocking) {
- msg->err = ERR_INPROGRESS;
- } else {
- msg->conn->current_msg = msg;
- /* sys_sem_signal() is called from do_connected (or err_tcp()),
- * when the connection is established! */
- return;
- }
- }
- }
- break;
-#endif /* LWIP_TCP */
- default:
- LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
- break;
- }
- }
- sys_sem_signal(&msg->conn->op_completed);
-}
-
-/**
- * Connect a pcb contained inside a netconn
- * Only used for UDP netconns.
- * Called from netconn_disconnect.
- *
- * @param msg the api_msg_msg pointing to the connection to disconnect
- */
-void
-do_disconnect(struct api_msg_msg *msg)
-{
-#if LWIP_UDP
- if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
- udp_disconnect(msg->conn->pcb.udp);
- msg->err = ERR_OK;
- } else
-#endif /* LWIP_UDP */
- {
- msg->err = ERR_VAL;
- }
- TCPIP_APIMSG_ACK(msg);
-}
-
-#if LWIP_TCP
-/**
- * Set a TCP pcb contained in a netconn into listen mode
- * Called from netconn_listen.
- *
- * @param msg the api_msg_msg pointing to the connection
- */
-void
-do_listen(struct api_msg_msg *msg)
-{
- if (ERR_IS_FATAL(msg->conn->last_err)) {
- msg->err = msg->conn->last_err;
- } else {
- msg->err = ERR_CONN;
- if (msg->conn->pcb.tcp != NULL) {
- if (msg->conn->type == NETCONN_TCP) {
- if (msg->conn->state == NETCONN_NONE) {
-#if TCP_LISTEN_BACKLOG
- struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
-#else /* TCP_LISTEN_BACKLOG */
- struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
-#endif /* TCP_LISTEN_BACKLOG */
- if (lpcb == NULL) {
- /* in this case, the old pcb is still allocated */
- msg->err = ERR_MEM;
- } else {
- /* delete the recvmbox and allocate the acceptmbox */
- if (sys_mbox_valid(&msg->conn->recvmbox)) {
- /** @todo: should we drain the recvmbox here? */
- sys_mbox_free(&msg->conn->recvmbox);
- sys_mbox_set_invalid(&msg->conn->recvmbox);
- }
- msg->err = ERR_OK;
- if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
- msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
- }
- if (msg->err == ERR_OK) {
- msg->conn->state = NETCONN_LISTEN;
- msg->conn->pcb.tcp = lpcb;
- tcp_arg(msg->conn->pcb.tcp, msg->conn);
- tcp_accept(msg->conn->pcb.tcp, accept_function);
- } else {
- /* since the old pcb is already deallocated, free lpcb now */
- tcp_close(lpcb);
- msg->conn->pcb.tcp = NULL;
- }
- }
- }
- }
- }
- }
- TCPIP_APIMSG_ACK(msg);
-}
-#endif /* LWIP_TCP */
-
-/**
- * Send some data on a RAW or UDP pcb contained in a netconn
- * Called from netconn_send
- *
- * @param msg the api_msg_msg pointing to the connection
- */
-void
-do_send(struct api_msg_msg *msg)
-{
- if (ERR_IS_FATAL(msg->conn->last_err)) {
- msg->err = msg->conn->last_err;
- } else {
- msg->err = ERR_CONN;
- if (msg->conn->pcb.tcp != NULL) {
- switch (NETCONNTYPE_GROUP(msg->conn->type)) {
-#if LWIP_RAW
- case NETCONN_RAW:
- if (ip_addr_isany(&msg->msg.b->addr)) {
- msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
- } else {
- msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
- }
- break;
-#endif
-#if LWIP_UDP
- case NETCONN_UDP:
-#if LWIP_CHECKSUM_ON_COPY
- if (ip_addr_isany(&msg->msg.b->addr)) {
- msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
- msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
- } else {
- msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
- &msg->msg.b->addr, msg->msg.b->port,
- msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
- }
-#else /* LWIP_CHECKSUM_ON_COPY */
- if (ip_addr_isany(&msg->msg.b->addr)) {
- msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
- } else {
- msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
- }
-#endif /* LWIP_CHECKSUM_ON_COPY */
- break;
-#endif /* LWIP_UDP */
- default:
- break;
- }
- }
- }
- TCPIP_APIMSG_ACK(msg);
-}
-
-#if LWIP_TCP
-/**
- * Indicate data has been received from a TCP pcb contained in a netconn
- * Called from netconn_recv
- *
- * @param msg the api_msg_msg pointing to the connection
- */
-void
-do_recv(struct api_msg_msg *msg)
-{
- msg->err = ERR_OK;
- if (msg->conn->pcb.tcp != NULL) {
- if (msg->conn->type == NETCONN_TCP) {
-#if TCP_LISTEN_BACKLOG
- if (msg->conn->pcb.tcp->state == LISTEN) {
- tcp_accepted(msg->conn->pcb.tcp);
- } else
-#endif /* TCP_LISTEN_BACKLOG */
- {
- u32_t remaining = msg->msg.r.len;
- do {
- u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
- tcp_recved(msg->conn->pcb.tcp, recved);
- remaining -= recved;
- }while(remaining != 0);
- }
- }
- }
- TCPIP_APIMSG_ACK(msg);
-}
-
-/**
- * See if more data needs to be written from a previous call to netconn_write.
- * Called initially from do_write. If the first call can't send all data
- * (because of low memory or empty send-buffer), this function is called again
- * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
- * blocking application thread (waiting in netconn_write) is released.
- *
- * @param conn netconn (that is currently in state NETCONN_WRITE) to process
- * @return ERR_OK
- * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
- */
-static err_t
-do_writemore(struct netconn *conn)
-{
- err_t err = ERR_OK;
- void *dataptr;
- u16_t len, available;
- u8_t write_finished = 0;
- size_t diff;
- u8_t dontblock = netconn_is_nonblocking(conn) ||
- (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK);
- u8_t apiflags = conn->current_msg->msg.w.apiflags;
-
- LWIP_ASSERT("conn != NULL", conn != NULL);
- LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
- LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
- LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
- LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
- conn->write_offset < conn->current_msg->msg.w.len);
-
- dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
- diff = conn->current_msg->msg.w.len - conn->write_offset;
- if (diff > 0xffffUL) { /* max_u16_t */
- len = 0xffff;
-#if LWIP_TCPIP_CORE_LOCKING
- conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
-#endif
- apiflags |= TCP_WRITE_FLAG_MORE;
- } else {
- len = (u16_t)diff;
- }
- available = tcp_sndbuf(conn->pcb.tcp);
- if (available < len) {
- /* don't try to write more than sendbuf */
- len = available;
-#if LWIP_TCPIP_CORE_LOCKING
- conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
-#endif
- apiflags |= TCP_WRITE_FLAG_MORE;
- }
- if (dontblock && (len < conn->current_msg->msg.w.len)) {
- /* failed to send all data at once -> nonblocking write not possible */
- err = ERR_MEM;
- }
- if (err == ERR_OK) {
- LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
- err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
- }
- if (dontblock && (err == ERR_MEM)) {
- /* nonblocking write failed */
- write_finished = 1;
- err = ERR_WOULDBLOCK;
- /* let poll_tcp check writable space to mark the pcb
- writable again */
- conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
- /* let select mark this pcb as non-writable. */
- API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
- } else {
- /* if OK or memory error, check available space */
- if (((err == ERR_OK) || (err == ERR_MEM)) &&
- ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
- (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) {
- /* The queued byte- or pbuf-count exceeds the configured low-water limit,
- let select mark this pcb as non-writable. */
- API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
- }
-
- if (err == ERR_OK) {
- conn->write_offset += len;
- if (conn->write_offset == conn->current_msg->msg.w.len) {
- /* everything was written */
- write_finished = 1;
- conn->write_offset = 0;
- }
- tcp_output(conn->pcb.tcp);
- } else if (err == ERR_MEM) {
- /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
- we do NOT return to the application thread, since ERR_MEM is
- only a temporary error! */
-
- /* tcp_write returned ERR_MEM, try tcp_output anyway */
- tcp_output(conn->pcb.tcp);
-
- #if LWIP_TCPIP_CORE_LOCKING
- conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
- #endif
- } else {
- /* On errors != ERR_MEM, we don't try writing any more but return
- the error to the application thread. */
- write_finished = 1;
- }
- }
-
- if (write_finished) {
- /* everything was written: set back connection state
- and back to application task */
- conn->current_msg->err = err;
- conn->current_msg = NULL;
- conn->state = NETCONN_NONE;
-#if LWIP_TCPIP_CORE_LOCKING
- if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0)
-#endif
- {
- sys_sem_signal(&conn->op_completed);
- }
- }
-#if LWIP_TCPIP_CORE_LOCKING
- else
- return ERR_MEM;
-#endif
- return ERR_OK;
-}
-#endif /* LWIP_TCP */
-
-/**
- * Send some data on a TCP pcb contained in a netconn
- * Called from netconn_write
- *
- * @param msg the api_msg_msg pointing to the connection
- */
-void
-do_write(struct api_msg_msg *msg)
-{
- if (ERR_IS_FATAL(msg->conn->last_err)) {
- msg->err = msg->conn->last_err;
- } else {
- if (msg->conn->type == NETCONN_TCP) {
-#if LWIP_TCP
- if (msg->conn->state != NETCONN_NONE) {
- /* netconn is connecting, closing or in blocking write */
- msg->err = ERR_INPROGRESS;
- } else if (msg->conn->pcb.tcp != NULL) {
- msg->conn->state = NETCONN_WRITE;
- /* set all the variables used by do_writemore */
- LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
- msg->conn->write_offset == 0);
- LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
- msg->conn->current_msg = msg;
- msg->conn->write_offset = 0;
-#if LWIP_TCPIP_CORE_LOCKING
- msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED;
- if (do_writemore(msg->conn) != ERR_OK) {
- LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
- UNLOCK_TCPIP_CORE();
- sys_arch_sem_wait(&msg->conn->op_completed, 0);
- LOCK_TCPIP_CORE();
- LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
- }
-#else /* LWIP_TCPIP_CORE_LOCKING */
- do_writemore(msg->conn);
-#endif /* LWIP_TCPIP_CORE_LOCKING */
- /* for both cases: if do_writemore was called, don't ACK the APIMSG
- since do_writemore ACKs it! */
- return;
- } else {
- msg->err = ERR_CONN;
- }
-#else /* LWIP_TCP */
- msg->err = ERR_VAL;
-#endif /* LWIP_TCP */
-#if (LWIP_UDP || LWIP_RAW)
- } else {
- msg->err = ERR_VAL;
-#endif /* (LWIP_UDP || LWIP_RAW) */
- }
- }
- TCPIP_APIMSG_ACK(msg);
-}
-
-/**
- * Return a connection's local or remote address
- * Called from netconn_getaddr
- *
- * @param msg the api_msg_msg pointing to the connection
- */
-void
-do_getaddr(struct api_msg_msg *msg)
-{
- if (msg->conn->pcb.ip != NULL) {
- *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip :
- msg->conn->pcb.ip->remote_ip);
-
- msg->err = ERR_OK;
- switch (NETCONNTYPE_GROUP(msg->conn->type)) {
-#if LWIP_RAW
- case NETCONN_RAW:
- if (msg->msg.ad.local) {
- *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
- } else {
- /* return an error as connecting is only a helper for upper layers */
- msg->err = ERR_CONN;
- }
- break;
-#endif /* LWIP_RAW */
-#if LWIP_UDP
- case NETCONN_UDP:
- if (msg->msg.ad.local) {
- *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
- } else {
- if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
- msg->err = ERR_CONN;
- } else {
- *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
- }
- }
- break;
-#endif /* LWIP_UDP */
-#if LWIP_TCP
- case NETCONN_TCP:
- *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);
- break;
-#endif /* LWIP_TCP */
- default:
- LWIP_ASSERT("invalid netconn_type", 0);
- break;
- }
- } else {
- msg->err = ERR_CONN;
- }
- TCPIP_APIMSG_ACK(msg);
-}
-
-/**
- * Close a TCP pcb contained in a netconn
- * Called from netconn_close
- *
- * @param msg the api_msg_msg pointing to the connection
- */
-void
-do_close(struct api_msg_msg *msg)
-{
-#if LWIP_TCP
- /* @todo: abort running write/connect? */
- if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) {
- /* this only happens for TCP netconns */
- LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
- msg->err = ERR_INPROGRESS;
- } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
- if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) {
- /* LISTEN doesn't support half shutdown */
- msg->err = ERR_CONN;
- } else {
- if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
- /* Drain and delete mboxes */
- netconn_drain(msg->conn);
- }
- LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
- msg->conn->write_offset == 0);
- msg->conn->state = NETCONN_CLOSE;
- msg->conn->current_msg = msg;
- do_close_internal(msg->conn);
- /* for tcp netconns, do_close_internal ACKs the message */
- return;
- }
- } else
-#endif /* LWIP_TCP */
- {
- msg->err = ERR_VAL;
- }
- sys_sem_signal(&msg->conn->op_completed);
-}
-
-#if LWIP_IGMP
-/**
- * Join multicast groups for UDP netconns.
- * Called from netconn_join_leave_group
- *
- * @param msg the api_msg_msg pointing to the connection
- */
-void
-do_join_leave_group(struct api_msg_msg *msg)
-{
- if (ERR_IS_FATAL(msg->conn->last_err)) {
- msg->err = msg->conn->last_err;
- } else {
- if (msg->conn->pcb.tcp != NULL) {
- if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
-#if LWIP_UDP
- if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
- msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
- } else {
- msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
- }
-#endif /* LWIP_UDP */
-#if (LWIP_TCP || LWIP_RAW)
- } else {
- msg->err = ERR_VAL;
-#endif /* (LWIP_TCP || LWIP_RAW) */
- }
- } else {
- msg->err = ERR_CONN;
- }
- }
- TCPIP_APIMSG_ACK(msg);
-}
-#endif /* LWIP_IGMP */
-
-#if LWIP_DNS
-/**
- * Callback function that is called when DNS name is resolved
- * (or on timeout). A waiting application thread is waked up by
- * signaling the semaphore.
- */
-static void
-do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
-{
- struct dns_api_msg *msg = (struct dns_api_msg*)arg;
-
- LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);
- LWIP_UNUSED_ARG(name);
-
- if (ipaddr == NULL) {
- /* timeout or memory error */
- *msg->err = ERR_VAL;
- } else {
- /* address was resolved */
- *msg->err = ERR_OK;
- *msg->addr = *ipaddr;
- }
- /* wake up the application task waiting in netconn_gethostbyname */
- sys_sem_signal(msg->sem);
-}
-
-/**
- * Execute a DNS query
- * Called from netconn_gethostbyname
- *
- * @param arg the dns_api_msg pointing to the query
- */
-void
-do_gethostbyname(void *arg)
-{
- struct dns_api_msg *msg = (struct dns_api_msg*)arg;
-
- *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);
- if (*msg->err != ERR_INPROGRESS) {
- /* on error or immediate success, wake up the application
- * task waiting in netconn_gethostbyname */
- sys_sem_signal(msg->sem);
- }
-}
-#endif /* LWIP_DNS */
-
-#endif /* LWIP_NETCONN */
+++ /dev/null
-/**
- * @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 */
+++ /dev/null
-/**
- * @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 */
+++ /dev/null
-/**
- * @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 */
+++ /dev/null
-/**
- * @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 */
+++ /dev/null
-/**
- * @file
- * Sockets BSD-Like API 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>
- *
- * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
- *
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/sockets.h"
-#include "lwip/api.h"
-#include "lwip/sys.h"
-#include "lwip/igmp.h"
-#include "lwip/inet.h"
-#include "lwip/tcp.h"
-#include "lwip/raw.h"
-#include "lwip/udp.h"
-#include "lwip/tcpip.h"
-#include "lwip/pbuf.h"
-#if LWIP_CHECKSUM_ON_COPY
-#include "lwip/inet_chksum.h"
-#endif
-
-#include <string.h>
-
-#define NUM_SOCKETS MEMP_NUM_NETCONN
-
-/** Contains all internal pointers and states used for a socket */
-struct lwip_sock {
- /** sockets currently are built on netconns, each socket has one netconn */
- struct netconn *conn;
- /** data that was left from the previous read */
- void *lastdata;
- /** offset in the data that was left from the previous read */
- u16_t lastoffset;
- /** number of times data was received, set by event_callback(),
- tested by the receive and select functions */
- s16_t rcvevent;
- /** number of times data was ACKed (free send buffer), set by event_callback(),
- tested by select */
- u16_t sendevent;
- /** error happened for this socket, set by event_callback(), tested by select */
- u16_t errevent;
- /** last error that occurred on this socket */
- int err;
- /** counter of how many threads are waiting for this socket using select */
- int select_waiting;
-};
-
-/** Description for a task waiting in select */
-struct lwip_select_cb {
- /** Pointer to the next waiting task */
- struct lwip_select_cb *next;
- /** Pointer to the previous waiting task */
- struct lwip_select_cb *prev;
- /** readset passed to select */
- fd_set *readset;
- /** writeset passed to select */
- fd_set *writeset;
- /** unimplemented: exceptset passed to select */
- fd_set *exceptset;
- /** don't signal the same semaphore twice: set to 1 when signalled */
- int sem_signalled;
- /** semaphore to wake up a task waiting for select */
- sys_sem_t sem;
-};
-
-/** This struct is used to pass data to the set/getsockopt_internal
- * functions running in tcpip_thread context (only a void* is allowed) */
-struct lwip_setgetsockopt_data {
- /** socket struct for which to change options */
- struct lwip_sock *sock;
-#ifdef LWIP_DEBUG
- /** socket index for which to change options */
- int s;
-#endif /* LWIP_DEBUG */
- /** level of the option to process */
- int level;
- /** name of the option to process */
- int optname;
- /** set: value to set the option to
- * get: value of the option is stored here */
- void *optval;
- /** size of *optval */
- socklen_t *optlen;
- /** if an error occures, it is temporarily stored here */
- err_t err;
-};
-
-/** The global array of available sockets */
-static struct lwip_sock sockets[NUM_SOCKETS];
-/** The global list of tasks waiting for select */
-static struct lwip_select_cb *select_cb_list;
-/** This counter is increased from lwip_select when the list is chagned
- and checked in event_callback to see if it has changed. */
-static volatile int select_cb_ctr;
-
-/** Table to quickly map an lwIP error (err_t) to a socket error
- * by using -err as an index */
-static const int err_to_errno_table[] = {
- 0, /* ERR_OK 0 No error, everything OK. */
- ENOMEM, /* ERR_MEM -1 Out of memory error. */
- ENOBUFS, /* ERR_BUF -2 Buffer error. */
- EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
- EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
- EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
- EINVAL, /* ERR_VAL -6 Illegal value. */
- EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
- EADDRINUSE, /* ERR_USE -8 Address in use. */
- EALREADY, /* ERR_ISCONN -9 Already connected. */
- ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */
- ECONNRESET, /* ERR_RST -11 Connection reset. */
- ENOTCONN, /* ERR_CLSD -12 Connection closed. */
- ENOTCONN, /* ERR_CONN -13 Not connected. */
- EIO, /* ERR_ARG -14 Illegal argument. */
- -1, /* ERR_IF -15 Low-level netif error */
-};
-
-#define ERR_TO_ERRNO_TABLE_SIZE \
- (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
-
-#define err_to_errno(err) \
- ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
- err_to_errno_table[-(err)] : EIO)
-
-#ifdef ERRNO
-#ifndef set_errno
-#define set_errno(err) errno = (err)
-#endif
-#else /* ERRNO */
-#define set_errno(err)
-#endif /* ERRNO */
-
-#define sock_set_errno(sk, e) do { \
- sk->err = (e); \
- set_errno(sk->err); \
-} while (0)
-
-/* Forward delcaration of some functions */
-static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
-static void lwip_getsockopt_internal(void *arg);
-static void lwip_setsockopt_internal(void *arg);
-
-/**
- * Initialize this module. This function has to be called before any other
- * functions in this module!
- */
-void
-lwip_socket_init(void)
-{
-}
-
-/**
- * Map a externally used socket index to the internal socket representation.
- *
- * @param s externally used socket index
- * @return struct lwip_sock for the socket or NULL if not found
- */
-static struct lwip_sock *
-get_socket(int s)
-{
- struct lwip_sock *sock;
-
- if ((s < 0) || (s >= NUM_SOCKETS)) {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
- set_errno(EBADF);
- return NULL;
- }
-
- sock = &sockets[s];
-
- if (!sock->conn) {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
- set_errno(EBADF);
- return NULL;
- }
-
- return sock;
-}
-
-/**
- * Same as get_socket but doesn't set errno
- *
- * @param s externally used socket index
- * @return struct lwip_sock for the socket or NULL if not found
- */
-static struct lwip_sock *
-tryget_socket(int s)
-{
- if ((s < 0) || (s >= NUM_SOCKETS)) {
- return NULL;
- }
- if (!sockets[s].conn) {
- return NULL;
- }
- return &sockets[s];
-}
-
-/**
- * Allocate a new socket for a given netconn.
- *
- * @param newconn the netconn for which to allocate a socket
- * @param accepted 1 if socket has been created by accept(),
- * 0 if socket has been created by socket()
- * @return the index of the new socket; -1 on error
- */
-static int
-alloc_socket(struct netconn *newconn, int accepted)
-{
- int i;
- SYS_ARCH_DECL_PROTECT(lev);
-
- /* allocate a new socket identifier */
- for (i = 0; i < NUM_SOCKETS; ++i) {
- /* Protect socket array */
- SYS_ARCH_PROTECT(lev);
- if (!sockets[i].conn) {
- sockets[i].conn = newconn;
- /* The socket is not yet known to anyone, so no need to protect
- after having marked it as used. */
- SYS_ARCH_UNPROTECT(lev);
- sockets[i].lastdata = NULL;
- sockets[i].lastoffset = 0;
- sockets[i].rcvevent = 0;
- /* TCP sendbuf is empty, but the socket is not yet writable until connected
- * (unless it has been created by accept()). */
- sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
- sockets[i].errevent = 0;
- sockets[i].err = 0;
- sockets[i].select_waiting = 0;
- return i;
- }
- SYS_ARCH_UNPROTECT(lev);
- }
- return -1;
-}
-
-/** Free a socket. The socket's netconn must have been
- * delete before!
- *
- * @param sock the socket to free
- * @param is_tcp != 0 for TCP sockets, used to free lastdata
- */
-static void
-free_socket(struct lwip_sock *sock, int is_tcp)
-{
- void *lastdata;
- SYS_ARCH_DECL_PROTECT(lev);
-
- lastdata = sock->lastdata;
- sock->lastdata = NULL;
- sock->lastoffset = 0;
- sock->err = 0;
-
- /* Protect socket array */
- SYS_ARCH_PROTECT(lev);
- sock->conn = NULL;
- SYS_ARCH_UNPROTECT(lev);
- /* don't use 'sock' after this line, as another task might have allocated it */
-
- if (lastdata != NULL) {
- if (is_tcp) {
- pbuf_free((struct pbuf *)lastdata);
- } else {
- netbuf_delete((struct netbuf *)lastdata);
- }
- }
-}
-
-/* Below this, the well-known socket functions are implemented.
- * Use google.com or opengroup.org to get a good description :-)
- *
- * Exceptions are documented!
- */
-
-int
-lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
-{
- struct lwip_sock *sock, *nsock;
- struct netconn *newconn;
- ip_addr_t naddr;
- u16_t port;
- int newsock;
- struct sockaddr_in sin;
- err_t err;
- SYS_ARCH_DECL_PROTECT(lev);
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
- sock = get_socket(s);
- if (!sock) {
- return -1;
- }
-
- if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
- sock_set_errno(sock, EWOULDBLOCK);
- return -1;
- }
-
- /* wait for a new connection */
- err = netconn_accept(sock->conn, &newconn);
- if (err != ERR_OK) {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
- sock_set_errno(sock, err_to_errno(err));
- return -1;
- }
- LWIP_ASSERT("newconn != NULL", newconn != NULL);
- /* Prevent automatic window updates, we do this on our own! */
- netconn_set_noautorecved(newconn, 1);
-
- /* get the IP address and port of the remote host */
- err = netconn_peer(newconn, &naddr, &port);
- if (err != ERR_OK) {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
- netconn_delete(newconn);
- sock_set_errno(sock, err_to_errno(err));
- return -1;
- }
-
- /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
- * not be NULL if addr is valid.
- */
- if (NULL != addr) {
- LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
- memset(&sin, 0, sizeof(sin));
- sin.sin_len = sizeof(sin);
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
- inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
-
- if (*addrlen > sizeof(sin))
- *addrlen = sizeof(sin);
-
- MEMCPY(addr, &sin, *addrlen);
- }
-
- newsock = alloc_socket(newconn, 1);
- if (newsock == -1) {
- netconn_delete(newconn);
- sock_set_errno(sock, ENFILE);
- return -1;
- }
- LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
- LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
- nsock = &sockets[newsock];
-
- /* See event_callback: If data comes in right away after an accept, even
- * though the server task might not have created a new socket yet.
- * In that case, newconn->socket is counted down (newconn->socket--),
- * so nsock->rcvevent is >= 1 here!
- */
- SYS_ARCH_PROTECT(lev);
- nsock->rcvevent += (s16_t)(-1 - newconn->socket);
- newconn->socket = newsock;
- SYS_ARCH_UNPROTECT(lev);
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
- ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
-
- sock_set_errno(sock, 0);
- return newsock;
-}
-
-int
-lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
-{
- struct lwip_sock *sock;
- ip_addr_t local_addr;
- u16_t local_port;
- err_t err;
- const struct sockaddr_in *name_in;
-
- sock = get_socket(s);
- if (!sock) {
- return -1;
- }
-
- /* check size, familiy and alignment of 'name' */
- LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
- ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
- sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
- name_in = (const struct sockaddr_in *)(void*)name;
-
- inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
- local_port = name_in->sin_port;
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
- ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
-
- err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
-
- if (err != ERR_OK) {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
- sock_set_errno(sock, err_to_errno(err));
- return -1;
- }
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
- sock_set_errno(sock, 0);
- return 0;
-}
-
-int
-lwip_close(int s)
-{
- struct lwip_sock *sock;
- int is_tcp = 0;
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
-
- sock = get_socket(s);
- if (!sock) {
- return -1;
- }
-
- if(sock->conn != NULL) {
- is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
- } else {
- LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
- }
-
- netconn_delete(sock->conn);
-
- free_socket(sock, is_tcp);
- set_errno(0);
- return 0;
-}
-
-int
-lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
-{
- struct lwip_sock *sock;
- err_t err;
- const struct sockaddr_in *name_in;
-
- sock = get_socket(s);
- if (!sock) {
- return -1;
- }
-
- /* check size, familiy and alignment of 'name' */
- LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
- ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
- sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
- name_in = (const struct sockaddr_in *)(void*)name;
-
- if (name_in->sin_family == AF_UNSPEC) {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
- err = netconn_disconnect(sock->conn);
- } else {
- ip_addr_t remote_addr;
- u16_t remote_port;
-
- inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
- remote_port = name_in->sin_port;
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
- ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
-
- err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
- }
-
- if (err != ERR_OK) {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
- sock_set_errno(sock, err_to_errno(err));
- return -1;
- }
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
- sock_set_errno(sock, 0);
- return 0;
-}
-
-/**
- * Set a socket into listen mode.
- * The socket may not have been used for another connection previously.
- *
- * @param s the socket to set to listening mode
- * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
- * @return 0 on success, non-zero on failure
- */
-int
-lwip_listen(int s, int backlog)
-{
- struct lwip_sock *sock;
- err_t err;
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
-
- sock = get_socket(s);
- if (!sock) {
- return -1;
- }
-
- /* limit the "backlog" parameter to fit in an u8_t */
- backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
-
- err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
-
- if (err != ERR_OK) {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
- sock_set_errno(sock, err_to_errno(err));
- return -1;
- }
-
- sock_set_errno(sock, 0);
- return 0;
-}
-
-int
-lwip_recvfrom(int s, void *mem, size_t len, int flags,
- struct sockaddr *from, socklen_t *fromlen)
-{
- struct lwip_sock *sock;
- void *buf = NULL;
- struct pbuf *p;
- u16_t buflen, copylen;
- int off = 0;
- ip_addr_t *addr;
- u16_t port;
- u8_t done = 0;
- err_t err;
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
- sock = get_socket(s);
- if (!sock) {
- return -1;
- }
-
- do {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
- /* Check if there is data left from the last recv operation. */
- if (sock->lastdata) {
- buf = sock->lastdata;
- } else {
- /* If this is non-blocking call, then check first */
- if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
- (sock->rcvevent <= 0)) {
- if (off > 0) {
- /* update receive window */
- netconn_recved(sock->conn, (u32_t)off);
- /* already received data, return that */
- sock_set_errno(sock, 0);
- return off;
- }
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
- sock_set_errno(sock, EWOULDBLOCK);
- return -1;
- }
-
- /* No data was left from the previous operation, so we try to get
- some from the network. */
- if (netconn_type(sock->conn) == NETCONN_TCP) {
- err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
- } else {
- err = netconn_recv(sock->conn, (struct netbuf **)&buf);
- }
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
- err, buf));
-
- if (err != ERR_OK) {
- if (off > 0) {
- /* update receive window */
- netconn_recved(sock->conn, (u32_t)off);
- /* already received data, return that */
- sock_set_errno(sock, 0);
- return off;
- }
- /* We should really do some error checking here. */
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
- s, lwip_strerr(err)));
- sock_set_errno(sock, err_to_errno(err));
- if (err == ERR_CLSD) {
- return 0;
- } else {
- return -1;
- }
- }
- LWIP_ASSERT("buf != NULL", buf != NULL);
- sock->lastdata = buf;
- }
-
- if (netconn_type(sock->conn) == NETCONN_TCP) {
- p = (struct pbuf *)buf;
- } else {
- p = ((struct netbuf *)buf)->p;
- }
- buflen = p->tot_len;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
- buflen, len, off, sock->lastoffset));
-
- buflen -= sock->lastoffset;
-
- if (len > buflen) {
- copylen = buflen;
- } else {
- copylen = (u16_t)len;
- }
-
- /* copy the contents of the received buffer into
- the supplied memory pointer mem */
- pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
-
- off += copylen;
-
- if (netconn_type(sock->conn) == NETCONN_TCP) {
- LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
- len -= copylen;
- if ( (len <= 0) ||
- (p->flags & PBUF_FLAG_PUSH) ||
- (sock->rcvevent <= 0) ||
- ((flags & MSG_PEEK)!=0)) {
- done = 1;
- }
- } else {
- done = 1;
- }
-
- /* Check to see from where the data was.*/
- if (done) {
- ip_addr_t fromaddr;
- if (from && fromlen) {
- struct sockaddr_in sin;
-
- if (netconn_type(sock->conn) == NETCONN_TCP) {
- addr = &fromaddr;
- netconn_getaddr(sock->conn, addr, &port, 0);
- } else {
- addr = netbuf_fromaddr((struct netbuf *)buf);
- port = netbuf_fromport((struct netbuf *)buf);
- }
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_len = sizeof(sin);
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
- inet_addr_from_ipaddr(&sin.sin_addr, addr);
-
- if (*fromlen > sizeof(sin)) {
- *fromlen = sizeof(sin);
- }
-
- MEMCPY(from, &sin, *fromlen);
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
- ip_addr_debug_print(SOCKETS_DEBUG, addr);
- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
- } else {
-#if SOCKETS_DEBUG
- if (netconn_type(sock->conn) == NETCONN_TCP) {
- addr = &fromaddr;
- netconn_getaddr(sock->conn, addr, &port, 0);
- } else {
- addr = netbuf_fromaddr((struct netbuf *)buf);
- port = netbuf_fromport((struct netbuf *)buf);
- }
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
- ip_addr_debug_print(SOCKETS_DEBUG, addr);
- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
-#endif /* SOCKETS_DEBUG */
- }
- }
-
- /* If we don't peek the incoming message... */
- if ((flags & MSG_PEEK) == 0) {
- /* If this is a TCP socket, check if there is data left in the
- buffer. If so, it should be saved in the sock structure for next
- time around. */
- if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
- sock->lastdata = buf;
- sock->lastoffset += copylen;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
- } else {
- sock->lastdata = NULL;
- sock->lastoffset = 0;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
- if (netconn_type(sock->conn) == NETCONN_TCP) {
- pbuf_free((struct pbuf *)buf);
- } else {
- netbuf_delete((struct netbuf *)buf);
- }
- }
- }
- } while (!done);
-
- if (off > 0) {
- /* update receive window */
- netconn_recved(sock->conn, (u32_t)off);
- }
- sock_set_errno(sock, 0);
- return off;
-}
-
-int
-lwip_read(int s, void *mem, size_t len)
-{
- return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
-}
-
-int
-lwip_recv(int s, void *mem, size_t len, int flags)
-{
- return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
-}
-
-int
-lwip_send(int s, const void *data, size_t size, int flags)
-{
- struct lwip_sock *sock;
- err_t err;
- u8_t write_flags;
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
- s, data, size, flags));
-
- sock = get_socket(s);
- if (!sock) {
- return -1;
- }
-
- if (sock->conn->type != NETCONN_TCP) {
-#if (LWIP_UDP || LWIP_RAW)
- return lwip_sendto(s, data, size, flags, NULL, 0);
-#else /* (LWIP_UDP || LWIP_RAW) */
- sock_set_errno(sock, err_to_errno(ERR_ARG));
- return -1;
-#endif /* (LWIP_UDP || LWIP_RAW) */
- }
-
- if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) {
- if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) {
- /* too much data to ever send nonblocking! */
- sock_set_errno(sock, EMSGSIZE);
- return -1;
- }
- }
-
- write_flags = NETCONN_COPY |
- ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
- ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
- err = netconn_write(sock->conn, data, size, write_flags);
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size));
- sock_set_errno(sock, err_to_errno(err));
- return (err == ERR_OK ? (int)size : -1);
-}
-
-int
-lwip_sendto(int s, const void *data, size_t size, int flags,
- const struct sockaddr *to, socklen_t tolen)
-{
- struct lwip_sock *sock;
- err_t err;
- u16_t short_size;
- const struct sockaddr_in *to_in;
- u16_t remote_port;
-#if !LWIP_TCPIP_CORE_LOCKING
- struct netbuf buf;
-#endif
-
- sock = get_socket(s);
- if (!sock) {
- return -1;
- }
-
- if (sock->conn->type == NETCONN_TCP) {
-#if LWIP_TCP
- return lwip_send(s, data, size, flags);
-#else /* LWIP_TCP */
- LWIP_UNUSED_ARG(flags);
- sock_set_errno(sock, err_to_errno(ERR_ARG));
- return -1;
-#endif /* LWIP_TCP */
- }
-
- /* @todo: split into multiple sendto's? */
- LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
- short_size = (u16_t)size;
- LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
- ((tolen == sizeof(struct sockaddr_in)) &&
- ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),
- sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
- to_in = (const struct sockaddr_in *)(void*)to;
-
-#if LWIP_TCPIP_CORE_LOCKING
- /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
- {
- struct pbuf* p;
- ip_addr_t *remote_addr;
-
-#if LWIP_NETIF_TX_SINGLE_PBUF
- p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
- if (p != NULL) {
-#if LWIP_CHECKSUM_ON_COPY
- u16_t chksum = 0;
- if (sock->conn->type != NETCONN_RAW) {
- chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
- } else
-#endif /* LWIP_CHECKSUM_ON_COPY */
- MEMCPY(p->payload, data, size);
-#else /* LWIP_NETIF_TX_SINGLE_PBUF */
- p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);
- if (p != NULL) {
- p->payload = (void*)data;
-#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
-
- if (to_in != NULL) {
- inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
- remote_port = ntohs(to_in->sin_port);
- } else {
- remote_addr = &sock->conn->pcb.raw->remote_ip;
- if (sock->conn->type == NETCONN_RAW) {
- remote_port = 0;
- } else {
- remote_port = sock->conn->pcb.udp->remote_port;
- }
- }
-
- LOCK_TCPIP_CORE();
- if (sock->conn->type == NETCONN_RAW) {
- err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);
- } else {
-#if LWIP_UDP
-#if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
- err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
- remote_addr, remote_port, 1, chksum);
-#else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
- err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
- remote_addr, remote_port);
-#endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
-#else /* LWIP_UDP */
- err = ERR_ARG;
-#endif /* LWIP_UDP */
- }
- UNLOCK_TCPIP_CORE();
-
- pbuf_free(p);
- } else {
- err = ERR_MEM;
- }
- }
-#else /* LWIP_TCPIP_CORE_LOCKING */
- /* initialize a buffer */
- buf.p = buf.ptr = NULL;
-#if LWIP_CHECKSUM_ON_COPY
- buf.flags = 0;
-#endif /* LWIP_CHECKSUM_ON_COPY */
- if (to) {
- inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
- remote_port = ntohs(to_in->sin_port);
- netbuf_fromport(&buf) = remote_port;
- } else {
- remote_port = 0;
- ip_addr_set_any(&buf.addr);
- netbuf_fromport(&buf) = 0;
- }
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
- s, data, short_size, flags));
- ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
-
- /* make the buffer point to the data that should be sent */
-#if LWIP_NETIF_TX_SINGLE_PBUF
- /* Allocate a new netbuf and copy the data into it. */
- if (netbuf_alloc(&buf, short_size) == NULL) {
- err = ERR_MEM;
- } else {
-#if LWIP_CHECKSUM_ON_COPY
- if (sock->conn->type != NETCONN_RAW) {
- u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
- netbuf_set_chksum(&buf, chksum);
- err = ERR_OK;
- } else
-#endif /* LWIP_CHECKSUM_ON_COPY */
- {
- err = netbuf_take(&buf, data, short_size);
- }
- }
-#else /* LWIP_NETIF_TX_SINGLE_PBUF */
- err = netbuf_ref(&buf, data, short_size);
-#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
- if (err == ERR_OK) {
- /* send the data */
- err = netconn_send(sock->conn, &buf);
- }
-
- /* deallocated the buffer */
- netbuf_free(&buf);
-#endif /* LWIP_TCPIP_CORE_LOCKING */
- sock_set_errno(sock, err_to_errno(err));
- return (err == ERR_OK ? short_size : -1);
-}
-
-int
-lwip_socket(int domain, int type, int protocol)
-{
- struct netconn *conn;
- int i;
-
- LWIP_UNUSED_ARG(domain);
-
- /* create a netconn */
- switch (type) {
- case SOCK_RAW:
- conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
- domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
- break;
- case SOCK_DGRAM:
- conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
- NETCONN_UDPLITE : NETCONN_UDP, event_callback);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
- domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
- break;
- case SOCK_STREAM:
- conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
- domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
- if (conn != NULL) {
- /* Prevent automatic window updates, we do this on our own! */
- netconn_set_noautorecved(conn, 1);
- }
- break;
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
- domain, type, protocol));
- set_errno(EINVAL);
- return -1;
- }
-
- if (!conn) {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
- set_errno(ENOBUFS);
- return -1;
- }
-
- i = alloc_socket(conn, 0);
-
- if (i == -1) {
- netconn_delete(conn);
- set_errno(ENFILE);
- return -1;
- }
- conn->socket = i;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
- set_errno(0);
- return i;
-}
-
-int
-lwip_write(int s, const void *data, size_t size)
-{
- return lwip_send(s, data, size, 0);
-}
-
-/**
- * Go through the readset and writeset lists and see which socket of the sockets
- * set in the sets has events. On return, readset, writeset and exceptset have
- * the sockets enabled that had events.
- *
- * exceptset is not used for now!!!
- *
- * @param maxfdp1 the highest socket index in the sets
- * @param readset_in: set of sockets to check for read events
- * @param writeset_in: set of sockets to check for write events
- * @param exceptset_in: set of sockets to check for error events
- * @param readset_out: set of sockets that had read events
- * @param writeset_out: set of sockets that had write events
- * @param exceptset_out: set os sockets that had error events
- * @return number of sockets that had events (read/write/exception) (>= 0)
- */
-static int
-lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
- fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
-{
- int i, nready = 0;
- fd_set lreadset, lwriteset, lexceptset;
- struct lwip_sock *sock;
- SYS_ARCH_DECL_PROTECT(lev);
-
- FD_ZERO(&lreadset);
- FD_ZERO(&lwriteset);
- FD_ZERO(&lexceptset);
-
- /* Go through each socket in each list to count number of sockets which
- currently match */
- for(i = 0; i < maxfdp1; i++) {
- void* lastdata = NULL;
- s16_t rcvevent = 0;
- u16_t sendevent = 0;
- u16_t errevent = 0;
- /* First get the socket's status (protected)... */
- SYS_ARCH_PROTECT(lev);
- sock = tryget_socket(i);
- if (sock != NULL) {
- lastdata = sock->lastdata;
- rcvevent = sock->rcvevent;
- sendevent = sock->sendevent;
- errevent = sock->errevent;
- }
- SYS_ARCH_UNPROTECT(lev);
- /* ... then examine it: */
- /* See if netconn of this socket is ready for read */
- if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
- FD_SET(i, &lreadset);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
- nready++;
- }
- /* See if netconn of this socket is ready for write */
- if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
- FD_SET(i, &lwriteset);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
- nready++;
- }
- /* See if netconn of this socket had an error */
- if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
- FD_SET(i, &lexceptset);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
- nready++;
- }
- }
- /* copy local sets to the ones provided as arguments */
- *readset_out = lreadset;
- *writeset_out = lwriteset;
- *exceptset_out = lexceptset;
-
- LWIP_ASSERT("nready >= 0", nready >= 0);
- return nready;
-}
-
-/**
- * Processing exceptset is not yet implemented.
- */
-int
-lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
- struct timeval *timeout)
-{
- u32_t waitres = 0;
- int nready;
- fd_set lreadset, lwriteset, lexceptset;
- u32_t msectimeout;
- struct lwip_select_cb select_cb;
- err_t err;
- int i;
- SYS_ARCH_DECL_PROTECT(lev);
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
- maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
- timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
- timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
-
- /* Go through each socket in each list to count number of sockets which
- currently match */
- nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
-
- /* If we don't have any current events, then suspend if we are supposed to */
- if (!nready) {
- if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
- /* This is OK as the local fdsets are empty and nready is zero,
- or we would have returned earlier. */
- goto return_copy_fdsets;
- }
-
- /* None ready: add our semaphore to list:
- We don't actually need any dynamic memory. Our entry on the
- list is only valid while we are in this function, so it's ok
- to use local variables. */
-
- select_cb.next = NULL;
- select_cb.prev = NULL;
- select_cb.readset = readset;
- select_cb.writeset = writeset;
- select_cb.exceptset = exceptset;
- select_cb.sem_signalled = 0;
- err = sys_sem_new(&select_cb.sem, 0);
- if (err != ERR_OK) {
- /* failed to create semaphore */
- set_errno(ENOMEM);
- return -1;
- }
-
- /* Protect the select_cb_list */
- SYS_ARCH_PROTECT(lev);
-
- /* Put this select_cb on top of list */
- select_cb.next = select_cb_list;
- if (select_cb_list != NULL) {
- select_cb_list->prev = &select_cb;
- }
- select_cb_list = &select_cb;
- /* Increasing this counter tells even_callback that the list has changed. */
- select_cb_ctr++;
-
- /* Now we can safely unprotect */
- SYS_ARCH_UNPROTECT(lev);
-
- /* Increase select_waiting for each socket we are interested in */
- for(i = 0; i < maxfdp1; i++) {
- if ((readset && FD_ISSET(i, readset)) ||
- (writeset && FD_ISSET(i, writeset)) ||
- (exceptset && FD_ISSET(i, exceptset))) {
- struct lwip_sock *sock = tryget_socket(i);
- LWIP_ASSERT("sock != NULL", sock != NULL);
- SYS_ARCH_PROTECT(lev);
- sock->select_waiting++;
- LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
- SYS_ARCH_UNPROTECT(lev);
- }
- }
-
- /* Call lwip_selscan again: there could have been events between
- the last scan (whithout us on the list) and putting us on the list! */
- nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
- if (!nready) {
- /* Still none ready, just wait to be woken */
- if (timeout == 0) {
- /* Wait forever */
- msectimeout = 0;
- } else {
- msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
- if (msectimeout == 0) {
- /* Wait 1ms at least (0 means wait forever) */
- msectimeout = 1;
- }
- }
-
- waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
- }
- /* Increase select_waiting for each socket we are interested in */
- for(i = 0; i < maxfdp1; i++) {
- if ((readset && FD_ISSET(i, readset)) ||
- (writeset && FD_ISSET(i, writeset)) ||
- (exceptset && FD_ISSET(i, exceptset))) {
- struct lwip_sock *sock = tryget_socket(i);
- LWIP_ASSERT("sock != NULL", sock != NULL);
- SYS_ARCH_PROTECT(lev);
- sock->select_waiting--;
- LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
- SYS_ARCH_UNPROTECT(lev);
- }
- }
- /* Take us off the list */
- SYS_ARCH_PROTECT(lev);
- if (select_cb.next != NULL) {
- select_cb.next->prev = select_cb.prev;
- }
- if (select_cb_list == &select_cb) {
- LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
- select_cb_list = select_cb.next;
- } else {
- LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
- select_cb.prev->next = select_cb.next;
- }
- /* Increasing this counter tells even_callback that the list has changed. */
- select_cb_ctr++;
- SYS_ARCH_UNPROTECT(lev);
-
- sys_sem_free(&select_cb.sem);
- if (waitres == SYS_ARCH_TIMEOUT) {
- /* Timeout */
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
- /* This is OK as the local fdsets are empty and nready is zero,
- or we would have returned earlier. */
- goto return_copy_fdsets;
- }
-
- /* See what's set */
- nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
- }
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
-return_copy_fdsets:
- set_errno(0);
- if (readset) {
- *readset = lreadset;
- }
- if (writeset) {
- *writeset = lwriteset;
- }
- if (exceptset) {
- *exceptset = lexceptset;
- }
-
-
- return nready;
-}
-
-/**
- * Callback registered in the netconn layer for each socket-netconn.
- * Processes recvevent (data available) and wakes up tasks waiting for select.
- */
-static void
-event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
-{
- int s;
- struct lwip_sock *sock;
- struct lwip_select_cb *scb;
- int last_select_cb_ctr;
- SYS_ARCH_DECL_PROTECT(lev);
-
- LWIP_UNUSED_ARG(len);
-
- /* Get socket */
- if (conn) {
- s = conn->socket;
- if (s < 0) {
- /* Data comes in right away after an accept, even though
- * the server task might not have created a new socket yet.
- * Just count down (or up) if that's the case and we
- * will use the data later. Note that only receive events
- * can happen before the new socket is set up. */
- SYS_ARCH_PROTECT(lev);
- if (conn->socket < 0) {
- if (evt == NETCONN_EVT_RCVPLUS) {
- conn->socket--;
- }
- SYS_ARCH_UNPROTECT(lev);
- return;
- }
- s = conn->socket;
- SYS_ARCH_UNPROTECT(lev);
- }
-
- sock = get_socket(s);
- if (!sock) {
- return;
- }
- } else {
- return;
- }
-
- SYS_ARCH_PROTECT(lev);
- /* Set event as required */
- switch (evt) {
- case NETCONN_EVT_RCVPLUS:
- sock->rcvevent++;
- break;
- case NETCONN_EVT_RCVMINUS:
- sock->rcvevent--;
- break;
- case NETCONN_EVT_SENDPLUS:
- sock->sendevent = 1;
- break;
- case NETCONN_EVT_SENDMINUS:
- sock->sendevent = 0;
- break;
- case NETCONN_EVT_ERROR:
- sock->errevent = 1;
- break;
- default:
- LWIP_ASSERT("unknown event", 0);
- break;
- }
-
- if (sock->select_waiting == 0) {
- /* noone is waiting for this socket, no need to check select_cb_list */
- SYS_ARCH_UNPROTECT(lev);
- return;
- }
-
- /* Now decide if anyone is waiting for this socket */
- /* NOTE: This code goes through the select_cb_list list multiple times
- ONLY IF a select was actually waiting. We go through the list the number
- of waiting select calls + 1. This list is expected to be small. */
-
- /* At this point, SYS_ARCH is still protected! */
-again:
- for (scb = select_cb_list; scb != NULL; scb = scb->next) {
- if (scb->sem_signalled == 0) {
- /* semaphore not signalled yet */
- int do_signal = 0;
- /* Test this select call for our socket */
- if (sock->rcvevent > 0) {
- if (scb->readset && FD_ISSET(s, scb->readset)) {
- do_signal = 1;
- }
- }
- if (sock->sendevent != 0) {
- if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
- do_signal = 1;
- }
- }
- if (sock->errevent != 0) {
- if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
- do_signal = 1;
- }
- }
- if (do_signal) {
- scb->sem_signalled = 1;
- /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
- lead to the select thread taking itself off the list, invalidagin the semaphore. */
- sys_sem_signal(&scb->sem);
- }
- }
- /* unlock interrupts with each step */
- last_select_cb_ctr = select_cb_ctr;
- SYS_ARCH_UNPROTECT(lev);
- /* this makes sure interrupt protection time is short */
- SYS_ARCH_PROTECT(lev);
- if (last_select_cb_ctr != select_cb_ctr) {
- /* someone has changed select_cb_list, restart at the beginning */
- goto again;
- }
- }
- SYS_ARCH_UNPROTECT(lev);
-}
-
-/**
- * Unimplemented: Close one end of a full-duplex connection.
- * Currently, the full connection is closed.
- */
-int
-lwip_shutdown(int s, int how)
-{
- struct lwip_sock *sock;
- err_t err;
- u8_t shut_rx = 0, shut_tx = 0;
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
-
- sock = get_socket(s);
- if (!sock) {
- return -1;
- }
-
- if (sock->conn != NULL) {
- if (netconn_type(sock->conn) != NETCONN_TCP) {
- sock_set_errno(sock, EOPNOTSUPP);
- return EOPNOTSUPP;
- }
- } else {
- sock_set_errno(sock, ENOTCONN);
- return ENOTCONN;
- }
-
- if (how == SHUT_RD) {
- shut_rx = 1;
- } else if (how == SHUT_WR) {
- shut_tx = 1;
- } else if(how == SHUT_RDWR) {
- shut_rx = 1;
- shut_tx = 1;
- } else {
- sock_set_errno(sock, EINVAL);
- return EINVAL;
- }
- err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
-
- sock_set_errno(sock, err_to_errno(err));
- return (err == ERR_OK ? 0 : -1);
-}
-
-static int
-lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
-{
- struct lwip_sock *sock;
- struct sockaddr_in sin;
- ip_addr_t naddr;
-
- sock = get_socket(s);
- if (!sock) {
- return -1;
- }
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_len = sizeof(sin);
- sin.sin_family = AF_INET;
-
- /* get the IP address and port */
- netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
- ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
-
- sin.sin_port = htons(sin.sin_port);
- inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
-
- if (*namelen > sizeof(sin)) {
- *namelen = sizeof(sin);
- }
-
- MEMCPY(name, &sin, *namelen);
- sock_set_errno(sock, 0);
- return 0;
-}
-
-int
-lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
-{
- return lwip_getaddrname(s, name, namelen, 0);
-}
-
-int
-lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
-{
- return lwip_getaddrname(s, name, namelen, 1);
-}
-
-int
-lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
-{
- err_t err = ERR_OK;
- struct lwip_sock *sock = get_socket(s);
- struct lwip_setgetsockopt_data data;
-
- if (!sock) {
- return -1;
- }
-
- if ((NULL == optval) || (NULL == optlen)) {
- sock_set_errno(sock, EFAULT);
- return -1;
- }
-
- /* Do length and type checks for the various options first, to keep it readable. */
- switch (level) {
-
-/* Level: SOL_SOCKET */
- case SOL_SOCKET:
- switch (optname) {
-
- case SO_ACCEPTCONN:
- case SO_BROADCAST:
- /* UNIMPL case SO_DEBUG: */
- /* UNIMPL case SO_DONTROUTE: */
- case SO_ERROR:
- case SO_KEEPALIVE:
- /* UNIMPL case SO_CONTIMEO: */
- /* UNIMPL case SO_SNDTIMEO: */
-#if LWIP_SO_RCVTIMEO
- case SO_RCVTIMEO:
-#endif /* LWIP_SO_RCVTIMEO */
-#if LWIP_SO_RCVBUF
- case SO_RCVBUF:
-#endif /* LWIP_SO_RCVBUF */
- /* UNIMPL case SO_OOBINLINE: */
- /* UNIMPL case SO_SNDBUF: */
- /* UNIMPL case SO_RCVLOWAT: */
- /* UNIMPL case SO_SNDLOWAT: */
-#if SO_REUSE
- case SO_REUSEADDR:
- case SO_REUSEPORT:
-#endif /* SO_REUSE */
- case SO_TYPE:
- /* UNIMPL case SO_USELOOPBACK: */
- if (*optlen < sizeof(int)) {
- err = EINVAL;
- }
- break;
-
- case SO_NO_CHECK:
- if (*optlen < sizeof(int)) {
- err = EINVAL;
- }
-#if LWIP_UDP
- if ((sock->conn->type != NETCONN_UDP) ||
- ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
- /* this flag is only available for UDP, not for UDP lite */
- err = EAFNOSUPPORT;
- }
-#endif /* LWIP_UDP */
- break;
-
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
- s, optname));
- err = ENOPROTOOPT;
- } /* switch (optname) */
- break;
-
-/* Level: IPPROTO_IP */
- case IPPROTO_IP:
- switch (optname) {
- /* UNIMPL case IP_HDRINCL: */
- /* UNIMPL case IP_RCVDSTADDR: */
- /* UNIMPL case IP_RCVIF: */
- case IP_TTL:
- case IP_TOS:
- if (*optlen < sizeof(int)) {
- err = EINVAL;
- }
- break;
-#if LWIP_IGMP
- case IP_MULTICAST_TTL:
- if (*optlen < sizeof(u8_t)) {
- err = EINVAL;
- }
- break;
- case IP_MULTICAST_IF:
- if (*optlen < sizeof(struct in_addr)) {
- err = EINVAL;
- }
- break;
- case IP_MULTICAST_LOOP:
- if (*optlen < sizeof(u8_t)) {
- err = EINVAL;
- }
- if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
- err = EAFNOSUPPORT;
- }
- break;
-#endif /* LWIP_IGMP */
-
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
- s, optname));
- err = ENOPROTOOPT;
- } /* switch (optname) */
- break;
-
-#if LWIP_TCP
-/* Level: IPPROTO_TCP */
- case IPPROTO_TCP:
- if (*optlen < sizeof(int)) {
- err = EINVAL;
- break;
- }
-
- /* If this is no TCP socket, ignore any options. */
- if (sock->conn->type != NETCONN_TCP)
- return 0;
-
- switch (optname) {
- case TCP_NODELAY:
- case TCP_KEEPALIVE:
-#if LWIP_TCP_KEEPALIVE
- case TCP_KEEPIDLE:
- case TCP_KEEPINTVL:
- case TCP_KEEPCNT:
-#endif /* LWIP_TCP_KEEPALIVE */
- break;
-
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
- s, optname));
- err = ENOPROTOOPT;
- } /* switch (optname) */
- break;
-#endif /* LWIP_TCP */
-#if LWIP_UDP && LWIP_UDPLITE
-/* Level: IPPROTO_UDPLITE */
- case IPPROTO_UDPLITE:
- if (*optlen < sizeof(int)) {
- err = EINVAL;
- break;
- }
-
- /* If this is no UDP lite socket, ignore any options. */
- if (sock->conn->type != NETCONN_UDPLITE) {
- return 0;
- }
-
- switch (optname) {
- case UDPLITE_SEND_CSCOV:
- case UDPLITE_RECV_CSCOV:
- break;
-
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
- s, optname));
- err = ENOPROTOOPT;
- } /* switch (optname) */
- break;
-#endif /* LWIP_UDP && LWIP_UDPLITE*/
-/* UNDEFINED LEVEL */
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
- s, level, optname));
- err = ENOPROTOOPT;
- } /* switch */
-
-
- if (err != ERR_OK) {
- sock_set_errno(sock, err);
- return -1;
- }
-
- /* Now do the actual option processing */
- data.sock = sock;
-#ifdef LWIP_DEBUG
- data.s = s;
-#endif /* LWIP_DEBUG */
- data.level = level;
- data.optname = optname;
- data.optval = optval;
- data.optlen = optlen;
- data.err = err;
- tcpip_callback(lwip_getsockopt_internal, &data);
- sys_arch_sem_wait(&sock->conn->op_completed, 0);
- /* maybe lwip_getsockopt_internal has changed err */
- err = data.err;
-
- sock_set_errno(sock, err);
- return err ? -1 : 0;
-}
-
-static void
-lwip_getsockopt_internal(void *arg)
-{
- struct lwip_sock *sock;
-#ifdef LWIP_DEBUG
- int s;
-#endif /* LWIP_DEBUG */
- int level, optname;
- void *optval;
- struct lwip_setgetsockopt_data *data;
-
- LWIP_ASSERT("arg != NULL", arg != NULL);
-
- data = (struct lwip_setgetsockopt_data*)arg;
- sock = data->sock;
-#ifdef LWIP_DEBUG
- s = data->s;
-#endif /* LWIP_DEBUG */
- level = data->level;
- optname = data->optname;
- optval = data->optval;
-
- switch (level) {
-
-/* Level: SOL_SOCKET */
- case SOL_SOCKET:
- switch (optname) {
-
- /* The option flags */
- case SO_ACCEPTCONN:
- case SO_BROADCAST:
- /* UNIMPL case SO_DEBUG: */
- /* UNIMPL case SO_DONTROUTE: */
- case SO_KEEPALIVE:
- /* UNIMPL case SO_OOBINCLUDE: */
-#if SO_REUSE
- case SO_REUSEADDR:
- case SO_REUSEPORT:
-#endif /* SO_REUSE */
- /*case SO_USELOOPBACK: UNIMPL */
- *(int*)optval = sock->conn->pcb.ip->so_options & optname;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
- s, optname, (*(int*)optval?"on":"off")));
- break;
-
- case SO_TYPE:
- switch (NETCONNTYPE_GROUP(sock->conn->type)) {
- case NETCONN_RAW:
- *(int*)optval = SOCK_RAW;
- break;
- case NETCONN_TCP:
- *(int*)optval = SOCK_STREAM;
- break;
- case NETCONN_UDP:
- *(int*)optval = SOCK_DGRAM;
- break;
- default: /* unrecognized socket type */
- *(int*)optval = sock->conn->type;
- LWIP_DEBUGF(SOCKETS_DEBUG,
- ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
- s, *(int *)optval));
- } /* switch (sock->conn->type) */
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
- s, *(int *)optval));
- break;
-
- case SO_ERROR:
- /* only overwrite ERR_OK or tempoary errors */
- if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
- sock_set_errno(sock, err_to_errno(sock->conn->last_err));
- }
- *(int *)optval = sock->err;
- sock->err = 0;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
- s, *(int *)optval));
- break;
-
-#if LWIP_SO_RCVTIMEO
- case SO_RCVTIMEO:
- *(int *)optval = netconn_get_recvtimeout(sock->conn);
- break;
-#endif /* LWIP_SO_RCVTIMEO */
-#if LWIP_SO_RCVBUF
- case SO_RCVBUF:
- *(int *)optval = netconn_get_recvbufsize(sock->conn);
- break;
-#endif /* LWIP_SO_RCVBUF */
-#if LWIP_UDP
- case SO_NO_CHECK:
- *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
- break;
-#endif /* LWIP_UDP*/
- default:
- LWIP_ASSERT("unhandled optname", 0);
- break;
- } /* switch (optname) */
- break;
-
-/* Level: IPPROTO_IP */
- case IPPROTO_IP:
- switch (optname) {
- case IP_TTL:
- *(int*)optval = sock->conn->pcb.ip->ttl;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
- s, *(int *)optval));
- break;
- case IP_TOS:
- *(int*)optval = sock->conn->pcb.ip->tos;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
- s, *(int *)optval));
- break;
-#if LWIP_IGMP
- case IP_MULTICAST_TTL:
- *(u8_t*)optval = sock->conn->pcb.ip->ttl;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
- s, *(int *)optval));
- break;
- case IP_MULTICAST_IF:
- inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
- s, *(u32_t *)optval));
- break;
- case IP_MULTICAST_LOOP:
- if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
- *(u8_t*)optval = 1;
- } else {
- *(u8_t*)optval = 0;
- }
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
- s, *(int *)optval));
- break;
-#endif /* LWIP_IGMP */
- default:
- LWIP_ASSERT("unhandled optname", 0);
- break;
- } /* switch (optname) */
- break;
-
-#if LWIP_TCP
-/* Level: IPPROTO_TCP */
- case IPPROTO_TCP:
- switch (optname) {
- case TCP_NODELAY:
- *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
- s, (*(int*)optval)?"on":"off") );
- break;
- case TCP_KEEPALIVE:
- *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
- s, *(int *)optval));
- break;
-
-#if LWIP_TCP_KEEPALIVE
- case TCP_KEEPIDLE:
- *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
- s, *(int *)optval));
- break;
- case TCP_KEEPINTVL:
- *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
- s, *(int *)optval));
- break;
- case TCP_KEEPCNT:
- *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
- s, *(int *)optval));
- break;
-#endif /* LWIP_TCP_KEEPALIVE */
- default:
- LWIP_ASSERT("unhandled optname", 0);
- break;
- } /* switch (optname) */
- break;
-#endif /* LWIP_TCP */
-#if LWIP_UDP && LWIP_UDPLITE
- /* Level: IPPROTO_UDPLITE */
- case IPPROTO_UDPLITE:
- switch (optname) {
- case UDPLITE_SEND_CSCOV:
- *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
- s, (*(int*)optval)) );
- break;
- case UDPLITE_RECV_CSCOV:
- *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
- s, (*(int*)optval)) );
- break;
- default:
- LWIP_ASSERT("unhandled optname", 0);
- break;
- } /* switch (optname) */
- break;
-#endif /* LWIP_UDP */
- default:
- LWIP_ASSERT("unhandled level", 0);
- break;
- } /* switch (level) */
- sys_sem_signal(&sock->conn->op_completed);
-}
-
-int
-lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
-{
- struct lwip_sock *sock = get_socket(s);
- err_t err = ERR_OK;
- struct lwip_setgetsockopt_data data;
-
- if (!sock) {
- return -1;
- }
-
- if (NULL == optval) {
- sock_set_errno(sock, EFAULT);
- return -1;
- }
-
- /* Do length and type checks for the various options first, to keep it readable. */
- switch (level) {
-
-/* Level: SOL_SOCKET */
- case SOL_SOCKET:
- switch (optname) {
-
- case SO_BROADCAST:
- /* UNIMPL case SO_DEBUG: */
- /* UNIMPL case SO_DONTROUTE: */
- case SO_KEEPALIVE:
- /* UNIMPL case case SO_CONTIMEO: */
- /* UNIMPL case case SO_SNDTIMEO: */
-#if LWIP_SO_RCVTIMEO
- case SO_RCVTIMEO:
-#endif /* LWIP_SO_RCVTIMEO */
-#if LWIP_SO_RCVBUF
- case SO_RCVBUF:
-#endif /* LWIP_SO_RCVBUF */
- /* UNIMPL case SO_OOBINLINE: */
- /* UNIMPL case SO_SNDBUF: */
- /* UNIMPL case SO_RCVLOWAT: */
- /* UNIMPL case SO_SNDLOWAT: */
-#if SO_REUSE
- case SO_REUSEADDR:
- case SO_REUSEPORT:
-#endif /* SO_REUSE */
- /* UNIMPL case SO_USELOOPBACK: */
- if (optlen < sizeof(int)) {
- err = EINVAL;
- }
- break;
- case SO_NO_CHECK:
- if (optlen < sizeof(int)) {
- err = EINVAL;
- }
-#if LWIP_UDP
- if ((sock->conn->type != NETCONN_UDP) ||
- ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
- /* this flag is only available for UDP, not for UDP lite */
- err = EAFNOSUPPORT;
- }
-#endif /* LWIP_UDP */
- break;
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
- s, optname));
- err = ENOPROTOOPT;
- } /* switch (optname) */
- break;
-
-/* Level: IPPROTO_IP */
- case IPPROTO_IP:
- switch (optname) {
- /* UNIMPL case IP_HDRINCL: */
- /* UNIMPL case IP_RCVDSTADDR: */
- /* UNIMPL case IP_RCVIF: */
- case IP_TTL:
- case IP_TOS:
- if (optlen < sizeof(int)) {
- err = EINVAL;
- }
- break;
-#if LWIP_IGMP
- case IP_MULTICAST_TTL:
- if (optlen < sizeof(u8_t)) {
- err = EINVAL;
- }
- if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
- err = EAFNOSUPPORT;
- }
- break;
- case IP_MULTICAST_IF:
- if (optlen < sizeof(struct in_addr)) {
- err = EINVAL;
- }
- if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
- err = EAFNOSUPPORT;
- }
- break;
- case IP_MULTICAST_LOOP:
- if (optlen < sizeof(u8_t)) {
- err = EINVAL;
- }
- if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
- err = EAFNOSUPPORT;
- }
- break;
- case IP_ADD_MEMBERSHIP:
- case IP_DROP_MEMBERSHIP:
- if (optlen < sizeof(struct ip_mreq)) {
- err = EINVAL;
- }
- if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
- err = EAFNOSUPPORT;
- }
- break;
-#endif /* LWIP_IGMP */
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
- s, optname));
- err = ENOPROTOOPT;
- } /* switch (optname) */
- break;
-
-#if LWIP_TCP
-/* Level: IPPROTO_TCP */
- case IPPROTO_TCP:
- if (optlen < sizeof(int)) {
- err = EINVAL;
- break;
- }
-
- /* If this is no TCP socket, ignore any options. */
- if (sock->conn->type != NETCONN_TCP)
- return 0;
-
- switch (optname) {
- case TCP_NODELAY:
- case TCP_KEEPALIVE:
-#if LWIP_TCP_KEEPALIVE
- case TCP_KEEPIDLE:
- case TCP_KEEPINTVL:
- case TCP_KEEPCNT:
-#endif /* LWIP_TCP_KEEPALIVE */
- break;
-
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
- s, optname));
- err = ENOPROTOOPT;
- } /* switch (optname) */
- break;
-#endif /* LWIP_TCP */
-#if LWIP_UDP && LWIP_UDPLITE
-/* Level: IPPROTO_UDPLITE */
- case IPPROTO_UDPLITE:
- if (optlen < sizeof(int)) {
- err = EINVAL;
- break;
- }
-
- /* If this is no UDP lite socket, ignore any options. */
- if (sock->conn->type != NETCONN_UDPLITE)
- return 0;
-
- switch (optname) {
- case UDPLITE_SEND_CSCOV:
- case UDPLITE_RECV_CSCOV:
- break;
-
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
- s, optname));
- err = ENOPROTOOPT;
- } /* switch (optname) */
- break;
-#endif /* LWIP_UDP && LWIP_UDPLITE */
-/* UNDEFINED LEVEL */
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
- s, level, optname));
- err = ENOPROTOOPT;
- } /* switch (level) */
-
-
- if (err != ERR_OK) {
- sock_set_errno(sock, err);
- return -1;
- }
-
-
- /* Now do the actual option processing */
- data.sock = sock;
-#ifdef LWIP_DEBUG
- data.s = s;
-#endif /* LWIP_DEBUG */
- data.level = level;
- data.optname = optname;
- data.optval = (void*)optval;
- data.optlen = &optlen;
- data.err = err;
- tcpip_callback(lwip_setsockopt_internal, &data);
- sys_arch_sem_wait(&sock->conn->op_completed, 0);
- /* maybe lwip_setsockopt_internal has changed err */
- err = data.err;
-
- sock_set_errno(sock, err);
- return err ? -1 : 0;
-}
-
-static void
-lwip_setsockopt_internal(void *arg)
-{
- struct lwip_sock *sock;
-#ifdef LWIP_DEBUG
- int s;
-#endif /* LWIP_DEBUG */
- int level, optname;
- const void *optval;
- struct lwip_setgetsockopt_data *data;
-
- LWIP_ASSERT("arg != NULL", arg != NULL);
-
- data = (struct lwip_setgetsockopt_data*)arg;
- sock = data->sock;
-#ifdef LWIP_DEBUG
- s = data->s;
-#endif /* LWIP_DEBUG */
- level = data->level;
- optname = data->optname;
- optval = data->optval;
-
- switch (level) {
-
-/* Level: SOL_SOCKET */
- case SOL_SOCKET:
- switch (optname) {
-
- /* The option flags */
- case SO_BROADCAST:
- /* UNIMPL case SO_DEBUG: */
- /* UNIMPL case SO_DONTROUTE: */
- case SO_KEEPALIVE:
- /* UNIMPL case SO_OOBINCLUDE: */
-#if SO_REUSE
- case SO_REUSEADDR:
- case SO_REUSEPORT:
-#endif /* SO_REUSE */
- /* UNIMPL case SO_USELOOPBACK: */
- if (*(int*)optval) {
- sock->conn->pcb.ip->so_options |= optname;
- } else {
- sock->conn->pcb.ip->so_options &= ~optname;
- }
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
- s, optname, (*(int*)optval?"on":"off")));
- break;
-#if LWIP_SO_RCVTIMEO
- case SO_RCVTIMEO:
- netconn_set_recvtimeout(sock->conn, *(int*)optval);
- break;
-#endif /* LWIP_SO_RCVTIMEO */
-#if LWIP_SO_RCVBUF
- case SO_RCVBUF:
- netconn_set_recvbufsize(sock->conn, *(int*)optval);
- break;
-#endif /* LWIP_SO_RCVBUF */
-#if LWIP_UDP
- case SO_NO_CHECK:
- if (*(int*)optval) {
- udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
- } else {
- udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
- }
- break;
-#endif /* LWIP_UDP */
- default:
- LWIP_ASSERT("unhandled optname", 0);
- break;
- } /* switch (optname) */
- break;
-
-/* Level: IPPROTO_IP */
- case IPPROTO_IP:
- switch (optname) {
- case IP_TTL:
- sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
- s, sock->conn->pcb.ip->ttl));
- break;
- case IP_TOS:
- sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
- s, sock->conn->pcb.ip->tos));
- break;
-#if LWIP_IGMP
- case IP_MULTICAST_TTL:
- sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
- break;
- case IP_MULTICAST_IF:
- inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
- break;
- case IP_MULTICAST_LOOP:
- if (*(u8_t*)optval) {
- udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
- } else {
- udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
- }
- break;
- case IP_ADD_MEMBERSHIP:
- case IP_DROP_MEMBERSHIP:
- {
- /* If this is a TCP or a RAW socket, ignore these options. */
- struct ip_mreq *imr = (struct ip_mreq *)optval;
- ip_addr_t if_addr;
- ip_addr_t multi_addr;
- inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
- inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
- if(optname == IP_ADD_MEMBERSHIP){
- data->err = igmp_joingroup(&if_addr, &multi_addr);
- } else {
- data->err = igmp_leavegroup(&if_addr, &multi_addr);
- }
- if(data->err != ERR_OK) {
- data->err = EADDRNOTAVAIL;
- }
- }
- break;
-#endif /* LWIP_IGMP */
- default:
- LWIP_ASSERT("unhandled optname", 0);
- break;
- } /* switch (optname) */
- break;
-
-#if LWIP_TCP
-/* Level: IPPROTO_TCP */
- case IPPROTO_TCP:
- switch (optname) {
- case TCP_NODELAY:
- if (*(int*)optval) {
- tcp_nagle_disable(sock->conn->pcb.tcp);
- } else {
- tcp_nagle_enable(sock->conn->pcb.tcp);
- }
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
- s, (*(int *)optval)?"on":"off") );
- break;
- case TCP_KEEPALIVE:
- sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
- s, sock->conn->pcb.tcp->keep_idle));
- break;
-
-#if LWIP_TCP_KEEPALIVE
- case TCP_KEEPIDLE:
- sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
- s, sock->conn->pcb.tcp->keep_idle));
- break;
- case TCP_KEEPINTVL:
- sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
- s, sock->conn->pcb.tcp->keep_intvl));
- break;
- case TCP_KEEPCNT:
- sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
- s, sock->conn->pcb.tcp->keep_cnt));
- break;
-#endif /* LWIP_TCP_KEEPALIVE */
- default:
- LWIP_ASSERT("unhandled optname", 0);
- break;
- } /* switch (optname) */
- break;
-#endif /* LWIP_TCP*/
-#if LWIP_UDP && LWIP_UDPLITE
- /* Level: IPPROTO_UDPLITE */
- case IPPROTO_UDPLITE:
- switch (optname) {
- case UDPLITE_SEND_CSCOV:
- if ( ( (*(int*)optval != 0) && ((*(int*)optval < 8)) ) || (*(int*)optval > 0xffff)) {
- /* don't allow illegal values! */
- sock->conn->pcb.udp->chksum_len_tx = 8;
- } else {
- sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
- }
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
- s, (*(int*)optval)) );
- break;
- case UDPLITE_RECV_CSCOV:
- if ( ((*(int*)optval != 0) && ((*(int*)optval < 8)) ) || (*(int*)optval > 0xffff)) {
- /* don't allow illegal values! */
- sock->conn->pcb.udp->chksum_len_rx = 8;
- } else {
- sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
- }
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
- s, (*(int*)optval)) );
- break;
- default:
- LWIP_ASSERT("unhandled optname", 0);
- break;
- } /* switch (optname) */
- break;
-#endif /* LWIP_UDP */
- default:
- LWIP_ASSERT("unhandled level", 0);
- break;
- } /* switch (level) */
- sys_sem_signal(&sock->conn->op_completed);
-}
-
-int
-lwip_ioctl(int s, long cmd, void *argp)
-{
- struct lwip_sock *sock = get_socket(s);
- u8_t val;
-#if LWIP_SO_RCVBUF
- u16_t buflen = 0;
- s16_t recv_avail;
-#endif /* LWIP_SO_RCVBUF */
-
- if (!sock) {
- return -1;
- }
-
- switch (cmd) {
-#if LWIP_SO_RCVBUF
- case FIONREAD:
- if (!argp) {
- sock_set_errno(sock, EINVAL);
- return -1;
- }
-
- SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
- if (recv_avail < 0) {
- recv_avail = 0;
- }
- *((u16_t*)argp) = (u16_t)recv_avail;
-
- /* Check if there is data left from the last recv operation. /maq 041215 */
- if (sock->lastdata) {
- struct pbuf *p = (struct pbuf *)sock->lastdata;
- if (netconn_type(sock->conn) != NETCONN_TCP) {
- p = ((struct netbuf *)p)->p;
- }
- buflen = p->tot_len;
- buflen -= sock->lastoffset;
-
- *((u16_t*)argp) += buflen;
- }
-
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
- sock_set_errno(sock, 0);
- return 0;
-#endif /* LWIP_SO_RCVBUF */
-
- case FIONBIO:
- val = 0;
- if (argp && *(u32_t*)argp) {
- val = 1;
- }
- netconn_set_nonblocking(sock->conn, val);
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
- sock_set_errno(sock, 0);
- return 0;
-
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
- sock_set_errno(sock, ENOSYS); /* not yet implemented */
- return -1;
- } /* switch (cmd) */
-}
-
-/** A minimal implementation of fcntl.
- * Currently only the commands F_GETFL and F_SETFL are implemented.
- * Only the flag O_NONBLOCK is implemented.
- */
-int
-lwip_fcntl(int s, int cmd, int val)
-{
- struct lwip_sock *sock = get_socket(s);
- int ret = -1;
-
- if (!sock || !sock->conn) {
- return -1;
- }
-
- switch (cmd) {
- case F_GETFL:
- ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
- break;
- case F_SETFL:
- if ((val & ~O_NONBLOCK) == 0) {
- /* only O_NONBLOCK, all other bits are zero */
- netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
- ret = 0;
- }
- break;
- default:
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
- break;
- }
- return ret;
-}
-
-#endif /* LWIP_SOCKET */
+++ /dev/null
-/**
- * @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 */
+++ /dev/null
-/**
- * @file
- * Common functions used throughout the stack.
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Simon Goldschmidt
- *
- */
-
-#include "lwip/opt.h"
-#include "lwip/def.h"
-
-/**
- * These are reference implementations of the byte swapping functions.
- * Again with the aim of being simple, correct and fully portable.
- * Byte swapping is the second thing you would want to optimize. You will
- * need to port it to your architecture and in your cc.h:
- *
- * #define LWIP_PLATFORM_BYTESWAP 1
- * #define LWIP_PLATFORM_HTONS(x) <your_htons>
- * #define LWIP_PLATFORM_HTONL(x) <your_htonl>
- *
- * Note ntohs() and ntohl() are merely references to the htonx counterparts.
- */
-
-#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
-
-/**
- * Convert an u16_t from host- to network byte order.
- *
- * @param n u16_t in host byte order
- * @return n in network byte order
- */
-u16_t
-lwip_htons(u16_t n)
-{
- return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
-}
-
-/**
- * Convert an u16_t from network- to host byte order.
- *
- * @param n u16_t in network byte order
- * @return n in host byte order
- */
-u16_t
-lwip_ntohs(u16_t n)
-{
- return lwip_htons(n);
-}
-
-/**
- * Convert an u32_t from host- to network byte order.
- *
- * @param n u32_t in host byte order
- * @return n in network byte order
- */
-u32_t
-lwip_htonl(u32_t n)
-{
- return ((n & 0xff) << 24) |
- ((n & 0xff00) << 8) |
- ((n & 0xff0000UL) >> 8) |
- ((n & 0xff000000UL) >> 24);
-}
-
-/**
- * Convert an u32_t from network- to host byte order.
- *
- * @param n u32_t in network byte order
- * @return n in host byte order
- */
-u32_t
-lwip_ntohl(u32_t n)
-{
- return lwip_htonl(n);
-}
-
-#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */
+++ /dev/null
-/**
- * @file
- * Dynamic Host Configuration Protocol client
- *
- */
-
-/*
- *
- * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>
- * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is a contribution to the lwIP TCP/IP stack.
- * The Swedish Institute of Computer Science and Adam Dunkels
- * are specifically granted permission to redistribute this
- * source code.
- *
- * Author: Leon Woestenberg <leon.woestenberg@gmx.net>
- *
- * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform
- * with RFC 2131 and RFC 2132.
- *
- * TODO:
- * - Support for interfaces other than Ethernet (SLIP, PPP, ...)
- *
- * Please coordinate changes and requests with Leon Woestenberg
- * <leon.woestenberg@gmx.net>
- *
- * Integration with your code:
- *
- * In lwip/dhcp.h
- * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)
- * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)
- *
- * Then have your application call dhcp_coarse_tmr() and
- * dhcp_fine_tmr() on the defined intervals.
- *
- * dhcp_start(struct netif *netif);
- * starts a DHCP client instance which configures the interface by
- * obtaining an IP address lease and maintaining it.
- *
- * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)
- * to remove the DHCP client.
- *
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/stats.h"
-#include "lwip/mem.h"
-#include "lwip/udp.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/def.h"
-#include "lwip/sys.h"
-#include "lwip/dhcp.h"
-#include "lwip/autoip.h"
-#include "lwip/dns.h"
-#include "netif/etharp.h"
-
-#include <string.h>
-
-/** Default for DHCP_GLOBAL_XID is 0xABCD0000
- * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g.
- * #define DHCP_GLOBAL_XID_HEADER "stdlib.h"
- * #define DHCP_GLOBAL_XID rand()
- */
-#ifdef DHCP_GLOBAL_XID_HEADER
-#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */
-#endif
-
-/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU
- * MTU is checked to be big enough in dhcp_start */
-#define DHCP_MAX_MSG_LEN(netif) (netif->mtu)
-#define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576
-/** Minimum length for reply before packet is parsed */
-#define DHCP_MIN_REPLY_LEN 44
-
-#define REBOOT_TRIES 2
-
-/** Option handling: options are parsed in dhcp_parse_reply
- * and saved in an array where other functions can load them from.
- * This might be moved into the struct dhcp (not necessarily since
- * lwIP is single-threaded and the array is only used while in recv
- * callback). */
-#define DHCP_OPTION_IDX_OVERLOAD 0
-#define DHCP_OPTION_IDX_MSG_TYPE 1
-#define DHCP_OPTION_IDX_SERVER_ID 2
-#define DHCP_OPTION_IDX_LEASE_TIME 3
-#define DHCP_OPTION_IDX_T1 4
-#define DHCP_OPTION_IDX_T2 5
-#define DHCP_OPTION_IDX_SUBNET_MASK 6
-#define DHCP_OPTION_IDX_ROUTER 7
-#define DHCP_OPTION_IDX_DNS_SERVER 8
-#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)
-
-/** Holds the decoded option values, only valid while in dhcp_recv.
- @todo: move this into struct dhcp? */
-u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX];
-/** Holds a flag which option was received and is contained in dhcp_rx_options_val,
- only valid while in dhcp_recv.
- @todo: move this into struct dhcp? */
-u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX];
-
-#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0)
-#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1)
-#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0)
-#define dhcp_clear_all_options(dhcp) (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given)))
-#define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx])
-#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val))
-
-
-/* DHCP client state machine functions */
-static err_t dhcp_discover(struct netif *netif);
-static err_t dhcp_select(struct netif *netif);
-static void dhcp_bind(struct netif *netif);
-#if DHCP_DOES_ARP_CHECK
-static err_t dhcp_decline(struct netif *netif);
-#endif /* DHCP_DOES_ARP_CHECK */
-static err_t dhcp_rebind(struct netif *netif);
-static err_t dhcp_reboot(struct netif *netif);
-static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);
-
-/* receive, unfold, parse and free incoming messages */
-static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
-
-/* set the DHCP timers */
-static void dhcp_timeout(struct netif *netif);
-static void dhcp_t1_timeout(struct netif *netif);
-static void dhcp_t2_timeout(struct netif *netif);
-
-/* build outgoing messages */
-/* create a DHCP message, fill in common headers */
-static err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type);
-/* free a DHCP request */
-static void dhcp_delete_msg(struct dhcp *dhcp);
-/* add a DHCP option (type, then length in bytes) */
-static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);
-/* add option values */
-static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);
-static void dhcp_option_short(struct dhcp *dhcp, u16_t value);
-static void dhcp_option_long(struct dhcp *dhcp, u32_t value);
-/* always add the DHCP options trailer to end and pad */
-static void dhcp_option_trailer(struct dhcp *dhcp);
-
-/**
- * Back-off the DHCP client (because of a received NAK response).
- *
- * Back-off the DHCP client because of a received NAK. Receiving a
- * NAK means the client asked for something non-sensible, for
- * example when it tries to renew a lease obtained on another network.
- *
- * We clear any existing set IP address and restart DHCP negotiation
- * afresh (as per RFC2131 3.2.3).
- *
- * @param netif the netif under DHCP control
- */
-static void
-dhcp_handle_nak(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n",
- (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
- /* Set the interface down since the address must no longer be used, as per RFC2131 */
- netif_set_down(netif);
- /* remove IP address from interface */
- netif_set_ipaddr(netif, IP_ADDR_ANY);
- netif_set_gw(netif, IP_ADDR_ANY);
- netif_set_netmask(netif, IP_ADDR_ANY);
- /* Change to a defined state */
- dhcp_set_state(dhcp, DHCP_BACKING_OFF);
- /* We can immediately restart discovery */
- dhcp_discover(netif);
-}
-
-#if DHCP_DOES_ARP_CHECK
-/**
- * Checks if the offered IP address is already in use.
- *
- * It does so by sending an ARP request for the offered address and
- * entering CHECKING state. If no ARP reply is received within a small
- * interval, the address is assumed to be free for use by us.
- *
- * @param netif the netif under DHCP control
- */
-static void
-dhcp_check(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- err_t result;
- u16_t msecs;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
- (s16_t)netif->name[1]));
- dhcp_set_state(dhcp, DHCP_CHECKING);
- /* create an ARP query for the offered IP address, expecting that no host
- responds, as the IP address should not be in use. */
- result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);
- if (result != ERR_OK) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n"));
- }
- dhcp->tries++;
- msecs = 500;
- dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));
-}
-#endif /* DHCP_DOES_ARP_CHECK */
-
-/**
- * Remember the configuration offered by a DHCP server.
- *
- * @param netif the netif under DHCP control
- */
-static void
-dhcp_handle_offer(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",
- (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
- /* obtain the server address */
- if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) {
- ip4_addr_set_u32(&dhcp->server_ip_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID)));
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n",
- ip4_addr_get_u32(&dhcp->server_ip_addr)));
- /* remember offered address */
- ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n",
- ip4_addr_get_u32(&dhcp->offered_ip_addr)));
-
- dhcp_select(netif);
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
- ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void*)netif));
- }
-}
-
-/**
- * Select a DHCP server offer out of all offers.
- *
- * Simply select the first offer received.
- *
- * @param netif the netif under DHCP control
- * @return lwIP specific error (see error.h)
- */
-static err_t
-dhcp_select(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- err_t result;
- u16_t msecs;
-
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
- dhcp_set_state(dhcp, DHCP_REQUESTING);
-
- /* create and initialize the DHCP message header */
- result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
- if (result == ERR_OK) {
- dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
- dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
-
- /* MUST request the offered IP address */
- dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
- dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
-
- dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
- dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->server_ip_addr)));
-
- dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
- dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
- dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
- dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
- dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
-
-#if LWIP_NETIF_HOSTNAME
- if (netif->hostname != NULL) {
- const char *p = (const char*)netif->hostname;
- u8_t namelen = (u8_t)strlen(p);
- if (namelen > 0) {
- LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
- dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
- while (*p) {
- dhcp_option_byte(dhcp, *p++);
- }
- }
- }
-#endif /* LWIP_NETIF_HOSTNAME */
-
- dhcp_option_trailer(dhcp);
- /* shrink the pbuf to the actual content length */
- pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
- /* send broadcast to any DHCP server */
- udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
- dhcp_delete_msg(dhcp);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n"));
- }
- dhcp->tries++;
- msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;
- dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs));
- return result;
-}
-
-/**
- * The DHCP timer that checks for lease renewal/rebind timeouts.
- */
-void
-dhcp_coarse_tmr()
-{
- struct netif *netif = netif_list;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n"));
- /* iterate through all network interfaces */
- while (netif != NULL) {
- /* only act on DHCP configured interfaces */
- if (netif->dhcp != NULL) {
- /* timer is active (non zero), and triggers (zeroes) now? */
- if (netif->dhcp->t2_timeout-- == 1) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));
- /* this clients' rebind timeout triggered */
- dhcp_t2_timeout(netif);
- /* timer is active (non zero), and triggers (zeroes) now */
- } else if (netif->dhcp->t1_timeout-- == 1) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));
- /* this clients' renewal timeout triggered */
- dhcp_t1_timeout(netif);
- }
- }
- /* proceed to next netif */
- netif = netif->next;
- }
-}
-
-/**
- * DHCP transaction timeout handling
- *
- * A DHCP server is expected to respond within a short period of time.
- * This timer checks whether an outstanding DHCP request is timed out.
- */
-void
-dhcp_fine_tmr()
-{
- struct netif *netif = netif_list;
- /* loop through netif's */
- while (netif != NULL) {
- /* only act on DHCP configured interfaces */
- if (netif->dhcp != NULL) {
- /* timer is active (non zero), and is about to trigger now */
- if (netif->dhcp->request_timeout > 1) {
- netif->dhcp->request_timeout--;
- }
- else if (netif->dhcp->request_timeout == 1) {
- netif->dhcp->request_timeout--;
- /* { netif->dhcp->request_timeout == 0 } */
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
- /* this client's request timeout triggered */
- dhcp_timeout(netif);
- }
- }
- /* proceed to next network interface */
- netif = netif->next;
- }
-}
-
-/**
- * A DHCP negotiation transaction, or ARP request, has timed out.
- *
- * The timer that was started with the DHCP or ARP request has
- * timed out, indicating no response was received in time.
- *
- * @param netif the netif under DHCP control
- */
-static void
-dhcp_timeout(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n"));
- /* back-off period has passed, or server selection timed out */
- if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
- dhcp_discover(netif);
- /* receiving the requested lease timed out */
- } else if (dhcp->state == DHCP_REQUESTING) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));
- if (dhcp->tries <= 5) {
- dhcp_select(netif);
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));
- dhcp_release(netif);
- dhcp_discover(netif);
- }
-#if DHCP_DOES_ARP_CHECK
- /* received no ARP reply for the offered address (which is good) */
- } else if (dhcp->state == DHCP_CHECKING) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));
- if (dhcp->tries <= 1) {
- dhcp_check(netif);
- /* no ARP replies on the offered address,
- looks like the IP address is indeed free */
- } else {
- /* bind the interface to the offered address */
- dhcp_bind(netif);
- }
-#endif /* DHCP_DOES_ARP_CHECK */
- }
- /* did not get response to renew request? */
- else if (dhcp->state == DHCP_RENEWING) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));
- /* just retry renewal */
- /* note that the rebind timer will eventually time-out if renew does not work */
- dhcp_renew(netif);
- /* did not get response to rebind request? */
- } else if (dhcp->state == DHCP_REBINDING) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));
- if (dhcp->tries <= 8) {
- dhcp_rebind(netif);
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));
- dhcp_release(netif);
- dhcp_discover(netif);
- }
- } else if (dhcp->state == DHCP_REBOOTING) {
- if (dhcp->tries < REBOOT_TRIES) {
- dhcp_reboot(netif);
- } else {
- dhcp_discover(netif);
- }
- }
-}
-
-/**
- * The renewal period has timed out.
- *
- * @param netif the netif under DHCP control
- */
-static void
-dhcp_t1_timeout(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n"));
- if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) ||
- (dhcp->state == DHCP_RENEWING)) {
- /* just retry to renew - note that the rebind timer (t2) will
- * eventually time-out if renew tries fail. */
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("dhcp_t1_timeout(): must renew\n"));
- /* This slightly different to RFC2131: DHCPREQUEST will be sent from state
- DHCP_RENEWING, not DHCP_BOUND */
- dhcp_renew(netif);
- }
-}
-
-/**
- * The rebind period has timed out.
- *
- * @param netif the netif under DHCP control
- */
-static void
-dhcp_t2_timeout(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n"));
- if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) ||
- (dhcp->state == DHCP_RENEWING)) {
- /* just retry to rebind */
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("dhcp_t2_timeout(): must rebind\n"));
- /* This slightly different to RFC2131: DHCPREQUEST will be sent from state
- DHCP_REBINDING, not DHCP_BOUND */
- dhcp_rebind(netif);
- }
-}
-
-/**
- * Handle a DHCP ACK packet
- *
- * @param netif the netif under DHCP control
- */
-static void
-dhcp_handle_ack(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
-#if LWIP_DNS
- u8_t n;
-#endif /* LWIP_DNS */
-
- /* clear options we might not get from the ACK */
- ip_addr_set_zero(&dhcp->offered_sn_mask);
- ip_addr_set_zero(&dhcp->offered_gw_addr);
-#if LWIP_DHCP_BOOTP_FILE
- ip_addr_set_zero(&dhcp->offered_si_addr);
-#endif /* LWIP_DHCP_BOOTP_FILE */
-
- /* lease time given? */
- if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) {
- /* remember offered lease time */
- dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME);
- }
- /* renewal period given? */
- if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) {
- /* remember given renewal period */
- dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1);
- } else {
- /* calculate safe periods for renewal */
- dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;
- }
-
- /* renewal period given? */
- if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) {
- /* remember given rebind period */
- dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2);
- } else {
- /* calculate safe periods for rebinding */
- dhcp->offered_t2_rebind = dhcp->offered_t0_lease;
- }
-
- /* (y)our internet address */
- ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr);
-
-#if LWIP_DHCP_BOOTP_FILE
- /* copy boot server address,
- boot file name copied in dhcp_parse_reply if not overloaded */
- ip_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr);
-#endif /* LWIP_DHCP_BOOTP_FILE */
-
- /* subnet mask given? */
- if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) {
- /* remember given subnet mask */
- ip4_addr_set_u32(&dhcp->offered_sn_mask, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)));
- dhcp->subnet_mask_given = 1;
- } else {
- dhcp->subnet_mask_given = 0;
- }
-
- /* gateway router */
- if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) {
- ip4_addr_set_u32(&dhcp->offered_gw_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER)));
- }
-
-#if LWIP_DNS
- /* DNS servers */
- n = 0;
- while(dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n) && (n < DNS_MAX_SERVERS)) {
- ip_addr_t dns_addr;
- ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
- dns_setserver(n, &dns_addr);
- n++;
- }
-#endif /* LWIP_DNS */
-}
-
-/** Set a statically allocated struct dhcp to work with.
- * Using this prevents dhcp_start to allocate it using mem_malloc.
- *
- * @param netif the netif for which to set the struct dhcp
- * @param dhcp (uninitialised) dhcp struct allocated by the application
- */
-void
-dhcp_set_struct(struct netif *netif, struct dhcp *dhcp)
-{
- LWIP_ASSERT("netif != NULL", netif != NULL);
- LWIP_ASSERT("dhcp != NULL", dhcp != NULL);
- LWIP_ASSERT("netif already has a struct dhcp set", netif->dhcp == NULL);
-
- /* clear data structure */
- memset(dhcp, 0, sizeof(struct dhcp));
- /* dhcp_set_state(&dhcp, DHCP_OFF); */
- netif->dhcp = dhcp;
-}
-
-/** Removes a struct dhcp from a netif.
- *
- * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the
- * struct dhcp since the memory is passed back to the heap.
- *
- * @param netif the netif from which to remove the struct dhcp
- */
-void dhcp_cleanup(struct netif *netif)
-{
- LWIP_ASSERT("netif != NULL", netif != NULL);
-
- if (netif->dhcp != NULL) {
- mem_free(netif->dhcp);
- netif->dhcp = NULL;
- }
-}
-
-/**
- * Start DHCP negotiation for a network interface.
- *
- * If no DHCP client instance was attached to this interface,
- * a new client is created first. If a DHCP client instance
- * was already present, it restarts negotiation.
- *
- * @param netif The lwIP network interface
- * @return lwIP error code
- * - ERR_OK - No error
- * - ERR_MEM - Out of memory
- */
-err_t
-dhcp_start(struct netif *netif)
-{
- struct dhcp *dhcp;
- err_t result = ERR_OK;
-
- LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
- dhcp = netif->dhcp;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
- /* Remove the flag that says this netif is handled by DHCP,
- it is set when we succeeded starting. */
- netif->flags &= ~NETIF_FLAG_DHCP;
-
- /* check hwtype of the netif */
- if ((netif->flags & NETIF_FLAG_ETHARP) == 0) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): No ETHARP netif\n"));
- return ERR_ARG;
- }
-
- /* check MTU of the netif */
- if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n"));
- return ERR_MEM;
- }
-
- /* no DHCP client attached yet? */
- if (dhcp == NULL) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
- dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp));
- if (dhcp == NULL) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
- return ERR_MEM;
- }
- /* store this dhcp client in the netif */
- netif->dhcp = dhcp;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
- /* already has DHCP client attached */
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n"));
- if (dhcp->pcb != NULL) {
- udp_remove(dhcp->pcb);
- }
- LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL);
- LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL );
- }
-
- /* clear data structure */
- memset(dhcp, 0, sizeof(struct dhcp));
- /* dhcp_set_state(&dhcp, DHCP_OFF); */
- /* allocate UDP PCB */
- dhcp->pcb = udp_new();
- if (dhcp->pcb == NULL) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
- return ERR_MEM;
- }
- dhcp->pcb->so_options |= SOF_BROADCAST;
- /* set up local and remote port for the pcb */
- udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
- udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
- /* set up the recv callback and argument */
- udp_recv(dhcp->pcb, dhcp_recv, netif);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
- /* (re)start the DHCP negotiation */
- result = dhcp_discover(netif);
- if (result != ERR_OK) {
- /* free resources allocated above */
- dhcp_stop(netif);
- return ERR_MEM;
- }
- /* Set the flag that says this netif is handled by DHCP. */
- netif->flags |= NETIF_FLAG_DHCP;
- return result;
-}
-
-/**
- * Inform a DHCP server of our manual configuration.
- *
- * This informs DHCP servers of our fixed IP address configuration
- * by sending an INFORM message. It does not involve DHCP address
- * configuration, it is just here to be nice to the network.
- *
- * @param netif The lwIP network interface
- */
-void
-dhcp_inform(struct netif *netif)
-{
- struct dhcp dhcp;
- err_t result = ERR_OK;
- struct udp_pcb *pcb;
-
- LWIP_ERROR("netif != NULL", (netif != NULL), return;);
-
- memset(&dhcp, 0, sizeof(struct dhcp));
- dhcp_set_state(&dhcp, DHCP_INFORM);
-
- if ((netif->dhcp != NULL) && (netif->dhcp->pcb != NULL)) {
- /* re-use existing pcb */
- pcb = netif->dhcp->pcb;
- } else {
- pcb = udp_new();
- if (pcb == NULL) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb"));
- return;
- }
- dhcp.pcb = pcb;
- dhcp.pcb->so_options |= SOF_BROADCAST;
- udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
- }
- /* create and initialize the DHCP message header */
- result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM);
- if (result == ERR_OK) {
- dhcp_option(&dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
- dhcp_option_short(&dhcp, DHCP_MAX_MSG_LEN(netif));
-
- dhcp_option_trailer(&dhcp);
-
- pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len);
-
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n"));
- udp_sendto_if(pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
- dhcp_delete_msg(&dhcp);
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n"));
- }
-
- if (dhcp.pcb != NULL) {
- /* otherwise, the existing pcb was used */
- udp_remove(dhcp.pcb);
- }
-}
-
-/** Handle a possible change in the network configuration.
- *
- * This enters the REBOOTING state to verify that the currently bound
- * address is still valid.
- */
-void
-dhcp_network_changed(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- if (!dhcp)
- return;
- switch (dhcp->state) {
- case DHCP_REBINDING:
- case DHCP_RENEWING:
- case DHCP_BOUND:
- case DHCP_REBOOTING:
- netif_set_down(netif);
- dhcp->tries = 0;
- dhcp_reboot(netif);
- break;
- case DHCP_OFF:
- /* stay off */
- break;
- default:
- dhcp->tries = 0;
-#if LWIP_DHCP_AUTOIP_COOP
- if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
- autoip_stop(netif);
- dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
- }
-#endif /* LWIP_DHCP_AUTOIP_COOP */
- dhcp_discover(netif);
- break;
- }
-}
-
-#if DHCP_DOES_ARP_CHECK
-/**
- * Match an ARP reply with the offered IP address.
- *
- * @param netif the network interface on which the reply was received
- * @param addr The IP address we received a reply from
- */
-void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr)
-{
- LWIP_ERROR("netif != NULL", (netif != NULL), return;);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n"));
- /* is a DHCP client doing an ARP check? */
- if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n",
- ip4_addr_get_u32(addr)));
- /* did a host respond with the address we
- were offered by the DHCP server? */
- if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {
- /* we will not accept the offered address */
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
- ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
- dhcp_decline(netif);
- }
- }
-}
-
-/**
- * Decline an offered lease.
- *
- * Tell the DHCP server we do not accept the offered address.
- * One reason to decline the lease is when we find out the address
- * is already in use by another host (through ARP).
- *
- * @param netif the netif under DHCP control
- */
-static err_t
-dhcp_decline(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- err_t result = ERR_OK;
- u16_t msecs;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n"));
- dhcp_set_state(dhcp, DHCP_BACKING_OFF);
- /* create and initialize the DHCP message header */
- result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE);
- if (result == ERR_OK) {
- dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
- dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
-
- dhcp_option_trailer(dhcp);
- /* resize pbuf to reflect true size of options */
- pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
- /* per section 4.4.4, broadcast DECLINE messages */
- udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
- dhcp_delete_msg(dhcp);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
- ("dhcp_decline: could not allocate DHCP request\n"));
- }
- dhcp->tries++;
- msecs = 10*1000;
- dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));
- return result;
-}
-#endif /* DHCP_DOES_ARP_CHECK */
-
-
-/**
- * Start the DHCP process, discover a DHCP server.
- *
- * @param netif the netif under DHCP control
- */
-static err_t
-dhcp_discover(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- err_t result = ERR_OK;
- u16_t msecs;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n"));
- ip_addr_set_any(&dhcp->offered_ip_addr);
- dhcp_set_state(dhcp, DHCP_SELECTING);
- /* create and initialize the DHCP message header */
- result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER);
- if (result == ERR_OK) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n"));
-
- dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
- dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
-
- dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
- dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
- dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
- dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
- dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
-
- dhcp_option_trailer(dhcp);
-
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n"));
- pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));
- udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
- dhcp_delete_msg(dhcp);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n"));
- }
- dhcp->tries++;
-#if LWIP_DHCP_AUTOIP_COOP
- if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) {
- dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON;
- autoip_start(netif);
- }
-#endif /* LWIP_DHCP_AUTOIP_COOP */
- msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;
- dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));
- return result;
-}
-
-
-/**
- * Bind the interface to the offered IP address.
- *
- * @param netif network interface to bind to the offered address
- */
-static void
-dhcp_bind(struct netif *netif)
-{
- u32_t timeout;
- struct dhcp *dhcp;
- ip_addr_t sn_mask, gw_addr;
- LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);
- dhcp = netif->dhcp;
- LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
-
- /* temporary DHCP lease? */
- if (dhcp->offered_t1_renew != 0xffffffffUL) {
- /* set renewal period timer */
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));
- timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
- if(timeout > 0xffff) {
- timeout = 0xffff;
- }
- dhcp->t1_timeout = (u16_t)timeout;
- if (dhcp->t1_timeout == 0) {
- dhcp->t1_timeout = 1;
- }
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));
- }
- /* set renewal period timer */
- if (dhcp->offered_t2_rebind != 0xffffffffUL) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));
- timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
- if(timeout > 0xffff) {
- timeout = 0xffff;
- }
- dhcp->t2_timeout = (u16_t)timeout;
- if (dhcp->t2_timeout == 0) {
- dhcp->t2_timeout = 1;
- }
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));
- }
-
- if (dhcp->subnet_mask_given) {
- /* copy offered network mask */
- ip_addr_copy(sn_mask, dhcp->offered_sn_mask);
- } else {
- /* subnet mask not given, choose a safe subnet mask given the network class */
- u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr);
- if (first_octet <= 127) {
- ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL));
- } else if (first_octet >= 192) {
- ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL));
- } else {
- ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL));
- }
- }
-
- ip_addr_copy(gw_addr, dhcp->offered_gw_addr);
- /* gateway address not given? */
- if (ip_addr_isany(&gw_addr)) {
- /* copy network address */
- ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask);
- /* use first host address on network as gateway */
- ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001UL));
- }
-
-#if LWIP_DHCP_AUTOIP_COOP
- if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
- autoip_stop(netif);
- dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
- }
-#endif /* LWIP_DHCP_AUTOIP_COOP */
-
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n",
- ip4_addr_get_u32(&dhcp->offered_ip_addr)));
- netif_set_ipaddr(netif, &dhcp->offered_ip_addr);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n",
- ip4_addr_get_u32(&sn_mask)));
- netif_set_netmask(netif, &sn_mask);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n",
- ip4_addr_get_u32(&gw_addr)));
- netif_set_gw(netif, &gw_addr);
- /* bring the interface up */
- netif_set_up(netif);
- /* netif is now bound to DHCP leased address */
- dhcp_set_state(dhcp, DHCP_BOUND);
-}
-
-/**
- * Renew an existing DHCP lease at the involved DHCP server.
- *
- * @param netif network interface which must renew its lease
- */
-err_t
-dhcp_renew(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- err_t result;
- u16_t msecs;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n"));
- dhcp_set_state(dhcp, DHCP_RENEWING);
-
- /* create and initialize the DHCP message header */
- result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
- if (result == ERR_OK) {
- dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
- dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
-
-#if LWIP_NETIF_HOSTNAME
- if (netif->hostname != NULL) {
- const char *p = (const char*)netif->hostname;
- u8_t namelen = (u8_t)strlen(p);
- if (namelen > 0) {
- LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
- dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
- while (*p) {
- dhcp_option_byte(dhcp, *p++);
- }
- }
- }
-#endif /* LWIP_NETIF_HOSTNAME */
-
-#if 0
- dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
- dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
-#endif
-
-#if 0
- dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
- dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
-#endif
- /* append DHCP message trailer */
- dhcp_option_trailer(dhcp);
-
- pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
- udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
- dhcp_delete_msg(dhcp);
-
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n"));
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n"));
- }
- dhcp->tries++;
- /* back-off on retries, but to a maximum of 20 seconds */
- msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;
- dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));
- return result;
-}
-
-/**
- * Rebind with a DHCP server for an existing DHCP lease.
- *
- * @param netif network interface which must rebind with a DHCP server
- */
-static err_t
-dhcp_rebind(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- err_t result;
- u16_t msecs;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n"));
- dhcp_set_state(dhcp, DHCP_REBINDING);
-
- /* create and initialize the DHCP message header */
- result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
- if (result == ERR_OK) {
- dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
- dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
-
-#if LWIP_NETIF_HOSTNAME
- if (netif->hostname != NULL) {
- const char *p = (const char*)netif->hostname;
- u8_t namelen = (u8_t)strlen(p);
- if (namelen > 0) {
- LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
- dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
- while (*p) {
- dhcp_option_byte(dhcp, *p++);
- }
- }
- }
-#endif /* LWIP_NETIF_HOSTNAME */
-
-#if 0
- dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
- dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
-
- dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
- dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
-#endif
-
- dhcp_option_trailer(dhcp);
-
- pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
- /* broadcast to server */
- udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
- dhcp_delete_msg(dhcp);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n"));
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n"));
- }
- dhcp->tries++;
- msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
- dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));
- return result;
-}
-
-/**
- * Enter REBOOTING state to verify an existing lease
- *
- * @param netif network interface which must reboot
- */
-static err_t
-dhcp_reboot(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- err_t result;
- u16_t msecs;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n"));
- dhcp_set_state(dhcp, DHCP_REBOOTING);
-
- /* create and initialize the DHCP message header */
- result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
- if (result == ERR_OK) {
- dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
- dhcp_option_short(dhcp, 576);
-
- dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
- dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
-
- dhcp_option_trailer(dhcp);
-
- pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
- /* broadcast to server */
- udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
- dhcp_delete_msg(dhcp);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n"));
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n"));
- }
- dhcp->tries++;
- msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
- dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs));
- return result;
-}
-
-
-/**
- * Release a DHCP lease.
- *
- * @param netif network interface which must release its lease
- */
-err_t
-dhcp_release(struct netif *netif)
-{
- struct dhcp *dhcp = netif->dhcp;
- err_t result;
- u16_t msecs;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n"));
-
- /* idle DHCP client */
- dhcp_set_state(dhcp, DHCP_OFF);
- /* clean old DHCP offer */
- ip_addr_set_zero(&dhcp->server_ip_addr);
- ip_addr_set_zero(&dhcp->offered_ip_addr);
- ip_addr_set_zero(&dhcp->offered_sn_mask);
- ip_addr_set_zero(&dhcp->offered_gw_addr);
-#if LWIP_DHCP_BOOTP_FILE
- ip_addr_set_zero(&dhcp->offered_si_addr);
-#endif /* LWIP_DHCP_BOOTP_FILE */
- dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;
-
- /* create and initialize the DHCP message header */
- result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE);
- if (result == ERR_OK) {
- dhcp_option_trailer(dhcp);
-
- pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
-
- udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
- dhcp_delete_msg(dhcp);
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n"));
- }
- dhcp->tries++;
- msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
- dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs));
- /* bring the interface down */
- netif_set_down(netif);
- /* remove IP address from interface */
- netif_set_ipaddr(netif, IP_ADDR_ANY);
- netif_set_gw(netif, IP_ADDR_ANY);
- netif_set_netmask(netif, IP_ADDR_ANY);
-
- return result;
-}
-
-/**
- * Remove the DHCP client from the interface.
- *
- * @param netif The network interface to stop DHCP on
- */
-void
-dhcp_stop(struct netif *netif)
-{
- struct dhcp *dhcp;
- LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;);
- dhcp = netif->dhcp;
- /* Remove the flag that says this netif is handled by DHCP. */
- netif->flags &= ~NETIF_FLAG_DHCP;
-
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n"));
- /* netif is DHCP configured? */
- if (dhcp != NULL) {
-#if LWIP_DHCP_AUTOIP_COOP
- if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
- autoip_stop(netif);
- dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
- }
-#endif /* LWIP_DHCP_AUTOIP_COOP */
-
- if (dhcp->pcb != NULL) {
- udp_remove(dhcp->pcb);
- dhcp->pcb = NULL;
- }
- LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL);
- dhcp_set_state(dhcp, DHCP_OFF);
- }
-}
-
-/*
- * Set the DHCP state of a DHCP client.
- *
- * If the state changed, reset the number of tries.
- */
-static void
-dhcp_set_state(struct dhcp *dhcp, u8_t new_state)
-{
- if (new_state != dhcp->state) {
- dhcp->state = new_state;
- dhcp->tries = 0;
- dhcp->request_timeout = 0;
- }
-}
-
-/*
- * Concatenate an option type and length field to the outgoing
- * DHCP message.
- *
- */
-static void
-dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)
-{
- LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN);
- dhcp->msg_out->options[dhcp->options_out_len++] = option_type;
- dhcp->msg_out->options[dhcp->options_out_len++] = option_len;
-}
-/*
- * Concatenate a single byte to the outgoing DHCP message.
- *
- */
-static void
-dhcp_option_byte(struct dhcp *dhcp, u8_t value)
-{
- LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);
- dhcp->msg_out->options[dhcp->options_out_len++] = value;
-}
-
-static void
-dhcp_option_short(struct dhcp *dhcp, u16_t value)
-{
- LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN);
- dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8);
- dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU);
-}
-
-static void
-dhcp_option_long(struct dhcp *dhcp, u32_t value)
-{
- LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN);
- dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24);
- dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16);
- dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8);
- dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL));
-}
-
-/**
- * Extract the DHCP message and the DHCP options.
- *
- * Extract the DHCP message and the DHCP options, each into a contiguous
- * piece of memory. As a DHCP message is variable sized by its options,
- * and also allows overriding some fields for options, the easy approach
- * is to first unfold the options into a conitguous piece of memory, and
- * use that further on.
- *
- */
-static err_t
-dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p)
-{
- u8_t *options;
- u16_t offset;
- u16_t offset_max;
- u16_t options_idx;
- u16_t options_idx_max;
- struct pbuf *q;
- int parse_file_as_options = 0;
- int parse_sname_as_options = 0;
-
- /* clear received options */
- dhcp_clear_all_options(dhcp);
- /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */
- if (p->len < DHCP_SNAME_OFS) {
- return ERR_BUF;
- }
- dhcp->msg_in = (struct dhcp_msg *)p->payload;
-#if LWIP_DHCP_BOOTP_FILE
- /* clear boot file name */
- dhcp->boot_file_name[0] = 0;
-#endif /* LWIP_DHCP_BOOTP_FILE */
-
- /* parse options */
-
- /* start with options field */
- options_idx = DHCP_OPTIONS_OFS;
- /* parse options to the end of the received packet */
- options_idx_max = p->tot_len;
-again:
- q = p;
- while((q != NULL) && (options_idx >= q->len)) {
- options_idx -= q->len;
- options_idx_max -= q->len;
- q = q->next;
- }
- if (q == NULL) {
- return ERR_BUF;
- }
- offset = options_idx;
- offset_max = options_idx_max;
- options = (u8_t*)q->payload;
- /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
- while((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) {
- u8_t op = options[offset];
- u8_t len;
- u8_t decode_len = 0;
- int decode_idx = -1;
- u16_t val_offset = offset + 2;
- /* len byte might be in the next pbuf */
- if (offset + 1 < q->len) {
- len = options[offset + 1];
- } else {
- len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0);
- }
- /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */
- decode_len = len;
- switch(op) {
- /* case(DHCP_OPTION_END): handled above */
- case(DHCP_OPTION_PAD):
- /* special option: no len encoded */
- decode_len = len = 0;
- /* will be increased below */
- offset--;
- break;
- case(DHCP_OPTION_SUBNET_MASK):
- LWIP_ASSERT("len == 4", len == 4);
- decode_idx = DHCP_OPTION_IDX_SUBNET_MASK;
- break;
- case(DHCP_OPTION_ROUTER):
- decode_len = 4; /* only copy the first given router */
- LWIP_ASSERT("len >= decode_len", len >= decode_len);
- decode_idx = DHCP_OPTION_IDX_ROUTER;
- break;
- case(DHCP_OPTION_DNS_SERVER):
- /* special case: there might be more than one server */
- LWIP_ASSERT("len % 4 == 0", len % 4 == 0);
- /* limit number of DNS servers */
- decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);
- LWIP_ASSERT("len >= decode_len", len >= decode_len);
- decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
- break;
- case(DHCP_OPTION_LEASE_TIME):
- LWIP_ASSERT("len == 4", len == 4);
- decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
- break;
- case(DHCP_OPTION_OVERLOAD):
- LWIP_ASSERT("len == 1", len == 1);
- decode_idx = DHCP_OPTION_IDX_OVERLOAD;
- break;
- case(DHCP_OPTION_MESSAGE_TYPE):
- LWIP_ASSERT("len == 1", len == 1);
- decode_idx = DHCP_OPTION_IDX_MSG_TYPE;
- break;
- case(DHCP_OPTION_SERVER_ID):
- LWIP_ASSERT("len == 4", len == 4);
- decode_idx = DHCP_OPTION_IDX_SERVER_ID;
- break;
- case(DHCP_OPTION_T1):
- LWIP_ASSERT("len == 4", len == 4);
- decode_idx = DHCP_OPTION_IDX_T1;
- break;
- case(DHCP_OPTION_T2):
- LWIP_ASSERT("len == 4", len == 4);
- decode_idx = DHCP_OPTION_IDX_T2;
- break;
- default:
- decode_len = 0;
- LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", op));
- break;
- }
- offset += len + 2;
- if (decode_len > 0) {
- u32_t value = 0;
- u16_t copy_len;
-decode_next:
- LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX);
- LWIP_ASSERT("option already decoded", !dhcp_option_given(dhcp, decode_idx));
- copy_len = LWIP_MIN(decode_len, 4);
- pbuf_copy_partial(q, &value, copy_len, val_offset);
- if (decode_len > 4) {
- /* decode more than one u32_t */
- LWIP_ASSERT("decode_len % 4 == 0", decode_len % 4 == 0);
- dhcp_got_option(dhcp, decode_idx);
- dhcp_set_option_value(dhcp, decode_idx, htonl(value));
- decode_len -= 4;
- val_offset += 4;
- decode_idx++;
- goto decode_next;
- } else if (decode_len == 4) {
- value = ntohl(value);
- } else {
- LWIP_ASSERT("invalid decode_len", decode_len == 1);
- value = ((u8_t*)&value)[0];
- }
- dhcp_got_option(dhcp, decode_idx);
- dhcp_set_option_value(dhcp, decode_idx, value);
- }
- if (offset >= q->len) {
- offset -= q->len;
- offset_max -= q->len;
- q = q->next;
- options = (u8_t*)q->payload;
- }
- }
- /* is this an overloaded message? */
- if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) {
- u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD);
- dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD);
- if (overload == DHCP_OVERLOAD_FILE) {
- parse_file_as_options = 1;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n"));
- } else if (overload == DHCP_OVERLOAD_SNAME) {
- parse_sname_as_options = 1;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n"));
- } else if (overload == DHCP_OVERLOAD_SNAME_FILE) {
- parse_sname_as_options = 1;
- parse_file_as_options = 1;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n"));
- } else {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload));
- }
-#if LWIP_DHCP_BOOTP_FILE
- if (!parse_file_as_options) {
- /* only do this for ACK messages */
- if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) &&
- (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK))
- /* copy bootp file name, don't care for sname (server hostname) */
- pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS);
- /* make sure the string is really NULL-terminated */
- dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0;
- }
-#endif /* LWIP_DHCP_BOOTP_FILE */
- }
- if (parse_file_as_options) {
- /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */
- parse_file_as_options = 0;
- options_idx = DHCP_FILE_OFS;
- options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN;
- goto again;
- } else if (parse_sname_as_options) {
- parse_sname_as_options = 0;
- options_idx = DHCP_SNAME_OFS;
- options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN;
- goto again;
- }
- return ERR_OK;
-}
-
-/**
- * If an incoming DHCP message is in response to us, then trigger the state machine
- */
-static void
-dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
-{
- struct netif *netif = (struct netif *)arg;
- struct dhcp *dhcp = netif->dhcp;
- struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
- u8_t msg_type;
- u8_t i;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
- ip4_addr1_16(addr), ip4_addr2_16(addr), ip4_addr3_16(addr), ip4_addr4_16(addr), port));
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
- /* prevent warnings about unused arguments */
- LWIP_UNUSED_ARG(pcb);
- LWIP_UNUSED_ARG(addr);
- LWIP_UNUSED_ARG(port);
-
- LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL);
-
- if (p->len < DHCP_MIN_REPLY_LEN) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n"));
- goto free_pbuf_and_return;
- }
-
- if (reply_msg->op != DHCP_BOOTREPLY) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
- goto free_pbuf_and_return;
- }
- /* iterate through hardware address and match against DHCP message */
- for (i = 0; i < netif->hwaddr_len; i++) {
- if (netif->hwaddr[i] != reply_msg->chaddr[i]) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
- ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
- (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));
- goto free_pbuf_and_return;
- }
- }
- /* match transaction ID against what we expected */
- if (ntohl(reply_msg->xid) != dhcp->xid) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
- ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
- goto free_pbuf_and_return;
- }
- /* option fields could be unfold? */
- if (dhcp_parse_reply(dhcp, p) != ERR_OK) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
- ("problem unfolding DHCP message - too short on memory?\n"));
- goto free_pbuf_and_return;
- }
-
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
- /* obtain pointer to DHCP message type */
- if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
- goto free_pbuf_and_return;
- }
-
- /* read DHCP message type */
- msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE);
- /* message type is DHCP ACK? */
- if (msg_type == DHCP_ACK) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n"));
- /* in requesting state? */
- if (dhcp->state == DHCP_REQUESTING) {
- dhcp_handle_ack(netif);
-#if DHCP_DOES_ARP_CHECK
- /* check if the acknowledged lease address is already in use */
- dhcp_check(netif);
-#else
- /* bind interface to the acknowledged lease address */
- dhcp_bind(netif);
-#endif
- }
- /* already bound to the given lease address? */
- else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {
- dhcp_bind(netif);
- }
- }
- /* received a DHCP_NAK in appropriate state? */
- else if ((msg_type == DHCP_NAK) &&
- ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||
- (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n"));
- dhcp_handle_nak(netif);
- }
- /* received a DHCP_OFFER in DHCP_SELECTING state? */
- else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
- dhcp->request_timeout = 0;
- /* remember offered lease */
- dhcp_handle_offer(netif);
- }
-free_pbuf_and_return:
- dhcp->msg_in = NULL;
- pbuf_free(p);
-}
-
-/**
- * Create a DHCP request, fill in common headers
- *
- * @param netif the netif under DHCP control
- * @param dhcp dhcp control struct
- * @param message_type message type of the request
- */
-static err_t
-dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)
-{
- u16_t i;
-#ifndef DHCP_GLOBAL_XID
- /** default global transaction identifier starting value (easy to match
- * with a packet analyser). We simply increment for each new request.
- * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one
- * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */
- static u32_t xid = 0xABCD0000;
-#else
- static u32_t xid;
- static u8_t xid_initialised = 0;
- if (!xid_initialised) {
- xid = DHCP_GLOBAL_XID;
- xid_initialised = !xid_initialised;
- }
-#endif
- LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return ERR_ARG;);
- LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL;);
- LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL);
- LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL);
- dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
- if (dhcp->p_out == NULL) {
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
- ("dhcp_create_msg(): could not allocate pbuf\n"));
- return ERR_MEM;
- }
- LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg",
- (dhcp->p_out->len >= sizeof(struct dhcp_msg)));
-
- /* reuse transaction identifier in retransmissions */
- if (dhcp->tries == 0) {
- xid++;
- }
- dhcp->xid = xid;
- LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
- ("transaction id xid(%"X32_F")\n", xid));
-
- dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
-
- dhcp->msg_out->op = DHCP_BOOTREQUEST;
- /* TODO: make link layer independent */
- dhcp->msg_out->htype = DHCP_HTYPE_ETH;
- dhcp->msg_out->hlen = netif->hwaddr_len;
- dhcp->msg_out->hops = 0;
- dhcp->msg_out->xid = htonl(dhcp->xid);
- dhcp->msg_out->secs = 0;
- /* we don't need the broadcast flag since we can receive unicast traffic
- before being fully configured! */
- dhcp->msg_out->flags = 0;
- ip_addr_set_zero(&dhcp->msg_out->ciaddr);
- /* set ciaddr to netif->ip_addr based on message_type and state */
- if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) ||
- ((message_type == DHCP_REQUEST) && /* DHCP_BOUND not used for sending! */
- ((dhcp->state==DHCP_RENEWING) || dhcp->state==DHCP_REBINDING))) {
- ip_addr_copy(dhcp->msg_out->ciaddr, netif->ip_addr);
- }
- ip_addr_set_zero(&dhcp->msg_out->yiaddr);
- ip_addr_set_zero(&dhcp->msg_out->siaddr);
- ip_addr_set_zero(&dhcp->msg_out->giaddr);
- for (i = 0; i < DHCP_CHADDR_LEN; i++) {
- /* copy netif hardware address, pad with zeroes */
- dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;
- }
- for (i = 0; i < DHCP_SNAME_LEN; i++) {
- dhcp->msg_out->sname[i] = 0;
- }
- for (i = 0; i < DHCP_FILE_LEN; i++) {
- dhcp->msg_out->file[i] = 0;
- }
- dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
- dhcp->options_out_len = 0;
- /* fill options field with an incrementing array (for debugging purposes) */
- for (i = 0; i < DHCP_OPTIONS_LEN; i++) {
- dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */
- }
- /* Add option MESSAGE_TYPE */
- dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
- dhcp_option_byte(dhcp, message_type);
- return ERR_OK;
-}
-
-/**
- * Free previously allocated memory used to send a DHCP request.
- *
- * @param dhcp the dhcp struct to free the request from
- */
-static void
-dhcp_delete_msg(struct dhcp *dhcp)
-{
- LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return;);
- LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);
- LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL);
- if (dhcp->p_out != NULL) {
- pbuf_free(dhcp->p_out);
- }
- dhcp->p_out = NULL;
- dhcp->msg_out = NULL;
-}
-
-/**
- * Add a DHCP message trailer
- *
- * Adds the END option to the DHCP message, and if
- * necessary, up to three padding bytes.
- *
- * @param dhcp DHCP state structure
- */
-static void
-dhcp_option_trailer(struct dhcp *dhcp)
-{
- LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;);
- LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);
- LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
- dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;
- /* packet is too small, or not 4 byte aligned? */
- while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {
- /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */
- LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
- /* add a fill/padding byte */
- dhcp->msg_out->options[dhcp->options_out_len++] = 0;
- }
-}
-
-#endif /* LWIP_DHCP */
+++ /dev/null
-/**
- * @file
- * DNS - host name to IP address resolver.
- *
- */
-
-/**
-
- * This file implements a DNS host name to IP address resolver.
-
- * Port to lwIP from uIP
- * by Jim Pettinato April 2007
-
- * uIP version Copyright (c) 2002-2003, Adam Dunkels.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * DNS.C
- *
- * The lwIP DNS resolver functions are used to lookup a host name and
- * map it to a numerical IP address. It maintains a list of resolved
- * hostnames that can be queried with the dns_lookup() function.
- * New hostnames can be resolved using the dns_query() function.
- *
- * The lwIP version of the resolver also adds a non-blocking version of
- * gethostbyname() that will work with a raw API application. This function
- * checks for an IP address string first and converts it if it is valid.
- * gethostbyname() then does a dns_lookup() to see if the name is
- * already in the table. If so, the IP is returned. If not, a query is
- * issued and the function returns with a ERR_INPROGRESS status. The app
- * using the dns client must then go into a waiting state.
- *
- * Once a hostname has been resolved (or found to be non-existent),
- * the resolver code calls a specified callback function (which
- * must be implemented by the module that uses the resolver).
- */
-
-/*-----------------------------------------------------------------------------
- * RFC 1035 - Domain names - implementation and specification
- * RFC 2181 - Clarifications to the DNS Specification
- *----------------------------------------------------------------------------*/
-
-/** @todo: define good default values (rfc compliance) */
-/** @todo: improve answer parsing, more checkings... */
-/** @todo: check RFC1035 - 7.3. Processing responses */
-
-/*-----------------------------------------------------------------------------
- * Includes
- *----------------------------------------------------------------------------*/
-
-#include "lwip/opt.h"
-
-#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/udp.h"
-#include "lwip/mem.h"
-#include "lwip/memp.h"
-#include "lwip/dns.h"
-
-#include <string.h>
-
-/** DNS server IP address */
-#ifndef DNS_SERVER_ADDRESS
-#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
-#endif
-
-/** DNS server port address */
-#ifndef DNS_SERVER_PORT
-#define DNS_SERVER_PORT 53
-#endif
-
-/** DNS maximum number of retries when asking for a name, before "timeout". */
-#ifndef DNS_MAX_RETRIES
-#define DNS_MAX_RETRIES 4
-#endif
-
-/** DNS resource record max. TTL (one week as default) */
-#ifndef DNS_MAX_TTL
-#define DNS_MAX_TTL 604800
-#endif
-
-/* DNS protocol flags */
-#define DNS_FLAG1_RESPONSE 0x80
-#define DNS_FLAG1_OPCODE_STATUS 0x10
-#define DNS_FLAG1_OPCODE_INVERSE 0x08
-#define DNS_FLAG1_OPCODE_STANDARD 0x00
-#define DNS_FLAG1_AUTHORATIVE 0x04
-#define DNS_FLAG1_TRUNC 0x02
-#define DNS_FLAG1_RD 0x01
-#define DNS_FLAG2_RA 0x80
-#define DNS_FLAG2_ERR_MASK 0x0f
-#define DNS_FLAG2_ERR_NONE 0x00
-#define DNS_FLAG2_ERR_NAME 0x03
-
-/* DNS protocol states */
-#define DNS_STATE_UNUSED 0
-#define DNS_STATE_NEW 1
-#define DNS_STATE_ASKING 2
-#define DNS_STATE_DONE 3
-
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-/** DNS message header */
-struct dns_hdr {
- PACK_STRUCT_FIELD(u16_t id);
- PACK_STRUCT_FIELD(u8_t flags1);
- PACK_STRUCT_FIELD(u8_t flags2);
- PACK_STRUCT_FIELD(u16_t numquestions);
- PACK_STRUCT_FIELD(u16_t numanswers);
- PACK_STRUCT_FIELD(u16_t numauthrr);
- PACK_STRUCT_FIELD(u16_t numextrarr);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-#define SIZEOF_DNS_HDR 12
-
-/** DNS query message structure.
- No packing needed: only used locally on the stack. */
-struct dns_query {
- /* DNS query record starts with either a domain name or a pointer
- to a name already present somewhere in the packet. */
- u16_t type;
- u16_t cls;
-};
-#define SIZEOF_DNS_QUERY 4
-
-/** DNS answer message structure.
- No packing needed: only used locally on the stack. */
-struct dns_answer {
- /* DNS answer record starts with either a domain name or a pointer
- to a name already present somewhere in the packet. */
- u16_t type;
- u16_t cls;
- u32_t ttl;
- u16_t len;
-};
-#define SIZEOF_DNS_ANSWER 10
-
-/** DNS table entry */
-struct dns_table_entry {
- u8_t state;
- u8_t numdns;
- u8_t tmr;
- u8_t retries;
- u8_t seqno;
- u8_t err;
- u32_t ttl;
- char name[DNS_MAX_NAME_LENGTH];
- ip_addr_t ipaddr;
- /* pointer to callback on DNS query done */
- dns_found_callback found;
- void *arg;
-};
-
-#if DNS_LOCAL_HOSTLIST
-
-#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
-/** Local host-list. For hostnames in this list, no
- * external name resolution is performed */
-static struct local_hostlist_entry *local_hostlist_dynamic;
-#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
-
-/** Defining this allows the local_hostlist_static to be placed in a different
- * linker section (e.g. FLASH) */
-#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
-#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
-#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
-/** Defining this allows the local_hostlist_static to be placed in a different
- * linker section (e.g. FLASH) */
-#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
-#define DNS_LOCAL_HOSTLIST_STORAGE_POST
-#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
-DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
- DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
-
-#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
-
-static void dns_init_local();
-#endif /* DNS_LOCAL_HOSTLIST */
-
-
-/* forward declarations */
-static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
-static void dns_check_entries(void);
-
-/*-----------------------------------------------------------------------------
- * Globales
- *----------------------------------------------------------------------------*/
-
-/* DNS variables */
-static struct udp_pcb *dns_pcb;
-static u8_t dns_seqno;
-static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
-static ip_addr_t dns_servers[DNS_MAX_SERVERS];
-/** Contiguous buffer for processing responses */
-static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
-static u8_t* dns_payload;
-
-/**
- * Initialize the resolver: set up the UDP pcb and configure the default server
- * (DNS_SERVER_ADDRESS).
- */
-void
-dns_init()
-{
- ip_addr_t dnsserver;
-
- dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
-
- /* initialize default DNS server address */
- DNS_SERVER_ADDRESS(&dnsserver);
-
- LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
-
- /* if dns client not yet initialized... */
- if (dns_pcb == NULL) {
- dns_pcb = udp_new();
-
- if (dns_pcb != NULL) {
- /* initialize DNS table not needed (initialized to zero since it is a
- * global variable) */
- LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
- DNS_STATE_UNUSED == 0);
-
- /* initialize DNS client */
- udp_bind(dns_pcb, IP_ADDR_ANY, 0);
- udp_recv(dns_pcb, dns_recv, NULL);
-
- /* initialize default DNS primary server */
- dns_setserver(0, &dnsserver);
- }
- }
-#if DNS_LOCAL_HOSTLIST
- dns_init_local();
-#endif
-}
-
-/**
- * Initialize one of the DNS servers.
- *
- * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
- * @param dnsserver IP address of the DNS server to set
- */
-void
-dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
-{
- if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
- (dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
- dns_servers[numdns] = (*dnsserver);
- }
-}
-
-/**
- * Obtain one of the currently configured DNS server.
- *
- * @param numdns the index of the DNS server
- * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
- * server has not been configured.
- */
-ip_addr_t
-dns_getserver(u8_t numdns)
-{
- if (numdns < DNS_MAX_SERVERS) {
- return dns_servers[numdns];
- } else {
- return *IP_ADDR_ANY;
- }
-}
-
-/**
- * The DNS resolver client timer - handle retries and timeouts and should
- * be called every DNS_TMR_INTERVAL milliseconds (every second by default).
- */
-void
-dns_tmr(void)
-{
- if (dns_pcb != NULL) {
- LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
- dns_check_entries();
- }
-}
-
-#if DNS_LOCAL_HOSTLIST
-static void
-dns_init_local()
-{
-#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
- int i;
- struct local_hostlist_entry *entry;
- /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
- struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
- size_t namelen;
- for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
- struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
- LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
- namelen = strlen(init_entry->name);
- LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
- entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
- LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
- if (entry != NULL) {
- entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
- MEMCPY((char*)entry->name, init_entry->name, namelen);
- ((char*)entry->name)[namelen] = 0;
- entry->addr = init_entry->addr;
- entry->next = local_hostlist_dynamic;
- local_hostlist_dynamic = entry;
- }
- }
-#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
-}
-
-/**
- * Scans the local host-list for a hostname.
- *
- * @param hostname Hostname to look for in the local host-list
- * @return The first IP address for the hostname in the local host-list or
- * IPADDR_NONE if not found.
- */
-static u32_t
-dns_lookup_local(const char *hostname)
-{
-#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
- struct local_hostlist_entry *entry = local_hostlist_dynamic;
- while(entry != NULL) {
- if(strcmp(entry->name, hostname) == 0) {
- return ip4_addr_get_u32(&entry->addr);
- }
- entry = entry->next;
- }
-#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
- int i;
- for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
- if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
- return ip4_addr_get_u32(&local_hostlist_static[i].addr);
- }
- }
-#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
- return IPADDR_NONE;
-}
-
-#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
-/** Remove all entries from the local host-list for a specific hostname
- * and/or IP addess
- *
- * @param hostname hostname for which entries shall be removed from the local
- * host-list
- * @param addr address for which entries shall be removed from the local host-list
- * @return the number of removed entries
- */
-int
-dns_local_removehost(const char *hostname, const ip_addr_t *addr)
-{
- int removed = 0;
- struct local_hostlist_entry *entry = local_hostlist_dynamic;
- struct local_hostlist_entry *last_entry = NULL;
- while (entry != NULL) {
- if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
- ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
- struct local_hostlist_entry *free_entry;
- if (last_entry != NULL) {
- last_entry->next = entry->next;
- } else {
- local_hostlist_dynamic = entry->next;
- }
- free_entry = entry;
- entry = entry->next;
- memp_free(MEMP_LOCALHOSTLIST, free_entry);
- removed++;
- } else {
- last_entry = entry;
- entry = entry->next;
- }
- }
- return removed;
-}
-
-/**
- * Add a hostname/IP address pair to the local host-list.
- * Duplicates are not checked.
- *
- * @param hostname hostname of the new entry
- * @param addr IP address of the new entry
- * @return ERR_OK if succeeded or ERR_MEM on memory error
- */
-err_t
-dns_local_addhost(const char *hostname, const ip_addr_t *addr)
-{
- struct local_hostlist_entry *entry;
- size_t namelen;
- LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
- namelen = strlen(hostname);
- LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
- entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
- if (entry == NULL) {
- return ERR_MEM;
- }
- entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
- MEMCPY((char*)entry->name, hostname, namelen);
- ((char*)entry->name)[namelen] = 0;
- ip_addr_copy(entry->addr, *addr);
- entry->next = local_hostlist_dynamic;
- local_hostlist_dynamic = entry;
- return ERR_OK;
-}
-#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
-#endif /* DNS_LOCAL_HOSTLIST */
-
-/**
- * Look up a hostname in the array of known hostnames.
- *
- * @note This function only looks in the internal array of known
- * hostnames, it does not send out a query for the hostname if none
- * was found. The function dns_enqueue() can be used to send a query
- * for a hostname.
- *
- * @param name the hostname to look up
- * @return the hostname's IP address, as u32_t (instead of ip_addr_t to
- * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname
- * was not found in the cached dns_table.
- */
-static u32_t
-dns_lookup(const char *name)
-{
- u8_t i;
-#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
- u32_t addr;
-#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
-#if DNS_LOCAL_HOSTLIST
- if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
- return addr;
- }
-#endif /* DNS_LOCAL_HOSTLIST */
-#ifdef DNS_LOOKUP_LOCAL_EXTERN
- if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
- return addr;
- }
-#endif /* DNS_LOOKUP_LOCAL_EXTERN */
-
- /* Walk through name list, return entry if found. If not, return NULL. */
- for (i = 0; i < DNS_TABLE_SIZE; ++i) {
- if ((dns_table[i].state == DNS_STATE_DONE) &&
- (strcmp(name, dns_table[i].name) == 0)) {
- LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
- ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
- LWIP_DEBUGF(DNS_DEBUG, ("\n"));
- return ip4_addr_get_u32(&dns_table[i].ipaddr);
- }
- }
-
- return IPADDR_NONE;
-}
-
-#if DNS_DOES_NAME_CHECK
-/**
- * Compare the "dotted" name "query" with the encoded name "response"
- * to make sure an answer from the DNS server matches the current dns_table
- * entry (otherwise, answers might arrive late for hostname not on the list
- * any more).
- *
- * @param query hostname (not encoded) from the dns_table
- * @param response encoded hostname in the DNS response
- * @return 0: names equal; 1: names differ
- */
-static u8_t
-dns_compare_name(unsigned char *query, unsigned char *response)
-{
- unsigned char n;
-
- do {
- n = *response++;
- /** @see RFC 1035 - 4.1.4. Message compression */
- if ((n & 0xc0) == 0xc0) {
- /* Compressed name */
- break;
- } else {
- /* Not compressed name */
- while (n > 0) {
- if ((*query) != (*response)) {
- return 1;
- }
- ++response;
- ++query;
- --n;
- };
- ++query;
- }
- } while (*response != 0);
-
- return 0;
-}
-#endif /* DNS_DOES_NAME_CHECK */
-
-/**
- * Walk through a compact encoded DNS name and return the end of the name.
- *
- * @param query encoded DNS name in the DNS server response
- * @return end of the name
- */
-static unsigned char *
-dns_parse_name(unsigned char *query)
-{
- unsigned char n;
-
- do {
- n = *query++;
- /** @see RFC 1035 - 4.1.4. Message compression */
- if ((n & 0xc0) == 0xc0) {
- /* Compressed name */
- break;
- } else {
- /* Not compressed name */
- while (n > 0) {
- ++query;
- --n;
- };
- }
- } while (*query != 0);
-
- return query + 1;
-}
-
-/**
- * Send a DNS query packet.
- *
- * @param numdns index of the DNS server in the dns_servers table
- * @param name hostname to query
- * @param id index of the hostname in dns_table, used as transaction ID in the
- * DNS query packet
- * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
- */
-static err_t
-dns_send(u8_t numdns, const char* name, u8_t id)
-{
- err_t err;
- struct dns_hdr *hdr;
- struct dns_query qry;
- struct pbuf *p;
- char *query, *nptr;
- const char *pHostname;
- u8_t n;
-
- LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
- (u16_t)(numdns), name));
- LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
- LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
-
- /* if here, we have either a new query or a retry on a previous query to process */
- p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
- SIZEOF_DNS_QUERY, PBUF_RAM);
- if (p != NULL) {
- LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
- /* fill dns header */
- hdr = (struct dns_hdr*)p->payload;
- memset(hdr, 0, SIZEOF_DNS_HDR);
- hdr->id = htons(id);
- hdr->flags1 = DNS_FLAG1_RD;
- hdr->numquestions = PP_HTONS(1);
- query = (char*)hdr + SIZEOF_DNS_HDR;
- pHostname = name;
- --pHostname;
-
- /* convert hostname into suitable query format. */
- do {
- ++pHostname;
- nptr = query;
- ++query;
- for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
- *query = *pHostname;
- ++query;
- ++n;
- }
- *nptr = n;
- } while(*pHostname != 0);
- *query++='\0';
-
- /* fill dns query */
- qry.type = PP_HTONS(DNS_RRTYPE_A);
- qry.cls = PP_HTONS(DNS_RRCLASS_IN);
- SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
-
- /* resize pbuf to the exact dns query */
- pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
-
- /* connect to the server for faster receiving */
- udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
- /* send dns packet */
- err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
-
- /* free pbuf */
- pbuf_free(p);
- } else {
- err = ERR_MEM;
- }
-
- return err;
-}
-
-/**
- * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.
- * Check an entry in the dns_table:
- * - send out query for new entries
- * - retry old pending entries on timeout (also with different servers)
- * - remove completed entries from the table if their TTL has expired
- *
- * @param i index of the dns_table entry to check
- */
-static void
-dns_check_entry(u8_t i)
-{
- err_t err;
- struct dns_table_entry *pEntry = &dns_table[i];
-
- LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
-
- switch(pEntry->state) {
-
- case DNS_STATE_NEW: {
- /* initialize new entry */
- pEntry->state = DNS_STATE_ASKING;
- pEntry->numdns = 0;
- pEntry->tmr = 1;
- pEntry->retries = 0;
-
- /* send DNS packet for this entry */
- err = dns_send(pEntry->numdns, pEntry->name, i);
- if (err != ERR_OK) {
- LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
- ("dns_send returned error: %s\n", lwip_strerr(err)));
- }
- break;
- }
-
- case DNS_STATE_ASKING: {
- if (--pEntry->tmr == 0) {
- if (++pEntry->retries == DNS_MAX_RETRIES) {
- if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
- /* change of server */
- pEntry->numdns++;
- pEntry->tmr = 1;
- pEntry->retries = 0;
- break;
- } else {
- LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
- /* call specified callback function if provided */
- if (pEntry->found)
- (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
- /* flush this entry */
- pEntry->state = DNS_STATE_UNUSED;
- pEntry->found = NULL;
- break;
- }
- }
-
- /* wait longer for the next retry */
- pEntry->tmr = pEntry->retries;
-
- /* send DNS packet for this entry */
- err = dns_send(pEntry->numdns, pEntry->name, i);
- if (err != ERR_OK) {
- LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
- ("dns_send returned error: %s\n", lwip_strerr(err)));
- }
- }
- break;
- }
-
- case DNS_STATE_DONE: {
- /* if the time to live is nul */
- if (--pEntry->ttl == 0) {
- LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
- /* flush this entry */
- pEntry->state = DNS_STATE_UNUSED;
- pEntry->found = NULL;
- }
- break;
- }
- case DNS_STATE_UNUSED:
- /* nothing to do */
- break;
- default:
- LWIP_ASSERT("unknown dns_table entry state:", 0);
- break;
- }
-}
-
-/**
- * Call dns_check_entry for each entry in dns_table - check all entries.
- */
-static void
-dns_check_entries(void)
-{
- u8_t i;
-
- for (i = 0; i < DNS_TABLE_SIZE; ++i) {
- dns_check_entry(i);
- }
-}
-
-/**
- * Receive input function for DNS response packets arriving for the dns UDP pcb.
- *
- * @params see udp.h
- */
-static void
-dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
-{
- u16_t i;
- char *pHostname;
- struct dns_hdr *hdr;
- struct dns_answer ans;
- struct dns_table_entry *pEntry;
- u16_t nquestions, nanswers;
-
- LWIP_UNUSED_ARG(arg);
- LWIP_UNUSED_ARG(pcb);
- LWIP_UNUSED_ARG(addr);
- LWIP_UNUSED_ARG(port);
-
- /* is the dns message too big ? */
- if (p->tot_len > DNS_MSG_SIZE) {
- LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
- /* free pbuf and return */
- goto memerr;
- }
-
- /* is the dns message big enough ? */
- if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
- LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
- /* free pbuf and return */
- goto memerr;
- }
-
- /* copy dns payload inside static buffer for processing */
- if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
- /* The ID in the DNS header should be our entry into the name table. */
- hdr = (struct dns_hdr*)dns_payload;
- i = htons(hdr->id);
- if (i < DNS_TABLE_SIZE) {
- pEntry = &dns_table[i];
- if(pEntry->state == DNS_STATE_ASKING) {
- /* This entry is now completed. */
- pEntry->state = DNS_STATE_DONE;
- pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
-
- /* We only care about the question(s) and the answers. The authrr
- and the extrarr are simply discarded. */
- nquestions = htons(hdr->numquestions);
- nanswers = htons(hdr->numanswers);
-
- /* Check for error. If so, call callback to inform. */
- if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
- LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
- /* call callback to indicate error, clean up memory and return */
- goto responseerr;
- }
-
-#if DNS_DOES_NAME_CHECK
- /* Check if the name in the "question" part match with the name in the entry. */
- if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
- LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
- /* call callback to indicate error, clean up memory and return */
- goto responseerr;
- }
-#endif /* DNS_DOES_NAME_CHECK */
-
- /* Skip the name in the "question" part */
- pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
-
- while (nanswers > 0) {
- /* skip answer resource record's host name */
- pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
-
- /* Check for IP address type and Internet class. Others are discarded. */
- SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
- if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&
- (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {
- /* read the answer resource record's TTL, and maximize it if needed */
- pEntry->ttl = ntohl(ans.ttl);
- if (pEntry->ttl > DNS_MAX_TTL) {
- pEntry->ttl = DNS_MAX_TTL;
- }
- /* read the IP address after answer resource record's header */
- SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
- LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
- ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
- LWIP_DEBUGF(DNS_DEBUG, ("\n"));
- /* call specified callback function if provided */
- if (pEntry->found) {
- (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
- }
- /* deallocate memory and return */
- goto memerr;
- } else {
- pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
- }
- --nanswers;
- }
- LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
- /* call callback to indicate error, clean up memory and return */
- goto responseerr;
- }
- }
- }
-
- /* deallocate memory and return */
- goto memerr;
-
-responseerr:
- /* ERROR: call specified callback function with NULL as name to indicate an error */
- if (pEntry->found) {
- (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
- }
- /* flush this entry */
- pEntry->state = DNS_STATE_UNUSED;
- pEntry->found = NULL;
-
-memerr:
- /* free pbuf */
- pbuf_free(p);
- return;
-}
-
-/**
- * Queues a new hostname to resolve and sends out a DNS query for that hostname
- *
- * @param name the hostname that is to be queried
- * @param found a callback founction to be called on success, failure or timeout
- * @param callback_arg argument to pass to the callback function
- * @return @return a err_t return code.
- */
-static err_t
-dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
-{
- u8_t i;
- u8_t lseq, lseqi;
- struct dns_table_entry *pEntry = NULL;
- size_t namelen;
-
- /* search an unused entry, or the oldest one */
- lseq = lseqi = 0;
- for (i = 0; i < DNS_TABLE_SIZE; ++i) {
- pEntry = &dns_table[i];
- /* is it an unused entry ? */
- if (pEntry->state == DNS_STATE_UNUSED)
- break;
-
- /* check if this is the oldest completed entry */
- if (pEntry->state == DNS_STATE_DONE) {
- if ((dns_seqno - pEntry->seqno) > lseq) {
- lseq = dns_seqno - pEntry->seqno;
- lseqi = i;
- }
- }
- }
-
- /* if we don't have found an unused entry, use the oldest completed one */
- if (i == DNS_TABLE_SIZE) {
- if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
- /* no entry can't be used now, table is full */
- LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
- return ERR_MEM;
- } else {
- /* use the oldest completed one */
- i = lseqi;
- pEntry = &dns_table[i];
- }
- }
-
- /* use this entry */
- LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
-
- /* fill the entry */
- pEntry->state = DNS_STATE_NEW;
- pEntry->seqno = dns_seqno++;
- pEntry->found = found;
- pEntry->arg = callback_arg;
- namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1);
- MEMCPY(pEntry->name, name, namelen);
- pEntry->name[namelen] = 0;
-
- /* force to send query without waiting timer */
- dns_check_entry(i);
-
- /* dns query is enqueued */
- return ERR_INPROGRESS;
-}
-
-/**
- * Resolve a hostname (string) into an IP address.
- * NON-BLOCKING callback version for use with raw API!!!
- *
- * Returns immediately with one of err_t return codes:
- * - ERR_OK if hostname is a valid IP address string or the host
- * name is already in the local names table.
- * - ERR_INPROGRESS enqueue a request to be sent to the DNS server
- * for resolution if no errors are present.
- * - ERR_ARG: dns client not initialized or invalid hostname
- *
- * @param hostname the hostname that is to be queried
- * @param addr pointer to a ip_addr_t where to store the address if it is already
- * cached in the dns_table (only valid if ERR_OK is returned!)
- * @param found a callback function to be called on success, failure or timeout (only if
- * ERR_INPROGRESS is returned!)
- * @param callback_arg argument to pass to the callback function
- * @return a err_t return code.
- */
-err_t
-dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
- void *callback_arg)
-{
- u32_t ipaddr;
- /* not initialized or no valid server yet, or invalid addr pointer
- * or invalid hostname or invalid hostname length */
- if ((dns_pcb == NULL) || (addr == NULL) ||
- (!hostname) || (!hostname[0]) ||
- (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
- return ERR_ARG;
- }
-
-#if LWIP_HAVE_LOOPIF
- if (strcmp(hostname, "localhost")==0) {
- ip_addr_set_loopback(addr);
- return ERR_OK;
- }
-#endif /* LWIP_HAVE_LOOPIF */
-
- /* host name already in octet notation? set ip addr and return ERR_OK */
- ipaddr = ipaddr_addr(hostname);
- if (ipaddr == IPADDR_NONE) {
- /* already have this address cached? */
- ipaddr = dns_lookup(hostname);
- }
- if (ipaddr != IPADDR_NONE) {
- ip4_addr_set_u32(addr, ipaddr);
- return ERR_OK;
- }
-
- /* queue query with specified callback */
- return dns_enqueue(hostname, found, callback_arg);
-}
-
-#endif /* LWIP_DNS */
+++ /dev/null
-/**
- * @file
- * Modules initialization
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-
-#include "lwip/init.h"
-#include "lwip/stats.h"
-#include "lwip/sys.h"
-#include "lwip/mem.h"
-#include "lwip/memp.h"
-#include "lwip/pbuf.h"
-#include "lwip/netif.h"
-#include "lwip/sockets.h"
-#include "lwip/ip.h"
-#include "lwip/raw.h"
-#include "lwip/udp.h"
-#include "lwip/tcp_impl.h"
-#include "lwip/snmp_msg.h"
-#include "lwip/autoip.h"
-#include "lwip/igmp.h"
-#include "lwip/dns.h"
-#include "lwip/timers.h"
-#include "netif/etharp.h"
-
-/* Compile-time sanity checks for configuration errors.
- * These can be done independently of LWIP_DEBUG, without penalty.
- */
-#ifndef BYTE_ORDER
- #error "BYTE_ORDER is not defined, you have to define it in your cc.h"
-#endif
-#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV)
- #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h"
-#endif
-#if (!LWIP_ARP && ARP_QUEUEING)
- #error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"
-#endif
-#if (!LWIP_UDP && LWIP_UDPLITE)
- #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h"
-#endif
-#if (!LWIP_UDP && LWIP_SNMP)
- #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
-#endif
-#if (!LWIP_UDP && LWIP_DHCP)
- #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h"
-#endif
-#if (!LWIP_UDP && LWIP_IGMP)
- #error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h"
-#endif
-#if (!LWIP_UDP && LWIP_SNMP)
- #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
-#endif
-#if (!LWIP_UDP && LWIP_DNS)
- #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"
-#endif
-#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))
- #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"
-#endif
-#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0))
- #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h"
-#endif
-#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0))
- #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h"
-#endif
-#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))
- #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"
-#endif
-#if (LWIP_TCP && (TCP_WND > 0xffff))
- #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
-#endif
-#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))
- #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
-#endif
-#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2))
- #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work"
-#endif
-#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))
- #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h"
-#endif
-#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))
- #error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t"
-#endif
-#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
- #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
-#endif
-#if (LWIP_NETIF_API && (NO_SYS==1))
- #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"
-#endif
-#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
- #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
-#endif
-#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
- #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
-#endif
-#if (!LWIP_NETCONN && LWIP_SOCKET)
- #error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"
-#endif
-#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP)
- #error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h"
-#endif
-#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK)
- #error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h"
-#endif
-#if (!LWIP_ARP && LWIP_AUTOIP)
- #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h"
-#endif
-#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0))
- #error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h"
-#endif
-#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))
- #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
-#endif
-#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))
- #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
-#endif
-/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
-#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
- #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
-#endif
-#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
- #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
-#endif
-#if (MEM_LIBC_MALLOC && MEM_USE_POOLS)
- #error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h"
-#endif
-#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)
- #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"
-#endif
-#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT)
- #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf"
-#endif
-#if (TCP_QUEUE_OOSEQ && !LWIP_TCP)
- #error "TCP_QUEUE_OOSEQ requires LWIP_TCP"
-#endif
-#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))
- #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST"
-#endif
-#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT
- #error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on"
-#endif
-#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT)
- #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT"
-#endif
-#if LWIP_IGMP && !defined(LWIP_RAND)
- #error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
-#endif
-#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING
- #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too"
-#endif
-#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE
- #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets"
-#endif
-#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF
- #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues"
-#endif
-
-
-/* Compile-time checks for deprecated options.
- */
-#ifdef MEMP_NUM_TCPIP_MSG
- #error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h."
-#endif
-#ifdef MEMP_NUM_API_MSG
- #error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h."
-#endif
-#ifdef TCP_REXMIT_DEBUG
- #error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h."
-#endif
-#ifdef RAW_STATS
- #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h."
-#endif
-#ifdef ETHARP_QUEUE_FIRST
- #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h."
-#endif
-#ifdef ETHARP_ALWAYS_INSERT
- #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
-#endif
-
-#ifdef LWIP_DEBUG
-static void
-lwip_sanity_check(void)
-{
- /* Warnings */
-#if LWIP_NETCONN
- if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB))
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n"));
-#endif /* LWIP_NETCONN */
-#if LWIP_TCP
- if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));
- if (TCP_SND_BUF < 2 * TCP_MSS)
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n"));
- if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n"));
- if (TCP_SNDLOWAT >= TCP_SND_BUF)
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n"));
- if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN)
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n"));
- if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n"));
- if (TCP_WND < TCP_MSS)
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));
-#endif /* LWIP_TCP */
-#if LWIP_SOCKET
- /* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
- if (SO_ACCEPTCONN != SOF_ACCEPTCONN)
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n"));
- if (SO_REUSEADDR != SOF_REUSEADDR)
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n"));
- if (SO_KEEPALIVE != SOF_KEEPALIVE)
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n"));
- if (SO_BROADCAST != SOF_BROADCAST)
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n"));
- if (SO_LINGER != SOF_LINGER)
- LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n"));
-#endif /* LWIP_SOCKET */
-}
-#else /* LWIP_DEBUG */
-#define lwip_sanity_check()
-#endif /* LWIP_DEBUG */
-
-/**
- * Perform Sanity check of user-configurable values, and initialize all modules.
- */
-void
-lwip_init(void)
-{
- /* Sanity check user-configurable values */
- lwip_sanity_check();
-
- /* Modules initialization */
- stats_init();
-#if !NO_SYS
- sys_init();
-#endif /* !NO_SYS */
- mem_init();
- memp_init();
- pbuf_init();
- netif_init();
-#if LWIP_SOCKET
- lwip_socket_init();
-#endif /* LWIP_SOCKET */
- ip_init();
-#if LWIP_ARP
- etharp_init();
-#endif /* LWIP_ARP */
-#if LWIP_RAW
- raw_init();
-#endif /* LWIP_RAW */
-#if LWIP_UDP
- udp_init();
-#endif /* LWIP_UDP */
-#if LWIP_TCP
- tcp_init();
-#endif /* LWIP_TCP */
-#if LWIP_SNMP
- snmp_init();
-#endif /* LWIP_SNMP */
-#if LWIP_AUTOIP
- autoip_init();
-#endif /* LWIP_AUTOIP */
-#if LWIP_IGMP
- igmp_init();
-#endif /* LWIP_IGMP */
-#if LWIP_DNS
- dns_init();
-#endif /* LWIP_DNS */
-
-#if LWIP_TIMERS
- sys_timeouts_init();
-#endif /* LWIP_TIMERS */
-}
+++ /dev/null
-/**
- * @file
- * AutoIP Automatic LinkLocal IP Configuration
- *
- */
-
-/*
- *
- * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * Author: Dominik Spies <kontakt@dspies.de>
- *
- * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
- * with RFC 3927.
- *
- *
- * Please coordinate changes and requests with Dominik Spies
- * <kontakt@dspies.de>
- */
-
-/*******************************************************************************
- * USAGE:
- *
- * define LWIP_AUTOIP 1 in your lwipopts.h
- *
- * If you don't use tcpip.c (so, don't call, you don't call tcpip_init):
- * - First, call autoip_init().
- * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,
- * that should be defined in autoip.h.
- * I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
- * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
- *
- * Without DHCP:
- * - Call autoip_start() after netif_add().
- *
- * With DHCP:
- * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
- * - Configure your DHCP Client.
- *
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/mem.h"
-#include "lwip/udp.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/autoip.h"
-#include "netif/etharp.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-/* 169.254.0.0 */
-#define AUTOIP_NET 0xA9FE0000
-/* 169.254.1.0 */
-#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)
-/* 169.254.254.255 */
-#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF)
-
-
-/** Pseudo random macro based on netif informations.
- * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
-#ifndef LWIP_AUTOIP_RAND
-#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
- ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
- ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
- ((u32_t)((netif->hwaddr[4]) & 0xff))) + \
- (netif->autoip?netif->autoip->tried_llipaddr:0))
-#endif /* LWIP_AUTOIP_RAND */
-
-/**
- * Macro that generates the initial IP address to be tried by AUTOIP.
- * If you want to override this, define it to something else in lwipopts.h.
- */
-#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
-#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
- htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
- ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
-#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
-
-/* static functions */
-static void autoip_handle_arp_conflict(struct netif *netif);
-
-/* creates a pseudo random LL IP-Address for a network interface */
-static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr);
-
-/* sends an ARP probe */
-static err_t autoip_arp_probe(struct netif *netif);
-
-/* sends an ARP announce */
-static err_t autoip_arp_announce(struct netif *netif);
-
-/* configure interface for use with current LL IP-Address */
-static err_t autoip_bind(struct netif *netif);
-
-/* start sending probes for llipaddr */
-static void autoip_start_probing(struct netif *netif);
-
-/**
- * Initialize this module
- */
-void
-autoip_init(void)
-{
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
-}
-
-/** Set a statically allocated struct autoip to work with.
- * Using this prevents autoip_start to allocate it using mem_malloc.
- *
- * @param netif the netif for which to set the struct autoip
- * @param dhcp (uninitialised) dhcp struct allocated by the application
- */
-void
-autoip_set_struct(struct netif *netif, struct autoip *autoip)
-{
- LWIP_ASSERT("netif != NULL", netif != NULL);
- LWIP_ASSERT("autoip != NULL", autoip != NULL);
- LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL);
-
- /* clear data structure */
- memset(autoip, 0, sizeof(struct autoip));
- /* autoip->state = AUTOIP_STATE_OFF; */
- netif->autoip = autoip;
-}
-
-/** Restart AutoIP client and check the next address (conflict detected)
- *
- * @param netif The netif under AutoIP control
- */
-static void
-autoip_restart(struct netif *netif)
-{
- netif->autoip->tried_llipaddr++;
- autoip_start(netif);
-}
-
-/**
- * Handle a IP address conflict after an ARP conflict detection
- */
-static void
-autoip_handle_arp_conflict(struct netif *netif)
-{
- /* Somehow detect if we are defending or retreating */
- unsigned char defend = 1; /* tbd */
-
- if(defend) {
- if(netif->autoip->lastconflict > 0) {
- /* retreat, there was a conflicting ARP in the last
- * DEFEND_INTERVAL seconds
- */
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
-
- /* TODO: close all TCP sessions */
- autoip_restart(netif);
- } else {
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
- autoip_arp_announce(netif);
- netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
- }
- } else {
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
- /* TODO: close all TCP sessions */
- autoip_restart(netif);
- }
-}
-
-/**
- * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
- *
- * @param netif network interface on which create the IP-Address
- * @param ipaddr ip address to initialize
- */
-static void
-autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
-{
- /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
- * compliant to RFC 3927 Section 2.1
- * We have 254 * 256 possibilities */
-
- u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
- addr += netif->autoip->tried_llipaddr;
- addr = AUTOIP_NET | (addr & 0xffff);
- /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
-
- if (addr < AUTOIP_RANGE_START) {
- addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
- }
- if (addr > AUTOIP_RANGE_END) {
- addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
- }
- LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
- (addr <= AUTOIP_RANGE_END));
- ip4_addr_set_u32(ipaddr, htonl(addr));
-
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
- ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
-}
-
-/**
- * Sends an ARP probe from a network interface
- *
- * @param netif network interface used to send the probe
- */
-static err_t
-autoip_arp_probe(struct netif *netif)
-{
- return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast,
- (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, ðzero,
- &netif->autoip->llipaddr, ARP_REQUEST);
-}
-
-/**
- * Sends an ARP announce from a network interface
- *
- * @param netif network interface used to send the announce
- */
-static err_t
-autoip_arp_announce(struct netif *netif)
-{
- return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast,
- (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero,
- &netif->autoip->llipaddr, ARP_REQUEST);
-}
-
-/**
- * Configure interface for use with current LL IP-Address
- *
- * @param netif network interface to configure with current LL IP-Address
- */
-static err_t
-autoip_bind(struct netif *netif)
-{
- struct autoip *autoip = netif->autoip;
- ip_addr_t sn_mask, gw_addr;
-
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
- ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num,
- ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
- ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
-
- IP4_ADDR(&sn_mask, 255, 255, 0, 0);
- IP4_ADDR(&gw_addr, 0, 0, 0, 0);
-
- netif_set_ipaddr(netif, &autoip->llipaddr);
- netif_set_netmask(netif, &sn_mask);
- netif_set_gw(netif, &gw_addr);
-
- /* bring the interface up */
- netif_set_up(netif);
-
- return ERR_OK;
-}
-
-/**
- * Start AutoIP client
- *
- * @param netif network interface on which start the AutoIP client
- */
-err_t
-autoip_start(struct netif *netif)
-{
- struct autoip *autoip = netif->autoip;
- err_t result = ERR_OK;
-
- if(netif_is_up(netif)) {
- netif_set_down(netif);
- }
-
- /* Set IP-Address, Netmask and Gateway to 0 to make sure that
- * ARP Packets are formed correctly
- */
- ip_addr_set_zero(&netif->ip_addr);
- ip_addr_set_zero(&netif->netmask);
- ip_addr_set_zero(&netif->gw);
-
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
- netif->name[1], (u16_t)netif->num));
- if(autoip == NULL) {
- /* no AutoIP client attached yet? */
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
- ("autoip_start(): starting new AUTOIP client\n"));
- autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
- if(autoip == NULL) {
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
- ("autoip_start(): could not allocate autoip\n"));
- return ERR_MEM;
- }
- memset(autoip, 0, sizeof(struct autoip));
- /* store this AutoIP client in the netif */
- netif->autoip = autoip;
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
- } else {
- autoip->state = AUTOIP_STATE_OFF;
- autoip->ttw = 0;
- autoip->sent_num = 0;
- ip_addr_set_zero(&autoip->llipaddr);
- autoip->lastconflict = 0;
- }
-
- autoip_create_addr(netif, &(autoip->llipaddr));
- autoip_start_probing(netif);
-
- return result;
-}
-
-static void
-autoip_start_probing(struct netif *netif)
-{
- struct autoip *autoip = netif->autoip;
-
- autoip->state = AUTOIP_STATE_PROBING;
- autoip->sent_num = 0;
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
- ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
-
- /* time to wait to first probe, this is randomly
- * choosen out of 0 to PROBE_WAIT seconds.
- * compliant to RFC 3927 Section 2.2.1
- */
- autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));
-
- /*
- * if we tried more then MAX_CONFLICTS we must limit our rate for
- * accquiring and probing address
- * compliant to RFC 3927 Section 2.2.1
- */
- if(autoip->tried_llipaddr > MAX_CONFLICTS) {
- autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
- }
-}
-
-/**
- * Handle a possible change in the network configuration.
- *
- * If there is an AutoIP address configured, take the interface down
- * and begin probing with the same address.
- */
-void
-autoip_network_changed(struct netif *netif)
-{
- if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
- netif_set_down(netif);
- autoip_start_probing(netif);
- }
-}
-
-/**
- * Stop AutoIP client
- *
- * @param netif network interface on which stop the AutoIP client
- */
-err_t
-autoip_stop(struct netif *netif)
-{
- netif->autoip->state = AUTOIP_STATE_OFF;
- netif_set_down(netif);
- return ERR_OK;
-}
-
-/**
- * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
- */
-void
-autoip_tmr()
-{
- struct netif *netif = netif_list;
- /* loop through netif's */
- while (netif != NULL) {
- /* only act on AutoIP configured interfaces */
- if (netif->autoip != NULL) {
- if(netif->autoip->lastconflict > 0) {
- netif->autoip->lastconflict--;
- }
-
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
- ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
- (u16_t)(netif->autoip->state), netif->autoip->ttw));
-
- switch(netif->autoip->state) {
- case AUTOIP_STATE_PROBING:
- if(netif->autoip->ttw > 0) {
- netif->autoip->ttw--;
- } else {
- if(netif->autoip->sent_num >= PROBE_NUM) {
- netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
- netif->autoip->sent_num = 0;
- netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
- ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
- } else {
- autoip_arp_probe(netif);
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
- ("autoip_tmr() PROBING Sent Probe\n"));
- netif->autoip->sent_num++;
- /* calculate time to wait to next probe */
- netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
- ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
- PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
- }
- }
- break;
-
- case AUTOIP_STATE_ANNOUNCING:
- if(netif->autoip->ttw > 0) {
- netif->autoip->ttw--;
- } else {
- if(netif->autoip->sent_num == 0) {
- /* We are here the first time, so we waited ANNOUNCE_WAIT seconds
- * Now we can bind to an IP address and use it.
- *
- * autoip_bind calls netif_set_up. This triggers a gratuitous ARP
- * which counts as an announcement.
- */
- autoip_bind(netif);
- } else {
- autoip_arp_announce(netif);
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
- ("autoip_tmr() ANNOUNCING Sent Announce\n"));
- }
- netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
- netif->autoip->sent_num++;
-
- if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
- netif->autoip->state = AUTOIP_STATE_BOUND;
- netif->autoip->sent_num = 0;
- netif->autoip->ttw = 0;
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
- ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
- }
- }
- break;
- }
- }
- /* proceed to next network interface */
- netif = netif->next;
- }
-}
-
-/**
- * Handles every incoming ARP Packet, called by etharp_arp_input.
- *
- * @param netif network interface to use for autoip processing
- * @param hdr Incoming ARP packet
- */
-void
-autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
-{
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
- if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {
- /* when ip.src == llipaddr && hw.src != netif->hwaddr
- *
- * when probing ip.dst == llipaddr && hw.src != netif->hwaddr
- * we have a conflict and must solve it
- */
- ip_addr_t sipaddr, dipaddr;
- struct eth_addr netifaddr;
- ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);
-
- /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
- * structure packing (not using structure copy which breaks strict-aliasing rules).
- */
- IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
- IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
-
- if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
- ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
- (netif->autoip->sent_num == 0))) {
- /* RFC 3927 Section 2.2.1:
- * from beginning to after ANNOUNCE_WAIT
- * seconds we have a conflict if
- * ip.src == llipaddr OR
- * ip.dst == llipaddr && hw.src != own hwaddr
- */
- if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
- (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
- !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
- ("autoip_arp_reply(): Probe Conflict detected\n"));
- autoip_restart(netif);
- }
- } else {
- /* RFC 3927 Section 2.5:
- * in any state we have a conflict if
- * ip.src == llipaddr && hw.src != own hwaddr
- */
- if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
- !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
- LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
- ("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
- autoip_handle_arp_conflict(netif);
- }
- }
- }
-}
-
-#endif /* LWIP_AUTOIP */
+++ /dev/null
-/**
- * @file
- * ICMP - Internet Control Message Protocol
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-/* Some ICMP messages should be passed to the transport protocols. This
- is not implemented. */
-
-#include "lwip/opt.h"
-
-#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/icmp.h"
-#include "lwip/inet_chksum.h"
-#include "lwip/ip.h"
-#include "lwip/def.h"
-#include "lwip/stats.h"
-#include "lwip/snmp.h"
-
-#include <string.h>
-
-/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be
- * used to modify and send a response packet (and to 1 if this is not the case,
- * e.g. when link header is stripped of when receiving) */
-#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
-#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
-#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
-
-/* The amount of data from the original packet to return in a dest-unreachable */
-#define ICMP_DEST_UNREACH_DATASIZE 8
-
-static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
-
-/**
- * Processes ICMP input packets, called from ip_input().
- *
- * Currently only processes icmp echo requests and sends
- * out the echo response.
- *
- * @param p the icmp echo request packet, p->payload pointing to the ip header
- * @param inp the netif on which this packet was received
- */
-void
-icmp_input(struct pbuf *p, struct netif *inp)
-{
- u8_t type;
-#ifdef LWIP_DEBUG
- u8_t code;
-#endif /* LWIP_DEBUG */
- struct icmp_echo_hdr *iecho;
- struct ip_hdr *iphdr;
- s16_t hlen;
-
- ICMP_STATS_INC(icmp.recv);
- snmp_inc_icmpinmsgs();
-
-
- iphdr = (struct ip_hdr *)p->payload;
- hlen = IPH_HL(iphdr) * 4;
- if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
- goto lenerr;
- }
-
- type = *((u8_t *)p->payload);
-#ifdef LWIP_DEBUG
- code = *(((u8_t *)p->payload)+1);
-#endif /* LWIP_DEBUG */
- switch (type) {
- case ICMP_ER:
- /* This is OK, echo reply might have been parsed by a raw PCB
- (as obviously, an echo request has been sent, too). */
- break;
- case ICMP_ECHO:
-#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
- {
- int accepted = 1;
-#if !LWIP_MULTICAST_PING
- /* multicast destination address? */
- if (ip_addr_ismulticast(¤t_iphdr_dest)) {
- accepted = 0;
- }
-#endif /* LWIP_MULTICAST_PING */
-#if !LWIP_BROADCAST_PING
- /* broadcast destination address? */
- if (ip_addr_isbroadcast(¤t_iphdr_dest, inp)) {
- accepted = 0;
- }
-#endif /* LWIP_BROADCAST_PING */
- /* broadcast or multicast destination address not acceptd? */
- if (!accepted) {
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
- ICMP_STATS_INC(icmp.err);
- pbuf_free(p);
- return;
- }
- }
-#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
- if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
- goto lenerr;
- }
- if (inet_chksum_pbuf(p) != 0) {
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
- pbuf_free(p);
- ICMP_STATS_INC(icmp.chkerr);
- snmp_inc_icmpinerrors();
- return;
- }
-#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
- if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
- /* p is not big enough to contain link headers
- * allocate a new one and copy p into it
- */
- struct pbuf *r;
- /* switch p->payload to ip header */
- if (pbuf_header(p, hlen)) {
- LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
- goto memerr;
- }
- /* allocate new packet buffer with space for link headers */
- r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
- if (r == NULL) {
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
- goto memerr;
- }
- LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
- (r->len >= hlen + sizeof(struct icmp_echo_hdr)));
- /* copy the whole packet including ip header */
- if (pbuf_copy(r, p) != ERR_OK) {
- LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
- goto memerr;
- }
- iphdr = (struct ip_hdr *)r->payload;
- /* switch r->payload back to icmp header */
- if (pbuf_header(r, -hlen)) {
- LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
- goto memerr;
- }
- /* free the original p */
- pbuf_free(p);
- /* we now have an identical copy of p that has room for link headers */
- p = r;
- } else {
- /* restore p->payload to point to icmp header */
- if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
- LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
- goto memerr;
- }
- }
-#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
- /* At this point, all checks are OK. */
- /* We generate an answer by switching the dest and src ip addresses,
- * setting the icmp type to ECHO_RESPONSE and updating the checksum. */
- iecho = (struct icmp_echo_hdr *)p->payload;
- ip_addr_copy(iphdr->src, *ip_current_dest_addr());
- ip_addr_copy(iphdr->dest, *ip_current_src_addr());
- ICMPH_TYPE_SET(iecho, ICMP_ER);
- /* adjust the checksum */
- if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
- iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
- } else {
- iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
- }
-
- /* Set the correct TTL and recalculate the header checksum. */
- IPH_TTL_SET(iphdr, ICMP_TTL);
- IPH_CHKSUM_SET(iphdr, 0);
-#if CHECKSUM_GEN_IP
- IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
-#endif /* CHECKSUM_GEN_IP */
-
- ICMP_STATS_INC(icmp.xmit);
- /* increase number of messages attempted to send */
- snmp_inc_icmpoutmsgs();
- /* increase number of echo replies attempted to send */
- snmp_inc_icmpoutechoreps();
-
- if(pbuf_header(p, hlen)) {
- LWIP_ASSERT("Can't move over header in packet", 0);
- } else {
- err_t ret;
- /* send an ICMP packet, src addr is the dest addr of the curren packet */
- ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL,
- ICMP_TTL, 0, IP_PROTO_ICMP, inp);
- if (ret != ERR_OK) {
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
- }
- }
- break;
- default:
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
- (s16_t)type, (s16_t)code));
- ICMP_STATS_INC(icmp.proterr);
- ICMP_STATS_INC(icmp.drop);
- }
- pbuf_free(p);
- return;
-lenerr:
- pbuf_free(p);
- ICMP_STATS_INC(icmp.lenerr);
- snmp_inc_icmpinerrors();
- return;
-#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
-memerr:
- pbuf_free(p);
- ICMP_STATS_INC(icmp.err);
- snmp_inc_icmpinerrors();
- return;
-#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
-}
-
-/**
- * Send an icmp 'destination unreachable' packet, called from ip_input() if
- * the transport layer protocol is unknown and from udp_input() if the local
- * port is not bound.
- *
- * @param p the input packet for which the 'unreachable' should be sent,
- * p->payload pointing to the IP header
- * @param t type of the 'unreachable' packet
- */
-void
-icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
-{
- icmp_send_response(p, ICMP_DUR, t);
-}
-
-#if IP_FORWARD || IP_REASSEMBLY
-/**
- * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.
- *
- * @param p the input packet for which the 'time exceeded' should be sent,
- * p->payload pointing to the IP header
- * @param t type of the 'time exceeded' packet
- */
-void
-icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
-{
- icmp_send_response(p, ICMP_TE, t);
-}
-
-#endif /* IP_FORWARD || IP_REASSEMBLY */
-
-/**
- * Send an icmp packet in response to an incoming packet.
- *
- * @param p the input packet for which the 'unreachable' should be sent,
- * p->payload pointing to the IP header
- * @param type Type of the ICMP header
- * @param code Code of the ICMP header
- */
-static void
-icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
-{
- struct pbuf *q;
- struct ip_hdr *iphdr;
- /* we can use the echo header here */
- struct icmp_echo_hdr *icmphdr;
- ip_addr_t iphdr_src;
-
- /* ICMP header + IP header + 8 bytes of data */
- q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
- PBUF_RAM);
- if (q == NULL) {
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
- return;
- }
- LWIP_ASSERT("check that first pbuf can hold icmp message",
- (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
-
- iphdr = (struct ip_hdr *)p->payload;
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
- ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
- LWIP_DEBUGF(ICMP_DEBUG, (" to "));
- ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
- LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
-
- icmphdr = (struct icmp_echo_hdr *)q->payload;
- icmphdr->type = type;
- icmphdr->code = code;
- icmphdr->id = 0;
- icmphdr->seqno = 0;
-
- /* copy fields from original packet */
- SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
- IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
-
- /* calculate checksum */
- icmphdr->chksum = 0;
- icmphdr->chksum = inet_chksum(icmphdr, q->len);
- ICMP_STATS_INC(icmp.xmit);
- /* increase number of messages attempted to send */
- snmp_inc_icmpoutmsgs();
- /* increase number of destination unreachable messages attempted to send */
- snmp_inc_icmpouttimeexcds();
- ip_addr_copy(iphdr_src, iphdr->src);
- ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
- pbuf_free(q);
-}
-
-#endif /* LWIP_ICMP */
+++ /dev/null
-/**
- * @file
- * IGMP - Internet Group Management Protocol
- *
- */
-
-/*
- * Copyright (c) 2002 CITEL Technologies Ltd.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This file is a contribution to the lwIP TCP/IP stack.
- * The Swedish Institute of Computer Science and Adam Dunkels
- * are specifically granted permission to redistribute this
- * source code.
-*/
-
-/*-------------------------------------------------------------
-Note 1)
-Although the rfc requires V1 AND V2 capability
-we will only support v2 since now V1 is very old (August 1989)
-V1 can be added if required
-
-a debug print and statistic have been implemented to
-show this up.
--------------------------------------------------------------
--------------------------------------------------------------
-Note 2)
-A query for a specific group address (as opposed to ALLHOSTS)
-has now been implemented as I am unsure if it is required
-
-a debug print and statistic have been implemented to
-show this up.
--------------------------------------------------------------
--------------------------------------------------------------
-Note 3)
-The router alert rfc 2113 is implemented in outgoing packets
-but not checked rigorously incoming
--------------------------------------------------------------
-Steve Reynolds
-------------------------------------------------------------*/
-
-/*-----------------------------------------------------------------------------
- * RFC 988 - Host extensions for IP multicasting - V0
- * RFC 1054 - Host extensions for IP multicasting -
- * RFC 1112 - Host extensions for IP multicasting - V1
- * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard)
- * RFC 3376 - Internet Group Management Protocol, Version 3 - V3
- * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+
- * RFC 2113 - IP Router Alert Option -
- *----------------------------------------------------------------------------*/
-
-/*-----------------------------------------------------------------------------
- * Includes
- *----------------------------------------------------------------------------*/
-
-#include "lwip/opt.h"
-
-#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/igmp.h"
-#include "lwip/debug.h"
-#include "lwip/def.h"
-#include "lwip/mem.h"
-#include "lwip/ip.h"
-#include "lwip/inet_chksum.h"
-#include "lwip/netif.h"
-#include "lwip/icmp.h"
-#include "lwip/udp.h"
-#include "lwip/tcp.h"
-#include "lwip/stats.h"
-
-#include "string.h"
-
-/*
- * IGMP constants
- */
-#define IGMP_TTL 1
-#define IGMP_MINLEN 8
-#define ROUTER_ALERT 0x9404U
-#define ROUTER_ALERTLEN 4
-
-/*
- * IGMP message types, including version number.
- */
-#define IGMP_MEMB_QUERY 0x11 /* Membership query */
-#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
-#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
-#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
-
-/* Group membership states */
-#define IGMP_GROUP_NON_MEMBER 0
-#define IGMP_GROUP_DELAYING_MEMBER 1
-#define IGMP_GROUP_IDLE_MEMBER 2
-
-/**
- * IGMP packet format.
- */
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-struct igmp_msg {
- PACK_STRUCT_FIELD(u8_t igmp_msgtype);
- PACK_STRUCT_FIELD(u8_t igmp_maxresp);
- PACK_STRUCT_FIELD(u16_t igmp_checksum);
- PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-
-static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
-static err_t igmp_remove_group(struct igmp_group *group);
-static void igmp_timeout( struct igmp_group *group);
-static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
-static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
-static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
-static void igmp_send(struct igmp_group *group, u8_t type);
-
-
-static struct igmp_group* igmp_group_list;
-static ip_addr_t allsystems;
-static ip_addr_t allrouters;
-
-
-/**
- * Initialize the IGMP module
- */
-void
-igmp_init(void)
-{
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
-
- IP4_ADDR(&allsystems, 224, 0, 0, 1);
- IP4_ADDR(&allrouters, 224, 0, 0, 2);
-}
-
-#ifdef LWIP_DEBUG
-/**
- * Dump global IGMP groups list
- */
-void
-igmp_dump_group_list()
-{
- struct igmp_group *group = igmp_group_list;
-
- while (group != NULL) {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
- ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
- LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
- group = group->next;
- }
- LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
-}
-#else
-#define igmp_dump_group_list()
-#endif /* LWIP_DEBUG */
-
-/**
- * Start IGMP processing on interface
- *
- * @param netif network interface on which start IGMP processing
- */
-err_t
-igmp_start(struct netif *netif)
-{
- struct igmp_group* group;
-
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
-
- group = igmp_lookup_group(netif, &allsystems);
-
- if (group != NULL) {
- group->group_state = IGMP_GROUP_IDLE_MEMBER;
- group->use++;
-
- /* Allow the igmp messages at the MAC level */
- if (netif->igmp_mac_filter != NULL) {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
- ip_addr_debug_print(IGMP_DEBUG, &allsystems);
- LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
- netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
- }
-
- return ERR_OK;
- }
-
- return ERR_MEM;
-}
-
-/**
- * Stop IGMP processing on interface
- *
- * @param netif network interface on which stop IGMP processing
- */
-err_t
-igmp_stop(struct netif *netif)
-{
- struct igmp_group *group = igmp_group_list;
- struct igmp_group *prev = NULL;
- struct igmp_group *next;
-
- /* look for groups joined on this interface further down the list */
- while (group != NULL) {
- next = group->next;
- /* is it a group joined on this interface? */
- if (group->netif == netif) {
- /* is it the first group of the list? */
- if (group == igmp_group_list) {
- igmp_group_list = next;
- }
- /* is there a "previous" group defined? */
- if (prev != NULL) {
- prev->next = next;
- }
- /* disable the group at the MAC level */
- if (netif->igmp_mac_filter != NULL) {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
- ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
- LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
- netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
- }
- /* free group */
- memp_free(MEMP_IGMP_GROUP, group);
- } else {
- /* change the "previous" */
- prev = group;
- }
- /* move to "next" */
- group = next;
- }
- return ERR_OK;
-}
-
-/**
- * Report IGMP memberships for this interface
- *
- * @param netif network interface on which report IGMP memberships
- */
-void
-igmp_report_groups(struct netif *netif)
-{
- struct igmp_group *group = igmp_group_list;
-
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
-
- while (group != NULL) {
- if (group->netif == netif) {
- igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
- }
- group = group->next;
- }
-}
-
-/**
- * Search for a group in the global igmp_group_list
- *
- * @param ifp the network interface for which to look
- * @param addr the group ip address to search for
- * @return a struct igmp_group* if the group has been found,
- * NULL if the group wasn't found.
- */
-struct igmp_group *
-igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)
-{
- struct igmp_group *group = igmp_group_list;
-
- while (group != NULL) {
- if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
- return group;
- }
- group = group->next;
- }
-
- /* to be clearer, we return NULL here instead of
- * 'group' (which is also NULL at this point).
- */
- return NULL;
-}
-
-/**
- * Search for a specific igmp group and create a new one if not found-
- *
- * @param ifp the network interface for which to look
- * @param addr the group ip address to search
- * @return a struct igmp_group*,
- * NULL on memory error.
- */
-struct igmp_group *
-igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
-{
- struct igmp_group *group = igmp_group_list;
-
- /* Search if the group already exists */
- group = igmp_lookfor_group(ifp, addr);
- if (group != NULL) {
- /* Group already exists. */
- return group;
- }
-
- /* Group doesn't exist yet, create a new one */
- group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
- if (group != NULL) {
- group->netif = ifp;
- ip_addr_set(&(group->group_address), addr);
- group->timer = 0; /* Not running */
- group->group_state = IGMP_GROUP_NON_MEMBER;
- group->last_reporter_flag = 0;
- group->use = 0;
- group->next = igmp_group_list;
-
- igmp_group_list = group;
- }
-
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
- ip_addr_debug_print(IGMP_DEBUG, addr);
- LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
-
- return group;
-}
-
-/**
- * Remove a group in the global igmp_group_list
- *
- * @param group the group to remove from the global igmp_group_list
- * @return ERR_OK if group was removed from the list, an err_t otherwise
- */
-static err_t
-igmp_remove_group(struct igmp_group *group)
-{
- err_t err = ERR_OK;
-
- /* Is it the first group? */
- if (igmp_group_list == group) {
- igmp_group_list = group->next;
- } else {
- /* look for group further down the list */
- struct igmp_group *tmpGroup;
- for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
- if (tmpGroup->next == group) {
- tmpGroup->next = group->next;
- break;
- }
- }
- /* Group not found in the global igmp_group_list */
- if (tmpGroup == NULL)
- err = ERR_ARG;
- }
- /* free group */
- memp_free(MEMP_IGMP_GROUP, group);
-
- return err;
-}
-
-/**
- * Called from ip_input() if a new IGMP packet is received.
- *
- * @param p received igmp packet, p->payload pointing to the ip header
- * @param inp network interface on which the packet was received
- * @param dest destination ip address of the igmp packet
- */
-void
-igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
-{
- struct ip_hdr * iphdr;
- struct igmp_msg* igmp;
- struct igmp_group* group;
- struct igmp_group* groupref;
-
- IGMP_STATS_INC(igmp.recv);
-
- /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
- iphdr = (struct ip_hdr *)p->payload;
- if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
- pbuf_free(p);
- IGMP_STATS_INC(igmp.lenerr);
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
- return;
- }
-
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
- ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
- LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
- ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
- LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
-
- /* Now calculate and check the checksum */
- igmp = (struct igmp_msg *)p->payload;
- if (inet_chksum(igmp, p->len)) {
- pbuf_free(p);
- IGMP_STATS_INC(igmp.chkerr);
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
- return;
- }
-
- /* Packet is ok so find an existing group */
- group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
-
- /* If group can be found or create... */
- if (!group) {
- pbuf_free(p);
- IGMP_STATS_INC(igmp.drop);
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
- return;
- }
-
- /* NOW ACT ON THE INCOMING MESSAGE TYPE... */
- switch (igmp->igmp_msgtype) {
- case IGMP_MEMB_QUERY: {
- /* IGMP_MEMB_QUERY to the "all systems" address ? */
- if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {
- /* THIS IS THE GENERAL QUERY */
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
-
- if (igmp->igmp_maxresp == 0) {
- IGMP_STATS_INC(igmp.rx_v1);
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
- igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
- } else {
- IGMP_STATS_INC(igmp.rx_general);
- }
-
- groupref = igmp_group_list;
- while (groupref) {
- /* Do not send messages on the all systems group address! */
- if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
- igmp_delaying_member(groupref, igmp->igmp_maxresp);
- }
- groupref = groupref->next;
- }
- } else {
- /* IGMP_MEMB_QUERY to a specific group ? */
- if (!ip_addr_isany(&igmp->igmp_group_address)) {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
- ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
- if (ip_addr_cmp(dest, &allsystems)) {
- ip_addr_t groupaddr;
- LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
- /* we first need to re-look for the group since we used dest last time */
- ip_addr_copy(groupaddr, igmp->igmp_group_address);
- group = igmp_lookfor_group(inp, &groupaddr);
- } else {
- LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
- }
-
- if (group != NULL) {
- IGMP_STATS_INC(igmp.rx_group);
- igmp_delaying_member(group, igmp->igmp_maxresp);
- } else {
- IGMP_STATS_INC(igmp.drop);
- }
- } else {
- IGMP_STATS_INC(igmp.proterr);
- }
- }
- break;
- }
- case IGMP_V2_MEMB_REPORT: {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
- IGMP_STATS_INC(igmp.rx_report);
- if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
- /* This is on a specific group we have already looked up */
- group->timer = 0; /* stopped */
- group->group_state = IGMP_GROUP_IDLE_MEMBER;
- group->last_reporter_flag = 0;
- }
- break;
- }
- default: {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
- igmp->igmp_msgtype, group->group_state, &group, group->netif));
- IGMP_STATS_INC(igmp.proterr);
- break;
- }
- }
-
- pbuf_free(p);
- return;
-}
-
-/**
- * Join a group on one network interface.
- *
- * @param ifaddr ip address of the network interface which should join a new group
- * @param groupaddr the ip address of the group which to join
- * @return ERR_OK if group was joined on the netif(s), an err_t otherwise
- */
-err_t
-igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
-{
- err_t err = ERR_VAL; /* no matching interface */
- struct igmp_group *group;
- struct netif *netif;
-
- /* make sure it is multicast address */
- LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
- LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
-
- /* loop through netif's */
- netif = netif_list;
- while (netif != NULL) {
- /* Should we join this interface ? */
- if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
- /* find group or create a new one if not found */
- group = igmp_lookup_group(netif, groupaddr);
-
- if (group != NULL) {
- /* This should create a new group, check the state to make sure */
- if (group->group_state != IGMP_GROUP_NON_MEMBER) {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
- } else {
- /* OK - it was new group */
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
- ip_addr_debug_print(IGMP_DEBUG, groupaddr);
- LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
-
- /* If first use of the group, allow the group at the MAC level */
- if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
- ip_addr_debug_print(IGMP_DEBUG, groupaddr);
- LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
- netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
- }
-
- IGMP_STATS_INC(igmp.tx_join);
- igmp_send(group, IGMP_V2_MEMB_REPORT);
-
- igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
-
- /* Need to work out where this timer comes from */
- group->group_state = IGMP_GROUP_DELAYING_MEMBER;
- }
- /* Increment group use */
- group->use++;
- /* Join on this interface */
- err = ERR_OK;
- } else {
- /* Return an error even if some network interfaces are joined */
- /** @todo undo any other netif already joined */
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
- return ERR_MEM;
- }
- }
- /* proceed to next network interface */
- netif = netif->next;
- }
-
- return err;
-}
-
-/**
- * Leave a group on one network interface.
- *
- * @param ifaddr ip address of the network interface which should leave a group
- * @param groupaddr the ip address of the group which to leave
- * @return ERR_OK if group was left on the netif(s), an err_t otherwise
- */
-err_t
-igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
-{
- err_t err = ERR_VAL; /* no matching interface */
- struct igmp_group *group;
- struct netif *netif;
-
- /* make sure it is multicast address */
- LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
- LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
-
- /* loop through netif's */
- netif = netif_list;
- while (netif != NULL) {
- /* Should we leave this interface ? */
- if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
- /* find group */
- group = igmp_lookfor_group(netif, groupaddr);
-
- if (group != NULL) {
- /* Only send a leave if the flag is set according to the state diagram */
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
- ip_addr_debug_print(IGMP_DEBUG, groupaddr);
- LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
-
- /* If there is no other use of the group */
- if (group->use <= 1) {
- /* If we are the last reporter for this group */
- if (group->last_reporter_flag) {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
- IGMP_STATS_INC(igmp.tx_leave);
- igmp_send(group, IGMP_LEAVE_GROUP);
- }
-
- /* Disable the group at the MAC level */
- if (netif->igmp_mac_filter != NULL) {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
- ip_addr_debug_print(IGMP_DEBUG, groupaddr);
- LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
- netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
- }
-
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
- ip_addr_debug_print(IGMP_DEBUG, groupaddr);
- LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
-
- /* Free the group */
- igmp_remove_group(group);
- } else {
- /* Decrement group use */
- group->use--;
- }
- /* Leave on this interface */
- err = ERR_OK;
- } else {
- /* It's not a fatal error on "leavegroup" */
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
- }
- }
- /* proceed to next network interface */
- netif = netif->next;
- }
-
- return err;
-}
-
-/**
- * The igmp timer function (both for NO_SYS=1 and =0)
- * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).
- */
-void
-igmp_tmr(void)
-{
- struct igmp_group *group = igmp_group_list;
-
- while (group != NULL) {
- if (group->timer > 0) {
- group->timer--;
- if (group->timer == 0) {
- igmp_timeout(group);
- }
- }
- group = group->next;
- }
-}
-
-/**
- * Called if a timeout for one group is reached.
- * Sends a report for this group.
- *
- * @param group an igmp_group for which a timeout is reached
- */
-static void
-igmp_timeout(struct igmp_group *group)
-{
- /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
- if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
- ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
- LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
-
- IGMP_STATS_INC(igmp.tx_report);
- igmp_send(group, IGMP_V2_MEMB_REPORT);
- }
-}
-
-/**
- * Start a timer for an igmp group
- *
- * @param group the igmp_group for which to start a timer
- * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
- * every call to igmp_tmr())
- */
-static void
-igmp_start_timer(struct igmp_group *group, u8_t max_time)
-{
- /* ensure the input value is > 0 */
- if (max_time == 0) {
- max_time = 1;
- }
- /* ensure the random value is > 0 */
- group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
-}
-
-
-/**
- * Delaying membership report for a group if necessary
- *
- * @param group the igmp_group for which "delaying" membership report
- * @param maxresp query delay
- */
-static void
-igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
-{
- if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
- ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
- ((group->timer == 0) || (maxresp < group->timer)))) {
- igmp_start_timer(group, maxresp);
- group->group_state = IGMP_GROUP_DELAYING_MEMBER;
- }
-}
-
-
-/**
- * Sends an IP packet on a network interface. This function constructs the IP header
- * and calculates the IP header checksum. If the source IP address is NULL,
- * the IP address of the outgoing network interface is filled in as source address.
- *
- * @param p the packet to send (p->payload points to the data, e.g. next
- protocol header; if dest == IP_HDRINCL, p already includes an IP
- header and p->payload points to that IP header)
- * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
- * IP address of the netif used to send is used as source address)
- * @param dest the destination IP address to send the packet to
- * @param ttl the TTL value to be set in the IP header
- * @param proto the PROTOCOL to be set in the IP header
- * @param netif the netif on which to send this packet
- * @return ERR_OK if the packet was sent OK
- * ERR_BUF if p doesn't have enough space for IP/LINK headers
- * returns errors returned by netif->output
- */
-static err_t
-igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)
-{
- /* This is the "router alert" option */
- u16_t ra[2];
- ra[0] = PP_HTONS(ROUTER_ALERT);
- ra[1] = 0x0000; /* Router shall examine packet */
- IGMP_STATS_INC(igmp.xmit);
- return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
-}
-
-/**
- * Send an igmp packet to a specific group.
- *
- * @param group the group to which to send the packet
- * @param type the type of igmp packet to send
- */
-static void
-igmp_send(struct igmp_group *group, u8_t type)
-{
- struct pbuf* p = NULL;
- struct igmp_msg* igmp = NULL;
- ip_addr_t src = *IP_ADDR_ANY;
- ip_addr_t* dest = NULL;
-
- /* IP header + "router alert" option + IGMP header */
- p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
-
- if (p) {
- igmp = (struct igmp_msg *)p->payload;
- LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
- (p->len >= sizeof(struct igmp_msg)));
- ip_addr_copy(src, group->netif->ip_addr);
-
- if (type == IGMP_V2_MEMB_REPORT) {
- dest = &(group->group_address);
- ip_addr_copy(igmp->igmp_group_address, group->group_address);
- group->last_reporter_flag = 1; /* Remember we were the last to report */
- } else {
- if (type == IGMP_LEAVE_GROUP) {
- dest = &allrouters;
- ip_addr_copy(igmp->igmp_group_address, group->group_address);
- }
- }
-
- if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
- igmp->igmp_msgtype = type;
- igmp->igmp_maxresp = 0;
- igmp->igmp_checksum = 0;
- igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
-
- igmp_ip_output_if(p, &src, dest, group->netif);
- }
-
- pbuf_free(p);
- } else {
- LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
- IGMP_STATS_INC(igmp.memerr);
- }
-}
-
-#endif /* LWIP_IGMP */
+++ /dev/null
-/**
- * @file
- * Functions common to all TCP/IPv4 modules, such as the byte order functions.
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-
-#include "lwip/inet.h"
-
+++ /dev/null
-/**
- * @file
- * Incluse internet checksum functions.
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-
-#include "lwip/inet_chksum.h"
-#include "lwip/def.h"
-
-#include <stddef.h>
-#include <string.h>
-
-/* These are some reference implementations of the checksum algorithm, with the
- * aim of being simple, correct and fully portable. Checksumming is the
- * first thing you would want to optimize for your platform. If you create
- * your own version, link it in and in your cc.h put:
- *
- * #define LWIP_CHKSUM <your_checksum_routine>
- *
- * Or you can select from the implementations below by defining
- * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
- */
-
-#ifndef LWIP_CHKSUM
-# define LWIP_CHKSUM lwip_standard_chksum
-# ifndef LWIP_CHKSUM_ALGORITHM
-# define LWIP_CHKSUM_ALGORITHM 2
-# endif
-#endif
-/* If none set: */
-#ifndef LWIP_CHKSUM_ALGORITHM
-# define LWIP_CHKSUM_ALGORITHM 0
-#endif
-
-#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
-/**
- * lwip checksum
- *
- * @param dataptr points to start of data to be summed at any boundary
- * @param len length of data to be summed
- * @return host order (!) lwip checksum (non-inverted Internet sum)
- *
- * @note accumulator size limits summable length to 64k
- * @note host endianess is irrelevant (p3 RFC1071)
- */
-static u16_t
-lwip_standard_chksum(void *dataptr, u16_t len)
-{
- u32_t acc;
- u16_t src;
- u8_t *octetptr;
-
- acc = 0;
- /* dataptr may be at odd or even addresses */
- octetptr = (u8_t*)dataptr;
- while (len > 1) {
- /* declare first octet as most significant
- thus assume network order, ignoring host order */
- src = (*octetptr) << 8;
- octetptr++;
- /* declare second octet as least significant */
- src |= (*octetptr);
- octetptr++;
- acc += src;
- len -= 2;
- }
- if (len > 0) {
- /* accumulate remaining octet */
- src = (*octetptr) << 8;
- acc += src;
- }
- /* add deferred carry bits */
- acc = (acc >> 16) + (acc & 0x0000ffffUL);
- if ((acc & 0xffff0000UL) != 0) {
- acc = (acc >> 16) + (acc & 0x0000ffffUL);
- }
- /* This maybe a little confusing: reorder sum using htons()
- instead of ntohs() since it has a little less call overhead.
- The caller must invert bits for Internet sum ! */
- return htons((u16_t)acc);
-}
-#endif
-
-#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
-/*
- * Curt McDowell
- * Broadcom Corp.
- * csm@broadcom.com
- *
- * IP checksum two bytes at a time with support for
- * unaligned buffer.
- * Works for len up to and including 0x20000.
- * by Curt McDowell, Broadcom Corp. 12/08/2005
- *
- * @param dataptr points to start of data to be summed at any boundary
- * @param len length of data to be summed
- * @return host order (!) lwip checksum (non-inverted Internet sum)
- */
-
-static u16_t
-lwip_standard_chksum(void *dataptr, int len)
-{
- u8_t *pb = (u8_t *)dataptr;
- u16_t *ps, t = 0;
- u32_t sum = 0;
- int odd = ((mem_ptr_t)pb & 1);
-
- /* Get aligned to u16_t */
- if (odd && len > 0) {
- ((u8_t *)&t)[1] = *pb++;
- len--;
- }
-
- /* Add the bulk of the data */
- ps = (u16_t *)(void *)pb;
- while (len > 1) {
- sum += *ps++;
- len -= 2;
- }
-
- /* Consume left-over byte, if any */
- if (len > 0) {
- ((u8_t *)&t)[0] = *(u8_t *)ps;
- }
-
- /* Add end bytes */
- sum += t;
-
- /* Fold 32-bit sum to 16 bits
- calling this twice is propably faster than if statements... */
- sum = FOLD_U32T(sum);
- sum = FOLD_U32T(sum);
-
- /* Swap if alignment was odd */
- if (odd) {
- sum = SWAP_BYTES_IN_WORD(sum);
- }
-
- return (u16_t)sum;
-}
-#endif
-
-#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
-/**
- * An optimized checksum routine. Basically, it uses loop-unrolling on
- * the checksum loop, treating the head and tail bytes specially, whereas
- * the inner loop acts on 8 bytes at a time.
- *
- * @arg start of buffer to be checksummed. May be an odd byte address.
- * @len number of bytes in the buffer to be checksummed.
- * @return host order (!) lwip checksum (non-inverted Internet sum)
- *
- * by Curt McDowell, Broadcom Corp. December 8th, 2005
- */
-
-static u16_t
-lwip_standard_chksum(void *dataptr, int len)
-{
- u8_t *pb = (u8_t *)dataptr;
- u16_t *ps, t = 0;
- u32_t *pl;
- u32_t sum = 0, tmp;
- /* starts at odd byte address? */
- int odd = ((mem_ptr_t)pb & 1);
-
- if (odd && len > 0) {
- ((u8_t *)&t)[1] = *pb++;
- len--;
- }
-
- ps = (u16_t *)pb;
-
- if (((mem_ptr_t)ps & 3) && len > 1) {
- sum += *ps++;
- len -= 2;
- }
-
- pl = (u32_t *)ps;
-
- while (len > 7) {
- tmp = sum + *pl++; /* ping */
- if (tmp < sum) {
- tmp++; /* add back carry */
- }
-
- sum = tmp + *pl++; /* pong */
- if (sum < tmp) {
- sum++; /* add back carry */
- }
-
- len -= 8;
- }
-
- /* make room in upper bits */
- sum = FOLD_U32T(sum);
-
- ps = (u16_t *)pl;
-
- /* 16-bit aligned word remaining? */
- while (len > 1) {
- sum += *ps++;
- len -= 2;
- }
-
- /* dangling tail byte remaining? */
- if (len > 0) { /* include odd byte */
- ((u8_t *)&t)[0] = *(u8_t *)ps;
- }
-
- sum += t; /* add end bytes */
-
- /* Fold 32-bit sum to 16 bits
- calling this twice is propably faster than if statements... */
- sum = FOLD_U32T(sum);
- sum = FOLD_U32T(sum);
-
- if (odd) {
- sum = SWAP_BYTES_IN_WORD(sum);
- }
-
- return (u16_t)sum;
-}
-#endif
-
-/* inet_chksum_pseudo:
- *
- * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
- * IP addresses are expected to be in network byte order.
- *
- * @param p chain of pbufs over that a checksum should be calculated (ip data part)
- * @param src source ip address (used for checksum of pseudo header)
- * @param dst destination ip address (used for checksum of pseudo header)
- * @param proto ip protocol (used for checksum of pseudo header)
- * @param proto_len length of the ip data part (used for checksum of pseudo header)
- * @return checksum (as u16_t) to be saved directly in the protocol header
- */
-u16_t
-inet_chksum_pseudo(struct pbuf *p,
- ip_addr_t *src, ip_addr_t *dest,
- u8_t proto, u16_t proto_len)
-{
- u32_t acc;
- u32_t addr;
- struct pbuf *q;
- u8_t swapped;
-
- acc = 0;
- swapped = 0;
- /* iterate through all pbuf in chain */
- for(q = p; q != NULL; q = q->next) {
- LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
- (void *)q, (void *)q->next));
- acc += LWIP_CHKSUM(q->payload, q->len);
- /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
- /* just executing this next line is probably faster that the if statement needed
- to check whether we really need to execute it, and does no harm */
- acc = FOLD_U32T(acc);
- if (q->len % 2 != 0) {
- swapped = 1 - swapped;
- acc = SWAP_BYTES_IN_WORD(acc);
- }
- /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
- }
-
- if (swapped) {
- acc = SWAP_BYTES_IN_WORD(acc);
- }
- addr = ip4_addr_get_u32(src);
- acc += (addr & 0xffffUL);
- acc += ((addr >> 16) & 0xffffUL);
- addr = ip4_addr_get_u32(dest);
- acc += (addr & 0xffffUL);
- acc += ((addr >> 16) & 0xffffUL);
- acc += (u32_t)htons((u16_t)proto);
- acc += (u32_t)htons(proto_len);
-
- /* Fold 32-bit sum to 16 bits
- calling this twice is propably faster than if statements... */
- acc = FOLD_U32T(acc);
- acc = FOLD_U32T(acc);
- LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
- return (u16_t)~(acc & 0xffffUL);
-}
-
-/* inet_chksum_pseudo:
- *
- * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
- * IP addresses are expected to be in network byte order.
- *
- * @param p chain of pbufs over that a checksum should be calculated (ip data part)
- * @param src source ip address (used for checksum of pseudo header)
- * @param dst destination ip address (used for checksum of pseudo header)
- * @param proto ip protocol (used for checksum of pseudo header)
- * @param proto_len length of the ip data part (used for checksum of pseudo header)
- * @return checksum (as u16_t) to be saved directly in the protocol header
- */
-u16_t
-inet_chksum_pseudo_partial(struct pbuf *p,
- ip_addr_t *src, ip_addr_t *dest,
- u8_t proto, u16_t proto_len, u16_t chksum_len)
-{
- u32_t acc;
- u32_t addr;
- struct pbuf *q;
- u8_t swapped;
- u16_t chklen;
-
- acc = 0;
- swapped = 0;
- /* iterate through all pbuf in chain */
- for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
- LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
- (void *)q, (void *)q->next));
- chklen = q->len;
- if (chklen > chksum_len) {
- chklen = chksum_len;
- }
- acc += LWIP_CHKSUM(q->payload, chklen);
- chksum_len -= chklen;
- LWIP_ASSERT("delete me", chksum_len < 0x7fff);
- /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
- /* fold the upper bit down */
- acc = FOLD_U32T(acc);
- if (q->len % 2 != 0) {
- swapped = 1 - swapped;
- acc = SWAP_BYTES_IN_WORD(acc);
- }
- /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
- }
-
- if (swapped) {
- acc = SWAP_BYTES_IN_WORD(acc);
- }
- addr = ip4_addr_get_u32(src);
- acc += (addr & 0xffffUL);
- acc += ((addr >> 16) & 0xffffUL);
- addr = ip4_addr_get_u32(dest);
- acc += (addr & 0xffffUL);
- acc += ((addr >> 16) & 0xffffUL);
- acc += (u32_t)htons((u16_t)proto);
- acc += (u32_t)htons(proto_len);
-
- /* Fold 32-bit sum to 16 bits
- calling this twice is propably faster than if statements... */
- acc = FOLD_U32T(acc);
- acc = FOLD_U32T(acc);
- LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
- return (u16_t)~(acc & 0xffffUL);
-}
-
-/* inet_chksum:
- *
- * Calculates the Internet checksum over a portion of memory. Used primarily for IP
- * and ICMP.
- *
- * @param dataptr start of the buffer to calculate the checksum (no alignment needed)
- * @param len length of the buffer to calculate the checksum
- * @return checksum (as u16_t) to be saved directly in the protocol header
- */
-
-u16_t
-inet_chksum(void *dataptr, u16_t len)
-{
- return ~LWIP_CHKSUM(dataptr, len);
-}
-
-/**
- * Calculate a checksum over a chain of pbufs (without pseudo-header, much like
- * inet_chksum only pbufs are used).
- *
- * @param p pbuf chain over that the checksum should be calculated
- * @return checksum (as u16_t) to be saved directly in the protocol header
- */
-u16_t
-inet_chksum_pbuf(struct pbuf *p)
-{
- u32_t acc;
- struct pbuf *q;
- u8_t swapped;
-
- acc = 0;
- swapped = 0;
- for(q = p; q != NULL; q = q->next) {
- acc += LWIP_CHKSUM(q->payload, q->len);
- acc = FOLD_U32T(acc);
- if (q->len % 2 != 0) {
- swapped = 1 - swapped;
- acc = SWAP_BYTES_IN_WORD(acc);
- }
- }
-
- if (swapped) {
- acc = SWAP_BYTES_IN_WORD(acc);
- }
- return (u16_t)~(acc & 0xffffUL);
-}
-
-/* These are some implementations for LWIP_CHKSUM_COPY, which copies data
- * like MEMCPY but generates a checksum at the same time. Since this is a
- * performance-sensitive function, you might want to create your own version
- * in assembly targeted at your hardware by defining it in lwipopts.h:
- * #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)
- */
-
-#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */
-/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM.
- * For architectures with big caches, data might still be in cache when
- * generating the checksum after copying.
- */
-u16_t
-lwip_chksum_copy(void *dst, const void *src, u16_t len)
-{
- MEMCPY(dst, src, len);
- return LWIP_CHKSUM(dst, len);
-}
-#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */
+++ /dev/null
-/**
- * @file
- * This is the IPv4 layer implementation for incoming and outgoing IP traffic.
- *
- * @see ip_frag.c
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-#include "lwip/ip.h"
-#include "lwip/def.h"
-#include "lwip/mem.h"
-#include "lwip/ip_frag.h"
-#include "lwip/inet_chksum.h"
-#include "lwip/netif.h"
-#include "lwip/icmp.h"
-#include "lwip/igmp.h"
-#include "lwip/raw.h"
-#include "lwip/udp.h"
-#include "lwip/tcp_impl.h"
-#include "lwip/snmp.h"
-#include "lwip/dhcp.h"
-#include "lwip/autoip.h"
-#include "lwip/stats.h"
-#include "arch/perf.h"
-
-#include <string.h>
-
-/** Set this to 0 in the rare case of wanting to call an extra function to
- * generate the IP checksum (in contrast to calculating it on-the-fly). */
-#ifndef LWIP_INLINE_IP_CHKSUM
-#define LWIP_INLINE_IP_CHKSUM 1
-#endif
-#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP
-#define CHECKSUM_GEN_IP_INLINE 1
-#else
-#define CHECKSUM_GEN_IP_INLINE 0
-#endif
-
-#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT)
-#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1
-
-/** Some defines for DHCP to let link-layer-addressed packets through while the
- * netif is down.
- * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT
- * to return 1 if the port is accepted and 0 if the port is not accepted.
- */
-#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT)
-/* accept DHCP client port and custom port */
-#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \
- || (LWIP_IP_ACCEPT_UDP_PORT(port)))
-#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
-/* accept custom port only */
-#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port))
-#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
-/* accept DHCP client port only */
-#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
-#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
-
-#else /* LWIP_DHCP */
-#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0
-#endif /* LWIP_DHCP */
-
-/**
- * The interface that provided the packet for the current callback
- * invocation.
- */
-struct netif *current_netif;
-
-/**
- * Header of the input packet currently being processed.
- */
-const struct ip_hdr *current_header;
-/** Source IP address of current_header */
-ip_addr_t current_iphdr_src;
-/** Destination IP address of current_header */
-ip_addr_t current_iphdr_dest;
-
-/** The IP header ID of the next outgoing IP packet */
-static u16_t ip_id;
-
-/**
- * Finds the appropriate network interface for a given IP address. It
- * searches the list of network interfaces linearly. A match is found
- * if the masked IP address of the network interface equals the masked
- * IP address given to the function.
- *
- * @param dest the destination IP address for which to find the route
- * @return the netif on which to send to reach dest
- */
-struct netif *
-ip_route(ip_addr_t *dest)
-{
- struct netif *netif;
-
- /* iterate through netifs */
- for(netif = netif_list; netif != NULL; netif = netif->next) {
- /* network mask matches? */
- if (netif_is_up(netif)) {
- if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
- /* return netif on which to forward IP packet */
- return netif;
- }
- }
- }
- if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
- IP_STATS_INC(ip.rterr);
- snmp_inc_ipoutnoroutes();
- return NULL;
- }
- /* no matching netif found, use default netif */
- return netif_default;
-}
-
-#if IP_FORWARD
-/**
- * Forwards an IP packet. It finds an appropriate route for the
- * packet, decrements the TTL value of the packet, adjusts the
- * checksum and outputs the packet on the appropriate interface.
- *
- * @param p the packet to forward (p->payload points to IP header)
- * @param iphdr the IP header of the input packet
- * @param inp the netif on which this packet was received
- */
-static void
-ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
-{
- struct netif *netif;
-
- PERF_START;
-
- /* RFC3927 2.7: do not forward link-local addresses */
- if (ip_addr_islinklocal(¤t_iphdr_dest)) {
- LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest),
- ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest)));
- goto return_noroute;
- }
-
- /* Find network interface where to forward this IP packet to. */
- netif = ip_route(¤t_iphdr_dest);
- if (netif == NULL) {
- LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n",
- ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest),
- ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest)));
- goto return_noroute;
- }
- /* Do not forward packets onto the same network interface on which
- * they arrived. */
- if (netif == inp) {
- LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
- goto return_noroute;
- }
-
- /* decrement TTL */
- IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
- /* send ICMP if TTL == 0 */
- if (IPH_TTL(iphdr) == 0) {
- snmp_inc_ipinhdrerrors();
-#if LWIP_ICMP
- /* Don't send ICMP messages in response to ICMP messages */
- if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
- icmp_time_exceeded(p, ICMP_TE_TTL);
- }
-#endif /* LWIP_ICMP */
- return;
- }
-
- /* Incrementally update the IP checksum. */
- if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) {
- IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
- } else {
- IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
- }
-
- LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest),
- ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest)));
-
- IP_STATS_INC(ip.fw);
- IP_STATS_INC(ip.xmit);
- snmp_inc_ipforwdatagrams();
-
- PERF_STOP("ip_forward");
- /* transmit pbuf on chosen interface */
- netif->output(netif, p, ¤t_iphdr_dest);
- return;
-return_noroute:
- snmp_inc_ipoutnoroutes();
-}
-#endif /* IP_FORWARD */
-
-/**
- * This function is called by the network interface device driver when
- * an IP packet is received. The function does the basic checks of the
- * IP header such as packet size being at least larger than the header
- * size etc. If the packet was not destined for us, the packet is
- * forwarded (using ip_forward). The IP checksum is always checked.
- *
- * Finally, the packet is sent to the upper layer protocol input function.
- *
- * @param p the received IP packet (p->payload points to IP header)
- * @param inp the netif on which this packet was received
- * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
- * processed, but currently always returns ERR_OK)
- */
-err_t
-ip_input(struct pbuf *p, struct netif *inp)
-{
- struct ip_hdr *iphdr;
- struct netif *netif;
- u16_t iphdr_hlen;
- u16_t iphdr_len;
-#if IP_ACCEPT_LINK_LAYER_ADDRESSING
- int check_ip_src=1;
-#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
-
- IP_STATS_INC(ip.recv);
- snmp_inc_ipinreceives();
-
- /* identify the IP header */
- iphdr = (struct ip_hdr *)p->payload;
- if (IPH_V(iphdr) != 4) {
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
- ip_debug_print(p);
- pbuf_free(p);
- IP_STATS_INC(ip.err);
- IP_STATS_INC(ip.drop);
- snmp_inc_ipinhdrerrors();
- return ERR_OK;
- }
-
- /* obtain IP header length in number of 32-bit words */
- iphdr_hlen = IPH_HL(iphdr);
- /* calculate IP header length in bytes */
- iphdr_hlen *= 4;
- /* obtain ip length in bytes */
- iphdr_len = ntohs(IPH_LEN(iphdr));
-
- /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
- if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
- if (iphdr_hlen > p->len) {
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
- ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
- iphdr_hlen, p->len));
- }
- if (iphdr_len > p->tot_len) {
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
- ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
- iphdr_len, p->tot_len));
- }
- /* free (drop) packet pbufs */
- pbuf_free(p);
- IP_STATS_INC(ip.lenerr);
- IP_STATS_INC(ip.drop);
- snmp_inc_ipindiscards();
- return ERR_OK;
- }
-
- /* verify checksum */
-#if CHECKSUM_CHECK_IP
- if (inet_chksum(iphdr, iphdr_hlen) != 0) {
-
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
- ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
- ip_debug_print(p);
- pbuf_free(p);
- IP_STATS_INC(ip.chkerr);
- IP_STATS_INC(ip.drop);
- snmp_inc_ipinhdrerrors();
- return ERR_OK;
- }
-#endif
-
- /* Trim pbuf. This should have been done at the netif layer,
- * but we'll do it anyway just to be sure that its done. */
- pbuf_realloc(p, iphdr_len);
-
- /* copy IP addresses to aligned ip_addr_t */
- ip_addr_copy(current_iphdr_dest, iphdr->dest);
- ip_addr_copy(current_iphdr_src, iphdr->src);
-
- /* match packet against an interface, i.e. is this packet for us? */
-#if LWIP_IGMP
- if (ip_addr_ismulticast(¤t_iphdr_dest)) {
- if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ¤t_iphdr_dest))) {
- netif = inp;
- } else {
- netif = NULL;
- }
- } else
-#endif /* LWIP_IGMP */
- {
- /* start trying with inp. if that's not acceptable, start walking the
- list of configured netifs.
- 'first' is used as a boolean to mark whether we started walking the list */
- int first = 1;
- netif = inp;
- do {
- LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
- ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr),
- ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask),
- ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask),
- ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask)));
-
- /* interface is up and configured? */
- if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
- /* unicast to this interface address? */
- if (ip_addr_cmp(¤t_iphdr_dest, &(netif->ip_addr)) ||
- /* or broadcast on this interface network address? */
- ip_addr_isbroadcast(¤t_iphdr_dest, netif)) {
- LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
- netif->name[0], netif->name[1]));
- /* break out of for loop */
- break;
- }
-#if LWIP_AUTOIP
- /* connections to link-local addresses must persist after changing
- the netif's address (RFC3927 ch. 1.9) */
- if ((netif->autoip != NULL) &&
- ip_addr_cmp(¤t_iphdr_dest, &(netif->autoip->llipaddr))) {
- LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n",
- netif->name[0], netif->name[1]));
- /* break out of for loop */
- break;
- }
-#endif /* LWIP_AUTOIP */
- }
- if (first) {
- first = 0;
- netif = netif_list;
- } else {
- netif = netif->next;
- }
- if (netif == inp) {
- netif = netif->next;
- }
- } while(netif != NULL);
- }
-
-#if IP_ACCEPT_LINK_LAYER_ADDRESSING
- /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
- * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
- * According to RFC 1542 section 3.1.1, referred by RFC 2131).
- *
- * If you want to accept private broadcast communication while a netif is down,
- * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.:
- *
- * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))
- */
- if (netif == NULL) {
- /* remote port is DHCP server? */
- if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
- struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen);
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
- ntohs(udphdr->dest)));
- if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
- netif = inp;
- check_ip_src = 0;
- }
- }
- }
-#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
-
- /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
-#if IP_ACCEPT_LINK_LAYER_ADDRESSING
- /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
- if (check_ip_src && !ip_addr_isany(¤t_iphdr_src))
-#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
- { if ((ip_addr_isbroadcast(¤t_iphdr_src, inp)) ||
- (ip_addr_ismulticast(¤t_iphdr_src))) {
- /* packet source is not valid */
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
- /* free (drop) packet pbufs */
- pbuf_free(p);
- IP_STATS_INC(ip.drop);
- snmp_inc_ipinaddrerrors();
- snmp_inc_ipindiscards();
- return ERR_OK;
- }
- }
-
- /* packet not for us? */
- if (netif == NULL) {
- /* packet not for us, route or discard */
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
-#if IP_FORWARD
- /* non-broadcast packet? */
- if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp)) {
- /* try to forward IP packet on (other) interfaces */
- ip_forward(p, iphdr, inp);
- } else
-#endif /* IP_FORWARD */
- {
- snmp_inc_ipinaddrerrors();
- snmp_inc_ipindiscards();
- }
- pbuf_free(p);
- return ERR_OK;
- }
- /* packet consists of multiple fragments? */
- if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
-#if IP_REASSEMBLY /* packet fragment reassembly code present? */
- LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
- ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
- /* reassemble the packet*/
- p = ip_reass(p);
- /* packet not fully reassembled yet? */
- if (p == NULL) {
- return ERR_OK;
- }
- iphdr = (struct ip_hdr *)p->payload;
-#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
- pbuf_free(p);
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
- ntohs(IPH_OFFSET(iphdr))));
- IP_STATS_INC(ip.opterr);
- IP_STATS_INC(ip.drop);
- /* unsupported protocol feature */
- snmp_inc_ipinunknownprotos();
- return ERR_OK;
-#endif /* IP_REASSEMBLY */
- }
-
-#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */
-
-#if LWIP_IGMP
- /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
- if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
-#else
- if (iphdr_hlen > IP_HLEN) {
-#endif /* LWIP_IGMP */
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
- pbuf_free(p);
- IP_STATS_INC(ip.opterr);
- IP_STATS_INC(ip.drop);
- /* unsupported protocol feature */
- snmp_inc_ipinunknownprotos();
- return ERR_OK;
- }
-#endif /* IP_OPTIONS_ALLOWED == 0 */
-
- /* send to upper layers */
- LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
- ip_debug_print(p);
- LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
-
- current_netif = inp;
- current_header = iphdr;
-
-#if LWIP_RAW
- /* raw input did not eat the packet? */
- if (raw_input(p, inp) == 0)
-#endif /* LWIP_RAW */
- {
-
- switch (IPH_PROTO(iphdr)) {
-#if LWIP_UDP
- case IP_PROTO_UDP:
-#if LWIP_UDPLITE
- case IP_PROTO_UDPLITE:
-#endif /* LWIP_UDPLITE */
- snmp_inc_ipindelivers();
- udp_input(p, inp);
- break;
-#endif /* LWIP_UDP */
-#if LWIP_TCP
- case IP_PROTO_TCP:
- snmp_inc_ipindelivers();
- tcp_input(p, inp);
- break;
-#endif /* LWIP_TCP */
-#if LWIP_ICMP
- case IP_PROTO_ICMP:
- snmp_inc_ipindelivers();
- icmp_input(p, inp);
- break;
-#endif /* LWIP_ICMP */
-#if LWIP_IGMP
- case IP_PROTO_IGMP:
- igmp_input(p, inp, ¤t_iphdr_dest);
- break;
-#endif /* LWIP_IGMP */
- default:
-#if LWIP_ICMP
- /* send ICMP destination protocol unreachable unless is was a broadcast */
- if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp) &&
- !ip_addr_ismulticast(¤t_iphdr_dest)) {
- p->payload = iphdr;
- icmp_dest_unreach(p, ICMP_DUR_PROTO);
- }
-#endif /* LWIP_ICMP */
- pbuf_free(p);
-
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
-
- IP_STATS_INC(ip.proterr);
- IP_STATS_INC(ip.drop);
- snmp_inc_ipinunknownprotos();
- }
- }
-
- current_netif = NULL;
- current_header = NULL;
- ip_addr_set_any(¤t_iphdr_src);
- ip_addr_set_any(¤t_iphdr_dest);
-
- return ERR_OK;
-}
-
-/**
- * Sends an IP packet on a network interface. This function constructs
- * the IP header and calculates the IP header checksum. If the source
- * IP address is NULL, the IP address of the outgoing network
- * interface is filled in as source address.
- * If the destination IP address is IP_HDRINCL, p is assumed to already
- * include an IP header and p->payload points to it instead of the data.
- *
- * @param p the packet to send (p->payload points to the data, e.g. next
- protocol header; if dest == IP_HDRINCL, p already includes an IP
- header and p->payload points to that IP header)
- * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
- * IP address of the netif used to send is used as source address)
- * @param dest the destination IP address to send the packet to
- * @param ttl the TTL value to be set in the IP header
- * @param tos the TOS value to be set in the IP header
- * @param proto the PROTOCOL to be set in the IP header
- * @param netif the netif on which to send this packet
- * @return ERR_OK if the packet was sent OK
- * ERR_BUF if p doesn't have enough space for IP/LINK headers
- * returns errors returned by netif->output
- *
- * @note ip_id: RFC791 "some host may be able to simply use
- * unique identifiers independent of destination"
- */
-err_t
-ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
- u8_t ttl, u8_t tos,
- u8_t proto, struct netif *netif)
-{
-#if IP_OPTIONS_SEND
- return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
-}
-
-/**
- * Same as ip_output_if() but with the possibility to include IP options:
- *
- * @ param ip_options pointer to the IP options, copied into the IP header
- * @ param optlen length of ip_options
- */
-err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
- u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
- u16_t optlen)
-{
-#endif /* IP_OPTIONS_SEND */
- struct ip_hdr *iphdr;
- ip_addr_t dest_addr;
-#if CHECKSUM_GEN_IP_INLINE
- u32_t chk_sum = 0;
-#endif /* CHECKSUM_GEN_IP_INLINE */
-
- /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
- gets altered as the packet is passed down the stack */
- LWIP_ASSERT("p->ref == 1", p->ref == 1);
-
- snmp_inc_ipoutrequests();
-
- /* Should the IP header be generated or is it already included in p? */
- if (dest != IP_HDRINCL) {
- u16_t ip_hlen = IP_HLEN;
-#if IP_OPTIONS_SEND
- u16_t optlen_aligned = 0;
- if (optlen != 0) {
-#if CHECKSUM_GEN_IP_INLINE
- int i;
-#endif /* CHECKSUM_GEN_IP_INLINE */
- /* round up to a multiple of 4 */
- optlen_aligned = ((optlen + 3) & ~3);
- ip_hlen += optlen_aligned;
- /* First write in the IP options */
- if (pbuf_header(p, optlen_aligned)) {
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
- IP_STATS_INC(ip.err);
- snmp_inc_ipoutdiscards();
- return ERR_BUF;
- }
- MEMCPY(p->payload, ip_options, optlen);
- if (optlen < optlen_aligned) {
- /* zero the remaining bytes */
- memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
- }
-#if CHECKSUM_GEN_IP_INLINE
- for (i = 0; i < optlen_aligned/2; i++) {
- chk_sum += ((u16_t*)p->payload)[i];
- }
-#endif /* CHECKSUM_GEN_IP_INLINE */
- }
-#endif /* IP_OPTIONS_SEND */
- /* generate IP header */
- if (pbuf_header(p, IP_HLEN)) {
- LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
-
- IP_STATS_INC(ip.err);
- snmp_inc_ipoutdiscards();
- return ERR_BUF;
- }
-
- iphdr = (struct ip_hdr *)p->payload;
- LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
- (p->len >= sizeof(struct ip_hdr)));
-
- IPH_TTL_SET(iphdr, ttl);
- IPH_PROTO_SET(iphdr, proto);
-#if CHECKSUM_GEN_IP_INLINE
- chk_sum += LWIP_MAKE_U16(proto, ttl);
-#endif /* CHECKSUM_GEN_IP_INLINE */
-
- /* dest cannot be NULL here */
- ip_addr_copy(iphdr->dest, *dest);
-#if CHECKSUM_GEN_IP_INLINE
- chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF;
- chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
-#endif /* CHECKSUM_GEN_IP_INLINE */
-
- IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
-#if CHECKSUM_GEN_IP_INLINE
- chk_sum += iphdr->_v_hl_tos;
-#endif /* CHECKSUM_GEN_IP_INLINE */
- IPH_LEN_SET(iphdr, htons(p->tot_len));
-#if CHECKSUM_GEN_IP_INLINE
- chk_sum += iphdr->_len;
-#endif /* CHECKSUM_GEN_IP_INLINE */
- IPH_OFFSET_SET(iphdr, 0);
- IPH_ID_SET(iphdr, htons(ip_id));
-#if CHECKSUM_GEN_IP_INLINE
- chk_sum += iphdr->_id;
-#endif /* CHECKSUM_GEN_IP_INLINE */
- ++ip_id;
-
- if (ip_addr_isany(src)) {
- ip_addr_copy(iphdr->src, netif->ip_addr);
- } else {
- /* src cannot be NULL here */
- ip_addr_copy(iphdr->src, *src);
- }
-
-#if CHECKSUM_GEN_IP_INLINE
- chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF;
- chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16;
- chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF);
- chk_sum = (chk_sum >> 16) + chk_sum;
- chk_sum = ~chk_sum;
- iphdr->_chksum = chk_sum; /* network order */
-#else /* CHECKSUM_GEN_IP_INLINE */
- IPH_CHKSUM_SET(iphdr, 0);
-#if CHECKSUM_GEN_IP
- IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
-#endif
-#endif /* CHECKSUM_GEN_IP_INLINE */
- } else {
- /* IP header already included in p */
- iphdr = (struct ip_hdr *)p->payload;
- ip_addr_copy(dest_addr, iphdr->dest);
- dest = &dest_addr;
- }
-
- IP_STATS_INC(ip.xmit);
-
- LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
- ip_debug_print(p);
-
-#if ENABLE_LOOPBACK
- if (ip_addr_cmp(dest, &netif->ip_addr)) {
- /* Packet to self, enqueue it for loopback */
- LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
- return netif_loop_output(netif, p, dest);
- }
-#if LWIP_IGMP
- if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {
- netif_loop_output(netif, p, dest);
- }
-#endif /* LWIP_IGMP */
-#endif /* ENABLE_LOOPBACK */
-#if IP_FRAG
- /* don't fragment if interface has mtu set to 0 [loopif] */
- if (netif->mtu && (p->tot_len > netif->mtu)) {
- return ip_frag(p, netif, dest);
- }
-#endif /* IP_FRAG */
-
- LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
- return netif->output(netif, p, dest);
-}
-
-/**
- * Simple interface to ip_output_if. It finds the outgoing network
- * interface and calls upon ip_output_if to do the actual work.
- *
- * @param p the packet to send (p->payload points to the data, e.g. next
- protocol header; if dest == IP_HDRINCL, p already includes an IP
- header and p->payload points to that IP header)
- * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
- * IP address of the netif used to send is used as source address)
- * @param dest the destination IP address to send the packet to
- * @param ttl the TTL value to be set in the IP header
- * @param tos the TOS value to be set in the IP header
- * @param proto the PROTOCOL to be set in the IP header
- *
- * @return ERR_RTE if no route is found
- * see ip_output_if() for more return values
- */
-err_t
-ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
- u8_t ttl, u8_t tos, u8_t proto)
-{
- struct netif *netif;
-
- /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
- gets altered as the packet is passed down the stack */
- LWIP_ASSERT("p->ref == 1", p->ref == 1);
-
- if ((netif = ip_route(dest)) == NULL) {
- LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
- IP_STATS_INC(ip.rterr);
- return ERR_RTE;
- }
-
- return ip_output_if(p, src, dest, ttl, tos, proto, netif);
-}
-
-#if LWIP_NETIF_HWADDRHINT
-/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
- * before calling ip_output_if.
- *
- * @param p the packet to send (p->payload points to the data, e.g. next
- protocol header; if dest == IP_HDRINCL, p already includes an IP
- header and p->payload points to that IP header)
- * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
- * IP address of the netif used to send is used as source address)
- * @param dest the destination IP address to send the packet to
- * @param ttl the TTL value to be set in the IP header
- * @param tos the TOS value to be set in the IP header
- * @param proto the PROTOCOL to be set in the IP header
- * @param addr_hint address hint pointer set to netif->addr_hint before
- * calling ip_output_if()
- *
- * @return ERR_RTE if no route is found
- * see ip_output_if() for more return values
- */
-err_t
-ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
- u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
-{
- struct netif *netif;
- err_t err;
-
- /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
- gets altered as the packet is passed down the stack */
- LWIP_ASSERT("p->ref == 1", p->ref == 1);
-
- if ((netif = ip_route(dest)) == NULL) {
- LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
- IP_STATS_INC(ip.rterr);
- return ERR_RTE;
- }
-
- netif->addr_hint = addr_hint;
- err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
- netif->addr_hint = NULL;
-
- return err;
-}
-#endif /* LWIP_NETIF_HWADDRHINT*/
-
-#if IP_DEBUG
-/* Print an IP header by using LWIP_DEBUGF
- * @param p an IP packet, p->payload pointing to the IP header
- */
-void
-ip_debug_print(struct pbuf *p)
-{
- struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
- u8_t *payload;
-
- payload = (u8_t *)iphdr + IP_HLEN;
-
- LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
- LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n",
- IPH_V(iphdr),
- IPH_HL(iphdr),
- IPH_TOS(iphdr),
- ntohs(IPH_LEN(iphdr))));
- LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n",
- ntohs(IPH_ID(iphdr)),
- ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
- ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
- ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
- ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
- LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n",
- IPH_TTL(iphdr),
- IPH_PROTO(iphdr),
- ntohs(IPH_CHKSUM(iphdr))));
- LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n",
- ip4_addr1_16(&iphdr->src),
- ip4_addr2_16(&iphdr->src),
- ip4_addr3_16(&iphdr->src),
- ip4_addr4_16(&iphdr->src)));
- LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n",
- ip4_addr1_16(&iphdr->dest),
- ip4_addr2_16(&iphdr->dest),
- ip4_addr3_16(&iphdr->dest),
- ip4_addr4_16(&iphdr->dest)));
- LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
-}
-#endif /* IP_DEBUG */
+++ /dev/null
-/**
- * @file
- * This is the IPv4 address tools implementation.
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-
-/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
-const ip_addr_t ip_addr_any = { IPADDR_ANY };
-const ip_addr_t ip_addr_broadcast = { IPADDR_BROADCAST };
-
-/**
- * Determine if an address is a broadcast address on a network interface
- *
- * @param addr address to be checked
- * @param netif the network interface against which the address is checked
- * @return returns non-zero if the address is a broadcast address
- */
-u8_t
-ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
-{
- ip_addr_t ipaddr;
- ip4_addr_set_u32(&ipaddr, addr);
-
- /* all ones (broadcast) or all zeroes (old skool broadcast) */
- if ((~addr == IPADDR_ANY) ||
- (addr == IPADDR_ANY)) {
- return 1;
- /* no broadcast support on this network interface? */
- } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) {
- /* the given address cannot be a broadcast address
- * nor can we check against any broadcast addresses */
- return 0;
- /* address matches network interface address exactly? => no broadcast */
- } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {
- return 0;
- /* on the same (sub) network... */
- } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
- /* ...and host identifier bits are all ones? =>... */
- && ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
- (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
- /* => network broadcast address */
- return 1;
- } else {
- return 0;
- }
-}
-
-/** Checks if a netmask is valid (starting with ones, then only zeros)
- *
- * @param netmask the IPv4 netmask to check (in network byte order!)
- * @return 1 if the netmask is valid, 0 if it is not
- */
-u8_t
-ip4_addr_netmask_valid(u32_t netmask)
-{
- u32_t mask;
- u32_t nm_hostorder = lwip_htonl(netmask);
-
- /* first, check for the first zero */
- for (mask = 1UL << 31 ; mask != 0; mask >>= 1) {
- if ((nm_hostorder & mask) == 0) {
- break;
- }
- }
- /* then check that there is no one */
- for (; mask != 0; mask >>= 1) {
- if ((nm_hostorder & mask) != 0) {
- /* there is a one after the first zero -> invalid */
- return 0;
- }
- }
- /* no one after the first zero -> valid */
- return 1;
-}
-
-/* Here for now until needed in other places in lwIP */
-#ifndef isprint
-#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
-#define isprint(c) in_range(c, 0x20, 0x7f)
-#define isdigit(c) in_range(c, '0', '9')
-#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
-#define islower(c) in_range(c, 'a', 'z')
-#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
-#endif
-
-/**
- * Ascii internet address interpretation routine.
- * The value returned is in network order.
- *
- * @param cp IP address in ascii represenation (e.g. "127.0.0.1")
- * @return ip address in network order
- */
-u32_t
-ipaddr_addr(const char *cp)
-{
- ip_addr_t val;
-
- if (ipaddr_aton(cp, &val)) {
- return ip4_addr_get_u32(&val);
- }
- return (IPADDR_NONE);
-}
-
-/**
- * Check whether "cp" is a valid ascii representation
- * of an Internet address and convert to a binary address.
- * Returns 1 if the address is valid, 0 if not.
- * This replaces inet_addr, the return value from which
- * cannot distinguish between failure and a local broadcast address.
- *
- * @param cp IP address in ascii represenation (e.g. "127.0.0.1")
- * @param addr pointer to which to save the ip address in network order
- * @return 1 if cp could be converted to addr, 0 on failure
- */
-int
-ipaddr_aton(const char *cp, ip_addr_t *addr)
-{
- u32_t val;
- u8_t base;
- char c;
- u32_t parts[4];
- u32_t *pp = parts;
-
- c = *cp;
- for (;;) {
- /*
- * Collect number up to ``.''.
- * Values are specified as for C:
- * 0x=hex, 0=octal, 1-9=decimal.
- */
- if (!isdigit(c))
- return (0);
- val = 0;
- base = 10;
- if (c == '0') {
- c = *++cp;
- if (c == 'x' || c == 'X') {
- base = 16;
- c = *++cp;
- } else
- base = 8;
- }
- for (;;) {
- if (isdigit(c)) {
- val = (val * base) + (int)(c - '0');
- c = *++cp;
- } else if (base == 16 && isxdigit(c)) {
- val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
- c = *++cp;
- } else
- break;
- }
- if (c == '.') {
- /*
- * Internet format:
- * a.b.c.d
- * a.b.c (with c treated as 16 bits)
- * a.b (with b treated as 24 bits)
- */
- if (pp >= parts + 3) {
- return (0);
- }
- *pp++ = val;
- c = *++cp;
- } else
- break;
- }
- /*
- * Check for trailing characters.
- */
- if (c != '\0' && !isspace(c)) {
- return (0);
- }
- /*
- * Concoct the address according to
- * the number of parts specified.
- */
- switch (pp - parts + 1) {
-
- case 0:
- return (0); /* initial nondigit */
-
- case 1: /* a -- 32 bits */
- break;
-
- case 2: /* a.b -- 8.24 bits */
- if (val > 0xffffffUL) {
- return (0);
- }
- val |= parts[0] << 24;
- break;
-
- case 3: /* a.b.c -- 8.8.16 bits */
- if (val > 0xffff) {
- return (0);
- }
- val |= (parts[0] << 24) | (parts[1] << 16);
- break;
-
- case 4: /* a.b.c.d -- 8.8.8.8 bits */
- if (val > 0xff) {
- return (0);
- }
- val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
- break;
- default:
- LWIP_ASSERT("unhandled", 0);
- break;
- }
- if (addr) {
- ip4_addr_set_u32(addr, htonl(val));
- }
- return (1);
-}
-
-/**
- * Convert numeric IP address into decimal dotted ASCII representation.
- * returns ptr to static buffer; not reentrant!
- *
- * @param addr ip address in network order to convert
- * @return pointer to a global static (!) buffer that holds the ASCII
- * represenation of addr
- */
-char *
-ipaddr_ntoa(const ip_addr_t *addr)
-{
- static char str[16];
- return ipaddr_ntoa_r(addr, str, 16);
-}
-
-/**
- * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
- *
- * @param addr ip address in network order to convert
- * @param buf target buffer where the string is stored
- * @param buflen length of buf
- * @return either pointer to buf which now holds the ASCII
- * representation of addr or NULL if buf was too small
- */
-char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
-{
- u32_t s_addr;
- char inv[3];
- char *rp;
- u8_t *ap;
- u8_t rem;
- u8_t n;
- u8_t i;
- int len = 0;
-
- s_addr = ip4_addr_get_u32(addr);
-
- rp = buf;
- ap = (u8_t *)&s_addr;
- for(n = 0; n < 4; n++) {
- i = 0;
- do {
- rem = *ap % (u8_t)10;
- *ap /= (u8_t)10;
- inv[i++] = '0' + rem;
- } while(*ap);
- while(i--) {
- if (len++ >= buflen) {
- return NULL;
- }
- *rp++ = inv[i];
- }
- if (len++ >= buflen) {
- return NULL;
- }
- *rp++ = '.';
- ap++;
- }
- *--rp = 0;
- return buf;
-}
+++ /dev/null
-/**
- * @file
- * This is the IPv4 packet segmentation and reassembly implementation.
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Jani Monoses <jani@iv.ro>
- * Simon Goldschmidt
- * original reassembly code by Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-#include "lwip/ip_frag.h"
-#include "lwip/def.h"
-#include "lwip/inet_chksum.h"
-#include "lwip/netif.h"
-#include "lwip/snmp.h"
-#include "lwip/stats.h"
-#include "lwip/icmp.h"
-
-#include <string.h>
-
-#if IP_REASSEMBLY
-/**
- * The IP reassembly code currently has the following limitations:
- * - IP header options are not supported
- * - fragments must not overlap (e.g. due to different routes),
- * currently, overlapping or duplicate fragments are thrown away
- * if IP_REASS_CHECK_OVERLAP=1 (the default)!
- *
- * @todo: work with IP header options
- */
-
-/** Setting this to 0, you can turn off checking the fragments for overlapping
- * regions. The code gets a little smaller. Only use this if you know that
- * overlapping won't occur on your network! */
-#ifndef IP_REASS_CHECK_OVERLAP
-#define IP_REASS_CHECK_OVERLAP 1
-#endif /* IP_REASS_CHECK_OVERLAP */
-
-/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
- * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
- * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
- * is set to 1, so one datagram can be reassembled at a time, only. */
-#ifndef IP_REASS_FREE_OLDEST
-#define IP_REASS_FREE_OLDEST 1
-#endif /* IP_REASS_FREE_OLDEST */
-
-#define IP_REASS_FLAG_LASTFRAG 0x01
-
-/** This is a helper struct which holds the starting
- * offset and the ending offset of this fragment to
- * easily chain the fragments.
- * It has the same packing requirements as the IP header, since it replaces
- * the IP header in memory in incoming fragments (after copying it) to keep
- * track of the various fragments. (-> If the IP header doesn't need packing,
- * this struct doesn't need packing, too.)
- */
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-struct ip_reass_helper {
- PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
- PACK_STRUCT_FIELD(u16_t start);
- PACK_STRUCT_FIELD(u16_t end);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
- (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
- ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
- IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
-
-/* global variables */
-static struct ip_reassdata *reassdatagrams;
-static u16_t ip_reass_pbufcount;
-
-/* function prototypes */
-static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
-static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
-
-/**
- * Reassembly timer base function
- * for both NO_SYS == 0 and 1 (!).
- *
- * Should be called every 1000 msec (defined by IP_TMR_INTERVAL).
- */
-void
-ip_reass_tmr(void)
-{
- struct ip_reassdata *r, *prev = NULL;
-
- r = reassdatagrams;
- while (r != NULL) {
- /* Decrement the timer. Once it reaches 0,
- * clean up the incomplete fragment assembly */
- if (r->timer > 0) {
- r->timer--;
- LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer));
- prev = r;
- r = r->next;
- } else {
- /* reassembly timed out */
- struct ip_reassdata *tmp;
- LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n"));
- tmp = r;
- /* get the next pointer before freeing */
- r = r->next;
- /* free the helper struct and all enqueued pbufs */
- ip_reass_free_complete_datagram(tmp, prev);
- }
- }
-}
-
-/**
- * Free a datagram (struct ip_reassdata) and all its pbufs.
- * Updates the total count of enqueued pbufs (ip_reass_pbufcount),
- * SNMP counters and sends an ICMP time exceeded packet.
- *
- * @param ipr datagram to free
- * @param prev the previous datagram in the linked list
- * @return the number of pbufs freed
- */
-static int
-ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
-{
- u16_t pbufs_freed = 0;
- u8_t clen;
- struct pbuf *p;
- struct ip_reass_helper *iprh;
-
- LWIP_ASSERT("prev != ipr", prev != ipr);
- if (prev != NULL) {
- LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
- }
-
- snmp_inc_ipreasmfails();
-#if LWIP_ICMP
- iprh = (struct ip_reass_helper *)ipr->p->payload;
- if (iprh->start == 0) {
- /* The first fragment was received, send ICMP time exceeded. */
- /* First, de-queue the first pbuf from r->p. */
- p = ipr->p;
- ipr->p = iprh->next_pbuf;
- /* Then, copy the original header into it. */
- SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
- icmp_time_exceeded(p, ICMP_TE_FRAG);
- clen = pbuf_clen(p);
- LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
- pbufs_freed += clen;
- pbuf_free(p);
- }
-#endif /* LWIP_ICMP */
-
- /* First, free all received pbufs. The individual pbufs need to be released
- separately as they have not yet been chained */
- p = ipr->p;
- while (p != NULL) {
- struct pbuf *pcur;
- iprh = (struct ip_reass_helper *)p->payload;
- pcur = p;
- /* get the next pointer before freeing */
- p = iprh->next_pbuf;
- clen = pbuf_clen(pcur);
- LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
- pbufs_freed += clen;
- pbuf_free(pcur);
- }
- /* Then, unchain the struct ip_reassdata from the list and free it. */
- ip_reass_dequeue_datagram(ipr, prev);
- LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);
- ip_reass_pbufcount -= pbufs_freed;
-
- return pbufs_freed;
-}
-
-#if IP_REASS_FREE_OLDEST
-/**
- * Free the oldest datagram to make room for enqueueing new fragments.
- * The datagram 'fraghdr' belongs to is not freed!
- *
- * @param fraghdr IP header of the current fragment
- * @param pbufs_needed number of pbufs needed to enqueue
- * (used for freeing other datagrams if not enough space)
- * @return the number of pbufs freed
- */
-static int
-ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
-{
- /* @todo Can't we simply remove the last datagram in the
- * linked list behind reassdatagrams?
- */
- struct ip_reassdata *r, *oldest, *prev;
- int pbufs_freed = 0, pbufs_freed_current;
- int other_datagrams;
-
- /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
- * but don't free the datagram that 'fraghdr' belongs to! */
- do {
- oldest = NULL;
- prev = NULL;
- other_datagrams = 0;
- r = reassdatagrams;
- while (r != NULL) {
- if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {
- /* Not the same datagram as fraghdr */
- other_datagrams++;
- if (oldest == NULL) {
- oldest = r;
- } else if (r->timer <= oldest->timer) {
- /* older than the previous oldest */
- oldest = r;
- }
- }
- if (r->next != NULL) {
- prev = r;
- }
- r = r->next;
- }
- if (oldest != NULL) {
- pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);
- pbufs_freed += pbufs_freed_current;
- }
- } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
- return pbufs_freed;
-}
-#endif /* IP_REASS_FREE_OLDEST */
-
-/**
- * Enqueues a new fragment into the fragment queue
- * @param fraghdr points to the new fragments IP hdr
- * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space)
- * @return A pointer to the queue location into which the fragment was enqueued
- */
-static struct ip_reassdata*
-ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
-{
- struct ip_reassdata* ipr;
- /* No matching previous fragment found, allocate a new reassdata struct */
- ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
- if (ipr == NULL) {
-#if IP_REASS_FREE_OLDEST
- if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
- ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
- }
- if (ipr == NULL)
-#endif /* IP_REASS_FREE_OLDEST */
- {
- IPFRAG_STATS_INC(ip_frag.memerr);
- LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n"));
- return NULL;
- }
- }
- memset(ipr, 0, sizeof(struct ip_reassdata));
- ipr->timer = IP_REASS_MAXAGE;
-
- /* enqueue the new structure to the front of the list */
- ipr->next = reassdatagrams;
- reassdatagrams = ipr;
- /* copy the ip header for later tests and input */
- /* @todo: no ip options supported? */
- SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);
- return ipr;
-}
-
-/**
- * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs.
- * @param ipr points to the queue entry to dequeue
- */
-static void
-ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
-{
-
- /* dequeue the reass struct */
- if (reassdatagrams == ipr) {
- /* it was the first in the list */
- reassdatagrams = ipr->next;
- } else {
- /* it wasn't the first, so it must have a valid 'prev' */
- LWIP_ASSERT("sanity check linked list", prev != NULL);
- prev->next = ipr->next;
- }
-
- /* now we can free the ip_reass struct */
- memp_free(MEMP_REASSDATA, ipr);
-}
-
-/**
- * Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list
- * will grow over time as new pbufs are rx.
- * Also checks that the datagram passes basic continuity checks (if the last
- * fragment was received at least once).
- * @param root_p points to the 'root' pbuf for the current datagram being assembled.
- * @param new_p points to the pbuf for the current fragment
- * @return 0 if invalid, >0 otherwise
- */
-static int
-ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)
-{
- struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
- struct pbuf *q;
- u16_t offset,len;
- struct ip_hdr *fraghdr;
- int valid = 1;
-
- /* Extract length and fragment offset from current fragment */
- fraghdr = (struct ip_hdr*)new_p->payload;
- len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
- offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
-
- /* overwrite the fragment's ip header from the pbuf with our helper struct,
- * and setup the embedded helper structure. */
- /* make sure the struct ip_reass_helper fits into the IP header */
- LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",
- sizeof(struct ip_reass_helper) <= IP_HLEN);
- iprh = (struct ip_reass_helper*)new_p->payload;
- iprh->next_pbuf = NULL;
- iprh->start = offset;
- iprh->end = offset + len;
-
- /* Iterate through until we either get to the end of the list (append),
- * or we find on with a larger offset (insert). */
- for (q = ipr->p; q != NULL;) {
- iprh_tmp = (struct ip_reass_helper*)q->payload;
- if (iprh->start < iprh_tmp->start) {
- /* the new pbuf should be inserted before this */
- iprh->next_pbuf = q;
- if (iprh_prev != NULL) {
- /* not the fragment with the lowest offset */
-#if IP_REASS_CHECK_OVERLAP
- if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
- /* fragment overlaps with previous or following, throw away */
- goto freepbuf;
- }
-#endif /* IP_REASS_CHECK_OVERLAP */
- iprh_prev->next_pbuf = new_p;
- } else {
- /* fragment with the lowest offset */
- ipr->p = new_p;
- }
- break;
- } else if(iprh->start == iprh_tmp->start) {
- /* received the same datagram twice: no need to keep the datagram */
- goto freepbuf;
-#if IP_REASS_CHECK_OVERLAP
- } else if(iprh->start < iprh_tmp->end) {
- /* overlap: no need to keep the new datagram */
- goto freepbuf;
-#endif /* IP_REASS_CHECK_OVERLAP */
- } else {
- /* Check if the fragments received so far have no wholes. */
- if (iprh_prev != NULL) {
- if (iprh_prev->end != iprh_tmp->start) {
- /* There is a fragment missing between the current
- * and the previous fragment */
- valid = 0;
- }
- }
- }
- q = iprh_tmp->next_pbuf;
- iprh_prev = iprh_tmp;
- }
-
- /* If q is NULL, then we made it to the end of the list. Determine what to do now */
- if (q == NULL) {
- if (iprh_prev != NULL) {
- /* this is (for now), the fragment with the highest offset:
- * chain it to the last fragment */
-#if IP_REASS_CHECK_OVERLAP
- LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
-#endif /* IP_REASS_CHECK_OVERLAP */
- iprh_prev->next_pbuf = new_p;
- if (iprh_prev->end != iprh->start) {
- valid = 0;
- }
- } else {
-#if IP_REASS_CHECK_OVERLAP
- LWIP_ASSERT("no previous fragment, this must be the first fragment!",
- ipr->p == NULL);
-#endif /* IP_REASS_CHECK_OVERLAP */
- /* this is the first fragment we ever received for this ip datagram */
- ipr->p = new_p;
- }
- }
-
- /* At this point, the validation part begins: */
- /* If we already received the last fragment */
- if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
- /* and had no wholes so far */
- if (valid) {
- /* then check if the rest of the fragments is here */
- /* Check if the queue starts with the first datagram */
- if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {
- valid = 0;
- } else {
- /* and check that there are no wholes after this datagram */
- iprh_prev = iprh;
- q = iprh->next_pbuf;
- while (q != NULL) {
- iprh = (struct ip_reass_helper*)q->payload;
- if (iprh_prev->end != iprh->start) {
- valid = 0;
- break;
- }
- iprh_prev = iprh;
- q = iprh->next_pbuf;
- }
- /* if still valid, all fragments are received
- * (because to the MF==0 already arrived */
- if (valid) {
- LWIP_ASSERT("sanity check", ipr->p != NULL);
- LWIP_ASSERT("sanity check",
- ((struct ip_reass_helper*)ipr->p->payload) != iprh);
- LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",
- iprh->next_pbuf == NULL);
- LWIP_ASSERT("validate_datagram:datagram end!=datagram len",
- iprh->end == ipr->datagram_len);
- }
- }
- }
- /* If valid is 0 here, there are some fragments missing in the middle
- * (since MF == 0 has already arrived). Such datagrams simply time out if
- * no more fragments are received... */
- return valid;
- }
- /* If we come here, not all fragments were received, yet! */
- return 0; /* not yet valid! */
-#if IP_REASS_CHECK_OVERLAP
-freepbuf:
- ip_reass_pbufcount -= pbuf_clen(new_p);
- pbuf_free(new_p);
- return 0;
-#endif /* IP_REASS_CHECK_OVERLAP */
-}
-
-/**
- * Reassembles incoming IP fragments into an IP datagram.
- *
- * @param p points to a pbuf chain of the fragment
- * @return NULL if reassembly is incomplete, ? otherwise
- */
-struct pbuf *
-ip_reass(struct pbuf *p)
-{
- struct pbuf *r;
- struct ip_hdr *fraghdr;
- struct ip_reassdata *ipr;
- struct ip_reass_helper *iprh;
- u16_t offset, len;
- u8_t clen;
- struct ip_reassdata *ipr_prev = NULL;
-
- IPFRAG_STATS_INC(ip_frag.recv);
- snmp_inc_ipreasmreqds();
-
- fraghdr = (struct ip_hdr*)p->payload;
-
- if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
- LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));
- IPFRAG_STATS_INC(ip_frag.err);
- goto nullreturn;
- }
-
- offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
- len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
-
- /* Check if we are allowed to enqueue more datagrams. */
- clen = pbuf_clen(p);
- if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
-#if IP_REASS_FREE_OLDEST
- if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
- ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
-#endif /* IP_REASS_FREE_OLDEST */
- {
- /* No datagram could be freed and still too many pbufs enqueued */
- LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
- ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
- IPFRAG_STATS_INC(ip_frag.memerr);
- /* @todo: send ICMP time exceeded here? */
- /* drop this pbuf */
- goto nullreturn;
- }
- }
-
- /* Look for the datagram the fragment belongs to in the current datagram queue,
- * remembering the previous in the queue for later dequeueing. */
- for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
- /* Check if the incoming fragment matches the one currently present
- in the reassembly buffer. If so, we proceed with copying the
- fragment into the buffer. */
- if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
- LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
- ntohs(IPH_ID(fraghdr))));
- IPFRAG_STATS_INC(ip_frag.cachehit);
- break;
- }
- ipr_prev = ipr;
- }
-
- if (ipr == NULL) {
- /* Enqueue a new datagram into the datagram queue */
- ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
- /* Bail if unable to enqueue */
- if(ipr == NULL) {
- goto nullreturn;
- }
- } else {
- if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
- ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
- /* ipr->iphdr is not the header from the first fragment, but fraghdr is
- * -> copy fraghdr into ipr->iphdr since we want to have the header
- * of the first fragment (for ICMP time exceeded and later, for copying
- * all options, if supported)*/
- SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
- }
- }
- /* Track the current number of pbufs current 'in-flight', in order to limit
- the number of fragments that may be enqueued at any one time */
- ip_reass_pbufcount += clen;
-
- /* At this point, we have either created a new entry or pointing
- * to an existing one */
-
- /* check for 'no more fragments', and update queue entry*/
- if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
- ipr->flags |= IP_REASS_FLAG_LASTFRAG;
- ipr->datagram_len = offset + len;
- LWIP_DEBUGF(IP_REASS_DEBUG,
- ("ip_reass: last fragment seen, total len %"S16_F"\n",
- ipr->datagram_len));
- }
- /* find the right place to insert this pbuf */
- /* @todo: trim pbufs if fragments are overlapping */
- if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
- /* the totally last fragment (flag more fragments = 0) was received at least
- * once AND all fragments are received */
- ipr->datagram_len += IP_HLEN;
-
- /* save the second pbuf before copying the header over the pointer */
- r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
-
- /* copy the original ip header back to the first pbuf */
- fraghdr = (struct ip_hdr*)(ipr->p->payload);
- SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
- IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
- IPH_OFFSET_SET(fraghdr, 0);
- IPH_CHKSUM_SET(fraghdr, 0);
- /* @todo: do we need to set calculate the correct checksum? */
- IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
-
- p = ipr->p;
-
- /* chain together the pbufs contained within the reass_data list. */
- while(r != NULL) {
- iprh = (struct ip_reass_helper*)r->payload;
-
- /* hide the ip header for every succeding fragment */
- pbuf_header(r, -IP_HLEN);
- pbuf_cat(p, r);
- r = iprh->next_pbuf;
- }
- /* release the sources allocate for the fragment queue entry */
- ip_reass_dequeue_datagram(ipr, ipr_prev);
-
- /* and adjust the number of pbufs currently queued for reassembly. */
- ip_reass_pbufcount -= pbuf_clen(p);
-
- /* Return the pbuf chain */
- return p;
- }
- /* the datagram is not (yet?) reassembled completely */
- LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));
- return NULL;
-
-nullreturn:
- LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));
- IPFRAG_STATS_INC(ip_frag.drop);
- pbuf_free(p);
- return NULL;
-}
-#endif /* IP_REASSEMBLY */
-
-#if IP_FRAG
-#if IP_FRAG_USES_STATIC_BUF
-static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
-#else /* IP_FRAG_USES_STATIC_BUF */
-
-#if !LWIP_NETIF_TX_SINGLE_PBUF
-/** Allocate a new struct pbuf_custom_ref */
-static struct pbuf_custom_ref*
-ip_frag_alloc_pbuf_custom_ref(void)
-{
- return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
-}
-
-/** Free a struct pbuf_custom_ref */
-static void
-ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
-{
- LWIP_ASSERT("p != NULL", p != NULL);
- memp_free(MEMP_FRAG_PBUF, p);
-}
-
-/** Free-callback function to free a 'struct pbuf_custom_ref', called by
- * pbuf_free. */
-static void
-ipfrag_free_pbuf_custom(struct pbuf *p)
-{
- struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
- LWIP_ASSERT("pcr != NULL", pcr != NULL);
- LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
- if (pcr->original != NULL) {
- pbuf_free(pcr->original);
- }
- ip_frag_free_pbuf_custom_ref(pcr);
-}
-#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
-#endif /* IP_FRAG_USES_STATIC_BUF */
-
-/**
- * Fragment an IP datagram if too large for the netif.
- *
- * Chop the datagram in MTU sized chunks and send them in order
- * by using a fixed size static memory buffer (PBUF_REF) or
- * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
- *
- * @param p ip packet to send
- * @param netif the netif on which to send
- * @param dest destination ip address to which to send
- *
- * @return ERR_OK if sent successfully, err_t otherwise
- */
-err_t
-ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
-{
- struct pbuf *rambuf;
-#if IP_FRAG_USES_STATIC_BUF
- struct pbuf *header;
-#else
-#if !LWIP_NETIF_TX_SINGLE_PBUF
- struct pbuf *newpbuf;
-#endif
- struct ip_hdr *original_iphdr;
-#endif
- struct ip_hdr *iphdr;
- u16_t nfb;
- u16_t left, cop;
- u16_t mtu = netif->mtu;
- u16_t ofo, omf;
- u16_t last;
- u16_t poff = IP_HLEN;
- u16_t tmp;
-#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
- u16_t newpbuflen = 0;
- u16_t left_to_copy;
-#endif
-
- /* Get a RAM based MTU sized pbuf */
-#if IP_FRAG_USES_STATIC_BUF
- /* When using a static buffer, we use a PBUF_REF, which we will
- * use to reference the packet (without link header).
- * Layer and length is irrelevant.
- */
- rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
- if (rambuf == NULL) {
- LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
- return ERR_MEM;
- }
- rambuf->tot_len = rambuf->len = mtu;
- rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
-
- /* Copy the IP header in it */
- iphdr = (struct ip_hdr *)rambuf->payload;
- SMEMCPY(iphdr, p->payload, IP_HLEN);
-#else /* IP_FRAG_USES_STATIC_BUF */
- original_iphdr = (struct ip_hdr *)p->payload;
- iphdr = original_iphdr;
-#endif /* IP_FRAG_USES_STATIC_BUF */
-
- /* Save original offset */
- tmp = ntohs(IPH_OFFSET(iphdr));
- ofo = tmp & IP_OFFMASK;
- omf = tmp & IP_MF;
-
- left = p->tot_len - IP_HLEN;
-
- nfb = (mtu - IP_HLEN) / 8;
-
- while (left) {
- last = (left <= mtu - IP_HLEN);
-
- /* Set new offset and MF flag */
- tmp = omf | (IP_OFFMASK & (ofo));
- if (!last) {
- tmp = tmp | IP_MF;
- }
-
- /* Fill this fragment */
- cop = last ? left : nfb * 8;
-
-#if IP_FRAG_USES_STATIC_BUF
- poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
-#else /* IP_FRAG_USES_STATIC_BUF */
-#if LWIP_NETIF_TX_SINGLE_PBUF
- rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
- if (rambuf == NULL) {
- return ERR_MEM;
- }
- LWIP_ASSERT("this needs a pbuf in one piece!",
- (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
- poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
- /* make room for the IP header */
- if(pbuf_header(rambuf, IP_HLEN)) {
- pbuf_free(rambuf);
- return ERR_MEM;
- }
- /* fill in the IP header */
- SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
- iphdr = rambuf->payload;
-#else /* LWIP_NETIF_TX_SINGLE_PBUF */
- /* When not using a static buffer, create a chain of pbufs.
- * The first will be a PBUF_RAM holding the link and IP header.
- * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
- * but limited to the size of an mtu.
- */
- rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
- if (rambuf == NULL) {
- return ERR_MEM;
- }
- LWIP_ASSERT("this needs a pbuf in one piece!",
- (p->len >= (IP_HLEN)));
- SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
- iphdr = (struct ip_hdr *)rambuf->payload;
-
- /* Can just adjust p directly for needed offset. */
- p->payload = (u8_t *)p->payload + poff;
- p->len -= poff;
-
- left_to_copy = cop;
- while (left_to_copy) {
- struct pbuf_custom_ref *pcr;
- newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
- /* Is this pbuf already empty? */
- if (!newpbuflen) {
- p = p->next;
- continue;
- }
- pcr = ip_frag_alloc_pbuf_custom_ref();
- if (pcr == NULL) {
- pbuf_free(rambuf);
- return ERR_MEM;
- }
- /* Mirror this pbuf, although we might not need all of it. */
- newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
- if (newpbuf == NULL) {
- ip_frag_free_pbuf_custom_ref(pcr);
- pbuf_free(rambuf);
- return ERR_MEM;
- }
- pbuf_ref(p);
- pcr->original = p;
- pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
-
- /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
- * so that it is removed when pbuf_dechain is later called on rambuf.
- */
- pbuf_cat(rambuf, newpbuf);
- left_to_copy -= newpbuflen;
- if (left_to_copy) {
- p = p->next;
- }
- }
- poff = newpbuflen;
-#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
-#endif /* IP_FRAG_USES_STATIC_BUF */
-
- /* Correct header */
- IPH_OFFSET_SET(iphdr, htons(tmp));
- IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
- IPH_CHKSUM_SET(iphdr, 0);
- IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
-
-#if IP_FRAG_USES_STATIC_BUF
- if (last) {
- pbuf_realloc(rambuf, left + IP_HLEN);
- }
-
- /* This part is ugly: we alloc a RAM based pbuf for
- * the link level header for each chunk and then
- * free it.A PBUF_ROM style pbuf for which pbuf_header
- * worked would make things simpler.
- */
- header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
- if (header != NULL) {
- pbuf_chain(header, rambuf);
- netif->output(netif, header, dest);
- IPFRAG_STATS_INC(ip_frag.xmit);
- snmp_inc_ipfragcreates();
- pbuf_free(header);
- } else {
- LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
- pbuf_free(rambuf);
- return ERR_MEM;
- }
-#else /* IP_FRAG_USES_STATIC_BUF */
- /* No need for separate header pbuf - we allowed room for it in rambuf
- * when allocated.
- */
- netif->output(netif, rambuf, dest);
- IPFRAG_STATS_INC(ip_frag.xmit);
-
- /* Unfortunately we can't reuse rambuf - the hardware may still be
- * using the buffer. Instead we free it (and the ensuing chain) and
- * recreate it next time round the loop. If we're lucky the hardware
- * will have already sent the packet, the free will really free, and
- * there will be zero memory penalty.
- */
-
- pbuf_free(rambuf);
-#endif /* IP_FRAG_USES_STATIC_BUF */
- left -= cop;
- ofo += nfb;
- }
-#if IP_FRAG_USES_STATIC_BUF
- pbuf_free(rambuf);
-#endif /* IP_FRAG_USES_STATIC_BUF */
- snmp_inc_ipfragoks();
- return ERR_OK;
-}
-#endif /* IP_FRAG */
+++ /dev/null
-/**
- * @file
- * Stack-internal timers implementation.
- * This file includes timer callbacks for stack-internal timers as well as
- * functions to set up or stop timers and check for expired timers.
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- * Simon Goldschmidt
- *
- */
-
-#include "lwip/opt.h"
-
-#include "lwip/timers.h"
-#include "lwip/tcp_impl.h"
-
-#if LWIP_TIMERS
-
-#include "lwip/def.h"
-#include "lwip/memp.h"
-#include "lwip/tcpip.h"
-
-#include "lwip/ip_frag.h"
-#include "netif/etharp.h"
-#include "lwip/dhcp.h"
-#include "lwip/autoip.h"
-#include "lwip/igmp.h"
-#include "lwip/dns.h"
-
-
-/** The one and only timeout list */
-static struct sys_timeo *next_timeout;
-#if NO_SYS
-static u32_t timeouts_last_time;
-#endif /* NO_SYS */
-
-#if LWIP_TCP
-/** global variable that shows if the tcp timer is currently scheduled or not */
-static int tcpip_tcp_timer_active;
-
-/**
- * Timer callback function that calls tcp_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-tcpip_tcp_timer(void *arg)
-{
- LWIP_UNUSED_ARG(arg);
-
- /* call TCP timer handler */
- tcp_tmr();
- /* timer still needed? */
- if (tcp_active_pcbs || tcp_tw_pcbs) {
- /* restart timer */
- sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
- } else {
- /* disable timer */
- tcpip_tcp_timer_active = 0;
- }
-}
-
-/**
- * Called from TCP_REG when registering a new PCB:
- * the reason is to have the TCP timer only running when
- * there are active (or time-wait) PCBs.
- */
-void
-tcp_timer_needed(void)
-{
- /* timer is off but needed again? */
- if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
- /* enable and start timer */
- tcpip_tcp_timer_active = 1;
- sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
- }
-}
-#endif /* LWIP_TCP */
-
-#if IP_REASSEMBLY
-/**
- * Timer callback function that calls ip_reass_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-ip_reass_timer(void *arg)
-{
- LWIP_UNUSED_ARG(arg);
- LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n"));
- ip_reass_tmr();
- sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
-}
-#endif /* IP_REASSEMBLY */
-
-#if LWIP_ARP
-/**
- * Timer callback function that calls etharp_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-arp_timer(void *arg)
-{
- LWIP_UNUSED_ARG(arg);
- LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n"));
- etharp_tmr();
- sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
-}
-#endif /* LWIP_ARP */
-
-#if LWIP_DHCP
-/**
- * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-dhcp_timer_coarse(void *arg)
-{
- LWIP_UNUSED_ARG(arg);
- LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
- dhcp_coarse_tmr();
- sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
-}
-
-/**
- * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-dhcp_timer_fine(void *arg)
-{
- LWIP_UNUSED_ARG(arg);
- LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
- dhcp_fine_tmr();
- sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
-}
-#endif /* LWIP_DHCP */
-
-#if LWIP_AUTOIP
-/**
- * Timer callback function that calls autoip_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-autoip_timer(void *arg)
-{
- LWIP_UNUSED_ARG(arg);
- LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n"));
- autoip_tmr();
- sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
-}
-#endif /* LWIP_AUTOIP */
-
-#if LWIP_IGMP
-/**
- * Timer callback function that calls igmp_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-igmp_timer(void *arg)
-{
- LWIP_UNUSED_ARG(arg);
- LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n"));
- igmp_tmr();
- sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
-}
-#endif /* LWIP_IGMP */
-
-#if LWIP_DNS
-/**
- * Timer callback function that calls dns_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-dns_timer(void *arg)
-{
- LWIP_UNUSED_ARG(arg);
- LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n"));
- dns_tmr();
- sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
-}
-#endif /* LWIP_DNS */
-
-/** Initialize this module */
-void sys_timeouts_init(void)
-{
-#if IP_REASSEMBLY
- sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
-#endif /* IP_REASSEMBLY */
-#if LWIP_ARP
- sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
-#endif /* LWIP_ARP */
-#if LWIP_DHCP
- sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
- sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
-#endif /* LWIP_DHCP */
-#if LWIP_AUTOIP
- sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
-#endif /* LWIP_AUTOIP */
-#if LWIP_IGMP
- sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
-#endif /* LWIP_IGMP */
-#if LWIP_DNS
- sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
-#endif /* LWIP_DNS */
-
-#if NO_SYS
- /* Initialise timestamp for sys_check_timeouts */
- timeouts_last_time = sys_now();
-#endif
-}
-
-/**
- * Create a one-shot timer (aka timeout). Timeouts are processed in the
- * following cases:
- * - while waiting for a message using sys_timeouts_mbox_fetch()
- * - by calling sys_check_timeouts() (NO_SYS==1 only)
- *
- * @param msecs time in milliseconds after that the timer should expire
- * @param handler callback function to call when msecs have elapsed
- * @param arg argument to pass to the callback function
- */
-#if LWIP_DEBUG_TIMERNAMES
-void
-sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)
-#else /* LWIP_DEBUG_TIMERNAMES */
-void
-sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
-#endif /* LWIP_DEBUG_TIMERNAMES */
-{
- struct sys_timeo *timeout, *t;
-
- timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);
- if (timeout == NULL) {
- LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL);
- return;
- }
- timeout->next = NULL;
- timeout->h = handler;
- timeout->arg = arg;
- timeout->time = msecs;
-#if LWIP_DEBUG_TIMERNAMES
- timeout->handler_name = handler_name;
- LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n",
- (void *)timeout, msecs, handler_name, (void *)arg));
-#endif /* LWIP_DEBUG_TIMERNAMES */
-
- if (next_timeout == NULL) {
- next_timeout = timeout;
- return;
- }
-
- if (next_timeout->time > msecs) {
- next_timeout->time -= msecs;
- timeout->next = next_timeout;
- next_timeout = timeout;
- } else {
- for(t = next_timeout; t != NULL; t = t->next) {
- timeout->time -= t->time;
- if (t->next == NULL || t->next->time > timeout->time) {
- if (t->next != NULL) {
- t->next->time -= timeout->time;
- }
- timeout->next = t->next;
- t->next = timeout;
- break;
- }
- }
- }
-}
-
-/**
- * Go through timeout list (for this task only) and remove the first matching
- * entry, even though the timeout has not triggered yet.
- *
- * @note This function only works as expected if there is only one timeout
- * calling 'handler' in the list of timeouts.
- *
- * @param handler callback function that would be called by the timeout
- * @param arg callback argument that would be passed to handler
-*/
-void
-sys_untimeout(sys_timeout_handler handler, void *arg)
-{
- struct sys_timeo *prev_t, *t;
-
- if (next_timeout == NULL) {
- return;
- }
-
- for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
- if ((t->h == handler) && (t->arg == arg)) {
- /* We have a match */
- /* Unlink from previous in list */
- if (prev_t == NULL) {
- next_timeout = t->next;
- } else {
- prev_t->next = t->next;
- }
- /* If not the last one, add time of this one back to next */
- if (t->next != NULL) {
- t->next->time += t->time;
- }
- memp_free(MEMP_SYS_TIMEOUT, t);
- return;
- }
- }
- return;
-}
-
-#if NO_SYS
-
-/** Handle timeouts for NO_SYS==1 (i.e. without using
- * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
- * handler functions when timeouts expire.
- *
- * Must be called periodically from your main loop.
- */
-void
-sys_check_timeouts(void)
-{
- struct sys_timeo *tmptimeout;
- u32_t diff;
- sys_timeout_handler handler;
- void *arg;
- int had_one;
- u32_t now;
-
- now = sys_now();
- if (next_timeout) {
- /* this cares for wraparounds */
- diff = LWIP_U32_DIFF(now, timeouts_last_time);
- do
- {
- had_one = 0;
- tmptimeout = next_timeout;
- if (tmptimeout->time <= diff) {
- /* timeout has expired */
- had_one = 1;
- timeouts_last_time = now;
- diff -= tmptimeout->time;
- next_timeout = tmptimeout->next;
- handler = tmptimeout->h;
- arg = tmptimeout->arg;
-#if LWIP_DEBUG_TIMERNAMES
- if (handler != NULL) {
- LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
- tmptimeout->handler_name, arg));
- }
-#endif /* LWIP_DEBUG_TIMERNAMES */
- memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
- if (handler != NULL) {
- handler(arg);
- }
- }
- /* repeat until all expired timers have been called */
- }while(had_one);
- }
-}
-
-/** Set back the timestamp of the last call to sys_check_timeouts()
- * This is necessary if sys_check_timeouts() hasn't been called for a long
- * time (e.g. while saving energy) to prevent all timer functions of that
- * period being called.
- */
-void
-sys_restart_timeouts(void)
-{
- timeouts_last_time = sys_now();
-}
-
-#else /* NO_SYS */
-
-/**
- * Wait (forever) for a message to arrive in an mbox.
- * While waiting, timeouts are processed.
- *
- * @param mbox the mbox to fetch the message from
- * @param msg the place to store the message
- */
-void
-sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
-{
- u32_t time_needed;
- struct sys_timeo *tmptimeout;
- sys_timeout_handler handler;
- void *arg;
-
- again:
- if (!next_timeout) {
- time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
- } else {
- if (next_timeout->time > 0) {
- time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);
- } else {
- time_needed = SYS_ARCH_TIMEOUT;
- }
-
- if (time_needed == SYS_ARCH_TIMEOUT) {
- /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
- could be fetched. We should now call the timeout handler and
- deallocate the memory allocated for the timeout. */
- tmptimeout = next_timeout;
- next_timeout = tmptimeout->next;
- handler = tmptimeout->h;
- arg = tmptimeout->arg;
-#if LWIP_DEBUG_TIMERNAMES
- if (handler != NULL) {
- LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n",
- tmptimeout->handler_name, arg));
- }
-#endif /* LWIP_DEBUG_TIMERNAMES */
- memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
- if (handler != NULL) {
- /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
- timeout handler function. */
- LOCK_TCPIP_CORE();
- handler(arg);
- UNLOCK_TCPIP_CORE();
- }
- LWIP_TCPIP_THREAD_ALIVE();
-
- /* We try again to fetch a message from the mbox. */
- goto again;
- } else {
- /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
- occured. The time variable is set to the number of
- milliseconds we waited for the message. */
- if (time_needed < next_timeout->time) {
- next_timeout->time -= time_needed;
- } else {
- next_timeout->time = 0;
- }
- }
- }
-}
-
-#endif /* NO_SYS */
-
-#else /* LWIP_TIMERS */
-/* Satisfy the TCP code which calls this function */
-void
-tcp_timer_needed(void)
-{
-}
-#endif /* LWIP_TIMERS */
+++ /dev/null
-/**
- * @file
- * Dynamic memory manager
- *
- * This is a lightweight replacement for the standard C library malloc().
- *
- * If you want to use the standard C library malloc() instead, define
- * MEM_LIBC_MALLOC to 1 in your lwipopts.h
- *
- * To let mem_malloc() use pools (prevents fragmentation and is much faster than
- * a heap but might waste some memory), define MEM_USE_POOLS to 1, define
- * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
- * of pools like this (more pools can be added between _START and _END):
- *
- * Define three pools with sizes 256, 512, and 1512 bytes
- * LWIP_MALLOC_MEMPOOL_START
- * LWIP_MALLOC_MEMPOOL(20, 256)
- * LWIP_MALLOC_MEMPOOL(10, 512)
- * LWIP_MALLOC_MEMPOOL(5, 1512)
- * LWIP_MALLOC_MEMPOOL_END
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- * Simon Goldschmidt
- *
- */
-
-#include "lwip/opt.h"
-
-#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/def.h"
-#include "lwip/mem.h"
-#include "lwip/sys.h"
-#include "lwip/stats.h"
-#include "lwip/err.h"
-
-#include <string.h>
-
-#if MEM_USE_POOLS
-/* lwIP head implemented with different sized pools */
-
-/**
- * Allocate memory: determine the smallest pool that is big enough
- * to contain an element of 'size' and get an element from that pool.
- *
- * @param size the size in bytes of the memory needed
- * @return a pointer to the allocated memory or NULL if the pool is empty
- */
-void *
-mem_malloc(mem_size_t size)
-{
- struct memp_malloc_helper *element;
- memp_t poolnr;
- mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
-
- for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {
-#if MEM_USE_POOLS_TRY_BIGGER_POOL
-again:
-#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
- /* is this pool big enough to hold an element of the required size
- plus a struct memp_malloc_helper that saves the pool this element came from? */
- if (required_size <= memp_sizes[poolnr]) {
- break;
- }
- }
- if (poolnr > MEMP_POOL_LAST) {
- LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
- return NULL;
- }
- element = (struct memp_malloc_helper*)memp_malloc(poolnr);
- if (element == NULL) {
- /* No need to DEBUGF or ASSERT: This error is already
- taken care of in memp.c */
-#if MEM_USE_POOLS_TRY_BIGGER_POOL
- /** Try a bigger pool if this one is empty! */
- if (poolnr < MEMP_POOL_LAST) {
- poolnr++;
- goto again;
- }
-#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
- return NULL;
- }
-
- /* save the pool number this element came from */
- element->poolnr = poolnr;
- /* and return a pointer to the memory directly after the struct memp_malloc_helper */
- element++;
-
- return element;
-}
-
-/**
- * Free memory previously allocated by mem_malloc. Loads the pool number
- * and calls memp_free with that pool number to put the element back into
- * its pool
- *
- * @param rmem the memory element to free
- */
-void
-mem_free(void *rmem)
-{
- struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;
-
- LWIP_ASSERT("rmem != NULL", (rmem != NULL));
- LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
-
- /* get the original struct memp_malloc_helper */
- hmem--;
-
- LWIP_ASSERT("hmem != NULL", (hmem != NULL));
- LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
- LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));
-
- /* and put it in the pool we saved earlier */
- memp_free(hmem->poolnr, hmem);
-}
-
-#else /* MEM_USE_POOLS */
-/* lwIP replacement for your libc malloc() */
-
-/**
- * The heap is made up as a list of structs of this type.
- * This does not have to be aligned since for getting its size,
- * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.
- */
-struct mem {
- /** index (-> ram[next]) of the next struct */
- mem_size_t next;
- /** index (-> ram[prev]) of the previous struct */
- mem_size_t prev;
- /** 1: this area is used; 0: this area is unused */
- u8_t used;
-};
-
-/** All allocated blocks will be MIN_SIZE bytes big, at least!
- * MIN_SIZE can be overridden to suit your needs. Smaller values save space,
- * larger values could prevent too small blocks to fragment the RAM too much. */
-#ifndef MIN_SIZE
-#define MIN_SIZE 12
-#endif /* MIN_SIZE */
-/* some alignment macros: we define them here for better source code layout */
-#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE)
-#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
-#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
-
-/** If you want to relocate the heap to external memory, simply define
- * LWIP_RAM_HEAP_POINTER as a void-pointer to that location.
- * If so, make sure the memory at that location is big enough (see below on
- * how that space is calculated). */
-#ifndef LWIP_RAM_HEAP_POINTER
-/** the heap. we need one struct mem at the end and some room for alignment */
-u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
-#define LWIP_RAM_HEAP_POINTER ram_heap
-#endif /* LWIP_RAM_HEAP_POINTER */
-
-/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */
-static u8_t *ram;
-/** the last entry, always unused! */
-static struct mem *ram_end;
-/** pointer to the lowest free block, this is used for faster search */
-static struct mem *lfree;
-
-/** concurrent access protection */
-static sys_mutex_t mem_mutex;
-
-#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
-
-static volatile u8_t mem_free_count;
-
-/* Allow mem_free from other (e.g. interrupt) context */
-#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free)
-#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free)
-#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free)
-#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
-#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc)
-#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc)
-
-#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
-
-/* Protect the heap only by using a semaphore */
-#define LWIP_MEM_FREE_DECL_PROTECT()
-#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex)
-#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex)
-/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */
-#define LWIP_MEM_ALLOC_DECL_PROTECT()
-#define LWIP_MEM_ALLOC_PROTECT()
-#define LWIP_MEM_ALLOC_UNPROTECT()
-
-#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
-
-
-/**
- * "Plug holes" by combining adjacent empty struct mems.
- * After this function is through, there should not exist
- * one empty struct mem pointing to another empty struct mem.
- *
- * @param mem this points to a struct mem which just has been freed
- * @internal this function is only called by mem_free() and mem_trim()
- *
- * This assumes access to the heap is protected by the calling function
- * already.
- */
-static void
-plug_holes(struct mem *mem)
-{
- struct mem *nmem;
- struct mem *pmem;
-
- LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
- LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
- LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
-
- /* plug hole forward */
- LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
-
- nmem = (struct mem *)(void *)&ram[mem->next];
- if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
- /* if mem->next is unused and not end of ram, combine mem and mem->next */
- if (lfree == nmem) {
- lfree = mem;
- }
- mem->next = nmem->next;
- ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram);
- }
-
- /* plug hole backward */
- pmem = (struct mem *)(void *)&ram[mem->prev];
- if (pmem != mem && pmem->used == 0) {
- /* if mem->prev is unused, combine mem and mem->prev */
- if (lfree == mem) {
- lfree = pmem;
- }
- pmem->next = mem->next;
- ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram);
- }
-}
-
-/**
- * Zero the heap and initialize start, end and lowest-free
- */
-void
-mem_init(void)
-{
- struct mem *mem;
-
- LWIP_ASSERT("Sanity check alignment",
- (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);
-
- /* align the heap */
- ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER);
- /* initialize the start of the heap */
- mem = (struct mem *)(void *)ram;
- mem->next = MEM_SIZE_ALIGNED;
- mem->prev = 0;
- mem->used = 0;
- /* initialize the end of the heap */
- ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED];
- ram_end->used = 1;
- ram_end->next = MEM_SIZE_ALIGNED;
- ram_end->prev = MEM_SIZE_ALIGNED;
-
- /* initialize the lowest-free pointer to the start of the heap */
- lfree = (struct mem *)(void *)ram;
-
- MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
-
- if(sys_mutex_new(&mem_mutex) != ERR_OK) {
- LWIP_ASSERT("failed to create mem_mutex", 0);
- }
-}
-
-/**
- * Put a struct mem back on the heap
- *
- * @param rmem is the data portion of a struct mem as returned by a previous
- * call to mem_malloc()
- */
-void
-mem_free(void *rmem)
-{
- struct mem *mem;
- LWIP_MEM_FREE_DECL_PROTECT();
-
- if (rmem == NULL) {
- LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
- return;
- }
- LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
-
- LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
- (u8_t *)rmem < (u8_t *)ram_end);
-
- if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
- SYS_ARCH_DECL_PROTECT(lev);
- LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
- /* protect mem stats from concurrent access */
- SYS_ARCH_PROTECT(lev);
- MEM_STATS_INC(illegal);
- SYS_ARCH_UNPROTECT(lev);
- return;
- }
- /* protect the heap from concurrent access */
- LWIP_MEM_FREE_PROTECT();
- /* Get the corresponding struct mem ... */
- mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
- /* ... which has to be in a used state ... */
- LWIP_ASSERT("mem_free: mem->used", mem->used);
- /* ... and is now unused. */
- mem->used = 0;
-
- if (mem < lfree) {
- /* the newly freed struct is now the lowest */
- lfree = mem;
- }
-
- MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram)));
-
- /* finally, see if prev or next are free also */
- plug_holes(mem);
-#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
- mem_free_count = 1;
-#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
- LWIP_MEM_FREE_UNPROTECT();
-}
-
-/**
- * Shrink memory returned by mem_malloc().
- *
- * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked
- * @param newsize required size after shrinking (needs to be smaller than or
- * equal to the previous size)
- * @return for compatibility reasons: is always == rmem, at the moment
- * or NULL if newsize is > old size, in which case rmem is NOT touched
- * or freed!
- */
-void *
-mem_trim(void *rmem, mem_size_t newsize)
-{
- mem_size_t size;
- mem_size_t ptr, ptr2;
- struct mem *mem, *mem2;
- /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
- LWIP_MEM_FREE_DECL_PROTECT();
-
- /* Expand the size of the allocated memory region so that we can
- adjust for alignment. */
- newsize = LWIP_MEM_ALIGN_SIZE(newsize);
-
- if(newsize < MIN_SIZE_ALIGNED) {
- /* every data block must be at least MIN_SIZE_ALIGNED long */
- newsize = MIN_SIZE_ALIGNED;
- }
-
- if (newsize > MEM_SIZE_ALIGNED) {
- return NULL;
- }
-
- LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
- (u8_t *)rmem < (u8_t *)ram_end);
-
- if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
- SYS_ARCH_DECL_PROTECT(lev);
- LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n"));
- /* protect mem stats from concurrent access */
- SYS_ARCH_PROTECT(lev);
- MEM_STATS_INC(illegal);
- SYS_ARCH_UNPROTECT(lev);
- return rmem;
- }
- /* Get the corresponding struct mem ... */
- mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
- /* ... and its offset pointer */
- ptr = (mem_size_t)((u8_t *)mem - ram);
-
- size = mem->next - ptr - SIZEOF_STRUCT_MEM;
- LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size);
- if (newsize > size) {
- /* not supported */
- return NULL;
- }
- if (newsize == size) {
- /* No change in size, simply return */
- return rmem;
- }
-
- /* protect the heap from concurrent access */
- LWIP_MEM_FREE_PROTECT();
-
- mem2 = (struct mem *)(void *)&ram[mem->next];
- if(mem2->used == 0) {
- /* The next struct is unused, we can simply move it at little */
- mem_size_t next;
- /* remember the old next pointer */
- next = mem2->next;
- /* create new struct mem which is moved directly after the shrinked mem */
- ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
- if (lfree == mem2) {
- lfree = (struct mem *)(void *)&ram[ptr2];
- }
- mem2 = (struct mem *)(void *)&ram[ptr2];
- mem2->used = 0;
- /* restore the next pointer */
- mem2->next = next;
- /* link it back to mem */
- mem2->prev = ptr;
- /* link mem to it */
- mem->next = ptr2;
- /* last thing to restore linked list: as we have moved mem2,
- * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not
- * the end of the heap */
- if (mem2->next != MEM_SIZE_ALIGNED) {
- ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
- }
- MEM_STATS_DEC_USED(used, (size - newsize));
- /* no need to plug holes, we've already done that */
- } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {
- /* Next struct is used but there's room for another struct mem with
- * at least MIN_SIZE_ALIGNED of data.
- * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem
- * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED').
- * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
- * region that couldn't hold data, but when mem->next gets freed,
- * the 2 regions would be combined, resulting in more free memory */
- ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
- mem2 = (struct mem *)(void *)&ram[ptr2];
- if (mem2 < lfree) {
- lfree = mem2;
- }
- mem2->used = 0;
- mem2->next = mem->next;
- mem2->prev = ptr;
- mem->next = ptr2;
- if (mem2->next != MEM_SIZE_ALIGNED) {
- ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
- }
- MEM_STATS_DEC_USED(used, (size - newsize));
- /* the original mem->next is used, so no need to plug holes! */
- }
- /* else {
- next struct mem is used but size between mem and mem2 is not big enough
- to create another struct mem
- -> don't do anyhting.
- -> the remaining space stays unused since it is too small
- } */
-#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
- mem_free_count = 1;
-#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
- LWIP_MEM_FREE_UNPROTECT();
- return rmem;
-}
-
-/**
- * Adam's mem_malloc() plus solution for bug #17922
- * Allocate a block of memory with a minimum of 'size' bytes.
- *
- * @param size is the minimum size of the requested block in bytes.
- * @return pointer to allocated memory or NULL if no free memory was found.
- *
- * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).
- */
-void *
-mem_malloc(mem_size_t size)
-{
- mem_size_t ptr, ptr2;
- struct mem *mem, *mem2;
-#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
- u8_t local_mem_free_count = 0;
-#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
- LWIP_MEM_ALLOC_DECL_PROTECT();
-
- if (size == 0) {
- return NULL;
- }
-
- /* Expand the size of the allocated memory region so that we can
- adjust for alignment. */
- size = LWIP_MEM_ALIGN_SIZE(size);
-
- if(size < MIN_SIZE_ALIGNED) {
- /* every data block must be at least MIN_SIZE_ALIGNED long */
- size = MIN_SIZE_ALIGNED;
- }
-
- if (size > MEM_SIZE_ALIGNED) {
- return NULL;
- }
-
- /* protect the heap from concurrent access */
- sys_mutex_lock(&mem_mutex);
- LWIP_MEM_ALLOC_PROTECT();
-#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
- /* run as long as a mem_free disturbed mem_malloc */
- do {
- local_mem_free_count = 0;
-#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
-
- /* Scan through the heap searching for a free block that is big enough,
- * beginning with the lowest free block.
- */
- for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size;
- ptr = ((struct mem *)(void *)&ram[ptr])->next) {
- mem = (struct mem *)(void *)&ram[ptr];
-#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
- mem_free_count = 0;
- LWIP_MEM_ALLOC_UNPROTECT();
- /* allow mem_free to run */
- LWIP_MEM_ALLOC_PROTECT();
- if (mem_free_count != 0) {
- local_mem_free_count = mem_free_count;
- }
- mem_free_count = 0;
-#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
-
- if ((!mem->used) &&
- (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
- /* mem is not used and at least perfect fit is possible:
- * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
-
- if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
- /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
- * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
- * -> split large block, create empty remainder,
- * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
- * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
- * struct mem would fit in but no data between mem2 and mem2->next
- * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
- * region that couldn't hold data, but when mem->next gets freed,
- * the 2 regions would be combined, resulting in more free memory
- */
- ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
- /* create mem2 struct */
- mem2 = (struct mem *)(void *)&ram[ptr2];
- mem2->used = 0;
- mem2->next = mem->next;
- mem2->prev = ptr;
- /* and insert it between mem and mem->next */
- mem->next = ptr2;
- mem->used = 1;
-
- if (mem2->next != MEM_SIZE_ALIGNED) {
- ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
- }
- MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
- } else {
- /* (a mem2 struct does no fit into the user data space of mem and mem->next will always
- * be used at this point: if not we have 2 unused structs in a row, plug_holes should have
- * take care of this).
- * -> near fit or excact fit: do not split, no mem2 creation
- * also can't move mem->next directly behind mem, since mem->next
- * will always be used at this point!
- */
- mem->used = 1;
- MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));
- }
-
- if (mem == lfree) {
- /* Find next free block after mem and update lowest free pointer */
- while (lfree->used && lfree != ram_end) {
- LWIP_MEM_ALLOC_UNPROTECT();
- /* prevent high interrupt latency... */
- LWIP_MEM_ALLOC_PROTECT();
- lfree = (struct mem *)(void *)&ram[lfree->next];
- }
- LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
- }
- LWIP_MEM_ALLOC_UNPROTECT();
- sys_mutex_unlock(&mem_mutex);
- LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
- (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
- LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
- ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
- LWIP_ASSERT("mem_malloc: sanity check alignment",
- (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
-
- return (u8_t *)mem + SIZEOF_STRUCT_MEM;
- }
- }
-#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
- /* if we got interrupted by a mem_free, try again */
- } while(local_mem_free_count != 0);
-#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
- LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
- MEM_STATS_INC(err);
- LWIP_MEM_ALLOC_UNPROTECT();
- sys_mutex_unlock(&mem_mutex);
- return NULL;
-}
-
-#endif /* MEM_USE_POOLS */
-/**
- * Contiguously allocates enough space for count objects that are size bytes
- * of memory each and returns a pointer to the allocated memory.
- *
- * The allocated memory is filled with bytes of value zero.
- *
- * @param count number of objects to allocate
- * @param size size of the objects to allocate
- * @return pointer to allocated memory / NULL pointer if there is an error
- */
-void *mem_calloc(mem_size_t count, mem_size_t size)
-{
- void *p;
-
- /* allocate 'count' objects of size 'size' */
- p = mem_malloc(count * size);
- if (p) {
- /* zero the memory */
- memset(p, 0, count * size);
- }
- return p;
-}
-
-#endif /* !MEM_LIBC_MALLOC */
+++ /dev/null
-/**
- * @file
- * Dynamic pool memory manager
- *
- * lwIP has dedicated pools for many structures (netconn, protocol control blocks,
- * packet buffers, ...). All these pools are managed here.
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-
-#include "lwip/memp.h"
-#include "lwip/pbuf.h"
-#include "lwip/udp.h"
-#include "lwip/raw.h"
-#include "lwip/tcp_impl.h"
-#include "lwip/igmp.h"
-#include "lwip/api.h"
-#include "lwip/api_msg.h"
-#include "lwip/tcpip.h"
-#include "lwip/sys.h"
-#include "lwip/timers.h"
-#include "lwip/stats.h"
-#include "netif/etharp.h"
-#include "lwip/ip_frag.h"
-#include "lwip/snmp_structs.h"
-#include "lwip/snmp_msg.h"
-#include "lwip/dns.h"
-#include "netif/ppp_oe.h"
-
-#include <string.h>
-
-#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
-
-struct memp {
- struct memp *next;
-#if MEMP_OVERFLOW_CHECK
- const char *file;
- int line;
-#endif /* MEMP_OVERFLOW_CHECK */
-};
-
-#if MEMP_OVERFLOW_CHECK
-/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
- * and at the end of each element, initialize them as 0xcd and check
- * them later. */
-/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
- * every single element in each pool is checked!
- * This is VERY SLOW but also very helpful. */
-/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
- * lwipopts.h to change the amount reserved for checking. */
-#ifndef MEMP_SANITY_REGION_BEFORE
-#define MEMP_SANITY_REGION_BEFORE 16
-#endif /* MEMP_SANITY_REGION_BEFORE*/
-#if MEMP_SANITY_REGION_BEFORE > 0
-#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
-#else
-#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0
-#endif /* MEMP_SANITY_REGION_BEFORE*/
-#ifndef MEMP_SANITY_REGION_AFTER
-#define MEMP_SANITY_REGION_AFTER 16
-#endif /* MEMP_SANITY_REGION_AFTER*/
-#if MEMP_SANITY_REGION_AFTER > 0
-#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
-#else
-#define MEMP_SANITY_REGION_AFTER_ALIGNED 0
-#endif /* MEMP_SANITY_REGION_AFTER*/
-
-/* MEMP_SIZE: save space for struct memp and for sanity check */
-#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
-#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
-
-#else /* MEMP_OVERFLOW_CHECK */
-
-/* No sanity checks
- * We don't need to preserve the struct memp while not allocated, so we
- * can save a little space and set MEMP_SIZE to 0.
- */
-#define MEMP_SIZE 0
-#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
-
-#endif /* MEMP_OVERFLOW_CHECK */
-
-/** This array holds the first free element of each pool.
- * Elements form a linked list. */
-static struct memp *memp_tab[MEMP_MAX];
-
-#else /* MEMP_MEM_MALLOC */
-
-#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
-
-#endif /* MEMP_MEM_MALLOC */
-
-/** This array holds the element sizes of each pool. */
-#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
-static
-#endif
-const u16_t memp_sizes[MEMP_MAX] = {
-#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size),
-#include "lwip/memp_std.h"
-};
-
-#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
-
-/** This array holds the number of elements in each pool. */
-static const u16_t memp_num[MEMP_MAX] = {
-#define LWIP_MEMPOOL(name,num,size,desc) (num),
-#include "lwip/memp_std.h"
-};
-
-/** This array holds a textual description of each pool. */
-#ifdef LWIP_DEBUG
-static const char *memp_desc[MEMP_MAX] = {
-#define LWIP_MEMPOOL(name,num,size,desc) (desc),
-#include "lwip/memp_std.h"
-};
-#endif /* LWIP_DEBUG */
-
-#if MEMP_SEPARATE_POOLS
-
-/** This creates each memory pool. These are named memp_memory_XXX_base (where
- * XXX is the name of the pool defined in memp_std.h).
- * To relocate a pool, declare it as extern in cc.h. Example for GCC:
- * extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[];
- */
-#define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \
- [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))];
-#include "lwip/memp_std.h"
-
-/** This array holds the base of each memory pool. */
-static u8_t *const memp_bases[] = {
-#define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base,
-#include "lwip/memp_std.h"
-};
-
-#else /* MEMP_SEPARATE_POOLS */
-
-/** This is the actual memory used by the pools (all pools in one big block). */
-static u8_t memp_memory[MEM_ALIGNMENT - 1
-#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
-#include "lwip/memp_std.h"
-];
-
-#endif /* MEMP_SEPARATE_POOLS */
-
-#if MEMP_SANITY_CHECK
-/**
- * Check that memp-lists don't form a circle
- */
-static int
-memp_sanity(void)
-{
- s16_t i, c;
- struct memp *m, *n;
-
- for (i = 0; i < MEMP_MAX; i++) {
- for (m = memp_tab[i]; m != NULL; m = m->next) {
- c = 1;
- for (n = memp_tab[i]; n != NULL; n = n->next) {
- if (n == m && --c < 0) {
- return 0;
- }
- }
- }
- }
- return 1;
-}
-#endif /* MEMP_SANITY_CHECK*/
-#if MEMP_OVERFLOW_CHECK
-#if defined(LWIP_DEBUG) && MEMP_STATS
-static const char * memp_overflow_names[] = {
-#define LWIP_MEMPOOL(name,num,size,desc) "/"desc,
-#include "lwip/memp_std.h"
- };
-#endif
-
-/**
- * Check if a memp element was victim of an overflow
- * (e.g. the restricted area after it has been altered)
- *
- * @param p the memp element to check
- * @param memp_type the pool p comes from
- */
-static void
-memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
-{
- u16_t k;
- u8_t *m;
-#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
- m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type];
- for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
- if (m[k] != 0xcd) {
- char errstr[128] = "detected memp overflow in pool ";
- char digit[] = "0";
- if(memp_type >= 10) {
- digit[0] = '0' + (memp_type/10);
- strcat(errstr, digit);
- }
- digit[0] = '0' + (memp_type%10);
- strcat(errstr, digit);
-#if defined(LWIP_DEBUG) && MEMP_STATS
- strcat(errstr, memp_overflow_names[memp_type]);
-#endif
- LWIP_ASSERT(errstr, 0);
- }
- }
-#endif
-}
-
-/**
- * Check if a memp element was victim of an underflow
- * (e.g. the restricted area before it has been altered)
- *
- * @param p the memp element to check
- * @param memp_type the pool p comes from
- */
-static void
-memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)
-{
- u16_t k;
- u8_t *m;
-#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
- m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
- for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
- if (m[k] != 0xcd) {
- char errstr[128] = "detected memp underflow in pool ";
- char digit[] = "0";
- if(memp_type >= 10) {
- digit[0] = '0' + (memp_type/10);
- strcat(errstr, digit);
- }
- digit[0] = '0' + (memp_type%10);
- strcat(errstr, digit);
-#if defined(LWIP_DEBUG) && MEMP_STATS
- strcat(errstr, memp_overflow_names[memp_type]);
-#endif
- LWIP_ASSERT(errstr, 0);
- }
- }
-#endif
-}
-
-/**
- * Do an overflow check for all elements in every pool.
- *
- * @see memp_overflow_check_element for a description of the check
- */
-static void
-memp_overflow_check_all(void)
-{
- u16_t i, j;
- struct memp *p;
-
- p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
- for (i = 0; i < MEMP_MAX; ++i) {
- p = p;
- for (j = 0; j < memp_num[i]; ++j) {
- memp_overflow_check_element_overflow(p, i);
- p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
- }
- }
- p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
- for (i = 0; i < MEMP_MAX; ++i) {
- p = p;
- for (j = 0; j < memp_num[i]; ++j) {
- memp_overflow_check_element_underflow(p, i);
- p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
- }
- }
-}
-
-/**
- * Initialize the restricted areas of all memp elements in every pool.
- */
-static void
-memp_overflow_init(void)
-{
- u16_t i, j;
- struct memp *p;
- u8_t *m;
-
- p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
- for (i = 0; i < MEMP_MAX; ++i) {
- p = p;
- for (j = 0; j < memp_num[i]; ++j) {
-#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
- m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
- memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
-#endif
-#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
- m = (u8_t*)p + MEMP_SIZE + memp_sizes[i];
- memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
-#endif
- p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
- }
- }
-}
-#endif /* MEMP_OVERFLOW_CHECK */
-
-/**
- * Initialize this module.
- *
- * Carves out memp_memory into linked lists for each pool-type.
- */
-void
-memp_init(void)
-{
- struct memp *memp;
- u16_t i, j;
-
- for (i = 0; i < MEMP_MAX; ++i) {
- MEMP_STATS_AVAIL(used, i, 0);
- MEMP_STATS_AVAIL(max, i, 0);
- MEMP_STATS_AVAIL(err, i, 0);
- MEMP_STATS_AVAIL(avail, i, memp_num[i]);
- }
-
-#if !MEMP_SEPARATE_POOLS
- memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
-#endif /* !MEMP_SEPARATE_POOLS */
- /* for every pool: */
- for (i = 0; i < MEMP_MAX; ++i) {
- memp_tab[i] = NULL;
-#if MEMP_SEPARATE_POOLS
- memp = (struct memp*)memp_bases[i];
-#endif /* MEMP_SEPARATE_POOLS */
- /* create a linked list of memp elements */
- for (j = 0; j < memp_num[i]; ++j) {
- memp->next = memp_tab[i];
- memp_tab[i] = memp;
- memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
-#if MEMP_OVERFLOW_CHECK
- + MEMP_SANITY_REGION_AFTER_ALIGNED
-#endif
- );
- }
- }
-#if MEMP_OVERFLOW_CHECK
- memp_overflow_init();
- /* check everything a first time to see if it worked */
- memp_overflow_check_all();
-#endif /* MEMP_OVERFLOW_CHECK */
-}
-
-/**
- * Get an element from a specific pool.
- *
- * @param type the pool to get an element from
- *
- * the debug version has two more parameters:
- * @param file file name calling this function
- * @param line number of line where this function is called
- *
- * @return a pointer to the allocated memory or a NULL pointer on error
- */
-void *
-#if !MEMP_OVERFLOW_CHECK
-memp_malloc(memp_t type)
-#else
-memp_malloc_fn(memp_t type, const char* file, const int line)
-#endif
-{
- struct memp *memp;
- SYS_ARCH_DECL_PROTECT(old_level);
-
- LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
-
- SYS_ARCH_PROTECT(old_level);
-#if MEMP_OVERFLOW_CHECK >= 2
- memp_overflow_check_all();
-#endif /* MEMP_OVERFLOW_CHECK >= 2 */
-
- memp = memp_tab[type];
-
- if (memp != NULL) {
- memp_tab[type] = memp->next;
-#if MEMP_OVERFLOW_CHECK
- memp->next = NULL;
- memp->file = file;
- memp->line = line;
-#endif /* MEMP_OVERFLOW_CHECK */
- MEMP_STATS_INC_USED(used, type);
- LWIP_ASSERT("memp_malloc: memp properly aligned",
- ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
- memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
- } else {
- LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
- MEMP_STATS_INC(err, type);
- }
-
- SYS_ARCH_UNPROTECT(old_level);
-
- return memp;
-}
-
-/**
- * Put an element back into its pool.
- *
- * @param type the pool where to put mem
- * @param mem the memp element to free
- */
-void
-memp_free(memp_t type, void *mem)
-{
- struct memp *memp;
- SYS_ARCH_DECL_PROTECT(old_level);
-
- if (mem == NULL) {
- return;
- }
- LWIP_ASSERT("memp_free: mem properly aligned",
- ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
-
- memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);
-
- SYS_ARCH_PROTECT(old_level);
-#if MEMP_OVERFLOW_CHECK
-#if MEMP_OVERFLOW_CHECK >= 2
- memp_overflow_check_all();
-#else
- memp_overflow_check_element_overflow(memp, type);
- memp_overflow_check_element_underflow(memp, type);
-#endif /* MEMP_OVERFLOW_CHECK >= 2 */
-#endif /* MEMP_OVERFLOW_CHECK */
-
- MEMP_STATS_DEC(used, type);
-
- memp->next = memp_tab[type];
- memp_tab[type] = memp;
-
-#if MEMP_SANITY_CHECK
- LWIP_ASSERT("memp sanity", memp_sanity());
-#endif /* MEMP_SANITY_CHECK */
-
- SYS_ARCH_UNPROTECT(old_level);
-}
-
-#endif /* MEMP_MEM_MALLOC */
+++ /dev/null
-/**
- * @file
- * lwIP network interface abstraction
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-
-#include "lwip/def.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/tcp_impl.h"
-#include "lwip/snmp.h"
-#include "lwip/igmp.h"
-#include "netif/etharp.h"
-#include "lwip/stats.h"
-#if ENABLE_LOOPBACK
-#include "lwip/sys.h"
-#if LWIP_NETIF_LOOPBACK_MULTITHREADING
-#include "lwip/tcpip.h"
-#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
-#endif /* ENABLE_LOOPBACK */
-
-#if LWIP_AUTOIP
-#include "lwip/autoip.h"
-#endif /* LWIP_AUTOIP */
-#if LWIP_DHCP
-#include "lwip/dhcp.h"
-#endif /* LWIP_DHCP */
-
-#if LWIP_NETIF_STATUS_CALLBACK
-#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
-#else
-#define NETIF_STATUS_CALLBACK(n)
-#endif /* LWIP_NETIF_STATUS_CALLBACK */
-
-#if LWIP_NETIF_LINK_CALLBACK
-#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0)
-#else
-#define NETIF_LINK_CALLBACK(n)
-#endif /* LWIP_NETIF_LINK_CALLBACK */
-
-struct netif *netif_list;
-struct netif *netif_default;
-
-#if LWIP_HAVE_LOOPIF
-static struct netif loop_netif;
-
-/**
- * Initialize a lwip network interface structure for a loopback interface
- *
- * @param netif the lwip network interface structure for this loopif
- * @return ERR_OK if the loopif is initialized
- * ERR_MEM if private data couldn't be allocated
- */
-static err_t
-netif_loopif_init(struct netif *netif)
-{
- /* initialize the snmp variables and counters inside the struct netif
- * ifSpeed: no assumption can be made!
- */
- NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0);
-
- netif->name[0] = 'l';
- netif->name[1] = 'o';
- netif->output = netif_loop_output;
- return ERR_OK;
-}
-#endif /* LWIP_HAVE_LOOPIF */
-
-void
-netif_init(void)
-{
-#if LWIP_HAVE_LOOPIF
- ip_addr_t loop_ipaddr, loop_netmask, loop_gw;
- IP4_ADDR(&loop_gw, 127,0,0,1);
- IP4_ADDR(&loop_ipaddr, 127,0,0,1);
- IP4_ADDR(&loop_netmask, 255,0,0,0);
-
-#if NO_SYS
- netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input);
-#else /* NO_SYS */
- netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input);
-#endif /* NO_SYS */
- netif_set_up(&loop_netif);
-
-#endif /* LWIP_HAVE_LOOPIF */
-}
-
-/**
- * Add a network interface to the list of lwIP netifs.
- *
- * @param netif a pre-allocated netif structure
- * @param ipaddr IP address for the new netif
- * @param netmask network mask for the new netif
- * @param gw default gateway IP address for the new netif
- * @param state opaque data passed to the new netif
- * @param init callback function that initializes the interface
- * @param input callback function that is called to pass
- * ingress packets up in the protocol layer stack.
- *
- * @return netif, or NULL if failed.
- */
-struct netif *
-netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
- ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
-{
- static u8_t netifnum = 0;
-
- LWIP_ASSERT("No init function given", init != NULL);
-
- /* reset new interface configuration state */
- ip_addr_set_zero(&netif->ip_addr);
- ip_addr_set_zero(&netif->netmask);
- ip_addr_set_zero(&netif->gw);
- netif->flags = 0;
-#if LWIP_DHCP
- /* netif not under DHCP control by default */
- netif->dhcp = NULL;
-#endif /* LWIP_DHCP */
-#if LWIP_AUTOIP
- /* netif not under AutoIP control by default */
- netif->autoip = NULL;
-#endif /* LWIP_AUTOIP */
-#if LWIP_NETIF_STATUS_CALLBACK
- netif->status_callback = NULL;
-#endif /* LWIP_NETIF_STATUS_CALLBACK */
-#if LWIP_NETIF_LINK_CALLBACK
- netif->link_callback = NULL;
-#endif /* LWIP_NETIF_LINK_CALLBACK */
-#if LWIP_IGMP
- netif->igmp_mac_filter = NULL;
-#endif /* LWIP_IGMP */
-#if ENABLE_LOOPBACK
- netif->loop_first = NULL;
- netif->loop_last = NULL;
-#endif /* ENABLE_LOOPBACK */
-
- /* remember netif specific state information data */
- netif->state = state;
- netif->num = netifnum++;
- netif->input = input;
-#if LWIP_NETIF_HWADDRHINT
- netif->addr_hint = NULL;
-#endif /* LWIP_NETIF_HWADDRHINT*/
-#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
- netif->loop_cnt_current = 0;
-#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
-
- netif_set_addr(netif, ipaddr, netmask, gw);
-
- /* call user specified initialization function for netif */
- if (init(netif) != ERR_OK) {
- return NULL;
- }
-
- /* add this netif to the list */
- netif->next = netif_list;
- netif_list = netif;
- snmp_inc_iflist();
-
-#if LWIP_IGMP
- /* start IGMP processing */
- if (netif->flags & NETIF_FLAG_IGMP) {
- igmp_start(netif);
- }
-#endif /* LWIP_IGMP */
-
- LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",
- netif->name[0], netif->name[1]));
- ip_addr_debug_print(NETIF_DEBUG, ipaddr);
- LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
- ip_addr_debug_print(NETIF_DEBUG, netmask);
- LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
- ip_addr_debug_print(NETIF_DEBUG, gw);
- LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
- return netif;
-}
-
-/**
- * Change IP address configuration for a network interface (including netmask
- * and default gateway).
- *
- * @param netif the network interface to change
- * @param ipaddr the new IP address
- * @param netmask the new netmask
- * @param gw the new default gateway
- */
-void
-netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
- ip_addr_t *gw)
-{
- netif_set_ipaddr(netif, ipaddr);
- netif_set_netmask(netif, netmask);
- netif_set_gw(netif, gw);
-}
-
-/**
- * Remove a network interface from the list of lwIP netifs.
- *
- * @param netif the network interface to remove
- */
-void
-netif_remove(struct netif *netif)
-{
- if (netif == NULL) {
- return;
- }
-
-#if LWIP_IGMP
- /* stop IGMP processing */
- if (netif->flags & NETIF_FLAG_IGMP) {
- igmp_stop(netif);
- }
-#endif /* LWIP_IGMP */
- if (netif_is_up(netif)) {
- /* set netif down before removing (call callback function) */
- netif_set_down(netif);
- }
-
- snmp_delete_ipaddridx_tree(netif);
-
- /* is it the first netif? */
- if (netif_list == netif) {
- netif_list = netif->next;
- } else {
- /* look for netif further down the list */
- struct netif * tmpNetif;
- for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {
- if (tmpNetif->next == netif) {
- tmpNetif->next = netif->next;
- break;
- }
- }
- if (tmpNetif == NULL)
- return; /* we didn't find any netif today */
- }
- snmp_dec_iflist();
- /* this netif is default? */
- if (netif_default == netif) {
- /* reset default netif */
- netif_set_default(NULL);
- }
- LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
-}
-
-/**
- * Find a network interface by searching for its name
- *
- * @param name the name of the netif (like netif->name) plus concatenated number
- * in ascii representation (e.g. 'en0')
- */
-struct netif *
-netif_find(char *name)
-{
- struct netif *netif;
- u8_t num;
-
- if (name == NULL) {
- return NULL;
- }
-
- num = name[2] - '0';
-
- for(netif = netif_list; netif != NULL; netif = netif->next) {
- if (num == netif->num &&
- name[0] == netif->name[0] &&
- name[1] == netif->name[1]) {
- LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));
- return netif;
- }
- }
- LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));
- return NULL;
-}
-
-/**
- * Change the IP address of a network interface
- *
- * @param netif the network interface to change
- * @param ipaddr the new IP address
- *
- * @note call netif_set_addr() if you also want to change netmask and
- * default gateway
- */
-void
-netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
-{
- /* TODO: Handling of obsolete pcbs */
- /* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
-#if LWIP_TCP
- struct tcp_pcb *pcb;
- struct tcp_pcb_listen *lpcb;
-
- /* address is actually being changed? */
- if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
- /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
- LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
- pcb = tcp_active_pcbs;
- while (pcb != NULL) {
- /* PCB bound to current local interface address? */
- if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))
-#if LWIP_AUTOIP
- /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
- && !ip_addr_islinklocal(&(pcb->local_ip))
-#endif /* LWIP_AUTOIP */
- ) {
- /* this connection must be aborted */
- struct tcp_pcb *next = pcb->next;
- LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
- tcp_abort(pcb);
- pcb = next;
- } else {
- pcb = pcb->next;
- }
- }
- for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
- /* PCB bound to current local interface address? */
- if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
- (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
- /* The PCB is listening to the old ipaddr and
- * is set to listen to the new one instead */
- ip_addr_set(&(lpcb->local_ip), ipaddr);
- }
- }
- }
-#endif
- snmp_delete_ipaddridx_tree(netif);
- snmp_delete_iprteidx_tree(0,netif);
- /* set new IP address to netif */
- ip_addr_set(&(netif->ip_addr), ipaddr);
- snmp_insert_ipaddridx_tree(netif);
- snmp_insert_iprteidx_tree(0,netif);
-
- LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- netif->name[0], netif->name[1],
- ip4_addr1_16(&netif->ip_addr),
- ip4_addr2_16(&netif->ip_addr),
- ip4_addr3_16(&netif->ip_addr),
- ip4_addr4_16(&netif->ip_addr)));
-}
-
-/**
- * Change the default gateway for a network interface
- *
- * @param netif the network interface to change
- * @param gw the new default gateway
- *
- * @note call netif_set_addr() if you also want to change ip address and netmask
- */
-void
-netif_set_gw(struct netif *netif, ip_addr_t *gw)
-{
- ip_addr_set(&(netif->gw), gw);
- LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- netif->name[0], netif->name[1],
- ip4_addr1_16(&netif->gw),
- ip4_addr2_16(&netif->gw),
- ip4_addr3_16(&netif->gw),
- ip4_addr4_16(&netif->gw)));
-}
-
-/**
- * Change the netmask of a network interface
- *
- * @param netif the network interface to change
- * @param netmask the new netmask
- *
- * @note call netif_set_addr() if you also want to change ip address and
- * default gateway
- */
-void
-netif_set_netmask(struct netif *netif, ip_addr_t *netmask)
-{
- snmp_delete_iprteidx_tree(0, netif);
- /* set new netmask to netif */
- ip_addr_set(&(netif->netmask), netmask);
- snmp_insert_iprteidx_tree(0, netif);
- LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- netif->name[0], netif->name[1],
- ip4_addr1_16(&netif->netmask),
- ip4_addr2_16(&netif->netmask),
- ip4_addr3_16(&netif->netmask),
- ip4_addr4_16(&netif->netmask)));
-}
-
-/**
- * Set a network interface as the default network interface
- * (used to output all packets for which no specific route is found)
- *
- * @param netif the default network interface
- */
-void
-netif_set_default(struct netif *netif)
-{
- if (netif == NULL) {
- /* remove default route */
- snmp_delete_iprteidx_tree(1, netif);
- } else {
- /* install default route */
- snmp_insert_iprteidx_tree(1, netif);
- }
- netif_default = netif;
- LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",
- netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
-}
-
-/**
- * Bring an interface up, available for processing
- * traffic.
- *
- * @note: Enabling DHCP on a down interface will make it come
- * up once configured.
- *
- * @see dhcp_start()
- */
-void netif_set_up(struct netif *netif)
-{
- if (!(netif->flags & NETIF_FLAG_UP)) {
- netif->flags |= NETIF_FLAG_UP;
-
-#if LWIP_SNMP
- snmp_get_sysuptime(&netif->ts);
-#endif /* LWIP_SNMP */
-
- NETIF_STATUS_CALLBACK(netif);
-
- if (netif->flags & NETIF_FLAG_LINK_UP) {
-#if LWIP_ARP
- /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
- if (netif->flags & (NETIF_FLAG_ETHARP)) {
- etharp_gratuitous(netif);
- }
-#endif /* LWIP_ARP */
-
-#if LWIP_IGMP
- /* resend IGMP memberships */
- if (netif->flags & NETIF_FLAG_IGMP) {
- igmp_report_groups( netif);
- }
-#endif /* LWIP_IGMP */
- }
- }
-}
-
-/**
- * Bring an interface down, disabling any traffic processing.
- *
- * @note: Enabling DHCP on a down interface will make it come
- * up once configured.
- *
- * @see dhcp_start()
- */
-void netif_set_down(struct netif *netif)
-{
- if (netif->flags & NETIF_FLAG_UP) {
- netif->flags &= ~NETIF_FLAG_UP;
-#if LWIP_SNMP
- snmp_get_sysuptime(&netif->ts);
-#endif
-
- NETIF_STATUS_CALLBACK(netif);
- }
-}
-
-#if LWIP_NETIF_STATUS_CALLBACK
-/**
- * Set callback to be called when interface is brought up/down
- */
-void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)
-{
- if (netif) {
- netif->status_callback = status_callback;
- }
-}
-#endif /* LWIP_NETIF_STATUS_CALLBACK */
-
-/**
- * Called by a driver when its link goes up
- */
-void netif_set_link_up(struct netif *netif )
-{
- if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
- netif->flags |= NETIF_FLAG_LINK_UP;
-
-#if LWIP_DHCP
- if (netif->dhcp) {
- dhcp_network_changed(netif);
- }
-#endif /* LWIP_DHCP */
-
-#if LWIP_AUTOIP
- if (netif->autoip) {
- autoip_network_changed(netif);
- }
-#endif /* LWIP_AUTOIP */
-
- if (netif->flags & NETIF_FLAG_UP) {
-#if LWIP_ARP
- /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
- if (netif->flags & NETIF_FLAG_ETHARP) {
- etharp_gratuitous(netif);
- }
-#endif /* LWIP_ARP */
-
-#if LWIP_IGMP
- /* resend IGMP memberships */
- if (netif->flags & NETIF_FLAG_IGMP) {
- igmp_report_groups( netif);
- }
-#endif /* LWIP_IGMP */
- }
- NETIF_LINK_CALLBACK(netif);
- }
-}
-
-/**
- * Called by a driver when its link goes down
- */
-void netif_set_link_down(struct netif *netif )
-{
- if (netif->flags & NETIF_FLAG_LINK_UP) {
- netif->flags &= ~NETIF_FLAG_LINK_UP;
- NETIF_LINK_CALLBACK(netif);
- }
-}
-
-#if LWIP_NETIF_LINK_CALLBACK
-/**
- * Set callback to be called when link is brought up/down
- */
-void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)
-{
- if (netif) {
- netif->link_callback = link_callback;
- }
-}
-#endif /* LWIP_NETIF_LINK_CALLBACK */
-
-#if ENABLE_LOOPBACK
-/**
- * Send an IP packet to be received on the same netif (loopif-like).
- * The pbuf is simply copied and handed back to netif->input.
- * In multithreaded mode, this is done directly since netif->input must put
- * the packet on a queue.
- * In callback mode, the packet is put on an internal queue and is fed to
- * netif->input by netif_poll().
- *
- * @param netif the lwip network interface structure
- * @param p the (IP) packet to 'send'
- * @param ipaddr the ip address to send the packet to (not used)
- * @return ERR_OK if the packet has been sent
- * ERR_MEM if the pbuf used to copy the packet couldn't be allocated
- */
-err_t
-netif_loop_output(struct netif *netif, struct pbuf *p,
- ip_addr_t *ipaddr)
-{
- struct pbuf *r;
- err_t err;
- struct pbuf *last;
-#if LWIP_LOOPBACK_MAX_PBUFS
- u8_t clen = 0;
-#endif /* LWIP_LOOPBACK_MAX_PBUFS */
- /* If we have a loopif, SNMP counters are adjusted for it,
- * if not they are adjusted for 'netif'. */
-#if LWIP_SNMP
-#if LWIP_HAVE_LOOPIF
- struct netif *stats_if = &loop_netif;
-#else /* LWIP_HAVE_LOOPIF */
- struct netif *stats_if = netif;
-#endif /* LWIP_HAVE_LOOPIF */
-#endif /* LWIP_SNMP */
- SYS_ARCH_DECL_PROTECT(lev);
- LWIP_UNUSED_ARG(ipaddr);
-
- /* Allocate a new pbuf */
- r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
- if (r == NULL) {
- LINK_STATS_INC(link.memerr);
- LINK_STATS_INC(link.drop);
- snmp_inc_ifoutdiscards(stats_if);
- return ERR_MEM;
- }
-#if LWIP_LOOPBACK_MAX_PBUFS
- clen = pbuf_clen(r);
- /* check for overflow or too many pbuf on queue */
- if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
- ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
- pbuf_free(r);
- LINK_STATS_INC(link.memerr);
- LINK_STATS_INC(link.drop);
- snmp_inc_ifoutdiscards(stats_if);
- return ERR_MEM;
- }
- netif->loop_cnt_current += clen;
-#endif /* LWIP_LOOPBACK_MAX_PBUFS */
-
- /* Copy the whole pbuf queue p into the single pbuf r */
- if ((err = pbuf_copy(r, p)) != ERR_OK) {
- pbuf_free(r);
- LINK_STATS_INC(link.memerr);
- LINK_STATS_INC(link.drop);
- snmp_inc_ifoutdiscards(stats_if);
- return err;
- }
-
- /* Put the packet on a linked list which gets emptied through calling
- netif_poll(). */
-
- /* let last point to the last pbuf in chain r */
- for (last = r; last->next != NULL; last = last->next);
-
- SYS_ARCH_PROTECT(lev);
- if(netif->loop_first != NULL) {
- LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
- netif->loop_last->next = r;
- netif->loop_last = last;
- } else {
- netif->loop_first = r;
- netif->loop_last = last;
- }
- SYS_ARCH_UNPROTECT(lev);
-
- LINK_STATS_INC(link.xmit);
- snmp_add_ifoutoctets(stats_if, p->tot_len);
- snmp_inc_ifoutucastpkts(stats_if);
-
-#if LWIP_NETIF_LOOPBACK_MULTITHREADING
- /* For multithreading environment, schedule a call to netif_poll */
- tcpip_callback((tcpip_callback_fn)netif_poll, netif);
-#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
-
- return ERR_OK;
-}
-
-/**
- * Call netif_poll() in the main loop of your application. This is to prevent
- * reentering non-reentrant functions like tcp_input(). Packets passed to
- * netif_loop_output() are put on a list that is passed to netif->input() by
- * netif_poll().
- */
-void
-netif_poll(struct netif *netif)
-{
- struct pbuf *in;
- /* If we have a loopif, SNMP counters are adjusted for it,
- * if not they are adjusted for 'netif'. */
-#if LWIP_SNMP
-#if LWIP_HAVE_LOOPIF
- struct netif *stats_if = &loop_netif;
-#else /* LWIP_HAVE_LOOPIF */
- struct netif *stats_if = netif;
-#endif /* LWIP_HAVE_LOOPIF */
-#endif /* LWIP_SNMP */
- SYS_ARCH_DECL_PROTECT(lev);
-
- do {
- /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
- SYS_ARCH_PROTECT(lev);
- in = netif->loop_first;
- if (in != NULL) {
- struct pbuf *in_end = in;
-#if LWIP_LOOPBACK_MAX_PBUFS
- u8_t clen = pbuf_clen(in);
- /* adjust the number of pbufs on queue */
- LWIP_ASSERT("netif->loop_cnt_current underflow",
- ((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
- netif->loop_cnt_current -= clen;
-#endif /* LWIP_LOOPBACK_MAX_PBUFS */
- while (in_end->len != in_end->tot_len) {
- LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
- in_end = in_end->next;
- }
- /* 'in_end' now points to the last pbuf from 'in' */
- if (in_end == netif->loop_last) {
- /* this was the last pbuf in the list */
- netif->loop_first = netif->loop_last = NULL;
- } else {
- /* pop the pbuf off the list */
- netif->loop_first = in_end->next;
- LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
- }
- /* De-queue the pbuf from its successors on the 'loop_' list. */
- in_end->next = NULL;
- }
- SYS_ARCH_UNPROTECT(lev);
-
- if (in != NULL) {
- LINK_STATS_INC(link.recv);
- snmp_add_ifinoctets(stats_if, in->tot_len);
- snmp_inc_ifinucastpkts(stats_if);
- /* loopback packets are always IP packets! */
- if (ip_input(in, netif) != ERR_OK) {
- pbuf_free(in);
- }
- /* Don't reference the packet any more! */
- in = NULL;
- }
- /* go on while there is a packet on the list */
- } while (netif->loop_first != NULL);
-}
-
-#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
-/**
- * Calls netif_poll() for every netif on the netif_list.
- */
-void
-netif_poll_all(void)
-{
- struct netif *netif = netif_list;
- /* loop through netifs */
- while (netif != NULL) {
- netif_poll(netif);
- /* proceed to next network interface */
- netif = netif->next;
- }
-}
-#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
-#endif /* ENABLE_LOOPBACK */
+++ /dev/null
-/**
- * @file
- * Packet buffer management
- *
- * Packets are built from the pbuf data structure. It supports dynamic
- * memory allocation for packet contents or can reference externally
- * managed packet contents both in RAM and ROM. Quick allocation for
- * incoming packets is provided through pools with fixed sized pbufs.
- *
- * A packet may span over multiple pbufs, chained as a singly linked
- * list. This is called a "pbuf chain".
- *
- * Multiple packets may be queued, also using this singly linked list.
- * This is called a "packet queue".
- *
- * So, a packet queue consists of one or more pbuf chains, each of
- * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE
- * NOT SUPPORTED!!! Use helper structs to queue multiple packets.
- *
- * The differences between a pbuf chain and a packet queue are very
- * precise but subtle.
- *
- * The last pbuf of a packet has a ->tot_len field that equals the
- * ->len field. It can be found by traversing the list. If the last
- * pbuf of a packet has a ->next field other than NULL, more packets
- * are on the queue.
- *
- * Therefore, looping through a pbuf of a single packet, has an
- * loop end condition (tot_len == p->len), NOT (next == NULL).
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-
-#include "lwip/stats.h"
-#include "lwip/def.h"
-#include "lwip/mem.h"
-#include "lwip/memp.h"
-#include "lwip/pbuf.h"
-#include "lwip/sys.h"
-#include "arch/perf.h"
-#if TCP_QUEUE_OOSEQ
-#include "lwip/tcp_impl.h"
-#endif
-#if LWIP_CHECKSUM_ON_COPY
-#include "lwip/inet_chksum.h"
-#endif
-
-#include <string.h>
-
-#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
-/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically
- aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
-#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
-
-#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS
-#define PBUF_POOL_IS_EMPTY()
-#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
-/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
-#ifndef PBUF_POOL_FREE_OOSEQ
-#define PBUF_POOL_FREE_OOSEQ 1
-#endif /* PBUF_POOL_FREE_OOSEQ */
-
-#if PBUF_POOL_FREE_OOSEQ
-#include "lwip/tcpip.h"
-#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
-static u8_t pbuf_free_ooseq_queued;
-/**
- * Attempt to reclaim some memory from queued out-of-sequence TCP segments
- * if we run out of pool pbufs. It's better to give priority to new packets
- * if we're running out.
- *
- * This must be done in the correct thread context therefore this function
- * can only be used with NO_SYS=0 and through tcpip_callback.
- */
-static void
-pbuf_free_ooseq(void* arg)
-{
- struct tcp_pcb* pcb;
- SYS_ARCH_DECL_PROTECT(old_level);
- LWIP_UNUSED_ARG(arg);
-
- SYS_ARCH_PROTECT(old_level);
- pbuf_free_ooseq_queued = 0;
- SYS_ARCH_UNPROTECT(old_level);
-
- for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
- if (NULL != pcb->ooseq) {
- /** Free the ooseq pbufs of one PCB only */
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
- tcp_segs_free(pcb->ooseq);
- pcb->ooseq = NULL;
- return;
- }
- }
-}
-
-/** Queue a call to pbuf_free_ooseq if not already queued. */
-static void
-pbuf_pool_is_empty(void)
-{
- u8_t queued;
- SYS_ARCH_DECL_PROTECT(old_level);
-
- SYS_ARCH_PROTECT(old_level);
- queued = pbuf_free_ooseq_queued;
- pbuf_free_ooseq_queued = 1;
- SYS_ARCH_UNPROTECT(old_level);
-
- if(!queued) {
- /* queue a call to pbuf_free_ooseq if not already queued */
- if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
- SYS_ARCH_PROTECT(old_level);
- pbuf_free_ooseq_queued = 0;
- SYS_ARCH_UNPROTECT(old_level);
- }
- }
-}
-#endif /* PBUF_POOL_FREE_OOSEQ */
-#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
-
-/**
- * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
- *
- * The actual memory allocated for the pbuf is determined by the
- * layer at which the pbuf is allocated and the requested size
- * (from the size parameter).
- *
- * @param layer flag to define header size
- * @param length size of the pbuf's payload
- * @param type this parameter decides how and where the pbuf
- * should be allocated as follows:
- *
- * - PBUF_RAM: buffer memory for pbuf is allocated as one large
- * chunk. This includes protocol headers as well.
- * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
- * protocol headers. Additional headers must be prepended
- * by allocating another pbuf and chain in to the front of
- * the ROM pbuf. It is assumed that the memory used is really
- * similar to ROM in that it is immutable and will not be
- * changed. Memory which is dynamic should generally not
- * be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
- * - PBUF_REF: no buffer memory is allocated for the pbuf, even for
- * protocol headers. It is assumed that the pbuf is only
- * being used in a single thread. If the pbuf gets queued,
- * then pbuf_take should be called to copy the buffer.
- * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
- * the pbuf pool that is allocated during pbuf_init().
- *
- * @return the allocated pbuf. If multiple pbufs where allocated, this
- * is the first pbuf of a pbuf chain.
- */
-struct pbuf *
-pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
-{
- struct pbuf *p, *q, *r;
- u16_t offset;
- s32_t rem_len; /* remaining length */
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
-
- /* determine header offset */
- offset = 0;
- switch (layer) {
- case PBUF_TRANSPORT:
- /* add room for transport (often TCP) layer header */
- offset += PBUF_TRANSPORT_HLEN;
- /* FALLTHROUGH */
- case PBUF_IP:
- /* add room for IP layer header */
- offset += PBUF_IP_HLEN;
- /* FALLTHROUGH */
- case PBUF_LINK:
- /* add room for link layer header */
- offset += PBUF_LINK_HLEN;
- break;
- case PBUF_RAW:
- break;
- default:
- LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
- return NULL;
- }
-
- switch (type) {
- case PBUF_POOL:
- /* allocate head of pbuf chain into p */
- p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
- if (p == NULL) {
- PBUF_POOL_IS_EMPTY();
- return NULL;
- }
- p->type = type;
- p->next = NULL;
-
- /* make the payload pointer point 'offset' bytes into pbuf data memory */
- p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
- LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
- ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
- /* the total length of the pbuf chain is the requested size */
- p->tot_len = length;
- /* set the length of the first pbuf in the chain */
- p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));
- LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
- ((u8_t*)p->payload + p->len <=
- (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
- LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
- (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );
- /* set reference count (needed here in case we fail) */
- p->ref = 1;
-
- /* now allocate the tail of the pbuf chain */
-
- /* remember first pbuf for linkage in next iteration */
- r = p;
- /* remaining length to be allocated */
- rem_len = length - p->len;
- /* any remaining pbufs to be allocated? */
- while (rem_len > 0) {
- q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
- if (q == NULL) {
- PBUF_POOL_IS_EMPTY();
- /* free chain so far allocated */
- pbuf_free(p);
- /* bail out unsuccesfully */
- return NULL;
- }
- q->type = type;
- q->flags = 0;
- q->next = NULL;
- /* make previous pbuf point to this pbuf */
- r->next = q;
- /* set total length of this pbuf and next in chain */
- LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
- q->tot_len = (u16_t)rem_len;
- /* this pbuf length is pool size, unless smaller sized tail */
- q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
- q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);
- LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
- ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
- LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
- ((u8_t*)p->payload + p->len <=
- (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
- q->ref = 1;
- /* calculate remaining length to be allocated */
- rem_len -= q->len;
- /* remember this pbuf for linkage in next iteration */
- r = q;
- }
- /* end of chain */
- /*r->next = NULL;*/
-
- break;
- case PBUF_RAM:
- /* If pbuf is to be allocated in RAM, allocate memory for it. */
- p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
- if (p == NULL) {
- return NULL;
- }
- /* Set up internal structure of the pbuf. */
- p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));
- p->len = p->tot_len = length;
- p->next = NULL;
- p->type = type;
-
- LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
- ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
- break;
- /* pbuf references existing (non-volatile static constant) ROM payload? */
- case PBUF_ROM:
- /* pbuf references existing (externally allocated) RAM payload? */
- case PBUF_REF:
- /* only allocate memory for the pbuf structure */
- p = (struct pbuf *)memp_malloc(MEMP_PBUF);
- if (p == NULL) {
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
- ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
- (type == PBUF_ROM) ? "ROM" : "REF"));
- return NULL;
- }
- /* caller must set this field properly, afterwards */
- p->payload = NULL;
- p->len = p->tot_len = length;
- p->next = NULL;
- p->type = type;
- break;
- default:
- LWIP_ASSERT("pbuf_alloc: erroneous type", 0);
- return NULL;
- }
- /* set reference count */
- p->ref = 1;
- /* set flags */
- p->flags = 0;
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
- return p;
-}
-
-#if LWIP_SUPPORT_CUSTOM_PBUF
-/** Initialize a custom pbuf (already allocated).
- *
- * @param layer flag to define header size
- * @param length size of the pbuf's payload
- * @param type type of the pbuf (only used to treat the pbuf accordingly, as
- * this function allocates no memory)
- * @param p pointer to the custom pbuf to initialize (already allocated)
- * @param payload_mem pointer to the buffer that is used for payload and headers,
- * must be at least big enough to hold 'length' plus the header size,
- * may be NULL if set later
- * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least
- * big enough to hold 'length' plus the header size
- */
-struct pbuf*
-pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p,
- void *payload_mem, u16_t payload_mem_len)
-{
- u16_t offset;
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
-
- /* determine header offset */
- offset = 0;
- switch (l) {
- case PBUF_TRANSPORT:
- /* add room for transport (often TCP) layer header */
- offset += PBUF_TRANSPORT_HLEN;
- /* FALLTHROUGH */
- case PBUF_IP:
- /* add room for IP layer header */
- offset += PBUF_IP_HLEN;
- /* FALLTHROUGH */
- case PBUF_LINK:
- /* add room for link layer header */
- offset += PBUF_LINK_HLEN;
- break;
- case PBUF_RAW:
- break;
- default:
- LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
- return NULL;
- }
-
- if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
- return NULL;
- }
-
- p->pbuf.next = NULL;
- if (payload_mem != NULL) {
- p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset));
- } else {
- p->pbuf.payload = NULL;
- }
- p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;
- p->pbuf.len = p->pbuf.tot_len = length;
- p->pbuf.type = type;
- p->pbuf.ref = 1;
- return &p->pbuf;
-}
-#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
-
-/**
- * Shrink a pbuf chain to a desired length.
- *
- * @param p pbuf to shrink.
- * @param new_len desired new length of pbuf chain
- *
- * Depending on the desired length, the first few pbufs in a chain might
- * be skipped and left unchanged. The new last pbuf in the chain will be
- * resized, and any remaining pbufs will be freed.
- *
- * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
- * @note May not be called on a packet queue.
- *
- * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).
- */
-void
-pbuf_realloc(struct pbuf *p, u16_t new_len)
-{
- struct pbuf *q;
- u16_t rem_len; /* remaining length */
- s32_t grow;
-
- LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
- LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
- p->type == PBUF_ROM ||
- p->type == PBUF_RAM ||
- p->type == PBUF_REF);
-
- /* desired length larger than current length? */
- if (new_len >= p->tot_len) {
- /* enlarging not yet supported */
- return;
- }
-
- /* the pbuf chain grows by (new_len - p->tot_len) bytes
- * (which may be negative in case of shrinking) */
- grow = new_len - p->tot_len;
-
- /* first, step over any pbufs that should remain in the chain */
- rem_len = new_len;
- q = p;
- /* should this pbuf be kept? */
- while (rem_len > q->len) {
- /* decrease remaining length by pbuf length */
- rem_len -= q->len;
- /* decrease total length indicator */
- LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);
- q->tot_len += (u16_t)grow;
- /* proceed to next pbuf in chain */
- q = q->next;
- LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
- }
- /* we have now reached the new last pbuf (in q) */
- /* rem_len == desired length for pbuf q */
-
- /* shrink allocated memory for PBUF_RAM */
- /* (other types merely adjust their length fields */
- if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
- /* reallocate and adjust the length of the pbuf that will be split */
- q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len);
- LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
- }
- /* adjust length fields for new last pbuf */
- q->len = rem_len;
- q->tot_len = q->len;
-
- /* any remaining pbufs in chain? */
- if (q->next != NULL) {
- /* free remaining pbufs in chain */
- pbuf_free(q->next);
- }
- /* q is last packet in chain */
- q->next = NULL;
-
-}
-
-/**
- * Adjusts the payload pointer to hide or reveal headers in the payload.
- *
- * Adjusts the ->payload pointer so that space for a header
- * (dis)appears in the pbuf payload.
- *
- * The ->payload, ->tot_len and ->len fields are adjusted.
- *
- * @param p pbuf to change the header size.
- * @param header_size_increment Number of bytes to increment header size which
- * increases the size of the pbuf. New space is on the front.
- * (Using a negative value decreases the header size.)
- * If hdr_size_inc is 0, this function does nothing and returns succesful.
- *
- * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
- * the call will fail. A check is made that the increase in header size does
- * not move the payload pointer in front of the start of the buffer.
- * @return non-zero on failure, zero on success.
- *
- */
-u8_t
-pbuf_header(struct pbuf *p, s16_t header_size_increment)
-{
- u16_t type;
- void *payload;
- u16_t increment_magnitude;
-
- LWIP_ASSERT("p != NULL", p != NULL);
- if ((header_size_increment == 0) || (p == NULL)) {
- return 0;
- }
-
- if (header_size_increment < 0){
- increment_magnitude = -header_size_increment;
- /* Check that we aren't going to move off the end of the pbuf */
- LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
- } else {
- increment_magnitude = header_size_increment;
-#if 0
- /* Can't assert these as some callers speculatively call
- pbuf_header() to see if it's OK. Will return 1 below instead. */
- /* Check that we've got the correct type of pbuf to work with */
- LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",
- p->type == PBUF_RAM || p->type == PBUF_POOL);
- /* Check that we aren't going to move off the beginning of the pbuf */
- LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",
- (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);
-#endif
- }
-
- type = p->type;
- /* remember current payload pointer */
- payload = p->payload;
-
- /* pbuf types containing payloads? */
- if (type == PBUF_RAM || type == PBUF_POOL) {
- /* set new payload pointer */
- p->payload = (u8_t *)p->payload - header_size_increment;
- /* boundary check fails? */
- if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
- LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
- ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
- (void *)p->payload, (void *)(p + 1)));
- /* restore old payload pointer */
- p->payload = payload;
- /* bail out unsuccesfully */
- return 1;
- }
- /* pbuf types refering to external payloads? */
- } else if (type == PBUF_REF || type == PBUF_ROM) {
- /* hide a header in the payload? */
- if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
- /* increase payload pointer */
- p->payload = (u8_t *)p->payload - header_size_increment;
- } else {
- /* cannot expand payload to front (yet!)
- * bail out unsuccesfully */
- return 1;
- }
- } else {
- /* Unknown type */
- LWIP_ASSERT("bad pbuf type", 0);
- return 1;
- }
- /* modify pbuf length fields */
- p->len += header_size_increment;
- p->tot_len += header_size_increment;
-
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
- (void *)payload, (void *)p->payload, header_size_increment));
-
- return 0;
-}
-
-/**
- * Dereference a pbuf chain or queue and deallocate any no-longer-used
- * pbufs at the head of this chain or queue.
- *
- * Decrements the pbuf reference count. If it reaches zero, the pbuf is
- * deallocated.
- *
- * For a pbuf chain, this is repeated for each pbuf in the chain,
- * up to the first pbuf which has a non-zero reference count after
- * decrementing. So, when all reference counts are one, the whole
- * chain is free'd.
- *
- * @param p The pbuf (chain) to be dereferenced.
- *
- * @return the number of pbufs that were de-allocated
- * from the head of the chain.
- *
- * @note MUST NOT be called on a packet queue (Not verified to work yet).
- * @note the reference counter of a pbuf equals the number of pointers
- * that refer to the pbuf (or into the pbuf).
- *
- * @internal examples:
- *
- * Assuming existing chains a->b->c with the following reference
- * counts, calling pbuf_free(a) results in:
- *
- * 1->2->3 becomes ...1->3
- * 3->3->3 becomes 2->3->3
- * 1->1->2 becomes ......1
- * 2->1->1 becomes 1->1->1
- * 1->1->1 becomes .......
- *
- */
-u8_t
-pbuf_free(struct pbuf *p)
-{
- u16_t type;
- struct pbuf *q;
- u8_t count;
-
- if (p == NULL) {
- LWIP_ASSERT("p != NULL", p != NULL);
- /* if assertions are disabled, proceed with debug output */
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
- ("pbuf_free(p == NULL) was called.\n"));
- return 0;
- }
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
-
- PERF_START;
-
- LWIP_ASSERT("pbuf_free: sane type",
- p->type == PBUF_RAM || p->type == PBUF_ROM ||
- p->type == PBUF_REF || p->type == PBUF_POOL);
-
- count = 0;
- /* de-allocate all consecutive pbufs from the head of the chain that
- * obtain a zero reference count after decrementing*/
- while (p != NULL) {
- u16_t ref;
- SYS_ARCH_DECL_PROTECT(old_level);
- /* Since decrementing ref cannot be guaranteed to be a single machine operation
- * we must protect it. We put the new ref into a local variable to prevent
- * further protection. */
- SYS_ARCH_PROTECT(old_level);
- /* all pbufs in a chain are referenced at least once */
- LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
- /* decrease reference count (number of pointers to pbuf) */
- ref = --(p->ref);
- SYS_ARCH_UNPROTECT(old_level);
- /* this pbuf is no longer referenced to? */
- if (ref == 0) {
- /* remember next pbuf in chain for next iteration */
- q = p->next;
- LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
- type = p->type;
-#if LWIP_SUPPORT_CUSTOM_PBUF
- /* is this a custom pbuf? */
- if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {
- struct pbuf_custom *pc = (struct pbuf_custom*)p;
- LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL);
- pc->custom_free_function(p);
- } else
-#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
- {
- /* is this a pbuf from the pool? */
- if (type == PBUF_POOL) {
- memp_free(MEMP_PBUF_POOL, p);
- /* is this a ROM or RAM referencing pbuf? */
- } else if (type == PBUF_ROM || type == PBUF_REF) {
- memp_free(MEMP_PBUF, p);
- /* type == PBUF_RAM */
- } else {
- mem_free(p);
- }
- }
- count++;
- /* proceed to next pbuf */
- p = q;
- /* p->ref > 0, this pbuf is still referenced to */
- /* (and so the remaining pbufs in chain as well) */
- } else {
- LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
- /* stop walking through the chain */
- p = NULL;
- }
- }
- PERF_STOP("pbuf_free");
- /* return number of de-allocated pbufs */
- return count;
-}
-
-/**
- * Count number of pbufs in a chain
- *
- * @param p first pbuf of chain
- * @return the number of pbufs in a chain
- */
-
-u8_t
-pbuf_clen(struct pbuf *p)
-{
- u8_t len;
-
- len = 0;
- while (p != NULL) {
- ++len;
- p = p->next;
- }
- return len;
-}
-
-/**
- * Increment the reference count of the pbuf.
- *
- * @param p pbuf to increase reference counter of
- *
- */
-void
-pbuf_ref(struct pbuf *p)
-{
- SYS_ARCH_DECL_PROTECT(old_level);
- /* pbuf given? */
- if (p != NULL) {
- SYS_ARCH_PROTECT(old_level);
- ++(p->ref);
- SYS_ARCH_UNPROTECT(old_level);
- }
-}
-
-/**
- * Concatenate two pbufs (each may be a pbuf chain) and take over
- * the caller's reference of the tail pbuf.
- *
- * @note The caller MAY NOT reference the tail pbuf afterwards.
- * Use pbuf_chain() for that purpose.
- *
- * @see pbuf_chain()
- */
-
-void
-pbuf_cat(struct pbuf *h, struct pbuf *t)
-{
- struct pbuf *p;
-
- LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
- ((h != NULL) && (t != NULL)), return;);
-
- /* proceed to last pbuf of chain */
- for (p = h; p->next != NULL; p = p->next) {
- /* add total length of second chain to all totals of first chain */
- p->tot_len += t->tot_len;
- }
- /* { p is last pbuf of first h chain, p->next == NULL } */
- LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
- LWIP_ASSERT("p->next == NULL", p->next == NULL);
- /* add total length of second chain to last pbuf total of first chain */
- p->tot_len += t->tot_len;
- /* chain last pbuf of head (p) with first of tail (t) */
- p->next = t;
- /* p->next now references t, but the caller will drop its reference to t,
- * so netto there is no change to the reference count of t.
- */
-}
-
-/**
- * Chain two pbufs (or pbuf chains) together.
- *
- * The caller MUST call pbuf_free(t) once it has stopped
- * using it. Use pbuf_cat() instead if you no longer use t.
- *
- * @param h head pbuf (chain)
- * @param t tail pbuf (chain)
- * @note The pbufs MUST belong to the same packet.
- * @note MAY NOT be called on a packet queue.
- *
- * The ->tot_len fields of all pbufs of the head chain are adjusted.
- * The ->next field of the last pbuf of the head chain is adjusted.
- * The ->ref field of the first pbuf of the tail chain is adjusted.
- *
- */
-void
-pbuf_chain(struct pbuf *h, struct pbuf *t)
-{
- pbuf_cat(h, t);
- /* t is now referenced by h */
- pbuf_ref(t);
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
-}
-
-/**
- * Dechains the first pbuf from its succeeding pbufs in the chain.
- *
- * Makes p->tot_len field equal to p->len.
- * @param p pbuf to dechain
- * @return remainder of the pbuf chain, or NULL if it was de-allocated.
- * @note May not be called on a packet queue.
- */
-struct pbuf *
-pbuf_dechain(struct pbuf *p)
-{
- struct pbuf *q;
- u8_t tail_gone = 1;
- /* tail */
- q = p->next;
- /* pbuf has successor in chain? */
- if (q != NULL) {
- /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
- LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
- /* enforce invariant if assertion is disabled */
- q->tot_len = p->tot_len - p->len;
- /* decouple pbuf from remainder */
- p->next = NULL;
- /* total length of pbuf p is its own length only */
- p->tot_len = p->len;
- /* q is no longer referenced by p, free it */
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
- tail_gone = pbuf_free(q);
- if (tail_gone > 0) {
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
- ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
- }
- /* return remaining tail or NULL if deallocated */
- }
- /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
- LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
- return ((tail_gone > 0) ? NULL : q);
-}
-
-/**
- *
- * Create PBUF_RAM copies of pbufs.
- *
- * Used to queue packets on behalf of the lwIP stack, such as
- * ARP based queueing.
- *
- * @note You MUST explicitly use p = pbuf_take(p);
- *
- * @note Only one packet is copied, no packet queue!
- *
- * @param p_to pbuf destination of the copy
- * @param p_from pbuf source of the copy
- *
- * @return ERR_OK if pbuf was copied
- * ERR_ARG if one of the pbufs is NULL or p_to is not big
- * enough to hold p_from
- */
-err_t
-pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
-{
- u16_t offset_to=0, offset_from=0, len;
-
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
- (void*)p_to, (void*)p_from));
-
- /* is the target big enough to hold the source? */
- LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
- (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);
-
- /* iterate through pbuf chain */
- do
- {
- LWIP_ASSERT("p_to != NULL", p_to != NULL);
- /* copy one part of the original chain */
- if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
- /* complete current p_from fits into current p_to */
- len = p_from->len - offset_from;
- } else {
- /* current p_from does not fit into current p_to */
- len = p_to->len - offset_to;
- }
- MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);
- offset_to += len;
- offset_from += len;
- LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
- if (offset_to == p_to->len) {
- /* on to next p_to (if any) */
- offset_to = 0;
- p_to = p_to->next;
- }
- LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
- if (offset_from >= p_from->len) {
- /* on to next p_from (if any) */
- offset_from = 0;
- p_from = p_from->next;
- }
-
- if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
- /* don't copy more than one packet! */
- LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
- (p_from->next == NULL), return ERR_VAL;);
- }
- if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
- /* don't copy more than one packet! */
- LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
- (p_to->next == NULL), return ERR_VAL;);
- }
- } while (p_from);
- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
- return ERR_OK;
-}
-
-/**
- * Copy (part of) the contents of a packet buffer
- * to an application supplied buffer.
- *
- * @param buf the pbuf from which to copy data
- * @param dataptr the application supplied buffer
- * @param len length of data to copy (dataptr must be big enough). No more
- * than buf->tot_len will be copied, irrespective of len
- * @param offset offset into the packet buffer from where to begin copying len bytes
- * @return the number of bytes copied, or 0 on failure
- */
-u16_t
-pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
-{
- struct pbuf *p;
- u16_t left;
- u16_t buf_copy_len;
- u16_t copied_total = 0;
-
- LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
- LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
-
- left = 0;
-
- if((buf == NULL) || (dataptr == NULL)) {
- return 0;
- }
-
- /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
- for(p = buf; len != 0 && p != NULL; p = p->next) {
- if ((offset != 0) && (offset >= p->len)) {
- /* don't copy from this buffer -> on to the next */
- offset -= p->len;
- } else {
- /* copy from this buffer. maybe only partially. */
- buf_copy_len = p->len - offset;
- if (buf_copy_len > len)
- buf_copy_len = len;
- /* copy the necessary parts of the buffer */
- MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
- copied_total += buf_copy_len;
- left += buf_copy_len;
- len -= buf_copy_len;
- offset = 0;
- }
- }
- return copied_total;
-}
-
-/**
- * Copy application supplied data into a pbuf.
- * This function can only be used to copy the equivalent of buf->tot_len data.
- *
- * @param buf pbuf to fill with data
- * @param dataptr application supplied data buffer
- * @param len length of the application supplied data buffer
- *
- * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
- */
-err_t
-pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
-{
- struct pbuf *p;
- u16_t buf_copy_len;
- u16_t total_copy_len = len;
- u16_t copied_total = 0;
-
- LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
- LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
-
- if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
- return ERR_ARG;
- }
-
- /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
- for(p = buf; total_copy_len != 0; p = p->next) {
- LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
- buf_copy_len = total_copy_len;
- if (buf_copy_len > p->len) {
- /* this pbuf cannot hold all remaining data */
- buf_copy_len = p->len;
- }
- /* copy the necessary parts of the buffer */
- MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
- total_copy_len -= buf_copy_len;
- copied_total += buf_copy_len;
- }
- LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
- return ERR_OK;
-}
-
-/**
- * Creates a single pbuf out of a queue of pbufs.
- *
- * @remark: Either the source pbuf 'p' is freed by this function or the original
- * pbuf 'p' is returned, therefore the caller has to check the result!
- *
- * @param p the source pbuf
- * @param layer pbuf_layer of the new pbuf
- *
- * @return a new, single pbuf (p->next is NULL)
- * or the old pbuf if allocation fails
- */
-struct pbuf*
-pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
-{
- struct pbuf *q;
- err_t err;
- if (p->next == NULL) {
- return p;
- }
- q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
- if (q == NULL) {
- /* @todo: what do we do now? */
- return p;
- }
- err = pbuf_copy(q, p);
- LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
- pbuf_free(p);
- return q;
-}
-
-#if LWIP_CHECKSUM_ON_COPY
-/**
- * Copies data into a single pbuf (*not* into a pbuf queue!) and updates
- * the checksum while copying
- *
- * @param p the pbuf to copy data into
- * @param start_offset offset of p->payload where to copy the data to
- * @param dataptr data to copy into the pbuf
- * @param len length of data to copy into the pbuf
- * @param chksum pointer to the checksum which is updated
- * @return ERR_OK if successful, another error if the data does not fit
- * within the (first) pbuf (no pbuf queues!)
- */
-err_t
-pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
- u16_t len, u16_t *chksum)
-{
- u32_t acc;
- u16_t copy_chksum;
- char *dst_ptr;
- LWIP_ASSERT("p != NULL", p != NULL);
- LWIP_ASSERT("dataptr != NULL", dataptr != NULL);
- LWIP_ASSERT("chksum != NULL", chksum != NULL);
- LWIP_ASSERT("len != 0", len != 0);
-
- if ((start_offset >= p->len) || (start_offset + len > p->len)) {
- return ERR_ARG;
- }
-
- dst_ptr = ((char*)p->payload) + start_offset;
- copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);
- if ((start_offset & 1) != 0) {
- copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);
- }
- acc = *chksum;
- acc += copy_chksum;
- *chksum = FOLD_U32T(acc);
- return ERR_OK;
-}
-#endif /* LWIP_CHECKSUM_ON_COPY */
-
- /** Get one byte from the specified position in a pbuf
- * WARNING: returns zero for offset >= p->tot_len
- *
- * @param p pbuf to parse
- * @param offset offset into p of the byte to return
- * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len
- */
-u8_t
-pbuf_get_at(struct pbuf* p, u16_t offset)
-{
- u16_t copy_from = offset;
- struct pbuf* q = p;
-
- /* get the correct pbuf */
- while ((q != NULL) && (q->len <= copy_from)) {
- copy_from -= q->len;
- q = q->next;
- }
- /* return requested data if pbuf is OK */
- if ((q != NULL) && (q->len > copy_from)) {
- return ((u8_t*)q->payload)[copy_from];
- }
- return 0;
-}
-
-/** Compare pbuf contents at specified offset with memory s2, both of length n
- *
- * @param p pbuf to compare
- * @param offset offset into p at wich to start comparing
- * @param s2 buffer to compare
- * @param n length of buffer to compare
- * @return zero if equal, nonzero otherwise
- * (0xffff if p is too short, diffoffset+1 otherwise)
- */
-u16_t
-pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
-{
- u16_t start = offset;
- struct pbuf* q = p;
-
- /* get the correct pbuf */
- while ((q != NULL) && (q->len <= start)) {
- start -= q->len;
- q = q->next;
- }
- /* return requested data if pbuf is OK */
- if ((q != NULL) && (q->len > start)) {
- u16_t i;
- for(i = 0; i < n; i++) {
- u8_t a = pbuf_get_at(q, start + i);
- u8_t b = ((u8_t*)s2)[i];
- if (a != b) {
- return i+1;
- }
- }
- return 0;
- }
- return 0xffff;
-}
-
-/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset
- * start_offset.
- *
- * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
- * return value 'not found'
- * @param mem search for the contents of this buffer
- * @param mem_len length of 'mem'
- * @param start_offset offset into p at which to start searching
- * @return 0xFFFF if substr was not found in p or the index where it was found
- */
-u16_t
-pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)
-{
- u16_t i;
- u16_t max = p->tot_len - mem_len;
- if (p->tot_len >= mem_len + start_offset) {
- for(i = start_offset; i <= max; ) {
- u16_t plus = pbuf_memcmp(p, i, mem, mem_len);
- if (plus == 0) {
- return i;
- } else {
- i += plus;
- }
- }
- }
- return 0xFFFF;
-}
-
-/** Find occurrence of substr with length substr_len in pbuf p, start at offset
- * start_offset
- * WARNING: in contrast to strstr(), this one does not stop at the first \0 in
- * the pbuf/source string!
- *
- * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
- * return value 'not found'
- * @param substr string to search for in p, maximum length is 0xFFFE
- * @return 0xFFFF if substr was not found in p or the index where it was found
- */
-u16_t
-pbuf_strstr(struct pbuf* p, const char* substr)
-{
- size_t substr_len;
- if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {
- return 0xFFFF;
- }
- substr_len = strlen(substr);
- if (substr_len >= 0xFFFF) {
- return 0xFFFF;
- }
- return pbuf_memfind(p, substr, (u16_t)substr_len, 0);
-}
+++ /dev/null
-/**
- * @file
- * Implementation of raw protocol PCBs for low-level handling of
- * different types of protocols besides (or overriding) those
- * already available in lwIP.
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/def.h"
-#include "lwip/memp.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/raw.h"
-#include "lwip/stats.h"
-#include "arch/perf.h"
-
-#include <string.h>
-
-/** The list of RAW PCBs */
-static struct raw_pcb *raw_pcbs;
-
-/**
- * Determine if in incoming IP packet is covered by a RAW PCB
- * and if so, pass it to a user-provided receive callback function.
- *
- * Given an incoming IP datagram (as a chain of pbufs) this function
- * finds a corresponding RAW PCB and calls the corresponding receive
- * callback function.
- *
- * @param p pbuf to be demultiplexed to a RAW PCB.
- * @param inp network interface on which the datagram was received.
- * @return - 1 if the packet has been eaten by a RAW PCB receive
- * callback function. The caller MAY NOT not reference the
- * packet any longer, and MAY NOT call pbuf_free().
- * @return - 0 if packet is not eaten (pbuf is still referenced by the
- * caller).
- *
- */
-u8_t
-raw_input(struct pbuf *p, struct netif *inp)
-{
- struct raw_pcb *pcb, *prev;
- struct ip_hdr *iphdr;
- s16_t proto;
- u8_t eaten = 0;
-
- LWIP_UNUSED_ARG(inp);
-
- iphdr = (struct ip_hdr *)p->payload;
- proto = IPH_PROTO(iphdr);
-
- prev = NULL;
- pcb = raw_pcbs;
- /* loop through all raw pcbs until the packet is eaten by one */
- /* this allows multiple pcbs to match against the packet by design */
- while ((eaten == 0) && (pcb != NULL)) {
- if ((pcb->protocol == proto) &&
- (ip_addr_isany(&pcb->local_ip) ||
- ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest))) {
-#if IP_SOF_BROADCAST_RECV
- /* broadcast filter? */
- if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(¤t_iphdr_dest, inp))
-#endif /* IP_SOF_BROADCAST_RECV */
- {
- /* receive callback function available? */
- if (pcb->recv != NULL) {
- /* the receive callback function did not eat the packet? */
- if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) {
- /* receive function ate the packet */
- p = NULL;
- eaten = 1;
- if (prev != NULL) {
- /* move the pcb to the front of raw_pcbs so that is
- found faster next time */
- prev->next = pcb->next;
- pcb->next = raw_pcbs;
- raw_pcbs = pcb;
- }
- }
- }
- /* no receive callback function was set for this raw PCB */
- }
- /* drop the packet */
- }
- prev = pcb;
- pcb = pcb->next;
- }
- return eaten;
-}
-
-/**
- * Bind a RAW PCB.
- *
- * @param pcb RAW PCB to be bound with a local address ipaddr.
- * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
- * bind to all local interfaces.
- *
- * @return lwIP error code.
- * - ERR_OK. Successful. No error occured.
- * - ERR_USE. The specified IP address is already bound to by
- * another RAW PCB.
- *
- * @see raw_disconnect()
- */
-err_t
-raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
-{
- ip_addr_set(&pcb->local_ip, ipaddr);
- return ERR_OK;
-}
-
-/**
- * Connect an RAW PCB. This function is required by upper layers
- * of lwip. Using the raw api you could use raw_sendto() instead
- *
- * This will associate the RAW PCB with the remote address.
- *
- * @param pcb RAW PCB to be connected with remote address ipaddr and port.
- * @param ipaddr remote IP address to connect with.
- *
- * @return lwIP error code
- *
- * @see raw_disconnect() and raw_sendto()
- */
-err_t
-raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
-{
- ip_addr_set(&pcb->remote_ip, ipaddr);
- return ERR_OK;
-}
-
-
-/**
- * Set the callback function for received packets that match the
- * raw PCB's protocol and binding.
- *
- * The callback function MUST either
- * - eat the packet by calling pbuf_free() and returning non-zero. The
- * packet will not be passed to other raw PCBs or other protocol layers.
- * - not free the packet, and return zero. The packet will be matched
- * against further PCBs and/or forwarded to another protocol layers.
- *
- * @return non-zero if the packet was free()d, zero if the packet remains
- * available for others.
- */
-void
-raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
-{
- /* remember recv() callback and user data */
- pcb->recv = recv;
- pcb->recv_arg = recv_arg;
-}
-
-/**
- * Send the raw IP packet to the given address. Note that actually you cannot
- * modify the IP headers (this is inconsistent with the receive callback where
- * you actually get the IP headers), you can only specify the IP payload here.
- * It requires some more changes in lwIP. (there will be a raw_send() function
- * then.)
- *
- * @param pcb the raw pcb which to send
- * @param p the IP payload to send
- * @param ipaddr the destination address of the IP packet
- *
- */
-err_t
-raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
-{
- err_t err;
- struct netif *netif;
- ip_addr_t *src_ip;
- struct pbuf *q; /* q will be sent down the stack */
-
- LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
-
- /* not enough space to add an IP header to first pbuf in given p chain? */
- if (pbuf_header(p, IP_HLEN)) {
- /* allocate header in new pbuf */
- q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
- /* new header pbuf could not be allocated? */
- if (q == NULL) {
- LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
- return ERR_MEM;
- }
- if (p->tot_len != 0) {
- /* chain header q in front of given pbuf p */
- pbuf_chain(q, p);
- }
- /* { first pbuf q points to header pbuf } */
- LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
- } else {
- /* first pbuf q equals given pbuf */
- q = p;
- if(pbuf_header(q, -IP_HLEN)) {
- LWIP_ASSERT("Can't restore header we just removed!", 0);
- return ERR_MEM;
- }
- }
-
- if ((netif = ip_route(ipaddr)) == NULL) {
- LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
- /* free any temporary header pbuf allocated by pbuf_header() */
- if (q != p) {
- pbuf_free(q);
- }
- return ERR_RTE;
- }
-
-#if IP_SOF_BROADCAST
- /* broadcast filter? */
- if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
- LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
- /* free any temporary header pbuf allocated by pbuf_header() */
- if (q != p) {
- pbuf_free(q);
- }
- return ERR_VAL;
- }
-#endif /* IP_SOF_BROADCAST */
-
- if (ip_addr_isany(&pcb->local_ip)) {
- /* use outgoing network interface IP address as source address */
- src_ip = &(netif->ip_addr);
- } else {
- /* use RAW PCB local IP address as source address */
- src_ip = &(pcb->local_ip);
- }
-
-#if LWIP_NETIF_HWADDRHINT
- netif->addr_hint = &(pcb->addr_hint);
-#endif /* LWIP_NETIF_HWADDRHINT*/
- err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
-#if LWIP_NETIF_HWADDRHINT
- netif->addr_hint = NULL;
-#endif /* LWIP_NETIF_HWADDRHINT*/
-
- /* did we chain a header earlier? */
- if (q != p) {
- /* free the header */
- pbuf_free(q);
- }
- return err;
-}
-
-/**
- * Send the raw IP packet to the address given by raw_connect()
- *
- * @param pcb the raw pcb which to send
- * @param p the IP payload to send
- *
- */
-err_t
-raw_send(struct raw_pcb *pcb, struct pbuf *p)
-{
- return raw_sendto(pcb, p, &pcb->remote_ip);
-}
-
-/**
- * Remove an RAW PCB.
- *
- * @param pcb RAW PCB to be removed. The PCB is removed from the list of
- * RAW PCB's and the data structure is freed from memory.
- *
- * @see raw_new()
- */
-void
-raw_remove(struct raw_pcb *pcb)
-{
- struct raw_pcb *pcb2;
- /* pcb to be removed is first in list? */
- if (raw_pcbs == pcb) {
- /* make list start at 2nd pcb */
- raw_pcbs = raw_pcbs->next;
- /* pcb not 1st in list */
- } else {
- for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
- /* find pcb in raw_pcbs list */
- if (pcb2->next != NULL && pcb2->next == pcb) {
- /* remove pcb from list */
- pcb2->next = pcb->next;
- }
- }
- }
- memp_free(MEMP_RAW_PCB, pcb);
-}
-
-/**
- * Create a RAW PCB.
- *
- * @return The RAW PCB which was created. NULL if the PCB data structure
- * could not be allocated.
- *
- * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
- *
- * @see raw_remove()
- */
-struct raw_pcb *
-raw_new(u8_t proto)
-{
- struct raw_pcb *pcb;
-
- LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
-
- pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
- /* could allocate RAW PCB? */
- if (pcb != NULL) {
- /* initialize PCB to all zeroes */
- memset(pcb, 0, sizeof(struct raw_pcb));
- pcb->protocol = proto;
- pcb->ttl = RAW_TTL;
- pcb->next = raw_pcbs;
- raw_pcbs = pcb;
- }
- return pcb;
-}
-
-#endif /* LWIP_RAW */
+++ /dev/null
-/**
- * @file
- * Statistics module
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/def.h"
-#include "lwip/stats.h"
-#include "lwip/mem.h"
-
-#include <string.h>
-
-struct stats_ lwip_stats;
-
-void stats_init(void)
-{
-#ifdef LWIP_DEBUG
-#if MEMP_STATS
- const char * memp_names[] = {
-#define LWIP_MEMPOOL(name,num,size,desc) desc,
-#include "lwip/memp_std.h"
- };
- int i;
- for (i = 0; i < MEMP_MAX; i++) {
- lwip_stats.memp[i].name = memp_names[i];
- }
-#endif /* MEMP_STATS */
-#if MEM_STATS
- lwip_stats.mem.name = "MEM";
-#endif /* MEM_STATS */
-#endif /* LWIP_DEBUG */
-}
-
-#if LWIP_STATS_DISPLAY
-void
-stats_display_proto(struct stats_proto *proto, char *name)
-{
- LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
- LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));
- LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv));
- LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));
- LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop));
- LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr));
- LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr));
- LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr));
- LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr));
- LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr));
- LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr));
- LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err));
- LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit));
-}
-
-#if IGMP_STATS
-void
-stats_display_igmp(struct stats_igmp *igmp)
-{
- LWIP_PLATFORM_DIAG(("\nIGMP\n\t"));
- LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit));
- LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv));
- LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop));
- LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr));
- LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));
- LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr));
- LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr));
- LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1));
- LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n", igmp->rx_group));
- LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n", igmp->rx_general));
- LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report));
- LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join));
- LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave));
- LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report));
-}
-#endif /* IGMP_STATS */
-
-#if MEM_STATS || MEMP_STATS
-void
-stats_display_mem(struct stats_mem *mem, char *name)
-{
- LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name));
- LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail));
- LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used));
- LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max));
- LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err));
-}
-
-#if MEMP_STATS
-void
-stats_display_memp(struct stats_mem *mem, int index)
-{
- char * memp_names[] = {
-#define LWIP_MEMPOOL(name,num,size,desc) desc,
-#include "lwip/memp_std.h"
- };
- if(index < MEMP_MAX) {
- stats_display_mem(mem, memp_names[index]);
- }
-}
-#endif /* MEMP_STATS */
-#endif /* MEM_STATS || MEMP_STATS */
-
-#if SYS_STATS
-void
-stats_display_sys(struct stats_sys *sys)
-{
- LWIP_PLATFORM_DIAG(("\nSYS\n\t"));
- LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used));
- LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max));
- LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err));
- LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used));
- LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max));
- LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err));
- LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used));
- LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max));
- LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err));
-}
-#endif /* SYS_STATS */
-
-void
-stats_display(void)
-{
- s16_t i;
-
- LINK_STATS_DISPLAY();
- ETHARP_STATS_DISPLAY();
- IPFRAG_STATS_DISPLAY();
- IP_STATS_DISPLAY();
- IGMP_STATS_DISPLAY();
- ICMP_STATS_DISPLAY();
- UDP_STATS_DISPLAY();
- TCP_STATS_DISPLAY();
- MEM_STATS_DISPLAY();
- for (i = 0; i < MEMP_MAX; i++) {
- MEMP_STATS_DISPLAY(i);
- }
- SYS_STATS_DISPLAY();
-}
-#endif /* LWIP_STATS_DISPLAY */
-
-#endif /* LWIP_STATS */
-
+++ /dev/null
-/**
- * @file
- * lwIP Operating System abstraction
- *
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#include "lwip/opt.h"
-
-#include "lwip/sys.h"
-
-/* Most of the functions defined in sys.h must be implemented in the
- * architecture-dependent file sys_arch.c */
-
-#if !NO_SYS
-
-/**
- * Sleep for some ms. Timeouts are NOT processed while sleeping.
- *
- * @param ms number of milliseconds to sleep
- */
-void
-sys_msleep(u32_t ms)
-{
- if (ms > 0) {
- sys_sem_t delaysem;
- err_t err = sys_sem_new(&delaysem, 0);
- if (err == ERR_OK) {
- sys_arch_sem_wait(&delaysem, ms);
- sys_sem_free(&delaysem);
- }
- }
-}
-
-#endif /* !NO_SYS */
+++ /dev/null
-/**
- * @file
- * Transmission Control Protocol for IP
- *
- * This file contains common functions for the TCP implementation, such as functinos
- * for manipulating the data structures and the TCP timer functions. TCP functions
- * related to input and output is found in tcp_in.c and tcp_out.c respectively.
- *
- */
-
-/*
- * 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_TCP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/def.h"
-#include "lwip/mem.h"
-#include "lwip/memp.h"
-#include "lwip/snmp.h"
-#include "lwip/tcp.h"
-#include "lwip/tcp_impl.h"
-#include "lwip/debug.h"
-#include "lwip/stats.h"
-
-#include <string.h>
-
-const char * const tcp_state_str[] = {
- "CLOSED",
- "LISTEN",
- "SYN_SENT",
- "SYN_RCVD",
- "ESTABLISHED",
- "FIN_WAIT_1",
- "FIN_WAIT_2",
- "CLOSE_WAIT",
- "CLOSING",
- "LAST_ACK",
- "TIME_WAIT"
-};
-
-/* Incremented every coarse grained timer shot (typically every 500 ms). */
-u32_t tcp_ticks;
-const u8_t tcp_backoff[13] =
- { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
- /* Times per slowtmr hits */
-const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };
-
-/* The TCP PCB lists. */
-
-/** List of all TCP PCBs bound but not yet (connected || listening) */
-struct tcp_pcb *tcp_bound_pcbs;
-/** List of all TCP PCBs in LISTEN state */
-union tcp_listen_pcbs_t tcp_listen_pcbs;
-/** List of all TCP PCBs that are in a state in which
- * they accept or send data. */
-struct tcp_pcb *tcp_active_pcbs;
-/** List of all TCP PCBs in TIME-WAIT state */
-struct tcp_pcb *tcp_tw_pcbs;
-
-#define NUM_TCP_PCB_LISTS 4
-#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3
-/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */
-struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs,
- &tcp_active_pcbs, &tcp_tw_pcbs};
-
-/** Only used for temporary storage. */
-struct tcp_pcb *tcp_tmp_pcb;
-
-/** Timer counter to handle calling slow-timer from tcp_tmr() */
-static u8_t tcp_timer;
-static u16_t tcp_new_port(void);
-
-/**
- * Called periodically to dispatch TCP timers.
- *
- */
-void
-tcp_tmr(void)
-{
- /* Call tcp_fasttmr() every 250 ms */
- tcp_fasttmr();
-
- if (++tcp_timer & 1) {
- /* Call tcp_tmr() every 500 ms, i.e., every other timer
- tcp_tmr() is called. */
- tcp_slowtmr();
- }
-}
-
-/**
- * Closes the TX side of a connection held by the PCB.
- * For tcp_close(), a RST is sent if the application didn't receive all data
- * (tcp_recved() not called for all data passed to recv callback).
- *
- * Listening pcbs are freed and may not be referenced any more.
- * Connection pcbs are freed if not yet connected and may not be referenced
- * any more. If a connection is established (at least SYN received or in
- * a closing state), the connection is closed, and put in a closing state.
- * The pcb is then automatically freed in tcp_slowtmr(). It is therefore
- * unsafe to reference it.
- *
- * @param pcb the tcp_pcb to close
- * @return ERR_OK if connection has been closed
- * another err_t if closing failed and pcb is not freed
- */
-static err_t
-tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
-{
- err_t err;
-
- if (rst_on_unacked_data && (pcb->state != LISTEN)) {
- if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) {
- /* Not all data received by application, send RST to tell the remote
- side about this. */
- LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED);
-
- /* don't call tcp_abort here: we must not deallocate the pcb since
- that might not be expected when calling tcp_close */
- tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
- pcb->local_port, pcb->remote_port);
-
- tcp_pcb_purge(pcb);
-
- /* TODO: to which state do we move now? */
-
- /* move to TIME_WAIT since we close actively */
- TCP_RMV(&tcp_active_pcbs, pcb);
- pcb->state = TIME_WAIT;
- TCP_REG(&tcp_tw_pcbs, pcb);
-
- return ERR_OK;
- }
- }
-
- switch (pcb->state) {
- case CLOSED:
- /* Closing a pcb in the CLOSED state might seem erroneous,
- * however, it is in this state once allocated and as yet unused
- * and the user needs some way to free it should the need arise.
- * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)
- * or for a pcb that has been used and then entered the CLOSED state
- * is erroneous, but this should never happen as the pcb has in those cases
- * been freed, and so any remaining handles are bogus. */
- err = ERR_OK;
- if (pcb->local_port != 0) {
- TCP_RMV(&tcp_bound_pcbs, pcb);
- }
- memp_free(MEMP_TCP_PCB, pcb);
- pcb = NULL;
- break;
- case LISTEN:
- err = ERR_OK;
- tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb);
- memp_free(MEMP_TCP_PCB_LISTEN, pcb);
- pcb = NULL;
- break;
- case SYN_SENT:
- err = ERR_OK;
- tcp_pcb_remove(&tcp_active_pcbs, pcb);
- memp_free(MEMP_TCP_PCB, pcb);
- pcb = NULL;
- snmp_inc_tcpattemptfails();
- break;
- case SYN_RCVD:
- err = tcp_send_fin(pcb);
- if (err == ERR_OK) {
- snmp_inc_tcpattemptfails();
- pcb->state = FIN_WAIT_1;
- }
- break;
- case ESTABLISHED:
- err = tcp_send_fin(pcb);
- if (err == ERR_OK) {
- snmp_inc_tcpestabresets();
- pcb->state = FIN_WAIT_1;
- }
- break;
- case CLOSE_WAIT:
- err = tcp_send_fin(pcb);
- if (err == ERR_OK) {
- snmp_inc_tcpestabresets();
- pcb->state = LAST_ACK;
- }
- break;
- default:
- /* Has already been closed, do nothing. */
- err = ERR_OK;
- pcb = NULL;
- break;
- }
-
- if (pcb != NULL && err == ERR_OK) {
- /* To ensure all data has been sent when tcp_close returns, we have
- to make sure tcp_output doesn't fail.
- Since we don't really have to ensure all data has been sent when tcp_close
- returns (unsent data is sent from tcp timer functions, also), we don't care
- for the return value of tcp_output for now. */
- /* @todo: When implementing SO_LINGER, this must be changed somehow:
- If SOF_LINGER is set, the data should be sent and acked before close returns.
- This can only be valid for sequential APIs, not for the raw API. */
- tcp_output(pcb);
- }
- return err;
-}
-
-/**
- * Closes the connection held by the PCB.
- *
- * Listening pcbs are freed and may not be referenced any more.
- * Connection pcbs are freed if not yet connected and may not be referenced
- * any more. If a connection is established (at least SYN received or in
- * a closing state), the connection is closed, and put in a closing state.
- * The pcb is then automatically freed in tcp_slowtmr(). It is therefore
- * unsafe to reference it (unless an error is returned).
- *
- * @param pcb the tcp_pcb to close
- * @return ERR_OK if connection has been closed
- * another err_t if closing failed and pcb is not freed
- */
-err_t
-tcp_close(struct tcp_pcb *pcb)
-{
-#if TCP_DEBUG
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));
- tcp_debug_print_state(pcb->state);
-#endif /* TCP_DEBUG */
-
- if (pcb->state != LISTEN) {
- /* Set a flag not to receive any more data... */
- pcb->flags |= TF_RXCLOSED;
- }
- /* ... and close */
- return tcp_close_shutdown(pcb, 1);
-}
-
-/**
- * Causes all or part of a full-duplex connection of this PCB to be shut down.
- * This doesn't deallocate the PCB!
- *
- * @param pcb PCB to shutdown
- * @param shut_rx shut down receive side if this is != 0
- * @param shut_tx shut down send side if this is != 0
- * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down)
- * another err_t on error.
- */
-err_t
-tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)
-{
- if (pcb->state == LISTEN) {
- return ERR_CONN;
- }
- if (shut_rx) {
- /* shut down the receive side: free buffered data... */
- if (pcb->refused_data != NULL) {
- pbuf_free(pcb->refused_data);
- pcb->refused_data = NULL;
- }
- /* ... and set a flag not to receive any more data */
- pcb->flags |= TF_RXCLOSED;
- }
- if (shut_tx) {
- /* This can't happen twice since if it succeeds, the pcb's state is changed.
- Only close in these states as the others directly deallocate the PCB */
- switch (pcb->state) {
- case SYN_RCVD:
- case ESTABLISHED:
- case CLOSE_WAIT:
- return tcp_close_shutdown(pcb, 0);
- default:
- /* don't shut down other states */
- break;
- }
- }
- /* @todo: return another err_t if not in correct state or already shut? */
- return ERR_OK;
-}
-
-/**
- * Abandons a connection and optionally sends a RST to the remote
- * host. Deletes the local protocol control block. This is done when
- * a connection is killed because of shortage of memory.
- *
- * @param pcb the tcp_pcb to abort
- * @param reset boolean to indicate whether a reset should be sent
- */
-void
-tcp_abandon(struct tcp_pcb *pcb, int reset)
-{
- u32_t seqno, ackno;
- u16_t remote_port, local_port;
- ip_addr_t remote_ip, local_ip;
-#if LWIP_CALLBACK_API
- tcp_err_fn errf;
-#endif /* LWIP_CALLBACK_API */
- void *errf_arg;
-
- /* pcb->state LISTEN not allowed here */
- LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs",
- pcb->state != LISTEN);
- /* Figure out on which TCP PCB list we are, and remove us. If we
- are in an active state, call the receive function associated with
- the PCB with a NULL argument, and send an RST to the remote end. */
- if (pcb->state == TIME_WAIT) {
- tcp_pcb_remove(&tcp_tw_pcbs, pcb);
- memp_free(MEMP_TCP_PCB, pcb);
- } else {
- seqno = pcb->snd_nxt;
- ackno = pcb->rcv_nxt;
- ip_addr_copy(local_ip, pcb->local_ip);
- ip_addr_copy(remote_ip, pcb->remote_ip);
- local_port = pcb->local_port;
- remote_port = pcb->remote_port;
-#if LWIP_CALLBACK_API
- errf = pcb->errf;
-#endif /* LWIP_CALLBACK_API */
- errf_arg = pcb->callback_arg;
- tcp_pcb_remove(&tcp_active_pcbs, pcb);
- if (pcb->unacked != NULL) {
- tcp_segs_free(pcb->unacked);
- }
- if (pcb->unsent != NULL) {
- tcp_segs_free(pcb->unsent);
- }
-#if TCP_QUEUE_OOSEQ
- if (pcb->ooseq != NULL) {
- tcp_segs_free(pcb->ooseq);
- }
-#endif /* TCP_QUEUE_OOSEQ */
- memp_free(MEMP_TCP_PCB, pcb);
- TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
- if (reset) {
- LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
- tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
- }
- }
-}
-
-/**
- * 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!
- *
- * @param pcb the tcp pcb to abort
- */
-void
-tcp_abort(struct tcp_pcb *pcb)
-{
- tcp_abandon(pcb, 1);
-}
-
-/**
- * Binds the connection to a local portnumber and IP address. If the
- * IP address is not given (i.e., ipaddr == NULL), the IP address of
- * the outgoing network interface is used instead.
- *
- * @param pcb the tcp_pcb to bind (no check is done whether this pcb is
- * already bound!)
- * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind
- * to any local address
- * @param port the local port to bind to
- * @return ERR_USE if the port is already in use
- * ERR_VAL if bind failed because the PCB is not in a valid state
- * ERR_OK if bound
- */
-err_t
-tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
-{
- int i;
- int max_pcb_list = NUM_TCP_PCB_LISTS;
- struct tcp_pcb *cpcb;
-
- LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL);
-
-#if SO_REUSE
- /* Unless the REUSEADDR flag is set,
- we have to check the pcbs in TIME-WAIT state, also.
- We do not dump TIME_WAIT pcb's; they can still be matched by incoming
- packets using both local and remote IP addresses and ports to distinguish.
- */
- if ((pcb->so_options & SOF_REUSEADDR) != 0) {
- max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT;
- }
-#endif /* SO_REUSE */
-
- if (port == 0) {
- port = tcp_new_port();
- }
-
- /* Check if the address already is in use (on all lists) */
- for (i = 0; i < max_pcb_list; i++) {
- for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {
- if (cpcb->local_port == port) {
-#if SO_REUSE
- /* Omit checking for the same port if both pcbs have REUSEADDR set.
- For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in
- tcp_connect. */
- if (((pcb->so_options & SOF_REUSEADDR) == 0) ||
- ((cpcb->so_options & SOF_REUSEADDR) == 0))
-#endif /* SO_REUSE */
- {
- if (ip_addr_isany(&(cpcb->local_ip)) ||
- ip_addr_isany(ipaddr) ||
- ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
- return ERR_USE;
- }
- }
- }
- }
- }
-
- if (!ip_addr_isany(ipaddr)) {
- pcb->local_ip = *ipaddr;
- }
- pcb->local_port = port;
- TCP_REG(&tcp_bound_pcbs, pcb);
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));
- return ERR_OK;
-}
-#if LWIP_CALLBACK_API
-/**
- * Default accept callback if no accept callback is specified by the user.
- */
-static err_t
-tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
-{
- LWIP_UNUSED_ARG(arg);
- LWIP_UNUSED_ARG(pcb);
- LWIP_UNUSED_ARG(err);
-
- return ERR_ABRT;
-}
-#endif /* LWIP_CALLBACK_API */
-
-/**
- * Set the state of the connection to be LISTEN, which means that it
- * is able to accept incoming connections. The protocol control block
- * is reallocated in order to consume less memory. Setting the
- * connection to LISTEN is an irreversible process.
- *
- * @param pcb the original tcp_pcb
- * @param backlog the incoming connections queue limit
- * @return tcp_pcb used for listening, consumes less memory.
- *
- * @note The original tcp_pcb is freed. This function therefore has to be
- * called like this:
- * tpcb = tcp_listen(tpcb);
- */
-struct tcp_pcb *
-tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
-{
- struct tcp_pcb_listen *lpcb;
-
- LWIP_UNUSED_ARG(backlog);
- LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL);
-
- /* already listening? */
- if (pcb->state == LISTEN) {
- return pcb;
- }
-#if SO_REUSE
- if ((pcb->so_options & SOF_REUSEADDR) != 0) {
- /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage
- is declared (listen-/connection-pcb), we have to make sure now that
- this port is only used once for every local IP. */
- for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
- if (lpcb->local_port == pcb->local_port) {
- if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {
- /* this address/port is already used */
- return NULL;
- }
- }
- }
- }
-#endif /* SO_REUSE */
- lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN);
- if (lpcb == NULL) {
- return NULL;
- }
- lpcb->callback_arg = pcb->callback_arg;
- lpcb->local_port = pcb->local_port;
- lpcb->state = LISTEN;
- lpcb->prio = pcb->prio;
- lpcb->so_options = pcb->so_options;
- lpcb->so_options |= SOF_ACCEPTCONN;
- lpcb->ttl = pcb->ttl;
- lpcb->tos = pcb->tos;
- ip_addr_copy(lpcb->local_ip, pcb->local_ip);
- if (pcb->local_port != 0) {
- TCP_RMV(&tcp_bound_pcbs, pcb);
- }
- memp_free(MEMP_TCP_PCB, pcb);
-#if LWIP_CALLBACK_API
- lpcb->accept = tcp_accept_null;
-#endif /* LWIP_CALLBACK_API */
-#if TCP_LISTEN_BACKLOG
- lpcb->accepts_pending = 0;
- lpcb->backlog = (backlog ? backlog : 1);
-#endif /* TCP_LISTEN_BACKLOG */
- TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb);
- return (struct tcp_pcb *)lpcb;
-}
-
-/**
- * Update the state that tracks the available window space to advertise.
- *
- * Returns how much extra window would be advertised if we sent an
- * update now.
- */
-u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)
-{
- u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd;
-
- if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) {
- /* we can advertise more window */
- pcb->rcv_ann_wnd = pcb->rcv_wnd;
- return new_right_edge - pcb->rcv_ann_right_edge;
- } else {
- if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) {
- /* Can happen due to other end sending out of advertised window,
- * but within actual available (but not yet advertised) window */
- pcb->rcv_ann_wnd = 0;
- } else {
- /* keep the right edge of window constant */
- u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;
- LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff);
- pcb->rcv_ann_wnd = (u16_t)new_rcv_ann_wnd;
- }
- return 0;
- }
-}
-
-/**
- * This function should be called by the application when it has
- * processed the data. The purpose is to advertise a larger window
- * when the data has been processed.
- *
- * @param pcb the tcp_pcb for which data is read
- * @param len the amount of bytes that have been read by the application
- */
-void
-tcp_recved(struct tcp_pcb *pcb, u16_t len)
-{
- int wnd_inflation;
-
- LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
- len <= 0xffff - pcb->rcv_wnd );
-
- pcb->rcv_wnd += len;
- if (pcb->rcv_wnd > TCP_WND) {
- pcb->rcv_wnd = TCP_WND;
- }
-
- wnd_inflation = tcp_update_rcv_ann_wnd(pcb);
-
- /* If the change in the right edge of window is significant (default
- * watermark is TCP_WND/4), then send an explicit update now.
- * Otherwise wait for a packet to be sent in the normal course of
- * events (or more window to be available later) */
- if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) {
- tcp_ack_now(pcb);
- tcp_output(pcb);
- }
-
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",
- len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
-}
-
-/**
- * A nastly hack featuring 'goto' statements that allocates a
- * new TCP local port.
- *
- * @return a new (free) local TCP port number
- */
-static u16_t
-tcp_new_port(void)
-{
- int i;
- struct tcp_pcb *pcb;
-#ifndef TCP_LOCAL_PORT_RANGE_START
-/* From http://www.iana.org/assignments/port-numbers:
- "The Dynamic and/or Private Ports are those from 49152 through 65535" */
-#define TCP_LOCAL_PORT_RANGE_START 0xc000
-#define TCP_LOCAL_PORT_RANGE_END 0xffff
-#endif
- static u16_t port = TCP_LOCAL_PORT_RANGE_START;
-
- again:
- if (port++ >= TCP_LOCAL_PORT_RANGE_END) {
- port = TCP_LOCAL_PORT_RANGE_START;
- }
- /* Check all PCB lists. */
- for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {
- for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) {
- if (pcb->local_port == port) {
- goto again;
- }
- }
- }
- return port;
-}
-
-/**
- * Connects to another host. The function given as the "connected"
- * argument will be called when the connection has been established.
- *
- * @param pcb the tcp_pcb used to establish the connection
- * @param ipaddr the remote ip address to connect to
- * @param port the remote tcp port to connect to
- * @param connected callback function to call when connected (or on error)
- * @return ERR_VAL if invalid arguments are given
- * ERR_OK if connect request has been sent
- * other err_t values if connect request couldn't be sent
- */
-err_t
-tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
- tcp_connected_fn connected)
-{
- err_t ret;
- u32_t iss;
- u16_t old_local_port;
-
- LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
-
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
- if (ipaddr != NULL) {
- pcb->remote_ip = *ipaddr;
- } else {
- return ERR_VAL;
- }
- pcb->remote_port = port;
-
- /* check if we have a route to the remote host */
- if (ip_addr_isany(&(pcb->local_ip))) {
- /* no local IP address set, yet. */
- struct netif *netif = ip_route(&(pcb->remote_ip));
- if (netif == NULL) {
- /* Don't even try to send a SYN packet if we have no route
- since that will fail. */
- return ERR_RTE;
- }
- /* Use the netif's IP address as local address. */
- ip_addr_copy(pcb->local_ip, netif->ip_addr);
- }
-
- old_local_port = pcb->local_port;
- if (pcb->local_port == 0) {
- pcb->local_port = tcp_new_port();
- }
-#if SO_REUSE
- if ((pcb->so_options & SOF_REUSEADDR) != 0) {
- /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure
- now that the 5-tuple is unique. */
- struct tcp_pcb *cpcb;
- int i;
- /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */
- for (i = 2; i < NUM_TCP_PCB_LISTS; i++) {
- for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {
- if ((cpcb->local_port == pcb->local_port) &&
- (cpcb->remote_port == port) &&
- ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) &&
- ip_addr_cmp(&cpcb->remote_ip, ipaddr)) {
- /* linux returns EISCONN here, but ERR_USE should be OK for us */
- return ERR_USE;
- }
- }
- }
- }
-#endif /* SO_REUSE */
- iss = tcp_next_iss();
- pcb->rcv_nxt = 0;
- pcb->snd_nxt = iss;
- pcb->lastack = iss - 1;
- pcb->snd_lbb = iss - 1;
- pcb->rcv_wnd = TCP_WND;
- pcb->rcv_ann_wnd = TCP_WND;
- pcb->rcv_ann_right_edge = pcb->rcv_nxt;
- pcb->snd_wnd = TCP_WND;
- /* As initial send MSS, we use TCP_MSS but limit it to 536.
- The send MSS is updated when an MSS option is received. */
- pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
-#if TCP_CALCULATE_EFF_SEND_MSS
- pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);
-#endif /* TCP_CALCULATE_EFF_SEND_MSS */
- pcb->cwnd = 1;
- pcb->ssthresh = pcb->mss * 10;
-#if LWIP_CALLBACK_API
- pcb->connected = connected;
-#else /* LWIP_CALLBACK_API */
- LWIP_UNUSED_ARG(connected);
-#endif /* LWIP_CALLBACK_API */
-
- /* Send a SYN together with the MSS option. */
- ret = tcp_enqueue_flags(pcb, TCP_SYN);
- if (ret == ERR_OK) {
- /* SYN segment was enqueued, changed the pcbs state now */
- pcb->state = SYN_SENT;
- if (old_local_port != 0) {
- TCP_RMV(&tcp_bound_pcbs, pcb);
- }
- TCP_REG(&tcp_active_pcbs, pcb);
- snmp_inc_tcpactiveopens();
-
- tcp_output(pcb);
- }
- return ret;
-}
-
-/**
- * Called every 500 ms and implements the retransmission timer and the timer that
- * removes PCBs that have been in TIME-WAIT for enough time. It also increments
- * various timers such as the inactivity timer in each PCB.
- *
- * Automatically called from tcp_tmr().
- */
-void
-tcp_slowtmr(void)
-{
- struct tcp_pcb *pcb, *prev;
- u16_t eff_wnd;
- u8_t pcb_remove; /* flag if a PCB should be removed */
- u8_t pcb_reset; /* flag if a RST should be sent when removing */
- err_t err;
-
- err = ERR_OK;
-
- ++tcp_ticks;
-
- /* Steps through all of the active PCBs. */
- prev = NULL;
- pcb = tcp_active_pcbs;
- if (pcb == NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
- }
- while (pcb != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));
- LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);
- LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);
- LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);
-
- pcb_remove = 0;
- pcb_reset = 0;
-
- if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {
- ++pcb_remove;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));
- }
- else if (pcb->nrtx == TCP_MAXRTX) {
- ++pcb_remove;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
- } else {
- if (pcb->persist_backoff > 0) {
- /* If snd_wnd is zero, use persist timer to send 1 byte probes
- * instead of using the standard retransmission mechanism. */
- pcb->persist_cnt++;
- if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {
- pcb->persist_cnt = 0;
- if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {
- pcb->persist_backoff++;
- }
- tcp_zero_window_probe(pcb);
- }
- } else {
- /* Increase the retransmission timer if it is running */
- if(pcb->rtime >= 0)
- ++pcb->rtime;
-
- if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
- /* Time for a retransmission. */
- LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F
- " pcb->rto %"S16_F"\n",
- pcb->rtime, pcb->rto));
-
- /* Double retransmission time-out unless we are trying to
- * connect to somebody (i.e., we are in SYN_SENT). */
- if (pcb->state != SYN_SENT) {
- pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
- }
-
- /* Reset the retransmission timer. */
- pcb->rtime = 0;
-
- /* Reduce congestion window and ssthresh. */
- eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
- pcb->ssthresh = eff_wnd >> 1;
- if (pcb->ssthresh < (pcb->mss << 1)) {
- pcb->ssthresh = (pcb->mss << 1);
- }
- pcb->cwnd = pcb->mss;
- LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F
- " ssthresh %"U16_F"\n",
- pcb->cwnd, pcb->ssthresh));
-
- /* The following needs to be called AFTER cwnd is set to one
- mss - STJ */
- tcp_rexmit_rto(pcb);
- }
- }
- }
- /* Check if this PCB has stayed too long in FIN-WAIT-2 */
- if (pcb->state == FIN_WAIT_2) {
- if ((u32_t)(tcp_ticks - pcb->tmr) >
- TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {
- ++pcb_remove;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
- }
- }
-
- /* Check if KEEPALIVE should be sent */
- if((pcb->so_options & SOF_KEEPALIVE) &&
- ((pcb->state == ESTABLISHED) ||
- (pcb->state == CLOSE_WAIT))) {
-#if LWIP_TCP_KEEPALIVE
- if((u32_t)(tcp_ticks - pcb->tmr) >
- (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))
- / TCP_SLOW_INTERVAL)
-#else
- if((u32_t)(tcp_ticks - pcb->tmr) >
- (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)
-#endif /* LWIP_TCP_KEEPALIVE */
- {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
- ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
- ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
-
- ++pcb_remove;
- ++pcb_reset;
- }
-#if LWIP_TCP_KEEPALIVE
- else if((u32_t)(tcp_ticks - pcb->tmr) >
- (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl)
- / TCP_SLOW_INTERVAL)
-#else
- else if((u32_t)(tcp_ticks - pcb->tmr) >
- (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT)
- / TCP_SLOW_INTERVAL)
-#endif /* LWIP_TCP_KEEPALIVE */
- {
- tcp_keepalive(pcb);
- pcb->keep_cnt_sent++;
- }
- }
-
- /* If this PCB has queued out of sequence data, but has been
- inactive for too long, will drop the data (it will eventually
- be retransmitted). */
-#if TCP_QUEUE_OOSEQ
- if (pcb->ooseq != NULL &&
- (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) {
- tcp_segs_free(pcb->ooseq);
- pcb->ooseq = NULL;
- LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));
- }
-#endif /* TCP_QUEUE_OOSEQ */
-
- /* Check if this PCB has stayed too long in SYN-RCVD */
- if (pcb->state == SYN_RCVD) {
- if ((u32_t)(tcp_ticks - pcb->tmr) >
- TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {
- ++pcb_remove;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));
- }
- }
-
- /* Check if this PCB has stayed too long in LAST-ACK */
- if (pcb->state == LAST_ACK) {
- if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
- ++pcb_remove;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n"));
- }
- }
-
- /* If the PCB should be removed, do it. */
- if (pcb_remove) {
- struct tcp_pcb *pcb2;
- tcp_pcb_purge(pcb);
- /* Remove PCB from tcp_active_pcbs list. */
- if (prev != NULL) {
- LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
- prev->next = pcb->next;
- } else {
- /* This PCB was the first. */
- LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);
- tcp_active_pcbs = pcb->next;
- }
-
- TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
- if (pcb_reset) {
- tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
- pcb->local_port, pcb->remote_port);
- }
-
- pcb2 = pcb;
- pcb = pcb->next;
- memp_free(MEMP_TCP_PCB, pcb2);
- } else {
- /* get the 'next' element now and work with 'prev' below (in case of abort) */
- prev = pcb;
- pcb = pcb->next;
-
- /* We check if we should poll the connection. */
- ++prev->polltmr;
- if (prev->polltmr >= prev->pollinterval) {
- prev->polltmr = 0;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
- TCP_EVENT_POLL(prev, err);
- /* if err == ERR_ABRT, 'prev' is already deallocated */
- if (err == ERR_OK) {
- tcp_output(prev);
- }
- }
- }
- }
-
-
- /* Steps through all of the TIME-WAIT PCBs. */
- prev = NULL;
- pcb = tcp_tw_pcbs;
- while (pcb != NULL) {
- LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
- pcb_remove = 0;
-
- /* Check if this PCB has stayed long enough in TIME-WAIT */
- if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
- ++pcb_remove;
- }
-
-
-
- /* If the PCB should be removed, do it. */
- if (pcb_remove) {
- struct tcp_pcb *pcb2;
- tcp_pcb_purge(pcb);
- /* Remove PCB from tcp_tw_pcbs list. */
- if (prev != NULL) {
- LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
- prev->next = pcb->next;
- } else {
- /* This PCB was the first. */
- LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
- tcp_tw_pcbs = pcb->next;
- }
- pcb2 = pcb;
- pcb = pcb->next;
- memp_free(MEMP_TCP_PCB, pcb2);
- } else {
- prev = pcb;
- pcb = pcb->next;
- }
- }
-}
-
-/**
- * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously
- * "refused" by upper layer (application) and sends delayed ACKs.
- *
- * Automatically called from tcp_tmr().
- */
-void
-tcp_fasttmr(void)
-{
- struct tcp_pcb *pcb = tcp_active_pcbs;
-
- while(pcb != NULL) {
- struct tcp_pcb *next = pcb->next;
- /* If there is data which was previously "refused" by upper layer */
- if (pcb->refused_data != NULL) {
- /* Notify again application with data previously received. */
- err_t err;
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));
- TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
- if (err == ERR_OK) {
- pcb->refused_data = NULL;
- } else if (err == ERR_ABRT) {
- /* if err == ERR_ABRT, 'pcb' is already deallocated */
- pcb = NULL;
- }
- }
-
- /* send delayed ACKs */
- if (pcb && (pcb->flags & TF_ACK_DELAY)) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
- tcp_ack_now(pcb);
- tcp_output(pcb);
- pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
- }
-
- pcb = next;
- }
-}
-
-/**
- * Deallocates a list of TCP segments (tcp_seg structures).
- *
- * @param seg tcp_seg list of TCP segments to free
- */
-void
-tcp_segs_free(struct tcp_seg *seg)
-{
- while (seg != NULL) {
- struct tcp_seg *next = seg->next;
- tcp_seg_free(seg);
- seg = next;
- }
-}
-
-/**
- * Frees a TCP segment (tcp_seg structure).
- *
- * @param seg single tcp_seg to free
- */
-void
-tcp_seg_free(struct tcp_seg *seg)
-{
- if (seg != NULL) {
- if (seg->p != NULL) {
- pbuf_free(seg->p);
-#if TCP_DEBUG
- seg->p = NULL;
-#endif /* TCP_DEBUG */
- }
- memp_free(MEMP_TCP_SEG, seg);
- }
-}
-
-/**
- * Sets the priority of a connection.
- *
- * @param pcb the tcp_pcb to manipulate
- * @param prio new priority
- */
-void
-tcp_setprio(struct tcp_pcb *pcb, u8_t prio)
-{
- pcb->prio = prio;
-}
-
-#if TCP_QUEUE_OOSEQ
-/**
- * Returns a copy of the given TCP segment.
- * The pbuf and data are not copied, only the pointers
- *
- * @param seg the old tcp_seg
- * @return a copy of seg
- */
-struct tcp_seg *
-tcp_seg_copy(struct tcp_seg *seg)
-{
- struct tcp_seg *cseg;
-
- cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG);
- if (cseg == NULL) {
- return NULL;
- }
- SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg));
- pbuf_ref(cseg->p);
- return cseg;
-}
-#endif /* TCP_QUEUE_OOSEQ */
-
-#if LWIP_CALLBACK_API
-/**
- * Default receive callback that is called if the user didn't register
- * a recv callback for the pcb.
- */
-err_t
-tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
-{
- LWIP_UNUSED_ARG(arg);
- if (p != NULL) {
- tcp_recved(pcb, p->tot_len);
- pbuf_free(p);
- } else if (err == ERR_OK) {
- return tcp_close(pcb);
- }
- return ERR_OK;
-}
-#endif /* LWIP_CALLBACK_API */
-
-/**
- * Kills the oldest active connection that has lower priority than prio.
- *
- * @param prio minimum priority
- */
-static void
-tcp_kill_prio(u8_t prio)
-{
- struct tcp_pcb *pcb, *inactive;
- u32_t inactivity;
- u8_t mprio;
-
-
- mprio = TCP_PRIO_MAX;
-
- /* We kill the oldest active connection that has lower priority than prio. */
- inactivity = 0;
- inactive = NULL;
- for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
- if (pcb->prio <= prio &&
- pcb->prio <= mprio &&
- (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
- inactivity = tcp_ticks - pcb->tmr;
- inactive = pcb;
- mprio = pcb->prio;
- }
- }
- if (inactive != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",
- (void *)inactive, inactivity));
- tcp_abort(inactive);
- }
-}
-
-/**
- * Kills the oldest connection that is in TIME_WAIT state.
- * Called from tcp_alloc() if no more connections are available.
- */
-static void
-tcp_kill_timewait(void)
-{
- struct tcp_pcb *pcb, *inactive;
- u32_t inactivity;
-
- inactivity = 0;
- inactive = NULL;
- /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */
- for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
- if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
- inactivity = tcp_ticks - pcb->tmr;
- inactive = pcb;
- }
- }
- if (inactive != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",
- (void *)inactive, inactivity));
- tcp_abort(inactive);
- }
-}
-
-/**
- * Allocate a new tcp_pcb structure.
- *
- * @param prio priority for the new pcb
- * @return a new tcp_pcb that initially is in state CLOSED
- */
-struct tcp_pcb *
-tcp_alloc(u8_t prio)
-{
- struct tcp_pcb *pcb;
- u32_t iss;
-
- pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
- if (pcb == NULL) {
- /* Try killing oldest connection in TIME-WAIT. */
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));
- tcp_kill_timewait();
- /* Try to allocate a tcp_pcb again. */
- pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
- if (pcb == NULL) {
- /* Try killing active connections with lower priority than the new one. */
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio));
- tcp_kill_prio(prio);
- /* Try to allocate a tcp_pcb again. */
- pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
- if (pcb != NULL) {
- /* adjust err stats: memp_malloc failed twice before */
- MEMP_STATS_DEC(err, MEMP_TCP_PCB);
- }
- }
- if (pcb != NULL) {
- /* adjust err stats: timewait PCB was freed above */
- MEMP_STATS_DEC(err, MEMP_TCP_PCB);
- }
- }
- if (pcb != NULL) {
- memset(pcb, 0, sizeof(struct tcp_pcb));
- pcb->prio = prio;
- pcb->snd_buf = TCP_SND_BUF;
- pcb->snd_queuelen = 0;
- pcb->rcv_wnd = TCP_WND;
- pcb->rcv_ann_wnd = TCP_WND;
- pcb->tos = 0;
- pcb->ttl = TCP_TTL;
- /* As initial send MSS, we use TCP_MSS but limit it to 536.
- The send MSS is updated when an MSS option is received. */
- pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
- pcb->rto = 3000 / TCP_SLOW_INTERVAL;
- pcb->sa = 0;
- pcb->sv = 3000 / TCP_SLOW_INTERVAL;
- pcb->rtime = -1;
- pcb->cwnd = 1;
- iss = tcp_next_iss();
- pcb->snd_wl2 = iss;
- pcb->snd_nxt = iss;
- pcb->lastack = iss;
- pcb->snd_lbb = iss;
- pcb->tmr = tcp_ticks;
-
- pcb->polltmr = 0;
-
-#if LWIP_CALLBACK_API
- pcb->recv = tcp_recv_null;
-#endif /* LWIP_CALLBACK_API */
-
- /* Init KEEPALIVE timer */
- pcb->keep_idle = TCP_KEEPIDLE_DEFAULT;
-
-#if LWIP_TCP_KEEPALIVE
- pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT;
- pcb->keep_cnt = TCP_KEEPCNT_DEFAULT;
-#endif /* LWIP_TCP_KEEPALIVE */
-
- pcb->keep_cnt_sent = 0;
- }
- return pcb;
-}
-
-/**
- * Creates a new TCP protocol control block but doesn't place it on
- * any of the TCP PCB lists.
- * The pcb is not put on any list until binding using tcp_bind().
- *
- * @internal: Maybe there should be a idle TCP PCB list where these
- * PCBs are put on. Port reservation using tcp_bind() is implemented but
- * allocated pcbs that are not bound can't be killed automatically if wanting
- * to allocate a pcb with higher prio (@see tcp_kill_prio())
- *
- * @return a new tcp_pcb that initially is in state CLOSED
- */
-struct tcp_pcb *
-tcp_new(void)
-{
- return tcp_alloc(TCP_PRIO_NORMAL);
-}
-
-/**
- * Used to specify the argument that should be passed callback
- * functions.
- *
- * @param pcb tcp_pcb to set the callback argument
- * @param arg void pointer argument to pass to callback functions
- */
-void
-tcp_arg(struct tcp_pcb *pcb, void *arg)
-{
- pcb->callback_arg = arg;
-}
-#if LWIP_CALLBACK_API
-
-/**
- * Used to specify the function that should be called when a TCP
- * connection receives data.
- *
- * @param pcb tcp_pcb to set the recv callback
- * @param recv callback function to call for this pcb when data is received
- */
-void
-tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
-{
- pcb->recv = recv;
-}
-
-/**
- * Used to specify the function that should be called when TCP data
- * has been successfully delivered to the remote host.
- *
- * @param pcb tcp_pcb to set the sent callback
- * @param sent callback function to call for this pcb when data is successfully sent
- */
-void
-tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
-{
- pcb->sent = sent;
-}
-
-/**
- * Used to specify the function that should be called when a fatal error
- * has occured on the connection.
- *
- * @param pcb tcp_pcb to set the err callback
- * @param err callback function to call for this pcb when a fatal error
- * has occured on the connection
- */
-void
-tcp_err(struct tcp_pcb *pcb, tcp_err_fn err)
-{
- pcb->errf = err;
-}
-
-/**
- * Used for specifying the function that should be called when a
- * LISTENing connection has been connected to another host.
- *
- * @param pcb tcp_pcb to set the accept callback
- * @param accept callback function to call for this pcb when LISTENing
- * connection has been connected to another host
- */
-void
-tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
-{
- pcb->accept = accept;
-}
-#endif /* LWIP_CALLBACK_API */
-
-
-/**
- * Used to specify the function that should be called periodically
- * from TCP. The interval is specified in terms of the TCP coarse
- * timer interval, which is called twice a second.
- *
- */
-void
-tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)
-{
-#if LWIP_CALLBACK_API
- pcb->poll = poll;
-#else /* LWIP_CALLBACK_API */
- LWIP_UNUSED_ARG(poll);
-#endif /* LWIP_CALLBACK_API */
- pcb->pollinterval = interval;
-}
-
-/**
- * Purges a TCP PCB. Removes any buffered data and frees the buffer memory
- * (pcb->ooseq, pcb->unsent and pcb->unacked are freed).
- *
- * @param pcb tcp_pcb to purge. The pcb itself is not deallocated!
- */
-void
-tcp_pcb_purge(struct tcp_pcb *pcb)
-{
- if (pcb->state != CLOSED &&
- pcb->state != TIME_WAIT &&
- pcb->state != LISTEN) {
-
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));
-
-#if TCP_LISTEN_BACKLOG
- if (pcb->state == SYN_RCVD) {
- /* Need to find the corresponding listen_pcb and decrease its accepts_pending */
- struct tcp_pcb_listen *lpcb;
- LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL",
- tcp_listen_pcbs.listen_pcbs != NULL);
- for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
- if ((lpcb->local_port == pcb->local_port) &&
- (ip_addr_isany(&lpcb->local_ip) ||
- ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
- /* port and address of the listen pcb match the timed-out pcb */
- LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
- lpcb->accepts_pending > 0);
- lpcb->accepts_pending--;
- break;
- }
- }
- }
-#endif /* TCP_LISTEN_BACKLOG */
-
-
- if (pcb->refused_data != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));
- pbuf_free(pcb->refused_data);
- pcb->refused_data = NULL;
- }
- if (pcb->unsent != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));
- }
- if (pcb->unacked != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));
- }
-#if TCP_QUEUE_OOSEQ
- if (pcb->ooseq != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
- }
- tcp_segs_free(pcb->ooseq);
- pcb->ooseq = NULL;
-#endif /* TCP_QUEUE_OOSEQ */
-
- /* Stop the retransmission timer as it will expect data on unacked
- queue if it fires */
- pcb->rtime = -1;
-
- tcp_segs_free(pcb->unsent);
- tcp_segs_free(pcb->unacked);
- pcb->unacked = pcb->unsent = NULL;
-#if TCP_OVERSIZE
- pcb->unsent_oversize = 0;
-#endif /* TCP_OVERSIZE */
- }
-}
-
-/**
- * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
- *
- * @param pcblist PCB list to purge.
- * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated!
- */
-void
-tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
-{
- TCP_RMV(pcblist, pcb);
-
- tcp_pcb_purge(pcb);
-
- /* if there is an outstanding delayed ACKs, send it */
- if (pcb->state != TIME_WAIT &&
- pcb->state != LISTEN &&
- pcb->flags & TF_ACK_DELAY) {
- pcb->flags |= TF_ACK_NOW;
- tcp_output(pcb);
- }
-
- if (pcb->state != LISTEN) {
- LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL);
- LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL);
-#if TCP_QUEUE_OOSEQ
- LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL);
-#endif /* TCP_QUEUE_OOSEQ */
- }
-
- pcb->state = CLOSED;
-
- LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
-}
-
-/**
- * Calculates a new initial sequence number for new connections.
- *
- * @return u32_t pseudo random sequence number
- */
-u32_t
-tcp_next_iss(void)
-{
- static u32_t iss = 6510;
-
- iss += tcp_ticks; /* XXX */
- return iss;
-}
-
-#if TCP_CALCULATE_EFF_SEND_MSS
-/**
- * Calcluates the effective send mss that can be used for a specific IP address
- * by using ip_route to determin the netif used to send to the address and
- * calculating the minimum of TCP_MSS and that netif's mtu (if set).
- */
-u16_t
-tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)
-{
- u16_t mss_s;
- struct netif *outif;
-
- outif = ip_route(addr);
- if ((outif != NULL) && (outif->mtu != 0)) {
- mss_s = outif->mtu - IP_HLEN - TCP_HLEN;
- /* RFC 1122, chap 4.2.2.6:
- * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
- * We correct for TCP options in tcp_write(), and don't support IP options.
- */
- sendmss = LWIP_MIN(sendmss, mss_s);
- }
- return sendmss;
-}
-#endif /* TCP_CALCULATE_EFF_SEND_MSS */
-
-const char*
-tcp_debug_state_str(enum tcp_state s)
-{
- return tcp_state_str[s];
-}
-
-#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
-/**
- * Print a tcp header for debugging purposes.
- *
- * @param tcphdr pointer to a struct tcp_hdr
- */
-void
-tcp_debug_print(struct tcp_hdr *tcphdr)
-{
- LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n",
- ntohs(tcphdr->src), ntohs(tcphdr->dest)));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n",
- ntohl(tcphdr->seqno)));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n",
- ntohl(tcphdr->ackno)));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (",
- TCPH_HDRLEN(tcphdr),
- TCPH_FLAGS(tcphdr) >> 5 & 1,
- TCPH_FLAGS(tcphdr) >> 4 & 1,
- TCPH_FLAGS(tcphdr) >> 3 & 1,
- TCPH_FLAGS(tcphdr) >> 2 & 1,
- TCPH_FLAGS(tcphdr) >> 1 & 1,
- TCPH_FLAGS(tcphdr) & 1,
- ntohs(tcphdr->wnd)));
- tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
- LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n",
- ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
-}
-
-/**
- * Print a tcp state for debugging purposes.
- *
- * @param s enum tcp_state to print
- */
-void
-tcp_debug_print_state(enum tcp_state s)
-{
- LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s]));
-}
-
-/**
- * Print tcp flags for debugging purposes.
- *
- * @param flags tcp flags, all active flags are printed
- */
-void
-tcp_debug_print_flags(u8_t flags)
-{
- if (flags & TCP_FIN) {
- LWIP_DEBUGF(TCP_DEBUG, ("FIN "));
- }
- if (flags & TCP_SYN) {
- LWIP_DEBUGF(TCP_DEBUG, ("SYN "));
- }
- if (flags & TCP_RST) {
- LWIP_DEBUGF(TCP_DEBUG, ("RST "));
- }
- if (flags & TCP_PSH) {
- LWIP_DEBUGF(TCP_DEBUG, ("PSH "));
- }
- if (flags & TCP_ACK) {
- LWIP_DEBUGF(TCP_DEBUG, ("ACK "));
- }
- if (flags & TCP_URG) {
- LWIP_DEBUGF(TCP_DEBUG, ("URG "));
- }
- if (flags & TCP_ECE) {
- LWIP_DEBUGF(TCP_DEBUG, ("ECE "));
- }
- if (flags & TCP_CWR) {
- LWIP_DEBUGF(TCP_DEBUG, ("CWR "));
- }
- LWIP_DEBUGF(TCP_DEBUG, ("\n"));
-}
-
-/**
- * Print all tcp_pcbs in every list for debugging purposes.
- */
-void
-tcp_debug_print_pcbs(void)
-{
- struct tcp_pcb *pcb;
- LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));
- for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
- pcb->local_port, pcb->remote_port,
- pcb->snd_nxt, pcb->rcv_nxt));
- tcp_debug_print_state(pcb->state);
- }
- LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));
- for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
- pcb->local_port, pcb->remote_port,
- pcb->snd_nxt, pcb->rcv_nxt));
- tcp_debug_print_state(pcb->state);
- }
- LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));
- for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
- pcb->local_port, pcb->remote_port,
- pcb->snd_nxt, pcb->rcv_nxt));
- tcp_debug_print_state(pcb->state);
- }
-}
-
-/**
- * Check state consistency of the tcp_pcb lists.
- */
-s16_t
-tcp_pcbs_sane(void)
-{
- struct tcp_pcb *pcb;
- for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);
- LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);
- LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
- }
- for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
- }
- return 1;
-}
-#endif /* TCP_DEBUG */
-
-#endif /* LWIP_TCP */
+++ /dev/null
-/**
- * @file
- * Transmission Control Protocol, incoming traffic
- *
- * The input processing functions of the TCP layer.
- *
- * These functions are generally called in the order (ip_input() ->)
- * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).
- *
- */
-
-/*
- * 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_TCP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/tcp_impl.h"
-#include "lwip/def.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/mem.h"
-#include "lwip/memp.h"
-#include "lwip/inet_chksum.h"
-#include "lwip/stats.h"
-#include "lwip/snmp.h"
-#include "arch/perf.h"
-
-/* These variables are global to all functions involved in the input
- processing of TCP segments. They are set by the tcp_input()
- function. */
-static struct tcp_seg inseg;
-static struct tcp_hdr *tcphdr;
-static struct ip_hdr *iphdr;
-static u32_t seqno, ackno;
-static u8_t flags;
-static u16_t tcplen;
-
-static u8_t recv_flags;
-static struct pbuf *recv_data;
-
-struct tcp_pcb *tcp_input_pcb;
-
-/* Forward declarations. */
-static err_t tcp_process(struct tcp_pcb *pcb);
-static void tcp_receive(struct tcp_pcb *pcb);
-static void tcp_parseopt(struct tcp_pcb *pcb);
-
-static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
-static err_t tcp_timewait_input(struct tcp_pcb *pcb);
-
-/**
- * The initial input processing of TCP. It verifies the TCP header, demultiplexes
- * the segment between the PCBs and passes it on to tcp_process(), which implements
- * the TCP finite state machine. This function is called by the IP layer (in
- * ip_input()).
- *
- * @param p received TCP segment to process (p->payload pointing to the IP header)
- * @param inp network interface on which this segment was received
- */
-void
-tcp_input(struct pbuf *p, struct netif *inp)
-{
- struct tcp_pcb *pcb, *prev;
- struct tcp_pcb_listen *lpcb;
-#if SO_REUSE
- struct tcp_pcb *lpcb_prev = NULL;
- struct tcp_pcb_listen *lpcb_any = NULL;
-#endif /* SO_REUSE */
- u8_t hdrlen;
- err_t err;
-
- PERF_START;
-
- TCP_STATS_INC(tcp.recv);
- snmp_inc_tcpinsegs();
-
- iphdr = (struct ip_hdr *)p->payload;
- tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
-
-#if TCP_INPUT_DEBUG
- tcp_debug_print(tcphdr);
-#endif
-
- /* remove header from payload */
- if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
- /* drop short packets */
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
- TCP_STATS_INC(tcp.lenerr);
- TCP_STATS_INC(tcp.drop);
- snmp_inc_tcpinerrs();
- pbuf_free(p);
- return;
- }
-
- /* Don't even process incoming broadcasts/multicasts. */
- if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) ||
- ip_addr_ismulticast(¤t_iphdr_dest)) {
- TCP_STATS_INC(tcp.proterr);
- TCP_STATS_INC(tcp.drop);
- snmp_inc_tcpinerrs();
- pbuf_free(p);
- return;
- }
-
-#if CHECKSUM_CHECK_TCP
- /* Verify TCP checksum. */
- if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
- IP_PROTO_TCP, p->tot_len) != 0) {
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
- inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
- IP_PROTO_TCP, p->tot_len)));
-#if TCP_DEBUG
- tcp_debug_print(tcphdr);
-#endif /* TCP_DEBUG */
- TCP_STATS_INC(tcp.chkerr);
- TCP_STATS_INC(tcp.drop);
- snmp_inc_tcpinerrs();
- pbuf_free(p);
- return;
- }
-#endif
-
- /* Move the payload pointer in the pbuf so that it points to the
- TCP data instead of the TCP header. */
- hdrlen = TCPH_HDRLEN(tcphdr);
- if(pbuf_header(p, -(hdrlen * 4))){
- /* drop short packets */
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
- TCP_STATS_INC(tcp.lenerr);
- TCP_STATS_INC(tcp.drop);
- snmp_inc_tcpinerrs();
- pbuf_free(p);
- return;
- }
-
- /* Convert fields in TCP header to host byte order. */
- tcphdr->src = ntohs(tcphdr->src);
- tcphdr->dest = ntohs(tcphdr->dest);
- seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
- ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
- tcphdr->wnd = ntohs(tcphdr->wnd);
-
- flags = TCPH_FLAGS(tcphdr);
- tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);
-
- /* Demultiplex an incoming segment. First, we check if it is destined
- for an active connection. */
- prev = NULL;
-
-
- for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
- LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
- LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
- if (pcb->remote_port == tcphdr->src &&
- pcb->local_port == tcphdr->dest &&
- ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) &&
- ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) {
-
- /* Move this PCB to the front of the list so that subsequent
- lookups will be faster (we exploit locality in TCP segment
- arrivals). */
- LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
- if (prev != NULL) {
- prev->next = pcb->next;
- pcb->next = tcp_active_pcbs;
- tcp_active_pcbs = pcb;
- }
- LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
- break;
- }
- prev = pcb;
- }
-
- if (pcb == NULL) {
- /* If it did not go to an active connection, we check the connections
- in the TIME-WAIT state. */
- for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
- if (pcb->remote_port == tcphdr->src &&
- pcb->local_port == tcphdr->dest &&
- ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) &&
- ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) {
- /* We don't really care enough to move this PCB to the front
- of the list since we are not very likely to receive that
- many segments for connections in TIME-WAIT. */
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));
- tcp_timewait_input(pcb);
- pbuf_free(p);
- return;
- }
- }
-
- /* Finally, if we still did not get a match, we check all PCBs that
- are LISTENing for incoming connections. */
- prev = NULL;
- for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
- if (lpcb->local_port == tcphdr->dest) {
-#if SO_REUSE
- if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest)) {
- /* found an exact match */
- break;
- } else if(ip_addr_isany(&(lpcb->local_ip))) {
- /* found an ANY-match */
- lpcb_any = lpcb;
- lpcb_prev = prev;
- }
-#else /* SO_REUSE */
- if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest) ||
- ip_addr_isany(&(lpcb->local_ip))) {
- /* found a match */
- break;
- }
-#endif /* SO_REUSE */
- }
- prev = (struct tcp_pcb *)lpcb;
- }
-#if SO_REUSE
- /* first try specific local IP */
- if (lpcb == NULL) {
- /* only pass to ANY if no specific local IP has been found */
- lpcb = lpcb_any;
- prev = lpcb_prev;
- }
-#endif /* SO_REUSE */
- if (lpcb != NULL) {
- /* Move this PCB to the front of the list so that subsequent
- lookups will be faster (we exploit locality in TCP segment
- arrivals). */
- if (prev != NULL) {
- ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
- /* our successor is the remainder of the listening list */
- lpcb->next = tcp_listen_pcbs.listen_pcbs;
- /* put this listening pcb at the head of the listening list */
- tcp_listen_pcbs.listen_pcbs = lpcb;
- }
-
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
- tcp_listen_input(lpcb);
- pbuf_free(p);
- return;
- }
- }
-
-#if TCP_INPUT_DEBUG
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));
- tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));
-#endif /* TCP_INPUT_DEBUG */
-
-
- if (pcb != NULL) {
- /* The incoming segment belongs to a connection. */
-#if TCP_INPUT_DEBUG
-#if TCP_DEBUG
- tcp_debug_print_state(pcb->state);
-#endif /* TCP_DEBUG */
-#endif /* TCP_INPUT_DEBUG */
-
- /* Set up a tcp_seg structure. */
- inseg.next = NULL;
- inseg.len = p->tot_len;
- inseg.p = p;
- inseg.tcphdr = tcphdr;
-
- recv_data = NULL;
- recv_flags = 0;
-
- /* If there is data which was previously "refused" by upper layer */
- if (pcb->refused_data != NULL) {
- /* Notify again application with data previously received. */
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
- TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
- if (err == ERR_OK) {
- pcb->refused_data = NULL;
- } else if ((err == ERR_ABRT) || (tcplen > 0)) {
- /* if err == ERR_ABRT, 'pcb' is already deallocated */
- /* Drop incoming packets because pcb is "full" (only if the incoming
- segment contains data). */
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
- TCP_STATS_INC(tcp.drop);
- snmp_inc_tcpinerrs();
- pbuf_free(p);
- return;
- }
- }
- tcp_input_pcb = pcb;
- err = tcp_process(pcb);
- /* A return value of ERR_ABRT means that tcp_abort() was called
- and that the pcb has been freed. If so, we don't do anything. */
- if (err != ERR_ABRT) {
- if (recv_flags & TF_RESET) {
- /* TF_RESET means that the connection was reset by the other
- end. We then call the error callback to inform the
- application that the connection is dead before we
- deallocate the PCB. */
- TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);
- tcp_pcb_remove(&tcp_active_pcbs, pcb);
- memp_free(MEMP_TCP_PCB, pcb);
- } else if (recv_flags & TF_CLOSED) {
- /* The connection has been closed and we will deallocate the
- PCB. */
- tcp_pcb_remove(&tcp_active_pcbs, pcb);
- memp_free(MEMP_TCP_PCB, pcb);
- } else {
- err = ERR_OK;
- /* If the application has registered a "sent" function to be
- called when new send buffer space is available, we call it
- now. */
- if (pcb->acked > 0) {
- TCP_EVENT_SENT(pcb, pcb->acked, err);
- if (err == ERR_ABRT) {
- goto aborted;
- }
- }
-
- if (recv_data != NULL) {
- LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL);
- if (pcb->flags & TF_RXCLOSED) {
- /* received data although already closed -> abort (send RST) to
- notify the remote host that not all data has been processed */
- pbuf_free(recv_data);
- tcp_abort(pcb);
- goto aborted;
- }
- if (flags & TCP_PSH) {
- recv_data->flags |= PBUF_FLAG_PUSH;
- }
-
- /* Notify application that data has been received. */
- TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
- if (err == ERR_ABRT) {
- goto aborted;
- }
-
- /* If the upper layer can't receive this data, store it */
- if (err != ERR_OK) {
- pcb->refused_data = recv_data;
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));
- }
- }
-
- /* If a FIN segment was received, we call the callback
- function with a NULL buffer to indicate EOF. */
- if (recv_flags & TF_GOT_FIN) {
- /* correct rcv_wnd as the application won't call tcp_recved()
- for the FIN's seqno */
- if (pcb->rcv_wnd != TCP_WND) {
- pcb->rcv_wnd++;
- }
- TCP_EVENT_CLOSED(pcb, err);
- if (err == ERR_ABRT) {
- goto aborted;
- }
- }
-
- tcp_input_pcb = NULL;
- /* Try to send something out. */
- tcp_output(pcb);
-#if TCP_INPUT_DEBUG
-#if TCP_DEBUG
- tcp_debug_print_state(pcb->state);
-#endif /* TCP_DEBUG */
-#endif /* TCP_INPUT_DEBUG */
- }
- }
- /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
- Below this line, 'pcb' may not be dereferenced! */
-aborted:
- tcp_input_pcb = NULL;
- recv_data = NULL;
-
- /* give up our reference to inseg.p */
- if (inseg.p != NULL)
- {
- pbuf_free(inseg.p);
- inseg.p = NULL;
- }
- } else {
-
- /* If no matching PCB was found, send a TCP RST (reset) to the
- sender. */
- LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
- if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
- TCP_STATS_INC(tcp.proterr);
- TCP_STATS_INC(tcp.drop);
- tcp_rst(ackno, seqno + tcplen,
- ip_current_dest_addr(), ip_current_src_addr(),
- tcphdr->dest, tcphdr->src);
- }
- pbuf_free(p);
- }
-
- LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
- PERF_STOP("tcp_input");
-}
-
-/**
- * Called by tcp_input() when a segment arrives for a listening
- * connection (from tcp_input()).
- *
- * @param pcb the tcp_pcb_listen for which a segment arrived
- * @return ERR_OK if the segment was processed
- * another err_t on error
- *
- * @note the return value is not (yet?) used in tcp_input()
- * @note the segment which arrived is saved in global variables, therefore only the pcb
- * involved is passed as a parameter to this function
- */
-static err_t
-tcp_listen_input(struct tcp_pcb_listen *pcb)
-{
- struct tcp_pcb *npcb;
- err_t rc;
-
- /* In the LISTEN state, we check for incoming SYN segments,
- creates a new PCB, and responds with a SYN|ACK. */
- if (flags & TCP_ACK) {
- /* For incoming segments with the ACK flag set, respond with a
- RST. */
- LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
- tcp_rst(ackno + 1, seqno + tcplen,
- ip_current_dest_addr(), ip_current_src_addr(),
- tcphdr->dest, tcphdr->src);
- } else if (flags & TCP_SYN) {
- LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
-#if TCP_LISTEN_BACKLOG
- if (pcb->accepts_pending >= pcb->backlog) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest));
- return ERR_ABRT;
- }
-#endif /* TCP_LISTEN_BACKLOG */
- npcb = tcp_alloc(pcb->prio);
- /* If a new PCB could not be created (probably due to lack of memory),
- we don't do anything, but rely on the sender will retransmit the
- SYN at a time when we have more memory available. */
- if (npcb == NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
- TCP_STATS_INC(tcp.memerr);
- return ERR_MEM;
- }
-#if TCP_LISTEN_BACKLOG
- pcb->accepts_pending++;
-#endif /* TCP_LISTEN_BACKLOG */
- /* Set up the new PCB. */
- ip_addr_copy(npcb->local_ip, current_iphdr_dest);
- npcb->local_port = pcb->local_port;
- ip_addr_copy(npcb->remote_ip, current_iphdr_src);
- npcb->remote_port = tcphdr->src;
- npcb->state = SYN_RCVD;
- npcb->rcv_nxt = seqno + 1;
- npcb->rcv_ann_right_edge = npcb->rcv_nxt;
- npcb->snd_wnd = tcphdr->wnd;
- npcb->ssthresh = npcb->snd_wnd;
- npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
- npcb->callback_arg = pcb->callback_arg;
-#if LWIP_CALLBACK_API
- npcb->accept = pcb->accept;
-#endif /* LWIP_CALLBACK_API */
- /* inherit socket options */
- npcb->so_options = pcb->so_options & SOF_INHERITED;
- /* Register the new PCB so that we can begin receiving segments
- for it. */
- TCP_REG(&tcp_active_pcbs, npcb);
-
- /* Parse any options in the SYN. */
- tcp_parseopt(npcb);
-#if TCP_CALCULATE_EFF_SEND_MSS
- npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
-#endif /* TCP_CALCULATE_EFF_SEND_MSS */
-
- snmp_inc_tcppassiveopens();
-
- /* Send a SYN|ACK together with the MSS option. */
- rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
- if (rc != ERR_OK) {
- tcp_abandon(npcb, 0);
- return rc;
- }
- return tcp_output(npcb);
- }
- return ERR_OK;
-}
-
-/**
- * Called by tcp_input() when a segment arrives for a connection in
- * TIME_WAIT.
- *
- * @param pcb the tcp_pcb for which a segment arrived
- *
- * @note the segment which arrived is saved in global variables, therefore only the pcb
- * involved is passed as a parameter to this function
- */
-static err_t
-tcp_timewait_input(struct tcp_pcb *pcb)
-{
- /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */
- /* RFC 793 3.9 Event Processing - Segment Arrives:
- * - first check sequence number - we skip that one in TIME_WAIT (always
- * acceptable since we only send ACKs)
- * - second check the RST bit (... return) */
- if (flags & TCP_RST) {
- return ERR_OK;
- }
- /* - fourth, check the SYN bit, */
- if (flags & TCP_SYN) {
- /* If an incoming segment is not acceptable, an acknowledgment
- should be sent in reply */
- if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
- /* If the SYN is in the window it is an error, send a reset */
- tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
- tcphdr->dest, tcphdr->src);
- return ERR_OK;
- }
- } else if (flags & TCP_FIN) {
- /* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
- Restart the 2 MSL time-wait timeout.*/
- pcb->tmr = tcp_ticks;
- }
-
- if ((tcplen > 0)) {
- /* Acknowledge data, FIN or out-of-window SYN */
- pcb->flags |= TF_ACK_NOW;
- return tcp_output(pcb);
- }
- return ERR_OK;
-}
-
-/**
- * Implements the TCP state machine. Called by tcp_input. In some
- * states tcp_receive() is called to receive data. The tcp_seg
- * argument will be freed by the caller (tcp_input()) unless the
- * recv_data pointer in the pcb is set.
- *
- * @param pcb the tcp_pcb for which a segment arrived
- *
- * @note the segment which arrived is saved in global variables, therefore only the pcb
- * involved is passed as a parameter to this function
- */
-static err_t
-tcp_process(struct tcp_pcb *pcb)
-{
- struct tcp_seg *rseg;
- u8_t acceptable = 0;
- err_t err;
-
- err = ERR_OK;
-
- /* Process incoming RST segments. */
- if (flags & TCP_RST) {
- /* First, determine if the reset is acceptable. */
- if (pcb->state == SYN_SENT) {
- if (ackno == pcb->snd_nxt) {
- acceptable = 1;
- }
- } else {
- if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
- pcb->rcv_nxt+pcb->rcv_wnd)) {
- acceptable = 1;
- }
- }
-
- if (acceptable) {
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
- LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
- recv_flags |= TF_RESET;
- pcb->flags &= ~TF_ACK_DELAY;
- return ERR_RST;
- } else {
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
- seqno, pcb->rcv_nxt));
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
- seqno, pcb->rcv_nxt));
- return ERR_OK;
- }
- }
-
- if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) {
- /* Cope with new connection attempt after remote end crashed */
- tcp_ack_now(pcb);
- return ERR_OK;
- }
-
- if ((pcb->flags & TF_RXCLOSED) == 0) {
- /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
- pcb->tmr = tcp_ticks;
- }
- pcb->keep_cnt_sent = 0;
-
- tcp_parseopt(pcb);
-
- /* Do different things depending on the TCP state. */
- switch (pcb->state) {
- case SYN_SENT:
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
- pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
- /* received SYN ACK with expected sequence number? */
- if ((flags & TCP_ACK) && (flags & TCP_SYN)
- && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
- pcb->snd_buf++;
- pcb->rcv_nxt = seqno + 1;
- pcb->rcv_ann_right_edge = pcb->rcv_nxt;
- pcb->lastack = ackno;
- pcb->snd_wnd = tcphdr->wnd;
- pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
- pcb->state = ESTABLISHED;
-
-#if TCP_CALCULATE_EFF_SEND_MSS
- pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
-#endif /* TCP_CALCULATE_EFF_SEND_MSS */
-
- /* Set ssthresh again after changing pcb->mss (already set in tcp_connect
- * but for the default value of pcb->mss) */
- pcb->ssthresh = pcb->mss * 10;
-
- pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
- LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
- --pcb->snd_queuelen;
- LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
- rseg = pcb->unacked;
- pcb->unacked = rseg->next;
-
- /* If there's nothing left to acknowledge, stop the retransmit
- timer, otherwise reset it to start again */
- if(pcb->unacked == NULL)
- pcb->rtime = -1;
- else {
- pcb->rtime = 0;
- pcb->nrtx = 0;
- }
-
- tcp_seg_free(rseg);
-
- /* Call the user specified function to call when sucessfully
- * connected. */
- TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
- if (err == ERR_ABRT) {
- return ERR_ABRT;
- }
- tcp_ack_now(pcb);
- }
- /* received ACK? possibly a half-open connection */
- else if (flags & TCP_ACK) {
- /* send a RST to bring the other side in a non-synchronized state. */
- tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
- tcphdr->dest, tcphdr->src);
- }
- break;
- case SYN_RCVD:
- if (flags & TCP_ACK) {
- /* expected ACK number? */
- if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
- u16_t old_cwnd;
- pcb->state = ESTABLISHED;
- LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
-#if LWIP_CALLBACK_API
- LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
-#endif
- /* Call the accept function. */
- TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
- if (err != ERR_OK) {
- /* If the accept function returns with an error, we abort
- * the connection. */
- /* Already aborted? */
- if (err != ERR_ABRT) {
- tcp_abort(pcb);
- }
- return ERR_ABRT;
- }
- old_cwnd = pcb->cwnd;
- /* If there was any data contained within this ACK,
- * we'd better pass it on to the application as well. */
- tcp_receive(pcb);
-
- /* Prevent ACK for SYN to generate a sent event */
- if (pcb->acked != 0) {
- pcb->acked--;
- }
-
- pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
-
- if (recv_flags & TF_GOT_FIN) {
- tcp_ack_now(pcb);
- pcb->state = CLOSE_WAIT;
- }
- } else {
- /* incorrect ACK number, send RST */
- tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
- tcphdr->dest, tcphdr->src);
- }
- } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
- /* Looks like another copy of the SYN - retransmit our SYN-ACK */
- tcp_rexmit(pcb);
- }
- break;
- case CLOSE_WAIT:
- /* FALLTHROUGH */
- case ESTABLISHED:
- tcp_receive(pcb);
- if (recv_flags & TF_GOT_FIN) { /* passive close */
- tcp_ack_now(pcb);
- pcb->state = CLOSE_WAIT;
- }
- break;
- case FIN_WAIT_1:
- tcp_receive(pcb);
- if (recv_flags & TF_GOT_FIN) {
- if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
- LWIP_DEBUGF(TCP_DEBUG,
- ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
- tcp_ack_now(pcb);
- tcp_pcb_purge(pcb);
- TCP_RMV(&tcp_active_pcbs, pcb);
- pcb->state = TIME_WAIT;
- TCP_REG(&tcp_tw_pcbs, pcb);
- } else {
- tcp_ack_now(pcb);
- pcb->state = CLOSING;
- }
- } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
- pcb->state = FIN_WAIT_2;
- }
- break;
- case FIN_WAIT_2:
- tcp_receive(pcb);
- if (recv_flags & TF_GOT_FIN) {
- LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
- tcp_ack_now(pcb);
- tcp_pcb_purge(pcb);
- TCP_RMV(&tcp_active_pcbs, pcb);
- pcb->state = TIME_WAIT;
- TCP_REG(&tcp_tw_pcbs, pcb);
- }
- break;
- case CLOSING:
- tcp_receive(pcb);
- if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
- LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
- tcp_pcb_purge(pcb);
- TCP_RMV(&tcp_active_pcbs, pcb);
- pcb->state = TIME_WAIT;
- TCP_REG(&tcp_tw_pcbs, pcb);
- }
- break;
- case LAST_ACK:
- tcp_receive(pcb);
- if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
- LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
- /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
- recv_flags |= TF_CLOSED;
- }
- break;
- default:
- break;
- }
- return ERR_OK;
-}
-
-#if TCP_QUEUE_OOSEQ
-/**
- * Insert segment into the list (segments covered with new one will be deleted)
- *
- * Called from tcp_receive()
- */
-static void
-tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
-{
- struct tcp_seg *old_seg;
-
- if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
- /* received segment overlaps all following segments */
- tcp_segs_free(next);
- next = NULL;
- }
- else {
- /* delete some following segments
- oos queue may have segments with FIN flag */
- while (next &&
- TCP_SEQ_GEQ((seqno + cseg->len),
- (next->tcphdr->seqno + next->len))) {
- /* cseg with FIN already processed */
- if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
- TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN);
- }
- old_seg = next;
- next = next->next;
- tcp_seg_free(old_seg);
- }
- if (next &&
- TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
- /* We need to trim the incoming segment. */
- cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
- pbuf_realloc(cseg->p, cseg->len);
- }
- }
- cseg->next = next;
-}
-#endif /* TCP_QUEUE_OOSEQ */
-
-/**
- * Called by tcp_process. Checks if the given segment is an ACK for outstanding
- * data, and if so frees the memory of the buffered data. Next, is places the
- * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
- * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
- * i it has been removed from the buffer.
- *
- * If the incoming segment constitutes an ACK for a segment that was used for RTT
- * estimation, the RTT is estimated here as well.
- *
- * Called from tcp_process().
- */
-static void
-tcp_receive(struct tcp_pcb *pcb)
-{
- struct tcp_seg *next;
-#if TCP_QUEUE_OOSEQ
- struct tcp_seg *prev, *cseg;
-#endif /* TCP_QUEUE_OOSEQ */
- struct pbuf *p;
- s32_t off;
- s16_t m;
- u32_t right_wnd_edge;
- u16_t new_tot_len;
- int found_dupack = 0;
-
- if (flags & TCP_ACK) {
- right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
-
- /* Update window. */
- if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
- (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
- (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
- pcb->snd_wnd = tcphdr->wnd;
- pcb->snd_wl1 = seqno;
- pcb->snd_wl2 = ackno;
- if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
- pcb->persist_backoff = 0;
- }
- LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
-#if TCP_WND_DEBUG
- } else {
- if (pcb->snd_wnd != tcphdr->wnd) {
- LWIP_DEBUGF(TCP_WND_DEBUG,
- ("tcp_receive: no window update lastack %"U32_F" ackno %"
- U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
- pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
- }
-#endif /* TCP_WND_DEBUG */
- }
-
- /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
- * duplicate ack if:
- * 1) It doesn't ACK new data
- * 2) length of received packet is zero (i.e. no payload)
- * 3) the advertised window hasn't changed
- * 4) There is outstanding unacknowledged data (retransmission timer running)
- * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
- *
- * If it passes all five, should process as a dupack:
- * a) dupacks < 3: do nothing
- * b) dupacks == 3: fast retransmit
- * c) dupacks > 3: increase cwnd
- *
- * If it only passes 1-3, should reset dupack counter (and add to
- * stats, which we don't do in lwIP)
- *
- * If it only passes 1, should reset dupack counter
- *
- */
-
- /* Clause 1 */
- if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {
- pcb->acked = 0;
- /* Clause 2 */
- if (tcplen == 0) {
- /* Clause 3 */
- if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
- /* Clause 4 */
- if (pcb->rtime >= 0) {
- /* Clause 5 */
- if (pcb->lastack == ackno) {
- found_dupack = 1;
- if (pcb->dupacks + 1 > pcb->dupacks)
- ++pcb->dupacks;
- if (pcb->dupacks > 3) {
- /* Inflate the congestion window, but not if it means that
- the value overflows. */
- if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
- pcb->cwnd += pcb->mss;
- }
- } else if (pcb->dupacks == 3) {
- /* Do fast retransmit */
- tcp_rexmit_fast(pcb);
- }
- }
- }
- }
- }
- /* If Clause (1) or more is true, but not a duplicate ack, reset
- * count of consecutive duplicate acks */
- if (!found_dupack) {
- pcb->dupacks = 0;
- }
- } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
- /* We come here when the ACK acknowledges new data. */
-
- /* Reset the "IN Fast Retransmit" flag, since we are no longer
- in fast retransmit. Also reset the congestion window to the
- slow start threshold. */
- if (pcb->flags & TF_INFR) {
- pcb->flags &= ~TF_INFR;
- pcb->cwnd = pcb->ssthresh;
- }
-
- /* Reset the number of retransmissions. */
- pcb->nrtx = 0;
-
- /* Reset the retransmission time-out. */
- pcb->rto = (pcb->sa >> 3) + pcb->sv;
-
- /* Update the send buffer space. Diff between the two can never exceed 64K? */
- pcb->acked = (u16_t)(ackno - pcb->lastack);
-
- pcb->snd_buf += pcb->acked;
-
- /* Reset the fast retransmit variables. */
- pcb->dupacks = 0;
- pcb->lastack = ackno;
-
- /* Update the congestion control variables (cwnd and
- ssthresh). */
- if (pcb->state >= ESTABLISHED) {
- if (pcb->cwnd < pcb->ssthresh) {
- if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
- pcb->cwnd += pcb->mss;
- }
- LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
- } else {
- u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
- if (new_cwnd > pcb->cwnd) {
- pcb->cwnd = new_cwnd;
- }
- LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
- }
- }
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
- ackno,
- pcb->unacked != NULL?
- ntohl(pcb->unacked->tcphdr->seqno): 0,
- pcb->unacked != NULL?
- ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
-
- /* Remove segment from the unacknowledged list if the incoming
- ACK acknowlegdes them. */
- while (pcb->unacked != NULL &&
- TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
- TCP_TCPLEN(pcb->unacked), ackno)) {
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
- ntohl(pcb->unacked->tcphdr->seqno),
- ntohl(pcb->unacked->tcphdr->seqno) +
- TCP_TCPLEN(pcb->unacked)));
-
- next = pcb->unacked;
- pcb->unacked = pcb->unacked->next;
-
- LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
- LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
- /* Prevent ACK for FIN to generate a sent event */
- if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
- pcb->acked--;
- }
-
- pcb->snd_queuelen -= pbuf_clen(next->p);
- tcp_seg_free(next);
-
- LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
- if (pcb->snd_queuelen != 0) {
- LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
- pcb->unsent != NULL);
- }
- }
-
- /* If there's nothing left to acknowledge, stop the retransmit
- timer, otherwise reset it to start again */
- if(pcb->unacked == NULL)
- pcb->rtime = -1;
- else
- pcb->rtime = 0;
-
- pcb->polltmr = 0;
- } else {
- /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
- pcb->acked = 0;
- }
-
- /* We go through the ->unsent list to see if any of the segments
- on the list are acknowledged by the ACK. This may seem
- strange since an "unsent" segment shouldn't be acked. The
- rationale is that lwIP puts all outstanding segments on the
- ->unsent list after a retransmission, so these segments may
- in fact have been sent once. */
- while (pcb->unsent != NULL &&
- TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) +
- TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
- ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
- TCP_TCPLEN(pcb->unsent)));
-
- next = pcb->unsent;
- pcb->unsent = pcb->unsent->next;
- LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
- LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
- /* Prevent ACK for FIN to generate a sent event */
- if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
- pcb->acked--;
- }
- pcb->snd_queuelen -= pbuf_clen(next->p);
- tcp_seg_free(next);
- LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
- if (pcb->snd_queuelen != 0) {
- LWIP_ASSERT("tcp_receive: valid queue length",
- pcb->unacked != NULL || pcb->unsent != NULL);
- }
- }
- /* End of ACK for new data processing. */
-
- LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
- pcb->rttest, pcb->rtseq, ackno));
-
- /* RTT estimation calculations. This is done by checking if the
- incoming segment acknowledges the segment we use to take a
- round-trip time measurement. */
- if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
- /* diff between this shouldn't exceed 32K since this are tcp timer ticks
- and a round-trip shouldn't be that long... */
- m = (s16_t)(tcp_ticks - pcb->rttest);
-
- LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
- m, m * TCP_SLOW_INTERVAL));
-
- /* This is taken directly from VJs original code in his paper */
- m = m - (pcb->sa >> 3);
- pcb->sa += m;
- if (m < 0) {
- m = -m;
- }
- m = m - (pcb->sv >> 2);
- pcb->sv += m;
- pcb->rto = (pcb->sa >> 3) + pcb->sv;
-
- LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",
- pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
-
- pcb->rttest = 0;
- }
- }
-
- /* If the incoming segment contains data, we must process it
- further. */
- if (tcplen > 0) {
- /* This code basically does three things:
-
- +) If the incoming segment contains data that is the next
- in-sequence data, this data is passed to the application. This
- might involve trimming the first edge of the data. The rcv_nxt
- variable and the advertised window are adjusted.
-
- +) If the incoming segment has data that is above the next
- sequence number expected (->rcv_nxt), the segment is placed on
- the ->ooseq queue. This is done by finding the appropriate
- place in the ->ooseq queue (which is ordered by sequence
- number) and trim the segment in both ends if needed. An
- immediate ACK is sent to indicate that we received an
- out-of-sequence segment.
-
- +) Finally, we check if the first segment on the ->ooseq queue
- now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
- rcv_nxt > ooseq->seqno, we must trim the first edge of the
- segment on ->ooseq before we adjust rcv_nxt. The data in the
- segments that are now on sequence are chained onto the
- incoming segment so that we only need to call the application
- once.
- */
-
- /* First, we check if we must trim the first edge. We have to do
- this if the sequence number of the incoming segment is less
- than rcv_nxt, and the sequence number plus the length of the
- segment is larger than rcv_nxt. */
- /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
- if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
- if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
- /* Trimming the first edge is done by pushing the payload
- pointer in the pbuf downwards. This is somewhat tricky since
- we do not want to discard the full contents of the pbuf up to
- the new starting point of the data since we have to keep the
- TCP header which is present in the first pbuf in the chain.
-
- What is done is really quite a nasty hack: the first pbuf in
- the pbuf chain is pointed to by inseg.p. Since we need to be
- able to deallocate the whole pbuf, we cannot change this
- inseg.p pointer to point to any of the later pbufs in the
- chain. Instead, we point the ->payload pointer in the first
- pbuf to data in one of the later pbufs. We also set the
- inseg.data pointer to point to the right place. This way, the
- ->p pointer will still point to the first pbuf, but the
- ->p->payload pointer will point to data in another pbuf.
-
- After we are done with adjusting the pbuf pointers we must
- adjust the ->data pointer in the seg and the segment
- length.*/
-
- off = pcb->rcv_nxt - seqno;
- p = inseg.p;
- LWIP_ASSERT("inseg.p != NULL", inseg.p);
- LWIP_ASSERT("insane offset!", (off < 0x7fff));
- if (inseg.p->len < off) {
- LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off));
- new_tot_len = (u16_t)(inseg.p->tot_len - off);
- while (p->len < off) {
- off -= p->len;
- /* KJM following line changed (with addition of new_tot_len var)
- to fix bug #9076
- inseg.p->tot_len -= p->len; */
- p->tot_len = new_tot_len;
- p->len = 0;
- p = p->next;
- }
- if(pbuf_header(p, (s16_t)-off)) {
- /* Do we need to cope with this failing? Assert for now */
- LWIP_ASSERT("pbuf_header failed", 0);
- }
- } else {
- if(pbuf_header(inseg.p, (s16_t)-off)) {
- /* Do we need to cope with this failing? Assert for now */
- LWIP_ASSERT("pbuf_header failed", 0);
- }
- }
- inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
- inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
- }
- else {
- if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
- /* the whole segment is < rcv_nxt */
- /* must be a duplicate of a packet that has already been correctly handled */
-
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
- tcp_ack_now(pcb);
- }
- }
-
- /* The sequence number must be within the window (above rcv_nxt
- and below rcv_nxt + rcv_wnd) in order to be further
- processed. */
- if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
- pcb->rcv_nxt + pcb->rcv_wnd - 1)){
- if (pcb->rcv_nxt == seqno) {
- /* The incoming segment is the next in sequence. We check if
- we have to trim the end of the segment and update rcv_nxt
- and pass the data to the application. */
- tcplen = TCP_TCPLEN(&inseg);
-
- if (tcplen > pcb->rcv_wnd) {
- LWIP_DEBUGF(TCP_INPUT_DEBUG,
- ("tcp_receive: other end overran receive window"
- "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
- seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
- if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
- /* Must remove the FIN from the header as we're trimming
- * that byte of sequence-space from the packet */
- TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);
- }
- /* Adjust length of segment to fit in the window. */
- inseg.len = pcb->rcv_wnd;
- if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
- inseg.len -= 1;
- }
- pbuf_realloc(inseg.p, inseg.len);
- tcplen = TCP_TCPLEN(&inseg);
- LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
- (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
- }
-#if TCP_QUEUE_OOSEQ
- /* Received in-sequence data, adjust ooseq data if:
- - FIN has been received or
- - inseq overlaps with ooseq */
- if (pcb->ooseq != NULL) {
- if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
- LWIP_DEBUGF(TCP_INPUT_DEBUG,
- ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
- /* Received in-order FIN means anything that was received
- * out of order must now have been received in-order, so
- * bin the ooseq queue */
- while (pcb->ooseq != NULL) {
- struct tcp_seg *old_ooseq = pcb->ooseq;
- pcb->ooseq = pcb->ooseq->next;
- tcp_seg_free(old_ooseq);
- }
- }
- else {
- next = pcb->ooseq;
- /* Remove all segments on ooseq that are covered by inseg already.
- * FIN is copied from ooseq to inseg if present. */
- while (next &&
- TCP_SEQ_GEQ(seqno + tcplen,
- next->tcphdr->seqno + next->len)) {
- /* inseg cannot have FIN here (already processed above) */
- if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
- (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
- TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);
- tcplen = TCP_TCPLEN(&inseg);
- }
- prev = next;
- next = next->next;
- tcp_seg_free(prev);
- }
- /* Now trim right side of inseg if it overlaps with the first
- * segment on ooseq */
- if (next &&
- TCP_SEQ_GT(seqno + tcplen,
- next->tcphdr->seqno)) {
- /* inseg cannot have FIN here (already processed above) */
- inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
- if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
- inseg.len -= 1;
- }
- pbuf_realloc(inseg.p, inseg.len);
- tcplen = TCP_TCPLEN(&inseg);
- LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
- (seqno + tcplen) == next->tcphdr->seqno);
- }
- pcb->ooseq = next;
- }
- }
-#endif /* TCP_QUEUE_OOSEQ */
-
- pcb->rcv_nxt = seqno + tcplen;
-
- /* Update the receiver's (our) window. */
- LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
- pcb->rcv_wnd -= tcplen;
-
- tcp_update_rcv_ann_wnd(pcb);
-
- /* If there is data in the segment, we make preparations to
- pass this up to the application. The ->recv_data variable
- is used for holding the pbuf that goes to the
- application. The code for reassembling out-of-sequence data
- chains its data on this pbuf as well.
-
- If the segment was a FIN, we set the TF_GOT_FIN flag that will
- be used to indicate to the application that the remote side has
- closed its end of the connection. */
- if (inseg.p->tot_len > 0) {
- recv_data = inseg.p;
- /* Since this pbuf now is the responsibility of the
- application, we delete our reference to it so that we won't
- (mistakingly) deallocate it. */
- inseg.p = NULL;
- }
- if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
- recv_flags |= TF_GOT_FIN;
- }
-
-#if TCP_QUEUE_OOSEQ
- /* We now check if we have segments on the ->ooseq queue that
- are now in sequence. */
- while (pcb->ooseq != NULL &&
- pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
-
- cseg = pcb->ooseq;
- seqno = pcb->ooseq->tcphdr->seqno;
-
- pcb->rcv_nxt += TCP_TCPLEN(cseg);
- LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
- pcb->rcv_wnd >= TCP_TCPLEN(cseg));
- pcb->rcv_wnd -= TCP_TCPLEN(cseg);
-
- tcp_update_rcv_ann_wnd(pcb);
-
- if (cseg->p->tot_len > 0) {
- /* Chain this pbuf onto the pbuf that we will pass to
- the application. */
- if (recv_data) {
- pbuf_cat(recv_data, cseg->p);
- } else {
- recv_data = cseg->p;
- }
- cseg->p = NULL;
- }
- if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
- recv_flags |= TF_GOT_FIN;
- if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
- pcb->state = CLOSE_WAIT;
- }
- }
-
- pcb->ooseq = cseg->next;
- tcp_seg_free(cseg);
- }
-#endif /* TCP_QUEUE_OOSEQ */
-
-
- /* Acknowledge the segment(s). */
- tcp_ack(pcb);
-
- } else {
- /* We get here if the incoming segment is out-of-sequence. */
- tcp_send_empty_ack(pcb);
-#if TCP_QUEUE_OOSEQ
- /* We queue the segment on the ->ooseq queue. */
- if (pcb->ooseq == NULL) {
- pcb->ooseq = tcp_seg_copy(&inseg);
- } else {
- /* If the queue is not empty, we walk through the queue and
- try to find a place where the sequence number of the
- incoming segment is between the sequence numbers of the
- previous and the next segment on the ->ooseq queue. That is
- the place where we put the incoming segment. If needed, we
- trim the second edges of the previous and the incoming
- segment so that it will fit into the sequence.
-
- If the incoming segment has the same sequence number as a
- segment on the ->ooseq queue, we discard the segment that
- contains less data. */
-
- prev = NULL;
- for(next = pcb->ooseq; next != NULL; next = next->next) {
- if (seqno == next->tcphdr->seqno) {
- /* The sequence number of the incoming segment is the
- same as the sequence number of the segment on
- ->ooseq. We check the lengths to see which one to
- discard. */
- if (inseg.len > next->len) {
- /* The incoming segment is larger than the old
- segment. We replace some segments with the new
- one. */
- cseg = tcp_seg_copy(&inseg);
- if (cseg != NULL) {
- if (prev != NULL) {
- prev->next = cseg;
- } else {
- pcb->ooseq = cseg;
- }
- tcp_oos_insert_segment(cseg, next);
- }
- break;
- } else {
- /* Either the lenghts are the same or the incoming
- segment was smaller than the old one; in either
- case, we ditch the incoming segment. */
- break;
- }
- } else {
- if (prev == NULL) {
- if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
- /* The sequence number of the incoming segment is lower
- than the sequence number of the first segment on the
- queue. We put the incoming segment first on the
- queue. */
- cseg = tcp_seg_copy(&inseg);
- if (cseg != NULL) {
- pcb->ooseq = cseg;
- tcp_oos_insert_segment(cseg, next);
- }
- break;
- }
- } else {
- /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
- TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
- if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {
- /* The sequence number of the incoming segment is in
- between the sequence numbers of the previous and
- the next segment on ->ooseq. We trim trim the previous
- segment, delete next segments that included in received segment
- and trim received, if needed. */
- cseg = tcp_seg_copy(&inseg);
- if (cseg != NULL) {
- if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
- /* We need to trim the prev segment. */
- prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
- pbuf_realloc(prev->p, prev->len);
- }
- prev->next = cseg;
- tcp_oos_insert_segment(cseg, next);
- }
- break;
- }
- }
- /* If the "next" segment is the last segment on the
- ooseq queue, we add the incoming segment to the end
- of the list. */
- if (next->next == NULL &&
- TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
- if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
- /* segment "next" already contains all data */
- break;
- }
- next->next = tcp_seg_copy(&inseg);
- if (next->next != NULL) {
- if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
- /* We need to trim the last segment. */
- next->len = (u16_t)(seqno - next->tcphdr->seqno);
- pbuf_realloc(next->p, next->len);
- }
- /* check if the remote side overruns our receive window */
- if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) {
- LWIP_DEBUGF(TCP_INPUT_DEBUG,
- ("tcp_receive: other end overran receive window"
- "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
- seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
- if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) {
- /* Must remove the FIN from the header as we're trimming
- * that byte of sequence-space from the packet */
- TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN);
- }
- /* Adjust length of segment to fit in the window. */
- next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno;
- pbuf_realloc(next->next->p, next->next->len);
- tcplen = TCP_TCPLEN(next->next);
- LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
- (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
- }
- }
- break;
- }
- }
- prev = next;
- }
- }
-#endif /* TCP_QUEUE_OOSEQ */
-
- }
- } else {
- /* The incoming segment is not withing the window. */
- tcp_send_empty_ack(pcb);
- }
- } else {
- /* Segments with length 0 is taken care of here. Segments that
- fall out of the window are ACKed. */
- /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
- TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
- if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
- tcp_ack_now(pcb);
- }
- }
-}
-
-/**
- * Parses the options contained in the incoming segment.
- *
- * Called from tcp_listen_input() and tcp_process().
- * Currently, only the MSS option is supported!
- *
- * @param pcb the tcp_pcb for which a segment arrived
- */
-static void
-tcp_parseopt(struct tcp_pcb *pcb)
-{
- u16_t c, max_c;
- u16_t mss;
- u8_t *opts, opt;
-#if LWIP_TCP_TIMESTAMPS
- u32_t tsval;
-#endif
-
- opts = (u8_t *)tcphdr + TCP_HLEN;
-
- /* Parse the TCP MSS option, if present. */
- if(TCPH_HDRLEN(tcphdr) > 0x5) {
- max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2;
- for (c = 0; c < max_c; ) {
- opt = opts[c];
- switch (opt) {
- case 0x00:
- /* End of options. */
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
- return;
- case 0x01:
- /* NOP option. */
- ++c;
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n"));
- break;
- case 0x02:
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n"));
- if (opts[c + 1] != 0x04 || c + 0x04 > max_c) {
- /* Bad length */
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
- return;
- }
- /* An MSS option with the right option length. */
- mss = (opts[c + 2] << 8) | opts[c + 3];
- /* Limit the mss to the configured TCP_MSS and prevent division by zero */
- pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;
- /* Advance to next option */
- c += 0x04;
- break;
-#if LWIP_TCP_TIMESTAMPS
- case 0x08:
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n"));
- if (opts[c + 1] != 0x0A || c + 0x0A > max_c) {
- /* Bad length */
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
- return;
- }
- /* TCP timestamp option with valid length */
- tsval = (opts[c+2]) | (opts[c+3] << 8) |
- (opts[c+4] << 16) | (opts[c+5] << 24);
- if (flags & TCP_SYN) {
- pcb->ts_recent = ntohl(tsval);
- pcb->flags |= TF_TIMESTAMP;
- } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {
- pcb->ts_recent = ntohl(tsval);
- }
- /* Advance to next option */
- c += 0x0A;
- break;
-#endif
- default:
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n"));
- if (opts[c + 1] == 0) {
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
- /* If the length field is zero, the options are malformed
- and we don't process them further. */
- return;
- }
- /* All other options have a length field, so that we easily
- can skip past them. */
- c += opts[c + 1];
- }
- }
- }
-}
-
-#endif /* LWIP_TCP */
+++ /dev/null
-/**
- * @file
- * Transmission Control Protocol, outgoing traffic
- *
- * The output functions of TCP.
- *
- */
-
-/*
- * 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_TCP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/tcp_impl.h"
-#include "lwip/def.h"
-#include "lwip/mem.h"
-#include "lwip/memp.h"
-#include "lwip/sys.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/inet_chksum.h"
-#include "lwip/stats.h"
-#include "lwip/snmp.h"
-
-#include <string.h>
-
-/* Define some copy-macros for checksum-on-copy so that the code looks
- nicer by preventing too many ifdef's. */
-#if TCP_CHECKSUM_ON_COPY
-#define TCP_DATA_COPY(dst, src, len, seg) do { \
- tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \
- len, &seg->chksum, &seg->chksum_swapped); \
- seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0)
-#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \
- tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped);
-#else /* TCP_CHECKSUM_ON_COPY*/
-#define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len)
-#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len)
-#endif /* TCP_CHECKSUM_ON_COPY*/
-
-/** Define this to 1 for an extra check that the output checksum is valid
- * (usefule when the checksum is generated by the application, not the stack) */
-#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK
-#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0
-#endif
-
-/* Forward declarations.*/
-static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
-
-/** Allocate a pbuf and create a tcphdr at p->payload, used for output
- * functions other than the default tcp_output -> tcp_output_segment
- * (e.g. tcp_send_empty_ack, etc.)
- *
- * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr)
- * @param optlen length of header-options
- * @param datalen length of tcp data to reserve in pbuf
- * @param seqno_be seqno in network byte order (big-endian)
- * @return pbuf with p->payload being the tcp_hdr
- */
-static struct pbuf *
-tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen,
- u32_t seqno_be /* already in network byte order */)
-{
- struct tcp_hdr *tcphdr;
- struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM);
- if (p != NULL) {
- LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
- (p->len >= TCP_HLEN + optlen));
- tcphdr = (struct tcp_hdr *)p->payload;
- tcphdr->src = htons(pcb->local_port);
- tcphdr->dest = htons(pcb->remote_port);
- tcphdr->seqno = seqno_be;
- tcphdr->ackno = htonl(pcb->rcv_nxt);
- TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);
- tcphdr->wnd = htons(pcb->rcv_ann_wnd);
- tcphdr->chksum = 0;
- tcphdr->urgp = 0;
-
- /* If we're sending a packet, update the announced right window edge */
- pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
- }
- return p;
-}
-
-/**
- * Called by tcp_close() to send a segment including FIN flag but not data.
- *
- * @param pcb the tcp_pcb over which to send a segment
- * @return ERR_OK if sent, another err_t otherwise
- */
-err_t
-tcp_send_fin(struct tcp_pcb *pcb)
-{
- /* first, try to add the fin to the last unsent segment */
- if (pcb->unsent != NULL) {
- struct tcp_seg *last_unsent;
- for (last_unsent = pcb->unsent; last_unsent->next != NULL;
- last_unsent = last_unsent->next);
-
- if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) {
- /* no SYN/FIN/RST flag in the header, we can add the FIN flag */
- TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN);
- return ERR_OK;
- }
- }
- /* no data, no length, flags, copy=1, no optdata */
- return tcp_enqueue_flags(pcb, TCP_FIN);
-}
-
-/**
- * Create a TCP segment with prefilled header.
- *
- * Called by tcp_write and tcp_enqueue_flags.
- *
- * @param pcb Protocol control block for the TCP connection.
- * @param p pbuf that is used to hold the TCP header.
- * @param flags TCP flags for header.
- * @param seqno TCP sequence number of this packet
- * @param optflags options to include in TCP header
- * @return a new tcp_seg pointing to p, or NULL.
- * The TCP header is filled in except ackno and wnd.
- * p is freed on failure.
- */
-static struct tcp_seg *
-tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags)
-{
- struct tcp_seg *seg;
- u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags);
-
- if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n"));
- pbuf_free(p);
- return NULL;
- }
- seg->flags = optflags;
- seg->next = NULL;
- seg->p = p;
- seg->len = p->tot_len - optlen;
-#if TCP_OVERSIZE_DBGCHECK
- seg->oversize_left = 0;
-#endif /* TCP_OVERSIZE_DBGCHECK */
-#if TCP_CHECKSUM_ON_COPY
- seg->chksum = 0;
- seg->chksum_swapped = 0;
- /* check optflags */
- LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED",
- (optflags & TF_SEG_DATA_CHECKSUMMED) == 0);
-#endif /* TCP_CHECKSUM_ON_COPY */
-
- /* build TCP header */
- if (pbuf_header(p, TCP_HLEN)) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n"));
- TCP_STATS_INC(tcp.err);
- tcp_seg_free(seg);
- return NULL;
- }
- seg->tcphdr = (struct tcp_hdr *)seg->p->payload;
- seg->tcphdr->src = htons(pcb->local_port);
- seg->tcphdr->dest = htons(pcb->remote_port);
- seg->tcphdr->seqno = htonl(seqno);
- /* ackno is set in tcp_output */
- TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags);
- /* wnd and chksum are set in tcp_output */
- seg->tcphdr->urgp = 0;
- return seg;
-}
-
-/**
- * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end.
- *
- * This function is like pbuf_alloc(layer, length, PBUF_RAM) except
- * there may be extra bytes available at the end.
- *
- * @param layer flag to define header size.
- * @param length size of the pbuf's payload.
- * @param max_length maximum usable size of payload+oversize.
- * @param oversize pointer to a u16_t that will receive the number of usable tail bytes.
- * @param pcb The TCP connection that willo enqueue the pbuf.
- * @param apiflags API flags given to tcp_write.
- * @param first_seg true when this pbuf will be used in the first enqueued segment.
- * @param
- */
-#if TCP_OVERSIZE
-static struct pbuf *
-tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length,
- u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags,
- u8_t first_seg)
-{
- struct pbuf *p;
- u16_t alloc = length;
-
-#if LWIP_NETIF_TX_SINGLE_PBUF
- LWIP_UNUSED_ARG(max_length);
- LWIP_UNUSED_ARG(pcb);
- LWIP_UNUSED_ARG(apiflags);
- LWIP_UNUSED_ARG(first_seg);
- /* always create MSS-sized pbufs */
- alloc = TCP_MSS;
-#else /* LWIP_NETIF_TX_SINGLE_PBUF */
- if (length < max_length) {
- /* Should we allocate an oversized pbuf, or just the minimum
- * length required? If tcp_write is going to be called again
- * before this segment is transmitted, we want the oversized
- * buffer. If the segment will be transmitted immediately, we can
- * save memory by allocating only length. We use a simple
- * heuristic based on the following information:
- *
- * Did the user set TCP_WRITE_FLAG_MORE?
- *
- * Will the Nagle algorithm defer transmission of this segment?
- */
- if ((apiflags & TCP_WRITE_FLAG_MORE) ||
- (!(pcb->flags & TF_NODELAY) &&
- (!first_seg ||
- pcb->unsent != NULL ||
- pcb->unacked != NULL))) {
- alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE));
- }
- }
-#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
- p = pbuf_alloc(layer, alloc, PBUF_RAM);
- if (p == NULL) {
- return NULL;
- }
- LWIP_ASSERT("need unchained pbuf", p->next == NULL);
- *oversize = p->len - length;
- /* trim p->len to the currently used size */
- p->len = p->tot_len = length;
- return p;
-}
-#else /* TCP_OVERSIZE */
-#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM)
-#endif /* TCP_OVERSIZE */
-
-#if TCP_CHECKSUM_ON_COPY
-/** Add a checksum of newly added data to the segment */
-static void
-tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum,
- u8_t *seg_chksum_swapped)
-{
- u32_t helper;
- /* add chksum to old chksum and fold to u16_t */
- helper = chksum + *seg_chksum;
- chksum = FOLD_U32T(helper);
- if ((len & 1) != 0) {
- *seg_chksum_swapped = 1 - *seg_chksum_swapped;
- chksum = SWAP_BYTES_IN_WORD(chksum);
- }
- *seg_chksum = chksum;
-}
-#endif /* TCP_CHECKSUM_ON_COPY */
-
-/** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen).
- *
- * @param pcb the tcp pcb to check for
- * @param len length of data to send (checked agains snd_buf)
- * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise
- */
-static err_t
-tcp_write_checks(struct tcp_pcb *pcb, u16_t len)
-{
- /* connection is in invalid state for data transmission? */
- if ((pcb->state != ESTABLISHED) &&
- (pcb->state != CLOSE_WAIT) &&
- (pcb->state != SYN_SENT) &&
- (pcb->state != SYN_RCVD)) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n"));
- return ERR_CONN;
- } else if (len == 0) {
- return ERR_OK;
- }
-
- /* fail on too much data */
- if (len > pcb->snd_buf) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n",
- len, pcb->snd_buf));
- pcb->flags |= TF_NAGLEMEMERR;
- return ERR_MEM;
- }
-
- LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
-
- /* If total number of pbufs on the unsent/unacked queues exceeds the
- * configured maximum, return an error */
- /* check for configured max queuelen and possible overflow */
- if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n",
- pcb->snd_queuelen, TCP_SND_QUEUELEN));
- TCP_STATS_INC(tcp.memerr);
- pcb->flags |= TF_NAGLEMEMERR;
- return ERR_MEM;
- }
- if (pcb->snd_queuelen != 0) {
- LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty",
- pcb->unacked != NULL || pcb->unsent != NULL);
- } else {
- LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty",
- pcb->unacked == NULL && pcb->unsent == NULL);
- }
- return ERR_OK;
-}
-
-/**
- * Write data for sending (but does not send it immediately).
- *
- * It waits in the expectation of more data being sent soon (as
- * it can send them more efficiently by combining them together).
- * To prompt the system to send data now, call tcp_output() after
- * calling tcp_write().
- *
- * @param pcb Protocol control block for the TCP connection to enqueue data for.
- * @param arg Pointer to the data to be enqueued for sending.
- * @param len Data length in bytes
- * @param apiflags combination of following flags :
- * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack
- * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,
- * @return ERR_OK if enqueued, another err_t on error
- */
-err_t
-tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
-{
- struct pbuf *concat_p = NULL;
- struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL;
- u16_t pos = 0; /* position in 'arg' data */
- u16_t queuelen;
- u8_t optlen = 0;
- u8_t optflags = 0;
-#if TCP_OVERSIZE
- u16_t oversize = 0;
- u16_t oversize_used = 0;
-#endif /* TCP_OVERSIZE */
-#if TCP_CHECKSUM_ON_COPY
- u16_t concat_chksum = 0;
- u8_t concat_chksum_swapped = 0;
- u16_t concat_chksummed = 0;
-#endif /* TCP_CHECKSUM_ON_COPY */
- err_t err;
-
-#if LWIP_NETIF_TX_SINGLE_PBUF
- /* Always copy to try to create single pbufs for TX */
- apiflags |= TCP_WRITE_FLAG_COPY;
-#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
-
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n",
- (void *)pcb, arg, len, (u16_t)apiflags));
- LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)",
- arg != NULL, return ERR_ARG;);
-
- err = tcp_write_checks(pcb, len);
- if (err != ERR_OK) {
- return err;
- }
- queuelen = pcb->snd_queuelen;
-
-#if LWIP_TCP_TIMESTAMPS
- if ((pcb->flags & TF_TIMESTAMP)) {
- optflags = TF_SEG_OPTS_TS;
- optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
- }
-#endif /* LWIP_TCP_TIMESTAMPS */
-
-
- /*
- * TCP segmentation is done in three phases with increasing complexity:
- *
- * 1. Copy data directly into an oversized pbuf.
- * 2. Chain a new pbuf to the end of pcb->unsent.
- * 3. Create new segments.
- *
- * We may run out of memory at any point. In that case we must
- * return ERR_MEM and not change anything in pcb. Therefore, all
- * changes are recorded in local variables and committed at the end
- * of the function. Some pcb fields are maintained in local copies:
- *
- * queuelen = pcb->snd_queuelen
- * oversize = pcb->unsent_oversize
- *
- * These variables are set consistently by the phases:
- *
- * seg points to the last segment tampered with.
- *
- * pos records progress as data is segmented.
- */
-
- /* Find the tail of the unsent queue. */
- if (pcb->unsent != NULL) {
- u16_t space;
- u16_t unsent_optlen;
-
- /* @todo: this could be sped up by keeping last_unsent in the pcb */
- for (last_unsent = pcb->unsent; last_unsent->next != NULL;
- last_unsent = last_unsent->next);
-
- /* Usable space at the end of the last unsent segment */
- unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags);
- space = pcb->mss - (last_unsent->len + unsent_optlen);
-
- /*
- * Phase 1: Copy data directly into an oversized pbuf.
- *
- * The number of bytes copied is recorded in the oversize_used
- * variable. The actual copying is done at the bottom of the
- * function.
- */
-#if TCP_OVERSIZE
-#if TCP_OVERSIZE_DBGCHECK
- /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */
- LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)",
- pcb->unsent_oversize == last_unsent->oversize_left);
-#endif /* TCP_OVERSIZE_DBGCHECK */
- oversize = pcb->unsent_oversize;
- if (oversize > 0) {
- LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space);
- seg = last_unsent;
- oversize_used = oversize < len ? oversize : len;
- pos += oversize_used;
- oversize -= oversize_used;
- space -= oversize_used;
- }
- /* now we are either finished or oversize is zero */
- LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len));
-#endif /* TCP_OVERSIZE */
-
- /*
- * Phase 2: Chain a new pbuf to the end of pcb->unsent.
- *
- * We don't extend segments containing SYN/FIN flags or options
- * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at
- * the end.
- */
- if ((pos < len) && (space > 0) && (last_unsent->len > 0)) {
- u16_t seglen = space < len - pos ? space : len - pos;
- seg = last_unsent;
-
- /* Create a pbuf with a copy or reference to seglen bytes. We
- * can use PBUF_RAW here since the data appears in the middle of
- * a segment. A header will never be prepended. */
- if (apiflags & TCP_WRITE_FLAG_COPY) {
- /* Data is copied */
- if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
- ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n",
- seglen));
- goto memerr;
- }
-#if TCP_OVERSIZE_DBGCHECK
- last_unsent->oversize_left = oversize;
-#endif /* TCP_OVERSIZE_DBGCHECK */
- TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped);
-#if TCP_CHECKSUM_ON_COPY
- concat_chksummed += seglen;
-#endif /* TCP_CHECKSUM_ON_COPY */
- } else {
- /* Data is not copied */
- if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
- ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
- goto memerr;
- }
-#if TCP_CHECKSUM_ON_COPY
- /* calculate the checksum of nocopy-data */
- tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen,
- &concat_chksum, &concat_chksum_swapped);
- concat_chksummed += seglen;
-#endif /* TCP_CHECKSUM_ON_COPY */
- /* reference the non-volatile payload data */
- concat_p->payload = (u8_t*)arg + pos;
- }
-
- pos += seglen;
- queuelen += pbuf_clen(concat_p);
- }
- } else {
-#if TCP_OVERSIZE
- LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)",
- pcb->unsent_oversize == 0);
-#endif /* TCP_OVERSIZE */
- }
-
- /*
- * Phase 3: Create new segments.
- *
- * The new segments are chained together in the local 'queue'
- * variable, ready to be appended to pcb->unsent.
- */
- while (pos < len) {
- struct pbuf *p;
- u16_t left = len - pos;
- u16_t max_len = pcb->mss - optlen;
- u16_t seglen = left > max_len ? max_len : left;
-#if TCP_CHECKSUM_ON_COPY
- u16_t chksum = 0;
- u8_t chksum_swapped = 0;
-#endif /* TCP_CHECKSUM_ON_COPY */
-
- if (apiflags & TCP_WRITE_FLAG_COPY) {
- /* If copy is set, memory should be allocated and data copied
- * into pbuf */
- if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
- goto memerr;
- }
- LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen",
- (p->len >= seglen));
- TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped);
- } else {
- /* Copy is not set: First allocate a pbuf for holding the data.
- * Since the referenced data is available at least until it is
- * sent out on the link (as it has to be ACKed by the remote
- * party) we can safely use PBUF_ROM instead of PBUF_REF here.
- */
- struct pbuf *p2;
-#if TCP_OVERSIZE
- LWIP_ASSERT("oversize == 0", oversize == 0);
-#endif /* TCP_OVERSIZE */
- if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
- goto memerr;
- }
-#if TCP_CHECKSUM_ON_COPY
- /* calculate the checksum of nocopy-data */
- chksum = ~inet_chksum((u8_t*)arg + pos, seglen);
-#endif /* TCP_CHECKSUM_ON_COPY */
- /* reference the non-volatile payload data */
- p2->payload = (u8_t*)arg + pos;
-
- /* Second, allocate a pbuf for the headers. */
- if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
- /* If allocation fails, we have to deallocate the data pbuf as
- * well. */
- pbuf_free(p2);
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n"));
- goto memerr;
- }
- /* Concatenate the headers and data pbufs together. */
- pbuf_cat(p/*header*/, p2/*data*/);
- }
-
- queuelen += pbuf_clen(p);
-
- /* Now that there are more segments queued, we check again if the
- * length of the queue exceeds the configured maximum or
- * overflows. */
- if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
- pbuf_free(p);
- goto memerr;
- }
-
- if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) {
- goto memerr;
- }
-#if TCP_OVERSIZE_DBGCHECK
- seg->oversize_left = oversize;
-#endif /* TCP_OVERSIZE_DBGCHECK */
-#if TCP_CHECKSUM_ON_COPY
- seg->chksum = chksum;
- seg->chksum_swapped = chksum_swapped;
- seg->flags |= TF_SEG_DATA_CHECKSUMMED;
-#endif /* TCP_CHECKSUM_ON_COPY */
-
- /* first segment of to-be-queued data? */
- if (queue == NULL) {
- queue = seg;
- } else {
- /* Attach the segment to the end of the queued segments */
- LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL);
- prev_seg->next = seg;
- }
- /* remember last segment of to-be-queued data for next iteration */
- prev_seg = seg;
-
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n",
- ntohl(seg->tcphdr->seqno),
- ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));
-
- pos += seglen;
- }
-
- /*
- * All three segmentation phases were successful. We can commit the
- * transaction.
- */
-
- /*
- * Phase 1: If data has been added to the preallocated tail of
- * last_unsent, we update the length fields of the pbuf chain.
- */
-#if TCP_OVERSIZE
- if (oversize_used > 0) {
- struct pbuf *p;
- /* Bump tot_len of whole chain, len of tail */
- for (p = last_unsent->p; p; p = p->next) {
- p->tot_len += oversize_used;
- if (p->next == NULL) {
- TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent);
- p->len += oversize_used;
- }
- }
- last_unsent->len += oversize_used;
-#if TCP_OVERSIZE_DBGCHECK
- last_unsent->oversize_left -= oversize_used;
-#endif /* TCP_OVERSIZE_DBGCHECK */
- }
- pcb->unsent_oversize = oversize;
-#endif /* TCP_OVERSIZE */
-
- /*
- * Phase 2: concat_p can be concatenated onto last_unsent->p
- */
- if (concat_p != NULL) {
- LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty",
- (last_unsent != NULL));
- pbuf_cat(last_unsent->p, concat_p);
- last_unsent->len += concat_p->tot_len;
-#if TCP_CHECKSUM_ON_COPY
- if (concat_chksummed) {
- tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
- &last_unsent->chksum_swapped);
- last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
- }
-#endif /* TCP_CHECKSUM_ON_COPY */
- }
-
- /*
- * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that
- * is harmless
- */
- if (last_unsent == NULL) {
- pcb->unsent = queue;
- } else {
- last_unsent->next = queue;
- }
-
- /*
- * Finally update the pcb state.
- */
- pcb->snd_lbb += len;
- pcb->snd_buf -= len;
- pcb->snd_queuelen = queuelen;
-
- LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n",
- pcb->snd_queuelen));
- if (pcb->snd_queuelen != 0) {
- LWIP_ASSERT("tcp_write: valid queue length",
- pcb->unacked != NULL || pcb->unsent != NULL);
- }
-
- /* Set the PSH flag in the last segment that we enqueued. */
- if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) {
- TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
- }
-
- return ERR_OK;
-memerr:
- pcb->flags |= TF_NAGLEMEMERR;
- TCP_STATS_INC(tcp.memerr);
-
- if (concat_p != NULL) {
- pbuf_free(concat_p);
- }
- if (queue != NULL) {
- tcp_segs_free(queue);
- }
- if (pcb->snd_queuelen != 0) {
- LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL ||
- pcb->unsent != NULL);
- }
- LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen));
- return ERR_MEM;
-}
-
-/**
- * Enqueue TCP options for transmission.
- *
- * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl().
- *
- * @param pcb Protocol control block for the TCP connection.
- * @param flags TCP header flags to set in the outgoing segment.
- * @param optdata pointer to TCP options, or NULL.
- * @param optlen length of TCP options in bytes.
- */
-err_t
-tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
-{
- struct pbuf *p;
- struct tcp_seg *seg;
- u8_t optflags = 0;
- u8_t optlen = 0;
-
- LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
-
- LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)",
- (flags & (TCP_SYN | TCP_FIN)) != 0);
-
- /* check for configured max queuelen and possible overflow */
- if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n",
- pcb->snd_queuelen, TCP_SND_QUEUELEN));
- TCP_STATS_INC(tcp.memerr);
- pcb->flags |= TF_NAGLEMEMERR;
- return ERR_MEM;
- }
-
- if (flags & TCP_SYN) {
- optflags = TF_SEG_OPTS_MSS;
- }
-#if LWIP_TCP_TIMESTAMPS
- if ((pcb->flags & TF_TIMESTAMP)) {
- optflags |= TF_SEG_OPTS_TS;
- }
-#endif /* LWIP_TCP_TIMESTAMPS */
- optlen = LWIP_TCP_OPT_LENGTH(optflags);
-
- /* tcp_enqueue_flags is always called with either SYN or FIN in flags.
- * We need one available snd_buf byte to do that.
- * This means we can't send FIN while snd_buf==0. A better fix would be to
- * not include SYN and FIN sequence numbers in the snd_buf count. */
- if (pcb->snd_buf == 0) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n"));
- TCP_STATS_INC(tcp.memerr);
- return ERR_MEM;
- }
-
- /* Allocate pbuf with room for TCP header + options */
- if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
- pcb->flags |= TF_NAGLEMEMERR;
- TCP_STATS_INC(tcp.memerr);
- return ERR_MEM;
- }
- LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen",
- (p->len >= optlen));
-
- /* Allocate memory for tcp_seg, and fill in fields. */
- if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) {
- pcb->flags |= TF_NAGLEMEMERR;
- TCP_STATS_INC(tcp.memerr);
- return ERR_MEM;
- }
- LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
- LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0);
-
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,
- ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
- ntohl(seg->tcphdr->seqno),
- ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
- (u16_t)flags));
-
- /* Now append seg to pcb->unsent queue */
- if (pcb->unsent == NULL) {
- pcb->unsent = seg;
- } else {
- struct tcp_seg *useg;
- for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
- useg->next = seg;
- }
-#if TCP_OVERSIZE
- /* The new unsent tail has no space */
- pcb->unsent_oversize = 0;
-#endif /* TCP_OVERSIZE */
-
- /* SYN and FIN bump the sequence number */
- if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
- pcb->snd_lbb++;
- /* optlen does not influence snd_buf */
- pcb->snd_buf--;
- }
- if (flags & TCP_FIN) {
- pcb->flags |= TF_FIN;
- }
-
- /* update number of segments on the queues */
- pcb->snd_queuelen += pbuf_clen(seg->p);
- LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));
- if (pcb->snd_queuelen != 0) {
- LWIP_ASSERT("tcp_enqueue_flags: invalid queue length",
- pcb->unacked != NULL || pcb->unsent != NULL);
- }
-
- return ERR_OK;
-}
-
-
-#if LWIP_TCP_TIMESTAMPS
-/* Build a timestamp option (12 bytes long) at the specified options pointer)
- *
- * @param pcb tcp_pcb
- * @param opts option pointer where to store the timestamp option
- */
-static void
-tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
-{
- /* Pad with two NOP options to make everything nicely aligned */
- opts[0] = PP_HTONL(0x0101080A);
- opts[1] = htonl(sys_now());
- opts[2] = htonl(pcb->ts_recent);
-}
-#endif
-
-/** Send an ACK without data.
- *
- * @param pcb Protocol control block for the TCP connection to send the ACK
- */
-err_t
-tcp_send_empty_ack(struct tcp_pcb *pcb)
-{
- struct pbuf *p;
- struct tcp_hdr *tcphdr;
- u8_t optlen = 0;
-
-#if LWIP_TCP_TIMESTAMPS
- if (pcb->flags & TF_TIMESTAMP) {
- optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
- }
-#endif
-
- p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));
- if (p == NULL) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
- return ERR_BUF;
- }
- tcphdr = (struct tcp_hdr *)p->payload;
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG,
- ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
- /* remove ACK flags from the PCB, as we send an empty ACK now */
- pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
-
- /* NB. MSS option is only sent on SYNs, so ignore it here */
-#if LWIP_TCP_TIMESTAMPS
- pcb->ts_lastacksent = pcb->rcv_nxt;
-
- if (pcb->flags & TF_TIMESTAMP) {
- tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
- }
-#endif
-
-#if CHECKSUM_GEN_TCP
- tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
- IP_PROTO_TCP, p->tot_len);
-#endif
-#if LWIP_NETIF_HWADDRHINT
- ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
- IP_PROTO_TCP, &(pcb->addr_hint));
-#else /* LWIP_NETIF_HWADDRHINT*/
- ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
- IP_PROTO_TCP);
-#endif /* LWIP_NETIF_HWADDRHINT*/
- pbuf_free(p);
-
- return ERR_OK;
-}
-
-/**
- * Find out what we can send and send it
- *
- * @param pcb Protocol control block for the TCP connection to send data
- * @return ERR_OK if data has been sent or nothing to send
- * another err_t on error
- */
-err_t
-tcp_output(struct tcp_pcb *pcb)
-{
- struct tcp_seg *seg, *useg;
- u32_t wnd, snd_nxt;
-#if TCP_CWND_DEBUG
- s16_t i = 0;
-#endif /* TCP_CWND_DEBUG */
-
- /* First, check if we are invoked by the TCP input processing
- code. If so, we do not output anything. Instead, we rely on the
- input processing code to call us when input processing is done
- with. */
- if (tcp_input_pcb == pcb) {
- return ERR_OK;
- }
-
- wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
-
- seg = pcb->unsent;
-
- /* If the TF_ACK_NOW flag is set and no data will be sent (either
- * because the ->unsent queue is empty or because the window does
- * not allow it), construct an empty ACK segment and send it.
- *
- * If data is to be sent, we will just piggyback the ACK (see below).
- */
- if (pcb->flags & TF_ACK_NOW &&
- (seg == NULL ||
- ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
- return tcp_send_empty_ack(pcb);
- }
-
- /* useg should point to last segment on unacked queue */
- useg = pcb->unacked;
- if (useg != NULL) {
- for (; useg->next != NULL; useg = useg->next);
- }
-
-#if TCP_OUTPUT_DEBUG
- if (seg == NULL) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
- (void*)pcb->unsent));
- }
-#endif /* TCP_OUTPUT_DEBUG */
-#if TCP_CWND_DEBUG
- if (seg == NULL) {
- LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F
- ", cwnd %"U16_F", wnd %"U32_F
- ", seg == NULL, ack %"U32_F"\n",
- pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));
- } else {
- LWIP_DEBUGF(TCP_CWND_DEBUG,
- ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F
- ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
- pcb->snd_wnd, pcb->cwnd, wnd,
- ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
- ntohl(seg->tcphdr->seqno), pcb->lastack));
- }
-#endif /* TCP_CWND_DEBUG */
- /* data available and window allows it to be sent? */
- while (seg != NULL &&
- ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
- LWIP_ASSERT("RST not expected here!",
- (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
- /* Stop sending if the nagle algorithm would prevent it
- * Don't stop:
- * - if tcp_write had a memory error before (prevent delayed ACK timeout) or
- * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -
- * either seg->next != NULL or pcb->unacked == NULL;
- * RST is no sent using tcp_write/tcp_output.
- */
- if((tcp_do_output_nagle(pcb) == 0) &&
- ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){
- break;
- }
-#if TCP_CWND_DEBUG
- LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
- pcb->snd_wnd, pcb->cwnd, wnd,
- ntohl(seg->tcphdr->seqno) + seg->len -
- pcb->lastack,
- ntohl(seg->tcphdr->seqno), pcb->lastack, i));
- ++i;
-#endif /* TCP_CWND_DEBUG */
-
- pcb->unsent = seg->next;
-
- if (pcb->state != SYN_SENT) {
- TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
- pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
- }
-
- tcp_output_segment(seg, pcb);
- snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
- if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
- pcb->snd_nxt = snd_nxt;
- }
- /* put segment on unacknowledged list if length > 0 */
- if (TCP_TCPLEN(seg) > 0) {
- seg->next = NULL;
- /* unacked list is empty? */
- if (pcb->unacked == NULL) {
- pcb->unacked = seg;
- useg = seg;
- /* unacked list is not empty? */
- } else {
- /* In the case of fast retransmit, the packet should not go to the tail
- * of the unacked queue, but rather somewhere before it. We need to check for
- * this case. -STJ Jul 27, 2004 */
- if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) {
- /* add segment to before tail of unacked list, keeping the list sorted */
- struct tcp_seg **cur_seg = &(pcb->unacked);
- while (*cur_seg &&
- TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
- cur_seg = &((*cur_seg)->next );
- }
- seg->next = (*cur_seg);
- (*cur_seg) = seg;
- } else {
- /* add segment to tail of unacked list */
- useg->next = seg;
- useg = useg->next;
- }
- }
- /* do not queue empty segments on the unacked list */
- } else {
- tcp_seg_free(seg);
- }
- seg = pcb->unsent;
- }
-#if TCP_OVERSIZE
- if (pcb->unsent == NULL) {
- /* last unsent has been removed, reset unsent_oversize */
- pcb->unsent_oversize = 0;
- }
-#endif /* TCP_OVERSIZE */
-
- if (seg != NULL && pcb->persist_backoff == 0 &&
- ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {
- /* prepare for persist timer */
- pcb->persist_cnt = 0;
- pcb->persist_backoff = 1;
- }
-
- pcb->flags &= ~TF_NAGLEMEMERR;
- return ERR_OK;
-}
-
-/**
- * Called by tcp_output() to actually send a TCP segment over IP.
- *
- * @param seg the tcp_seg to send
- * @param pcb the tcp_pcb for the TCP connection used to send the segment
- */
-static void
-tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
-{
- u16_t len;
- struct netif *netif;
- u32_t *opts;
-
- /** @bug Exclude retransmitted segments from this count. */
- snmp_inc_tcpoutsegs();
-
- /* The TCP header has already been constructed, but the ackno and
- wnd fields remain. */
- seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
-
- /* advertise our receive window size in this TCP segment */
- seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
-
- pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
-
- /* Add any requested options. NB MSS option is only set on SYN
- packets, so ignore it here */
- LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
- opts = (u32_t *)(void *)(seg->tcphdr + 1);
- if (seg->flags & TF_SEG_OPTS_MSS) {
- TCP_BUILD_MSS_OPTION(*opts);
- opts += 1;
- }
-#if LWIP_TCP_TIMESTAMPS
- pcb->ts_lastacksent = pcb->rcv_nxt;
-
- if (seg->flags & TF_SEG_OPTS_TS) {
- tcp_build_timestamp_option(pcb, opts);
- opts += 3;
- }
-#endif
-
- /* Set retransmission timer running if it is not currently enabled
- This must be set before checking the route. */
- if (pcb->rtime == -1) {
- pcb->rtime = 0;
- }
-
- /* If we don't have a local IP address, we get one by
- calling ip_route(). */
- if (ip_addr_isany(&(pcb->local_ip))) {
- netif = ip_route(&(pcb->remote_ip));
- if (netif == NULL) {
- return;
- }
- ip_addr_copy(pcb->local_ip, netif->ip_addr);
- }
-
- if (pcb->rttest == 0) {
- pcb->rttest = tcp_ticks;
- pcb->rtseq = ntohl(seg->tcphdr->seqno);
-
- LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));
- }
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",
- htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
- seg->len));
-
- len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
-
- seg->p->len -= len;
- seg->p->tot_len -= len;
-
- seg->p->payload = seg->tcphdr;
-
- seg->tcphdr->chksum = 0;
-#if CHECKSUM_GEN_TCP
-#if TCP_CHECKSUM_ON_COPY
- {
- u32_t acc;
-#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
- u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
- &(pcb->remote_ip),
- IP_PROTO_TCP, seg->p->tot_len);
-#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
- if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
- LWIP_ASSERT("data included but not checksummed",
- seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4));
- }
-
- /* rebuild TCP header checksum (TCP header changes for retransmissions!) */
- acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
- &(pcb->remote_ip),
- IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
- /* add payload checksum */
- if (seg->chksum_swapped) {
- seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
- seg->chksum_swapped = 0;
- }
- acc += (u16_t)~(seg->chksum);
- seg->tcphdr->chksum = FOLD_U32T(acc);
-#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
- if (chksum_slow != seg->tcphdr->chksum) {
- LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,
- ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n",
- seg->tcphdr->chksum, chksum_slow));
- seg->tcphdr->chksum = chksum_slow;
- }
-#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
- }
-#else /* TCP_CHECKSUM_ON_COPY */
- seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
- &(pcb->remote_ip),
- IP_PROTO_TCP, seg->p->tot_len);
-#endif /* TCP_CHECKSUM_ON_COPY */
-#endif /* CHECKSUM_GEN_TCP */
- TCP_STATS_INC(tcp.xmit);
-
-#if LWIP_NETIF_HWADDRHINT
- ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
- IP_PROTO_TCP, &(pcb->addr_hint));
-#else /* LWIP_NETIF_HWADDRHINT*/
- ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
- IP_PROTO_TCP);
-#endif /* LWIP_NETIF_HWADDRHINT*/
-}
-
-/**
- * Send a TCP RESET packet (empty segment with RST flag set) either to
- * abort a connection or to show that there is no matching local connection
- * for a received segment.
- *
- * Called by tcp_abort() (to abort a local connection), tcp_input() (if no
- * matching local pcb was found), tcp_listen_input() (if incoming segment
- * has ACK flag set) and tcp_process() (received segment in the wrong state)
- *
- * Since a RST segment is in most cases not sent for an active connection,
- * tcp_rst() has a number of arguments that are taken from a tcp_pcb for
- * most other segment output functions.
- *
- * @param seqno the sequence number to use for the outgoing segment
- * @param ackno the acknowledge number to use for the outgoing segment
- * @param local_ip the local IP address to send the segment from
- * @param remote_ip the remote IP address to send the segment to
- * @param local_port the local TCP port to send the segment from
- * @param remote_port the remote TCP port to send the segment to
- */
-void
-tcp_rst(u32_t seqno, u32_t ackno,
- ip_addr_t *local_ip, ip_addr_t *remote_ip,
- u16_t local_port, u16_t remote_port)
-{
- struct pbuf *p;
- struct tcp_hdr *tcphdr;
- p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
- if (p == NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
- return;
- }
- LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
- (p->len >= sizeof(struct tcp_hdr)));
-
- tcphdr = (struct tcp_hdr *)p->payload;
- tcphdr->src = htons(local_port);
- tcphdr->dest = htons(remote_port);
- tcphdr->seqno = htonl(seqno);
- tcphdr->ackno = htonl(ackno);
- TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
- tcphdr->wnd = PP_HTONS(TCP_WND);
- tcphdr->chksum = 0;
- tcphdr->urgp = 0;
-
-#if CHECKSUM_GEN_TCP
- tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
- IP_PROTO_TCP, p->tot_len);
-#endif
- TCP_STATS_INC(tcp.xmit);
- snmp_inc_tcpoutrsts();
- /* Send output with hardcoded TTL since we have no access to the pcb */
- ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
- pbuf_free(p);
- LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
-}
-
-/**
- * Requeue all unacked segments for retransmission
- *
- * Called by tcp_slowtmr() for slow retransmission.
- *
- * @param pcb the tcp_pcb for which to re-enqueue all unacked segments
- */
-void
-tcp_rexmit_rto(struct tcp_pcb *pcb)
-{
- struct tcp_seg *seg;
-
- if (pcb->unacked == NULL) {
- return;
- }
-
- /* Move all unacked segments to the head of the unsent queue */
- for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
- /* concatenate unsent queue after unacked queue */
- seg->next = pcb->unsent;
- /* unsent queue is the concatenated queue (of unacked, unsent) */
- pcb->unsent = pcb->unacked;
- /* unacked queue is now empty */
- pcb->unacked = NULL;
-
- /* increment number of retransmissions */
- ++pcb->nrtx;
-
- /* Don't take any RTT measurements after retransmitting. */
- pcb->rttest = 0;
-
- /* Do the actual retransmission */
- tcp_output(pcb);
-}
-
-/**
- * Requeue the first unacked segment for retransmission
- *
- * Called by tcp_receive() for fast retramsmit.
- *
- * @param pcb the tcp_pcb for which to retransmit the first unacked segment
- */
-void
-tcp_rexmit(struct tcp_pcb *pcb)
-{
- struct tcp_seg *seg;
- struct tcp_seg **cur_seg;
-
- if (pcb->unacked == NULL) {
- return;
- }
-
- /* Move the first unacked segment to the unsent queue */
- /* Keep the unsent queue sorted. */
- seg = pcb->unacked;
- pcb->unacked = seg->next;
-
- cur_seg = &(pcb->unsent);
- while (*cur_seg &&
- TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
- cur_seg = &((*cur_seg)->next );
- }
- seg->next = *cur_seg;
- *cur_seg = seg;
-
- ++pcb->nrtx;
-
- /* Don't take any rtt measurements after retransmitting. */
- pcb->rttest = 0;
-
- /* Do the actual retransmission. */
- snmp_inc_tcpretranssegs();
- /* No need to call tcp_output: we are always called from tcp_input()
- and thus tcp_output directly returns. */
-}
-
-
-/**
- * Handle retransmission after three dupacks received
- *
- * @param pcb the tcp_pcb for which to retransmit the first unacked segment
- */
-void
-tcp_rexmit_fast(struct tcp_pcb *pcb)
-{
- if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) {
- /* This is fast retransmit. Retransmit the first unacked segment. */
- LWIP_DEBUGF(TCP_FR_DEBUG,
- ("tcp_receive: dupacks %"U16_F" (%"U32_F
- "), fast retransmit %"U32_F"\n",
- (u16_t)pcb->dupacks, pcb->lastack,
- ntohl(pcb->unacked->tcphdr->seqno)));
- tcp_rexmit(pcb);
-
- /* Set ssthresh to half of the minimum of the current
- * cwnd and the advertised window */
- if (pcb->cwnd > pcb->snd_wnd) {
- pcb->ssthresh = pcb->snd_wnd / 2;
- } else {
- pcb->ssthresh = pcb->cwnd / 2;
- }
-
- /* The minimum value for ssthresh should be 2 MSS */
- if (pcb->ssthresh < 2*pcb->mss) {
- LWIP_DEBUGF(TCP_FR_DEBUG,
- ("tcp_receive: The minimum value for ssthresh %"U16_F
- " should be min 2 mss %"U16_F"...\n",
- pcb->ssthresh, 2*pcb->mss));
- pcb->ssthresh = 2*pcb->mss;
- }
-
- pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
- pcb->flags |= TF_INFR;
- }
-}
-
-
-/**
- * Send keepalive packets to keep a connection active although
- * no data is sent over it.
- *
- * Called by tcp_slowtmr()
- *
- * @param pcb the tcp_pcb for which to send a keepalive packet
- */
-void
-tcp_keepalive(struct tcp_pcb *pcb)
-{
- struct pbuf *p;
- struct tcp_hdr *tcphdr;
-
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
- ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
-
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
- tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
-
- p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1));
- if(p == NULL) {
- LWIP_DEBUGF(TCP_DEBUG,
- ("tcp_keepalive: could not allocate memory for pbuf\n"));
- return;
- }
- tcphdr = (struct tcp_hdr *)p->payload;
-
-#if CHECKSUM_GEN_TCP
- tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
- IP_PROTO_TCP, p->tot_len);
-#endif
- TCP_STATS_INC(tcp.xmit);
-
- /* Send output to IP */
-#if LWIP_NETIF_HWADDRHINT
- ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
- &(pcb->addr_hint));
-#else /* LWIP_NETIF_HWADDRHINT*/
- ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
-#endif /* LWIP_NETIF_HWADDRHINT*/
-
- pbuf_free(p);
-
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n",
- pcb->snd_nxt - 1, pcb->rcv_nxt));
-}
-
-
-/**
- * Send persist timer zero-window probes to keep a connection active
- * when a window update is lost.
- *
- * Called by tcp_slowtmr()
- *
- * @param pcb the tcp_pcb for which to send a zero-window probe packet
- */
-void
-tcp_zero_window_probe(struct tcp_pcb *pcb)
-{
- struct pbuf *p;
- struct tcp_hdr *tcphdr;
- struct tcp_seg *seg;
- u16_t len;
- u8_t is_fin;
-
- LWIP_DEBUGF(TCP_DEBUG,
- ("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
- U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
- ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
-
- LWIP_DEBUGF(TCP_DEBUG,
- ("tcp_zero_window_probe: tcp_ticks %"U32_F
- " pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
- tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
-
- seg = pcb->unacked;
-
- if(seg == NULL) {
- seg = pcb->unsent;
- }
- if(seg == NULL) {
- return;
- }
-
- is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
- /* we want to send one seqno: either FIN or data (no options) */
- len = is_fin ? 0 : 1;
-
- p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno);
- if(p == NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
- return;
- }
- tcphdr = (struct tcp_hdr *)p->payload;
-
- if (is_fin) {
- /* FIN segment, no data */
- TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
- } else {
- /* Data segment, copy in one byte from the head of the unacked queue */
- struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload;
- char *d = ((char *)p->payload + TCP_HLEN);
- pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4);
- }
-
-#if CHECKSUM_GEN_TCP
- tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
- IP_PROTO_TCP, p->tot_len);
-#endif
- TCP_STATS_INC(tcp.xmit);
-
- /* Send output to IP */
-#if LWIP_NETIF_HWADDRHINT
- ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
- &(pcb->addr_hint));
-#else /* LWIP_NETIF_HWADDRHINT*/
- ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
-#endif /* LWIP_NETIF_HWADDRHINT*/
-
- pbuf_free(p);
-
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F
- " ackno %"U32_F".\n",
- pcb->snd_nxt - 1, pcb->rcv_nxt));
-}
-#endif /* LWIP_TCP */
+++ /dev/null
-/**
- * @file
- * User Datagram Protocol 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>
- *
- */
-
-
-/* udp.c
- *
- * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).
- *
- */
-
-/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'!
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/udp.h"
-#include "lwip/def.h"
-#include "lwip/memp.h"
-#include "lwip/inet_chksum.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/icmp.h"
-#include "lwip/stats.h"
-#include "lwip/snmp.h"
-#include "arch/perf.h"
-#include "lwip/dhcp.h"
-
-#include <string.h>
-
-/* The list of UDP PCBs */
-/* exported in udp.h (was static) */
-struct udp_pcb *udp_pcbs;
-
-/**
- * Process an incoming UDP datagram.
- *
- * Given an incoming UDP datagram (as a chain of pbufs) this function
- * finds a corresponding UDP PCB and hands over the pbuf to the pcbs
- * recv function. If no pcb is found or the datagram is incorrect, the
- * pbuf is freed.
- *
- * @param p pbuf to be demultiplexed to a UDP PCB.
- * @param inp network interface on which the datagram was received.
- *
- */
-void
-udp_input(struct pbuf *p, struct netif *inp)
-{
- struct udp_hdr *udphdr;
- struct udp_pcb *pcb, *prev;
- struct udp_pcb *uncon_pcb;
- struct ip_hdr *iphdr;
- u16_t src, dest;
- u8_t local_match;
- u8_t broadcast;
-
- PERF_START;
-
- UDP_STATS_INC(udp.recv);
-
- iphdr = (struct ip_hdr *)p->payload;
-
- /* Check minimum length (IP header + UDP header)
- * and move payload pointer to UDP header */
- if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {
- /* drop short packets */
- LWIP_DEBUGF(UDP_DEBUG,
- ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));
- UDP_STATS_INC(udp.lenerr);
- UDP_STATS_INC(udp.drop);
- snmp_inc_udpinerrors();
- pbuf_free(p);
- goto end;
- }
-
- udphdr = (struct udp_hdr *)p->payload;
-
- /* is broadcast packet ? */
- broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp);
-
- LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
-
- /* convert src and dest ports to host byte order */
- src = ntohs(udphdr->src);
- dest = ntohs(udphdr->dest);
-
- udp_debug_print(udphdr);
-
- /* print the UDP source and destination */
- LWIP_DEBUGF(UDP_DEBUG,
- ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "
- "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
- ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest),
- ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest),
- ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src),
- ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src)));
-
-#if LWIP_DHCP
- pcb = NULL;
- /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by
- the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */
- if (dest == DHCP_CLIENT_PORT) {
- /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */
- if (src == DHCP_SERVER_PORT) {
- if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {
- /* accept the packe if
- (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
- - inp->dhcp->pcb->remote == ANY or iphdr->src */
- if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
- ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), ¤t_iphdr_src))) {
- pcb = inp->dhcp->pcb;
- }
- }
- }
- } else
-#endif /* LWIP_DHCP */
- {
- prev = NULL;
- local_match = 0;
- uncon_pcb = NULL;
- /* Iterate through the UDP pcb list for a matching pcb.
- * 'Perfect match' pcbs (connected to the remote port & ip address) are
- * preferred. If no perfect match is found, the first unconnected pcb that
- * matches the local port and ip address gets the datagram. */
- for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
- local_match = 0;
- /* print the PCB local and remote address */
- LWIP_DEBUGF(UDP_DEBUG,
- ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "
- "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
- ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
- ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port,
- ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
- ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port));
-
- /* compare PCB local addr+port to UDP destination addr+port */
- if ((pcb->local_port == dest) &&
- ((!broadcast && ip_addr_isany(&pcb->local_ip)) ||
- ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest) ||
-#if LWIP_IGMP
- ip_addr_ismulticast(¤t_iphdr_dest) ||
-#endif /* LWIP_IGMP */
-#if IP_SOF_BROADCAST_RECV
- (broadcast && (pcb->so_options & SOF_BROADCAST)))) {
-#else /* IP_SOF_BROADCAST_RECV */
- (broadcast))) {
-#endif /* IP_SOF_BROADCAST_RECV */
- local_match = 1;
- if ((uncon_pcb == NULL) &&
- ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
- /* the first unconnected matching PCB */
- uncon_pcb = pcb;
- }
- }
- /* compare PCB remote addr+port to UDP source addr+port */
- if ((local_match != 0) &&
- (pcb->remote_port == src) &&
- (ip_addr_isany(&pcb->remote_ip) ||
- ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src))) {
- /* the first fully matching PCB */
- if (prev != NULL) {
- /* move the pcb to the front of udp_pcbs so that is
- found faster next time */
- prev->next = pcb->next;
- pcb->next = udp_pcbs;
- udp_pcbs = pcb;
- } else {
- UDP_STATS_INC(udp.cachehit);
- }
- break;
- }
- prev = pcb;
- }
- /* no fully matching pcb found? then look for an unconnected pcb */
- if (pcb == NULL) {
- pcb = uncon_pcb;
- }
- }
-
- /* Check checksum if this is a match or if it was directed at us. */
- if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, ¤t_iphdr_dest)) {
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
-#if LWIP_UDPLITE
- if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
- /* Do the UDP Lite checksum */
-#if CHECKSUM_CHECK_UDP
- u16_t chklen = ntohs(udphdr->len);
- if (chklen < sizeof(struct udp_hdr)) {
- if (chklen == 0) {
- /* For UDP-Lite, checksum length of 0 means checksum
- over the complete packet (See RFC 3828 chap. 3.1) */
- chklen = p->tot_len;
- } else {
- /* At least the UDP-Lite header must be covered by the
- checksum! (Again, see RFC 3828 chap. 3.1) */
- UDP_STATS_INC(udp.chkerr);
- UDP_STATS_INC(udp.drop);
- snmp_inc_udpinerrors();
- pbuf_free(p);
- goto end;
- }
- }
- if (inet_chksum_pseudo_partial(p, ¤t_iphdr_src, ¤t_iphdr_dest,
- IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
- ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
- UDP_STATS_INC(udp.chkerr);
- UDP_STATS_INC(udp.drop);
- snmp_inc_udpinerrors();
- pbuf_free(p);
- goto end;
- }
-#endif /* CHECKSUM_CHECK_UDP */
- } else
-#endif /* LWIP_UDPLITE */
- {
-#if CHECKSUM_CHECK_UDP
- if (udphdr->chksum != 0) {
- if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
- IP_PROTO_UDP, p->tot_len) != 0) {
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
- ("udp_input: UDP datagram discarded due to failing checksum\n"));
- UDP_STATS_INC(udp.chkerr);
- UDP_STATS_INC(udp.drop);
- snmp_inc_udpinerrors();
- pbuf_free(p);
- goto end;
- }
- }
-#endif /* CHECKSUM_CHECK_UDP */
- }
- if(pbuf_header(p, -UDP_HLEN)) {
- /* Can we cope with this failing? Just assert for now */
- LWIP_ASSERT("pbuf_header failed\n", 0);
- UDP_STATS_INC(udp.drop);
- snmp_inc_udpinerrors();
- pbuf_free(p);
- goto end;
- }
- if (pcb != NULL) {
- snmp_inc_udpindatagrams();
-#if SO_REUSE && SO_REUSE_RXTOALL
- if ((broadcast || ip_addr_ismulticast(¤t_iphdr_dest)) &&
- ((pcb->so_options & SOF_REUSEADDR) != 0)) {
- /* pass broadcast- or multicast packets to all multicast pcbs
- if SOF_REUSEADDR is set on the first match */
- struct udp_pcb *mpcb;
- u8_t p_header_changed = 0;
- for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) {
- if (mpcb != pcb) {
- /* compare PCB local addr+port to UDP destination addr+port */
- if ((mpcb->local_port == dest) &&
- ((!broadcast && ip_addr_isany(&mpcb->local_ip)) ||
- ip_addr_cmp(&(mpcb->local_ip), ¤t_iphdr_dest) ||
-#if LWIP_IGMP
- ip_addr_ismulticast(¤t_iphdr_dest) ||
-#endif /* LWIP_IGMP */
-#if IP_SOF_BROADCAST_RECV
- (broadcast && (mpcb->so_options & SOF_BROADCAST)))) {
-#else /* IP_SOF_BROADCAST_RECV */
- (broadcast))) {
-#endif /* IP_SOF_BROADCAST_RECV */
- /* pass a copy of the packet to all local matches */
- if (mpcb->recv != NULL) {
- struct pbuf *q;
- /* for that, move payload to IP header again */
- if (p_header_changed == 0) {
- pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
- p_header_changed = 1;
- }
- q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
- if (q != NULL) {
- err_t err = pbuf_copy(q, p);
- if (err == ERR_OK) {
- /* move payload to UDP data */
- pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
- mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);
- }
- }
- }
- }
- }
- }
- if (p_header_changed) {
- /* and move payload to UDP data again */
- pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
- }
- }
-#endif /* SO_REUSE && SO_REUSE_RXTOALL */
- /* callback */
- if (pcb->recv != NULL) {
- /* now the recv function is responsible for freeing p */
- pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
- } else {
- /* no recv function registered? then we have to free the pbuf! */
- pbuf_free(p);
- goto end;
- }
- } else {
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));
-
-#if LWIP_ICMP
- /* No match was found, send ICMP destination port unreachable unless
- destination address was broadcast/multicast. */
- if (!broadcast &&
- !ip_addr_ismulticast(¤t_iphdr_dest)) {
- /* move payload pointer back to ip header */
- pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);
- LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr));
- icmp_dest_unreach(p, ICMP_DUR_PORT);
- }
-#endif /* LWIP_ICMP */
- UDP_STATS_INC(udp.proterr);
- UDP_STATS_INC(udp.drop);
- snmp_inc_udpnoports();
- pbuf_free(p);
- }
- } else {
- pbuf_free(p);
- }
-end:
- PERF_STOP("udp_input");
-}
-
-/**
- * Send data using UDP.
- *
- * @param pcb UDP PCB used to send the data.
- * @param p chain of pbuf's to be sent.
- *
- * The datagram will be sent to the current remote_ip & remote_port
- * stored in pcb. If the pcb is not bound to a port, it will
- * automatically be bound to a random port.
- *
- * @return lwIP error code.
- * - ERR_OK. Successful. No error occured.
- * - ERR_MEM. Out of memory.
- * - ERR_RTE. Could not find route to destination address.
- * - More errors could be returned by lower protocol layers.
- *
- * @see udp_disconnect() udp_sendto()
- */
-err_t
-udp_send(struct udp_pcb *pcb, struct pbuf *p)
-{
- /* send to the packet using remote ip and port stored in the pcb */
- return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
-}
-
-#if LWIP_CHECKSUM_ON_COPY
-/** Same as udp_send() but with checksum
- */
-err_t
-udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
- u8_t have_chksum, u16_t chksum)
-{
- /* send to the packet using remote ip and port stored in the pcb */
- return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port,
- have_chksum, chksum);
-}
-#endif /* LWIP_CHECKSUM_ON_COPY */
-
-/**
- * Send data to a specified address using UDP.
- *
- * @param pcb UDP PCB used to send the data.
- * @param p chain of pbuf's to be sent.
- * @param dst_ip Destination IP address.
- * @param dst_port Destination UDP port.
- *
- * dst_ip & dst_port are expected to be in the same byte order as in the pcb.
- *
- * If the PCB already has a remote address association, it will
- * be restored after the data is sent.
- *
- * @return lwIP error code (@see udp_send for possible error codes)
- *
- * @see udp_disconnect() udp_send()
- */
-err_t
-udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
- ip_addr_t *dst_ip, u16_t dst_port)
-{
-#if LWIP_CHECKSUM_ON_COPY
- return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0);
-}
-
-/** Same as udp_sendto(), but with checksum */
-err_t
-udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
- u16_t dst_port, u8_t have_chksum, u16_t chksum)
-{
-#endif /* LWIP_CHECKSUM_ON_COPY */
- struct netif *netif;
-
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
-
- /* find the outgoing network interface for this packet */
-#if LWIP_IGMP
- netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
-#else
- netif = ip_route(dst_ip);
-#endif /* LWIP_IGMP */
-
- /* no outgoing network interface could be found? */
- if (netif == NULL) {
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip)));
- UDP_STATS_INC(udp.rterr);
- return ERR_RTE;
- }
-#if LWIP_CHECKSUM_ON_COPY
- return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum);
-#else /* LWIP_CHECKSUM_ON_COPY */
- return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);
-#endif /* LWIP_CHECKSUM_ON_COPY */
-}
-
-/**
- * Send data to a specified address using UDP.
- * The netif used for sending can be specified.
- *
- * This function exists mainly for DHCP, to be able to send UDP packets
- * on a netif that is still down.
- *
- * @param pcb UDP PCB used to send the data.
- * @param p chain of pbuf's to be sent.
- * @param dst_ip Destination IP address.
- * @param dst_port Destination UDP port.
- * @param netif the netif used for sending.
- *
- * dst_ip & dst_port are expected to be in the same byte order as in the pcb.
- *
- * @return lwIP error code (@see udp_send for possible error codes)
- *
- * @see udp_disconnect() udp_send()
- */
-err_t
-udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
- ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif)
-{
-#if LWIP_CHECKSUM_ON_COPY
- return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0);
-}
-
-/** Same as udp_sendto_if(), but with checksum */
-err_t
-udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
- u16_t dst_port, struct netif *netif, u8_t have_chksum,
- u16_t chksum)
-{
-#endif /* LWIP_CHECKSUM_ON_COPY */
- struct udp_hdr *udphdr;
- ip_addr_t *src_ip;
- err_t err;
- struct pbuf *q; /* q will be sent down the stack */
-
-#if IP_SOF_BROADCAST
- /* broadcast filter? */
- if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) {
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
- ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
- return ERR_VAL;
- }
-#endif /* IP_SOF_BROADCAST */
-
- /* if the PCB is not yet bound to a port, bind it here */
- if (pcb->local_port == 0) {
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n"));
- err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
- if (err != ERR_OK) {
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n"));
- return err;
- }
- }
-
- /* not enough space to add an UDP header to first pbuf in given p chain? */
- if (pbuf_header(p, UDP_HLEN)) {
- /* allocate header in a separate new pbuf */
- q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
- /* new header pbuf could not be allocated? */
- if (q == NULL) {
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n"));
- return ERR_MEM;
- }
- if (p->tot_len != 0) {
- /* chain header q in front of given pbuf p (only if p contains data) */
- pbuf_chain(q, p);
- }
- /* first pbuf q points to header pbuf */
- LWIP_DEBUGF(UDP_DEBUG,
- ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
- } else {
- /* adding space for header within p succeeded */
- /* first pbuf q equals given pbuf */
- q = p;
- LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));
- }
- LWIP_ASSERT("check that first pbuf can hold struct udp_hdr",
- (q->len >= sizeof(struct udp_hdr)));
- /* q now represents the packet to be sent */
- udphdr = (struct udp_hdr *)q->payload;
- udphdr->src = htons(pcb->local_port);
- udphdr->dest = htons(dst_port);
- /* in UDP, 0 checksum means 'no checksum' */
- udphdr->chksum = 0x0000;
-
- /* Multicast Loop? */
-#if LWIP_IGMP
- if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) {
- q->flags |= PBUF_FLAG_MCASTLOOP;
- }
-#endif /* LWIP_IGMP */
-
-
- /* PCB local address is IP_ANY_ADDR? */
- if (ip_addr_isany(&pcb->local_ip)) {
- /* use outgoing network interface IP address as source address */
- src_ip = &(netif->ip_addr);
- } else {
- /* check if UDP PCB local IP address is correct
- * this could be an old address if netif->ip_addr has changed */
- if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
- /* local_ip doesn't match, drop the packet */
- if (q != p) {
- /* free the header pbuf */
- pbuf_free(q);
- q = NULL;
- /* p is still referenced by the caller, and will live on */
- }
- return ERR_VAL;
- }
- /* use UDP PCB local IP address as source address */
- src_ip = &(pcb->local_ip);
- }
-
- LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));
-
-#if LWIP_UDPLITE
- /* UDP Lite protocol? */
- if (pcb->flags & UDP_FLAGS_UDPLITE) {
- u16_t chklen, chklen_hdr;
- LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len));
- /* set UDP message length in UDP header */
- chklen_hdr = chklen = pcb->chksum_len_tx;
- if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) {
- if (chklen != 0) {
- LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen));
- }
- /* For UDP-Lite, checksum length of 0 means checksum
- over the complete packet. (See RFC 3828 chap. 3.1)
- At least the UDP-Lite header must be covered by the
- checksum, therefore, if chksum_len has an illegal
- value, we generate the checksum over the complete
- packet to be safe. */
- chklen_hdr = 0;
- chklen = q->tot_len;
- }
- udphdr->len = htons(chklen_hdr);
- /* calculate checksum */
-#if CHECKSUM_GEN_UDP
- udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,
- IP_PROTO_UDPLITE, q->tot_len,
-#if !LWIP_CHECKSUM_ON_COPY
- chklen);
-#else /* !LWIP_CHECKSUM_ON_COPY */
- (have_chksum ? UDP_HLEN : chklen));
- if (have_chksum) {
- u32_t acc;
- acc = udphdr->chksum + (u16_t)~(chksum);
- udphdr->chksum = FOLD_U32T(acc);
- }
-#endif /* !LWIP_CHECKSUM_ON_COPY */
-
- /* chksum zero must become 0xffff, as zero means 'no checksum' */
- if (udphdr->chksum == 0x0000) {
- udphdr->chksum = 0xffff;
- }
-#endif /* CHECKSUM_GEN_UDP */
- /* output to IP */
- LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
-#if LWIP_NETIF_HWADDRHINT
- netif->addr_hint = &(pcb->addr_hint);
-#endif /* LWIP_NETIF_HWADDRHINT*/
- err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
-#if LWIP_NETIF_HWADDRHINT
- netif->addr_hint = NULL;
-#endif /* LWIP_NETIF_HWADDRHINT*/
- } else
-#endif /* LWIP_UDPLITE */
- { /* UDP */
- LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));
- udphdr->len = htons(q->tot_len);
- /* calculate checksum */
-#if CHECKSUM_GEN_UDP
- if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
- u16_t udpchksum;
-#if LWIP_CHECKSUM_ON_COPY
- if (have_chksum) {
- u32_t acc;
- udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP,
- q->tot_len, UDP_HLEN);
- acc = udpchksum + (u16_t)~(chksum);
- udpchksum = FOLD_U32T(acc);
- } else
-#endif /* LWIP_CHECKSUM_ON_COPY */
- {
- udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
- }
-
- /* chksum zero must become 0xffff, as zero means 'no checksum' */
- if (udpchksum == 0x0000) {
- udpchksum = 0xffff;
- }
- udphdr->chksum = udpchksum;
- }
-#endif /* CHECKSUM_GEN_UDP */
- LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
- LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
- /* output to IP */
-#if LWIP_NETIF_HWADDRHINT
- netif->addr_hint = &(pcb->addr_hint);
-#endif /* LWIP_NETIF_HWADDRHINT*/
- err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
-#if LWIP_NETIF_HWADDRHINT
- netif->addr_hint = NULL;
-#endif /* LWIP_NETIF_HWADDRHINT*/
- }
- /* TODO: must this be increased even if error occured? */
- snmp_inc_udpoutdatagrams();
-
- /* did we chain a separate header pbuf earlier? */
- if (q != p) {
- /* free the header pbuf */
- pbuf_free(q);
- q = NULL;
- /* p is still referenced by the caller, and will live on */
- }
-
- UDP_STATS_INC(udp.xmit);
- return err;
-}
-
-/**
- * Bind an UDP PCB.
- *
- * @param pcb UDP PCB to be bound with a local address ipaddr and port.
- * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
- * bind to all local interfaces.
- * @param port local UDP port to bind with. Use 0 to automatically bind
- * to a random port between UDP_LOCAL_PORT_RANGE_START and
- * UDP_LOCAL_PORT_RANGE_END.
- *
- * ipaddr & port are expected to be in the same byte order as in the pcb.
- *
- * @return lwIP error code.
- * - ERR_OK. Successful. No error occured.
- * - ERR_USE. The specified ipaddr and port are already bound to by
- * another UDP PCB.
- *
- * @see udp_disconnect()
- */
-err_t
-udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
-{
- struct udp_pcb *ipcb;
- u8_t rebind;
-
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));
- ip_addr_debug_print(UDP_DEBUG, ipaddr);
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));
-
- rebind = 0;
- /* Check for double bind and rebind of the same pcb */
- for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
- /* is this UDP PCB already on active list? */
- if (pcb == ipcb) {
- /* pcb may occur at most once in active list */
- LWIP_ASSERT("rebind == 0", rebind == 0);
- /* pcb already in list, just rebind */
- rebind = 1;
- }
-
- /* By default, we don't allow to bind to a port that any other udp
- PCB is alread bound to, unless *all* PCBs with that port have tha
- REUSEADDR flag set. */
-#if SO_REUSE
- else if (((pcb->so_options & SOF_REUSEADDR) == 0) &&
- ((ipcb->so_options & SOF_REUSEADDR) == 0)) {
-#else /* SO_REUSE */
- /* port matches that of PCB in list and REUSEADDR not set -> reject */
- else {
-#endif /* SO_REUSE */
- if ((ipcb->local_port == port) &&
- /* IP address matches, or one is IP_ADDR_ANY? */
- (ip_addr_isany(&(ipcb->local_ip)) ||
- ip_addr_isany(ipaddr) ||
- ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
- /* other PCB already binds to this local IP and port */
- LWIP_DEBUGF(UDP_DEBUG,
- ("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
- return ERR_USE;
- }
- }
- }
-
- ip_addr_set(&pcb->local_ip, ipaddr);
-
- /* no port specified? */
- if (port == 0) {
-#ifndef UDP_LOCAL_PORT_RANGE_START
-/* From http://www.iana.org/assignments/port-numbers:
- "The Dynamic and/or Private Ports are those from 49152 through 65535" */
-#define UDP_LOCAL_PORT_RANGE_START 0xc000
-#define UDP_LOCAL_PORT_RANGE_END 0xffff
-#endif
- port = UDP_LOCAL_PORT_RANGE_START;
- ipcb = udp_pcbs;
- while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {
- if (ipcb->local_port == port) {
- /* port is already used by another udp_pcb */
- port++;
- /* restart scanning all udp pcbs */
- ipcb = udp_pcbs;
- } else {
- /* go on with next udp pcb */
- ipcb = ipcb->next;
- }
- }
- if (ipcb != NULL) {
- /* no more ports available in local range */
- LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
- return ERR_USE;
- }
- }
- pcb->local_port = port;
- snmp_insert_udpidx_tree(pcb);
- /* pcb not active yet? */
- if (rebind == 0) {
- /* place the PCB on the active list if not already there */
- pcb->next = udp_pcbs;
- udp_pcbs = pcb;
- }
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
- ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
- ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
- pcb->local_port));
- return ERR_OK;
-}
-/**
- * Connect an UDP PCB.
- *
- * This will associate the UDP PCB with the remote address.
- *
- * @param pcb UDP PCB to be connected with remote address ipaddr and port.
- * @param ipaddr remote IP address to connect with.
- * @param port remote UDP port to connect with.
- *
- * @return lwIP error code
- *
- * ipaddr & port are expected to be in the same byte order as in the pcb.
- *
- * The udp pcb is bound to a random local port if not already bound.
- *
- * @see udp_disconnect()
- */
-err_t
-udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
-{
- struct udp_pcb *ipcb;
-
- if (pcb->local_port == 0) {
- err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
- if (err != ERR_OK) {
- return err;
- }
- }
-
- ip_addr_set(&pcb->remote_ip, ipaddr);
- pcb->remote_port = port;
- pcb->flags |= UDP_FLAGS_CONNECTED;
-/** TODO: this functionality belongs in upper layers */
-#ifdef LWIP_UDP_TODO
- /* Nail down local IP for netconn_addr()/getsockname() */
- if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
- struct netif *netif;
-
- if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
- LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
- UDP_STATS_INC(udp.rterr);
- return ERR_RTE;
- }
- /** TODO: this will bind the udp pcb locally, to the interface which
- is used to route output packets to the remote address. However, we
- might want to accept incoming packets on any interface! */
- pcb->local_ip = netif->ip_addr;
- } else if (ip_addr_isany(&pcb->remote_ip)) {
- pcb->local_ip.addr = 0;
- }
-#endif
- LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
- ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
- ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
- ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
- pcb->local_port));
-
- /* Insert UDP PCB into the list of active UDP PCBs. */
- for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
- if (pcb == ipcb) {
- /* already on the list, just return */
- return ERR_OK;
- }
- }
- /* PCB not yet on the list, add PCB now */
- pcb->next = udp_pcbs;
- udp_pcbs = pcb;
- return ERR_OK;
-}
-
-/**
- * Disconnect a UDP PCB
- *
- * @param pcb the udp pcb to disconnect.
- */
-void
-udp_disconnect(struct udp_pcb *pcb)
-{
- /* reset remote address association */
- ip_addr_set_any(&pcb->remote_ip);
- pcb->remote_port = 0;
- /* mark PCB as unconnected */
- pcb->flags &= ~UDP_FLAGS_CONNECTED;
-}
-
-/**
- * Set a receive callback for a UDP PCB
- *
- * This callback will be called when receiving a datagram for the pcb.
- *
- * @param pcb the pcb for wich to set the recv callback
- * @param recv function pointer of the callback function
- * @param recv_arg additional argument to pass to the callback function
- */
-void
-udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)
-{
- /* remember recv() callback and user data */
- pcb->recv = recv;
- pcb->recv_arg = recv_arg;
-}
-
-/**
- * Remove an UDP PCB.
- *
- * @param pcb UDP PCB to be removed. The PCB is removed from the list of
- * UDP PCB's and the data structure is freed from memory.
- *
- * @see udp_new()
- */
-void
-udp_remove(struct udp_pcb *pcb)
-{
- struct udp_pcb *pcb2;
-
- snmp_delete_udpidx_tree(pcb);
- /* pcb to be removed is first in list? */
- if (udp_pcbs == pcb) {
- /* make list start at 2nd pcb */
- udp_pcbs = udp_pcbs->next;
- /* pcb not 1st in list */
- } else {
- for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
- /* find pcb in udp_pcbs list */
- if (pcb2->next != NULL && pcb2->next == pcb) {
- /* remove pcb from list */
- pcb2->next = pcb->next;
- }
- }
- }
- memp_free(MEMP_UDP_PCB, pcb);
-}
-
-/**
- * Create a UDP PCB.
- *
- * @return The UDP PCB which was created. NULL if the PCB data structure
- * could not be allocated.
- *
- * @see udp_remove()
- */
-struct udp_pcb *
-udp_new(void)
-{
- struct udp_pcb *pcb;
- pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB);
- /* could allocate UDP PCB? */
- if (pcb != NULL) {
- /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0
- * which means checksum is generated over the whole datagram per default
- * (recommended as default by RFC 3828). */
- /* initialize PCB to all zeroes */
- memset(pcb, 0, sizeof(struct udp_pcb));
- pcb->ttl = UDP_TTL;
- }
- return pcb;
-}
-
-#if UDP_DEBUG
-/**
- * Print UDP header information for debug purposes.
- *
- * @param udphdr pointer to the udp header in memory.
- */
-void
-udp_debug_print(struct udp_hdr *udphdr)
-{
- LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));
- LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n",
- ntohs(udphdr->src), ntohs(udphdr->dest)));
- LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n",
- ntohs(udphdr->len), ntohs(udphdr->chksum)));
- LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
-}
-#endif /* UDP_DEBUG */
-
-#endif /* LWIP_UDP */
+++ /dev/null
-/**
- * @file
- *
- * AutoIP Automatic LinkLocal IP Configuration
- */
-
-/*
- *
- * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * Author: Dominik Spies <kontakt@dspies.de>
- *
- * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
- * with RFC 3927.
- *
- *
- * Please coordinate changes and requests with Dominik Spies
- * <kontakt@dspies.de>
- */
-
-#ifndef __LWIP_AUTOIP_H__
-#define __LWIP_AUTOIP_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/netif.h"
-#include "lwip/udp.h"
-#include "netif/etharp.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* AutoIP Timing */
-#define AUTOIP_TMR_INTERVAL 100
-#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL)
-
-/* RFC 3927 Constants */
-#define PROBE_WAIT 1 /* second (initial random delay) */
-#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */
-#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */
-#define PROBE_NUM 3 /* (number of probe packets) */
-#define ANNOUNCE_NUM 2 /* (number of announcement packets) */
-#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */
-#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */
-#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */
-#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */
-#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */
-
-/* AutoIP client states */
-#define AUTOIP_STATE_OFF 0
-#define AUTOIP_STATE_PROBING 1
-#define AUTOIP_STATE_ANNOUNCING 2
-#define AUTOIP_STATE_BOUND 3
-
-struct autoip
-{
- ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */
- u8_t state; /* current AutoIP state machine state */
- u8_t sent_num; /* sent number of probes or announces, dependent on state */
- u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */
- u8_t lastconflict; /* ticks until a conflict can be solved by defending */
- u8_t tried_llipaddr; /* total number of probed/used Link Local IP-Addresses */
-};
-
-
-/** Init srand, has to be called before entering mainloop */
-void autoip_init(void);
-
-/** Set a struct autoip allocated by the application to work with */
-void autoip_set_struct(struct netif *netif, struct autoip *autoip);
-
-/** Start AutoIP client */
-err_t autoip_start(struct netif *netif);
-
-/** Stop AutoIP client */
-err_t autoip_stop(struct netif *netif);
-
-/** Handles every incoming ARP Packet, called by etharp_arp_input */
-void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr);
-
-/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */
-void autoip_tmr(void);
-
-/** Handle a possible change in the network configuration */
-void autoip_network_changed(struct netif *netif);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_AUTOIP */
-
-#endif /* __LWIP_AUTOIP_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_ICMP_H__
-#define __LWIP_ICMP_H__
-
-#include "lwip/opt.h"
-#include "lwip/pbuf.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define ICMP_ER 0 /* echo reply */
-#define ICMP_DUR 3 /* destination unreachable */
-#define ICMP_SQ 4 /* source quench */
-#define ICMP_RD 5 /* redirect */
-#define ICMP_ECHO 8 /* echo */
-#define ICMP_TE 11 /* time exceeded */
-#define ICMP_PP 12 /* parameter problem */
-#define ICMP_TS 13 /* timestamp */
-#define ICMP_TSR 14 /* timestamp reply */
-#define ICMP_IRQ 15 /* information request */
-#define ICMP_IR 16 /* information reply */
-
-enum icmp_dur_type {
- ICMP_DUR_NET = 0, /* net unreachable */
- ICMP_DUR_HOST = 1, /* host unreachable */
- ICMP_DUR_PROTO = 2, /* protocol unreachable */
- ICMP_DUR_PORT = 3, /* port unreachable */
- ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
- ICMP_DUR_SR = 5 /* source route failed */
-};
-
-enum icmp_te_type {
- ICMP_TE_TTL = 0, /* time to live exceeded in transit */
- ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
-};
-
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-/** This is the standard ICMP header only that the u32_t data
- * is splitted to two u16_t like ICMP echo needs it.
- * This header is also used for other ICMP types that do not
- * use the data part.
- */
-PACK_STRUCT_BEGIN
-struct icmp_echo_hdr {
- PACK_STRUCT_FIELD(u8_t type);
- PACK_STRUCT_FIELD(u8_t code);
- PACK_STRUCT_FIELD(u16_t chksum);
- PACK_STRUCT_FIELD(u16_t id);
- PACK_STRUCT_FIELD(u16_t seqno);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-#define ICMPH_TYPE(hdr) ((hdr)->type)
-#define ICMPH_CODE(hdr) ((hdr)->code)
-
-/** Combines type and code to an u16_t */
-#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t))
-#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c))
-
-
-#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
-
-void icmp_input(struct pbuf *p, struct netif *inp);
-void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
-void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
-
-#endif /* LWIP_ICMP */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_ICMP_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2002 CITEL Technologies Ltd.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This file is a contribution to the lwIP TCP/IP stack.
- * The Swedish Institute of Computer Science and Adam Dunkels
- * are specifically granted permission to redistribute this
- * source code.
-*/
-
-#ifndef __LWIP_IGMP_H__
-#define __LWIP_IGMP_H__
-
-#include "lwip/opt.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/pbuf.h"
-
-#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* IGMP timer */
-#define IGMP_TMR_INTERVAL 100 /* Milliseconds */
-#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL)
-#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL)
-
-/* MAC Filter Actions, these are passed to a netif's
- * igmp_mac_filter callback function. */
-#define IGMP_DEL_MAC_FILTER 0
-#define IGMP_ADD_MAC_FILTER 1
-
-
-/**
- * igmp group structure - there is
- * a list of groups for each interface
- * these should really be linked from the interface, but
- * if we keep them separate we will not affect the lwip original code
- * too much
- *
- * There will be a group for the all systems group address but this
- * will not run the state machine as it is used to kick off reports
- * from all the other groups
- */
-struct igmp_group {
- /** next link */
- struct igmp_group *next;
- /** interface on which the group is active */
- struct netif *netif;
- /** multicast address */
- ip_addr_t group_address;
- /** signifies we were the last person to report */
- u8_t last_reporter_flag;
- /** current state of the group */
- u8_t group_state;
- /** timer for reporting, negative is OFF */
- u16_t timer;
- /** counter of simultaneous uses */
- u8_t use;
-};
-
-/* Prototypes */
-void igmp_init(void);
-err_t igmp_start(struct netif *netif);
-err_t igmp_stop(struct netif *netif);
-void igmp_report_groups(struct netif *netif);
-struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr);
-void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest);
-err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
-err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
-void igmp_tmr(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_IGMP */
-
-#endif /* __LWIP_IGMP_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_INET_H__
-#define __LWIP_INET_H__
-
-#include "lwip/opt.h"
-#include "lwip/def.h"
-#include "lwip/ip_addr.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** For compatibility with BSD code */
-struct in_addr {
- u32_t s_addr;
-};
-
-/** 255.255.255.255 */
-#define INADDR_NONE IPADDR_NONE
-/** 127.0.0.1 */
-#define INADDR_LOOPBACK IPADDR_LOOPBACK
-/** 0.0.0.0 */
-#define INADDR_ANY IPADDR_ANY
-/** 255.255.255.255 */
-#define INADDR_BROADCAST IPADDR_BROADCAST
-
-/* Definitions of the bits in an Internet address integer.
-
- On subnets, host and network parts are found according to
- the subnet mask, not these masks. */
-#define IN_CLASSA(a) IP_CLASSA(a)
-#define IN_CLASSA_NET IP_CLASSA_NET
-#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT
-#define IN_CLASSA_HOST IP_CLASSA_HOST
-#define IN_CLASSA_MAX IP_CLASSA_MAX
-
-#define IN_CLASSB(b) IP_CLASSB(b)
-#define IN_CLASSB_NET IP_CLASSB_NET
-#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT
-#define IN_CLASSB_HOST IP_CLASSB_HOST
-#define IN_CLASSB_MAX IP_CLASSB_MAX
-
-#define IN_CLASSC(c) IP_CLASSC(c)
-#define IN_CLASSC_NET IP_CLASSC_NET
-#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT
-#define IN_CLASSC_HOST IP_CLASSC_HOST
-#define IN_CLASSC_MAX IP_CLASSC_MAX
-
-#define IN_CLASSD(d) IP_CLASSD(d)
-#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */
-#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */
-#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */
-#define IN_CLASSD_MAX IP_CLASSD_MAX
-
-#define IN_MULTICAST(a) IP_MULTICAST(a)
-
-#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a)
-#define IN_BADCLASS(a) IP_BADCLASS(a)
-
-#define IN_LOOPBACKNET IP_LOOPBACKNET
-
-#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr))
-#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr))
-/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */
-#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr))
-
-/* directly map this to the lwip internal functions */
-#define inet_addr(cp) ipaddr_addr(cp)
-#define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr)
-#define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr))
-#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_INET_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_INET_CHKSUM_H__
-#define __LWIP_INET_CHKSUM_H__
-
-#include "lwip/opt.h"
-
-#include "lwip/pbuf.h"
-#include "lwip/ip_addr.h"
-
-/** Swap the bytes in an u16_t: much like htons() for little-endian */
-#ifndef SWAP_BYTES_IN_WORD
-#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
-/* little endian and PLATFORM_BYTESWAP defined */
-#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
-#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */
-/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
-#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8)
-#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/
-#endif /* SWAP_BYTES_IN_WORD */
-
-/** Split an u32_t in two u16_ts and add them up */
-#ifndef FOLD_U32T
-#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL))
-#endif
-
-#if LWIP_CHECKSUM_ON_COPY
-/** Function-like macro: same as MEMCPY but returns the checksum of copied data
- as u16_t */
-#ifndef LWIP_CHKSUM_COPY
-#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len)
-#ifndef LWIP_CHKSUM_COPY_ALGORITHM
-#define LWIP_CHKSUM_COPY_ALGORITHM 1
-#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
-#endif /* LWIP_CHKSUM_COPY */
-#else /* LWIP_CHECKSUM_ON_COPY */
-#define LWIP_CHKSUM_COPY_ALGORITHM 0
-#endif /* LWIP_CHECKSUM_ON_COPY */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-u16_t inet_chksum(void *dataptr, u16_t len);
-u16_t inet_chksum_pbuf(struct pbuf *p);
-u16_t inet_chksum_pseudo(struct pbuf *p,
- ip_addr_t *src, ip_addr_t *dest,
- u8_t proto, u16_t proto_len);
-u16_t inet_chksum_pseudo_partial(struct pbuf *p,
- ip_addr_t *src, ip_addr_t *dest,
- u8_t proto, u16_t proto_len, u16_t chksum_len);
-#if LWIP_CHKSUM_COPY_ALGORITHM
-u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len);
-#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_INET_H__ */
-
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_IP_H__
-#define __LWIP_IP_H__
-
-#include "lwip/opt.h"
-
-#include "lwip/def.h"
-#include "lwip/pbuf.h"
-#include "lwip/ip_addr.h"
-#include "lwip/err.h"
-#include "lwip/netif.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** Currently, the function ip_output_if_opt() is only used with IGMP */
-#define IP_OPTIONS_SEND LWIP_IGMP
-
-#define IP_HLEN 20
-
-#define IP_PROTO_ICMP 1
-#define IP_PROTO_IGMP 2
-#define IP_PROTO_UDP 17
-#define IP_PROTO_UDPLITE 136
-#define IP_PROTO_TCP 6
-
-/* This is passed as the destination address to ip_output_if (not
- to ip_output), meaning that an IP header already is constructed
- in the pbuf. This is used when TCP retransmits. */
-#ifdef IP_HDRINCL
-#undef IP_HDRINCL
-#endif /* IP_HDRINCL */
-#define IP_HDRINCL NULL
-
-#if LWIP_NETIF_HWADDRHINT
-#define IP_PCB_ADDRHINT ;u8_t addr_hint
-#else
-#define IP_PCB_ADDRHINT
-#endif /* LWIP_NETIF_HWADDRHINT */
-
-/* This is the common part of all PCB types. It needs to be at the
- beginning of a PCB type definition. It is located here so that
- changes to this common part are made in one location instead of
- having to change all PCB structs. */
-#define IP_PCB \
- /* ip addresses in network byte order */ \
- ip_addr_t local_ip; \
- ip_addr_t remote_ip; \
- /* Socket options */ \
- u8_t so_options; \
- /* Type Of Service */ \
- u8_t tos; \
- /* Time To Live */ \
- u8_t ttl \
- /* link layer address resolution hint */ \
- IP_PCB_ADDRHINT
-
-struct ip_pcb {
-/* Common members of all PCB types */
- IP_PCB;
-};
-
-/*
- * Option flags per-socket. These are the same like SO_XXX.
- */
-/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */
-#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */
-#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */
-#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */
-/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */
-#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
-/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */
-#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */
-/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */
-/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */
-
-/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */
-#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/)
-
-
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-struct ip_hdr {
- /* version / header length / type of service */
- PACK_STRUCT_FIELD(u16_t _v_hl_tos);
- /* total length */
- PACK_STRUCT_FIELD(u16_t _len);
- /* identification */
- PACK_STRUCT_FIELD(u16_t _id);
- /* fragment offset field */
- PACK_STRUCT_FIELD(u16_t _offset);
-#define IP_RF 0x8000U /* reserved fragment flag */
-#define IP_DF 0x4000U /* dont fragment flag */
-#define IP_MF 0x2000U /* more fragments flag */
-#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */
- /* time to live */
- PACK_STRUCT_FIELD(u8_t _ttl);
- /* protocol*/
- PACK_STRUCT_FIELD(u8_t _proto);
- /* checksum */
- PACK_STRUCT_FIELD(u16_t _chksum);
- /* source and destination IP addresses */
- PACK_STRUCT_FIELD(ip_addr_p_t src);
- PACK_STRUCT_FIELD(ip_addr_p_t dest);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12)
-#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)
-#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)
-#define IPH_LEN(hdr) ((hdr)->_len)
-#define IPH_ID(hdr) ((hdr)->_id)
-#define IPH_OFFSET(hdr) ((hdr)->_offset)
-#define IPH_TTL(hdr) ((hdr)->_ttl)
-#define IPH_PROTO(hdr) ((hdr)->_proto)
-#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
-
-#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))
-#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
-#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
-#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
-#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl)
-#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto)
-#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
-
-/** The interface that provided the packet for the current callback invocation. */
-extern struct netif *current_netif;
-/** Header of the input packet currently being processed. */
-extern const struct ip_hdr *current_header;
-/** Source IP address of current_header */
-extern ip_addr_t current_iphdr_src;
-/** Destination IP address of current_header */
-extern ip_addr_t current_iphdr_dest;
-
-#define ip_init() /* Compatibility define, not init needed. */
-struct netif *ip_route(ip_addr_t *dest);
-err_t ip_input(struct pbuf *p, struct netif *inp);
-err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
- u8_t ttl, u8_t tos, u8_t proto);
-err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
- u8_t ttl, u8_t tos, u8_t proto,
- struct netif *netif);
-#if LWIP_NETIF_HWADDRHINT
-err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
- u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint);
-#endif /* LWIP_NETIF_HWADDRHINT */
-#if IP_OPTIONS_SEND
-err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
- u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
- u16_t optlen);
-#endif /* IP_OPTIONS_SEND */
-/** Get the interface that received the current packet.
- * This function must only be called from a receive callback (udp_recv,
- * raw_recv, tcp_accept). It will return NULL otherwise. */
-#define ip_current_netif() (current_netif)
-/** Get the IP header of the current packet.
- * This function must only be called from a receive callback (udp_recv,
- * raw_recv, tcp_accept). It will return NULL otherwise. */
-#define ip_current_header() (current_header)
-/** Source IP address of current_header */
-#define ip_current_src_addr() (¤t_iphdr_src)
-/** Destination IP address of current_header */
-#define ip_current_dest_addr() (¤t_iphdr_dest)
-
-#if IP_DEBUG
-void ip_debug_print(struct pbuf *p);
-#else
-#define ip_debug_print(p)
-#endif /* IP_DEBUG */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_IP_H__ */
-
-
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_IP_ADDR_H__
-#define __LWIP_IP_ADDR_H__
-
-#include "lwip/opt.h"
-#include "lwip/def.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* This is the aligned version of ip_addr_t,
- used as local variable, on the stack, etc. */
-struct ip_addr {
- u32_t addr;
-};
-
-/* This is the packed version of ip_addr_t,
- used in network headers that are itself packed */
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-struct ip_addr_packed {
- PACK_STRUCT_FIELD(u32_t addr);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-/** ip_addr_t uses a struct for convenience only, so that the same defines can
- * operate both on ip_addr_t as well as on ip_addr_p_t. */
-typedef struct ip_addr ip_addr_t;
-typedef struct ip_addr_packed ip_addr_p_t;
-
-/*
- * struct ipaddr2 is used in the definition of the ARP packet format in
- * order to support compilers that don't have structure packing.
- */
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-struct ip_addr2 {
- PACK_STRUCT_FIELD(u16_t addrw[2]);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-/* Forward declaration to not include netif.h */
-struct netif;
-
-extern const ip_addr_t ip_addr_any;
-extern const ip_addr_t ip_addr_broadcast;
-
-/** IP_ADDR_ can be used as a fixed IP address
- * for the wildcard and the broadcast address
- */
-#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any)
-#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast)
-
-/** 255.255.255.255 */
-#define IPADDR_NONE ((u32_t)0xffffffffUL)
-/** 127.0.0.1 */
-#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL)
-/** 0.0.0.0 */
-#define IPADDR_ANY ((u32_t)0x00000000UL)
-/** 255.255.255.255 */
-#define IPADDR_BROADCAST ((u32_t)0xffffffffUL)
-
-/* Definitions of the bits in an Internet address integer.
-
- On subnets, host and network parts are found according to
- the subnet mask, not these masks. */
-#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
-#define IP_CLASSA_NET 0xff000000
-#define IP_CLASSA_NSHIFT 24
-#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET)
-#define IP_CLASSA_MAX 128
-
-#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
-#define IP_CLASSB_NET 0xffff0000
-#define IP_CLASSB_NSHIFT 16
-#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET)
-#define IP_CLASSB_MAX 65536
-
-#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
-#define IP_CLASSC_NET 0xffffff00
-#define IP_CLASSC_NSHIFT 8
-#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET)
-
-#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
-#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */
-#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */
-#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */
-#define IP_MULTICAST(a) IP_CLASSD(a)
-
-#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
-#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
-
-#define IP_LOOPBACKNET 127 /* official! */
-
-
-#if BYTE_ORDER == BIG_ENDIAN
-/** Set an IP address given by the four byte-parts */
-#define IP4_ADDR(ipaddr, a,b,c,d) \
- (ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \
- ((u32_t)((b) & 0xff) << 16) | \
- ((u32_t)((c) & 0xff) << 8) | \
- (u32_t)((d) & 0xff)
-#else
-/** Set an IP address given by the four byte-parts.
- Little-endian version that prevents the use of htonl. */
-#define IP4_ADDR(ipaddr, a,b,c,d) \
- (ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \
- ((u32_t)((c) & 0xff) << 16) | \
- ((u32_t)((b) & 0xff) << 8) | \
- (u32_t)((a) & 0xff)
-#endif
-
-/** MEMCPY-like copying of IP addresses where addresses are known to be
- * 16-bit-aligned if the port is correctly configured (so a port could define
- * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */
-#ifndef IPADDR2_COPY
-#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t))
-#endif
-
-/** Copy IP address - faster than ip_addr_set: no NULL check */
-#define ip_addr_copy(dest, src) ((dest).addr = (src).addr)
-/** Safely copy one IP address to another (src may be NULL) */
-#define ip_addr_set(dest, src) ((dest)->addr = \
- ((src) == NULL ? 0 : \
- (src)->addr))
-/** Set complete address to zero */
-#define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0)
-/** Set address to IPADDR_ANY (no need for htonl()) */
-#define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY)
-/** Set address to loopback address */
-#define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK))
-/** Safely copy one IP address to another and change byte order
- * from host- to network-order. */
-#define ip_addr_set_hton(dest, src) ((dest)->addr = \
- ((src) == NULL ? 0:\
- htonl((src)->addr)))
-/** IPv4 only: set the IP address given as an u32_t */
-#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32))
-/** IPv4 only: get the IP address as an u32_t */
-#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)
-
-/** Get the network address by combining host address with netmask */
-#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr))
-
-/**
- * Determine if two address are on the same network.
- *
- * @arg addr1 IP address 1
- * @arg addr2 IP address 2
- * @arg mask network identifier mask
- * @return !0 if the network identifiers of both address match
- */
-#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
- (mask)->addr) == \
- ((addr2)->addr & \
- (mask)->addr))
-#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
-
-#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY)
-
-#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif))
-u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif);
-
-#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr)
-u8_t ip4_addr_netmask_valid(u32_t netmask);
-
-#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL))
-
-#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL))
-
-#define ip_addr_debug_print(debug, ipaddr) \
- LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
- ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \
- ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \
- ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \
- ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0))
-
-/* Get one byte from the 4-byte address */
-#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])
-#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])
-#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])
-#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])
-/* These are cast to u16_t, with the intent that they are often arguments
- * to printf using the U16_F format from cc.h. */
-#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))
-#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))
-#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))
-#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))
-
-/** For backwards compatibility */
-#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr)
-
-u32_t ipaddr_addr(const char *cp);
-int ipaddr_aton(const char *cp, ip_addr_t *addr);
-/** returns ptr to static buffer; not reentrant! */
-char *ipaddr_ntoa(const ip_addr_t *addr);
-char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_IP_ADDR_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Jani Monoses <jani@iv.ro>
- *
- */
-
-#ifndef __LWIP_IP_FRAG_H__
-#define __LWIP_IP_FRAG_H__
-
-#include "lwip/opt.h"
-#include "lwip/err.h"
-#include "lwip/pbuf.h"
-#include "lwip/netif.h"
-#include "lwip/ip_addr.h"
-#include "lwip/ip.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if IP_REASSEMBLY
-/* The IP reassembly timer interval in milliseconds. */
-#define IP_TMR_INTERVAL 1000
-
-/* IP reassembly helper struct.
- * This is exported because memp needs to know the size.
- */
-struct ip_reassdata {
- struct ip_reassdata *next;
- struct pbuf *p;
- struct ip_hdr iphdr;
- u16_t datagram_len;
- u8_t flags;
- u8_t timer;
-};
-
-void ip_reass_init(void);
-void ip_reass_tmr(void);
-struct pbuf * ip_reass(struct pbuf *p);
-#endif /* IP_REASSEMBLY */
-
-#if IP_FRAG
-#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
-/** A custom pbuf that holds a reference to another pbuf, which is freed
- * when this custom pbuf is freed. This is used to create a custom PBUF_REF
- * that points into the original pbuf. */
-struct pbuf_custom_ref {
- /** 'base class' */
- struct pbuf_custom pc;
- /** pointer to the original pbuf that is referenced */
- struct pbuf *original;
-};
-#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
-
-err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest);
-#endif /* IP_FRAG */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_IP_FRAG_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_API_H__
-#define __LWIP_API_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
-
-#include <stddef.h> /* for size_t */
-
-#include "lwip/netbuf.h"
-#include "lwip/sys.h"
-#include "lwip/ip_addr.h"
-#include "lwip/err.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Throughout this file, IP addresses and port numbers are expected to be in
- * the same byte order as in the corresponding pcb.
- */
-
-/* Flags for netconn_write (u8_t) */
-#define NETCONN_NOFLAG 0x00
-#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */
-#define NETCONN_COPY 0x01
-#define NETCONN_MORE 0x02
-#define NETCONN_DONTBLOCK 0x04
-
-/* Flags for struct netconn.flags (u8_t) */
-/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
- this temporarily stores whether to wake up the original application task
- if data couldn't be sent in the first try. */
-#define NETCONN_FLAG_WRITE_DELAYED 0x01
-/** Should this netconn avoid blocking? */
-#define NETCONN_FLAG_NON_BLOCKING 0x02
-/** Was the last connect action a non-blocking one? */
-#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04
-/** If this is set, a TCP netconn must call netconn_recved() to update
- the TCP receive window (done automatically if not set). */
-#define NETCONN_FLAG_NO_AUTO_RECVED 0x08
-/** If a nonblocking write has been rejected before, poll_tcp needs to
- check if the netconn is writable again */
-#define NETCONN_FLAG_CHECK_WRITESPACE 0x10
-
-
-/* Helpers to process several netconn_types by the same code */
-#define NETCONNTYPE_GROUP(t) (t&0xF0)
-#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)
-
-/** Protocol family and type of the netconn */
-enum netconn_type {
- NETCONN_INVALID = 0,
- /* NETCONN_TCP Group */
- NETCONN_TCP = 0x10,
- /* NETCONN_UDP Group */
- NETCONN_UDP = 0x20,
- NETCONN_UDPLITE = 0x21,
- NETCONN_UDPNOCHKSUM= 0x22,
- /* NETCONN_RAW Group */
- NETCONN_RAW = 0x40
-};
-
-/** Current state of the netconn. Non-TCP netconns are always
- * in state NETCONN_NONE! */
-enum netconn_state {
- NETCONN_NONE,
- NETCONN_WRITE,
- NETCONN_LISTEN,
- NETCONN_CONNECT,
- NETCONN_CLOSE
-};
-
-/** Use to inform the callback function about changes */
-enum netconn_evt {
- NETCONN_EVT_RCVPLUS,
- NETCONN_EVT_RCVMINUS,
- NETCONN_EVT_SENDPLUS,
- NETCONN_EVT_SENDMINUS,
- NETCONN_EVT_ERROR
-};
-
-#if LWIP_IGMP
-/** Used for netconn_join_leave_group() */
-enum netconn_igmp {
- NETCONN_JOIN,
- NETCONN_LEAVE
-};
-#endif /* LWIP_IGMP */
-
-/* forward-declare some structs to avoid to include their headers */
-struct ip_pcb;
-struct tcp_pcb;
-struct udp_pcb;
-struct raw_pcb;
-struct netconn;
-struct api_msg_msg;
-
-/** A callback prototype to inform about events for a netconn */
-typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len);
-
-/** A netconn descriptor */
-struct netconn {
- /** type of the netconn (TCP, UDP or RAW) */
- enum netconn_type type;
- /** current state of the netconn */
- enum netconn_state state;
- /** the lwIP internal protocol control block */
- union {
- struct ip_pcb *ip;
- struct tcp_pcb *tcp;
- struct udp_pcb *udp;
- struct raw_pcb *raw;
- } pcb;
- /** the last error this netconn had */
- err_t last_err;
- /** sem that is used to synchroneously execute functions in the core context */
- sys_sem_t op_completed;
- /** mbox where received packets are stored until they are fetched
- by the netconn application thread (can grow quite big) */
- sys_mbox_t recvmbox;
-#if LWIP_TCP
- /** mbox where new connections are stored until processed
- by the application thread */
- sys_mbox_t acceptmbox;
-#endif /* LWIP_TCP */
- /** only used for socket layer */
-#if LWIP_SOCKET
- int socket;
-#endif /* LWIP_SOCKET */
-#if LWIP_SO_RCVTIMEO
- /** timeout to wait for new data to be received
- (or connections to arrive for listening netconns) */
- int recv_timeout;
-#endif /* LWIP_SO_RCVTIMEO */
-#if LWIP_SO_RCVBUF
- /** maximum amount of bytes queued in recvmbox
- not used for TCP: adjust TCP_WND instead! */
- int recv_bufsize;
- /** number of bytes currently in recvmbox to be received,
- tested against recv_bufsize to limit bytes on recvmbox
- for UDP and RAW, used for FIONREAD */
- s16_t recv_avail;
-#endif /* LWIP_SO_RCVBUF */
- /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */
- u8_t flags;
-#if LWIP_TCP
- /** TCP: when data passed to netconn_write doesn't fit into the send buffer,
- this temporarily stores how much is already sent. */
- size_t write_offset;
- /** TCP: when data passed to netconn_write doesn't fit into the send buffer,
- this temporarily stores the message.
- Also used during connect and close. */
- struct api_msg_msg *current_msg;
-#endif /* LWIP_TCP */
- /** A callback function that is informed about events for this netconn */
- netconn_callback callback;
-};
-
-/** Register an Network connection event */
-#define API_EVENT(c,e,l) if (c->callback) { \
- (*c->callback)(c, e, l); \
- }
-
-/** Set conn->last_err to err but don't overwrite fatal errors */
-#define NETCONN_SET_SAFE_ERR(conn, err) do { \
- SYS_ARCH_DECL_PROTECT(lev); \
- SYS_ARCH_PROTECT(lev); \
- if (!ERR_IS_FATAL((conn)->last_err)) { \
- (conn)->last_err = err; \
- } \
- SYS_ARCH_UNPROTECT(lev); \
-} while(0);
-
-/* Network connection functions: */
-#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL)
-#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)
-struct
-netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
- netconn_callback callback);
-err_t netconn_delete(struct netconn *conn);
-/** Get the type of a netconn (as enum netconn_type). */
-#define netconn_type(conn) (conn->type)
-
-err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr,
- u16_t *port, u8_t local);
-#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0)
-#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1)
-
-err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port);
-err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port);
-err_t netconn_disconnect (struct netconn *conn);
-err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
-#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)
-err_t netconn_accept(struct netconn *conn, struct netconn **new_conn);
-err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf);
-err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf);
-void netconn_recved(struct netconn *conn, u32_t length);
-err_t netconn_sendto(struct netconn *conn, struct netbuf *buf,
- ip_addr_t *addr, u16_t port);
-err_t netconn_send(struct netconn *conn, struct netbuf *buf);
-err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size,
- u8_t apiflags);
-err_t netconn_close(struct netconn *conn);
-err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx);
-
-#if LWIP_IGMP
-err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr,
- ip_addr_t *netif_addr, enum netconn_igmp join_or_leave);
-#endif /* LWIP_IGMP */
-#if LWIP_DNS
-err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
-#endif /* LWIP_DNS */
-
-#define netconn_err(conn) ((conn)->last_err)
-#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
-
-/** Set the blocking status of netconn calls (@todo: write/send is missing) */
-#define netconn_set_nonblocking(conn, val) do { if(val) { \
- (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \
-} else { \
- (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0)
-/** Get the blocking status of netconn calls (@todo: write/send is missing) */
-#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0)
-
-/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
-#define netconn_set_noautorecved(conn, val) do { if(val) { \
- (conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \
-} else { \
- (conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0)
-/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
-#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0)
-
-#if LWIP_SO_RCVTIMEO
-/** Set the receive timeout in milliseconds */
-#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout))
-/** Get the receive timeout in milliseconds */
-#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout)
-#endif /* LWIP_SO_RCVTIMEO */
-#if LWIP_SO_RCVBUF
-/** Set the receive buffer in bytes */
-#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize))
-/** Get the receive buffer in bytes */
-#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize)
-#endif /* LWIP_SO_RCVBUF*/
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_NETCONN */
-
-#endif /* __LWIP_API_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_API_MSG_H__
-#define __LWIP_API_MSG_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
-
-#include <stddef.h> /* for size_t */
-
-#include "lwip/ip_addr.h"
-#include "lwip/err.h"
-#include "lwip/sys.h"
-#include "lwip/igmp.h"
-#include "lwip/api.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* For the netconn API, these values are use as a bitmask! */
-#define NETCONN_SHUT_RD 1
-#define NETCONN_SHUT_WR 2
-#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR)
-
-/* IP addresses and port numbers are expected to be in
- * the same byte order as in the corresponding pcb.
- */
-/** This struct includes everything that is necessary to execute a function
- for a netconn in another thread context (mainly used to process netconns
- in the tcpip_thread context to be thread safe). */
-struct api_msg_msg {
- /** The netconn which to process - always needed: it includes the semaphore
- which is used to block the application thread until the function finished. */
- struct netconn *conn;
- /** The return value of the function executed in tcpip_thread. */
- err_t err;
- /** Depending on the executed function, one of these union members is used */
- union {
- /** used for do_send */
- struct netbuf *b;
- /** used for do_newconn */
- struct {
- u8_t proto;
- } n;
- /** used for do_bind and do_connect */
- struct {
- ip_addr_t *ipaddr;
- u16_t port;
- } bc;
- /** used for do_getaddr */
- struct {
- ip_addr_t *ipaddr;
- u16_t *port;
- u8_t local;
- } ad;
- /** used for do_write */
- struct {
- const void *dataptr;
- size_t len;
- u8_t apiflags;
- } w;
- /** used for do_recv */
- struct {
- u32_t len;
- } r;
- /** used for do_close (/shutdown) */
- struct {
- u8_t shut;
- } sd;
-#if LWIP_IGMP
- /** used for do_join_leave_group */
- struct {
- ip_addr_t *multiaddr;
- ip_addr_t *netif_addr;
- enum netconn_igmp join_or_leave;
- } jl;
-#endif /* LWIP_IGMP */
-#if TCP_LISTEN_BACKLOG
- struct {
- u8_t backlog;
- } lb;
-#endif /* TCP_LISTEN_BACKLOG */
- } msg;
-};
-
-/** This struct contains a function to execute in another thread context and
- a struct api_msg_msg that serves as an argument for this function.
- This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */
-struct api_msg {
- /** function to execute in tcpip_thread context */
- void (* function)(struct api_msg_msg *msg);
- /** arguments for this function */
- struct api_msg_msg msg;
-};
-
-#if LWIP_DNS
-/** As do_gethostbyname requires more arguments but doesn't require a netconn,
- it has its own struct (to avoid struct api_msg getting bigger than necessary).
- do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg
- (see netconn_gethostbyname). */
-struct dns_api_msg {
- /** Hostname to query or dotted IP address string */
- const char *name;
- /** Rhe resolved address is stored here */
- ip_addr_t *addr;
- /** This semaphore is posted when the name is resolved, the application thread
- should wait on it. */
- sys_sem_t *sem;
- /** Errors are given back here */
- err_t *err;
-};
-#endif /* LWIP_DNS */
-
-void do_newconn ( struct api_msg_msg *msg);
-void do_delconn ( struct api_msg_msg *msg);
-void do_bind ( struct api_msg_msg *msg);
-void do_connect ( struct api_msg_msg *msg);
-void do_disconnect ( struct api_msg_msg *msg);
-void do_listen ( struct api_msg_msg *msg);
-void do_send ( struct api_msg_msg *msg);
-void do_recv ( struct api_msg_msg *msg);
-void do_write ( struct api_msg_msg *msg);
-void do_getaddr ( struct api_msg_msg *msg);
-void do_close ( struct api_msg_msg *msg);
-void do_shutdown ( struct api_msg_msg *msg);
-#if LWIP_IGMP
-void do_join_leave_group( struct api_msg_msg *msg);
-#endif /* LWIP_IGMP */
-
-#if LWIP_DNS
-void do_gethostbyname(void *arg);
-#endif /* LWIP_DNS */
-
-struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback);
-void netconn_free(struct netconn *conn);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_NETCONN */
-
-#endif /* __LWIP_API_MSG_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_ARCH_H__
-#define __LWIP_ARCH_H__
-
-#ifndef LITTLE_ENDIAN
-#define LITTLE_ENDIAN 1234
-#endif
-
-#ifndef BIG_ENDIAN
-#define BIG_ENDIAN 4321
-#endif
-
-#include "arch/cc.h"
-
-/** Temporary: define format string for size_t if not defined in cc.h */
-#ifndef SZT_F
-#define SZT_F U32_F
-#endif /* SZT_F */
-/** Temporary upgrade helper: define format string for u8_t as hex if not
- defined in cc.h */
-#ifndef X8_F
-#define X8_F "02x"
-#endif /* X8_F */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef PACK_STRUCT_BEGIN
-#define PACK_STRUCT_BEGIN
-#endif /* PACK_STRUCT_BEGIN */
-
-#ifndef PACK_STRUCT_END
-#define PACK_STRUCT_END
-#endif /* PACK_STRUCT_END */
-
-#ifndef PACK_STRUCT_FIELD
-#define PACK_STRUCT_FIELD(x) x
-#endif /* PACK_STRUCT_FIELD */
-
-
-#ifndef LWIP_UNUSED_ARG
-#define LWIP_UNUSED_ARG(x) (void)x
-#endif /* LWIP_UNUSED_ARG */
-
-
-#ifdef LWIP_PROVIDE_ERRNO
-
-#define EPERM 1 /* Operation not permitted */
-#define ENOENT 2 /* No such file or directory */
-#define ESRCH 3 /* No such process */
-#define EINTR 4 /* Interrupted system call */
-#define EIO 5 /* I/O error */
-#define ENXIO 6 /* No such device or address */
-#define E2BIG 7 /* Arg list too long */
-#define ENOEXEC 8 /* Exec format error */
-#define EBADF 9 /* Bad file number */
-#define ECHILD 10 /* No child processes */
-#define EAGAIN 11 /* Try again */
-#define ENOMEM 12 /* Out of memory */
-#define EACCES 13 /* Permission denied */
-#define EFAULT 14 /* Bad address */
-#define ENOTBLK 15 /* Block device required */
-#define EBUSY 16 /* Device or resource busy */
-#define EEXIST 17 /* File exists */
-#define EXDEV 18 /* Cross-device link */
-#define ENODEV 19 /* No such device */
-#define ENOTDIR 20 /* Not a directory */
-#define EISDIR 21 /* Is a directory */
-#define EINVAL 22 /* Invalid argument */
-#define ENFILE 23 /* File table overflow */
-#define EMFILE 24 /* Too many open files */
-#define ENOTTY 25 /* Not a typewriter */
-#define ETXTBSY 26 /* Text file busy */
-#define EFBIG 27 /* File too large */
-#define ENOSPC 28 /* No space left on device */
-#define ESPIPE 29 /* Illegal seek */
-#define EROFS 30 /* Read-only file system */
-#define EMLINK 31 /* Too many links */
-#define EPIPE 32 /* Broken pipe */
-#define EDOM 33 /* Math argument out of domain of func */
-#define ERANGE 34 /* Math result not representable */
-#define EDEADLK 35 /* Resource deadlock would occur */
-#define ENAMETOOLONG 36 /* File name too long */
-#define ENOLCK 37 /* No record locks available */
-#define ENOSYS 38 /* Function not implemented */
-#define ENOTEMPTY 39 /* Directory not empty */
-#define ELOOP 40 /* Too many symbolic links encountered */
-#define EWOULDBLOCK EAGAIN /* Operation would block */
-#define ENOMSG 42 /* No message of desired type */
-#define EIDRM 43 /* Identifier removed */
-#define ECHRNG 44 /* Channel number out of range */
-#define EL2NSYNC 45 /* Level 2 not synchronized */
-#define EL3HLT 46 /* Level 3 halted */
-#define EL3RST 47 /* Level 3 reset */
-#define ELNRNG 48 /* Link number out of range */
-#define EUNATCH 49 /* Protocol driver not attached */
-#define ENOCSI 50 /* No CSI structure available */
-#define EL2HLT 51 /* Level 2 halted */
-#define EBADE 52 /* Invalid exchange */
-#define EBADR 53 /* Invalid request descriptor */
-#define EXFULL 54 /* Exchange full */
-#define ENOANO 55 /* No anode */
-#define EBADRQC 56 /* Invalid request code */
-#define EBADSLT 57 /* Invalid slot */
-
-#define EDEADLOCK EDEADLK
-
-#define EBFONT 59 /* Bad font file format */
-#define ENOSTR 60 /* Device not a stream */
-#define ENODATA 61 /* No data available */
-#define ETIME 62 /* Timer expired */
-#define ENOSR 63 /* Out of streams resources */
-#define ENONET 64 /* Machine is not on the network */
-#define ENOPKG 65 /* Package not installed */
-#define EREMOTE 66 /* Object is remote */
-#define ENOLINK 67 /* Link has been severed */
-#define EADV 68 /* Advertise error */
-#define ESRMNT 69 /* Srmount error */
-#define ECOMM 70 /* Communication error on send */
-#define EPROTO 71 /* Protocol error */
-#define EMULTIHOP 72 /* Multihop attempted */
-#define EDOTDOT 73 /* RFS specific error */
-#define EBADMSG 74 /* Not a data message */
-#define EOVERFLOW 75 /* Value too large for defined data type */
-#define ENOTUNIQ 76 /* Name not unique on network */
-#define EBADFD 77 /* File descriptor in bad state */
-#define EREMCHG 78 /* Remote address changed */
-#define ELIBACC 79 /* Can not access a needed shared library */
-#define ELIBBAD 80 /* Accessing a corrupted shared library */
-#define ELIBSCN 81 /* .lib section in a.out corrupted */
-#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
-#define ELIBEXEC 83 /* Cannot exec a shared library directly */
-#define EILSEQ 84 /* Illegal byte sequence */
-#define ERESTART 85 /* Interrupted system call should be restarted */
-#define ESTRPIPE 86 /* Streams pipe error */
-#define EUSERS 87 /* Too many users */
-#define ENOTSOCK 88 /* Socket operation on non-socket */
-#define EDESTADDRREQ 89 /* Destination address required */
-#define EMSGSIZE 90 /* Message too long */
-#define EPROTOTYPE 91 /* Protocol wrong type for socket */
-#define ENOPROTOOPT 92 /* Protocol not available */
-#define EPROTONOSUPPORT 93 /* Protocol not supported */
-#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
-#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
-#define EPFNOSUPPORT 96 /* Protocol family not supported */
-#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
-#define EADDRINUSE 98 /* Address already in use */
-#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
-#define ENETDOWN 100 /* Network is down */
-#define ENETUNREACH 101 /* Network is unreachable */
-#define ENETRESET 102 /* Network dropped connection because of reset */
-#define ECONNABORTED 103 /* Software caused connection abort */
-#define ECONNRESET 104 /* Connection reset by peer */
-#define ENOBUFS 105 /* No buffer space available */
-#define EISCONN 106 /* Transport endpoint is already connected */
-#define ENOTCONN 107 /* Transport endpoint is not connected */
-#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
-#define ETOOMANYREFS 109 /* Too many references: cannot splice */
-#define ETIMEDOUT 110 /* Connection timed out */
-#define ECONNREFUSED 111 /* Connection refused */
-#define EHOSTDOWN 112 /* Host is down */
-#define EHOSTUNREACH 113 /* No route to host */
-#define EALREADY 114 /* Operation already in progress */
-#define EINPROGRESS 115 /* Operation now in progress */
-#define ESTALE 116 /* Stale NFS file handle */
-#define EUCLEAN 117 /* Structure needs cleaning */
-#define ENOTNAM 118 /* Not a XENIX named type file */
-#define ENAVAIL 119 /* No XENIX semaphores available */
-#define EISNAM 120 /* Is a named type file */
-#define EREMOTEIO 121 /* Remote I/O error */
-#define EDQUOT 122 /* Quota exceeded */
-
-#define ENOMEDIUM 123 /* No medium found */
-#define EMEDIUMTYPE 124 /* Wrong medium type */
-
-
-#define ENSROK 0 /* DNS server returned answer with no data */
-#define ENSRNODATA 160 /* DNS server returned answer with no data */
-#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
-#define ENSRSERVFAIL 162 /* DNS server returned general failure */
-#define ENSRNOTFOUND 163 /* Domain name not found */
-#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
-#define ENSRREFUSED 165 /* DNS server refused query */
-#define ENSRBADQUERY 166 /* Misformatted DNS query */
-#define ENSRBADNAME 167 /* Misformatted domain name */
-#define ENSRBADFAMILY 168 /* Unsupported address family */
-#define ENSRBADRESP 169 /* Misformatted DNS reply */
-#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
-#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
-#define ENSROF 172 /* End of file */
-#define ENSRFILE 173 /* Error reading file */
-#define ENSRNOMEM 174 /* Out of memory */
-#define ENSRDESTRUCTION 175 /* Application terminated lookup */
-#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
-#define ENSRCNAMELOOP 177 /* Domain name is too long */
-
-#ifndef errno
-extern int errno;
-#endif
-
-#endif /* LWIP_PROVIDE_ERRNO */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_ARCH_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_DEBUG_H__
-#define __LWIP_DEBUG_H__
-
-#include "lwip/arch.h"
-
-/** lower two bits indicate debug level
- * - 0 all
- * - 1 warning
- * - 2 serious
- * - 3 severe
- */
-#define LWIP_DBG_LEVEL_ALL 0x00
-#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */
-#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */
-#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */
-#define LWIP_DBG_LEVEL_SEVERE 0x03
-#define LWIP_DBG_MASK_LEVEL 0x03
-
-/** flag for LWIP_DEBUGF to enable that debug message */
-#define LWIP_DBG_ON 0x80U
-/** flag for LWIP_DEBUGF to disable that debug message */
-#define LWIP_DBG_OFF 0x00U
-
-/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */
-#define LWIP_DBG_TRACE 0x40U
-/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */
-#define LWIP_DBG_STATE 0x20U
-/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */
-#define LWIP_DBG_FRESH 0x10U
-/** flag for LWIP_DEBUGF to halt after printing this debug message */
-#define LWIP_DBG_HALT 0x08U
-
-#ifndef LWIP_NOASSERT
-#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \
- LWIP_PLATFORM_ASSERT(message); } while(0)
-#else /* LWIP_NOASSERT */
-#define LWIP_ASSERT(message, assertion)
-#endif /* LWIP_NOASSERT */
-
-/** if "expression" isn't true, then print "message" and execute "handler" expression */
-#ifndef LWIP_ERROR
-#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
- LWIP_PLATFORM_ASSERT(message); handler;}} while(0)
-#endif /* LWIP_ERROR */
-
-#ifdef LWIP_DEBUG
-/** print debug message only if debug message type is enabled...
- * AND is of correct type AND is at least LWIP_DBG_LEVEL
- */
-#define LWIP_DEBUGF(debug, message) do { \
- if ( \
- ((debug) & LWIP_DBG_ON) && \
- ((debug) & LWIP_DBG_TYPES_ON) && \
- ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
- LWIP_PLATFORM_DIAG(message); \
- if ((debug) & LWIP_DBG_HALT) { \
- while(1); \
- } \
- } \
- } while(0)
-
-#else /* LWIP_DEBUG */
-#define LWIP_DEBUGF(debug, message)
-#endif /* LWIP_DEBUG */
-
-#endif /* __LWIP_DEBUG_H__ */
-
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_DEF_H__
-#define __LWIP_DEF_H__
-
-/* arch.h might define NULL already */
-#include "lwip/arch.h"
-#include "lwip/opt.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y))
-#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y))
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
-/** Get the absolute difference between 2 u32_t values (correcting overflows)
- * 'a' is expected to be 'higher' (without overflow) than 'b'. */
-#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
-
-/* Endianess-optimized shifting of two u8_t to create one u16_t */
-#if BYTE_ORDER == LITTLE_ENDIAN
-#define LWIP_MAKE_U16(a, b) ((a << 8) | b)
-#else
-#define LWIP_MAKE_U16(a, b) ((b << 8) | a)
-#endif
-
-#ifndef LWIP_PLATFORM_BYTESWAP
-#define LWIP_PLATFORM_BYTESWAP 0
-#endif
-
-#ifndef LWIP_PREFIX_BYTEORDER_FUNCS
-/* workaround for naming collisions on some platforms */
-
-#ifdef htons
-#undef htons
-#endif /* htons */
-#ifdef htonl
-#undef htonl
-#endif /* htonl */
-#ifdef ntohs
-#undef ntohs
-#endif /* ntohs */
-#ifdef ntohl
-#undef ntohl
-#endif /* ntohl */
-
-#define htons(x) lwip_htons(x)
-#define ntohs(x) lwip_ntohs(x)
-#define htonl(x) lwip_htonl(x)
-#define ntohl(x) lwip_ntohl(x)
-#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */
-
-#if BYTE_ORDER == BIG_ENDIAN
-#define lwip_htons(x) (x)
-#define lwip_ntohs(x) (x)
-#define lwip_htonl(x) (x)
-#define lwip_ntohl(x) (x)
-#define PP_HTONS(x) (x)
-#define PP_NTOHS(x) (x)
-#define PP_HTONL(x) (x)
-#define PP_NTOHL(x) (x)
-#else /* BYTE_ORDER != BIG_ENDIAN */
-#if LWIP_PLATFORM_BYTESWAP
-#define lwip_htons(x) LWIP_PLATFORM_HTONS(x)
-#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x)
-#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x)
-#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x)
-#else /* LWIP_PLATFORM_BYTESWAP */
-u16_t lwip_htons(u16_t x);
-u16_t lwip_ntohs(u16_t x);
-u32_t lwip_htonl(u32_t x);
-u32_t lwip_ntohl(u32_t x);
-#endif /* LWIP_PLATFORM_BYTESWAP */
-
-/* These macros should be calculated by the preprocessor and are used
- with compile-time constants only (so that there is no little-endian
- overhead at runtime). */
-#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
-#define PP_NTOHS(x) PP_HTONS(x)
-#define PP_HTONL(x) ((((x) & 0xff) << 24) | \
- (((x) & 0xff00) << 8) | \
- (((x) & 0xff0000UL) >> 8) | \
- (((x) & 0xff000000UL) >> 24))
-#define PP_NTOHL(x) PP_HTONL(x)
-
-#endif /* BYTE_ORDER == BIG_ENDIAN */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_DEF_H__ */
-
+++ /dev/null
-/** @file
- */
-
-#ifndef __LWIP_DHCP_H__
-#define __LWIP_DHCP_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/netif.h"
-#include "lwip/udp.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** period (in seconds) of the application calling dhcp_coarse_tmr() */
-#define DHCP_COARSE_TIMER_SECS 60
-/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */
-#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL)
-/** period (in milliseconds) of the application calling dhcp_fine_tmr() */
-#define DHCP_FINE_TIMER_MSECS 500
-
-#define DHCP_CHADDR_LEN 16U
-#define DHCP_SNAME_LEN 64U
-#define DHCP_FILE_LEN 128U
-
-struct dhcp
-{
- /** transaction identifier of last sent request */
- u32_t xid;
- /** our connection to the DHCP server */
- struct udp_pcb *pcb;
- /** incoming msg */
- struct dhcp_msg *msg_in;
- /** current DHCP state machine state */
- u8_t state;
- /** retries of current request */
- u8_t tries;
-#if LWIP_DHCP_AUTOIP_COOP
- u8_t autoip_coop_state;
-#endif
- u8_t subnet_mask_given;
-
- struct pbuf *p_out; /* pbuf of outcoming msg */
- struct dhcp_msg *msg_out; /* outgoing msg */
- u16_t options_out_len; /* outgoing msg options length */
- u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */
- u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */
- u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */
- ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */
- ip_addr_t offered_ip_addr;
- ip_addr_t offered_sn_mask;
- ip_addr_t offered_gw_addr;
-
- u32_t offered_t0_lease; /* lease period (in seconds) */
- u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */
- u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */
- /* @todo: LWIP_DHCP_BOOTP_FILE configuration option?
- integrate with possible TFTP-client for booting? */
-#if LWIP_DHCP_BOOTP_FILE
- ip_addr_t offered_si_addr;
- char boot_file_name[DHCP_FILE_LEN];
-#endif /* LWIP_DHCP_BOOTPFILE */
-};
-
-/* MUST be compiled with "pack structs" or equivalent! */
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-/** minimum set of fields of any DHCP message */
-struct dhcp_msg
-{
- PACK_STRUCT_FIELD(u8_t op);
- PACK_STRUCT_FIELD(u8_t htype);
- PACK_STRUCT_FIELD(u8_t hlen);
- PACK_STRUCT_FIELD(u8_t hops);
- PACK_STRUCT_FIELD(u32_t xid);
- PACK_STRUCT_FIELD(u16_t secs);
- PACK_STRUCT_FIELD(u16_t flags);
- PACK_STRUCT_FIELD(ip_addr_p_t ciaddr);
- PACK_STRUCT_FIELD(ip_addr_p_t yiaddr);
- PACK_STRUCT_FIELD(ip_addr_p_t siaddr);
- PACK_STRUCT_FIELD(ip_addr_p_t giaddr);
- PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
- PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);
- PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
- PACK_STRUCT_FIELD(u32_t cookie);
-#define DHCP_MIN_OPTIONS_LEN 68U
-/** make sure user does not configure this too small */
-#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))
-# undef DHCP_OPTIONS_LEN
-#endif
-/** allow this to be configured in lwipopts.h, but not too small */
-#if (!defined(DHCP_OPTIONS_LEN))
-/** set this to be sufficient for your options in outgoing DHCP msgs */
-# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN
-#endif
- PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp);
-/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */
-#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0)
-void dhcp_cleanup(struct netif *netif);
-/** start DHCP configuration */
-err_t dhcp_start(struct netif *netif);
-/** enforce early lease renewal (not needed normally)*/
-err_t dhcp_renew(struct netif *netif);
-/** release the DHCP lease, usually called before dhcp_stop()*/
-err_t dhcp_release(struct netif *netif);
-/** stop DHCP configuration */
-void dhcp_stop(struct netif *netif);
-/** inform server of our manual IP address */
-void dhcp_inform(struct netif *netif);
-/** Handle a possible change in the network configuration */
-void dhcp_network_changed(struct netif *netif);
-
-/** if enabled, check whether the offered IP address is not in use, using ARP */
-#if DHCP_DOES_ARP_CHECK
-void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr);
-#endif
-
-/** to be called every minute */
-void dhcp_coarse_tmr(void);
-/** to be called every half second */
-void dhcp_fine_tmr(void);
-
-/** DHCP message item offsets and length */
-#define DHCP_OP_OFS 0
-#define DHCP_HTYPE_OFS 1
-#define DHCP_HLEN_OFS 2
-#define DHCP_HOPS_OFS 3
-#define DHCP_XID_OFS 4
-#define DHCP_SECS_OFS 8
-#define DHCP_FLAGS_OFS 10
-#define DHCP_CIADDR_OFS 12
-#define DHCP_YIADDR_OFS 16
-#define DHCP_SIADDR_OFS 20
-#define DHCP_GIADDR_OFS 24
-#define DHCP_CHADDR_OFS 28
-#define DHCP_SNAME_OFS 44
-#define DHCP_FILE_OFS 108
-#define DHCP_MSG_LEN 236
-
-#define DHCP_COOKIE_OFS DHCP_MSG_LEN
-#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4)
-
-#define DHCP_CLIENT_PORT 68
-#define DHCP_SERVER_PORT 67
-
-/** DHCP client states */
-#define DHCP_OFF 0
-#define DHCP_REQUESTING 1
-#define DHCP_INIT 2
-#define DHCP_REBOOTING 3
-#define DHCP_REBINDING 4
-#define DHCP_RENEWING 5
-#define DHCP_SELECTING 6
-#define DHCP_INFORMING 7
-#define DHCP_CHECKING 8
-#define DHCP_PERMANENT 9
-#define DHCP_BOUND 10
-/** not yet implemented #define DHCP_RELEASING 11 */
-#define DHCP_BACKING_OFF 12
-
-/** AUTOIP cooperatation flags */
-#define DHCP_AUTOIP_COOP_STATE_OFF 0
-#define DHCP_AUTOIP_COOP_STATE_ON 1
-
-#define DHCP_BOOTREQUEST 1
-#define DHCP_BOOTREPLY 2
-
-/** DHCP message types */
-#define DHCP_DISCOVER 1
-#define DHCP_OFFER 2
-#define DHCP_REQUEST 3
-#define DHCP_DECLINE 4
-#define DHCP_ACK 5
-#define DHCP_NAK 6
-#define DHCP_RELEASE 7
-#define DHCP_INFORM 8
-
-/** DHCP hardware type, currently only ethernet is supported */
-#define DHCP_HTYPE_ETH 1
-
-#define DHCP_MAGIC_COOKIE 0x63825363UL
-
-/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */
-
-/** BootP options */
-#define DHCP_OPTION_PAD 0
-#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */
-#define DHCP_OPTION_ROUTER 3
-#define DHCP_OPTION_DNS_SERVER 6
-#define DHCP_OPTION_HOSTNAME 12
-#define DHCP_OPTION_IP_TTL 23
-#define DHCP_OPTION_MTU 26
-#define DHCP_OPTION_BROADCAST 28
-#define DHCP_OPTION_TCP_TTL 37
-#define DHCP_OPTION_END 255
-
-/** DHCP options */
-#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */
-#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */
-#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */
-
-#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
-#define DHCP_OPTION_MESSAGE_TYPE_LEN 1
-
-#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */
-#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */
-
-#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */
-#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2
-
-#define DHCP_OPTION_T1 58 /* T1 renewal time */
-#define DHCP_OPTION_T2 59 /* T2 rebinding time */
-#define DHCP_OPTION_US 60
-#define DHCP_OPTION_CLIENT_ID 61
-#define DHCP_OPTION_TFTP_SERVERNAME 66
-#define DHCP_OPTION_BOOTFILE 67
-
-/** possible combinations of overloading the file and sname fields with options */
-#define DHCP_OVERLOAD_NONE 0
-#define DHCP_OVERLOAD_FILE 1
-#define DHCP_OVERLOAD_SNAME 2
-#define DHCP_OVERLOAD_SNAME_FILE 3
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_DHCP */
-
-#endif /*__LWIP_DHCP_H__*/
+++ /dev/null
-/**
- * lwip DNS resolver header file.
-
- * Author: Jim Pettinato
- * April 2007
-
- * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __LWIP_DNS_H__
-#define __LWIP_DNS_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** DNS timer period */
-#define DNS_TMR_INTERVAL 1000
-
-/** DNS field TYPE used for "Resource Records" */
-#define DNS_RRTYPE_A 1 /* a host address */
-#define DNS_RRTYPE_NS 2 /* an authoritative name server */
-#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */
-#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */
-#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */
-#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */
-#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */
-#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */
-#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */
-#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */
-#define DNS_RRTYPE_WKS 11 /* a well known service description */
-#define DNS_RRTYPE_PTR 12 /* a domain name pointer */
-#define DNS_RRTYPE_HINFO 13 /* host information */
-#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */
-#define DNS_RRTYPE_MX 15 /* mail exchange */
-#define DNS_RRTYPE_TXT 16 /* text strings */
-
-/** DNS field CLASS used for "Resource Records" */
-#define DNS_RRCLASS_IN 1 /* the Internet */
-#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
-#define DNS_RRCLASS_CH 3 /* the CHAOS class */
-#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */
-#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */
-
-/* The size used for the next line is rather a hack, but it prevents including socket.h in all files
- that include memp.h, and that would possibly break portability (since socket.h defines some types
- and constants possibly already define by the OS).
- Calculation rule:
- sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */
-#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1)
-
-#if DNS_LOCAL_HOSTLIST
-/** struct used for local host-list */
-struct local_hostlist_entry {
- /** static hostname */
- const char *name;
- /** static host address in network byteorder */
- ip_addr_t addr;
- struct local_hostlist_entry *next;
-};
-#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
-#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN
-#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH
-#endif
-#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1))
-#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
-#endif /* DNS_LOCAL_HOSTLIST */
-
-/** Callback which is invoked when a hostname is found.
- * A function of this type must be implemented by the application using the DNS resolver.
- * @param name pointer to the name that was looked up.
- * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname,
- * or NULL if the name could not be found (or on any other error).
- * @param callback_arg a user-specified callback argument passed to dns_gethostbyname
-*/
-typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);
-
-void dns_init(void);
-void dns_tmr(void);
-void dns_setserver(u8_t numdns, ip_addr_t *dnsserver);
-ip_addr_t dns_getserver(u8_t numdns);
-err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr,
- dns_found_callback found, void *callback_arg);
-
-#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
-int dns_local_removehost(const char *hostname, const ip_addr_t *addr);
-err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr);
-#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_DNS */
-
-#endif /* __LWIP_DNS_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_ERR_H__
-#define __LWIP_ERR_H__
-
-#include "lwip/opt.h"
-#include "lwip/arch.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** Define LWIP_ERR_T in cc.h if you want to use
- * a different type for your platform (must be signed). */
-#ifdef LWIP_ERR_T
-typedef LWIP_ERR_T err_t;
-#else /* LWIP_ERR_T */
-typedef s8_t err_t;
-#endif /* LWIP_ERR_T*/
-
-/* Definitions for error constants. */
-
-#define ERR_OK 0 /* No error, everything OK. */
-#define ERR_MEM -1 /* Out of memory error. */
-#define ERR_BUF -2 /* Buffer error. */
-#define ERR_TIMEOUT -3 /* Timeout. */
-#define ERR_RTE -4 /* Routing problem. */
-#define ERR_INPROGRESS -5 /* Operation in progress */
-#define ERR_VAL -6 /* Illegal value. */
-#define ERR_WOULDBLOCK -7 /* Operation would block. */
-#define ERR_USE -8 /* Address in use. */
-#define ERR_ISCONN -9 /* Already connected. */
-
-#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN)
-
-#define ERR_ABRT -10 /* Connection aborted. */
-#define ERR_RST -11 /* Connection reset. */
-#define ERR_CLSD -12 /* Connection closed. */
-#define ERR_CONN -13 /* Not connected. */
-
-#define ERR_ARG -14 /* Illegal argument. */
-
-#define ERR_IF -15 /* Low-level netif error */
-
-
-#ifdef LWIP_DEBUG
-extern const char *lwip_strerr(err_t err);
-#else
-#define lwip_strerr(x) ""
-#endif /* LWIP_DEBUG */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_ERR_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_INIT_H__
-#define __LWIP_INIT_H__
-
-#include "lwip/opt.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** X.x.x: Major version of the stack */
-#define LWIP_VERSION_MAJOR 1U
-/** x.X.x: Minor version of the stack */
-#define LWIP_VERSION_MINOR 4U
-/** x.x.X: Revision of the stack */
-#define LWIP_VERSION_REVISION 0U
-/** For release candidates, this is set to 1..254
- * For official releases, this is set to 255 (LWIP_RC_RELEASE)
- * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */
-#define LWIP_VERSION_RC 255U
-
-/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */
-#define LWIP_RC_RELEASE 255U
-/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */
-#define LWIP_RC_DEVELOPMENT 0U
-
-#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE)
-#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT)
-#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT))
-
-/** Provides the version of the stack */
-#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \
- LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC)
-
-/* Modules initialization */
-void lwip_init(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_INIT_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_MEM_H__
-#define __LWIP_MEM_H__
-
-#include "lwip/opt.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if MEM_LIBC_MALLOC
-
-#include <stddef.h> /* for size_t */
-
-typedef size_t mem_size_t;
-
-/* aliases for C library malloc() */
-#define mem_init()
-/* in case C library malloc() needs extra protection,
- * allow these defines to be overridden.
- */
-#ifndef mem_free
-#define mem_free free
-#endif
-#ifndef mem_malloc
-#define mem_malloc malloc
-#endif
-#ifndef mem_calloc
-#define mem_calloc calloc
-#endif
-/* Since there is no C library allocation function to shrink memory without
- moving it, define this to nothing. */
-#ifndef mem_trim
-#define mem_trim(mem, size) (mem)
-#endif
-#else /* MEM_LIBC_MALLOC */
-
-/* MEM_SIZE would have to be aligned, but using 64000 here instead of
- * 65535 leaves some room for alignment...
- */
-#if MEM_SIZE > 64000L
-typedef u32_t mem_size_t;
-#define MEM_SIZE_F U32_F
-#else
-typedef u16_t mem_size_t;
-#define MEM_SIZE_F U16_F
-#endif /* MEM_SIZE > 64000 */
-
-#if MEM_USE_POOLS
-/** mem_init is not used when using pools instead of a heap */
-#define mem_init()
-/** mem_trim is not used when using pools instead of a heap:
- we can't free part of a pool element and don't want to copy the rest */
-#define mem_trim(mem, size) (mem)
-#else /* MEM_USE_POOLS */
-/* lwIP alternative malloc */
-void mem_init(void);
-void *mem_trim(void *mem, mem_size_t size);
-#endif /* MEM_USE_POOLS */
-void *mem_malloc(mem_size_t size);
-void *mem_calloc(mem_size_t count, mem_size_t size);
-void mem_free(void *mem);
-#endif /* MEM_LIBC_MALLOC */
-
-/** Calculate memory size for an aligned buffer - returns the next highest
- * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and
- * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4).
- */
-#ifndef LWIP_MEM_ALIGN_SIZE
-#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))
-#endif
-
-/** Calculate safe memory size for an aligned buffer when using an unaligned
- * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the
- * start (e.g. if buffer is u8_t[] and actual data will be u32_t*)
- */
-#ifndef LWIP_MEM_ALIGN_BUFFER
-#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1))
-#endif
-
-/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT
- * so that ADDR % MEM_ALIGNMENT == 0
- */
-#ifndef LWIP_MEM_ALIGN
-#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_MEM_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#ifndef __LWIP_MEMP_H__
-#define __LWIP_MEMP_H__
-
-#include "lwip/opt.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */
-typedef enum {
-#define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name,
-#include "lwip/memp_std.h"
- MEMP_MAX
-} memp_t;
-
-#if MEM_USE_POOLS
-/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */
-typedef enum {
- /* Get the first (via:
- MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/
- MEMP_POOL_HELPER_FIRST = ((u8_t)
-#define LWIP_MEMPOOL(name,num,size,desc)
-#define LWIP_MALLOC_MEMPOOL_START 1
-#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0
-#define LWIP_MALLOC_MEMPOOL_END
-#include "lwip/memp_std.h"
- ) ,
- /* Get the last (via:
- MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */
- MEMP_POOL_HELPER_LAST = ((u8_t)
-#define LWIP_MEMPOOL(name,num,size,desc)
-#define LWIP_MALLOC_MEMPOOL_START
-#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size *
-#define LWIP_MALLOC_MEMPOOL_END 1
-#include "lwip/memp_std.h"
- )
-} memp_pool_helper_t;
-
-/* The actual start and stop values are here (cast them over)
- We use this helper type and these defines so we can avoid using const memp_t values */
-#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST)
-#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST)
-#endif /* MEM_USE_POOLS */
-
-#if MEMP_MEM_MALLOC || MEM_USE_POOLS
-extern const u16_t memp_sizes[MEMP_MAX];
-#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */
-
-#if MEMP_MEM_MALLOC
-
-#include "mem.h"
-
-#define memp_init()
-#define memp_malloc(type) mem_malloc(memp_sizes[type])
-#define memp_free(type, mem) mem_free(mem)
-
-#else /* MEMP_MEM_MALLOC */
-
-#if MEM_USE_POOLS
-/** This structure is used to save the pool one element came from. */
-struct memp_malloc_helper
-{
- memp_t poolnr;
-};
-#endif /* MEM_USE_POOLS */
-
-void memp_init(void);
-
-#if MEMP_OVERFLOW_CHECK
-void *memp_malloc_fn(memp_t type, const char* file, const int line);
-#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__)
-#else
-void *memp_malloc(memp_t type);
-#endif
-void memp_free(memp_t type, void *mem);
-
-#endif /* MEMP_MEM_MALLOC */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_MEMP_H__ */
+++ /dev/null
-/*
- * SETUP: Make sure we define everything we will need.
- *
- * We have create three types of pools:
- * 1) MEMPOOL - standard pools
- * 2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c
- * 3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct
- *
- * If the include'r doesn't require any special treatment of each of the types
- * above, then will declare #2 & #3 to be just standard mempools.
- */
-#ifndef LWIP_MALLOC_MEMPOOL
-/* This treats "malloc pools" just like any other pool.
- The pools are a little bigger to provide 'size' as the amount of user data. */
-#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size)
-#define LWIP_MALLOC_MEMPOOL_START
-#define LWIP_MALLOC_MEMPOOL_END
-#endif /* LWIP_MALLOC_MEMPOOL */
-
-#ifndef LWIP_PBUF_MEMPOOL
-/* This treats "pbuf pools" just like any other pool.
- * Allocates buffers for a pbuf struct AND a payload size */
-#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc)
-#endif /* LWIP_PBUF_MEMPOOL */
-
-
-/*
- * A list of internal pools used by LWIP.
- *
- * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description)
- * creates a pool name MEMP_pool_name. description is used in stats.c
- */
-#if LWIP_RAW
-LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB")
-#endif /* LWIP_RAW */
-
-#if LWIP_UDP
-LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB")
-#endif /* LWIP_UDP */
-
-#if LWIP_TCP
-LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB")
-LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN")
-LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG")
-#endif /* LWIP_TCP */
-
-#if IP_REASSEMBLY
-LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA")
-#endif /* IP_REASSEMBLY */
-#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
-LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF")
-#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
-
-#if LWIP_NETCONN
-LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF")
-LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN")
-#endif /* LWIP_NETCONN */
-
-#if NO_SYS==0
-LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API")
-#if !LWIP_TCPIP_CORE_LOCKING_INPUT
-LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT")
-#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
-#endif /* NO_SYS==0 */
-
-#if ARP_QUEUEING
-LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE")
-#endif /* ARP_QUEUEING */
-
-#if LWIP_IGMP
-LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP")
-#endif /* LWIP_IGMP */
-
-#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */
-LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT")
-#endif /* LWIP_TIMERS */
-
-#if LWIP_SNMP
-LWIP_MEMPOOL(SNMP_ROOTNODE, MEMP_NUM_SNMP_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE")
-LWIP_MEMPOOL(SNMP_NODE, MEMP_NUM_SNMP_NODE, sizeof(struct mib_list_node), "SNMP_NODE")
-LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbind), "SNMP_VARBIND")
-LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE")
-#endif /* LWIP_SNMP */
-#if LWIP_DNS && LWIP_SOCKET
-LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB")
-#endif /* LWIP_DNS && LWIP_SOCKET */
-#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
-LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST")
-#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
-#if PPP_SUPPORT && PPPOE_SUPPORT
-LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF")
-#endif /* PPP_SUPPORT && PPPOE_SUPPORT */
-
-/*
- * A list of pools of pbuf's used by LWIP.
- *
- * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description)
- * creates a pool name MEMP_pool_name. description is used in stats.c
- * This allocates enough space for the pbuf struct and a payload.
- * (Example: pbuf_payload_size=0 allocates only size for the struct)
- */
-LWIP_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "PBUF_REF/ROM")
-LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, PBUF_POOL_BUFSIZE, "PBUF_POOL")
-
-
-/*
- * Allow for user-defined pools; this must be explicitly set in lwipopts.h
- * since the default is to NOT look for lwippools.h
- */
-#if MEMP_USE_CUSTOM_POOLS
-#include "lwippools.h"
-#endif /* MEMP_USE_CUSTOM_POOLS */
-
-/*
- * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later
- * (#undef is ignored for something that is not defined)
- */
-#undef LWIP_MEMPOOL
-#undef LWIP_MALLOC_MEMPOOL
-#undef LWIP_MALLOC_MEMPOOL_START
-#undef LWIP_MALLOC_MEMPOOL_END
-#undef LWIP_PBUF_MEMPOOL
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_NETBUF_H__
-#define __LWIP_NETBUF_H__
-
-#include "lwip/opt.h"
-#include "lwip/pbuf.h"
-#include "lwip/ip_addr.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** This netbuf has dest-addr/port set */
-#define NETBUF_FLAG_DESTADDR 0x01
-/** This netbuf includes a checksum */
-#define NETBUF_FLAG_CHKSUM 0x02
-
-struct netbuf {
- struct pbuf *p, *ptr;
- ip_addr_t addr;
- u16_t port;
-#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
-#if LWIP_CHECKSUM_ON_COPY
- u8_t flags;
-#endif /* LWIP_CHECKSUM_ON_COPY */
- u16_t toport_chksum;
-#if LWIP_NETBUF_RECVINFO
- ip_addr_t toaddr;
-#endif /* LWIP_NETBUF_RECVINFO */
-#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
-};
-
-/* Network buffer functions: */
-struct netbuf * netbuf_new (void);
-void netbuf_delete (struct netbuf *buf);
-void * netbuf_alloc (struct netbuf *buf, u16_t size);
-void netbuf_free (struct netbuf *buf);
-err_t netbuf_ref (struct netbuf *buf,
- const void *dataptr, u16_t size);
-void netbuf_chain (struct netbuf *head,
- struct netbuf *tail);
-
-err_t netbuf_data (struct netbuf *buf,
- void **dataptr, u16_t *len);
-s8_t netbuf_next (struct netbuf *buf);
-void netbuf_first (struct netbuf *buf);
-
-
-#define netbuf_copy_partial(buf, dataptr, len, offset) \
- pbuf_copy_partial((buf)->p, (dataptr), (len), (offset))
-#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)
-#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len)
-#define netbuf_len(buf) ((buf)->p->tot_len)
-#define netbuf_fromaddr(buf) (&((buf)->addr))
-#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr), fromaddr)
-#define netbuf_fromport(buf) ((buf)->port)
-#if LWIP_NETBUF_RECVINFO
-#define netbuf_destaddr(buf) (&((buf)->toaddr))
-#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->addr), destaddr)
-#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0)
-#endif /* LWIP_NETBUF_RECVINFO */
-#if LWIP_CHECKSUM_ON_COPY
-#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \
- (buf)->toport_chksum = chksum; } while(0)
-#endif /* LWIP_CHECKSUM_ON_COPY */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_NETBUF_H__ */
+++ /dev/null
-/*
- * 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
- *
- */
-#ifndef __LWIP_NETDB_H__
-#define __LWIP_NETDB_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_DNS && LWIP_SOCKET
-
-#include <stddef.h> /* for size_t */
-
-#include "lwip/inet.h"
-#include "lwip/sockets.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* some rarely used options */
-#ifndef LWIP_DNS_API_DECLARE_H_ERRNO
-#define LWIP_DNS_API_DECLARE_H_ERRNO 1
-#endif
-
-#ifndef LWIP_DNS_API_DEFINE_ERRORS
-#define LWIP_DNS_API_DEFINE_ERRORS 1
-#endif
-
-#ifndef LWIP_DNS_API_DECLARE_STRUCTS
-#define LWIP_DNS_API_DECLARE_STRUCTS 1
-#endif
-
-#if LWIP_DNS_API_DEFINE_ERRORS
-/** Errors used by the DNS API functions, h_errno can be one of them */
-#define EAI_NONAME 200
-#define EAI_SERVICE 201
-#define EAI_FAIL 202
-#define EAI_MEMORY 203
-
-#define HOST_NOT_FOUND 210
-#define NO_DATA 211
-#define NO_RECOVERY 212
-#define TRY_AGAIN 213
-#endif /* LWIP_DNS_API_DEFINE_ERRORS */
-
-#if LWIP_DNS_API_DECLARE_STRUCTS
-struct hostent {
- char *h_name; /* Official name of the host. */
- char **h_aliases; /* A pointer to an array of pointers to alternative host names,
- terminated by a null pointer. */
- int h_addrtype; /* Address type. */
- int h_length; /* The length, in bytes, of the address. */
- char **h_addr_list; /* A pointer to an array of pointers to network addresses (in
- network byte order) for the host, terminated by a null pointer. */
-#define h_addr h_addr_list[0] /* for backward compatibility */
-};
-
-struct addrinfo {
- int ai_flags; /* Input flags. */
- int ai_family; /* Address family of socket. */
- int ai_socktype; /* Socket type. */
- int ai_protocol; /* Protocol of socket. */
- socklen_t ai_addrlen; /* Length of socket address. */
- struct sockaddr *ai_addr; /* Socket address of socket. */
- char *ai_canonname; /* Canonical name of service location. */
- struct addrinfo *ai_next; /* Pointer to next in list. */
-};
-#endif /* LWIP_DNS_API_DECLARE_STRUCTS */
-
-#if LWIP_DNS_API_DECLARE_H_ERRNO
-/* application accessable error code set by the DNS API functions */
-extern int h_errno;
-#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/
-
-struct hostent *lwip_gethostbyname(const char *name);
-int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
- size_t buflen, struct hostent **result, int *h_errnop);
-void lwip_freeaddrinfo(struct addrinfo *ai);
-int lwip_getaddrinfo(const char *nodename,
- const char *servname,
- const struct addrinfo *hints,
- struct addrinfo **res);
-
-#if LWIP_COMPAT_SOCKETS
-#define gethostbyname(name) lwip_gethostbyname(name)
-#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \
- lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)
-#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo)
-#define getaddrinfo(nodname, servname, hints, res) \
- lwip_getaddrinfo(nodname, servname, hints, res)
-#endif /* LWIP_COMPAT_SOCKETS */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_DNS && LWIP_SOCKET */
-
-#endif /* __LWIP_NETDB_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_NETIF_H__
-#define __LWIP_NETIF_H__
-
-#include "lwip/opt.h"
-
-#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
-
-#include "lwip/err.h"
-
-#include "lwip/ip_addr.h"
-
-#include "lwip/def.h"
-#include "lwip/pbuf.h"
-#if LWIP_DHCP
-struct dhcp;
-#endif
-#if LWIP_AUTOIP
-struct autoip;
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Throughout this file, IP addresses are expected to be in
- * the same byte order as in IP_PCB. */
-
-/** must be the maximum of all used hardware address lengths
- across all types of interfaces in use */
-#define NETIF_MAX_HWADDR_LEN 6U
-
-/** Whether the network interface is 'up'. This is
- * a software flag used to control whether this network
- * interface is enabled and processes traffic.
- * It is set by the startup code (for static IP configuration) or
- * by dhcp/autoip when an address has been assigned.
- */
-#define NETIF_FLAG_UP 0x01U
-/** If set, the netif has broadcast capability.
- * Set by the netif driver in its init function. */
-#define NETIF_FLAG_BROADCAST 0x02U
-/** If set, the netif is one end of a point-to-point connection.
- * Set by the netif driver in its init function. */
-#define NETIF_FLAG_POINTTOPOINT 0x04U
-/** If set, the interface is configured using DHCP.
- * Set by the DHCP code when starting or stopping DHCP. */
-#define NETIF_FLAG_DHCP 0x08U
-/** If set, the interface has an active link
- * (set by the network interface driver).
- * Either set by the netif driver in its init function (if the link
- * is up at that time) or at a later point once the link comes up
- * (if link detection is supported by the hardware). */
-#define NETIF_FLAG_LINK_UP 0x10U
-/** If set, the netif is an ethernet device using ARP.
- * Set by the netif driver in its init function.
- * Used to check input packet types and use of DHCP. */
-#define NETIF_FLAG_ETHARP 0x20U
-/** If set, the netif is an ethernet device. It might not use
- * ARP or TCP/IP if it is used for PPPoE only.
- */
-#define NETIF_FLAG_ETHERNET 0x40U
-/** If set, the netif has IGMP capability.
- * Set by the netif driver in its init function. */
-#define NETIF_FLAG_IGMP 0x80U
-
-/** Function prototype for netif init functions. Set up flags and output/linkoutput
- * callback functions in this function.
- *
- * @param netif The netif to initialize
- */
-typedef err_t (*netif_init_fn)(struct netif *netif);
-/** Function prototype for netif->input functions. This function is saved as 'input'
- * callback function in the netif struct. Call it when a packet has been received.
- *
- * @param p The received packet, copied into a pbuf
- * @param inp The netif which received the packet
- */
-typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp);
-/** Function prototype for netif->output functions. Called by lwIP when a packet
- * shall be sent. For ethernet netif, set this to 'etharp_output' and set
- * 'linkoutput'.
- *
- * @param netif The netif which shall send a packet
- * @param p The packet to send (p->payload points to IP header)
- * @param ipaddr The IP address to which the packet shall be sent
- */
-typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p,
- ip_addr_t *ipaddr);
-/** Function prototype for netif->linkoutput functions. Only used for ethernet
- * netifs. This function is called by ARP when a packet shall be sent.
- *
- * @param netif The netif which shall send a packet
- * @param p The packet to send (raw ethernet packet)
- */
-typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p);
-/** Function prototype for netif status- or link-callback functions. */
-typedef void (*netif_status_callback_fn)(struct netif *netif);
-/** Function prototype for netif igmp_mac_filter functions */
-typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,
- ip_addr_t *group, u8_t action);
-
-/** Generic data structure used for all lwIP network interfaces.
- * The following fields should be filled in by the initialization
- * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
-struct netif {
- /** pointer to next in linked list */
- struct netif *next;
-
- /** IP address configuration in network byte order */
- ip_addr_t ip_addr;
- ip_addr_t netmask;
- ip_addr_t gw;
-
- /** This function is called by the network device driver
- * to pass a packet up the TCP/IP stack. */
- netif_input_fn input;
- /** This function is called by the IP module when it wants
- * to send a packet on the interface. This function typically
- * first resolves the hardware address, then sends the packet. */
- netif_output_fn output;
- /** This function is called by the ARP module when it wants
- * to send a packet on the interface. This function outputs
- * the pbuf as-is on the link medium. */
- netif_linkoutput_fn linkoutput;
-#if LWIP_NETIF_STATUS_CALLBACK
- /** This function is called when the netif state is set to up or down
- */
- netif_status_callback_fn status_callback;
-#endif /* LWIP_NETIF_STATUS_CALLBACK */
-#if LWIP_NETIF_LINK_CALLBACK
- /** This function is called when the netif link is set to up or down
- */
- netif_status_callback_fn link_callback;
-#endif /* LWIP_NETIF_LINK_CALLBACK */
- /** This field can be set by the device driver and could point
- * to state information for the device. */
- void *state;
-#if LWIP_DHCP
- /** the DHCP client state information for this netif */
- struct dhcp *dhcp;
-#endif /* LWIP_DHCP */
-#if LWIP_AUTOIP
- /** the AutoIP client state information for this netif */
- struct autoip *autoip;
-#endif
-#if LWIP_NETIF_HOSTNAME
- /* the hostname for this netif, NULL is a valid value */
- char* hostname;
-#endif /* LWIP_NETIF_HOSTNAME */
- /** maximum transfer unit (in bytes) */
- u16_t mtu;
- /** number of bytes used in hwaddr */
- u8_t hwaddr_len;
- /** link level hardware address of this interface */
- u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
- /** flags (see NETIF_FLAG_ above) */
- u8_t flags;
- /** descriptive abbreviation */
- char name[2];
- /** number of this interface */
- u8_t num;
-#if LWIP_SNMP
- /** link type (from "snmp_ifType" enum from snmp.h) */
- u8_t link_type;
- /** (estimate) link speed */
- u32_t link_speed;
- /** timestamp at last change made (up/down) */
- u32_t ts;
- /** counters */
- u32_t ifinoctets;
- u32_t ifinucastpkts;
- u32_t ifinnucastpkts;
- u32_t ifindiscards;
- u32_t ifoutoctets;
- u32_t ifoutucastpkts;
- u32_t ifoutnucastpkts;
- u32_t ifoutdiscards;
-#endif /* LWIP_SNMP */
-#if LWIP_IGMP
- /** This function could be called to add or delete a entry in the multicast
- filter table of the ethernet MAC.*/
- netif_igmp_mac_filter_fn igmp_mac_filter;
-#endif /* LWIP_IGMP */
-#if LWIP_NETIF_HWADDRHINT
- u8_t *addr_hint;
-#endif /* LWIP_NETIF_HWADDRHINT */
-#if ENABLE_LOOPBACK
- /* List of packets to be queued for ourselves. */
- struct pbuf *loop_first;
- struct pbuf *loop_last;
-#if LWIP_LOOPBACK_MAX_PBUFS
- u16_t loop_cnt_current;
-#endif /* LWIP_LOOPBACK_MAX_PBUFS */
-#endif /* ENABLE_LOOPBACK */
-};
-
-#if LWIP_SNMP
-#define NETIF_INIT_SNMP(netif, type, speed) \
- /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \
- (netif)->link_type = (type); \
- /* your link speed here (units: bits per second) */ \
- (netif)->link_speed = (speed); \
- (netif)->ts = 0; \
- (netif)->ifinoctets = 0; \
- (netif)->ifinucastpkts = 0; \
- (netif)->ifinnucastpkts = 0; \
- (netif)->ifindiscards = 0; \
- (netif)->ifoutoctets = 0; \
- (netif)->ifoutucastpkts = 0; \
- (netif)->ifoutnucastpkts = 0; \
- (netif)->ifoutdiscards = 0
-#else /* LWIP_SNMP */
-#define NETIF_INIT_SNMP(netif, type, speed)
-#endif /* LWIP_SNMP */
-
-
-/** The list of network interfaces. */
-extern struct netif *netif_list;
-/** The default network interface. */
-extern struct netif *netif_default;
-
-void netif_init(void);
-
-struct netif *netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
- ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input);
-
-void
-netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
- ip_addr_t *gw);
-void netif_remove(struct netif * netif);
-
-/* Returns a network interface given its name. The name is of the form
- "et0", where the first two letters are the "name" field in the
- netif structure, and the digit is in the num field in the same
- structure. */
-struct netif *netif_find(char *name);
-
-void netif_set_default(struct netif *netif);
-
-void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr);
-void netif_set_netmask(struct netif *netif, ip_addr_t *netmask);
-void netif_set_gw(struct netif *netif, ip_addr_t *gw);
-
-void netif_set_up(struct netif *netif);
-void netif_set_down(struct netif *netif);
-/** Ask if an interface is up */
-#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0)
-
-#if LWIP_NETIF_STATUS_CALLBACK
-void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback);
-#endif /* LWIP_NETIF_STATUS_CALLBACK */
-
-void netif_set_link_up(struct netif *netif);
-void netif_set_link_down(struct netif *netif);
-/** Ask if a link is up */
-#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0)
-
-#if LWIP_NETIF_LINK_CALLBACK
-void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback);
-#endif /* LWIP_NETIF_LINK_CALLBACK */
-
-#if LWIP_NETIF_HOSTNAME
-#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0)
-#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL)
-#endif /* LWIP_NETIF_HOSTNAME */
-
-#if LWIP_IGMP
-#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0)
-#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL)
-#endif /* LWIP_IGMP */
-
-#if ENABLE_LOOPBACK
-err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip);
-void netif_poll(struct netif *netif);
-#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
-void netif_poll_all(void);
-#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
-#endif /* ENABLE_LOOPBACK */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_NETIF_H__ */
+++ /dev/null
-/*
- * 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.
- *
- */
-
-#ifndef __LWIP_NETIFAPI_H__
-#define __LWIP_NETIFAPI_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/sys.h"
-#include "lwip/netif.h"
-#include "lwip/dhcp.h"
-#include "lwip/autoip.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void (*netifapi_void_fn)(struct netif *netif);
-typedef err_t (*netifapi_errt_fn)(struct netif *netif);
-
-struct netifapi_msg_msg {
-#if !LWIP_TCPIP_CORE_LOCKING
- sys_sem_t sem;
-#endif /* !LWIP_TCPIP_CORE_LOCKING */
- err_t err;
- struct netif *netif;
- union {
- struct {
- ip_addr_t *ipaddr;
- ip_addr_t *netmask;
- ip_addr_t *gw;
- void *state;
- netif_init_fn init;
- netif_input_fn input;
- } add;
- struct {
- netifapi_void_fn voidfunc;
- netifapi_errt_fn errtfunc;
- } common;
- } msg;
-};
-
-struct netifapi_msg {
- void (* function)(struct netifapi_msg_msg *msg);
- struct netifapi_msg_msg msg;
-};
-
-
-/* API for application */
-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);
-
-err_t netifapi_netif_set_addr ( struct netif *netif,
- ip_addr_t *ipaddr,
- ip_addr_t *netmask,
- ip_addr_t *gw );
-
-err_t netifapi_netif_common ( struct netif *netif,
- netifapi_void_fn voidfunc,
- netifapi_errt_fn errtfunc);
-
-#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL)
-#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL)
-#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL)
-#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL)
-#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start)
-#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL)
-#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start)
-#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_NETIF_API */
-
-#endif /* __LWIP_NETIFAPI_H__ */
+++ /dev/null
-/**
- * @file
- *
- * lwIP Options Configuration
- */
-
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_OPT_H__
-#define __LWIP_OPT_H__
-
-/*
- * Include user defined options first. Anything not defined in these files
- * will be set to standard values. Override anything you dont like!
- */
-#include "lwipopts.h"
-#include "lwip/debug.h"
-
-/*
- -----------------------------------------------
- ---------- Platform specific locking ----------
- -----------------------------------------------
-*/
-
-/**
- * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain
- * critical regions during buffer allocation, deallocation and memory
- * allocation and deallocation.
- */
-#ifndef SYS_LIGHTWEIGHT_PROT
-#define SYS_LIGHTWEIGHT_PROT 0
-#endif
-
-/**
- * NO_SYS==1: Provides VERY minimal functionality. Otherwise,
- * use lwIP facilities.
- */
-#ifndef NO_SYS
-#define NO_SYS 0
-#endif
-
-/**
- * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1
- * Mainly for compatibility to old versions.
- */
-#ifndef NO_SYS_NO_TIMERS
-#define NO_SYS_NO_TIMERS 0
-#endif
-
-/**
- * MEMCPY: override this if you have a faster implementation at hand than the
- * one included in your C library
- */
-#ifndef MEMCPY
-#define MEMCPY(dst,src,len) memcpy(dst,src,len)
-#endif
-
-/**
- * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a
- * call to memcpy() if the length is known at compile time and is small.
- */
-#ifndef SMEMCPY
-#define SMEMCPY(dst,src,len) memcpy(dst,src,len)
-#endif
-
-/*
- ------------------------------------
- ---------- Memory options ----------
- ------------------------------------
-*/
-/**
- * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library
- * instead of the lwip internal allocator. Can save code size if you
- * already use it.
- */
-#ifndef MEM_LIBC_MALLOC
-#define MEM_LIBC_MALLOC 0
-#endif
-
-/**
-* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator.
-* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution
-* speed and usage from interrupts!
-*/
-#ifndef MEMP_MEM_MALLOC
-#define MEMP_MEM_MALLOC 0
-#endif
-
-/**
- * MEM_ALIGNMENT: should be set to the alignment of the CPU
- * 4 byte alignment -> #define MEM_ALIGNMENT 4
- * 2 byte alignment -> #define MEM_ALIGNMENT 2
- */
-#ifndef MEM_ALIGNMENT
-#define MEM_ALIGNMENT 1
-#endif
-
-/**
- * MEM_SIZE: the size of the heap memory. If the application will send
- * a lot of data that needs to be copied, this should be set high.
- */
-#ifndef MEM_SIZE
-#define MEM_SIZE 1600
-#endif
-
-/**
- * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array.
- * This can be used to individually change the location of each pool.
- * Default is one big array for all pools
- */
-#ifndef MEMP_SEPARATE_POOLS
-#define MEMP_SEPARATE_POOLS 0
-#endif
-
-/**
- * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable
- * amount of bytes before and after each memp element in every pool and fills
- * it with a prominent default value.
- * MEMP_OVERFLOW_CHECK == 0 no checking
- * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed
- * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time
- * memp_malloc() or memp_free() is called (useful but slow!)
- */
-#ifndef MEMP_OVERFLOW_CHECK
-#define MEMP_OVERFLOW_CHECK 0
-#endif
-
-/**
- * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make
- * sure that there are no cycles in the linked lists.
- */
-#ifndef MEMP_SANITY_CHECK
-#define MEMP_SANITY_CHECK 0
-#endif
-
-/**
- * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set
- * of memory pools of various sizes. When mem_malloc is called, an element of
- * the smallest pool that can provide the length needed is returned.
- * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled.
- */
-#ifndef MEM_USE_POOLS
-#define MEM_USE_POOLS 0
-#endif
-
-/**
- * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next
- * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more
- * reliable. */
-#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL
-#define MEM_USE_POOLS_TRY_BIGGER_POOL 0
-#endif
-
-/**
- * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h
- * that defines additional pools beyond the "standard" ones required
- * by lwIP. If you set this to 1, you must have lwippools.h in your
- * inlude path somewhere.
- */
-#ifndef MEMP_USE_CUSTOM_POOLS
-#define MEMP_USE_CUSTOM_POOLS 0
-#endif
-
-/**
- * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from
- * interrupt context (or another context that doesn't allow waiting for a
- * semaphore).
- * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT,
- * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs
- * with each loop so that mem_free can run.
- *
- * ATTENTION: As you can see from the above description, this leads to dis-/
- * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc
- * can need longer.
- *
- * If you don't want that, at least for NO_SYS=0, you can still use the following
- * functions to enqueue a deallocation call which then runs in the tcpip_thread
- * context:
- * - pbuf_free_callback(p);
- * - mem_free_callback(m);
- */
-#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
-#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0
-#endif
-
-/*
- ------------------------------------------------
- ---------- Internal Memory Pool Sizes ----------
- ------------------------------------------------
-*/
-/**
- * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF).
- * If the application sends a lot of data out of ROM (or other static memory),
- * this should be set high.
- */
-#ifndef MEMP_NUM_PBUF
-#define MEMP_NUM_PBUF 16
-#endif
-
-/**
- * MEMP_NUM_RAW_PCB: Number of raw connection PCBs
- * (requires the LWIP_RAW option)
- */
-#ifndef MEMP_NUM_RAW_PCB
-#define MEMP_NUM_RAW_PCB 4
-#endif
-
-/**
- * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
- * per active UDP "connection".
- * (requires the LWIP_UDP option)
- */
-#ifndef MEMP_NUM_UDP_PCB
-#define MEMP_NUM_UDP_PCB 4
-#endif
-
-/**
- * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections.
- * (requires the LWIP_TCP option)
- */
-#ifndef MEMP_NUM_TCP_PCB
-#define MEMP_NUM_TCP_PCB 5
-#endif
-
-/**
- * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections.
- * (requires the LWIP_TCP option)
- */
-#ifndef MEMP_NUM_TCP_PCB_LISTEN
-#define MEMP_NUM_TCP_PCB_LISTEN 8
-#endif
-
-/**
- * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments.
- * (requires the LWIP_TCP option)
- */
-#ifndef MEMP_NUM_TCP_SEG
-#define MEMP_NUM_TCP_SEG 16
-#endif
-
-/**
- * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for
- * reassembly (whole packets, not fragments!)
- */
-#ifndef MEMP_NUM_REASSDATA
-#define MEMP_NUM_REASSDATA 5
-#endif
-
-/**
- * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent
- * (fragments, not whole packets!).
- * This is only used with IP_FRAG_USES_STATIC_BUF==0 and
- * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs
- * where the packet is not yet sent when netif->output returns.
- */
-#ifndef MEMP_NUM_FRAG_PBUF
-#define MEMP_NUM_FRAG_PBUF 15
-#endif
-
-/**
- * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing
- * packets (pbufs) that are waiting for an ARP request (to resolve
- * their destination address) to finish.
- * (requires the ARP_QUEUEING option)
- */
-#ifndef MEMP_NUM_ARP_QUEUE
-#define MEMP_NUM_ARP_QUEUE 30
-#endif
-
-/**
- * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces
- * can be members et the same time (one per netif - allsystems group -, plus one
- * per netif membership).
- * (requires the LWIP_IGMP option)
- */
-#ifndef MEMP_NUM_IGMP_GROUP
-#define MEMP_NUM_IGMP_GROUP 8
-#endif
-
-/**
- * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.
- * (requires NO_SYS==0)
- */
-#ifndef MEMP_NUM_SYS_TIMEOUT
-#define MEMP_NUM_SYS_TIMEOUT 3
-#endif
-
-/**
- * MEMP_NUM_NETBUF: the number of struct netbufs.
- * (only needed if you use the sequential API, like api_lib.c)
- */
-#ifndef MEMP_NUM_NETBUF
-#define MEMP_NUM_NETBUF 2
-#endif
-
-/**
- * MEMP_NUM_NETCONN: the number of struct netconns.
- * (only needed if you use the sequential API, like api_lib.c)
- */
-#ifndef MEMP_NUM_NETCONN
-#define MEMP_NUM_NETCONN 4
-#endif
-
-/**
- * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used
- * for callback/timeout API communication.
- * (only needed if you use tcpip.c)
- */
-#ifndef MEMP_NUM_TCPIP_MSG_API
-#define MEMP_NUM_TCPIP_MSG_API 8
-#endif
-
-/**
- * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used
- * for incoming packets.
- * (only needed if you use tcpip.c)
- */
-#ifndef MEMP_NUM_TCPIP_MSG_INPKT
-#define MEMP_NUM_TCPIP_MSG_INPKT 8
-#endif
-
-/**
- * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree.
- */
-#ifndef MEMP_NUM_SNMP_NODE
-#define MEMP_NUM_SNMP_NODE 50
-#endif
-
-/**
- * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree.
- * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least!
- */
-#ifndef MEMP_NUM_SNMP_ROOTNODE
-#define MEMP_NUM_SNMP_ROOTNODE 30
-#endif
-
-/**
- * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to
- * be changed normally) - 2 of these are used per request (1 for input,
- * 1 for output)
- */
-#ifndef MEMP_NUM_SNMP_VARBIND
-#define MEMP_NUM_SNMP_VARBIND 2
-#endif
-
-/**
- * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used
- * (does not have to be changed normally) - 3 of these are used per request
- * (1 for the value read and 2 for OIDs - input and output)
- */
-#ifndef MEMP_NUM_SNMP_VALUE
-#define MEMP_NUM_SNMP_VALUE 3
-#endif
-
-/**
- * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls
- * (before freeing the corresponding memory using lwip_freeaddrinfo()).
- */
-#ifndef MEMP_NUM_NETDB
-#define MEMP_NUM_NETDB 1
-#endif
-
-/**
- * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list
- * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1.
- */
-#ifndef MEMP_NUM_LOCALHOSTLIST
-#define MEMP_NUM_LOCALHOSTLIST 1
-#endif
-
-/**
- * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE
- * interfaces (only used with PPPOE_SUPPORT==1)
- */
-#ifndef MEMP_NUM_PPPOE_INTERFACES
-#define MEMP_NUM_PPPOE_INTERFACES 1
-#endif
-
-/**
- * PBUF_POOL_SIZE: the number of buffers in the pbuf pool.
- */
-#ifndef PBUF_POOL_SIZE
-#define PBUF_POOL_SIZE 16
-#endif
-
-/*
- ---------------------------------
- ---------- ARP options ----------
- ---------------------------------
-*/
-/**
- * LWIP_ARP==1: Enable ARP functionality.
- */
-#ifndef LWIP_ARP
-#define LWIP_ARP 1
-#endif
-
-/**
- * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached.
- */
-#ifndef ARP_TABLE_SIZE
-#define ARP_TABLE_SIZE 10
-#endif
-
-/**
- * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address
- * resolution. By default, only the most recent packet is queued per IP address.
- * This is sufficient for most protocols and mainly reduces TCP connection
- * startup time. Set this to 1 if you know your application sends more than one
- * packet in a row to an IP address that is not in the ARP cache.
- */
-#ifndef ARP_QUEUEING
-#define ARP_QUEUEING 0
-#endif
-
-/**
- * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be
- * updated with the source MAC and IP addresses supplied in the packet.
- * You may want to disable this if you do not trust LAN peers to have the
- * correct addresses, or as a limited approach to attempt to handle
- * spoofing. If disabled, lwIP will need to make a new ARP request if
- * the peer is not already in the ARP table, adding a little latency.
- * The peer *is* in the ARP table if it requested our address before.
- * Also notice that this slows down input processing of every IP packet!
- */
-#ifndef ETHARP_TRUST_IP_MAC
-#define ETHARP_TRUST_IP_MAC 0
-#endif
-
-/**
- * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header.
- * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check.
- * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted.
- * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted.
- */
-#ifndef ETHARP_SUPPORT_VLAN
-#define ETHARP_SUPPORT_VLAN 0
-#endif
-
-/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP
- * might be disabled
- */
-#ifndef LWIP_ETHERNET
-#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT)
-#endif
-
-/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure
- * alignment of payload after that header. Since the header is 14 bytes long,
- * without this padding e.g. addresses in the IP header will not be aligned
- * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms.
- */
-#ifndef ETH_PAD_SIZE
-#define ETH_PAD_SIZE 0
-#endif
-
-/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table
- * entries (using etharp_add_static_entry/etharp_remove_static_entry).
- */
-#ifndef ETHARP_SUPPORT_STATIC_ENTRIES
-#define ETHARP_SUPPORT_STATIC_ENTRIES 0
-#endif
-
-
-/*
- --------------------------------
- ---------- IP options ----------
- --------------------------------
-*/
-/**
- * IP_FORWARD==1: Enables the ability to forward IP packets across network
- * interfaces. If you are going to run lwIP on a device with only one network
- * interface, define this to 0.
- */
-#ifndef IP_FORWARD
-#define IP_FORWARD 0
-#endif
-
-/**
- * IP_OPTIONS_ALLOWED: Defines the behavior for IP options.
- * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped.
- * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed).
- */
-#ifndef IP_OPTIONS_ALLOWED
-#define IP_OPTIONS_ALLOWED 1
-#endif
-
-/**
- * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that
- * this option does not affect outgoing packet sizes, which can be controlled
- * via IP_FRAG.
- */
-#ifndef IP_REASSEMBLY
-#define IP_REASSEMBLY 1
-#endif
-
-/**
- * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note
- * that this option does not affect incoming packet sizes, which can be
- * controlled via IP_REASSEMBLY.
- */
-#ifndef IP_FRAG
-#define IP_FRAG 1
-#endif
-
-/**
- * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally)
- * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived
- * in this time, the whole packet is discarded.
- */
-#ifndef IP_REASS_MAXAGE
-#define IP_REASS_MAXAGE 3
-#endif
-
-/**
- * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled.
- * Since the received pbufs are enqueued, be sure to configure
- * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive
- * packets even if the maximum amount of fragments is enqueued for reassembly!
- */
-#ifndef IP_REASS_MAX_PBUFS
-#define IP_REASS_MAX_PBUFS 10
-#endif
-
-/**
- * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP
- * fragmentation. Otherwise pbufs are allocated and reference the original
- * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1,
- * new PBUF_RAM pbufs are used for fragments).
- * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs!
- */
-#ifndef IP_FRAG_USES_STATIC_BUF
-#define IP_FRAG_USES_STATIC_BUF 0
-#endif
-
-/**
- * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer
- * (requires IP_FRAG_USES_STATIC_BUF==1)
- */
-#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU)
-#define IP_FRAG_MAX_MTU 1500
-#endif
-
-/**
- * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers.
- */
-#ifndef IP_DEFAULT_TTL
-#define IP_DEFAULT_TTL 255
-#endif
-
-/**
- * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast
- * filter per pcb on udp and raw send operations. To enable broadcast filter
- * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1.
- */
-#ifndef IP_SOF_BROADCAST
-#define IP_SOF_BROADCAST 0
-#endif
-
-/**
- * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast
- * filter on recv operations.
- */
-#ifndef IP_SOF_BROADCAST_RECV
-#define IP_SOF_BROADCAST_RECV 0
-#endif
-
-/*
- ----------------------------------
- ---------- ICMP options ----------
- ----------------------------------
-*/
-/**
- * LWIP_ICMP==1: Enable ICMP module inside the IP stack.
- * Be careful, disable that make your product non-compliant to RFC1122
- */
-#ifndef LWIP_ICMP
-#define LWIP_ICMP 1
-#endif
-
-/**
- * ICMP_TTL: Default value for Time-To-Live used by ICMP packets.
- */
-#ifndef ICMP_TTL
-#define ICMP_TTL (IP_DEFAULT_TTL)
-#endif
-
-/**
- * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only)
- */
-#ifndef LWIP_BROADCAST_PING
-#define LWIP_BROADCAST_PING 0
-#endif
-
-/**
- * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only)
- */
-#ifndef LWIP_MULTICAST_PING
-#define LWIP_MULTICAST_PING 0
-#endif
-
-/*
- ---------------------------------
- ---------- RAW options ----------
- ---------------------------------
-*/
-/**
- * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.
- */
-#ifndef LWIP_RAW
-#define LWIP_RAW 1
-#endif
-
-/**
- * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.
- */
-#ifndef RAW_TTL
-#define RAW_TTL (IP_DEFAULT_TTL)
-#endif
-
-/*
- ----------------------------------
- ---------- DHCP options ----------
- ----------------------------------
-*/
-/**
- * LWIP_DHCP==1: Enable DHCP module.
- */
-#ifndef LWIP_DHCP
-#define LWIP_DHCP 0
-#endif
-
-/**
- * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address.
- */
-#ifndef DHCP_DOES_ARP_CHECK
-#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP))
-#endif
-
-/*
- ------------------------------------
- ---------- AUTOIP options ----------
- ------------------------------------
-*/
-/**
- * LWIP_AUTOIP==1: Enable AUTOIP module.
- */
-#ifndef LWIP_AUTOIP
-#define LWIP_AUTOIP 0
-#endif
-
-/**
- * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on
- * the same interface at the same time.
- */
-#ifndef LWIP_DHCP_AUTOIP_COOP
-#define LWIP_DHCP_AUTOIP_COOP 0
-#endif
-
-/**
- * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes
- * that should be sent before falling back on AUTOIP. This can be set
- * as low as 1 to get an AutoIP address very quickly, but you should
- * be prepared to handle a changing IP address when DHCP overrides
- * AutoIP.
- */
-#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES
-#define LWIP_DHCP_AUTOIP_COOP_TRIES 9
-#endif
-
-/*
- ----------------------------------
- ---------- SNMP options ----------
- ----------------------------------
-*/
-/**
- * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP
- * transport.
- */
-#ifndef LWIP_SNMP
-#define LWIP_SNMP 0
-#endif
-
-/**
- * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will
- * allow. At least one request buffer is required.
- * Does not have to be changed unless external MIBs answer request asynchronously
- */
-#ifndef SNMP_CONCURRENT_REQUESTS
-#define SNMP_CONCURRENT_REQUESTS 1
-#endif
-
-/**
- * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap
- * destination is required
- */
-#ifndef SNMP_TRAP_DESTINATIONS
-#define SNMP_TRAP_DESTINATIONS 1
-#endif
-
-/**
- * SNMP_PRIVATE_MIB:
- * When using a private MIB, you have to create a file 'private_mib.h' that contains
- * a 'struct mib_array_node mib_private' which contains your MIB.
- */
-#ifndef SNMP_PRIVATE_MIB
-#define SNMP_PRIVATE_MIB 0
-#endif
-
-/**
- * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not
- * a safe action and disabled when SNMP_SAFE_REQUESTS = 1).
- * Unsafe requests are disabled by default!
- */
-#ifndef SNMP_SAFE_REQUESTS
-#define SNMP_SAFE_REQUESTS 1
-#endif
-
-/**
- * The maximum length of strings used. This affects the size of
- * MEMP_SNMP_VALUE elements.
- */
-#ifndef SNMP_MAX_OCTET_STRING_LEN
-#define SNMP_MAX_OCTET_STRING_LEN 127
-#endif
-
-/**
- * The maximum depth of the SNMP tree.
- * With private MIBs enabled, this depends on your MIB!
- * This affects the size of MEMP_SNMP_VALUE elements.
- */
-#ifndef SNMP_MAX_TREE_DEPTH
-#define SNMP_MAX_TREE_DEPTH 15
-#endif
-
-/**
- * The size of the MEMP_SNMP_VALUE elements, normally calculated from
- * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH.
- */
-#ifndef SNMP_MAX_VALUE_SIZE
-#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH))
-#endif
-
-/*
- ----------------------------------
- ---------- IGMP options ----------
- ----------------------------------
-*/
-/**
- * LWIP_IGMP==1: Turn on IGMP module.
- */
-#ifndef LWIP_IGMP
-#define LWIP_IGMP 0
-#endif
-
-/*
- ----------------------------------
- ---------- DNS options -----------
- ----------------------------------
-*/
-/**
- * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS
- * transport.
- */
-#ifndef LWIP_DNS
-#define LWIP_DNS 0
-#endif
-
-/** DNS maximum number of entries to maintain locally. */
-#ifndef DNS_TABLE_SIZE
-#define DNS_TABLE_SIZE 4
-#endif
-
-/** DNS maximum host name length supported in the name table. */
-#ifndef DNS_MAX_NAME_LENGTH
-#define DNS_MAX_NAME_LENGTH 256
-#endif
-
-/** The maximum of DNS servers */
-#ifndef DNS_MAX_SERVERS
-#define DNS_MAX_SERVERS 2
-#endif
-
-/** DNS do a name checking between the query and the response. */
-#ifndef DNS_DOES_NAME_CHECK
-#define DNS_DOES_NAME_CHECK 1
-#endif
-
-/** DNS message max. size. Default value is RFC compliant. */
-#ifndef DNS_MSG_SIZE
-#define DNS_MSG_SIZE 512
-#endif
-
-/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled,
- * you have to define
- * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}}
- * (an array of structs name/address, where address is an u32_t in network
- * byte order).
- *
- * Instead, you can also use an external function:
- * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name)
- * that returns the IP address or INADDR_NONE if not found.
- */
-#ifndef DNS_LOCAL_HOSTLIST
-#define DNS_LOCAL_HOSTLIST 0
-#endif /* DNS_LOCAL_HOSTLIST */
-
-/** If this is turned on, the local host-list can be dynamically changed
- * at runtime. */
-#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC
-#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0
-#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
-
-/*
- ---------------------------------
- ---------- UDP options ----------
- ---------------------------------
-*/
-/**
- * LWIP_UDP==1: Turn on UDP.
- */
-#ifndef LWIP_UDP
-#define LWIP_UDP 1
-#endif
-
-/**
- * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP)
- */
-#ifndef LWIP_UDPLITE
-#define LWIP_UDPLITE 0
-#endif
-
-/**
- * UDP_TTL: Default Time-To-Live value.
- */
-#ifndef UDP_TTL
-#define UDP_TTL (IP_DEFAULT_TTL)
-#endif
-
-/**
- * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf.
- */
-#ifndef LWIP_NETBUF_RECVINFO
-#define LWIP_NETBUF_RECVINFO 0
-#endif
-
-/*
- ---------------------------------
- ---------- TCP options ----------
- ---------------------------------
-*/
-/**
- * LWIP_TCP==1: Turn on TCP.
- */
-#ifndef LWIP_TCP
-#define LWIP_TCP 1
-#endif
-
-/**
- * TCP_TTL: Default Time-To-Live value.
- */
-#ifndef TCP_TTL
-#define TCP_TTL (IP_DEFAULT_TTL)
-#endif
-
-/**
- * TCP_WND: The size of a TCP window. This must be at least
- * (2 * TCP_MSS) for things to work well
- */
-#ifndef TCP_WND
-#define TCP_WND (4 * TCP_MSS)
-#endif
-
-/**
- * TCP_MAXRTX: Maximum number of retransmissions of data segments.
- */
-#ifndef TCP_MAXRTX
-#define TCP_MAXRTX 12
-#endif
-
-/**
- * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments.
- */
-#ifndef TCP_SYNMAXRTX
-#define TCP_SYNMAXRTX 6
-#endif
-
-/**
- * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order.
- * Define to 0 if your device is low on memory.
- */
-#ifndef TCP_QUEUE_OOSEQ
-#define TCP_QUEUE_OOSEQ (LWIP_TCP)
-#endif
-
-/**
- * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default,
- * you might want to increase this.)
- * For the receive side, this MSS is advertised to the remote side
- * when opening a connection. For the transmit size, this MSS sets
- * an upper limit on the MSS advertised by the remote host.
- */
-#ifndef TCP_MSS
-#define TCP_MSS 536
-#endif
-
-/**
- * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really
- * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which
- * reflects the available reassembly buffer size at the remote host) and the
- * largest size permitted by the IP layer" (RFC 1122)
- * Setting this to 1 enables code that checks TCP_MSS against the MTU of the
- * netif used for a connection and limits the MSS if it would be too big otherwise.
- */
-#ifndef TCP_CALCULATE_EFF_SEND_MSS
-#define TCP_CALCULATE_EFF_SEND_MSS 1
-#endif
-
-
-/**
- * TCP_SND_BUF: TCP sender buffer space (bytes).
- */
-#ifndef TCP_SND_BUF
-#define TCP_SND_BUF 256
-#endif
-
-/**
- * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least
- * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.
- */
-#ifndef TCP_SND_QUEUELEN
-#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS))
-#endif
-
-/**
- * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than
- * TCP_SND_BUF. It is the amount of space which must be available in the
- * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT).
- */
-#ifndef TCP_SNDLOWAT
-#define TCP_SNDLOWAT ((TCP_SND_BUF)/2)
-#endif
-
-/**
- * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater
- * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below
- * this number, select returns writable (combined with TCP_SNDLOWAT).
- */
-#ifndef TCP_SNDQUEUELOWAT
-#define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2)
-#endif
-
-/**
- * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb.
- */
-#ifndef TCP_LISTEN_BACKLOG
-#define TCP_LISTEN_BACKLOG 0
-#endif
-
-/**
- * The maximum allowed backlog for TCP listen netconns.
- * This backlog is used unless another is explicitly specified.
- * 0xff is the maximum (u8_t).
- */
-#ifndef TCP_DEFAULT_LISTEN_BACKLOG
-#define TCP_DEFAULT_LISTEN_BACKLOG 0xff
-#endif
-
-/**
- * TCP_OVERSIZE: The maximum number of bytes that tcp_write may
- * allocate ahead of time in an attempt to create shorter pbuf chains
- * for transmission. The meaningful range is 0 to TCP_MSS. Some
- * suggested values are:
- *
- * 0: Disable oversized allocation. Each tcp_write() allocates a new
- pbuf (old behaviour).
- * 1: Allocate size-aligned pbufs with minimal excess. Use this if your
- * scatter-gather DMA requires aligned fragments.
- * 128: Limit the pbuf/memory overhead to 20%.
- * TCP_MSS: Try to create unfragmented TCP packets.
- * TCP_MSS/4: Try to create 4 fragments or less per TCP packet.
- */
-#ifndef TCP_OVERSIZE
-#define TCP_OVERSIZE TCP_MSS
-#endif
-
-/**
- * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option.
- */
-#ifndef LWIP_TCP_TIMESTAMPS
-#define LWIP_TCP_TIMESTAMPS 0
-#endif
-
-/**
- * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an
- * explicit window update
- */
-#ifndef TCP_WND_UPDATE_THRESHOLD
-#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4)
-#endif
-
-/**
- * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1.
- * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all
- * events (accept, sent, etc) that happen in the system.
- * LWIP_CALLBACK_API==1: The PCB callback function is called directly
- * for the event.
- */
-#ifndef LWIP_EVENT_API
-#define LWIP_EVENT_API 0
-#define LWIP_CALLBACK_API 1
-#else
-#define LWIP_EVENT_API 1
-#define LWIP_CALLBACK_API 0
-#endif
-
-
-/*
- ----------------------------------
- ---------- Pbuf options ----------
- ----------------------------------
-*/
-/**
- * PBUF_LINK_HLEN: the number of bytes that should be allocated for a
- * link level header. The default is 14, the standard value for
- * Ethernet.
- */
-#ifndef PBUF_LINK_HLEN
-#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE)
-#endif
-
-/**
- * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is
- * designed to accomodate single full size TCP frame in one pbuf, including
- * TCP_MSS, IP header, and link header.
- */
-#ifndef PBUF_POOL_BUFSIZE
-#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN)
-#endif
-
-/*
- ------------------------------------------------
- ---------- Network Interfaces options ----------
- ------------------------------------------------
-*/
-/**
- * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname
- * field.
- */
-#ifndef LWIP_NETIF_HOSTNAME
-#define LWIP_NETIF_HOSTNAME 0
-#endif
-
-/**
- * LWIP_NETIF_API==1: Support netif api (in netifapi.c)
- */
-#ifndef LWIP_NETIF_API
-#define LWIP_NETIF_API 0
-#endif
-
-/**
- * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface
- * changes its up/down status (i.e., due to DHCP IP acquistion)
- */
-#ifndef LWIP_NETIF_STATUS_CALLBACK
-#define LWIP_NETIF_STATUS_CALLBACK 0
-#endif
-
-/**
- * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface
- * whenever the link changes (i.e., link down)
- */
-#ifndef LWIP_NETIF_LINK_CALLBACK
-#define LWIP_NETIF_LINK_CALLBACK 0
-#endif
-
-/**
- * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table
- * indices) in struct netif. TCP and UDP can make use of this to prevent
- * scanning the ARP table for every sent packet. While this is faster for big
- * ARP tables or many concurrent connections, it might be counterproductive
- * if you have a tiny ARP table or if there never are concurrent connections.
- */
-#ifndef LWIP_NETIF_HWADDRHINT
-#define LWIP_NETIF_HWADDRHINT 0
-#endif
-
-/**
- * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP
- * address equal to the netif IP address, looping them back up the stack.
- */
-#ifndef LWIP_NETIF_LOOPBACK
-#define LWIP_NETIF_LOOPBACK 0
-#endif
-
-/**
- * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback
- * sending for each netif (0 = disabled)
- */
-#ifndef LWIP_LOOPBACK_MAX_PBUFS
-#define LWIP_LOOPBACK_MAX_PBUFS 0
-#endif
-
-/**
- * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in
- * the system, as netifs must change how they behave depending on this setting
- * for the LWIP_NETIF_LOOPBACK option to work.
- * Setting this is needed to avoid reentering non-reentrant functions like
- * tcp_input().
- * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a
- * multithreaded environment like tcpip.c. In this case, netif->input()
- * is called directly.
- * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup.
- * The packets are put on a list and netif_poll() must be called in
- * the main application loop.
- */
-#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING
-#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS)
-#endif
-
-/**
- * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data
- * to be sent into one single pbuf. This is for compatibility with DMA-enabled
- * MACs that do not support scatter-gather.
- * Beware that this might involve CPU-memcpy before transmitting that would not
- * be needed without this flag! Use this only if you need to!
- *
- * @todo: TCP and IP-frag do not work with this, yet:
- */
-#ifndef LWIP_NETIF_TX_SINGLE_PBUF
-#define LWIP_NETIF_TX_SINGLE_PBUF 0
-#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
-
-/*
- ------------------------------------
- ---------- LOOPIF options ----------
- ------------------------------------
-*/
-/**
- * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c
- */
-#ifndef LWIP_HAVE_LOOPIF
-#define LWIP_HAVE_LOOPIF 0
-#endif
-
-/*
- ------------------------------------
- ---------- SLIPIF options ----------
- ------------------------------------
-*/
-/**
- * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c
- */
-#ifndef LWIP_HAVE_SLIPIF
-#define LWIP_HAVE_SLIPIF 0
-#endif
-
-/*
- ------------------------------------
- ---------- Thread options ----------
- ------------------------------------
-*/
-/**
- * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread.
- */
-#ifndef TCPIP_THREAD_NAME
-#define TCPIP_THREAD_NAME "tcpip_thread"
-#endif
-
-/**
- * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread.
- * The stack size value itself is platform-dependent, but is passed to
- * sys_thread_new() when the thread is created.
- */
-#ifndef TCPIP_THREAD_STACKSIZE
-#define TCPIP_THREAD_STACKSIZE 0
-#endif
-
-/**
- * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread.
- * The priority value itself is platform-dependent, but is passed to
- * sys_thread_new() when the thread is created.
- */
-#ifndef TCPIP_THREAD_PRIO
-#define TCPIP_THREAD_PRIO 1
-#endif
-
-/**
- * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages
- * The queue size value itself is platform-dependent, but is passed to
- * sys_mbox_new() when tcpip_init is called.
- */
-#ifndef TCPIP_MBOX_SIZE
-#define TCPIP_MBOX_SIZE 0
-#endif
-
-/**
- * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread.
- */
-#ifndef SLIPIF_THREAD_NAME
-#define SLIPIF_THREAD_NAME "slipif_loop"
-#endif
-
-/**
- * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread.
- * The stack size value itself is platform-dependent, but is passed to
- * sys_thread_new() when the thread is created.
- */
-#ifndef SLIPIF_THREAD_STACKSIZE
-#define SLIPIF_THREAD_STACKSIZE 0
-#endif
-
-/**
- * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread.
- * The priority value itself is platform-dependent, but is passed to
- * sys_thread_new() when the thread is created.
- */
-#ifndef SLIPIF_THREAD_PRIO
-#define SLIPIF_THREAD_PRIO 1
-#endif
-
-/**
- * PPP_THREAD_NAME: The name assigned to the pppInputThread.
- */
-#ifndef PPP_THREAD_NAME
-#define PPP_THREAD_NAME "pppInputThread"
-#endif
-
-/**
- * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread.
- * The stack size value itself is platform-dependent, but is passed to
- * sys_thread_new() when the thread is created.
- */
-#ifndef PPP_THREAD_STACKSIZE
-#define PPP_THREAD_STACKSIZE 0
-#endif
-
-/**
- * PPP_THREAD_PRIO: The priority assigned to the pppInputThread.
- * The priority value itself is platform-dependent, but is passed to
- * sys_thread_new() when the thread is created.
- */
-#ifndef PPP_THREAD_PRIO
-#define PPP_THREAD_PRIO 1
-#endif
-
-/**
- * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread.
- */
-#ifndef DEFAULT_THREAD_NAME
-#define DEFAULT_THREAD_NAME "lwIP"
-#endif
-
-/**
- * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread.
- * The stack size value itself is platform-dependent, but is passed to
- * sys_thread_new() when the thread is created.
- */
-#ifndef DEFAULT_THREAD_STACKSIZE
-#define DEFAULT_THREAD_STACKSIZE 0
-#endif
-
-/**
- * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread.
- * The priority value itself is platform-dependent, but is passed to
- * sys_thread_new() when the thread is created.
- */
-#ifndef DEFAULT_THREAD_PRIO
-#define DEFAULT_THREAD_PRIO 1
-#endif
-
-/**
- * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
- * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed
- * to sys_mbox_new() when the recvmbox is created.
- */
-#ifndef DEFAULT_RAW_RECVMBOX_SIZE
-#define DEFAULT_RAW_RECVMBOX_SIZE 0
-#endif
-
-/**
- * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
- * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed
- * to sys_mbox_new() when the recvmbox is created.
- */
-#ifndef DEFAULT_UDP_RECVMBOX_SIZE
-#define DEFAULT_UDP_RECVMBOX_SIZE 0
-#endif
-
-/**
- * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
- * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed
- * to sys_mbox_new() when the recvmbox is created.
- */
-#ifndef DEFAULT_TCP_RECVMBOX_SIZE
-#define DEFAULT_TCP_RECVMBOX_SIZE 0
-#endif
-
-/**
- * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections.
- * The queue size value itself is platform-dependent, but is passed to
- * sys_mbox_new() when the acceptmbox is created.
- */
-#ifndef DEFAULT_ACCEPTMBOX_SIZE
-#define DEFAULT_ACCEPTMBOX_SIZE 0
-#endif
-
-/*
- ----------------------------------------------
- ---------- Sequential layer options ----------
- ----------------------------------------------
-*/
-/**
- * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!)
- * Don't use it if you're not an active lwIP project member
- */
-#ifndef LWIP_TCPIP_CORE_LOCKING
-#define LWIP_TCPIP_CORE_LOCKING 0
-#endif
-
-/**
- * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!)
- * Don't use it if you're not an active lwIP project member
- */
-#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT
-#define LWIP_TCPIP_CORE_LOCKING_INPUT 0
-#endif
-
-/**
- * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
- */
-#ifndef LWIP_NETCONN
-#define LWIP_NETCONN 1
-#endif
-
-/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create
- * timers running in tcpip_thread from another thread.
- */
-#ifndef LWIP_TCPIP_TIMEOUT
-#define LWIP_TCPIP_TIMEOUT 1
-#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_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names.
- * Disable this option if you use a POSIX operating system that uses the same
- * names (read, write & close). (only used if you use sockets.c)
- */
-#ifndef LWIP_POSIX_SOCKETS_IO_NAMES
-#define LWIP_POSIX_SOCKETS_IO_NAMES 1
-#endif
-
-/**
- * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT
- * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set
- * in seconds. (does not require sockets.c, and will affect tcp.c)
- */
-#ifndef LWIP_TCP_KEEPALIVE
-#define LWIP_TCP_KEEPALIVE 0
-#endif
-
-/**
- * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing.
- */
-#ifndef LWIP_SO_RCVTIMEO
-#define LWIP_SO_RCVTIMEO 0
-#endif
-
-/**
- * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing.
- */
-#ifndef LWIP_SO_RCVBUF
-#define LWIP_SO_RCVBUF 0
-#endif
-
-/**
- * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize.
- */
-#ifndef RECV_BUFSIZE_DEFAULT
-#define RECV_BUFSIZE_DEFAULT INT_MAX
-#endif
-
-/**
- * SO_REUSE==1: Enable SO_REUSEADDR option.
- */
-#ifndef SO_REUSE
-#define SO_REUSE 0
-#endif
-
-/**
- * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets
- * to all local matches if SO_REUSEADDR is turned on.
- * WARNING: Adds a memcpy for every packet if passing to more than one pcb!
- */
-#ifndef SO_REUSE_RXTOALL
-#define SO_REUSE_RXTOALL 0
-#endif
-
-/*
- ----------------------------------------
- ---------- Statistics options ----------
- ----------------------------------------
-*/
-/**
- * LWIP_STATS==1: Enable statistics collection in lwip_stats.
- */
-#ifndef LWIP_STATS
-#define LWIP_STATS 1
-#endif
-
-#if LWIP_STATS
-
-/**
- * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions.
- */
-#ifndef LWIP_STATS_DISPLAY
-#define LWIP_STATS_DISPLAY 0
-#endif
-
-/**
- * LINK_STATS==1: Enable link stats.
- */
-#ifndef LINK_STATS
-#define LINK_STATS 1
-#endif
-
-/**
- * ETHARP_STATS==1: Enable etharp stats.
- */
-#ifndef ETHARP_STATS
-#define ETHARP_STATS (LWIP_ARP)
-#endif
-
-/**
- * IP_STATS==1: Enable IP stats.
- */
-#ifndef IP_STATS
-#define IP_STATS 1
-#endif
-
-/**
- * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is
- * on if using either frag or reass.
- */
-#ifndef IPFRAG_STATS
-#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG)
-#endif
-
-/**
- * ICMP_STATS==1: Enable ICMP stats.
- */
-#ifndef ICMP_STATS
-#define ICMP_STATS 1
-#endif
-
-/**
- * IGMP_STATS==1: Enable IGMP stats.
- */
-#ifndef IGMP_STATS
-#define IGMP_STATS (LWIP_IGMP)
-#endif
-
-/**
- * UDP_STATS==1: Enable UDP stats. Default is on if
- * UDP enabled, otherwise off.
- */
-#ifndef UDP_STATS
-#define UDP_STATS (LWIP_UDP)
-#endif
-
-/**
- * TCP_STATS==1: Enable TCP stats. Default is on if TCP
- * enabled, otherwise off.
- */
-#ifndef TCP_STATS
-#define TCP_STATS (LWIP_TCP)
-#endif
-
-/**
- * MEM_STATS==1: Enable mem.c stats.
- */
-#ifndef MEM_STATS
-#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0))
-#endif
-
-/**
- * MEMP_STATS==1: Enable memp.c pool stats.
- */
-#ifndef MEMP_STATS
-#define MEMP_STATS (MEMP_MEM_MALLOC == 0)
-#endif
-
-/**
- * SYS_STATS==1: Enable system stats (sem and mbox counts, etc).
- */
-#ifndef SYS_STATS
-#define SYS_STATS (NO_SYS == 0)
-#endif
-
-#else
-
-#define LINK_STATS 0
-#define IP_STATS 0
-#define IPFRAG_STATS 0
-#define ICMP_STATS 0
-#define IGMP_STATS 0
-#define UDP_STATS 0
-#define TCP_STATS 0
-#define MEM_STATS 0
-#define MEMP_STATS 0
-#define SYS_STATS 0
-#define LWIP_STATS_DISPLAY 0
-
-#endif /* LWIP_STATS */
-
-/*
- ---------------------------------
- ---------- PPP options ----------
- ---------------------------------
-*/
-/**
- * PPP_SUPPORT==1: Enable PPP.
- */
-#ifndef PPP_SUPPORT
-#define PPP_SUPPORT 0
-#endif
-
-/**
- * PPPOE_SUPPORT==1: Enable PPP Over Ethernet
- */
-#ifndef PPPOE_SUPPORT
-#define PPPOE_SUPPORT 0
-#endif
-
-/**
- * PPPOS_SUPPORT==1: Enable PPP Over Serial
- */
-#ifndef PPPOS_SUPPORT
-#define PPPOS_SUPPORT PPP_SUPPORT
-#endif
-
-#if PPP_SUPPORT
-
-/**
- * NUM_PPP: Max PPP sessions.
- */
-#ifndef NUM_PPP
-#define NUM_PPP 1
-#endif
-
-/**
- * PAP_SUPPORT==1: Support PAP.
- */
-#ifndef PAP_SUPPORT
-#define PAP_SUPPORT 0
-#endif
-
-/**
- * CHAP_SUPPORT==1: Support CHAP.
- */
-#ifndef CHAP_SUPPORT
-#define CHAP_SUPPORT 0
-#endif
-
-/**
- * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET!
- */
-#ifndef MSCHAP_SUPPORT
-#define MSCHAP_SUPPORT 0
-#endif
-
-/**
- * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET!
- */
-#ifndef CBCP_SUPPORT
-#define CBCP_SUPPORT 0
-#endif
-
-/**
- * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET!
- */
-#ifndef CCP_SUPPORT
-#define CCP_SUPPORT 0
-#endif
-
-/**
- * VJ_SUPPORT==1: Support VJ header compression.
- */
-#ifndef VJ_SUPPORT
-#define VJ_SUPPORT 0
-#endif
-
-/**
- * MD5_SUPPORT==1: Support MD5 (see also CHAP).
- */
-#ifndef MD5_SUPPORT
-#define MD5_SUPPORT 0
-#endif
-
-/*
- * Timeouts
- */
-#ifndef FSM_DEFTIMEOUT
-#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */
-#endif
-
-#ifndef FSM_DEFMAXTERMREQS
-#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */
-#endif
-
-#ifndef FSM_DEFMAXCONFREQS
-#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */
-#endif
-
-#ifndef FSM_DEFMAXNAKLOOPS
-#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */
-#endif
-
-#ifndef UPAP_DEFTIMEOUT
-#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */
-#endif
-
-#ifndef UPAP_DEFREQTIME
-#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */
-#endif
-
-#ifndef CHAP_DEFTIMEOUT
-#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */
-#endif
-
-#ifndef CHAP_DEFTRANSMITS
-#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */
-#endif
-
-/* Interval in seconds between keepalive echo requests, 0 to disable. */
-#ifndef LCP_ECHOINTERVAL
-#define LCP_ECHOINTERVAL 0
-#endif
-
-/* Number of unanswered echo requests before failure. */
-#ifndef LCP_MAXECHOFAILS
-#define LCP_MAXECHOFAILS 3
-#endif
-
-/* Max Xmit idle time (in jiffies) before resend flag char. */
-#ifndef PPP_MAXIDLEFLAG
-#define PPP_MAXIDLEFLAG 100
-#endif
-
-/*
- * Packet sizes
- *
- * Note - lcp shouldn't be allowed to negotiate stuff outside these
- * limits. See lcp.h in the pppd directory.
- * (XXX - these constants should simply be shared by lcp.c instead
- * of living in lcp.h)
- */
-#define PPP_MTU 1500 /* Default MTU (size of Info field) */
-#ifndef PPP_MAXMTU
-/* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */
-#define PPP_MAXMTU 1500 /* Largest MTU we allow */
-#endif
-#define PPP_MINMTU 64
-#define PPP_MRU 1500 /* default MRU = max length of info field */
-#define PPP_MAXMRU 1500 /* Largest MRU we allow */
-#ifndef PPP_DEFMRU
-#define PPP_DEFMRU 296 /* Try for this */
-#endif
-#define PPP_MINMRU 128 /* No MRUs below this */
-
-#ifndef MAXNAMELEN
-#define MAXNAMELEN 256 /* max length of hostname or name for auth */
-#endif
-#ifndef MAXSECRETLEN
-#define MAXSECRETLEN 256 /* max length of password or secret */
-#endif
-
-#endif /* PPP_SUPPORT */
-
-/*
- --------------------------------------
- ---------- Checksum options ----------
- --------------------------------------
-*/
-/**
- * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.
- */
-#ifndef CHECKSUM_GEN_IP
-#define CHECKSUM_GEN_IP 1
-#endif
-
-/**
- * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.
- */
-#ifndef CHECKSUM_GEN_UDP
-#define CHECKSUM_GEN_UDP 1
-#endif
-
-/**
- * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.
- */
-#ifndef CHECKSUM_GEN_TCP
-#define CHECKSUM_GEN_TCP 1
-#endif
-
-/**
- * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.
- */
-#ifndef CHECKSUM_CHECK_IP
-#define CHECKSUM_CHECK_IP 1
-#endif
-
-/**
- * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.
- */
-#ifndef CHECKSUM_CHECK_UDP
-#define CHECKSUM_CHECK_UDP 1
-#endif
-
-/**
- * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.
- */
-#ifndef CHECKSUM_CHECK_TCP
-#define CHECKSUM_CHECK_TCP 1
-#endif
-
-/**
- * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from
- * application buffers to pbufs.
- */
-#ifndef LWIP_CHECKSUM_ON_COPY
-#define LWIP_CHECKSUM_ON_COPY 0
-#endif
-
-/*
- ---------------------------------------
- ---------- Debugging options ----------
- ---------------------------------------
-*/
-/**
- * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is
- * compared against this value. If it is smaller, then debugging
- * messages are written.
- */
-#ifndef LWIP_DBG_MIN_LEVEL
-#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL
-#endif
-
-/**
- * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable
- * debug messages of certain types.
- */
-#ifndef LWIP_DBG_TYPES_ON
-#define LWIP_DBG_TYPES_ON LWIP_DBG_ON
-#endif
-
-/**
- * ETHARP_DEBUG: Enable debugging in etharp.c.
- */
-#ifndef ETHARP_DEBUG
-#define ETHARP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * NETIF_DEBUG: Enable debugging in netif.c.
- */
-#ifndef NETIF_DEBUG
-#define NETIF_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * PBUF_DEBUG: Enable debugging in pbuf.c.
- */
-#ifndef PBUF_DEBUG
-#define PBUF_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * API_LIB_DEBUG: Enable debugging in api_lib.c.
- */
-#ifndef API_LIB_DEBUG
-#define API_LIB_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * API_MSG_DEBUG: Enable debugging in api_msg.c.
- */
-#ifndef API_MSG_DEBUG
-#define API_MSG_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * SOCKETS_DEBUG: Enable debugging in sockets.c.
- */
-#ifndef SOCKETS_DEBUG
-#define SOCKETS_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * ICMP_DEBUG: Enable debugging in icmp.c.
- */
-#ifndef ICMP_DEBUG
-#define ICMP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * IGMP_DEBUG: Enable debugging in igmp.c.
- */
-#ifndef IGMP_DEBUG
-#define IGMP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * INET_DEBUG: Enable debugging in inet.c.
- */
-#ifndef INET_DEBUG
-#define INET_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * IP_DEBUG: Enable debugging for IP.
- */
-#ifndef IP_DEBUG
-#define IP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass.
- */
-#ifndef IP_REASS_DEBUG
-#define IP_REASS_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * RAW_DEBUG: Enable debugging in raw.c.
- */
-#ifndef RAW_DEBUG
-#define RAW_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * MEM_DEBUG: Enable debugging in mem.c.
- */
-#ifndef MEM_DEBUG
-#define MEM_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * MEMP_DEBUG: Enable debugging in memp.c.
- */
-#ifndef MEMP_DEBUG
-#define MEMP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * SYS_DEBUG: Enable debugging in sys.c.
- */
-#ifndef SYS_DEBUG
-#define SYS_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * TIMERS_DEBUG: Enable debugging in timers.c.
- */
-#ifndef TIMERS_DEBUG
-#define TIMERS_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * TCP_DEBUG: Enable debugging for TCP.
- */
-#ifndef TCP_DEBUG
-#define TCP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug.
- */
-#ifndef TCP_INPUT_DEBUG
-#define TCP_INPUT_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit.
- */
-#ifndef TCP_FR_DEBUG
-#define TCP_FR_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit
- * timeout.
- */
-#ifndef TCP_RTO_DEBUG
-#define TCP_RTO_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * TCP_CWND_DEBUG: Enable debugging for TCP congestion window.
- */
-#ifndef TCP_CWND_DEBUG
-#define TCP_CWND_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating.
- */
-#ifndef TCP_WND_DEBUG
-#define TCP_WND_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions.
- */
-#ifndef TCP_OUTPUT_DEBUG
-#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * TCP_RST_DEBUG: Enable debugging for TCP with the RST message.
- */
-#ifndef TCP_RST_DEBUG
-#define TCP_RST_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths.
- */
-#ifndef TCP_QLEN_DEBUG
-#define TCP_QLEN_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * UDP_DEBUG: Enable debugging in UDP.
- */
-#ifndef UDP_DEBUG
-#define UDP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * TCPIP_DEBUG: Enable debugging in tcpip.c.
- */
-#ifndef TCPIP_DEBUG
-#define TCPIP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * PPP_DEBUG: Enable debugging for PPP.
- */
-#ifndef PPP_DEBUG
-#define PPP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * SLIP_DEBUG: Enable debugging in slipif.c.
- */
-#ifndef SLIP_DEBUG
-#define SLIP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * DHCP_DEBUG: Enable debugging in dhcp.c.
- */
-#ifndef DHCP_DEBUG
-#define DHCP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * AUTOIP_DEBUG: Enable debugging in autoip.c.
- */
-#ifndef AUTOIP_DEBUG
-#define AUTOIP_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * SNMP_MSG_DEBUG: Enable debugging for SNMP messages.
- */
-#ifndef SNMP_MSG_DEBUG
-#define SNMP_MSG_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs.
- */
-#ifndef SNMP_MIB_DEBUG
-#define SNMP_MIB_DEBUG LWIP_DBG_OFF
-#endif
-
-/**
- * DNS_DEBUG: Enable debugging for DNS.
- */
-#ifndef DNS_DEBUG
-#define DNS_DEBUG LWIP_DBG_OFF
-#endif
-
-#endif /* __LWIP_OPT_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#ifndef __LWIP_PBUF_H__
-#define __LWIP_PBUF_H__
-
-#include "lwip/opt.h"
-#include "lwip/err.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** Currently, the pbuf_custom code is only needed for one specific configuration
- * of IP_FRAG */
-#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF)
-
-#define PBUF_TRANSPORT_HLEN 20
-#define PBUF_IP_HLEN 20
-
-typedef enum {
- PBUF_TRANSPORT,
- PBUF_IP,
- PBUF_LINK,
- PBUF_RAW
-} pbuf_layer;
-
-typedef enum {
- PBUF_RAM, /* pbuf data is stored in RAM */
- PBUF_ROM, /* pbuf data is stored in ROM */
- PBUF_REF, /* pbuf comes from the pbuf pool */
- PBUF_POOL /* pbuf payload refers to RAM */
-} pbuf_type;
-
-
-/** indicates this packet's data should be immediately passed to the application */
-#define PBUF_FLAG_PUSH 0x01U
-/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a
- a pbuf differently */
-#define PBUF_FLAG_IS_CUSTOM 0x02U
-/** indicates this pbuf is UDP multicast to be looped back */
-#define PBUF_FLAG_MCASTLOOP 0x04U
-
-struct pbuf {
- /** next pbuf in singly linked pbuf chain */
- struct pbuf *next;
-
- /** pointer to the actual data in the buffer */
- void *payload;
-
- /**
- * total length of this buffer and all next buffers in chain
- * belonging to the same packet.
- *
- * For non-queue packet chains this is the invariant:
- * p->tot_len == p->len + (p->next? p->next->tot_len: 0)
- */
- u16_t tot_len;
-
- /** length of this buffer */
- u16_t len;
-
- /** pbuf_type as u8_t instead of enum to save space */
- u8_t /*pbuf_type*/ type;
-
- /** misc flags */
- u8_t flags;
-
- /**
- * the reference count always equals the number of pointers
- * that refer to this pbuf. This can be pointers from an application,
- * the stack itself, or pbuf->next pointers from a chain.
- */
- u16_t ref;
-};
-
-#if LWIP_SUPPORT_CUSTOM_PBUF
-/** Prototype for a function to free a custom pbuf */
-typedef void (*pbuf_free_custom_fn)(struct pbuf *p);
-
-/** A custom pbuf: like a pbuf, but following a function pointer to free it. */
-struct pbuf_custom {
- /** The actual pbuf */
- struct pbuf pbuf;
- /** This function is called when pbuf_free deallocates this pbuf(_custom) */
- pbuf_free_custom_fn custom_free_function;
-};
-#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
-
-/* Initializes the pbuf module. This call is empty for now, but may not be in future. */
-#define pbuf_init()
-
-struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type);
-#if LWIP_SUPPORT_CUSTOM_PBUF
-struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type,
- struct pbuf_custom *p, void *payload_mem,
- u16_t payload_mem_len);
-#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
-void pbuf_realloc(struct pbuf *p, u16_t size);
-u8_t pbuf_header(struct pbuf *p, s16_t header_size);
-void pbuf_ref(struct pbuf *p);
-u8_t pbuf_free(struct pbuf *p);
-u8_t pbuf_clen(struct pbuf *p);
-void pbuf_cat(struct pbuf *head, struct pbuf *tail);
-void pbuf_chain(struct pbuf *head, struct pbuf *tail);
-struct pbuf *pbuf_dechain(struct pbuf *p);
-err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);
-u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset);
-err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
-struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer);
-#if LWIP_CHECKSUM_ON_COPY
-err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
- u16_t len, u16_t *chksum);
-#endif /* LWIP_CHECKSUM_ON_COPY */
-
-u8_t pbuf_get_at(struct pbuf* p, u16_t offset);
-u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n);
-u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset);
-u16_t pbuf_strstr(struct pbuf* p, const char* substr);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_PBUF_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_RAW_H__
-#define __LWIP_RAW_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/pbuf.h"
-#include "lwip/def.h"
-#include "lwip/ip.h"
-#include "lwip/ip_addr.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct raw_pcb;
-
-/** Function prototype for raw pcb receive callback functions.
- * @param arg user supplied argument (raw_pcb.recv_arg)
- * @param pcb the raw_pcb which received data
- * @param p the packet buffer that was received
- * @param addr the remote IP address from which the packet was received
- * @return 1 if the packet was 'eaten' (aka. deleted),
- * 0 if the packet lives on
- * If returning 1, the callback is responsible for freeing the pbuf
- * if it's not used any more.
- */
-typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
- ip_addr_t *addr);
-
-struct raw_pcb {
- /* Common members of all PCB types */
- IP_PCB;
-
- struct raw_pcb *next;
-
- u8_t protocol;
-
- /** receive callback function */
- raw_recv_fn recv;
- /* user-supplied argument for the recv callback */
- void *recv_arg;
-};
-
-/* The following functions is the application layer interface to the
- RAW code. */
-struct raw_pcb * raw_new (u8_t proto);
-void raw_remove (struct raw_pcb *pcb);
-err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr);
-err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr);
-
-void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg);
-err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr);
-err_t raw_send (struct raw_pcb *pcb, struct pbuf *p);
-
-/* The following functions are the lower layer interface to RAW. */
-u8_t raw_input (struct pbuf *p, struct netif *inp);
-#define raw_init() /* Compatibility define, not init needed. */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_RAW */
-
-#endif /* __LWIP_RAW_H__ */
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * This is the interface to the platform specific serial IO module
- * It needs to be implemented by those platforms which need SLIP or PPP
- */
-
-#ifndef __SIO_H__
-#define __SIO_H__
-
-#include "lwip/arch.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* If you want to define sio_fd_t elsewhere or differently,
- define this in your cc.h file. */
-#ifndef __sio_fd_t_defined
-typedef void * sio_fd_t;
-#endif
-
-/* The following functions can be defined to something else in your cc.h file
- or be implemented in your custom sio.c file. */
-
-#ifndef sio_open
-/**
- * Opens a serial device for communication.
- *
- * @param devnum device number
- * @return handle to serial device if successful, NULL otherwise
- */
-sio_fd_t sio_open(u8_t devnum);
-#endif
-
-#ifndef sio_send
-/**
- * Sends a single character to the serial device.
- *
- * @param c character to send
- * @param fd serial device handle
- *
- * @note This function will block until the character can be sent.
- */
-void sio_send(u8_t c, sio_fd_t fd);
-#endif
-
-#ifndef sio_recv
-/**
- * Receives a single character from the serial device.
- *
- * @param fd serial device handle
- *
- * @note This function will block until a character is received.
- */
-u8_t sio_recv(sio_fd_t fd);
-#endif
-
-#ifndef sio_read
-/**
- * Reads from the serial device.
- *
- * @param fd serial device handle
- * @param data pointer to data buffer for receiving
- * @param len maximum length (in bytes) of data to receive
- * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
- *
- * @note This function will block until data can be received. The blocking
- * can be cancelled by calling sio_read_abort().
- */
-u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
-#endif
-
-#ifndef sio_tryread
-/**
- * Tries to read from the serial device. Same as sio_read but returns
- * immediately if no data is available and never blocks.
- *
- * @param fd serial device handle
- * @param data pointer to data buffer for receiving
- * @param len maximum length (in bytes) of data to receive
- * @return number of bytes actually received
- */
-u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len);
-#endif
-
-#ifndef sio_write
-/**
- * Writes to the serial device.
- *
- * @param fd serial device handle
- * @param data pointer to data to send
- * @param len length (in bytes) of data to send
- * @return number of bytes actually sent
- *
- * @note This function will block until all data can be sent.
- */
-u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
-#endif
-
-#ifndef sio_read_abort
-/**
- * Aborts a blocking sio_read() call.
- *
- * @param fd serial device handle
- */
-void sio_read_abort(sio_fd_t fd);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __SIO_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001, 2002 Leon Woestenberg <leon.woestenberg@axon.tv>
- * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Leon Woestenberg <leon.woestenberg@axon.tv>
- *
- */
-#ifndef __LWIP_SNMP_H__
-#define __LWIP_SNMP_H__
-
-#include "lwip/opt.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "lwip/ip_addr.h"
-
-struct udp_pcb;
-struct netif;
-
-/**
- * @see RFC1213, "MIB-II, 6. Definitions"
- */
-enum snmp_ifType {
- snmp_ifType_other=1, /* none of the following */
- snmp_ifType_regular1822,
- snmp_ifType_hdh1822,
- snmp_ifType_ddn_x25,
- snmp_ifType_rfc877_x25,
- snmp_ifType_ethernet_csmacd,
- snmp_ifType_iso88023_csmacd,
- snmp_ifType_iso88024_tokenBus,
- snmp_ifType_iso88025_tokenRing,
- snmp_ifType_iso88026_man,
- snmp_ifType_starLan,
- snmp_ifType_proteon_10Mbit,
- snmp_ifType_proteon_80Mbit,
- snmp_ifType_hyperchannel,
- snmp_ifType_fddi,
- snmp_ifType_lapb,
- snmp_ifType_sdlc,
- snmp_ifType_ds1, /* T-1 */
- snmp_ifType_e1, /* european equiv. of T-1 */
- snmp_ifType_basicISDN,
- snmp_ifType_primaryISDN, /* proprietary serial */
- snmp_ifType_propPointToPointSerial,
- snmp_ifType_ppp,
- snmp_ifType_softwareLoopback,
- snmp_ifType_eon, /* CLNP over IP [11] */
- snmp_ifType_ethernet_3Mbit,
- snmp_ifType_nsip, /* XNS over IP */
- snmp_ifType_slip, /* generic SLIP */
- snmp_ifType_ultra, /* ULTRA technologies */
- snmp_ifType_ds3, /* T-3 */
- snmp_ifType_sip, /* SMDS */
- snmp_ifType_frame_relay
-};
-
-#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
-
-/** SNMP "sysuptime" Interval */
-#define SNMP_SYSUPTIME_INTERVAL 10
-
-/** fixed maximum length for object identifier type */
-#define LWIP_SNMP_OBJ_ID_LEN 32
-
-/** internal object identifier representation */
-struct snmp_obj_id
-{
- u8_t len;
- s32_t id[LWIP_SNMP_OBJ_ID_LEN];
-};
-
-/* system */
-void snmp_set_sysdesr(u8_t* str, u8_t* len);
-void snmp_set_sysobjid(struct snmp_obj_id *oid);
-void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid);
-void snmp_inc_sysuptime(void);
-void snmp_add_sysuptime(u32_t value);
-void snmp_get_sysuptime(u32_t *value);
-void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen);
-void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen);
-void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen);
-
-/* network interface */
-void snmp_add_ifinoctets(struct netif *ni, u32_t value);
-void snmp_inc_ifinucastpkts(struct netif *ni);
-void snmp_inc_ifinnucastpkts(struct netif *ni);
-void snmp_inc_ifindiscards(struct netif *ni);
-void snmp_add_ifoutoctets(struct netif *ni, u32_t value);
-void snmp_inc_ifoutucastpkts(struct netif *ni);
-void snmp_inc_ifoutnucastpkts(struct netif *ni);
-void snmp_inc_ifoutdiscards(struct netif *ni);
-void snmp_inc_iflist(void);
-void snmp_dec_iflist(void);
-
-/* ARP (for atTable and ipNetToMediaTable) */
-void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip);
-void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip);
-
-/* IP */
-void snmp_inc_ipinreceives(void);
-void snmp_inc_ipinhdrerrors(void);
-void snmp_inc_ipinaddrerrors(void);
-void snmp_inc_ipforwdatagrams(void);
-void snmp_inc_ipinunknownprotos(void);
-void snmp_inc_ipindiscards(void);
-void snmp_inc_ipindelivers(void);
-void snmp_inc_ipoutrequests(void);
-void snmp_inc_ipoutdiscards(void);
-void snmp_inc_ipoutnoroutes(void);
-void snmp_inc_ipreasmreqds(void);
-void snmp_inc_ipreasmoks(void);
-void snmp_inc_ipreasmfails(void);
-void snmp_inc_ipfragoks(void);
-void snmp_inc_ipfragfails(void);
-void snmp_inc_ipfragcreates(void);
-void snmp_inc_iproutingdiscards(void);
-void snmp_insert_ipaddridx_tree(struct netif *ni);
-void snmp_delete_ipaddridx_tree(struct netif *ni);
-void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni);
-void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni);
-
-/* ICMP */
-void snmp_inc_icmpinmsgs(void);
-void snmp_inc_icmpinerrors(void);
-void snmp_inc_icmpindestunreachs(void);
-void snmp_inc_icmpintimeexcds(void);
-void snmp_inc_icmpinparmprobs(void);
-void snmp_inc_icmpinsrcquenchs(void);
-void snmp_inc_icmpinredirects(void);
-void snmp_inc_icmpinechos(void);
-void snmp_inc_icmpinechoreps(void);
-void snmp_inc_icmpintimestamps(void);
-void snmp_inc_icmpintimestampreps(void);
-void snmp_inc_icmpinaddrmasks(void);
-void snmp_inc_icmpinaddrmaskreps(void);
-void snmp_inc_icmpoutmsgs(void);
-void snmp_inc_icmpouterrors(void);
-void snmp_inc_icmpoutdestunreachs(void);
-void snmp_inc_icmpouttimeexcds(void);
-void snmp_inc_icmpoutparmprobs(void);
-void snmp_inc_icmpoutsrcquenchs(void);
-void snmp_inc_icmpoutredirects(void);
-void snmp_inc_icmpoutechos(void);
-void snmp_inc_icmpoutechoreps(void);
-void snmp_inc_icmpouttimestamps(void);
-void snmp_inc_icmpouttimestampreps(void);
-void snmp_inc_icmpoutaddrmasks(void);
-void snmp_inc_icmpoutaddrmaskreps(void);
-
-/* TCP */
-void snmp_inc_tcpactiveopens(void);
-void snmp_inc_tcppassiveopens(void);
-void snmp_inc_tcpattemptfails(void);
-void snmp_inc_tcpestabresets(void);
-void snmp_inc_tcpinsegs(void);
-void snmp_inc_tcpoutsegs(void);
-void snmp_inc_tcpretranssegs(void);
-void snmp_inc_tcpinerrs(void);
-void snmp_inc_tcpoutrsts(void);
-
-/* UDP */
-void snmp_inc_udpindatagrams(void);
-void snmp_inc_udpnoports(void);
-void snmp_inc_udpinerrors(void);
-void snmp_inc_udpoutdatagrams(void);
-void snmp_insert_udpidx_tree(struct udp_pcb *pcb);
-void snmp_delete_udpidx_tree(struct udp_pcb *pcb);
-
-/* SNMP */
-void snmp_inc_snmpinpkts(void);
-void snmp_inc_snmpoutpkts(void);
-void snmp_inc_snmpinbadversions(void);
-void snmp_inc_snmpinbadcommunitynames(void);
-void snmp_inc_snmpinbadcommunityuses(void);
-void snmp_inc_snmpinasnparseerrs(void);
-void snmp_inc_snmpintoobigs(void);
-void snmp_inc_snmpinnosuchnames(void);
-void snmp_inc_snmpinbadvalues(void);
-void snmp_inc_snmpinreadonlys(void);
-void snmp_inc_snmpingenerrs(void);
-void snmp_add_snmpintotalreqvars(u8_t value);
-void snmp_add_snmpintotalsetvars(u8_t value);
-void snmp_inc_snmpingetrequests(void);
-void snmp_inc_snmpingetnexts(void);
-void snmp_inc_snmpinsetrequests(void);
-void snmp_inc_snmpingetresponses(void);
-void snmp_inc_snmpintraps(void);
-void snmp_inc_snmpouttoobigs(void);
-void snmp_inc_snmpoutnosuchnames(void);
-void snmp_inc_snmpoutbadvalues(void);
-void snmp_inc_snmpoutgenerrs(void);
-void snmp_inc_snmpoutgetrequests(void);
-void snmp_inc_snmpoutgetnexts(void);
-void snmp_inc_snmpoutsetrequests(void);
-void snmp_inc_snmpoutgetresponses(void);
-void snmp_inc_snmpouttraps(void);
-void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid);
-void snmp_set_snmpenableauthentraps(u8_t *value);
-void snmp_get_snmpenableauthentraps(u8_t *value);
-
-/* LWIP_SNMP support not available */
-/* define everything to be empty */
-#else
-
-/* system */
-#define snmp_set_sysdesr(str, len)
-#define snmp_set_sysobjid(oid);
-#define snmp_get_sysobjid_ptr(oid)
-#define snmp_inc_sysuptime()
-#define snmp_add_sysuptime(value)
-#define snmp_get_sysuptime(value)
-#define snmp_set_syscontact(ocstr, ocstrlen);
-#define snmp_set_sysname(ocstr, ocstrlen);
-#define snmp_set_syslocation(ocstr, ocstrlen);
-
-/* network interface */
-#define snmp_add_ifinoctets(ni,value)
-#define snmp_inc_ifinucastpkts(ni)
-#define snmp_inc_ifinnucastpkts(ni)
-#define snmp_inc_ifindiscards(ni)
-#define snmp_add_ifoutoctets(ni,value)
-#define snmp_inc_ifoutucastpkts(ni)
-#define snmp_inc_ifoutnucastpkts(ni)
-#define snmp_inc_ifoutdiscards(ni)
-#define snmp_inc_iflist()
-#define snmp_dec_iflist()
-
-/* ARP */
-#define snmp_insert_arpidx_tree(ni,ip)
-#define snmp_delete_arpidx_tree(ni,ip)
-
-/* IP */
-#define snmp_inc_ipinreceives()
-#define snmp_inc_ipinhdrerrors()
-#define snmp_inc_ipinaddrerrors()
-#define snmp_inc_ipforwdatagrams()
-#define snmp_inc_ipinunknownprotos()
-#define snmp_inc_ipindiscards()
-#define snmp_inc_ipindelivers()
-#define snmp_inc_ipoutrequests()
-#define snmp_inc_ipoutdiscards()
-#define snmp_inc_ipoutnoroutes()
-#define snmp_inc_ipreasmreqds()
-#define snmp_inc_ipreasmoks()
-#define snmp_inc_ipreasmfails()
-#define snmp_inc_ipfragoks()
-#define snmp_inc_ipfragfails()
-#define snmp_inc_ipfragcreates()
-#define snmp_inc_iproutingdiscards()
-#define snmp_insert_ipaddridx_tree(ni)
-#define snmp_delete_ipaddridx_tree(ni)
-#define snmp_insert_iprteidx_tree(dflt, ni)
-#define snmp_delete_iprteidx_tree(dflt, ni)
-
-/* ICMP */
-#define snmp_inc_icmpinmsgs()
-#define snmp_inc_icmpinerrors()
-#define snmp_inc_icmpindestunreachs()
-#define snmp_inc_icmpintimeexcds()
-#define snmp_inc_icmpinparmprobs()
-#define snmp_inc_icmpinsrcquenchs()
-#define snmp_inc_icmpinredirects()
-#define snmp_inc_icmpinechos()
-#define snmp_inc_icmpinechoreps()
-#define snmp_inc_icmpintimestamps()
-#define snmp_inc_icmpintimestampreps()
-#define snmp_inc_icmpinaddrmasks()
-#define snmp_inc_icmpinaddrmaskreps()
-#define snmp_inc_icmpoutmsgs()
-#define snmp_inc_icmpouterrors()
-#define snmp_inc_icmpoutdestunreachs()
-#define snmp_inc_icmpouttimeexcds()
-#define snmp_inc_icmpoutparmprobs()
-#define snmp_inc_icmpoutsrcquenchs()
-#define snmp_inc_icmpoutredirects()
-#define snmp_inc_icmpoutechos()
-#define snmp_inc_icmpoutechoreps()
-#define snmp_inc_icmpouttimestamps()
-#define snmp_inc_icmpouttimestampreps()
-#define snmp_inc_icmpoutaddrmasks()
-#define snmp_inc_icmpoutaddrmaskreps()
-/* TCP */
-#define snmp_inc_tcpactiveopens()
-#define snmp_inc_tcppassiveopens()
-#define snmp_inc_tcpattemptfails()
-#define snmp_inc_tcpestabresets()
-#define snmp_inc_tcpinsegs()
-#define snmp_inc_tcpoutsegs()
-#define snmp_inc_tcpretranssegs()
-#define snmp_inc_tcpinerrs()
-#define snmp_inc_tcpoutrsts()
-
-/* UDP */
-#define snmp_inc_udpindatagrams()
-#define snmp_inc_udpnoports()
-#define snmp_inc_udpinerrors()
-#define snmp_inc_udpoutdatagrams()
-#define snmp_insert_udpidx_tree(pcb)
-#define snmp_delete_udpidx_tree(pcb)
-
-/* SNMP */
-#define snmp_inc_snmpinpkts()
-#define snmp_inc_snmpoutpkts()
-#define snmp_inc_snmpinbadversions()
-#define snmp_inc_snmpinbadcommunitynames()
-#define snmp_inc_snmpinbadcommunityuses()
-#define snmp_inc_snmpinasnparseerrs()
-#define snmp_inc_snmpintoobigs()
-#define snmp_inc_snmpinnosuchnames()
-#define snmp_inc_snmpinbadvalues()
-#define snmp_inc_snmpinreadonlys()
-#define snmp_inc_snmpingenerrs()
-#define snmp_add_snmpintotalreqvars(value)
-#define snmp_add_snmpintotalsetvars(value)
-#define snmp_inc_snmpingetrequests()
-#define snmp_inc_snmpingetnexts()
-#define snmp_inc_snmpinsetrequests()
-#define snmp_inc_snmpingetresponses()
-#define snmp_inc_snmpintraps()
-#define snmp_inc_snmpouttoobigs()
-#define snmp_inc_snmpoutnosuchnames()
-#define snmp_inc_snmpoutbadvalues()
-#define snmp_inc_snmpoutgenerrs()
-#define snmp_inc_snmpoutgetrequests()
-#define snmp_inc_snmpoutgetnexts()
-#define snmp_inc_snmpoutsetrequests()
-#define snmp_inc_snmpoutgetresponses()
-#define snmp_inc_snmpouttraps()
-#define snmp_get_snmpgrpid_ptr(oid)
-#define snmp_set_snmpenableauthentraps(value)
-#define snmp_get_snmpenableauthentraps(value)
-
-#endif /* LWIP_SNMP */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_SNMP_H__ */
+++ /dev/null
-/**
- * @file
- * Abstract Syntax Notation One (ISO 8824, 8825) codec.
- */
-
-/*
- * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * Author: Christiaan Simons <christiaan.simons@axon.tv>
- */
-
-#ifndef __LWIP_SNMP_ASN1_H__
-#define __LWIP_SNMP_ASN1_H__
-
-#include "lwip/opt.h"
-#include "lwip/err.h"
-#include "lwip/pbuf.h"
-#include "lwip/snmp.h"
-
-#if LWIP_SNMP
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */
-#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */
-#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */
-
-#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */
-#define SNMP_ASN1_PRIMIT (0) /* (!0x20) */
-
-/* universal tags */
-#define SNMP_ASN1_INTEG 2
-#define SNMP_ASN1_OC_STR 4
-#define SNMP_ASN1_NUL 5
-#define SNMP_ASN1_OBJ_ID 6
-#define SNMP_ASN1_SEQ 16
-
-/* application specific (SNMP) tags */
-#define SNMP_ASN1_IPADDR 0 /* octet string size(4) */
-#define SNMP_ASN1_COUNTER 1 /* u32_t */
-#define SNMP_ASN1_GAUGE 2 /* u32_t */
-#define SNMP_ASN1_TIMETICKS 3 /* u32_t */
-#define SNMP_ASN1_OPAQUE 4 /* octet string */
-
-/* context specific (SNMP) tags */
-#define SNMP_ASN1_PDU_GET_REQ 0
-#define SNMP_ASN1_PDU_GET_NEXT_REQ 1
-#define SNMP_ASN1_PDU_GET_RESP 2
-#define SNMP_ASN1_PDU_SET_REQ 3
-#define SNMP_ASN1_PDU_TRAP 4
-
-err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type);
-err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length);
-err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value);
-err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value);
-err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid);
-err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw);
-
-void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);
-void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);
-void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
-void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed);
-err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type);
-err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length);
-err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value);
-err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value);
-err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident);
-err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_SNMP */
-
-#endif /* __LWIP_SNMP_ASN1_H__ */
+++ /dev/null
-/**
- * @file
- * SNMP Agent message handling structures.
- */
-
-/*
- * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * Author: Christiaan Simons <christiaan.simons@axon.tv>
- */
-
-#ifndef __LWIP_SNMP_MSG_H__
-#define __LWIP_SNMP_MSG_H__
-
-#include "lwip/opt.h"
-#include "lwip/snmp.h"
-#include "lwip/snmp_structs.h"
-#include "lwip/ip_addr.h"
-#include "lwip/err.h"
-
-#if LWIP_SNMP
-
-#if SNMP_PRIVATE_MIB
-/* When using a private MIB, you have to create a file 'private_mib.h' that contains
- * a 'struct mib_array_node mib_private' which contains your MIB. */
-#include "private_mib.h"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* The listen port of the SNMP agent. Clients have to make their requests to
- this port. Most standard clients won't work if you change this! */
-#ifndef SNMP_IN_PORT
-#define SNMP_IN_PORT 161
-#endif
-/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't
- work if you change this! */
-#ifndef SNMP_TRAP_PORT
-#define SNMP_TRAP_PORT 162
-#endif
-
-#define SNMP_ES_NOERROR 0
-#define SNMP_ES_TOOBIG 1
-#define SNMP_ES_NOSUCHNAME 2
-#define SNMP_ES_BADVALUE 3
-#define SNMP_ES_READONLY 4
-#define SNMP_ES_GENERROR 5
-
-#define SNMP_GENTRAP_COLDSTART 0
-#define SNMP_GENTRAP_WARMSTART 1
-#define SNMP_GENTRAP_AUTHFAIL 4
-#define SNMP_GENTRAP_ENTERPRISESPC 6
-
-struct snmp_varbind
-{
- /* next pointer, NULL for last in list */
- struct snmp_varbind *next;
- /* previous pointer, NULL for first in list */
- struct snmp_varbind *prev;
-
- /* object identifier length (in s32_t) */
- u8_t ident_len;
- /* object identifier array */
- s32_t *ident;
-
- /* object value ASN1 type */
- u8_t value_type;
- /* object value length (in u8_t) */
- u8_t value_len;
- /* object value */
- void *value;
-
- /* encoding varbind seq length length */
- u8_t seqlenlen;
- /* encoding object identifier length length */
- u8_t olenlen;
- /* encoding object value length length */
- u8_t vlenlen;
- /* encoding varbind seq length */
- u16_t seqlen;
- /* encoding object identifier length */
- u16_t olen;
- /* encoding object value length */
- u16_t vlen;
-};
-
-struct snmp_varbind_root
-{
- struct snmp_varbind *head;
- struct snmp_varbind *tail;
- /* number of variable bindings in list */
- u8_t count;
- /* encoding varbind-list seq length length */
- u8_t seqlenlen;
- /* encoding varbind-list seq length */
- u16_t seqlen;
-};
-
-/** output response message header length fields */
-struct snmp_resp_header_lengths
-{
- /* encoding error-index length length */
- u8_t erridxlenlen;
- /* encoding error-status length length */
- u8_t errstatlenlen;
- /* encoding request id length length */
- u8_t ridlenlen;
- /* encoding pdu length length */
- u8_t pdulenlen;
- /* encoding community length length */
- u8_t comlenlen;
- /* encoding version length length */
- u8_t verlenlen;
- /* encoding sequence length length */
- u8_t seqlenlen;
-
- /* encoding error-index length */
- u16_t erridxlen;
- /* encoding error-status length */
- u16_t errstatlen;
- /* encoding request id length */
- u16_t ridlen;
- /* encoding pdu length */
- u16_t pdulen;
- /* encoding community length */
- u16_t comlen;
- /* encoding version length */
- u16_t verlen;
- /* encoding sequence length */
- u16_t seqlen;
-};
-
-/** output response message header length fields */
-struct snmp_trap_header_lengths
-{
- /* encoding timestamp length length */
- u8_t tslenlen;
- /* encoding specific-trap length length */
- u8_t strplenlen;
- /* encoding generic-trap length length */
- u8_t gtrplenlen;
- /* encoding agent-addr length length */
- u8_t aaddrlenlen;
- /* encoding enterprise-id length length */
- u8_t eidlenlen;
- /* encoding pdu length length */
- u8_t pdulenlen;
- /* encoding community length length */
- u8_t comlenlen;
- /* encoding version length length */
- u8_t verlenlen;
- /* encoding sequence length length */
- u8_t seqlenlen;
-
- /* encoding timestamp length */
- u16_t tslen;
- /* encoding specific-trap length */
- u16_t strplen;
- /* encoding generic-trap length */
- u16_t gtrplen;
- /* encoding agent-addr length */
- u16_t aaddrlen;
- /* encoding enterprise-id length */
- u16_t eidlen;
- /* encoding pdu length */
- u16_t pdulen;
- /* encoding community length */
- u16_t comlen;
- /* encoding version length */
- u16_t verlen;
- /* encoding sequence length */
- u16_t seqlen;
-};
-
-/* Accepting new SNMP messages. */
-#define SNMP_MSG_EMPTY 0
-/* Search for matching object for variable binding. */
-#define SNMP_MSG_SEARCH_OBJ 1
-/* Perform SNMP operation on in-memory object.
- Pass-through states, for symmetry only. */
-#define SNMP_MSG_INTERNAL_GET_OBJDEF 2
-#define SNMP_MSG_INTERNAL_GET_VALUE 3
-#define SNMP_MSG_INTERNAL_SET_TEST 4
-#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5
-#define SNMP_MSG_INTERNAL_SET_VALUE 6
-/* Perform SNMP operation on object located externally.
- In theory this could be used for building a proxy agent.
- Practical use is for an enterprise spc. app. gateway. */
-#define SNMP_MSG_EXTERNAL_GET_OBJDEF 7
-#define SNMP_MSG_EXTERNAL_GET_VALUE 8
-#define SNMP_MSG_EXTERNAL_SET_TEST 9
-#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10
-#define SNMP_MSG_EXTERNAL_SET_VALUE 11
-
-#define SNMP_COMMUNITY_STR_LEN 64
-struct snmp_msg_pstat
-{
- /* lwIP local port (161) binding */
- struct udp_pcb *pcb;
- /* source IP address */
- ip_addr_t sip;
- /* source UDP port */
- u16_t sp;
- /* request type */
- u8_t rt;
- /* request ID */
- s32_t rid;
- /* error status */
- s32_t error_status;
- /* error index */
- s32_t error_index;
- /* community name (zero terminated) */
- u8_t community[SNMP_COMMUNITY_STR_LEN + 1];
- /* community string length (exclusive zero term) */
- u8_t com_strlen;
- /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */
- u8_t state;
- /* saved arguments for MSG_EXTERNAL_x */
- struct mib_external_node *ext_mib_node;
- struct snmp_name_ptr ext_name_ptr;
- struct obj_def ext_object_def;
- struct snmp_obj_id ext_oid;
- /* index into input variable binding list */
- u8_t vb_idx;
- /* ptr into input variable binding list */
- struct snmp_varbind *vb_ptr;
- /* list of variable bindings from input */
- struct snmp_varbind_root invb;
- /* list of variable bindings to output */
- struct snmp_varbind_root outvb;
- /* output response lengths used in ASN encoding */
- struct snmp_resp_header_lengths rhl;
-};
-
-struct snmp_msg_trap
-{
- /* lwIP local port (161) binding */
- struct udp_pcb *pcb;
- /* destination IP address in network order */
- ip_addr_t dip;
-
- /* source enterprise ID (sysObjectID) */
- struct snmp_obj_id *enterprise;
- /* source IP address, raw network order format */
- u8_t sip_raw[4];
- /* generic trap code */
- u32_t gen_trap;
- /* specific trap code */
- u32_t spc_trap;
- /* timestamp */
- u32_t ts;
- /* list of variable bindings to output */
- struct snmp_varbind_root outvb;
- /* output trap lengths used in ASN encoding */
- struct snmp_trap_header_lengths thl;
-};
-
-/** Agent Version constant, 0 = v1 oddity */
-extern const s32_t snmp_version;
-/** Agent default "public" community string */
-extern const char snmp_publiccommunity[7];
-
-extern struct snmp_msg_trap trap_msg;
-
-/** Agent setup, start listening to port 161. */
-void snmp_init(void);
-void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable);
-void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst);
-
-/** Varbind-list functions. */
-struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len);
-void snmp_varbind_free(struct snmp_varbind *vb);
-void snmp_varbind_list_free(struct snmp_varbind_root *root);
-void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb);
-struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root);
-
-/** Handle an internal (recv) or external (private response) event. */
-void snmp_msg_event(u8_t request_id);
-err_t snmp_send_response(struct snmp_msg_pstat *m_stat);
-err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap);
-void snmp_coldstart_trap(void);
-void snmp_authfail_trap(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_SNMP */
-
-#endif /* __LWIP_SNMP_MSG_H__ */
+++ /dev/null
-/**
- * @file
- * Generic MIB tree structures.
- *
- * @todo namespace prefixes
- */
-
-/*
- * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * Author: Christiaan Simons <christiaan.simons@axon.tv>
- */
-
-#ifndef __LWIP_SNMP_STRUCTS_H__
-#define __LWIP_SNMP_STRUCTS_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/snmp.h"
-
-#if SNMP_PRIVATE_MIB
-/* When using a private MIB, you have to create a file 'private_mib.h' that contains
- * a 'struct mib_array_node mib_private' which contains your MIB. */
-#include "private_mib.h"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* MIB object instance */
-#define MIB_OBJECT_NONE 0
-#define MIB_OBJECT_SCALAR 1
-#define MIB_OBJECT_TAB 2
-
-/* MIB access types */
-#define MIB_ACCESS_READ 1
-#define MIB_ACCESS_WRITE 2
-
-/* MIB object access */
-#define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ
-#define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE)
-#define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE
-#define MIB_OBJECT_NOT_ACCESSIBLE 0
-
-/** object definition returned by (get_object_def)() */
-struct obj_def
-{
- /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */
- u8_t instance;
- /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */
- u8_t access;
- /* ASN type for this object */
- u8_t asn_type;
- /* value length (host length) */
- u16_t v_len;
- /* length of instance part of supplied object identifier */
- u8_t id_inst_len;
- /* instance part of supplied object identifier */
- s32_t *id_inst_ptr;
-};
-
-struct snmp_name_ptr
-{
- u8_t ident_len;
- s32_t *ident;
-};
-
-/** MIB const scalar (.0) node */
-#define MIB_NODE_SC 0x01
-/** MIB const array node */
-#define MIB_NODE_AR 0x02
-/** MIB array node (mem_malloced from RAM) */
-#define MIB_NODE_RA 0x03
-/** MIB list root node (mem_malloced from RAM) */
-#define MIB_NODE_LR 0x04
-/** MIB node for external objects */
-#define MIB_NODE_EX 0x05
-
-/** node "base class" layout, the mandatory fields for a node */
-struct mib_node
-{
- /** returns struct obj_def for the given object identifier */
- void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
- /** returns object value for the given object identifier,
- @note the caller must allocate at least len bytes for the value */
- void (*get_value)(struct obj_def *od, u16_t len, void *value);
- /** tests length and/or range BEFORE setting */
- u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
- /** sets object value, only to be called when set_test() */
- void (*set_value)(struct obj_def *od, u16_t len, void *value);
- /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */
- u8_t node_type;
- /* array or max list length */
- u16_t maxlength;
-};
-
-/** derived node for scalars .0 index */
-typedef struct mib_node mib_scalar_node;
-
-/** derived node, points to a fixed size const array
- of sub-identifiers plus a 'child' pointer */
-struct mib_array_node
-{
- /* inherited "base class" members */
- void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
- void (*get_value)(struct obj_def *od, u16_t len, void *value);
- u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
- void (*set_value)(struct obj_def *od, u16_t len, void *value);
-
- u8_t node_type;
- u16_t maxlength;
-
- /* additional struct members */
- const s32_t *objid;
- struct mib_node* const *nptr;
-};
-
-/** derived node, points to a fixed size mem_malloced array
- of sub-identifiers plus a 'child' pointer */
-struct mib_ram_array_node
-{
- /* inherited "base class" members */
- void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
- void (*get_value)(struct obj_def *od, u16_t len, void *value);
- u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
- void (*set_value)(struct obj_def *od, u16_t len, void *value);
-
- u8_t node_type;
- u16_t maxlength;
-
- /* aditional struct members */
- s32_t *objid;
- struct mib_node **nptr;
-};
-
-struct mib_list_node
-{
- struct mib_list_node *prev;
- struct mib_list_node *next;
- s32_t objid;
- struct mib_node *nptr;
-};
-
-/** derived node, points to a doubly linked list
- of sub-identifiers plus a 'child' pointer */
-struct mib_list_rootnode
-{
- /* inherited "base class" members */
- void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
- void (*get_value)(struct obj_def *od, u16_t len, void *value);
- u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
- void (*set_value)(struct obj_def *od, u16_t len, void *value);
-
- u8_t node_type;
- u16_t maxlength;
-
- /* additional struct members */
- struct mib_list_node *head;
- struct mib_list_node *tail;
- /* counts list nodes in list */
- u16_t count;
-};
-
-/** derived node, has access functions for mib object in external memory or device
- using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */
-struct mib_external_node
-{
- /* inherited "base class" members */
- void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
- void (*get_value)(struct obj_def *od, u16_t len, void *value);
- u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
- void (*set_value)(struct obj_def *od, u16_t len, void *value);
-
- u8_t node_type;
- u16_t maxlength;
-
- /* additional struct members */
- /** points to an external (in memory) record of some sort of addressing
- information, passed to and interpreted by the funtions below */
- void* addr_inf;
- /** tree levels under this node */
- u8_t tree_levels;
- /** number of objects at this level */
- u16_t (*level_length)(void* addr_inf, u8_t level);
- /** compares object sub identifier with external id
- return zero when equal, nonzero when unequal */
- s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id);
- void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id);
-
- /** async Questions */
- void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident);
- void (*get_value_q)(u8_t rid, struct obj_def *od);
- void (*set_test_q)(u8_t rid, struct obj_def *od);
- void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value);
- /** async Answers */
- void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od);
- void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);
- u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);
- void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);
- /** async Panic Close (agent returns error reply,
- e.g. used for external transaction cleanup) */
- void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident);
- void (*get_value_pc)(u8_t rid, struct obj_def *od);
- void (*set_test_pc)(u8_t rid, struct obj_def *od);
- void (*set_value_pc)(u8_t rid, struct obj_def *od);
-};
-
-/** export MIB tree from mib2.c */
-extern const struct mib_array_node internet;
-
-/** dummy function pointers for non-leaf MIB nodes from mib2.c */
-void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
-void noleafs_get_value(struct obj_def *od, u16_t len, void *value);
-u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value);
-void noleafs_set_value(struct obj_def *od, u16_t len, void *value);
-
-void snmp_oidtoip(s32_t *ident, ip_addr_t *ip);
-void snmp_iptooid(ip_addr_t *ip, s32_t *ident);
-void snmp_ifindextonetif(s32_t ifindex, struct netif **netif);
-void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx);
-
-struct mib_list_node* snmp_mib_ln_alloc(s32_t id);
-void snmp_mib_ln_free(struct mib_list_node *ln);
-struct mib_list_rootnode* snmp_mib_lrn_alloc(void);
-void snmp_mib_lrn_free(struct mib_list_rootnode *lrn);
-
-s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn);
-s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn);
-struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n);
-
-struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np);
-struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);
-u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident);
-u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_SNMP */
-
-#endif /* __LWIP_SNMP_STRUCTS_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-
-#ifndef __LWIP_SOCKETS_H__
-#define __LWIP_SOCKETS_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
-
-#include <stddef.h> /* for size_t */
-
-#include "lwip/ip_addr.h"
-#include "lwip/inet.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* members are in network byte order */
-struct sockaddr_in {
- u8_t sin_len;
- u8_t sin_family;
- u16_t sin_port;
- struct in_addr sin_addr;
- char sin_zero[8];
-};
-
-struct sockaddr {
- u8_t sa_len;
- u8_t sa_family;
- char sa_data[14];
-};
-
-#ifndef socklen_t
-# define socklen_t u32_t
-#endif
-
-/* Socket protocol types (TCP/UDP/RAW) */
-#define SOCK_STREAM 1
-#define SOCK_DGRAM 2
-#define SOCK_RAW 3
-
-/*
- * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c)
- */
-#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */
-#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
-#define SO_REUSEADDR 0x0004 /* Allow local address reuse */
-#define SO_KEEPALIVE 0x0008 /* keep connections alive */
-#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */
-#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
-#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */
-#define SO_LINGER 0x0080 /* linger on close if data present */
-#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */
-#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */
-
-#define SO_DONTLINGER ((int)(~SO_LINGER))
-
-/*
- * Additional options, not kept in so_options.
- */
-#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */
-#define SO_RCVBUF 0x1002 /* receive buffer size */
-#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */
-#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */
-#define SO_SNDTIMEO 0x1005 /* Unimplemented: send timeout */
-#define SO_RCVTIMEO 0x1006 /* receive timeout */
-#define SO_ERROR 0x1007 /* get error status and clear */
-#define SO_TYPE 0x1008 /* get socket type */
-#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */
-#define SO_NO_CHECK 0x100a /* don't create UDP checksum */
-
-
-/*
- * Structure used for manipulating linger option.
- */
-struct linger {
- int l_onoff; /* option on/off */
- int l_linger; /* linger time */
-};
-
-/*
- * Level number for (get/set)sockopt() to apply to socket itself.
- */
-#define SOL_SOCKET 0xfff /* options for socket level */
-
-
-#define AF_UNSPEC 0
-#define AF_INET 2
-#define PF_INET AF_INET
-#define PF_UNSPEC AF_UNSPEC
-
-#define IPPROTO_IP 0
-#define IPPROTO_TCP 6
-#define IPPROTO_UDP 17
-#define IPPROTO_UDPLITE 136
-
-/* Flags we can use with send and recv. */
-#define MSG_PEEK 0x01 /* Peeks at an incoming message */
-#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */
-#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */
-#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */
-#define MSG_MORE 0x10 /* Sender will send more */
-
-
-/*
- * Options for level IPPROTO_IP
- */
-#define IP_TOS 1
-#define IP_TTL 2
-
-#if LWIP_TCP
-/*
- * Options for level IPPROTO_TCP
- */
-#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
-#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */
-#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */
-#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */
-#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */
-#endif /* LWIP_TCP */
-
-#if LWIP_UDP && LWIP_UDPLITE
-/*
- * Options for level IPPROTO_UDPLITE
- */
-#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */
-#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */
-#endif /* LWIP_UDP && LWIP_UDPLITE*/
-
-
-#if LWIP_IGMP
-/*
- * Options and types for UDP multicast traffic handling
- */
-#define IP_ADD_MEMBERSHIP 3
-#define IP_DROP_MEMBERSHIP 4
-#define IP_MULTICAST_TTL 5
-#define IP_MULTICAST_IF 6
-#define IP_MULTICAST_LOOP 7
-
-typedef struct ip_mreq {
- struct in_addr imr_multiaddr; /* IP multicast address of group */
- struct in_addr imr_interface; /* local IP address of interface */
-} ip_mreq;
-#endif /* LWIP_IGMP */
-
-/*
- * The Type of Service provides an indication of the abstract
- * parameters of the quality of service desired. These parameters are
- * to be used to guide the selection of the actual service parameters
- * when transmitting a datagram through a particular network. Several
- * networks offer service precedence, which somehow treats high
- * precedence traffic as more important than other traffic (generally
- * by accepting only traffic above a certain precedence at time of high
- * load). The major choice is a three way tradeoff between low-delay,
- * high-reliability, and high-throughput.
- * The use of the Delay, Throughput, and Reliability indications may
- * increase the cost (in some sense) of the service. In many networks
- * better performance for one of these parameters is coupled with worse
- * performance on another. Except for very unusual cases at most two
- * of these three indications should be set.
- */
-#define IPTOS_TOS_MASK 0x1E
-#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK)
-#define IPTOS_LOWDELAY 0x10
-#define IPTOS_THROUGHPUT 0x08
-#define IPTOS_RELIABILITY 0x04
-#define IPTOS_LOWCOST 0x02
-#define IPTOS_MINCOST IPTOS_LOWCOST
-
-/*
- * The Network Control precedence designation is intended to be used
- * within a network only. The actual use and control of that
- * designation is up to each network. The Internetwork Control
- * designation is intended for use by gateway control originators only.
- * If the actual use of these precedence designations is of concern to
- * a particular network, it is the responsibility of that network to
- * control the access to, and use of, those precedence designations.
- */
-#define IPTOS_PREC_MASK 0xe0
-#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK)
-#define IPTOS_PREC_NETCONTROL 0xe0
-#define IPTOS_PREC_INTERNETCONTROL 0xc0
-#define IPTOS_PREC_CRITIC_ECP 0xa0
-#define IPTOS_PREC_FLASHOVERRIDE 0x80
-#define IPTOS_PREC_FLASH 0x60
-#define IPTOS_PREC_IMMEDIATE 0x40
-#define IPTOS_PREC_PRIORITY 0x20
-#define IPTOS_PREC_ROUTINE 0x00
-
-
-/*
- * Commands for ioctlsocket(), taken from the BSD file fcntl.h.
- * lwip_ioctl only supports FIONREAD and FIONBIO, for now
- *
- * Ioctl's have the command encoded in the lower word,
- * and the size of any in or out parameters in the upper
- * word. The high 2 bits of the upper word are used
- * to encode the in/out status of the parameter; for now
- * we restrict parameters to at most 128 bytes.
- */
-#if !defined(FIONREAD) || !defined(FIONBIO)
-#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */
-#define IOC_VOID 0x20000000UL /* no parameters */
-#define IOC_OUT 0x40000000UL /* copy out parameters */
-#define IOC_IN 0x80000000UL /* copy in parameters */
-#define IOC_INOUT (IOC_IN|IOC_OUT)
- /* 0x20000000 distinguishes new &
- old ioctl's */
-#define _IO(x,y) (IOC_VOID|((x)<<8)|(y))
-
-#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
-
-#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
-#endif /* !defined(FIONREAD) || !defined(FIONBIO) */
-
-#ifndef FIONREAD
-#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */
-#endif
-#ifndef FIONBIO
-#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */
-#endif
-
-/* Socket I/O Controls: unimplemented */
-#ifndef SIOCSHIWAT
-#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */
-#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */
-#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */
-#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */
-#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */
-#endif
-
-/* commands for fnctl */
-#ifndef F_GETFL
-#define F_GETFL 3
-#endif
-#ifndef F_SETFL
-#define F_SETFL 4
-#endif
-
-/* File status flags and file access modes for fnctl,
- these are bits in an int. */
-#ifndef O_NONBLOCK
-#define O_NONBLOCK 1 /* nonblocking I/O */
-#endif
-#ifndef O_NDELAY
-#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */
-#endif
-
-#ifndef SHUT_RD
- #define SHUT_RD 0
- #define SHUT_WR 1
- #define SHUT_RDWR 2
-#endif
-
-/* FD_SET used for lwip_select */
-#ifndef FD_SET
- #undef FD_SETSIZE
- /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */
- #define FD_SETSIZE MEMP_NUM_NETCONN
- #define FD_SET(n, p) ((p)->fd_bits[(n)/8] |= (1 << ((n) & 7)))
- #define FD_CLR(n, p) ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7)))
- #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] & (1 << ((n) & 7)))
- #define FD_ZERO(p) memset((void*)(p),0,sizeof(*(p)))
-
- typedef struct fd_set {
- unsigned char fd_bits [(FD_SETSIZE+7)/8];
- } fd_set;
-
-#endif /* FD_SET */
-
-/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided
- * by your system, set this to 0 and include <sys/time.h> in cc.h */
-#ifndef LWIP_TIMEVAL_PRIVATE
-#define LWIP_TIMEVAL_PRIVATE 1
-#endif
-
-#if LWIP_TIMEVAL_PRIVATE
-struct timeval {
- long tv_sec; /* seconds */
- long tv_usec; /* and microseconds */
-};
-#endif /* LWIP_TIMEVAL_PRIVATE */
-
-void lwip_socket_init(void);
-
-int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
-int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen);
-int lwip_shutdown(int s, int how);
-int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen);
-int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen);
-int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen);
-int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen);
-int lwip_close(int s);
-int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen);
-int lwip_listen(int s, int backlog);
-int lwip_recv(int s, void *mem, size_t len, int flags);
-int lwip_read(int s, void *mem, size_t len);
-int lwip_recvfrom(int s, void *mem, size_t len, int flags,
- struct sockaddr *from, socklen_t *fromlen);
-int lwip_send(int s, const void *dataptr, size_t size, int flags);
-int lwip_sendto(int s, const void *dataptr, size_t size, int flags,
- const struct sockaddr *to, socklen_t tolen);
-int lwip_socket(int domain, int type, int protocol);
-int lwip_write(int s, const void *dataptr, size_t size);
-int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
- struct timeval *timeout);
-int lwip_ioctl(int s, long cmd, void *argp);
-int lwip_fcntl(int s, int cmd, int val);
-
-#if LWIP_COMPAT_SOCKETS
-#define accept(a,b,c) lwip_accept(a,b,c)
-#define bind(a,b,c) lwip_bind(a,b,c)
-#define shutdown(a,b) lwip_shutdown(a,b)
-#define closesocket(s) lwip_close(s)
-#define connect(a,b,c) lwip_connect(a,b,c)
-#define getsockname(a,b,c) lwip_getsockname(a,b,c)
-#define getpeername(a,b,c) lwip_getpeername(a,b,c)
-#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)
-#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)
-#define listen(a,b) lwip_listen(a,b)
-#define recv(a,b,c,d) lwip_recv(a,b,c,d)
-#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)
-#define send(a,b,c,d) lwip_send(a,b,c,d)
-#define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f)
-#define socket(a,b,c) lwip_socket(a,b,c)
-#define select(a,b,c,d,e) lwip_select(a,b,c,d,e)
-#define ioctlsocket(a,b,c) lwip_ioctl(a,b,c)
-
-#if LWIP_POSIX_SOCKETS_IO_NAMES
-#define read(a,b,c) lwip_read(a,b,c)
-#define write(a,b,c) lwip_write(a,b,c)
-#define close(s) lwip_close(s)
-#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */
-
-#endif /* LWIP_COMPAT_SOCKETS */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_SOCKET */
-
-#endif /* __LWIP_SOCKETS_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_STATS_H__
-#define __LWIP_STATS_H__
-
-#include "lwip/opt.h"
-
-#include "lwip/mem.h"
-#include "lwip/memp.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if LWIP_STATS
-
-#ifndef LWIP_STATS_LARGE
-#define LWIP_STATS_LARGE 0
-#endif
-
-#if LWIP_STATS_LARGE
-#define STAT_COUNTER u32_t
-#define STAT_COUNTER_F U32_F
-#else
-#define STAT_COUNTER u16_t
-#define STAT_COUNTER_F U16_F
-#endif
-
-struct stats_proto {
- STAT_COUNTER xmit; /* Transmitted packets. */
- STAT_COUNTER recv; /* Received packets. */
- STAT_COUNTER fw; /* Forwarded packets. */
- STAT_COUNTER drop; /* Dropped packets. */
- STAT_COUNTER chkerr; /* Checksum error. */
- STAT_COUNTER lenerr; /* Invalid length error. */
- STAT_COUNTER memerr; /* Out of memory error. */
- STAT_COUNTER rterr; /* Routing error. */
- STAT_COUNTER proterr; /* Protocol error. */
- STAT_COUNTER opterr; /* Error in options. */
- STAT_COUNTER err; /* Misc error. */
- STAT_COUNTER cachehit;
-};
-
-struct stats_igmp {
- STAT_COUNTER xmit; /* Transmitted packets. */
- STAT_COUNTER recv; /* Received packets. */
- STAT_COUNTER drop; /* Dropped packets. */
- STAT_COUNTER chkerr; /* Checksum error. */
- STAT_COUNTER lenerr; /* Invalid length error. */
- STAT_COUNTER memerr; /* Out of memory error. */
- STAT_COUNTER proterr; /* Protocol error. */
- STAT_COUNTER rx_v1; /* Received v1 frames. */
- STAT_COUNTER rx_group; /* Received group-specific queries. */
- STAT_COUNTER rx_general; /* Received general queries. */
- STAT_COUNTER rx_report; /* Received reports. */
- STAT_COUNTER tx_join; /* Sent joins. */
- STAT_COUNTER tx_leave; /* Sent leaves. */
- STAT_COUNTER tx_report; /* Sent reports. */
-};
-
-struct stats_mem {
-#ifdef LWIP_DEBUG
- const char *name;
-#endif /* LWIP_DEBUG */
- mem_size_t avail;
- mem_size_t used;
- mem_size_t max;
- STAT_COUNTER err;
- STAT_COUNTER illegal;
-};
-
-struct stats_syselem {
- STAT_COUNTER used;
- STAT_COUNTER max;
- STAT_COUNTER err;
-};
-
-struct stats_sys {
- struct stats_syselem sem;
- struct stats_syselem mutex;
- struct stats_syselem mbox;
-};
-
-struct stats_ {
-#if LINK_STATS
- struct stats_proto link;
-#endif
-#if ETHARP_STATS
- struct stats_proto etharp;
-#endif
-#if IPFRAG_STATS
- struct stats_proto ip_frag;
-#endif
-#if IP_STATS
- struct stats_proto ip;
-#endif
-#if ICMP_STATS
- struct stats_proto icmp;
-#endif
-#if IGMP_STATS
- struct stats_igmp igmp;
-#endif
-#if UDP_STATS
- struct stats_proto udp;
-#endif
-#if TCP_STATS
- struct stats_proto tcp;
-#endif
-#if MEM_STATS
- struct stats_mem mem;
-#endif
-#if MEMP_STATS
- struct stats_mem memp[MEMP_MAX];
-#endif
-#if SYS_STATS
- struct stats_sys sys;
-#endif
-};
-
-extern struct stats_ lwip_stats;
-
-void stats_init(void);
-
-#define STATS_INC(x) ++lwip_stats.x
-#define STATS_DEC(x) --lwip_stats.x
-#define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \
- if (lwip_stats.x.max < lwip_stats.x.used) { \
- lwip_stats.x.max = lwip_stats.x.used; \
- } \
- } while(0)
-#else /* LWIP_STATS */
-#define stats_init()
-#define STATS_INC(x)
-#define STATS_DEC(x)
-#define STATS_INC_USED(x)
-#endif /* LWIP_STATS */
-
-#if TCP_STATS
-#define TCP_STATS_INC(x) STATS_INC(x)
-#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP")
-#else
-#define TCP_STATS_INC(x)
-#define TCP_STATS_DISPLAY()
-#endif
-
-#if UDP_STATS
-#define UDP_STATS_INC(x) STATS_INC(x)
-#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP")
-#else
-#define UDP_STATS_INC(x)
-#define UDP_STATS_DISPLAY()
-#endif
-
-#if ICMP_STATS
-#define ICMP_STATS_INC(x) STATS_INC(x)
-#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP")
-#else
-#define ICMP_STATS_INC(x)
-#define ICMP_STATS_DISPLAY()
-#endif
-
-#if IGMP_STATS
-#define IGMP_STATS_INC(x) STATS_INC(x)
-#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp)
-#else
-#define IGMP_STATS_INC(x)
-#define IGMP_STATS_DISPLAY()
-#endif
-
-#if IP_STATS
-#define IP_STATS_INC(x) STATS_INC(x)
-#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP")
-#else
-#define IP_STATS_INC(x)
-#define IP_STATS_DISPLAY()
-#endif
-
-#if IPFRAG_STATS
-#define IPFRAG_STATS_INC(x) STATS_INC(x)
-#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG")
-#else
-#define IPFRAG_STATS_INC(x)
-#define IPFRAG_STATS_DISPLAY()
-#endif
-
-#if ETHARP_STATS
-#define ETHARP_STATS_INC(x) STATS_INC(x)
-#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP")
-#else
-#define ETHARP_STATS_INC(x)
-#define ETHARP_STATS_DISPLAY()
-#endif
-
-#if LINK_STATS
-#define LINK_STATS_INC(x) STATS_INC(x)
-#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK")
-#else
-#define LINK_STATS_INC(x)
-#define LINK_STATS_DISPLAY()
-#endif
-
-#if MEM_STATS
-#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y
-#define MEM_STATS_INC(x) STATS_INC(mem.x)
-#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y)
-#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y
-#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP")
-#else
-#define MEM_STATS_AVAIL(x, y)
-#define MEM_STATS_INC(x)
-#define MEM_STATS_INC_USED(x, y)
-#define MEM_STATS_DEC_USED(x, y)
-#define MEM_STATS_DISPLAY()
-#endif
-
-#if MEMP_STATS
-#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y
-#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x)
-#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x)
-#define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1)
-#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i)
-#else
-#define MEMP_STATS_AVAIL(x, i, y)
-#define MEMP_STATS_INC(x, i)
-#define MEMP_STATS_DEC(x, i)
-#define MEMP_STATS_INC_USED(x, i)
-#define MEMP_STATS_DISPLAY(i)
-#endif
-
-#if SYS_STATS
-#define SYS_STATS_INC(x) STATS_INC(sys.x)
-#define SYS_STATS_DEC(x) STATS_DEC(sys.x)
-#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1)
-#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys)
-#else
-#define SYS_STATS_INC(x)
-#define SYS_STATS_DEC(x)
-#define SYS_STATS_INC_USED(x)
-#define SYS_STATS_DISPLAY()
-#endif
-
-/* Display of statistics */
-#if LWIP_STATS_DISPLAY
-void stats_display(void);
-void stats_display_proto(struct stats_proto *proto, char *name);
-void stats_display_igmp(struct stats_igmp *igmp);
-void stats_display_mem(struct stats_mem *mem, char *name);
-void stats_display_memp(struct stats_mem *mem, int index);
-void stats_display_sys(struct stats_sys *sys);
-#else /* LWIP_STATS_DISPLAY */
-#define stats_display()
-#define stats_display_proto(proto, name)
-#define stats_display_igmp(igmp)
-#define stats_display_mem(mem, name)
-#define stats_display_memp(mem, index)
-#define stats_display_sys(sys)
-#endif /* LWIP_STATS_DISPLAY */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_STATS_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_SYS_H__
-#define __LWIP_SYS_H__
-
-#include "lwip/opt.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if NO_SYS
-
-/* For a totally minimal and standalone system, we provide null
- definitions of the sys_ functions. */
-typedef u8_t sys_sem_t;
-typedef u8_t sys_mutex_t;
-typedef u8_t sys_mbox_t;
-
-#define sys_sem_new(s, c) ERR_OK
-#define sys_sem_signal(s)
-#define sys_sem_wait(s)
-#define sys_arch_sem_wait(s,t)
-#define sys_sem_free(s)
-#define sys_mutex_new(mu) ERR_OK
-#define sys_mutex_lock(mu)
-#define sys_mutex_unlock(mu)
-#define sys_mutex_free(mu)
-#define sys_mbox_new(m, s) ERR_OK
-#define sys_mbox_fetch(m,d)
-#define sys_mbox_tryfetch(m,d)
-#define sys_mbox_post(m,d)
-#define sys_mbox_trypost(m,d)
-#define sys_mbox_free(m)
-
-#define sys_thread_new(n,t,a,s,p)
-
-#define sys_msleep(t)
-
-#else /* NO_SYS */
-
-/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */
-#define SYS_ARCH_TIMEOUT 0xffffffffUL
-
-/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate.
- * For now we use the same magic value, but we allow this to change in future.
- */
-#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT
-
-#include "lwip/err.h"
-#include "arch/sys_arch.h"
-
-/** Function prototype for thread functions */
-typedef void (*lwip_thread_fn)(void *arg);
-
-/* Function prototypes for functions to be implemented by platform ports
- (in sys_arch.c) */
-
-/* Mutex functions: */
-
-/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores
- should be used instead */
-#if LWIP_COMPAT_MUTEX
-/* for old ports that don't have mutexes: define them to binary semaphores */
-#define sys_mutex_t sys_sem_t
-#define sys_mutex_new(mutex) sys_sem_new(mutex, 1)
-#define sys_mutex_lock(mutex) sys_sem_wait(mutex)
-#define sys_mutex_unlock(mutex) sys_sem_signal(mutex)
-#define sys_mutex_free(mutex) sys_sem_free(mutex)
-#define sys_mutex_valid(mutex) sys_sem_valid(mutex)
-#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex)
-
-#else /* LWIP_COMPAT_MUTEX */
-
-/** Create a new mutex
- * @param mutex pointer to the mutex to create
- * @return a new mutex */
-err_t sys_mutex_new(sys_mutex_t *mutex);
-/** Lock a mutex
- * @param mutex the mutex to lock */
-void sys_mutex_lock(sys_mutex_t *mutex);
-/** Unlock a mutex
- * @param mutex the mutex to unlock */
-void sys_mutex_unlock(sys_mutex_t *mutex);
-/** Delete a semaphore
- * @param mutex the mutex to delete */
-void sys_mutex_free(sys_mutex_t *mutex);
-#ifndef sys_mutex_valid
-/** Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid */
-int sys_mutex_valid(sys_mutex_t *mutex);
-#endif
-#ifndef sys_mutex_set_invalid
-/** Set a mutex invalid so that sys_mutex_valid returns 0 */
-void sys_mutex_set_invalid(sys_mutex_t *mutex);
-#endif
-#endif /* LWIP_COMPAT_MUTEX */
-
-/* Semaphore functions: */
-
-/** Create a new semaphore
- * @param sem pointer to the semaphore to create
- * @param count initial count of the semaphore
- * @return ERR_OK if successful, another err_t otherwise */
-err_t sys_sem_new(sys_sem_t *sem, u8_t count);
-/** Signals a semaphore
- * @param sem the semaphore to signal */
-void sys_sem_signal(sys_sem_t *sem);
-/** Wait for a semaphore for the specified timeout
- * @param sem the semaphore to wait for
- * @param timeout timeout in milliseconds to wait (0 = wait forever)
- * @return time (in milliseconds) waited for the semaphore
- * or SYS_ARCH_TIMEOUT on timeout */
-u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout);
-/** Delete a semaphore
- * @param sem semaphore to delete */
-void sys_sem_free(sys_sem_t *sem);
-/** Wait for a semaphore - forever/no timeout */
-#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0)
-#ifndef sys_sem_valid
-/** Check if a sempahore is valid/allocated: return 1 for valid, 0 for invalid */
-int sys_sem_valid(sys_sem_t *sem);
-#endif
-#ifndef sys_sem_set_invalid
-/** Set a semaphore invalid so that sys_sem_valid returns 0 */
-void sys_sem_set_invalid(sys_sem_t *sem);
-#endif
-
-/* Time functions. */
-#ifndef sys_msleep
-void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */
-#endif
-
-/* Mailbox functions. */
-
-/** Create a new mbox of specified size
- * @param mbox pointer to the mbox to create
- * @param size (miminum) number of messages in this mbox
- * @return ERR_OK if successful, another err_t otherwise */
-err_t sys_mbox_new(sys_mbox_t *mbox, int size);
-/** Post a message to an mbox - may not fail
- * -> blocks if full, only used from tasks not from ISR
- * @param mbox mbox to posts the message
- * @param msg message to post (ATTENTION: can be NULL) */
-void sys_mbox_post(sys_mbox_t *mbox, void *msg);
-/** Try to post a message to an mbox - may fail if full or ISR
- * @param mbox mbox to posts the message
- * @param msg message to post (ATTENTION: can be NULL) */
-err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg);
-/** Wait for a new message to arrive in the mbox
- * @param mbox mbox to get a message from
- * @param msg pointer where the message is stored
- * @param timeout maximum time (in milliseconds) to wait for a message
- * @return time (in milliseconds) waited for a message, may be 0 if not waited
- or SYS_ARCH_TIMEOUT on timeout
- * The returned time has to be accurate to prevent timer jitter! */
-u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout);
-/* Allow port to override with a macro, e.g. special timout for sys_arch_mbox_fetch() */
-#ifndef sys_arch_mbox_tryfetch
-/** Wait for a new message to arrive in the mbox
- * @param mbox mbox to get a message from
- * @param msg pointer where the message is stored
- * @param timeout maximum time (in milliseconds) to wait for a message
- * @return 0 (milliseconds) if a message has been received
- * or SYS_MBOX_EMPTY if the mailbox is empty */
-u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg);
-#endif
-/** For now, we map straight to sys_arch implementation. */
-#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg)
-/** Delete an mbox
- * @param mbox mbox to delete */
-void sys_mbox_free(sys_mbox_t *mbox);
-#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0)
-#ifndef sys_mbox_valid
-/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */
-int sys_mbox_valid(sys_mbox_t *mbox);
-#endif
-#ifndef sys_mbox_set_invalid
-/** Set an mbox invalid so that sys_mbox_valid returns 0 */
-void sys_mbox_set_invalid(sys_mbox_t *mbox);
-#endif
-
-/** The only thread function:
- * Creates a new thread
- * @param name human-readable name for the thread (used for debugging purposes)
- * @param thread thread-function
- * @param arg parameter passed to 'thread'
- * @param stacksize stack size in bytes for the new thread (may be ignored by ports)
- * @param prio priority of the new thread (may be ignored by ports) */
-sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio);
-
-#endif /* NO_SYS */
-
-/* sys_init() must be called before anthing else. */
-void sys_init(void);
-
-#ifndef sys_jiffies
-/** Ticks/jiffies since power up. */
-u32_t sys_jiffies(void);
-#endif
-
-/** Returns the current time in milliseconds,
- * may be the same as sys_jiffies or at least based on it. */
-u32_t sys_now(void);
-
-/* Critical Region Protection */
-/* These functions must be implemented in the sys_arch.c file.
- In some implementations they can provide a more light-weight protection
- mechanism than using semaphores. Otherwise semaphores can be used for
- implementation */
-#ifndef SYS_ARCH_PROTECT
-/** SYS_LIGHTWEIGHT_PROT
- * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection
- * for certain critical regions during buffer allocation, deallocation and memory
- * allocation and deallocation.
- */
-#if SYS_LIGHTWEIGHT_PROT
-
-/** SYS_ARCH_DECL_PROTECT
- * declare a protection variable. This macro will default to defining a variable of
- * type sys_prot_t. If a particular port needs a different implementation, then
- * this macro may be defined in sys_arch.h.
- */
-#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev
-/** SYS_ARCH_PROTECT
- * Perform a "fast" protect. This could be implemented by
- * disabling interrupts for an embedded system or by using a semaphore or
- * mutex. The implementation should allow calling SYS_ARCH_PROTECT when
- * already protected. The old protection level is returned in the variable
- * "lev". This macro will default to calling the sys_arch_protect() function
- * which should be implemented in sys_arch.c. If a particular port needs a
- * different implementation, then this macro may be defined in sys_arch.h
- */
-#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect()
-/** SYS_ARCH_UNPROTECT
- * Perform a "fast" set of the protection level to "lev". This could be
- * implemented by setting the interrupt level to "lev" within the MACRO or by
- * using a semaphore or mutex. This macro will default to calling the
- * sys_arch_unprotect() function which should be implemented in
- * sys_arch.c. If a particular port needs a different implementation, then
- * this macro may be defined in sys_arch.h
- */
-#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev)
-sys_prot_t sys_arch_protect(void);
-void sys_arch_unprotect(sys_prot_t pval);
-
-#else
-
-#define SYS_ARCH_DECL_PROTECT(lev)
-#define SYS_ARCH_PROTECT(lev)
-#define SYS_ARCH_UNPROTECT(lev)
-
-#endif /* SYS_LIGHTWEIGHT_PROT */
-
-#endif /* SYS_ARCH_PROTECT */
-
-/*
- * Macros to set/get and increase/decrease variables in a thread-safe way.
- * Use these for accessing variable that are used from more than one thread.
- */
-
-#ifndef SYS_ARCH_INC
-#define SYS_ARCH_INC(var, val) do { \
- SYS_ARCH_DECL_PROTECT(old_level); \
- SYS_ARCH_PROTECT(old_level); \
- var += val; \
- SYS_ARCH_UNPROTECT(old_level); \
- } while(0)
-#endif /* SYS_ARCH_INC */
-
-#ifndef SYS_ARCH_DEC
-#define SYS_ARCH_DEC(var, val) do { \
- SYS_ARCH_DECL_PROTECT(old_level); \
- SYS_ARCH_PROTECT(old_level); \
- var -= val; \
- SYS_ARCH_UNPROTECT(old_level); \
- } while(0)
-#endif /* SYS_ARCH_DEC */
-
-#ifndef SYS_ARCH_GET
-#define SYS_ARCH_GET(var, ret) do { \
- SYS_ARCH_DECL_PROTECT(old_level); \
- SYS_ARCH_PROTECT(old_level); \
- ret = var; \
- SYS_ARCH_UNPROTECT(old_level); \
- } while(0)
-#endif /* SYS_ARCH_GET */
-
-#ifndef SYS_ARCH_SET
-#define SYS_ARCH_SET(var, val) do { \
- SYS_ARCH_DECL_PROTECT(old_level); \
- SYS_ARCH_PROTECT(old_level); \
- var = val; \
- SYS_ARCH_UNPROTECT(old_level); \
- } while(0)
-#endif /* SYS_ARCH_SET */
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LWIP_SYS_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_TCP_H__
-#define __LWIP_TCP_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/sys.h"
-#include "lwip/mem.h"
-#include "lwip/pbuf.h"
-#include "lwip/ip.h"
-#include "lwip/icmp.h"
-#include "lwip/err.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct tcp_pcb;
-
-/** Function prototype for tcp accept callback functions. Called when a new
- * connection can be accepted on a listening pcb.
- *
- * @param arg Additional argument to pass to the callback function (@see tcp_arg())
- * @param newpcb The new connection pcb
- * @param err An error code if there has been an error accepting.
- * Only return ERR_ABRT if you have called tcp_abort from within the
- * callback function!
- */
-typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err);
-
-/** Function prototype for tcp receive callback functions. Called when data has
- * been received.
- *
- * @param arg Additional argument to pass to the callback function (@see tcp_arg())
- * @param tpcb The connection pcb which received data
- * @param p The received data (or NULL when the connection has been closed!)
- * @param err An error code if there has been an error receiving
- * Only return ERR_ABRT if you have called tcp_abort from within the
- * callback function!
- */
-typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb,
- struct pbuf *p, err_t err);
-
-/** Function prototype for tcp sent callback functions. Called when sent data has
- * been acknowledged by the remote side. Use it to free corresponding resources.
- * This also means that the pcb has now space available to send new data.
- *
- * @param arg Additional argument to pass to the callback function (@see tcp_arg())
- * @param tpcb The connection pcb for which data has been acknowledged
- * @param len The amount of bytes acknowledged
- * @return ERR_OK: try to send some data by calling tcp_output
- * Only return ERR_ABRT if you have called tcp_abort from within the
- * callback function!
- */
-typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb,
- u16_t len);
-
-/** Function prototype for tcp poll callback functions. Called periodically as
- * specified by @see tcp_poll.
- *
- * @param arg Additional argument to pass to the callback function (@see tcp_arg())
- * @param tpcb tcp pcb
- * @return ERR_OK: try to send some data by calling tcp_output
- * Only return ERR_ABRT if you have called tcp_abort from within the
- * callback function!
- */
-typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb);
-
-/** Function prototype for tcp error callback functions. Called when the pcb
- * receives a RST or is unexpectedly closed for any other reason.
- *
- * @note The corresponding pcb is already freed when this callback is called!
- *
- * @param arg Additional argument to pass to the callback function (@see tcp_arg())
- * @param err Error code to indicate why the pcb has been closed
- * ERR_ABRT: aborted through tcp_abort or by a TCP timer
- * ERR_RST: the connection was reset by the remote host
- */
-typedef void (*tcp_err_fn)(void *arg, err_t err);
-
-/** Function prototype for tcp connected callback functions. Called when a pcb
- * is connected to the remote side after initiating a connection attempt by
- * calling tcp_connect().
- *
- * @param arg Additional argument to pass to the callback function (@see tcp_arg())
- * @param tpcb The connection pcb which is connected
- * @param err An unused error code, always ERR_OK currently ;-) TODO!
- * Only return ERR_ABRT if you have called tcp_abort from within the
- * callback function!
- *
- * @note When a connection attempt fails, the error callback is currently called!
- */
-typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err);
-
-enum tcp_state {
- CLOSED = 0,
- LISTEN = 1,
- SYN_SENT = 2,
- SYN_RCVD = 3,
- ESTABLISHED = 4,
- FIN_WAIT_1 = 5,
- FIN_WAIT_2 = 6,
- CLOSE_WAIT = 7,
- CLOSING = 8,
- LAST_ACK = 9,
- TIME_WAIT = 10
-};
-
-#if LWIP_CALLBACK_API
- /* Function to call when a listener has been connected.
- * @param arg user-supplied argument (tcp_pcb.callback_arg)
- * @param pcb a new tcp_pcb that now is connected
- * @param err an error argument (TODO: that is current always ERR_OK?)
- * @return ERR_OK: accept the new connection,
- * any other err_t abortsthe new connection
- */
-#define DEF_ACCEPT_CALLBACK tcp_accept_fn accept;
-#else /* LWIP_CALLBACK_API */
-#define DEF_ACCEPT_CALLBACK
-#endif /* LWIP_CALLBACK_API */
-
-/**
- * members common to struct tcp_pcb and struct tcp_listen_pcb
- */
-#define TCP_PCB_COMMON(type) \
- type *next; /* for the linked list */ \
- enum tcp_state state; /* TCP state */ \
- u8_t prio; \
- void *callback_arg; \
- /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \
- DEF_ACCEPT_CALLBACK \
- /* ports are in host byte order */ \
- u16_t local_port
-
-
-/* the TCP protocol control block */
-struct tcp_pcb {
-/** common PCB members */
- IP_PCB;
-/** protocol specific PCB members */
- TCP_PCB_COMMON(struct tcp_pcb);
-
- /* ports are in host byte order */
- u16_t remote_port;
-
- u8_t flags;
-#define TF_ACK_DELAY ((u8_t)0x01U) /* Delayed ACK. */
-#define TF_ACK_NOW ((u8_t)0x02U) /* Immediate ACK. */
-#define TF_INFR ((u8_t)0x04U) /* In fast recovery. */
-#define TF_TIMESTAMP ((u8_t)0x08U) /* Timestamp option enabled */
-#define TF_RXCLOSED ((u8_t)0x10U) /* rx closed by tcp_shutdown */
-#define TF_FIN ((u8_t)0x20U) /* Connection was closed locally (FIN segment enqueued). */
-#define TF_NODELAY ((u8_t)0x40U) /* Disable Nagle algorithm */
-#define TF_NAGLEMEMERR ((u8_t)0x80U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */
-
- /* the rest of the fields are in host byte order
- as we have to do some math with them */
- /* receiver variables */
- u32_t rcv_nxt; /* next seqno expected */
- u16_t rcv_wnd; /* receiver window available */
- u16_t rcv_ann_wnd; /* receiver window to announce */
- u32_t rcv_ann_right_edge; /* announced right edge of window */
-
- /* Timers */
- u32_t tmr;
- u8_t polltmr, pollinterval;
-
- /* Retransmission timer. */
- s16_t rtime;
-
- u16_t mss; /* maximum segment size */
-
- /* RTT (round trip time) estimation variables */
- u32_t rttest; /* RTT estimate in 500ms ticks */
- u32_t rtseq; /* sequence number being timed */
- s16_t sa, sv; /* @todo document this */
-
- s16_t rto; /* retransmission time-out */
- u8_t nrtx; /* number of retransmissions */
-
- /* fast retransmit/recovery */
- u32_t lastack; /* Highest acknowledged seqno. */
- u8_t dupacks;
-
- /* congestion avoidance/control variables */
- u16_t cwnd;
- u16_t ssthresh;
-
- /* sender variables */
- u32_t snd_nxt; /* next new seqno to be sent */
- u16_t snd_wnd; /* sender window */
- u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last
- window update. */
- u32_t snd_lbb; /* Sequence number of next byte to be buffered. */
-
- u16_t acked;
-
- u16_t snd_buf; /* Available buffer space for sending (in bytes). */
-#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3)
- u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */
-
-#if TCP_OVERSIZE
- /* Extra bytes available at the end of the last pbuf in unsent. */
- u16_t unsent_oversize;
-#endif /* TCP_OVERSIZE */
-
- /* These are ordered by sequence number: */
- struct tcp_seg *unsent; /* Unsent (queued) segments. */
- struct tcp_seg *unacked; /* Sent but unacknowledged segments. */
-#if TCP_QUEUE_OOSEQ
- struct tcp_seg *ooseq; /* Received out of sequence segments. */
-#endif /* TCP_QUEUE_OOSEQ */
-
- struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */
-
-#if LWIP_CALLBACK_API
- /* Function to be called when more send buffer space is available. */
- tcp_sent_fn sent;
- /* Function to be called when (in-sequence) data has arrived. */
- tcp_recv_fn recv;
- /* Function to be called when a connection has been set up. */
- tcp_connected_fn connected;
- /* Function which is called periodically. */
- tcp_poll_fn poll;
- /* Function to be called whenever a fatal error occurs. */
- tcp_err_fn errf;
-#endif /* LWIP_CALLBACK_API */
-
-#if LWIP_TCP_TIMESTAMPS
- u32_t ts_lastacksent;
- u32_t ts_recent;
-#endif /* LWIP_TCP_TIMESTAMPS */
-
- /* idle time before KEEPALIVE is sent */
- u32_t keep_idle;
-#if LWIP_TCP_KEEPALIVE
- u32_t keep_intvl;
- u32_t keep_cnt;
-#endif /* LWIP_TCP_KEEPALIVE */
-
- /* Persist timer counter */
- u32_t persist_cnt;
- /* Persist timer back-off */
- u8_t persist_backoff;
-
- /* KEEPALIVE counter */
- u8_t keep_cnt_sent;
-};
-
-struct tcp_pcb_listen {
-/* Common members of all PCB types */
- IP_PCB;
-/* Protocol specific PCB members */
- TCP_PCB_COMMON(struct tcp_pcb_listen);
-
-#if TCP_LISTEN_BACKLOG
- u8_t backlog;
- u8_t accepts_pending;
-#endif /* TCP_LISTEN_BACKLOG */
-};
-
-#if LWIP_EVENT_API
-
-enum lwip_event {
- LWIP_EVENT_ACCEPT,
- LWIP_EVENT_SENT,
- LWIP_EVENT_RECV,
- LWIP_EVENT_CONNECTED,
- LWIP_EVENT_POLL,
- LWIP_EVENT_ERR
-};
-
-err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
- enum lwip_event,
- struct pbuf *p,
- u16_t size,
- err_t err);
-
-#endif /* LWIP_EVENT_API */
-
-/* Application program's interface: */
-struct tcp_pcb * tcp_new (void);
-
-void tcp_arg (struct tcp_pcb *pcb, void *arg);
-void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept);
-void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv);
-void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent);
-void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval);
-void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err);
-
-#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss)
-#define tcp_sndbuf(pcb) ((pcb)->snd_buf)
-#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen)
-#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY)
-#define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY)
-#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0)
-
-#if TCP_LISTEN_BACKLOG
-#define tcp_accepted(pcb) do { \
- LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", pcb->state == LISTEN); \
- (((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0)
-#else /* TCP_LISTEN_BACKLOG */
-#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \
- pcb->state == LISTEN)
-#endif /* TCP_LISTEN_BACKLOG */
-
-void tcp_recved (struct tcp_pcb *pcb, u16_t len);
-err_t tcp_bind (struct tcp_pcb *pcb, ip_addr_t *ipaddr,
- u16_t port);
-err_t tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr,
- u16_t port, tcp_connected_fn connected);
-
-struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog);
-#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)
-
-void tcp_abort (struct tcp_pcb *pcb);
-err_t tcp_close (struct tcp_pcb *pcb);
-err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx);
-
-/* Flags for "apiflags" parameter in tcp_write */
-#define TCP_WRITE_FLAG_COPY 0x01
-#define TCP_WRITE_FLAG_MORE 0x02
-
-err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len,
- u8_t apiflags);
-
-void tcp_setprio (struct tcp_pcb *pcb, u8_t prio);
-
-#define TCP_PRIO_MIN 1
-#define TCP_PRIO_NORMAL 64
-#define TCP_PRIO_MAX 127
-
-err_t tcp_output (struct tcp_pcb *pcb);
-
-
-const char* tcp_debug_state_str(enum tcp_state s);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_TCP */
-
-#endif /* __LWIP_TCP_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_TCP_IMPL_H__
-#define __LWIP_TCP_IMPL_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/tcp.h"
-#include "lwip/sys.h"
-#include "lwip/mem.h"
-#include "lwip/pbuf.h"
-#include "lwip/ip.h"
-#include "lwip/icmp.h"
-#include "lwip/err.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Functions for interfacing with TCP: */
-
-/* Lower layer interface to TCP: */
-#define tcp_init() /* Compatibility define, no init needed. */
-void tcp_tmr (void); /* Must be called every
- TCP_TMR_INTERVAL
- ms. (Typically 250 ms). */
-/* It is also possible to call these two functions at the right
- intervals (instead of calling tcp_tmr()). */
-void tcp_slowtmr (void);
-void tcp_fasttmr (void);
-
-
-/* Only used by IP to pass a TCP segment to TCP: */
-void tcp_input (struct pbuf *p, struct netif *inp);
-/* Used within the TCP code only: */
-struct tcp_pcb * tcp_alloc (u8_t prio);
-void tcp_abandon (struct tcp_pcb *pcb, int reset);
-err_t tcp_send_empty_ack(struct tcp_pcb *pcb);
-void tcp_rexmit (struct tcp_pcb *pcb);
-void tcp_rexmit_rto (struct tcp_pcb *pcb);
-void tcp_rexmit_fast (struct tcp_pcb *pcb);
-u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb);
-
-/**
- * This is the Nagle algorithm: try to combine user data to send as few TCP
- * segments as possible. Only send if
- * - no previously transmitted data on the connection remains unacknowledged or
- * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or
- * - the only unsent segment is at least pcb->mss bytes long (or there is more
- * than one unsent segment - with lwIP, this can happen although unsent->len < mss)
- * - or if we are in fast-retransmit (TF_INFR)
- */
-#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \
- ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \
- (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \
- ((tpcb)->unsent->len >= (tpcb)->mss))) \
- ) ? 1 : 0)
-#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK)
-
-
-#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0)
-#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0)
-#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0)
-#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0)
-/* is b<=a<=c? */
-#if 0 /* see bug #10548 */
-#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))
-#endif
-#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c))
-#define TCP_FIN 0x01U
-#define TCP_SYN 0x02U
-#define TCP_RST 0x04U
-#define TCP_PSH 0x08U
-#define TCP_ACK 0x10U
-#define TCP_URG 0x20U
-#define TCP_ECE 0x40U
-#define TCP_CWR 0x80U
-
-#define TCP_FLAGS 0x3fU
-
-/* Length of the TCP header, excluding options. */
-#define TCP_HLEN 20
-
-#ifndef TCP_TMR_INTERVAL
-#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */
-#endif /* TCP_TMR_INTERVAL */
-
-#ifndef TCP_FAST_INTERVAL
-#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */
-#endif /* TCP_FAST_INTERVAL */
-
-#ifndef TCP_SLOW_INTERVAL
-#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */
-#endif /* TCP_SLOW_INTERVAL */
-
-#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */
-#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */
-
-#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */
-
-#ifndef TCP_MSL
-#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */
-#endif
-
-/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */
-#ifndef TCP_KEEPIDLE_DEFAULT
-#define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */
-#endif
-
-#ifndef TCP_KEEPINTVL_DEFAULT
-#define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */
-#endif
-
-#ifndef TCP_KEEPCNT_DEFAULT
-#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */
-#endif
-
-#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */
-
-/* Fields are (of course) in network byte order.
- * Some fields are converted to host byte order in tcp_input().
- */
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-struct tcp_hdr {
- PACK_STRUCT_FIELD(u16_t src);
- PACK_STRUCT_FIELD(u16_t dest);
- PACK_STRUCT_FIELD(u32_t seqno);
- PACK_STRUCT_FIELD(u32_t ackno);
- PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);
- PACK_STRUCT_FIELD(u16_t wnd);
- PACK_STRUCT_FIELD(u16_t chksum);
- PACK_STRUCT_FIELD(u16_t urgp);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)
-#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)
-#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)
-
-#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))
-#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))
-#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags))
-#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags))
-
-#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags))
-#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) )
-
-#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0))
-
-/** Flags used on input processing, not on pcb->flags
-*/
-#define TF_RESET (u8_t)0x08U /* Connection was reset. */
-#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */
-#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */
-
-
-#if LWIP_EVENT_API
-
-#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
- LWIP_EVENT_ACCEPT, NULL, 0, err)
-#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
- LWIP_EVENT_SENT, NULL, space, ERR_OK)
-#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
- LWIP_EVENT_RECV, (p), 0, (err))
-#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
- LWIP_EVENT_RECV, NULL, 0, ERR_OK)
-#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
- LWIP_EVENT_CONNECTED, NULL, 0, (err))
-#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
- LWIP_EVENT_POLL, NULL, 0, ERR_OK)
-#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \
- LWIP_EVENT_ERR, NULL, 0, (err))
-
-#else /* LWIP_EVENT_API */
-
-#define TCP_EVENT_ACCEPT(pcb,err,ret) \
- do { \
- if((pcb)->accept != NULL) \
- (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \
- else (ret) = ERR_ARG; \
- } while (0)
-
-#define TCP_EVENT_SENT(pcb,space,ret) \
- do { \
- if((pcb)->sent != NULL) \
- (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \
- else (ret) = ERR_OK; \
- } while (0)
-
-#define TCP_EVENT_RECV(pcb,p,err,ret) \
- do { \
- if((pcb)->recv != NULL) { \
- (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\
- } else { \
- (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \
- } \
- } while (0)
-
-#define TCP_EVENT_CLOSED(pcb,ret) \
- do { \
- if(((pcb)->recv != NULL)) { \
- (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\
- } else { \
- (ret) = ERR_OK; \
- } \
- } while (0)
-
-#define TCP_EVENT_CONNECTED(pcb,err,ret) \
- do { \
- if((pcb)->connected != NULL) \
- (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \
- else (ret) = ERR_OK; \
- } while (0)
-
-#define TCP_EVENT_POLL(pcb,ret) \
- do { \
- if((pcb)->poll != NULL) \
- (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \
- else (ret) = ERR_OK; \
- } while (0)
-
-#define TCP_EVENT_ERR(errf,arg,err) \
- do { \
- if((errf) != NULL) \
- (errf)((arg),(err)); \
- } while (0)
-
-#endif /* LWIP_EVENT_API */
-
-/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */
-#if TCP_OVERSIZE && defined(LWIP_DEBUG)
-#define TCP_OVERSIZE_DBGCHECK 1
-#else
-#define TCP_OVERSIZE_DBGCHECK 0
-#endif
-
-/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */
-#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP)
-
-/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */
-struct tcp_seg {
- struct tcp_seg *next; /* used when putting segements on a queue */
- struct pbuf *p; /* buffer containing data + TCP header */
- u16_t len; /* the TCP length of this segment */
-#if TCP_OVERSIZE_DBGCHECK
- u16_t oversize_left; /* Extra bytes available at the end of the last
- pbuf in unsent (used for asserting vs.
- tcp_pcb.unsent_oversized only) */
-#endif /* TCP_OVERSIZE_DBGCHECK */
-#if TCP_CHECKSUM_ON_COPY
- u16_t chksum;
- u8_t chksum_swapped;
-#endif /* TCP_CHECKSUM_ON_COPY */
- u8_t flags;
-#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */
-#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */
-#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is
- checksummed into 'chksum' */
- struct tcp_hdr *tcphdr; /* the TCP header */
-};
-
-#define LWIP_TCP_OPT_LENGTH(flags) \
- (flags & TF_SEG_OPTS_MSS ? 4 : 0) + \
- (flags & TF_SEG_OPTS_TS ? 12 : 0)
-
-/** This returns a TCP header option for MSS in an u32_t */
-#define TCP_BUILD_MSS_OPTION(x) (x) = PP_HTONL(((u32_t)2 << 24) | \
- ((u32_t)4 << 16) | \
- (((u32_t)TCP_MSS / 256) << 8) | \
- (TCP_MSS & 255))
-
-/* Global variables: */
-extern struct tcp_pcb *tcp_input_pcb;
-extern u32_t tcp_ticks;
-
-/* The TCP PCB lists. */
-union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */
- struct tcp_pcb_listen *listen_pcbs;
- struct tcp_pcb *pcbs;
-};
-extern struct tcp_pcb *tcp_bound_pcbs;
-extern union tcp_listen_pcbs_t tcp_listen_pcbs;
-extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a
- state in which they accept or send
- data. */
-extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */
-
-extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */
-
-/* Axioms about the above lists:
- 1) Every TCP PCB that is not CLOSED is in one of the lists.
- 2) A PCB is only in one of the lists.
- 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state.
- 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state.
-*/
-/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB
- with a PCB list or removes a PCB from a list, respectively. */
-#ifndef TCP_DEBUG_PCB_LISTS
-#define TCP_DEBUG_PCB_LISTS 0
-#endif
-#if TCP_DEBUG_PCB_LISTS
-#define TCP_REG(pcbs, npcb) do {\
- LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \
- for(tcp_tmp_pcb = *(pcbs); \
- tcp_tmp_pcb != NULL; \
- tcp_tmp_pcb = tcp_tmp_pcb->next) { \
- LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \
- } \
- LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \
- (npcb)->next = *(pcbs); \
- LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \
- *(pcbs) = (npcb); \
- LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \
- tcp_timer_needed(); \
- } while(0)
-#define TCP_RMV(pcbs, npcb) do { \
- LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \
- LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \
- if(*(pcbs) == (npcb)) { \
- *(pcbs) = (*pcbs)->next; \
- } else for(tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \
- if(tcp_tmp_pcb->next == (npcb)) { \
- tcp_tmp_pcb->next = (npcb)->next; \
- break; \
- } \
- } \
- (npcb)->next = NULL; \
- LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \
- LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \
- } while(0)
-
-#else /* LWIP_DEBUG */
-
-#define TCP_REG(pcbs, npcb) \
- do { \
- (npcb)->next = *pcbs; \
- *(pcbs) = (npcb); \
- tcp_timer_needed(); \
- } while (0)
-
-#define TCP_RMV(pcbs, npcb) \
- do { \
- if(*(pcbs) == (npcb)) { \
- (*(pcbs)) = (*pcbs)->next; \
- } \
- else { \
- for(tcp_tmp_pcb = *pcbs; \
- tcp_tmp_pcb != NULL; \
- tcp_tmp_pcb = tcp_tmp_pcb->next) { \
- if(tcp_tmp_pcb->next == (npcb)) { \
- tcp_tmp_pcb->next = (npcb)->next; \
- break; \
- } \
- } \
- } \
- (npcb)->next = NULL; \
- } while(0)
-
-#endif /* LWIP_DEBUG */
-
-
-/* Internal functions: */
-struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);
-void tcp_pcb_purge(struct tcp_pcb *pcb);
-void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb);
-
-void tcp_segs_free(struct tcp_seg *seg);
-void tcp_seg_free(struct tcp_seg *seg);
-struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);
-
-#define tcp_ack(pcb) \
- do { \
- if((pcb)->flags & TF_ACK_DELAY) { \
- (pcb)->flags &= ~TF_ACK_DELAY; \
- (pcb)->flags |= TF_ACK_NOW; \
- } \
- else { \
- (pcb)->flags |= TF_ACK_DELAY; \
- } \
- } while (0)
-
-#define tcp_ack_now(pcb) \
- do { \
- (pcb)->flags |= TF_ACK_NOW; \
- } while (0)
-
-err_t tcp_send_fin(struct tcp_pcb *pcb);
-err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags);
-
-void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);
-
-void tcp_rst(u32_t seqno, u32_t ackno,
- ip_addr_t *local_ip, ip_addr_t *remote_ip,
- u16_t local_port, u16_t remote_port);
-
-u32_t tcp_next_iss(void);
-
-void tcp_keepalive(struct tcp_pcb *pcb);
-void tcp_zero_window_probe(struct tcp_pcb *pcb);
-
-#if TCP_CALCULATE_EFF_SEND_MSS
-u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr);
-#endif /* TCP_CALCULATE_EFF_SEND_MSS */
-
-#if LWIP_CALLBACK_API
-err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
-#endif /* LWIP_CALLBACK_API */
-
-#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
-void tcp_debug_print(struct tcp_hdr *tcphdr);
-void tcp_debug_print_flags(u8_t flags);
-void tcp_debug_print_state(enum tcp_state s);
-void tcp_debug_print_pcbs(void);
-s16_t tcp_pcbs_sane(void);
-#else
-# define tcp_debug_print(tcphdr)
-# define tcp_debug_print_flags(flags)
-# define tcp_debug_print_state(s)
-# define tcp_debug_print_pcbs()
-# define tcp_pcbs_sane() 1
-#endif /* TCP_DEBUG */
-
-/** External function (implemented in timers.c), called when TCP detects
- * that a timer is needed (i.e. active- or time-wait-pcb found). */
-void tcp_timer_needed(void);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_TCP */
-
-#endif /* __LWIP_TCP_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_TCPIP_H__
-#define __LWIP_TCPIP_H__
-
-#include "lwip/opt.h"
-
-#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/api_msg.h"
-#include "lwip/netifapi.h"
-#include "lwip/pbuf.h"
-#include "lwip/api.h"
-#include "lwip/sys.h"
-#include "lwip/timers.h"
-#include "lwip/netif.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** Define this to something that triggers a watchdog. This is called from
- * tcpip_thread after processing a message. */
-#ifndef LWIP_TCPIP_THREAD_ALIVE
-#define LWIP_TCPIP_THREAD_ALIVE()
-#endif
-
-#if LWIP_TCPIP_CORE_LOCKING
-/** The global semaphore to lock the stack. */
-extern sys_mutex_t lock_tcpip_core;
-#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core)
-#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core)
-#define TCPIP_APIMSG(m) tcpip_apimsg_lock(m)
-#define TCPIP_APIMSG_ACK(m)
-#define TCPIP_NETIFAPI(m) tcpip_netifapi_lock(m)
-#define TCPIP_NETIFAPI_ACK(m)
-#else /* LWIP_TCPIP_CORE_LOCKING */
-#define LOCK_TCPIP_CORE()
-#define UNLOCK_TCPIP_CORE()
-#define TCPIP_APIMSG(m) tcpip_apimsg(m)
-#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed)
-#define TCPIP_NETIFAPI(m) tcpip_netifapi(m)
-#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem)
-#endif /* LWIP_TCPIP_CORE_LOCKING */
-
-/** Function prototype for the init_done function passed to tcpip_init */
-typedef void (*tcpip_init_done_fn)(void *arg);
-/** Function prototype for functions passed to tcpip_callback() */
-typedef void (*tcpip_callback_fn)(void *ctx);
-
-void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg);
-
-#if LWIP_NETCONN
-err_t tcpip_apimsg(struct api_msg *apimsg);
-#if LWIP_TCPIP_CORE_LOCKING
-err_t tcpip_apimsg_lock(struct api_msg *apimsg);
-#endif /* LWIP_TCPIP_CORE_LOCKING */
-#endif /* LWIP_NETCONN */
-
-err_t tcpip_input(struct pbuf *p, struct netif *inp);
-
-#if LWIP_NETIF_API
-err_t tcpip_netifapi(struct netifapi_msg *netifapimsg);
-#if LWIP_TCPIP_CORE_LOCKING
-err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);
-#endif /* LWIP_TCPIP_CORE_LOCKING */
-#endif /* LWIP_NETIF_API */
-
-err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block);
-#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1)
-
-/* free pbufs or heap memory from another context without blocking */
-err_t pbuf_free_callback(struct pbuf *p);
-err_t mem_free_callback(void *m);
-
-#if LWIP_TCPIP_TIMEOUT
-err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg);
-err_t tcpip_untimeout(sys_timeout_handler h, void *arg);
-#endif /* LWIP_TCPIP_TIMEOUT */
-
-enum tcpip_msg_type {
-#if LWIP_NETCONN
- TCPIP_MSG_API,
-#endif /* LWIP_NETCONN */
- TCPIP_MSG_INPKT,
-#if LWIP_NETIF_API
- TCPIP_MSG_NETIFAPI,
-#endif /* LWIP_NETIF_API */
-#if LWIP_TCPIP_TIMEOUT
- TCPIP_MSG_TIMEOUT,
- TCPIP_MSG_UNTIMEOUT,
-#endif /* LWIP_TCPIP_TIMEOUT */
- TCPIP_MSG_CALLBACK
-};
-
-struct tcpip_msg {
- enum tcpip_msg_type type;
- sys_sem_t *sem;
- union {
-#if LWIP_NETCONN
- struct api_msg *apimsg;
-#endif /* LWIP_NETCONN */
-#if LWIP_NETIF_API
- struct netifapi_msg *netifapimsg;
-#endif /* LWIP_NETIF_API */
- struct {
- struct pbuf *p;
- struct netif *netif;
- } inp;
- struct {
- tcpip_callback_fn function;
- void *ctx;
- } cb;
-#if LWIP_TCPIP_TIMEOUT
- struct {
- u32_t msecs;
- sys_timeout_handler h;
- void *arg;
- } tmo;
-#endif /* LWIP_TCPIP_TIMEOUT */
- } msg;
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !NO_SYS */
-
-#endif /* __LWIP_TCPIP_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- * Simon Goldschmidt
- *
- */
-#ifndef __LWIP_TIMERS_H__
-#define __LWIP_TIMERS_H__
-
-#include "lwip/opt.h"
-
-/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */
-#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS))
-
-#if LWIP_TIMERS
-
-#include "lwip/err.h"
-#include "lwip/sys.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef LWIP_DEBUG_TIMERNAMES
-#ifdef LWIP_DEBUG
-#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG
-#else /* LWIP_DEBUG */
-#define LWIP_DEBUG_TIMERNAMES 0
-#endif /* LWIP_DEBUG*/
-#endif
-
-/** Function prototype for a timeout callback function. Register such a function
- * using sys_timeout().
- *
- * @param arg Additional argument to pass to the function - set up by sys_timeout()
- */
-typedef void (* sys_timeout_handler)(void *arg);
-
-struct sys_timeo {
- struct sys_timeo *next;
- u32_t time;
- sys_timeout_handler h;
- void *arg;
-#if LWIP_DEBUG_TIMERNAMES
- const char* handler_name;
-#endif /* LWIP_DEBUG_TIMERNAMES */
-};
-
-void sys_timeouts_init(void);
-
-#if LWIP_DEBUG_TIMERNAMES
-void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name);
-#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler)
-#else /* LWIP_DEBUG_TIMERNAMES */
-void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg);
-#endif /* LWIP_DEBUG_TIMERNAMES */
-
-void sys_untimeout(sys_timeout_handler handler, void *arg);
-#if NO_SYS
-void sys_check_timeouts(void);
-void sys_restart_timeouts(void);
-#else /* NO_SYS */
-void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg);
-#endif /* NO_SYS */
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_TIMERS */
-#endif /* __LWIP_TIMERS_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __LWIP_UDP_H__
-#define __LWIP_UDP_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/pbuf.h"
-#include "lwip/netif.h"
-#include "lwip/ip_addr.h"
-#include "lwip/ip.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define UDP_HLEN 8
-
-/* Fields are (of course) in network byte order. */
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-struct udp_hdr {
- PACK_STRUCT_FIELD(u16_t src);
- PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */
- PACK_STRUCT_FIELD(u16_t len);
- PACK_STRUCT_FIELD(u16_t chksum);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-#define UDP_FLAGS_NOCHKSUM 0x01U
-#define UDP_FLAGS_UDPLITE 0x02U
-#define UDP_FLAGS_CONNECTED 0x04U
-#define UDP_FLAGS_MULTICAST_LOOP 0x08U
-
-struct udp_pcb;
-
-/** Function prototype for udp pcb receive callback functions
- * addr and port are in same byte order as in the pcb
- * The callback is responsible for freeing the pbuf
- * if it's not used any more.
- *
- * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf
- * makes 'addr' invalid, too.
- *
- * @param arg user supplied argument (udp_pcb.recv_arg)
- * @param pcb the udp_pcb which received data
- * @param p the packet buffer that was received
- * @param addr the remote IP address from which the packet was received
- * @param port the remote port from which the packet was received
- */
-typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
- ip_addr_t *addr, u16_t port);
-
-
-struct udp_pcb {
-/* Common members of all PCB types */
- IP_PCB;
-
-/* Protocol specific PCB members */
-
- struct udp_pcb *next;
-
- u8_t flags;
- /** ports are in host byte order */
- u16_t local_port, remote_port;
-
-#if LWIP_IGMP
- /** outgoing network interface for multicast packets */
- ip_addr_t multicast_ip;
-#endif /* LWIP_IGMP */
-
-#if LWIP_UDPLITE
- /** used for UDP_LITE only */
- u16_t chksum_len_rx, chksum_len_tx;
-#endif /* LWIP_UDPLITE */
-
- /** receive callback function */
- udp_recv_fn recv;
- /** user-supplied argument for the recv callback */
- void *recv_arg;
-};
-/* udp_pcbs export for exernal reference (e.g. SNMP agent) */
-extern struct udp_pcb *udp_pcbs;
-
-/* The following functions is the application layer interface to the
- UDP code. */
-struct udp_pcb * udp_new (void);
-void udp_remove (struct udp_pcb *pcb);
-err_t udp_bind (struct udp_pcb *pcb, ip_addr_t *ipaddr,
- u16_t port);
-err_t udp_connect (struct udp_pcb *pcb, ip_addr_t *ipaddr,
- u16_t port);
-void udp_disconnect (struct udp_pcb *pcb);
-void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv,
- void *recv_arg);
-err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p,
- ip_addr_t *dst_ip, u16_t dst_port,
- struct netif *netif);
-err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p,
- ip_addr_t *dst_ip, u16_t dst_port);
-err_t udp_send (struct udp_pcb *pcb, struct pbuf *p);
-
-#if LWIP_CHECKSUM_ON_COPY
-err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p,
- ip_addr_t *dst_ip, u16_t dst_port,
- struct netif *netif, u8_t have_chksum,
- u16_t chksum);
-err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p,
- ip_addr_t *dst_ip, u16_t dst_port,
- u8_t have_chksum, u16_t chksum);
-err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
- u8_t have_chksum, u16_t chksum);
-#endif /* LWIP_CHECKSUM_ON_COPY */
-
-#define udp_flags(pcb) ((pcb)->flags)
-#define udp_setflags(pcb, f) ((pcb)->flags = (f))
-
-/* The following functions are the lower layer interface to UDP. */
-void udp_input (struct pbuf *p, struct netif *inp);
-
-#define udp_init() /* Compatibility define, not init needed. */
-
-#if UDP_DEBUG
-void udp_debug_print(struct udp_hdr *udphdr);
-#else
-#define udp_debug_print(udphdr)
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LWIP_UDP */
-
-#endif /* __LWIP_UDP_H__ */
+++ /dev/null
-/*
- * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
- * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
- * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-#ifndef __NETIF_ETHARP_H__
-#define __NETIF_ETHARP_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/pbuf.h"
-#include "lwip/ip_addr.h"
-#include "lwip/netif.h"
-#include "lwip/ip.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef ETHARP_HWADDR_LEN
-#define ETHARP_HWADDR_LEN 6
-#endif
-
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-struct eth_addr {
- PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-/** Ethernet header */
-struct eth_hdr {
-#if ETH_PAD_SIZE
- PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
-#endif
- PACK_STRUCT_FIELD(struct eth_addr dest);
- PACK_STRUCT_FIELD(struct eth_addr src);
- PACK_STRUCT_FIELD(u16_t type);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
-
-#if ETHARP_SUPPORT_VLAN
-
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-/** VLAN header inserted between ethernet header and payload
- * if 'type' in ethernet header is ETHTYPE_VLAN.
- * See IEEE802.Q */
-struct eth_vlan_hdr {
- PACK_STRUCT_FIELD(u16_t prio_vid);
- PACK_STRUCT_FIELD(u16_t tpid);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-#define SIZEOF_VLAN_HDR 4
-#define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF)
-
-#endif /* ETHARP_SUPPORT_VLAN */
-
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-/** the ARP message, see RFC 826 ("Packet format") */
-struct etharp_hdr {
- PACK_STRUCT_FIELD(u16_t hwtype);
- PACK_STRUCT_FIELD(u16_t proto);
- PACK_STRUCT_FIELD(u8_t hwlen);
- PACK_STRUCT_FIELD(u8_t protolen);
- PACK_STRUCT_FIELD(u16_t opcode);
- PACK_STRUCT_FIELD(struct eth_addr shwaddr);
- PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);
- PACK_STRUCT_FIELD(struct eth_addr dhwaddr);
- PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-#define SIZEOF_ETHARP_HDR 28
-#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR)
-
-/** 5 seconds period */
-#define ARP_TMR_INTERVAL 5000
-
-#define ETHTYPE_ARP 0x0806U
-#define ETHTYPE_IP 0x0800U
-#define ETHTYPE_VLAN 0x8100U
-#define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */
-#define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session Stage */
-
-/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables
- * or known to be 32-bit aligned within the protocol header. */
-#ifndef ETHADDR32_COPY
-#define ETHADDR32_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN)
-#endif
-
-/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local
- * variables and known to be 16-bit aligned within the protocol header. */
-#ifndef ETHADDR16_COPY
-#define ETHADDR16_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN)
-#endif
-
-#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
-
-/** ARP message types (opcodes) */
-#define ARP_REQUEST 1
-#define ARP_REPLY 2
-
-/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type)
- * to a filter function that returns the correct netif when using multiple
- * netifs on one hardware interface where the netif's low-level receive
- * routine cannot decide for the correct netif (e.g. when mapping multiple
- * IP addresses to one hardware interface).
- */
-#ifndef LWIP_ARP_FILTER_NETIF
-#define LWIP_ARP_FILTER_NETIF 0
-#endif
-
-#if ARP_QUEUEING
-/** struct for queueing outgoing packets for unknown address
- * defined here to be accessed by memp.h
- */
-struct etharp_q_entry {
- struct etharp_q_entry *next;
- struct pbuf *p;
-};
-#endif /* ARP_QUEUEING */
-
-#define etharp_init() /* Compatibility define, not init needed. */
-void etharp_tmr(void);
-s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
- struct eth_addr **eth_ret, ip_addr_t **ip_ret);
-err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr);
-err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q);
-err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr);
-/** For Ethernet network interfaces, we might want to send "gratuitous ARP";
- * this is an ARP packet sent by a node in order to spontaneously cause other
- * nodes to update an entry in their ARP cache.
- * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */
-#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr)
-
-#if ETHARP_SUPPORT_STATIC_ENTRIES
-err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr);
-err_t etharp_remove_static_entry(ip_addr_t *ipaddr);
-#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
-
-#if LWIP_AUTOIP
-err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
- const struct eth_addr *ethdst_addr,
- const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr,
- const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr,
- const u16_t opcode);
-#endif /* LWIP_AUTOIP */
-
-#endif /* LWIP_ARP */
-
-err_t ethernet_input(struct pbuf *p, struct netif *netif);
-
-#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0)
-
-extern const struct eth_addr ethbroadcast, ethzero;
-
-#endif /* LWIP_ARP || LWIP_ETHERNET */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __NETIF_ARP_H__ */
+++ /dev/null
-/*****************************************************************************
-* ppp_oe.h - PPP Over Ethernet implementation for lwIP.
-*
-* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.
-*
-* The authors hereby grant permission to use, copy, modify, distribute,
-* and license this software and its documentation for any purpose, provided
-* that existing copyright notices are retained in all copies and that this
-* notice and the following disclaimer are included verbatim in any
-* distributions. No written agreement, license, or royalty fee is required
-* for any of the authorized uses.
-*
-* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
-* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*
-******************************************************************************
-* REVISION HISTORY
-*
-* 06-01-01 Marc Boucher <marc@mbsi.ca>
-* Ported to lwIP.
-*****************************************************************************/
-
-
-
-/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */
-
-/*-
- * Copyright (c) 2002 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Martin Husemann <martin@NetBSD.org>.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef PPP_OE_H
-#define PPP_OE_H
-
-#include "lwip/opt.h"
-
-#if PPPOE_SUPPORT > 0
-
-#include "netif/etharp.h"
-
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-struct pppoehdr {
- PACK_STRUCT_FIELD(u8_t vertype);
- PACK_STRUCT_FIELD(u8_t code);
- PACK_STRUCT_FIELD(u16_t session);
- PACK_STRUCT_FIELD(u16_t plen);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-struct pppoetag {
- PACK_STRUCT_FIELD(u16_t tag);
- PACK_STRUCT_FIELD(u16_t len);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-# include "arch/epstruct.h"
-#endif
-
-
-#define PPPOE_STATE_INITIAL 0
-#define PPPOE_STATE_PADI_SENT 1
-#define PPPOE_STATE_PADR_SENT 2
-#define PPPOE_STATE_SESSION 3
-#define PPPOE_STATE_CLOSING 4
-/* passive */
-#define PPPOE_STATE_PADO_SENT 1
-
-#define PPPOE_HEADERLEN sizeof(struct pppoehdr)
-#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */
-
-#define PPPOE_TAG_EOL 0x0000 /* end of list */
-#define PPPOE_TAG_SNAME 0x0101 /* service name */
-#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */
-#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */
-#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */
-#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */
-#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */
-#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */
-#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */
-#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */
-
-#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */
-#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */
-#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */
-#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */
-#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */
-
-#ifndef ETHERMTU
-#define ETHERMTU 1500
-#endif
-
-/* two byte PPP protocol discriminator, then IP data */
-#define PPPOE_MAXMTU (ETHERMTU-PPPOE_HEADERLEN-2)
-
-#ifndef PPPOE_MAX_AC_COOKIE_LEN
-#define PPPOE_MAX_AC_COOKIE_LEN 64
-#endif
-
-struct pppoe_softc {
- struct pppoe_softc *next;
- struct netif *sc_ethif; /* ethernet interface we are using */
- int sc_pd; /* ppp unit number */
- void (*sc_linkStatusCB)(int pd, int up);
-
- int sc_state; /* discovery phase or session connected */
- struct eth_addr sc_dest; /* hardware address of concentrator */
- u16_t sc_session; /* PPPoE session id */
-
-#ifdef PPPOE_TODO
- char *sc_service_name; /* if != NULL: requested name of service */
- char *sc_concentrator_name; /* if != NULL: requested concentrator id */
-#endif /* PPPOE_TODO */
- u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */
- size_t sc_ac_cookie_len; /* length of cookie data */
-#ifdef PPPOE_SERVER
- u8_t *sc_hunique; /* content of host unique we must echo back */
- size_t sc_hunique_len; /* length of host unique */
-#endif
- int sc_padi_retried; /* number of PADI retries already done */
- int sc_padr_retried; /* number of PADR retries already done */
-};
-
-
-#define pppoe_init() /* compatibility define, no initialization needed */
-
-err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr);
-err_t pppoe_destroy(struct netif *ifp);
-
-int pppoe_connect(struct pppoe_softc *sc);
-void pppoe_disconnect(struct pppoe_softc *sc);
-
-void pppoe_disc_input(struct netif *netif, struct pbuf *p);
-void pppoe_data_input(struct netif *netif, struct pbuf *p);
-
-err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb);
-
-/** used in ppp.c */
-#define PPPOE_HDRLEN (sizeof(struct eth_hdr) + PPPOE_HEADERLEN)
-
-#endif /* PPPOE_SUPPORT */
-
-#endif /* PPP_OE_H */
+++ /dev/null
-/*
- * 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>
- *
- */
-#ifndef __NETIF_SLIPIF_H__
-#define __NETIF_SLIPIF_H__
-
-#include "lwip/netif.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-err_t slipif_init(struct netif * netif);
-void slipif_poll(struct netif *netif);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
+++ /dev/null
-/**
- * @file
- * Address Resolution Protocol module for IP over Ethernet
- *
- * Functionally, ARP is divided into two parts. The first maps an IP address
- * to a physical address when sending a packet, and the second part answers
- * requests from other machines for our physical address.
- *
- * This implementation complies with RFC 826 (Ethernet ARP). It supports
- * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6
- * if an interface calls etharp_gratuitous(our_netif) upon address change.
- */
-
-/*
- * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
- * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
- * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- */
-
-#include "lwip/opt.h"
-
-#if LWIP_ARP || LWIP_ETHERNET
-
-#include "lwip/ip_addr.h"
-#include "lwip/def.h"
-#include "lwip/ip.h"
-#include "lwip/stats.h"
-#include "lwip/snmp.h"
-#include "lwip/dhcp.h"
-#include "lwip/autoip.h"
-#include "netif/etharp.h"
-
-#if PPPOE_SUPPORT
-#include "netif/ppp_oe.h"
-#endif /* PPPOE_SUPPORT */
-
-#include <string.h>
-
-const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
-const struct eth_addr ethzero = {{0,0,0,0,0,0}};
-
-#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
-
-/** the time an ARP entry stays valid after its last update,
- * for ARP_TMR_INTERVAL = 5000, this is
- * (240 * 5) seconds = 20 minutes.
- */
-#define ARP_MAXAGE 240
-/** the time an ARP entry stays pending after first request,
- * for ARP_TMR_INTERVAL = 5000, this is
- * (2 * 5) seconds = 10 seconds.
- *
- * @internal Keep this number at least 2, otherwise it might
- * run out instantly if the timeout occurs directly after a request.
- */
-#define ARP_MAXPENDING 2
-
-#define HWTYPE_ETHERNET 1
-
-enum etharp_state {
- ETHARP_STATE_EMPTY = 0,
- ETHARP_STATE_PENDING,
- ETHARP_STATE_STABLE
-};
-
-struct etharp_entry {
-#if ARP_QUEUEING
- /** Pointer to queue of pending outgoing packets on this ARP entry. */
- struct etharp_q_entry *q;
-#else /* ARP_QUEUEING */
- /** Pointer to a single pending outgoing packet on this ARP entry. */
- struct pbuf *q;
-#endif /* ARP_QUEUEING */
- ip_addr_t ipaddr;
- struct eth_addr ethaddr;
-#if LWIP_SNMP
- struct netif *netif;
-#endif /* LWIP_SNMP */
- u8_t state;
- u8_t ctime;
-#if ETHARP_SUPPORT_STATIC_ENTRIES
- u8_t static_entry;
-#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
-};
-
-static struct etharp_entry arp_table[ARP_TABLE_SIZE];
-
-#if !LWIP_NETIF_HWADDRHINT
-static u8_t etharp_cached_entry;
-#endif /* !LWIP_NETIF_HWADDRHINT */
-
-/** Try hard to create a new entry - we want the IP address to appear in
- the cache (even if this means removing an active entry or so). */
-#define ETHARP_FLAG_TRY_HARD 1
-#define ETHARP_FLAG_FIND_ONLY 2
-#define ETHARP_FLAG_STATIC_ENTRY 4
-
-#if LWIP_NETIF_HWADDRHINT
-#define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \
- *((netif)->addr_hint) = (hint);
-#else /* LWIP_NETIF_HWADDRHINT */
-#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint))
-#endif /* LWIP_NETIF_HWADDRHINT */
-
-static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags);
-
-
-/* Some checks, instead of etharp_init(): */
-#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
- #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h"
-#endif
-
-
-#if ARP_QUEUEING
-/**
- * Free a complete queue of etharp entries
- *
- * @param q a qeueue of etharp_q_entry's to free
- */
-static void
-free_etharp_q(struct etharp_q_entry *q)
-{
- struct etharp_q_entry *r;
- LWIP_ASSERT("q != NULL", q != NULL);
- LWIP_ASSERT("q->p != NULL", q->p != NULL);
- while (q) {
- r = q;
- q = q->next;
- LWIP_ASSERT("r->p != NULL", (r->p != NULL));
- pbuf_free(r->p);
- memp_free(MEMP_ARP_QUEUE, r);
- }
-}
-#else /* ARP_QUEUEING */
-
-/** Compatibility define: free the queued pbuf */
-#define free_etharp_q(q) pbuf_free(q)
-
-#endif /* ARP_QUEUEING */
-
-/** Clean up ARP table entries */
-static void
-free_entry(int i)
-{
- /* remove from SNMP ARP index tree */
- snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
- /* and empty packet queue */
- if (arp_table[i].q != NULL) {
- /* remove all queued packets */
- LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
- free_etharp_q(arp_table[i].q);
- arp_table[i].q = NULL;
- }
- /* recycle entry for re-use */
- arp_table[i].state = ETHARP_STATE_EMPTY;
-#if ETHARP_SUPPORT_STATIC_ENTRIES
- arp_table[i].static_entry = 0;
-#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
-#ifdef LWIP_DEBUG
- /* for debugging, clean out the complete entry */
- arp_table[i].ctime = 0;
-#if LWIP_SNMP
- arp_table[i].netif = NULL;
-#endif /* LWIP_SNMP */
- ip_addr_set_zero(&arp_table[i].ipaddr);
- arp_table[i].ethaddr = ethzero;
-#endif /* LWIP_DEBUG */
-}
-
-/**
- * Clears expired entries in the ARP table.
- *
- * This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds),
- * in order to expire entries in the ARP table.
- */
-void
-etharp_tmr(void)
-{
- u8_t i;
-
- LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
- /* remove expired entries from the ARP table */
- for (i = 0; i < ARP_TABLE_SIZE; ++i) {
- u8_t state = arp_table[i].state;
- if (state != ETHARP_STATE_EMPTY
-#if ETHARP_SUPPORT_STATIC_ENTRIES
- && (arp_table[i].static_entry == 0)
-#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
- ) {
- arp_table[i].ctime++;
- if ((arp_table[i].ctime >= ARP_MAXAGE) ||
- ((arp_table[i].state == ETHARP_STATE_PENDING) &&
- (arp_table[i].ctime >= ARP_MAXPENDING))) {
- /* pending or stable entry has become old! */
- LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",
- arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
- /* clean up entries that have just been expired */
- free_entry(i);
- }
-#if ARP_QUEUEING
- /* still pending entry? (not expired) */
- if (arp_table[i].state == ETHARP_STATE_PENDING) {
- /* resend an ARP query here? */
- }
-#endif /* ARP_QUEUEING */
- }
- }
-}
-
-/**
- * Search the ARP table for a matching or new entry.
- *
- * If an IP address is given, return a pending or stable ARP entry that matches
- * the address. If no match is found, create a new entry with this address set,
- * but in state ETHARP_EMPTY. The caller must check and possibly change the
- * state of the returned entry.
- *
- * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
- *
- * In all cases, attempt to create new entries from an empty entry. If no
- * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle
- * old entries. Heuristic choose the least important entry for recycling.
- *
- * @param ipaddr IP address to find in ARP cache, or to add if not found.
- * @param flags @see definition of ETHARP_FLAG_*
- * @param netif netif related to this address (used for NETIF_HWADDRHINT)
- *
- * @return The ARP entry index that matched or is created, ERR_MEM if no
- * entry is found or could be recycled.
- */
-static s8_t
-find_entry(ip_addr_t *ipaddr, u8_t flags)
-{
- s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
- s8_t empty = ARP_TABLE_SIZE;
- u8_t i = 0, age_pending = 0, age_stable = 0;
- /* oldest entry with packets on queue */
- s8_t old_queue = ARP_TABLE_SIZE;
- /* its age */
- u8_t age_queue = 0;
-
- /**
- * a) do a search through the cache, remember candidates
- * b) select candidate entry
- * c) create new entry
- */
-
- /* a) in a single search sweep, do all of this
- * 1) remember the first empty entry (if any)
- * 2) remember the oldest stable entry (if any)
- * 3) remember the oldest pending entry without queued packets (if any)
- * 4) remember the oldest pending entry with queued packets (if any)
- * 5) search for a matching IP entry, either pending or stable
- * until 5 matches, or all entries are searched for.
- */
-
- for (i = 0; i < ARP_TABLE_SIZE; ++i) {
- u8_t state = arp_table[i].state;
- /* no empty entry found yet and now we do find one? */
- if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) {
- LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
- /* remember first empty entry */
- empty = i;
- } else if (state != ETHARP_STATE_EMPTY) {
- LWIP_ASSERT("state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE",
- state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE);
- /* if given, does IP address match IP address in ARP entry? */
- if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i));
- /* found exact IP address match, simply bail out */
- return i;
- }
- /* pending entry? */
- if (state == ETHARP_STATE_PENDING) {
- /* pending with queued packets? */
- if (arp_table[i].q != NULL) {
- if (arp_table[i].ctime >= age_queue) {
- old_queue = i;
- age_queue = arp_table[i].ctime;
- }
- } else
- /* pending without queued packets? */
- {
- if (arp_table[i].ctime >= age_pending) {
- old_pending = i;
- age_pending = arp_table[i].ctime;
- }
- }
- /* stable entry? */
- } else if (state == ETHARP_STATE_STABLE) {
-#if ETHARP_SUPPORT_STATIC_ENTRIES
- /* don't record old_stable for static entries since they never expire */
- if (arp_table[i].static_entry == 0)
-#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
- {
- /* remember entry with oldest stable entry in oldest, its age in maxtime */
- if (arp_table[i].ctime >= age_stable) {
- old_stable = i;
- age_stable = arp_table[i].ctime;
- }
- }
- }
- }
- }
- /* { we have no match } => try to create a new entry */
-
- /* don't create new entry, only search? */
- if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) ||
- /* or no empty entry found and not allowed to recycle? */
- ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) {
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n"));
- return (s8_t)ERR_MEM;
- }
-
- /* b) choose the least destructive entry to recycle:
- * 1) empty entry
- * 2) oldest stable entry
- * 3) oldest pending entry without queued packets
- * 4) oldest pending entry with queued packets
- *
- * { ETHARP_FLAG_TRY_HARD is set at this point }
- */
-
- /* 1) empty entry available? */
- if (empty < ARP_TABLE_SIZE) {
- i = empty;
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
- } else {
- /* 2) found recyclable stable entry? */
- if (old_stable < ARP_TABLE_SIZE) {
- /* recycle oldest stable*/
- i = old_stable;
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
- /* no queued packets should exist on stable entries */
- LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
- /* 3) found recyclable pending entry without queued packets? */
- } else if (old_pending < ARP_TABLE_SIZE) {
- /* recycle oldest pending */
- i = old_pending;
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
- /* 4) found recyclable pending entry with queued packets? */
- } else if (old_queue < ARP_TABLE_SIZE) {
- /* recycle oldest pending (queued packets are free in free_entry) */
- i = old_queue;
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
- /* no empty or recyclable entries found */
- } else {
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty or recyclable entries found\n"));
- return (s8_t)ERR_MEM;
- }
-
- /* { empty or recyclable entry found } */
- LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
- free_entry(i);
- }
-
- LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
- LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY",
- arp_table[i].state == ETHARP_STATE_EMPTY);
-
- /* IP address given? */
- if (ipaddr != NULL) {
- /* set IP address */
- ip_addr_copy(arp_table[i].ipaddr, *ipaddr);
- }
- arp_table[i].ctime = 0;
-#if ETHARP_SUPPORT_STATIC_ENTRIES
- arp_table[i].static_entry = 0;
-#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
- return (err_t)i;
-}
-
-/**
- * Send an IP packet on the network using netif->linkoutput
- * The ethernet header is filled in before sending.
- *
- * @params netif the lwIP network interface on which to send the packet
- * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header
- * @params src the source MAC address to be copied into the ethernet header
- * @params dst the destination MAC address to be copied into the ethernet header
- * @return ERR_OK if the packet was sent, any other err_t on failure
- */
-static err_t
-etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)
-{
- struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;
-
- LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
- (netif->hwaddr_len == ETHARP_HWADDR_LEN));
- ETHADDR32_COPY(ðhdr->dest, dst);
- ETHADDR16_COPY(ðhdr->src, src);
- ethhdr->type = PP_HTONS(ETHTYPE_IP);
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p));
- /* send the packet */
- return netif->linkoutput(netif, p);
-}
-
-/**
- * Update (or insert) a IP/MAC address pair in the ARP cache.
- *
- * If a pending entry is resolved, any queued packets will be sent
- * at this point.
- *
- * @param netif netif related to this entry (used for NETIF_ADDRHINT)
- * @param ipaddr IP address of the inserted ARP entry.
- * @param ethaddr Ethernet address of the inserted ARP entry.
- * @param flags @see definition of ETHARP_FLAG_*
- *
- * @return
- * - ERR_OK Succesfully updated ARP cache.
- * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set.
- * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
- *
- * @see pbuf_free()
- */
-static err_t
-update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
-{
- s8_t i;
- LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
- ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
- ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
- ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
- /* non-unicast address? */
- if (ip_addr_isany(ipaddr) ||
- ip_addr_isbroadcast(ipaddr, netif) ||
- ip_addr_ismulticast(ipaddr)) {
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
- return ERR_ARG;
- }
- /* find or create ARP entry */
- i = find_entry(ipaddr, flags);
- /* bail out if no entry could be found */
- if (i < 0) {
- return (err_t)i;
- }
-
-#if ETHARP_SUPPORT_STATIC_ENTRIES
- if (flags & ETHARP_FLAG_STATIC_ENTRY) {
- /* record static type */
- arp_table[i].static_entry = 1;
- }
-#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
-
- /* mark it stable */
- arp_table[i].state = ETHARP_STATE_STABLE;
-
-#if LWIP_SNMP
- /* record network interface */
- arp_table[i].netif = netif;
-#endif /* LWIP_SNMP */
- /* insert in SNMP ARP index tree */
- snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
-
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
- /* update address */
- ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr);
- /* reset time stamp */
- arp_table[i].ctime = 0;
- /* this is where we will send out queued packets! */
-#if ARP_QUEUEING
- while (arp_table[i].q != NULL) {
- struct pbuf *p;
- /* remember remainder of queue */
- struct etharp_q_entry *q = arp_table[i].q;
- /* pop first item off the queue */
- arp_table[i].q = q->next;
- /* get the packet pointer */
- p = q->p;
- /* now queue entry can be freed */
- memp_free(MEMP_ARP_QUEUE, q);
-#else /* ARP_QUEUEING */
- if (arp_table[i].q != NULL) {
- struct pbuf *p = arp_table[i].q;
- arp_table[i].q = NULL;
-#endif /* ARP_QUEUEING */
- /* send the queued IP packet */
- etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr);
- /* free the queued IP packet */
- pbuf_free(p);
- }
- return ERR_OK;
-}
-
-#if ETHARP_SUPPORT_STATIC_ENTRIES
-/** Add a new static entry to the ARP table. If an entry exists for the
- * specified IP address, this entry is overwritten.
- * If packets are queued for the specified IP address, they are sent out.
- *
- * @param ipaddr IP address for the new static entry
- * @param ethaddr ethernet address for the new static entry
- * @return @see return values of etharp_add_static_entry
- */
-err_t
-etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)
-{
- struct netif *netif;
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_add_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
- ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
- ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
- ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
-
- netif = ip_route(ipaddr);
- if (netif == NULL) {
- return ERR_RTE;
- }
-
- return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
-}
-
-/** Remove a static entry from the ARP table previously added with a call to
- * etharp_add_static_entry.
- *
- * @param ipaddr IP address of the static entry to remove
- * @return ERR_OK: entry removed
- * ERR_MEM: entry wasn't found
- * ERR_ARG: entry wasn't a static entry but a dynamic one
- */
-err_t
-etharp_remove_static_entry(ip_addr_t *ipaddr)
-{
- s8_t i;
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
- ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
-
- /* find or create ARP entry */
- i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
- /* bail out if no entry could be found */
- if (i < 0) {
- return (err_t)i;
- }
-
- if ((arp_table[i].state != ETHARP_STATE_STABLE) ||
- (arp_table[i].static_entry == 0)) {
- /* entry wasn't a static entry, cannot remove it */
- return ERR_ARG;
- }
- /* entry found, free it */
- free_entry(i);
- return ERR_OK;
-}
-#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
-
-/**
- * Finds (stable) ethernet/IP address pair from ARP table
- * using interface and IP address index.
- * @note the addresses in the ARP table are in network order!
- *
- * @param netif points to interface index
- * @param ipaddr points to the (network order) IP address index
- * @param eth_ret points to return pointer
- * @param ip_ret points to return pointer
- * @return table index if found, -1 otherwise
- */
-s8_t
-etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
- struct eth_addr **eth_ret, ip_addr_t **ip_ret)
-{
- s8_t i;
-
- LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL",
- eth_ret != NULL && ip_ret != NULL);
-
- LWIP_UNUSED_ARG(netif);
-
- i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
- if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {
- *eth_ret = &arp_table[i].ethaddr;
- *ip_ret = &arp_table[i].ipaddr;
- return i;
- }
- return -1;
-}
-
-#if ETHARP_TRUST_IP_MAC
-/**
- * Updates the ARP table using the given IP packet.
- *
- * Uses the incoming IP packet's source address to update the
- * ARP cache for the local network. The function does not alter
- * or free the packet. This function must be called before the
- * packet p is passed to the IP layer.
- *
- * @param netif The lwIP network interface on which the IP packet pbuf arrived.
- * @param p The IP packet that arrived on netif.
- *
- * @return NULL
- *
- * @see pbuf_free()
- */
-static void
-etharp_ip_input(struct netif *netif, struct pbuf *p)
-{
- struct eth_hdr *ethhdr;
- struct ip_hdr *iphdr;
- ip_addr_t iphdr_src;
- LWIP_ERROR("netif != NULL", (netif != NULL), return;);
-
- /* Only insert an entry if the source IP address of the
- incoming IP packet comes from a host on the local network. */
- ethhdr = (struct eth_hdr *)p->payload;
- iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
-#if ETHARP_SUPPORT_VLAN
- if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
- iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
- }
-#endif /* ETHARP_SUPPORT_VLAN */
-
- ip_addr_copy(iphdr_src, iphdr->src);
-
- /* source is not on the local network? */
- if (!ip_addr_netcmp(&iphdr_src, &(netif->ip_addr), &(netif->netmask))) {
- /* do nothing */
- return;
- }
-
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
- /* update the source IP address in the cache, if present */
- /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk
- * back soon (for example, if the destination IP address is ours. */
- update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);
-}
-#endif /* ETHARP_TRUST_IP_MAC */
-
-/**
- * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache
- * send out queued IP packets. Updates cache with snooped address pairs.
- *
- * Should be called for incoming ARP packets. The pbuf in the argument
- * is freed by this function.
- *
- * @param netif The lwIP network interface on which the ARP packet pbuf arrived.
- * @param ethaddr Ethernet address of netif.
- * @param p The ARP packet that arrived on netif. Is freed by this function.
- *
- * @return NULL
- *
- * @see pbuf_free()
- */
-static void
-etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
-{
- struct etharp_hdr *hdr;
- struct eth_hdr *ethhdr;
- /* these are aligned properly, whereas the ARP header fields might not be */
- ip_addr_t sipaddr, dipaddr;
- u8_t for_us;
-#if LWIP_AUTOIP
- const u8_t * ethdst_hwaddr;
-#endif /* LWIP_AUTOIP */
-
- LWIP_ERROR("netif != NULL", (netif != NULL), return;);
-
- /* drop short ARP packets: we have to check for p->len instead of p->tot_len here
- since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */
- if (p->len < SIZEOF_ETHARP_PACKET) {
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
- ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len,
- (s16_t)SIZEOF_ETHARP_PACKET));
- ETHARP_STATS_INC(etharp.lenerr);
- ETHARP_STATS_INC(etharp.drop);
- pbuf_free(p);
- return;
- }
-
- ethhdr = (struct eth_hdr *)p->payload;
- hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
-#if ETHARP_SUPPORT_VLAN
- if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
- hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
- }
-#endif /* ETHARP_SUPPORT_VLAN */
-
- /* RFC 826 "Packet Reception": */
- if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||
- (hdr->hwlen != ETHARP_HWADDR_LEN) ||
- (hdr->protolen != sizeof(ip_addr_t)) ||
- (hdr->proto != PP_HTONS(ETHTYPE_IP))) {
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
- ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
- hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen));
- ETHARP_STATS_INC(etharp.proterr);
- ETHARP_STATS_INC(etharp.drop);
- pbuf_free(p);
- return;
- }
- ETHARP_STATS_INC(etharp.recv);
-
-#if LWIP_AUTOIP
- /* We have to check if a host already has configured our random
- * created link local address and continously check if there is
- * a host with this IP-address so we can detect collisions */
- autoip_arp_reply(netif, hdr);
-#endif /* LWIP_AUTOIP */
-
- /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
- * structure packing (not using structure copy which breaks strict-aliasing rules). */
- IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
- IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
-
- /* this interface is not configured? */
- if (ip_addr_isany(&netif->ip_addr)) {
- for_us = 0;
- } else {
- /* ARP packet directed to us? */
- for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr));
- }
-
- /* ARP message directed to us?
- -> add IP address in ARP cache; assume requester wants to talk to us,
- can result in directly sending the queued packets for this host.
- ARP message not directed to us?
- -> update the source IP address in the cache, if present */
- update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
- for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);
-
- /* now act on the message itself */
- switch (hdr->opcode) {
- /* ARP request? */
- case PP_HTONS(ARP_REQUEST):
- /* ARP request. If it asked for our address, we send out a
- * reply. In any case, we time-stamp any existing ARP entry,
- * and possiby send out an IP packet that was queued on it. */
-
- LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));
- /* ARP request for our address? */
- if (for_us) {
-
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));
- /* Re-use pbuf to send ARP reply.
- Since we are re-using an existing pbuf, we can't call etharp_raw since
- that would allocate a new pbuf. */
- hdr->opcode = htons(ARP_REPLY);
-
- IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr);
- IPADDR2_COPY(&hdr->sipaddr, &netif->ip_addr);
-
- LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
- (netif->hwaddr_len == ETHARP_HWADDR_LEN));
-#if LWIP_AUTOIP
- /* If we are using Link-Local, all ARP packets that contain a Link-Local
- * 'sender IP address' MUST be sent using link-layer broadcast instead of
- * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
- ethdst_hwaddr = ip_addr_islinklocal(&netif->ip_addr) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr;
-#endif /* LWIP_AUTOIP */
-
- ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr);
-#if LWIP_AUTOIP
- ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr);
-#else /* LWIP_AUTOIP */
- ETHADDR16_COPY(ðhdr->dest, &hdr->shwaddr);
-#endif /* LWIP_AUTOIP */
- ETHADDR16_COPY(&hdr->shwaddr, ethaddr);
- ETHADDR16_COPY(ðhdr->src, ethaddr);
-
- /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header
- are already correct, we tested that before */
-
- /* return ARP reply */
- netif->linkoutput(netif, p);
- /* we are not configured? */
- } else if (ip_addr_isany(&netif->ip_addr)) {
- /* { for_us == 0 and netif->ip_addr.addr == 0 } */
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));
- /* request was not directed to us */
- } else {
- /* { for_us == 0 and netif->ip_addr.addr != 0 } */
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));
- }
- break;
- case PP_HTONS(ARP_REPLY):
- /* ARP reply. We already updated the ARP cache earlier. */
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));
-#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
- /* DHCP wants to know about ARP replies from any host with an
- * IP address also offered to us by the DHCP server. We do not
- * want to take a duplicate IP address on a single network.
- * @todo How should we handle redundant (fail-over) interfaces? */
- dhcp_arp_reply(netif, &sipaddr);
-#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */
- break;
- default:
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));
- ETHARP_STATS_INC(etharp.err);
- break;
- }
- /* free ARP packet */
- pbuf_free(p);
-}
-
-/**
- * Resolve and fill-in Ethernet address header for outgoing IP packet.
- *
- * For IP multicast and broadcast, corresponding Ethernet addresses
- * are selected and the packet is transmitted on the link.
- *
- * For unicast addresses, the packet is submitted to etharp_query(). In
- * case the IP address is outside the local network, the IP address of
- * the gateway is used.
- *
- * @param netif The lwIP network interface which the IP packet will be sent on.
- * @param q The pbuf(s) containing the IP packet to be sent.
- * @param ipaddr The IP address of the packet destination.
- *
- * @return
- * - ERR_RTE No route to destination (no gateway to external networks),
- * or the return type of either etharp_query() or etharp_send_ip().
- */
-err_t
-etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
-{
- struct eth_addr *dest, mcastaddr;
-
- /* make room for Ethernet header - should not fail */
- if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
- /* bail out */
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
- ("etharp_output: could not allocate room for header.\n"));
- LINK_STATS_INC(link.lenerr);
- return ERR_BUF;
- }
-
- /* assume unresolved Ethernet address */
- dest = NULL;
- /* Determine on destination hardware address. Broadcasts and multicasts
- * are special, other IP addresses are looked up in the ARP table. */
-
- /* broadcast destination IP address? */
- if (ip_addr_isbroadcast(ipaddr, netif)) {
- /* broadcast on Ethernet also */
- dest = (struct eth_addr *)ðbroadcast;
- /* multicast destination IP address? */
- } else if (ip_addr_ismulticast(ipaddr)) {
- /* Hash IP multicast address to MAC address.*/
- mcastaddr.addr[0] = 0x01;
- mcastaddr.addr[1] = 0x00;
- mcastaddr.addr[2] = 0x5e;
- mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
- mcastaddr.addr[4] = ip4_addr3(ipaddr);
- mcastaddr.addr[5] = ip4_addr4(ipaddr);
- /* destination Ethernet address is multicast */
- dest = &mcastaddr;
- /* unicast destination IP address? */
- } else {
- /* outside local network? */
- if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) &&
- !ip_addr_islinklocal(ipaddr)) {
-#if LWIP_AUTOIP
- struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload +
- sizeof(struct eth_hdr));
- /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with
- a link-local source address must always be "directly to its destination
- on the same physical link. The host MUST NOT send the packet to any
- router for forwarding". */
- if (!ip_addr_islinklocal(&iphdr->src))
-#endif /* LWIP_AUTOIP */
- {
- /* interface has default gateway? */
- if (!ip_addr_isany(&netif->gw)) {
- /* send to hardware address of default gateway IP address */
- ipaddr = &(netif->gw);
- /* no default gateway available */
- } else {
- /* no route to destination error (default gateway missing) */
- return ERR_RTE;
- }
- }
- }
-#if LWIP_NETIF_HWADDRHINT
- if (netif->addr_hint != NULL) {
- /* per-pcb cached entry was given */
- u8_t etharp_cached_entry = *(netif->addr_hint);
- if (etharp_cached_entry < ARP_TABLE_SIZE) {
-#endif /* LWIP_NETIF_HWADDRHINT */
- if ((arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) &&
- (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) {
- /* the per-pcb-cached entry is stable and the right one! */
- ETHARP_STATS_INC(etharp.cachehit);
- return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
- &arp_table[etharp_cached_entry].ethaddr);
- }
-#if LWIP_NETIF_HWADDRHINT
- }
- }
-#endif /* LWIP_NETIF_HWADDRHINT */
- /* queue on destination Ethernet address belonging to ipaddr */
- return etharp_query(netif, ipaddr, q);
- }
-
- /* continuation for multicast/broadcast destinations */
- /* obtain source Ethernet address of the given interface */
- /* send packet directly on the link */
- return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest);
-}
-
-/**
- * Send an ARP request for the given IP address and/or queue a packet.
- *
- * If the IP address was not yet in the cache, a pending ARP cache entry
- * is added and an ARP request is sent for the given address. The packet
- * is queued on this entry.
- *
- * If the IP address was already pending in the cache, a new ARP request
- * is sent for the given address. The packet is queued on this entry.
- *
- * If the IP address was already stable in the cache, and a packet is
- * given, it is directly sent and no ARP request is sent out.
- *
- * If the IP address was already stable in the cache, and no packet is
- * given, an ARP request is sent out.
- *
- * @param netif The lwIP network interface on which ipaddr
- * must be queried for.
- * @param ipaddr The IP address to be resolved.
- * @param q If non-NULL, a pbuf that must be delivered to the IP address.
- * q is not freed by this function.
- *
- * @note q must only be ONE packet, not a packet queue!
- *
- * @return
- * - ERR_BUF Could not make room for Ethernet header.
- * - ERR_MEM Hardware address unknown, and no more ARP entries available
- * to query for address or queue the packet.
- * - ERR_MEM Could not queue packet due to memory shortage.
- * - ERR_RTE No route to destination (no gateway to external networks).
- * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
- *
- */
-err_t
-etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
-{
- struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
- err_t result = ERR_MEM;
- s8_t i; /* ARP entry index */
-
- /* non-unicast address? */
- if (ip_addr_isbroadcast(ipaddr, netif) ||
- ip_addr_ismulticast(ipaddr) ||
- ip_addr_isany(ipaddr)) {
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));
- return ERR_ARG;
- }
-
- /* find entry in ARP cache, ask to create entry if queueing packet */
- i = find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);
-
- /* could not find or create entry? */
- if (i < 0) {
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n"));
- if (q) {
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n"));
- ETHARP_STATS_INC(etharp.memerr);
- }
- return (err_t)i;
- }
-
- /* mark a fresh entry as pending (we just sent a request) */
- if (arp_table[i].state == ETHARP_STATE_EMPTY) {
- arp_table[i].state = ETHARP_STATE_PENDING;
- }
-
- /* { i is either a STABLE or (new or existing) PENDING entry } */
- LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
- ((arp_table[i].state == ETHARP_STATE_PENDING) ||
- (arp_table[i].state == ETHARP_STATE_STABLE)));
-
- /* do we have a pending entry? or an implicit query request? */
- if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
- /* try to resolve it; send out ARP request */
- result = etharp_request(netif, ipaddr);
- if (result != ERR_OK) {
- /* ARP request couldn't be sent */
- /* We don't re-send arp request in etharp_tmr, but we still queue packets,
- since this failure could be temporary, and the next packet calling
- etharp_query again could lead to sending the queued packets. */
- }
- if (q == NULL) {
- return result;
- }
- }
-
- /* packet given? */
- LWIP_ASSERT("q != NULL", q != NULL);
- /* stable entry? */
- if (arp_table[i].state == ETHARP_STATE_STABLE) {
- /* we have a valid IP->Ethernet address mapping */
- ETHARP_SET_HINT(netif, i);
- /* send the packet */
- result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
- /* pending entry? (either just created or already pending */
- } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
- /* entry is still pending, queue the given packet 'q' */
- struct pbuf *p;
- int copy_needed = 0;
- /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
- * to copy the whole queue into a new PBUF_RAM (see bug #11400)
- * PBUF_ROMs can be left as they are, since ROM must not get changed. */
- p = q;
- while (p) {
- LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));
- if(p->type != PBUF_ROM) {
- copy_needed = 1;
- break;
- }
- p = p->next;
- }
- if(copy_needed) {
- /* copy the whole packet into new pbufs */
- p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
- if(p != NULL) {
- if (pbuf_copy(p, q) != ERR_OK) {
- pbuf_free(p);
- p = NULL;
- }
- }
- } else {
- /* referencing the old pbuf is enough */
- p = q;
- pbuf_ref(p);
- }
- /* packet could be taken over? */
- if (p != NULL) {
- /* queue packet ... */
-#if ARP_QUEUEING
- struct etharp_q_entry *new_entry;
- /* allocate a new arp queue entry */
- new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE);
- if (new_entry != NULL) {
- new_entry->next = 0;
- new_entry->p = p;
- if(arp_table[i].q != NULL) {
- /* queue was already existent, append the new entry to the end */
- struct etharp_q_entry *r;
- r = arp_table[i].q;
- while (r->next != NULL) {
- r = r->next;
- }
- r->next = new_entry;
- } else {
- /* queue did not exist, first item in queue */
- arp_table[i].q = new_entry;
- }
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
- result = ERR_OK;
- } else {
- /* the pool MEMP_ARP_QUEUE is empty */
- pbuf_free(p);
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
- result = ERR_MEM;
- }
-#else /* ARP_QUEUEING */
- /* always queue one packet per ARP request only, freeing a previously queued packet */
- if (arp_table[i].q != NULL) {
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
- pbuf_free(arp_table[i].q);
- }
- arp_table[i].q = p;
- result = ERR_OK;
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
-#endif /* ARP_QUEUEING */
- } else {
- ETHARP_STATS_INC(etharp.memerr);
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
- result = ERR_MEM;
- }
- }
- return result;
-}
-
-/**
- * Send a raw ARP packet (opcode and all addresses can be modified)
- *
- * @param netif the lwip network interface on which to send the ARP packet
- * @param ethsrc_addr the source MAC address for the ethernet header
- * @param ethdst_addr the destination MAC address for the ethernet header
- * @param hwsrc_addr the source MAC address for the ARP protocol header
- * @param ipsrc_addr the source IP address for the ARP protocol header
- * @param hwdst_addr the destination MAC address for the ARP protocol header
- * @param ipdst_addr the destination IP address for the ARP protocol header
- * @param opcode the type of the ARP packet
- * @return ERR_OK if the ARP packet has been sent
- * ERR_MEM if the ARP packet couldn't be allocated
- * any other err_t on failure
- */
-#if !LWIP_AUTOIP
-static
-#endif /* LWIP_AUTOIP */
-err_t
-etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
- const struct eth_addr *ethdst_addr,
- const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr,
- const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr,
- const u16_t opcode)
-{
- struct pbuf *p;
- err_t result = ERR_OK;
- struct eth_hdr *ethhdr;
- struct etharp_hdr *hdr;
-#if LWIP_AUTOIP
- const u8_t * ethdst_hwaddr;
-#endif /* LWIP_AUTOIP */
-
- /* allocate a pbuf for the outgoing ARP request packet */
- p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM);
- /* could allocate a pbuf for an ARP request? */
- if (p == NULL) {
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
- ("etharp_raw: could not allocate pbuf for ARP request.\n"));
- ETHARP_STATS_INC(etharp.memerr);
- return ERR_MEM;
- }
- LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr",
- (p->len >= SIZEOF_ETHARP_PACKET));
-
- ethhdr = (struct eth_hdr *)p->payload;
- hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n"));
- hdr->opcode = htons(opcode);
-
- LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
- (netif->hwaddr_len == ETHARP_HWADDR_LEN));
-#if LWIP_AUTOIP
- /* If we are using Link-Local, all ARP packets that contain a Link-Local
- * 'sender IP address' MUST be sent using link-layer broadcast instead of
- * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
- ethdst_hwaddr = ip_addr_islinklocal(ipsrc_addr) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr;
-#endif /* LWIP_AUTOIP */
- /* Write the ARP MAC-Addresses */
- ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr);
- ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr);
- /* Write the Ethernet MAC-Addresses */
-#if LWIP_AUTOIP
- ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr);
-#else /* LWIP_AUTOIP */
- ETHADDR16_COPY(ðhdr->dest, ethdst_addr);
-#endif /* LWIP_AUTOIP */
- ETHADDR16_COPY(ðhdr->src, ethsrc_addr);
- /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
- * structure packing. */
- IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr);
- IPADDR2_COPY(&hdr->dipaddr, ipdst_addr);
-
- hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET);
- hdr->proto = PP_HTONS(ETHTYPE_IP);
- /* set hwlen and protolen */
- hdr->hwlen = ETHARP_HWADDR_LEN;
- hdr->protolen = sizeof(ip_addr_t);
-
- ethhdr->type = PP_HTONS(ETHTYPE_ARP);
- /* send ARP query */
- result = netif->linkoutput(netif, p);
- ETHARP_STATS_INC(etharp.xmit);
- /* free ARP query packet */
- pbuf_free(p);
- p = NULL;
- /* could not allocate pbuf for ARP request */
-
- return result;
-}
-
-/**
- * Send an ARP request packet asking for ipaddr.
- *
- * @param netif the lwip network interface on which to send the request
- * @param ipaddr the IP address for which to ask
- * @return ERR_OK if the request has been sent
- * ERR_MEM if the ARP packet couldn't be allocated
- * any other err_t on failure
- */
-err_t
-etharp_request(struct netif *netif, ip_addr_t *ipaddr)
-{
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n"));
- return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast,
- (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero,
- ipaddr, ARP_REQUEST);
-}
-#endif /* LWIP_ARP */
-
-/**
- * Process received ethernet frames. Using this function instead of directly
- * calling ip_input and passing ARP frames through etharp in ethernetif_input,
- * the ARP cache is protected from concurrent access.
- *
- * @param p the recevied packet, p->payload pointing to the ethernet header
- * @param netif the network interface on which the packet was received
- */
-err_t
-ethernet_input(struct pbuf *p, struct netif *netif)
-{
- struct eth_hdr* ethhdr;
- u16_t type;
- s16_t ip_hdr_offset = SIZEOF_ETH_HDR;
-
- if (p->len <= SIZEOF_ETH_HDR) {
- /* a packet with only an ethernet header (or less) is not valid for us */
- ETHARP_STATS_INC(etharp.proterr);
- ETHARP_STATS_INC(etharp.drop);
- goto free_and_return;
- }
-
- /* points to packet payload, which starts with an Ethernet header */
- ethhdr = (struct eth_hdr *)p->payload;
- LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
- ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n",
- (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2],
- (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5],
- (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2],
- (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5],
- (unsigned)htons(ethhdr->type)));
-
- type = ethhdr->type;
-#if ETHARP_SUPPORT_VLAN
- if (type == PP_HTONS(ETHTYPE_VLAN)) {
- struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR);
- if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {
- /* a packet with only an ethernet/vlan header (or less) is not valid for us */
- ETHARP_STATS_INC(etharp.proterr);
- ETHARP_STATS_INC(etharp.drop);
- goto free_and_return;
- }
-#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */
- if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {
- /* silently ignore this packet: not for our VLAN */
- pbuf_free(p);
- return ERR_OK;
- }
-#endif /* ETHARP_VLAN_CHECK */
- type = vlan->tpid;
- ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;
- }
-#endif /* ETHARP_SUPPORT_VLAN */
-
-#if LWIP_ARP_FILTER_NETIF
- netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type));
-#endif /* LWIP_ARP_FILTER_NETIF*/
-
- switch (type) {
-#if LWIP_ARP
- /* IP packet? */
- case PP_HTONS(ETHTYPE_IP):
- if (!(netif->flags & NETIF_FLAG_ETHARP)) {
- goto free_and_return;
- }
-#if ETHARP_TRUST_IP_MAC
- /* update ARP table */
- etharp_ip_input(netif, p);
-#endif /* ETHARP_TRUST_IP_MAC */
- /* skip Ethernet header */
- if(pbuf_header(p, -ip_hdr_offset)) {
- LWIP_ASSERT("Can't move over header in packet", 0);
- goto free_and_return;
- } else {
- /* pass to IP layer */
- ip_input(p, netif);
- }
- break;
-
- case PP_HTONS(ETHTYPE_ARP):
- if (!(netif->flags & NETIF_FLAG_ETHARP)) {
- goto free_and_return;
- }
- /* pass p to ARP module */
- etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p);
- break;
-#endif /* LWIP_ARP */
-#if PPPOE_SUPPORT
- case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */
- pppoe_disc_input(netif, p);
- break;
-
- case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */
- pppoe_data_input(netif, p);
- break;
-#endif /* PPPOE_SUPPORT */
-
- default:
- ETHARP_STATS_INC(etharp.proterr);
- ETHARP_STATS_INC(etharp.drop);
- goto free_and_return;
- }
-
- /* This means the pbuf is freed or consumed,
- so the caller doesn't have to free it again */
- return ERR_OK;
-
-free_and_return:
- pbuf_free(p);
- return ERR_OK;
-}
-#endif /* LWIP_ARP || LWIP_ETHERNET */
+++ /dev/null
-/*\r
- FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
- \r
-\r
- ***************************************************************************\r
- * *\r
- * FreeRTOS tutorial books are available in pdf and paperback. *\r
- * Complete, revised, and edited pdf reference manuals are also *\r
- * available. *\r
- * *\r
- * Purchasing FreeRTOS documentation will not only help you, by *\r
- * ensuring you get running as quickly as possible and with an *\r
- * in-depth knowledge of how to use FreeRTOS, it will also help *\r
- * the FreeRTOS project to continue with its mission of providing *\r
- * professional grade, cross platform, de facto standard solutions *\r
- * for microcontrollers - completely free of charge! *\r
- * *\r
- * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
- * *\r
- * Thank you for using FreeRTOS, and thank you for your support! *\r
- * *\r
- ***************************************************************************\r
-\r
-\r
- This file is part of the FreeRTOS distribution.\r
-\r
- FreeRTOS is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License (version 2) as published by the\r
- Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
- >>>NOTE<<< The modification to the GPL is included to allow you to\r
- distribute a combined work that includes FreeRTOS without being obliged to\r
- provide the source code for proprietary components outside of the FreeRTOS\r
- kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
- more details. You should have received a copy of the GNU General Public\r
- License and the FreeRTOS license exception along with FreeRTOS; if not it\r
- can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
- by writing to Richard Barry, contact details for whom are available on the\r
- FreeRTOS WEB site.\r
-\r
- 1 tab == 4 spaces!\r
-\r
- http://www.FreeRTOS.org - Documentation, latest information, license and\r
- contact details.\r
-\r
- http://www.SafeRTOS.com - A version that is certified for use in safety\r
- critical systems.\r
-\r
- http://www.OpenRTOS.com - Commercial support, development, porting,\r
- licensing and training services.\r
-*/\r
-\r
-/* FreeRTOS includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-\r
-/* BSP includes. */\r
-#include "xemaclite.h"\r
-#include "xintc_l.h"\r
-\r
-/* lwIP includes. */\r
-#include "lwip/opt.h"\r
-#include "lwip/def.h"\r
-#include "lwip/mem.h"\r
-#include "lwip/pbuf.h"\r
-#include "lwip/sys.h"\r
-#include <lwip/stats.h>\r
-#include <lwip/snmp.h>\r
-#include "netif/etharp.h"\r
-\r
-/* Define those to better describe your network interface. */\r
-#define IFNAME0 'e'\r
-#define IFNAME1 'l'\r
-\r
-/* When a packet is ready to be sent, if it cannot be sent immediately then\r
- * the task performing the transmit will block for netifTX_BUFFER_FREE_WAIT\r
- * milliseconds. It will do this a maximum of netifMAX_TX_ATTEMPTS before\r
- * giving up.
- */\r
-#define netifTX_BUFFER_FREE_WAIT ( ( portTickType ) 5UL / portTICK_RATE_MS )\r
-#define netifMAX_TX_ATTEMPTS ( 5 )\r
-\r
-#define netifMAX_MTU 1500\r
-\r
-struct xEthernetIf\r
-{\r
- struct eth_addr *ethaddr;\r
- /* Add whatever per-interface state that is needed here. */\r
-};\r
-\r
-/*\r
- * Place received packet in a pbuf and send a message to the tcpip task to let\r
- * it know new data has arrived.\r
- */\r
-static void prvEthernetInput( struct netif *pxNetIf, const unsigned char * const pucInputData, long lInputLength );\r
-\r
-/*\r
- * Copy the received data into a pbuf.\r
- */\r
-static struct pbuf *prvLowLevelInput( const unsigned char * const pucInputData, unsigned short usDataLength );\r
-\r
-/*\r
- * Send data from a pbuf to the hardware.\r
- */\r
-static err_t prvLowLevelOutput( struct netif *pxNetIf, struct pbuf *p );\r
-\r
-/*\r
- * Perform any hardware and/or driver initialisation necessary.\r
- */\r
-static void prvLowLevelInit( struct netif *pxNetIf );\r
-\r
-/*\r
- * Functions that get registered as the Rx and Tx interrupt handers\r
- * respectively.\r
- */\r
-static void prvRxHandler( void *pvNetIf );\r
-static void prvTxHandler( void *pvUnused );\r
-\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* The instance of the xEmacLite IP being used in this driver. */\r
-static XEmacLite xEMACInstance;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/**\r
- * In this function, the hardware should be initialized.\r
- * Called from ethernetif_init().\r
- *\r
- * @param pxNetIf the already initialized lwip network interface structure\r
- * for this etherpxNetIf\r
- */\r
-static void prvLowLevelInit( struct netif *pxNetIf )\r
-{\r
-portBASE_TYPE xStatus;\r
-\r
- /* set MAC hardware address length */\r
- pxNetIf->hwaddr_len = ETHARP_HWADDR_LEN;\r
-\r
- /* set MAC hardware address */\r
- pxNetIf->hwaddr[ 0 ] = configMAC_ADDR0;\r
- pxNetIf->hwaddr[ 1 ] = configMAC_ADDR1;\r
- pxNetIf->hwaddr[ 2 ] = configMAC_ADDR2;\r
- pxNetIf->hwaddr[ 3 ] = configMAC_ADDR3;\r
- pxNetIf->hwaddr[ 4 ] = configMAC_ADDR4;\r
- pxNetIf->hwaddr[ 5 ] = configMAC_ADDR5;\r
-\r
- /* device capabilities */\r
- pxNetIf->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;\r
-\r
- /* maximum transfer unit */\r
- pxNetIf->mtu = netifMAX_MTU;\r
-\r
- /* Broadcast capability */\r
- pxNetIf->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;\r
-\r
- /* Initialize the mac */\r
- xStatus = XEmacLite_Initialize( &xEMACInstance, XPAR_EMACLITE_0_DEVICE_ID );\r
-\r
- if( xStatus == XST_SUCCESS )\r
- {\r
- /* Set mac address */\r
- XEmacLite_SetMacAddress( &xEMACInstance, ( Xuint8* )( pxNetIf->hwaddr ) );\r
-\r
- /* Flush any frames already received */\r
- XEmacLite_FlushReceive( &xEMACInstance );\r
-\r
- /* Set Rx, Tx interrupt handlers */\r
- XEmacLite_SetRecvHandler( &xEMACInstance, ( void * ) pxNetIf, prvRxHandler );\r
- XEmacLite_SetSendHandler( &xEMACInstance, NULL, prvTxHandler );\r
-\r
- /* Enable Rx, Tx interrupts */\r
- XEmacLite_EnableInterrupts( &xEMACInstance );\r
-\r
- /* Install the standard Xilinx library interrupt handler itself.\r
- *NOTE* The xPortInstallInterruptHandler() API function must be used\r
- for this purpose. */\r
- xStatus = xPortInstallInterruptHandler( XPAR_INTC_0_EMACLITE_0_VEC_ID, ( XInterruptHandler ) XEmacLite_InterruptHandler, &xEMACInstance );\r
-\r
- /* Enable the interrupt in the interrupt controller.\r
- *NOTE* The vPortEnableInterrupt() API function must be used for this\r
- purpose. */\r
- vPortEnableInterrupt( XPAR_INTC_0_EMACLITE_0_VEC_ID );\r
- }\r
-\r
- configASSERT( xStatus == pdPASS );\r
-}\r
-\r
-/**\r
- * This function should do the actual transmission of the packet. The packet is\r
- * contained in the pbuf that is passed to the function. This pbuf\r
- * might be chained.\r
- *\r
- * @param pxNetIf the lwip network interface structure for this etherpxNetIf\r
- * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)\r
- * @return ERR_OK if the packet could be sent\r
- * an err_t value if the packet couldn't be sent\r
- *\r
- * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to\r
- * strange results. You might consider waiting for space in the DMA queue\r
- * to become availale since the stack doesn't retry to send a packet\r
- * dropped because of memory failure (except for the TCP timers).\r
- */\r
-\r
-static err_t prvLowLevelOutput( struct netif *pxNetIf, struct pbuf *p )\r
-{\r
-\r
- /* This is taken from lwIP example code and therefore does not conform\r
- to the FreeRTOS coding standard. */\r
-\r
-struct pbuf *q;\r
-static unsigned char ucBuffer[ 1520 ] __attribute__((aligned(32)));\r
-unsigned char *pucBuffer = ucBuffer;\r
-unsigned char *pucChar;\r
-struct eth_hdr *pxHeader;\r
-u16_t usTotalLength = p->tot_len - ETH_PAD_SIZE;\r
-err_t xReturn = ERR_OK;\r
-long x;\r
-\r
- #if defined(LWIP_DEBUG) && LWIP_NETIF_TX_SINGLE_PBUF\r
- LWIP_ASSERT("p->next == NULL && p->len == p->tot_len", p->next == NULL && p->len == p->tot_len);\r
- #endif\r
-\r
- /* Initiate transfer. */\r
- if( p->len == p->tot_len ) \r
- {\r
- /* No pbuf chain, don't have to copy -> faster. */\r
- pucBuffer = &( ( unsigned char * ) p->payload )[ ETH_PAD_SIZE ];\r
- } \r
- else \r
- {\r
- /* pbuf chain, copy into contiguous ucBuffer. */\r
- if( p->tot_len >= sizeof( ucBuffer ) )\r
- {\r
- LINK_STATS_INC( link.lenerr );\r
- LINK_STATS_INC( link.drop );\r
- snmp_inc_ifoutdiscards( pxNetIf );\r
- xReturn = ERR_BUF;\r
- }\r
- else\r
- {\r
- pucChar = ucBuffer;\r
-\r
- for( q = p; q != NULL; q = q->next )\r
- {\r
- /* Send the data from the pbuf to the interface, one pbuf at a\r
- time. The size of the data in each pbuf is kept in the ->len\r
- variable. */\r
- /* send data from(q->payload, q->len); */\r
- LWIP_DEBUGF( NETIF_DEBUG, ( "NETIF: send pucChar %p q->payload %p q->len %i q->next %p\n", pucChar, q->payload, ( int ) q->len, ( void* ) q->next ) );\r
- if( q == p )\r
- {\r
- memcpy( pucChar, &( ( char * ) q->payload )[ ETH_PAD_SIZE ], q->len - ETH_PAD_SIZE );\r
- pucChar += q->len - ETH_PAD_SIZE;\r
- }\r
- else\r
- {\r
- memcpy( pucChar, q->payload, q->len );\r
- pucChar += q->len;\r
- }\r
- }\r
- }\r
- }\r
-\r
- if( xReturn == ERR_OK )\r
- {\r
- for( x = 0; x < netifMAX_TX_ATTEMPTS; x++ )\r
- {\r
- xReturn = XEmacLite_Send( &xEMACInstance, pucBuffer, ( int ) usTotalLength );\r
- if( xReturn == XST_SUCCESS )\r
- {\r
- break;\r
- }\r
- else\r
- {\r
- vTaskDelay( netifTX_BUFFER_FREE_WAIT );\r
- }\r
- }\r
-\r
- if( xReturn != XST_SUCCESS )\r
- {\r
- LINK_STATS_INC( link.memerr );\r
- LINK_STATS_INC( link.drop );\r
- snmp_inc_ifoutdiscards( pxNetIf );\r
- xReturn = ERR_BUF;\r
- }\r
- else\r
- {\r
- LINK_STATS_INC( link.xmit );\r
- snmp_add_ifoutoctets( pxNetIf, usTotalLength );\r
- pxHeader = ( struct eth_hdr * )p->payload;\r
-\r
- if( ( pxHeader->dest.addr[ 0 ] & 1 ) != 0 ) \r
- {\r
- /* broadcast or multicast packet*/\r
- snmp_inc_ifoutnucastpkts( pxNetIf );\r
- } \r
- else \r
- {\r
- /* unicast packet */\r
- snmp_inc_ifoutucastpkts( pxNetIf );\r
- }\r
- }\r
- }\r
-\r
- return xReturn;\r
-}\r
-\r
-/**\r
- * Should allocate a pbuf and transfer the bytes of the incoming\r
- * packet from the interface into the pbuf.\r
- *\r
- * @param pxNetIf the lwip network interface structure for this etherpxNetIf\r
- * @return a pbuf filled with the received packet (including MAC header)\r
- * NULL on memory error\r
- */\r
-static struct pbuf *prvLowLevelInput( const unsigned char * const pucInputData, unsigned short usDataLength )\r
-{\r
-struct pbuf *p = NULL, *q;\r
-\r
- if( usDataLength > 0U )\r
- {\r
- #if ETH_PAD_SIZE\r
- len += ETH_PAD_SIZE; /* allow room for Ethernet padding */\r
- #endif\r
-\r
- /* We allocate a pbuf chain of pbufs from the pool. */\r
- p = pbuf_alloc( PBUF_RAW, usDataLength, PBUF_POOL );\r
- \r
- if( p != NULL ) \r
- {\r
- #if ETH_PAD_SIZE\r
- pbuf_header( p, -ETH_PAD_SIZE ); /* drop the padding word */\r
- #endif\r
-\r
- /* We iterate over the pbuf chain until we have read the entire\r
- * packet into the pbuf. */\r
- usDataLength = 0U;\r
- for( q = p; q != NULL; q = q->next ) \r
- {\r
- /* Read enough bytes to fill this pbuf in the chain. The\r
- * available data in the pbuf is given by the q->len\r
- * variable.\r
- * This does not necessarily have to be a memcpy, you can also preallocate\r
- * pbufs for a DMA-enabled MAC and after receiving truncate it to the\r
- * actually received size. In this case, ensure the usTotalLength member of the\r
- * pbuf is the sum of the chained pbuf len members.\r
- */\r
- memcpy( q->payload, &( pucInputData[ usDataLength ] ), q->len );\r
- usDataLength += q->len;\r
- }\r
-\r
- #if ETH_PAD_SIZE\r
- pbuf_header( p, ETH_PAD_SIZE ); /* reclaim the padding word */\r
- #endif\r
-\r
- LINK_STATS_INC(link.recv);\r
- }\r
- }\r
-\r
- return p; \r
-}\r
-\r
-/**\r
- * This function should be called when a packet is ready to be read\r
- * from the interface. It uses the function prvLowLevelInput() that\r
- * should handle the actual reception of bytes from the network\r
- * interface. Then the type of the received packet is determined and\r
- * the appropriate input function is called.\r
- *\r
- * @param pxNetIf the lwip network interface structure for this etherpxNetIf\r
- */\r
-static void prvEthernetInput( struct netif *pxNetIf, const unsigned char * const pucInputData, long lInputLength )\r
-{\r
- /* This is taken from lwIP example code and therefore does not conform\r
- to the FreeRTOS coding standard. */\r
- \r
-struct eth_hdr *pxHeader;\r
-struct pbuf *p;\r
-\r
- /* move received packet into a new pbuf */\r
- p = prvLowLevelInput( pucInputData, lInputLength );\r
-\r
- /* no packet could be read, silently ignore this */\r
- if( p != NULL )\r
- {\r
- /* points to packet payload, which starts with an Ethernet header */\r
- pxHeader = p->payload;\r
-\r
- switch( htons( pxHeader->type ) )\r
- {\r
- /* IP or ARP packet? */\r
- case ETHTYPE_IP:\r
- case ETHTYPE_ARP:\r
- /* full packet send to tcpip_thread to process */\r
- if( pxNetIf->input( p, pxNetIf ) != ERR_OK )\r
- {\r
- LWIP_DEBUGF(NETIF_DEBUG, ( "ethernetif_input: IP input error\n" ) );\r
- pbuf_free(p);\r
- p = NULL;\r
- }\r
- break;\r
-\r
- default:\r
- pbuf_free( p );\r
- p = NULL;\r
- break;\r
- }\r
- }\r
-}\r
-\r
-/**\r
- * Should be called at the beginning of the program to set up the\r
- * network interface. It calls the function prvLowLevelInit() to do the\r
- * actual setup of the hardware.\r
- *\r
- * This function should be passed as a parameter to pxNetIf_add().\r
- *\r
- * @param pxNetIf the lwip network interface structure for this etherpxNetIf\r
- * @return ERR_OK if the loopif is initialized\r
- * ERR_MEM if private data couldn't be allocated\r
- * any other err_t on error\r
- */\r
-err_t ethernetif_init( struct netif *pxNetIf )\r
-{\r
-err_t xReturn = ERR_OK;\r
-\r
- /* This is taken from lwIP example code and therefore does not conform\r
- to the FreeRTOS coding standard. */\r
- \r
-struct xEthernetIf *pxEthernetIf;\r
-\r
- LWIP_ASSERT( "pxNetIf != NULL", ( pxNetIf != NULL ) );\r
- \r
- pxEthernetIf = mem_malloc( sizeof( struct xEthernetIf ) );\r
- if( pxEthernetIf == NULL ) \r
- {\r
- LWIP_DEBUGF(NETIF_DEBUG, ( "ethernetif_init: out of memory\n" ) );\r
- xReturn = ERR_MEM;\r
- }\r
- else\r
- {\r
- #if LWIP_NETIF_HOSTNAME\r
- {\r
- /* Initialize interface hostname */\r
- pxNetIf->hostname = "lwip";\r
- }\r
- #endif /* LWIP_NETIF_HOSTNAME */\r
-\r
- pxNetIf->state = pxEthernetIf;\r
- pxNetIf->name[ 0 ] = IFNAME0;\r
- pxNetIf->name[ 1 ] = IFNAME1;\r
-\r
- /* We directly use etharp_output() here to save a function call.\r
- * You can instead declare your own function an call etharp_output()\r
- * from it if you have to do some checks before sending (e.g. if link\r
- * is available...) */\r
- pxNetIf->output = etharp_output;\r
- pxNetIf->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP;\r
- pxNetIf->hwaddr_len = ETHARP_HWADDR_LEN;\r
- pxNetIf->mtu = netifMAX_MTU;\r
- pxNetIf->linkoutput = prvLowLevelOutput;\r
-\r
- pxEthernetIf->ethaddr = ( struct eth_addr * ) &( pxNetIf->hwaddr[ 0 ] );\r
-\r
- /* initialize the hardware */\r
- prvLowLevelInit( pxNetIf );\r
- }\r
-\r
- return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvRxHandler( void *pvNetIf )\r
-{\r
- /* This is taken from lwIP example code and therefore does not conform\r
- to the FreeRTOS coding standard. */\r
-\r
-struct eth_hdr *pxHeader;\r
-struct pbuf *p;\r
-unsigned short usInputLength;\r
-static unsigned char ucBuffer[ 1520 ] __attribute__((aligned(32)));\r
-extern portBASE_TYPE xInsideISR;\r
-struct netif *pxNetIf = ( struct netif * ) pvNetIf;\r
-\r
- XIntc_AckIntr( XPAR_ETHERNET_LITE_BASEADDR, XPAR_ETHERNET_LITE_IP2INTC_IRPT_MASK );\r
-\r
- /* Ensure the pbuf handling functions don't attempt to use critical\r
- sections. */\r
- xInsideISR++;\r
-\r
- usInputLength = ( long ) XEmacLite_Recv( &xEMACInstance, ucBuffer );\r
-\r
- /* move received packet into a new pbuf */\r
- p = prvLowLevelInput( ucBuffer, usInputLength );\r
-\r
- /* no packet could be read, silently ignore this */\r
- if( p != NULL )\r
- {\r
- /* points to packet payload, which starts with an Ethernet header */\r
- pxHeader = p->payload;\r
-\r
- switch( htons( pxHeader->type ) )\r
- {\r
- /* IP or ARP packet? */\r
- case ETHTYPE_IP:\r
- case ETHTYPE_ARP:\r
- /* full packet send to tcpip_thread to process */\r
- if( pxNetIf->input( p, pxNetIf ) != ERR_OK )\r
- {\r
- LWIP_DEBUGF(NETIF_DEBUG, ( "ethernetif_input: IP input error\n" ) );\r
- pbuf_free(p);\r
- p = NULL;\r
- }\r
- break;\r
-\r
- default:\r
- pbuf_free( p );\r
- p = NULL;\r
- break;\r
- }\r
- }\r
-\r
- xInsideISR--;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvTxHandler( void *pvUnused )\r
-{\r
- XIntc_AckIntr( XPAR_ETHERNET_LITE_BASEADDR, XPAR_ETHERNET_LITE_IP2INTC_IRPT_MASK );\r
-}\r
-\r
-\r
-void vTemp( void )\r
-{\r
-char *pc;\r
-\r
- XEmacLite_Recv( &xEMACInstance, pc );\r
-}\r
-\r
-\r
-\r
-\r
-\r
-\r
-#if 0\r
-\r
-static void\r
-xemacif_recv_handler(void *arg) {\r
- struct xemac_s *xemac = (struct xemac_s *)(arg);\r
- xemacliteif_s *xemacliteif = (xemacliteif_s *)(xemac->state);\r
- XEmacLite *instance = xemacliteif->instance;\r
- struct pbuf *p;\r
- int len = 0;\r
- struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];\r
-\r
- XIntc_AckIntr(xtopologyp->intc_baseaddr, 1 << xtopologyp->intc_emac_intr);\r
- p = pbuf_alloc(PBUF_RAW, XEL_MAX_FRAME_SIZE, PBUF_POOL);\r
- if (!p) {\r
-#if LINK_STATS\r
- lwip_stats.link.memerr++;\r
- lwip_stats.link.drop++;\r
-#endif\r
- /* receive and just ignore the frame.\r
- * we need to receive the frame because otherwise emaclite will\r
- * not generate any other interrupts since it cannot receive,\r
- * and we do not actively poll the emaclite\r
- */\r
- XEmacLite_Recv(instance, xemac_tx_frame);\r
- return;\r
- }\r
-\r
- /* receive the packet */\r
- len = XEmacLite_Recv(instance, p->payload);\r
-\r
- if (len == 0) {\r
-#if LINK_STATS\r
- lwip_stats.link.drop++;\r
-#endif\r
- return;\r
- }\r
-\r
- /* store it in the receive queue, where it'll be processed by xemacif input thread */\r
- if (pq_enqueue(xemacliteif->recv_q, (void*)p) < 0) {\r
-#if LINK_STATS\r
- lwip_stats.link.memerr++;\r
- lwip_stats.link.drop++;\r
-#endif\r
- return;\r
- }\r
-\r
-#if !NO_SYS\r
- sys_sem_signal(xemac->sem_rx_data_available);\r
-#endif\r
-\r
-}\r
-\r
-#endif\r
-\r
-\r
+++ /dev/null
-#pragma pack(push,1)
+++ /dev/null
-/*
- * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-#ifndef __ARCH_CC_H__
-#define __ARCH_CC_H__
-
-/* Include some files for defining library routines */
-#include <stdio.h> /* printf, fflush, FILE */
-#include <stdlib.h> /* abort */
-
-
-
-/** @todo fix some warnings: don't use #pragma if compiling with cygwin gcc */
-#ifndef __GNUC__
- #include <limits.h>
- #pragma warning (disable: 4244) /* disable conversion warning (implicit integer promotion!) */
- #pragma warning (disable: 4127) /* conditional expression is constant */
- #pragma warning (disable: 4996) /* 'strncpy' was declared deprecated */
- #pragma warning (disable: 4103) /* structure packing changed by including file */
-#endif
-
-#define LWIP_PROVIDE_ERRNO
-
-/* Define generic types used in lwIP */
-typedef unsigned char u8_t;
-typedef signed char s8_t;
-typedef unsigned short u16_t;
-typedef signed short s16_t;
-typedef unsigned long u32_t;
-typedef signed long s32_t;
-
-typedef size_t mem_ptr_t;
-typedef u32_t sys_prot_t;
-
-/* Define (sn)printf formatters for these lwIP types */
-#define X8_F "02x"
-#define U16_F "hu"
-#define S16_F "hd"
-#define X16_F "hx"
-#define U32_F "lu"
-#define S32_F "ld"
-#define X32_F "lx"
-#define SZT_F U32_F
-
-/* Compiler hints for packing structures */
-#define PACK_STRUCT_STRUCT __attribute__( (packed) )
-
-/* Plaform specific diagnostic output */
-#define LWIP_PLATFORM_DIAG(x) do { printf x; } while(0)
-
-#define LWIP_PLATFORM_ASSERT(x) do { printf("Assertion \"%s\" failed at line %d in %s\n", \
- x, __LINE__, __FILE__); fflush(NULL); abort(); } while(0)
-
-#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
- printf("Assertion \"%s\" failed at line %d in %s\n", message, __LINE__, __FILE__); \
- fflush(NULL);handler;} } while(0)
-
-/* C runtime functions redefined */
-#define snprintf _snprintf
-
-u32_t dns_lookup_external_hosts_file(const char *name);
-
-#define LWIP_RAND() ((u32_t)rand())
-
-#endif /* __ARCH_CC_H__ */
+++ /dev/null
-#pragma pack(pop)
+++ /dev/null
-/*
- * 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>
- *
- */
-#ifndef __PERF_H__
-#define __PERF_H__
-
-#define PERF_START /* null definition */
-#define PERF_STOP(x) /* null definition */
-
-#endif /* __PERF_H__ */
+++ /dev/null
-/*\r
- * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
- * All rights reserved. \r
- * \r
- * Redistribution and use in source and binary forms, with or without modification, \r
- * are permitted provided that the following conditions are met:\r
- *\r
- * 1. Redistributions of source code must retain the above copyright notice,\r
- * this list of conditions and the following disclaimer.\r
- * 2. Redistributions in binary form must reproduce the above copyright notice,\r
- * this list of conditions and the following disclaimer in the documentation\r
- * and/or other materials provided with the distribution.\r
- * 3. The name of the author may not be used to endorse or promote products\r
- * derived from this software without specific prior written permission. \r
- *\r
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
- * OF SUCH DAMAGE.\r
- *\r
- * This file is part of the lwIP TCP/IP stack.\r
- * \r
- * Author: Adam Dunkels <adam@sics.se>\r
- *\r
- */\r
-#ifndef __ARCH_SYS_ARCH_H__\r
-#define __ARCH_SYS_ARCH_H__\r
-\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-#include "semphr.h"\r
-\r
-#define SYS_MBOX_NULL ( ( xQueueHandle ) NULL )\r
-#define SYS_SEM_NULL ( ( xSemaphoreHandle ) NULL )\r
-#define SYS_DEFAULT_THREAD_STACK_DEPTH configMINIMAL_STACK_SIZE\r
-\r
-typedef xSemaphoreHandle sys_sem_t;\r
-typedef xSemaphoreHandle sys_mutex_t;\r
-typedef xQueueHandle sys_mbox_t;\r
-typedef xTaskHandle sys_thread_t;\r
-\r
-#define sys_mbox_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE )\r
-#define sys_mbox_set_invalid( x ) ( ( *x ) = NULL )\r
-#define sys_sem_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE )\r
-#define sys_sem_set_invalid( x ) ( ( *x ) = NULL )\r
-\r
-\r
-#endif /* __ARCH_SYS_ARCH_H__ */\r
-\r
+++ /dev/null
-/*\r
- * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
- * All rights reserved.\r
- *\r
- * Redistribution and use in source and binary forms, with or without modification,\r
- * are permitted provided that the following conditions are met:\r
- *\r
- * 1. Redistributions of source code must retain the above copyright notice,\r
- * this list of conditions and the following disclaimer.\r
- * 2. Redistributions in binary form must reproduce the above copyright notice,\r
- * this list of conditions and the following disclaimer in the documentation\r
- * and/or other materials provided with the distribution.\r
- * 3. The name of the author may not be used to endorse or promote products\r
- * derived from this software without specific prior written permission.\r
- *\r
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
- * OF SUCH DAMAGE.\r
- *\r
- * This file is part of the lwIP TCP/IP stack.\r
- *\r
- * Author: Adam Dunkels <adam@sics.se>\r
- *\r
- */\r
-\r
-//*****************************************************************************\r
-//\r
-// Include OS functionality.\r
-//\r
-//*****************************************************************************\r
-\r
-/* ------------------------ System architecture includes ----------------------------- */\r
-#include "arch/sys_arch.h"\r
-\r
-/* ------------------------ lwIP includes --------------------------------- */\r
-#include "lwip/opt.h"\r
-\r
-#include "lwip/debug.h"\r
-#include "lwip/def.h"\r
-#include "lwip/sys.h"\r
-#include "lwip/mem.h"\r
-#include "lwip/stats.h"\r
-\r
-/* Very crude mechanism used to determine if the critical section handling\r
-functions are being called from an interrupt context or not. This relies on\r
-the interrupt handler setting this variable manually. */\r
-portBASE_TYPE xInsideISR = pdFALSE;\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_mbox_new\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Creates a new mailbox\r
- * Inputs:\r
- * int size -- Size of elements in the mailbox\r
- * Outputs:\r
- * sys_mbox_t -- Handle to new mailbox\r
- *---------------------------------------------------------------------------*/\r
-err_t sys_mbox_new( sys_mbox_t *pxMailBox, int iSize )\r
-{\r
-err_t xReturn = ERR_MEM;\r
-\r
- *pxMailBox = xQueueCreate( iSize, sizeof( void * ) );\r
-\r
- if( *pxMailBox != NULL )\r
- {\r
- xReturn = ERR_OK;\r
- #if SYS_STATS\r
- {\r
- SYS_STATS_INC( mbox.used );\r
- }\r
- #endif /* SYS_STATS */\r
- }\r
-\r
- return xReturn;\r
-}\r
-\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_mbox_free\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Deallocates a mailbox. If there are messages still present in the\r
- * mailbox when the mailbox is deallocated, it is an indication of a\r
- * programming error in lwIP and the developer should be notified.\r
- * Inputs:\r
- * sys_mbox_t mbox -- Handle of mailbox\r
- * Outputs:\r
- * sys_mbox_t -- Handle to new mailbox\r
- *---------------------------------------------------------------------------*/\r
-void sys_mbox_free( sys_mbox_t *pxMailBox )\r
-{\r
-unsigned long ulMessagesWaiting;\r
-\r
- ulMessagesWaiting = uxQueueMessagesWaiting( *pxMailBox );\r
- configASSERT( ( ulMessagesWaiting == 0 ) );\r
-\r
- #if SYS_STATS\r
- {\r
- if( ulMessagesWaiting != 0UL )\r
- {\r
- SYS_STATS_INC( mbox.err );\r
- }\r
-\r
- SYS_STATS_DEC( mbox.used );\r
- }\r
- #endif /* SYS_STATS */\r
-\r
- vQueueDelete( *pxMailBox );\r
-}\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_mbox_post\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Post the "msg" to the mailbox.\r
- * Inputs:\r
- * sys_mbox_t mbox -- Handle of mailbox\r
- * void *data -- Pointer to data to post\r
- *---------------------------------------------------------------------------*/\r
-void sys_mbox_post( sys_mbox_t *pxMailBox, void *pxMessageToPost )\r
-{\r
- while( xQueueSendToBack( *pxMailBox, &pxMessageToPost, portMAX_DELAY ) != pdTRUE );\r
-}\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_mbox_trypost\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Try to post the "msg" to the mailbox. Returns immediately with\r
- * error if cannot.\r
- * Inputs:\r
- * sys_mbox_t mbox -- Handle of mailbox\r
- * void *msg -- Pointer to data to post\r
- * Outputs:\r
- * err_t -- ERR_OK if message posted, else ERR_MEM\r
- * if not.\r
- *---------------------------------------------------------------------------*/\r
-err_t sys_mbox_trypost( sys_mbox_t *pxMailBox, void *pxMessageToPost )\r
-{\r
-err_t xReturn;\r
-portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
-\r
- if( xInsideISR != pdFALSE )\r
- {\r
- xReturn = xQueueSendFromISR( *pxMailBox, &pxMessageToPost, &xHigherPriorityTaskWoken );\r
- }\r
- else\r
- {\r
- xReturn = xQueueSend( *pxMailBox, &pxMessageToPost, ( portTickType ) 0 );\r
- }\r
-\r
- if( xReturn == pdPASS )\r
- {\r
- xReturn = ERR_OK;\r
- }\r
- else\r
- {\r
- /* The queue was already full. */\r
- xReturn = ERR_MEM;\r
- #if SYS_STATS\r
- {\r
- SYS_STATS_INC( mbox.err );\r
- }\r
- #endif /* SYS_STATS */\r
- }\r
-\r
- return xReturn;\r
-}\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_arch_mbox_fetch\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Blocks the thread until a message arrives in the mailbox, but does\r
- * not block the thread longer than "timeout" milliseconds (similar to\r
- * the sys_arch_sem_wait() function). The "msg" argument is a result\r
- * parameter that is set by the function (i.e., by doing "*msg =\r
- * ptr"). The "msg" parameter maybe NULL to indicate that the message\r
- * should be dropped.\r
- *\r
- * The return values are the same as for the sys_arch_sem_wait() function:\r
- * Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a\r
- * timeout.\r
- *\r
- * Note that a function with a similar name, sys_mbox_fetch(), is\r
- * implemented by lwIP.\r
- * Inputs:\r
- * sys_mbox_t mbox -- Handle of mailbox\r
- * void **msg -- Pointer to pointer to msg received\r
- * u32_t timeout -- Number of milliseconds until timeout\r
- * Outputs:\r
- * u32_t -- SYS_ARCH_TIMEOUT if timeout, else number\r
- * of milliseconds until received.\r
- *---------------------------------------------------------------------------*/\r
-u32_t sys_arch_mbox_fetch( sys_mbox_t *pxMailBox, void **ppvBuffer, u32_t ulTimeOut )\r
-{\r
-void *pvDummy;\r
-portTickType xStartTime, xEndTime, xElapsed;\r
-unsigned long ulReturn;\r
-\r
- xStartTime = xTaskGetTickCount();\r
-\r
- if( NULL == ppvBuffer )\r
- {\r
- ppvBuffer = &pvDummy;\r
- }\r
-\r
- if( ulTimeOut != 0UL )\r
- {\r
- configASSERT( xInsideISR == ( portBASE_TYPE ) 0 );\r
-\r
- if( pdTRUE == xQueueReceive( *pxMailBox, &( *ppvBuffer ), ulTimeOut/ portTICK_RATE_MS ) )\r
- {\r
- xEndTime = xTaskGetTickCount();\r
- xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS;\r
-\r
- ulReturn = xElapsed;\r
- }\r
- else\r
- {\r
- /* Timed out. */\r
- *ppvBuffer = NULL;\r
- ulReturn = SYS_ARCH_TIMEOUT;\r
- }\r
- }\r
- else\r
- {\r
- while( pdTRUE != xQueueReceive( pxMailBox, &( *ppvBuffer ), portMAX_DELAY ) );\r
- xEndTime = xTaskGetTickCount();\r
- xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS;\r
-\r
- if( xElapsed == 0UL )\r
- {\r
- xElapsed = 1UL;\r
- }\r
-\r
- ulReturn = xElapsed;\r
- }\r
-\r
- return ulReturn;\r
-}\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_arch_mbox_tryfetch\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Similar to sys_arch_mbox_fetch, but if message is not ready\r
- * immediately, we'll return with SYS_MBOX_EMPTY. On success, 0 is\r
- * returned.\r
- * Inputs:\r
- * sys_mbox_t mbox -- Handle of mailbox\r
- * void **msg -- Pointer to pointer to msg received\r
- * Outputs:\r
- * u32_t -- SYS_MBOX_EMPTY if no messages. Otherwise,\r
- * return ERR_OK.\r
- *---------------------------------------------------------------------------*/\r
-u32_t sys_arch_mbox_tryfetch( sys_mbox_t *pxMailBox, void **ppvBuffer )\r
-{\r
-void *pvDummy;\r
-unsigned long ulReturn;\r
-long lResult;\r
-portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
-\r
- if( ppvBuffer== NULL )\r
- {\r
- ppvBuffer = &pvDummy;\r
- }\r
-\r
- if( xInsideISR != pdFALSE )\r
- {\r
- lResult = xQueueReceiveFromISR( *pxMailBox, &( *ppvBuffer ), &xHigherPriorityTaskWoken );\r
- }\r
- else\r
- {\r
- lResult = xQueueReceive( *pxMailBox, &( *ppvBuffer ), 0UL );\r
- }\r
-\r
- if( lResult == pdPASS )\r
- {\r
- ulReturn = ERR_OK;\r
- }\r
- else\r
- {\r
- ulReturn = SYS_MBOX_EMPTY;\r
- }\r
-\r
- return ulReturn;\r
-}\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_sem_new\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Creates and returns a new semaphore. The "ucCount" argument specifies\r
- * the initial state of the semaphore.\r
- * NOTE: Currently this routine only creates counts of 1 or 0\r
- * Inputs:\r
- * sys_mbox_t mbox -- Handle of mailbox\r
- * u8_t ucCount -- Initial ucCount of semaphore (1 or 0)\r
- * Outputs:\r
- * sys_sem_t -- Created semaphore or 0 if could not create.\r
- *---------------------------------------------------------------------------*/\r
-err_t sys_sem_new( sys_sem_t *pxSemaphore, u8_t ucCount )\r
-{\r
-err_t xReturn = ERR_MEM;\r
-\r
- vSemaphoreCreateBinary( ( *pxSemaphore ) );\r
-\r
- if( *pxSemaphore != NULL )\r
- {\r
- if( ucCount == 0U )\r
- {\r
- xSemaphoreTake( *pxSemaphore, 1UL );\r
- }\r
-\r
- xReturn = ERR_OK;\r
-\r
- #if SYS_STATS\r
- {\r
- SYS_STATS_INC( sem.used );\r
- }\r
- #endif\r
- }\r
- else\r
- {\r
- #if SYS_STATS\r
- {\r
- SYS_STATS_INC( sem.err );\r
- }\r
- #endif\r
- }\r
-\r
- return xReturn;\r
-}\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_arch_sem_wait\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Blocks the thread while waiting for the semaphore to be\r
- * signaled. If the "timeout" argument is non-zero, the thread should\r
- * only be blocked for the specified time (measured in\r
- * milliseconds).\r
- *\r
- * If the timeout argument is non-zero, the return value is the number of\r
- * milliseconds spent waiting for the semaphore to be signaled. If the\r
- * semaphore wasn't signaled within the specified time, the return value is\r
- * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore\r
- * (i.e., it was already signaled), the function may return zero.\r
- *\r
- * Notice that lwIP implements a function with a similar name,\r
- * sys_sem_wait(), that uses the sys_arch_sem_wait() function.\r
- * Inputs:\r
- * sys_sem_t sem -- Semaphore to wait on\r
- * u32_t timeout -- Number of milliseconds until timeout\r
- * Outputs:\r
- * u32_t -- Time elapsed or SYS_ARCH_TIMEOUT.\r
- *---------------------------------------------------------------------------*/\r
-u32_t sys_arch_sem_wait( sys_sem_t *pxSemaphore, u32_t ulTimeout )\r
-{\r
-portTickType xStartTime, xEndTime, xElapsed;\r
-unsigned long ulReturn;\r
-\r
- xStartTime = xTaskGetTickCount();\r
-\r
- if( ulTimeout != 0UL )\r
- {\r
- if( xSemaphoreTake( *pxSemaphore, ulTimeout / portTICK_RATE_MS ) == pdTRUE )\r
- {\r
- xEndTime = xTaskGetTickCount();\r
- xElapsed = (xEndTime - xStartTime) * portTICK_RATE_MS;\r
- ulReturn = xElapsed;\r
- }\r
- else\r
- {\r
- ulReturn = SYS_ARCH_TIMEOUT;\r
- }\r
- }\r
- else\r
- {\r
- while( xSemaphoreTake( pxSemaphore, portMAX_DELAY ) != pdTRUE );\r
- xEndTime = xTaskGetTickCount();\r
- xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS;\r
-\r
- if( xElapsed == 0UL )\r
- {\r
- xElapsed = 1UL;\r
- }\r
-\r
- ulReturn = xElapsed;\r
- }\r
-\r
- return ulReturn;\r
-}\r
-\r
-/** Create a new mutex\r
- * @param mutex pointer to the mutex to create\r
- * @return a new mutex */\r
-err_t sys_mutex_new( sys_mutex_t *pxMutex )\r
-{\r
-err_t xReturn = ERR_MEM;\r
-\r
- *pxMutex = xQueueCreateMutex();\r
-\r
- if( *pxMutex != NULL )\r
- {\r
- xReturn = ERR_OK;\r
- #if SYS_STATS\r
- {\r
- SYS_STATS_INC( mutex.used );\r
- }\r
- #endif\r
- } \r
- else \r
- {\r
- #if SYS_STATS\r
- {\r
- SYS_STATS_INC( mutex.err );\r
- }\r
- #endif\r
- }\r
- \r
- return xReturn;\r
-}\r
-\r
-/** Lock a mutex\r
- * @param mutex the mutex to lock */\r
-void sys_mutex_lock( sys_mutex_t *pxMutex )\r
-{\r
- while( xSemaphoreTake( *pxMutex, portMAX_DELAY ) != pdPASS );\r
-}\r
-\r
-/** Unlock a mutex\r
- * @param mutex the mutex to unlock */\r
-void sys_mutex_unlock(sys_mutex_t *pxMutex )\r
-{\r
- xSemaphoreGive( *pxMutex );\r
-}\r
-\r
-\r
-/** Delete a semaphore\r
- * @param mutex the mutex to delete */\r
-void sys_mutex_free( sys_mutex_t *pxMutex )\r
-{\r
- #if SYS_STATS\r
- {\r
- SYS_STATS_DEC( mutex.used );\r
- }\r
- #endif /* SYS_STATS */\r
- vQueueDelete( *pxMutex );\r
-}\r
-\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_sem_signal\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Signals (releases) a semaphore\r
- * Inputs:\r
- * sys_sem_t sem -- Semaphore to signal\r
- *---------------------------------------------------------------------------*/\r
-void sys_sem_signal( sys_sem_t *pxSemaphore )\r
-{\r
-portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
-\r
- if( xInsideISR != pdFALSE )\r
- {\r
- xSemaphoreGiveFromISR( *pxSemaphore, &xHigherPriorityTaskWoken );\r
- }\r
- else\r
- {\r
- xSemaphoreGive( *pxSemaphore );\r
- }\r
-}\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_sem_free\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Deallocates a semaphore\r
- * Inputs:\r
- * sys_sem_t sem -- Semaphore to free\r
- *---------------------------------------------------------------------------*/\r
-void sys_sem_free( sys_sem_t *pxSemaphore )\r
-{\r
- #if SYS_STATS\r
- {\r
- SYS_STATS_DEC(sem.used);\r
- }\r
- #endif\r
-\r
- vQueueDelete( *pxSemaphore );\r
-}\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_init\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Initialize sys arch\r
- *---------------------------------------------------------------------------*/\r
-void sys_init(void)\r
-{\r
-}\r
-\r
-u32_t sys_now(void)\r
-{\r
- return xTaskGetTickCount();\r
-}\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_thread_new\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * Starts a new thread with priority "prio" that will begin its\r
- * execution in the function "thread()". The "arg" argument will be\r
- * passed as an argument to the thread() function. The id of the new\r
- * thread is returned. Both the id and the priority are system\r
- * dependent.\r
- * Inputs:\r
- * char *name -- Name of thread\r
- * void (* thread)(void *arg) -- Pointer to function to run.\r
- * void *arg -- Argument passed into function\r
- * int stacksize -- Required stack amount in bytes\r
- * int prio -- Thread priority\r
- * Outputs:\r
- * sys_thread_t -- Pointer to per-thread timeouts.\r
- *---------------------------------------------------------------------------*/\r
-sys_thread_t sys_thread_new( const char *pcName, void( *pxThread )( void *pvParameters ), void *pvArg, int iStackSize, int iPriority )\r
-{\r
-xTaskHandle xCreatedTask;\r
-portBASE_TYPE xResult;\r
-sys_thread_t xReturn;\r
-\r
- xResult = xTaskCreate( pxThread, ( signed char * ) pcName, iStackSize, pvArg, iPriority, &xCreatedTask );\r
-\r
- if( xResult == pdPASS )\r
- {\r
- xReturn = xCreatedTask;\r
- }\r
- else\r
- {\r
- xReturn = NULL;\r
- }\r
-\r
- return xReturn;\r
-}\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_arch_protect\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * This optional function does a "fast" critical region protection and\r
- * returns the previous protection level. This function is only called\r
- * during very short critical regions. An embedded system which supports\r
- * ISR-based drivers might want to implement this function by disabling\r
- * interrupts. Task-based systems might want to implement this by using\r
- * a mutex or disabling tasking. This function should support recursive\r
- * calls from the same task or interrupt. In other words,\r
- * sys_arch_protect() could be called while already protected. In\r
- * that case the return value indicates that it is already protected.\r
- *\r
- * sys_arch_protect() is only required if your port is supporting an\r
- * operating system.\r
- * Outputs:\r
- * sys_prot_t -- Previous protection level (not used here)\r
- *---------------------------------------------------------------------------*/\r
-sys_prot_t sys_arch_protect( void )\r
-{\r
- if( xInsideISR == pdFALSE )\r
- {\r
- taskENTER_CRITICAL();\r
- }\r
- return ( sys_prot_t ) 1;\r
-}\r
-\r
-/*---------------------------------------------------------------------------*\r
- * Routine: sys_arch_unprotect\r
- *---------------------------------------------------------------------------*\r
- * Description:\r
- * This optional function does a "fast" set of critical region\r
- * protection to the value specified by pval. See the documentation for\r
- * sys_arch_protect() for more information. This function is only\r
- * required if your port is supporting an operating system.\r
- * Inputs:\r
- * sys_prot_t -- Previous protection level (not used here)\r
- *---------------------------------------------------------------------------*/\r
-void sys_arch_unprotect( sys_prot_t xValue )\r
-{\r
- (void) xValue;\r
- if( xInsideISR == pdFALSE )\r
- {\r
- taskEXIT_CRITICAL();\r
- }\r
-}\r
-\r
-/*\r
- * Prints an assertion messages and aborts execution.\r
- */\r
-void sys_assert( const char *pcMessage )\r
-{\r
- (void) pcMessage;\r
-\r
- for (;;)\r
- {\r
- }\r
-}\r
-/*-------------------------------------------------------------------------*\r
- * End of File: sys_arch.c\r
- *-------------------------------------------------------------------------*/\r
-\r