1 /* Standard includes. */
2 #include <stdint.h>
3 #include <stdio.h>
4
5 /* FreeRTOS includes. */
6 #include "FreeRTOS.h"
7 #include "task.h"
8 #include "queue.h"
9 #include "semphr.h"
10
11 /* FreeRTOS+TCP includes. */
12 #include "FreeRTOS_UDP_IP.h"
13 #include "FreeRTOS_IP.h"
14 #include "FreeRTOS_Sockets.h"
15 #include "FreeRTOS_IP_Private.h"
16 #include "FreeRTOS_DNS.h"
17 #include "NetworkBufferManagement.h"
18
19 #include "cbmc.h"
20
21 /****************************************************************
22 * This is a collection of abstractions of methods in the FreeRTOS TCP
23 * API. The abstractions simply perform minimal validation of
24 * function arguments, and return unconstrained values of the
25 * appropriate type.
26 ****************************************************************/
27
28 /****************************************************************
29 * Abstract FreeRTOS_socket.
30 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/socket.html
31 *
32 * We stub out this function to do nothing but allocate space for a
33 * socket containing unconstrained data or return an error.
34 ****************************************************************/
35
FreeRTOS_socket(BaseType_t xDomain,BaseType_t xType,BaseType_t xProtocol)36 Socket_t FreeRTOS_socket( BaseType_t xDomain,
37 BaseType_t xType,
38 BaseType_t xProtocol )
39 {
40 if( nondet_bool() )
41 {
42 return FREERTOS_INVALID_SOCKET;
43 }
44 else
45 {
46 void * ptr = malloc( sizeof( struct xSOCKET ) );
47 __CPROVER_assume( ptr != NULL );
48 return ptr;
49 }
50 }
51
52 /****************************************************************
53 * Abstract FreeRTOS_setsockopt.
54 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/setsockopt.html
55 ****************************************************************/
56
FreeRTOS_setsockopt(Socket_t xSocket,int32_t lLevel,int32_t lOptionName,const void * pvOptionValue,size_t uxOptionLength)57 BaseType_t FreeRTOS_setsockopt( Socket_t xSocket,
58 int32_t lLevel,
59 int32_t lOptionName,
60 const void * pvOptionValue,
61 size_t uxOptionLength )
62 {
63 __CPROVER_assert( xSocket != NULL,
64 "FreeRTOS precondition: xSocket != NULL" );
65 __CPROVER_assert( pvOptionValue != NULL,
66 "FreeRTOS precondition: pvOptionValue != NULL" );
67 return nondet_BaseType();
68 }
69
70 /****************************************************************
71 * Abstract FreeRTOS_closesocket.
72 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/close.html
73 ****************************************************************/
74
FreeRTOS_closesocket(Socket_t xSocket)75 BaseType_t FreeRTOS_closesocket( Socket_t xSocket )
76 {
77 __CPROVER_assert( xSocket != NULL,
78 "FreeRTOS precondition: xSocket != NULL" );
79 return nondet_BaseType();
80 }
81
82 /****************************************************************
83 * Abstract FreeRTOS_bind.
84 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/bind.html
85 ****************************************************************/
86
FreeRTOS_bind(Socket_t xSocket,struct freertos_sockaddr * pxAddress,socklen_t xAddressLength)87 BaseType_t FreeRTOS_bind( Socket_t xSocket,
88 struct freertos_sockaddr * pxAddress,
89 socklen_t xAddressLength )
90 {
91 __CPROVER_assert( xSocket != NULL,
92 "FreeRTOS precondition: xSocket != NULL" );
93 __CPROVER_assert( pxAddress != NULL,
94 "FreeRTOS precondition: pxAddress != NULL" );
95 return nondet_BaseType();
96 }
97
98 /****************************************************************
99 * Abstract FreeRTOS_inet_addr.
100 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/inet_addr.html
101 ****************************************************************/
102
FreeRTOS_inet_addr(const char * pcIPAddress)103 uint32_t FreeRTOS_inet_addr( const char * pcIPAddress )
104 {
105 __CPROVER_assert( pcIPAddress != NULL,
106 "FreeRTOS precondition: pcIPAddress != NULL" );
107 return nondet_uint32();
108 }
109
110 /****************************************************************
111 * Abstract FreeRTOS_recvfrom.
112 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/recvfrom.html
113 *
114 * We stub out this function to do nothing but allocate a buffer of
115 * unconstrained size containing unconstrained data and return the
116 * size (or return the size 0 if the allocation fails).
117 ****************************************************************/
118
FreeRTOS_recvfrom(Socket_t xSocket,void * pvBuffer,size_t uxBufferLength,BaseType_t xFlags,struct freertos_sockaddr * pxSourceAddress,socklen_t * pxSourceAddressLength)119 int32_t FreeRTOS_recvfrom( Socket_t xSocket,
120 void * pvBuffer,
121 size_t uxBufferLength,
122 BaseType_t xFlags,
123 struct freertos_sockaddr * pxSourceAddress,
124 socklen_t * pxSourceAddressLength )
125
126 {
127 /****************************************************************
128 * "If the zero copy calling semantics are used (the ulFlags
129 * parameter does not have the FREERTOS_ZERO_COPY bit set) then
130 * pvBuffer does not point to a buffer and xBufferLength is not
131 * used." This is from the documentation.
132 ****************************************************************/
133 __CPROVER_assert( xFlags & FREERTOS_ZERO_COPY, "I can only do ZERO_COPY" );
134
135 __CPROVER_assert( pvBuffer != NULL,
136 "FreeRTOS precondition: pvBuffer != NULL" );
137
138 /****************************************************************
139 * TODO: We need to check this out.
140 *
141 * The code calls recvfrom with these parameters NULL, it is not
142 * clear from the documentation that this is allowed.
143 ****************************************************************/
144 #if 0
145 __CPROVER_assert( pxSourceAddress != NULL,
146 "FreeRTOS precondition: pxSourceAddress != NULL" );
147 __CPROVER_assert( pxSourceAddressLength != NULL,
148 "FreeRTOS precondition: pxSourceAddress != NULL" );
149 #endif
150
151 size_t payload_size;
152 __CPROVER_assume( payload_size + sizeof( UDPPacket_t )
153 < CBMC_MAX_OBJECT_SIZE );
154
155 /****************************************************************
156 * TODO: We need to make this lower bound explicit in the Makefile.json
157 *
158 * DNSMessage_t is a typedef in FreeRTOS_DNS.c
159 * sizeof(DNSMessage_t) = 6 * sizeof(uint16_t)
160 ****************************************************************/
161 __CPROVER_assume( payload_size >= 6 * sizeof( uint16_t ) );
162
163 #ifdef CBMC_FREERTOS_RECVFROM_BUFFER_BOUND
164 __CPROVER_assume( payload_size <= CBMC_FREERTOS_RECVFROM_BUFFER_BOUND );
165 #endif
166
167 uint32_t buffer_size = payload_size + sizeof( UDPPacket_t );
168 uint8_t * buffer = safeMalloc( buffer_size );
169
170 if( buffer == NULL )
171 {
172 buffer_size = 0;
173 }
174 else
175 {
176 buffer = buffer + sizeof( UDPPacket_t );
177 buffer_size = buffer_size - sizeof( UDPPacket_t );
178 }
179
180 *( ( uint8_t ** ) pvBuffer ) = buffer;
181 return buffer_size;
182 }
183
184 /****************************************************************
185 * Abstract FreeRTOS_recvfrom.
186 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/sendto.html
187 ****************************************************************/
188
FreeRTOS_sendto(Socket_t xSocket,const void * pvBuffer,size_t uxTotalDataLength,BaseType_t xFlags,const struct freertos_sockaddr * pxDestinationAddress,socklen_t xDestinationAddressLength)189 int32_t FreeRTOS_sendto( Socket_t xSocket,
190 const void * pvBuffer,
191 size_t uxTotalDataLength,
192 BaseType_t xFlags,
193 const struct freertos_sockaddr * pxDestinationAddress,
194 socklen_t xDestinationAddressLength )
195 {
196 __CPROVER_assert( xSocket != NULL,
197 "FreeRTOS precondition: xSocket != NULL" );
198 __CPROVER_assert( pvBuffer != NULL,
199 "FreeRTOS precondition: pvBuffer != NULL" );
200 __CPROVER_assert( pxDestinationAddress != NULL,
201 "FreeRTOS precondition: pxDestinationAddress != NULL" );
202 return nondet_int32();
203 }
204
205 /****************************************************************
206 * Abstract FreeRTOS_GetUDPPayloadBuffer
207 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/FreeRTOS_GetUDPPayloadBuffer.html
208 *
209 * We stub out this function to do nothing but allocate a buffer of
210 * unconstrained size containing unconstrained data and return a
211 * pointer to the buffer (or NULL).
212 ****************************************************************/
213
FreeRTOS_GetUDPPayloadBuffer_Multi(size_t uxRequestedSizeBytes,TickType_t uxBlockTimeTicks,uint8_t ucIPType)214 void * FreeRTOS_GetUDPPayloadBuffer_Multi( size_t uxRequestedSizeBytes,
215 TickType_t uxBlockTimeTicks,
216 uint8_t ucIPType )
217 {
218 size_t size;
219
220 __CPROVER_assume( size < CBMC_MAX_OBJECT_SIZE );
221 __CPROVER_assume( size >= sizeof( UDPPacket_t ) );
222
223 uint8_t * buffer = safeMalloc( size );
224
225 return buffer == NULL ? buffer : buffer + sizeof( UDPPacket_t );
226 }
227
228 /****************************************************************
229 * Abstract FreeRTOS_ReleaseUDPPayloadBuffer
230 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/FreeRTOS_ReleaseUDPPayloadBuffer.html
231 ****************************************************************/
232
FreeRTOS_ReleaseUDPPayloadBuffer(void * pvBuffer)233 void FreeRTOS_ReleaseUDPPayloadBuffer( void * pvBuffer )
234 {
235 __CPROVER_assert( pvBuffer != NULL,
236 "FreeRTOS precondition: pvBuffer != NULL" );
237 __CPROVER_assert( __CPROVER_POINTER_OFFSET( pvBuffer )
238 == sizeof( UDPPacket_t ),
239 "FreeRTOS precondition: pvBuffer offset" );
240
241 free( pvBuffer - sizeof( UDPPacket_t ) );
242 }
243
244 /****************************************************************
245 * Abstract pxGetNetworkBufferWithDescriptor.
246 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/pxGetNetworkBufferWithDescriptor.html
247 *
248 * The real allocator take buffers off a list.
249 ****************************************************************/
250
251 uint32_t GetNetworkBuffer_failure_count;
252
pxGetNetworkBufferWithDescriptor(size_t xRequestedSizeBytes,TickType_t xBlockTimeTicks)253 NetworkBufferDescriptor_t * pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes,
254 TickType_t xBlockTimeTicks )
255 {
256 __CPROVER_assert(
257 xRequestedSizeBytes + ipBUFFER_PADDING < CBMC_MAX_OBJECT_SIZE,
258 "pxGetNetworkBufferWithDescriptor: request too big" );
259
260 /*
261 * The semantics of this function is to wait until a buffer with
262 * at least the requested number of bytes becomes available. If a
263 * timeout occurs before the buffer is available, then return a
264 * NULL pointer.
265 */
266
267 NetworkBufferDescriptor_t * desc = safeMalloc( sizeof( *desc ) );
268
269 #ifdef CBMC_GETNETWORKBUFFER_FAILURE_BOUND
270
271 /*
272 * This interprets the failure bound as being one greater than the
273 * actual number of times GetNetworkBuffer should be allowed to
274 * fail.
275 *
276 * This makes it possible to use the same bound for loop unrolling
277 * which must be one greater than the actual number of times the
278 * loop should be unwound.
279 *
280 * NOTE: Using this bound with --nondet-static requires setting
281 * (or assuming) GetNetworkBuffer_failure_count to a value (like 0)
282 * in the proof harness that won't induce an integer overflow.
283 */
284 GetNetworkBuffer_failure_count++;
285 __CPROVER_assume(
286 IMPLIES(
287 GetNetworkBuffer_failure_count >= CBMC_GETNETWORKBUFFER_FAILURE_BOUND,
288 desc != NULL ) );
289 #endif
290
291 if( desc != NULL )
292 {
293 /*
294 * We may want to experiment with allocating space other than
295 * (more than) the exact amount of space requested.
296 */
297
298 size_t size = xRequestedSizeBytes;
299 __CPROVER_assume( size < CBMC_MAX_OBJECT_SIZE );
300
301 desc->pucEthernetBuffer = safeMalloc( size );
302 desc->xDataLength = desc->pucEthernetBuffer == NULL ? 0 : size;
303
304 #ifdef CBMC_REQUIRE_NETWORKBUFFER_ETHERNETBUFFER_NONNULL
305 /* This may be implied by the semantics of the function. */
306 __CPROVER_assume( desc->pucEthernetBuffer != NULL );
307 #endif
308
309 /* Allow method to fail again next time */
310 GetNetworkBuffer_failure_count = 0;
311 }
312
313 return desc;
314 }
315
316 /****************************************************************
317 * Abstract pxGetNetworkBufferWithDescriptor.
318 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/vReleaseNetworkBufferAndDescriptor.html
319 ****************************************************************/
320
vReleaseNetworkBufferAndDescriptor(NetworkBufferDescriptor_t * const pxNetworkBuffer)321 void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
322 {
323 __CPROVER_assert( pxNetworkBuffer != NULL,
324 "Precondition: pxNetworkBuffer != NULL" );
325
326 if( pxNetworkBuffer->pucEthernetBuffer != NULL )
327 {
328 free( pxNetworkBuffer->pucEthernetBuffer );
329 }
330
331 free( pxNetworkBuffer );
332 }
333
334 /****************************************************************
335 * Abstract FreeRTOS_GetAddressConfiguration
336 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/FreeRTOS_GetAddressConfiguration.html
337 ****************************************************************/
338
FreeRTOS_GetAddressConfiguration(uint32_t * pulIPAddress,uint32_t * pulNetMask,uint32_t * pulGatewayAddress,uint32_t * pulDNSServerAddress)339 void FreeRTOS_GetAddressConfiguration( uint32_t * pulIPAddress,
340 uint32_t * pulNetMask,
341 uint32_t * pulGatewayAddress,
342 uint32_t * pulDNSServerAddress )
343 {
344 if( pulIPAddress != NULL )
345 {
346 *pulIPAddress = nondet_unint32();
347 }
348
349 if( pulNetMask != NULL )
350 {
351 *pulNetMask = nondet_unint32();
352 }
353
354 if( pulGatewayAddress != NULL )
355 {
356 *pulGatewayAddress = nondet_unint32();
357 }
358
359 if( pulDNSServerAddress != NULL )
360 {
361 *pulDNSServerAddress = nondet_unint32();
362 }
363 }
364
365 /****************************************************************/
366
367 /****************************************************************
368 * This is a collection of methods that are defined by the user
369 * application but are invoked by the FreeRTOS API.
370 ****************************************************************/
371
372 /****************************************************************
373 * Abstract FreeRTOS_GetAddressConfiguration
374 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/API/vApplicationIPNetworkEventHook.html
375 ****************************************************************/
376
vApplicationIPNetworkEventHook(eIPCallbackEvent_t eNetworkEvent)377 void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
378 {
379 }
380
381 /****************************************************************
382 * Abstract pcApplicationHostnameHook
383 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html
384 ****************************************************************/
385
pcApplicationHostnameHook(void)386 const char * pcApplicationHostnameHook( void )
387 {
388 return "hostname";
389 }
390
391 /****************************************************************/
392
393
394 /****************************************************************
395 * Abstract xNetworkInterfaceOutput
396 * https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Porting.html#xNetworkInterfaceOutput
397 ****************************************************************/
xNetworkInterfaceOutput(NetworkBufferDescriptor_t * const pxNetworkBuffer,BaseType_t bReleaseAfterSend)398 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer,
399 BaseType_t bReleaseAfterSend )
400 {
401 __CPROVER_assert( pxNetworkBuffer != NULL, "The networkbuffer cannot be NULL" );
402
403 BaseType_t xReturn;
404
405 /* Return some random value. */
406 return xReturn;
407 }
408
409 /****************************************************************/
410