blob: b9b0d0e676a952ff908d065a924e92362b7164ee [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GARNET_DRIVERS_BLUETOOTH_LIB_RFCOMM_RFCOMM_H_
#define GARNET_DRIVERS_BLUETOOTH_LIB_RFCOMM_RFCOMM_H_
#include <cstdint>
#include <lib/fxl/logging.h>
#include "garnet/drivers/bluetooth/lib/common/byte_buffer.h"
#include "garnet/drivers/bluetooth/lib/l2cap/l2cap.h"
namespace btlib {
namespace rfcomm {
// C/R bit, used at both the frame level and the multiplexer channel command
// level. See RFCOMM 5.1.3 and 5.4.6.1/2.
enum class CommandResponse { kCommand, kResponse };
// Role assigned to this device's end of the RFCOMM session. Start-up procedure
// is described in RFCOMM 5.2.1; the device which starts up the multiplexer
// control channel is considered the initiator (see "RFCOMM initiator" in the
// glossary, RFCOMM 9).
// A value of kUnassigned indicates that the RFCOMM session has not started the
// start-up procedure, and thus no role has yet been assigned. A value of
// kNegotiating indicates that the start-up procedure has started, but not
// finished.
enum class Role { kUnassigned, kNegotiating, kInitiator, kResponder };
// Return the Role opposite to the one given in |role|. The opposite of the
// Unassigned role is Unassigned. This is used to get our peer's role when we
// know our own.
inline constexpr Role OppositeRole(Role role) {
return role == Role::kUnassigned
? Role::kUnassigned
: role == Role::kInitiator ? Role::kResponder : Role::kInitiator;
}
// This function defines what it means for a multiplexer to be started: namely,
// it has its role set to initiator or responder.
inline constexpr bool IsMultiplexerStarted(Role role) {
return role == Role::kInitiator || role == Role::kResponder;
}
// DLCIs are 6 bits. See RFCOMM 5.4. Any DLCI value will be truncated to the
// least significant 6 bits.
using DLCI = uint8_t;
// DLCI 0 is internally used by RFCOMM as the multiplexer control channel, over
// which the two multiplexers communicate. DLCIs 2-61 correspond to user data
// channels, which can be used by applications.
constexpr DLCI kMuxControlDLCI = 0;
constexpr DLCI kMinUserDLCI = 2;
constexpr DLCI kMaxUserDLCI = 61;
constexpr bool IsUserDLCI(DLCI dlci) {
return dlci >= kMinUserDLCI && dlci <= kMaxUserDLCI;
}
constexpr bool IsValidDLCI(DLCI dlci) {
return dlci == kMuxControlDLCI || IsUserDLCI(dlci);
}
// Server Channels are 5 bits wide; they are the 5 most significant bits of the
// DLCI. Server Channels are exposed to the outside world; a user who is
// requesting to open a channel will know the Server Channel. DLCIs, on the
// other hand, are internal to RFCOMM.
using ServerChannel = uint8_t;
constexpr ServerChannel kMinServerChannel = 1;
constexpr ServerChannel kMaxServerChannel = 30;
// Used to indicate error.
constexpr ServerChannel kInvalidServerChannel = 0;
// Used to convert between Server Channel and DLCI. See RFCOMM 5.4 for the
// spec's description of Server Channels and how they relate to DLCIs.
constexpr size_t kServerChannelShift = 1;
inline constexpr ServerChannel DLCIToServerChannel(DLCI dlci) {
FXL_DCHECK(IsUserDLCI(dlci));
return dlci >> kServerChannelShift;
}
inline constexpr DLCI ServerChannelToDLCI(ServerChannel server_channel,
Role role) {
FXL_DCHECK(role == Role::kInitiator || role == Role::kResponder);
FXL_DCHECK(server_channel >= kMinServerChannel &&
server_channel <= kMaxServerChannel);
return (server_channel << kServerChannelShift) |
(role == Role::kInitiator ? 1 : 0);
}
// The length field encodes the length of the information (payload) field. The
// length field can be one or two octets, and can encode at most a 15-bit value.
using InformationLength = uint16_t;
// The maximum Length value which can be encoded in a single-octet length field.
// This constant is used to quickly determine whether two (or more) length
// octets will be needed to encode a length value. It is used by Frames and
// MuxCommands alike.
constexpr InformationLength kMaxSingleOctetLength = 127;
// Encodes the Control Field; see table 2, GSM 07.10 5.2.1.3 and RFCOMM 4.2.
// The P/F bit is set to 0 for all frame types.
// clang-format off
enum class FrameType : uint8_t {
kSetAsynchronousBalancedMode = 0b00101111,
kUnnumberedAcknowledgement = 0b01100011,
kDisconnectedMode = 0b00001111,
kDisconnect = 0b01000011,
kUnnumberedInfoHeaderCheck = 0b11101111
};
// clang-format on
// Whether the frame is a valid multiplexer start-up frame. Valid multiplexer
// start-up frames are the only frames which are allowed to be sent before the
// multiplexer starts.
constexpr bool IsMuxStartupFrame(FrameType type, DLCI dlci) {
return dlci == kMuxControlDLCI &&
(type == FrameType::kSetAsynchronousBalancedMode ||
type == FrameType::kUnnumberedAcknowledgement ||
type == FrameType::kDisconnectedMode);
}
} // namespace rfcomm
} // namespace btlib
#endif // GARNET_DRIVERS_BLUETOOTH_LIB_RFCOMM_RFCOMM_H_