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