1 /*
2  * Copyright (C) 2019 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 
17 package android.net.shared;
18 
19 import android.annotation.Nullable;
20 import android.net.INetd;
21 import android.net.Network;
22 import android.net.ProvisioningConfigurationParcelable;
23 import android.net.StaticIpConfiguration;
24 import android.net.apf.ApfCapabilities;
25 import android.net.ip.IIpClient;
26 
27 import java.util.Objects;
28 import java.util.StringJoiner;
29 
30 /**
31  * This class encapsulates parameters to be passed to
32  * IpClient#startProvisioning(). A defensive copy is made by IpClient
33  * and the values specified herein are in force until IpClient#stop()
34  * is called.
35  *
36  * Example use:
37  *
38  *     final ProvisioningConfiguration config =
39  *             new ProvisioningConfiguration.Builder()
40  *                     .withPreDhcpAction()
41  *                     .withProvisioningTimeoutMs(36 * 1000)
42  *                     .build();
43  *     mIpClient.startProvisioning(config.toStableParcelable());
44  *     ...
45  *     mIpClient.stop();
46  *
47  * The specified provisioning configuration will only be active until
48  * IIpClient#stop() is called. Future calls to IIpClient#startProvisioning()
49  * must specify the configuration again.
50  * @hide
51  */
52 public class ProvisioningConfiguration {
53     // TODO: Delete this default timeout once those callers that care are
54     // fixed to pass in their preferred timeout.
55     //
56     // We pick 36 seconds so we can send DHCP requests at
57     //
58     //     t=0, t=2, t=6, t=14, t=30
59     //
60     // allowing for 10% jitter.
61     private static final int DEFAULT_TIMEOUT_MS = 36 * 1000;
62 
63     /**
64      * Builder to create a {@link ProvisioningConfiguration}.
65      */
66     public static class Builder {
67         protected ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
68 
69         /**
70          * Specify that the configuration should not enable IPv4. It is enabled by default.
71          */
withoutIPv4()72         public Builder withoutIPv4() {
73             mConfig.mEnableIPv4 = false;
74             return this;
75         }
76 
77         /**
78          * Specify that the configuration should not enable IPv6. It is enabled by default.
79          */
withoutIPv6()80         public Builder withoutIPv6() {
81             mConfig.mEnableIPv6 = false;
82             return this;
83         }
84 
85         /**
86          * Specify that the configuration should not use a MultinetworkPolicyTracker. It is used
87          * by default.
88          */
withoutMultinetworkPolicyTracker()89         public Builder withoutMultinetworkPolicyTracker() {
90             mConfig.mUsingMultinetworkPolicyTracker = false;
91             return this;
92         }
93 
94         /**
95          * Specify that the configuration should not use a IpReachabilityMonitor. It is used by
96          * default.
97          */
withoutIpReachabilityMonitor()98         public Builder withoutIpReachabilityMonitor() {
99             mConfig.mUsingIpReachabilityMonitor = false;
100             return this;
101         }
102 
103         /**
104          * Identical to {@link #withPreDhcpAction(int)}, using a default timeout.
105          * @see #withPreDhcpAction(int)
106          */
withPreDhcpAction()107         public Builder withPreDhcpAction() {
108             mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS;
109             return this;
110         }
111 
112         /**
113          * Specify that {@link IpClientCallbacks#onPreDhcpAction()} should be called. Clients must
114          * call {@link IIpClient#completedPreDhcpAction()} when the callback called. This behavior
115          * is disabled by default.
116          * @param dhcpActionTimeoutMs Timeout for clients to call completedPreDhcpAction().
117          */
withPreDhcpAction(int dhcpActionTimeoutMs)118         public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
119             mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs;
120             return this;
121         }
122 
123         /**
124          * Specify the initial provisioning configuration.
125          */
withInitialConfiguration(InitialConfiguration initialConfig)126         public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
127             mConfig.mInitialConfig = initialConfig;
128             return this;
129         }
130 
131         /**
132          * Specify a static configuration for provisioning.
133          */
withStaticConfiguration(StaticIpConfiguration staticConfig)134         public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
135             mConfig.mStaticIpConfig = staticConfig;
136             return this;
137         }
138 
139         /**
140          * Specify ApfCapabilities.
141          */
withApfCapabilities(ApfCapabilities apfCapabilities)142         public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
143             mConfig.mApfCapabilities = apfCapabilities;
144             return this;
145         }
146 
147         /**
148          * Specify the timeout to use for provisioning.
149          */
withProvisioningTimeoutMs(int timeoutMs)150         public Builder withProvisioningTimeoutMs(int timeoutMs) {
151             mConfig.mProvisioningTimeoutMs = timeoutMs;
152             return this;
153         }
154 
155         /**
156          * Specify that IPv6 address generation should use a random MAC address.
157          */
withRandomMacAddress()158         public Builder withRandomMacAddress() {
159             mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
160             return this;
161         }
162 
163         /**
164          * Specify that IPv6 address generation should use a stable MAC address.
165          */
withStableMacAddress()166         public Builder withStableMacAddress() {
167             mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
168             return this;
169         }
170 
171         /**
172          * Specify the network to use for provisioning.
173          */
withNetwork(Network network)174         public Builder withNetwork(Network network) {
175             mConfig.mNetwork = network;
176             return this;
177         }
178 
179         /**
180          * Specify the display name that the IpClient should use.
181          */
withDisplayName(String displayName)182         public Builder withDisplayName(String displayName) {
183             mConfig.mDisplayName = displayName;
184             return this;
185         }
186 
187         /**
188          * Build the configuration using previously specified parameters.
189          */
build()190         public ProvisioningConfiguration build() {
191             return new ProvisioningConfiguration(mConfig);
192         }
193     }
194 
195     public boolean mEnableIPv4 = true;
196     public boolean mEnableIPv6 = true;
197     public boolean mUsingMultinetworkPolicyTracker = true;
198     public boolean mUsingIpReachabilityMonitor = true;
199     public int mRequestedPreDhcpActionMs;
200     public InitialConfiguration mInitialConfig;
201     public StaticIpConfiguration mStaticIpConfig;
202     public ApfCapabilities mApfCapabilities;
203     public int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
204     public int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
205     public Network mNetwork = null;
206     public String mDisplayName = null;
207 
ProvisioningConfiguration()208     public ProvisioningConfiguration() {} // used by Builder
209 
ProvisioningConfiguration(ProvisioningConfiguration other)210     public ProvisioningConfiguration(ProvisioningConfiguration other) {
211         mEnableIPv4 = other.mEnableIPv4;
212         mEnableIPv6 = other.mEnableIPv6;
213         mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker;
214         mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
215         mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
216         mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
217         mStaticIpConfig = other.mStaticIpConfig == null
218                 ? null
219                 : new StaticIpConfiguration(other.mStaticIpConfig);
220         mApfCapabilities = other.mApfCapabilities;
221         mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
222         mIPv6AddrGenMode = other.mIPv6AddrGenMode;
223         mNetwork = other.mNetwork;
224         mDisplayName = other.mDisplayName;
225     }
226 
227     /**
228      * Create a ProvisioningConfigurationParcelable from this ProvisioningConfiguration.
229      */
toStableParcelable()230     public ProvisioningConfigurationParcelable toStableParcelable() {
231         final ProvisioningConfigurationParcelable p = new ProvisioningConfigurationParcelable();
232         p.enableIPv4 = mEnableIPv4;
233         p.enableIPv6 = mEnableIPv6;
234         p.usingMultinetworkPolicyTracker = mUsingMultinetworkPolicyTracker;
235         p.usingIpReachabilityMonitor = mUsingIpReachabilityMonitor;
236         p.requestedPreDhcpActionMs = mRequestedPreDhcpActionMs;
237         p.initialConfig = mInitialConfig == null ? null : mInitialConfig.toStableParcelable();
238         p.staticIpConfig = mStaticIpConfig == null
239                 ? null
240                 : new StaticIpConfiguration(mStaticIpConfig);
241         p.apfCapabilities = mApfCapabilities; // ApfCapabilities is immutable
242         p.provisioningTimeoutMs = mProvisioningTimeoutMs;
243         p.ipv6AddrGenMode = mIPv6AddrGenMode;
244         p.network = mNetwork;
245         p.displayName = mDisplayName;
246         return p;
247     }
248 
249     /**
250      * Create a ProvisioningConfiguration from a ProvisioningConfigurationParcelable.
251      */
fromStableParcelable( @ullable ProvisioningConfigurationParcelable p)252     public static ProvisioningConfiguration fromStableParcelable(
253             @Nullable ProvisioningConfigurationParcelable p) {
254         if (p == null) return null;
255         final ProvisioningConfiguration config = new ProvisioningConfiguration();
256         config.mEnableIPv4 = p.enableIPv4;
257         config.mEnableIPv6 = p.enableIPv6;
258         config.mUsingMultinetworkPolicyTracker = p.usingMultinetworkPolicyTracker;
259         config.mUsingIpReachabilityMonitor = p.usingIpReachabilityMonitor;
260         config.mRequestedPreDhcpActionMs = p.requestedPreDhcpActionMs;
261         config.mInitialConfig = InitialConfiguration.fromStableParcelable(p.initialConfig);
262         config.mStaticIpConfig = p.staticIpConfig == null
263                 ? null
264                 : new StaticIpConfiguration(p.staticIpConfig);
265         config.mApfCapabilities = p.apfCapabilities; // ApfCapabilities is immutable
266         config.mProvisioningTimeoutMs = p.provisioningTimeoutMs;
267         config.mIPv6AddrGenMode = p.ipv6AddrGenMode;
268         config.mNetwork = p.network;
269         config.mDisplayName = p.displayName;
270         return config;
271     }
272 
273     @Override
toString()274     public String toString() {
275         return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
276                 .add("mEnableIPv4: " + mEnableIPv4)
277                 .add("mEnableIPv6: " + mEnableIPv6)
278                 .add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker)
279                 .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
280                 .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
281                 .add("mInitialConfig: " + mInitialConfig)
282                 .add("mStaticIpConfig: " + mStaticIpConfig)
283                 .add("mApfCapabilities: " + mApfCapabilities)
284                 .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
285                 .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
286                 .add("mNetwork: " + mNetwork)
287                 .add("mDisplayName: " + mDisplayName)
288                 .toString();
289     }
290 
291     @Override
equals(Object obj)292     public boolean equals(Object obj) {
293         if (!(obj instanceof ProvisioningConfiguration)) return false;
294         final ProvisioningConfiguration other = (ProvisioningConfiguration) obj;
295         return mEnableIPv4 == other.mEnableIPv4
296                 && mEnableIPv6 == other.mEnableIPv6
297                 && mUsingMultinetworkPolicyTracker == other.mUsingMultinetworkPolicyTracker
298                 && mUsingIpReachabilityMonitor == other.mUsingIpReachabilityMonitor
299                 && mRequestedPreDhcpActionMs == other.mRequestedPreDhcpActionMs
300                 && Objects.equals(mInitialConfig, other.mInitialConfig)
301                 && Objects.equals(mStaticIpConfig, other.mStaticIpConfig)
302                 && Objects.equals(mApfCapabilities, other.mApfCapabilities)
303                 && mProvisioningTimeoutMs == other.mProvisioningTimeoutMs
304                 && mIPv6AddrGenMode == other.mIPv6AddrGenMode
305                 && Objects.equals(mNetwork, other.mNetwork)
306                 && Objects.equals(mDisplayName, other.mDisplayName);
307     }
308 
isValid()309     public boolean isValid() {
310         return (mInitialConfig == null) || mInitialConfig.isValid();
311     }
312 }
313