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], 31 in_addr_t requestAddress, 32 in_addr_t serverAddress); 33 static Message offer(const Message& sourceMessage, 34 in_addr_t serverAddress, 35 in_addr_t offeredAddress, 36 in_addr_t offeredNetmask, 37 in_addr_t offeredGateway, 38 const in_addr_t* offeredDnsServers, 39 size_t numOfferedDnsServers); 40 static Message ack(const Message& sourceMessage, 41 in_addr_t serverAddress, 42 in_addr_t offeredAddress, 43 in_addr_t offeredNetmask, 44 in_addr_t offeredGateway, 45 const in_addr_t* offeredDnsServers, 46 size_t numOfferedDnsServers); 47 static Message nack(const Message& sourceMessage, in_addr_t serverAddress); 48 49 // Ensure that the data in the message represent a valid DHCP message 50 bool isValidDhcpMessage(uint8_t expectedOp) const; 51 // Ensure that the data in the message represent a valid DHCP message and 52 // has a xid (transaction ID) that matches |expectedXid|. 53 bool isValidDhcpMessage(uint8_t expectedOp, uint32_t expectedXid) const; 54 data()55 const uint8_t* data() const { 56 return reinterpret_cast<const uint8_t*>(&dhcpData); 57 } data()58 uint8_t* data() { 59 return reinterpret_cast<uint8_t*>(&dhcpData); 60 } end()61 const uint8_t* end() const { return data() + mSize; } 62 63 size_t optionsSize() const; size()64 size_t size() const { return mSize; } setSize(size_t size)65 void setSize(size_t size) { mSize = size; } capacity()66 size_t capacity() const { return sizeof(dhcpData); } 67 68 // Get the DHCP message type 69 uint8_t type() const; 70 // Get the DHCP server ID 71 in_addr_t serverId() const; 72 // Get the requested IP 73 in_addr_t requestedIp() const; 74 75 struct Dhcp { 76 uint8_t op; /* BOOTREQUEST / BOOTREPLY */ 77 uint8_t htype; /* hw addr type */ 78 uint8_t hlen; /* hw addr len */ 79 uint8_t hops; /* client set to 0 */ 80 81 uint32_t xid; /* transaction id */ 82 83 uint16_t secs; /* seconds since start of acq */ 84 uint16_t flags; 85 86 uint32_t ciaddr; /* client IP addr */ 87 uint32_t yiaddr; /* your (client) IP addr */ 88 uint32_t siaddr; /* ip addr of next server */ 89 /* (DHCPOFFER and DHCPACK) */ 90 uint32_t giaddr; /* relay agent IP addr */ 91 92 uint8_t chaddr[16]; /* client hw addr */ 93 char sname[64]; /* asciiz server hostname */ 94 char file[128]; /* asciiz boot file name */ 95 96 uint8_t options[1024]; /* optional parameters */ 97 } dhcpData; 98 private: 99 Message(uint8_t operation, 100 const uint8_t (&macAddress)[ETH_ALEN], 101 uint8_t type); 102 103 void addOption(uint8_t type, const void* data, uint8_t size); 104 template<typename T> addOption(uint8_t type,T data)105 void addOption(uint8_t type, T data) { 106 static_assert(sizeof(T) <= 255, "The size of data is too large"); 107 addOption(type, &data, sizeof(data)); 108 } 109 template<typename T, size_t N> addOption(uint8_t type,T (& items)[N])110 void addOption(uint8_t type, T (&items)[N]) { 111 static_assert(sizeof(T) * N <= 255, 112 "The size of data is too large"); 113 uint8_t* opts = nextOption(); 114 *opts++ = type; 115 *opts++ = sizeof(T) * N; 116 for (const T& item : items) { 117 memcpy(opts, &item, sizeof(item)); 118 opts += sizeof(item); 119 } 120 updateSize(opts); 121 } 122 void endOptions(); 123 124 const uint8_t* getOption(uint8_t optCode, uint8_t* length) const; 125 uint8_t* nextOption(); 126 void updateSize(uint8_t* optionsEnd); 127 size_t mSize; 128 }; 129 130 static_assert(offsetof(Message::Dhcp, htype) == sizeof(Message::Dhcp::op), 131 "Invalid packing for DHCP message struct"); 132