atsectl.c revision 256946
1/*- 2 * Copyright (c) 2012 SRI International 3 * Copyright (c) 2013 Bjoern A. Zeeb 4 * All rights reserved. 5 * 6 * This software was developed by SRI International and the University of 7 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 8 * ("CTSRD"), as part of the DARPA CRASH research programme. 9 * 10 * This software was developed by SRI International and the University of 11 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249) 12 * ("MRC2"), as part of the DARPA MRC research programme. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $ FreeBSD: head/usr.sbin/isfctl/isfctl.c 239685 2012-08-25 18:08:20Z brooks $ 36 * $FreeBSD: head/tools/tools/atsectl/atsectl.c 256946 2013-10-22 22:17:48Z brooks $ 37 */ 38 39#include <sys/types.h> 40#include <sys/ioctl.h> 41#include <sys/endian.h> 42#include <sys/errno.h> 43#include <sys/socket.h> 44 45#include <assert.h> 46#include <err.h> 47#include <fcntl.h> 48#include <inttypes.h> 49#include <kenv.h> 50#include <md5.h> 51#include <stdlib.h> 52#include <stdio.h> 53#include <string.h> 54#include <unistd.h> 55 56#include <net/if_dl.h> 57#include <net/ethernet.h> 58 59 60#define CONFIG_BLOCK (128 * 1024) 61#define DEV_CFI0_PATH "/dev/cfi0" 62 63static u_char block[CONFIG_BLOCK]; 64 65#define UNKNOWN 0 66#define CFI 1 67static int fdev = UNKNOWN; 68static const char *fdevs[] = { 69 "UNKNOWN", 70 "CFI" 71}; 72static int gflag; 73 74/* XXX-BZ should include if_atsereg.h. */ 75#define ALTERA_ETHERNET_OPTION_BITS_OFF 0x00008000 76#define ALTERA_ETHERNET_OPTION_BITS_LEN 0x00007fff 77 78 79static void 80usage(int rc) 81{ 82 83 fprintf(stderr, "usage: atsectl [-ghlu] [-s <etheraddr>]\n"); 84 exit(rc); 85} 86 87static void 88read_block(void) 89{ 90 int fd; 91 92 fd = open(DEV_CFI0_PATH, O_RDONLY, 0); 93 if (fd == -1) 94 errx(1, "Failed to open " DEV_CFI0_PATH); 95 else 96 fdev = CFI; 97 98 if (read(fd, block, sizeof(block)) != CONFIG_BLOCK) 99 errx(1, "Short read from %s", fdevs[fdev]); 100 101 close(fd); 102} 103 104static void 105write_block(void) 106{ 107 int fd; 108 109 assert(fdev == CFI); 110 111 fd = open(DEV_CFI0_PATH, O_WRONLY, 0); 112 if (fd == -1) 113 errx(1, "Failed to open " DEV_CFI0_PATH); 114 115 if (write(fd, block, sizeof(block)) != CONFIG_BLOCK) 116 errx(1, "Short write on %s", fdevs[fdev]); 117 118 close(fd); 119} 120 121static void 122print_eaddr(void) 123{ 124 uint32_t safe; 125 126 /* 127 * XXX-BZ we are on our own: keep in sync with atse(4). 128 * Everything past the first address is a guess currently. 129 * So we will always only write one address into there. 130 */ 131#if 0 132root@cheri1:/root # dd if=/dev/isf0 bs=32k skip=1 count=1 | hd 13300000000 fe 5a 00 00 00 07 ed ff ed 15 ff ff c0 a8 01 ea |.Z..............| 13400000010 ff ff ff ff ff ff ff 00 c0 a8 01 ff ff ff ff ff |................| 13500000020 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| 136* 1371+0 records in 1381+0 records out 13932768 bytes transferred in 0.053036 secs (617845 bytes/sec) 14000008000 141#endif 142 143 safe = block[ALTERA_ETHERNET_OPTION_BITS_OFF + 0] << 24; 144 safe |= block[ALTERA_ETHERNET_OPTION_BITS_OFF + 1] << 16; 145 safe |= block[ALTERA_ETHERNET_OPTION_BITS_OFF + 2] << 8; 146 safe |= block[ALTERA_ETHERNET_OPTION_BITS_OFF + 3]; 147 148 printf("%02x:%02x:%02x:%02x:%02x:%02x%s\n", 149 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 4], 150 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 5], 151 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 6], 152 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 7], 153 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 8], 154 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 9], 155 (safe != le32toh(0x00005afe)) ? 156 " (invalid control pattern)" : ""); 157} 158 159static void 160list(void) 161{ 162 163 read_block(); 164 print_eaddr(); 165 exit(0); 166} 167 168static void 169_set(uint8_t *eaddr) 170{ 171 uint8_t buf[32]; 172 MD5_CTX ctx; 173 int rc; 174 175 printf("Original:\n"); 176 read_block(); 177 print_eaddr(); 178 179 if (eaddr == NULL) { 180 /* cfi0.factory_ppr="0x0123456789abcdef" */ 181 rc = kenv(KENV_GET, "cfi0.factory_ppr", buf, sizeof(buf)); 182 if (rc == -1) 183 err(1, "Could not find Intel flash PPR serial\n"); 184 185 MD5Init(&ctx); 186 MD5Update(&ctx, buf+2, 16); 187 MD5Final(buf, &ctx); 188 189 /* Set the device specifc address (prefix). */ 190 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 7] = 191 buf[14] << 4 | buf[13] >> 4; 192 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 8] = 193 buf[13] << 4 | buf[12] >> 4; 194 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 9] = buf[12] << 4; 195 /* Just make sure the last half-byte is really zero. */ 196 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 9] &= ~0x0f; 197 198 /* Set (or clear) locally administred flag. */ 199 if (gflag == 0) 200 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 4] |= 2; 201 else 202 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 4] &= ~2; 203 /* Make sure it is not a MC address by accident we start with. */ 204 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 4] &= ~1; 205 } else { 206 int e; 207 208 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 4] = eaddr[0]; 209 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 5] = eaddr[1]; 210 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 6] = eaddr[2]; 211 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 7] = eaddr[3]; 212 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 8] = eaddr[4]; 213 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 9] = eaddr[5]; 214 215 e = 0; 216 if ((eaddr[5] & 0xf) != 0x0) { 217 e++; 218 warnx("WARN: Selected Ethernet Address is " 219 "not multi-MAC compatible.\n"); 220 } 221 if (gflag == 0 && ((eaddr[0] & 0x2) == 0x0)) { 222 e++; 223 warnx("WARN: Locally administered bit not set.\n"); 224 } 225 if ((eaddr[0] & 0x1) != 0x0) { 226 e++; 227 warnx("WARN: You are setting a Multicast address.\n"); 228 } 229 if (e != 0) 230 warnx("Suggesting to re-run with: " 231 "%02x:%02x:%02x:%02x:%02x:%02x", 232 (eaddr[0] & 0xfe) | 0x2, 233 eaddr[1], eaddr[2], eaddr[3], eaddr[4], 234 eaddr[5] & 0xf0); 235 } 236 237 /* Write the "safe" out, just to be sure. */ 238 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 0] = 0xfe; 239 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 1] = 0x5a; 240 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 2] = 0x00; 241 block[ALTERA_ETHERNET_OPTION_BITS_OFF + 3] = 0x00; 242 243 write_block(); 244 245 printf("Updated to:\n"); 246 read_block(); 247 print_eaddr(); 248 exit(0); 249} 250 251static void 252update(void) 253{ 254 255 _set(NULL); 256 exit(0); 257} 258 259static void 260set(char *eaddrstr) 261{ 262 uint8_t eaddr[ETHER_ADDR_LEN]; 263 char *p; 264 long l; 265 int i; 266 267 memset(eaddr, 0x00, ETHER_ADDR_LEN); 268 i = 0; 269 while ((p = strsep(&eaddrstr, ":")) != NULL && i < ETHER_ADDR_LEN) { 270 errno = 0; 271 l = strtol(p, (char **)NULL, 16); 272 if (l == 0 && errno != 0) 273 errx(1, "Failed to parse Ethernet address given: %s\n", p); 274 if (l < 0x00 || l > 0xff) 275 errx(1, "Failed to parse Ethernet address given: %lx\n", l); 276 eaddr[i++] = strtol(p, (char **)NULL, 16); 277 } 278 279 if (i != ETHER_ADDR_LEN) 280 errx(1, "Failed to parse Ethernet address given\n"); 281 282 _set(eaddr); 283 exit(0); 284} 285 286int 287main(int argc, char **argv) 288{ 289 char ch, *s; 290 291 s = NULL; 292 while ((ch = getopt(argc, argv, "ghlus:")) != -1) { 293 switch (ch) { 294 case 'g': 295 gflag = 1; 296 break; 297 case 'h': 298 usage(0); 299 /* NOTREACHED */ 300 break; 301 case 'l': 302 list(); 303 /* NOTREACHED */ 304 break; 305 case 'u': 306 update(); 307 /* NOTREACHED */ 308 break; 309 310 case 's': 311 set(optarg); 312 /* NOTREACHED */ 313 break; 314 315 case '?': 316 default: 317 usage(1); 318 /* NOTREACHED */ 319 break; 320 } 321 } 322 323 usage(1); 324 /* NOTREACHED */ 325 326 return (0); 327} 328