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 public class NetIdManager {
32     // Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
33     public static final int MIN_NET_ID = 100; // some reserved marks
34     // Top IDs reserved by IpSecService
35     public static final int MAX_NET_ID = ConnectivityManager.getIpSecNetIdRange().getLower() - 1;
36 
37     @GuardedBy("mNetIdInUse")
38     private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
39 
40     @GuardedBy("mNetIdInUse")
41     private int mLastNetId = MIN_NET_ID - 1;
42 
43     private final int mMaxNetId;
44 
NetIdManager()45     public NetIdManager() {
46         this(MAX_NET_ID);
47     }
48 
49     @VisibleForTesting
NetIdManager(int maxNetId)50     NetIdManager(int maxNetId) {
51         mMaxNetId = maxNetId;
52     }
53 
54     /**
55      * Get the first netId that follows the provided lastId and is available.
56      */
getNextAvailableNetIdLocked( int lastId, @NonNull SparseBooleanArray netIdInUse)57     private int getNextAvailableNetIdLocked(
58             int lastId, @NonNull SparseBooleanArray netIdInUse) {
59         int netId = lastId;
60         for (int i = MIN_NET_ID; i <= mMaxNetId; i++) {
61             netId = netId < mMaxNetId ? netId + 1 : MIN_NET_ID;
62             if (!netIdInUse.get(netId)) {
63                 return netId;
64             }
65         }
66         throw new IllegalStateException("No free netIds");
67     }
68 
69     /**
70      * Reserve a new ID for a network.
71      */
72     public int reserveNetId() {
73         synchronized (mNetIdInUse) {
74             mLastNetId = getNextAvailableNetIdLocked(mLastNetId, mNetIdInUse);
75             // Make sure NetID unused.  http://b/16815182
76             mNetIdInUse.put(mLastNetId, true);
77             return mLastNetId;
78         }
79     }
80 
81     /**
82      * Clear a previously reserved ID for a network.
83      */
84     public void releaseNetId(int id) {
85         synchronized (mNetIdInUse) {
86             mNetIdInUse.delete(id);
87         }
88     }
89 }
90