1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.nfc; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import androidx.test.ext.junit.runners.AndroidJUnit4; 21 22 import org.junit.After; 23 import org.junit.Before; 24 import org.junit.Test; 25 import org.junit.runner.RunWith; 26 27 @RunWith(AndroidJUnit4.class) 28 public final class NfcRoutingTableParseTest { 29 private static final String TAG = NfcRoutingTableParseTest.class.getSimpleName(); 30 private RoutingTableParser mRoutingTableParser; 31 32 // NFCEE-ID 33 static final byte EE_ID_HOST = (byte) 0x00; 34 static final byte EE_ID_UICC = (byte) 0x81; 35 static final byte EE_ID_ESE = (byte) 0x86; 36 37 // Power State Mask 38 static final byte APPLY_ALL = (byte) 0x3F; 39 static final byte SWITCH_ON_SUB_3 = (byte) 0x20; 40 static final byte SWITCH_ON_SUB_2 = (byte) 0x10; 41 static final byte SWITCH_ON_SUB_1 = (byte) 0x08; 42 static final byte BATTERY_OFF = (byte) 0x04; 43 static final byte SWITCH_OFF = (byte) 0x02; 44 static final byte SWITCH_ON = (byte) 0x01; 45 46 @Before setUp()47 public void setUp() { 48 mRoutingTableParser = new RoutingTableParser(); 49 } 50 51 @After tearDown()52 public void tearDown() throws Exception { 53 } 54 55 @Test testParseValidTechnologyEntry()56 public void testParseValidTechnologyEntry() { 57 /** 58 * set qualifier = 0x00 to indicates the routing is allowed for the power modes 59 * where it is not supported 60 */ 61 byte qualifier = (byte) 0x00; 62 byte type = RoutingTableParser.TYPE_TECHNOLOGY; 63 byte eeId = EE_ID_HOST; 64 byte pwrState = (byte) (SWITCH_ON_SUB_3 | SWITCH_ON_SUB_2 | SWITCH_ON_SUB_1 | SWITCH_ON); 65 byte[] entry = hexStrToByteArray("01"); 66 byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry); 67 mRoutingTableParser.parse(rt); 68 69 int ret = mRoutingTableParser.getCommitStatus(type, entry); 70 71 assertThat(ret).isEqualTo(mRoutingTableParser.STATS_HOST_OK); 72 } 73 74 @Test testParseInvalidTechnologyEntry()75 public void testParseInvalidTechnologyEntry() { 76 /** 77 * set qualifier = 0x00 to indicates the routing is allowed for the power modes 78 * where it is not supported 79 */ 80 byte qualifier = (byte) 0x00; 81 byte type = RoutingTableParser.TYPE_TECHNOLOGY; 82 byte eeId = EE_ID_HOST; 83 byte pwrState = (byte) (SWITCH_ON_SUB_3 | SWITCH_ON_SUB_2 | SWITCH_ON_SUB_1 | SWITCH_ON); 84 byte[] entry = hexStrToByteArray("0001"); 85 byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry); 86 mRoutingTableParser.parse(rt); 87 88 int ret = mRoutingTableParser.getCommitStatus(type, entry); 89 90 assertThat(ret).isEqualTo(mRoutingTableParser.STATS_NOT_FOUND); 91 } 92 93 @Test testParseValidProtocolEntry()94 public void testParseValidProtocolEntry() { 95 /** 96 * set qualifier = 0x00 to indicates the routing is allowed for the power modes 97 * where it is not supported 98 */ 99 byte qualifier = (byte) 0x00; 100 byte type = RoutingTableParser.TYPE_PROTOCOL; 101 byte eeId = EE_ID_HOST; 102 byte pwrState = SWITCH_ON; 103 byte[] entry = hexStrToByteArray("04"); 104 byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry); 105 mRoutingTableParser.parse(rt); 106 107 int ret = mRoutingTableParser.getCommitStatus(type, entry); 108 109 assertThat(ret).isEqualTo(mRoutingTableParser.STATS_HOST_OK); 110 } 111 112 @Test testParseInvalidProtocolEntry()113 public void testParseInvalidProtocolEntry() { 114 /** 115 * set qualifier = 0x00 to indicates the routing is allowed for the power modes 116 * where it is not supported 117 */ 118 byte qualifier = (byte) 0x00; 119 byte type = RoutingTableParser.TYPE_PROTOCOL; 120 byte eeId = EE_ID_HOST; 121 byte pwrState = SWITCH_ON; 122 byte[] entry = hexStrToByteArray("0405"); 123 byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry); 124 mRoutingTableParser.parse(rt); 125 126 int ret = mRoutingTableParser.getCommitStatus(type, entry); 127 128 assertThat(ret).isEqualTo(mRoutingTableParser.STATS_NOT_FOUND); 129 } 130 131 @Test testParseValidAidEntry()132 public void testParseValidAidEntry() { 133 /** 134 * set qualifier = 0x40 to indicates the routing is blocked for the power modes 135 * where it is not supported 136 */ 137 byte qualifier = (byte) 0x40; 138 byte type = RoutingTableParser.TYPE_AID; 139 byte eeId = EE_ID_UICC; 140 byte pwrState = (byte) (APPLY_ALL ^ BATTERY_OFF); 141 byte[] entry = hexStrToByteArray("6E6663746573743031"); 142 byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry); 143 mRoutingTableParser.parse(rt); 144 145 int ret = mRoutingTableParser.getCommitStatus(type, entry); 146 147 assertThat(ret).isEqualTo(mRoutingTableParser.STATS_OFFHOST_OK); 148 } 149 150 @Test testParseInvalidAidEntry()151 public void testParseInvalidAidEntry() { 152 /** 153 * set qualifier = 0x40 to indicates the routing is blocked for the power modes 154 * where it is not supported 155 */ 156 byte qualifier = (byte) 0x40; 157 byte type = RoutingTableParser.TYPE_AID; 158 byte eeId = EE_ID_UICC; 159 byte pwrState = (byte) (APPLY_ALL ^ BATTERY_OFF); 160 byte[] entry = hexStrToByteArray("6E66637465737430316E6663746573743031"); 161 byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry); 162 mRoutingTableParser.parse(rt); 163 164 int ret = mRoutingTableParser.getCommitStatus(type, entry); 165 166 assertThat(ret).isEqualTo(mRoutingTableParser.STATS_NOT_FOUND); 167 } 168 169 @Test testParseValidSystemCodeEntry()170 public void testParseValidSystemCodeEntry() { 171 /** 172 * set qualifier = 0x40 to indicates the routing is blocked for the power modes 173 * where it is not supported 174 */ 175 byte qualifier = (byte) 0x40; 176 byte type = RoutingTableParser.TYPE_SYSTEMCODE; 177 byte eeId = EE_ID_ESE; 178 byte pwrState = (byte) (APPLY_ALL ^ BATTERY_OFF); 179 byte[] entry = hexStrToByteArray("FEFE"); 180 byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry); 181 mRoutingTableParser.parse(rt); 182 183 int ret = mRoutingTableParser.getCommitStatus(type, entry); 184 185 assertThat(ret).isEqualTo(mRoutingTableParser.STATS_OFFHOST_OK); 186 } 187 188 @Test testParseSeveralValidSystemCodeEntry()189 public void testParseSeveralValidSystemCodeEntry() { 190 /** 191 * set qualifier = 0x40 to indicates the routing is blocked for the power modes 192 * where it is not supported 193 */ 194 byte qualifier = (byte) 0x40; 195 byte type = RoutingTableParser.TYPE_SYSTEMCODE; 196 byte eeId = EE_ID_ESE; 197 byte pwrState = (byte) (APPLY_ALL ^ BATTERY_OFF); 198 byte[] entry1 = hexStrToByteArray("FEFE"); 199 byte[] entry2 = hexStrToByteArray("EEEE"); 200 byte[] entryAll = hexStrToByteArray("FEFEEEEE"); 201 byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entryAll); 202 mRoutingTableParser.parse(rt); 203 204 int ret1 = mRoutingTableParser.getCommitStatus(type, entry1); 205 int ret2 = mRoutingTableParser.getCommitStatus(type, entry2); 206 207 assertThat(ret1).isEqualTo(mRoutingTableParser.STATS_OFFHOST_OK); 208 assertThat(ret2).isEqualTo(mRoutingTableParser.STATS_OFFHOST_OK); 209 } 210 211 @Test testParseInvalidSystemCodeEntry()212 public void testParseInvalidSystemCodeEntry() { 213 /** 214 * set qualifier = 0x40 to indicates the routing is blocked for the power modes 215 * where it is not supported 216 */ 217 byte qualifier = (byte) 0x40; 218 byte type = RoutingTableParser.TYPE_SYSTEMCODE; 219 byte eeId = EE_ID_ESE; 220 byte pwrState = (byte) (APPLY_ALL ^ BATTERY_OFF); 221 byte[] entry = hexStrToByteArray("FEFEFE"); 222 byte[] rt = generateRoutingEntry(qualifier, type, eeId, pwrState, entry); 223 mRoutingTableParser.parse(rt); 224 225 int ret = mRoutingTableParser.getCommitStatus(type, entry); 226 227 assertThat(ret).isEqualTo(mRoutingTableParser.STATS_NOT_FOUND); 228 } 229 generateRoutingEntry(byte qualifier, byte type, byte eeId, byte pwrState, byte[] entry)230 private byte[] generateRoutingEntry(byte qualifier, byte type, byte eeId, byte pwrState, 231 byte[] entry) { 232 int length = 2 + entry.length; 233 byte[] rt = new byte[length + 2]; 234 rt[0] = (byte) (qualifier | type); 235 rt[1] = (byte) length; 236 rt[2] = eeId; 237 rt[3] = pwrState; 238 239 for (int i = 0; i < entry.length; i++) { 240 rt[i + 4] = entry[i]; 241 } 242 243 return rt; 244 } 245 hexStrToByteArray(String hexStr)246 private byte[] hexStrToByteArray(String hexStr) { 247 if (hexStr.length() % 2 != 0) { 248 return new byte[0]; 249 } 250 251 char[] hex = hexStr.toCharArray(); 252 int length = hexStr.length() / 2; 253 byte[] byteArr = new byte[length]; 254 for (int i = 0; i < length; i++) { 255 int high = Character.digit(hex[i * 2], 16); 256 int low = Character.digit(hex[i * 2 + 1], 16); 257 int value = (high << 4) | low; 258 259 if (value > 127) { 260 value -= 256; 261 } 262 byteArr [i] = (byte) value; 263 } 264 265 return byteArr; 266 } 267 } 268