xref: /freebsd/sys/fs/ext2fs/ext2_csum.c (revision 7abc09cddb410487e6a1c9d59f3c01d5ff805be6)
1d23db91eSPedro F. Giffuni /*-
2*7abc09cdSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*7abc09cdSPedro F. Giffuni  *
4d23db91eSPedro F. Giffuni  * Copyright (c) 2017, Fedor Uporov
5d23db91eSPedro F. Giffuni  * All rights reserved.
6d23db91eSPedro F. Giffuni  *
7d23db91eSPedro F. Giffuni  * Redistribution and use in source and binary forms, with or without
8d23db91eSPedro F. Giffuni  * modification, are permitted provided that the following conditions
9d23db91eSPedro F. Giffuni  * are met:
10d23db91eSPedro F. Giffuni  * 1. Redistributions of source code must retain the above copyright
11d23db91eSPedro F. Giffuni  *    notice, this list of conditions and the following disclaimer.
12d23db91eSPedro F. Giffuni  * 2. Redistributions in binary form must reproduce the above copyright
13d23db91eSPedro F. Giffuni  *    notice, this list of conditions and the following disclaimer in the
14d23db91eSPedro F. Giffuni  *    documentation and/or other materials provided with the distribution.
15d23db91eSPedro F. Giffuni  *
16d23db91eSPedro F. Giffuni  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17d23db91eSPedro F. Giffuni  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d23db91eSPedro F. Giffuni  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19d23db91eSPedro F. Giffuni  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20d23db91eSPedro F. Giffuni  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21d23db91eSPedro F. Giffuni  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22d23db91eSPedro F. Giffuni  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23d23db91eSPedro F. Giffuni  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24d23db91eSPedro F. Giffuni  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25d23db91eSPedro F. Giffuni  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26d23db91eSPedro F. Giffuni  * SUCH DAMAGE.
27d23db91eSPedro F. Giffuni  *
28d23db91eSPedro F. Giffuni  * $FreeBSD$
29d23db91eSPedro F. Giffuni  */
30d23db91eSPedro F. Giffuni 
31d23db91eSPedro F. Giffuni #include <sys/param.h>
32d23db91eSPedro F. Giffuni #include <sys/systm.h>
33d23db91eSPedro F. Giffuni #include <sys/types.h>
34d23db91eSPedro F. Giffuni #include <sys/stat.h>
35d23db91eSPedro F. Giffuni #include <sys/kernel.h>
36d23db91eSPedro F. Giffuni #include <sys/malloc.h>
37d23db91eSPedro F. Giffuni #include <sys/vnode.h>
38d23db91eSPedro F. Giffuni #include <sys/bio.h>
39d23db91eSPedro F. Giffuni #include <sys/buf.h>
40d23db91eSPedro F. Giffuni #include <sys/endian.h>
41d23db91eSPedro F. Giffuni #include <sys/conf.h>
42d23db91eSPedro F. Giffuni #include <sys/mount.h>
43d23db91eSPedro F. Giffuni 
44d23db91eSPedro F. Giffuni #include <fs/ext2fs/fs.h>
45d23db91eSPedro F. Giffuni #include <fs/ext2fs/ext2fs.h>
46d23db91eSPedro F. Giffuni #include <fs/ext2fs/inode.h>
47d23db91eSPedro F. Giffuni #include <fs/ext2fs/ext2_extern.h>
48d23db91eSPedro F. Giffuni 
49d23db91eSPedro F. Giffuni static uint16_t
50d23db91eSPedro F. Giffuni ext2_crc16(uint16_t crc, const void *buffer, unsigned int len)
51d23db91eSPedro F. Giffuni {
52d23db91eSPedro F. Giffuni 	const unsigned char *cp = buffer;
53d23db91eSPedro F. Giffuni 	/* CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1). */
54d23db91eSPedro F. Giffuni 	static uint16_t const crc16_table[256] = {
55d23db91eSPedro F. Giffuni 		0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
56d23db91eSPedro F. Giffuni 		0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
57d23db91eSPedro F. Giffuni 		0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
58d23db91eSPedro F. Giffuni 		0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
59d23db91eSPedro F. Giffuni 		0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
60d23db91eSPedro F. Giffuni 		0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
61d23db91eSPedro F. Giffuni 		0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
62d23db91eSPedro F. Giffuni 		0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
63d23db91eSPedro F. Giffuni 		0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
64d23db91eSPedro F. Giffuni 		0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
65d23db91eSPedro F. Giffuni 		0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
66d23db91eSPedro F. Giffuni 		0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
67d23db91eSPedro F. Giffuni 		0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
68d23db91eSPedro F. Giffuni 		0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
69d23db91eSPedro F. Giffuni 		0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
70d23db91eSPedro F. Giffuni 		0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
71d23db91eSPedro F. Giffuni 		0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
72d23db91eSPedro F. Giffuni 		0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
73d23db91eSPedro F. Giffuni 		0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
74d23db91eSPedro F. Giffuni 		0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
75d23db91eSPedro F. Giffuni 		0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
76d23db91eSPedro F. Giffuni 		0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
77d23db91eSPedro F. Giffuni 		0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
78d23db91eSPedro F. Giffuni 		0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
79d23db91eSPedro F. Giffuni 		0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
80d23db91eSPedro F. Giffuni 		0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
81d23db91eSPedro F. Giffuni 		0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
82d23db91eSPedro F. Giffuni 		0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
83d23db91eSPedro F. Giffuni 		0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
84d23db91eSPedro F. Giffuni 		0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
85d23db91eSPedro F. Giffuni 		0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
86d23db91eSPedro F. Giffuni 		0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
87d23db91eSPedro F. Giffuni 	};
88d23db91eSPedro F. Giffuni 
89d23db91eSPedro F. Giffuni 	while (len--)
90d23db91eSPedro F. Giffuni 		crc = (((crc >> 8) & 0xffU) ^
91d23db91eSPedro F. Giffuni 		    crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU;
92d23db91eSPedro F. Giffuni 	return crc;
93d23db91eSPedro F. Giffuni }
94d23db91eSPedro F. Giffuni 
95d23db91eSPedro F. Giffuni static uint16_t
96d23db91eSPedro F. Giffuni ext2_gd_csum(struct m_ext2fs *fs, uint32_t block_group, struct ext2_gd *gd)
97d23db91eSPedro F. Giffuni {
98d23db91eSPedro F. Giffuni 	size_t offset;
99d23db91eSPedro F. Giffuni 	uint16_t crc;
100d23db91eSPedro F. Giffuni 
101d23db91eSPedro F. Giffuni 	offset = offsetof(struct ext2_gd, ext4bgd_csum);
102d23db91eSPedro F. Giffuni 
103d23db91eSPedro F. Giffuni 	if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) {
104d23db91eSPedro F. Giffuni 		crc = ext2_crc16(~0, fs->e2fs->e2fs_uuid,
105d23db91eSPedro F. Giffuni 		    sizeof(fs->e2fs->e2fs_uuid));
106d23db91eSPedro F. Giffuni 		crc = ext2_crc16(crc, (uint8_t *)&block_group,
107d23db91eSPedro F. Giffuni 		    sizeof(block_group));
108d23db91eSPedro F. Giffuni 		crc = ext2_crc16(crc, (uint8_t *)gd, offset);
109d23db91eSPedro F. Giffuni 		offset += sizeof(gd->ext4bgd_csum); /* skip checksum */
110d23db91eSPedro F. Giffuni 		if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) &&
111d23db91eSPedro F. Giffuni 		    offset < fs->e2fs->e3fs_desc_size)
112d23db91eSPedro F. Giffuni 			crc = ext2_crc16(crc, (uint8_t *)gd + offset,
113d23db91eSPedro F. Giffuni 					 fs->e2fs->e3fs_desc_size - offset);
114d23db91eSPedro F. Giffuni 		return (crc);
115d23db91eSPedro F. Giffuni 	}
116d23db91eSPedro F. Giffuni 
117d23db91eSPedro F. Giffuni 	return (0);
118d23db91eSPedro F. Giffuni }
119d23db91eSPedro F. Giffuni 
120d23db91eSPedro F. Giffuni int
121d23db91eSPedro F. Giffuni ext2_gd_csum_verify(struct m_ext2fs *fs, struct cdev *dev)
122d23db91eSPedro F. Giffuni {
123d23db91eSPedro F. Giffuni 	unsigned int i;
124d23db91eSPedro F. Giffuni 	int error = 0;
125d23db91eSPedro F. Giffuni 
126d23db91eSPedro F. Giffuni 	for (i = 0; i < fs->e2fs_gcount; i++) {
127d23db91eSPedro F. Giffuni 		if (fs->e2fs_gd[i].ext4bgd_csum !=
128d23db91eSPedro F. Giffuni 		    ext2_gd_csum(fs, i, &fs->e2fs_gd[i])) {
129d23db91eSPedro F. Giffuni 			printf(
130d23db91eSPedro F. Giffuni "WARNING: mount of %s denied due bad gd=%d csum=0x%x, expected=0x%x - run fsck\n",
131d23db91eSPedro F. Giffuni 			    devtoname(dev), i, fs->e2fs_gd[i].ext4bgd_csum,
132d23db91eSPedro F. Giffuni 			    ext2_gd_csum(fs, i, &fs->e2fs_gd[i]));
133d23db91eSPedro F. Giffuni 			error = EINVAL;
134d23db91eSPedro F. Giffuni 			break;
135d23db91eSPedro F. Giffuni 		}
136d23db91eSPedro F. Giffuni 	}
137d23db91eSPedro F. Giffuni 
138d23db91eSPedro F. Giffuni 	return (error);
139d23db91eSPedro F. Giffuni }
140d23db91eSPedro F. Giffuni 
141d23db91eSPedro F. Giffuni void
142d23db91eSPedro F. Giffuni ext2_gd_csum_set(struct m_ext2fs *fs)
143d23db91eSPedro F. Giffuni {
144d23db91eSPedro F. Giffuni 	unsigned int i;
145d23db91eSPedro F. Giffuni 
146d23db91eSPedro F. Giffuni 	for (i = 0; i < fs->e2fs_gcount; i++)
147d23db91eSPedro F. Giffuni 		    fs->e2fs_gd[i].ext4bgd_csum =
148d23db91eSPedro F. Giffuni 			ext2_gd_csum(fs, i, &fs->e2fs_gd[i]);
149d23db91eSPedro F. Giffuni }
150