IpSecService.java revision d6d8e452c15cd7f7020891601e41a9561dedc468
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);
2098dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            val.checkOwnerOrSystemAndThrow();
2108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return val;
2118dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
2128dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2138dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        void put(int key, T obj) {
2148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            checkNotNull(obj, "Null resources cannot be added");
2158dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mArray.put(key, obj);
2168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
2178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        void remove(int key) {
2198dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mArray.remove(key);
2208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
2218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
2228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
22393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    private final class TransformRecord extends ManagedResource {
2248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final IpSecConfig mConfig;
2258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final SpiRecord[] mSpis;
2268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final UdpSocketRecord mSocket;
22793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
2288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        TransformRecord(
2298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                int resourceId,
2308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                IBinder binder,
2318dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                IpSecConfig config,
2328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                SpiRecord[] spis,
2338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                UdpSocketRecord socket) {
2348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            super(resourceId, binder);
23593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mConfig = config;
2368dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mSpis = spis;
2378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mSocket = socket;
2388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            for (int direction : DIRECTIONS) {
2408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSpis[direction].addReference();
2418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSpis[direction].setOwnedByTransform();
2428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
2438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (mSocket != null) {
2458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSocket.addReference();
2468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
24793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
24893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
24993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        public IpSecConfig getConfig() {
25093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            return mConfig;
25193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
25293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
2538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public SpiRecord getSpiRecord(int direction) {
2548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mSpis[direction];
2558dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
2568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /** always guarded by IpSecService#this */
25893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        @Override
25993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        protected void releaseResources() {
26093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            for (int direction : DIRECTIONS) {
2618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                int spi = mSpis[direction].getSpi();
26293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                try {
26393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    getNetdInstance()
26493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                            .ipSecDeleteSecurityAssociation(
26593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    mResourceId,
26693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    direction,
26793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    (mConfig.getLocalAddress() != null)
26893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                            ? mConfig.getLocalAddress().getHostAddress()
26993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                            : "",
27093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    (mConfig.getRemoteAddress() != null)
27193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                            ? mConfig.getRemoteAddress().getHostAddress()
27293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                            : "",
2738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                    spi);
27493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                } catch (ServiceSpecificException e) {
27593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    // FIXME: get the error code and throw is at an IOException from Errno Exception
27693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                } catch (RemoteException e) {
27793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    Log.e(TAG, "Failed to delete SA with ID: " + mResourceId);
27893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                }
27993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            }
28093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
2818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            for (int direction : DIRECTIONS) {
2828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSpis[direction].removeReference();
2838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
2848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (mSocket != null) {
2868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSocket.removeReference();
2878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
28893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
28993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
29093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
29193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    private final class SpiRecord extends ManagedResource {
29293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private final int mDirection;
29393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private final String mLocalAddress;
29493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private final String mRemoteAddress;
29593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private int mSpi;
2968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private boolean mOwnedByTransform = false;
29893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
29993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        SpiRecord(
30093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                int resourceId,
3018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                IBinder binder,
30293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                int direction,
30393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                String localAddress,
30493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                String remoteAddress,
3058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                int spi) {
3068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            super(resourceId, binder);
30793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mDirection = direction;
30893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mLocalAddress = localAddress;
30993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mRemoteAddress = remoteAddress;
31093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mSpi = spi;
31193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
31293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
3138dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /** always guarded by IpSecService#this */
3148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        @Override
31593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        protected void releaseResources() {
3168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (mOwnedByTransform) {
3178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Log.d(TAG, "Cannot release Spi " + mSpi + ": Currently locked by a Transform");
3188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // Because SPIs are "handed off" to transform, objects, they should never be
3198dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // freed from the SpiRecord once used in a transform. (They refer to the same SA,
3208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // thus ownership and responsibility for freeing these resources passes to the
3218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // Transform object). Thus, we should let the user free them without penalty once
3228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // they are applied in a Transform object.
3238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                return;
3248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
3258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
32693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            try {
32793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                getNetdInstance()
32893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        .ipSecDeleteSecurityAssociation(
32993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi);
33093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            } catch (ServiceSpecificException e) {
33193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                // FIXME: get the error code and throw is at an IOException from Errno Exception
33293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            } catch (RemoteException e) {
33393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId);
33493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            }
33593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
33693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
3378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
3388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public int getSpi() {
3408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mSpi;
3418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
3428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public void setOwnedByTransform() {
3448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (mOwnedByTransform) {
3458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // Programming error
346d6d8e452c15cd7f7020891601e41a9561dedc468Andreas Gampe                throw new IllegalStateException("Cannot own an SPI twice!");
3478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
3488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mOwnedByTransform = true;
35093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
35193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
35293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
3538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private final class UdpSocketRecord extends ManagedResource {
3548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private FileDescriptor mSocket;
3558dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final int mPort;
3568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        UdpSocketRecord(int resourceId, IBinder binder, FileDescriptor socket, int port) {
3588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            super(resourceId, binder);
3598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mSocket = socket;
3608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mPort = port;
3618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
3628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /** always guarded by IpSecService#this */
3648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        @Override
3658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        protected void releaseResources() {
3668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            Log.d(TAG, "Closing port " + mPort);
3678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            IoUtils.closeQuietly(mSocket);
3688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mSocket = null;
3698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
3708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public int getPort() {
3728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mPort;
3738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
37493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
3758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        public FileDescriptor getSocket() {
3768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mSocket;
3778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
3788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
37993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
3801afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    /**
3811afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold     * Constructs a new IpSecService instance
3821afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold     *
3831afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold     * @param context Binder context for this service
3841afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold     */
3851afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    private IpSecService(Context context) {
3861afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        mContext = context;
3871afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
3881afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
3891afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    static IpSecService create(Context context) throws InterruptedException {
3901afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        final IpSecService service = new IpSecService(context);
3911afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        service.connectNativeNetdService();
3921afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        return service;
3931afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
3941afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
3951afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    public void systemReady() {
3961afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        if (isNetdAlive()) {
3971afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold            Slog.d(TAG, "IpSecService is ready");
3981afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        } else {
3991afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold            Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!");
4001afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        }
4011afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
4021afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
4031afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    private void connectNativeNetdService() {
4041afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        // Avoid blocking the system server to do this
4051afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        Thread t =
4061afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold                new Thread(
4071afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold                        new Runnable() {
4081afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold                            @Override
4091afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold                            public void run() {
4108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                synchronized (IpSecService.this) {
4111afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold                                    NetdService.get(NETD_FETCH_TIMEOUT);
4121afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold                                }
4131afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold                            }
4141afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold                        });
4151afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        t.run();
4161afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
4171afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
41893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    INetd getNetdInstance() throws RemoteException {
4191afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        final INetd netd = NetdService.getInstance();
4201afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        if (netd == null) {
42193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            throw new RemoteException("Failed to Get Netd Instance");
4221afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        }
4231afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        return netd;
4241afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
4251afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
4268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    synchronized boolean isNetdAlive() {
4278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try {
4288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            final INetd netd = getNetdInstance();
4298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (netd == null) {
4301afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold                return false;
4311afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold            }
4328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return netd.isAlive();
4338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        } catch (RemoteException re) {
4348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return false;
4351afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        }
4361afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
4371afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold
4381afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    @Override
43993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /** Get a new SPI and maintain the reservation in the system server */
4408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public synchronized IpSecSpiResponse reserveSecurityParameterIndex(
44193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            int direction, String remoteAddress, int requestedSpi, IBinder binder)
44293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            throws RemoteException {
44393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        int resourceId = mNextResourceId.getAndIncrement();
44493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
44593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
44693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        String localAddress = "";
44793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        try {
44893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            spi =
44993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    getNetdInstance()
45093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                            .ipSecAllocateSpi(
45193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    resourceId,
45293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    direction,
45393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    localAddress,
45493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    remoteAddress,
45593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                    requestedSpi);
45693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            Log.d(TAG, "Allocated SPI " + spi);
4578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mSpiRecords.put(
4588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    resourceId,
4598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    new SpiRecord(resourceId, binder, direction, localAddress, remoteAddress, spi));
46093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        } catch (ServiceSpecificException e) {
46193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            // TODO: Add appropriate checks when other ServiceSpecificException types are supported
4628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return new IpSecSpiResponse(
4638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    IpSecManager.Status.SPI_UNAVAILABLE, IpSecManager.INVALID_RESOURCE_ID, spi);
46493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        } catch (RemoteException e) {
46593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            throw e.rethrowFromSystemServer();
46693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
4678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        return new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, spi);
4688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
4698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
4708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    /* This method should only be called from Binder threads. Do not call this from
4718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * within the system server as it will crash the system on failure.
4728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     */
4738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private synchronized <T extends ManagedResource> void releaseManagedResource(
4748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            ManagedResourceArray<T> resArray, int resourceId, String typeName)
4758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throws RemoteException {
4768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // We want to non-destructively get so that we can check credentials before removing
4778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // this from the records.
4788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        T record = resArray.get(resourceId);
4798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
4808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (record == null) {
4818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw new IllegalArgumentException(
4828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    typeName + " " + resourceId + " is not available to be deleted");
4838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
4848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
4858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        record.release();
4868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        resArray.remove(resourceId);
48793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
48893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
48993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /** Release a previously allocated SPI that has been registered with the system server */
49093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
4918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public void releaseSecurityParameterIndex(int resourceId) throws RemoteException {
4928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        releaseManagedResource(mSpiRecords, resourceId, "SecurityParameterIndex");
4938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
4948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
4958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    /**
4968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * This function finds and forcibly binds to a random system port, ensuring that the port cannot
4978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * be unbound.
4988dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     *
4998dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * <p>A socket cannot be un-bound from a port if it was bound to that port by number. To select
5008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * a random open port and then bind by number, this function creates a temp socket, binds to a
5018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * random port (specifying 0), gets that port number, and then uses is to bind the user's UDP
5028dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * Encapsulation Socket forcibly, so that it cannot be un-bound by the user with the returned
5038dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * FileHandle.
5048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     *
5058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * <p>The loop in this function handles the inherent race window between un-binding to a port
5068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * and re-binding, during which the system could *technically* hand that port out to someone
5078dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     * else.
5088dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold     */
5098dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private void bindToRandomPort(FileDescriptor sockFd) throws IOException {
5108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) {
5118dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            try {
5128dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
5138dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Os.bind(probeSocket, INADDR_ANY, 0);
5148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                int port = ((InetSocketAddress) Os.getsockname(probeSocket)).getPort();
5158dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Os.close(probeSocket);
5168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Log.v(TAG, "Binding to port " + port);
5178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Os.bind(sockFd, INADDR_ANY, port);
5188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                return;
5198dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } catch (ErrnoException e) {
5208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                // Someone miraculously claimed the port just after we closed probeSocket.
5218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                if (e.errno == OsConstants.EADDRINUSE) {
5228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    continue;
5238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                }
5248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throw e.rethrowAsIOException();
5258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
5268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
5278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port");
5288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
52993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
53093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
53193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * Open a socket via the system server and bind it to the specified port (random if port=0).
53293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * This will return a PFD to the user that represent a bound UDP socket. The system server will
53393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * cache the socket and a record of its owner so that it can and must be freed when no longer
53493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * needed.
53593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
53693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
5378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public synchronized IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, IBinder binder)
5388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throws RemoteException {
5398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (port != 0 && (port < FREE_PORT_MIN || port > PORT_MAX)) {
5408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw new IllegalArgumentException(
5418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    "Specified port number must be a valid non-reserved UDP port");
5428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
5438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        int resourceId = mNextResourceId.getAndIncrement();
5448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        FileDescriptor sockFd = null;
5458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try {
5468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
5478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
5488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (port != 0) {
5498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Log.v(TAG, "Binding to port " + port);
5508dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Os.bind(sockFd, INADDR_ANY, port);
5518dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } else {
5528dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                bindToRandomPort(sockFd);
5538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
5548dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            // This code is common to both the unspecified and specified port cases
5558dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            Os.setsockoptInt(
5568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    sockFd,
5578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    OsConstants.IPPROTO_UDP,
5588dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    OsConstants.UDP_ENCAP,
5598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    OsConstants.UDP_ENCAP_ESPINUDP);
5608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
5618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mUdpSocketRecords.put(
5628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    resourceId, new UdpSocketRecord(resourceId, binder, sockFd, port));
5638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, sockFd);
5648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        } catch (IOException | ErrnoException e) {
5658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            IoUtils.closeQuietly(sockFd);
5668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
5678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // If we make it to here, then something has gone wrong and we couldn't open a socket.
5688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // The only reasonable condition that would cause that is resource unavailable.
5698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
57093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
57193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
57293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /** close a socket that has been been allocated by and registered with the system server */
57393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
5748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public void closeUdpEncapsulationSocket(int resourceId) throws RemoteException {
5758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
5768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        releaseManagedResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket");
5778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
57893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
57993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
58093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * Create a transport mode transform, which represent two security associations (one in each
58193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * direction) in the kernel. The transform will be cached by the system server and must be freed
58293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * when no longer needed. It is possible to free one, deleting the SA from underneath sockets
58393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * that are using it, which will result in all of those sockets becoming unable to send or
58493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * receive data.
58593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
58693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
5878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public synchronized IpSecTransformResponse createTransportModeTransform(
5888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            IpSecConfig c, IBinder binder) throws RemoteException {
58993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        int resourceId = mNextResourceId.getAndIncrement();
5908dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        SpiRecord[] spis = new SpiRecord[DIRECTIONS.length];
5918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // TODO: Basic input validation here since it's coming over the Binder
5928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        int encapType, encapLocalPort = 0, encapRemotePort = 0;
5938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        UdpSocketRecord socketRecord = null;
5948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        encapType = c.getEncapType();
5958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (encapType != IpSecTransform.ENCAP_NONE) {
5968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            socketRecord = mUdpSocketRecords.get(c.getEncapLocalResourceId());
5978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            encapLocalPort = socketRecord.getPort();
5988dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            encapRemotePort = c.getEncapRemotePort();
5998dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
6008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
60193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        for (int direction : DIRECTIONS) {
60293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            IpSecAlgorithm auth = c.getAuthentication(direction);
60393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            IpSecAlgorithm crypt = c.getEncryption(direction);
6048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
6058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction));
6068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            int spi = spis[direction].getSpi();
60793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            try {
60893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                int result =
60993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        getNetdInstance()
61093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                .ipSecAddSecurityAssociation(
61193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        resourceId,
61293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        c.getMode(),
61393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        direction,
61493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        (c.getLocalAddress() != null)
61593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                                ? c.getLocalAddress().getHostAddress()
61693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                                : "",
61793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        (c.getRemoteAddress() != null)
61893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                                ? c.getRemoteAddress().getHostAddress()
61993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                                : "",
62093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        (c.getNetwork() != null)
62193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                                ? c.getNetwork().getNetworkHandle()
62293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                                : 0,
6238dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        spi,
62493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        (auth != null) ? auth.getName() : "",
62593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        (auth != null) ? auth.getKey() : null,
62693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        (auth != null) ? auth.getTruncationLengthBits() : 0,
62793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        (crypt != null) ? crypt.getName() : "",
62893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        (crypt != null) ? crypt.getKey() : null,
62993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                        (crypt != null) ? crypt.getTruncationLengthBits() : 0,
6308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        encapType,
6318dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        encapLocalPort,
6328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        encapRemotePort);
6338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                if (result != spi) {
63493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    // TODO: cleanup the first SA if creation of second SA fails
6358dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    return new IpSecTransformResponse(
6368dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                            IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID);
63793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                }
63893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            } catch (ServiceSpecificException e) {
63993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                // FIXME: get the error code and throw is at an IOException from Errno Exception
64093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            }
64193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
6428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // Both SAs were created successfully, time to construct a record and lock it away
6438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        mTransformRecords.put(
6448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                resourceId, new TransformRecord(resourceId, binder, c, spis, socketRecord));
6458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId);
64693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
64793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
64893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
64993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * Delete a transport mode transform that was previously allocated by + registered with the
65093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * system server. If this is called on an inactive (or non-existent) transform, it will not
65193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * return an error. It's safe to de-allocate transforms that may have already been deleted for
65293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * other reasons.
65393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
65493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
65593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    public void deleteTransportModeTransform(int resourceId) throws RemoteException {
6568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        releaseManagedResource(mTransformRecords, resourceId, "IpSecTransform");
65793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
65893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
65993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
66093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * Apply an active transport mode transform to a socket, which will apply the IPsec security
66193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * association as a correspondent policy to the provided socket
66293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
66393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
6648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    public synchronized void applyTransportModeTransform(
6658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            ParcelFileDescriptor socket, int resourceId) throws RemoteException {
6668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // Synchronize liberally here because we are using ManagedResources in this block
6678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        TransformRecord info;
6688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // FIXME: this code should be factored out into a security check + getter
6698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        info = mTransformRecords.get(resourceId);
6708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
6718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (info == null) {
6728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw new IllegalArgumentException("Transform " + resourceId + " is not active");
6738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
67493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
6758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // TODO: make this a function.
6768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (info.pid != getCallingPid() || info.uid != getCallingUid()) {
6778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw new SecurityException("Only the owner of an IpSec Transform may apply it!");
6788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
67993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
6808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        IpSecConfig c = info.getConfig();
6818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try {
6828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            for (int direction : DIRECTIONS) {
6838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                getNetdInstance()
6848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                        .ipSecApplyTransportModeTransform(
6858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                socket.getFileDescriptor(),
6868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                resourceId,
6878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                direction,
6888dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                (c.getLocalAddress() != null)
6898dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        ? c.getLocalAddress().getHostAddress()
6908dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        : "",
6918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                (c.getRemoteAddress() != null)
6928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        ? c.getRemoteAddress().getHostAddress()
6938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                        : "",
6948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                info.getSpiRecord(direction).getSpi());
69593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            }
6968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        } catch (ServiceSpecificException e) {
6978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            // FIXME: get the error code and throw is at an IOException from Errno Exception
69893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
69993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
7008dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
70193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
70293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * Remove a transport mode transform from a socket, applying the default (empty) policy. This
70393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * will ensure that NO IPsec policy is applied to the socket (would be the equivalent of
70493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * applying a policy that performs no IPsec). Today the resourceId parameter is passed but not
70593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * used: reserved for future improved input validation.
70693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
70793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
70893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    public void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId)
70993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            throws RemoteException {
71093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        try {
71193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            getNetdInstance().ipSecRemoveTransportModeTransform(socket.getFileDescriptor());
71293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        } catch (ServiceSpecificException e) {
71393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            // FIXME: get the error code and throw is at an IOException from Errno Exception
71493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
71593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
71693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
71793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    @Override
7181afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
7191afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
7208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // TODO: Add dump code to print out a log of all the resources being tracked
7211afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        pw.println("IpSecService Log:");
7221afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead"));
7231afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        pw.println();
7241afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    }
7251afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold}
726