/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.connectivity.tethering;

import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkState;
import android.net.RouteInfo;
import android.net.ip.IpServer;
import android.net.util.NetworkConstants;
import android.net.util.SharedLog;
import android.util.Log;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Random;


/**
 * IPv6 tethering is rather different from IPv4 owing to the absence of NAT.
 * This coordinator is responsible for evaluating the dedicated prefixes
 * assigned to the device and deciding how to divvy them up among downstream
 * interfaces.
 *
 * @hide
 */
public class IPv6TetheringCoordinator {
    private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName();
    private static final boolean DBG = false;
    private static final boolean VDBG = false;

    private static class Downstream {
        public final IpServer ipServer;
        public final int mode;  // IpServer.STATE_*
        // Used to append to a ULA /48, constructing a ULA /64 for local use.
        public final short subnetId;

        Downstream(IpServer ipServer, int mode, short subnetId) {
            this.ipServer = ipServer;
            this.mode = mode;
            this.subnetId = subnetId;
        }
    }

    private final ArrayList<IpServer> mNotifyList;
    private final SharedLog mLog;
    // NOTE: mActiveDownstreams is a list and not a hash data structure because
    // we keep active downstreams in arrival order.  This is done so /64s can
    // be parceled out on a "first come, first served" basis and a /64 used by
    // a downstream that is no longer active can be redistributed to any next
    // waiting active downstream (again, in arrival order).
    private final LinkedList<Downstream> mActiveDownstreams;
    private final byte[] mUniqueLocalPrefix;
    private short mNextSubnetId;
    private NetworkState mUpstreamNetworkState;

