1 /* *****************************************************************
\r
3 * Copyright 2016 Samsung Electronics All Rights Reserved.
\r
7 * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * you may not use this file except in compliance with the License.
\r
9 * You may obtain a copy of the License at
\r
11 * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * Unless required by applicable law or agreed to in writing, software
\r
14 * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * See the License for the specific language governing permissions and
\r
17 * limitations under the License.
\r
19 * *****************************************************************/
\r
20 #ifndef _POSIX_C_SOURCE
\r
21 #define _POSIX_C_SOURCE 200112L
\r
27 #include <sys/time.h>
\r
29 #include "ocstack.h"
\r
30 #include "oic_malloc.h"
\r
31 #include "oic_string.h"
\r
35 #include "ocpayload.h"
\r
36 #include "payload_logging.h"
\r
37 #include "cainterface.h"
\r
39 #include "directpairing.h"
\r
40 #include "srmresourcestrings.h" //@note: SRM's internal header
\r
41 #include "doxmresource.h" //@note: SRM's internal header
\r
42 #include "pconfresource.h" //@note: SRM's internal header
\r
43 #include "dpairingresource.h" //@note: SRM's internal header
\r
44 #include "credresource.h"
\r
46 #include "pmtypes.h"
\r
47 #include "pmutility.h"
\r
49 #include "srmutility.h"
\r
51 #ifdef __WITH_DTLS__
\r
59 * Structure to carry direct-pairing API data to callback.
\r
61 typedef struct DPairData
\r
63 OCDirectPairingDev_t *peer; /**< Pointer to pairing target info.**/
\r
64 char pin[DP_PIN_LENGTH]; /**< PIN **/
\r
65 OCDirectPairingResultCB resultCallback; /**< Pointer to result callback.**/
\r
68 static OCDirectPairingDev_t *g_dp_paired = NULL;
\r
69 static OCDirectPairingDev_t *g_dp_discover = NULL;
\r
70 static DPairData_t *g_dp_proceed_ctx = NULL;
\r
73 const char *getResult(OCStackResult result) {
\r
76 return "OC_STACK_OK";
\r
77 case OC_STACK_RESOURCE_CREATED:
\r
78 return "OC_STACK_RESOURCE_CREATED";
\r
79 case OC_STACK_RESOURCE_DELETED:
\r
80 return "OC_STACK_RESOURCE_DELETED";
\r
81 case OC_STACK_INVALID_URI:
\r
82 return "OC_STACK_INVALID_URI";
\r
83 case OC_STACK_INVALID_QUERY:
\r
84 return "OC_STACK_INVALID_QUERY";
\r
85 case OC_STACK_INVALID_IP:
\r
86 return "OC_STACK_INVALID_IP";
\r
87 case OC_STACK_INVALID_PORT:
\r
88 return "OC_STACK_INVALID_PORT";
\r
89 case OC_STACK_INVALID_CALLBACK:
\r
90 return "OC_STACK_INVALID_CALLBACK";
\r
91 case OC_STACK_INVALID_METHOD:
\r
92 return "OC_STACK_INVALID_METHOD";
\r
93 case OC_STACK_NO_MEMORY:
\r
94 return "OC_STACK_NO_MEMORY";
\r
95 case OC_STACK_COMM_ERROR:
\r
96 return "OC_STACK_COMM_ERROR";
\r
97 case OC_STACK_INVALID_PARAM:
\r
98 return "OC_STACK_INVALID_PARAM";
\r
99 case OC_STACK_NOTIMPL:
\r
100 return "OC_STACK_NOTIMPL";
\r
101 case OC_STACK_NO_RESOURCE:
\r
102 return "OC_STACK_NO_RESOURCE";
\r
103 case OC_STACK_RESOURCE_ERROR:
\r
104 return "OC_STACK_RESOURCE_ERROR";
\r
105 case OC_STACK_SLOW_RESOURCE:
\r
106 return "OC_STACK_SLOW_RESOURCE";
\r
107 case OC_STACK_NO_OBSERVERS:
\r
108 return "OC_STACK_NO_OBSERVERS";
\r
109 case OC_STACK_UNAUTHORIZED_REQ:
\r
110 return "OC_STACK_UNAUTHORIZED_REQ";
\r
111 #ifdef WITH_PRESENCE
\r
112 case OC_STACK_PRESENCE_STOPPED:
\r
113 return "OC_STACK_PRESENCE_STOPPED";
\r
115 case OC_STACK_ERROR:
\r
116 return "OC_STACK_ERROR";
\r
123 * Function to search node in linked list that matches given IP and port.
\r
125 * @param[in] pList List of OCProvisionDev_t.
\r
126 * @param[in] addr address of target device.
\r
127 * @param[in] port port of remote server.
\r
129 * @return pointer of OCProvisionDev_t if exist, otherwise NULL
\r
131 OCDirectPairingDev_t* getDev(OCDirectPairingDev_t **ppList, const char* addr, const uint16_t port)
\r
135 OIC_LOG_V(ERROR, TAG, "Invalid Input parameters in [%s]\n", __FUNCTION__);
\r
139 OCDirectPairingDev_t *ptr = NULL;
\r
140 LL_FOREACH(*ppList, ptr)
\r
142 if( strcmp(ptr->endpoint.addr, addr) == 0 && port == ptr->endpoint.port)
\r
154 * Add device information to list.
\r
156 * @param[in] pList List of OCProvisionDev_t.
\r
157 * @param[in] addr address of target device.
\r
158 * @param[in] port port of remote server.
\r
159 * @param[in] adapter adapter type of endpoint.
\r
160 * @param[in] doxm pointer to doxm instance.
\r
161 * @param[in] connType connectivity type of endpoint
\r
163 * @return OC_STACK_OK for success and errorcode otherwise.
\r
165 OCStackResult addDev(OCDirectPairingDev_t **ppList, OCDevAddr *endpoint,
\r
166 OCConnectivityType conn, OicSecPconf_t *pconf)
\r
168 if(NULL == endpoint || NULL == pconf)
\r
170 OIC_LOG_V(ERROR, TAG, "Invalid Input parameters in [%s]\n", __FUNCTION__);
\r
171 return OC_STACK_INVALID_PARAM;
\r
174 OCDirectPairingDev_t *ptr = getDev(ppList, endpoint->addr, endpoint->port);
\r
177 ptr = (OCDirectPairingDev_t *)OICCalloc(1, sizeof (OCDirectPairingDev_t));
\r
180 OIC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");
\r
181 return OC_STACK_NO_MEMORY;
\r
184 memcpy(&ptr->endpoint, endpoint, sizeof(OCDevAddr));
\r
185 ptr->connType = conn;
\r
186 ptr->securePort = DEFAULT_SECURE_PORT;
\r
187 ptr->edp = pconf->edp;
\r
188 ptr->prm = pconf->prm;
\r
189 pconf->prm = NULL; // to prevent free
\r
190 ptr->prmLen = pconf->prmLen;
\r
191 memcpy(&ptr->deviceID, &pconf->deviceID, sizeof(OicUuid_t));
\r
192 memcpy(&ptr->rowner, &pconf->rowner, sizeof(OicUuid_t));
\r
195 LL_PREPEND(*ppList, ptr);
\r
196 OIC_LOG(INFO, TAG, "device added !");
\r
199 return OC_STACK_OK;
\r
204 * Add device information to list.
\r
206 * @param[in] ppList List of OCProvisionDev_t.
\r
207 * @param[in] pDev target device.
\r
209 * @return OC_STACK_OK for success and errorcode otherwise.
\r
211 OCStackResult addDev2(OCDirectPairingDev_t **ppList, OCDirectPairingDev_t *pDev)
\r
215 OIC_LOG_V(ERROR, TAG, "Invalid Input parameters in [%s]\n", __FUNCTION__);
\r
216 return OC_STACK_INVALID_PARAM;
\r
219 OCDirectPairingDev_t *ptr = getDev(ppList, pDev->endpoint.addr, pDev->endpoint.port);
\r
222 ptr = (OCDirectPairingDev_t *)OICCalloc(1, sizeof (OCDirectPairingDev_t));
\r
225 OIC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");
\r
226 return OC_STACK_NO_MEMORY;
\r
229 memcpy(&ptr->endpoint, &pDev->endpoint, sizeof(OCDevAddr));
\r
230 ptr->connType = pDev->connType;
\r
231 ptr->securePort = pDev->securePort;
\r
232 ptr->edp = pDev->edp;
\r
233 ptr->prmLen = pDev->prmLen;
\r
234 ptr->prm = (OicSecPrm_t*)OICCalloc(ptr->prmLen, sizeof (OicSecPrm_t));
\r
235 if (NULL == ptr->prm)
\r
237 OIC_LOG(ERROR, TAG, "Error while allocating memory for prm !!");
\r
238 return OC_STACK_NO_MEMORY;
\r
240 memcpy(ptr->prm, pDev->prm, sizeof(OicSecPrm_t)*ptr->prmLen);
\r
241 memcpy(&ptr->deviceID, &pDev->deviceID, sizeof(OicUuid_t));
\r
242 memcpy(&ptr->rowner, &pDev->rowner, sizeof(OicUuid_t));
\r
245 LL_PREPEND(*ppList, ptr);
\r
246 OIC_LOG(INFO, TAG, "device added !");
\r
249 return OC_STACK_OK;
\r
255 * This function deletes list of provision target devices
\r
257 * @param[in] pDevicesList List of OCProvisionDev_t.
\r
259 void delList(OCDirectPairingDev_t *pList)
\r
263 OCDirectPairingDev_t *del = NULL, *tmp = NULL;
\r
264 LL_FOREACH_SAFE(pList, del, tmp)
\r
266 LL_DELETE(pList, del);
\r
267 if (del && del->prm)
\r
275 bool DPGenerateQuery(bool isSecure,
\r
276 const char* address, const uint16_t port,
\r
277 const OCConnectivityType connType,
\r
278 char* buffer, size_t bufferSize, const char* uri)
\r
280 if(!address || !buffer || !uri)
\r
282 OIC_LOG(ERROR, TAG, "DPGenerateQuery : Invalid parameters.");
\r
286 static char QPREFIX_COAP[] = "coap://";
\r
287 static char QPREFIX_COAPS[] = "coaps://";
\r
290 char* prefix = (isSecure == true) ? QPREFIX_COAPS : QPREFIX_COAP;
\r
292 switch(connType & CT_MASK_ADAPTER)
\r
294 case CT_ADAPTER_IP:
\r
295 switch(connType & CT_MASK_FLAGS & ~CT_FLAG_SECURE)
\r
298 snRet = snprintf(buffer, bufferSize, "%s%s:%d%s",
\r
299 prefix, address, port, uri);
\r
302 snRet = snprintf(buffer, bufferSize, "%s[%s]:%d%s",
\r
303 prefix, address, port, uri);
\r
306 OIC_LOG(ERROR, TAG, "Unknown address format.");
\r
309 // snprintf return value check
\r
312 OIC_LOG_V(ERROR, TAG, "DPGenerateQuery : Error (snprintf) %d\n", snRet);
\r
315 else if ((size_t)snRet >= bufferSize)
\r
317 OIC_LOG_V(ERROR, TAG, "DPGenerateQuery : Truncated (snprintf) %d\n", snRet);
\r
322 // TODO: We need to verify tinyDTLS in below cases
\r
323 case CT_ADAPTER_GATT_BTLE:
\r
324 case CT_ADAPTER_RFCOMM_BTEDR:
\r
325 OIC_LOG(ERROR, TAG, "Not supported connectivity adapter.");
\r
329 OIC_LOG(ERROR, TAG, "Unknown connectivity adapter.");
\r
336 const OCDirectPairingDev_t* DPGetDiscoveredDevices()
\r
338 return g_dp_discover;
\r
341 const OCDirectPairingDev_t* DPGetPairedDevices()
\r
343 return g_dp_paired;
\r
346 void DPDeleteLists()
\r
348 delList(g_dp_discover);
\r
349 delList(g_dp_paired);
\r
353 * Callback handler of FinalizeDirectPairing.
\r
355 * @param[in] ctx ctx value passed to callback from calling function.
\r
356 * @param[in] UNUSED handle to an invocation
\r
357 * @param[in] clientResponse Response from queries to remote servers.
\r
358 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
\r
359 * and OC_STACK_KEEP_TRANSACTION to keep it.
\r
361 static OCStackApplicationResult DirectPairingFinalizeHandler(void *ctx, OCDoHandle UNUSED,
\r
362 OCClientResponse *clientResponse)
\r
364 OIC_LOG_V(INFO, TAG, "IN DirectPairingFinalizeHandler()");
\r
368 OIC_LOG(ERROR, TAG, "Context is Null");
\r
369 return OC_STACK_DELETE_TRANSACTION;
\r
373 DPairData_t *dpairData = (DPairData_t*)ctx;
\r
374 OCDirectPairingDev_t *peer = dpairData->peer;
\r
375 OCDirectPairingResultCB resultCallback = dpairData->resultCallback;
\r
377 if (clientResponse)
\r
379 if(OC_STACK_OK == clientResponse->result)
\r
382 OIC_LOG(INFO, TAG, "DirectPairingFinalizeHandler : success PUT request to /oic/sec/dpairing");
\r
384 CAEndpoint_t endpoint;
\r
385 memset(&endpoint, 0x00, sizeof(CAEndpoint_t));
\r
386 OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, peer->endpoint.addr);
\r
387 endpoint.addr[MAX_ADDR_STR_SIZE_CA - 1] = '\0';
\r
388 endpoint.port = peer->securePort;
\r
390 OicUuid_t ptDeviceID = {.id={0}};
\r
391 if (OC_STACK_OK != GetDoxmDeviceID(&ptDeviceID))
\r
393 OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
\r
394 resultCallback(peer, OC_STACK_ERROR);
\r
395 return OC_STACK_DELETE_TRANSACTION;
\r
398 #ifdef __WITH_DTLS__
\r
399 res = SavePairingPSK((OCDevAddr*)&endpoint, &peer->deviceID, &ptDeviceID, false);
\r
400 if(OC_STACK_OK != res)
\r
402 OIC_LOG(ERROR, TAG, "Failed to PairingPSK generation");
\r
403 resultCallback(peer, res);
\r
404 return OC_STACK_DELETE_TRANSACTION;
\r
407 // close temporary sesion
\r
408 CAResult_t caResult = CACloseDtlsSession((const CAEndpoint_t*)&endpoint);
\r
409 if(CA_STATUS_OK != caResult)
\r
411 OIC_LOG(INFO, TAG, "Fail to close temporary dtls session");
\r
414 caResult = CASelectCipherSuite(TLS_NULL_WITH_NULL_NULL);
\r
415 if(CA_STATUS_OK != caResult)
\r
417 OIC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL");
\r
419 #endif // __WITH_DTLS__
\r
421 OIC_LOG(INFO, TAG, "Direct-Papring was successfully completed.");
\r
423 // update paired list
\r
424 OCDirectPairingDev_t *dev = getDev(&g_dp_discover, peer->endpoint.addr, peer->endpoint.port);
\r
425 res = addDev2(&g_dp_paired, dev);
\r
426 if (OC_STACK_OK != res)
\r
428 OIC_LOG(ERROR, TAG, "Error while adding a device to paired list.");
\r
431 resultCallback(peer, OC_STACK_OK);
\r
433 return OC_STACK_DELETE_TRANSACTION;
\r
437 OIC_LOG(INFO, TAG, "Direct-Papring received error response.");
\r
442 OIC_LOG(ERROR, TAG, "DirectPairingFinalizeHandler received Null clientResponse");
\r
445 resultCallback(peer, OC_STACK_ERROR);
\r
446 OICFree(dpairData);
\r
447 return OC_STACK_DELETE_TRANSACTION;
\r
451 * Finalize direct-pairing .
\r
453 * @param[in] peer target device to establish direct-pairing.
\r
454 * @param[in] resultCallback result event callback.
\r
456 * @return OC_STACK_OK on success otherwise error.
\r
458 OCStackResult FinalizeDirectPairing(OCDirectPairingDev_t* peer,
\r
459 OCDirectPairingResultCB resultCallback)
\r
463 return OC_STACK_INVALID_PARAM;
\r
466 OicUuid_t deviceID = {.id={0}};
\r
467 if (OC_STACK_OK != GetDoxmDeviceID(&deviceID))
\r
469 OIC_LOG(ERROR, TAG, "Error while retrieving device ID");
\r
470 return OC_STACK_ERROR;
\r
473 OicSecDpairing_t dpair;
\r
474 memset(&dpair, 0, sizeof(OicSecDpairing_t));
\r
475 dpair.spm = (OicSecPrm_t)PRM_NOT_ALLOWED;
\r
476 memcpy(&dpair.pdeviceID, &deviceID, sizeof(OicUuid_t));
\r
478 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
\r
481 OIC_LOG(ERROR, TAG, "Failed to memory allocation");
\r
482 return OC_STACK_NO_MEMORY;
\r
484 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
\r
485 secPayload->securityData = BinToDpairingJSON(&dpair);
\r
486 if(NULL == secPayload->securityData)
\r
488 OICFree(secPayload);
\r
489 OIC_LOG(ERROR, TAG, "Failed to BinToDpairingJSON");
\r
490 return OC_STACK_NO_MEMORY;
\r
492 OIC_LOG_V(INFO, TAG, "DPARING : %s", secPayload->securityData);
\r
494 char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
\r
495 if(!DPGenerateQuery(true,
\r
496 peer->endpoint.addr,
\r
499 query, sizeof(query), OIC_RSRC_DPAIRING_URI))
\r
501 OIC_LOG(ERROR, TAG, "DPDirectPairing : Failed to generate query");
\r
502 return OC_STACK_ERROR;
\r
504 OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
\r
506 DPairData_t *dpairData = (DPairData_t *) OICCalloc(1, sizeof(DPairData_t));
\r
507 if (dpairData == NULL)
\r
509 OICFree(secPayload->securityData);
\r
510 OICFree(secPayload);
\r
511 OIC_LOG(ERROR, TAG, "Unable to allocate memory");
\r
512 return OC_STACK_NO_MEMORY;
\r
514 dpairData->peer = peer;
\r
515 dpairData->resultCallback = resultCallback;
\r
517 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
\r
518 cbData.cb = DirectPairingFinalizeHandler;
\r
519 cbData.context = (void*)dpairData;
\r
522 OCMethod method = OC_REST_PUT;
\r
523 OCDoHandle handle = NULL;
\r
524 OIC_LOG(DEBUG, TAG, "Sending DPAIRNG setting to resource server");
\r
525 OCStackResult ret = OCDoResource(&handle, method, query,
\r
526 &peer->endpoint, (OCPayload*)secPayload,
\r
527 peer->connType, OC_LOW_QOS, &cbData, NULL, 0);
\r
528 if(OC_STACK_OK != ret)
\r
530 OIC_LOG(ERROR, TAG, "error in OCDoResource");
\r
531 return OC_STACK_ERROR;
\r
534 return OC_STACK_OK;
\r
538 * Function to handle the handshake result in Direct-Pairing.
\r
539 * This function will be invoked after DTLS handshake
\r
540 * @param endPoint [IN] The remote endpoint.
\r
541 * @param errorInfo [IN] Error information from the endpoint.
\r
544 void DirectPairingDTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
\r
546 OIC_LOG_V(INFO, TAG, "IN DirectPairingDTLSHandshakeCB");
\r
549 if(g_dp_proceed_ctx && g_dp_proceed_ctx->peer && endpoint && info)
\r
551 OIC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d",
\r
552 endpoint->addr, endpoint->port, info->result);
\r
554 OCDirectPairingDev_t *peer = g_dp_proceed_ctx->peer;
\r
555 OCDirectPairingResultCB resultCallback = g_dp_proceed_ctx->resultCallback;
\r
558 //Make sure the address matches.
\r
559 if(strncmp(peer->endpoint.addr, endpoint->addr, sizeof(endpoint->addr)) == 0 &&
\r
560 peer->securePort == endpoint->port)
\r
562 //In case of success, send next coaps request.
\r
563 if(CA_STATUS_OK == info->result)
\r
565 OIC_LOG(INFO, TAG, "Now, finalize Direct-Pairing procedure.");
\r
567 res = FinalizeDirectPairing(peer, resultCallback);
\r
568 if(OC_STACK_OK != res)
\r
570 OIC_LOG(ERROR, TAG, "Failed to finalize direct-pairing");
\r
571 resultCallback(peer, res);
\r
574 else if(CA_DTLS_AUTHENTICATION_FAILURE == info->result)
\r
576 OIC_LOG(INFO, TAG, "DirectPairingDTLSHandshakeCB - Authentication failed");
\r
577 resultCallback(peer, OC_STACK_AUTHENTICATION_FAILURE);
\r
580 #ifdef __WITH_DTLS__
\r
581 CARegisterDTLSHandshakeCallback(NULL);
\r
582 #endif // __WITH_DTLS__
\r
583 res = RemoveCredential(&peer->deviceID);
\r
584 if(OC_STACK_RESOURCE_DELETED != res)
\r
586 OIC_LOG_V(ERROR, TAG, "Failed to remove temporal PSK : %d", res);
\r
589 OICFree(g_dp_proceed_ctx);
\r
590 g_dp_proceed_ctx = NULL;
\r
594 OIC_LOG_V(INFO, TAG, "DirectPairingDTLSHandshakeCB - Not matched to peer address");
\r
598 OIC_LOG_V(INFO, TAG, "OUT DirectPairingDTLSHandshakeCB");
\r
602 * Callback handler of DPDirectPairing.
\r
604 * @param[in] ctx ctx value passed to callback from calling function.
\r
605 * @param[in] UNUSED handle to an invocation
\r
606 * @param[in] clientResponse Response from queries to remote servers.
\r
607 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
\r
608 * and OC_STACK_KEEP_TRANSACTION to keep it.
\r
610 static OCStackApplicationResult DirectPairingHandler(void *ctx, OCDoHandle UNUSED,
\r
611 OCClientResponse *clientResponse)
\r
613 OIC_LOG_V(INFO, TAG, "IN DirectPairingHandler.");
\r
617 OIC_LOG(ERROR, TAG, "Context is Null");
\r
618 return OC_STACK_DELETE_TRANSACTION;
\r
621 OCStackResult res = OC_STACK_ERROR;
\r
622 DPairData_t *dpairData = (DPairData_t*)ctx;
\r
623 OCDirectPairingResultCB resultCallback = (OCDirectPairingResultCB)dpairData->resultCallback;
\r
624 OicUuid_t subjectId = {.id={0}};
\r
626 if (clientResponse)
\r
628 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
\r
631 OIC_LOG(INFO, TAG, "DirectPairingHandler : success POST request to /oic/sec/dpairing");
\r
633 #ifdef __WITH_DTLS__
\r
634 // Add temporary psk
\r
635 res = AddTmpPskWithPIN(&dpairData->peer->deviceID,
\r
636 SYMMETRIC_PAIR_WISE_KEY,
\r
637 (char*)dpairData->pin, DP_PIN_LENGTH,
\r
638 1, &dpairData->peer->rowner, &subjectId);
\r
639 VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
\r
642 // Start to establish a secure channel with Pin-based PSK cipher suite
\r
643 CAResult_t caresult;
\r
645 caresult = CAEnableAnonECDHCipherSuite(false);
\r
646 VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);
\r
648 caresult = CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256);
\r
649 VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);
\r
651 //Register proceeding peer info. & DTLS event handler to catch the dtls event while handshake
\r
652 g_dp_proceed_ctx = dpairData;
\r
653 res = CARegisterDTLSHandshakeCallback(DirectPairingDTLSHandshakeCB);
\r
654 VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);
\r
657 CAEndpoint_t *endpoint = (CAEndpoint_t *)OICCalloc(1, sizeof (CAEndpoint_t));
\r
658 VERIFY_NON_NULL(TAG, endpoint, FATAL);
\r
659 memcpy(endpoint,&dpairData->peer->endpoint,sizeof(CAEndpoint_t));
\r
660 endpoint->port = dpairData->peer->securePort;
\r
661 OIC_LOG_V(INFO, TAG, "Initiate DTLS handshake to %s(%d)", endpoint->addr, endpoint->port);
\r
663 caresult = CAInitiateHandshake(endpoint);
\r
665 VERIFY_SUCCESS(TAG, CA_STATUS_OK == caresult, ERROR);
\r
666 #endif // __WITH_DTLS__
\r
673 OIC_LOG(INFO, TAG, "DirectPairingHandler : fail POST request to /oic/sec/dpairing");
\r
678 OIC_LOG(ERROR, TAG, "DirectPairingHandler received Null clientResponse");
\r
681 #ifdef __WITH_DTLS__
\r
683 #endif // __WITH_DTLS__
\r
685 if (OC_STACK_OK != res)
\r
687 if (0 < strlen((const char*)subjectId.id))
\r
689 RemoveCredential(&dpairData->peer->deviceID);
\r
690 OICFree(dpairData);
\r
691 g_dp_proceed_ctx = NULL;
\r
694 resultCallback(dpairData->peer, res);
\r
696 OIC_LOG_V(INFO, TAG, "OUT DirectPairingHandler.");
\r
697 return OC_STACK_DELETE_TRANSACTION;
\r
701 * Start direct-pairing .
\r
703 * @param[in] peer target device to establish direct-pairing.
\r
704 * @param[in] pmSel selected pairing method.
\r
705 * @param[in] pinNumber secret value for dtls connection.
\r
707 * @return OC_STACK_OK on success otherwise error.
\r
709 OCStackResult DPDirectPairing(OCDirectPairingDev_t* peer, OicSecPrm_t pmSel, char *pinNumber,
\r
710 OCDirectPairingResultCB resultCallback)
\r
712 if(NULL == peer || NULL == pinNumber)
\r
714 return OC_STACK_INVALID_PARAM;
\r
717 OicUuid_t deviceID = {.id={0}};
\r
718 if (OC_STACK_OK != GetDoxmDeviceID(&deviceID))
\r
720 OIC_LOG(ERROR, TAG, "Error while retrieving device ID");
\r
721 return OC_STACK_ERROR;
\r
724 OicSecDpairing_t dpair;
\r
725 memset(&dpair, 0, sizeof(OicSecDpairing_t));
\r
727 memcpy(&dpair.pdeviceID, &deviceID, sizeof(OicUuid_t));
\r
729 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
\r
732 OIC_LOG(ERROR, TAG, "Failed to memory allocation");
\r
733 return OC_STACK_NO_MEMORY;
\r
735 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
\r
736 secPayload->securityData = BinToDpairingJSON(&dpair);
\r
737 if(NULL == secPayload->securityData)
\r
739 OICFree(secPayload);
\r
740 OIC_LOG(ERROR, TAG, "Failed to BinToDpairingJSON");
\r
741 return OC_STACK_NO_MEMORY;
\r
743 OIC_LOG_V(INFO, TAG, "DPAIRING : %s", secPayload->securityData);
\r
745 char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
\r
746 if(!DPGenerateQuery(false,
\r
747 peer->endpoint.addr,
\r
748 peer->endpoint.port,
\r
749 //peer->securePort,
\r
751 query, sizeof(query), OIC_RSRC_DPAIRING_URI))
\r
753 OIC_LOG(ERROR, TAG, "DPDirectPairing : Failed to generate query");
\r
754 return OC_STACK_ERROR;
\r
756 OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
\r
758 DPairData_t *dpairData = (DPairData_t *) OICCalloc(1, sizeof(DPairData_t));
\r
759 if (dpairData == NULL)
\r
761 OICFree(secPayload->securityData);
\r
762 OICFree(secPayload);
\r
763 OIC_LOG(ERROR, TAG, "Unable to allocate memory");
\r
764 return OC_STACK_NO_MEMORY;
\r
766 dpairData->peer = peer;
\r
767 memcpy(dpairData->pin, pinNumber, DP_PIN_LENGTH);
\r
768 dpairData->resultCallback = resultCallback;
\r
770 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
\r
771 cbData.cb = DirectPairingHandler;
\r
772 cbData.context = (void*)dpairData;
\r
775 OCMethod method = OC_REST_POST;
\r
776 OCDoHandle handle = NULL;
\r
777 OIC_LOG(DEBUG, TAG, "Sending DPAIRNG setting to resource server");
\r
778 OCStackResult ret = OCDoResource(&handle, method, query,
\r
779 &peer->endpoint, (OCPayload*)secPayload,
\r
780 peer->connType, OC_LOW_QOS, &cbData, NULL, 0);
\r
781 if(OC_STACK_OK != ret)
\r
783 OIC_LOG(ERROR, TAG, "error in OCDoResource");
\r
784 return OC_STACK_ERROR;
\r
787 return OC_STACK_OK;
\r
792 * Callback handler for getting secure port information using /oic/res discovery.
\r
794 * @param[in] ctx user context
\r
795 * @param[in] handle Handle for response
\r
796 * @param[in] clientResponse Response information(It will contain payload)
\r
798 * @return OC_STACK_KEEP_TRANSACTION to keep transaction and
\r
799 * OC_STACK_DELETE_TRANSACTION to delete it.
\r
801 static OCStackApplicationResult DirectPairingPortDiscoveryHandler(void *ctx, OCDoHandle UNUSED,
\r
802 OCClientResponse *clientResponse)
\r
804 OIC_LOG(INFO, TAG, "Callback Context for Direct-Pairing Secure Port DISCOVER query recvd successfully");
\r
808 if (clientResponse)
\r
810 if (NULL == clientResponse->payload)
\r
812 OIC_LOG(INFO, TAG, "Skiping Null payload");
\r
816 if (PAYLOAD_TYPE_DISCOVERY != clientResponse->payload->type)
\r
818 OIC_LOG(INFO, TAG, "Wrong payload type");
\r
819 return OC_STACK_DELETE_TRANSACTION;
\r
822 uint16_t securePort = 0;
\r
823 OCResourcePayload* resPayload = ((OCDiscoveryPayload*)clientResponse->payload)->resources;
\r
824 OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
\r
826 if (resPayload && resPayload->secure)
\r
828 securePort = resPayload->port;
\r
832 OIC_LOG(INFO, TAG, "Can not find secure port information.");
\r
833 return OC_STACK_DELETE_TRANSACTION;
\r
836 OCDirectPairingDev_t *ptr = getDev(&g_dp_discover,
\r
837 clientResponse->devAddr.addr, clientResponse->devAddr.port);
\r
840 OIC_LOG(ERROR, TAG, "Can not find device information in the discovery device list");
\r
841 return OC_STACK_DELETE_TRANSACTION;
\r
843 ptr->securePort = securePort;
\r
845 OIC_LOG(INFO, TAG, "Exiting DirectPairingPortDiscoveryHandler.");
\r
848 return OC_STACK_DELETE_TRANSACTION;
\r
852 OIC_LOG(INFO, TAG, "Skiping Null response");
\r
854 return OC_STACK_DELETE_TRANSACTION;
\r
858 * Callback handler for DPDeviceDiscovery API.
\r
860 * @param[in] ctx User context
\r
861 * @param[in] handle Handler for response
\r
862 * @param[in] clientResponse Response information (It will contain payload)
\r
863 * @return OC_STACK_KEEP_TRANSACTION to keep transaction and
\r
864 * OC_STACK_DELETE_TRANSACTION to delete it.
\r
866 static OCStackApplicationResult DirectPairingDiscoveryHandler(void* ctx, OCDoHandle UNUSED,
\r
867 OCClientResponse * clientResponse)
\r
869 OIC_LOG(INFO, TAG, "Callback Context for Direct-Pairing DISCOVER query recvd successfully");
\r
873 if (clientResponse)
\r
875 OIC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
\r
876 OIC_LOG_V(INFO, TAG,
\r
877 "Device =============> Discovered @ %s:%d",
\r
878 clientResponse->devAddr.addr,
\r
879 clientResponse->devAddr.port);
\r
881 if (NULL == clientResponse->payload)
\r
883 OIC_LOG(INFO, TAG, "Skiping Null payload");
\r
884 return OC_STACK_KEEP_TRANSACTION;
\r
886 if (OC_STACK_OK != clientResponse->result)
\r
888 OIC_LOG(INFO, TAG, "Error in response");
\r
889 return OC_STACK_KEEP_TRANSACTION;
\r
892 OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
\r
893 OicSecPconf_t *pconf = JSONToPconfBin(
\r
894 ((OCSecurityPayload*)clientResponse->payload)->securityData);
\r
897 OIC_LOG(INFO, TAG, "Ignoring malformed JSON");
\r
898 return OC_STACK_KEEP_TRANSACTION;
\r
902 OCDevAddr endpoint;
\r
903 memcpy(&endpoint, &clientResponse->devAddr, sizeof(OCDevAddr));
\r
905 OCStackResult res = addDev(&g_dp_discover, &endpoint,
\r
906 clientResponse->connType, pconf);
\r
907 DeletePconfBinData(pconf);
\r
908 if (OC_STACK_OK != res)
\r
910 OIC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
\r
911 return OC_STACK_KEEP_TRANSACTION;
\r
915 char rsrc_uri[MAX_URI_LENGTH+1] = {0};
\r
916 int wr_len = snprintf(rsrc_uri, sizeof(rsrc_uri), "%s?%s=%s",
\r
917 OC_RSRVD_WELL_KNOWN_URI, OC_RSRVD_RESOURCE_TYPE, OIC_RSRC_TYPE_SEC_DPAIRING);
\r
918 if(wr_len <= 0 || (size_t)wr_len >= sizeof(rsrc_uri))
\r
920 OIC_LOG(ERROR, TAG, "rsrc_uri_string_print failed");
\r
921 return OC_STACK_ERROR;
\r
924 //Try to the unicast discovery to getting secure port
\r
925 char query[MAX_URI_LENGTH+MAX_QUERY_LENGTH+1] = {0};
\r
926 if(!DPGenerateQuery(false,
\r
927 clientResponse->devAddr.addr, clientResponse->devAddr.port,
\r
928 clientResponse->connType,
\r
929 query, sizeof(query), rsrc_uri))
\r
931 OIC_LOG(ERROR, TAG, "DirectPairingDiscoveryHandler : Failed to generate query");
\r
932 return OC_STACK_KEEP_TRANSACTION;
\r
934 OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
\r
936 OCCallbackData cbData;
\r
937 cbData.cb = &DirectPairingPortDiscoveryHandler;
\r
938 cbData.context = NULL;
\r
940 OCStackResult ret = OCDoResource(NULL, OC_REST_DISCOVER, query, 0, 0,
\r
941 clientResponse->connType, OC_LOW_QOS, &cbData, NULL, 0);
\r
942 if(OC_STACK_OK != ret)
\r
944 OIC_LOG(ERROR, TAG, "Failed to Secure Port Discovery");
\r
945 return OC_STACK_KEEP_TRANSACTION;
\r
949 OIC_LOG_V(INFO, TAG, "OCDoResource with [%s] Success", query);
\r
952 return OC_STACK_KEEP_TRANSACTION;
\r
957 OIC_LOG(INFO, TAG, "Skiping Null response");
\r
960 return OC_STACK_DELETE_TRANSACTION;
\r
964 * Discover direct-pairing devices in the same IP subnet. .
\r
966 * @param[in] waittime Timeout in seconds.
\r
968 * @return OC_STACK_OK on success otherwise error.
\r
970 OCStackResult DPDeviceDiscovery(unsigned short waittime)
\r
972 OIC_LOG(DEBUG, TAG, "IN DPDeviceDiscovery");
\r
976 delList(g_dp_discover);
\r
977 g_dp_discover = NULL;
\r
981 struct timespec startTime = {.tv_sec=0, .tv_nsec=0};
\r
982 struct timespec currTime = {.tv_sec=0, .tv_nsec=0};
\r
983 struct timespec timeout;
\r
985 const char DP_DISCOVERY_QUERY[] = "/oic/sec/pconf";
\r
987 OCCallbackData cbData;
\r
988 cbData.cb = DirectPairingDiscoveryHandler;
\r
989 cbData.context = NULL;
\r
992 /* Start a DP discovery query*/
\r
993 OIC_LOG_V(INFO, TAG, "Initiating Direct-Pairing Discovery : %s\n", DP_DISCOVERY_QUERY);
\r
994 OCDoHandle handle = NULL;
\r
995 ret = OCDoResource(&handle, OC_REST_DISCOVER, DP_DISCOVERY_QUERY, 0, 0, CT_DEFAULT,
\r
996 OC_LOW_QOS, &cbData, NULL, 0);
\r
997 if (ret != OC_STACK_OK)
\r
999 OIC_LOG(ERROR, TAG, "OCStack resource error");
\r
1004 timeout.tv_sec = 0;
\r
1005 timeout.tv_nsec = 100000000L;
\r
1007 int clock_res = -1;
\r
1008 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
\r
1009 clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
\r
1011 if (0 != clock_res)
\r
1013 OIC_LOG(ERROR, TAG, "clock error");
\r
1014 if(OC_STACK_OK != OCCancel(handle, OC_LOW_QOS, NULL, 0))
\r
1016 OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
\r
1018 return OC_STACK_ERROR;
\r
1023 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
\r
1024 clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
\r
1026 if (0 != clock_res)
\r
1028 OIC_LOG(ERROR, TAG, "clock error");
\r
1029 ret = OC_STACK_ERROR;
\r
1032 long elapsed = (currTime.tv_sec - startTime.tv_sec);
\r
1033 if (elapsed > waittime)
\r
1039 nanosleep(&timeout, NULL);
\r
1043 //Waiting for each response.
\r
1044 ret = OCCancel(handle, OC_LOW_QOS, NULL, 0);
\r
1045 if (OC_STACK_OK != ret)
\r
1047 OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
\r
1049 OIC_LOG(DEBUG, TAG, "OUT DPDeviceDiscovery");
\r