/* $NetBSD: iplsum.c,v 1.2 2015/12/13 18:38:23 christos Exp $ */
/*
* Calculate 32bit checksum of IPL and store in a certain location
*
* Written in 2003 by ITOH Yasufumi.
* Public domain
*/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#ifndef __BIT_TYPES_DEFINED__
typedef unsigned int uint32_t;
#endif
/* see README.ipl */
#define IPLOFF (4*1024) /* 4KB */
#define IPL1SIZE (4*1024) /* 4KB */
#define IPL2SIZE (1*1024) /* 1KB */
#define IPL2ONDISK 0x0400
#define IPL3SIZE (3*512) /* 1.5KB */
#define IPL3ONDISK 0x0A00
#define IPLSIZE (IPL1SIZE + IPL2SIZE + IPL3SIZE)
#define BOOTSIZE (IPLOFF + IPLSIZE)
#define BOOTBLOCKSIZE 8192
uint32_t bootblk[BOOTSIZE / sizeof(uint32_t) + 1];
#define SUMOFF ((IPLOFF + 4) / sizeof(uint32_t))
#ifdef __STDC__
int main(int, char *[]);
#endif
int
main(int argc, char *argv[])
{
FILE *fp;
int len;
uint32_t sum, *p;
int iploff, iplsumsize;
if (argc != 3) {
fprintf(stderr, "usage: %s <input> <output>\n", argv[0]);
return 1;
}
/* read file */
if ((fp = fopen(argv[1], "rb")) == NULL) {
perror(argv[1]);
return 1;
}
if ((len = fread(bootblk, 1, sizeof bootblk, fp)) <= IPLOFF) {
fclose(fp);
fprintf(stderr, "%s: too short\n", argv[1]);
return 1;
} else if (len > BOOTSIZE) {
fclose(fp);
fprintf(stderr, "%s: too long (%d vs %d)\n", argv[1], len, BOOTSIZE);
return 1;
}
(void) fclose(fp);
/* sanity check */
if ((ntohl(bootblk[0]) & 0xffff0000) != 0x80000000) {
fprintf(stderr, "%s: bad LIF magic\n", argv[1]);
return 1;
}
iploff = ntohl(bootblk[0xf0 / sizeof(uint32_t)]);
iplsumsize = ntohl(bootblk[0xf4 / sizeof(uint32_t)]);
printf("%d bytes free, ipl offset = %d, ipl sum size = %d\n",
BOOTSIZE - len, iploff, iplsumsize);
if (iploff != IPLOFF || iplsumsize <= 0 || iplsumsize % 2048 ||
iploff + iplsumsize > BOOTBLOCKSIZE) {
fprintf(stderr, "%s: bad ipl offset / size\n", argv[1]);
return 1;
}
/* checksum */
sum = 0;
for (p = bootblk + IPLOFF / sizeof(uint32_t);
p < bootblk + (IPLOFF + IPL1SIZE) / sizeof(uint32_t); p++)
sum += ntohl(*p);
bootblk[SUMOFF] = htonl(ntohl(bootblk[SUMOFF]) - sum);
/* transfer ipl part 2 */
memcpy(bootblk + IPL2ONDISK / sizeof(uint32_t),
bootblk + (IPLOFF + IPL1SIZE) / sizeof(uint32_t),
IPL2SIZE);
/* transfer ipl part 3 */
memcpy(bootblk + IPL3ONDISK / sizeof(uint32_t),
bootblk + (IPLOFF + IPL1SIZE + IPL2SIZE) / sizeof(uint32_t),
IPL3SIZE);
/* write file */
if ((fp = fopen(argv[2], "wb")) == NULL) {
perror(argv[2]);
return 1;
}
if ((len = fwrite(bootblk, 1, BOOTBLOCKSIZE, fp)) != BOOTBLOCKSIZE) {
if (len < 0)
perror(argv[2]);
else
fprintf(stderr, "%s: short write\n", argv[2]);
fclose(fp);
(void) remove(argv[2]);
return 1;
}
if (fclose(fp)) {
perror(argv[2]);
(void) remove(argv[2]);
return 1;
}
return 0;
}