    public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) {
        mNotifyList = notifyList;
        mLog = log.forSubComponent(TAG);
        mActiveDownstreams = new LinkedList<>();
        mUniqueLocalPrefix = generateUniqueLocalPrefix();
        mNextSubnetId = 0;
    }

    /** Add active downstream to ipv6 tethering candidate list. */
    public void addActiveDownstream(IpServer downstream, int mode) {
        if (findDownstream(downstream) == null) {
            // Adding a new downstream appends it to the list. Adding a
            // downstream a second time without first removing it has no effect.
            // We never change the mode of a downstream except by first removing
            // it and then re-adding it (with its new mode specified);
            if (mActiveDownstreams.offer(new Downstream(downstream, mode, mNextSubnetId))) {
                // Make sure subnet IDs are always positive. They are appended
                // to a ULA /48 to make a ULA /64 for local use.
                mNextSubnetId = (short) Math.max(0, mNextSubnetId + 1);
            }
            updateIPv6TetheringInterfaces();
        }
    }

    /** Remove downstream from ipv6 tethering candidate list. */
    public void removeActiveDownstream(IpServer downstream) {
        stopIPv6TetheringOn(downstream);
        if (mActiveDownstreams.remove(findDownstream(downstream))) {
            updateIPv6TetheringInterfaces();
        }

        // When tethering is stopping we can reset the subnet counter.
        if (mNotifyList.isEmpty()) {
            if (!mActiveDownstreams.isEmpty()) {
                Log.wtf(TAG, "Tethering notify list empty, IPv6 downstreams non-empty.");
            }
            mNextSubnetId = 0;
        }
    }

    /**
     * Call when upstream NetworkState may be changed.
     * If upstream has ipv6 for tethering, update this new NetworkState
     * to IpServer. Otherwise stop ipv6 tethering on downstream interfaces.
     */
    public void updateUpstreamNetworkState(NetworkState ns) {
        if (VDBG) {
            Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
        }
        if (TetheringInterfaceUtils.getIPv6Interface(ns) == null) {
            stopIPv6TetheringOnAllInterfaces();
            setUpstreamNetworkState(null);
            return;
        }

        if (mUpstreamNetworkState != null
                && !ns.network.equals(mUpstreamNetworkState.network)) {
            stopIPv6TetheringOnAllInterfaces();
        }

        setUpstreamNetworkState(ns);
        updateIPv6TetheringInterfaces();
    }

    private void stopIPv6TetheringOnAllInterfaces() {
        for (IpServer ipServer : mNotifyList) {
            stopIPv6TetheringOn(ipServer);
        }
    }

    private void setUpstreamNetworkState(NetworkState ns) {
        if (ns == null) {
            mUpstreamNetworkState = null;
        } else {
            // Make a deep copy of the parts we need.
            mUpstreamNetworkState = new NetworkState(
                    null,
                    new LinkProperties(ns.linkProperties),
                    new NetworkCapabilities(ns.networkCapabilities),
                    new Network(ns.network),
                    null,
                    null);
        }

        mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
    }

    private void updateIPv6TetheringInterfaces() {
        for (IpServer ipServer : mNotifyList) {
            final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer);
            ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
            break;
        }
    }

    private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) {
        final Downstream ds = findDownstream(ipServer);
        if (ds == null) return null;

        if (ds.mode == IpServer.STATE_LOCAL_ONLY) {
            // Build a Unique Locally-assigned Prefix configuration.
            return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
        }

        // This downstream is in IpServer.STATE_TETHERED mode.
        if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
            return null;
        }

        // NOTE: Here, in future, we would have policies to decide how to divvy
        // up the available dedicated prefixes among downstream interfaces.
        // At this time we have no such mechanism--we only support tethering
        // IPv6 toward the oldest (first requested) active downstream.

        final Downstream currentActive = mActiveDownstreams.peek();
        if (currentActive != null && currentActive.ipServer == ipServer) {
            final LinkProperties lp = getIPv6OnlyLinkProperties(
                    mUpstreamNetworkState.linkProperties);
            if (lp.hasIpv6DefaultRoute() && lp.hasGlobalIpv6Address()) {
                return lp;
            }
        }

        return null;
    }

    Downstream findDownstream(IpServer ipServer) {
        for (Downstream ds : mActiveDownstreams) {
            if (ds.ipServer == ipServer) return ds;
        }
        return null;
    }

    private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) {
        final LinkProperties v6only = new LinkProperties();
        if (lp == null) {
            return v6only;
        }

        // NOTE: At this time we don't copy over any information about any
        // stacked links. No current stacked link configuration has IPv6.

        v6only.setInterfaceName(lp.getInterfaceName());

        v6only.setMtu(lp.getMtu());

        for (LinkAddress linkAddr : lp.getLinkAddresses()) {
            if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) {
                v6only.addLinkAddress(linkAddr);
            }
        }

        for (RouteInfo routeInfo : lp.getRoutes()) {
            final IpPrefix destination = routeInfo.getDestination();
            if ((destination.getAddress() instanceof Inet6Address)
                    && (destination.getPrefixLength() <= 64)) {
                v6only.addRoute(routeInfo);
            }
        }

        for (InetAddress dnsServer : lp.getDnsServers()) {
            if (isIPv6GlobalAddress(dnsServer)) {
                // For now we include ULAs.
                v6only.addDnsServer(dnsServer);
            }
        }

        v6only.setDomains(lp.getDomains());

        return v6only;
    }

    // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we
    // announce our own IPv6 address as DNS server.
    private static boolean isIPv6GlobalAddress(InetAddress ip) {
        return (ip instanceof Inet6Address)
               && !ip.isAnyLocalAddress()
               && !ip.isLoopbackAddress()
               && !ip.isLinkLocalAddress()
               && !ip.isSiteLocalAddress()
               && !ip.isMulticastAddress();
    }

    private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) {
        final LinkProperties lp = new LinkProperties();

        final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48);
        lp.addRoute(new RouteInfo(local48, null, null));

        final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64);
        // Because this is a locally-generated ULA, we don't have an upstream
        // address. But because the downstream IP address management code gets
        // its prefix from the upstream's IP address, we create a fake one here.
        lp.addLinkAddress(new LinkAddress(local64.getAddress(), 64));

        lp.setMtu(NetworkConstants.ETHER_MTU);
        return lp;
    }

    private static IpPrefix makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen) {
        final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length);
        bytes[7] = (byte) (subnetId >> 8);
        bytes[8] = (byte) subnetId;
        return new IpPrefix(bytes, prefixlen);
    }

    // Generates a Unique Locally-assigned Prefix:
    //
    //     https://tools.ietf.org/html/rfc4193#section-3.1
    //
    // The result is a /48 that can be used for local-only communications.
    private static byte[] generateUniqueLocalPrefix() {
        final byte[] ulp = new byte[6];  // 6 = 48bits / 8bits/byte
        (new Random()).nextBytes(ulp);

        final byte[] in6addr = Arrays.copyOf(ulp, NetworkConstants.IPV6_ADDR_LEN);
        in6addr[0] = (byte) 0xfd;  // fc00::/7 and L=1

        return in6addr;
    }

    private static String toDebugString(NetworkState ns) {
        if (ns == null) {
            return "NetworkState{null}";
        }
        return String.format("NetworkState{%s, %s, %s}",
                ns.network,
                ns.networkCapabilities,
                ns.linkProperties);
    }

    private static void stopIPv6TetheringOn(IpServer ipServer) {
        ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
    }
}
