libnetfilter-log: Backport kernel header syncs
[openwrt/openwrt.git] / target / linux / generic / files / drivers / platform / mikrotik / rb_hardconfig.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Driver for MikroTik RouterBoot hard config.
4 *
5 * Copyright (C) 2020 Thibaut VARĂˆNE <hacks+kernel@slashdirt.org>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published
9 * by the Free Software Foundation.
10 *
11 * This driver exposes the data encoded in the "hard_config" flash segment of
12 * MikroTik RouterBOARDs devices. It presents the data in a sysfs folder
13 * named "hard_config". The WLAN calibration data is available on demand via
14 * the 'wlan_data' sysfs file in that folder.
15 *
16 * This driver permanently allocates a chunk of RAM as large as the hard_config
17 * MTD partition, although it is technically possible to operate entirely from
18 * the MTD device without using a local buffer (except when requesting WLAN
19 * calibration data), at the cost of a performance penalty.
20 *
21 * Note: PAGE_SIZE is assumed to be >= 4K, hence the device attribute show
22 * routines need not check for output overflow.
23 *
24 * Some constant defines extracted from routerboot.{c,h} by Gabor Juhos
25 * <juhosg@openwrt.org>
26 */
27
28 #include <linux/types.h>
29 #include <linux/init.h>
30 #include <linux/kernel.h>
31 #include <linux/slab.h>
32 #include <linux/errno.h>
33 #include <linux/kobject.h>
34 #include <linux/bitops.h>
35 #include <linux/string.h>
36 #include <linux/mtd/mtd.h>
37 #include <linux/sysfs.h>
38 #include <linux/lzo.h>
39
40 #include "routerboot.h"
41
42 #define RB_HARDCONFIG_VER "0.05"
43 #define RB_HC_PR_PFX "[rb_hardconfig] "
44
45 /* ID values for hardware settings */
46 #define RB_ID_FLASH_INFO 0x03
47 #define RB_ID_MAC_ADDRESS_PACK 0x04
48 #define RB_ID_BOARD_PRODUCT_CODE 0x05
49 #define RB_ID_BIOS_VERSION 0x06
50 #define RB_ID_SDRAM_TIMINGS 0x08
51 #define RB_ID_DEVICE_TIMINGS 0x09
52 #define RB_ID_SOFTWARE_ID 0x0A
53 #define RB_ID_SERIAL_NUMBER 0x0B
54 #define RB_ID_MEMORY_SIZE 0x0D
55 #define RB_ID_MAC_ADDRESS_COUNT 0x0E
56 #define RB_ID_HW_OPTIONS 0x15
57 #define RB_ID_WLAN_DATA 0x16
58 #define RB_ID_BOARD_IDENTIFIER 0x17
59 #define RB_ID_PRODUCT_NAME 0x21
60 #define RB_ID_DEFCONF 0x26
61 #define RB_ID_BOARD_REVISION 0x27
62
63 /* Bit definitions for hardware options */
64 #define RB_HW_OPT_NO_UART BIT(0)
65 #define RB_HW_OPT_HAS_VOLTAGE BIT(1)
66 #define RB_HW_OPT_HAS_USB BIT(2)
67 #define RB_HW_OPT_HAS_ATTINY BIT(3)
68 #define RB_HW_OPT_PULSE_DUTY_CYCLE BIT(9)
69 #define RB_HW_OPT_NO_NAND BIT(14)
70 #define RB_HW_OPT_HAS_LCD BIT(15)
71 #define RB_HW_OPT_HAS_POE_OUT BIT(16)
72 #define RB_HW_OPT_HAS_uSD BIT(17)
73 #define RB_HW_OPT_HAS_SIM BIT(18)
74 #define RB_HW_OPT_HAS_SFP BIT(20)
75 #define RB_HW_OPT_HAS_WIFI BIT(21)
76 #define RB_HW_OPT_HAS_TS_FOR_ADC BIT(22)
77 #define RB_HW_OPT_HAS_PLC BIT(29)
78
79 static struct kobject *hc_kobj;
80 static u8 *hc_buf; // ro buffer after init(): no locking required
81 static size_t hc_buflen;
82
83 /*
84 * For LZOR style WLAN data unpacking.
85 * This binary blob is prepended to the data encoded on some devices as
86 * RB_ID_WLAN_DATA, the result is then first decompressed with LZO, and then
87 * finally RLE-decoded.
88 * This binary blob has been extracted from RouterOS by
89 * https://forum.openwrt.org/u/ius
90 */
91 static const u8 hc_lzor_prefix[] = {
92 0x00, 0x05, 0x4c, 0x4c, 0x44, 0x00, 0x34, 0xfe,
93 0xfe, 0x34, 0x11, 0x3c, 0x1e, 0x3c, 0x2e, 0x3c,
94 0x4c, 0x34, 0x00, 0x52, 0x62, 0x92, 0xa2, 0xb2,
95 0xc3, 0x2a, 0x14, 0x00, 0x00, 0x05, 0xfe, 0x6a,
96 0x3c, 0x16, 0x32, 0x16, 0x11, 0x1e, 0x12, 0x46,
97 0x32, 0x46, 0x11, 0x4e, 0x12, 0x36, 0x32, 0x36,
98 0x11, 0x3e, 0x12, 0x5a, 0x9a, 0x64, 0x00, 0x04,
99 0xfe, 0x10, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x28,
100 0x0c, 0x00, 0x0f, 0xfe, 0x14, 0x00, 0x24, 0x24,
101 0x23, 0x24, 0x24, 0x23, 0x25, 0x22, 0x21, 0x21,
102 0x23, 0x22, 0x21, 0x22, 0x21, 0x2d, 0x38, 0x00,
103 0x0c, 0x25, 0x25, 0x24, 0x25, 0x25, 0x24, 0x23,
104 0x22, 0x21, 0x20, 0x23, 0x21, 0x21, 0x22, 0x21,
105 0x2d, 0x38, 0x00, 0x28, 0xb0, 0x00, 0x00, 0x22,
106 0x00, 0x00, 0xc0, 0xfe, 0x03, 0x00, 0xc0, 0x00,
107 0x62, 0xff, 0x62, 0xff, 0xfe, 0x06, 0x00, 0xbb,
108 0xff, 0xba, 0xff, 0xfe, 0x08, 0x00, 0x9e, 0xff,
109 0xfe, 0x0a, 0x00, 0x53, 0xff, 0xfe, 0x02, 0x00,
110 0x20, 0xff, 0xb1, 0xfe, 0xfe, 0xb2, 0xfe, 0xfe,
111 0xed, 0xfe, 0xfe, 0xfe, 0x04, 0x00, 0x3a, 0xff,
112 0x3a, 0xff, 0xde, 0xfd, 0x5f, 0x04, 0x33, 0xff,
113 0x4c, 0x74, 0x03, 0x05, 0x05, 0xff, 0x6d, 0xfe,
114 0xfe, 0x6d, 0xfe, 0xfe, 0xaf, 0x08, 0x63, 0xff,
115 0x64, 0x6f, 0x08, 0xac, 0xff, 0xbf, 0x6d, 0x08,
116 0x7a, 0x6d, 0x08, 0x96, 0x74, 0x04, 0x00, 0x08,
117 0x79, 0xff, 0xda, 0xfe, 0xfe, 0xdb, 0xfe, 0xfe,
118 0x56, 0xff, 0xfe, 0x04, 0x00, 0x5e, 0xff, 0x5e,
119 0xff, 0x6c, 0xfe, 0xfe, 0xfe, 0x06, 0x00, 0x41,
120 0xff, 0x7f, 0x74, 0x03, 0x00, 0x11, 0x44, 0xff,
121 0xa9, 0xfe, 0xfe, 0xa9, 0xfe, 0xfe, 0xa5, 0x8f,
122 0x01, 0x00, 0x08, 0x01, 0x01, 0x02, 0x04, 0x08,
123 0x02, 0x04, 0x08, 0x08, 0x01, 0x01, 0xfe, 0x22,
124 0x00, 0x4c, 0x60, 0x64, 0x8c, 0x90, 0xd0, 0xd4,
125 0xd8, 0x5c, 0x10, 0x09, 0xd8, 0xff, 0xb0, 0xff,
126 0x00, 0x00, 0xba, 0xff, 0x14, 0x00, 0xba, 0xff,
127 0x64, 0x00, 0x00, 0x08, 0xfe, 0x06, 0x00, 0x74,
128 0xff, 0x42, 0xff, 0xce, 0xff, 0x60, 0xff, 0x0a,
129 0x00, 0xb4, 0x00, 0xa0, 0x00, 0xa0, 0xfe, 0x07,
130 0x00, 0x0a, 0x00, 0xb0, 0xff, 0x96, 0x4d, 0x00,
131 0x56, 0x57, 0x18, 0xa6, 0xff, 0x92, 0x70, 0x11,
132 0x00, 0x12, 0x90, 0x90, 0x76, 0x5a, 0x54, 0x54,
133 0x4c, 0x46, 0x38, 0x00, 0x10, 0x10, 0x08, 0xfe,
134 0x05, 0x00, 0x38, 0x29, 0x25, 0x23, 0x22, 0x22,
135 0x1f, 0x00, 0x00, 0x00, 0xf6, 0xe1, 0xdd, 0xf8,
136 0xfe, 0x00, 0xfe, 0x15, 0x00, 0x00, 0xd0, 0x02,
137 0x74, 0x02, 0x08, 0xf8, 0xe5, 0xde, 0x02, 0x04,
138 0x04, 0xfd, 0x00, 0x00, 0x00, 0x07, 0x50, 0x2d,
139 0x01, 0x90, 0x90, 0x76, 0x60, 0xb0, 0x07, 0x07,
140 0x0c, 0x0c, 0x04, 0xfe, 0x05, 0x00, 0x66, 0x66,
141 0x5a, 0x56, 0xbc, 0x01, 0x06, 0xfc, 0xfc, 0xf1,
142 0xfe, 0x07, 0x00, 0x24, 0x95, 0x70, 0x64, 0x18,
143 0x06, 0x2c, 0xff, 0xb5, 0xfe, 0xfe, 0xb5, 0xfe,
144 0xfe, 0xe2, 0x8c, 0x24, 0x02, 0x2f, 0xff, 0x2f,
145 0xff, 0xb4, 0x78, 0x02, 0x05, 0x73, 0xff, 0xed,
146 0xfe, 0xfe, 0x4f, 0xff, 0x36, 0x74, 0x1e, 0x09,
147 0x4f, 0xff, 0x50, 0xff, 0xfe, 0x16, 0x00, 0x70,
148 0xac, 0x70, 0x8e, 0xac, 0x40, 0x0e, 0x01, 0x70,
149 0x7f, 0x8e, 0xac, 0x6c, 0x00, 0x0b, 0xfe, 0x02,
150 0x00, 0xfe, 0x0a, 0x2c, 0x2a, 0x2a, 0x28, 0x26,
151 0x1e, 0x1e, 0xfe, 0x02, 0x20, 0x65, 0x20, 0x00,
152 0x00, 0x05, 0x12, 0x00, 0x11, 0x1e, 0x11, 0x11,
153 0x41, 0x1e, 0x41, 0x11, 0x31, 0x1e, 0x31, 0x11,
154 0x70, 0x75, 0x7a, 0x7f, 0x84, 0x89, 0x8e, 0x93,
155 0x98, 0x30, 0x20, 0x00, 0x02, 0x00, 0xfe, 0x06,
156 0x3c, 0xbc, 0x32, 0x0c, 0x00, 0x00, 0x2a, 0x12,
157 0x1e, 0x12, 0x2e, 0x12, 0xcc, 0x12, 0x11, 0x1a,
158 0x1e, 0x1a, 0x2e, 0x1a, 0x4c, 0x10, 0x1e, 0x10,
159 0x11, 0x18, 0x1e, 0x42, 0x1e, 0x42, 0x2e, 0x42,
160 0xcc, 0x42, 0x11, 0x4a, 0x1e, 0x4a, 0x2e, 0x4a,
161 0x4c, 0x40, 0x1e, 0x40, 0x11, 0x48, 0x1e, 0x32,
162 0x1e, 0x32, 0x2e, 0x32, 0xcc, 0x32, 0x11, 0x3a,
163 0x1e, 0x3a, 0x2e, 0x3a, 0x4c, 0x30, 0x1e, 0x30,
164 0x11, 0x38, 0x1e, 0x27, 0x9a, 0x01, 0x9d, 0xa2,
165 0x2f, 0x28, 0x00, 0x00, 0x46, 0xde, 0xc4, 0xbf,
166 0xa6, 0x9d, 0x81, 0x7b, 0x5c, 0x61, 0x40, 0xc7,
167 0xc0, 0xae, 0xa9, 0x8c, 0x83, 0x6a, 0x62, 0x50,
168 0x3e, 0xce, 0xc2, 0xae, 0xa3, 0x8c, 0x7b, 0x6a,
169 0x5a, 0x50, 0x35, 0xd7, 0xc2, 0xb7, 0xa4, 0x95,
170 0x7e, 0x72, 0x5a, 0x59, 0x37, 0xfe, 0x02, 0xf8,
171 0x8c, 0x95, 0x90, 0x8f, 0x00, 0xd7, 0xc0, 0xb7,
172 0xa2, 0x95, 0x7b, 0x72, 0x56, 0x59, 0x32, 0xc7,
173 0xc3, 0xae, 0xad, 0x8c, 0x85, 0x6a, 0x63, 0x50,
174 0x3e, 0xce, 0xc3, 0xae, 0xa4, 0x8c, 0x7c, 0x6a,
175 0x59, 0x50, 0x34, 0xd7, 0xc2, 0xb7, 0xa5, 0x95,
176 0x7e, 0x72, 0x59, 0x59, 0x36, 0xfc, 0x05, 0x00,
177 0x02, 0xce, 0xc5, 0xae, 0xa5, 0x95, 0x83, 0x72,
178 0x5c, 0x59, 0x36, 0xbf, 0xc6, 0xa5, 0xab, 0x8c,
179 0x8c, 0x6a, 0x67, 0x50, 0x41, 0x64, 0x07, 0x00,
180 0x02, 0x95, 0x8c, 0x72, 0x65, 0x59, 0x3f, 0xce,
181 0xc7, 0xae, 0xa8, 0x95, 0x86, 0x72, 0x5f, 0x59,
182 0x39, 0xfe, 0x02, 0xf8, 0x8b, 0x7c, 0x0b, 0x09,
183 0xb7, 0xc2, 0x9d, 0xa4, 0x83, 0x85, 0x6a, 0x6b,
184 0x50, 0x44, 0xb7, 0xc1, 0x64, 0x01, 0x00, 0x06,
185 0x61, 0x5d, 0x48, 0x3d, 0xae, 0xc4, 0x9d, 0xad,
186 0x7b, 0x85, 0x61, 0x66, 0x48, 0x46, 0xae, 0xc3,
187 0x95, 0xa3, 0x72, 0x7c, 0x59, 0x56, 0x38, 0x31,
188 0x7c, 0x0b, 0x00, 0x0c, 0x96, 0x91, 0x8f, 0x00,
189 0xb7, 0xc0, 0xa5, 0xab, 0x8c, 0x8a, 0x6a, 0x64,
190 0x50, 0x3c, 0xb7, 0xc0, 0x9d, 0xa0, 0x83, 0x80,
191 0x6a, 0x64, 0x50, 0x3d, 0xb7, 0xc5, 0x9d, 0xa5,
192 0x83, 0x87, 0x6c, 0x08, 0x07, 0xae, 0xc0, 0x9d,
193 0xa8, 0x83, 0x88, 0x6a, 0x6d, 0x50, 0x46, 0xfc,
194 0x05, 0x00, 0x16, 0xbf, 0xc0, 0xa5, 0xa2, 0x8c,
195 0x7f, 0x6a, 0x57, 0x50, 0x2f, 0xb7, 0xc7, 0xa5,
196 0xb1, 0x8c, 0x8e, 0x72, 0x6d, 0x59, 0x45, 0xbf,
197 0xc6, 0xa5, 0xa8, 0x8c, 0x87, 0x6a, 0x5f, 0x50,
198 0x37, 0xbf, 0xc2, 0xa5, 0xa4, 0x8c, 0x83, 0x6a,
199 0x5c, 0x50, 0x34, 0xbc, 0x05, 0x00, 0x0e, 0x90,
200 0x00, 0xc7, 0xc2, 0xae, 0xaa, 0x95, 0x82, 0x7b,
201 0x60, 0x61, 0x3f, 0xb7, 0xc6, 0xa5, 0xb1, 0x8c,
202 0x8d, 0x72, 0x6b, 0x61, 0x51, 0xbf, 0xc4, 0xa5,
203 0xa5, 0x8c, 0x82, 0x72, 0x61, 0x59, 0x39, 0x6c,
204 0x26, 0x03, 0x95, 0x82, 0x7b, 0x61, 0x61, 0x40,
205 0xfc, 0x05, 0x00, 0x00, 0x7e, 0xd7, 0xc3, 0xb7,
206 0xa8, 0x9d, 0x80, 0x83, 0x5d, 0x6a, 0x3f, 0xbf,
207 0xc7, 0xa5, 0xa8, 0x8c, 0x84, 0x72, 0x60, 0x61,
208 0x46, 0xbf, 0xc2, 0xae, 0xb0, 0x9d, 0x92, 0x83,
209 0x6f, 0x6a, 0x50, 0xd7, 0xc3, 0xb7, 0xa7, 0x9d,
210 0x80, 0x83, 0x5e, 0x6a, 0x40, 0xfe, 0x02, 0xf8,
211 0x8d, 0x96, 0x90, 0x90, 0xfe, 0x05, 0x00, 0x8a,
212 0xc4, 0x63, 0xb8, 0x3c, 0xa6, 0x29, 0x97, 0x16,
213 0x81, 0x84, 0xb7, 0x5b, 0xa9, 0x33, 0x94, 0x1e,
214 0x83, 0x11, 0x70, 0xb8, 0xc2, 0x70, 0xb1, 0x4d,
215 0xa3, 0x2a, 0x8d, 0x1b, 0x7b, 0xa8, 0xbc, 0x68,
216 0xab, 0x47, 0x9d, 0x27, 0x87, 0x18, 0x75, 0xae,
217 0xc6, 0x7d, 0xbb, 0x4d, 0xaa, 0x1c, 0x84, 0x11,
218 0x72, 0xa3, 0xbb, 0x6e, 0xad, 0x3c, 0x97, 0x24,
219 0x85, 0x16, 0x71, 0x80, 0xb2, 0x57, 0xa4, 0x30,
220 0x8e, 0x1c, 0x7c, 0x10, 0x68, 0xbb, 0xbd, 0x75,
221 0xac, 0x4f, 0x9e, 0x2b, 0x87, 0x1a, 0x76, 0x96,
222 0xc5, 0x5e, 0xb5, 0x3e, 0xa5, 0x1f, 0x8c, 0x12,
223 0x7a, 0xc1, 0xc6, 0x42, 0x9f, 0x27, 0x8c, 0x16,
224 0x77, 0x0f, 0x67, 0x9d, 0xbc, 0x68, 0xad, 0x36,
225 0x95, 0x20, 0x83, 0x11, 0x6d, 0x9b, 0xb8, 0x67,
226 0xa8, 0x34, 0x90, 0x1f, 0x7c, 0x10, 0x67, 0x9e,
227 0xc9, 0x6a, 0xbb, 0x37, 0xa4, 0x20, 0x90, 0x11,
228 0x7b, 0xc6, 0xc8, 0x47, 0xa4, 0x2a, 0x90, 0x18,
229 0x7b, 0x10, 0x6c, 0xae, 0xc4, 0x5d, 0xad, 0x37,
230 0x9a, 0x1f, 0x85, 0x13, 0x75, 0x70, 0xad, 0x42,
231 0x99, 0x25, 0x84, 0x17, 0x74, 0x0b, 0x56, 0x87,
232 0xc8, 0x57, 0xb8, 0x2b, 0x9e, 0x19, 0x8a, 0x0d,
233 0x74, 0xa7, 0xc8, 0x6e, 0xb9, 0x36, 0xa0, 0x1f,
234 0x8b, 0x11, 0x75, 0x94, 0xbe, 0x4b, 0xa5, 0x2a,
235 0x92, 0x18, 0x7c, 0x0f, 0x6b, 0xaf, 0xc0, 0x58,
236 0xa8, 0x34, 0x94, 0x1d, 0x7d, 0x12, 0x6d, 0x82,
237 0xc0, 0x52, 0xb0, 0x25, 0x94, 0x14, 0x7f, 0x0c,
238 0x68, 0x84, 0xbf, 0x3e, 0xa4, 0x22, 0x8e, 0x10,
239 0x76, 0x0b, 0x65, 0x88, 0xb6, 0x42, 0x9b, 0x26,
240 0x87, 0x14, 0x70, 0x0c, 0x5f, 0xc5, 0xc2, 0x3e,
241 0x97, 0x23, 0x83, 0x13, 0x6c, 0x0c, 0x5c, 0xb1,
242 0xc9, 0x76, 0xbc, 0x4a, 0xaa, 0x20, 0x8d, 0x12,
243 0x78, 0x93, 0xbf, 0x46, 0xa3, 0x26, 0x8d, 0x14,
244 0x74, 0x0c, 0x62, 0xc8, 0xc4, 0x3b, 0x97, 0x21,
245 0x82, 0x11, 0x6a, 0x0a, 0x59, 0xa3, 0xb9, 0x68,
246 0xa9, 0x30, 0x8d, 0x1a, 0x78, 0x0f, 0x61, 0xa0,
247 0xc9, 0x73, 0xbe, 0x50, 0xb1, 0x30, 0x9f, 0x14,
248 0x80, 0x83, 0xb7, 0x3c, 0x9a, 0x20, 0x84, 0x0e,
249 0x6a, 0x0a, 0x57, 0xac, 0xc2, 0x68, 0xb0, 0x2e,
250 0x92, 0x19, 0x7c, 0x0d, 0x63, 0x93, 0xbe, 0x62,
251 0xb0, 0x3c, 0x9e, 0x1a, 0x80, 0x0e, 0x6b, 0xbb,
252 0x02, 0xa0, 0x02, 0xa0, 0x02, 0x6f, 0x00, 0x75,
253 0x00, 0x75, 0x00, 0x00, 0x00, 0xad, 0x02, 0xb3,
254 0x02, 0x6f, 0x00, 0x87, 0x00, 0x85, 0xfe, 0x03,
255 0x00, 0xc2, 0x02, 0x82, 0x4d, 0x92, 0x6e, 0x4d,
256 0xb1, 0xa8, 0x84, 0x01, 0x00, 0x07, 0x7e, 0x00,
257 0xa8, 0x02, 0xa4, 0x02, 0xa4, 0x02, 0xa2, 0x00,
258 0xa6, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xb4, 0x02,
259 0xb4, 0x02, 0x92, 0x00, 0x96, 0x00, 0x96, 0x46,
260 0x04, 0xb0, 0x02, 0x64, 0x02, 0x0a, 0x8c, 0x00,
261 0x90, 0x02, 0x98, 0x02, 0x98, 0x02, 0x0e, 0x01,
262 0x11, 0x01, 0x11, 0x50, 0xc3, 0x08, 0x88, 0x02,
263 0x88, 0x02, 0x19, 0x01, 0x02, 0x01, 0x02, 0x01,
264 0xf3, 0x2d, 0x00, 0x00
265 };
266
267 /* Array of known hw_options bits with human-friendly parsing */
268 static struct hc_hwopt {
269 const u32 bit;
270 const char *str;
271 } const hc_hwopts[] = {
272 {
273 .bit = RB_HW_OPT_NO_UART,
274 .str = "no UART\t\t",
275 }, {
276 .bit = RB_HW_OPT_HAS_VOLTAGE,
277 .str = "has Vreg\t",
278 }, {
279 .bit = RB_HW_OPT_HAS_USB,
280 .str = "has usb\t\t",
281 }, {
282 .bit = RB_HW_OPT_HAS_ATTINY,
283 .str = "has ATtiny\t",
284 }, {
285 .bit = RB_HW_OPT_NO_NAND,
286 .str = "no NAND\t\t",
287 }, {
288 .bit = RB_HW_OPT_HAS_LCD,
289 .str = "has LCD\t\t",
290 }, {
291 .bit = RB_HW_OPT_HAS_POE_OUT,
292 .str = "has POE out\t",
293 }, {
294 .bit = RB_HW_OPT_HAS_uSD,
295 .str = "has MicroSD\t",
296 }, {
297 .bit = RB_HW_OPT_HAS_SIM,
298 .str = "has SIM\t\t",
299 }, {
300 .bit = RB_HW_OPT_HAS_SFP,
301 .str = "has SFP\t\t",
302 }, {
303 .bit = RB_HW_OPT_HAS_WIFI,
304 .str = "has WiFi\t",
305 }, {
306 .bit = RB_HW_OPT_HAS_TS_FOR_ADC,
307 .str = "has TS ADC\t",
308 }, {
309 .bit = RB_HW_OPT_HAS_PLC,
310 .str = "has PLC\t\t",
311 },
312 };
313
314 /*
315 * The MAC is stored network-endian on all devices, in 2 32-bit segments:
316 * <XX:XX:XX:XX> <XX:XX:00:00>. Kernel print has us covered.
317 */
318 static ssize_t hc_tag_show_mac(const u8 *pld, u16 pld_len, char *buf)
319 {
320 if (8 != pld_len)
321 return -EINVAL;
322
323 return sprintf(buf, "%pM\n", pld);
324 }
325
326 /*
327 * Print HW options in a human readable way:
328 * The raw number and in decoded form
329 */
330 static ssize_t hc_tag_show_hwoptions(const u8 *pld, u16 pld_len, char *buf)
331 {
332 char *out = buf;
333 u32 data; // cpu-endian
334 int i;
335
336 if (sizeof(data) != pld_len)
337 return -EINVAL;
338
339 data = *(u32 *)pld;
340 out += sprintf(out, "raw\t\t: 0x%08x\n\n", data);
341
342 for (i = 0; i < ARRAY_SIZE(hc_hwopts); i++)
343 out += sprintf(out, "%s: %s\n", hc_hwopts[i].str,
344 (data & hc_hwopts[i].bit) ? "true" : "false");
345
346 return out - buf;
347 }
348
349 static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj,
350 struct bin_attribute *attr, char *buf,
351 loff_t off, size_t count);
352
353 static struct hc_wlan_attr {
354 struct bin_attribute battr;
355 u16 pld_ofs;
356 u16 pld_len;
357 } hc_wlandata_battr = {
358 .battr = __BIN_ATTR(wlan_data, S_IRUSR, hc_wlan_data_bin_read, NULL, 0),
359 };
360
361 static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
362 char *buf);
363
364 /* Array of known tags to publish in sysfs */
365 static struct hc_attr {
366 const u16 tag_id;
367 ssize_t (* const tshow)(const u8 *pld, u16 pld_len, char *buf);
368 struct kobj_attribute kattr;
369 u16 pld_ofs;
370 u16 pld_len;
371 } hc_attrs[] = {
372 {
373 .tag_id = RB_ID_FLASH_INFO,
374 .tshow = routerboot_tag_show_u32s,
375 .kattr = __ATTR(flash_info, S_IRUSR, hc_attr_show, NULL),
376 }, {
377 .tag_id = RB_ID_MAC_ADDRESS_PACK,
378 .tshow = hc_tag_show_mac,
379 .kattr = __ATTR(mac_base, S_IRUSR, hc_attr_show, NULL),
380 }, {
381 .tag_id = RB_ID_BOARD_PRODUCT_CODE,
382 .tshow = routerboot_tag_show_string,
383 .kattr = __ATTR(board_product_code, S_IRUSR, hc_attr_show, NULL),
384 }, {
385 .tag_id = RB_ID_BIOS_VERSION,
386 .tshow = routerboot_tag_show_string,
387 .kattr = __ATTR(booter_version, S_IRUSR, hc_attr_show, NULL),
388 }, {
389 .tag_id = RB_ID_SERIAL_NUMBER,
390 .tshow = routerboot_tag_show_string,
391 .kattr = __ATTR(board_serial, S_IRUSR, hc_attr_show, NULL),
392 }, {
393 .tag_id = RB_ID_MEMORY_SIZE,
394 .tshow = routerboot_tag_show_u32s,
395 .kattr = __ATTR(mem_size, S_IRUSR, hc_attr_show, NULL),
396 }, {
397 .tag_id = RB_ID_MAC_ADDRESS_COUNT,
398 .tshow = routerboot_tag_show_u32s,
399 .kattr = __ATTR(mac_count, S_IRUSR, hc_attr_show, NULL),
400 }, {
401 .tag_id = RB_ID_HW_OPTIONS,
402 .tshow = hc_tag_show_hwoptions,
403 .kattr = __ATTR(hw_options, S_IRUSR, hc_attr_show, NULL),
404 }, {
405 .tag_id = RB_ID_WLAN_DATA,
406 .tshow = NULL,
407 }, {
408 .tag_id = RB_ID_BOARD_IDENTIFIER,
409 .tshow = routerboot_tag_show_string,
410 .kattr = __ATTR(board_identifier, S_IRUSR, hc_attr_show, NULL),
411 }, {
412 .tag_id = RB_ID_PRODUCT_NAME,
413 .tshow = routerboot_tag_show_string,
414 .kattr = __ATTR(product_name, S_IRUSR, hc_attr_show, NULL),
415 }, {
416 .tag_id = RB_ID_DEFCONF,
417 .tshow = routerboot_tag_show_string,
418 .kattr = __ATTR(defconf, S_IRUSR, hc_attr_show, NULL),
419 }, {
420 .tag_id = RB_ID_BOARD_REVISION,
421 .tshow = routerboot_tag_show_string,
422 .kattr = __ATTR(board_revision, S_IRUSR, hc_attr_show, NULL),
423 }
424 };
425
426 /*
427 * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_ERD, then past
428 * that magic number the payload itself contains a routerboot tag node
429 * locating the LZO-compressed calibration data at id 0x1.
430 */
431 static int hc_wlan_data_unpack_erd(const u8 *inbuf, size_t inlen,
432 void *outbuf, size_t *outlen)
433 {
434 u16 lzo_ofs, lzo_len;
435 int ret;
436
437 /* Find embedded tag */
438 ret = routerboot_tag_find(inbuf, inlen, 0x1, // always id 1
439 &lzo_ofs, &lzo_len);
440 if (ret) {
441 pr_debug(RB_HC_PR_PFX "ERD data not found\n");
442 goto fail;
443 }
444
445 if (lzo_len > inlen) {
446 pr_debug(RB_HC_PR_PFX "Invalid ERD data length\n");
447 ret = -EINVAL;
448 goto fail;
449 }
450
451 ret = lzo1x_decompress_safe(inbuf+lzo_ofs, lzo_len, outbuf, outlen);
452 if (ret)
453 pr_debug(RB_HC_PR_PFX "LZO decompression error (%d)\n", ret);
454
455 fail:
456 return ret;
457 }
458
459 /*
460 * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_LZOR, then past
461 * that magic number is a payload that must be appended to the hc_lzor_prefix,
462 * the resulting blob is LZO-compressed. In the LZO decompression result,
463 * the RB_MAGIC_ERD magic number (aligned) must be located. Following that
464 * magic, there is a routerboot tag node (id 0x1) locating the RLE-encoded
465 * calibration data payload.
466 */
467 static int hc_wlan_data_unpack_lzor(const u8 *inbuf, size_t inlen,
468 void *outbuf, size_t *outlen)
469 {
470 u16 rle_ofs, rle_len;
471 const u32 *needle;
472 u8 *tempbuf;
473 size_t templen, lzo_len;
474 int ret;
475
476 lzo_len = inlen + sizeof(hc_lzor_prefix);
477 if (lzo_len > *outlen)
478 return -EFBIG;
479
480 /* Temporary buffer same size as the outbuf */
481 templen = *outlen;
482 tempbuf = kmalloc(templen, GFP_KERNEL);
483 if (!tempbuf)
484 return -ENOMEM;
485
486 /* Concatenate into the outbuf */
487 memcpy(outbuf, hc_lzor_prefix, sizeof(hc_lzor_prefix));
488 memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen);
489
490 /* LZO-decompress lzo_len bytes of outbuf into the tempbuf */
491 ret = lzo1x_decompress_safe(outbuf, lzo_len, tempbuf, &templen);
492 if (ret) {
493 if (LZO_E_INPUT_NOT_CONSUMED == ret) {
494 /*
495 * The tag length appears to always be aligned (probably
496 * because it is the "root" RB_ID_WLAN_DATA tag), thus
497 * the LZO payload may be padded, which can trigger a
498 * spurious error which we ignore here.
499 */
500 pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end - this may be harmless\n");
501 } else {
502 pr_debug(RB_HC_PR_PFX "LZOR: LZO decompression error (%d)\n", ret);
503 goto fail;
504 }
505 }
506
507 /*
508 * Post decompression we have a blob (possibly byproduct of the lzo
509 * dictionary). We need to find RB_MAGIC_ERD. The magic number seems to
510 * be 32bit-aligned in the decompression output.
511 */
512 needle = (const u32 *)tempbuf;
513 while (RB_MAGIC_ERD != *needle++) {
514 if ((u8 *)needle >= tempbuf+templen) {
515 pr_debug(RB_HC_PR_PFX "LZOR: ERD magic not found\n");
516 ret = -ENODATA;
517 goto fail;
518 }
519 };
520 templen -= (u8 *)needle - tempbuf;
521
522 /* Past magic. Look for tag node */
523 ret = routerboot_tag_find((u8 *)needle, templen, 0x1, &rle_ofs, &rle_len);
524 if (ret) {
525 pr_debug(RB_HC_PR_PFX "LZOR: RLE data not found\n");
526 goto fail;
527 }
528
529 if (rle_len > templen) {
530 pr_debug(RB_HC_PR_PFX "LZOR: Invalid RLE data length\n");
531 ret = -EINVAL;
532 goto fail;
533 }
534
535 /* RLE-decode tempbuf from needle back into the outbuf */
536 ret = routerboot_rle_decode((u8 *)needle+rle_ofs, rle_len, outbuf, outlen);
537 if (ret)
538 pr_debug(RB_HC_PR_PFX "LZOR: RLE decoding error (%d)\n", ret);
539
540 fail:
541 kfree(tempbuf);
542 return ret;
543 }
544
545 static int hc_wlan_data_unpack(const size_t tofs, size_t tlen,
546 void *outbuf, size_t *outlen)
547 {
548 const u8 *lbuf;
549 u32 magic;
550 int ret;
551
552 /* Caller ensure tlen > 0. tofs is aligned */
553 if ((tofs + tlen) > hc_buflen)
554 return -EIO;
555
556 lbuf = hc_buf + tofs;
557 magic = *(u32 *)lbuf;
558
559 ret = -ENODATA;
560 switch (magic) {
561 case RB_MAGIC_LZOR:
562 /* Skip magic */
563 lbuf += sizeof(magic);
564 tlen -= sizeof(magic);
565 ret = hc_wlan_data_unpack_lzor(lbuf, tlen, outbuf, outlen);
566 break;
567 case RB_MAGIC_ERD:
568 /* Skip magic */
569 lbuf += sizeof(magic);
570 tlen -= sizeof(magic);
571 ret = hc_wlan_data_unpack_erd(lbuf, tlen, outbuf, outlen);
572 break;
573 default:
574 /*
575 * If the RB_ID_WLAN_DATA payload doesn't start with a
576 * magic number, the payload itself is the raw RLE-encoded
577 * calibration data.
578 */
579 ret = routerboot_rle_decode(lbuf, tlen, outbuf, outlen);
580 if (ret)
581 pr_debug(RB_HC_PR_PFX "RLE decoding error (%d)\n", ret);
582 break;
583 }
584
585 return ret;
586 }
587
588 static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
589 char *buf)
590 {
591 const struct hc_attr *hc_attr;
592 const u8 *pld;
593 u16 pld_len;
594
595 hc_attr = container_of(attr, typeof(*hc_attr), kattr);
596
597 if (!hc_attr->pld_len)
598 return -ENOENT;
599
600 pld = hc_buf + hc_attr->pld_ofs;
601 pld_len = hc_attr->pld_len;
602
603 return hc_attr->tshow(pld, pld_len, buf);
604 }
605
606 /*
607 * This function will allocate and free memory every time it is called. This
608 * is not the fastest way to do this, but since the data is rarely read (mainly
609 * at boot time to load wlan caldata), this makes it possible to save memory for
610 * the system.
611 */
612 static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj,
613 struct bin_attribute *attr, char *buf,
614 loff_t off, size_t count)
615 {
616 struct hc_wlan_attr *hc_wattr;
617 size_t outlen;
618 void *outbuf;
619 int ret;
620
621 hc_wattr = container_of(attr, typeof(*hc_wattr), battr);
622
623 if (!hc_wattr->pld_len)
624 return -ENOENT;
625
626 outlen = RB_ART_SIZE;
627
628 /* Don't bother unpacking if the source is already too large */
629 if (hc_wattr->pld_len > outlen)
630 return -EFBIG;
631
632 outbuf = kmalloc(outlen, GFP_KERNEL);
633 if (!outbuf)
634 return -ENOMEM;
635
636 ret = hc_wlan_data_unpack(hc_wattr->pld_ofs, hc_wattr->pld_len, outbuf, &outlen);
637 if (ret) {
638 kfree(outbuf);
639 return ret;
640 }
641
642 if (off >= outlen) {
643 kfree(outbuf);
644 return 0;
645 }
646
647 if (off + count > outlen)
648 count = outlen - off;
649
650 memcpy(buf, outbuf + off, count);
651
652 kfree(outbuf);
653 return count;
654 }
655
656 int __init rb_hardconfig_init(struct kobject *rb_kobj)
657 {
658 struct mtd_info *mtd;
659 size_t bytes_read, buflen;
660 const u8 *buf;
661 int i, ret;
662 u32 magic;
663
664 hc_buf = NULL;
665 hc_kobj = NULL;
666
667 // TODO allow override
668 mtd = get_mtd_device_nm(RB_MTD_HARD_CONFIG);
669 if (IS_ERR(mtd))
670 return -ENODEV;
671
672 hc_buflen = mtd->size;
673 hc_buf = kmalloc(hc_buflen, GFP_KERNEL);
674 if (!hc_buf)
675 return -ENOMEM;
676
677 ret = mtd_read(mtd, 0, hc_buflen, &bytes_read, hc_buf);
678
679 if (ret)
680 goto fail;
681
682 if (bytes_read != hc_buflen) {
683 ret = -EIO;
684 goto fail;
685 }
686
687 /* Check we have what we expect */
688 magic = *(const u32 *)hc_buf;
689 if (RB_MAGIC_HARD != magic) {
690 ret = -EINVAL;
691 goto fail;
692 }
693
694 /* Skip magic */
695 buf = hc_buf + sizeof(magic);
696 buflen = hc_buflen - sizeof(magic);
697
698 /* Populate sysfs */
699 ret = -ENOMEM;
700 hc_kobj = kobject_create_and_add(RB_MTD_HARD_CONFIG, rb_kobj);
701 if (!hc_kobj)
702 goto fail;
703
704 /* Locate and publish all known tags */
705 for (i = 0; i < ARRAY_SIZE(hc_attrs); i++) {
706 ret = routerboot_tag_find(buf, buflen, hc_attrs[i].tag_id,
707 &hc_attrs[i].pld_ofs, &hc_attrs[i].pld_len);
708 if (ret) {
709 hc_attrs[i].pld_ofs = hc_attrs[i].pld_len = 0;
710 continue;
711 }
712
713 /* Account for skipped magic */
714 hc_attrs[i].pld_ofs += sizeof(magic);
715
716 /* Special case RB_ID_WLAN_DATA to prep and create the binary attribute */
717 if ((RB_ID_WLAN_DATA == hc_attrs[i].tag_id) && hc_attrs[i].pld_len) {
718 hc_wlandata_battr.pld_ofs = hc_attrs[i].pld_ofs;
719 hc_wlandata_battr.pld_len = hc_attrs[i].pld_len;
720
721 ret = sysfs_create_bin_file(hc_kobj, &hc_wlandata_battr.battr);
722 if (ret)
723 pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n",
724 hc_wlandata_battr.battr.attr.name, ret);
725 }
726 /* All other tags are published via standard attributes */
727 else {
728 ret = sysfs_create_file(hc_kobj, &hc_attrs[i].kattr.attr);
729 if (ret)
730 pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n",
731 hc_attrs[i].kattr.attr.name, ret);
732 }
733 }
734
735 pr_info("MikroTik RouterBOARD hardware configuration sysfs driver v" RB_HARDCONFIG_VER "\n");
736
737 return 0;
738
739 fail:
740 kfree(hc_buf);
741 hc_buf = NULL;
742 return ret;
743 }
744
745 void __exit rb_hardconfig_exit(void)
746 {
747 kobject_put(hc_kobj);
748 kfree(hc_buf);
749 }