1 /*
2  * Copyright (c) 2017-2023 Nordic Semiconductor ASA
3  * Copyright (c) 2015 Runtime Inc
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/sys/crc.h>
9 
10 #include <zephyr/fs/fcb.h>
11 #include "fcb_priv.h"
12 
13 #define FCB_FIXED_ENDMARKER 0xab
14 
15 /*
16  * Given offset in flash sector, fill in rest of the fcb_entry, and crc8 over
17  * the data.
18  */
19 static int
fcb_elem_crc8(struct fcb * _fcb,struct fcb_entry * loc,uint8_t * c8p)20 fcb_elem_crc8(struct fcb *_fcb, struct fcb_entry *loc, uint8_t *c8p)
21 {
22 	uint8_t tmp_str[FCB_TMP_BUF_SZ];
23 	int cnt;
24 	int blk_sz;
25 	uint8_t crc8;
26 	uint16_t len;
27 	uint32_t off;
28 	uint32_t end;
29 	int rc;
30 
31 	if (loc->fe_elem_off + 2 > loc->fe_sector->fs_size) {
32 		return -ENOTSUP;
33 	}
34 
35 	rc = fcb_flash_read(_fcb, loc->fe_sector, loc->fe_elem_off, tmp_str, 2);
36 	if (rc) {
37 		return -EIO;
38 	}
39 
40 	cnt = fcb_get_len(_fcb, tmp_str, &len);
41 	if (cnt < 0) {
42 		return cnt;
43 	}
44 	loc->fe_data_off = loc->fe_elem_off + fcb_len_in_flash(_fcb, cnt);
45 	loc->fe_data_len = len;
46 
47 	crc8 = CRC8_CCITT_INITIAL_VALUE;
48 	crc8 = crc8_ccitt(crc8, tmp_str, cnt);
49 
50 	off = loc->fe_data_off;
51 	end = loc->fe_data_off + len;
52 	for (; off < end; off += blk_sz) {
53 		blk_sz = end - off;
54 		if (blk_sz > sizeof(tmp_str)) {
55 			blk_sz = sizeof(tmp_str);
56 		}
57 
58 		rc = fcb_flash_read(_fcb, loc->fe_sector, off, tmp_str, blk_sz);
59 		if (rc) {
60 			return -EIO;
61 		}
62 		crc8 = crc8_ccitt(crc8, tmp_str, blk_sz);
63 	}
64 	*c8p = crc8;
65 
66 	return 0;
67 }
68 
69 #if IS_ENABLED(CONFIG_FCB_ALLOW_FIXED_ENDMARKER)
70 /* Given the offset in flash sector, calculate the FCB entry data offset and size, and set
71  * the fixed endmarker.
72  */
73 static int
fcb_elem_endmarker_fixed(struct fcb * _fcb,struct fcb_entry * loc,uint8_t * em)74 fcb_elem_endmarker_fixed(struct fcb *_fcb, struct fcb_entry *loc, uint8_t *em)
75 {
76 	uint8_t tmp_str[2];
77 	int cnt;
78 	uint16_t len;
79 	int rc;
80 
81 	if (loc->fe_elem_off + 2 > loc->fe_sector->fs_size) {
82 		return -ENOTSUP;
83 	}
84 
85 	rc = fcb_flash_read(_fcb, loc->fe_sector, loc->fe_elem_off, tmp_str, 2);
86 	if (rc) {
87 		return -EIO;
88 	}
89 
90 	cnt = fcb_get_len(_fcb, tmp_str, &len);
91 	if (cnt < 0) {
92 		return cnt;
93 	}
94 	loc->fe_data_off = loc->fe_elem_off + fcb_len_in_flash(_fcb, cnt);
95 	loc->fe_data_len = len;
96 
97 	*em = FCB_FIXED_ENDMARKER;
98 	return 0;
99 }
100 #endif /* IS_ENABLED(CONFIG_FCB_ALLOW_FIXED_ENDMARKER) */
101 
102 /* Given the offset in flash sector, calculate the FCB entry data offset and size, and calculate
103  * the expected endmarker.
104  */
105 int
fcb_elem_endmarker(struct fcb * _fcb,struct fcb_entry * loc,uint8_t * em)106 fcb_elem_endmarker(struct fcb *_fcb, struct fcb_entry *loc, uint8_t *em)
107 {
108 #if IS_ENABLED(CONFIG_FCB_ALLOW_FIXED_ENDMARKER)
109 	if (_fcb->f_flags & FCB_FLAGS_CRC_DISABLED) {
110 		return fcb_elem_endmarker_fixed(_fcb, loc, em);
111 	}
112 #endif /* IS_ENABLED(CONFIG_FCB_ALLOW_FIXED_ENDMARKER) */
113 
114 	return fcb_elem_crc8(_fcb, loc, em);
115 }
116 
117 /* Given the offset in flash sector, calculate the FCB entry data offset and size, and verify that
118  * the FCB entry endmarker is correct.
119  */
fcb_elem_info(struct fcb * _fcb,struct fcb_entry * loc)120 int fcb_elem_info(struct fcb *_fcb, struct fcb_entry *loc)
121 {
122 	int rc;
123 	uint8_t em;
124 	uint8_t fl_em;
125 	off_t off;
126 
127 	rc = fcb_elem_endmarker(_fcb, loc, &em);
128 	if (rc) {
129 		return rc;
130 	}
131 	off = loc->fe_data_off + fcb_len_in_flash(_fcb, loc->fe_data_len);
132 
133 	rc = fcb_flash_read(_fcb, loc->fe_sector, off, &fl_em, sizeof(fl_em));
134 	if (rc) {
135 		return -EIO;
136 	}
137 
138 	if (IS_ENABLED(CONFIG_FCB_ALLOW_FIXED_ENDMARKER) && (fl_em != em)) {
139 		rc = fcb_elem_crc8(_fcb, loc, &em);
140 		if (rc) {
141 			return rc;
142 		}
143 	}
144 
145 	if (fl_em != em) {
146 		return -EBADMSG;
147 	}
148 	return 0;
149 }
150