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