1578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen/* 2578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * Copyright (C) 2016 The Android Open Source Project 3578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * 4578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * Licensed under the Apache License, Version 2.0 (the "License"); 5578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * you may not use this file except in compliance with the License. 6578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * You may obtain a copy of the License at 7578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * 8578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * http://www.apache.org/licenses/LICENSE-2.0 9578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * 10578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * Unless required by applicable law or agreed to in writing, software 11578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * distributed under the License is distributed on an "AS IS" BASIS, 12578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * See the License for the specific language governing permissions and 14578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * limitations under the License. 15578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen */ 16578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 17f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensenpackage android.net.apf; 18578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 19578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport static android.system.OsConstants.*; 20578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 21647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichiimport android.os.SystemClock; 227d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichiimport android.net.LinkAddress; 23a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensenimport android.net.LinkProperties; 24578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.net.NetworkUtils; 25578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.net.apf.ApfGenerator; 26578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.net.apf.ApfGenerator.IllegalInstructionException; 27578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.net.apf.ApfGenerator.Register; 28f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensenimport android.net.ip.IpManager; 294fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichiimport android.net.metrics.ApfProgramEvent; 30647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichiimport android.net.metrics.ApfStats; 314fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichiimport android.net.metrics.IpConnectivityLog; 32cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichiimport android.net.metrics.RaEvent; 33578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.system.ErrnoException; 34578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.system.Os; 35578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.system.PacketSocketAddress; 364fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichiimport android.text.format.DateUtils; 37578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.util.Log; 38578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.util.Pair; 39578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 40dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensenimport com.android.internal.annotations.GuardedBy; 419132f34976f16a626c2ec1d3d90624d71e054346Paul Jensenimport com.android.internal.annotations.VisibleForTesting; 42578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport com.android.internal.util.HexDump; 435ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colittiimport com.android.internal.util.IndentingPrintWriter; 44578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 45578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.io.FileDescriptor; 46578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.io.IOException; 47578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.lang.Thread; 487d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichiimport java.net.Inet4Address; 495ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colittiimport java.net.Inet6Address; 505ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colittiimport java.net.InetAddress; 51578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.net.NetworkInterface; 52578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.net.SocketException; 535ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colittiimport java.net.UnknownHostException; 54578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.nio.ByteBuffer; 555ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colittiimport java.nio.BufferUnderflowException; 56578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.util.ArrayList; 57578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.util.Arrays; 58578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 59578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport libcore.io.IoBridge; 60578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 61578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen/** 62578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * For networks that support packet filtering via APF programs, {@code ApfFilter} 63578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to 64578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * filter out redundant duplicate ones. 65578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * 66dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * Threading model: 67dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to 68dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * know what RAs to filter for, thus generating APF programs is dependent on mRas. 69dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * mRas can be accessed by multiple threads: 70dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs. 71dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * - callers of: 72dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * - setMulticastFilter(), which can cause an APF program to be generated. 73dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * - dump(), which dumps mRas among other things. 74dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * - shutdown(), which clears mRas. 75dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * So access to mRas is synchronized. 76dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * 77578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * @hide 78578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen */ 79578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenpublic class ApfFilter { 80647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi 81647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi // Enums describing the outcome of receiving an RA packet. 82647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi private static enum ProcessRaResult { 83647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi MATCH, // Received RA matched a known RA 84647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi DROPPED, // Received RA ignored due to MAX_RAS 85647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi PARSE_ERROR, // Received RA could not be parsed 86647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi ZERO_LIFETIME, // Received RA had 0 lifetime 87647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi UPDATE_NEW_RA, // APF program updated for new RA 88647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi UPDATE_EXPIRY // APF program updated for expiry 89647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi } 90647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi 91578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Thread to listen for RAs. 929132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen @VisibleForTesting 939132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen class ReceiveThread extends Thread { 94578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private final byte[] mPacket = new byte[1514]; 95578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private final FileDescriptor mSocket; 96647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi private final long mStart = SystemClock.elapsedRealtime(); 9722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi private final ApfStats mStats = new ApfStats(); 98647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi 9922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi private volatile boolean mStopped; 100647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi 101578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen public ReceiveThread(FileDescriptor socket) { 102578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen mSocket = socket; 103578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 104578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 105578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen public void halt() { 106578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen mStopped = true; 107578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen try { 108578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Interrupts the read() call the thread is blocked in. 109578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen IoBridge.closeAndSignalBlockedThreads(mSocket); 110578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } catch (IOException ignored) {} 111578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 112578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 113578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen @Override 114578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen public void run() { 115578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen log("begin monitoring"); 116578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen while (!mStopped) { 117578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen try { 118578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen int length = Os.read(mSocket, mPacket, 0, mPacket.length); 119647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi updateStats(processRa(mPacket, length)); 120578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } catch (IOException|ErrnoException e) { 121578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen if (!mStopped) { 122578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen Log.e(TAG, "Read error", e); 123578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 124578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 125578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 126647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi logStats(); 127647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi } 128647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi 129647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi private void updateStats(ProcessRaResult result) { 13022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.receivedRas++; 131647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi switch(result) { 132647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi case MATCH: 13322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.matchingRas++; 134647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return; 135647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi case DROPPED: 13622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.droppedRas++; 137647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return; 138647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi case PARSE_ERROR: 13922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.parseErrors++; 140647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return; 141647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi case ZERO_LIFETIME: 14222d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.zeroLifetimeRas++; 143647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return; 144647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi case UPDATE_EXPIRY: 14522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.matchingRas++; 14622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.programUpdates++; 147647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return; 148647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi case UPDATE_NEW_RA: 14922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.programUpdates++; 150647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return; 151647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi } 152647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi } 153647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi 154647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi private void logStats() { 15522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi final long nowMs = SystemClock.elapsedRealtime(); 15622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi synchronized (this) { 15722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.durationMs = nowMs - mStart; 15822d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.maxProgramSize = mApfCapabilities.maximumApfProgramSize; 15922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.programUpdatesAll = mNumProgramUpdates; 16022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mStats.programUpdatesAllowingMulticast = mNumProgramUpdatesAllowingMulticast; 16122d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mMetricsLog.log(mStats); 16222d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS); 16322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi } 164578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 165578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 166578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 167578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final String TAG = "ApfFilter"; 16839c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti private static final boolean DBG = true; 1697a8797f6c8406bbc335f67b85ef0cf00dc3a2b24Joe Onorato private static final boolean VDBG = false; 170578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 171dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int ETH_HEADER_LEN = 14; 17291723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen private static final int ETH_DEST_ADDR_OFFSET = 0; 173dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int ETH_ETHERTYPE_OFFSET = 12; 174961ca49fd67b39d8076ea49d12d2fda73f581399Hugo Benichi private static final byte[] ETH_BROADCAST_MAC_ADDRESS = 175961ca49fd67b39d8076ea49d12d2fda73f581399Hugo Benichi {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; 176dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN. 177dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6; 178dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // Endianness is not an issue for this constant because the APF interpreter always operates in 179dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // network byte order. 180dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff; 181dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9; 182dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16; 18338db976514ff2ad12d207a927219762eab179882Hugo Benichi private static final int IPV4_ANY_HOST_ADDRESS = 0; 1840dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255 185dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 186dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6; 187dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8; 188dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24; 189dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int IPV6_HEADER_LEN = 40; 190dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // The IPv6 all nodes address ff02::1 191dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final byte[] IPV6_ALL_NODES_ADDRESS = 192961ca49fd67b39d8076ea49d12d2fda73f581399Hugo Benichi { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; 193dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 194dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN; 19502428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi private static final int ICMP6_ROUTER_SOLICITATION = 133; 1964b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen private static final int ICMP6_ROUTER_ADVERTISEMENT = 134; 19702428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi private static final int ICMP6_NEIGHBOR_SOLICITATION = 135; 19802428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136; 199dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 200dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT 201dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2; 202dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int UDP_HEADER_LEN = 8; 203dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 204dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int DHCP_CLIENT_PORT = 68; 205dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT 206dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28; 207dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 2084fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN; 20938db976514ff2ad12d207a927219762eab179882Hugo Benichi private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6; 21038db976514ff2ad12d207a927219762eab179882Hugo Benichi private static final short ARP_OPCODE_REQUEST = 1; 21138db976514ff2ad12d207a927219762eab179882Hugo Benichi private static final short ARP_OPCODE_REPLY = 2; 212961ca49fd67b39d8076ea49d12d2fda73f581399Hugo Benichi private static final byte[] ARP_IPV4_HEADER = { 213a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen 0, 1, // Hardware type: Ethernet (1) 214a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen 8, 0, // Protocol type: IP (0x0800) 215a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen 6, // Hardware size: 6 216a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen 4, // Protocol size: 4 217a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen }; 2184fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24; 21922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi // Do not log ApfProgramEvents whose actual lifetimes was less than this. 22022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2; 221a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen 222f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen private final ApfCapabilities mApfCapabilities; 223f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen private final IpManager.Callback mIpManagerCallback; 224f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen private final NetworkInterface mNetworkInterface; 2256ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi private final IpConnectivityLog mMetricsLog; 2269132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen @VisibleForTesting 2279132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen byte[] mHardwareAddress; 2289132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen @VisibleForTesting 2299132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen ReceiveThread mReceiveThread; 230dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 231578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private long mUniqueCounter; 232dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 233dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private boolean mMulticastFilter; 234a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen // Our IPv4 address, if we have just one, otherwise null. 235a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen @GuardedBy("this") 236a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen private byte[] mIPv4Address; 2377d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null. 2387d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi @GuardedBy("this") 2397d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi private int mIPv4PrefixLength; 240578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 2419132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen @VisibleForTesting 2429132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface, 2436ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi IpManager.Callback ipManagerCallback, boolean multicastFilter, IpConnectivityLog log) { 244f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen mApfCapabilities = apfCapabilities; 245f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen mIpManagerCallback = ipManagerCallback; 246f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen mNetworkInterface = networkInterface; 2472e074db972355a77f91378b5b1daceb500dde019Paul Jensen mMulticastFilter = multicastFilter; 2486ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi mMetricsLog = log; 249f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen 25022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi // TODO: ApfFilter should not generate programs until IpManager sends provisioning success. 251578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen maybeStartFilter(); 252578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 253578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 254578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private void log(String s) { 255f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen Log.d(TAG, "(" + mNetworkInterface.getName() + "): " + s); 256578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 257578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 258dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 259dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private long getUniqueNumberLocked() { 260578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen return mUniqueCounter++; 261578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 262578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 263578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen /** 264578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * Attempt to start listening for RAs and, if RAs are received, generating and installing 265578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * filters to ignore useless RAs. 266578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen */ 2679132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen @VisibleForTesting 2689132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen void maybeStartFilter() { 269578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen FileDescriptor socket; 270578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen try { 271f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen mHardwareAddress = mNetworkInterface.getHardwareAddress(); 272dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen synchronized(this) { 273dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // Install basic filters 274dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen installNewProgramLocked(); 275dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen } 276578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6); 277578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, 278f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen mNetworkInterface.getIndex()); 279578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen Os.bind(socket, addr); 280f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat); 281578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } catch(SocketException|ErrnoException e) { 282dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen Log.e(TAG, "Error starting filter", e); 283578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen return; 284578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 285578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen mReceiveThread = new ReceiveThread(socket); 286578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen mReceiveThread.start(); 287578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 288578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 289dafc44ea11972b3152e67dc305a98d658f1465baHugo Benichi // Returns seconds since device boot. 2904456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi @VisibleForTesting 2914456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi protected long currentTimeSeconds() { 292dafc44ea11972b3152e67dc305a98d658f1465baHugo Benichi return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS; 293578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 294578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 2950668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi public static class InvalidRaException extends Exception { 2960668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi public InvalidRaException(String m) { 2970668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi super(m); 2980668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi } 2990668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi } 3000668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi 301578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // A class to hold information about an RA. 3020668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi @VisibleForTesting 3030668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi class Ra { 304578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // From RFC4861: 305578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_RA_HEADER_LEN = 16; 306e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti private static final int ICMP6_RA_CHECKSUM_OFFSET = 307e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti ETH_HEADER_LEN + IPV6_HEADER_LEN + 2; 308e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti private static final int ICMP6_RA_CHECKSUM_LEN = 2; 309578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_RA_OPTION_OFFSET = 310578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN; 311578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET = 312578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen ETH_HEADER_LEN + IPV6_HEADER_LEN + 6; 313578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2; 314578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Prefix information option. 315578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_PREFIX_OPTION_TYPE = 3; 316578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_PREFIX_OPTION_LEN = 32; 317578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4; 318578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4; 319578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8; 320578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4; 321578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 322578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // From RFC6106: Recursive DNS Server option 323578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_RDNSS_OPTION_TYPE = 25; 324578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // From RFC6106: DNS Search List option 325578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_DNSSL_OPTION_TYPE = 31; 326578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 327578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // From RFC4191: Route Information option 328578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24; 329578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Above three options all have the same format: 330578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4; 331578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4; 332578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 3331c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen // Note: mPacket's position() cannot be assumed to be reset. 334578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private final ByteBuffer mPacket; 335578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // List of binary ranges that include the whole packet except the lifetimes. 336578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Pairs consist of offset and length. 337578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private final ArrayList<Pair<Integer, Integer>> mNonLifetimes = 338578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen new ArrayList<Pair<Integer, Integer>>(); 339578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Minimum lifetime in packet 340578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen long mMinLifetime; 341578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // When the packet was last captured, in seconds since Unix Epoch 342578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen long mLastSeen; 343578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 3445ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti // For debugging only. Offsets into the packet where PIOs are. 345059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>(); 346059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti 347059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti // For debugging only. Offsets into the packet where RDNSS options are. 348059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>(); 349059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti 3505ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti // For debugging only. How many times this RA was seen. 3515ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti int seenCount = 0; 3525ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti 35339c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti // For debugging only. Returns the hex representation of the last matching packet. 35439c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti String getLastMatchingPacket() { 355059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(), 356059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti false /* lowercase */); 35739c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti } 3585ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti 359059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti // For debugging only. Returns the string representation of the IPv6 address starting at 360059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti // position pos in the packet. 3615ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti private String IPv6AddresstoString(int pos) { 3625ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti try { 3635ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti byte[] array = mPacket.array(); 3645ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti // Can't just call copyOfRange() and see if it throws, because if it reads past the 3655ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti // end it pads with zeros instead of throwing. 3665ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) { 3675ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti return "???"; 3685ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti } 3695ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16); 3705ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes); 3715ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti return address.getHostAddress(); 3725ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti } catch (UnsupportedOperationException e) { 3735ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti // array() failed. Cannot happen, mPacket is array-backed and read-write. 3745ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti return "???"; 3750668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi } catch (ClassCastException|UnknownHostException e) { 3765ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti // Cannot happen. 3775ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti return "???"; 3785ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti } 3795ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti } 3805ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti 3815ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti // Can't be static because it's in a non-static inner class. 382cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi // TODO: Make this static once RA is its own class. 383059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti private void prefixOptionToString(StringBuffer sb, int offset) { 384059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti String prefix = IPv6AddresstoString(offset + 16); 3854104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi int length = getUint8(mPacket, offset + 2); 3864104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi long valid = getUint32(mPacket, offset + 4); 3874104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi long preferred = getUint32(mPacket, offset + 8); 388059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred)); 389059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti } 390059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti 391059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti private void rdnssOptionToString(StringBuffer sb, int offset) { 3924104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi int optLen = getUint8(mPacket, offset + 1) * 8; 393059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti if (optLen < 24) return; // Malformed or empty. 3944104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi long lifetime = getUint32(mPacket, offset + 4); 395059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti int numServers = (optLen - 8) / 16; 396059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti sb.append("DNS ").append(lifetime).append("s"); 397059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti for (int server = 0; server < numServers; server++) { 398059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server)); 399059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti } 400059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti } 401059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti 4025ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti public String toString() { 4035ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti try { 4045ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti StringBuffer sb = new StringBuffer(); 405059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti sb.append(String.format("RA %s -> %s %ds ", 4065ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET), 407dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET), 4084104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET))); 4095ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti for (int i: mPrefixOptionOffsets) { 410059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti prefixOptionToString(sb, i); 411059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti } 412059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti for (int i: mRdnssOptionOffsets) { 413059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti rdnssOptionToString(sb, i); 4145ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti } 4155ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti return sb.toString(); 4160668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi } catch (BufferUnderflowException|IndexOutOfBoundsException e) { 4175ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti return "<Malformed RA>"; 4185ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti } 4195ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti } 4205ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti 421578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen /** 422578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * Add a binary range of the packet that does not include a lifetime to mNonLifetimes. 423578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * Assumes mPacket.position() is as far as we've parsed the packet. 424578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * @param lastNonLifetimeStart offset within packet of where the last binary range of 425578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * data not including a lifetime. 426578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * @param lifetimeOffset offset from mPacket.position() to the next lifetime data. 427578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * @param lifetimeLength length of the next lifetime data. 428578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * @return offset within packet of where the next binary range of data not including 4296ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi * a lifetime. This can be passed into the next invocation of this function 430578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * via {@code lastNonLifetimeStart}. 431578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen */ 432578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset, 433578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen int lifetimeLength) { 434578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen lifetimeOffset += mPacket.position(); 435578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart, 436578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen lifetimeOffset - lastNonLifetimeStart)); 437578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen return lifetimeOffset + lifetimeLength; 438578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 439578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 440cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi private int addNonLifetimeU32(int lastNonLifetimeStart) { 441cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi return addNonLifetime(lastNonLifetimeStart, 442cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi ICMP6_4_BYTE_LIFETIME_OFFSET, ICMP6_4_BYTE_LIFETIME_LEN); 443cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi } 444cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi 445578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Note that this parses RA and may throw IllegalArgumentException (from 4468995d85b9432387520c9f04a69251536754b996bLorenzo Colitti // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException 4478995d85b9432387520c9f04a69251536754b996bLorenzo Colitti // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with 4488995d85b9432387520c9f04a69251536754b996bLorenzo Colitti // specifications. 4490668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi Ra(byte[] packet, int length) throws InvalidRaException { 4500668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi if (length < ICMP6_RA_OPTION_OFFSET) { 4510668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi throw new InvalidRaException("Not an ICMP6 router advertisement"); 4520668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi } 4530668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi 4546ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length)); 4554456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi mLastSeen = currentTimeSeconds(); 4564b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen 4574b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen // Sanity check packet in case a packet arrives before we attach RA filter 4584b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen // to our packet socket. b/29586253 4594b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 || 4604104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 || 4614104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMP6_ROUTER_ADVERTISEMENT) { 4620668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi throw new InvalidRaException("Not an ICMP6 router advertisement"); 4634b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen } 4644b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen 4654b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen 4666ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi RaEvent.Builder builder = new RaEvent.Builder(); 467578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 468e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti // Ignore the checksum. 469e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti int lastNonLifetimeStart = addNonLifetime(0, 470e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti ICMP6_RA_CHECKSUM_OFFSET, 471e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti ICMP6_RA_CHECKSUM_LEN); 472e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti 473578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Parse router lifetime 474e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, 475e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti ICMP6_RA_ROUTER_LIFETIME_OFFSET, 476578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen ICMP6_RA_ROUTER_LIFETIME_LEN); 4776ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)); 478cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi 479059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti // Ensures that the RA is not truncated. 480578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen mPacket.position(ICMP6_RA_OPTION_OFFSET); 481578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen while (mPacket.hasRemaining()) { 482cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi final int position = mPacket.position(); 4834104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi final int optionType = getUint8(mPacket, position); 4844104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi final int optionLength = getUint8(mPacket, position + 1) * 8; 4856ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi long lifetime; 486578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen switch (optionType) { 487578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen case ICMP6_PREFIX_OPTION_TYPE: 488578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Parse valid lifetime 489578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, 490578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 491578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN); 4926ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi lifetime = getUint32(mPacket, 4936ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET); 4946ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi builder.updatePrefixValidLifetime(lifetime); 495578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Parse preferred lifetime 496578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, 497578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, 498578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN); 4996ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi lifetime = getUint32(mPacket, 5006ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET); 5016ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi builder.updatePrefixPreferredLifetime(lifetime); 502cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi mPrefixOptionOffsets.add(position); 503578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen break; 504cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi // These three options have the same lifetime offset and size, and 5056ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi // are processed with the same specialized addNonLifetimeU32: 506578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen case ICMP6_RDNSS_OPTION_TYPE: 507cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi mRdnssOptionOffsets.add(position); 508cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); 5096ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); 5106ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi builder.updateRdnssLifetime(lifetime); 511cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi break; 512059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti case ICMP6_ROUTE_INFO_OPTION_TYPE: 513cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); 5146ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); 5156ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi builder.updateRouteInfoLifetime(lifetime); 516cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi break; 517578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen case ICMP6_DNSSL_OPTION_TYPE: 518cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); 5196ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); 5206ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi builder.updateDnsslLifetime(lifetime); 521578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen break; 522578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen default: 523578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // RFC4861 section 4.2 dictates we ignore unknown options for fowards 524578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // compatibility. 525578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen break; 526578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 5278995d85b9432387520c9f04a69251536754b996bLorenzo Colitti if (optionLength <= 0) { 5280668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi throw new InvalidRaException(String.format( 5298995d85b9432387520c9f04a69251536754b996bLorenzo Colitti "Invalid option length opt=%d len=%d", optionType, optionLength)); 5308995d85b9432387520c9f04a69251536754b996bLorenzo Colitti } 531cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi mPacket.position(position + optionLength); 532578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 533578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Mark non-lifetime bytes since last lifetime. 534578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen addNonLifetime(lastNonLifetimeStart, 0, 0); 535578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen mMinLifetime = minLifetime(packet, length); 5366ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi mMetricsLog.log(builder.build()); 537578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 538578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 539578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Ignoring lifetimes (which may change) does {@code packet} match this RA? 540578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen boolean matches(byte[] packet, int length) { 5411c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen if (length != mPacket.capacity()) return false; 5421c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen byte[] referencePacket = mPacket.array(); 543578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) { 5441c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) { 5451c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen if (packet[i] != referencePacket[i]) return false; 5461c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen } 547578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 548578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen return true; 549578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 550578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 551578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // What is the minimum of all lifetimes within {@code packet} in seconds? 552578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Precondition: matches(packet, length) already returned true. 553578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen long minLifetime(byte[] packet, int length) { 554578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen long minLifetime = Long.MAX_VALUE; 555578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Wrap packet in ByteBuffer so we can read big-endian values easily 556578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen ByteBuffer byteBuffer = ByteBuffer.wrap(packet); 557578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) { 558578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second; 559e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti 560e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti // The checksum is in mNonLifetimes, but it's not a lifetime. 561e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti if (offset == ICMP6_RA_CHECKSUM_OFFSET) { 562e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti continue; 563e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti } 564e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti 565cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi final int lifetimeLength = mNonLifetimes.get(i+1).first - offset; 566cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi final long optionLifetime; 567578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen switch (lifetimeLength) { 568cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi case 2: 5694104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi optionLifetime = getUint16(byteBuffer, offset); 570cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi break; 571cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi case 4: 5724104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi optionLifetime = getUint32(byteBuffer, offset); 573cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi break; 574cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi default: 575cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi throw new IllegalStateException("bogus lifetime size " + lifetimeLength); 576578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 577cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi minLifetime = Math.min(minLifetime, optionLifetime); 578578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 579578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen return minLifetime; 580578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 581578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 582578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // How many seconds does this RA's have to live, taking into account the fact 583578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // that we might have seen it a while ago. 584578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen long currentLifetime() { 5854456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi return mMinLifetime - (currentTimeSeconds() - mLastSeen); 586578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 587578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 588578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen boolean isExpired() { 589dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll 590dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // have to calculte the filter lifetime specially as a fraction of 0 is still 0. 591dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen return currentLifetime() <= 0; 592578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 593578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 594578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped. 595578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Jump to the next filter if packet doesn't match this RA. 596dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("ApfFilter.this") 597dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException { 598dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen String nextFilterLabel = "Ra" + getUniqueNumberLocked(); 599578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Skip if packet is not the right size 600578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT); 6011c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel); 602578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER); 603578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Skip filter if expired 604578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT); 605578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel); 606578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen for (int i = 0; i < mNonLifetimes.size(); i++) { 607578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Generate code to match the packet bytes 608578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i); 6097c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen // Don't generate JNEBS instruction for 0 bytes as it always fails the 6107c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check where cmp_imm is 6117c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen // the number of bytes to compare. nonLifetime is zero between the 6127c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen // valid and preferred lifetimes in the prefix option. 6137c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen if (nonLifetime.second != 0) { 6147c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen gen.addLoadImmediate(Register.R0, nonLifetime.first); 6157c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen gen.addJumpIfBytesNotEqual(Register.R0, 6167c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen Arrays.copyOfRange(mPacket.array(), nonLifetime.first, 6177c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen nonLifetime.first + nonLifetime.second), 6187c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen nextFilterLabel); 6197c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen } 620578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Generate code to test the lifetimes haven't gone down too far 621578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen if ((i + 1) < mNonLifetimes.size()) { 622578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1); 623578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen int offset = nonLifetime.first + nonLifetime.second; 624e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti // Skip the checksum. 625e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti if (offset == ICMP6_RA_CHECKSUM_OFFSET) { 626e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti continue; 627e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti } 628578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen int length = nextNonLifetime.first - offset; 629578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen switch (length) { 630578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen case 4: gen.addLoad32(Register.R0, offset); break; 631578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen case 2: gen.addLoad16(Register.R0, offset); break; 632578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen default: throw new IllegalStateException("bogus lifetime size " + length); 633578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 634578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel); 635578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 636578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 637578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen gen.addJump(gen.DROP_LABEL); 638578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen gen.defineLabel(nextFilterLabel); 639578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen return filterLifetime; 640578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 641578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 642578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 643578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Maximum number of RAs to filter for. 644578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int MAX_RAS = 10; 645dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 646dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 647578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private ArrayList<Ra> mRas = new ArrayList<Ra>(); 648578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 649578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // There is always some marginal benefit to updating the installed APF program when an RA is 650578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // seen because we can extend the program's lifetime slightly, but there is some cost to 651578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // updating the program, so don't bother unless the program is going to expire soon. This 652578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // constant defines "soon" in seconds. 653578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30; 654578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever 655578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // see a refresh. Using half the lifetime might be a good idea except for the fact that 656578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // packets may be dropped, so let's use 6. 657578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6; 658578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 659578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // When did we last install a filter program? In seconds since Unix Epoch. 660dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 661578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private long mLastTimeInstalledProgram; 662578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // How long should the last installed filter program live for? In seconds. 663dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 664578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private long mLastInstalledProgramMinLifetime; 66522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi @GuardedBy("this") 66622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi private ApfProgramEvent mLastInstallEvent; 667578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 668dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // For debugging only. The last program installed. 669dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 67039c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti private byte[] mLastInstalledProgram; 6715ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti 67222d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi // How many times the program was updated since we started. 67322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi @GuardedBy("this") 67422d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi private int mNumProgramUpdates = 0; 67522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi // How many times the program was updated since we started for allowing multicast traffic. 676059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti @GuardedBy("this") 67722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi private int mNumProgramUpdatesAllowingMulticast = 0; 678059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti 679dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen /** 680a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen * Generate filter code to process ARP packets. Execution of this code ends in either the 681a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen * DROP_LABEL or PASS_LABEL and does not fall off the end. 682a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen * Preconditions: 683a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen * - Packet being filtered is ARP 684a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen */ 685a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen @GuardedBy("this") 686a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException { 687a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen // Here's a basic summary of what the ARP filter program does: 688a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen // 68938db976514ff2ad12d207a927219762eab179882Hugo Benichi // if not ARP IPv4 69038db976514ff2ad12d207a927219762eab179882Hugo Benichi // pass 69138db976514ff2ad12d207a927219762eab179882Hugo Benichi // if not ARP IPv4 reply or request 69238db976514ff2ad12d207a927219762eab179882Hugo Benichi // pass 69338db976514ff2ad12d207a927219762eab179882Hugo Benichi // if unicast ARP reply 69438db976514ff2ad12d207a927219762eab179882Hugo Benichi // pass 69538db976514ff2ad12d207a927219762eab179882Hugo Benichi // if interface has no IPv4 address 69638db976514ff2ad12d207a927219762eab179882Hugo Benichi // if target ip is 0.0.0.0 69738db976514ff2ad12d207a927219762eab179882Hugo Benichi // drop 69838db976514ff2ad12d207a927219762eab179882Hugo Benichi // else 69938db976514ff2ad12d207a927219762eab179882Hugo Benichi // if target ip is not the interface ip 70038db976514ff2ad12d207a927219762eab179882Hugo Benichi // drop 701a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen // pass 702a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen 70338db976514ff2ad12d207a927219762eab179882Hugo Benichi final String checkTargetIPv4 = "checkTargetIPv4"; 70438db976514ff2ad12d207a927219762eab179882Hugo Benichi 70538db976514ff2ad12d207a927219762eab179882Hugo Benichi // Pass if not ARP IPv4. 70638db976514ff2ad12d207a927219762eab179882Hugo Benichi gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET); 70738db976514ff2ad12d207a927219762eab179882Hugo Benichi gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, gen.PASS_LABEL); 70838db976514ff2ad12d207a927219762eab179882Hugo Benichi 70938db976514ff2ad12d207a927219762eab179882Hugo Benichi // Pass if unknown ARP opcode. 71038db976514ff2ad12d207a927219762eab179882Hugo Benichi gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET); 71138db976514ff2ad12d207a927219762eab179882Hugo Benichi gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check 71238db976514ff2ad12d207a927219762eab179882Hugo Benichi gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, gen.PASS_LABEL); 71338db976514ff2ad12d207a927219762eab179882Hugo Benichi 71438db976514ff2ad12d207a927219762eab179882Hugo Benichi // Pass if unicast reply. 71538db976514ff2ad12d207a927219762eab179882Hugo Benichi gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); 71638db976514ff2ad12d207a927219762eab179882Hugo Benichi gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL); 71738db976514ff2ad12d207a927219762eab179882Hugo Benichi 71838db976514ff2ad12d207a927219762eab179882Hugo Benichi // Either a unicast request, a unicast reply, or a broadcast reply. 71938db976514ff2ad12d207a927219762eab179882Hugo Benichi gen.defineLabel(checkTargetIPv4); 72038db976514ff2ad12d207a927219762eab179882Hugo Benichi if (mIPv4Address == null) { 72138db976514ff2ad12d207a927219762eab179882Hugo Benichi // When there is no IPv4 address, drop GARP replies (b/29404209). 72238db976514ff2ad12d207a927219762eab179882Hugo Benichi gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET); 72338db976514ff2ad12d207a927219762eab179882Hugo Benichi gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, gen.DROP_LABEL); 72438db976514ff2ad12d207a927219762eab179882Hugo Benichi } else { 72538db976514ff2ad12d207a927219762eab179882Hugo Benichi // When there is an IPv4 address, drop unicast/broadcast requests 72638db976514ff2ad12d207a927219762eab179882Hugo Benichi // and broadcast replies with a different target IPv4 address. 727dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET); 728dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, gen.DROP_LABEL); 729dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen } 730a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen 731a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen gen.addJump(gen.PASS_LABEL); 732a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen } 733a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen 734a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen /** 735dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * Generate filter code to process IPv4 packets. Execution of this code ends in either the 736dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * DROP_LABEL or PASS_LABEL and does not fall off the end. 737dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * Preconditions: 738dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * - Packet being filtered is IPv4 739dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen */ 740dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 741dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException { 742dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // Here's a basic summary of what the IPv4 filter program does: 743dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // 744f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen // if filtering multicast (i.e. multicast lock not held): 7450dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // if it's DHCP destined to our MAC: 746f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen // pass 7470dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // if it's L2 broadcast: 7480dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // drop 7490dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // if it's IPv4 multicast: 7500dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // drop 7510dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // if it's IPv4 broadcast: 752f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen // drop 753dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // pass 754dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 755dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen if (mMulticastFilter) { 7560dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi final String skipDhcpv4Filter = "skip_dhcp_v4_filter"; 757dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 7580dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // Pass DHCP addressed to us. 7590dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // Check it's UDP. 760f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET); 7610dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter); 7620dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // Check it's not a fragment. This matches the BPF filter installed by the DHCP client. 763f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET); 7640dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter); 7650dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // Check it's addressed to DHCP client port. 766f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); 767f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET); 7680dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter); 7690dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // Check it's DHCP to our MAC address. 770f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET); 771f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen // NOTE: Relies on R1 containing IPv4 header offset. 772f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen gen.addAddR1(); 7730dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter); 7740dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addJump(gen.PASS_LABEL); 7750dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi 7760dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // Drop all multicasts/broadcasts. 7770dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.defineLabel(skipDhcpv4Filter); 7780dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi 7790dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // If IPv4 destination address is in multicast range, drop. 7800dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET); 7810dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addAnd(0xf0); 7820dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL); 7830dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi 7840dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // If IPv4 broadcast packet, drop regardless of L2 (b/30231088). 7850dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET); 7860dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, gen.DROP_LABEL); 7877d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi if (mIPv4Address != null && mIPv4PrefixLength < 31) { 7887d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength); 7897d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi gen.addJumpIfR0Equals(broadcastAddr, gen.DROP_LABEL); 7907d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi } 7910dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi 7920dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi // If L2 broadcast packet, drop. 7930dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); 7940dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL); 7950dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi gen.addJump(gen.DROP_LABEL); 796f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen } 797dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 798dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // Otherwise, pass 799dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen gen.addJump(gen.PASS_LABEL); 800dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen } 801dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 802dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 803dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen /** 804dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * Generate filter code to process IPv6 packets. Execution of this code ends in either the 805dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets. 806dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * Preconditions: 807dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * - Packet being filtered is IPv6 808dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen */ 809dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 810dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException { 811dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // Here's a basic summary of what the IPv6 filter program does: 812dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // 813dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // if it's not ICMPv6: 81411e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti // if it's multicast and we're dropping multicast: 81511e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti // drop 816dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // pass 81702428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi // if it's ICMPv6 RS to any: 81802428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi // drop 819dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // if it's ICMPv6 NA to ff02::1: 820dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // drop 821dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 822dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET); 82311e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti 82411e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti // Drop multicast if the multicast filter is enabled. 82511e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti if (mMulticastFilter) { 82611e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti // Don't touch ICMPv6 multicast here, we deal with it in more detail later. 82711e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti String skipIpv6MulticastFilterLabel = "skipIPv6MulticastFilter"; 82811e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIpv6MulticastFilterLabel); 82911e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti 83011e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti // Drop all other packets sent to ff00::/8. 83111e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET); 83211e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti gen.addJumpIfR0Equals(0xff, gen.DROP_LABEL); 83311e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti // Not multicast and not ICMPv6. Pass. 83411e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti gen.addJump(gen.PASS_LABEL); 83511e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti gen.defineLabel(skipIpv6MulticastFilterLabel); 83611e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti } else { 83711e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti // If not ICMPv6, pass. 83811e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL); 83911e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti } 84011e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti 841dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // Add unsolicited multicast neighbor announcements filter 842dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA"; 843dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET); 84402428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi // Drop all router solicitations (b/32833400) 84502428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi gen.addJumpIfR0Equals(ICMP6_ROUTER_SOLICITATION, gen.DROP_LABEL); 84602428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi // If not neighbor announcements, skip filter. 847dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel); 84802428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi // If to ff02::1, drop. 849dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // TODO: Drop only if they don't contain the address of on-link neighbours. 850dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET); 851dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS, 852dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen skipUnsolicitedMulticastNALabel); 853dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen gen.addJump(gen.DROP_LABEL); 854dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen gen.defineLabel(skipUnsolicitedMulticastNALabel); 855dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen } 856dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 857dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen /** 858dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * Begin generating an APF program to: 859dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * <ul> 860a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen * <li>Drop ARP requests not for us, if mIPv4Address is set, 861dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC, 862dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * <li>Drop IPv4 multicast packets, if mMulticastFilter, 863dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * <li>Pass all other IPv4 packets, 864dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen * <li>Drop all broadcast non-IP non-ARP packets. 865dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * <li>Pass all non-ICMPv6 IPv6 packets, 866dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * <li>Pass all non-IPv4 and non-IPv6 packets, 867dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * <li>Drop IPv6 ICMPv6 NAs to ff02::1. 86802428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi * <li>Drop IPv6 ICMPv6 RSs. 869dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows 870dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * insertion of RA filters here, or if there aren't any, just passes the packets. 871dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * </ul> 872dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen */ 873dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 874dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private ApfGenerator beginProgramLocked() throws IllegalInstructionException { 875dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen ApfGenerator gen = new ApfGenerator(); 876dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // This is guaranteed to return true because of the check in maybeCreate. 877f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen gen.setApfVersion(mApfCapabilities.apfVersionSupported); 878dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 879dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // Here's a basic summary of what the initial program does: 880dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // 881a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen // if it's ARP: 882dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen // insert ARP filter to drop or pass these appropriately 883dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // if it's IPv4: 884dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // insert IPv4 filter to drop or pass these appropriately 885dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // if it's not IPv6: 886dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen // if it's broadcast: 887dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen // drop 888dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // pass 889dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets 890dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 891dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen // Add ARP filters: 892dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen String skipArpFiltersLabel = "skipArpFilters"; 893a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET); 894dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel); 895dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen generateArpFilterLocked(gen); 896dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen gen.defineLabel(skipArpFiltersLabel); 897a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen 898dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // Add IPv4 filters: 899dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen String skipIPv4FiltersLabel = "skipIPv4Filters"; 900a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not 901a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen // execute the ARP filter, since that filter does not fall through, but either drops or 902a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen // passes. 903dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel); 904dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen generateIPv4FilterLocked(gen); 905dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen gen.defineLabel(skipIPv4FiltersLabel); 906dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 907dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen // Check for IPv6: 908dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not 909a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen // execute the ARP or IPv4 filters, since those filters do not fall through, but either 910a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen // drop or pass. 911dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen String ipv6FilterLabel = "IPv6Filters"; 912dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel); 913dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen 914dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen // Drop non-IP non-ARP broadcasts, pass the rest 915dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); 916dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL); 917dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen gen.addJump(gen.DROP_LABEL); 918dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen 919dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen // Add IPv6 filters: 920dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen gen.defineLabel(ipv6FilterLabel); 921dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen generateIPv6FilterLocked(gen); 922dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen return gen; 923dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen } 924dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 9254fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi /** 9264fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi * Generate and install a new filter program. 9274fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi */ 928dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 9299132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen @VisibleForTesting 9309132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen void installNewProgramLocked() { 931dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen purgeExpiredRasLocked(); 9324fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi ArrayList<Ra> rasToFilter = new ArrayList<>(); 933578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen final byte[] program; 934578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen long programMinLifetime = Long.MAX_VALUE; 935578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen try { 936578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Step 1: Determine how many RA filters we can fit in the program. 937dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen ApfGenerator gen = beginProgramLocked(); 938578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen for (Ra ra : mRas) { 939dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen ra.generateFilterLocked(gen); 940dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // Stop if we get too big. 941f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen if (gen.programLengthOverEstimate() > mApfCapabilities.maximumApfProgramSize) break; 942dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen rasToFilter.add(ra); 943578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 944dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // Step 2: Actually generate the program 945dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen gen = beginProgramLocked(); 946dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen for (Ra ra : rasToFilter) { 947dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen)); 948578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 949578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Execution will reach the end of the program if no filters match, which will pass the 950578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // packet to the AP. 951578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen program = gen.generate(); 9520668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi } catch (IllegalInstructionException|IllegalStateException e) { 9530668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi Log.e(TAG, "Failed to generate APF program.", e); 954578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen return; 955578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 95622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi final long now = currentTimeSeconds(); 95722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mLastTimeInstalledProgram = now; 958578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen mLastInstalledProgramMinLifetime = programMinLifetime; 95939c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti mLastInstalledProgram = program; 960059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti mNumProgramUpdates++; 961059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti 9625ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti if (VDBG) { 9635ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti hexDump("Installing filter: ", program, program.length); 9645ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti } 965f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen mIpManagerCallback.installPacketFilter(program); 96622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi logApfProgramEventLocked(now); 96722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mLastInstallEvent = new ApfProgramEvent(); 96822d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mLastInstallEvent.lifetime = programMinLifetime; 96922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mLastInstallEvent.filteredRas = rasToFilter.size(); 97022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mLastInstallEvent.currentRas = mRas.size(); 97122d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mLastInstallEvent.programLength = program.length; 97222d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mLastInstallEvent.flags = ApfProgramEvent.flagsFor(mIPv4Address != null, mMulticastFilter); 97322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi } 97422d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi 97522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi private void logApfProgramEventLocked(long now) { 97622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi if (mLastInstallEvent == null) { 97722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi return; 97822d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi } 97922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi ApfProgramEvent ev = mLastInstallEvent; 98022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mLastInstallEvent = null; 98122d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi ev.actualLifetime = now - mLastTimeInstalledProgram; 98222d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi if (ev.actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) { 98322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi return; 98422d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi } 98522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mMetricsLog.log(ev); 986578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 987578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 988647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi /** 989647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi * Returns {@code true} if a new program should be installed because the current one dies soon. 990647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi */ 991647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi private boolean shouldInstallnewProgram() { 992578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime; 9934456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING; 994578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 995578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 996578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen private void hexDump(String msg, byte[] packet, int length) { 99739c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */)); 998578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 999578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 1000dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen @GuardedBy("this") 1001dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen private void purgeExpiredRasLocked() { 1002dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen for (int i = 0; i < mRas.size();) { 1003dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen if (mRas.get(i).isExpired()) { 1004dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen log("Expiring " + mRas.get(i)); 1005dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen mRas.remove(i); 1006dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen } else { 1007dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen i++; 1008dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen } 1009dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen } 1010dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen } 1011dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 1012647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi /** 1013647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi * Process an RA packet, updating the list of known RAs and installing a new APF program 1014647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi * if the current APF program should be updated. 1015647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi * @return a ProcessRaResult enum describing what action was performed. 1016647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi */ 10170668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi @VisibleForTesting 10180668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi synchronized ProcessRaResult processRa(byte[] packet, int length) { 10195ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti if (VDBG) hexDump("Read packet = ", packet, length); 1020578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 1021578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Have we seen this RA before? 1022578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen for (int i = 0; i < mRas.size(); i++) { 1023578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen Ra ra = mRas.get(i); 1024578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen if (ra.matches(packet, length)) { 10255ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti if (VDBG) log("matched RA " + ra); 1026578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Update lifetimes. 10274456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi ra.mLastSeen = currentTimeSeconds(); 1028578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen ra.mMinLifetime = ra.minLifetime(packet, length); 10295ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti ra.seenCount++; 1030578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 1031578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Keep mRas in LRU order so as to prioritize generating filters for recently seen 1032578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // RAs. LRU prioritizes this because RA filters are generated in order from mRas 1033578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // until the filter program exceeds the maximum filter program size allowed by the 1034578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // chipset, so RAs appearing earlier in mRas are more likely to make it into the 1035578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // filter program. 1036578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // TODO: consider sorting the RAs in order of increasing expiry time as well. 1037578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // Swap to front of array. 1038578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen mRas.add(0, mRas.remove(i)); 1039578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 1040647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi // If the current program doesn't expire for a while, don't update. 1041647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi if (shouldInstallnewProgram()) { 1042647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi installNewProgramLocked(); 1043647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return ProcessRaResult.UPDATE_EXPIRY; 1044647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi } 1045647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return ProcessRaResult.MATCH; 1046578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 1047578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 1048dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen purgeExpiredRasLocked(); 1049578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // TODO: figure out how to proceed when we've received more then MAX_RAS RAs. 1050647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi if (mRas.size() >= MAX_RAS) { 1051647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return ProcessRaResult.DROPPED; 1052647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi } 1053dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen final Ra ra; 1054578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen try { 1055dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen ra = new Ra(packet, length); 1056578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } catch (Exception e) { 10570668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi Log.e(TAG, "Error parsing RA", e); 1058647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return ProcessRaResult.PARSE_ERROR; 1059578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 1060dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen // Ignore 0 lifetime RAs. 1061647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi if (ra.isExpired()) { 1062647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return ProcessRaResult.ZERO_LIFETIME; 1063647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi } 1064dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen log("Adding " + ra); 1065dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen mRas.add(ra); 1066dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen installNewProgramLocked(); 1067647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi return ProcessRaResult.UPDATE_NEW_RA; 1068578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 1069578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 1070578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen /** 1071f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet 1072578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * filtering using APF programs. 1073578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen */ 1074f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities, 10752e074db972355a77f91378b5b1daceb500dde019Paul Jensen NetworkInterface networkInterface, IpManager.Callback ipManagerCallback, 10762e074db972355a77f91378b5b1daceb500dde019Paul Jensen boolean multicastFilter) { 1077f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen if (apfCapabilities == null || networkInterface == null) return null; 1078f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen if (apfCapabilities.apfVersionSupported == 0) return null; 1079f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen if (apfCapabilities.maximumApfProgramSize < 512) { 1080f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize); 1081f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen return null; 1082578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 1083578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // For now only support generating programs for Ethernet frames. If this restriction is 1084578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // lifted: 1085578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // 1. the program generator will need its offsets adjusted. 1086578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen // 2. the packet filter attached to our packet socket will need its offset adjusted. 1087f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null; 1088f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen if (!new ApfGenerator().setApfVersion(apfCapabilities.apfVersionSupported)) { 1089f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported); 1090f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen return null; 1091578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 10926ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback, 10936ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi multicastFilter, new IpConnectivityLog()); 1094578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 1095578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen 1096dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen public synchronized void shutdown() { 1097578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen if (mReceiveThread != null) { 10985ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti log("shutting down"); 1099578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen mReceiveThread.halt(); // Also closes socket. 1100578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen mReceiveThread = null; 1101578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 1102dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen mRas.clear(); 1103dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen } 1104dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen 110522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi public synchronized void setMulticastFilter(boolean isEnabled) { 110622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi if (mMulticastFilter == isEnabled) { 110722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi return; 110822d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi } 110922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mMulticastFilter = isEnabled; 111022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi if (!isEnabled) { 111122d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi mNumProgramUpdatesAllowingMulticast++; 1112dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen } 111322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi installNewProgramLocked(); 1114578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen } 11155ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti 11167d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */ 11177d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi private static LinkAddress findIPv4LinkAddress(LinkProperties lp) { 11187d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi LinkAddress ipv4Address = null; 11197d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi for (LinkAddress address : lp.getLinkAddresses()) { 11207d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi if (!(address.getAddress() instanceof Inet4Address)) { 11217d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi continue; 11227d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi } 11237d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) { 11247d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi // More than one IPv4 address, abort. 11257d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi return null; 11267d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi } 11277d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi ipv4Address = address; 1128a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen } 1129a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen return ipv4Address; 1130a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen } 1131a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen 1132a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen public synchronized void setLinkProperties(LinkProperties lp) { 1133a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state. 11347d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi final LinkAddress ipv4Address = findIPv4LinkAddress(lp); 11357d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null; 11367d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0; 11377d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) { 11387d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi return; 11397d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi } 11407d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi mIPv4Address = addr; 11417d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi mIPv4PrefixLength = prefix; 1142a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen installNewProgramLocked(); 1143a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen } 1144a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen 1145dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen public synchronized void dump(IndentingPrintWriter pw) { 1146059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti pw.println("Capabilities: " + mApfCapabilities); 11475ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED")); 1148059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW")); 1149a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen try { 1150059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress()); 1151a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen } catch (UnknownHostException|NullPointerException e) {} 1152059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti 11535ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti if (mLastTimeInstalledProgram == 0) { 11545ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti pw.println("No program installed."); 11555ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti return; 11565ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti } 1157059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti pw.println("Program updates: " + mNumProgramUpdates); 11585ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti pw.println(String.format( 1159059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti "Last program length %d, installed %ds ago, lifetime %ds", 11604456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram, 11615ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti mLastInstalledProgramMinLifetime)); 11625ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti 11635ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti pw.println("RA filters:"); 11645ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti pw.increaseIndent(); 11655ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti for (Ra ra: mRas) { 11665ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti pw.println(ra); 11675ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti pw.increaseIndent(); 11685ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti pw.println(String.format( 11694456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen)); 117039c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti if (DBG) { 117139c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti pw.println("Last match:"); 117239c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti pw.increaseIndent(); 117339c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti pw.println(ra.getLastMatchingPacket()); 117439c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti pw.decreaseIndent(); 117539c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti } 11765ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti pw.decreaseIndent(); 11775ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti } 1178059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti pw.decreaseIndent(); 117939c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti 118039c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti if (DBG) { 118139c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti pw.println("Last program:"); 118239c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti pw.increaseIndent(); 118339c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */)); 118439c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti pw.decreaseIndent(); 118539c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti } 11865ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti } 11877d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi 11887d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi private static int uint8(byte b) { 11897d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi return b & 0xff; 11907d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi } 11917d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi 11927d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi private static int uint16(short s) { 11937d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi return s & 0xffff; 11947d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi } 11957d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi 11967d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi private static long uint32(int i) { 11977d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi return i & 0xffffffffL; 11987d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi } 11997d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi 12004104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi private static int getUint8(ByteBuffer buffer, int position) { 12014104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi return uint8(buffer.get(position)); 12024104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi } 12034104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi 12044104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi private static int getUint16(ByteBuffer buffer, int position) { 12057d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi return uint16(buffer.getShort(position)); 12067d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi } 12077d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi 12087d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi private static long getUint32(ByteBuffer buffer, int position) { 12097d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi return uint32(buffer.getInt(position)); 12107d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi } 12117d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi 12127d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi // TODO: move to android.net.NetworkUtils 12137d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi @VisibleForTesting 12147d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) { 12157d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi return bytesToInt(addrBytes) | (int) (uint32(-1) >>> prefixLength); 12167d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi } 12177d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi 12187d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi @VisibleForTesting 12197d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi public static int bytesToInt(byte[] addrBytes) { 12207d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi return (uint8(addrBytes[0]) << 24) 12217d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi + (uint8(addrBytes[1]) << 16) 12227d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi + (uint8(addrBytes[2]) << 8) 12237d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi + (uint8(addrBytes[3])); 12247d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi } 1225578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen} 1226