Home | History | Annotate | Line # | Download | only in eeprom
      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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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