Home | History | Annotate | Download | only in common
      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 
     55     const uint8_t* data() const {
     56         return reinterpret_cast<const uint8_t*>(&dhcpData);
     57     }
     58     uint8_t* data() {
     59         return reinterpret_cast<uint8_t*>(&dhcpData);
     60     }
     61     const uint8_t* end() const { return data() + mSize; }
     62 
     63     size_t optionsSize() const;
     64     size_t size() const { return mSize; }
     65     void setSize(size_t size) { mSize = size; }
     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>
    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>
    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