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 "interface.h"
19 #include "message.h"
20 #include "result.h"
21 #include "router.h"
22 #include "socket.h"
23 #include "timer.h"
24 
25 #include <netinet/in.h>
26 #include <stdint.h>
27 
28 #include <random>
29 
30 // Options to configure the behavior of the DHCP client.
31 enum class ClientOption : uint32_t {
32     NoGateway = (1 << 0),   // Do not configure the system's default gateway
33 };
34 
35 class DhcpClient {
36 public:
37     // Create a DHCP client with the given |options|. These options are values
38     // from the ClientOption enum.
39     explicit DhcpClient(uint32_t options);
40 
41     // Initialize the DHCP client to listen on |interfaceName|.
42     Result init(const char* interfaceName);
43     Result run();
44 private:
45     enum class State {
46         Init,
47         Selecting,
48         Requesting,
49         Bound,
50         Renewing,
51         Rebinding
52     };
53     const char* stateToStr(State state);
54 
55     // Wait for any pending timeouts
56     void waitAndReceive(const sigset_t& pollSignalMask);
57     // Create a varying timeout (+- 1 second) based on the next timeout.
58     uint32_t calculateTimeoutMillis();
59     // Increase the next timeout in a manner that's compliant with the DHCP RFC.
60     void increaseTimeout();
61     // Move to |state|, the next poll timeout will be zero and the new
62     // state will be immediately evaluated.
63     void setNextState(State state);
64     // Configure network interface based on the DHCP configuration in |msg|.
65     bool configureDhcp(const Message& msg);
66     // Halt network operations on the network interface for when configuration
67     // is not possible and the protocol demands it.
68     void haltNetwork();
69     // Receive a message on the socket and populate |msg| with the received
70     // data. If the message is a valid DHCP message the method returns true. If
71     // it's not valid false is returned.
72     bool receiveDhcpMessage(Message* msg);
73 
74     void sendDhcpDiscover();
75     void sendDhcpRequest(in_addr_t destination);
76     void sendMessage(const Message& message);
77     Result send(in_addr_t source, in_addr_t destination,
78                 uint16_t sourcePort, uint16_t destinationPort,
79                 const uint8_t* data, size_t size);
80 
81     uint32_t mOptions;
82     std::mt19937 mRandomEngine; // Mersenne Twister RNG
83     std::uniform_int_distribution<int> mRandomDistribution;
84 
85     struct DhcpInfo {
86         uint32_t t1;
87         uint32_t t2;
88         uint32_t leaseTime;
89         uint16_t mtu;
90         in_addr_t dns[4];
91         in_addr_t gateway;
92         in_addr_t subnetMask;
93         in_addr_t serverId;
94         in_addr_t offeredAddress;
95     } mDhcpInfo;
96 
97     Router mRouter;
98     Interface mInterface;
99     Message mLastMsg;
100     Timer mT1, mT2;
101     Socket mSocket;
102     State mState;
103     uint32_t mNextTimeout;
104     bool mFuzzNextTimeout;
105 
106     in_addr_t mRequestAddress; // Address we'd like to use in requests
107     in_addr_t mServerAddress;  // Server to send request to
108 };
109 
110