| 1 | //----------------------------------------------------------------------------- |
| 2 | // Jonathan Westhues, Aug 2005 |
| 3 | // Gerhard de Koning Gans, April 2008, May 2011 |
| 4 | // |
| 5 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, |
| 6 | // at your option, any later version. See the LICENSE.txt file for the text of |
| 7 | // the license. |
| 8 | //----------------------------------------------------------------------------- |
| 9 | // BigBuf and functions to allocate/free parts of it. |
| 10 | //----------------------------------------------------------------------------- |
| 11 | |
| 12 | #include <stdint.h> |
| 13 | #include "proxmark3.h" |
| 14 | #include "apps.h" |
| 15 | #include "string.h" |
| 16 | #include "util.h" |
| 17 | |
| 18 | // BigBuf is the large multi-purpose buffer, typically used to hold A/D samples or traces. |
| 19 | // Also used to hold various smaller buffers and the Mifare Emulator Memory. |
| 20 | |
| 21 | // declare it as uint32_t to achieve alignment to 4 Byte boundary |
| 22 | static uint32_t BigBuf[BIGBUF_SIZE/sizeof(uint32_t)]; |
| 23 | |
| 24 | // High memory mark |
| 25 | static uint16_t BigBuf_hi = BIGBUF_SIZE; |
| 26 | |
| 27 | // pointer to the emulator memory. |
| 28 | static uint8_t *emulator_memory = NULL; |
| 29 | |
| 30 | // trace related variables |
| 31 | static uint16_t traceLen = 0; |
| 32 | int tracing = 1; //Last global one.. todo static? |
| 33 | |
| 34 | // get the address of BigBuf |
| 35 | uint8_t *BigBuf_get_addr(void) |
| 36 | { |
| 37 | return (uint8_t *)BigBuf; |
| 38 | } |
| 39 | |
| 40 | |
| 41 | // get the address of the emulator memory. Allocate part of Bigbuf for it, if not yet done |
| 42 | uint8_t *BigBuf_get_EM_addr(void) |
| 43 | { |
| 44 | if (emulator_memory == NULL) { // not yet allocated |
| 45 | emulator_memory = BigBuf_malloc(CARD_MEMORY_SIZE); |
| 46 | } |
| 47 | |
| 48 | return emulator_memory; |
| 49 | } |
| 50 | |
| 51 | |
| 52 | // clear ALL of BigBuf |
| 53 | void BigBuf_Clear(void) |
| 54 | { |
| 55 | BigBuf_Clear_ext(true); |
| 56 | } |
| 57 | // clear ALL of BigBuf |
| 58 | void BigBuf_Clear_ext(bool verbose) |
| 59 | { |
| 60 | memset(BigBuf,0,BIGBUF_SIZE); |
| 61 | if (verbose) |
| 62 | Dbprintf("Buffer cleared (%i bytes)",BIGBUF_SIZE); |
| 63 | } |
| 64 | |
| 65 | void BigBuf_Clear_keep_EM(void) |
| 66 | { |
| 67 | memset(BigBuf,0,BigBuf_hi); |
| 68 | } |
| 69 | |
| 70 | // allocate a chunk of memory from BigBuf. We allocate high memory first. The unallocated memory |
| 71 | // at the beginning of BigBuf is always for traces/samples |
| 72 | uint8_t *BigBuf_malloc(uint16_t chunksize) |
| 73 | { |
| 74 | if (BigBuf_hi - chunksize < 0) { |
| 75 | return NULL; // no memory left |
| 76 | } else { |
| 77 | chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4 |
| 78 | BigBuf_hi -= chunksize; // aligned to 4 Byte boundary |
| 79 | return (uint8_t *)BigBuf + BigBuf_hi; |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | |
| 84 | // free ALL allocated chunks. The whole BigBuf is available for traces or samples again. |
| 85 | void BigBuf_free(void) |
| 86 | { |
| 87 | BigBuf_hi = BIGBUF_SIZE; |
| 88 | emulator_memory = NULL; |
| 89 | } |
| 90 | |
| 91 | |
| 92 | // free allocated chunks EXCEPT the emulator memory |
| 93 | void BigBuf_free_keep_EM(void) |
| 94 | { |
| 95 | if (emulator_memory != NULL) { |
| 96 | BigBuf_hi = emulator_memory - (uint8_t *)BigBuf; |
| 97 | } else { |
| 98 | BigBuf_hi = BIGBUF_SIZE; |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | void BigBuf_print_status(void) |
| 103 | { |
| 104 | Dbprintf("Memory"); |
| 105 | Dbprintf(" BIGBUF_SIZE.............%d", BIGBUF_SIZE); |
| 106 | Dbprintf(" BigBuf_hi .............%d", BigBuf_hi); |
| 107 | Dbprintf("Tracing"); |
| 108 | Dbprintf(" tracing ................%d", tracing); |
| 109 | Dbprintf(" traceLen ...............%d", traceLen); |
| 110 | } |
| 111 | |
| 112 | |
| 113 | // return the maximum trace length (i.e. the unallocated size of BigBuf) |
| 114 | uint16_t BigBuf_max_traceLen(void) |
| 115 | { |
| 116 | return BigBuf_hi; |
| 117 | } |
| 118 | |
| 119 | void clear_trace() { |
| 120 | traceLen = 0; |
| 121 | } |
| 122 | |
| 123 | void set_tracing(bool enable) { |
| 124 | tracing = enable; |
| 125 | } |
| 126 | |
| 127 | /** |
| 128 | * Get the number of bytes traced |
| 129 | * @return |
| 130 | */ |
| 131 | uint16_t BigBuf_get_traceLen(void) |
| 132 | { |
| 133 | return traceLen; |
| 134 | } |
| 135 | |
| 136 | /** |
| 137 | This is a function to store traces. All protocols can use this generic tracer-function. |
| 138 | The traces produced by calling this function can be fetched on the client-side |
| 139 | by 'hf list raw', alternatively 'hf list <proto>' for protocol-specific |
| 140 | annotation of commands/responses. |
| 141 | |
| 142 | **/ |
| 143 | bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag) |
| 144 | { |
| 145 | if (!tracing) return FALSE; |
| 146 | |
| 147 | uint8_t *trace = BigBuf_get_addr(); |
| 148 | |
| 149 | uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity |
| 150 | uint16_t duration = timestamp_end - timestamp_start; |
| 151 | |
| 152 | // Return when trace is full |
| 153 | uint16_t max_traceLen = BigBuf_max_traceLen(); |
| 154 | |
| 155 | if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= max_traceLen) { |
| 156 | tracing = FALSE; // don't trace any more |
| 157 | return FALSE; |
| 158 | } |
| 159 | // Traceformat: |
| 160 | // 32 bits timestamp (little endian) |
| 161 | // 16 bits duration (little endian) |
| 162 | // 16 bits data length (little endian, Highest Bit used as readerToTag flag) |
| 163 | // y Bytes data |
| 164 | // x Bytes parity (one byte per 8 bytes data) |
| 165 | |
| 166 | // timestamp (start) |
| 167 | trace[traceLen++] = ((timestamp_start >> 0) & 0xff); |
| 168 | trace[traceLen++] = ((timestamp_start >> 8) & 0xff); |
| 169 | trace[traceLen++] = ((timestamp_start >> 16) & 0xff); |
| 170 | trace[traceLen++] = ((timestamp_start >> 24) & 0xff); |
| 171 | |
| 172 | // duration |
| 173 | trace[traceLen++] = ((duration >> 0) & 0xff); |
| 174 | trace[traceLen++] = ((duration >> 8) & 0xff); |
| 175 | |
| 176 | // data length |
| 177 | trace[traceLen++] = ((iLen >> 0) & 0xff); |
| 178 | trace[traceLen++] = ((iLen >> 8) & 0xff); |
| 179 | |
| 180 | // readerToTag flag |
| 181 | if (!readerToTag) { |
| 182 | trace[traceLen - 1] |= 0x80; |
| 183 | } |
| 184 | |
| 185 | // data bytes |
| 186 | if (btBytes != NULL && iLen != 0) { |
| 187 | memcpy(trace + traceLen, btBytes, iLen); |
| 188 | } |
| 189 | traceLen += iLen; |
| 190 | |
| 191 | // parity bytes |
| 192 | if (num_paritybytes != 0) { |
| 193 | if (parity != NULL) { |
| 194 | memcpy(trace + traceLen, parity, num_paritybytes); |
| 195 | } else { |
| 196 | memset(trace + traceLen, 0x00, num_paritybytes); |
| 197 | } |
| 198 | } |
| 199 | traceLen += num_paritybytes; |
| 200 | |
| 201 | return TRUE; |
| 202 | } |
| 203 | |
| 204 | |
| 205 | int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int readerToTag) |
| 206 | { |
| 207 | /** |
| 208 | Todo, rewrite the logger to use the generic functionality instead. It should be noted, however, |
| 209 | that this logger takes number of bits as argument, not number of bytes. |
| 210 | **/ |
| 211 | |
| 212 | if (!tracing) return FALSE; |
| 213 | |
| 214 | uint8_t *trace = BigBuf_get_addr(); |
| 215 | uint16_t iLen = nbytes(iBits); |
| 216 | // Return when trace is full |
| 217 | if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) return FALSE; |
| 218 | |
| 219 | //Hitag traces appear to use this traceformat: |
| 220 | // 32 bits timestamp (little endian,Highest Bit used as readerToTag flag) |
| 221 | // 32 bits parity |
| 222 | // 8 bits size (number of bits in the trace entry, not number of bytes) |
| 223 | // y Bytes data |
| 224 | |
| 225 | rsamples += iSamples; |
| 226 | trace[traceLen++] = ((rsamples >> 0) & 0xff); |
| 227 | trace[traceLen++] = ((rsamples >> 8) & 0xff); |
| 228 | trace[traceLen++] = ((rsamples >> 16) & 0xff); |
| 229 | trace[traceLen++] = ((rsamples >> 24) & 0xff); |
| 230 | |
| 231 | if (!readerToTag) { |
| 232 | trace[traceLen - 1] |= 0x80; |
| 233 | } |
| 234 | |
| 235 | trace[traceLen++] = ((dwParity >> 0) & 0xff); |
| 236 | trace[traceLen++] = ((dwParity >> 8) & 0xff); |
| 237 | trace[traceLen++] = ((dwParity >> 16) & 0xff); |
| 238 | trace[traceLen++] = ((dwParity >> 24) & 0xff); |
| 239 | trace[traceLen++] = iBits; |
| 240 | |
| 241 | memcpy(trace + traceLen, btBytes, iLen); |
| 242 | traceLen += iLen; |
| 243 | |
| 244 | return TRUE; |
| 245 | } |
| 246 | |
| 247 | |
| 248 | // Emulator memory |
| 249 | uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length){ |
| 250 | uint8_t* mem = BigBuf_get_EM_addr(); |
| 251 | if(offset+length < CARD_MEMORY_SIZE) |
| 252 | { |
| 253 | memcpy(mem+offset, data, length); |
| 254 | return 0; |
| 255 | }else |
| 256 | { |
| 257 | Dbprintf("Error, trying to set memory outside of bounds! %d > %d", (offset+length), CARD_MEMORY_SIZE); |
| 258 | return 1; |
| 259 | } |
| 260 | } |