1/*- 2 * bt3cfw.c 3 * 4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5 * 6 * Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $Id: bt3cfw.c,v 1.2 2003/05/21 22:40:29 max Exp $ 31 * $FreeBSD: stable/11/usr.sbin/bluetooth/bt3cfw/bt3cfw.c 330449 2018-03-05 07:26:05Z eadler $ 32 */ 33 34#include <sys/types.h> 35#include <errno.h> 36#include <netgraph.h> 37#include <netgraph/bluetooth/include/ng_bt3c.h> 38#include <stdarg.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <syslog.h> 43#include <unistd.h> 44 45#define BT3CFW_IDENT "bt3cfw" 46#define BT3CFW_MAX_FIRMWARE_SIZE 0xffff 47 48/* Convert hex ASCII to int4 */ 49static int 50hexa2int4(const char *a) 51{ 52 if ('0' <= *a && *a <= '9') 53 return (*a - '0'); 54 55 if ('A' <= *a && *a <= 'F') 56 return (*a - 'A' + 0xa); 57 58 if ('a' <= *a && *a <= 'f') 59 return (*a - 'a' + 0xa); 60 61 syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a); 62 exit(255); 63} 64 65/* Convert hex ASCII to int8 */ 66static int 67hexa2int8(const char *a) 68{ 69 return ((hexa2int4(a) << 4) | hexa2int4(a + 1)); 70} 71 72/* Convert hex ASCII to int16 */ 73static int 74hexa2int16(const char *a) 75{ 76 return ((hexa2int8(a) << 8) | hexa2int8(a + 2)); 77} 78 79/* Convert hex ASCII to int32 */ 80static int 81hexa2int32(const char *a) 82{ 83 return ((hexa2int16(a) << 16) | hexa2int16(a + 4)); 84} 85 86/* Display usage() and exit */ 87static void 88usage(void) 89{ 90 syslog(LOG_ERR, "Usage: %s -f FirmwareFile -n NodeName", BT3CFW_IDENT); 91 exit(255); 92} 93 94/* Main */ 95int 96main(int argc, char *argv[]) 97{ 98 FILE *firmware_file = NULL; 99 char buffer[80], path[NG_PATHSIZ], 100 *firmware_filename = NULL; 101 uint8_t *firmware = NULL; 102 int firmware_size, opt, cs, ds; 103 104 memset(path, 0, sizeof(path)); 105 openlog(BT3CFW_IDENT, LOG_NDELAY|LOG_PID|LOG_PERROR, LOG_USER); 106 107 while ((opt = getopt(argc, argv, "f:hn:")) != -1) { 108 switch (opt) { 109 case 'f': 110 firmware_filename = optarg; 111 break; 112 113 case 'n': 114 snprintf(path, sizeof(path), "%s:", optarg); 115 break; 116 117 case 'h': 118 default: 119 usage(); 120 /* NOT REACHED */ 121 } 122 } 123 124 if (firmware_filename == NULL || path[0] == 0) 125 usage(); 126 /* NOT REACHED */ 127 128 firmware = (uint8_t *) calloc(BT3CFW_MAX_FIRMWARE_SIZE, 129 sizeof(uint8_t)); 130 if (firmware == NULL) { 131 syslog(LOG_ERR, "Could not allocate firmware buffer"); 132 exit(255); 133 } 134 135 if ((firmware_file = fopen(firmware_filename, "r")) == NULL) { 136 syslog(LOG_ERR, "Could not open BT3C firmware file %s. %s (%d)", 137 firmware_filename, strerror(errno), errno); 138 exit(255); 139 } 140 141 firmware_size = 0; 142 143 while (fgets(buffer, sizeof(buffer), firmware_file)) { 144 int i, size, address, cs, fcs; 145 146 size = hexa2int8(buffer + 2); 147 address = hexa2int32(buffer + 4); 148 fcs = hexa2int8(buffer + 2 + size * 2); 149 150 if (buffer[1] == '3') { 151 ng_bt3c_firmware_block_ep *block = NULL; 152 uint16_t *data = NULL; 153 154 block = (ng_bt3c_firmware_block_ep *) 155 (firmware + firmware_size); 156 157 firmware_size += sizeof(*block); 158 if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) { 159 syslog(LOG_ERR, "Could not add new firmware " \ 160 "block. Firmware file %s is " \ 161 "too big, firmware_size=%d", 162 firmware_filename, 163 firmware_size); 164 exit(255); 165 } 166 167 block->block_address = address; 168 block->block_size = (size - 4) / 2; 169 block->block_alignment = (block->block_size * 2) % 3; 170 if (block->block_alignment != 0) 171 block->block_alignment = 3 - block->block_alignment; 172 173 firmware_size += (block->block_size * 2); 174 firmware_size += block->block_alignment; 175 if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) { 176 syslog(LOG_ERR, "Could not add new firmware " \ 177 "data. Firmware file %s is " \ 178 "too big, firmware_size=%d", 179 firmware_filename, 180 firmware_size); 181 exit(255); 182 } 183 184 /* First part of the cheksum: size and address */ 185 cs = 0; 186 for (i = 0; i < 5; i++) 187 cs += hexa2int8(buffer + 2 + i * 2); 188 189 /* Data + second part of the cheksum: data */ 190 data = (uint16_t *)(block + 1); 191 for (i = 0; i < block->block_size; i++) { 192 data[i] = hexa2int16(buffer + (i * 4) + 12); 193 cs += (((data[i] & 0xff00) >> 8) & 0xff); 194 cs += (data[i] & 0x00ff); 195 } 196 } else 197 for (cs = 0, i = 0; i < size; i++) 198 cs += hexa2int8(buffer + 2 + i * 2); 199 200 if (((cs + fcs) & 0xff) != 0xff) { 201 syslog(LOG_ERR, "Invalid firmware file %s. Checksum " \ 202 "error, cs=%#x, fcs=%#x, checksum=%#x", 203 firmware_filename, (cs & 0xff), fcs, 204 ((cs + fcs) & 0xff)); 205 exit(255); 206 } 207 } 208 209 /* Send firmware to the card */ 210 if (NgMkSockNode(NULL, &cs, &ds) < 0) { 211 syslog(LOG_ERR, "Could not create Netgraph socket. %s (%d)", 212 strerror(errno), errno); 213 exit(255); 214 } 215 216 if (NgSendMsg(cs, path, NGM_BT3C_COOKIE, 217 NGM_BT3C_NODE_DOWNLOAD_FIRMWARE, 218 (void const *) firmware, firmware_size) < 0) { 219 syslog(LOG_ERR, "Could not send Netgraph message. %s (%d)", 220 strerror(errno), errno); 221 exit(255); 222 } 223 224 free(firmware); 225 firmware = NULL; 226 fclose(firmware_file); 227 228 return (0); 229} 230 231