Merge branch 'resource-container'
[platform/upstream/iotivity.git] / resource / csdk / routing / src / routingutility.c
1 /* ****************************************************************
2  *
3  * Copyright 2015 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************/
20
21 #include <stdio.h>
22 #include <string.h>
23 #include "routingutility.h"
24 #include "routingmanager.h"
25 #include "oic_malloc.h"
26 #include "include/logger.h"
27
28 /**
29  * Logging tag for module name.
30  */
31 #define TAG "OIC_RM_UTIL"
32
33 /**
34  * Tag for printing the logs of forwarding the packet.
35  */
36 #define RM_TAG "OIC_RM_RAP"
37
38 /**
39  * Minimum routing option data length is
40  * length of src address(1byte) + length of destination address(1byte) +
41  * Seq Num(2bytes) + Msg Type(1 bytes)
42  */
43 #define MIN_ROUTE_OPTION_LEN 5
44
45 /**
46  * Stack mode.
47  */
48 static OCMode g_rmStackMode = OC_CLIENT;
49
50 void RMSetStackMode(OCMode mode)
51 {
52     g_rmStackMode = mode;
53 }
54
55 // destination and source are <GatewayId><ClientId> here, where ClientId is optional.
56 OCStackResult RMAddInfo(const char *destination, void *message, bool isRequest,
57                         bool *doPost)
58 {
59     OIC_LOG(DEBUG, TAG, "IN");
60     RM_NULL_CHECK_WITH_RET(message, TAG, "options");
61
62     CAHeaderOption_t **options = NULL;
63     uint8_t *numOptions = NULL;
64
65     if (isRequest)
66     {
67         CARequestInfo_t *requestMsg = message;
68         options = &(requestMsg->info.options);
69         RM_NULL_CHECK_WITH_RET(options, TAG, "options");
70         numOptions = &(requestMsg->info.numOptions);
71         RM_NULL_CHECK_WITH_RET(numOptions, TAG, "numOptions");
72     }
73     else
74     {
75         CAResponseInfo_t *respMsg = message;
76         if ('\0' == destination[0] && (CA_EMPTY == respMsg->result))
77         {
78             OIC_LOG(DEBUG, TAG, "Response is for an Endpoint, No need to add the routing Option");
79             return OC_STACK_OK;
80         }
81         options = &(respMsg->info.options);
82         RM_NULL_CHECK_WITH_RET(options, TAG, "options");
83         numOptions = &(respMsg->info.numOptions);
84         RM_NULL_CHECK_WITH_RET(numOptions, TAG, "numOptions");
85     }
86
87
88     CAHeaderOption_t *optionPtr = NULL;
89     int8_t index = -1;
90
91     RMGetRouteOptionIndex(*options, *numOptions, &index);
92
93     if (-1 < index)
94     {
95         OIC_LOG(INFO, TAG, "Route option is present");
96         optionPtr = *options;
97     }
98     else
99     {
100         OIC_LOG(INFO, TAG, "Route option is not present");
101         index = *numOptions;
102         optionPtr = OICCalloc((*numOptions + 1), sizeof(CAHeaderOption_t));
103         if (!optionPtr)
104         {
105             OIC_LOG(ERROR, TAG, "OICCalloc failed");
106             return OC_STACK_NO_MEMORY;
107         }
108
109         memcpy(optionPtr, *options, sizeof(CAHeaderOption_t) * (*numOptions));
110     }
111
112     OCStackResult res = OC_STACK_OK;
113     RMRouteOption_t routeOption = {.destGw = 0};
114     if (*numOptions != index)
115     {
116         OIC_LOG(INFO, TAG, "Route option is already present");
117         res = RMParseRouteOption(&optionPtr[index], &routeOption);
118         if (OC_STACK_OK != res)
119         {
120             OIC_LOG(ERROR, TAG, "RMParseRouteOption failed");
121             return OC_STACK_ERROR;
122         }
123     }
124
125     if (!isRequest)
126     {
127         CAResponseInfo_t *respMsg = message;
128         if (CA_EMPTY == respMsg->result && CA_MSG_ACKNOWLEDGE == respMsg->info.type)
129         {
130             OIC_LOG(DEBUG, TAG, "CA_EMPTY WITH ACKNOWLEDGEMENT");
131             routeOption.msgType = ACK;
132             if (OC_SERVER == g_rmStackMode)
133             {
134                 OIC_LOG(DEBUG, TAG, "This is server mode");
135                 // Send the Empty message in the response with adding the MSGType in Route option.
136                 respMsg->info.type = CA_MSG_NONCONFIRM;
137                 respMsg->result = CA_CONTENT;
138             }
139             else
140             {
141                 OIC_LOG(DEBUG, TAG, "Send a POST request");
142                 if (NULL != doPost)
143                 {
144                     *doPost = true;
145                 }
146             }
147         }
148         else if (CA_EMPTY == respMsg->result && CA_MSG_RESET == respMsg->info.type)
149         {
150             OIC_LOG(DEBUG, TAG, "CA_EMPTY WITH RESET");
151             routeOption.msgType = RST;
152             respMsg->info.type = CA_MSG_NONCONFIRM;
153             respMsg->result = CA_CONTENT;
154         }
155     }
156
157     if(destination)
158     {
159         memcpy(&(routeOption.destGw), destination, sizeof(routeOption.destGw));
160         memcpy(&(routeOption.destEp), destination + sizeof(routeOption.destGw),
161                sizeof(routeOption.destEp));
162     }
163
164 #ifdef ROUTING_GATEWAY
165     // A gateway is supposed to add its ID as source.
166     uint32_t gatewayId = RMGetGatewayId();
167     if (gatewayId)
168     {
169         memcpy(&(routeOption.srcGw), &gatewayId, sizeof(routeOption.srcGw));
170     }
171
172     if(!routeOption.destGw)
173     {
174         routeOption.mSeqNum = RMGetMcastSeqNumber();
175     }
176 #endif
177
178     res = RMCreateRouteOption(&routeOption, optionPtr + index);
179     if (OC_STACK_OK != res)
180     {
181         OIC_LOG(ERROR, TAG, "Creation of routing option failed");
182         OICFree(optionPtr);
183         return res;
184     }
185
186     if ((*numOptions) == index )
187     {
188         (*numOptions) = (*numOptions) + 1;
189         OICFree(*options);
190         *options = optionPtr;
191     }
192
193     OIC_LOG(DEBUG, TAG, "OUT");
194     return OC_STACK_OK;
195 }
196
197 OCStackResult RMUpdateInfo(CAHeaderOption_t **options, uint8_t *numOptions,
198                            CAEndpoint_t *endpoint)
199 {
200     OIC_LOG(DEBUG, TAG, "IN");
201     RM_NULL_CHECK_WITH_RET(options, TAG, "options");
202     RM_NULL_CHECK_WITH_RET(*options, TAG, "invalid option");
203     RM_NULL_CHECK_WITH_RET(numOptions, TAG, "numOptions");
204     RM_NULL_CHECK_WITH_RET(endpoint, TAG, "endpoint");
205
206     if (0 >= *numOptions)
207     {
208         OIC_LOG(ERROR, TAG, "Invalid arguement: numOptions");
209         return OC_STACK_ERROR;
210     }
211
212     int8_t routeIndex = -1;
213     RMGetRouteOptionIndex(*options, *numOptions, &routeIndex);
214
215     if (-1 >= routeIndex)
216     {
217         OIC_LOG(DEBUG, TAG, "Nothing to remove.");
218         return OC_STACK_OK;
219     }
220
221     // Update Endpoint with source address from RM header option.
222     if (0 != (*options + routeIndex)->optionLength)
223     {
224         uint8_t dLen = 0;
225         uint16_t count = sizeof(dLen);
226         memcpy(&dLen, (*options + routeIndex)->optionData, sizeof(dLen));
227         count += dLen;
228         uint8_t sLen = 0;
229         memcpy(&sLen, (*options + routeIndex)->optionData + count, sizeof(sLen));
230         count += sizeof(sLen);
231         if (0 < sLen)
232         {
233             memcpy(endpoint->routeData, (*options + routeIndex)->optionData + count,
234                    GATEWAY_ID_LENGTH);
235             OIC_LOG_V(DEBUG, TAG, "adding srcgid: %u in endpoint [%d]",
236                      *((uint32_t *)endpoint->routeData), sLen);
237
238             count += GATEWAY_ID_LENGTH;
239
240             if (GATEWAY_ID_LENGTH < sLen)
241             {
242                 memcpy(endpoint->routeData + GATEWAY_ID_LENGTH,
243                        (*options + routeIndex)->optionData + count, ENDPOINT_ID_LENGTH);
244                 OIC_LOG_V(DEBUG, TAG, "adding srceid: %u in endpoint",
245                          *((uint16_t *)(endpoint->routeData + GATEWAY_ID_LENGTH)));
246             }
247         }
248     }
249
250     // Remove route option from header.
251     for (uint8_t i = routeIndex; i < (*numOptions)-1; i++)
252     {
253         memcpy((*options) + i, (*options)+i+1, sizeof(**options));
254     }
255     *numOptions = (*numOptions) - 1;
256
257     if (0 == *numOptions)
258     {
259         // Remove route option.
260         OICFree(*options);
261         *options = NULL;
262     }
263     OIC_LOG(DEBUG, TAG, "OUT");
264     return OC_STACK_OK;
265 }
266
267 void RMGetRouteOptionIndex(const CAHeaderOption_t *options, uint8_t numOptions, int8_t *index)
268 {
269     OIC_LOG(DEBUG, TAG, "IN");
270     RM_NULL_CHECK_VOID(options, TAG, "options");
271     RM_NULL_CHECK_VOID(index, TAG, "index");
272     for (uint32_t i = 0; i < numOptions; i++)
273     {
274         OIC_LOG_V(DEBUG, TAG, "Request- optionID: %u", options[i].optionID);
275         if (RM_OPTION_MESSAGE_SWITCHING == options[i].optionID)
276         {
277             OIC_LOG_V(INFO, TAG, "Found Option at %d", i);
278             *index = i;
279             break;
280         }
281     }
282     OIC_LOG(DEBUG, TAG, "OUT");
283 }
284
285 OCStackResult RMCreateRouteOption(const RMRouteOption_t *optValue, CAHeaderOption_t *options)
286 {
287     OIC_LOG(DEBUG, RM_TAG, "IN");
288     RM_NULL_CHECK_WITH_RET(optValue, RM_TAG, "optValue");
289     RM_NULL_CHECK_WITH_RET(options, RM_TAG, "options");
290
291     uint8_t dLen = (optValue->destGw ? GATEWAY_ID_LENGTH:0) +
292                         (optValue->destEp ? ENDPOINT_ID_LENGTH:0);
293     uint8_t sLen = (optValue->srcGw ? GATEWAY_ID_LENGTH:0) +
294                         (optValue->srcEp ? ENDPOINT_ID_LENGTH:0);
295
296     OIC_LOG_V(DEBUG, RM_TAG, "createoption dlen %u slen [%u]", dLen, sLen);
297     unsigned int totalLength = MIN_ROUTE_OPTION_LEN + dLen + sLen;
298     void *tempData = OICCalloc(totalLength, sizeof(char));
299     if (NULL == tempData)
300     {
301         OIC_LOG(ERROR, RM_TAG, "Calloc failed");
302         return OC_STACK_NO_MEMORY;
303     }
304     memcpy(tempData, &dLen, sizeof(dLen));
305     unsigned int count = sizeof(dLen);
306     if (0 < dLen)
307     {
308         if (optValue->destGw)
309         {
310             memcpy(tempData + count, &(optValue->destGw), GATEWAY_ID_LENGTH);
311             count += GATEWAY_ID_LENGTH;
312         }
313
314         if (optValue->destEp)
315         {
316             memcpy(tempData + count, &(optValue->destEp), ENDPOINT_ID_LENGTH);
317             count += ENDPOINT_ID_LENGTH;
318         }
319     }
320
321     memcpy(tempData + count, &sLen, sizeof(sLen));
322     count += sizeof(sLen);
323     if (0 < sLen)
324     {
325         if (optValue->srcGw)
326         {
327             memcpy(tempData + count, &(optValue->srcGw), GATEWAY_ID_LENGTH);
328             count += GATEWAY_ID_LENGTH;
329         }
330
331         if (optValue->srcEp)
332         {
333             memcpy(tempData + count, &(optValue->srcEp), ENDPOINT_ID_LENGTH);
334             count += ENDPOINT_ID_LENGTH;
335         }
336     }
337
338     memcpy(tempData + count, &optValue->mSeqNum, sizeof(optValue->mSeqNum));
339     count += sizeof(optValue->mSeqNum);
340     memcpy(tempData + count, &optValue->msgType, sizeof(optValue->msgType));
341     memcpy(options->optionData, tempData, totalLength);
342
343     options->optionID = RM_OPTION_MESSAGE_SWITCHING;
344     options->optionLength = totalLength;
345
346     OIC_LOG_V(INFO, RM_TAG, "Option Length is %d", options->optionLength);
347
348     OICFree(tempData);
349     OIC_LOG(DEBUG, RM_TAG, "OUT");
350     return OC_STACK_OK;
351 }
352
353 OCStackResult RMParseRouteOption(const CAHeaderOption_t *options, RMRouteOption_t *optValue)
354 {
355     OIC_LOG(DEBUG, RM_TAG, "IN");
356     RM_NULL_CHECK_WITH_RET(options, RM_TAG, "options");
357     RM_NULL_CHECK_WITH_RET(optValue, RM_TAG, "optValue");
358     if (0 == options->optionLength)
359     {
360         OIC_LOG(ERROR, RM_TAG, "Option data is not present");
361         return OC_STACK_ERROR;
362     }
363
364     uint8_t dLen = 0 ;
365     uint16_t count = sizeof(dLen);
366     memcpy(&dLen, options->optionData, sizeof(dLen));
367     if (0 < dLen)
368     {
369         memcpy(&(optValue->destGw), options->optionData + count, GATEWAY_ID_LENGTH);
370         count += GATEWAY_ID_LENGTH;
371
372         if (GATEWAY_ID_LENGTH < dLen)
373         {
374             memcpy(&(optValue->destEp), options->optionData + count, ENDPOINT_ID_LENGTH);
375             count += ENDPOINT_ID_LENGTH;
376         }
377     }
378
379     uint8_t sLen = 0;
380     memcpy(&sLen, options->optionData + count, sizeof(sLen));
381     count += sizeof(sLen);
382     if (0 < sLen)
383     {
384         memcpy(&(optValue->srcGw), options->optionData + count, GATEWAY_ID_LENGTH);
385         count += GATEWAY_ID_LENGTH;
386
387         if (GATEWAY_ID_LENGTH < sLen)
388         {
389             memcpy(&(optValue->srcEp), options->optionData + count, ENDPOINT_ID_LENGTH);
390             count += ENDPOINT_ID_LENGTH;
391         }
392     }
393     memcpy(&optValue->mSeqNum, options->optionData + count, sizeof(optValue->mSeqNum));
394     count += sizeof(optValue->mSeqNum);
395     memcpy(&optValue->msgType, options->optionData + count, sizeof(optValue->msgType));
396
397     OIC_LOG_V(INFO, RM_TAG, "Option hopcount is %d", optValue->mSeqNum);
398     OIC_LOG_V(INFO, RM_TAG, "Option Sender Addr is [%u][%u]", optValue->srcGw, optValue->srcEp);
399     OIC_LOG_V(INFO, RM_TAG, "Option Dest Addr is [%u][%u]", optValue->destGw, optValue->destEp);
400     OIC_LOG_V(INFO, RM_TAG, "Message Type is [%u]", optValue->msgType);
401     OIC_LOG(DEBUG, RM_TAG, "OUT");
402     return OC_STACK_OK;
403 }