1 /*
2 * coreMQTT Agent v1.1.0
3 * Copyright (C) 2021 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
23 /**
24 * @file mqtt_agent_cbmc_state.c
25 * @brief Implements the functions defined in mqtt_agent_cbmc_state.h.
26 */
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include "core_mqtt_agent.h"
30 #include "mqtt_agent_cbmc_state.h"
31 #include "network_interface_stubs.h"
32 #include "get_time_stub.h"
33 #include "incoming_publish_callback_stub.h"
34 #include "agent_message_stubs.h"
35 #include "agent_command_pool_stubs.h"
36
commandCompleteCallbackStub(void * pCmdCallbackContext,MQTTAgentReturnInfo_t * pReturnInfo)37 static void commandCompleteCallbackStub( void * pCmdCallbackContext,
38 MQTTAgentReturnInfo_t * pReturnInfo )
39 {
40 __CPROVER_assert( pReturnInfo != NULL,
41 "Command complete return info is not NULL." );
42 }
43
allocateMqttFixedBuffer(MQTTFixedBuffer_t * pFixedBuffer)44 MQTTFixedBuffer_t * allocateMqttFixedBuffer( MQTTFixedBuffer_t * pFixedBuffer )
45 {
46 if( pFixedBuffer == NULL )
47 {
48 pFixedBuffer = malloc( sizeof( MQTTFixedBuffer_t ) );
49 }
50
51 if( pFixedBuffer != NULL )
52 {
53 __CPROVER_assume( pFixedBuffer->size < CBMC_MAX_OBJECT_SIZE );
54 pFixedBuffer->pBuffer = malloc( pFixedBuffer->size );
55 }
56
57 return pFixedBuffer;
58 }
59
isValidMqttFixedBuffer(const MQTTFixedBuffer_t * pFixedBuffer)60 bool isValidMqttFixedBuffer( const MQTTFixedBuffer_t * pFixedBuffer )
61 {
62 bool isValid = false;
63
64 if( pFixedBuffer != NULL )
65 {
66 isValid = pFixedBuffer->size < CBMC_MAX_OBJECT_SIZE;
67 }
68
69 return isValid;
70 }
71
allocateMqttAgentContext(MQTTAgentContext_t * pContext)72 MQTTAgentContext_t * allocateMqttAgentContext( MQTTAgentContext_t * pContext )
73 {
74 TransportInterface_t * pTransportInterface;
75 MQTTFixedBuffer_t * pNetworkBuffer;
76 MQTTAgentMessageInterface_t * pMessageInterface;
77 MQTTStatus_t status = MQTTSuccess;
78 void * pIncomingCallbackContext;
79
80 if( pContext == NULL )
81 {
82 pContext = malloc( sizeof( MQTTAgentContext_t ) );
83 }
84
85 pTransportInterface = malloc( sizeof( TransportInterface_t ) );
86
87 if( pTransportInterface != NULL )
88 {
89 /* The possibility that recv and send callbacks are NULL is tested in the
90 * MQTT_Init proof. MQTT_Init is required to be called before any other
91 * function in core_mqtt.h. */
92 pTransportInterface->recv = NetworkInterfaceReceiveStub;
93 pTransportInterface->send = NetworkInterfaceSendStub;
94 }
95
96 pNetworkBuffer = allocateMqttFixedBuffer( NULL );
97 __CPROVER_assume( isValidMqttFixedBuffer( pNetworkBuffer ) );
98
99 pMessageInterface = malloc( sizeof( MQTTAgentMessageInterface_t ) );
100
101 if( pMessageInterface != NULL )
102 {
103 pMessageInterface->send = AgentMessageSendStub;
104 pMessageInterface->recv = AgentMessageRecvStub;
105 pMessageInterface->getCommand = AgentGetCommandStub;
106 pMessageInterface->releaseCommand = Agent_ReleaseCommand;
107 }
108
109 /* It is part of the API contract to call MQTT_Init() with the MQTTContext_t
110 * before any other function in core_mqtt.h. */
111 if( pContext != NULL )
112 {
113 status = MQTTAgent_Init( pContext,
114 pMessageInterface,
115 pNetworkBuffer,
116 pTransportInterface,
117 GetCurrentTimeStub,
118 IncomingPublishCallbackStub,
119 pIncomingCallbackContext );
120 }
121
122 /* If the MQTTAgentContext_t initialization failed, then set the context to NULL
123 * so that function under harness will return immediately upon a NULL
124 * parameter check. */
125 if( status != MQTTSuccess )
126 {
127 pContext = NULL;
128 }
129
130 return pContext;
131 }
132
isValidMqttAgentContext(const MQTTAgentContext_t * pContext)133 bool isValidMqttAgentContext( const MQTTAgentContext_t * pContext )
134 {
135 bool isValid = false;
136
137 if( pContext != NULL )
138 {
139 isValid = isValidMqttFixedBuffer( &( pContext->mqttContext.networkBuffer ) );
140 }
141
142 return isValid;
143 }
144
isAgentSendCommandFunctionStatus(MQTTStatus_t mqttStatus)145 bool isAgentSendCommandFunctionStatus( MQTTStatus_t mqttStatus )
146 {
147 return( ( mqttStatus == MQTTSuccess ) ||
148 ( mqttStatus == MQTTBadParameter ) ||
149 ( mqttStatus == MQTTNoMemory ) ||
150 ( mqttStatus == MQTTSendFailed ) );
151 }
152
allocateConnectArgs(MQTTAgentConnectArgs_t * pConnectArgs)153 MQTTAgentConnectArgs_t * allocateConnectArgs( MQTTAgentConnectArgs_t * pConnectArgs )
154 {
155 if( pConnectArgs == NULL )
156 {
157 pConnectArgs = malloc( sizeof( MQTTAgentConnectArgs_t ) );
158 __CPROVER_assume( pConnectArgs != NULL );
159 }
160
161 pConnectArgs->pConnectInfo = malloc( sizeof( MQTTConnectInfo_t ) );
162 __CPROVER_assume( pConnectArgs->pConnectInfo != NULL );
163 pConnectArgs->pWillInfo = malloc( sizeof( MQTTPublishInfo_t ) );
164
165 return pConnectArgs;
166 }
167
addPendingAcks(MQTTAgentContext_t * pContext)168 void addPendingAcks( MQTTAgentContext_t * pContext )
169 {
170 uint8_t i;
171 uint16_t packetId;
172 MQTTAgentCommand_t * pCommand;
173 MQTTPublishInfo_t * pPublishInfo;
174
175 __CPROVER_assert( pContext != NULL, "MQTT Agent Context is not NULL" );
176
177 for( i = 0; i < MQTT_AGENT_MAX_OUTSTANDING_ACKS; i++ )
178 {
179 #ifdef MAX_PACKET_ID
180
181 /* Limit the packet Ids so that the range of packet ids retrieved through
182 * MQTT_PublishToResend can be limited as well. */
183 __CPROVER_assume( packetId < MAX_PACKET_ID );
184 #endif
185 pContext->pPendingAcks[ i ].packetId = packetId;
186
187 /* Add a publish command. */
188 pCommand = malloc( sizeof( MQTTAgentCommand_t ) );
189 __CPROVER_assume( pCommand != NULL );
190
191 pCommand->commandType = MQTT_PACKET_TYPE_PUBLISH;
192
193 /* Add Publish Info. */
194 pPublishInfo = malloc( sizeof( MQTTPublishInfo_t ) );
195 __CPROVER_assume( pPublishInfo != NULL );
196 pCommand->pArgs = pPublishInfo;
197
198 pCommand->pCommandCompleteCallback = commandCompleteCallbackStub;
199
200 pContext->pPendingAcks[ i ].pOriginalCommand = pCommand;
201 }
202 }
203
allocateSubscribeArgs(MQTTAgentSubscribeArgs_t * pSubscribeArgs)204 MQTTAgentSubscribeArgs_t * allocateSubscribeArgs( MQTTAgentSubscribeArgs_t * pSubscribeArgs )
205 {
206 if( pSubscribeArgs == NULL )
207 {
208 pSubscribeArgs = malloc( sizeof( MQTTAgentSubscribeArgs_t ) );
209 __CPROVER_assume( pSubscribeArgs != NULL );
210 }
211
212 pSubscribeArgs->pSubscribeInfo = malloc( sizeof( MQTTSubscribeInfo_t ) );
213 __CPROVER_assume( pSubscribeArgs->pSubscribeInfo != NULL );
214
215 return pSubscribeArgs;
216 }
217