1 /*
2  * Percepio DFM v2.1.0
3  * Copyright 2023 Percepio AB
4  * www.percepio.com
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * DFM Session
9  */
10 
11 #include <dfm.h>
12 
13 #if ((DFM_CFG_ENABLED) >= 1)
14 
15 typedef struct DfmSessionStorage
16 {
17 	uint32_t ulVersion;
18 	uint32_t ulEnabled;
19 } DfmSessionStorage_t;
20 
21 #define DFM_SESSION_STORAGE_VERSION 1
22 
23 #define DFM_SESSION_STORAGE_DUMMY_VALUE 0x93105271UL
24 
25 #if ((DFM_DEVICE_NAME_MAX_LEN) < 8)
26 #error Minimum DFM_CFG_DEVICE_NAME_MAX_LEN size is 8!
27 #endif
28 
29 static DfmSessionData_t* pxDfmSessionData = (void*)0;
30 
31 DfmResult_t prvGetSessionStorageVersion(DfmSessionStorage_t* pxSessionStorage, uint32_t* pulVersion);
32 DfmResult_t prvGetSessionStorageEnabled(DfmSessionStorage_t* pxSessionStorage, uint32_t* pulEnabled);
33 
xDfmSessionInitialize(DfmSessionData_t * pxBuffer)34 DfmResult_t xDfmSessionInitialize(DfmSessionData_t* pxBuffer)
35 {
36 	uint32_t i;
37 	uint32_t ulBytesWritten;
38 
39 	if (pxBuffer == (void*)0)
40 	{
41 		return DFM_FAIL;
42 	}
43 
44 	pxDfmSessionData = pxBuffer;
45 
46 	pxDfmSessionData->ulAlertCounter = 0;
47 
48 	pxDfmSessionData->ulProduct = DFM_CFG_PRODUCTID;
49 
50 	pxDfmSessionData->xStorageStrategy = DFM_CFG_STORAGE_STRATEGY;
51 	pxDfmSessionData->xCloudStrategy = DFM_CFG_CLOUD_STRATEGY;
52 	pxDfmSessionData->xSessionIdStrategy = DFM_CFG_SESSIONID_STRATEGY;
53 
54 	pxDfmSessionData->ulDfmStatus = DFM_STATUS_CODE_OK;
55 
56 	/* We disable it here */
57 	pxDfmSessionData->ulEnabled = DFM_DISABLED;
58 
59 	if (pxDfmSessionData->xSessionIdStrategy == DFM_SESSIONID_STRATEGY_ONSTARTUP)
60 	{
61 		/* Verify that the user supplied callback has been set */
62 		if (xDfmUserGetUniqueSessionID == 0)
63 		{
64 			return DFM_FAIL;
65 		}
66 
67 		if (xDfmUserGetUniqueSessionID(pxDfmSessionData->cUniqueSessionIdBuffer, DFM_SESSION_ID_MAX_LEN, &ulBytesWritten) == DFM_FAIL) /*cstat !MISRAC2012-Rule-14.3_b The User implementation used for MISRA always returns DFM_SUCCESS so this check will never be true. In a real system that will not be the case.*/
68 		{
69 			return DFM_FAIL;
70 		}
71 
72 		if (pxDfmSessionData->cUniqueSessionIdBuffer[0] == (char)0)
73 		{
74 			return DFM_FAIL;
75 		}
76 	}
77 	else
78 	{
79 		pxDfmSessionData->cUniqueSessionIdBuffer[0] = (char)0;
80 	}
81 
82 	pxDfmSessionData->cDeviceNameBuffer[0] = (char)0;
83 
84 	for (i = 0; i < (uint32_t)DFM_CFG_FIRMWARE_VERSION_MAX_LEN; i++)
85 	{
86 		pxDfmSessionData->cFirmwareVersionBuffer[i] = (char)(DFM_CFG_FIRMWARE_VERSION)[i];
87 
88 		if (pxDfmSessionData->cFirmwareVersionBuffer[i] == (char)0)
89 		{
90 			break;
91 		}
92 	}
93 
94 	pxDfmSessionData->ulInitialized = 1;
95 
96 	return DFM_SUCCESS;
97 }
98 
xDfmSessionEnable(uint32_t ulOverride)99 DfmResult_t xDfmSessionEnable(uint32_t ulOverride)
100 {
101 	uint8_t cSessionStorageBuffer[8] = { 0 }; /* This must be large enough to hold all previous versions of DfmSessionStorage_t */
102 	uint32_t ulStoredEnabledValue = DFM_SESSION_STORAGE_DUMMY_VALUE;
103 	DfmSessionStorage_t* pxSessionStorage = (DfmSessionStorage_t*)cSessionStorageBuffer; /*cstat !MISRAC2012-Rule-11.3 We use an untyped buffer to retrieve the session data since we can't know what version and size it might have been stored in the past. The stored Session data might be larger than the current DfmSessionStorage_t*/
104 
105 	if (pxDfmSessionData == (void*)0)
106 	{
107 		return DFM_FAIL;
108 	}
109 
110 	if (pxDfmSessionData->ulInitialized == 0UL)
111 	{
112 		return DFM_FAIL;
113 	}
114 
115 	if (ulDfmIsInitialized() == 0UL)
116 	{
117 		return DFM_FAIL;
118 	}
119 
120 	/* Already enabled? */
121 	if (pxDfmSessionData->ulEnabled == DFM_ENABLED)
122 	{
123 		return DFM_SUCCESS;
124 	}
125 
126 	/* Is a previous session stored? */
127 	if (xDfmStorageGetSession(cSessionStorageBuffer, sizeof(cSessionStorageBuffer)) == DFM_SUCCESS)
128 	{
129 		if (prvGetSessionStorageEnabled((DfmSessionStorage_t*)cSessionStorageBuffer, &ulStoredEnabledValue) == DFM_FAIL) /*cstat !MISRAC2012-Rule-11.3 We use an untyped buffer to retrieve the session data since we can't know what version and size it might have been stored in the past. The stored Session data might be larger than the current DfmSessionStorage_t*/
130 		{
131 			/* Unexpected error */
132 			ulStoredEnabledValue = DFM_SESSION_STORAGE_DUMMY_VALUE;
133 		}
134 	}
135 
136 	if ((ulStoredEnabledValue == DFM_SESSION_STORAGE_DUMMY_VALUE) || ((ulOverride == 1UL) && (ulStoredEnabledValue == DFM_DISABLED)))
137 	{
138 		/* Couldn't read stored value or we override a disabled value */
139 		pxSessionStorage->ulVersion = DFM_SESSION_STORAGE_VERSION;
140 		pxSessionStorage->ulEnabled = DFM_ENABLED;
141 
142 		(void)xDfmStorageStoreSession(pxSessionStorage, sizeof(DfmSessionStorage_t)); /* Attempt to store the session info. We can't really do anything if it fails. */
143 
144 		ulStoredEnabledValue = DFM_ENABLED;
145 	}
146 
147 	if (ulStoredEnabledValue == DFM_DISABLED)
148 	{
149 		/* We are expressly disabled and not overriding */
150 		return DFM_FAIL;
151 	}
152 
153 	pxDfmSessionData->ulEnabled = DFM_ENABLED;
154 
155 	return DFM_SUCCESS;
156 }
157 
xDfmSessionDisable(uint32_t ulRemember)158 DfmResult_t xDfmSessionDisable(uint32_t ulRemember)
159 {
160 	uint8_t cSessionStorageBuffer[8] = { 0 }; /* This must be large enough to hold all previous versions of DfmSessionStorage_t */
161 	uint32_t ulStoredEnabledValue = DFM_SESSION_STORAGE_DUMMY_VALUE;
162 	DfmSessionStorage_t* pxSessionStorage = (DfmSessionStorage_t*)cSessionStorageBuffer; /*cstat !MISRAC2012-Rule-11.3 We use an untyped buffer to retrieve the session data since we can't know what version and size it might have been stored in the past. The stored Session data might be larger than the current DfmSessionStorage_t*/
163 
164 	if (pxDfmSessionData == (void*)0)
165 	{
166 		return DFM_FAIL;
167 	}
168 
169 	if (pxDfmSessionData->ulInitialized == 0UL)
170 	{
171 		return DFM_FAIL;
172 	}
173 
174 	/* Is a previous session stored? */
175 	if (xDfmStorageGetSession(cSessionStorageBuffer, sizeof(cSessionStorageBuffer)) == DFM_SUCCESS)
176 	{
177 		if (prvGetSessionStorageEnabled((DfmSessionStorage_t*)cSessionStorageBuffer, &ulStoredEnabledValue) == DFM_FAIL) /*cstat !MISRAC2012-Rule-11.3 We use an untyped buffer to retrieve the session data since we can't know what version and size it might have been stored in the past. The stored Session data might be larger than the current DfmSessionStorage_t*/
178 		{
179 			/* Unexpected error */
180 			ulStoredEnabledValue = DFM_SESSION_STORAGE_DUMMY_VALUE;
181 		}
182 	}
183 
184 	if (ulStoredEnabledValue != DFM_DISABLED)
185 	{
186 		/* We didn't find disabled */
187 		pxSessionStorage->ulVersion = DFM_SESSION_STORAGE_VERSION;
188 		pxSessionStorage->ulEnabled = DFM_DISABLED;
189 
190 		if (ulRemember != 0UL)
191 		{
192 			(void)xDfmStorageStoreSession(pxSessionStorage, sizeof(DfmSessionStorage_t)); /* Attempt to store the session info. We can't really do anything if it fails. */
193 		}
194 	}
195 
196 	pxDfmSessionData->ulEnabled = DFM_DISABLED;
197 
198 	return DFM_SUCCESS;
199 }
200 
ulDfmSessionIsEnabled()201 uint32_t ulDfmSessionIsEnabled()
202 {
203 	if (pxDfmSessionData == (void*)0)
204 	{
205 		return 0;
206 	}
207 
208 	if (pxDfmSessionData->ulInitialized == 0UL)
209 	{
210 		return 0;
211 	}
212 
213 	if (ulDfmIsInitialized() == 0UL)
214 	{
215 		return 0;
216 	}
217 
218 	return (uint32_t)(pxDfmSessionData->ulEnabled == DFM_ENABLED);
219 }
220 
xDfmSessionGetUniqueSessionId(char ** pszUniqueSessionId)221 DfmResult_t xDfmSessionGetUniqueSessionId(char **pszUniqueSessionId)
222 {
223 	uint32_t ulBytesWritten = 0UL;
224 
225 	if (pxDfmSessionData == (void*)0)
226 	{
227 		return DFM_FAIL;
228 	}
229 
230 	if (pxDfmSessionData->ulInitialized == 0UL)
231 	{
232 		return DFM_FAIL;
233 	}
234 
235 	if (pszUniqueSessionId == (void*)0)
236 	{
237 		return DFM_FAIL;
238 	}
239 
240 	if (pxDfmSessionData->cUniqueSessionIdBuffer[0] == (char)0)
241 	{
242 		if (pxDfmSessionData->xSessionIdStrategy == DFM_SESSIONID_STRATEGY_ONALERT)
243 		{
244 			/* Verify that the user supplied callback has been set */
245 			if (xDfmUserGetUniqueSessionID == 0)
246 			{
247 				return DFM_FAIL;
248 			}
249 
250 			/* Attempt to get a valid session id. Reserve last buffer slot for null termination. */
251 			if (xDfmUserGetUniqueSessionID(pxDfmSessionData->cUniqueSessionIdBuffer, (uint32_t)(DFM_SESSION_ID_MAX_LEN) - 1UL, &ulBytesWritten) == DFM_FAIL) /*cstat !MISRAC2012-Rule-14.3_b The User implementation used for MISRA always returns DFM_SUCCESS so this check will never be true. In a real system that will not be the case.*/
252 			{
253 				return DFM_FAIL;
254 			}
255 
256 			if (pxDfmSessionData->cUniqueSessionIdBuffer[0] == (char)0)
257 			{
258 				return DFM_FAIL;
259 			}
260 
261 			if (ulBytesWritten > (uint32_t)(DFM_SESSION_ID_MAX_LEN) - 1UL)
262 			{
263 				/* Wrote outside buffer? */
264 				return DFM_FAIL;
265 			}
266 
267 			/* Make sure we have null termination */
268 			pxDfmSessionData->cUniqueSessionIdBuffer[ulBytesWritten] = (char)0;
269 		}
270 		else
271 		{
272 			/* This should have been set on startup! */
273 			return DFM_FAIL;
274 		}
275 	}
276 
277 	*pszUniqueSessionId = pxDfmSessionData->cUniqueSessionIdBuffer;
278 
279 	return DFM_SUCCESS;
280 }
281 
xDfmSessionSetDeviceName(const char * szDeviceName)282 DfmResult_t xDfmSessionSetDeviceName(const char* szDeviceName)
283 {
284 	if (pxDfmSessionData == (void*)0)
285 	{
286 		return DFM_FAIL;
287 	}
288 
289 	if (pxDfmSessionData->ulInitialized == 0UL)
290 	{
291 		return DFM_FAIL;
292 	}
293 
294 	if (szDeviceName == (void*)0)
295 	{
296 		return DFM_FAIL;
297 	}
298 
299 	/* Copy the device name string, but make sure we leave the last byte for zero termination */
300 	for (int i = 0; i < DFM_DEVICE_NAME_MAX_LEN - 1; i++)
301 	{
302 		pxDfmSessionData->cDeviceNameBuffer[i] = szDeviceName[i];
303 
304 		/* Break at zero termination */
305 		if (szDeviceName[i] == (char)0)
306 		{
307 			break;
308 		}
309 	}
310 
311 	pxDfmSessionData->cDeviceNameBuffer[DFM_DEVICE_NAME_MAX_LEN - 1] = (char)0;
312 
313 	return DFM_SUCCESS;
314 }
315 
xDfmSessionGetDeviceName(const char ** pszDeviceName)316 DfmResult_t xDfmSessionGetDeviceName(const char** pszDeviceName)
317 {
318 	uint32_t ulBytesWritten = 0UL;
319 
320 	if (pxDfmSessionData == (void*)0)
321 	{
322 		return DFM_FAIL;
323 	}
324 
325 	if (pxDfmSessionData->ulInitialized == 0UL)
326 	{
327 		return DFM_FAIL;
328 	}
329 
330 	if (pszDeviceName == (void*)0)
331 	{
332 		return DFM_FAIL;
333 	}
334 
335 	if (pxDfmSessionData->cDeviceNameBuffer[0] == (char)0)
336 	{
337 		/* Verify that the user supplied callback has been set */
338 		if (xDfmUserGetDeviceName == 0)
339 		{
340 			return DFM_FAIL;
341 		}
342 
343 		/* Attempt to get a valid device name. Reserve last buffer slot for null termination. */
344 		if (xDfmUserGetDeviceName(pxDfmSessionData->cDeviceNameBuffer, (uint32_t)(DFM_DEVICE_NAME_MAX_LEN) - 1UL, &ulBytesWritten) == DFM_FAIL) /*cstat !MISRAC2012-Rule-14.3_b The User implementation used for MISRA always returns DFM_SUCCESS so this check will never be true. In a real system that will not be the case.*/
345 		{
346 			return DFM_FAIL;
347 		}
348 
349 		if (pxDfmSessionData->cDeviceNameBuffer[0] == (char)0)
350 		{
351 			return DFM_FAIL;
352 		}
353 
354 		if (ulBytesWritten > (uint32_t)(DFM_DEVICE_NAME_MAX_LEN) - 1UL)
355 		{
356 			/* Wrote too much, no room for null termination! */
357 			return DFM_FAIL;
358 		}
359 
360 		/* Make sure we have null termination */
361 		pxDfmSessionData->cDeviceNameBuffer[ulBytesWritten] = (char)0;
362 	}
363 
364 	*pszDeviceName = pxDfmSessionData->cDeviceNameBuffer;
365 
366 	return DFM_SUCCESS;
367 }
368 
xDfmSessionGenerateNewAlertId(void)369 DfmResult_t xDfmSessionGenerateNewAlertId(void)
370 {
371 	if (pxDfmSessionData == (void*)0)
372 	{
373 		return DFM_FAIL;
374 	}
375 
376 	if (pxDfmSessionData->ulInitialized == 0UL)
377 	{
378 		return DFM_FAIL;
379 	}
380 
381 	/* alertIDs start at 1 */
382 	pxDfmSessionData->ulAlertCounter++;
383 
384 	return DFM_SUCCESS;
385 }
386 
xDfmSessionGetAlertId(uint32_t * pulAlertId)387 DfmResult_t xDfmSessionGetAlertId(uint32_t* pulAlertId)
388 {
389 	if (pxDfmSessionData == (void*)0)
390 	{
391 		return DFM_FAIL;
392 	}
393 
394 	if (pxDfmSessionData->ulInitialized == 0UL)
395 	{
396 		return DFM_FAIL;
397 	}
398 
399 	if (pulAlertId == (void*)0)
400 	{
401 		return DFM_FAIL;
402 	}
403 
404 	*pulAlertId = pxDfmSessionData->ulAlertCounter;
405 
406 	return DFM_SUCCESS;
407 }
408 
xDfmSessionGetProduct(uint32_t * pulProduct)409 DfmResult_t xDfmSessionGetProduct(uint32_t* pulProduct)
410 {
411 	if (pxDfmSessionData == (void*)0)
412 	{
413 		return DFM_FAIL;
414 	}
415 
416 	if (pxDfmSessionData->ulInitialized == 0UL)
417 	{
418 		return DFM_FAIL;
419 	}
420 
421 	if (pulProduct == (void*)0)
422 	{
423 		return DFM_FAIL;
424 	}
425 
426 	*pulProduct = pxDfmSessionData->ulProduct;
427 
428 	return DFM_SUCCESS;
429 }
430 
xDfmSessionGetFirmwareVersion(char ** pszFirmwareVersion)431 DfmResult_t xDfmSessionGetFirmwareVersion(char** pszFirmwareVersion)
432 {
433 	if (pxDfmSessionData == (void*)0)
434 	{
435 		return DFM_FAIL;
436 	}
437 
438 	if (pxDfmSessionData->ulInitialized == 0UL)
439 	{
440 		return DFM_FAIL;
441 	}
442 
443 	if (pszFirmwareVersion == (void*)0)
444 	{
445 		return DFM_FAIL;
446 	}
447 
448 	*pszFirmwareVersion = pxDfmSessionData->cFirmwareVersionBuffer;
449 	return DFM_SUCCESS;
450 }
451 
xDfmSessionSetStatus(uint32_t ulStatus)452 DfmResult_t xDfmSessionSetStatus(uint32_t ulStatus)
453 {
454 	if (pxDfmSessionData == (void*)0)
455 	{
456 		return DFM_FAIL;
457 	}
458 
459 	if (pxDfmSessionData->ulInitialized == 0UL)
460 	{
461 		return DFM_FAIL;
462 	}
463 
464 	if (pxDfmSessionData->ulDfmStatus != DFM_STATUS_CODE_OK)
465 	{
466 		return DFM_FAIL;
467 	}
468 
469 	pxDfmSessionData->ulDfmStatus = ulStatus;
470 
471 	return DFM_SUCCESS;
472 }
473 
xDfmSessionGetStatus(uint32_t * pulStatus)474 DfmResult_t xDfmSessionGetStatus(uint32_t* pulStatus)
475 {
476 	if (pxDfmSessionData == (void*)0)
477 	{
478 		return DFM_FAIL;
479 	}
480 
481 	if (pxDfmSessionData->ulInitialized == 0UL)
482 	{
483 		return DFM_FAIL;
484 	}
485 
486 	if (pulStatus == (void*)0)
487 	{
488 		return DFM_FAIL;
489 	}
490 
491 	*pulStatus = pxDfmSessionData->ulDfmStatus;
492 
493 	return DFM_SUCCESS;
494 }
495 
xDfmSessionSetCloudStrategy(DfmCloudStrategy_t xStrategy)496 DfmResult_t xDfmSessionSetCloudStrategy(DfmCloudStrategy_t xStrategy)
497 {
498 	if (pxDfmSessionData == (void*)0)
499 	{
500 		return DFM_FAIL;
501 	}
502 
503 	if (pxDfmSessionData->ulInitialized == 0UL)
504 	{
505 		return DFM_FAIL;
506 	}
507 
508 	pxDfmSessionData->xCloudStrategy = xStrategy;
509 
510 	return DFM_SUCCESS;
511 }
512 
xDfmSessionGetCloudStrategy(DfmCloudStrategy_t * pxStrategy)513 DfmResult_t xDfmSessionGetCloudStrategy(DfmCloudStrategy_t* pxStrategy)
514 {
515 	if (pxDfmSessionData == (void*)0)
516 	{
517 		return DFM_FAIL;
518 	}
519 
520 	if (pxDfmSessionData->ulInitialized == 0UL)
521 	{
522 		return DFM_FAIL;
523 	}
524 
525 	if (pxStrategy == (void*)0)
526 	{
527 		return DFM_FAIL;
528 	}
529 
530 	*pxStrategy = pxDfmSessionData->xCloudStrategy;
531 
532 	return DFM_SUCCESS;
533 }
534 
xDfmSessionSetStorageStrategy(DfmStorageStrategy_t xStrategy)535 DfmResult_t xDfmSessionSetStorageStrategy(DfmStorageStrategy_t xStrategy)
536 {
537 	if (pxDfmSessionData == (void*)0)
538 	{
539 		return DFM_FAIL;
540 	}
541 
542 	if (pxDfmSessionData->ulInitialized == 0UL)
543 	{
544 		return DFM_FAIL;
545 	}
546 
547 	pxDfmSessionData->xStorageStrategy = xStrategy;
548 
549 	return DFM_SUCCESS;
550 }
551 
xDfmSessionGetStorageStrategy(DfmStorageStrategy_t * pxStrategy)552 DfmResult_t xDfmSessionGetStorageStrategy(DfmStorageStrategy_t* pxStrategy)
553 {
554 	if (pxDfmSessionData == (void*)0)
555 	{
556 		return DFM_FAIL;
557 	}
558 
559 	if (pxDfmSessionData->ulInitialized == 0UL)
560 	{
561 		return DFM_FAIL;
562 	}
563 
564 	if (pxStrategy == (void*)0)
565 	{
566 		return DFM_FAIL;
567 	}
568 
569 	*pxStrategy = pxDfmSessionData->xStorageStrategy;
570 
571 	return DFM_SUCCESS;
572 }
573 
xDfmSessionSetSessionIdStrategy(DfmSessionIdStrategy_t xStrategy)574 DfmResult_t xDfmSessionSetSessionIdStrategy(DfmSessionIdStrategy_t xStrategy)
575 {
576 	if (pxDfmSessionData == (void*)0)
577 	{
578 		return DFM_FAIL;
579 	}
580 
581 	if (pxDfmSessionData->ulInitialized == 0UL)
582 	{
583 		return DFM_FAIL;
584 	}
585 
586 	pxDfmSessionData->xSessionIdStrategy = xStrategy;
587 
588 	return DFM_SUCCESS;
589 }
590 
xDfmSessionGetSessionIdStrategy(DfmSessionIdStrategy_t * pxStrategy)591 DfmResult_t xDfmSessionGetSessionIdStrategy(DfmSessionIdStrategy_t* pxStrategy)
592 {
593 	if (pxDfmSessionData == (void*)0)
594 	{
595 		return DFM_FAIL;
596 	}
597 
598 	if (pxDfmSessionData->ulInitialized == 0UL)
599 	{
600 		return DFM_FAIL;
601 	}
602 
603 	if (pxStrategy == (void*)0)
604 	{
605 		return DFM_FAIL;
606 	}
607 
608 	*pxStrategy = pxDfmSessionData->xSessionIdStrategy;
609 
610 	return DFM_SUCCESS;
611 }
612 
prvGetSessionStorageVersion(DfmSessionStorage_t * pxSessionStorage,uint32_t * pulVersion)613 DfmResult_t prvGetSessionStorageVersion(DfmSessionStorage_t* pxSessionStorage, uint32_t* pulVersion)
614 {
615 	if (pxSessionStorage->ulVersion != 1UL)
616 	{
617 		return DFM_FAIL;
618 	}
619 
620 	*pulVersion = pxSessionStorage->ulVersion;
621 
622 	return DFM_SUCCESS;
623 }
624 
prvGetSessionStorageEnabled(DfmSessionStorage_t * pxSessionStorage,uint32_t * pulEnabled)625 DfmResult_t prvGetSessionStorageEnabled(DfmSessionStorage_t* pxSessionStorage, uint32_t* pulEnabled)
626 {
627 	if (pxSessionStorage->ulVersion != 1UL)
628 	{
629 		return DFM_FAIL;
630 	}
631 
632 	*pulEnabled = pxSessionStorage->ulEnabled;
633 
634 	return DFM_SUCCESS;
635 }
636 
637 #endif
638