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 com.android.server;
18 
19 import android.annotation.NonNull;
20 import android.net.ConnectivityManager;
21 import android.util.SparseBooleanArray;
22 
23 import com.android.internal.annotations.GuardedBy;
24 import com.android.internal.annotations.VisibleForTesting;
25 
26 /**
27  * Class used to reserve and release net IDs.
28  *
29  * <p>Instances of this class are thread-safe.
30  *
31  * NetIds are currently 16 bits long and consume 16 bits in the fwmark.
32  * The reason they are large is that applications might get confused if the netId counter
33  * wraps - for example, Network#equals would return true for a current network
34  * and a long-disconnected network.
35  * We could in theory fix this by splitting the identifier in two, e.g., a 24-bit generation
36  * counter and an 8-bit netId. Java Network objects would be constructed from the full 32-bit
37  * number, but only the 8-bit number would be used by netd and the fwmark.
38  * We'd have to fix all code that assumes that it can take a netId or a mark and construct
39  * a Network object from it.
40  */
41 public class NetIdManager {
42     // Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
43     public static final int MIN_NET_ID = 100; // some reserved marks
44     // Top IDs reserved by IpSecService
45     public static final int MAX_NET_ID = ConnectivityManager.getIpSecNetIdRange().getLower() - 1;
46 
47     @GuardedBy("mNetIdInUse")
48     private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
49 
50     @GuardedBy("mNetIdInUse")
51     private int mLastNetId = MIN_NET_ID - 1;
52 
53     private final int mMaxNetId;
54 
NetIdManager()55     public NetIdManager() {
56         this(MAX_NET_ID);
57     }
58 
59     @VisibleForTesting
NetIdManager(int maxNetId)60     NetIdManager(int maxNetId) {
61         mMaxNetId = maxNetId;
62     }
63 
64     /**
65      * Get the first netId that follows the provided lastId and is available.
66      */
getNextAvailableNetIdLocked( int lastId, @NonNull SparseBooleanArray netIdInUse)67     private int getNextAvailableNetIdLocked(
68             int lastId, @NonNull SparseBooleanArray netIdInUse) {
69         int netId = lastId;
70         for (int i = MIN_NET_ID; i <= mMaxNetId; i++) {
71             netId = netId < mMaxNetId ? netId + 1 : MIN_NET_ID;
72             if (!netIdInUse.get(netId)) {
73                 return netId;
74             }
75         }
76         throw new IllegalStateException("No free netIds");
77     }
78 
79     /**
80      * Reserve a new ID for a network.
81      */
82     public int reserveNetId() {
83         synchronized (mNetIdInUse) {
84             mLastNetId = getNextAvailableNetIdLocked(mLastNetId, mNetIdInUse);
85             // Make sure NetID unused.  http://b/16815182
86             mNetIdInUse.put(mLastNetId, true);
87             return mLastNetId;
88         }
89     }
90 
91     /**
92      * Clear a previously reserved ID for a network.
93      */
94     public void releaseNetId(int id) {
95         synchronized (mNetIdInUse) {
96             mNetIdInUse.delete(id);
97         }
98     }
99 }
100