1 /*
2  * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 /*
29  * @file tcp_dump_packets.c
30  * @brief Used in the PC/Win project to dump Ethernet packets, along with some description.
31  * See tools/tcp_dump_packets.md for further description.
32  */
33 
34 /* Standard includes. */
35 #include <stdio.h>
36 #include <stdint.h>
37 #include <stdarg.h>
38 #include <ctype.h>
39 
40 /* FreeRTOS includes. */
41 #include <FreeRTOS.h>
42 #include "task.h"
43 
44 /* FreeRTOS+TCP includes. */
45 #include "FreeRTOS_IP.h"
46 #include "FreeRTOS_Sockets.h"
47 #include "FreeRTOS_Stream_Buffer.h"
48 #include "FreeRTOS_IP_Private.h"
49 
50 #if ( ipconfigUSE_DUMP_PACKETS != 0 )
51 
52     #include "tcp_dump_packets.h"
53 
54 /* The priority of the windows thread. */
55     #define dumpPROCESS_THREAD_PRIORITY    THREAD_PRIORITY_NORMAL
56 
57 /* There is a stream buffer between the FreeRTOS tasks sending network packets,
58  * and the Windows thread that writes these packets to disk. The macro 'dumpITEM_COUNT'
59  * determines the number of full-size packets that can be stored in this stream buffer. */
60     #ifndef dumpITEM_COUNT
61         #define dumpITEM_COUNT    32
62     #endif
63 
64 /* Packets are written in hex notation, no more than 16 bytes on a row. */
65     #ifndef dumpBYTES_PER_ROW
66         #define dumpBYTES_PER_ROW    16
67     #endif
68 
69 /* The TCP port number reserved for a DNS server. */
70     #define dnsDNS_PORT        0x0035u
71 
72 /* Some const values describing the 'flags' in a TCP packet. */
73     #define tcpTCP_FLAG_FIN    0x0001u          /* No more data from sender */
74     #define tcpTCP_FLAG_SYN    0x0002u          /* Synchronize sequence numbers */
75     #define tcpTCP_FLAG_RST    0x0004u          /* Reset the connection */
76     #define tcpTCP_FLAG_PSH    0x0008u          /* Push function: please push buffered data to the recv application */
77     #define tcpTCP_FLAG_ACK    0x0010u          /* Acknowledgment field is significant */
78 
79 /* A macro to add a type, both as a numeric value, as well as a string. */
80     #define ADD_TYPE( FLAGS ) \
81     vAddType( flag_ ## FLAGS, # FLAGS )
82 
83 /*-----------------------------------------------------------*/
84 
85     static char pcTypeString[ 255 ];
86     static uint32_t ulTypeMask;
87 
88 /* The name of the C source file to be written. */
89     static char pcCodeFileName[ MAX_PATH ];
90 
91 /* The name of the header file to be written. */
92     static char pcHeaderFileName[ MAX_PATH ];
93 
94 /* A stream buffer between the FreeRTOS tasks and the Windows thread. */
95     static StreamBuffer_t * xPacketBuffer;
96 
97 /* A process handle of the Windows thread. */
98     static HANDLE pvProcessHandle;
99 
100     static UBaseType_t uxNextPacketNumber;
101     static BaseType_t xFirstPacket = 1;
102 
103 /* Boolean 'xDumpingReady' becomes true once all desired packet have been collected.
104  * Further packets will be dropped (ignored). */
105     static volatile BaseType_t xDumpingReady = pdFALSE;
106 
107     static DumpEntries_t * pxCurrentEntries;
108 
109     static uint16_t usSourcePort;
110     static uint16_t usDestinationPort;
111 
112     typedef struct xBufferheader
113     {
114         size_t uxLength;
115         UBaseType_t bIncoming : 1;
116     } Bufferheader_t;
117 
118     static DumpEntries_t xExampleEntries =
119     {
120         .uxEntryCount = 4,                  /* No more than 'dumpMAX_DUMP_ENTRIES' elements. */
121         .xEntries     =
122         {
123             { .ulMask = flag_IN | flag_UDP, .uxMax = 2u },
124             { .ulMask = flag_IN | flag_ARP, .uxMax = 2u },
125             { .ulMask = flag_IN | flag_TCP, .uxMax = 5u },
126             { .ulMask = flag_IN | flag_SYN, .uxMax = 1u },
127         }
128     };
129 
130     const char pcHeaderCode[] =
131         "/*\n"
132         " * This file was created automatically by 'dump_packets.c'\n"
133         " */\n"
134         "\n"
135         "/* Standard includes. */\n"
136         "#include <stdio.h>\n"
137         "#include <stdint.h>\n"
138         "#include <stdarg.h>\n"
139         "#include <io.h>\n"
140         "#include <ctype.h>\n"
141         "\n"
142         "/* FreeRTOS includes. */\n"
143         "#include <FreeRTOS.h>\n"
144         "#include <task.h>\n\n"
145         "#include \"%s\"\n\n";
146 
147     const char pcHeaderHeader[] =
148         "/*\n"
149         " * This file was created automatically by 'dump_packets.c'\n"
150         " */\n"
151         "\n"
152         "#ifndef PACKET_LIST_H\n\n"
153         "#define PACKET_LIST_H\n\n"
154         "typedef struct xDumpPacket\n"
155         "{\n"
156         "	const uint8_t *pucData;\n"
157         "	size_t uxLength;\n"
158         "	uint32_t ulType;\n"
159         "	uint16_t usSource;\n"
160         "	uint16_t usDestination;\n"
161         "} DumpPacket_t;\n\n";
162 
163 /*-----------------------------------------------------------*/
164 
165 /* The Windows thread that actually writes the network packets to a C source and header file. */
166     static DWORD WINAPI prvWritePackets( LPVOID lpParameter );
167 
168     static void vAddProtocolTags( uint8_t * pucEthernetBuffer,
169                                   BaseType_t xIPType );
170     static void vDetermineMessageType( uint8_t * pucBuffer,
171                                        BaseType_t xIncoming );
172     static void vActualDump( uint8_t * pucBuffer,
173                              size_t uxLength,
174                              BaseType_t xIncoming );
175     static void vAddType( uint32_t ulFlags,
176                           const char * pcFlagName );
177     static void vWriteHeaderFile( void );
178 
179 /*-----------------------------------------------------------*/
180 
dump_packet_init(const char * pcFileName,DumpEntries_t * pxEntries)181     void dump_packet_init( const char * pcFileName,
182                            DumpEntries_t * pxEntries )
183     {
184         size_t uxIndex;
185 
186         snprintf( pcCodeFileName, sizeof pcCodeFileName, "%s.c", pcFileName );
187         snprintf( pcHeaderFileName, sizeof pcHeaderFileName, "%s.h", pcFileName );
188 
189         if( pxEntries == NULL )
190         {
191             pxEntries = &( xExampleEntries );
192         }
193 
194         configASSERT( pxEntries->uxEntryCount > 0 );
195         configASSERT( pxEntries->uxEntryCount <= dumpMAX_DUMP_ENTRIES );
196 
197         for( uxIndex = 0; uxIndex < pxEntries->uxEntryCount; uxIndex++ )
198         {
199             pxEntries->xEntries[ uxIndex ].uxCount = 0;
200         }
201 
202         pxCurrentEntries = pxEntries;
203 
204         if( xPacketBuffer == NULL )
205         {
206             size_t uxLength, uxSize;
207 
208             /* Enough space for e.g. 32 buffers and length words. */
209             uxLength = dumpITEM_COUNT * ( sizeof( void * ) + ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER );
210             uxSize = ( sizeof( *xPacketBuffer ) + uxLength ) - sizeof( xPacketBuffer->ucArray );
211             xPacketBuffer = ( StreamBuffer_t * ) pvPortMalloc( uxSize );
212             configASSERT( xPacketBuffer != NULL );
213             vStreamBufferClear( xPacketBuffer );
214             xPacketBuffer->LENGTH = uxLength;
215         }
216 
217         if( pvProcessHandle == NULL )
218         {
219             pvProcessHandle = CreateThread( NULL, 0, prvWritePackets, NULL, CREATE_SUSPENDED, NULL );
220 
221             if( pvProcessHandle != NULL )
222             {
223                 SetThreadPriority( pvProcessHandle, dumpPROCESS_THREAD_PRIORITY );
224                 SetThreadPriorityBoost( pvProcessHandle, TRUE );
225                 SetThreadAffinityMask( pvProcessHandle, 0x0E );
226                 ResumeThread( pvProcessHandle );
227             }
228         }
229     }
230 /*-----------------------------------------------------------*/
231 
dump_packet(const uint8_t * pucBuffer,size_t uxLength,BaseType_t xIncoming)232     void dump_packet( const uint8_t * pucBuffer,
233                       size_t uxLength,
234                       BaseType_t xIncoming )
235     {
236         /* This function shall be called from a normal FreeRTOS task only. */
237         if( xPacketBuffer != NULL )
238         {
239             if( xDumpingReady == pdFALSE )
240             {
241                 size_t uxSpace = uxStreamBufferGetSpace( xPacketBuffer );
242                 size_t uxNeeded = uxLength + sizeof( size_t );
243 
244                 if( uxNeeded < uxSpace )
245                 {
246                     Bufferheader_t xheader;
247 
248                     xheader.uxLength = uxLength;
249                     xheader.bIncoming = xIncoming;
250                     uxStreamBufferAdd( xPacketBuffer, 0u, ( const uint8_t * ) &( xheader ), sizeof( xheader ) );
251                     uxStreamBufferAdd( xPacketBuffer, 0u, pucBuffer, uxLength );
252                 }
253                 else
254                 {
255                     /* Drop this packet. */
256                 }
257             }
258             else
259             {
260                 /* The Windows thread 'prvWritePackets()' had received enough packets.
261                  * The packet buffer may be freed. */
262                 vPortFree( xPacketBuffer );
263                 xPacketBuffer = NULL;
264             }
265         }
266     }
267 /*-----------------------------------------------------------*/
268 
prvWritePackets(LPVOID lpParameter)269     static DWORD WINAPI prvWritePackets( LPVOID lpParameter )
270     {
271         /* This is a Windows thread, not a FreeRTOS task. FreeRTOS API's may not be called. */
272         for( ; ; )
273         {
274             Sleep( 100 );
275 
276             while( ( xPacketBuffer != NULL ) && ( xDumpingReady == pdFALSE ) )
277             {
278                 Bufferheader_t xHeader;
279                 size_t uxBytes = uxStreamBufferGetSize( xPacketBuffer );
280 
281                 if( uxBytes <= sizeof( xHeader ) )
282                 {
283                     break;
284                 }
285 
286                 /* Peek the number of bytes available. */
287                 uxStreamBufferGet( xPacketBuffer, 0u, ( uint8_t * ) &( xHeader ), sizeof( xHeader ), pdTRUE );
288 
289                 if( uxBytes >= sizeof( xHeader ) + xHeader.uxLength )
290                 {
291                 }
292 
293                 {
294                     size_t xBytesRead;
295                     uint8_t pcBuffer[ ipconfigNETWORK_MTU ];
296                     size_t xActualCount;
297 
298                     uxStreamBufferGet( xPacketBuffer, 0u, NULL, sizeof( xHeader ), pdFALSE );
299                     xActualCount = uxStreamBufferGet( xPacketBuffer, 0u, pcBuffer, xHeader.uxLength, pdFALSE );
300                     vActualDump( pcBuffer, xActualCount, xHeader.bIncoming );
301                 }
302             }
303         }
304     }
305 /*-----------------------------------------------------------*/
306 
_fprintf(FILE * pxHandle,const char * pcFormat,...)307     static int _fprintf( FILE * pxHandle,
308                          const char * pcFormat,
309                          ... )
310     {
311         char pcString[ 255 ];
312         BaseType_t iCount;
313 
314         va_list args;
315 
316         va_start( args, pcFormat );
317         iCount = vsnprintf( pcString, sizeof pcString, pcFormat, args );
318         va_end( args );
319         fwrite( pcString, 1u, iCount, pxHandle );
320 
321         return iCount;
322     }
323 /*-----------------------------------------------------------*/
324 
vWriteHeaderFile(void)325     static void vWriteHeaderFile( void )
326     {
327         FILE * outfile;
328 
329         outfile = fopen( pcHeaderFileName, "w" );
330 
331         if( outfile != NULL )
332         {
333             fwrite( pcHeaderHeader, 1u, sizeof( pcHeaderHeader ) - 1u, outfile );
334             _fprintf( outfile, "#define dumpPACKET_COUNT %lu\n\n",
335                       ( uxNextPacketNumber < 1u ) ? 1u : uxNextPacketNumber );
336             _fprintf( outfile, "extern DumpPacket_t *xPacketList[ dumpPACKET_COUNT ];\n\n" );
337             _fprintf( outfile, "#endif PACKET_LIST_H\n" );
338 
339             fclose( outfile );
340         }
341     }
342 /*-----------------------------------------------------------*/
343 
vAddType(uint32_t ulFlags,const char * pcFlagName)344     static void vAddType( uint32_t ulFlags,
345                           const char * pcFlagName )
346     {
347         size_t uxLength = strlen( pcTypeString );
348         char pcString[ 64 ];
349         BaseType_t iCount;
350 
351         ulTypeMask |= ulFlags;
352 
353         if( uxLength == 0 )
354         {
355             snprintf( pcTypeString, sizeof pcTypeString, "%s", pcFlagName );
356         }
357         else
358         {
359             snprintf( pcTypeString + uxLength, sizeof pcTypeString - 1, " | %s", pcFlagName );
360         }
361     }
362 /*-----------------------------------------------------------*/
363 
vAddProtocolTags(uint8_t * pucEthernetBuffer,BaseType_t xIPType)364     static void vAddProtocolTags( uint8_t * pucEthernetBuffer,
365                                   BaseType_t xIPType )
366     {
367         ProtocolHeaders_t * pxProtocolHeaders;
368 
369         #if ( ipconfigUSE_IPv6 != 0 )
370             const IPHeader_IPv6_t * pxIPHeader_IPv6;
371         #endif
372         UBaseType_t uxHeaderLength;
373         uint8_t ucProtocol;
374         IPPacket_t * pxIPPacket;
375         IPHeader_t * pxIPHeader;
376 
377         pxIPPacket = ( IPPacket_t * ) pucEthernetBuffer;
378         pxIPHeader = &( pxIPPacket->xIPHeader );
379         #if ( ipconfigUSE_IPv6 != 0 )
380             pxIPHeader_IPv6 = ( const IPHeader_IPv6_t * ) &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] );
381 
382             if( pxIPPacket->xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE )
383             {
384                 uxHeaderLength = ipSIZE_OF_IPv6_HEADER;
385                 ucProtocol = pxIPHeader_IPv6->ucNextHeader;
386                 pxProtocolHeaders = ( ProtocolHeaders_t * ) &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER ] );
387             }
388             else
389         #endif
390         {
391             size_t uxLength = ( size_t ) pxIPHeader->ucVersionHeaderLength;
392 
393             /* Check if the IP headers are acceptable and if it has our destination.
394              * The lowest four bits of 'ucVersionHeaderLength' indicate the IP-header
395              * length in multiples of 4. */
396             uxHeaderLength = ( size_t ) ( ( uxLength & 0x0Fu ) << 2 );
397             ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
398             pxProtocolHeaders = ( ProtocolHeaders_t * ) &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxHeaderLength ] );
399         }
400 
401         switch( ucProtocol )
402         {
403             case ipPROTOCOL_ICMP:
404                 ADD_TYPE( ICMP4 );
405                 break;
406 
407                 #if ( ipconfigUSE_IPv6 != 0 )
408                     case ipPROTOCOL_ICMP_IPv6:
409                         ADD_TYPE( ICMP6 );
410                         break;
411                 #endif
412 
413             case ipPROTOCOL_UDP:
414                 ADD_TYPE( UDP );
415                 usSourcePort = pxProtocolHeaders->xUDPHeader.usSourcePort;
416                 usDestinationPort = pxProtocolHeaders->xUDPHeader.usDestinationPort;
417 
418                 if( usSourcePort == FreeRTOS_htons( dnsDNS_PORT ) )
419                 {
420                     ADD_TYPE( DNS );
421                     ADD_TYPE( REPLY );
422                 }
423                 else if( usDestinationPort == FreeRTOS_htons( dnsDNS_PORT ) )
424                 {
425                     ADD_TYPE( DNS );
426                     ADD_TYPE( REQUEST );
427                 }
428 
429                 break;
430 
431                 #if ipconfigUSE_TCP == 1
432                     case ipPROTOCOL_TCP:
433                         ADD_TYPE( TCP );
434                         usSourcePort = pxProtocolHeaders->xTCPHeader.usSourcePort;
435                         usDestinationPort = pxProtocolHeaders->xTCPHeader.usDestinationPort;
436 
437                         if( ( pxProtocolHeaders->xTCPHeader.ucTCPFlags & tcpTCP_FLAG_SYN ) != 0u )
438                         {
439                             ADD_TYPE( SYN );
440                         }
441 
442                         if( ( pxProtocolHeaders->xTCPHeader.ucTCPFlags & tcpTCP_FLAG_FIN ) != 0u )
443                         {
444                             ADD_TYPE( FIN );
445                         }
446 
447                         if( ( pxProtocolHeaders->xTCPHeader.ucTCPFlags & tcpTCP_FLAG_RST ) != 0u )
448                         {
449                             ADD_TYPE( RST );
450                         }
451 
452                         if( ( pxProtocolHeaders->xTCPHeader.ucTCPFlags & tcpTCP_FLAG_ACK ) != 0u )
453                         {
454                             ADD_TYPE( ACK );
455                         }
456                         break;
457                 #endif /* if ipconfigUSE_TCP == 1 */
458         }
459     }
460 /*-----------------------------------------------------------*/
461 
vDetermineMessageType(uint8_t * pucBuffer,BaseType_t xIncoming)462     static void vDetermineMessageType( uint8_t * pucBuffer,
463                                        BaseType_t xIncoming )
464     {
465         EthernetHeader_t * pxEthernetHeader;
466 
467         if( xIncoming != 0 )
468         {
469             ADD_TYPE( IN );
470         }
471         else
472         {
473             ADD_TYPE( OUT );
474         }
475 
476         pxEthernetHeader = ( EthernetHeader_t * ) pucBuffer;
477 
478         /* Interpret the received Ethernet packet. */
479         switch( pxEthernetHeader->usFrameType )
480         {
481             case ipARP_FRAME_TYPE:
482                {
483                    ARPPacket_t * pxARPFrame;
484                    ARPHeader_t * pxARPHeader;
485 
486                    /* The Ethernet frame contains an ARP packet. */
487                    ADD_TYPE( FRAME_ARP );
488                    pxARPFrame = ( ARPPacket_t * ) pucBuffer;
489                    pxARPHeader = &( pxARPFrame->xARPHeader );
490                    ADD_TYPE( ARP );
491 
492                    switch( pxARPHeader->usOperation )
493                    {
494                        case ipARP_REQUEST:
495                            ADD_TYPE( REQUEST );
496                            break;
497 
498                        case ipARP_REPLY:
499                            ADD_TYPE( REPLY );
500                            break;
501 
502                        default:
503                            ADD_TYPE( UNKNOWN );
504                            break;
505                    }
506                }
507                break;
508 
509             case ipIPv4_FRAME_TYPE:
510                 ADD_TYPE( FRAME_4 );
511                 vAddProtocolTags( pucBuffer, 4 );
512                 break;
513 
514                 #if ( ipconfigUSE_IPv6 != 0 )
515                     case ipIPv6_FRAME_TYPE:
516                         ADD_TYPE( FRAME_6 );
517                         vAddProtocolTags( pucBuffer, 6 );
518                         break;
519                 #endif
520             default:
521                 /* No other packet types are handled.  Nothing to do. */
522                 ADD_TYPE( Unknown_FRAME );
523                 break;
524         }
525     }
526 /*-----------------------------------------------------------*/
527 
vActualDump(uint8_t * pucBuffer,size_t uxLength,BaseType_t xIncoming)528     static void vActualDump( uint8_t * pucBuffer,
529                              size_t uxLength,
530                              BaseType_t xIncoming )
531     {
532         char pcString[ 513 ];
533         size_t uxOffset;
534         size_t uxIndex;
535         size_t uxCompleteCount = 0;
536         BaseType_t xUseIt = pdFALSE;
537 
538         usSourcePort = 0u;
539         usDestinationPort = 0u;
540         pcTypeString[ 0 ] = 0;
541         ulTypeMask = 0uL;
542 
543         if( pxCurrentEntries == NULL )
544         {
545             return;
546         }
547 
548         vDetermineMessageType( pucBuffer, xIncoming );
549 
550         for( uxIndex = 0; uxIndex < pxCurrentEntries->uxEntryCount; uxIndex++ )
551         {
552             if( pxCurrentEntries->xEntries[ uxIndex ].uxCount < pxCurrentEntries->xEntries[ uxIndex ].uxMax )
553             {
554                 uint32_t ulMask = pxCurrentEntries->xEntries[ uxIndex ].ulMask;
555 
556                 if( ( ulMask & ulTypeMask ) == ulMask )
557                 {
558                     pxCurrentEntries->xEntries[ uxIndex ].uxCount++;
559                     xUseIt = pdTRUE;
560                 }
561             }
562             else
563             {
564                 uxCompleteCount++;
565             }
566         }
567 
568         FreeRTOS_printf( ( "prvWritePackets: done %d/%d : (%d,%d) (%d,%d) (%d,%d) (%d,%d)\n",
569                            uxCompleteCount,
570                            pxCurrentEntries->uxEntryCount,
571                            pxCurrentEntries->xEntries[ 0 ].uxCount, pxCurrentEntries->xEntries[ 0 ].uxMax,
572                            pxCurrentEntries->xEntries[ 1 ].uxCount, pxCurrentEntries->xEntries[ 1 ].uxMax,
573                            pxCurrentEntries->xEntries[ 2 ].uxCount, pxCurrentEntries->xEntries[ 2 ].uxMax,
574                            pxCurrentEntries->xEntries[ 3 ].uxCount, pxCurrentEntries->xEntries[ 3 ].uxMax ) );
575 
576         if( uxCompleteCount >= pxCurrentEntries->uxEntryCount )
577         {
578             FreeRTOS_printf( ( "prvWritePackets: all %lu packets have been collected\n", pxCurrentEntries->uxEntryCount ) );
579 
580             if( pxCurrentEntries != NULL )
581             {
582                 FILE * outfile = fopen( pcCodeFileName, ( xFirstPacket != 0 ) ? "w" : "a+" );
583 
584                 if( outfile == NULL )
585                 {
586                     FreeRTOS_printf( ( "Can not create '%s'\n", pcCodeFileName ) );
587                 }
588                 else
589                 {
590                     /*
591                      *  Create a list with pointers to each network packet.
592                      *  DumpPacket_t *xPacketList[ dumpPACKET_COUNT ] =
593                      *  {
594                      *      &xPacket_0000,
595                      *      &xPacket_0001,
596                      *      &xPacket_0002,
597                      *      &xPacket_0003,
598                      *  }
599                      */
600                     _fprintf( outfile, "\nDumpPacket_t *xPacketList[ dumpPACKET_COUNT ] =\n{\n" );
601 
602                     for( uxIndex = 0; uxIndex < uxNextPacketNumber; uxIndex++ )
603                     {
604                         _fprintf( outfile, "\t&xPacket_%04lu,\n", uxIndex );
605                     }
606 
607                     _fprintf( outfile, "};\n" );
608                     fclose( outfile );
609                     vWriteHeaderFile();
610                 }
611 
612                 pxCurrentEntries = NULL;
613 
614                 /* Tell the thread and the function dump_packet() that packet
615                  * dumping is ready. */
616                 xDumpingReady = pdTRUE;
617             }
618 
619             return;
620         }
621 
622         if( xUseIt == pdFALSE )
623         {
624             return;
625         }
626 
627         printf( "prvWritePackets: Read %lu bytes, type %s\n", uxLength, pcTypeString );
628 
629         FILE * outfile = fopen( pcCodeFileName, ( xFirstPacket != 0 ) ? "w" : "a+" );
630 
631         if( outfile == NULL )
632         {
633             FreeRTOS_printf( ( "Can not create '%s'\n", pcCodeFileName ) );
634             return;
635         }
636 
637         if( xFirstPacket != 0 )
638         {
639             char * pcPtr;
640             size_t xLength;
641 
642             vWriteHeaderFile( pcHeaderFileName );
643             xLength = snprintf( pcString, sizeof pcString, pcHeaderCode, pcHeaderFileName );
644             fwrite( pcString, 1u, xLength, outfile );
645             xFirstPacket = pdFALSE;
646         }
647 
648         _fprintf( outfile, "\n/* Packet_%04d */\n", uxNextPacketNumber );
649         _fprintf( outfile, "uint8_t ucPacket_%04lx[ %lu ] =\n{\n", uxNextPacketNumber, uxLength );
650 
651         for( uxOffset = 0u; uxOffset < uxLength; )
652         {
653             size_t uxCurLength = 0u;
654             size_t uxLast = uxOffset + dumpBYTES_PER_ROW;
655             BaseType_t xFirst = pdTRUE;
656 
657             if( uxLast > uxLength )
658             {
659                 uxLast = uxLength;
660             }
661 
662             while( uxOffset < uxLast )
663             {
664                 uxCurLength += snprintf( pcString + uxCurLength, sizeof pcString - uxCurLength, "%s0x%02x",
665                                          ( uxCurLength == 0 ) ? "\t" : ", ", pucBuffer[ uxOffset ] );
666                 uxOffset++;
667             }
668 
669             if( uxCurLength != 0u )
670             {
671                 uxCurLength += snprintf( pcString + uxCurLength, sizeof pcString - uxCurLength, "%s\n",
672                                          ( uxOffset == uxLength ) ? "\n};" : "," );
673                 fwrite( pcString, 1u, uxCurLength, outfile );
674             }
675         }
676 
677         _fprintf( outfile, "\n" );
678 
679         _fprintf( outfile,
680                   "DumpPacket_t xPacket_%04lx =\n{\n"
681                   "\t.pucData = ucPacket_%04lx,\n"
682                   "\t.uxLength = %lu,\n"
683                   "\t.ulType = 0x%lX, /* %s */\n",
684                   uxNextPacketNumber, uxNextPacketNumber, uxLength, ulTypeMask, pcTypeString );
685 
686         if( usSourcePort != 0u )
687         {
688             _fprintf( outfile,
689                       "\t.usSource = %u,\n", FreeRTOS_ntohs( usSourcePort ) );
690         }
691 
692         if( usSourcePort != 0u )
693         {
694             _fprintf( outfile,
695                       "\t.usDestination = %u,\n", FreeRTOS_ntohs( usDestinationPort ) );
696         }
697 
698         _fprintf( outfile,
699                   "};\n"
700                   "/*-----------------------------------------------------------*/\n\n" );
701         fclose( outfile );
702         uxNextPacketNumber++;
703     }
704 /*-----------------------------------------------------------*/
705 
706 #endif /* ( ipconfigUSE_DUMP_PACKETS != 0 ) */
707