blob: 2e68893223bccb83f56603ef75cf67c4ebd04354 [file] [log] [blame]
/* 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%pP: %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 @ %pP: 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 @%pP: 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);
}
}