199 lines
4.7 KiB
C
199 lines
4.7 KiB
C
|
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
|
||
|
* Use of this source code is governed by a BSD-style license that can be
|
||
|
* found in the LICENSE file.
|
||
|
*/
|
||
|
|
||
|
#include "bluetooth_le.h"
|
||
|
#include "util.h"
|
||
|
#include "console.h"
|
||
|
|
||
|
#define CPRINTF(format, args...) cprintf(CC_BLUETOOTH_LE, format, ## args)
|
||
|
|
||
|
/*
|
||
|
* Convert from BLE Channel to frequency
|
||
|
*
|
||
|
* Bluetooth 4.1 Vol 6 pg 36 4.1 Table 1.1
|
||
|
*/
|
||
|
|
||
|
#define CHAN_0_MHZ 2404
|
||
|
#define CHAN_11_MHZ 2428
|
||
|
#define CHAN_37_MHZ 2402
|
||
|
#define CHAN_38_MHZ 2426
|
||
|
#define CHAN_39_MHZ 2480
|
||
|
|
||
|
int chan2freq(int channel)
|
||
|
{
|
||
|
int freq;
|
||
|
|
||
|
ASSERT(channel < 40 && channel >= 0);
|
||
|
|
||
|
switch (channel) {
|
||
|
case 37: /* Advertising */
|
||
|
freq = CHAN_37_MHZ;
|
||
|
break;
|
||
|
case 38: /* Advertising */
|
||
|
freq = CHAN_38_MHZ;
|
||
|
break;
|
||
|
case 39: /* Advertising */
|
||
|
freq = CHAN_39_MHZ;
|
||
|
break;
|
||
|
default:
|
||
|
/* Data Channels */
|
||
|
if (channel < 11)
|
||
|
freq = channel * 2 + CHAN_0_MHZ;
|
||
|
else
|
||
|
freq = (channel - 11) * 2 + CHAN_11_MHZ;
|
||
|
}
|
||
|
return freq;
|
||
|
}
|
||
|
|
||
|
/* BLE 4.1 Vol 6 2.3.3.1 */
|
||
|
|
||
|
void fill_remapping_table(struct remapping_table *rt, uint8_t map[5],
|
||
|
int hop_increment)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
rt->num_used_channels = 0;
|
||
|
rt->last_unmapped_channel = 0;
|
||
|
rt->hop_increment = hop_increment;
|
||
|
|
||
|
for (i = 0; i < 37; i++)
|
||
|
if (map[i / 8] & (1 << (i % 8)))
|
||
|
rt->remapping_index[rt->num_used_channels++] = i;
|
||
|
memcpy(rt->map, map, sizeof(rt->map));
|
||
|
}
|
||
|
|
||
|
/* BLE 4.1 Vol 6 4.5.8 */
|
||
|
uint8_t get_next_data_channel(struct remapping_table *rt)
|
||
|
{
|
||
|
rt->last_unmapped_channel =
|
||
|
(rt->last_unmapped_channel + rt->hop_increment) % 37;
|
||
|
|
||
|
/* Check if the channel is mapped */
|
||
|
if (rt->map[rt->last_unmapped_channel / 8] &
|
||
|
(1 << (rt->last_unmapped_channel % 8)))
|
||
|
return rt->last_unmapped_channel;
|
||
|
else
|
||
|
return rt->remapping_index
|
||
|
[rt->last_unmapped_channel % rt->num_used_channels];
|
||
|
}
|
||
|
|
||
|
/* BLE 4.1 Vol 3 Part C 11 */
|
||
|
|
||
|
/* Pack advertising structures for sending */
|
||
|
uint8_t *pack_adv(uint8_t *dest, int length, int type, const uint8_t *data)
|
||
|
{
|
||
|
/* Add the structure length */
|
||
|
dest[0] = (uint8_t)length+1;
|
||
|
/* Add the structure type */
|
||
|
dest[1] = (uint8_t)type;
|
||
|
/* Add the data */
|
||
|
memcpy(&dest[2], data, length);
|
||
|
|
||
|
/* Return a pointer to the next structure */
|
||
|
return &dest[2+length];
|
||
|
}
|
||
|
|
||
|
uint8_t *pack_adv_int(uint8_t *dest, int length, int type, int data)
|
||
|
{
|
||
|
/* Add the structure length */
|
||
|
dest[0] = (uint8_t)length+1;
|
||
|
/* Add the structure type */
|
||
|
dest[1] = (uint8_t)type;
|
||
|
/* Add the data */
|
||
|
memcpy(&dest[2], &data, length);
|
||
|
|
||
|
/* Return a pointer to the next structure */
|
||
|
return &dest[2+length];
|
||
|
}
|
||
|
|
||
|
uint8_t *pack_adv_addr(uint8_t *dest, uint64_t addr)
|
||
|
{
|
||
|
memcpy(&dest[0], &addr, BLUETOOTH_ADDR_OCTETS);
|
||
|
|
||
|
/* Return a pointer to the next structure */
|
||
|
return &dest[BLUETOOTH_ADDR_OCTETS];
|
||
|
}
|
||
|
|
||
|
/* Parse advertising structures that have been received */
|
||
|
const uint8_t *unpack_adv(const uint8_t *src, int *length, int *type,
|
||
|
const uint8_t **data)
|
||
|
{
|
||
|
/* Get the structure length */
|
||
|
*length = *(src++);
|
||
|
/* Get the structure type */
|
||
|
*type = *(src++);
|
||
|
/* Get the data */
|
||
|
*data = src;
|
||
|
|
||
|
/* Return a pointer to the next structure */
|
||
|
return src + *length;
|
||
|
}
|
||
|
|
||
|
static void mem_dump(uint8_t *mem, int len)
|
||
|
{
|
||
|
int i;
|
||
|
uint8_t value;
|
||
|
|
||
|
for (i = 0; i < len; i++) {
|
||
|
value = mem[i];
|
||
|
if (i % 8 == 0)
|
||
|
CPRINTF("\n%08x: %02x", &mem[i], value);
|
||
|
else
|
||
|
CPRINTF(" %02x", value);
|
||
|
}
|
||
|
CPRINTF("\n");
|
||
|
}
|
||
|
|
||
|
void dump_ble_addr(uint8_t *mem, char *name)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 5; i > 0; i--)
|
||
|
CPRINTF("%02x.", mem[i]);
|
||
|
CPRINTF("%02x %s\n", mem[0], name);
|
||
|
}
|
||
|
|
||
|
void dump_ble_packet(struct ble_pdu *ble_p)
|
||
|
{
|
||
|
int curr_offs;
|
||
|
|
||
|
if (ble_p->header_type_adv) {
|
||
|
CPRINTF("BLE packet @ %p: type %d, len %d, %s %s\n",
|
||
|
ble_p, ble_p->header.adv.type, ble_p->header.adv.length,
|
||
|
(ble_p->header.adv.txaddr ? " TXADDR" : ""),
|
||
|
(ble_p->header.adv.rxaddr ? " RXADDR" : ""));
|
||
|
|
||
|
curr_offs = 0;
|
||
|
|
||
|
if (ble_p->header.adv.type ==
|
||
|
BLE_ADV_HEADER_PDU_TYPE_SCAN_REQ) {
|
||
|
dump_ble_addr(ble_p->payload, "ScanA");
|
||
|
curr_offs += BLUETOOTH_ADDR_OCTETS;
|
||
|
} else if (ble_p->header.adv.type ==
|
||
|
BLE_ADV_HEADER_PDU_TYPE_CONNECT_REQ) {
|
||
|
dump_ble_addr(ble_p->payload, "InitA");
|
||
|
curr_offs += BLUETOOTH_ADDR_OCTETS;
|
||
|
}
|
||
|
/* All packets have AdvA */
|
||
|
dump_ble_addr(ble_p->payload + curr_offs, "AdvA");
|
||
|
curr_offs += BLUETOOTH_ADDR_OCTETS;
|
||
|
|
||
|
if (ble_p->header.adv.type ==
|
||
|
BLE_ADV_HEADER_PDU_TYPE_ADV_DIRECT_IND)
|
||
|
dump_ble_addr(ble_p->payload + curr_offs, "InitA");
|
||
|
else
|
||
|
mem_dump(ble_p->payload + curr_offs,
|
||
|
ble_p->header.adv.length - curr_offs);
|
||
|
} else { /* Data PDUs */
|
||
|
CPRINTF("BLE data packet @%p: LLID %d,"
|
||
|
" nesn %d, sn %d, md %d, length %d\n",
|
||
|
ble_p, ble_p->header.data.llid, ble_p->header.data.nesn,
|
||
|
ble_p->header.data.sn, ble_p->header.data.md,
|
||
|
ble_p->header.data.length);
|
||
|
mem_dump(ble_p->payload, ble_p->header.data.length);
|
||
|
}
|
||
|
}
|
||
|
|