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