107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff/*
207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * Copyright (C) 2012 The Android Open Source Project
307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff *
407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * Licensed under the Apache License, Version 2.0 (the "License");
507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * you may not use this file except in compliance with the License.
607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * You may obtain a copy of the License at
707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff *
807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff *      http://www.apache.org/licenses/LICENSE-2.0
907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff *
1007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * Unless required by applicable law or agreed to in writing, software
1107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * distributed under the License is distributed on an "AS IS" BASIS,
1207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * See the License for the specific language governing permissions and
1407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * limitations under the License.
1507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff */
1607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
1707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffpackage android.net.arp;
1807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
1955b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriffimport android.net.LinkAddress;
2055b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriffimport android.net.LinkProperties;
2155b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriffimport android.net.RouteInfo;
2207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffimport android.os.SystemClock;
2307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffimport android.util.Log;
2455b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff
2507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffimport java.io.IOException;
2607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffimport java.net.InetAddress;
2707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffimport java.net.Inet6Address;
2807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffimport java.net.SocketException;
2907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffimport java.nio.ByteBuffer;
3007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffimport java.nio.ByteOrder;
3107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffimport java.util.Arrays;
3207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
3307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffimport libcore.net.RawSocket;
3407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
3507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff/**
3607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * This class allows simple ARP exchanges over an uninitialized network
3707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * interface.
3807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff *
3907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff * @hide
4007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff */
4107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriffpublic class ArpPeer {
4255b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff    private static final boolean DBG = false;
4355b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff    private static final String TAG = "ArpPeer";
4407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    private String mInterfaceName;
4507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    private final InetAddress mMyAddr;
4607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    private final byte[] mMyMac = new byte[6];
4707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    private final InetAddress mPeer;
4807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    private final RawSocket mSocket;
4907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    private final byte[] L2_BROADCAST;  // TODO: refactor from DhcpClient.java
5007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    private static final int MAX_LENGTH = 1500; // refactor from DhcpPacket.java
5107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    private static final int ETHERNET_TYPE = 1;
5207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    private static final int ARP_LENGTH = 28;
5307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    private static final int MAC_ADDR_LENGTH = 6;
5407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    private static final int IPV4_LENGTH = 4;
5507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
5607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    public ArpPeer(String interfaceName, InetAddress myAddr, String mac,
5707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                   InetAddress peer) throws SocketException {
5807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        mInterfaceName = interfaceName;
5907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        mMyAddr = myAddr;
6007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
6121326d8b77cfd1567d87d5ebe3e327b744632e24Chih-Wei Huang        if (mac != null) {
6221326d8b77cfd1567d87d5ebe3e327b744632e24Chih-Wei Huang            for (int i = 0; i < MAC_ADDR_LENGTH; i++) {
6321326d8b77cfd1567d87d5ebe3e327b744632e24Chih-Wei Huang                mMyMac[i] = (byte) Integer.parseInt(mac.substring(
6421326d8b77cfd1567d87d5ebe3e327b744632e24Chih-Wei Huang                            i*3, (i*3) + 2), 16);
6521326d8b77cfd1567d87d5ebe3e327b744632e24Chih-Wei Huang            }
6607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        }
6707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
6807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        if (myAddr instanceof Inet6Address || peer instanceof Inet6Address) {
6907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff            throw new IllegalArgumentException("IPv6 unsupported");
7007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        }
7107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
7207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        mPeer = peer;
7307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        L2_BROADCAST = new byte[MAC_ADDR_LENGTH];
7407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        Arrays.fill(L2_BROADCAST, (byte) 0xFF);
7507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
7607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        mSocket = new RawSocket(mInterfaceName, RawSocket.ETH_P_ARP);
7707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    }
7807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
7907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    /**
8007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff     * Returns the MAC address (or null if timeout) for the requested
8107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff     * peer.
8207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff     */
8307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    public byte[] doArp(int timeoutMillis) {
8407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        ByteBuffer buf = ByteBuffer.allocate(MAX_LENGTH);
8507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        byte[] desiredIp = mPeer.getAddress();
8607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        long timeout = SystemClock.elapsedRealtime() + timeoutMillis;
8707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
8807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        // construct ARP request packet, using a ByteBuffer as a
8907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        // convenient container
9007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.clear();
9107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.order(ByteOrder.BIG_ENDIAN);
9207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
9307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.putShort((short) ETHERNET_TYPE); // Ethernet type, 16 bits
9407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.putShort(RawSocket.ETH_P_IP); // Protocol type IP, 16 bits
9507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.put((byte)MAC_ADDR_LENGTH);  // MAC address length, 6 bytes
9607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.put((byte)IPV4_LENGTH);  // IPv4 protocol size
9707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.putShort((short) 1); // ARP opcode 1: 'request'
9807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.put(mMyMac);        // six bytes: sender MAC
9907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.put(mMyAddr.getAddress());  // four bytes: sender IP address
10007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.put(new byte[MAC_ADDR_LENGTH]); // target MAC address: unknown
10107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.put(desiredIp); // target IP address, 4 bytes
10207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        buf.flip();
10307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        mSocket.write(L2_BROADCAST, buf.array(), 0, buf.limit());
10407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
10507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        byte[] recvBuf = new byte[MAX_LENGTH];
10607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
10707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        while (SystemClock.elapsedRealtime() < timeout) {
10807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff            long duration = (long) timeout - SystemClock.elapsedRealtime();
10907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff            int readLen = mSocket.read(recvBuf, 0, recvBuf.length, -1,
11007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                (int) duration);
11107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
11207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff            // Verify packet details. see RFC 826
11307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff            if ((readLen >= ARP_LENGTH) // trailing bytes at times
11407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                && (recvBuf[0] == 0) && (recvBuf[1] == ETHERNET_TYPE) // type Ethernet
11507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                && (recvBuf[2] == 8) && (recvBuf[3] == 0) // protocol IP
11607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                && (recvBuf[4] == MAC_ADDR_LENGTH) // mac length
11707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                && (recvBuf[5] == IPV4_LENGTH) // IPv4 protocol size
11807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                && (recvBuf[6] == 0) && (recvBuf[7] == 2) // ARP reply
11907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                // verify desired IP address
12007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                && (recvBuf[14] == desiredIp[0]) && (recvBuf[15] == desiredIp[1])
12107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                && (recvBuf[16] == desiredIp[2]) && (recvBuf[17] == desiredIp[3]))
12207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff            {
12307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                // looks good.  copy out the MAC
12407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                byte[] result = new byte[MAC_ADDR_LENGTH];
12507573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                System.arraycopy(recvBuf, 8, result, 0, MAC_ADDR_LENGTH);
12607573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff                return result;
12707573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff            }
12807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        }
12907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
13007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        return null;
13107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    }
13207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff
13355b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff    public static boolean doArp(String myMacAddress, LinkProperties linkProperties,
13455b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            int timeoutMillis, int numArpPings, int minArpResponses) {
13555b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        String interfaceName = linkProperties.getInterfaceName();
13655b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        InetAddress inetAddress = null;
13755b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        InetAddress gateway = null;
13855b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        boolean success;
13955b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff
14055b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        for (LinkAddress la : linkProperties.getLinkAddresses()) {
14155b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            inetAddress = la.getAddress();
14255b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            break;
14355b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        }
14455b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff
14555b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        for (RouteInfo route : linkProperties.getRoutes()) {
14655b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            gateway = route.getGateway();
14755b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            break;
14855b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        }
14955b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff
15055b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        try {
15155b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            ArpPeer peer = new ArpPeer(interfaceName, inetAddress, myMacAddress, gateway);
15255b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            int responses = 0;
15355b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            for (int i=0; i < numArpPings; i++) {
15455b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff                if(peer.doArp(timeoutMillis) != null) responses++;
15555b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            }
15655b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            if (DBG) Log.d(TAG, "ARP test result: " + responses + "/" + numArpPings);
15755b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            success = (responses >= minArpResponses);
15855b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            peer.close();
15955b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        } catch (SocketException se) {
16055b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            //Consider an Arp socket creation issue as a successful Arp
16155b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            //test to avoid any wifi connectivity issues
16255b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            Log.e(TAG, "ARP test initiation failure: " + se);
16355b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff            success = true;
16455b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        }
16555b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff        return success;
16655b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff    }
16755b9821dffe5991e554841bf871155a2c4024c56Irfan Sheriff
16807573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    public void close() {
16907573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        try {
17007573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff            mSocket.close();
17107573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        } catch (IOException ex) {
17207573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff        }
17307573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff    }
17407573b32494acbabd21979d8b9584c1ed3f7a6adIrfan Sheriff}
175