• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 #include <endian.h>
17 
18 #include <memory>
19 
20 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
22 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
23 #include "pw_bluetooth_sapphire/internal/host/hci-spec/vendor_protocol.h"
24 #include "pw_bluetooth_sapphire/internal/host/transport/error.h"
25 #include "pw_bluetooth_sapphire/internal/host/transport/packet.h"
26 
27 namespace bt::hci {
28 
29 using CommandPacket = Packet<hci_spec::CommandHeader>;
30 using EventPacket = Packet<hci_spec::EventHeader>;
31 using EventPacketPtr = std::unique_ptr<EventPacket>;
32 
33 // Packet template specialization for HCI command packets.
34 template <>
35 class Packet<hci_spec::CommandHeader>
36     : public PacketBase<hci_spec::CommandHeader, CommandPacket> {
37  public:
38   // Slab-allocates a new CommandPacket with the given payload size and
39   // initializes the packet's header field.
40   static std::unique_ptr<CommandPacket> New(hci_spec::OpCode opcode,
41                                             size_t payload_size = 0u);
42 
43   // Returns the HCI command opcode currently in this packet.
opcode()44   hci_spec::OpCode opcode() const { return le16toh(view().header().opcode); }
45 
46   // Convenience function to get a mutable payload of a packet.
47   template <typename PayloadType>
mutable_payload()48   PayloadType* mutable_payload() {
49     return mutable_view()->mutable_payload<PayloadType>();
50   }
51 
52  protected:
53   using PacketBase<hci_spec::CommandHeader, CommandPacket>::PacketBase;
54 
55  private:
56   // Writes the given header fields into the underlying buffer.
57   void WriteHeader(hci_spec::OpCode opcode);
58 };
59 
60 // Packet template specialization for HCI event packets.
61 template <>
62 class Packet<hci_spec::EventHeader>
63     : public PacketBase<hci_spec::EventHeader, EventPacket> {
64  public:
65   // Slab-allocates a new EventPacket with the given payload size without
66   // initializing its contents.
67   static std::unique_ptr<EventPacket> New(size_t payload_size);
68 
69   // Returns the HCI event code currently in this packet.
event_code()70   hci_spec::EventCode event_code() const { return view().header().event_code; }
71 
72   // Convenience function to get a parameter payload from a packet
73   template <typename ParamsType>
params()74   const ParamsType& params() const {
75     return view().payload<ParamsType>();
76   }
77 
78   // If this is a CommandComplete event packet, this method returns a pointer to
79   // the beginning of the return parameter structure. If the given template type
80   // would exceed the bounds of the packet or if this packet does not represent
81   // a CommandComplete event, this method returns nullptr.
82   template <typename ReturnParams>
return_params()83   const ReturnParams* return_params() const {
84     if (event_code() != hci_spec::kCommandCompleteEventCode ||
85         sizeof(ReturnParams) > view().payload_size() -
86                                    sizeof(hci_spec::CommandCompleteEventParams))
87       return nullptr;
88     return reinterpret_cast<const ReturnParams*>(
89         params<hci_spec::CommandCompleteEventParams>().return_parameters);
90   }
91 
92   // If this is a LE Meta Event packet, this method returns a pointer to the
93   // beginning of the subevent parameter structure. If the given template type
94   // would exceed the bounds of the packet or if this packet does not represent
95   // a LE Meta Event, this method returns nullptr.
96   template <typename SubeventParams>
subevent_params()97   const SubeventParams* subevent_params() const {
98     if (event_code() != hci_spec::kLEMetaEventCode ||
99         sizeof(SubeventParams) >
100             view().payload_size() - sizeof(hci_spec::LEMetaEventParams)) {
101       return nullptr;
102     }
103 
104     return reinterpret_cast<const SubeventParams*>(
105         params<hci_spec::LEMetaEventParams>().subevent_parameters);
106   }
107 
108   // If this is an event packet with a standard status (See Vol 2, Part D), this
109   // method returns true and populates |out_status| using the status from the
110   // event parameters.
111   //
112   // Not all events contain a status code and not all of those that do are
113   // supported by this method. Returns false for such events and |out_status| is
114   // left unmodified.
115   //
116   // NOTE: Using this method on an unsupported event packet will trigger an
117   // assertion in debug builds. If you intend to use this with a new event code,
118   // make sure to add an entry to the implementation in control_packets.cc.
119   //
120   // TODO(armansito): Add more event entries here as needed.
121   bool ToStatusCode(pw::bluetooth::emboss::StatusCode* out_code) const;
122 
123   // Returns a status if this event represents the result of an operation. See
124   // the documentation on ToStatusCode() as the same conditions apply to this
125   // method. Instead of a boolean, this returns a default status of type
126   // HostError::kMalformedPacket.
127   Result<> ToResult() const;
128 
129   // Initializes the internal PacketView by reading the header portion of the
130   // underlying buffer.
131   void InitializeFromBuffer();
132 
133  protected:
134   using PacketBase<hci_spec::EventHeader, EventPacket>::PacketBase;
135 };
136 
137 }  // namespace bt::hci
138 
139 // Convenience macros to check and log any non-Success status of an event.
140 // Evaluate to true if the event status is not success.
141 #define hci_is_error(event, flag, tag, fmt...) \
142   bt_is_error(event.ToResult(), flag, tag, fmt)
143