FreeRTOS_IP.c 130 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425
  1. /*
  2. * FreeRTOS+TCP V2.3.2 LTS Patch 1
  3. * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. * this software and associated documentation files (the "Software"), to deal in
  7. * the Software without restriction, including without limitation the rights to
  8. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. * the Software, and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * http://aws.amazon.com/freertos
  23. * http://www.FreeRTOS.org
  24. */
  25. /**
  26. * @file FreeRTOS_IP.c
  27. * @brief Implements the basic functionality for the FreeRTOS+TCP network stack.
  28. */
  29. /* Standard includes. */
  30. #include <stdint.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. /* FreeRTOS includes. */
  34. #include "FreeRTOS.h"
  35. #include "task.h"
  36. #include "queue.h"
  37. #include "semphr.h"
  38. /* FreeRTOS+TCP includes. */
  39. #include "FreeRTOS_IP.h"
  40. #include "FreeRTOS_Sockets.h"
  41. #include "FreeRTOS_IP_Private.h"
  42. #include "FreeRTOS_ARP.h"
  43. #include "FreeRTOS_UDP_IP.h"
  44. #include "FreeRTOS_DHCP.h"
  45. #include "NetworkInterface.h"
  46. #include "NetworkBufferManagement.h"
  47. #include "FreeRTOS_DNS.h"
  48. /* Used to ensure the structure packing is having the desired effect. The
  49. * 'volatile' is used to prevent compiler warnings about comparing a constant with
  50. * a constant. */
  51. #ifndef _lint
  52. #define ipEXPECTED_EthernetHeader_t_SIZE ( ( size_t ) 14 ) /**< Ethernet Header size in bytes. */
  53. #define ipEXPECTED_ARPHeader_t_SIZE ( ( size_t ) 28 ) /**< ARP header size in bytes. */
  54. #define ipEXPECTED_IPHeader_t_SIZE ( ( size_t ) 20 ) /**< IP header size in bytes. */
  55. #define ipEXPECTED_IGMPHeader_t_SIZE ( ( size_t ) 8 ) /**< IGMP header size in bytes. */
  56. #define ipEXPECTED_ICMPHeader_t_SIZE ( ( size_t ) 8 ) /**< ICMP header size in bytes. */
  57. #define ipEXPECTED_UDPHeader_t_SIZE ( ( size_t ) 8 ) /**< UDP header size in bytes. */
  58. #define ipEXPECTED_TCPHeader_t_SIZE ( ( size_t ) 20 ) /**< TCP header size in bytes. */
  59. #endif
  60. /* ICMP protocol definitions. */
  61. #define ipICMP_ECHO_REQUEST ( ( uint8_t ) 8 ) /**< ICMP echo request. */
  62. #define ipICMP_ECHO_REPLY ( ( uint8_t ) 0 ) /**< ICMP echo reply. */
  63. /* IPv4 multi-cast addresses range from 224.0.0.0.0 to 240.0.0.0. */
  64. #define ipFIRST_MULTI_CAST_IPv4 0xE0000000UL /**< Lower bound of the IPv4 multicast address. */
  65. #define ipLAST_MULTI_CAST_IPv4 0xF0000000UL /**< Higher bound of the IPv4 multicast address. */
  66. /* The first byte in the IPv4 header combines the IP version (4) with
  67. * with the length of the IP header. */
  68. #define ipIPV4_VERSION_HEADER_LENGTH_MIN 0x45U /**< Minimum IPv4 header length. */
  69. #define ipIPV4_VERSION_HEADER_LENGTH_MAX 0x4FU /**< Maximum IPv4 header length. */
  70. /** @brief Time delay between repeated attempts to initialise the network hardware. */
  71. #ifndef ipINITIALISATION_RETRY_DELAY
  72. #define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000U ) )
  73. #endif
  74. /** @brief Defines how often the ARP timer callback function is executed. The time is
  75. * shorter in the Windows simulator as simulated time is not real time. */
  76. #ifndef ipARP_TIMER_PERIOD_MS
  77. #ifdef _WINDOWS_
  78. #define ipARP_TIMER_PERIOD_MS ( 500U ) /* For windows simulator builds. */
  79. #else
  80. #define ipARP_TIMER_PERIOD_MS ( 10000U )
  81. #endif
  82. #endif
  83. #ifndef iptraceIP_TASK_STARTING
  84. #define iptraceIP_TASK_STARTING() do {} while( ipFALSE_BOOL ) /**< Empty definition in case iptraceIP_TASK_STARTING is not defined. */
  85. #endif
  86. #if ( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )
  87. /** @brief When initialising the TCP timer, give it an initial time-out of 1 second. */
  88. #define ipTCP_TIMER_PERIOD_MS ( 1000U )
  89. #endif
  90. /** @brief If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
  91. * driver will filter incoming packets and only pass the stack those packets it
  92. * considers need processing. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
  93. * be #-defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
  94. * then the Ethernet driver will pass all received packets to the stack, and the
  95. * stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING
  96. * needs to call eConsiderFrameForProcessing.
  97. */
  98. #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0
  99. #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
  100. #else
  101. #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
  102. #endif
  103. #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 )
  104. #if ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
  105. /** @brief The bits in the two byte IP header field that make up the fragment offset value. */
  106. #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0xff0f )
  107. #else
  108. /** @brief The bits in the two byte IP header field that make up the fragment offset value. */
  109. #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff )
  110. #endif /* ipconfigBYTE_ORDER */
  111. #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
  112. /** @brief The maximum time the IP task is allowed to remain in the Blocked state if no
  113. * events are posted to the network event queue. */
  114. #ifndef ipconfigMAX_IP_TASK_SLEEP_TIME
  115. #define ipconfigMAX_IP_TASK_SLEEP_TIME ( pdMS_TO_TICKS( 10000UL ) )
  116. #endif
  117. /** @brief Returned as the (invalid) checksum when the protocol being checked is not
  118. * handled. The value is chosen simply to be easy to spot when debugging. */
  119. #define ipUNHANDLED_PROTOCOL 0x4321U
  120. /** @brief Returned to indicate a valid checksum. */
  121. #define ipCORRECT_CRC 0xffffU
  122. /** @brief Returned to indicate incorrect checksum. */
  123. #define ipWRONG_CRC 0x0000U
  124. /** @brief Returned as the (invalid) checksum when the length of the data being checked
  125. * had an invalid length. */
  126. #define ipINVALID_LENGTH 0x1234U
  127. /* Trace macros to aid in debugging, disabled if ipconfigHAS_PRINTF != 1 */
  128. #if ( ipconfigHAS_PRINTF == 1 )
  129. #define DEBUG_DECLARE_TRACE_VARIABLE( type, var, init ) type var = ( init ) /**< Trace macro to set "type var = init". */
  130. #define DEBUG_SET_TRACE_VARIABLE( var, value ) var = ( value ) /**< Trace macro to set var = value. */
  131. #else
  132. #define DEBUG_DECLARE_TRACE_VARIABLE( type, var, init ) /**< Empty definition since ipconfigHAS_PRINTF != 1. */
  133. #define DEBUG_SET_TRACE_VARIABLE( var, value ) /**< Empty definition since ipconfigHAS_PRINTF != 1. */
  134. #endif
  135. /*-----------------------------------------------------------*/
  136. /**
  137. * Used in checksum calculation.
  138. */
  139. typedef union _xUnion32
  140. {
  141. uint32_t u32; /**< The 32-bit member of the union. */
  142. uint16_t u16[ 2 ]; /**< The array of 2 16-bit members of the union. */
  143. uint8_t u8[ 4 ]; /**< The array of 4 8-bit members of the union. */
  144. } xUnion32;
  145. /**
  146. * Used in checksum calculation.
  147. */
  148. typedef union _xUnionPtr
  149. {
  150. uint32_t * u32ptr; /**< The pointer member to a 32-bit variable. */
  151. uint16_t * u16ptr; /**< The pointer member to a 16-bit variable. */
  152. uint8_t * u8ptr; /**< The pointer member to an 8-bit variable. */
  153. } xUnionPtr;
  154. /**
  155. * @brief Utility function to cast pointer of a type to pointer of type NetworkBufferDescriptor_t.
  156. *
  157. * @return The casted pointer.
  158. */
  159. static portINLINE ipDECL_CAST_PTR_FUNC_FOR_TYPE( NetworkBufferDescriptor_t )
  160. {
  161. return ( NetworkBufferDescriptor_t * ) pvArgument;
  162. }
  163. /*-----------------------------------------------------------*/
  164. /*
  165. * The main TCP/IP stack processing task. This task receives commands/events
  166. * from the network hardware drivers and tasks that are using sockets. It also
  167. * maintains a set of protocol timers.
  168. */
  169. static void prvIPTask( void * pvParameters );
  170. /*
  171. * Called when new data is available from the network interface.
  172. */
  173. static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
  174. /*
  175. * Process incoming IP packets.
  176. */
  177. static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * pxIPPacket,
  178. NetworkBufferDescriptor_t * const pxNetworkBuffer );
  179. #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
  180. /*
  181. * Process incoming ICMP packets.
  182. */
  183. static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket );
  184. #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
  185. /*
  186. * Turns around an incoming ping request to convert it into a ping reply.
  187. */
  188. #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
  189. static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket );
  190. #endif /* ipconfigREPLY_TO_INCOMING_PINGS */
  191. /*
  192. * Processes incoming ping replies. The application callback function
  193. * vApplicationPingReplyHook() is called with the results.
  194. */
  195. #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
  196. static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket );
  197. #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
  198. /*
  199. * Called to create a network connection when the stack is first started, or
  200. * when the network connection is lost.
  201. */
  202. static void prvProcessNetworkDownEvent( void );
  203. /*
  204. * Checks the ARP, DHCP and TCP timers to see if any periodic or timeout
  205. * processing is required.
  206. */
  207. static void prvCheckNetworkTimers( void );
  208. /*
  209. * Determine how long the IP task can sleep for, which depends on when the next
  210. * periodic or timeout processing must be performed.
  211. */
  212. static TickType_t prvCalculateSleepTime( void );
  213. /*
  214. * The network card driver has received a packet. In the case that it is part
  215. * of a linked packet chain, walk through it to handle every message.
  216. */
  217. static void prvHandleEthernetPacket( NetworkBufferDescriptor_t * pxBuffer );
  218. /*
  219. * Utility functions for the light weight IP timers.
  220. */
  221. static void prvIPTimerStart( IPTimer_t * pxTimer,
  222. TickType_t xTime );
  223. static BaseType_t prvIPTimerCheck( IPTimer_t * pxTimer );
  224. static void prvIPTimerReload( IPTimer_t * pxTimer,
  225. TickType_t xTime );
  226. /* The function 'prvAllowIPPacket()' checks if a packets should be processed. */
  227. static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,
  228. const NetworkBufferDescriptor_t * const pxNetworkBuffer,
  229. UBaseType_t uxHeaderLength );
  230. #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 )
  231. /* Even when the driver takes care of checksum calculations,
  232. * the IP-task will still check if the length fields are OK. */
  233. static BaseType_t xCheckSizeFields( const uint8_t * const pucEthernetBuffer,
  234. size_t uxBufferLength );
  235. #endif /* ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 ) */
  236. /*
  237. * Returns the network buffer descriptor that owns a given packet buffer.
  238. */
  239. static NetworkBufferDescriptor_t * prvPacketBuffer_to_NetworkBuffer( const void * pvBuffer,
  240. size_t uxOffset );
  241. /*-----------------------------------------------------------*/
  242. /** @brief The queue used to pass events into the IP-task for processing. */
  243. QueueHandle_t xNetworkEventQueue = NULL;
  244. /** @brief The IP packet ID. */
  245. uint16_t usPacketIdentifier = 0U;
  246. /** @brief For convenience, a MAC address of all 0xffs is defined const for quick
  247. * reference. */
  248. const MACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
  249. /** @brief Structure that stores the netmask, gateway address and DNS server addresses. */
  250. NetworkAddressingParameters_t xNetworkAddressing = { 0, 0, 0, 0, 0 };
  251. /** @brief Default values for the above struct in case DHCP
  252. * does not lead to a confirmed request. */
  253. NetworkAddressingParameters_t xDefaultAddressing = { 0, 0, 0, 0, 0 };
  254. /** @brief Used to ensure network down events cannot be missed when they cannot be
  255. * posted to the network event queue because the network event queue is already
  256. * full. */
  257. static volatile BaseType_t xNetworkDownEventPending = pdFALSE;
  258. /** @brief Stores the handle of the task that handles the stack. The handle is used
  259. * (indirectly) by some utility function to determine if the utility function is
  260. * being called by a task (in which case it is ok to block) or by the IP task
  261. * itself (in which case it is not ok to block). */
  262. static TaskHandle_t xIPTaskHandle = NULL;
  263. #if ( ipconfigUSE_TCP != 0 )
  264. /** @brief Set to a non-zero value if one or more TCP message have been processed
  265. * within the last round. */
  266. static BaseType_t xProcessedTCPMessage;
  267. #endif
  268. /** @brief Simple set to pdTRUE or pdFALSE depending on whether the network is up or
  269. * down (connected, not connected) respectively. */
  270. static BaseType_t xNetworkUp = pdFALSE;
  271. /*
  272. * A timer for each of the following processes, all of which need attention on a
  273. * regular basis
  274. */
  275. /** @brief ARP timer, to check its table entries. */
  276. static IPTimer_t xARPTimer;
  277. #if ( ipconfigUSE_DHCP != 0 )
  278. /** @brief DHCP timer, to send requests and to renew a reservation. */
  279. static IPTimer_t xDHCPTimer;
  280. #endif
  281. #if ( ipconfigUSE_TCP != 0 )
  282. /** @brief TCP timer, to check for timeouts, resends. */
  283. static IPTimer_t xTCPTimer;
  284. #endif
  285. #if ( ipconfigDNS_USE_CALLBACKS != 0 )
  286. /** @brief DNS timer, to check for timeouts when looking-up a domain. */
  287. static IPTimer_t xDNSTimer;
  288. #endif
  289. /** @brief Set to pdTRUE when the IP task is ready to start processing packets. */
  290. static BaseType_t xIPTaskInitialised = pdFALSE;
  291. #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
  292. /** @brief Keep track of the lowest amount of space in 'xNetworkEventQueue'. */
  293. static UBaseType_t uxQueueMinimumSpace = ipconfigEVENT_QUEUE_LENGTH;
  294. #endif
  295. /*-----------------------------------------------------------*/
  296. /* Coverity wants to make pvParameters const, which would make it incompatible. Leave the
  297. * function signature as is. */
  298. /**
  299. * @brief The IP task handles all requests from the user application and the
  300. * network interface. It receives messages through a FreeRTOS queue called
  301. * 'xNetworkEventQueue'. prvIPTask() is the only task which has access to
  302. * the data of the IP-stack, and so it has no need of using mutexes.
  303. *
  304. * @param[in] pvParameters: Not used.
  305. */
  306. static void prvIPTask( void * pvParameters )
  307. {
  308. IPStackEvent_t xReceivedEvent;
  309. TickType_t xNextIPSleep;
  310. FreeRTOS_Socket_t * pxSocket;
  311. struct freertos_sockaddr xAddress;
  312. /* Just to prevent compiler warnings about unused parameters. */
  313. ( void ) pvParameters;
  314. /* A possibility to set some additional task properties. */
  315. iptraceIP_TASK_STARTING();
  316. /* Generate a dummy message to say that the network connection has gone
  317. * down. This will cause this task to initialise the network interface. After
  318. * this it is the responsibility of the network interface hardware driver to
  319. * send this message if a previously connected network is disconnected. */
  320. FreeRTOS_NetworkDown();
  321. #if ( ipconfigUSE_TCP == 1 )
  322. {
  323. /* Initialise the TCP timer. */
  324. prvIPTimerReload( &xTCPTimer, pdMS_TO_TICKS( ipTCP_TIMER_PERIOD_MS ) );
  325. }
  326. #endif
  327. /* Initialisation is complete and events can now be processed. */
  328. xIPTaskInitialised = pdTRUE;
  329. FreeRTOS_debug_printf( ( "prvIPTask started\n" ) );
  330. /* Loop, processing IP events. */
  331. for( ; ; )
  332. {
  333. ipconfigWATCHDOG_TIMER();
  334. /* Check the ARP, DHCP and TCP timers to see if there is any periodic
  335. * or timeout processing to perform. */
  336. prvCheckNetworkTimers();
  337. /* Calculate the acceptable maximum sleep time. */
  338. xNextIPSleep = prvCalculateSleepTime();
  339. /* Wait until there is something to do. If the following call exits
  340. * due to a time out rather than a message being received, set a
  341. * 'NoEvent' value. */
  342. if( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE )
  343. {
  344. xReceivedEvent.eEventType = eNoEvent;
  345. }
  346. #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
  347. {
  348. if( xReceivedEvent.eEventType != eNoEvent )
  349. {
  350. UBaseType_t uxCount;
  351. uxCount = uxQueueSpacesAvailable( xNetworkEventQueue );
  352. if( uxQueueMinimumSpace > uxCount )
  353. {
  354. uxQueueMinimumSpace = uxCount;
  355. }
  356. }
  357. }
  358. #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
  359. iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType );
  360. switch( xReceivedEvent.eEventType )
  361. {
  362. case eNetworkDownEvent:
  363. /* Attempt to establish a connection. */
  364. xNetworkUp = pdFALSE;
  365. prvProcessNetworkDownEvent();
  366. break;
  367. case eNetworkRxEvent:
  368. /* The network hardware driver has received a new packet. A
  369. * pointer to the received buffer is located in the pvData member
  370. * of the received event structure. */
  371. prvHandleEthernetPacket( ipCAST_PTR_TO_TYPE_PTR( NetworkBufferDescriptor_t, xReceivedEvent.pvData ) );
  372. break;
  373. case eNetworkTxEvent:
  374. {
  375. NetworkBufferDescriptor_t * pxDescriptor = ipCAST_PTR_TO_TYPE_PTR( NetworkBufferDescriptor_t, xReceivedEvent.pvData );
  376. /* Send a network packet. The ownership will be transferred to
  377. * the driver, which will release it after delivery. */
  378. iptraceNETWORK_INTERFACE_OUTPUT( pxDescriptor->xDataLength, pxDescriptor->pucEthernetBuffer );
  379. ( void ) xNetworkInterfaceOutput( pxDescriptor, pdTRUE );
  380. }
  381. break;
  382. case eARPTimerEvent:
  383. /* The ARP timer has expired, process the ARP cache. */
  384. vARPAgeCache();
  385. break;
  386. case eSocketBindEvent:
  387. /* FreeRTOS_bind (a user API) wants the IP-task to bind a socket
  388. * to a port. The port number is communicated in the socket field
  389. * usLocalPort. vSocketBind() will actually bind the socket and the
  390. * API will unblock as soon as the eSOCKET_BOUND event is
  391. * triggered. */
  392. pxSocket = ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, xReceivedEvent.pvData );
  393. xAddress.sin_addr = 0U; /* For the moment. */
  394. xAddress.sin_port = FreeRTOS_ntohs( pxSocket->usLocalPort );
  395. pxSocket->usLocalPort = 0U;
  396. ( void ) vSocketBind( pxSocket, &xAddress, sizeof( xAddress ), pdFALSE );
  397. /* Before 'eSocketBindEvent' was sent it was tested that
  398. * ( xEventGroup != NULL ) so it can be used now to wake up the
  399. * user. */
  400. pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_BOUND;
  401. vSocketWakeUpUser( pxSocket );
  402. break;
  403. case eSocketCloseEvent:
  404. /* The user API FreeRTOS_closesocket() has sent a message to the
  405. * IP-task to actually close a socket. This is handled in
  406. * vSocketClose(). As the socket gets closed, there is no way to
  407. * report back to the API, so the API won't wait for the result */
  408. ( void ) vSocketClose( ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, xReceivedEvent.pvData ) );
  409. break;
  410. case eStackTxEvent:
  411. //printf("%s:%d\r\r\n", __func__, __LINE__);
  412. /* The network stack has generated a packet to send. A
  413. * pointer to the generated buffer is located in the pvData
  414. * member of the received event structure. */
  415. vProcessGeneratedUDPPacket( ipCAST_PTR_TO_TYPE_PTR( NetworkBufferDescriptor_t, xReceivedEvent.pvData ) );
  416. break;
  417. case eDHCPEvent:
  418. /* The DHCP state machine needs processing. */
  419. #if ( ipconfigUSE_DHCP == 1 )
  420. {
  421. uintptr_t uxState;
  422. eDHCPState_t eState;
  423. /* Cast in two steps to please MISRA. */
  424. uxState = ( uintptr_t ) xReceivedEvent.pvData;
  425. eState = ( eDHCPState_t ) uxState;
  426. /* Process DHCP messages for a given end-point. */
  427. //if (g_enable_dhcp)
  428. vDHCPProcess( pdFALSE, eState );
  429. }
  430. #endif /* ipconfigUSE_DHCP */
  431. break;
  432. case eSocketSelectEvent:
  433. /* FreeRTOS_select() has got unblocked by a socket event,
  434. * vSocketSelect() will check which sockets actually have an event
  435. * and update the socket field xSocketBits. */
  436. #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
  437. #if ( ipconfigSELECT_USES_NOTIFY != 0 )
  438. {
  439. SocketSelectMessage_t * pxMessage = ipCAST_PTR_TO_TYPE_PTR( SocketSelectMessage_t, xReceivedEvent.pvData );
  440. vSocketSelect( pxMessage->pxSocketSet );
  441. ( void ) xTaskNotifyGive( pxMessage->xTaskhandle );
  442. }
  443. #else
  444. {
  445. vSocketSelect( ipCAST_PTR_TO_TYPE_PTR( SocketSelect_t, xReceivedEvent.pvData ) );
  446. }
  447. #endif /* ( ipconfigSELECT_USES_NOTIFY != 0 ) */
  448. #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
  449. break;
  450. case eSocketSignalEvent:
  451. #if ( ipconfigSUPPORT_SIGNALS != 0 )
  452. /* Some task wants to signal the user of this socket in
  453. * order to interrupt a call to recv() or a call to select(). */
  454. ( void ) FreeRTOS_SignalSocket( ipPOINTER_CAST( Socket_t, xReceivedEvent.pvData ) );
  455. #endif /* ipconfigSUPPORT_SIGNALS */
  456. break;
  457. case eTCPTimerEvent:
  458. #if ( ipconfigUSE_TCP == 1 )
  459. /* Simply mark the TCP timer as expired so it gets processed
  460. * the next time prvCheckNetworkTimers() is called. */
  461. xTCPTimer.bExpired = pdTRUE_UNSIGNED;
  462. #endif /* ipconfigUSE_TCP */
  463. break;
  464. case eTCPAcceptEvent:
  465. /* The API FreeRTOS_accept() was called, the IP-task will now
  466. * check if the listening socket (communicated in pvData) actually
  467. * received a new connection. */
  468. #if ( ipconfigUSE_TCP == 1 )
  469. pxSocket = ipCAST_PTR_TO_TYPE_PTR( FreeRTOS_Socket_t, xReceivedEvent.pvData );
  470. if( xTCPCheckNewClient( pxSocket ) != pdFALSE )
  471. {
  472. pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_ACCEPT;
  473. vSocketWakeUpUser( pxSocket );
  474. }
  475. #endif /* ipconfigUSE_TCP */
  476. break;
  477. case eTCPNetStat:
  478. /* FreeRTOS_netstat() was called to have the IP-task print an
  479. * overview of all sockets and their connections */
  480. #if ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_PRINTF == 1 ) )
  481. vTCPNetStat();
  482. #endif /* ipconfigUSE_TCP */
  483. break;
  484. case eNoEvent:
  485. /* xQueueReceive() returned because of a normal time-out. */
  486. break;
  487. default:
  488. /* Should not get here. */
  489. break;
  490. }
  491. if( xNetworkDownEventPending != pdFALSE )
  492. {
  493. /* A network down event could not be posted to the network event
  494. * queue because the queue was full.
  495. * As this code runs in the IP-task, it can be done directly by
  496. * calling prvProcessNetworkDownEvent(). */
  497. prvProcessNetworkDownEvent();
  498. }
  499. }
  500. }
  501. /*-----------------------------------------------------------*/
  502. /**
  503. * @brief Function to check whether the current context belongs to
  504. * the IP-task.
  505. *
  506. * @return If the current context belongs to the IP-task, then pdTRUE is
  507. * returned. Else pdFALSE is returned.
  508. *
  509. * @note Very important: the IP-task is not allowed to call its own API's,
  510. * because it would easily get into a dead-lock.
  511. */
  512. BaseType_t xIsCallingFromIPTask( void )
  513. {
  514. BaseType_t xReturn;
  515. if( xTaskGetCurrentTaskHandle() == xIPTaskHandle )
  516. {
  517. xReturn = pdTRUE;
  518. }
  519. else
  520. {
  521. xReturn = pdFALSE;
  522. }
  523. return xReturn;
  524. }
  525. /*-----------------------------------------------------------*/
  526. /**
  527. * @brief Handle the incoming Ethernet packets.
  528. *
  529. * @param[in] pxBuffer: Linked/un-linked network buffer descriptor(s)
  530. * to be processed.
  531. */
  532. static void prvHandleEthernetPacket( NetworkBufferDescriptor_t * pxBuffer )
  533. {
  534. #if ( ipconfigUSE_LINKED_RX_MESSAGES == 0 )
  535. {
  536. /* When ipconfigUSE_LINKED_RX_MESSAGES is not set to 0 then only one
  537. * buffer will be sent at a time. This is the default way for +TCP to pass
  538. * messages from the MAC to the TCP/IP stack. */
  539. prvProcessEthernetPacket( pxBuffer );
  540. }
  541. #else /* ipconfigUSE_LINKED_RX_MESSAGES */
  542. {
  543. NetworkBufferDescriptor_t * pxNextBuffer;
  544. /* An optimisation that is useful when there is high network traffic.
  545. * Instead of passing received packets into the IP task one at a time the
  546. * network interface can chain received packets together and pass them into
  547. * the IP task in one go. The packets are chained using the pxNextBuffer
  548. * member. The loop below walks through the chain processing each packet
  549. * in the chain in turn. */
  550. do
  551. {
  552. /* Store a pointer to the buffer after pxBuffer for use later on. */
  553. pxNextBuffer = pxBuffer->pxNextBuffer;
  554. /* Make it NULL to avoid using it later on. */
  555. pxBuffer->pxNextBuffer = NULL;
  556. prvProcessEthernetPacket( pxBuffer );
  557. pxBuffer = pxNextBuffer;
  558. /* While there is another packet in the chain. */
  559. } while( pxBuffer != NULL );
  560. }
  561. #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
  562. }
  563. /*-----------------------------------------------------------*/
  564. /**
  565. * @brief Calculate the maximum sleep time remaining. It will go through all
  566. * timers to see which timer will expire first. That will be the amount
  567. * of time to block in the next call to xQueueReceive().
  568. *
  569. * @return The maximum sleep time or ipconfigMAX_IP_TASK_SLEEP_TIME,
  570. * whichever is smaller.
  571. */
  572. static TickType_t prvCalculateSleepTime( void )
  573. {
  574. TickType_t xMaximumSleepTime;
  575. /* Start with the maximum sleep time, then check this against the remaining
  576. * time in any other timers that are active. */
  577. xMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME;
  578. if( xARPTimer.bActive != pdFALSE_UNSIGNED )
  579. {
  580. if( xARPTimer.ulRemainingTime < xMaximumSleepTime )
  581. {
  582. xMaximumSleepTime = xARPTimer.ulReloadTime;
  583. }
  584. }
  585. #if ( ipconfigUSE_DHCP == 1 )
  586. {
  587. if( xDHCPTimer.bActive != pdFALSE_UNSIGNED )
  588. {
  589. if( xDHCPTimer.ulRemainingTime < xMaximumSleepTime )
  590. {
  591. xMaximumSleepTime = xDHCPTimer.ulRemainingTime;
  592. }
  593. }
  594. }
  595. #endif /* ipconfigUSE_DHCP */
  596. #if ( ipconfigUSE_TCP == 1 )
  597. {
  598. if( xTCPTimer.ulRemainingTime < xMaximumSleepTime )
  599. {
  600. xMaximumSleepTime = xTCPTimer.ulRemainingTime;
  601. }
  602. }
  603. #endif
  604. #if ( ipconfigDNS_USE_CALLBACKS != 0 )
  605. {
  606. if( xDNSTimer.bActive != pdFALSE_UNSIGNED )
  607. {
  608. if( xDNSTimer.ulRemainingTime < xMaximumSleepTime )
  609. {
  610. xMaximumSleepTime = xDNSTimer.ulRemainingTime;
  611. }
  612. }
  613. }
  614. #endif
  615. return xMaximumSleepTime;
  616. }
  617. /*-----------------------------------------------------------*/
  618. /**
  619. * @brief Check the network timers (ARP/DHCP/DNS/TCP) and if they are
  620. * expired, send an event to the IP-Task.
  621. */
  622. static void prvCheckNetworkTimers( void )
  623. {
  624. /* Is it time for ARP processing? */
  625. if( prvIPTimerCheck( &xARPTimer ) != pdFALSE )
  626. {
  627. ( void ) xSendEventToIPTask( eARPTimerEvent );
  628. }
  629. #if ( ipconfigUSE_DHCP == 1 )
  630. {
  631. /* Is it time for DHCP processing? */
  632. if( prvIPTimerCheck( &xDHCPTimer ) != pdFALSE )
  633. {
  634. ( void ) xSendDHCPEvent();
  635. }
  636. }
  637. #endif /* ipconfigUSE_DHCP */
  638. #if ( ipconfigDNS_USE_CALLBACKS != 0 )
  639. {
  640. /* Is it time for DNS processing? */
  641. if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE )
  642. {
  643. vDNSCheckCallBack( NULL );
  644. }
  645. }
  646. #endif /* ipconfigDNS_USE_CALLBACKS */
  647. #if ( ipconfigUSE_TCP == 1 )
  648. {
  649. BaseType_t xWillSleep;
  650. TickType_t xNextTime;
  651. BaseType_t xCheckTCPSockets;
  652. /* If the IP task has messages waiting to be processed then
  653. * it will not sleep in any case. */
  654. if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0U )
  655. {
  656. xWillSleep = pdTRUE;
  657. }
  658. else
  659. {
  660. xWillSleep = pdFALSE;
  661. }
  662. /* Sockets need to be checked if the TCP timer has expired. */
  663. xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer );
  664. /* Sockets will also be checked if there are TCP messages but the
  665. * message queue is empty (indicated by xWillSleep being true). */
  666. if( ( xProcessedTCPMessage != pdFALSE ) && ( xWillSleep != pdFALSE ) )
  667. {
  668. xCheckTCPSockets = pdTRUE;
  669. }
  670. if( xCheckTCPSockets != pdFALSE )
  671. {
  672. /* Attend to the sockets, returning the period after which the
  673. * check must be repeated. */
  674. xNextTime = xTCPTimerCheck( xWillSleep );
  675. prvIPTimerStart( &xTCPTimer, xNextTime );
  676. xProcessedTCPMessage = 0;
  677. }
  678. }
  679. #endif /* ipconfigUSE_TCP == 1 */
  680. }
  681. /*-----------------------------------------------------------*/
  682. /**
  683. * @brief Start an IP timer. The IP-task has its own implementation of a timer
  684. * called 'IPTimer_t', which is based on the FreeRTOS 'TimeOut_t'.
  685. *
  686. * @param[in] pxTimer: Pointer to the IP timer. When zero, the timer is marked
  687. * as expired.
  688. * @param[in] xTime: Time to be loaded into the IP timer.
  689. */
  690. static void prvIPTimerStart( IPTimer_t * pxTimer,
  691. TickType_t xTime )
  692. {
  693. vTaskSetTimeOutState( &pxTimer->xTimeOut );
  694. pxTimer->ulRemainingTime = xTime;
  695. if( xTime == ( TickType_t ) 0 )
  696. {
  697. pxTimer->bExpired = pdTRUE_UNSIGNED;
  698. }
  699. else
  700. {
  701. pxTimer->bExpired = pdFALSE_UNSIGNED;
  702. }
  703. pxTimer->bActive = pdTRUE_UNSIGNED;
  704. }
  705. /*-----------------------------------------------------------*/
  706. /**
  707. * @brief Sets the reload time of an IP timer and restarts it.
  708. *
  709. * @param[in] pxTimer: Pointer to the IP timer.
  710. * @param[in] xTime: Time to be reloaded into the IP timer.
  711. */
  712. static void prvIPTimerReload( IPTimer_t * pxTimer,
  713. TickType_t xTime )
  714. {
  715. pxTimer->ulReloadTime = xTime;
  716. prvIPTimerStart( pxTimer, xTime );
  717. }
  718. /*-----------------------------------------------------------*/
  719. /**
  720. * @brief Check the IP timer to see whether an IP event should be processed or not.
  721. *
  722. * @param[in] pxTimer: Pointer to the IP timer.
  723. *
  724. * @return If the timer is expired then pdTRUE is returned. Else pdFALSE.
  725. */
  726. static BaseType_t prvIPTimerCheck( IPTimer_t * pxTimer )
  727. {
  728. BaseType_t xReturn;
  729. if( pxTimer->bActive == pdFALSE_UNSIGNED )
  730. {
  731. /* The timer is not enabled. */
  732. xReturn = pdFALSE;
  733. }
  734. else
  735. {
  736. /* The timer might have set the bExpired flag already, if not, check the
  737. * value of xTimeOut against ulRemainingTime. */
  738. if( pxTimer->bExpired == pdFALSE_UNSIGNED )
  739. {
  740. if( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE )
  741. {
  742. pxTimer->bExpired = pdTRUE_UNSIGNED;
  743. }
  744. }
  745. if( pxTimer->bExpired != pdFALSE_UNSIGNED )
  746. {
  747. prvIPTimerStart( pxTimer, pxTimer->ulReloadTime );
  748. xReturn = pdTRUE;
  749. }
  750. else
  751. {
  752. xReturn = pdFALSE;
  753. }
  754. }
  755. return xReturn;
  756. }
  757. /*-----------------------------------------------------------*/
  758. /**
  759. * @brief Send a network down event to the IP-task. If it fails to post a message,
  760. * the failure will be noted in the variable 'xNetworkDownEventPending'
  761. * and later on a 'network-down' event, it will be executed.
  762. */
  763. void FreeRTOS_NetworkDown( void )
  764. {
  765. static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
  766. const TickType_t xDontBlock = ( TickType_t ) 0;
  767. /* Simply send the network task the appropriate event. */
  768. if( xSendEventStructToIPTask( &xNetworkDownEvent, xDontBlock ) != pdPASS )
  769. {
  770. /* Could not send the message, so it is still pending. */
  771. xNetworkDownEventPending = pdTRUE;
  772. }
  773. else
  774. {
  775. /* Message was sent so it is not pending. */
  776. xNetworkDownEventPending = pdFALSE;
  777. }
  778. iptraceNETWORK_DOWN();
  779. }
  780. /*-----------------------------------------------------------*/
  781. /**
  782. * @brief Utility function. Process Network Down event from ISR.
  783. * This function is supposed to be called form an ISR. It is recommended
  784. * - * use 'FreeRTOS_NetworkDown()', when calling from a normal task.
  785. *
  786. * @return If the event was processed successfully, then return pdTRUE.
  787. * Else pdFALSE.
  788. */
  789. BaseType_t FreeRTOS_NetworkDownFromISR( void )
  790. {
  791. static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
  792. BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  793. /* Simply send the network task the appropriate event. */
  794. if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )
  795. {
  796. xNetworkDownEventPending = pdTRUE;
  797. }
  798. else
  799. {
  800. xNetworkDownEventPending = pdFALSE;
  801. }
  802. iptraceNETWORK_DOWN();
  803. return xHigherPriorityTaskWoken;
  804. }
  805. /*-----------------------------------------------------------*/
  806. /**
  807. * @brief Obtain a buffer big enough for a UDP payload of given size.
  808. *
  809. * @param[in] uxRequestedSizeBytes: The size of the UDP payload.
  810. * @param[in] uxBlockTimeTicks: Maximum amount of time for which this call
  811. * can block. This value is capped internally.
  812. *
  813. * @return If a buffer was created then the pointer to that buffer is returned,
  814. * else a NULL pointer is returned.
  815. */
  816. void * FreeRTOS_GetUDPPayloadBuffer( size_t uxRequestedSizeBytes,
  817. TickType_t uxBlockTimeTicks )
  818. {
  819. NetworkBufferDescriptor_t * pxNetworkBuffer;
  820. void * pvReturn;
  821. TickType_t uxBlockTime = uxBlockTimeTicks;
  822. /* Cap the block time. The reason for this is explained where
  823. * ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined (assuming an official
  824. * FreeRTOSIPConfig.h header file is being used). */
  825. if( uxBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
  826. {
  827. uxBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
  828. }
  829. /* Obtain a network buffer with the required amount of storage. */
  830. pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( UDPPacket_t ) + uxRequestedSizeBytes, uxBlockTime );
  831. if( pxNetworkBuffer != NULL )
  832. {
  833. /* Set the actual packet size in case a bigger buffer was returned. */
  834. pxNetworkBuffer->xDataLength = sizeof( UDPPacket_t ) + uxRequestedSizeBytes;
  835. /* Skip 3 headers. */
  836. pvReturn = &( pxNetworkBuffer->pucEthernetBuffer[ sizeof( UDPPacket_t ) ] );
  837. }
  838. else
  839. {
  840. pvReturn = NULL;
  841. }
  842. return ( void * ) pvReturn;
  843. }
  844. /*-----------------------------------------------------------*/
  845. /**
  846. * @brief Duplicate the given network buffer descriptor with a modified length.
  847. *
  848. * @param[in] pxNetworkBuffer: The network buffer to be duplicated.
  849. * @param[in] uxNewLength: The length for the new buffer.
  850. *
  851. * @return If properly duplicated, then the duplicate network buffer or else, NULL.
  852. */
  853. NetworkBufferDescriptor_t * pxDuplicateNetworkBufferWithDescriptor( const NetworkBufferDescriptor_t * const pxNetworkBuffer,
  854. size_t uxNewLength )
  855. {
  856. NetworkBufferDescriptor_t * pxNewBuffer;
  857. /* This function is only used when 'ipconfigZERO_COPY_TX_DRIVER' is set to 1.
  858. * The transmit routine wants to have ownership of the network buffer
  859. * descriptor, because it will pass the buffer straight to DMA. */
  860. pxNewBuffer = pxGetNetworkBufferWithDescriptor( uxNewLength, ( TickType_t ) 0 );
  861. if( pxNewBuffer != NULL )
  862. {
  863. /* Set the actual packet size in case a bigger buffer than requested
  864. * was returned. */
  865. pxNewBuffer->xDataLength = uxNewLength;
  866. /* Copy the original packet information. */
  867. pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress;
  868. pxNewBuffer->usPort = pxNetworkBuffer->usPort;
  869. pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort;
  870. ( void ) memcpy( pxNewBuffer->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
  871. }
  872. return pxNewBuffer;
  873. }
  874. /*-----------------------------------------------------------*/
  875. /**
  876. * @brief Get the network buffer descriptor from the packet buffer.
  877. *
  878. * @param[in] pvBuffer: The pointer to packet buffer.
  879. * @param[in] uxOffset: Additional offset (such as the packet length of UDP packet etc.).
  880. *
  881. * @return The network buffer descriptor if the alignment is correct. Else a NULL is returned.
  882. */
  883. static NetworkBufferDescriptor_t * prvPacketBuffer_to_NetworkBuffer( const void * pvBuffer,
  884. size_t uxOffset )
  885. {
  886. uintptr_t uxBuffer;
  887. NetworkBufferDescriptor_t * pxResult;
  888. if( pvBuffer == NULL )
  889. {
  890. pxResult = NULL;
  891. }
  892. else
  893. {
  894. /* Obtain the network buffer from the zero copy pointer. */
  895. uxBuffer = ipPOINTER_CAST( uintptr_t, pvBuffer );
  896. /* The input here is a pointer to a packet buffer plus some offset. Subtract
  897. * this offset, and also the size of the header in the network buffer, usually
  898. * 8 + 2 bytes. */
  899. uxBuffer -= ( uxOffset + ipBUFFER_PADDING );
  900. /* Here a pointer was placed to the network descriptor. As a
  901. * pointer is dereferenced, make sure it is well aligned. */
  902. if( ( uxBuffer & ( ( ( uintptr_t ) sizeof( uxBuffer ) ) - 1U ) ) == ( uintptr_t ) 0U )
  903. {
  904. /* The following statement may trigger a:
  905. * warning: cast increases required alignment of target type [-Wcast-align].
  906. * It has been confirmed though that the alignment is suitable. */
  907. pxResult = *( ( NetworkBufferDescriptor_t ** ) uxBuffer );
  908. }
  909. else
  910. {
  911. pxResult = NULL;
  912. }
  913. }
  914. return pxResult;
  915. }
  916. /*-----------------------------------------------------------*/
  917. #if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 )
  918. /**
  919. * @brief Get the network buffer from the packet buffer.
  920. *
  921. * @param[in] pvBuffer: Pointer to the packet buffer.
  922. *
  923. * @return The network buffer if the alignment is correct. Else a NULL is returned.
  924. */
  925. NetworkBufferDescriptor_t * pxPacketBuffer_to_NetworkBuffer( const void * pvBuffer )
  926. {
  927. return prvPacketBuffer_to_NetworkBuffer( pvBuffer, 0U );
  928. }
  929. #endif /* ( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
  930. /*-----------------------------------------------------------*/
  931. /**
  932. * @brief Get the network buffer from the UDP Payload buffer.
  933. *
  934. * @param[in] pvBuffer: Pointer to the UDP payload buffer.
  935. *
  936. * @return The network buffer if the alignment is correct. Else a NULL is returned.
  937. */
  938. NetworkBufferDescriptor_t * pxUDPPayloadBuffer_to_NetworkBuffer( const void * pvBuffer )
  939. {
  940. return prvPacketBuffer_to_NetworkBuffer( pvBuffer, sizeof( UDPPacket_t ) );
  941. }
  942. /*-----------------------------------------------------------*/
  943. /**
  944. * @brief Release the UDP payload buffer.
  945. *
  946. * @param[in] pvBuffer: Pointer to the UDP buffer that is to be released.
  947. */
  948. void FreeRTOS_ReleaseUDPPayloadBuffer( void const * pvBuffer )
  949. {
  950. vReleaseNetworkBufferAndDescriptor( pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer ) );
  951. }
  952. /*-----------------------------------------------------------*/
  953. /*_RB_ Should we add an error or assert if the task priorities are set such that the servers won't function as expected? */
  954. /*_HT_ There was a bug in FreeRTOS_TCP_IP.c that only occurred when the applications' priority was too high.
  955. * As that bug has been repaired, there is not an urgent reason to warn.
  956. * It is better though to use the advised priority scheme. */
  957. /**
  958. * @brief Initialise the FreeRTOS-Plus-TCP network stack and initialise the IP-task.
  959. *
  960. * @param[in] ucIPAddress: Local IP address.
  961. * @param[in] ucNetMask: Local netmask.
  962. * @param[in] ucGatewayAddress: Local gateway address.
  963. * @param[in] ucDNSServerAddress: Local DNS server address.
  964. * @param[in] ucMACAddress: MAC address of the node.
  965. *
  966. * @return pdPASS if the task was successfully created and added to a ready
  967. * list, otherwise an error code defined in the file projdefs.h
  968. */
  969. BaseType_t FreeRTOS_IPInit( const uint8_t ucIPAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
  970. const uint8_t ucNetMask[ ipIP_ADDRESS_LENGTH_BYTES ],
  971. const uint8_t ucGatewayAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
  972. const uint8_t ucDNSServerAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
  973. const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] )
  974. {
  975. BaseType_t xReturn = pdFALSE;
  976. /* This function should only be called once. */
  977. configASSERT( xIPIsNetworkTaskReady() == pdFALSE );
  978. configASSERT( xNetworkEventQueue == NULL );
  979. configASSERT( xIPTaskHandle == NULL );
  980. if( sizeof( uintptr_t ) == 8 )
  981. {
  982. /* This is a 64-bit platform, make sure there is enough space in
  983. * pucEthernetBuffer to store a pointer. */
  984. configASSERT( ipconfigBUFFER_PADDING == 14 );
  985. }
  986. #ifndef _lint
  987. {
  988. /* Check if MTU is big enough. */
  989. configASSERT( ( ( size_t ) ipconfigNETWORK_MTU ) >= ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + ipconfigTCP_MSS ) );
  990. /* Check structure packing is correct. */
  991. configASSERT( sizeof( EthernetHeader_t ) == ipEXPECTED_EthernetHeader_t_SIZE );
  992. configASSERT( sizeof( ARPHeader_t ) == ipEXPECTED_ARPHeader_t_SIZE );
  993. configASSERT( sizeof( IPHeader_t ) == ipEXPECTED_IPHeader_t_SIZE );
  994. configASSERT( sizeof( ICMPHeader_t ) == ipEXPECTED_ICMPHeader_t_SIZE );
  995. configASSERT( sizeof( UDPHeader_t ) == ipEXPECTED_UDPHeader_t_SIZE );
  996. }
  997. #endif /* ifndef _lint */
  998. /* Attempt to create the queue used to communicate with the IP task. */
  999. xNetworkEventQueue = xQueueCreate( ipconfigEVENT_QUEUE_LENGTH, sizeof( IPStackEvent_t ) );
  1000. configASSERT( xNetworkEventQueue != NULL );
  1001. if( xNetworkEventQueue != NULL )
  1002. {
  1003. #if ( configQUEUE_REGISTRY_SIZE > 0 )
  1004. {
  1005. /* A queue registry is normally used to assist a kernel aware
  1006. * debugger. If one is in use then it will be helpful for the debugger
  1007. * to show information about the network event queue. */
  1008. vQueueAddToRegistry( xNetworkEventQueue, "NetEvnt" );
  1009. }
  1010. #endif /* configQUEUE_REGISTRY_SIZE */
  1011. if( xNetworkBuffersInitialise() == pdPASS )
  1012. {
  1013. /* Store the local IP and MAC address. */
  1014. xNetworkAddressing.ulDefaultIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] );
  1015. xNetworkAddressing.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] );
  1016. xNetworkAddressing.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] );
  1017. xNetworkAddressing.ulDNSServerAddress = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] );
  1018. xNetworkAddressing.ulBroadcastAddress = ( xNetworkAddressing.ulDefaultIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask;
  1019. ( void ) memcpy( &xDefaultAddressing, &xNetworkAddressing, sizeof( xDefaultAddressing ) );
  1020. #if ipconfigUSE_DHCP == 1
  1021. {
  1022. /* The IP address is not set until DHCP completes. */
  1023. *ipLOCAL_IP_ADDRESS_POINTER = 0x00UL;
  1024. }
  1025. #else
  1026. {
  1027. /* The IP address is set from the value passed in. */
  1028. *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;
  1029. /* Added to prevent ARP flood to gateway. Ensure the
  1030. * gateway is on the same subnet as the IP address. */
  1031. if( xNetworkAddressing.ulGatewayAddress != 0UL )
  1032. {
  1033. configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) );
  1034. }
  1035. }
  1036. #endif /* ipconfigUSE_DHCP == 1 */
  1037. /* The MAC address is stored in the start of the default packet
  1038. * header fragment, which is used when sending UDP packets. */
  1039. ( void ) memcpy( ipLOCAL_MAC_ADDRESS, ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
  1040. /* Prepare the sockets interface. */
  1041. vNetworkSocketsInit();
  1042. /* Create the task that processes Ethernet and stack events. */
  1043. xReturn = xTaskCreate( prvIPTask,
  1044. "IP-task",
  1045. ipconfigIP_TASK_STACK_SIZE_WORDS,
  1046. NULL,
  1047. ipconfigIP_TASK_PRIORITY,
  1048. &( xIPTaskHandle ) );
  1049. }
  1050. else
  1051. {
  1052. FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: xNetworkBuffersInitialise() failed\n" ) );
  1053. /* Clean up. */
  1054. vQueueDelete( xNetworkEventQueue );
  1055. xNetworkEventQueue = NULL;
  1056. }
  1057. }
  1058. else
  1059. {
  1060. FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: Network event queue could not be created\n" ) );
  1061. }
  1062. return xReturn;
  1063. }
  1064. /*-----------------------------------------------------------*/
  1065. /**
  1066. * @brief Get the current address configuration. Only non-NULL pointers will
  1067. * be filled in.
  1068. *
  1069. * @param[out] pulIPAddress: The current IP-address assigned.
  1070. * @param[out] pulNetMask: The netmask used for current subnet.
  1071. * @param[out] pulGatewayAddress: The gateway address.
  1072. * @param[out] pulDNSServerAddress: The DNS server address.
  1073. */
  1074. void FreeRTOS_GetAddressConfiguration( uint32_t * pulIPAddress,
  1075. uint32_t * pulNetMask,
  1076. uint32_t * pulGatewayAddress,
  1077. uint32_t * pulDNSServerAddress )
  1078. {
  1079. /* Return the address configuration to the caller. */
  1080. if( pulIPAddress != NULL )
  1081. {
  1082. *pulIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
  1083. }
  1084. if( pulNetMask != NULL )
  1085. {
  1086. *pulNetMask = xNetworkAddressing.ulNetMask;
  1087. }
  1088. if( pulGatewayAddress != NULL )
  1089. {
  1090. *pulGatewayAddress = xNetworkAddressing.ulGatewayAddress;
  1091. }
  1092. if( pulDNSServerAddress != NULL )
  1093. {
  1094. *pulDNSServerAddress = xNetworkAddressing.ulDNSServerAddress;
  1095. }
  1096. }
  1097. /*-----------------------------------------------------------*/
  1098. /**
  1099. * @brief Set the current network address configuration. Only non-NULL pointers will
  1100. * be used.
  1101. *
  1102. * @param[in] pulIPAddress: The current IP-address assigned.
  1103. * @param[in] pulNetMask: The netmask used for current subnet.
  1104. * @param[in] pulGatewayAddress: The gateway address.
  1105. * @param[in] pulDNSServerAddress: The DNS server address.
  1106. */
  1107. void FreeRTOS_SetAddressConfiguration( const uint32_t * pulIPAddress,
  1108. const uint32_t * pulNetMask,
  1109. const uint32_t * pulGatewayAddress,
  1110. const uint32_t * pulDNSServerAddress )
  1111. {
  1112. /* Update the address configuration. */
  1113. if( pulIPAddress != NULL )
  1114. {
  1115. *ipLOCAL_IP_ADDRESS_POINTER = *pulIPAddress;
  1116. }
  1117. if( pulNetMask != NULL )
  1118. {
  1119. xNetworkAddressing.ulNetMask = *pulNetMask;
  1120. }
  1121. if( pulGatewayAddress != NULL )
  1122. {
  1123. xNetworkAddressing.ulGatewayAddress = *pulGatewayAddress;
  1124. }
  1125. if( pulDNSServerAddress != NULL )
  1126. {
  1127. xNetworkAddressing.ulDNSServerAddress = *pulDNSServerAddress;
  1128. }
  1129. }
  1130. /*-----------------------------------------------------------*/
  1131. #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
  1132. /**
  1133. * @brief Send a ping request to the given IP address. After receiving a reply,
  1134. * IP-task will call a user-supplied function 'vApplicationPingReplyHook()'.
  1135. *
  1136. * @param[in] ulIPAddress: The IP address to which the ping is to be sent.
  1137. * @param[in] uxNumberOfBytesToSend: Number of bytes in the ping request.
  1138. * @param[in] uxBlockTimeTicks: Maximum number of ticks to wait.
  1139. *
  1140. * @return If successfully sent to IP task for processing then the sequence
  1141. * number of the ping packet or else, pdFAIL.
  1142. */
  1143. BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress,
  1144. size_t uxNumberOfBytesToSend,
  1145. TickType_t uxBlockTimeTicks )
  1146. {
  1147. NetworkBufferDescriptor_t * pxNetworkBuffer;
  1148. ICMPHeader_t * pxICMPHeader;
  1149. EthernetHeader_t * pxEthernetHeader;
  1150. BaseType_t xReturn = pdFAIL;
  1151. static uint16_t usSequenceNumber = 0;
  1152. uint8_t * pucChar;
  1153. size_t uxTotalLength;
  1154. IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
  1155. uxTotalLength = uxNumberOfBytesToSend + sizeof( ICMPPacket_t );
  1156. BaseType_t xEnoughSpace;
  1157. if( uxNumberOfBytesToSend < ( ipconfigNETWORK_MTU - ( sizeof( IPHeader_t ) + sizeof( ICMPHeader_t ) ) ) )
  1158. {
  1159. xEnoughSpace = pdTRUE;
  1160. }
  1161. else
  1162. {
  1163. xEnoughSpace = pdFALSE;
  1164. }
  1165. if( ( uxGetNumberOfFreeNetworkBuffers() >= 4U ) && ( uxNumberOfBytesToSend >= 1U ) && ( xEnoughSpace != pdFALSE ) )
  1166. {
  1167. pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxTotalLength, uxBlockTimeTicks );
  1168. if( pxNetworkBuffer != NULL )
  1169. {
  1170. pxEthernetHeader = ipCAST_PTR_TO_TYPE_PTR( EthernetHeader_t, pxNetworkBuffer->pucEthernetBuffer );
  1171. pxEthernetHeader->usFrameType = ipIPv4_FRAME_TYPE;
  1172. pxICMPHeader = ipCAST_PTR_TO_TYPE_PTR( ICMPHeader_t, &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] ) );
  1173. usSequenceNumber++;
  1174. /* Fill in the basic header information. */
  1175. pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST;
  1176. pxICMPHeader->ucTypeOfService = 0;
  1177. pxICMPHeader->usIdentifier = usSequenceNumber;
  1178. pxICMPHeader->usSequenceNumber = usSequenceNumber;
  1179. printf("\r\nsend icmp seq:%d request\r\n", usSequenceNumber);//FreeRTOS_htons
  1180. /* Find the start of the data. */
  1181. pucChar = ( uint8_t * ) pxICMPHeader;
  1182. pucChar = &( pucChar[ sizeof( ICMPHeader_t ) ] );
  1183. /* Just memset the data to a fixed value. */
  1184. ( void ) memset( pucChar, ( int ) ipECHO_DATA_FILL_BYTE, uxNumberOfBytesToSend );
  1185. /* The message is complete, IP and checksum's are handled by
  1186. * vProcessGeneratedUDPPacket */
  1187. pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT;
  1188. pxNetworkBuffer->ulIPAddress = ulIPAddress;
  1189. pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA;
  1190. /* xDataLength is the size of the total packet, including the Ethernet header. */
  1191. pxNetworkBuffer->xDataLength = uxTotalLength;
  1192. /* Send to the stack. */
  1193. xStackTxEvent.pvData = pxNetworkBuffer;
  1194. if( xSendEventStructToIPTask( &( xStackTxEvent ), uxBlockTimeTicks ) != pdPASS )
  1195. {
  1196. vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
  1197. iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
  1198. }
  1199. else
  1200. {
  1201. xReturn = ( BaseType_t ) usSequenceNumber;
  1202. }
  1203. }
  1204. }
  1205. else
  1206. {
  1207. /* The requested number of bytes will not fit in the available space
  1208. * in the network buffer. */
  1209. }
  1210. return xReturn;
  1211. }
  1212. #endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */
  1213. /*-----------------------------------------------------------*/
  1214. /**
  1215. * @brief Send an event to the IP task. It calls 'xSendEventStructToIPTask' internally.
  1216. *
  1217. * @param[in] eEvent: The event to be sent.
  1218. *
  1219. * @return pdPASS if the event was sent (or the desired effect was achieved). Else, pdFAIL.
  1220. */
  1221. BaseType_t xSendEventToIPTask( eIPEvent_t eEvent )
  1222. {
  1223. IPStackEvent_t xEventMessage;
  1224. const TickType_t xDontBlock = ( TickType_t ) 0;
  1225. xEventMessage.eEventType = eEvent;
  1226. xEventMessage.pvData = ( void * ) NULL;
  1227. return xSendEventStructToIPTask( &xEventMessage, xDontBlock );
  1228. }
  1229. /*-----------------------------------------------------------*/
  1230. /**
  1231. * @brief Send an event (in form of struct) to the IP task to be processed.
  1232. *
  1233. * @param[in] pxEvent: The event to be sent.
  1234. * @param[in] uxTimeout: Timeout for waiting in case the queue is full. 0 for non-blocking calls.
  1235. *
  1236. * @return pdPASS if the event was sent (or the desired effect was achieved). Else, pdFAIL.
  1237. */
  1238. BaseType_t xSendEventStructToIPTask( const IPStackEvent_t * pxEvent,
  1239. TickType_t uxTimeout )
  1240. {
  1241. BaseType_t xReturn, xSendMessage;
  1242. TickType_t uxUseTimeout = uxTimeout;
  1243. if( ( xIPIsNetworkTaskReady() == pdFALSE ) && ( pxEvent->eEventType != eNetworkDownEvent ) )
  1244. {
  1245. /* Only allow eNetworkDownEvent events if the IP task is not ready
  1246. * yet. Not going to attempt to send the message so the send failed. */
  1247. xReturn = pdFAIL;
  1248. }
  1249. else
  1250. {
  1251. xSendMessage = pdTRUE;
  1252. #if ( ipconfigUSE_TCP == 1 )
  1253. {
  1254. if( pxEvent->eEventType == eTCPTimerEvent )
  1255. {
  1256. /* TCP timer events are sent to wake the timer task when
  1257. * xTCPTimer has expired, but there is no point sending them if the
  1258. * IP task is already awake processing other message. */
  1259. xTCPTimer.bExpired = pdTRUE_UNSIGNED;
  1260. if( uxQueueMessagesWaiting( xNetworkEventQueue ) != 0U )
  1261. {
  1262. /* Not actually going to send the message but this is not a
  1263. * failure as the message didn't need to be sent. */
  1264. xSendMessage = pdFALSE;
  1265. }
  1266. }
  1267. }
  1268. #endif /* ipconfigUSE_TCP */
  1269. if( xSendMessage != pdFALSE )
  1270. {
  1271. /* The IP task cannot block itself while waiting for itself to
  1272. * respond. */
  1273. if( ( xIsCallingFromIPTask() == pdTRUE ) && ( uxUseTimeout > ( TickType_t ) 0U ) )
  1274. {
  1275. uxUseTimeout = ( TickType_t ) 0;
  1276. }
  1277. xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, uxUseTimeout );
  1278. if( xReturn == pdFAIL )
  1279. {
  1280. /* A message should have been sent to the IP task, but wasn't. */
  1281. FreeRTOS_debug_printf( ( "xSendEventStructToIPTask: CAN NOT ADD %d\n", pxEvent->eEventType ) );
  1282. iptraceSTACK_TX_EVENT_LOST( pxEvent->eEventType );
  1283. }
  1284. }
  1285. else
  1286. {
  1287. /* It was not necessary to send the message to process the event so
  1288. * even though the message was not sent the call was successful. */
  1289. xReturn = pdPASS;
  1290. }
  1291. }
  1292. return xReturn;
  1293. }
  1294. /*-----------------------------------------------------------*/
  1295. #if ( ipconfigUSE_DHCP != 0 )
  1296. /**
  1297. * @brief Create a DHCP event.
  1298. *
  1299. * @return pdPASS or pdFAIL, depending on whether xSendEventStructToIPTask()
  1300. * succeeded.
  1301. */
  1302. BaseType_t xSendDHCPEvent( void )
  1303. {
  1304. IPStackEvent_t xEventMessage;
  1305. const TickType_t uxDontBlock = 0U;
  1306. uintptr_t uxOption = eGetDHCPState();
  1307. xEventMessage.eEventType = eDHCPEvent;
  1308. xEventMessage.pvData = ( void * ) uxOption;
  1309. return xSendEventStructToIPTask( &xEventMessage, uxDontBlock );
  1310. }
  1311. /*-----------------------------------------------------------*/
  1312. #endif /* ( ipconfigUSE_DHCP != 0 ) */
  1313. /**
  1314. * @brief Decide whether this packet should be processed or not based on the IP address in the packet.
  1315. *
  1316. * @param[in] pucEthernetBuffer: The ethernet packet under consideration.
  1317. *
  1318. * @return Enum saying whether to release or to process the packet.
  1319. */
  1320. eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer )
  1321. {
  1322. eFrameProcessingResult_t eReturn;
  1323. const EthernetHeader_t * pxEthernetHeader;
  1324. /* Map the buffer onto Ethernet Header struct for easy access to fields. */
  1325. pxEthernetHeader = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( EthernetHeader_t, pucEthernetBuffer );
  1326. if( memcmp( ipLOCAL_MAC_ADDRESS, pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
  1327. {
  1328. /* The packet was directed to this node - process it. */
  1329. eReturn = eProcessBuffer;
  1330. }
  1331. else if( memcmp( xBroadcastMACAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
  1332. {
  1333. /* The packet was a broadcast - process it. */
  1334. eReturn = eProcessBuffer;
  1335. }
  1336. else
  1337. #if ( ipconfigUSE_LLMNR == 1 )
  1338. if( memcmp( xLLMNR_MacAdress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
  1339. {
  1340. /* The packet is a request for LLMNR - process it. */
  1341. eReturn = eProcessBuffer;
  1342. }
  1343. else
  1344. #endif /* ipconfigUSE_LLMNR */
  1345. {
  1346. /* The packet was not a broadcast, or for this node, just release
  1347. * the buffer without taking any other action. */
  1348. eReturn = eReleaseBuffer;
  1349. }
  1350. #if ( ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 )
  1351. {
  1352. uint16_t usFrameType;
  1353. if( eReturn == eProcessBuffer )
  1354. {
  1355. usFrameType = pxEthernetHeader->usFrameType;
  1356. usFrameType = FreeRTOS_ntohs( usFrameType );
  1357. if( usFrameType <= 0x600U )
  1358. {
  1359. /* Not an Ethernet II frame. */
  1360. eReturn = eReleaseBuffer;
  1361. }
  1362. }
  1363. }
  1364. #endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 */
  1365. return eReturn;
  1366. }
  1367. /*-----------------------------------------------------------*/
  1368. /**
  1369. * @brief Process a 'Network down' event and complete required processing.
  1370. */
  1371. static void prvProcessNetworkDownEvent( void )
  1372. {
  1373. /* Stop the ARP timer while there is no network. */
  1374. xARPTimer.bActive = pdFALSE_UNSIGNED;
  1375. #if ipconfigUSE_NETWORK_EVENT_HOOK == 1
  1376. {
  1377. static BaseType_t xCallEventHook = pdFALSE;
  1378. /* The first network down event is generated by the IP stack itself to
  1379. * initialise the network hardware, so do not call the network down event
  1380. * the first time through. */
  1381. if( xCallEventHook == pdTRUE )
  1382. {
  1383. vApplicationIPNetworkEventHook( eNetworkDown );
  1384. }
  1385. xCallEventHook = pdTRUE;
  1386. }
  1387. #endif /* if ipconfigUSE_NETWORK_EVENT_HOOK == 1 */
  1388. /* Per the ARP Cache Validation section of https://tools.ietf.org/html/rfc1122,
  1389. * treat network down as a "delivery problem" and flush the ARP cache for this
  1390. * interface. */
  1391. FreeRTOS_ClearARP();
  1392. /* The network has been disconnected (or is being initialised for the first
  1393. * time). Perform whatever hardware processing is necessary to bring it up
  1394. * again, or wait for it to be available again. This is hardware dependent. */
  1395. if( xNetworkInterfaceInitialise() != pdPASS )
  1396. {
  1397. /* Ideally the network interface initialisation function will only
  1398. * return when the network is available. In case this is not the case,
  1399. * wait a while before retrying the initialisation. */
  1400. vTaskDelay( ipINITIALISATION_RETRY_DELAY );
  1401. FreeRTOS_NetworkDown();
  1402. }
  1403. else
  1404. {
  1405. /* Set remaining time to 0 so it will become active immediately. */
  1406. #if ipconfigUSE_DHCP == 1
  1407. {
  1408. /* The network is not up until DHCP has completed. */
  1409. vDHCPProcess( pdTRUE, eInitialWait );
  1410. }
  1411. #else
  1412. {
  1413. /* Perform any necessary 'network up' processing. */
  1414. vIPNetworkUpCalls();
  1415. }
  1416. #endif
  1417. }
  1418. }
  1419. /*-----------------------------------------------------------*/
  1420. /**
  1421. * @brief Perform all the required tasks when the network gets connected.
  1422. */
  1423. void vIPNetworkUpCalls( void )
  1424. {
  1425. xNetworkUp = pdTRUE;
  1426. #if ( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
  1427. {
  1428. vApplicationIPNetworkEventHook( eNetworkUp );
  1429. }
  1430. #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */
  1431. #if ( ipconfigDNS_USE_CALLBACKS != 0 )
  1432. {
  1433. /* The following function is declared in FreeRTOS_DNS.c and 'private' to
  1434. * this library */
  1435. extern void vDNSInitialise( void );
  1436. vDNSInitialise();
  1437. }
  1438. #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
  1439. /* Set remaining time to 0 so it will become active immediately. */
  1440. prvIPTimerReload( &xARPTimer, pdMS_TO_TICKS( ipARP_TIMER_PERIOD_MS ) );
  1441. }
  1442. /*-----------------------------------------------------------*/
  1443. /**
  1444. * @brief Process the Ethernet packet.
  1445. *
  1446. * @param[in,out] pxNetworkBuffer: the network buffer containing the ethernet packet. If the
  1447. * buffer is large enough, it may be reused to send a reply.
  1448. */
  1449. static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
  1450. {
  1451. const EthernetHeader_t * pxEthernetHeader;
  1452. eFrameProcessingResult_t eReturned = eReleaseBuffer;
  1453. configASSERT( pxNetworkBuffer != NULL );
  1454. iptraceNETWORK_INTERFACE_INPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
  1455. /* Interpret the Ethernet frame. */
  1456. if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) )
  1457. {
  1458. eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );
  1459. /* Map the buffer onto the Ethernet Header struct for easy access to the fields. */
  1460. pxEthernetHeader = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( EthernetHeader_t, pxNetworkBuffer->pucEthernetBuffer );
  1461. /* The condition "eReturned == eProcessBuffer" must be true. */
  1462. #if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
  1463. if( eReturned == eProcessBuffer )
  1464. #endif
  1465. {
  1466. /* Interpret the received Ethernet packet. */
  1467. switch( pxEthernetHeader->usFrameType )
  1468. {
  1469. case ipARP_FRAME_TYPE:
  1470. /* The Ethernet frame contains an ARP packet. */
  1471. if( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) )
  1472. {
  1473. eReturned = eARPProcessPacket( ipCAST_PTR_TO_TYPE_PTR( ARPPacket_t, pxNetworkBuffer->pucEthernetBuffer ) );
  1474. }
  1475. else
  1476. {
  1477. eReturned = eReleaseBuffer;
  1478. }
  1479. break;
  1480. case ipIPv4_FRAME_TYPE:
  1481. /* The Ethernet frame contains an IP packet. */
  1482. if( pxNetworkBuffer->xDataLength >= sizeof( IPPacket_t ) )
  1483. {
  1484. eReturned = prvProcessIPPacket( ipCAST_PTR_TO_TYPE_PTR( IPPacket_t, pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer );
  1485. }
  1486. else
  1487. {
  1488. eReturned = eReleaseBuffer;
  1489. }
  1490. break;
  1491. default:
  1492. /* No other packet types are handled. Nothing to do. */
  1493. eReturned = eReleaseBuffer;
  1494. break;
  1495. }
  1496. }
  1497. }
  1498. /* Perform any actions that resulted from processing the Ethernet frame. */
  1499. switch( eReturned )
  1500. {
  1501. case eReturnEthernetFrame:
  1502. /* The Ethernet frame will have been updated (maybe it was
  1503. * an ARP request or a PING request?) and should be sent back to
  1504. * its source. */
  1505. vReturnEthernetFrame( pxNetworkBuffer, pdTRUE );
  1506. /* parameter pdTRUE: the buffer must be released once
  1507. * the frame has been transmitted */
  1508. break;
  1509. case eFrameConsumed:
  1510. /* The frame is in use somewhere, don't release the buffer
  1511. * yet. */
  1512. break;
  1513. case eReleaseBuffer:
  1514. case eProcessBuffer:
  1515. default:
  1516. /* The frame is not being used anywhere, and the
  1517. * NetworkBufferDescriptor_t structure containing the frame should
  1518. * just be released back to the list of free buffers. */
  1519. vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
  1520. break;
  1521. }
  1522. }
  1523. /*-----------------------------------------------------------*/
  1524. /**
  1525. * @brief Is the IP address an IPv4 multicast address.
  1526. *
  1527. * @param[in] ulIPAddress: The IP address being checked.
  1528. *
  1529. * @return pdTRUE if the IP address is a multicast address or else, pdFALSE.
  1530. */
  1531. BaseType_t xIsIPv4Multicast( uint32_t ulIPAddress )
  1532. {
  1533. BaseType_t xReturn;
  1534. uint32_t ulIP = FreeRTOS_ntohl( ulIPAddress );
  1535. if( ( ulIP >= ipFIRST_MULTI_CAST_IPv4 ) && ( ulIP < ipLAST_MULTI_CAST_IPv4 ) )
  1536. {
  1537. xReturn = pdTRUE;
  1538. }
  1539. else
  1540. {
  1541. xReturn = pdFALSE;
  1542. }
  1543. return xReturn;
  1544. }
  1545. /*-----------------------------------------------------------*/
  1546. /**
  1547. * @brief Set multicast MAC address.
  1548. *
  1549. * @param[in] ulIPAddress: IP address.
  1550. * @param[out] pxMACAddress: Pointer to MAC address.
  1551. */
  1552. void vSetMultiCastIPv4MacAddress( uint32_t ulIPAddress,
  1553. MACAddress_t * pxMACAddress )
  1554. {
  1555. uint32_t ulIP = FreeRTOS_ntohl( ulIPAddress );
  1556. pxMACAddress->ucBytes[ 0 ] = ( uint8_t ) 0x01U;
  1557. pxMACAddress->ucBytes[ 1 ] = ( uint8_t ) 0x00U;
  1558. pxMACAddress->ucBytes[ 2 ] = ( uint8_t ) 0x5EU;
  1559. pxMACAddress->ucBytes[ 3 ] = ( uint8_t ) ( ( ulIP >> 16 ) & 0x7fU ); /* Use 7 bits. */
  1560. pxMACAddress->ucBytes[ 4 ] = ( uint8_t ) ( ( ulIP >> 8 ) & 0xffU ); /* Use 8 bits. */
  1561. pxMACAddress->ucBytes[ 5 ] = ( uint8_t ) ( ( ulIP ) & 0xffU ); /* Use 8 bits. */
  1562. }
  1563. /*-----------------------------------------------------------*/
  1564. /**
  1565. * @brief Check whether this IP packet is to be allowed or to be dropped.
  1566. *
  1567. * @param[in] pxIPPacket: The IP packet under consideration.
  1568. * @param[in] pxNetworkBuffer: The whole network buffer.
  1569. * @param[in] uxHeaderLength: The length of the header.
  1570. *
  1571. * @return Whether the packet should be processed or dropped.
  1572. */
  1573. static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,
  1574. const NetworkBufferDescriptor_t * const pxNetworkBuffer,
  1575. UBaseType_t uxHeaderLength )
  1576. {
  1577. eFrameProcessingResult_t eReturn = eProcessBuffer;
  1578. #if ( ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) )
  1579. const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
  1580. #else
  1581. /* or else, the parameter won't be used and the function will be optimised
  1582. * away */
  1583. ( void ) pxIPPacket;
  1584. #endif
  1585. #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 )
  1586. {
  1587. /* In systems with a very small amount of RAM, it might be advantageous
  1588. * to have incoming messages checked earlier, by the network card driver.
  1589. * This method may decrease the usage of sparse network buffers. */
  1590. uint32_t ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;
  1591. /* Ensure that the incoming packet is not fragmented (only outgoing
  1592. * packets can be fragmented) as these are the only handled IP frames
  1593. * currently. */
  1594. if( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U )
  1595. {
  1596. /* Can not handle, fragmented packet. */
  1597. eReturn = eReleaseBuffer;
  1598. }
  1599. /* Test if the length of the IP-header is between 20 and 60 bytes,
  1600. * and if the IP-version is 4. */
  1601. else if( ( pxIPHeader->ucVersionHeaderLength < ipIPV4_VERSION_HEADER_LENGTH_MIN ) ||
  1602. ( pxIPHeader->ucVersionHeaderLength > ipIPV4_VERSION_HEADER_LENGTH_MAX ) )
  1603. {
  1604. /* Can not handle, unknown or invalid header version. */
  1605. eReturn = eReleaseBuffer;
  1606. }
  1607. /* Is the packet for this IP address? */
  1608. else if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&
  1609. /* Is it the global broadcast address 255.255.255.255 ? */
  1610. ( ulDestinationIPAddress != ipBROADCAST_IP_ADDRESS ) &&
  1611. /* Is it a specific broadcast address 192.168.1.255 ? */
  1612. ( ulDestinationIPAddress != xNetworkAddressing.ulBroadcastAddress ) &&
  1613. #if ( ipconfigUSE_LLMNR == 1 )
  1614. /* Is it the LLMNR multicast address? */
  1615. ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&
  1616. #endif
  1617. /* Or (during DHCP negotiation) we have no IP-address yet? */
  1618. ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) )
  1619. {
  1620. /* Packet is not for this node, release it */
  1621. eReturn = eReleaseBuffer;
  1622. }
  1623. else
  1624. {
  1625. /* Packet is not fragmented, destination is this device. */
  1626. }
  1627. }
  1628. #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
  1629. #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 )
  1630. {
  1631. /* Some drivers of NIC's with checksum-offloading will enable the above
  1632. * define, so that the checksum won't be checked again here */
  1633. if( eReturn == eProcessBuffer )
  1634. {
  1635. /* Is the IP header checksum correct? */
  1636. if( ( pxIPHeader->ucProtocol != ( uint8_t ) ipPROTOCOL_ICMP ) &&
  1637. ( usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ( size_t ) uxHeaderLength ) != ipCORRECT_CRC ) )
  1638. {
  1639. /* Check sum in IP-header not correct. */
  1640. eReturn = eReleaseBuffer;
  1641. }
  1642. /* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */
  1643. else if( usGenerateProtocolChecksum( ( uint8_t * ) ( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE ) != ipCORRECT_CRC )
  1644. {
  1645. /* Protocol checksum not accepted. */
  1646. eReturn = eReleaseBuffer;
  1647. }
  1648. else
  1649. {
  1650. /* The checksum of the received packet is OK. */
  1651. }
  1652. }
  1653. }
  1654. #else /* if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) */
  1655. {
  1656. if( eReturn == eProcessBuffer )
  1657. {
  1658. if( xCheckSizeFields( ( uint8_t * ) ( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength ) != pdPASS )
  1659. {
  1660. /* Some of the length checks were not successful. */
  1661. eReturn = eReleaseBuffer;
  1662. }
  1663. }
  1664. #if ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 )
  1665. {
  1666. /* Check if this is a UDP packet without a checksum. */
  1667. if( eReturn == eProcessBuffer )
  1668. {
  1669. /* ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS is defined as 0,
  1670. * and so UDP packets carrying a protocol checksum of 0, will
  1671. * be dropped. */
  1672. /* Identify the next protocol. */
  1673. if( pxIPPacket->xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
  1674. {
  1675. ProtocolPacket_t * pxProtPack;
  1676. const uint16_t * pusChecksum;
  1677. /* pxProtPack will point to the offset were the protocols begin. */
  1678. pxProtPack = ipCAST_PTR_TO_TYPE_PTR( ProtocolPacket_t, &( pxNetworkBuffer->pucEthernetBuffer[ uxHeaderLength - ipSIZE_OF_IPv4_HEADER ] ) );
  1679. pusChecksum = ( const uint16_t * ) ( &( pxProtPack->xUDPPacket.xUDPHeader.usChecksum ) );
  1680. if( *pusChecksum == ( uint16_t ) 0U )
  1681. {
  1682. #if ( ipconfigHAS_PRINTF != 0 )
  1683. {
  1684. static BaseType_t xCount = 0;
  1685. if( xCount < 5 )
  1686. {
  1687. FreeRTOS_printf( ( "prvAllowIPPacket: UDP packet from %xip without CRC dropped\n",
  1688. FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ) ) );
  1689. xCount++;
  1690. }
  1691. }
  1692. #endif /* ( ipconfigHAS_PRINTF != 0 ) */
  1693. /* Protocol checksum not accepted. */
  1694. eReturn = eReleaseBuffer;
  1695. }
  1696. }
  1697. }
  1698. }
  1699. #endif /* ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 ) */
  1700. /* to avoid warning unused parameters */
  1701. ( void ) uxHeaderLength;
  1702. }
  1703. #endif /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 */
  1704. return eReturn;
  1705. }
  1706. /*-----------------------------------------------------------*/
  1707. /**
  1708. * @brief Process an IP-packet.
  1709. *
  1710. * @param[in] pxIPPacket: The IP packet to be processed.
  1711. * @param[in] pxNetworkBuffer: The networkbuffer descriptor having the IP packet.
  1712. *
  1713. * @return An enum to show whether the packet should be released/kept/processed etc.
  1714. */
  1715. static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * pxIPPacket,
  1716. NetworkBufferDescriptor_t * const pxNetworkBuffer )
  1717. {
  1718. eFrameProcessingResult_t eReturn;
  1719. IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
  1720. size_t uxLength = ( size_t ) pxIPHeader->ucVersionHeaderLength;
  1721. UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( uxLength & 0x0FU ) << 2 );
  1722. uint8_t ucProtocol;
  1723. /* Bound the calculated header length: take away the Ethernet header size,
  1724. * then check if the IP header is claiming to be longer than the remaining
  1725. * total packet size. Also check for minimal header field length. */
  1726. if( ( uxHeaderLength > ( pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER ) ) ||
  1727. ( uxHeaderLength < ipSIZE_OF_IPv4_HEADER ) )
  1728. {
  1729. eReturn = eReleaseBuffer;
  1730. }
  1731. else
  1732. {
  1733. ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
  1734. /* Check if the IP headers are acceptable and if it has our destination. */
  1735. eReturn = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength );
  1736. if( eReturn == eProcessBuffer )
  1737. {
  1738. /* Are there IP-options. */
  1739. if( uxHeaderLength > ipSIZE_OF_IPv4_HEADER )
  1740. {
  1741. /* The size of the IP-header is larger than 20 bytes.
  1742. * The extra space is used for IP-options. */
  1743. #if ( ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS != 0 )
  1744. {
  1745. /* All structs of headers expect a IP header size of 20 bytes
  1746. * IP header options were included, we'll ignore them and cut them out. */
  1747. const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER;
  1748. /* From: the previous start of UDP/ICMP/TCP data. */
  1749. const uint8_t * pucSource = ( const uint8_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ sizeof( EthernetHeader_t ) + uxHeaderLength ] );
  1750. /* To: the usual start of UDP/ICMP/TCP data at offset 20 (decimal ) from IP header. */
  1751. uint8_t * pucTarget = ( uint8_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ sizeof( EthernetHeader_t ) + ipSIZE_OF_IPv4_HEADER ] );
  1752. /* How many: total length minus the options and the lower headers. */
  1753. const size_t xMoveLen = pxNetworkBuffer->xDataLength - ( optlen + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_ETH_HEADER );
  1754. ( void ) memmove( pucTarget, pucSource, xMoveLen );
  1755. pxNetworkBuffer->xDataLength -= optlen;
  1756. /* Rewrite the Version/IHL byte to indicate that this packet has no IP options. */
  1757. pxIPHeader->ucVersionHeaderLength = ( pxIPHeader->ucVersionHeaderLength & 0xF0U ) | /* High nibble is the version. */
  1758. ( ( ipSIZE_OF_IPv4_HEADER >> 2 ) & 0x0FU );
  1759. }
  1760. #else /* if ( ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS != 0 ) */
  1761. {
  1762. /* 'ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS' is not set, so packets carrying
  1763. * IP-options will be dropped. */
  1764. eReturn = eReleaseBuffer;
  1765. }
  1766. #endif /* if ( ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS != 0 ) */
  1767. }
  1768. if( eReturn != eReleaseBuffer )
  1769. {
  1770. /* Add the IP and MAC addresses to the ARP table if they are not
  1771. * already there - otherwise refresh the age of the existing
  1772. * entry. */
  1773. if( ucProtocol != ( uint8_t ) ipPROTOCOL_UDP )
  1774. {
  1775. /* Refresh the ARP cache with the IP/MAC-address of the received
  1776. * packet. For UDP packets, this will be done later in
  1777. * xProcessReceivedUDPPacket(), as soon as it's know that the message
  1778. * will be handled. This will prevent the ARP cache getting
  1779. * overwritten with the IP address of useless broadcast packets. */
  1780. vARPRefreshCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress );
  1781. }
  1782. switch( ucProtocol )
  1783. {
  1784. case ipPROTOCOL_ICMP:
  1785. /* The IP packet contained an ICMP frame. Don't bother checking
  1786. * the ICMP checksum, as if it is wrong then the wrong data will
  1787. * also be returned, and the source of the ping will know something
  1788. * went wrong because it will not be able to validate what it
  1789. * receives. */
  1790. #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
  1791. if( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) )
  1792. {
  1793. /* Map the buffer onto a ICMP-Packet struct to easily access the
  1794. * fields of ICMP packet. */
  1795. ICMPPacket_t * pxICMPPacket = ipCAST_PTR_TO_TYPE_PTR( ICMPPacket_t, pxNetworkBuffer->pucEthernetBuffer );
  1796. if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )
  1797. {
  1798. eReturn = prvProcessICMPPacket( pxICMPPacket );
  1799. }
  1800. }
  1801. else
  1802. {
  1803. eReturn = eReleaseBuffer;
  1804. }
  1805. #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
  1806. break;
  1807. case ipPROTOCOL_UDP:
  1808. {
  1809. /* The IP packet contained a UDP frame. */
  1810. /* Map the buffer onto a UDP-Packet struct to easily access the
  1811. * fields of UDP packet. */
  1812. const UDPPacket_t * pxUDPPacket = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( UDPPacket_t, pxNetworkBuffer->pucEthernetBuffer );
  1813. uint16_t usLength;
  1814. /* Note the header values required prior to the checksum
  1815. * generation as the checksum pseudo header may clobber some of
  1816. * these values. */
  1817. usLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength );
  1818. if( ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) ) &&
  1819. ( ( ( size_t ) usLength ) >= sizeof( UDPHeader_t ) ) )
  1820. {
  1821. size_t uxPayloadSize_1, uxPayloadSize_2;
  1822. /* Ensure that downstream UDP packet handling has the lesser
  1823. * of: the actual network buffer Ethernet frame length, or
  1824. * the sender's UDP packet header payload length, minus the
  1825. * size of the UDP header.
  1826. *
  1827. * The size of the UDP packet structure in this implementation
  1828. * includes the size of the Ethernet header, the size of
  1829. * the IP header, and the size of the UDP header. */
  1830. uxPayloadSize_1 = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );
  1831. uxPayloadSize_2 = ( ( size_t ) usLength ) - sizeof( UDPHeader_t );
  1832. if( uxPayloadSize_1 > uxPayloadSize_2 )
  1833. {
  1834. pxNetworkBuffer->xDataLength = uxPayloadSize_2 + sizeof( UDPPacket_t );
  1835. }
  1836. /* Fields in pxNetworkBuffer (usPort, ulIPAddress) are network order. */
  1837. pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;
  1838. pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;
  1839. /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM:
  1840. * In some cases, the upper-layer checksum has been calculated
  1841. * by the NIC driver. */
  1842. /* Pass the packet payload to the UDP sockets
  1843. * implementation. */
  1844. if( xProcessReceivedUDPPacket( pxNetworkBuffer,
  1845. pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )
  1846. {
  1847. eReturn = eFrameConsumed;
  1848. }
  1849. }
  1850. else
  1851. {
  1852. eReturn = eReleaseBuffer;
  1853. }
  1854. }
  1855. break;
  1856. #if ipconfigUSE_TCP == 1
  1857. case ipPROTOCOL_TCP:
  1858. if( xProcessReceivedTCPPacket( pxNetworkBuffer ) == pdPASS )
  1859. {
  1860. eReturn = eFrameConsumed;
  1861. }
  1862. /* Setting this variable will cause xTCPTimerCheck()
  1863. * to be called just before the IP-task blocks. */
  1864. xProcessedTCPMessage++;
  1865. break;
  1866. #endif /* if ipconfigUSE_TCP == 1 */
  1867. default:
  1868. /* Not a supported frame type. */
  1869. break;
  1870. }
  1871. }
  1872. }
  1873. }
  1874. return eReturn;
  1875. }
  1876. /*-----------------------------------------------------------*/
  1877. #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
  1878. /**
  1879. * @brief Process an ICMP echo reply.
  1880. *
  1881. * @param[in] pxICMPPacket: The IP packet that contains the ICMP message.
  1882. */
  1883. static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket )
  1884. {
  1885. ePingReplyStatus_t eStatus = eSuccess;
  1886. uint16_t usDataLength, usCount;
  1887. uint8_t * pucByte;
  1888. /* Find the total length of the IP packet. */
  1889. usDataLength = pxICMPPacket->xIPHeader.usLength;
  1890. usDataLength = FreeRTOS_ntohs( usDataLength );
  1891. /* Remove the length of the IP headers to obtain the length of the ICMP
  1892. * message itself. */
  1893. usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_IPv4_HEADER );
  1894. /* Remove the length of the ICMP header, to obtain the length of
  1895. * data contained in the ping. */
  1896. usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_ICMP_HEADER );
  1897. /* Checksum has already been checked before in prvProcessIPPacket */
  1898. /* Find the first byte of the data within the ICMP packet. */
  1899. pucByte = ( uint8_t * ) pxICMPPacket;
  1900. pucByte = &( pucByte[ sizeof( ICMPPacket_t ) ] );
  1901. /* Check each byte. */
  1902. for( usCount = 0; usCount < usDataLength; usCount++ )
  1903. {
  1904. if( *pucByte != ( uint8_t ) ipECHO_DATA_FILL_BYTE )
  1905. {
  1906. eStatus = eInvalidData;
  1907. break;
  1908. }
  1909. pucByte++;
  1910. }
  1911. /* Call back into the application to pass it the result. */
  1912. vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier );
  1913. }
  1914. #endif /* if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
  1915. /*-----------------------------------------------------------*/
  1916. #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
  1917. /**
  1918. * @brief Process an ICMP echo request.
  1919. *
  1920. * @param[in,out] pxICMPPacket: The IP packet that contains the ICMP message.
  1921. */
  1922. static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket )
  1923. {
  1924. ICMPHeader_t * pxICMPHeader;
  1925. IPHeader_t * pxIPHeader;
  1926. uint16_t usRequest;
  1927. pxICMPHeader = &( pxICMPPacket->xICMPHeader );
  1928. pxIPHeader = &( pxICMPPacket->xIPHeader );
  1929. /* HT:endian: changed back */
  1930. iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress );
  1931. /* The checksum can be checked here - but a ping reply should be
  1932. * returned even if the checksum is incorrect so the other end can
  1933. * tell that the ping was received - even if the ping reply contains
  1934. * invalid data. */
  1935. pxICMPHeader->ucTypeOfMessage = ( uint8_t ) ipICMP_ECHO_REPLY;
  1936. pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
  1937. pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
  1938. /* Update the checksum because the ucTypeOfMessage member in the header
  1939. * has been changed to ipICMP_ECHO_REPLY. This is faster than calling
  1940. * usGenerateChecksum(). */
  1941. /* due to compiler warning "integer operation result is out of range" */
  1942. usRequest = ( uint16_t ) ( ( uint16_t ) ipICMP_ECHO_REQUEST << 8 );
  1943. if( pxICMPHeader->usChecksum >= FreeRTOS_htons( 0xFFFFU - usRequest ) )
  1944. {
  1945. pxICMPHeader->usChecksum = pxICMPHeader->usChecksum + FreeRTOS_htons( usRequest + 1U );
  1946. }
  1947. else
  1948. {
  1949. pxICMPHeader->usChecksum = pxICMPHeader->usChecksum + FreeRTOS_htons( usRequest );
  1950. }
  1951. printf("\r\n send icmp seq:%d reply \r\n", FreeRTOS_htons(pxICMPPacket->xICMPHeader.usSequenceNumber));
  1952. return eReturnEthernetFrame;
  1953. }
  1954. #endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */
  1955. /*-----------------------------------------------------------*/
  1956. #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
  1957. /**
  1958. * @brief Process an ICMP packet. Only echo requests and echo replies are recognised and handled.
  1959. *
  1960. * @param[in,out] pxICMPPacket: The IP packet that contains the ICMP message.
  1961. *
  1962. * @return eReleaseBuffer when the message buffer should be released, or eReturnEthernetFrame
  1963. * when the packet should be returned.
  1964. */
  1965. static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket )
  1966. {
  1967. eFrameProcessingResult_t eReturn = eReleaseBuffer;
  1968. iptraceICMP_PACKET_RECEIVED();
  1969. switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage )
  1970. {
  1971. case ipICMP_ECHO_REQUEST:
  1972. #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
  1973. printf("\r\n receive icmp seq:%d request \r\n", FreeRTOS_htons(pxICMPPacket->xICMPHeader.usSequenceNumber));
  1974. eReturn = prvProcessICMPEchoRequest( pxICMPPacket );
  1975. #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */
  1976. break;
  1977. case ipICMP_ECHO_REPLY:
  1978. #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
  1979. prvProcessICMPEchoReply( pxICMPPacket );
  1980. #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
  1981. break;
  1982. default:
  1983. /* Only ICMP echo packets are handled. */
  1984. break;
  1985. }
  1986. return eReturn;
  1987. }
  1988. #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
  1989. /*-----------------------------------------------------------*/
  1990. #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 )
  1991. /**
  1992. * @brief Although the driver will take care of checksum calculations, the IP-task
  1993. * will still check if the length fields are OK.
  1994. *
  1995. * @param[in] pucEthernetBuffer: The Ethernet packet received.
  1996. * @param[in] uxBufferLength: The total number of bytes received.
  1997. *
  1998. * @return pdPASS when the length fields in the packet OK, pdFAIL when the packet
  1999. * should be dropped.
  2000. */
  2001. static BaseType_t xCheckSizeFields( const uint8_t * const pucEthernetBuffer,
  2002. size_t uxBufferLength )
  2003. {
  2004. size_t uxLength;
  2005. const IPPacket_t * pxIPPacket;
  2006. UBaseType_t uxIPHeaderLength;
  2007. const ProtocolPacket_t * pxProtPack;
  2008. uint8_t ucProtocol;
  2009. uint16_t usLength;
  2010. uint16_t ucVersionHeaderLength;
  2011. size_t uxMinimumLength;
  2012. BaseType_t xResult = pdFAIL;
  2013. DEBUG_DECLARE_TRACE_VARIABLE( BaseType_t, xLocation, 0 );
  2014. do
  2015. {
  2016. /* Check for minimum packet size: Ethernet header and an IP-header, 34 bytes */
  2017. if( uxBufferLength < sizeof( IPPacket_t ) )
  2018. {
  2019. DEBUG_SET_TRACE_VARIABLE( xLocation, 1 );
  2020. break;
  2021. }
  2022. /* Map the buffer onto a IP-Packet struct to easily access the
  2023. * fields of the IP packet. */
  2024. pxIPPacket = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( IPPacket_t, pucEthernetBuffer );
  2025. ucVersionHeaderLength = pxIPPacket->xIPHeader.ucVersionHeaderLength;
  2026. /* Test if the length of the IP-header is between 20 and 60 bytes,
  2027. * and if the IP-version is 4. */
  2028. if( ( ucVersionHeaderLength < ipIPV4_VERSION_HEADER_LENGTH_MIN ) ||
  2029. ( ucVersionHeaderLength > ipIPV4_VERSION_HEADER_LENGTH_MAX ) )
  2030. {
  2031. DEBUG_SET_TRACE_VARIABLE( xLocation, 2 );
  2032. break;
  2033. }
  2034. ucVersionHeaderLength = ( ucVersionHeaderLength & ( uint8_t ) 0x0FU ) << 2;
  2035. uxIPHeaderLength = ( UBaseType_t ) ucVersionHeaderLength;
  2036. /* Check if the complete IP-header is transferred. */
  2037. if( uxBufferLength < ( ipSIZE_OF_ETH_HEADER + uxIPHeaderLength ) )
  2038. {
  2039. DEBUG_SET_TRACE_VARIABLE( xLocation, 3 );
  2040. break;
  2041. }
  2042. /* Check if the complete IP-header plus protocol data have been transferred: */
  2043. usLength = pxIPPacket->xIPHeader.usLength;
  2044. usLength = FreeRTOS_ntohs( usLength );
  2045. if( uxBufferLength < ( size_t ) ( ipSIZE_OF_ETH_HEADER + ( size_t ) usLength ) )
  2046. {
  2047. DEBUG_SET_TRACE_VARIABLE( xLocation, 4 );
  2048. break;
  2049. }
  2050. /* Identify the next protocol. */
  2051. ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
  2052. /* If this IP packet header includes Options, then the following
  2053. * assignment results in a pointer into the protocol packet with the Ethernet
  2054. * and IP headers incorrectly aligned. However, either way, the "third"
  2055. * protocol (Layer 3 or 4) header will be aligned, which is the convenience
  2056. * of this calculation. */
  2057. /* Map the Buffer onto the Protocol Packet struct for easy access to the
  2058. * struct fields. */
  2059. pxProtPack = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( ProtocolPacket_t, &( pucEthernetBuffer[ uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ] ) );
  2060. /* Switch on the Layer 3/4 protocol. */
  2061. if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
  2062. {
  2063. /* Expect at least a complete UDP header. */
  2064. uxMinimumLength = uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER;
  2065. }
  2066. else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )
  2067. {
  2068. uxMinimumLength = uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_TCP_HEADER;
  2069. }
  2070. else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||
  2071. ( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )
  2072. {
  2073. uxMinimumLength = uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_ICMP_HEADER;
  2074. }
  2075. else
  2076. {
  2077. /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */
  2078. DEBUG_SET_TRACE_VARIABLE( xLocation, 5 );
  2079. break;
  2080. }
  2081. if( uxBufferLength < uxMinimumLength )
  2082. {
  2083. DEBUG_SET_TRACE_VARIABLE( xLocation, 6 );
  2084. break;
  2085. }
  2086. uxLength = ( size_t ) usLength;
  2087. uxLength -= ( ( uint16_t ) uxIPHeaderLength ); /* normally, minus 20. */
  2088. if( ( uxLength < ( ( size_t ) sizeof( pxProtPack->xUDPPacket.xUDPHeader ) ) ) ||
  2089. ( uxLength > ( ( size_t ) ipconfigNETWORK_MTU - ( size_t ) uxIPHeaderLength ) ) )
  2090. {
  2091. /* For incoming packets, the length is out of bound: either
  2092. * too short or too long. For outgoing packets, there is a
  2093. * serious problem with the format/length. */
  2094. DEBUG_SET_TRACE_VARIABLE( xLocation, 7 );
  2095. break;
  2096. }
  2097. xResult = pdPASS;
  2098. } while( ipFALSE_BOOL );
  2099. if( xResult != pdPASS )
  2100. {
  2101. /* NOP if ipconfigHAS_PRINTF != 1 */
  2102. FreeRTOS_printf( ( "xCheckSizeFields: location %ld\n", xLocation ) );
  2103. }
  2104. xLocation = xLocation;
  2105. (void)pxProtPack;//make iar happy
  2106. return xResult;
  2107. }
  2108. #endif /* ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 ) */
  2109. /*-----------------------------------------------------------*/
  2110. /**
  2111. * @brief Generate or check the protocol checksum of the data sent in the first parameter.
  2112. * At the same time, the length of the packet and the length of the different layers
  2113. * will be checked.
  2114. *
  2115. * @param[in] pucEthernetBuffer: The Ethernet buffer for which the checksum is to be calculated
  2116. * or checked.
  2117. * @param[in] uxBufferLength: the total number of bytes received, or the number of bytes written
  2118. * in the packet buffer.
  2119. * @param[in] xOutgoingPacket: Whether this is an outgoing packet or not.
  2120. *
  2121. * @return When xOutgoingPacket is false: the error code can be either: ipINVALID_LENGTH,
  2122. * ipUNHANDLED_PROTOCOL, ipWRONG_CRC, or ipCORRECT_CRC.
  2123. * When xOutgoingPacket is true: either ipINVALID_LENGTH or ipCORRECT_CRC.
  2124. */
  2125. uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer,
  2126. size_t uxBufferLength,
  2127. BaseType_t xOutgoingPacket )
  2128. {
  2129. uint32_t ulLength;
  2130. uint16_t usChecksum, * pusChecksum;
  2131. const IPPacket_t * pxIPPacket;
  2132. UBaseType_t uxIPHeaderLength;
  2133. const ProtocolPacket_t * pxProtPack;
  2134. uint8_t ucProtocol;
  2135. #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
  2136. const char * pcType;
  2137. #endif
  2138. uint16_t usLength;
  2139. uint16_t ucVersionHeaderLength;
  2140. DEBUG_DECLARE_TRACE_VARIABLE( BaseType_t, xLocation, 0 );
  2141. /* Introduce a do-while loop to allow use of break statements.
  2142. * Note: MISRA prohibits use of 'goto', thus replaced with breaks. */
  2143. do
  2144. {
  2145. /* Check for minimum packet size. */
  2146. if( uxBufferLength < sizeof( IPPacket_t ) )
  2147. {
  2148. usChecksum = ipINVALID_LENGTH;
  2149. DEBUG_SET_TRACE_VARIABLE( xLocation, 1 );
  2150. break;
  2151. }
  2152. /* Parse the packet length. */
  2153. pxIPPacket = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( IPPacket_t, pucEthernetBuffer );
  2154. /* Per https://tools.ietf.org/html/rfc791, the four-bit Internet Header
  2155. * Length field contains the length of the internet header in 32-bit words. */
  2156. ucVersionHeaderLength = pxIPPacket->xIPHeader.ucVersionHeaderLength;
  2157. ucVersionHeaderLength = ( ucVersionHeaderLength & ( uint8_t ) 0x0FU ) << 2;
  2158. uxIPHeaderLength = ( UBaseType_t ) ucVersionHeaderLength;
  2159. /* Check for minimum packet size. */
  2160. if( uxBufferLength < ( sizeof( IPPacket_t ) + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) ) )
  2161. {
  2162. usChecksum = ipINVALID_LENGTH;
  2163. DEBUG_SET_TRACE_VARIABLE( xLocation, 2 );
  2164. break;
  2165. }
  2166. usLength = pxIPPacket->xIPHeader.usLength;
  2167. usLength = FreeRTOS_ntohs( usLength );
  2168. if( uxBufferLength < ( size_t ) ( ipSIZE_OF_ETH_HEADER + ( size_t ) usLength ) )
  2169. {
  2170. usChecksum = ipINVALID_LENGTH;
  2171. DEBUG_SET_TRACE_VARIABLE( xLocation, 3 );
  2172. break;
  2173. }
  2174. /* Identify the next protocol. */
  2175. ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
  2176. /* N.B., if this IP packet header includes Options, then the following
  2177. * assignment results in a pointer into the protocol packet with the Ethernet
  2178. * and IP headers incorrectly aligned. However, either way, the "third"
  2179. * protocol (Layer 3 or 4) header will be aligned, which is the convenience
  2180. * of this calculation. */
  2181. pxProtPack = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( ProtocolPacket_t, &( pucEthernetBuffer[ uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ] ) );
  2182. /* Switch on the Layer 3/4 protocol. */
  2183. if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
  2184. {
  2185. if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER ) )
  2186. {
  2187. usChecksum = ipINVALID_LENGTH;
  2188. DEBUG_SET_TRACE_VARIABLE( xLocation, 4 );
  2189. break;
  2190. }
  2191. pusChecksum = ( uint16_t * ) ( &( pxProtPack->xUDPPacket.xUDPHeader.usChecksum ) );
  2192. #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
  2193. {
  2194. pcType = "UDP";
  2195. }
  2196. #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
  2197. }
  2198. else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )
  2199. {
  2200. if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_TCP_HEADER ) )
  2201. {
  2202. usChecksum = ipINVALID_LENGTH;
  2203. DEBUG_SET_TRACE_VARIABLE( xLocation, 5 );
  2204. break;
  2205. }
  2206. pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) );
  2207. #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
  2208. {
  2209. pcType = "TCP";
  2210. }
  2211. #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
  2212. }
  2213. else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||
  2214. ( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )
  2215. {
  2216. if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_ICMP_HEADER ) )
  2217. {
  2218. usChecksum = ipINVALID_LENGTH;
  2219. DEBUG_SET_TRACE_VARIABLE( xLocation, 6 );
  2220. break;
  2221. }
  2222. pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) );
  2223. #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
  2224. {
  2225. if( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
  2226. {
  2227. pcType = "ICMP";
  2228. }
  2229. else
  2230. {
  2231. pcType = "IGMP";
  2232. }
  2233. }
  2234. #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
  2235. }
  2236. else
  2237. {
  2238. /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */
  2239. usChecksum = ipUNHANDLED_PROTOCOL;
  2240. DEBUG_SET_TRACE_VARIABLE( xLocation, 7 );
  2241. break;
  2242. }
  2243. /* The protocol and checksum field have been identified. Check the direction
  2244. * of the packet. */
  2245. if( xOutgoingPacket != pdFALSE )
  2246. {
  2247. /* This is an outgoing packet. Before calculating the checksum, set it
  2248. * to zero. */
  2249. *( pusChecksum ) = 0U;
  2250. }
  2251. else if( ( *pusChecksum == 0U ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
  2252. {
  2253. #if ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 )
  2254. {
  2255. /* Sender hasn't set the checksum, drop the packet because
  2256. * ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS is not set. */
  2257. usChecksum = ipWRONG_CRC;
  2258. #if ( ipconfigHAS_PRINTF != 0 )
  2259. {
  2260. static BaseType_t xCount = 0;
  2261. if( xCount < 5 )
  2262. {
  2263. FreeRTOS_printf( ( "usGenerateProtocolChecksum: UDP packet from %xip without CRC dropped\n",
  2264. FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ) ) );
  2265. xCount++;
  2266. }
  2267. }
  2268. #endif /* ( ipconfigHAS_PRINTF != 0 ) */
  2269. }
  2270. #else /* if ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 ) */
  2271. {
  2272. /* Sender hasn't set the checksum, no use to calculate it. */
  2273. usChecksum = ipCORRECT_CRC;
  2274. }
  2275. #endif /* if ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 ) */
  2276. DEBUG_SET_TRACE_VARIABLE( xLocation, 8 );
  2277. break;
  2278. }
  2279. else
  2280. {
  2281. /* Other incoming packet than UDP. */
  2282. }
  2283. usLength = pxIPPacket->xIPHeader.usLength;
  2284. usLength = FreeRTOS_ntohs( usLength );
  2285. ulLength = ( uint32_t ) usLength;
  2286. ulLength -= ( ( uint16_t ) uxIPHeaderLength ); /* normally minus 20 */
  2287. if( ( ulLength < ( ( uint32_t ) sizeof( pxProtPack->xUDPPacket.xUDPHeader ) ) ) ||
  2288. ( ulLength > ( ( uint32_t ) ipconfigNETWORK_MTU - ( uint32_t ) uxIPHeaderLength ) ) )
  2289. {
  2290. #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
  2291. {
  2292. FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: len invalid: %lu\n", pcType, ulLength ) );
  2293. }
  2294. #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
  2295. /* Again, in a 16-bit return value there is no space to indicate an
  2296. * error. For incoming packets, 0x1234 will cause dropping of the packet.
  2297. * For outgoing packets, there is a serious problem with the
  2298. * format/length */
  2299. usChecksum = ipINVALID_LENGTH;
  2300. DEBUG_SET_TRACE_VARIABLE( xLocation, 9 );
  2301. break;
  2302. }
  2303. if( ucProtocol <= ( uint8_t ) ipPROTOCOL_IGMP )
  2304. {
  2305. /* ICMP/IGMP do not have a pseudo header for CRC-calculation. */
  2306. usChecksum = ( uint16_t )
  2307. ( ~usGenerateChecksum( 0U,
  2308. ( const uint8_t * ) &( pxProtPack->xTCPPacket.xTCPHeader ), ( size_t ) ulLength ) );
  2309. }
  2310. else
  2311. {
  2312. /* For UDP and TCP, sum the pseudo header, i.e. IP protocol + length
  2313. * fields */
  2314. usChecksum = ( uint16_t ) ( ulLength + ( ( uint16_t ) ucProtocol ) );
  2315. /* And then continue at the IPv4 source and destination addresses. */
  2316. usChecksum = ( uint16_t )
  2317. ( ~usGenerateChecksum( usChecksum,
  2318. ipPOINTER_CAST( const uint8_t *, &( pxIPPacket->xIPHeader.ulSourceIPAddress ) ),
  2319. ( size_t ) ( ( 2U * ipSIZE_OF_IPv4_ADDRESS ) + ulLength ) ) );
  2320. /* Sum TCP header and data. */
  2321. }
  2322. if( xOutgoingPacket == pdFALSE )
  2323. {
  2324. /* This is in incoming packet. If the CRC is correct, it should be zero. */
  2325. if( usChecksum == 0U )
  2326. {
  2327. usChecksum = ( uint16_t ) ipCORRECT_CRC;
  2328. }
  2329. }
  2330. else
  2331. {
  2332. if( ( usChecksum == 0U ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
  2333. {
  2334. /* In case of UDP, a calculated checksum of 0x0000 is transmitted
  2335. * as 0xffff. A value of zero would mean that the checksum is not used. */
  2336. #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
  2337. {
  2338. if( xOutgoingPacket != pdFALSE )
  2339. {
  2340. FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: crc swap: %04X\n", pcType, usChecksum ) );
  2341. }
  2342. }
  2343. #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
  2344. usChecksum = ( uint16_t ) 0xffffu;
  2345. }
  2346. }
  2347. usChecksum = FreeRTOS_htons( usChecksum );
  2348. if( xOutgoingPacket != pdFALSE )
  2349. {
  2350. *( pusChecksum ) = usChecksum;
  2351. }
  2352. #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
  2353. else if( ( xOutgoingPacket == pdFALSE ) && ( usChecksum != ipCORRECT_CRC ) )
  2354. {
  2355. FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: ID %04X: from %lxip to %lxip bad crc: %04X\n",
  2356. pcType,
  2357. FreeRTOS_ntohs( pxIPPacket->xIPHeader.usIdentification ),
  2358. FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ),
  2359. FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulDestinationIPAddress ),
  2360. FreeRTOS_ntohs( *pusChecksum ) ) );
  2361. }
  2362. else
  2363. {
  2364. /* Nothing. */
  2365. }
  2366. #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
  2367. } while( ipFALSE_BOOL );
  2368. if( ( usChecksum == ipUNHANDLED_PROTOCOL ) ||
  2369. ( usChecksum == ipINVALID_LENGTH ) )
  2370. {
  2371. /* NOP if ipconfigHAS_PRINTF != 0 */
  2372. FreeRTOS_printf( ( "CRC error: %04x location %ld\n", usChecksum, xLocation ) );
  2373. }
  2374. xLocation = xLocation;
  2375. return usChecksum;
  2376. }
  2377. /*-----------------------------------------------------------*/
  2378. /**
  2379. * This method generates a checksum for a given IPv4 header, per RFC791 (page 14).
  2380. * The checksum algorithm is described as:
  2381. * "[T]he 16 bit one's complement of the one's complement sum of all 16 bit words in the
  2382. * header. For purposes of computing the checksum, the value of the checksum field is zero."
  2383. *
  2384. * In a nutshell, that means that each 16-bit 'word' must be summed, after which
  2385. * the number of 'carries' (overflows) is added to the result. If that addition
  2386. * produces an overflow, that 'carry' must also be added to the final result. The final checksum
  2387. * should be the bitwise 'not' (ones-complement) of the result if the packet is
  2388. * meant to be transmitted, but this method simply returns the raw value, probably
  2389. * because when a packet is received, the checksum is verified by checking that
  2390. * ((received & calculated) == 0) without applying a bitwise 'not' to the 'calculated' checksum.
  2391. *
  2392. * This logic is optimized for microcontrollers which have limited resources, so the logic looks odd.
  2393. * It iterates over the full range of 16-bit words, but it does so by processing several 32-bit
  2394. * words at once whenever possible. Its first step is to align the memory pointer to a 32-bit boundary,
  2395. * after which it runs a fast loop to process multiple 32-bit words at once and adding their 'carries'.
  2396. * Finally, it finishes up by processing any remaining 16-bit words, and adding up all of the 'carries'.
  2397. * With 32-bit arithmetic, the number of 16-bit 'carries' produced by sequential additions can be found
  2398. * by looking at the 16 most-significant bits of the 32-bit integer, since a 32-bit int will continue
  2399. * counting up instead of overflowing after 16 bits. That is why the actual checksum calculations look like:
  2400. * union.u32 = ( uint32_t ) union.u16[ 0 ] + union.u16[ 1 ];
  2401. *
  2402. * Arguments:
  2403. * ulSum: This argument provides a value to initialise the progressive summation
  2404. * of the header's values to. It is often 0, but protocols like TCP or UDP
  2405. * can have pseudo-header fields which need to be included in the checksum.
  2406. * pucNextData: This argument contains the address of the first byte which this
  2407. * method should process. The method's memory iterator is initialised to this value.
  2408. * uxDataLengthBytes: This argument contains the number of bytes that this method
  2409. * should process.
  2410. */
  2411. /**
  2412. * @brief Calculates the 16-bit checksum of an array of bytes
  2413. *
  2414. * @param[in] usSum: The initial sum, obtained from earlier data.
  2415. * @param[in] pucNextData: The actual data.
  2416. * @param[in] uxByteCount: The number of bytes.
  2417. *
  2418. * @return The 16-bit one's complement of the one's complement sum of all 16-bit
  2419. * words in the header
  2420. */
  2421. uint16_t usGenerateChecksum( uint16_t usSum,
  2422. const uint8_t * pucNextData,
  2423. size_t uxByteCount )
  2424. {
  2425. /* MISRA/PC-lint doesn't like the use of unions. Here, they are a great
  2426. * aid though to optimise the calculations. */
  2427. xUnion32 xSum2, xSum, xTerm;
  2428. xUnionPtr xSource;
  2429. xUnionPtr xLastSource;
  2430. uintptr_t uxAlignBits;
  2431. uint32_t ulCarry = 0UL;
  2432. uint16_t usTemp;
  2433. size_t uxDataLengthBytes = uxByteCount;
  2434. /* Small MCUs often spend up to 30% of the time doing checksum calculations
  2435. * This function is optimised for 32-bit CPUs; Each time it will try to fetch
  2436. * 32-bits, sums it with an accumulator and counts the number of carries. */
  2437. /* Swap the input (little endian platform only). */
  2438. usTemp = FreeRTOS_ntohs( usSum );
  2439. xSum.u32 = ( uint32_t ) usTemp;
  2440. xTerm.u32 = 0UL;
  2441. xSource.u8ptr = ipPOINTER_CAST( uint8_t *, pucNextData );
  2442. uxAlignBits = ( ( ( uintptr_t ) pucNextData ) & 0x03U );
  2443. /*
  2444. * If pucNextData is non-aligned then the checksum is starting at an
  2445. * odd position and we need to make sure the usSum value now in xSum is
  2446. * as if it had been "aligned" in the same way.
  2447. */
  2448. if( ( uxAlignBits & 1UL ) != 0U )
  2449. {
  2450. xSum.u32 = ( ( xSum.u32 & 0xffU ) << 8 ) | ( ( xSum.u32 & 0xff00U ) >> 8 );
  2451. }
  2452. /* If byte (8-bit) aligned... */
  2453. if( ( ( uxAlignBits & 1UL ) != 0UL ) && ( uxDataLengthBytes >= ( size_t ) 1 ) )
  2454. {
  2455. xTerm.u8[ 1 ] = *( xSource.u8ptr );
  2456. xSource.u8ptr++;
  2457. uxDataLengthBytes--;
  2458. /* Now xSource is word (16-bit) aligned. */
  2459. }
  2460. /* If half-word (16-bit) aligned... */
  2461. if( ( ( uxAlignBits == 1U ) || ( uxAlignBits == 2U ) ) && ( uxDataLengthBytes >= 2U ) )
  2462. {
  2463. xSum.u32 += *( xSource.u16ptr );
  2464. xSource.u16ptr++;
  2465. uxDataLengthBytes -= 2U;
  2466. /* Now xSource is word (32-bit) aligned. */
  2467. }
  2468. /* Word (32-bit) aligned, do the most part. */
  2469. xLastSource.u32ptr = ( xSource.u32ptr + ( uxDataLengthBytes / 4U ) ) - 3U;
  2470. /* In this loop, four 32-bit additions will be done, in total 16 bytes.
  2471. * Indexing with constants (0,1,2,3) gives faster code than using
  2472. * post-increments. */
  2473. while( xSource.u32ptr < xLastSource.u32ptr )
  2474. {
  2475. /* Use a secondary Sum2, just to see if the addition produced an
  2476. * overflow. */
  2477. xSum2.u32 = xSum.u32 + xSource.u32ptr[ 0 ];
  2478. if( xSum2.u32 < xSum.u32 )
  2479. {
  2480. ulCarry++;
  2481. }
  2482. /* Now add the secondary sum to the major sum, and remember if there was
  2483. * a carry. */
  2484. xSum.u32 = xSum2.u32 + xSource.u32ptr[ 1 ];
  2485. if( xSum2.u32 > xSum.u32 )
  2486. {
  2487. ulCarry++;
  2488. }
  2489. /* And do the same trick once again for indexes 2 and 3 */
  2490. xSum2.u32 = xSum.u32 + xSource.u32ptr[ 2 ];
  2491. if( xSum2.u32 < xSum.u32 )
  2492. {
  2493. ulCarry++;
  2494. }
  2495. xSum.u32 = xSum2.u32 + xSource.u32ptr[ 3 ];
  2496. if( xSum2.u32 > xSum.u32 )
  2497. {
  2498. ulCarry++;
  2499. }
  2500. /* And finally advance the pointer 4 * 4 = 16 bytes. */
  2501. xSource.u32ptr = &( xSource.u32ptr[ 4 ] );
  2502. }
  2503. /* Now add all carries. */
  2504. xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ] + ulCarry;
  2505. uxDataLengthBytes %= 16U;
  2506. xLastSource.u8ptr = ( uint8_t * ) ( xSource.u8ptr + ( uxDataLengthBytes & ~( ( size_t ) 1 ) ) );
  2507. /* Half-word aligned. */
  2508. /* Coverity does not like Unions. Warning issued here: "The operator "<"
  2509. * is being applied to the pointers "xSource.u16ptr" and "xLastSource.u16ptr",
  2510. * which do not point into the same object." */
  2511. while( xSource.u16ptr < xLastSource.u16ptr )
  2512. {
  2513. /* At least one more short. */
  2514. xSum.u32 += xSource.u16ptr[ 0 ];
  2515. xSource.u16ptr++;
  2516. }
  2517. if( ( uxDataLengthBytes & ( size_t ) 1 ) != 0U ) /* Maybe one more ? */
  2518. {
  2519. xTerm.u8[ 0 ] = xSource.u8ptr[ 0 ];
  2520. }
  2521. xSum.u32 += xTerm.u32;
  2522. /* Now add all carries again. */
  2523. /* Assigning value from "xTerm.u32" to "xSum.u32" here, but that stored value is overwritten before it can be used.
  2524. * Coverity doesn't understand about union variables. */
  2525. xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
  2526. /* coverity[value_overwrite] */
  2527. xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
  2528. if( ( uxAlignBits & 1U ) != 0U )
  2529. {
  2530. /* Quite unlikely, but pucNextData might be non-aligned, which would
  2531. * mean that a checksum is calculated starting at an odd position. */
  2532. xSum.u32 = ( ( xSum.u32 & 0xffU ) << 8 ) | ( ( xSum.u32 & 0xff00U ) >> 8 );
  2533. }
  2534. /* swap the output (little endian platform only). */
  2535. return FreeRTOS_htons( ( ( uint16_t ) xSum.u32 ) );
  2536. }
  2537. /*-----------------------------------------------------------*/
  2538. /* This function is used in other files, has external linkage e.g. in
  2539. * FreeRTOS_DNS.c. Not to be made static. */
  2540. /**
  2541. * @brief Send the Ethernet frame after checking for some conditions.
  2542. *
  2543. * @param[in,out] pxNetworkBuffer: The network buffer which is to be sent.
  2544. * @param[in] xReleaseAfterSend: Whether this network buffer is to be released or not.
  2545. */
  2546. void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer,
  2547. BaseType_t xReleaseAfterSend )
  2548. {
  2549. EthernetHeader_t * pxEthernetHeader;
  2550. /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
  2551. const void * pvCopySource;
  2552. void * pvCopyDest;
  2553. #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
  2554. NetworkBufferDescriptor_t * pxNewBuffer;
  2555. #endif
  2556. #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
  2557. {
  2558. if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
  2559. {
  2560. BaseType_t xIndex;
  2561. FreeRTOS_printf( ( "vReturnEthernetFrame: length %u\n", ( unsigned ) pxNetworkBuffer->xDataLength ) );
  2562. for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
  2563. {
  2564. pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
  2565. }
  2566. pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
  2567. }
  2568. }
  2569. #endif /* if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) */
  2570. #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
  2571. if( xReleaseAfterSend == pdFALSE )
  2572. {
  2573. pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, pxNetworkBuffer->xDataLength );
  2574. if( pxNewBuffer != NULL )
  2575. {
  2576. xReleaseAfterSend = pdTRUE;
  2577. /* Want no rounding up. */
  2578. pxNewBuffer->xDataLength = pxNetworkBuffer->xDataLength;
  2579. }
  2580. pxNetworkBuffer = pxNewBuffer;
  2581. }
  2582. if( pxNetworkBuffer != NULL )
  2583. #endif /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
  2584. {
  2585. /* Map the Buffer to Ethernet Header struct for easy access to fields. */
  2586. pxEthernetHeader = ipCAST_PTR_TO_TYPE_PTR( EthernetHeader_t, pxNetworkBuffer->pucEthernetBuffer );
  2587. /*
  2588. * Use helper variables for memcpy() to remain
  2589. * compliant with MISRA Rule 21.15. These should be
  2590. * optimized away.
  2591. */
  2592. /* Swap source and destination MAC addresses. */
  2593. pvCopySource = &pxEthernetHeader->xSourceAddress;
  2594. pvCopyDest = &pxEthernetHeader->xDestinationAddress;
  2595. ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxEthernetHeader->xDestinationAddress ) );
  2596. pvCopySource = ipLOCAL_MAC_ADDRESS;
  2597. pvCopyDest = &pxEthernetHeader->xSourceAddress;
  2598. ( void ) memcpy( pvCopyDest, pvCopySource, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
  2599. /* Send! */
  2600. iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
  2601. ( void ) xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
  2602. }
  2603. }
  2604. /*-----------------------------------------------------------*/
  2605. #if ( ipconfigHAS_PRINTF != 0 )
  2606. #ifndef ipMONITOR_MAX_HEAP
  2607. /* As long as the heap has more space than e.g. 1 MB, there
  2608. * will be no messages. */
  2609. #define ipMONITOR_MAX_HEAP ( 1024U * 1024U )
  2610. #endif /* ipMONITOR_MAX_HEAP */
  2611. #ifndef ipMONITOR_PERCENTAGE_90
  2612. /* Make this number lower to get less logging messages. */
  2613. #define ipMONITOR_PERCENTAGE_90 ( 90U )
  2614. #endif
  2615. #define ipMONITOR_PERCENTAGE_100 ( 100U )
  2616. /**
  2617. * @brief A function that monitors a three resources: the heap, the space in the message
  2618. * queue of the IP-task, the number of available network buffer descriptors.
  2619. */
  2620. void vPrintResourceStats( void )
  2621. {
  2622. static UBaseType_t uxLastMinBufferCount = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
  2623. static size_t uxMinLastSize = 0u;
  2624. UBaseType_t uxCurrentBufferCount;
  2625. size_t uxMinSize;
  2626. /* When setting up and testing a project with FreeRTOS+TCP, it is
  2627. * can be helpful to monitor a few resources: the number of network
  2628. * buffers and the amount of available heap.
  2629. * This function will issue some logging when a minimum value has
  2630. * changed. */
  2631. uxCurrentBufferCount = uxGetMinimumFreeNetworkBuffers();
  2632. if( uxLastMinBufferCount > uxCurrentBufferCount )
  2633. {
  2634. /* The logging produced below may be helpful
  2635. * while tuning +TCP: see how many buffers are in use. */
  2636. uxLastMinBufferCount = uxCurrentBufferCount;
  2637. FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
  2638. uxGetNumberOfFreeNetworkBuffers(),
  2639. uxCurrentBufferCount ) );
  2640. }
  2641. uxMinSize = xPortGetMinimumEverFreeHeapSize();
  2642. if( uxMinLastSize == 0U )
  2643. {
  2644. /* Probably the first time this function is called. */
  2645. uxMinLastSize = uxMinSize;
  2646. }
  2647. else if( uxMinSize >= ipMONITOR_MAX_HEAP )
  2648. {
  2649. /* There is more than enough heap space. No need for logging. */
  2650. }
  2651. /* Write logging if there is a 10% decrease since the last time logging was written. */
  2652. else if( ( uxMinLastSize * ipMONITOR_PERCENTAGE_90 ) > ( uxMinSize * ipMONITOR_PERCENTAGE_100 ) )
  2653. {
  2654. uxMinLastSize = uxMinSize;
  2655. FreeRTOS_printf( ( "Heap: current %lu lowest %lu\n", xPortGetFreeHeapSize(), uxMinSize ) );
  2656. }
  2657. else
  2658. {
  2659. /* Nothing to log. */
  2660. }
  2661. #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
  2662. {
  2663. static UBaseType_t uxLastMinQueueSpace = 0;
  2664. UBaseType_t uxCurrentCount = 0u;
  2665. uxCurrentCount = uxGetMinimumIPQueueSpace();
  2666. if( uxLastMinQueueSpace != uxCurrentCount )
  2667. {
  2668. /* The logging produced below may be helpful
  2669. * while tuning +TCP: see how many buffers are in use. */
  2670. uxLastMinQueueSpace = uxCurrentCount;
  2671. FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
  2672. }
  2673. }
  2674. #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
  2675. }
  2676. #endif /* ( ipconfigHAS_PRINTF != 0 ) */
  2677. /*-----------------------------------------------------------*/
  2678. /**
  2679. * @brief Returns the IP address of the NIC.
  2680. *
  2681. * @return The IP address of the NIC.
  2682. */
  2683. uint32_t FreeRTOS_GetIPAddress( void )
  2684. {
  2685. return *ipLOCAL_IP_ADDRESS_POINTER;
  2686. }
  2687. /*-----------------------------------------------------------*/
  2688. /**
  2689. * @brief Sets the IP address of the NIC.
  2690. *
  2691. * @param[in] ulIPAddress: IP address of the NIC to be set.
  2692. */
  2693. void FreeRTOS_SetIPAddress( uint32_t ulIPAddress )
  2694. {
  2695. *ipLOCAL_IP_ADDRESS_POINTER = ulIPAddress;
  2696. }
  2697. /*-----------------------------------------------------------*/
  2698. /**
  2699. * @brief Get the gateway address of the subnet.
  2700. *
  2701. * @return The IP-address of the gateway, zero if a gateway is
  2702. * not used/defined.
  2703. */
  2704. uint32_t FreeRTOS_GetGatewayAddress( void )
  2705. {
  2706. return xNetworkAddressing.ulGatewayAddress;
  2707. }
  2708. /*-----------------------------------------------------------*/
  2709. /**
  2710. * @brief Get the DNS server address.
  2711. *
  2712. * @return The IP address of the DNS server.
  2713. */
  2714. uint32_t FreeRTOS_GetDNSServerAddress( void )
  2715. {
  2716. return xNetworkAddressing.ulDNSServerAddress;
  2717. }
  2718. /*-----------------------------------------------------------*/
  2719. /**
  2720. * @brief Get the netmask for the subnet.
  2721. *
  2722. * @return The 32 bit netmask for the subnet.
  2723. */
  2724. uint32_t FreeRTOS_GetNetmask( void )
  2725. {
  2726. return xNetworkAddressing.ulNetMask;
  2727. }
  2728. /*-----------------------------------------------------------*/
  2729. /**
  2730. * @brief Update the MAC address.
  2731. *
  2732. * @param[in] ucMACAddress: the MAC address to be set.
  2733. */
  2734. void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] )
  2735. {
  2736. /* Copy the MAC address at the start of the default packet header fragment. */
  2737. ( void ) memcpy( ipLOCAL_MAC_ADDRESS, ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
  2738. }
  2739. /*-----------------------------------------------------------*/
  2740. /**
  2741. * @brief Get the MAC address.
  2742. *
  2743. * @return The pointer to MAC address.
  2744. */
  2745. const uint8_t * FreeRTOS_GetMACAddress( void )
  2746. {
  2747. return ipLOCAL_MAC_ADDRESS;
  2748. }
  2749. /*-----------------------------------------------------------*/
  2750. /**
  2751. * @brief Set the netmask for the subnet.
  2752. *
  2753. * @param[in] ulNetmask: The 32 bit netmask of the subnet.
  2754. */
  2755. void FreeRTOS_SetNetmask( uint32_t ulNetmask )
  2756. {
  2757. xNetworkAddressing.ulNetMask = ulNetmask;
  2758. }
  2759. /*-----------------------------------------------------------*/
  2760. /**
  2761. * @brief Set the gateway address.
  2762. *
  2763. * @param[in] ulGatewayAddress: The gateway address.
  2764. */
  2765. void FreeRTOS_SetGatewayAddress( uint32_t ulGatewayAddress )
  2766. {
  2767. xNetworkAddressing.ulGatewayAddress = ulGatewayAddress;
  2768. }
  2769. /*-----------------------------------------------------------*/
  2770. #if ( ipconfigUSE_DHCP == 1 )
  2771. /**
  2772. * @brief Enable/disable the DHCP timer.
  2773. *
  2774. * @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
  2775. */
  2776. void vIPSetDHCPTimerEnableState( BaseType_t xEnableState )
  2777. {
  2778. if( xEnableState != pdFALSE )
  2779. {
  2780. xDHCPTimer.bActive = pdTRUE_UNSIGNED;
  2781. }
  2782. else
  2783. {
  2784. xDHCPTimer.bActive = pdFALSE_UNSIGNED;
  2785. }
  2786. }
  2787. #endif /* ipconfigUSE_DHCP */
  2788. /*-----------------------------------------------------------*/
  2789. #if ( ipconfigUSE_DHCP == 1 )
  2790. /**
  2791. * @brief Reload the DHCP timer.
  2792. *
  2793. * @param[in] ulLeaseTime: The reload value.
  2794. */
  2795. void vIPReloadDHCPTimer( uint32_t ulLeaseTime )
  2796. {
  2797. prvIPTimerReload( &xDHCPTimer, ulLeaseTime );
  2798. }
  2799. #endif /* ipconfigUSE_DHCP */
  2800. /*-----------------------------------------------------------*/
  2801. #if ( ipconfigDNS_USE_CALLBACKS == 1 )
  2802. /**
  2803. * @brief Enable/disable the DNS timer.
  2804. *
  2805. * @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
  2806. */
  2807. void vIPSetDnsTimerEnableState( BaseType_t xEnableState )
  2808. {
  2809. if( xEnableState != 0 )
  2810. {
  2811. xDNSTimer.bActive = pdTRUE;
  2812. }
  2813. else
  2814. {
  2815. xDNSTimer.bActive = pdFALSE;
  2816. }
  2817. }
  2818. #endif /* ipconfigUSE_DHCP */
  2819. /*-----------------------------------------------------------*/
  2820. #if ( ipconfigDNS_USE_CALLBACKS != 0 )
  2821. /**
  2822. * @brief Reload the DNS timer.
  2823. *
  2824. * @param[in] ulCheckTime: The reload value.
  2825. */
  2826. void vIPReloadDNSTimer( uint32_t ulCheckTime )
  2827. {
  2828. prvIPTimerReload( &xDNSTimer, ulCheckTime );
  2829. }
  2830. #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
  2831. /*-----------------------------------------------------------*/
  2832. /**
  2833. * @brief Returns whether the IP task is ready.
  2834. *
  2835. * @return pdTRUE if IP task is ready, else pdFALSE.
  2836. */
  2837. BaseType_t xIPIsNetworkTaskReady( void )
  2838. {
  2839. return xIPTaskInitialised;
  2840. }
  2841. /*-----------------------------------------------------------*/
  2842. /**
  2843. * @brief Returns whether this node is connected to network or not.
  2844. *
  2845. * @return pdTRUE if network is connected, else pdFALSE.
  2846. */
  2847. BaseType_t FreeRTOS_IsNetworkUp( void )
  2848. {
  2849. return xNetworkUp;
  2850. }
  2851. /*-----------------------------------------------------------*/
  2852. #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
  2853. /**
  2854. * @brief Get the minimum space in the IP task queue.
  2855. *
  2856. * @return The minimum possible space in the IP task queue.
  2857. */
  2858. UBaseType_t uxGetMinimumIPQueueSpace( void )
  2859. {
  2860. return uxQueueMinimumSpace;
  2861. }
  2862. #endif
  2863. /*-----------------------------------------------------------*/
  2864. /**
  2865. * @brief Utility function: Convert error number to a human readable
  2866. * string. Declaration in FreeRTOS_errno_TCP.h.
  2867. *
  2868. * @param[in] xErrnum: The error number.
  2869. * @param[in] pcBuffer: Buffer big enough to be filled with the human readable message.
  2870. * @param[in] uxLength: Maximum length of the buffer.
  2871. *
  2872. * @return The buffer filled with human readable error string.
  2873. */
  2874. const char * FreeRTOS_strerror_r( BaseType_t xErrnum,
  2875. char * pcBuffer,
  2876. size_t uxLength )
  2877. {
  2878. const char * pcName;
  2879. switch( xErrnum )
  2880. {
  2881. case pdFREERTOS_ERRNO_EADDRINUSE:
  2882. pcName = "EADDRINUSE";
  2883. break;
  2884. case pdFREERTOS_ERRNO_ENOMEM:
  2885. pcName = "ENOMEM";
  2886. break;
  2887. case pdFREERTOS_ERRNO_EADDRNOTAVAIL:
  2888. pcName = "EADDRNOTAVAIL";
  2889. break;
  2890. case pdFREERTOS_ERRNO_ENOPROTOOPT:
  2891. pcName = "ENOPROTOOPT";
  2892. break;
  2893. case pdFREERTOS_ERRNO_EBADF:
  2894. pcName = "EBADF";
  2895. break;
  2896. case pdFREERTOS_ERRNO_ENOSPC:
  2897. pcName = "ENOSPC";
  2898. break;
  2899. case pdFREERTOS_ERRNO_ECANCELED:
  2900. pcName = "ECANCELED";
  2901. break;
  2902. case pdFREERTOS_ERRNO_ENOTCONN:
  2903. pcName = "ENOTCONN";
  2904. break;
  2905. case pdFREERTOS_ERRNO_EINPROGRESS:
  2906. pcName = "EINPROGRESS";
  2907. break;
  2908. case pdFREERTOS_ERRNO_EOPNOTSUPP:
  2909. pcName = "EOPNOTSUPP";
  2910. break;
  2911. case pdFREERTOS_ERRNO_EINTR:
  2912. pcName = "EINTR";
  2913. break;
  2914. case pdFREERTOS_ERRNO_ETIMEDOUT:
  2915. pcName = "ETIMEDOUT";
  2916. break;
  2917. case pdFREERTOS_ERRNO_EINVAL:
  2918. pcName = "EINVAL";
  2919. break;
  2920. case pdFREERTOS_ERRNO_EWOULDBLOCK:
  2921. pcName = "EWOULDBLOCK";
  2922. break; /* same as EAGAIN */
  2923. case pdFREERTOS_ERRNO_EISCONN:
  2924. pcName = "EISCONN";
  2925. break;
  2926. default:
  2927. /* Using function "snprintf". */
  2928. ( void ) snprintf( pcBuffer, uxLength, "Errno %d", ( int32_t ) xErrnum );
  2929. pcName = NULL;
  2930. break;
  2931. }
  2932. if( pcName != NULL )
  2933. {
  2934. /* Using function "snprintf". */
  2935. ( void ) snprintf( pcBuffer, uxLength, "%s", pcName );
  2936. }
  2937. if( uxLength > 0U )
  2938. {
  2939. pcBuffer[ uxLength - 1U ] = '\0';
  2940. }
  2941. return pcBuffer;
  2942. }
  2943. /*-----------------------------------------------------------*/
  2944. /* Provide access to private members for verification. */
  2945. #ifdef FREERTOS_TCP_ENABLE_VERIFICATION
  2946. #include "aws_freertos_ip_verification_access_ip_define.h"
  2947. #endif