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 * Driver code:
8 * Copyright (C) Nicholas J. Kinar <n.kinar@usask.ca>, Centre for Hydrology, University of Saskatchewan
9 *
10 * MSP432 Driverlib (C) 2017-2019 Texas Instruments Incorporated <https://www.ti.com/>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy of
13 * this software and associated documentation files (the "Software"), to deal in
14 * the Software without restriction, including without limitation the rights to
15 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
16 * the Software, and to permit persons to whom the Software is furnished to do so,
17 * subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in all
20 * copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
25 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
26 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * http://aws.amazon.com/freertos
30 * http://www.FreeRTOS.org
31 */
32
33 #include <stdint.h>
34
35 #include "FreeRTOS.h"
36 #include "FreeRTOS_IP.h"
37 #include "FreeRTOS_IP_private.h"
38 #include "FreeRTOS_Sockets.h"
39
40 #include "NetworkMiddleware.h"
41 #include "NetworkInterface.h"
42
43 /* Waiting time between network EMAC hardware up and down */
44 #define TIME_TO_WAIT_BETWEEN_NETUP_DOWN 2000
45
46 /* Stack for up and down thread */
47 #define NETWORK_TASK_MIDDLEWARE_STACK 1000
48
49 /* Holds the device name used for LLMNR */
50 static char DEV_NAME[ MAX_NAME_LLMNR ];
51
52 /* This function is provided by external code to obtain a random number */
53 extern uint32_t obtain_rand32();
54
55 static SemaphoreHandle_t xSemaphore = NULL;
56 static TaskHandle_t xTaskToNotifyReset = NULL;
57 static uint32_t xDelay;
58
59 static void prvNetworkResetTask( void * pvParameters );
60
61
62 /* Call this function before starting the scheduler and after the MAC address and device name has been loaded.
63 * The function can only be called once to set up the tasks. */
vPublicSetupFreeRTOSTasks(const struct InternalNetworkMiddlewareData data)64 void vPublicSetupFreeRTOSTasks( const struct InternalNetworkMiddlewareData data )
65 {
66 /* setup a device name */
67 vPublicSetupDeviceName( data.deviceName );
68
69 /* get the MAC address from the driver code (assuming this is also set up) */
70 uint8_t uc8MACAddr[ ipMAC_ADDRESS_LENGTH_BYTES ];
71 vPublicGetMACAddr( uc8MACAddr );
72
73 /* set up the task to reset the network every so often */
74 if( data.resetNetworkTaskRunning == pdTRUE )
75 {
76 xDelay = data.resetNetworkTaskEveryXSeconds;
77 xSemaphore = xSemaphoreCreateMutex();
78 xTaskCreate( prvNetworkResetTask,
79 "resetNet",
80 NETWORK_TASK_MIDDLEWARE_STACK,
81 NULL,
82 tskIDLE_PRIORITY,
83 &xTaskToNotifyReset );
84 }
85
86 /* init the network stack */
87 FreeRTOS_IPInit( data.ucIPAddress,
88 data.ucNetMask,
89 data.ucGatewayAddress,
90 data.ucDNSServerAddress,
91 uc8MACAddr );
92 }
93
94
95 /* Helper function to assign bytes to an array used to indicate the IP address */
vConvertOctetsToAddr(uint8_t arr[ipIP_ADDRESS_LENGTH_BYTES],uint8_t b0,uint8_t b1,uint8_t b2,uint8_t b3)96 void vConvertOctetsToAddr( uint8_t arr[ ipIP_ADDRESS_LENGTH_BYTES ],
97 uint8_t b0,
98 uint8_t b1,
99 uint8_t b2,
100 uint8_t b3 )
101 {
102 arr[ 0 ] = b0;
103 arr[ 1 ] = b1;
104 arr[ 2 ] = b2;
105 arr[ 3 ] = b3;
106 } /* end */
107
108
109 /* Task that resets the network every so often */
prvNetworkResetTask(void * pvParameters)110 void prvNetworkResetTask( void * pvParameters )
111 {
112 uint32_t cnt;
113
114 cnt = 0;
115
116 for( ; ; )
117 {
118 vTaskDelay( pdMS_TO_TICKS( 1000 ) );
119 cnt++;
120
121 if( cnt > xDelay )
122 {
123 cnt = 0;
124
125 if( xSemaphoreTake( xSemaphore, 0 ) == pdTRUE )
126 {
127 FreeRTOS_NetworkDown();
128 xSemaphoreGive( xSemaphore );
129 }
130 }
131 }
132 }
133
134
135 /* Call this function from a task to prevent a network reset during a critical section of the code */
publicPreventNetworkReset(const BaseType_t preventReset,const uint32_t waitTime)136 BaseType_t publicPreventNetworkReset( const BaseType_t preventReset,
137 const uint32_t waitTime )
138 {
139 if( preventReset == pdTRUE )
140 {
141 if( xSemaphoreTake( xSemaphore, pdMS_TO_TICKS( waitTime ) ) == pdTRUE )
142 {
143 return pdTRUE;
144 }
145 else
146 {
147 return pdFALSE;
148 }
149 }
150 else /* do not prevent reset */
151 {
152 xSemaphoreGive( xSemaphore );
153 }
154
155 return pdTRUE;
156 }
157
158
159 /* CALLED BY FREERTOS
160 * Function that sets pulNumber to a random number, and then returns pdTRUE.
161 * If the random number could not be obtained, then the function will return pdFALSE. */
xApplicationGetRandomNumber(uint32_t * pulNumber)162 BaseType_t xApplicationGetRandomNumber( uint32_t * pulNumber )
163 {
164 *pulNumber = 0;
165 uint32_t num = obtain_rand32();
166
167 if( num == 0 )
168 {
169 return pdFALSE;
170 }
171
172 *pulNumber = num;
173 return pdTRUE;
174 }
175
176 /* CALLED BY FREERTOS
177 * Function that returns a random number for TCP. This is taken to be a random number. */
ulApplicationGetNextSequenceNumber(uint32_t ulSourceAddress,uint16_t usSourcePort,uint32_t ulDestinationAddress,uint16_t usDestinationPort)178 uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,
179 uint16_t usSourcePort,
180 uint32_t ulDestinationAddress,
181 uint16_t usDestinationPort )
182 {
183 uint32_t pulNumber = 0;
184
185 xApplicationGetRandomNumber( &pulNumber );
186 return pulNumber;
187 }
188
189
190 /* CALLED BY FREERTOS
191 * Function to obtain random number */
uxRand()192 UBaseType_t uxRand()
193 {
194 uint32_t num = obtain_rand32();
195
196 return num;
197 }
198
199
200 /* CALLED BY FREERTOS
201 * Function called when the network connects or disconnects */
vApplicationIPNetworkEventHook(eIPCallbackEvent_t eNetworkEvent)202 void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
203 {
204 uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress;
205 static BaseType_t xNetworkTasksAlreadyCreated = pdFALSE;
206 char cBuffer[ 16 ];
207
208 if( eNetworkEvent == eNetworkUp )
209 {
210 if( xNetworkTasksAlreadyCreated == pdFALSE )
211 {
212 /* Unblock any necessary tasks here when the network is up
213 * Set a flag to indicate that the tasks do not need to be created again */
214 xNetworkTasksAlreadyCreated = pdTRUE;
215 }
216
217 FreeRTOS_GetAddressConfiguration( &ulIPAddress,
218 &ulNetMask,
219 &ulGatewayAddress,
220 &ulDNSServerAddress );
221
222 FreeRTOS_inet_ntoa( ulIPAddress, cBuffer );
223 vLoggingPrintf( "IP Address: %s\r\n", cBuffer );
224
225 FreeRTOS_inet_ntoa( ulNetMask, cBuffer );
226 vLoggingPrintf( "Subnet Mask: %s\r\n", cBuffer );
227
228 FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer );
229 vLoggingPrintf( "Gateway IP Address: %s\r\n", cBuffer );
230
231 FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer );
232 vLoggingPrintf( "DNS server IP Address: %s\r\n", cBuffer );
233 } /* end if */
234 else if( eNetworkEvent == eNetworkDown )
235 {
236 xNetworkTasksAlreadyCreated = pdFALSE; /* clear a flag to indicate that the tasks needs to be created again */
237 /* Stop or block any running tasks here */
238 } /* end if */
239 } /* end */
240
241
242 /* CALLED BY FREERTOS
243 * Function that indicates there is a ping response
244 * Called from IPTraceMacroDefaults.h
245 * NOTE: This function can cause the stack to slow down, so it should
246 * only be used for debugging. */
247
248 /*
249 #ifndef iptraceSENDING_PING_REPLY
250 * extern void pingReply( uint32_t ulIPAddress );
251 #define iptraceSENDING_PING_REPLY( ulIPAddress ) pingReply(ulIPAddress )
252 #endif
253 */
pingReply(uint32_t ulIPAddress)254 void pingReply( uint32_t ulIPAddress )
255 {
256 #ifdef SEND_PING_PRINT_REPLY
257 char cBuffer[ 16 ];
258 FreeRTOS_inet_ntoa( ulIPAddress, cBuffer );
259 vLoggingPrintf( "Ping response to: %s\r\n", cBuffer );
260 #endif
261 }
262
263
264 /* CALLED BY FREERTOS when conducting a DNS query
265 * Function that returns pdTRUE if the pcName matches the LLMNR node name */
xApplicationDNSQueryHook(const char * pcName)266 BaseType_t xApplicationDNSQueryHook( const char * pcName )
267 {
268 if( strcmp( pcName, DEV_NAME ) )
269 {
270 return pdTRUE;
271 }
272
273 return pdFALSE;
274 }
275
276
277 /* CALLED BY FREERTOS
278 * Hook to return a human-readable name */
pcApplicationHostnameHook(void)279 const char * pcApplicationHostnameHook( void )
280 {
281 const char * name;
282
283 name = DEV_NAME;
284 return name;
285 }
286
287
288 /* Call this function to assign a device name before the stack is up */
vPublicSetupDeviceName(const char * deviceName)289 void vPublicSetupDeviceName( const char * deviceName )
290 {
291 memset( DEV_NAME, 0, sizeof( DEV_NAME ) );
292 strncpy( DEV_NAME, deviceName, MAX_NAME_LLMNR - 1 );
293 }
294