xref: /netbsd-src/usr.sbin/eeprom/eehandlers.c (revision 630723670f6dbd04f83c13ea1da9c8e7ef00b09d)
1 /*	$NetBSD: eehandlers.c,v 1.19 2019/10/05 23:30:22 mrg Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/types.h>
33 #include <ctype.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41 #include <unistd.h>
42 #include <util.h>
43 #include <sys/inttypes.h>
44 
45 #include <machine/eeprom.h>
46 
47 #include "defs.h"
48 
49 extern	char *path_eeprom;
50 extern	int eval;
51 extern	int update_checksums;
52 extern	int ignore_checksum;
53 extern	int fix_checksum;
54 extern	int cksumfail;
55 extern	u_short writecount;
56 
57 static	char err_str[BUFSIZE];
58 
59 static	void badval(const struct keytabent *, char *);
60 static	int doio(const struct keytabent *, u_char *, ssize_t, int);
61 
62 static	u_char ee_checksum(u_char *, size_t);
63 static	void ee_hwupdate(const struct keytabent *, char *);
64 static	void ee_num8(const struct keytabent *, char *);
65 static	void ee_num16(const struct keytabent *, char *);
66 static	void ee_screensize(const struct keytabent *, char *);
67 static	void ee_truefalse(const struct keytabent *, char *);
68 static	void ee_bootdev(const struct keytabent *, char *);
69 static	void ee_kbdtype(const struct keytabent *, char *);
70 static	void ee_constype(const struct keytabent *, char *);
71 static	void ee_diagpath(const struct keytabent *, char *);
72 static	void ee_banner(const struct keytabent *, char *);
73 static	void ee_notsupp(const struct keytabent *, char *);
74 
75 static const struct	keytabent eekeytab[] = {
76 	{ "hwupdate",		0x10,	ee_hwupdate },
77 	{ "memsize",		0x14,	ee_num8 },
78 	{ "memtest",		0x15,	ee_num8 },
79 	{ "scrsize",		0x16,	ee_screensize },
80 	{ "watchdog_reboot",	0x17,	ee_truefalse },
81 	{ "default_boot",	0x18,	ee_truefalse },
82 	{ "bootdev",		0x19,	ee_bootdev },
83 	{ "kbdtype",		0x1e,	ee_kbdtype },
84 	{ "console",		0x1f,	ee_constype },
85 	{ "keyclick",		0x21,	ee_truefalse },
86 	{ "diagdev",		0x22,	ee_bootdev },
87 	{ "diagpath",		0x28,	ee_diagpath },
88 	{ "columns",		0x50,	ee_num8 },
89 	{ "rows",		0x51,	ee_num8 },
90 	{ "ttya_use_baud",	0x58,	ee_truefalse },
91 	{ "ttya_baud",		0x59,	ee_num16 },
92 	{ "ttya_no_rtsdtr",	0x5b,	ee_truefalse },
93 	{ "ttyb_use_baud",	0x60,	ee_truefalse },
94 	{ "ttyb_baud",		0x61,	ee_num16 },
95 	{ "ttyb_no_rtsdtr",	0x63,	ee_truefalse },
96 	{ "banner",		0x68,	ee_banner },
97 	{ "secure",		0,	ee_notsupp },
98 	{ "bad_login",		0,	ee_notsupp },
99 	{ "password",		0,	ee_notsupp },
100 	{ NULL,			0,	ee_notsupp },
101 };
102 
103 #define BARF(kt) {							\
104 	badval((kt), arg);						\
105 	++eval;								\
106 	return;								\
107 }
108 
109 #define FAILEDREAD(kt) {						\
110 	warnx("%s", err_str);						\
111 	warnx("failed to read field `%s'", (kt)->kt_keyword);		\
112 	++eval;								\
113 	return;								\
114 }
115 
116 #define FAILEDWRITE(kt) {						\
117 	warnx("%s", err_str);						\
118 	warnx("failed to update field `%s'", (kt)->kt_keyword);		\
119 	++eval;								\
120 	return;								\
121 }
122 
123 void
ee_action(char * keyword,char * arg)124 ee_action(char *keyword, char *arg)
125 {
126 	const struct keytabent *ktent;
127 
128 	for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent) {
129 		if (strcmp(ktent->kt_keyword, keyword) == 0) {
130 			(*ktent->kt_handler)(ktent, arg);
131 			return;
132 		}
133 	}
134 
135 	warnx("unknown keyword %s", keyword);
136 	++eval;
137 }
138 
139 void
ee_dump(void)140 ee_dump(void)
141 {
142 	const struct keytabent *ktent;
143 
144 	for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent)
145 		(*ktent->kt_handler)(ktent, NULL);
146 }
147 
148 static void
ee_hwupdate(const struct keytabent * ktent,char * arg)149 ee_hwupdate(const struct keytabent *ktent, char *arg)
150 {
151 	uint32_t hwtime;
152 	time_t t;
153 	char *cp, *cp2;
154 
155 	if (arg) {
156 		if ((strcmp(arg, "now") == 0) ||
157 		    (strcmp(arg, "today") == 0)) {
158 			if ((t = time(NULL)) == (time_t)(-1)) {
159 				warnx("can't get current time");
160 				++eval;
161 				return;
162 			}
163 		} else
164 			if ((t = parsedate(arg, NULL, NULL)) == (time_t)(-1))
165 				BARF(ktent);
166 		hwtime = (uint32_t)t;	/* XXX 32 bit time_t on hardware */
167 		if (hwtime != t)
168 			warnx("time overflow");
169 
170 		if (doio(ktent, (u_char *)&hwtime, sizeof(hwtime), IO_WRITE))
171 			FAILEDWRITE(ktent);
172 	} else {
173 		if (doio(ktent, (u_char *)&hwtime, sizeof(hwtime), IO_READ))
174 			FAILEDREAD(ktent);
175 		t = (time_t)hwtime;	/* XXX 32 bit time_t on hardware */
176 	}
177 
178 	cp = ctime(&t);
179 	if (cp != NULL && (cp2 = strrchr(cp, '\n')) != NULL)
180 		*cp2 = '\0';
181 
182 	printf("%s=%" PRId64, ktent->kt_keyword, (int64_t)t);
183 	if (cp != NULL)
184 		printf(" (%s)", cp);
185 	printf("\n");
186 }
187 
188 static void
ee_num8(const struct keytabent * ktent,char * arg)189 ee_num8(const struct keytabent *ktent, char *arg)
190 {
191 	u_char num8 = 0;
192 	u_int num32;
193 	int i;
194 
195 	if (arg) {
196 		for (i = 0; i < (int)strlen(arg) - 1; ++i)
197 			if (!isdigit((unsigned char)arg[i]))
198 				BARF(ktent);
199 		num32 = atoi(arg);
200 		if (num32 > 0xff)
201 			BARF(ktent);
202 		num8 += num32;
203 		if (doio(ktent, &num8, sizeof(num8), IO_WRITE))
204 			FAILEDWRITE(ktent);
205 	} else
206 		if (doio(ktent, &num8, sizeof(num8), IO_READ))
207 			FAILEDREAD(ktent);
208 
209 	printf("%s=%d\n", ktent->kt_keyword, num8);
210 }
211 
212 static void
ee_num16(const struct keytabent * ktent,char * arg)213 ee_num16(const struct keytabent *ktent, char *arg)
214 {
215 	u_int16_t num16 = 0;
216 	u_int num32;
217 	int i;
218 
219 	if (arg) {
220 		for (i = 0; i < (int)strlen(arg) - 1; ++i)
221 			if (!isdigit((unsigned char)arg[i]))
222 				BARF(ktent);
223 		num32 = atoi(arg);
224 		if (num32 > 0xffff)
225 			BARF(ktent);
226 		num16 += num32;
227 		if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_WRITE))
228 			FAILEDWRITE(ktent);
229 	} else
230 		if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_READ))
231 			FAILEDREAD(ktent);
232 
233 	printf("%s=%d\n", ktent->kt_keyword, num16);
234 }
235 
236 static	const struct strvaltabent scrsizetab[] = {
237 	{ "1152x900",		EE_SCR_1152X900 },
238 	{ "1024x1024",		EE_SCR_1024X1024 },
239 	{ "1600x1280",		EE_SCR_1600X1280 },
240 	{ "1440x1440",		EE_SCR_1440X1440 },
241 	{ NULL,			0 },
242 };
243 
244 static void
ee_screensize(const struct keytabent * ktent,char * arg)245 ee_screensize(const struct keytabent *ktent, char *arg)
246 {
247 	const struct strvaltabent *svp;
248 	u_char scsize;
249 
250 	if (arg) {
251 		for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
252 			if (strcmp(svp->sv_str, arg) == 0)
253 				break;
254 		if (svp->sv_str == NULL)
255 			BARF(ktent);
256 
257 		scsize = svp->sv_val;
258 		if (doio(ktent, &scsize, sizeof(scsize), IO_WRITE))
259 			FAILEDWRITE(ktent);
260 	} else {
261 		if (doio(ktent, &scsize, sizeof(scsize), IO_READ))
262 			FAILEDREAD(ktent);
263 
264 		for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
265 			if (svp->sv_val == scsize)
266 				break;
267 		if (svp->sv_str == NULL) {
268 			warnx("unknown %s value %d", ktent->kt_keyword,
269 			    scsize);
270 			return;
271 		}
272 	}
273 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
274 }
275 
276 static	const struct strvaltabent truthtab[] = {
277 	{ "true",		EE_TRUE },
278 	{ "false",		EE_FALSE },
279 	{ NULL,			0 },
280 };
281 
282 static void
ee_truefalse(const struct keytabent * ktent,char * arg)283 ee_truefalse(const struct keytabent *ktent, char *arg)
284 {
285 	const struct strvaltabent *svp;
286 	u_char truth;
287 
288 	if (arg) {
289 		for (svp = truthtab; svp->sv_str != NULL; ++svp)
290 			if (strcmp(svp->sv_str, arg) == 0)
291 				break;
292 		if (svp->sv_str == NULL)
293 			BARF(ktent);
294 
295 		truth = svp->sv_val;
296 		if (doio(ktent, &truth, sizeof(truth), IO_WRITE))
297 			FAILEDWRITE(ktent);
298 	} else {
299 		if (doio(ktent, &truth, sizeof(truth), IO_READ))
300 			FAILEDREAD(ktent);
301 
302 		for (svp = truthtab; svp->sv_str != NULL; ++svp)
303 			if (svp->sv_val == truth)
304 				break;
305 		if (svp->sv_str == NULL) {
306 			warnx("unknown truth value 0x%x for %s", truth,
307 			    ktent->kt_keyword);
308 			return;
309 		}
310 	}
311 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
312 }
313 
314 static void
ee_bootdev(const struct keytabent * ktent,char * arg)315 ee_bootdev(const struct keytabent *ktent, char *arg)
316 {
317 	u_char dev[5];
318 	int i;
319 	size_t arglen;
320 	char *cp;
321 
322 	if (arg) {
323 		/*
324 		 * The format of the string we accept is the following:
325 		 *	cc(n,n,n)
326 		 * where:
327 		 *	c -- an alphabetical character [a-z]
328 		 *	n -- a number in hexadecimal, between 0 and ff,
329 		 *	     with no leading `0x'.
330 		 */
331 		arglen = strlen(arg);
332 		if (arglen < 9 || arglen > 12 || arg[2] != '(' ||
333 		     arg[arglen - 1] != ')')
334 			BARF(ktent);
335 
336 		/* Handle the first 2 letters. */
337 		for (i = 0; i < 2; ++i) {
338 			if (arg[i] < 'a' || arg[i] > 'z')
339 				BARF(ktent);
340 			dev[i] = (u_char)arg[i];
341 		}
342 
343 		/* Handle the 3 `0x'-less hex values. */
344 		cp = &arg[3];
345 		for (i = 2; i < 5; ++i) {
346 			if (*cp == '\0')
347 				BARF(ktent);
348 
349 			if (*cp >= '0' && *cp <= '9')
350 				dev[i] = *cp++ - '0';
351 			else if (*cp >= 'a' && *cp <= 'f')
352 				dev[i] = 10 + (*cp++ - 'a');
353 			else
354 				BARF(ktent);
355 
356 			/* Deal with a second digit. */
357 			if (*cp >= '0' && *cp <= '9') {
358 				dev[i] <<= 4;
359 				dev[i] &= 0xf0;
360 				dev[i] += *cp++ - '0';
361 			} else if (*cp >= 'a' && *cp <= 'f') {
362 				dev[i] <<= 4;
363 				dev[i] &= 0xf0;
364 				dev[i] += 10 + (*cp++ - 'a');
365 			}
366 
367 			/* Ensure we have the correct delimiter. */
368 			if ((*cp == ',' && i < 4) || (*cp == ')' && i == 4)) {
369 				++cp;
370 				continue;
371 			} else
372 				BARF(ktent);
373 		}
374 		if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_WRITE))
375 			FAILEDWRITE(ktent);
376 	} else
377 		if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_READ))
378 			FAILEDREAD(ktent);
379 
380 	printf("%s=%c%c(%x,%x,%x)\n", ktent->kt_keyword, dev[0],
381 	     dev[1], dev[2], dev[3], dev[4]);
382 }
383 
384 static void
ee_kbdtype(const struct keytabent * ktent,char * arg)385 ee_kbdtype(const struct keytabent *ktent, char *arg)
386 {
387 	u_char kbd = 0;
388 	u_int kbd2;
389 	int i;
390 
391 	if (arg) {
392 		for (i = 0; i < (int)strlen(arg) - 1; ++i)
393 			if (!isdigit((unsigned char)arg[i]))
394 				BARF(ktent);
395 		kbd2 = atoi(arg);
396 		if (kbd2 > 0xff)
397 			BARF(ktent);
398 		kbd += kbd2;
399 		if (doio(ktent, &kbd, sizeof(kbd), IO_WRITE))
400 			FAILEDWRITE(ktent);
401 	} else
402 		if (doio(ktent, &kbd, sizeof(kbd), IO_READ))
403 			FAILEDREAD(ktent);
404 
405 	printf("%s=%d (%s)\n", ktent->kt_keyword, kbd, kbd ? "other" : "Sun");
406 }
407 
408 static	const struct strvaltabent constab[] = {
409 	{ "b&w",		EE_CONS_BW },
410 	{ "ttya",		EE_CONS_TTYA },
411 	{ "ttyb",		EE_CONS_TTYB },
412 	{ "color",		EE_CONS_COLOR },
413 	{ "p4opt",		EE_CONS_P4OPT },
414 	{ NULL,			0 },
415 };
416 
417 static void
ee_constype(const struct keytabent * ktent,char * arg)418 ee_constype(const struct keytabent *ktent, char *arg)
419 {
420 	const struct strvaltabent *svp;
421 	u_char cons;
422 
423 	if (arg) {
424 		for (svp = constab; svp->sv_str != NULL; ++svp)
425 			if (strcmp(svp->sv_str, arg) == 0)
426 				break;
427 		if (svp->sv_str == NULL)
428 			BARF(ktent);
429 
430 		cons = svp->sv_val;
431 		if (doio(ktent, &cons, sizeof(cons), IO_WRITE))
432 			FAILEDWRITE(ktent);
433 	} else {
434 		if (doio(ktent, &cons, sizeof(cons), IO_READ))
435 			FAILEDREAD(ktent);
436 
437 		for (svp = constab; svp->sv_str != NULL; ++svp)
438 			if (svp->sv_val == cons)
439 				break;
440 		if (svp->sv_str == NULL) {
441 			warnx("unknown type 0x%x for %s", cons,
442 			    ktent->kt_keyword);
443 			return;
444 		}
445 	}
446 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
447 
448 }
449 
450 static void
ee_diagpath(const struct keytabent * ktent,char * arg)451 ee_diagpath(const struct keytabent *ktent, char *arg)
452 {
453 	char path[40];
454 
455 	memset(path, 0, sizeof(path));
456 	if (arg) {
457 		if (strlen(arg) > sizeof(path))
458 			BARF(ktent);
459 		memcpy(path, arg, sizeof path);
460 		if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_WRITE))
461 			FAILEDWRITE(ktent);
462 	} else
463 		if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_READ))
464 			FAILEDREAD(ktent);
465 
466 	printf("%s=%s\n", ktent->kt_keyword, path);
467 }
468 
469 static void
ee_banner(const struct keytabent * ktent,char * arg)470 ee_banner(const struct keytabent *ktent, char *arg)
471 {
472 	char string[80];
473 	u_char enable;
474 	struct keytabent kt;
475 
476 	kt.kt_keyword = "enable_banner";
477 	kt.kt_offset = EE_BANNER_ENABLE_LOC;
478 	kt.kt_handler = ee_notsupp;
479 
480 	memset(string, '\0', sizeof(string));
481 	if (arg) {
482 		if (strlen(arg) > sizeof(string))
483 			BARF(ktent);
484 		if (*arg != '\0') {
485 			enable = EE_TRUE;
486 			memcpy(string, arg, sizeof string);
487 			if (doio(ktent, (u_char *)string,
488 			    sizeof(string), IO_WRITE))
489 				FAILEDWRITE(ktent);
490 		} else {
491 			enable = EE_FALSE;
492 			if (doio(ktent, (u_char *)string,
493 			    sizeof(string), IO_READ))
494 				FAILEDREAD(ktent);
495 		}
496 
497 		if (doio(&kt, &enable, sizeof(enable), IO_WRITE))
498 			FAILEDWRITE(&kt);
499 	} else {
500 		if (doio(ktent, (u_char *)string, sizeof(string), IO_READ))
501 			FAILEDREAD(ktent);
502 		if (doio(&kt, &enable, sizeof(enable), IO_READ))
503 			FAILEDREAD(&kt);
504 	}
505 	printf("%s=%s (%s)\n", ktent->kt_keyword, string,
506 	    enable == EE_TRUE ? "enabled" : "disabled");
507 }
508 
509 /* ARGSUSED */
510 static void
ee_notsupp(const struct keytabent * ktent,char * arg)511 ee_notsupp(const struct keytabent *ktent, char *arg)
512 {
513 
514 	warnx("field `%s' not yet supported", ktent->kt_keyword);
515 }
516 
517 static void
badval(const struct keytabent * ktent,char * arg)518 badval(const struct keytabent *ktent, char *arg)
519 {
520 
521 	warnx("inappropriate value `%s' for field `%s'", arg,
522 	    ktent->kt_keyword);
523 }
524 
525 static int
doio(const struct keytabent * ktent,u_char * buf,ssize_t len,int wr)526 doio(const struct keytabent *ktent, u_char *buf, ssize_t len, int wr)
527 {
528 	int fd, rval = 0;
529 	u_char *buf2;
530 
531 	buf2 = (u_char *)calloc(1, len);
532 	if (buf2 == NULL) {
533 		strncpy(err_str, "memory allocation failed", sizeof err_str);
534 		return (1);
535 	}
536 
537 	fd = open(path_eeprom, wr == IO_WRITE ? O_RDWR : O_RDONLY, 0640);
538 	if (fd < 0) {
539 		(void)snprintf(err_str, sizeof err_str, "open: %s: %s", path_eeprom,
540 		    strerror(errno));
541 		free(buf2);
542 		return (1);
543 	}
544 
545 	if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
546 		(void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
547 		    path_eeprom, strerror(errno));
548 		rval = 1;
549 		goto done;
550 	}
551 
552 	if (read(fd, buf2, len) != len) {
553 		(void)snprintf(err_str, sizeof err_str, "read: %s: %s",
554 		    path_eeprom, strerror(errno));
555 		return (1);
556 	}
557 
558 	if (wr == IO_WRITE) {
559 		if (memcmp(buf, buf2, len) == 0)
560 			goto done;
561 
562 		if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
563 			(void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
564 			    path_eeprom, strerror(errno));
565 			rval = 1;
566 			goto done;
567 		}
568 
569 		++update_checksums;
570 		if (write(fd, buf, len) < 0) {
571 			(void)snprintf(err_str, sizeof err_str, "write: %s: %s",
572 			    path_eeprom, strerror(errno));
573 			rval = 1;
574 			goto done;
575 		}
576 	} else
577 		memmove(buf, buf2, len);
578 
579  done:
580 	free(buf2);
581 	(void)close(fd);
582 	return (rval);
583 }
584 
585 /*
586  * Read from eeLastHwUpdate to just before eeReserved.  Calculate
587  * a checksum, and deposit 3 copies of it sequentially starting at
588  * eeChecksum[0].  Increment the write count, and deposit 3 copies
589  * of it sequentially starting at eeWriteCount[0].
590  */
591 void
ee_updatechecksums(void)592 ee_updatechecksums(void)
593 {
594 	struct keytabent kt;
595 	u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
596 	u_char checksum;
597 	int i;
598 
599 	kt.kt_keyword = "eeprom contents";
600 	kt.kt_offset = EE_HWUPDATE_LOC;
601 	kt.kt_handler = ee_notsupp;
602 
603 	if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
604 		cksumfail = 1;
605 		FAILEDREAD(&kt);
606 	}
607 
608 	checksum = ee_checksum(checkme, sizeof(checkme));
609 
610 	kt.kt_keyword = "eeprom checksum";
611 	for (i = 0; i < 4; ++i) {
612 		kt.kt_offset = EE_CKSUM_LOC + (i * sizeof(checksum));
613 		if (doio(&kt, &checksum, sizeof(checksum), IO_WRITE)) {
614 			cksumfail = 1;
615 			FAILEDWRITE(&kt);
616 		}
617 	}
618 
619 	kt.kt_keyword = "eeprom writecount";
620 	for (i = 0; i < 4; ++i) {
621 		kt.kt_offset = EE_WC_LOC + (i * sizeof(writecount));
622 		if (doio(&kt, (u_char *)&writecount, sizeof(writecount),
623 		    IO_WRITE)) {
624 			cksumfail = 1;
625 			FAILEDWRITE(&kt);
626 		}
627 	}
628 }
629 
630 void
ee_verifychecksums(void)631 ee_verifychecksums(void)
632 {
633 	struct keytabent kt;
634 	u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
635 	u_char checksum, ochecksum[3];
636 	u_short owritecount[3];
637 
638 	/*
639 	 * Verify that the EEPROM's write counts match, and update the
640 	 * global copy for use later.
641 	 */
642 	kt.kt_keyword = "eeprom writecount";
643 	kt.kt_offset = EE_WC_LOC;
644 	kt.kt_handler = ee_notsupp;
645 
646 	if (doio(&kt, (u_char *)&owritecount, sizeof(owritecount), IO_READ)) {
647 		cksumfail = 1;
648 		FAILEDREAD(&kt);
649 	}
650 
651 	if (owritecount[0] != owritecount[1] ||
652 	    owritecount[0] != owritecount[2]) {
653 		warnx("eeprom writecount mismatch %s",
654 		    ignore_checksum ? "(ignoring)" :
655 		    (fix_checksum ? "(fixing)" : ""));
656 
657 		if (!ignore_checksum && !fix_checksum) {
658 			cksumfail = 1;
659 			return;
660 		}
661 
662 		writecount = MAXIMUM(owritecount[0], owritecount[1]);
663 		writecount = MAXIMUM(writecount, owritecount[2]);
664 	} else
665 		writecount = owritecount[0];
666 
667 	/*
668 	 * Verify that the EEPROM's checksums match and are correct.
669 	 */
670 	kt.kt_keyword = "eeprom checksum";
671 	kt.kt_offset = EE_CKSUM_LOC;
672 
673 	if (doio(&kt, ochecksum, sizeof(ochecksum), IO_READ)) {
674 		cksumfail = 1;
675 		FAILEDREAD(&kt);
676 	}
677 
678 	if (ochecksum[0] != ochecksum[1] ||
679 	    ochecksum[0] != ochecksum[2]) {
680 		warnx("eeprom checksum mismatch %s",
681 		    ignore_checksum ? "(ignoring)" :
682 		    (fix_checksum ? "(fixing)" : ""));
683 
684 		if (!ignore_checksum && !fix_checksum) {
685 			cksumfail = 1;
686 			return;
687 		}
688 	}
689 
690 	kt.kt_keyword = "eeprom contents";
691 	kt.kt_offset = EE_HWUPDATE_LOC;
692 
693 	if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
694 		cksumfail = 1;
695 		FAILEDREAD(&kt);
696 	}
697 
698 	checksum = ee_checksum(checkme, sizeof(checkme));
699 
700 	if (ochecksum[0] != checksum) {
701 		warnx("eeprom checksum incorrect %s",
702 		    ignore_checksum ? "(ignoring)" :
703 		    (fix_checksum ? "(fixing)" : ""));
704 
705 		if (!ignore_checksum && !fix_checksum) {
706 			cksumfail = 1;
707 			return;
708 		}
709 	}
710 
711 	if (fix_checksum)
712 		ee_updatechecksums();
713 }
714 
715 static u_char
ee_checksum(u_char * area,size_t len)716 ee_checksum(u_char *area, size_t len)
717 {
718 	u_char sum = 0;
719 
720 	while (len--)
721 		sum += *area++;
722 
723 	return (0x100 - sum);
724 }
725