11afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold/*
21afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * Copyright (C) 2017 The Android Open Source Project
31afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold *
41afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * Licensed under the Apache License, Version 2.0 (the "License");
51afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * you may not use this file except in compliance with the License.
61afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * You may obtain a copy of the License at
71afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold *
81afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold *      http://www.apache.org/licenses/LICENSE-2.0
91afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold *
101afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * Unless required by applicable law or agreed to in writing, software
111afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * distributed under the License is distributed on an "AS IS" BASIS,
121afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * See the License for the specific language governing permissions and
141afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold * limitations under the License.
151afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold */
161afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
171afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldpackage com.android.server;
181afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
191afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport static android.Manifest.permission.DUMP;
2093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport static android.net.IpSecManager.INVALID_RESOURCE_ID;
218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport static android.system.OsConstants.AF_INET;
228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport static android.system.OsConstants.IPPROTO_UDP;
238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport static android.system.OsConstants.SOCK_DGRAM;
248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport static com.android.internal.util.Preconditions.checkNotNull;
251afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
261afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.content.Context;
271afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.net.IIpSecService;
281afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.net.INetd;
2993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.net.IpSecAlgorithm;
3093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.net.IpSecConfig;
3193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.net.IpSecManager;
328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.net.IpSecSpiResponse;
3393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.net.IpSecTransform;
348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.net.IpSecTransformResponse;
358dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.net.IpSecUdpEncapResponse;
361afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.net.util.NetdService;
3793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.Binder;
3893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.IBinder;
3993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.ParcelFileDescriptor;
401afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.os.RemoteException;
4193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.ServiceSpecificException;
428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.system.ErrnoException;
438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.system.Os;
448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.system.OsConstants;
451afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.util.Log;
461afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport android.util.Slog;
4793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.util.SparseArray;
4893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport com.android.internal.annotations.GuardedBy;
491afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport java.io.FileDescriptor;
508dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport java.io.IOException;
511afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldimport java.io.PrintWriter;
528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport java.net.InetAddress;
538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport java.net.InetSocketAddress;
548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport java.net.UnknownHostException;
5593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport java.util.concurrent.atomic.AtomicInteger;
568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport libcore.io.IoUtils;
571afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
581afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold/** @hide */
591afbef40c68373f3871eed087c546cfe1911ee36Nathan Haroldpublic class IpSecService extends IIpSecService.Stub {
601afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    private static final String TAG = "IpSecService";
611afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
631afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    private static final String NETD_SERVICE_NAME = "netd";
6493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    private static final int[] DIRECTIONS =
6593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN};
661afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private static final int NETD_FETCH_TIMEOUT = 5000; //ms
688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private static final int MAX_PORT_BIND_ATTEMPTS = 10;
698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private static final InetAddress INADDR_ANY;
708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    static {
728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try {
738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        } catch (UnknownHostException e) {
758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw new RuntimeException(e);
768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved
808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer
818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    /* Binder context for this service */
831afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    private final Context mContext;
841afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    /** Should be a never-repeating global ID for resources */
868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private static AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0);
871afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    @GuardedBy("this")
898dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private final ManagedResourceArray<SpiRecord> mSpiRecords = new ManagedResourceArray<>();
908dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    @GuardedBy("this")
928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private final ManagedResourceArray<TransformRecord> mTransformRecords =
938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            new ManagedResourceArray<>();
941afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    @GuardedBy("this")
968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private final ManagedResourceArray<UdpSocketRecord> mUdpSocketRecords =
978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            new ManagedResourceArray<>();
9893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
998dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    /**
1008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * The ManagedResource class provides a facility to cleanly and reliably release system
1018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * resources. It relies on two things: an IBinder that allows ManagedResource to automatically
1028dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * clean up in the event that the Binder dies and a user-provided resourceId that should
1038dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * uniquely identify the managed resource. To use this class, the user should implement the
1048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * releaseResources() method that is responsible for releasing system resources when invoked.
1058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     */
10693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    private abstract class ManagedResource implements IBinder.DeathRecipient {
10793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        final int pid;
10893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        final int uid;
10993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private IBinder mBinder;
1108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        protected int mResourceId;
1118dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
1128dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private AtomicInteger mReferenceCount = new AtomicInteger(0);
11393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
1148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        ManagedResource(int resourceId, IBinder binder) {
11593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            super();
11693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mBinder = binder;
1178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mResourceId = resourceId;
11893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            pid = Binder.getCallingPid();
11993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            uid = Binder.getCallingUid();
12093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
12193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            try {
12293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                mBinder.linkToDeath(this, 0);
12393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            } catch (RemoteException e) {
12493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                binderDied();
12593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            }
12693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
12793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
1288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public void addReference() {
1298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mReferenceCount.incrementAndGet();
1308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
1318dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
1328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public void removeReference() {
1338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (mReferenceCount.decrementAndGet() < 0) {
1348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Log.wtf(TAG, "Programming error: negative reference count");
1358dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
1368dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
1378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
1388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public boolean isReferenced() {
1398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return (mReferenceCount.get() > 0);
1408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
1418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
1428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public void checkOwnerOrSystemAndThrow() {
1438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (uid != Binder.getCallingUid()
1448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) {
1458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throw new SecurityException("Only the owner may access managed resources!");
1468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
1478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
1488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
14993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        /**
15093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold         * When this record is no longer needed for managing system resources this function should
1518dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         * clean up all system resources and nullify the record. This function shall perform all
1528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         * necessary cleanup of the resources managed by this record.
1538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         *
1548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         * <p>NOTE: this function verifies ownership before allowing resources to be freed.
15593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold         */
1568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public final void release() throws RemoteException {
1578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            synchronized (IpSecService.this) {
1588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                if (isReferenced()) {
1598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    throw new IllegalStateException(
1608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                            "Cannot release a resource that has active references!");
1618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                }
16293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
1638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                if (mResourceId == INVALID_RESOURCE_ID) {
1648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    return;
1658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                }
1668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
1678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                releaseResources();
1688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                if (mBinder != null) {
1698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    mBinder.unlinkToDeath(this, 0);
1708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                }
1718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mBinder = null;
17293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
1738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mResourceId = INVALID_RESOURCE_ID;
1748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
17593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
17693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
17793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        /**
17893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold         * If the Binder object dies, this function is called to free the system resources that are
17993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold         * being managed by this record and to subsequently release this record for garbage
18093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold         * collection
18193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold         */
18293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        public final void binderDied() {
1838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            try {
1848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                release();
1858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } catch (Exception e) {
1868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Log.e(TAG, "Failed to release resource: " + e);
1878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
18893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
18993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
19093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        /**
19193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold         * Implement this method to release all system resources that are being protected by this
19293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold         * record. Once the resources are released, the record should be invalidated and no longer
1938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         * used by calling release(). This should NEVER be called directly.
1948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         *
1958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         * <p>Calls to this are always guarded by IpSecService#this
19693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold         */
1978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        protected abstract void releaseResources() throws RemoteException;
19893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    };
19993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
2008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    /**
2018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * Minimal wrapper around SparseArray that performs ownership
2028dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * validation on element accesses.
2038dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     */
2048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private class ManagedResourceArray<T extends ManagedResource> {
2058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        SparseArray<T> mArray = new SparseArray<>();
2068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2078dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        T get(int key) {
2088dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            T val = mArray.get(key);
209b6d2eff8b1ad4ceed1f8a97f19e43aff5452898fNathan Harold            // The value should never be null unless the resource doesn't exist
210b6d2eff8b1ad4ceed1f8a97f19e43aff5452898fNathan Harold            // (since we do not allow null resources to be added).
211b6d2eff8b1ad4ceed1f8a97f19e43aff5452898fNathan Harold            if (val != null) {
212b6d2eff8b1ad4ceed1f8a97f19e43aff5452898fNathan Harold                val.checkOwnerOrSystemAndThrow();
213b6d2eff8b1ad4ceed1f8a97f19e43aff5452898fNathan Harold            }
2148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return val;
2158dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
2168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        void put(int key, T obj) {
2188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            checkNotNull(obj, "Null resources cannot be added");
2198dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mArray.put(key, obj);
2208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
2218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        void remove(int key) {
2238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mArray.remove(key);
2248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
2258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
2268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
22793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    private final class TransformRecord extends ManagedResource {
2288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final IpSecConfig mConfig;
2298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final SpiRecord[] mSpis;
2308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final UdpSocketRecord mSocket;
23193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
2328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        TransformRecord(
2338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                int resourceId,
2348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                IBinder binder,
2358dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                IpSecConfig config,
2368dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                SpiRecord[] spis,
2378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                UdpSocketRecord socket) {
2388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            super(resourceId, binder);
23993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mConfig = config;
2408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mSpis = spis;
2418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mSocket = socket;
2428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            for (int direction : DIRECTIONS) {
2448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSpis[direction].addReference();
2458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSpis[direction].setOwnedByTransform();
2468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
2478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (mSocket != null) {
2498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSocket.addReference();
2508dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
25193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
25293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
25393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        public IpSecConfig getConfig() {
25493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            return mConfig;
25593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
25693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
2578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public SpiRecord getSpiRecord(int direction) {
2588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mSpis[direction];
2598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
2608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /** always guarded by IpSecService#this */
26293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        @Override
26393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        protected void releaseResources() {
26493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            for (int direction : DIRECTIONS) {
2658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                int spi = mSpis[direction].getSpi();
26693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                try {
26793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    getNetdInstance()
26893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                            .ipSecDeleteSecurityAssociation(
26993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    mResourceId,
27093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    direction,
27193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    (mConfig.getLocalAddress() != null)
27293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                            ? mConfig.getLocalAddress().getHostAddress()
27393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                            : "",
27493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    (mConfig.getRemoteAddress() != null)
27593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                            ? mConfig.getRemoteAddress().getHostAddress()
27693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                            : "",
2778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                    spi);
27893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                } catch (ServiceSpecificException e) {
27993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    // FIXME: get the error code and throw is at an IOException from Errno Exception
28093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                } catch (RemoteException e) {
28193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    Log.e(TAG, "Failed to delete SA with ID: " + mResourceId);
28293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                }
28393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            }
28493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
2858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            for (int direction : DIRECTIONS) {
2868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSpis[direction].removeReference();
2878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
2888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2898dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (mSocket != null) {
2908dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSocket.removeReference();
2918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
29293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
29393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
29493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
29593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    private final class SpiRecord extends ManagedResource {
29693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private final int mDirection;
29793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private final String mLocalAddress;
29893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private final String mRemoteAddress;
29993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private int mSpi;
3008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private boolean mOwnedByTransform = false;
30293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
30393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        SpiRecord(
30493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                int resourceId,
3058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                IBinder binder,
30693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                int direction,
30793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                String localAddress,
30893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                String remoteAddress,
3098dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                int spi) {
3108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            super(resourceId, binder);
31193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mDirection = direction;
31293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mLocalAddress = localAddress;
31393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mRemoteAddress = remoteAddress;
31493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mSpi = spi;
31593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
31693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
3178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /** always guarded by IpSecService#this */
3188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        @Override
31993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        protected void releaseResources() {
3208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (mOwnedByTransform) {
3218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Log.d(TAG, "Cannot release Spi " + mSpi + ": Currently locked by a Transform");
3228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // Because SPIs are "handed off" to transform, objects, they should never be
3238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // freed from the SpiRecord once used in a transform. (They refer to the same SA,
3248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // thus ownership and responsibility for freeing these resources passes to the
3258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // Transform object). Thus, we should let the user free them without penalty once
3268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // they are applied in a Transform object.
3278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                return;
3288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
3298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
33093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            try {
33193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                getNetdInstance()
33293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        .ipSecDeleteSecurityAssociation(
33393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi);
33493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            } catch (ServiceSpecificException e) {
33593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                // FIXME: get the error code and throw is at an IOException from Errno Exception
33693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            } catch (RemoteException e) {
33793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId);
33893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            }
33993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
34093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
3418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
3428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public int getSpi() {
3448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mSpi;
3458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
3468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public void setOwnedByTransform() {
3488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (mOwnedByTransform) {
3498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // Programming error
350d6d8e452c15cd7f7020891601e41a9561dedc468Andreas Gampe                throw new IllegalStateException("Cannot own an SPI twice!");
3518dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
3528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mOwnedByTransform = true;
35493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
35593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
35693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
3578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private final class UdpSocketRecord extends ManagedResource {
3588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private FileDescriptor mSocket;
3598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final int mPort;
3608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        UdpSocketRecord(int resourceId, IBinder binder, FileDescriptor socket, int port) {
3628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            super(resourceId, binder);
3638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mSocket = socket;
3648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mPort = port;
3658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
3668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /** always guarded by IpSecService#this */
3688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        @Override
3698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        protected void releaseResources() {
3708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            Log.d(TAG, "Closing port " + mPort);
3718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            IoUtils.closeQuietly(mSocket);
3728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mSocket = null;
3738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
3748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public int getPort() {
3768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mPort;
3778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
37893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
3798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public FileDescriptor getSocket() {
3808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mSocket;
3818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
3828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
38393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
3841afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    /**
3851afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold     * Constructs a new IpSecService instance
3861afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold     *
3871afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold     * @param context Binder context for this service
3881afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold     */
3891afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    private IpSecService(Context context) {
3901afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        mContext = context;
3911afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
3921afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
3931afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    static IpSecService create(Context context) throws InterruptedException {
3941afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        final IpSecService service = new IpSecService(context);
3951afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        service.connectNativeNetdService();
3961afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        return service;
3971afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
3981afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
3991afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    public void systemReady() {
4001afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        if (isNetdAlive()) {
4011afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold            Slog.d(TAG, "IpSecService is ready");
4021afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        } else {
4031afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold            Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!");
4041afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        }
4051afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
4061afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
4071afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    private void connectNativeNetdService() {
4081afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        // Avoid blocking the system server to do this
409b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold        new Thread() {
410b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold            @Override
411b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold            public void run() {
412b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold                synchronized (IpSecService.this) {
413b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold                    NetdService.get(NETD_FETCH_TIMEOUT);
414b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold                }
415b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold            }
416b0e0508582c8f1cbee74ffbf11b8409dd28934e8Nathan Harold        }.start();
4171afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
4181afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
41993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    INetd getNetdInstance() throws RemoteException {
4201afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        final INetd netd = NetdService.getInstance();
4211afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        if (netd == null) {
42293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            throw new RemoteException("Failed to Get Netd Instance");
4231afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        }
4241afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        return netd;
4251afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
4261afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
4278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    synchronized boolean isNetdAlive() {
4288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try {
4298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            final INetd netd = getNetdInstance();
4308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (netd == null) {
4311afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold                return false;
4321afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold            }
4338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return netd.isAlive();
4348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        } catch (RemoteException re) {
4358dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return false;
4361afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        }
4371afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
4381afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
4391afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    @Override
44093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /** Get a new SPI and maintain the reservation in the system server */
4418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public synchronized IpSecSpiResponse reserveSecurityParameterIndex(
44293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            int direction, String remoteAddress, int requestedSpi, IBinder binder)
44393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            throws RemoteException {
44493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        int resourceId = mNextResourceId.getAndIncrement();
44593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
44693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
44793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        String localAddress = "";
44893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        try {
44993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            spi =
45093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    getNetdInstance()
45193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                            .ipSecAllocateSpi(
45293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    resourceId,
45393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    direction,
45493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    localAddress,
45593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    remoteAddress,
45693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    requestedSpi);
45793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            Log.d(TAG, "Allocated SPI " + spi);
4588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mSpiRecords.put(
4598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    resourceId,
4608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    new SpiRecord(resourceId, binder, direction, localAddress, remoteAddress, spi));
46193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        } catch (ServiceSpecificException e) {
46293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            // TODO: Add appropriate checks when other ServiceSpecificException types are supported
4638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return new IpSecSpiResponse(
4648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    IpSecManager.Status.SPI_UNAVAILABLE, IpSecManager.INVALID_RESOURCE_ID, spi);
46593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        } catch (RemoteException e) {
46693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            throw e.rethrowFromSystemServer();
46793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
4688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        return new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, spi);
4698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
4708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
4718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    /* This method should only be called from Binder threads. Do not call this from
4728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * within the system server as it will crash the system on failure.
4738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     */
4748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private synchronized <T extends ManagedResource> void releaseManagedResource(
4758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            ManagedResourceArray<T> resArray, int resourceId, String typeName)
4768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throws RemoteException {
4778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // We want to non-destructively get so that we can check credentials before removing
4788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // this from the records.
4798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        T record = resArray.get(resourceId);
4808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
4818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (record == null) {
4828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw new IllegalArgumentException(
4838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    typeName + " " + resourceId + " is not available to be deleted");
4848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
4858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
4868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        record.release();
4878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        resArray.remove(resourceId);
48893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
48993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
49093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /** Release a previously allocated SPI that has been registered with the system server */
49193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
4928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public void releaseSecurityParameterIndex(int resourceId) throws RemoteException {
4938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        releaseManagedResource(mSpiRecords, resourceId, "SecurityParameterIndex");
4948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
4958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
4968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    /**
4978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * This function finds and forcibly binds to a random system port, ensuring that the port cannot
4988dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * be unbound.
4998dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     *
5008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * <p>A socket cannot be un-bound from a port if it was bound to that port by number. To select
5018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * a random open port and then bind by number, this function creates a temp socket, binds to a
5028dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * random port (specifying 0), gets that port number, and then uses is to bind the user's UDP
5038dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * Encapsulation Socket forcibly, so that it cannot be un-bound by the user with the returned
5048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * FileHandle.
5058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     *
5068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * <p>The loop in this function handles the inherent race window between un-binding to a port
5078dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * and re-binding, during which the system could *technically* hand that port out to someone
5088dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * else.
5098dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     */
5108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private void bindToRandomPort(FileDescriptor sockFd) throws IOException {
5118dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) {
5128dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            try {
5138dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
5148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Os.bind(probeSocket, INADDR_ANY, 0);
5158dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                int port = ((InetSocketAddress) Os.getsockname(probeSocket)).getPort();
5168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Os.close(probeSocket);
5178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Log.v(TAG, "Binding to port " + port);
5188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Os.bind(sockFd, INADDR_ANY, port);
5198dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                return;
5208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } catch (ErrnoException e) {
5218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // Someone miraculously claimed the port just after we closed probeSocket.
5228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                if (e.errno == OsConstants.EADDRINUSE) {
5238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    continue;
5248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                }
5258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throw e.rethrowAsIOException();
5268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
5278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
5288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port");
5298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
53093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
53193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
53293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * Open a socket via the system server and bind it to the specified port (random if port=0).
53393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * This will return a PFD to the user that represent a bound UDP socket. The system server will
53493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * cache the socket and a record of its owner so that it can and must be freed when no longer
53593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * needed.
53693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
53793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
5388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public synchronized IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, IBinder binder)
5398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throws RemoteException {
5408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (port != 0 && (port < FREE_PORT_MIN || port > PORT_MAX)) {
5418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw new IllegalArgumentException(
5428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    "Specified port number must be a valid non-reserved UDP port");
5438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
5448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        int resourceId = mNextResourceId.getAndIncrement();
5458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        FileDescriptor sockFd = null;
5468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try {
5478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
5488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
5498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (port != 0) {
5508dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Log.v(TAG, "Binding to port " + port);
5518dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Os.bind(sockFd, INADDR_ANY, port);
5528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } else {
5538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                bindToRandomPort(sockFd);
5548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
5558dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            // This code is common to both the unspecified and specified port cases
5568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            Os.setsockoptInt(
5578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    sockFd,
5588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    OsConstants.IPPROTO_UDP,
5598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    OsConstants.UDP_ENCAP,
5608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    OsConstants.UDP_ENCAP_ESPINUDP);
5618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
5628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mUdpSocketRecords.put(
5638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    resourceId, new UdpSocketRecord(resourceId, binder, sockFd, port));
5648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, sockFd);
5658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        } catch (IOException | ErrnoException e) {
5668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            IoUtils.closeQuietly(sockFd);
5678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
5688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // If we make it to here, then something has gone wrong and we couldn't open a socket.
5698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // The only reasonable condition that would cause that is resource unavailable.
5708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
57193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
57293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
57393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /** close a socket that has been been allocated by and registered with the system server */
57493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
5758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public void closeUdpEncapsulationSocket(int resourceId) throws RemoteException {
5768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
5778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        releaseManagedResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket");
5788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
57993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
58093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
58193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * Create a transport mode transform, which represent two security associations (one in each
58293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * direction) in the kernel. The transform will be cached by the system server and must be freed
58393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * when no longer needed. It is possible to free one, deleting the SA from underneath sockets
58493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * that are using it, which will result in all of those sockets becoming unable to send or
58593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * receive data.
58693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
58793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
5888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public synchronized IpSecTransformResponse createTransportModeTransform(
5898dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            IpSecConfig c, IBinder binder) throws RemoteException {
59093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        int resourceId = mNextResourceId.getAndIncrement();
5918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        SpiRecord[] spis = new SpiRecord[DIRECTIONS.length];
5928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // TODO: Basic input validation here since it's coming over the Binder
5938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        int encapType, encapLocalPort = 0, encapRemotePort = 0;
5948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        UdpSocketRecord socketRecord = null;
5958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        encapType = c.getEncapType();
5968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (encapType != IpSecTransform.ENCAP_NONE) {
5978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            socketRecord = mUdpSocketRecords.get(c.getEncapLocalResourceId());
5988dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            encapLocalPort = socketRecord.getPort();
5998dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            encapRemotePort = c.getEncapRemotePort();
6008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
6018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
60293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        for (int direction : DIRECTIONS) {
60393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            IpSecAlgorithm auth = c.getAuthentication(direction);
60493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            IpSecAlgorithm crypt = c.getEncryption(direction);
6058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
6068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction));
6078dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            int spi = spis[direction].getSpi();
60893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            try {
6090f807899b803a20ba1b0b047bf8c5c8717331508ludi                getNetdInstance()
6100f807899b803a20ba1b0b047bf8c5c8717331508ludi                        .ipSecAddSecurityAssociation(
6110f807899b803a20ba1b0b047bf8c5c8717331508ludi                                resourceId,
6120f807899b803a20ba1b0b047bf8c5c8717331508ludi                                c.getMode(),
6130f807899b803a20ba1b0b047bf8c5c8717331508ludi                                direction,
6140f807899b803a20ba1b0b047bf8c5c8717331508ludi                                (c.getLocalAddress() != null)
6150f807899b803a20ba1b0b047bf8c5c8717331508ludi                                        ? c.getLocalAddress().getHostAddress()
6160f807899b803a20ba1b0b047bf8c5c8717331508ludi                                        : "",
6170f807899b803a20ba1b0b047bf8c5c8717331508ludi                                (c.getRemoteAddress() != null)
6180f807899b803a20ba1b0b047bf8c5c8717331508ludi                                        ? c.getRemoteAddress().getHostAddress()
6190f807899b803a20ba1b0b047bf8c5c8717331508ludi                                        : "",
6200f807899b803a20ba1b0b047bf8c5c8717331508ludi                                (c.getNetwork() != null)
6210f807899b803a20ba1b0b047bf8c5c8717331508ludi                                        ? c.getNetwork().getNetworkHandle()
6220f807899b803a20ba1b0b047bf8c5c8717331508ludi                                        : 0,
6230f807899b803a20ba1b0b047bf8c5c8717331508ludi                                spi,
6240f807899b803a20ba1b0b047bf8c5c8717331508ludi                                (auth != null) ? auth.getName() : "",
6250f807899b803a20ba1b0b047bf8c5c8717331508ludi                                (auth != null) ? auth.getKey() : null,
6260f807899b803a20ba1b0b047bf8c5c8717331508ludi                                (auth != null) ? auth.getTruncationLengthBits() : 0,
6270f807899b803a20ba1b0b047bf8c5c8717331508ludi                                (crypt != null) ? crypt.getName() : "",
6280f807899b803a20ba1b0b047bf8c5c8717331508ludi                                (crypt != null) ? crypt.getKey() : null,
6290f807899b803a20ba1b0b047bf8c5c8717331508ludi                                (crypt != null) ? crypt.getTruncationLengthBits() : 0,
6300f807899b803a20ba1b0b047bf8c5c8717331508ludi                                encapType,
6310f807899b803a20ba1b0b047bf8c5c8717331508ludi                                encapLocalPort,
6320f807899b803a20ba1b0b047bf8c5c8717331508ludi                                encapRemotePort);
63393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            } catch (ServiceSpecificException e) {
63493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                // FIXME: get the error code and throw is at an IOException from Errno Exception
6350f807899b803a20ba1b0b047bf8c5c8717331508ludi                return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
63693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            }
63793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
6388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // Both SAs were created successfully, time to construct a record and lock it away
6398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        mTransformRecords.put(
6408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                resourceId, new TransformRecord(resourceId, binder, c, spis, socketRecord));
6418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId);
64293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
64393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
64493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
64593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * Delete a transport mode transform that was previously allocated by + registered with the
64693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * system server. If this is called on an inactive (or non-existent) transform, it will not
64793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * return an error. It's safe to de-allocate transforms that may have already been deleted for
64893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * other reasons.
64993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
65093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
65193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    public void deleteTransportModeTransform(int resourceId) throws RemoteException {
6528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        releaseManagedResource(mTransformRecords, resourceId, "IpSecTransform");
65393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
65493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
65593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
65693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * Apply an active transport mode transform to a socket, which will apply the IPsec security
65793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * association as a correspondent policy to the provided socket
65893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
65993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
6608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public synchronized void applyTransportModeTransform(
6618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            ParcelFileDescriptor socket, int resourceId) throws RemoteException {
6628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // Synchronize liberally here because we are using ManagedResources in this block
6638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        TransformRecord info;
6648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // FIXME: this code should be factored out into a security check + getter
6658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        info = mTransformRecords.get(resourceId);
6668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
6678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (info == null) {
6688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw new IllegalArgumentException("Transform " + resourceId + " is not active");
6698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
67093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
6718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // TODO: make this a function.
6728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (info.pid != getCallingPid() || info.uid != getCallingUid()) {
6738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw new SecurityException("Only the owner of an IpSec Transform may apply it!");
6748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
67593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
6768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        IpSecConfig c = info.getConfig();
6778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try {
6788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            for (int direction : DIRECTIONS) {
6798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                getNetdInstance()
6808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                        .ipSecApplyTransportModeTransform(
6818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                socket.getFileDescriptor(),
6828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                resourceId,
6838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                direction,
6848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                (c.getLocalAddress() != null)
6858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        ? c.getLocalAddress().getHostAddress()
6868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        : "",
6878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                (c.getRemoteAddress() != null)
6888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        ? c.getRemoteAddress().getHostAddress()
6898dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        : "",
6908dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                info.getSpiRecord(direction).getSpi());
69193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            }
6928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        } catch (ServiceSpecificException e) {
6938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            // FIXME: get the error code and throw is at an IOException from Errno Exception
69493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
69593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
6968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
69793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
69893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * Remove a transport mode transform from a socket, applying the default (empty) policy. This
69993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * will ensure that NO IPsec policy is applied to the socket (would be the equivalent of
70093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * applying a policy that performs no IPsec). Today the resourceId parameter is passed but not
70193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * used: reserved for future improved input validation.
70293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
70393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
70493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    public void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId)
70593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            throws RemoteException {
70693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        try {
70793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            getNetdInstance().ipSecRemoveTransportModeTransform(socket.getFileDescriptor());
70893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        } catch (ServiceSpecificException e) {
70993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            // FIXME: get the error code and throw is at an IOException from Errno Exception
71093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
71193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
71293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
71393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
7141afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
7151afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
7168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // TODO: Add dump code to print out a log of all the resources being tracked
7171afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        pw.println("IpSecService Log:");
7181afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead"));
7191afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        pw.println();
7201afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
7211afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold}
722