blob: f4b0205f4b914de3050f43214eb9c2235af97cdd [file] [log] [blame]
// Copyright 2016 The Chromium 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 "components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator.h"
#include <string.h>
#include <algorithm>
#ifdef OS_WIN
#include <winsock2.h>
#else
#include <netinet/in.h>
#endif
#include "base/logging.h"
namespace cryptauth {
namespace weave {
BluetoothLowEnergyWeavePacketGenerator::BluetoothLowEnergyWeavePacketGenerator()
: max_packet_size_(kDefaultMaxPacketSize), next_packet_counter_(0) {}
BluetoothLowEnergyWeavePacketGenerator::
~BluetoothLowEnergyWeavePacketGenerator() {}
Packet BluetoothLowEnergyWeavePacketGenerator::CreateConnectionRequest() {
Packet packet(kMinConnectionRequestSize, 0);
SetPacketTypeBit(PacketType::CONTROL, &packet);
// Since it only make sense for connection request to be the 0th packet,
// resets the packet counter.
next_packet_counter_ = 1;
SetControlCommand(ControlCommand::CONNECTION_REQUEST, &packet);
SetShortField(1, kWeaveVersion, &packet);
SetShortField(3, kWeaveVersion, &packet);
SetShortField(5, kSelectMaxPacketSize, &packet);
return packet;
}
Packet BluetoothLowEnergyWeavePacketGenerator::CreateConnectionResponse() {
Packet packet(kMinConnectionResponseSize, 0);
SetPacketTypeBit(PacketType::CONTROL, &packet);
// Since it only make sense for connection response to be the 0th packet,
// resets the next packet counter.
next_packet_counter_ = 1;
SetControlCommand(ControlCommand::CONNECTION_RESPONSE, &packet);
SetShortField(1, kWeaveVersion, &packet);
SetShortField(3, max_packet_size_, &packet);
return packet;
}
Packet BluetoothLowEnergyWeavePacketGenerator::CreateConnectionClose(
ReasonForClose reason_for_close) {
Packet packet(kMaxConnectionCloseSize, 0);
SetPacketTypeBit(PacketType::CONTROL, &packet);
SetPacketCounter(&packet);
SetControlCommand(ControlCommand::CONNECTION_CLOSE, &packet);
SetShortField(1, reason_for_close, &packet);
return packet;
}
void BluetoothLowEnergyWeavePacketGenerator::SetMaxPacketSize(uint16_t size) {
DCHECK(size >= kDefaultMaxPacketSize);
max_packet_size_ = size;
}
std::vector<Packet> BluetoothLowEnergyWeavePacketGenerator::EncodeDataMessage(
std::string message) {
DCHECK(!message.empty());
// The first byte of a packet is used by the uWeave protocol,
// hence the payload is 1 byte smaller than the packet size.
uint32_t packet_payload_size = max_packet_size_ - 1;
uint32_t message_length = message.length();
// (packet_payload_size - 1) is used to enforce rounding up.
uint32_t num_packets =
(message_length + (packet_payload_size - 1)) / packet_payload_size;
std::vector<Packet> weave_message(num_packets);
const char* byte_message = message.c_str();
for (uint32_t i = 0; i < num_packets; ++i) {
Packet* packet = &weave_message[i];
uint32_t begin = packet_payload_size * i;
uint32_t end = std::min(begin + packet_payload_size, message_length);
packet->push_back(0);
SetPacketTypeBit(PacketType::DATA, packet);
SetPacketCounter(packet);
for (uint32_t j = begin; j < end; ++j) {
packet->push_back(byte_message[j]);
}
}
// Guaranteed to have at least one packet since message is not empty.
SetDataFirstBit(&weave_message[0]);
SetDataLastBit(&weave_message[num_packets - 1]);
return weave_message;
}
void BluetoothLowEnergyWeavePacketGenerator::SetShortField(uint32_t byte_offset,
uint16_t val,
Packet* packet) {
DCHECK(packet);
DCHECK_LT(byte_offset, packet->size());
DCHECK_LT(byte_offset + 1, packet->size());
uint16_t network_val = htons(val);
uint8_t* network_val_ptr = reinterpret_cast<uint8_t*>(&network_val);
packet->at(byte_offset) = network_val_ptr[0];
packet->at(byte_offset + 1) = network_val_ptr[1];
}
void BluetoothLowEnergyWeavePacketGenerator::SetPacketTypeBit(PacketType type,
Packet* packet) {
DCHECK(packet);
DCHECK(!packet->empty());
// Type bit is the highest bit of the first byte of the packet.
// So clear the highest bit and set it according to val.
packet->at(0) = (packet->at(0) & 0x7F) | (type << 7);
}
void BluetoothLowEnergyWeavePacketGenerator::SetControlCommand(
ControlCommand command,
Packet* packet) {
DCHECK(packet);
DCHECK(!packet->empty());
// Control Command is the lower 4 bits of the packet's first byte.
// So clear the lower 4 bites and set it according to val.
packet->at(0) = (packet->at(0) & 0xF0) | command;
}
void BluetoothLowEnergyWeavePacketGenerator::SetPacketCounter(Packet* packet) {
DCHECK(packet);
DCHECK(!packet->empty());
uint8_t counter = next_packet_counter_ % kMaxPacketCounter;
// Packet counter is the bits 4, 5, and 6 of the packet's first byte.
// So clear those bits and set them according to current packet counter
// modular max packet counter.
packet->at(0) = (packet->at(0) & 0x8F) | (counter << 4);
next_packet_counter_++;
}
void BluetoothLowEnergyWeavePacketGenerator::SetDataFirstBit(Packet* packet) {
DCHECK(packet);
DCHECK(!packet->empty());
// First bit is bit 3 of the packet's first byte and set it to 1.
packet->at(0) = packet->at(0) | (1 << 3);
}
void BluetoothLowEnergyWeavePacketGenerator::SetDataLastBit(Packet* packet) {
DCHECK(packet);
DCHECK(!packet->empty());
// Last bit is the bit 2 of the packet's first byte and set it to 1.
packet->at(0) = packet->at(0) | (1 << 2);
}
} // namespace weave
} // namespace cryptauth