blob: ea1d9b84a468830264984920fcbe1d654adce6c2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <crc/crc8.h>
#include <crc/crc16.h>
#include "fcb/fcb2.h"
#include "fcb_priv.h"
/*
* Given offset in flash area, compute crc16 over the data.
*/
int
fcb2_elem_crc16(struct fcb2_entry *loc, uint16_t *c16p)
{
uint8_t tmp_str[FCB2_TMP_BUF_SZ];
int blk_sz;
uint16_t crc16;
uint32_t off;
uint32_t end;
int rc;
crc16 = 0xFFFF;
off = loc->fe_data_off;
end = loc->fe_data_off + loc->fe_data_len;
for (; off < end; off += blk_sz) {
blk_sz = end - off;
if (blk_sz > sizeof(tmp_str)) {
blk_sz = sizeof(tmp_str);
}
rc = fcb2_read_from_sector(loc, off, tmp_str, blk_sz);
if (rc) {
return FCB2_ERR_FLASH;
}
crc16 = crc16_ccitt(crc16, tmp_str, blk_sz);
}
*c16p = crc16;
return 0;
}
static int
fcb2_read_entry(struct fcb2_entry *loc)
{
uint8_t buf[FCB2_ENTRY_SIZE];
uint8_t entry_crc;
uint32_t entry_offset;
uint32_t offset;
uint16_t len;
int rc;
assert(loc != NULL);
entry_offset = fcb2_entry_location_in_range(loc);
rc = flash_area_read_is_empty(&loc->fe_range->fsr_flash_area,
entry_offset, buf, sizeof(buf));
if (rc < 0) {
/* Error reading from flash */
return FCB2_ERR_FLASH;
} else if (rc == 1) {
/* Entry not filled on flash */
return FCB2_ERR_NOVAR;
}
/* Check entry CRC first */
entry_crc = crc8_calc(crc8_init(), buf, FCB2_ENTRY_SIZE - 1);
if (entry_crc != buf[FCB2_ENTRY_SIZE - 1]) {
return FCB2_ERR_CRC;
}
offset = (buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0);
len = (buf[3] << 8) | (buf[4] << 0);
/* Sanity check for entry */
if (offset < fcb2_len_in_flash(loc->fe_range,
sizeof(struct fcb2_disk_area)) ||
len > FCB2_MAX_LEN ||
offset + len > entry_offset) {
/* Entry was found but data stored does not make any sense
* report as CRC error so it can be skipped */
return FCB2_ERR_CRC;
}
/* Entry looks decent, pass to the caller */
loc->fe_data_off = offset;
loc->fe_data_len = len;
return 0;
}
int
fcb2_elem_info(struct fcb2_entry *loc)
{
int rc;
uint16_t crc16;
uint8_t fl_crc16[2];
/* Read entry from the end of the sector */
rc = fcb2_read_entry(loc);
if (rc != 0) {
return rc;
}
/* Read actual data and calculate CRC */
rc = fcb2_elem_crc16(loc, &crc16);
if (rc) {
return rc;
}
/* Read CRC from flash */
rc = fcb2_read_from_sector(loc,
loc->fe_data_off + fcb2_len_in_flash(loc->fe_range, loc->fe_data_len),
&fl_crc16, 2);
if (rc || get_be16(fl_crc16) != crc16) {
return FCB2_ERR_CRC;
}
return 0;
}