Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / lib / mdns / minimal / core / DnsHeader.h
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *
5  *    Licensed under the Apache License, Version 2.0 (the "License");
6  *    you may not use this file except in compliance with the License.
7  *    You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *    Unless required by applicable law or agreed to in writing, software
12  *    distributed under the License is distributed on an "AS IS" BASIS,
13  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *    See the License for the specific language governing permissions and
15  *    limitations under the License.
16  */
17 #pragma once
18
19 #include <core/CHIPEncoding.h>
20
21 namespace mdns {
22 namespace Minimal {
23
24 /**
25  * Wrapper around a MDNS bit-packed flags in a DNS header as defined in
26  * RFC 1035 and RFC 6762
27  *
28  * | 0| 1 2 3 4| 5| 6| 7| 8| 9| 0| 1| 2 3 4 5 |
29  * |QR| OPCODE |AA|TC|RD|RA| Z|AD|CD| RCODE   |
30  *
31  * RFC 6762 states:
32  *   - OPCODE must be 0 on transmission and queries received that are not 0 MUST be ignored
33  *   - RCODE must be 0 on transmission and messages received with non-zero must be silently ignored
34  *
35  *   - AA (Authoritative Answer) MUST be 0 on transmission, ignored on reception
36  *   - RD (Recursion desired) MUST be 0 on transmission, ignored on reception
37  *   - RA (Recursion available) MUST be 0 on transmission, ignored on reception
38  *   - AD (Authentic data) MUST be 0 on transmission, ignored on reception
39  *   - CD (Checking Disabled) MUST be 0 on transmission, ignored on reception
40  *
41  * Accessors are only provided on useful values
42  */
43 class BitPackedFlags
44 {
45 public:
46     explicit BitPackedFlags(uint16_t value) : mValue(value) {}
47
48     uint16_t RawValue() const { return mValue & kMdnsNonIgnoredMask; }
49
50     bool IsQuery() const { return (mValue & kIsResponseMask) == 0; }
51     BitPackedFlags & SetQuery() { return ClearMask(kIsResponseMask); }
52
53     bool IsResponse() const { return (mValue & kIsResponseMask) == kIsResponseMask; }
54     BitPackedFlags & SetResponse() { return SetMask(kIsResponseMask); }
55
56     bool IsTruncated() const { return (mValue & kTruncationMask) != 0; }
57     BitPackedFlags & SetTruncated(bool value) { return value ? SetMask(kTruncationMask) : ClearMask(kTruncationMask); }
58
59     /// Validates that the message does not need to be ignored according to
60     /// RFC 6762
61     bool IsValidMdns() const { return (mValue & (kOpcodeMask | kReturnCodeMask)) == 0; }
62
63 private:
64     uint16_t mValue = 0;
65
66     inline BitPackedFlags & ClearMask(uint16_t mask)
67     {
68         mValue &= static_cast<uint16_t>(~mask);
69         return *this;
70     }
71
72     inline BitPackedFlags & SetMask(uint16_t mask)
73     {
74         mValue |= mask;
75         return *this;
76     }
77
78     // Mask to limit values to what RFC 6762 consideres useful
79     // 1111 1010 0000 0000 = FA0F
80     static constexpr uint16_t kMdnsNonIgnoredMask = 0x8A08;
81
82     static constexpr uint16_t kIsResponseMask = 0x8000;
83     static constexpr uint16_t kOpcodeMask     = 0x7000;
84     static constexpr uint16_t kTruncationMask = 0x0400;
85     static constexpr uint16_t kReturnCodeMask = 0x000F;
86 };
87
88 /**
89  * Allows operations on a DNS header. A DNS Header is defined in RFC 1035
90  * and looks like this:
91  *
92  * | 0| 1 2 3 4| 5| 6| 7| 8| 9| 0| 1| 2 3 4 5 |
93  * |               Message ID                 |
94  * |QR| OPCODE |AA|TC|RD|RA| Z|AD|CD| RCODE   |
95  * |       Items in QUESTION Section          |
96  * |       Items in ANSWER Section            |
97  * |       Items in AUTHORITY Section         |
98  * |       Items in ADDITIONAL Section        |
99  */
100 class ConstHeaderRef
101 {
102 public:
103     static constexpr size_t kSizeBytes = 12; /// size of a DNS header structure
104     ConstHeaderRef(const uint8_t * buffer) : mBuffer(buffer) {}
105
106     uint16_t GetMessageId() const { return Get16At(kMessageIdOffset); }
107
108     BitPackedFlags GetFlags() const { return BitPackedFlags(Get16At(kFlagsOffset)); }
109
110     uint16_t GetQueryCount() const { return Get16At(kQueryCountOffset); }
111     uint16_t GetAnswerCount() const { return Get16At(kAnswerCountOffset); }
112     uint16_t GetAuthorityCount() const { return Get16At(kAuthorityCountOffset); }
113     uint16_t GetAdditionalCount() const { return Get16At(kAdditionalCountOffset); }
114
115 protected:
116     const uint8_t * mBuffer;
117
118     inline uint16_t Get16At(size_t offset) const { return chip::Encoding::BigEndian::Get16(mBuffer + offset); }
119     uint16_t GetRawFlags() const { return Get16At(kFlagsOffset); }
120
121     static constexpr size_t kMessageIdOffset       = 0;
122     static constexpr size_t kFlagsOffset           = 2;
123     static constexpr size_t kQueryCountOffset      = 4;
124     static constexpr size_t kAnswerCountOffset     = 6;
125     static constexpr size_t kAuthorityCountOffset  = 8;
126     static constexpr size_t kAdditionalCountOffset = 10;
127 };
128
129 class HeaderRef : public ConstHeaderRef
130 {
131 public:
132     HeaderRef(uint8_t * buffer) : ConstHeaderRef(buffer) {}
133     HeaderRef & operator=(const HeaderRef & other) = default;
134
135     HeaderRef & Clear()
136     {
137         memset(GetWritable(), 0, kSizeBytes);
138         return *this;
139     }
140
141     HeaderRef & SetMessageId(uint16_t value) { return Set16At(kMessageIdOffset, value); }
142     HeaderRef & SetFlags(BitPackedFlags flags) { return Set16At(kFlagsOffset, flags.RawValue()); }
143     HeaderRef & SetQueryCount(uint16_t value) { return Set16At(kQueryCountOffset, value); }
144     HeaderRef & SetAnswerCount(uint16_t value) { return Set16At(kAnswerCountOffset, value); }
145     HeaderRef & SetAuthorityCount(uint16_t value) { return Set16At(kAuthorityCountOffset, value); }
146     HeaderRef & SetAdditionalCount(uint16_t value) { return Set16At(kAdditionalCountOffset, value); }
147
148 private:
149     /// Returns the internal buffer as writable. Const-cast is correct because
150     /// the construct took a non-const buffer as well.
151     uint8_t * GetWritable() { return const_cast<uint8_t *>(mBuffer); }
152
153     inline HeaderRef & Set16At(size_t offset, uint16_t value)
154     {
155         chip::Encoding::BigEndian::Put16(GetWritable() + offset, value);
156         return *this;
157     }
158
159     HeaderRef & SetRawFlags(uint16_t value) { return Set16At(kFlagsOffset, value); }
160 };
161
162 } // namespace Minimal
163 } // namespace mdns