1 /* $NetBSD: iplsum.c,v 1.2 2015/12/13 18:38:23 christos Exp $ */ 2 3 /* 4 * Calculate 32bit checksum of IPL and store in a certain location 5 * 6 * Written in 2003 by ITOH Yasufumi. 7 * Public domain 8 */ 9 10 #include <sys/types.h> 11 #include <stdio.h> 12 #include <string.h> 13 #include <netinet/in.h> 14 15 #ifndef __BIT_TYPES_DEFINED__ 16 typedef unsigned int uint32_t; 17 #endif 18 19 /* see README.ipl */ 20 #define IPLOFF (4*1024) /* 4KB */ 21 #define IPL1SIZE (4*1024) /* 4KB */ 22 #define IPL2SIZE (1*1024) /* 1KB */ 23 #define IPL2ONDISK 0x0400 24 #define IPL3SIZE (3*512) /* 1.5KB */ 25 #define IPL3ONDISK 0x0A00 26 #define IPLSIZE (IPL1SIZE + IPL2SIZE + IPL3SIZE) 27 #define BOOTSIZE (IPLOFF + IPLSIZE) 28 #define BOOTBLOCKSIZE 8192 29 30 uint32_t bootblk[BOOTSIZE / sizeof(uint32_t) + 1]; 31 32 #define SUMOFF ((IPLOFF + 4) / sizeof(uint32_t)) 33 34 #ifdef __STDC__ 35 int main(int, char *[]); 36 #endif 37 38 int 39 main(int argc, char *argv[]) 40 { 41 FILE *fp; 42 int len; 43 uint32_t sum, *p; 44 int iploff, iplsumsize; 45 46 if (argc != 3) { 47 fprintf(stderr, "usage: %s <input> <output>\n", argv[0]); 48 return 1; 49 } 50 51 /* read file */ 52 if ((fp = fopen(argv[1], "rb")) == NULL) { 53 perror(argv[1]); 54 return 1; 55 } 56 if ((len = fread(bootblk, 1, sizeof bootblk, fp)) <= IPLOFF) { 57 fclose(fp); 58 fprintf(stderr, "%s: too short\n", argv[1]); 59 return 1; 60 } else if (len > BOOTSIZE) { 61 fclose(fp); 62 fprintf(stderr, "%s: too long (%d vs %d)\n", argv[1], len, BOOTSIZE); 63 return 1; 64 } 65 (void) fclose(fp); 66 67 /* sanity check */ 68 if ((ntohl(bootblk[0]) & 0xffff0000) != 0x80000000) { 69 fprintf(stderr, "%s: bad LIF magic\n", argv[1]); 70 return 1; 71 } 72 iploff = ntohl(bootblk[0xf0 / sizeof(uint32_t)]); 73 iplsumsize = ntohl(bootblk[0xf4 / sizeof(uint32_t)]); 74 printf("%d bytes free, ipl offset = %d, ipl sum size = %d\n", 75 BOOTSIZE - len, iploff, iplsumsize); 76 if (iploff != IPLOFF || iplsumsize <= 0 || iplsumsize % 2048 || 77 iploff + iplsumsize > BOOTBLOCKSIZE) { 78 fprintf(stderr, "%s: bad ipl offset / size\n", argv[1]); 79 return 1; 80 } 81 82 /* checksum */ 83 sum = 0; 84 for (p = bootblk + IPLOFF / sizeof(uint32_t); 85 p < bootblk + (IPLOFF + IPL1SIZE) / sizeof(uint32_t); p++) 86 sum += ntohl(*p); 87 88 bootblk[SUMOFF] = htonl(ntohl(bootblk[SUMOFF]) - sum); 89 90 /* transfer ipl part 2 */ 91 memcpy(bootblk + IPL2ONDISK / sizeof(uint32_t), 92 bootblk + (IPLOFF + IPL1SIZE) / sizeof(uint32_t), 93 IPL2SIZE); 94 95 /* transfer ipl part 3 */ 96 memcpy(bootblk + IPL3ONDISK / sizeof(uint32_t), 97 bootblk + (IPLOFF + IPL1SIZE + IPL2SIZE) / sizeof(uint32_t), 98 IPL3SIZE); 99 100 /* write file */ 101 if ((fp = fopen(argv[2], "wb")) == NULL) { 102 perror(argv[2]); 103 return 1; 104 } 105 if ((len = fwrite(bootblk, 1, BOOTBLOCKSIZE, fp)) != BOOTBLOCKSIZE) { 106 if (len < 0) 107 perror(argv[2]); 108 else 109 fprintf(stderr, "%s: short write\n", argv[2]); 110 fclose(fp); 111 (void) remove(argv[2]); 112 return 1; 113 } 114 if (fclose(fp)) { 115 perror(argv[2]); 116 (void) remove(argv[2]); 117 return 1; 118 } 119 120 return 0; 121 } 122