1107120Sjulian/* 2107120Sjulian * bt3cfw.c 3107120Sjulian * 4107120Sjulian * Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5107120Sjulian * All rights reserved. 6107120Sjulian * 7107120Sjulian * Redistribution and use in source and binary forms, with or without 8107120Sjulian * modification, are permitted provided that the following conditions 9107120Sjulian * are met: 10107120Sjulian * 1. Redistributions of source code must retain the above copyright 11107120Sjulian * notice, this list of conditions and the following disclaimer. 12107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright 13107120Sjulian * notice, this list of conditions and the following disclaimer in the 14107120Sjulian * documentation and/or other materials provided with the distribution. 15107120Sjulian * 16107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26107120Sjulian * SUCH DAMAGE. 27107120Sjulian * 28121054Semax * $Id: bt3cfw.c,v 1.2 2003/05/21 22:40:29 max Exp $ 29107120Sjulian * $FreeBSD$ 30107120Sjulian */ 31107120Sjulian 32107120Sjulian#include <sys/types.h> 33107120Sjulian#include <errno.h> 34107120Sjulian#include <netgraph.h> 35121054Semax#include <netgraph/bluetooth/include/ng_bt3c.h> 36107120Sjulian#include <stdarg.h> 37107120Sjulian#include <stdio.h> 38107120Sjulian#include <stdlib.h> 39107120Sjulian#include <string.h> 40107120Sjulian#include <syslog.h> 41107120Sjulian#include <unistd.h> 42107120Sjulian 43107120Sjulian#define BT3CFW_IDENT "bt3cfw" 44107120Sjulian#define BT3CFW_MAX_FIRMWARE_SIZE 0xffff 45107120Sjulian 46107120Sjulian/* Convert hex ASCII to int4 */ 47107120Sjulianstatic int 48107120Sjulianhexa2int4(const char *a) 49107120Sjulian{ 50107120Sjulian if ('0' <= *a && *a <= '9') 51107120Sjulian return (*a - '0'); 52107120Sjulian 53107120Sjulian if ('A' <= *a && *a <= 'F') 54107120Sjulian return (*a - 'A' + 0xa); 55107120Sjulian 56107120Sjulian if ('a' <= *a && *a <= 'f') 57107120Sjulian return (*a - 'a' + 0xa); 58107120Sjulian 59107120Sjulian syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a); 60107120Sjulian exit(255); 61107120Sjulian} 62107120Sjulian 63107120Sjulian/* Convert hex ASCII to int8 */ 64107120Sjulianstatic int 65107120Sjulianhexa2int8(const char *a) 66107120Sjulian{ 67107120Sjulian return ((hexa2int4(a) << 4) | hexa2int4(a + 1)); 68107120Sjulian} 69107120Sjulian 70107120Sjulian/* Convert hex ASCII to int16 */ 71107120Sjulianstatic int 72107120Sjulianhexa2int16(const char *a) 73107120Sjulian{ 74107120Sjulian return ((hexa2int8(a) << 8) | hexa2int8(a + 2)); 75107120Sjulian} 76107120Sjulian 77107120Sjulian/* Convert hex ASCII to int32 */ 78107120Sjulianstatic int 79107120Sjulianhexa2int32(const char *a) 80107120Sjulian{ 81107120Sjulian return ((hexa2int16(a) << 16) | hexa2int16(a + 4)); 82107120Sjulian} 83107120Sjulian 84107120Sjulian/* Display usage() and exit */ 85107120Sjulianstatic void 86107120Sjulianusage(void) 87107120Sjulian{ 88107120Sjulian syslog(LOG_ERR, "Usage: %s -f FirmwareFile -n NodeName", BT3CFW_IDENT); 89107120Sjulian exit(255); 90107120Sjulian} 91107120Sjulian 92107120Sjulian/* Main */ 93107120Sjulianint 94107120Sjulianmain(int argc, char *argv[]) 95107120Sjulian{ 96128079Semax FILE *firmware_file = NULL; 97128079Semax char buffer[80], path[NG_PATHSIZ], 98128079Semax *firmware_filename = NULL; 99128079Semax uint8_t *firmware = NULL; 100128079Semax int firmware_size, opt, cs, ds; 101107120Sjulian 102107120Sjulian memset(path, 0, sizeof(path)); 103107120Sjulian openlog(BT3CFW_IDENT, LOG_NDELAY|LOG_PID|LOG_PERROR, LOG_USER); 104107120Sjulian 105107120Sjulian while ((opt = getopt(argc, argv, "f:hn:")) != -1) { 106107120Sjulian switch (opt) { 107107120Sjulian case 'f': 108107120Sjulian firmware_filename = optarg; 109107120Sjulian break; 110107120Sjulian 111107120Sjulian case 'n': 112107120Sjulian snprintf(path, sizeof(path), "%s:", optarg); 113107120Sjulian break; 114107120Sjulian 115107120Sjulian case 'h': 116107120Sjulian default: 117107120Sjulian usage(); 118107120Sjulian /* NOT REACHED */ 119107120Sjulian } 120107120Sjulian } 121107120Sjulian 122107120Sjulian if (firmware_filename == NULL || path[0] == 0) 123107120Sjulian usage(); 124107120Sjulian /* NOT REACHED */ 125107120Sjulian 126128079Semax firmware = (uint8_t *) calloc(BT3CFW_MAX_FIRMWARE_SIZE, 127128079Semax sizeof(uint8_t)); 128107120Sjulian if (firmware == NULL) { 129107120Sjulian syslog(LOG_ERR, "Could not allocate firmware buffer"); 130107120Sjulian exit(255); 131107120Sjulian } 132107120Sjulian 133107120Sjulian if ((firmware_file = fopen(firmware_filename, "r")) == NULL) { 134107120Sjulian syslog(LOG_ERR, "Could not open BT3C firmware file %s. %s (%d)", 135107120Sjulian firmware_filename, strerror(errno), errno); 136107120Sjulian exit(255); 137107120Sjulian } 138107120Sjulian 139107120Sjulian firmware_size = 0; 140107120Sjulian 141107120Sjulian while (fgets(buffer, sizeof(buffer), firmware_file)) { 142107120Sjulian int i, size, address, cs, fcs; 143107120Sjulian 144107120Sjulian size = hexa2int8(buffer + 2); 145107120Sjulian address = hexa2int32(buffer + 4); 146107120Sjulian fcs = hexa2int8(buffer + 2 + size * 2); 147107120Sjulian 148107120Sjulian if (buffer[1] == '3') { 149107120Sjulian ng_bt3c_firmware_block_ep *block = NULL; 150128079Semax uint16_t *data = NULL; 151107120Sjulian 152107120Sjulian block = (ng_bt3c_firmware_block_ep *) 153107120Sjulian (firmware + firmware_size); 154107120Sjulian 155107120Sjulian firmware_size += sizeof(*block); 156107120Sjulian if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) { 157107120Sjulian syslog(LOG_ERR, "Could not add new firmware " \ 158107120Sjulian "block. Firmware file %s is " \ 159107120Sjulian "too big, firmware_size=%d", 160107120Sjulian firmware_filename, 161107120Sjulian firmware_size); 162107120Sjulian exit(255); 163107120Sjulian } 164107120Sjulian 165107120Sjulian block->block_address = address; 166107120Sjulian block->block_size = (size - 4) / 2; 167107120Sjulian block->block_alignment = (block->block_size * 2) % 3; 168107120Sjulian if (block->block_alignment != 0) 169107120Sjulian block->block_alignment = 3 - block->block_alignment; 170107120Sjulian 171107120Sjulian firmware_size += (block->block_size * 2); 172107120Sjulian firmware_size += block->block_alignment; 173107120Sjulian if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) { 174107120Sjulian syslog(LOG_ERR, "Could not add new firmware " \ 175107120Sjulian "data. Firmware file %s is " \ 176107120Sjulian "too big, firmware_size=%d", 177107120Sjulian firmware_filename, 178107120Sjulian firmware_size); 179107120Sjulian exit(255); 180107120Sjulian } 181107120Sjulian 182107120Sjulian /* First part of the cheksum: size and address */ 183107120Sjulian cs = 0; 184107120Sjulian for (i = 0; i < 5; i++) 185107120Sjulian cs += hexa2int8(buffer + 2 + i * 2); 186107120Sjulian 187107120Sjulian /* Data + second part of the cheksum: data */ 188128079Semax data = (uint16_t *)(block + 1); 189107120Sjulian for (i = 0; i < block->block_size; i++) { 190107120Sjulian data[i] = hexa2int16(buffer + (i * 4) + 12); 191107120Sjulian cs += (((data[i] & 0xff00) >> 8) & 0xff); 192107120Sjulian cs += (data[i] & 0x00ff); 193107120Sjulian } 194107120Sjulian } else 195107120Sjulian for (cs = 0, i = 0; i < size; i++) 196107120Sjulian cs += hexa2int8(buffer + 2 + i * 2); 197107120Sjulian 198107120Sjulian if (((cs + fcs) & 0xff) != 0xff) { 199107120Sjulian syslog(LOG_ERR, "Invalid firmware file %s. Checksum " \ 200107120Sjulian "error, cs=%#x, fcs=%#x, checksum=%#x", 201107120Sjulian firmware_filename, (cs & 0xff), fcs, 202107120Sjulian ((cs + fcs) & 0xff)); 203107120Sjulian exit(255); 204107120Sjulian } 205107120Sjulian } 206107120Sjulian 207107120Sjulian /* Send firmware to the card */ 208107120Sjulian if (NgMkSockNode(NULL, &cs, &ds) < 0) { 209107120Sjulian syslog(LOG_ERR, "Could not create Netgraph socket. %s (%d)", 210107120Sjulian strerror(errno), errno); 211107120Sjulian exit(255); 212107120Sjulian } 213107120Sjulian 214107120Sjulian if (NgSendMsg(cs, path, NGM_BT3C_COOKIE, 215107120Sjulian NGM_BT3C_NODE_DOWNLOAD_FIRMWARE, 216107120Sjulian (void const *) firmware, firmware_size) < 0) { 217107120Sjulian syslog(LOG_ERR, "Could not send Netgraph message. %s (%d)", 218107120Sjulian strerror(errno), errno); 219107120Sjulian exit(255); 220107120Sjulian } 221107120Sjulian 222107120Sjulian free(firmware); 223107120Sjulian firmware = NULL; 224227876Skevlo fclose(firmware_file); 225107120Sjulian 226107120Sjulian return (0); 227107120Sjulian} 228107120Sjulian 229