1/* 2 * Linksys boot counter reset code for mtd 3 * 4 * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License v2 8 * as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 * 19 */ 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <stddef.h> 24#include <unistd.h> 25#include <fcntl.h> 26#include <sys/mman.h> 27#include <sys/stat.h> 28#include <endian.h> 29#include <string.h> 30#include <errno.h> 31 32#include <sys/ioctl.h> 33#include <mtd/mtd-user.h> 34 35#include "mtd.h" 36 37#define BOOTCOUNT_MAGIC 0x20110811 38 39struct bootcounter { 40 uint32_t magic; 41 uint32_t count; 42 uint32_t checksum; 43}; 44 45static char page[2048]; 46 47int mtd_resetbc(const char *mtd) 48{ 49 struct mtd_info_user mtd_info; 50 struct bootcounter *curr = (struct bootcounter *)page; 51 unsigned int i; 52 int last_count = 0; 53 int num_bc; 54 int fd; 55 int ret; 56 57 fd = mtd_check_open(mtd); 58 59 if (ioctl(fd, MEMGETINFO, &mtd_info) < 0) { 60 fprintf(stderr, "failed to get mtd info!\n"); 61 return -1; 62 } 63 64 num_bc = mtd_info.size / mtd_info.writesize; 65 66 for (i = 0; i < num_bc; i++) { 67 pread(fd, curr, sizeof(*curr), i * mtd_info.writesize); 68 69 if (curr->magic != BOOTCOUNT_MAGIC && curr->magic != 0xffffffff) { 70 fprintf(stderr, "unexpected magic %08x, bailing out\n", curr->magic); 71 goto out; 72 } 73 74 if (curr->magic == 0xffffffff) 75 break; 76 77 last_count = curr->count; 78 } 79 80 /* no need to do writes when last boot count is already 0 */ 81 if (last_count == 0) 82 goto out; 83 84 85 if (i == num_bc) { 86 struct erase_info_user erase_info; 87 erase_info.start = 0; 88 erase_info.length = mtd_info.size; 89 90 /* erase block */ 91 ret = ioctl(fd, MEMERASE, &erase_info); 92 if (ret < 0) { 93 fprintf(stderr, "failed to erase block: %i\n", ret); 94 return -1; 95 } 96 97 i = 0; 98 } 99 100 memset(curr, 0xff, mtd_info.writesize); 101 102 curr->magic = BOOTCOUNT_MAGIC; 103 curr->count = 0; 104 curr->checksum = BOOTCOUNT_MAGIC; 105 106 ret = pwrite(fd, curr, mtd_info.writesize, i * mtd_info.writesize); 107 if (ret < 0) 108 fprintf(stderr, "failed to write: %i\n", ret); 109 sync(); 110out: 111 close(fd); 112 113 return 0; 114} 115