• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <linux/if_ether.h>
19 #include <netinet/in.h>
20 #include <stddef.h>
21 #include <string.h>
22 
23 #include <initializer_list>
24 
25 class Message {
26   public:
27     Message();
28     Message(const uint8_t* data, size_t size);
29     static Message discover(const uint8_t (&sourceMac)[ETH_ALEN]);
30     static Message request(const uint8_t (&sourceMac)[ETH_ALEN], in_addr_t requestAddress,
31                            in_addr_t serverAddress);
32     static Message offer(const Message& sourceMessage, in_addr_t serverAddress,
33                          in_addr_t offeredAddress, in_addr_t offeredNetmask,
34                          in_addr_t offeredGateway, const in_addr_t* offeredDnsServers,
35                          size_t numOfferedDnsServers);
36     static Message ack(const Message& sourceMessage, in_addr_t serverAddress,
37                        in_addr_t offeredAddress, in_addr_t offeredNetmask, in_addr_t offeredGateway,
38                        const in_addr_t* offeredDnsServers, size_t numOfferedDnsServers);
39     static Message nack(const Message& sourceMessage, in_addr_t serverAddress);
40 
41     // Ensure that the data in the message represent a valid DHCP message
42     bool isValidDhcpMessage(uint8_t expectedOp) const;
43     // Ensure that the data in the message represent a valid DHCP message and
44     // has a xid (transaction ID) that matches |expectedXid|.
45     bool isValidDhcpMessage(uint8_t expectedOp, uint32_t expectedXid) const;
46 
data()47     const uint8_t* data() const { return reinterpret_cast<const uint8_t*>(&dhcpData); }
data()48     uint8_t* data() { return reinterpret_cast<uint8_t*>(&dhcpData); }
end()49     const uint8_t* end() const { return data() + mSize; }
50 
51     size_t optionsSize() const;
size()52     size_t size() const { return mSize; }
setSize(size_t size)53     void setSize(size_t size) { mSize = size; }
capacity()54     size_t capacity() const { return sizeof(dhcpData); }
55 
56     // Get the DHCP message type
57     uint8_t type() const;
58     // Get the DHCP server ID
59     in_addr_t serverId() const;
60     // Get the requested IP
61     in_addr_t requestedIp() const;
62 
63     struct Dhcp {
64         uint8_t op;    /* BOOTREQUEST / BOOTREPLY    */
65         uint8_t htype; /* hw addr type               */
66         uint8_t hlen;  /* hw addr len                */
67         uint8_t hops;  /* client set to 0            */
68 
69         uint32_t xid; /* transaction id             */
70 
71         uint16_t secs; /* seconds since start of acq */
72         uint16_t flags;
73 
74         uint32_t ciaddr; /* client IP addr             */
75         uint32_t yiaddr; /* your (client) IP addr      */
76         uint32_t siaddr; /* ip addr of next server     */
77                          /* (DHCPOFFER and DHCPACK)    */
78         uint32_t giaddr; /* relay agent IP addr        */
79 
80         uint8_t chaddr[16]; /* client hw addr             */
81         char sname[64];     /* asciiz server hostname     */
82         char file[128];     /* asciiz boot file name      */
83 
84         uint8_t options[1024]; /* optional parameters        */
85     } dhcpData;
86 
87   private:
88     Message(uint8_t operation, const uint8_t (&macAddress)[ETH_ALEN], uint8_t type);
89 
90     void addOption(uint8_t type, const void* data, uint8_t size);
addOption(uint8_t type,T data)91     template <typename T> void addOption(uint8_t type, T data) {
92         static_assert(sizeof(T) <= 255, "The size of data is too large");
93         addOption(type, &data, sizeof(data));
94     }
addOption(uint8_t type,T (& items)[N])95     template <typename T, size_t N> void addOption(uint8_t type, T (&items)[N]) {
96         static_assert(sizeof(T) * N <= 255, "The size of data is too large");
97         uint8_t* opts = nextOption();
98         *opts++ = type;
99         *opts++ = sizeof(T) * N;
100         for (const T& item : items) {
101             memcpy(opts, &item, sizeof(item));
102             opts += sizeof(item);
103         }
104         updateSize(opts);
105     }
106     void endOptions();
107 
108     const uint8_t* getOption(uint8_t optCode, uint8_t* length) const;
109     uint8_t* nextOption();
110     void updateSize(uint8_t* optionsEnd);
111     size_t mSize;
112 };
113 
114 static_assert(offsetof(Message::Dhcp, htype) == sizeof(Message::Dhcp::op),
115               "Invalid packing for DHCP message struct");
116